diff --git a/c/CMakeLists.txt b/c/CMakeLists.txt new file mode 100644 index 00000000..99ef04fd --- /dev/null +++ b/c/CMakeLists.txt @@ -0,0 +1,167 @@ +#Copyright (c) Microsoft. All rights reserved. +#Licensed under the MIT license. See LICENSE file in the project root for full license information. + +cmake_minimum_required(VERSION 3.0) +project(azure_c_shared_utility) + +#the following variables are project-wide and can be used with cmake-gui +option(skip_unittests "set skip_unittests to ON to skip unittests (default is OFF)[if possible, they are always build]" OFF) +option(compileOption_C "passes a string to the command line of the C compiler" OFF) +option(compileOption_CXX "passes a string to the command line of the C++ compiler" OFF) + +#Use solution folders. +set_property(GLOBAL PROPERTY USE_FOLDERS ON) + +enable_testing() + +#if any compiler has a command line switch called "OFF" then it will need special care +if(NOT "${compileOption_C}" STREQUAL "OFF") + set(CMAKE_C_FLAGS "${compileOption_C} ${CMAKE_C_FLAGS}") +endif() + +if(NOT "${compileOption_CXX}" STREQUAL "OFF") + set(CMAKE_CXX_FLAGS "${compileOption_CXX} ${CMAKE_CXX_FLAGS}") +endif() + +#this project uses several other projects that are build not by these CMakeFiles +#this project also targets several OSes + +#this function takes care of three things: +#1. copying some shared libraries(.dll or .so) to the location of the output executable + +macro(compileAsC99) + if (CMAKE_VERSION VERSION_LESS "3.1") + if (CMAKE_C_COMPILER_ID STREQUAL "GNU") + set (CMAKE_C_FLAGS "--std=c99 ${CMAKE_C_FLAGS}") + set (CMAKE_CXX_FLAGS "--std=c++11 ${CMAKE_CXX_FLAGS}") + endif() + else() + set (CMAKE_C_STANDARD 99) + set (CMAKE_CXX_STANDARD 11) + endif() +endmacro(compileAsC99) + + +function(windows_unittests_add_dll whatIsBuilding) + link_directories(${whatIsBuilding}_dll $ENV{VCInstallDir}UnitTest/lib) + + add_library(${whatIsBuilding}_dll SHARED + ${${whatIsBuilding}_cpp_files} + ${${whatIsBuilding}_h_files} + ${${whatIsBuilding}_c_files} + ) + + set_target_properties(${whatIsBuilding}_dll + PROPERTIES + FOLDER "UnitTests") + + target_include_directories(${whatIsBuilding}_dll PUBLIC ${sharedutil_include_directories} $ENV{VCInstallDir}UnitTest/include) + target_compile_definitions(${whatIsBuilding}_dll PUBLIC -DCPP_UNITTEST) + target_link_libraries(${whatIsBuilding}_dll micromock_cpp_unittest ctest ${ARGN}) +endfunction() + +function(windows_unittests_add_lib whatIsBuilding) + link_directories(${whatIsBuilding}_lib $ENV{VCInstallDir}UnitTest/lib) + + add_library(${whatIsBuilding}_lib STATIC + ${${whatIsBuilding}_cpp_files} + ${${whatIsBuilding}_h_files} + ${${whatIsBuilding}_c_files} + ) + + target_include_directories(${whatIsBuilding}_lib PUBLIC ${sharedutil_include_directories}) + target_compile_definitions(${whatIsBuilding}_lib PUBLIC -DUSE_CTEST) + target_link_libraries(${whatIsBuilding}_lib micromock_ctest ctest ${ARGN}) +endfunction() + +function(windows_unittests_add_exe whatIsBuilding) + add_executable(${whatIsBuilding}_exe + ${${whatIsBuilding}_cpp_files} + ${${whatIsBuilding}_h_files} + ${${whatIsBuilding}_c_files} + ${CMAKE_CURRENT_LIST_DIR}/main.c + ) + set_target_properties(${whatIsBuilding}_exe + PROPERTIES + FOLDER "UnitTests") + + target_compile_definitions(${whatIsBuilding}_exe PUBLIC -DUSE_CTEST) + target_include_directories(${whatIsBuilding}_exe PUBLIC ${sharedutil_include_directories}) + target_link_libraries(${whatIsBuilding}_exe micromock_ctest ctest ${ARGN}) + add_test(NAME ${whatIsBuilding} COMMAND ${whatIsBuilding}_exe) +endfunction() + +function(build_test_artifacts whatIsBuilding use_gballoc) + + #the first argument is what is building + #the second argument is whether the tests should be build with gballoc #defines or not + #the following arguments are a list of libraries to link with + + if(${use_gballoc}) + add_definitions(-DGB_MEASURE_MEMORY_FOR_THIS -DGB_DEBUG_ALLOC) + else() + endif() + + #setting #defines + if(WIN32) + add_definitions(-D_CRT_SECURE_NO_WARNINGS) + else() + endif() + + #setting includes + set(sharedutil_include_directories ${MICROMOCK_INC_FOLDER} ${TESTRUNNERSWITCHER_INC_FOLDER} ${CTEST_INC_FOLDER} ${SAL_INC_FOLDER} ${SHARED_UTIL_INC_FOLDER} ${SHARED_UTIL_SRC_FOLDER}) + if(WIN32) + else() + include_directories(${sharedutil_include_directories}) + endif() + + + #setting output type + if(WIN32) + #to disable running e2e or longhaul or unittests tests for windows, we build the the same thing as "static library" so it is not picked up by visual studio + if( + (("${whatIsBuilding}" MATCHES ".*longhaul.*") AND NOT ${run_longhaul_tests}) OR + (("${whatIsBuilding}" MATCHES ".*unittests.*") AND ${skip_unittests}) + ) + windows_unittests_add_lib(${whatIsBuilding} ${ARGN}) + else() + windows_unittests_add_exe(${whatIsBuilding} ${ARGN}) + windows_unittests_add_dll(${whatIsBuilding} ${ARGN}) + endif() + else() + if( + (("${whatIsBuilding}" MATCHES ".*longhaul.*") AND NOT ${run_longhaul_tests}) OR + (("${whatIsBuilding}" MATCHES ".*unittests.*") AND ${skip_unittests}) + ) + windows_unittests_add_lib(${whatIsBuilding} ${ARGN}) + else() + windows_unittests_add_exe(${whatIsBuilding} ${ARGN}) + endif() + endif() +endfunction(build_test_artifacts) + +function(set_platform_files) +if(WIN32) + set(PLATFORM_C_FILE ${CMAKE_CURRENT_LIST_DIR}/sharedutil/adapters/platform_win32.c PARENT_SCOPE) + set(TLSIO_C_FILE ${CMAKE_CURRENT_LIST_DIR}/sharedutil/adapters/tlsio_win32.c PARENT_SCOPE) + set(SOCKETIO_C_FILE ${CMAKE_CURRENT_LIST_DIR}/sharedutil/adapters/socketio_win32.c PARENT_SCOPE) + set(LOCK_C_FILE ${CMAKE_CURRENT_LIST_DIR}/sharedutil/adapters/lock_c11.c PARENT_SCOPE) + set(THREAD_C_FILE ${CMAKE_CURRENT_LIST_DIR}/sharedutil/adapters/threadapi_c11.c PARENT_SCOPE) + set(HTTP_C_FILE ${CMAKE_CURRENT_LIST_DIR}/sharedutil/adapters/httpapi_winhttp.c PARENT_SCOPE) + #set(CONDITION_C_FILE ${CMAKE_CURRENT_LIST_DIR}/sharedutil/adapters/condition_c11.c PARENT_SCOPE) +else() + set(LOCK_C_FILE ${CMAKE_CURRENT_LIST_DIR}/sharedutil/adapters/lock_pthreads.c PARENT_SCOPE) + #set(CONDITION_C_FILE ${CMAKE_CURRENT_LIST_DIR}/sharedutil/adapters/condition_pthreads.c PARENT_SCOPE) + set(THREAD_C_FILE ${CMAKE_CURRENT_LIST_DIR}/sharedutil/adapters/threadapi_pthreads.c PARENT_SCOPE) + set(HTTP_C_FILE ${CMAKE_CURRENT_LIST_DIR}/sharedutil/adapters/httpapi_curl.c PARENT_SCOPE) + set(PLATFORM_C_FILE ${CMAKE_CURRENT_LIST_DIR}/sharedutil/adapters/platform_linux.c PARENT_SCOPE) + set(TLSIO_C_FILE ${CMAKE_CURRENT_LIST_DIR}/sharedutil/adapters/tlsio_linux.c PARENT_SCOPE) + set(SOCKETIO_C_FILE ${CMAKE_CURRENT_LIST_DIR}/sharedutil/adapters/socketio_linux.c PARENT_SCOPE) +endif() +endfunction(set_platform_files) + +set_platform_files() + +add_subdirectory(testtools) + +add_subdirectory(sharedutil) diff --git a/c/sharedutil/CMakeLists.txt b/c/sharedutil/CMakeLists.txt new file mode 100644 index 00000000..549f1ec2 --- /dev/null +++ b/c/sharedutil/CMakeLists.txt @@ -0,0 +1,104 @@ +#Copyright (c) Microsoft. All rights reserved. +#Licensed under the MIT license. See LICENSE file in the project root for full license information. + +cmake_minimum_required(VERSION 3.0) + +compileAsC99() +#these are the C source files +set(source_c_files +./src/base64.c +./src/buffer.c +./src/crt_abstractions.c +./src/doublylinkedlist.c +./src/gballoc.c +./src/hmac.c +./src/hmacsha256.c +./src/io.c +./src/list.c +./src/map.c +./src/sastoken.c +./src/sha1.c +./src/sha224.c +./src/sha384-512.c +./src/strings.c +./src/string_tokenizer.c +./src/urlencode.c +./src/usha.c +./src/vector.c +./adapters/agenttime.c +) + +if(${use_http}) + set(source_c_files ${source_c_files} + ./src/httpapiex.c + ./src/httpapiexsas.c + ./src/httpheaders.c + ) +endif() + +#these are the C headers +set(source_h_files +./inc/agenttime.h +./inc/base64.h +./inc/buffer_.h +./inc/crt_abstractions.h +#./inc/condition.h +./inc/doublylinkedlist.h +./inc/gballoc.h +./inc/hmac.h +./inc/hmacsha256.h +./inc/io.h +./inc/iot_logging.h +./inc/list.h +./inc/lock.h +./inc/macro_utils.h +./inc/map.h +./inc/platform.h +./inc/sastoken.h +./inc/sha-private.h +./inc/sha.h +./inc/socketio.h +./inc/stdint_ce6.h +./inc/strings.h +./inc/string_tokenizer.h +./inc/threadapi.h +./inc/tlsio.h +./inc/urlencode.h +./inc/vector.h +) + +if(${use_http}) + set(source_h_files ${source_h_files} + ./inc/httpapi.h + ./inc/httpapiex.h + ./inc/httpapiexsas.h + ./inc/httpheaders.h + ) +endif() + +#these are the include folders +#the following "set" statetement exports across the project a global variable called COMMON_INC_FOLDER that expands to whatever needs to included when using COMMON library +set(SHARED_UTIL_INC_FOLDER ${CMAKE_CURRENT_LIST_DIR}/inc CACHE INTERNAL "this is what needs to be included if using sharedLib lib" FORCE) +set(SHARED_UTIL_SRC_FOLDER ${CMAKE_CURRENT_LIST_DIR}/src CACHE INTERNAL "this is what needs to be included when doing include sources" FORCE) +include_directories(${SHARED_UTIL_INC_FOLDER}) + +IF(WIN32) + #windows needs this define + add_definitions(-D_CRT_SECURE_NO_WARNINGS) +ENDIF(WIN32) + +#Setup the platform files +set(source_h_files ${source_h_files} + ${PLATFORM_C_FILE} + ${TLSIO_C_FILE} + ${SOCKETIO_C_FILE} + ${LOCK_C_FILE} + ${THREAD_C_FILE} + ${HTTP_C_FILE} +) + +#this is the product (a library) +add_library(aziotsharedlib ${source_c_files} ${source_h_files}) + +add_subdirectory(tests) +add_subdirectory(testtools) \ No newline at end of file diff --git a/c/sharedutil/adapters/agenttime.c b/c/sharedutil/adapters/agenttime.c new file mode 100644 index 00000000..88798de2 --- /dev/null +++ b/c/sharedutil/adapters/agenttime.c @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include +#ifdef _CRTDBG_MAP_ALLOC +#include +#endif +#include "gballoc.h" + +#include "time.h" +#include "agenttime.h" + +time_t get_time(time_t* p) +{ + return time(p); +} + +struct tm* get_gmtime(time_t* currentTime) +{ + return gmtime(currentTime); +} + +char* get_ctime(time_t* timeToGet) +{ + return ctime(timeToGet); +} + +double get_difftime(time_t stopTime, time_t startTime) +{ + return difftime(stopTime, startTime); +} \ No newline at end of file diff --git a/c/sharedutil/adapters/agenttime_mbed.c b/c/sharedutil/adapters/agenttime_mbed.c new file mode 100644 index 00000000..661ebca4 --- /dev/null +++ b/c/sharedutil/adapters/agenttime_mbed.c @@ -0,0 +1,28 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include "agenttime.h" + +// mbed version of gmtime() returns NULL. +// system RTC should be set to UTC as its localtime + +time_t get_time(time_t* currentTime) +{ + return time(currentTime); +} + +double get_difftime(time_t stopTime, time_t startTime) +{ + return difftime(stopTime, startTime); +} + + +struct tm* get_gmtime(time_t* currentTime) +{ + return localtime(currentTime); +} + +char* get_ctime(time_t* timeToGet) +{ + return ctime(timeToGet); +} diff --git a/c/sharedutil/adapters/condition_c11.c b/c/sharedutil/adapters/condition_c11.c new file mode 100644 index 00000000..a73f7216 --- /dev/null +++ b/c/sharedutil/adapters/condition_c11.c @@ -0,0 +1,63 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include +#ifdef _CRTDBG_MAP_ALLOC +#include +#endif +#include "stdlib.h" + +#include "macro_utils.h" +#include "condition.h" +#include "iot_logging.h" +#include + +DEFINE_ENUM_STRINGS(COND_RESULT, COND_RESULT_VALUES); + +COND_HANDLE Condition_Init(void) +{ + cnd_t* cond = (cnd_t*)malloc(sizeof(cnd_t)); + cnd_init(cond); + return cond; +} + +COND_RESULT Condition_Post(COND_HANDLE handle) +{ + cnd_broadcast((cnd_t*)handle); + return COND_OK; +} + +COND_RESULT Condition_Wait(COND_HANDLE handle, LOCK_HANDLE lock, int timeout_milliseconds) +{ + if (timeout_milliseconds > 0) + { + struct xtime tm; + tm.sec = timeout_milliseconds / 1000; + tm.nsec = (timeout_milliseconds % 1000) * 1000000L; + int wait_result = cnd_timedwait((cnd_t *)handle, (mtx_t *)lock, &tm); + if (wait_result == ETIMEDOUT) + { + return COND_TIMEOUT; + } + else + { + LogError("Failed to Condition_Wait\r\n"); + return COND_ERROR; + } + } + else + { + if (cnd_wait((cnd_t*)handle, (mtx_t *)lock) != 0) + { + LogError("Failed to cnd_wait\r\n"); + return COND_ERROR; + } + } + return COND_OK; +} + +COND_RESULT Condition_Deinit(COND_HANDLE handle) +{ + cnd_destroy((cnd_t*)handle); + return COND_OK; +} diff --git a/c/sharedutil/adapters/condition_pthreads.c b/c/sharedutil/adapters/condition_pthreads.c new file mode 100644 index 00000000..b12a666a --- /dev/null +++ b/c/sharedutil/adapters/condition_pthreads.c @@ -0,0 +1,57 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include "lock.h" +#include +#include +#include + +DEFINE_ENUM_STRINGS(COND_RESULT, COND_RESULT_VALUES); + +COND_HANDLE Condition_Init(void) +{ + pthread_cond_t * cond = (pthread_cond_t*)malloc(sizeof(pthread_cond_t)); + pthread_cond_init(cond, NULL); + return cond; +} + +COND_RESULT Condition_Post(COND_HANDLE handle) +{ + pthread_cond_broadcast((pthread_cond_t*)handle); + return COND_OK; +} + +COND_RESULT Condition_Wait(COND_HANDLE handle, LOCK_HANDLE lock, int timeout_milliseconds) +{ + if ( timeout_milliseconds > 0) + { + struct timespec tm; + tm.tv_sec = timeout_milliseconds / 1000; + tm.tv_nsec = (timeout_milliseconds % 1000) * 1000000L; + int wait_result = pthread_cond_timedwait((pthread_cond_t *)handle, (pthread_mutex_t *)lock, &tm); + if ( wait_result == ETIMEDOUT) + { + return COND_TIMEOUT; + } + else + { + LogError("Failed to pthread_cond_timedwait\r\n"); + return COND_ERROR; + } + } + else + { + if (pthread_cond_wait((pthread_cond_t*)handle, (pthread_mutex_t *)lock) != 0 ) + { + LogError("Failed to pthread_cond_wait\r\n"); + return COND_ERROR; + } + } + return COND_OK; +} + +COND_RESULT Condition_Deinit(COND_HANDLE handle) +{ + pthread_cond_destroy((pthread_cond_t*)handle); + return COND_OK; +} diff --git a/c/sharedutil/adapters/condition_rtx_mbed.cpp b/c/sharedutil/adapters/condition_rtx_mbed.cpp new file mode 100644 index 00000000..206498d4 --- /dev/null +++ b/c/sharedutil/adapters/condition_rtx_mbed.cpp @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include +#ifdef _CRTDBG_MAP_ALLOC +#include +#endif + +#include "lock.h" +#include "iot_logging.h" +#include "rtos.h" + +COND_HANDLE Condition_Init(void) +{ + return NULL; +} + +COND_RESULT Condition_Post(COND_HANDLE handle) +{ + return COND_ERROR; +} + +COND_RESULT Condition_Wait(COND_HANDLE handle, LOCK_HANDLE lock, int timeout_milliseconds) +{ + return COND_ERROR; +} + +COND_RESULT Condition_Deinit(COND_HANDLE handle) +{ + return COND_ERROR; +} diff --git a/c/sharedutil/adapters/httpapi_curl.c b/c/sharedutil/adapters/httpapi_curl.c new file mode 100644 index 00000000..9ffda459 --- /dev/null +++ b/c/sharedutil/adapters/httpapi_curl.c @@ -0,0 +1,676 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include +#include +#include +#include +#include + +#include "strings.h" +#include "httpapi.h" +#include "httpheaders.h" +#include "crt_abstractions.h" +#include "curl/curl.h" +#include "iot_logging.h" + +#define TEMP_BUFFER_SIZE 1024 + +DEFINE_ENUM_STRINGS(HTTPAPI_RESULT, HTTPAPI_RESULT_VALUES); + +typedef struct HTTP_HANDLE_DATA_TAG +{ + CURL* curl; + char* hostURL; + long timeout; + long lowSpeedLimit; + long lowSpeedTime; + long forbidReuse; + long freshConnect; + long verbose; +} HTTP_HANDLE_DATA; + +typedef struct HTTP_RESPONSE_CONTENT_BUFFER_TAG +{ + unsigned char* buffer; + size_t bufferSize; + unsigned char error; +} HTTP_RESPONSE_CONTENT_BUFFER; + +static size_t nUsersOfHTTPAPI = 0; /*used for reference counting (a weak one)*/ + +HTTPAPI_RESULT HTTPAPI_Init(void) +{ + HTTPAPI_RESULT result; + if (nUsersOfHTTPAPI == 0) + { + if (curl_global_init(CURL_GLOBAL_DEFAULT) != 0) + { + result = HTTPAPI_INIT_FAILED; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + else + { + nUsersOfHTTPAPI++; + result = HTTPAPI_OK; + } + } + else + { + nUsersOfHTTPAPI++; + result = HTTPAPI_OK; + } + + return result; +} + +void HTTPAPI_Deinit(void) +{ + if (nUsersOfHTTPAPI > 0) + { + nUsersOfHTTPAPI--; + if (nUsersOfHTTPAPI == 0) + { + curl_global_cleanup(); + } + } +} + +HTTP_HANDLE HTTPAPI_CreateConnection(const char* hostName) +{ + HTTP_HANDLE_DATA* httpHandleData = NULL; + + if (hostName != NULL) + { + httpHandleData = (HTTP_HANDLE_DATA*)malloc(sizeof(HTTP_HANDLE_DATA)); + if (httpHandleData != NULL) + { + size_t hostURL_size = strlen("https://") + strlen(hostName) + 1; + httpHandleData->hostURL = malloc(hostURL_size); + if (httpHandleData->hostURL == NULL) + { + LogError("unable to malloc\r\n"); + } + else + { + if ((strcpy_s(httpHandleData->hostURL, hostURL_size, "https://") == 0) && + (strcat_s(httpHandleData->hostURL, hostURL_size, hostName) == 0)) + { + httpHandleData->curl = curl_easy_init(); + if (httpHandleData->curl == NULL) + { + free(httpHandleData->hostURL); + free(httpHandleData); + httpHandleData = NULL; + } + else + { + httpHandleData->timeout = 242 * 1000; /*242 seconds seems like a nice enough time. Reasone for 242: + 1. http://curl.haxx.se/libcurl/c/CURLOPT_TIMEOUT.html says Normally, name lookups can take a considerable time and limiting operations to less than a few minutes risk aborting perfectly normal operations. + 2. 256KB of data... at 9600 bps transfers in about 218 seconds. Add to that a buffer of 10%... round it up to 242 :)*/ + httpHandleData->lowSpeedTime = 0; + httpHandleData->lowSpeedLimit = 0; + httpHandleData->forbidReuse = 0; + httpHandleData->freshConnect = 0; + httpHandleData->verbose = 0; + } + } + else + { + free(httpHandleData->hostURL); + free(httpHandleData); + httpHandleData = NULL; + } + } + } + } + + return (HTTP_HANDLE)httpHandleData; +} + +void HTTPAPI_CloseConnection(HTTP_HANDLE handle) +{ + HTTP_HANDLE_DATA* httpHandleData = (HTTP_HANDLE_DATA*)handle; + if (httpHandleData != NULL) + { + free(httpHandleData->hostURL); + curl_easy_cleanup(httpHandleData->curl); + free(httpHandleData); + } +} + +static size_t HeadersWriteFunction(void *ptr, size_t size, size_t nmemb, void *userdata) +{ + HTTP_HEADERS_HANDLE responseHeadersHandle = (HTTP_HEADERS_HANDLE)userdata; + char* headerLine = (char*)ptr; + + if (headerLine != NULL) + { + char* token = strtok(headerLine, "\r\n"); + while ((token != NULL) && + (token[0] != '\0')) + { + char* whereIsColon = strchr(token, ':'); + if(whereIsColon!=NULL) + { + *whereIsColon='\0'; + HTTPHeaders_AddHeaderNameValuePair(responseHeadersHandle, token, whereIsColon+1); + *whereIsColon=':'; + } + else + { + /*not a header, maybe a status-line*/ + } + token = strtok(NULL, "\r\n"); + } + } + + return size * nmemb; +} + +static size_t ContentWriteFunction(void *ptr, size_t size, size_t nmemb, void *userdata) +{ + HTTP_RESPONSE_CONTENT_BUFFER* responseContentBuffer = (HTTP_RESPONSE_CONTENT_BUFFER*)userdata; + if ((userdata != NULL) && + (ptr != NULL) && + (size * nmemb > 0)) + { + void* newBuffer = realloc(responseContentBuffer->buffer, responseContentBuffer->bufferSize + (size * nmemb)); + if (newBuffer != NULL) + { + responseContentBuffer->buffer = newBuffer; + memcpy(responseContentBuffer->buffer + responseContentBuffer->bufferSize, ptr, size * nmemb); + responseContentBuffer->bufferSize += size * nmemb; + } + else + { + LogError("Could not allocate buffer of size %zu\r\n", (size_t)(responseContentBuffer->bufferSize + (size * nmemb))); + responseContentBuffer->error = 1; + if (responseContentBuffer->buffer != NULL) + { + free(responseContentBuffer->buffer); + } + } + } + + return size * nmemb; +} + +HTTPAPI_RESULT HTTPAPI_ExecuteRequest(HTTP_HANDLE handle, HTTPAPI_REQUEST_TYPE requestType, const char* relativePath, + HTTP_HEADERS_HANDLE httpHeadersHandle, const unsigned char* content, + size_t contentLength, unsigned int* statusCode, + HTTP_HEADERS_HANDLE responseHeadersHandle, BUFFER_HANDLE responseContent) +{ + HTTPAPI_RESULT result; + HTTP_HANDLE_DATA* httpHandleData = (HTTP_HANDLE_DATA*)handle; + size_t headersCount; + HTTP_RESPONSE_CONTENT_BUFFER responseContentBuffer; + + if ((httpHandleData == NULL) || + (relativePath == NULL) || + (httpHeadersHandle == NULL) || + ((content == NULL) && (contentLength > 0)) + ) + { + result = HTTPAPI_INVALID_ARG; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + else if (HTTPHeaders_GetHeaderCount(httpHeadersHandle, &headersCount) != HTTP_HEADERS_OK) + { + result = HTTPAPI_INVALID_ARG; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + else + { + char* tempHostURL; + size_t tempHostURL_size = strlen(httpHandleData->hostURL) + strlen(relativePath) + 1; + tempHostURL = malloc(tempHostURL_size); + if (tempHostURL == NULL) + { + result = HTTPAPI_ERROR; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + else + { + if (curl_easy_setopt(httpHandleData->curl, CURLOPT_VERBOSE, httpHandleData->verbose) != CURLE_OK) + { + result = HTTPAPI_SET_OPTION_FAILED; + LogError("failed to set CURLOPT_VERBOSE (result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + else if ((strcpy_s(tempHostURL, tempHostURL_size, httpHandleData->hostURL) != 0) || + (strcat_s(tempHostURL, tempHostURL_size, relativePath) != 0)) + { + result = HTTPAPI_STRING_PROCESSING_ERROR; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + /* set the URL */ + else if (curl_easy_setopt(httpHandleData->curl, CURLOPT_URL, tempHostURL) != CURLE_OK) + { + result = HTTPAPI_SET_OPTION_FAILED; + LogError("failed to set CURLOPT_URL (result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + else if (curl_easy_setopt(httpHandleData->curl, CURLOPT_TIMEOUT_MS, httpHandleData->timeout) != CURLE_OK) + { + result = HTTPAPI_SET_OPTION_FAILED; + LogError("failed to set CURLOPT_TIMEOUT_MS (result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + else if (curl_easy_setopt(httpHandleData->curl, CURLOPT_LOW_SPEED_LIMIT, httpHandleData->lowSpeedLimit) != CURLE_OK) + { + result = HTTPAPI_SET_OPTION_FAILED; + LogError("failed to set CURLOPT_LOW_SPEED_LIMIT (result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + else if (curl_easy_setopt(httpHandleData->curl, CURLOPT_LOW_SPEED_TIME, httpHandleData->lowSpeedTime) != CURLE_OK) + { + result = HTTPAPI_SET_OPTION_FAILED; + LogError("failed to set CURLOPT_LOW_SPEED_TIME (result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + else if (curl_easy_setopt(httpHandleData->curl, CURLOPT_FRESH_CONNECT, httpHandleData->freshConnect) != CURLE_OK) + { + result = HTTPAPI_SET_OPTION_FAILED; + LogError("failed to set CURLOPT_FRESH_CONNECT (result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + else if (curl_easy_setopt(httpHandleData->curl, CURLOPT_FORBID_REUSE, httpHandleData->forbidReuse) != CURLE_OK) + { + result = HTTPAPI_SET_OPTION_FAILED; + LogError("failed to set CURLOPT_FORBID_REUSE (result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + else if (curl_easy_setopt(httpHandleData->curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1) != CURLE_OK) + { + result = HTTPAPI_SET_OPTION_FAILED; + LogError("failed to set CURLOPT_HTTP_VERSION (result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + else + { + result = HTTPAPI_OK; + + switch (requestType) + { + default: + result = HTTPAPI_INVALID_ARG; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + break; + + case HTTPAPI_REQUEST_GET: + if (curl_easy_setopt(httpHandleData->curl, CURLOPT_HTTPGET, 1L) != CURLE_OK) + { + result = HTTPAPI_SET_OPTION_FAILED; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + else + { + if (curl_easy_setopt(httpHandleData->curl, CURLOPT_CUSTOMREQUEST, NULL) != CURLE_OK) + { + result = HTTPAPI_SET_OPTION_FAILED; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + } + + break; + + case HTTPAPI_REQUEST_POST: + if (curl_easy_setopt(httpHandleData->curl, CURLOPT_POST, 1L) != CURLE_OK) + { + result = HTTPAPI_SET_OPTION_FAILED; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + else + { + if (curl_easy_setopt(httpHandleData->curl, CURLOPT_CUSTOMREQUEST, NULL) != CURLE_OK) + { + result = HTTPAPI_SET_OPTION_FAILED; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + } + + break; + + case HTTPAPI_REQUEST_PUT: + if (curl_easy_setopt(httpHandleData->curl, CURLOPT_POST, 1L)) + { + result = HTTPAPI_SET_OPTION_FAILED; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + else + { + if (curl_easy_setopt(httpHandleData->curl, CURLOPT_CUSTOMREQUEST, "PUT") != CURLE_OK) + { + result = HTTPAPI_SET_OPTION_FAILED; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + } + break; + + case HTTPAPI_REQUEST_DELETE: + if (curl_easy_setopt(httpHandleData->curl, CURLOPT_POST, 1L) != CURLE_OK) + { + result = HTTPAPI_SET_OPTION_FAILED; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + else + { + if (curl_easy_setopt(httpHandleData->curl, CURLOPT_CUSTOMREQUEST, "DELETE") != CURLE_OK) + { + result = HTTPAPI_SET_OPTION_FAILED; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + } + break; + + case HTTPAPI_REQUEST_PATCH: + if (curl_easy_setopt(httpHandleData->curl, CURLOPT_POST, 1L) != CURLE_OK) + { + result = HTTPAPI_SET_OPTION_FAILED; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + else + { + if (curl_easy_setopt(httpHandleData->curl, CURLOPT_CUSTOMREQUEST, "PATCH") != CURLE_OK) + { + result = HTTPAPI_SET_OPTION_FAILED; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + } + + break; + } + + if (result == HTTPAPI_OK) + { + /* add headers */ + struct curl_slist* headers = NULL; + size_t i; + + for (i = 0; i < headersCount; i++) + { + char *tempBuffer; + if (HTTPHeaders_GetHeader(httpHeadersHandle, i, &tempBuffer) != HTTP_HEADERS_OK) + { + /* error */ + result = HTTPAPI_HTTP_HEADERS_FAILED; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + break; + } + else + { + struct curl_slist* newHeaders = curl_slist_append(headers, tempBuffer); + if (newHeaders == NULL) + { + result = HTTPAPI_ALLOC_FAILED; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + free(tempBuffer); + break; + } + else + { + free(tempBuffer); + headers = newHeaders; + } + } + } + + if (result == HTTPAPI_OK) + { + if (curl_easy_setopt(httpHandleData->curl, CURLOPT_HTTPHEADER, headers) != CURLE_OK) + { + result = HTTPAPI_SET_OPTION_FAILED; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + else + { + /* add content */ + if ((content != NULL) && + (contentLength > 0)) + { + if ((curl_easy_setopt(httpHandleData->curl, CURLOPT_POSTFIELDS, (void*)content) != CURLE_OK) || + (curl_easy_setopt(httpHandleData->curl, CURLOPT_POSTFIELDSIZE, contentLength) != CURLE_OK)) + { + result = HTTPAPI_SET_OPTION_FAILED; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + } + else + { + if (requestType != HTTPAPI_REQUEST_GET) + { + if ((curl_easy_setopt(httpHandleData->curl, CURLOPT_POSTFIELDS, (void*)NULL) != CURLE_OK) || + (curl_easy_setopt(httpHandleData->curl, CURLOPT_POSTFIELDSIZE, 0) != CURLE_OK)) + { + result = HTTPAPI_SET_OPTION_FAILED; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + } + else + { + /*GET request cannot POST, so "do nothing*/ + } + } + + if (result == HTTPAPI_OK) + { + if ((curl_easy_setopt(httpHandleData->curl, CURLOPT_WRITEHEADER, NULL) != CURLE_OK) || + (curl_easy_setopt(httpHandleData->curl, CURLOPT_HEADERFUNCTION, NULL) != CURLE_OK) || + (curl_easy_setopt(httpHandleData->curl, CURLOPT_WRITEFUNCTION, ContentWriteFunction) != CURLE_OK)) + { + result = HTTPAPI_SET_OPTION_FAILED; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + else + { + if (responseHeadersHandle != NULL) + { + /* setup the code to get the response headers */ + if ((curl_easy_setopt(httpHandleData->curl, CURLOPT_WRITEHEADER, responseHeadersHandle) != CURLE_OK) || + (curl_easy_setopt(httpHandleData->curl, CURLOPT_HEADERFUNCTION, HeadersWriteFunction) != CURLE_OK)) + { + result = HTTPAPI_SET_OPTION_FAILED; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + } + + if (result == HTTPAPI_OK) + { + responseContentBuffer.buffer = NULL; + responseContentBuffer.bufferSize = 0; + responseContentBuffer.error = 0; + + if (curl_easy_setopt(httpHandleData->curl, CURLOPT_WRITEDATA, &responseContentBuffer) != CURLE_OK) + { + result = HTTPAPI_SET_OPTION_FAILED; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + + if (result == HTTPAPI_OK) + { + /* Execute request */ + CURLcode curlRes = curl_easy_perform(httpHandleData->curl); + if (curlRes != CURLE_OK) + { + LogError("curl_easy_perform() failed: %s\n", curl_easy_strerror(curlRes)); + result = HTTPAPI_OPEN_REQUEST_FAILED; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + else + { + long httpCode; + + /* get the status code */ + if (curl_easy_getinfo(httpHandleData->curl, CURLINFO_RESPONSE_CODE, &httpCode) != CURLE_OK) + { + result = HTTPAPI_QUERY_HEADERS_FAILED; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + else if (responseContentBuffer.error) + { + result = HTTPAPI_READ_DATA_FAILED; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + else + { + if (statusCode != NULL) + { + *statusCode = httpCode; + } + + /* fill response content length */ + if (responseContent != NULL) + { + if ((responseContentBuffer.bufferSize > 0) && (BUFFER_build(responseContent, responseContentBuffer.buffer, responseContentBuffer.bufferSize) != 0)) + { + result = HTTPAPI_INSUFFICIENT_RESPONSE_BUFFER; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + else + { + /*all nice*/ + } + } + + if (httpCode >= 300) + { + LogError("Failure in HTTP communication: server reply code is %ld\r\n", httpCode); + LogInfo("HTTP Response:\r\n%*.*s\r\n", (int)responseContentBuffer.bufferSize, + (int)responseContentBuffer.bufferSize, responseContentBuffer.buffer); + } + else + { + result = HTTPAPI_OK; + } + } + } + } + + if (responseContentBuffer.buffer != NULL) + { + free(responseContentBuffer.buffer); + } + } + } + } + } + } + curl_slist_free_all(headers); + } + } + free(tempHostURL); + } + } + + return result; +} + +HTTPAPI_RESULT HTTPAPI_SetOption(HTTP_HANDLE handle, const char* optionName, const void* value) +{ + HTTPAPI_RESULT result; + if ( + (handle == NULL) || + (optionName == NULL) || + (value == NULL) + ) + { + result = HTTPAPI_INVALID_ARG; + LogError("invalid parameter (NULL) passed to HTTPAPI_SetOption\r\n"); + } + else + { + HTTP_HANDLE_DATA* httpHandleData = (HTTP_HANDLE_DATA*)handle; + if (strcmp("timeout", optionName) == 0) + { + long timeout = (long)(*(unsigned int*)value); + httpHandleData->timeout = timeout; + result = HTTPAPI_OK; + } + else if (strcmp("CURLOPT_LOW_SPEED_LIMIT", optionName) == 0) + { + httpHandleData->lowSpeedLimit = *(const long*)value; + result = HTTPAPI_OK; + } + else if (strcmp("CURLOPT_LOW_SPEED_TIME", optionName) == 0) + { + httpHandleData->lowSpeedTime = *(const long*)value; + result = HTTPAPI_OK; + } + else if (strcmp("CURLOPT_FRESH_CONNECT", optionName) == 0) + { + httpHandleData->freshConnect = *(const long*)value; + result = HTTPAPI_OK; + } + else if (strcmp("CURLOPT_FORBID_REUSE", optionName) == 0) + { + httpHandleData->forbidReuse = *(const long*)value; + result = HTTPAPI_OK; + } + else if (strcmp("CURLOPT_VERBOSE", optionName) == 0) + { + httpHandleData->verbose = *(const long*)value; + result = HTTPAPI_OK; + } + else + { + result = HTTPAPI_INVALID_ARG; + LogError("unknown option %s\r\n", optionName); + } + } + return result; +} + +HTTPAPI_RESULT HTTPAPI_CloneOption(const char* optionName, const void* value, const void** savedValue) +{ + HTTPAPI_RESULT result; + if ( + (optionName == NULL) || + (value == NULL) || + (savedValue == NULL) + ) + { + result = HTTPAPI_INVALID_ARG; + LogError("invalid argument(NULL) passed to HTTPAPI_CloneOption\r\n"); + } + else + { + if (strcmp("timeout", optionName) == 0) + { + /*by convention value is pointing to an unsigned int */ + unsigned int* temp = malloc(sizeof(unsigned int)); /*shall be freed by HTTPAPIEX*/ + if (temp == NULL) + { + result = HTTPAPI_ERROR; + LogError("malloc failed (result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + else + { + *temp = *(const unsigned int*)value; + *savedValue = temp; + result = HTTPAPI_OK; + } + } + /*all "long" options are cloned in the same way*/ + else if ( + (strcmp("CURLOPT_LOW_SPEED_LIMIT", optionName) == 0) || + (strcmp("CURLOPT_LOW_SPEED_TIME", optionName) == 0) || + (strcmp("CURLOPT_FRESH_CONNECT", optionName) == 0) || + (strcmp("CURLOPT_FORBID_REUSE", optionName) == 0) || + (strcmp("CURLOPT_VERBOSE", optionName) == 0) + ) + { + /*by convention value is pointing to an long */ + long* temp = malloc(sizeof(long)); /*shall be freed by HTTPAPIEX*/ + if (temp == NULL) + { + result = HTTPAPI_ERROR; + LogError("malloc failed (result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + else + { + *temp = *(const long*)value; + *savedValue = temp; + result = HTTPAPI_OK; + } + } + else + { + result = HTTPAPI_INVALID_ARG; + LogError("unknown option %s\r\n", optionName); + } + } + return result; +} \ No newline at end of file diff --git a/c/sharedutil/adapters/httpapi_mbed.cpp b/c/sharedutil/adapters/httpapi_mbed.cpp new file mode 100644 index 00000000..48659806 --- /dev/null +++ b/c/sharedutil/adapters/httpapi_mbed.cpp @@ -0,0 +1,589 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include +#ifdef _CRTDBG_MAP_ALLOC +#include +#endif + +#include +#include +#include +#include "httpapi.h" +#include "httpheaders.h" +#include "crt_abstractions.h" +#include "mbed.h" +#include "EthernetInterface.h" +#include "wolfssl_connection.h" +#include "iot_logging.h" +#include "string.h" +#include "certs.h" + +#define MAX_HOSTNAME 64 +#define TEMP_BUFFER_SIZE 4096 + +#define CHAR_COUNT(A) (sizeof(A) - 1) + +DEFINE_ENUM_STRINGS(HTTPAPI_RESULT, HTTPAPI_RESULT_VALUES) + +class HTTP_HANDLE_DATA +{ +public: + char host[MAX_HOSTNAME]; + char* certificate; + WolfSSLConnection con; +}; + +HTTPAPI_RESULT HTTPAPI_Init(void) +{ + LogInfo("HTTPAPI_Init::Start\r\n"); + time_t ctTime; + ctTime = time(NULL); + HTTPAPI_RESULT result; + LogInfo("HTTAPI_Init::Time is now (UTC) %s\r\n", ctime(&ctTime)); + + if (EthernetInterface::connect(30000)) + { + LogError("HTTPAPI_Init::Error with connecting.\r\n"); + result = HTTPAPI_INIT_FAILED; + } + else + { + LogInfo("HTTAPI_Init::Ethernet interface was connected (brought up)!\r\n"); + LogInfo("HTTAPI_Init::MAC address %s\r\n", EthernetInterface::getMACAddress()); + LogInfo("HTTAPI_Init::IP address %s\r\n", EthernetInterface::getIPAddress()); + result = HTTPAPI_OK; + } + + LogInfo("HTTPAPI_Init::End\r\n"); + + return result; +} + +void HTTPAPI_Deinit(void) +{ + (void)EthernetInterface::disconnect(); +} + +HTTP_HANDLE HTTPAPI_CreateConnection(const char* hostName) +{ + LogInfo("HTTPAPI_CreateConnection::Start\r\n"); + HTTP_HANDLE_DATA* handle = NULL; + + if (hostName) + { + LogInfo("HTTPAPI_CreateConnection::Connecting to %s\r\n", hostName); + handle = new HTTP_HANDLE_DATA(); + if (strcpy_s(handle->host, MAX_HOSTNAME, hostName) != 0) + { + LogError("HTTPAPI_CreateConnection::Could not strcpy_s\r\n"); + delete handle; + handle = NULL; + } + else + { + handle->certificate = NULL; + } + } + else + { + LogInfo("HTTPAPI_CreateConnection:: null hostName parameter\r\n"); + } + LogInfo("HTTPAPI_CreateConnection::End\r\n"); + + return (HTTP_HANDLE)handle; +} + +void HTTPAPI_CloseConnection(HTTP_HANDLE handle) +{ + HTTP_HANDLE_DATA* h = (HTTP_HANDLE_DATA*)handle; + + if (h) + { + LogInfo("HTTPAPI_CloseConnection to %s\r\n", h->host); + if (h->con.is_connected()) + { + LogInfo("HTTPAPI_CloseConnection h->con.close(); to %s\r\n", h->host); + h->con.close(); + } + if (h->certificate) + { + delete[] h->certificate; + } + LogInfo("HTTPAPI_CloseConnection (delete h) to %s\r\n", h->host); + delete h; + } +} + +static int readLine(WolfSSLConnection* con, char* buf, const size_t size) +{ + // reads until \r\n is encountered. writes in buf all the characters + // read until \r\n and returns the number of characters in the buffer. + char* p = buf; + char c; + if (con->receive(&c, 1) < 0) + return -1; + while (c != '\r') { + if ((p - buf + 1) >= (int)size) + return -1; + *p++ = c; + if (con->receive(&c, 1) < 0) + return -1; + } + *p = 0; + if (con->receive(&c, 1) < 0 || c != '\n') // skip \n + return -1; + return p - buf; +} + +static int readChunk(WolfSSLConnection* con, char* buf, size_t size) +{ + size_t cur, offset; + + // read content with specified length, even if it is received + // only in chunks due to fragmentation in the networking layer. + // returns -1 in case of error. + offset = 0; + while (size > 0) + { + cur = con->receive(buf + offset, size); + + // end of stream reached + if (cur == 0) + return offset; + + // read cur bytes (might be less than requested) + size -= cur; + offset += cur; + } + + return offset; +} + +static int skipN(WolfSSLConnection* con, size_t n, char* buf, size_t size) +{ + size_t org = n; + // read and abandon response content with specified length + // returns -1 in case of error. + while (n > size) + { + if (readChunk(con, (char*)buf, size) < 0) + return -1; + + n -= size; + } + + if (readChunk(con, (char*)buf, n) < 0) + return -1; + + return org; +} + +//Note: This function assumes that "Host:" and "Content-Length:" headers are setup +// by the caller of HTTPAPI_ExecuteRequest() (which is true for httptransport.c). +HTTPAPI_RESULT HTTPAPI_ExecuteRequest(HTTP_HANDLE handle, HTTPAPI_REQUEST_TYPE requestType, const char* relativePath, + HTTP_HEADERS_HANDLE httpHeadersHandle, const unsigned char* content, + size_t contentLength, unsigned int* statusCode, + HTTP_HEADERS_HANDLE responseHeadersHandle, BUFFER_HANDLE responseContent) +{ + LogInfo("HTTPAPI_ExecuteRequest::Start\r\n"); + + HTTPAPI_RESULT result; + size_t headersCount; + char buf[TEMP_BUFFER_SIZE]; + int ret; + WolfSSLConnection* con = NULL; + size_t bodyLength = 0; + bool chunked = false; + const unsigned char* receivedContent; + + const char* method = (requestType == HTTPAPI_REQUEST_GET) ? "GET" + : (requestType == HTTPAPI_REQUEST_POST) ? "POST" + : (requestType == HTTPAPI_REQUEST_PUT) ? "PUT" + : (requestType == HTTPAPI_REQUEST_DELETE) ? "DELETE" + : (requestType == HTTPAPI_REQUEST_PATCH) ? "PATCH" + : NULL; + + if (handle == NULL || + relativePath == NULL || + httpHeadersHandle == NULL || + method == NULL || + HTTPHeaders_GetHeaderCount(httpHeadersHandle, &headersCount) != HTTP_HEADERS_OK) + { + result = HTTPAPI_INVALID_ARG; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + goto exit; + } + + HTTP_HANDLE_DATA* httpHandle = (HTTP_HANDLE_DATA*)handle; + con = &(httpHandle->con); + + if (!con->is_connected()) + { + // Load the certificate + if ((httpHandle->certificate != NULL) && + (!con->load_certificate((const unsigned char*)httpHandle->certificate, strlen(httpHandle->certificate) + 1))) + { + result = HTTPAPI_ERROR; + LogError("Could not load certificate (result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + goto exit; + } + + // Make the connection + if (con->connect(httpHandle->host, 443) != 0) + { + result = HTTPAPI_ERROR; + LogError("Could not connect (result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + goto exit; + } + else + { + LogInfo("HTTPAPI_CreateConnection::Connection to %s successful!\r\n", httpHandle->host); + } + } + + //Send request + if ((ret = snprintf(buf, sizeof(buf), "%s %s HTTP/1.1\r\n", method, relativePath)) < 0 + || ret >= sizeof(buf)) + { + result = HTTPAPI_STRING_PROCESSING_ERROR; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + goto exit; + } + LogInfo("HTTPAPI_ExecuteRequest::Sending=%*.*s\r\n", strlen(buf), strlen(buf), buf); + if (con->send_all(buf, strlen(buf)) < 0) + { + result = HTTPAPI_SEND_REQUEST_FAILED; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + goto exit; + } + + //Send default headers + for (size_t i = 0; i < headersCount; i++) + { + char* header; + if (HTTPHeaders_GetHeader(httpHeadersHandle, i, &header) != HTTP_HEADERS_OK) + { + result = HTTPAPI_HTTP_HEADERS_FAILED; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + goto exit; + } + LogInfo("HTTPAPI_ExecuteRequest::Sending=%*.*s\r\n", strlen(header), strlen(header), header); + if (con->send_all(header, strlen(header)) < 0) + { + result = HTTPAPI_SEND_REQUEST_FAILED; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + free(header); + goto exit; + } + if (con->send_all("\r\n", 2) < 0) + { + result = HTTPAPI_SEND_REQUEST_FAILED; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + free(header); + goto exit; + } + free(header); + } + + //Close headers + if (con->send_all("\r\n", 2) < 0) + { + result = HTTPAPI_SEND_REQUEST_FAILED; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + goto exit; + } + + //Send data (if available) + if (content && contentLength > 0) + { + LogInfo("HTTPAPI_ExecuteRequest::Sending data=%*.*s\r\n", contentLength, contentLength, content); + if (con->send_all((char*)content, contentLength) < 0) + { + result = HTTPAPI_SEND_REQUEST_FAILED; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + goto exit; + } + } + + //Receive response + if (readLine(con, buf, sizeof(buf)) < 0) + { + result = HTTPAPI_READ_DATA_FAILED; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + goto exit; + } + + //Parse HTTP response + if (sscanf(buf, "HTTP/%*d.%*d %d %*[^\r\n]", &ret) != 1) + { + //Cannot match string, error + LogInfo("HTTPAPI_ExecuteRequest::Not a correct HTTP answer=%s\r\n", buf); + result = HTTPAPI_READ_DATA_FAILED; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + goto exit; + } + if (statusCode) + *statusCode = ret; + LogInfo("HTTPAPI_ExecuteRequest::Received response=%*.*s\r\n", strlen(buf), strlen(buf), buf); + + //Read HTTP response headers + if (readLine(con, buf, sizeof(buf)) < 0) + { + result = HTTPAPI_READ_DATA_FAILED; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + goto exit; + } + + while (buf[0]) + { + const char ContentLength[] = "content-length:"; + const char TransferEncoding[] = "transfer-encoding:"; + + LogInfo("Receiving header=%*.*s\r\n", strlen(buf), strlen(buf), buf); + + if (strncasecmp(buf, ContentLength, CHAR_COUNT(ContentLength)) == 0) + { + if (sscanf(buf + CHAR_COUNT(ContentLength), " %d", &bodyLength) != 1) + { + result = HTTPAPI_READ_DATA_FAILED; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + goto exit; + } + } + else if (strncasecmp(buf, TransferEncoding, CHAR_COUNT(TransferEncoding)) == 0) + { + const char* p = buf + CHAR_COUNT(TransferEncoding); + while (isspace(*p)) p++; + if (strcasecmp(p, "chunked") == 0) + chunked = true; + } + + char* whereIsColon = strchr((char*)buf, ':'); + if (whereIsColon && responseHeadersHandle != NULL) + { + *whereIsColon = '\0'; + HTTPHeaders_AddHeaderNameValuePair(responseHeadersHandle, buf, whereIsColon + 1); + } + + if (readLine(con, buf, sizeof(buf)) < 0) + { + result = HTTPAPI_READ_DATA_FAILED; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + goto exit; + } + } + + //Read HTTP response body + LogInfo("HTTPAPI_ExecuteRequest::Receiving body=%d,%x\r\n", bodyLength, responseContent); + if (!chunked) + { + if (bodyLength) + { + if (responseContent != NULL) + { + if (BUFFER_pre_build(responseContent, bodyLength) != 0) + { + result = HTTPAPI_ALLOC_FAILED; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + else if (BUFFER_content(responseContent, &receivedContent) != 0) + { + (void)BUFFER_unbuild(responseContent); + + result = HTTPAPI_ALLOC_FAILED; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + + if (readChunk(con, (char*)receivedContent, bodyLength) < 0) + { + result = HTTPAPI_READ_DATA_FAILED; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + goto exit; + } + else + { + LogInfo("HTTPAPI_ExecuteRequest::Received response body=%*.*s\r\n", bodyLength, bodyLength, receivedContent); + result = HTTPAPI_OK; + } + } + else + { + (void)skipN(con, bodyLength, buf, sizeof(buf)); + result = HTTPAPI_OK; + } + } + else + { + result = HTTPAPI_OK; + } + } + else + { + size_t size = 0; + result = HTTPAPI_OK; + for (;;) + { + int chunkSize; + if (readLine(con, buf, sizeof(buf)) < 0) // read [length in hex]/r/n + { + result = HTTPAPI_READ_DATA_FAILED; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + goto exit; + } + if (sscanf(buf, "%x", &chunkSize) != 1) // chunkSize is length of next line (/r/n is not counted) + { + //Cannot match string, error + result = HTTPAPI_RECEIVE_RESPONSE_FAILED; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + goto exit; + } + + if (chunkSize == 0) + { + // 0 length means next line is just '\r\n' and end of chunks + if (readChunk(con, (char*)buf, 2) < 0 + || buf[0] != '\r' || buf[1] != '\n') // skip /r/n + { + (void)BUFFER_unbuild(responseContent); + + result = HTTPAPI_READ_DATA_FAILED; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + goto exit; + } + break; + } + else + { + if (responseContent != NULL) + { + if (BUFFER_enlarge(responseContent, chunkSize) != 0) + { + (void)BUFFER_unbuild(responseContent); + + result = HTTPAPI_ALLOC_FAILED; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + else if (BUFFER_content(responseContent, &receivedContent) != 0) + { + (void)BUFFER_unbuild(responseContent); + + result = HTTPAPI_ALLOC_FAILED; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + + if (readChunk(con, (char*)receivedContent + size, chunkSize) < 0) + { + result = HTTPAPI_READ_DATA_FAILED; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + goto exit; + } + } + else + { + if (skipN(con, chunkSize, buf, sizeof(buf)) < 0) + { + result = HTTPAPI_READ_DATA_FAILED; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + goto exit; + } + } + + if (readChunk(con, (char*)buf, 2) < 0 + || buf[0] != '\r' || buf[1] != '\n') // skip /r/n + { + result = HTTPAPI_READ_DATA_FAILED; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + goto exit; + } + size += chunkSize; + } + } + + if (size > 0) + { + LogInfo("HTTPAPI_ExecuteRequest::Received chunk body=%*.*s\r\n", (int)size, (int)size, (const char*)responseContent); + } + } + +exit: + LogInfo("HTTPAPI_ExecuteRequest::End=%d\r\n", result); + return result; +} + +HTTPAPI_RESULT HTTPAPI_SetOption(HTTP_HANDLE handle, const char* optionName, const void* value) +{ + HTTPAPI_RESULT result; + if ( + (handle == NULL) || + (optionName == NULL) || + (value == NULL) + ) + { + result = HTTPAPI_INVALID_ARG; + LogError("invalid parameter (NULL) passed to HTTPAPI_SetOption\r\n"); + } + else if (strcmp("TrustedCerts", optionName) == 0) + { + HTTP_HANDLE_DATA* h = (HTTP_HANDLE_DATA*)handle; + if (h->certificate) + { + delete[] h->certificate; + } + + int len = strlen((char*)value); + h->certificate = new char[len + 1]; + if (h->certificate == NULL) + { + result = HTTPAPI_ERROR; + LogError("unable to allocate certificate memory in HTTPAPI_SetOption\r\n"); + } + else + { + (void)strcpy(h->certificate, (const char*)value); + result = HTTPAPI_OK; + } + } + else + { + result = HTTPAPI_INVALID_ARG; + LogError("unknown option %s\r\n", optionName); + } + return result; +} + +HTTPAPI_RESULT HTTPAPI_CloneOption(const char* optionName, const void* value, const void** savedValue) +{ + HTTPAPI_RESULT result; + if ( + (optionName == NULL) || + (value == NULL) || + (savedValue == NULL) + ) + { + result = HTTPAPI_INVALID_ARG; + LogError("invalid argument(NULL) passed to HTTPAPI_CloneOption\r\n"); + } + else if (strcmp("TrustedCerts", optionName) == 0) + { + size_t certLen = strlen((const char*)value); + char* tempCert = (char*)malloc(certLen+1); + if (tempCert == NULL) + { + result = HTTPAPI_INVALID_ARG; + LogError("unable to allocate certificate memory in HTTPAPI_CloneOption\r\n"); + } + else + { + (void)strcpy(tempCert, (const char*)value); + *savedValue = tempCert; + result = HTTPAPI_OK; + } + } + else + { + result = HTTPAPI_INVALID_ARG; + LogError("unknown option %s\r\n", optionName); + } + return result; +} diff --git a/c/sharedutil/adapters/httpapi_tirtos.c b/c/sharedutil/adapters/httpapi_tirtos.c new file mode 100644 index 00000000..19dc59b5 --- /dev/null +++ b/c/sharedutil/adapters/httpapi_tirtos.c @@ -0,0 +1,278 @@ +// Copyright (c) Texas Instruments. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include +#include +#include + +#include + +#include "httpapi.h" +#include "strings.h" + +#define CONTENT_BUF_LEN 128 + +static const char* getHttpMethod(HTTPAPI_REQUEST_TYPE requestType) +{ + switch (requestType) { + case HTTPAPI_REQUEST_GET: + return (HTTPStd_GET); + case HTTPAPI_REQUEST_POST: + return (HTTPStd_POST); + case HTTPAPI_REQUEST_PUT: + return (HTTPStd_PUT); + case HTTPAPI_REQUEST_DELETE: + return (HTTPStd_DELETE); + case HTTPAPI_REQUEST_PATCH: + return (HTTPStd_PATCH); + default: + return (NULL); + } +} + +static int splitHeader(char *headerName, char **headerValue) +{ + *headerValue = strchr(headerName, ':'); + if (*headerValue == NULL) { + return (-1); + } + + **headerValue = '\0'; + (*headerValue)++; + while (**headerValue == ' ') { + (*headerValue)++; + } + + return (0); +} + +HTTPAPI_RESULT HTTPAPI_Init(void) +{ + return (HTTPAPI_OK); +} + +void HTTPAPI_Deinit(void) +{ +} + +HTTP_HANDLE HTTPAPI_CreateConnection(const char* hostName) +{ + int ret; + struct sockaddr addr; + HTTPCli_Handle cli; + + ret = HTTPCli_initSockAddr(&addr, hostName, 0); + if (ret < 0) { + return (NULL); + } + ((struct sockaddr_in *) (&addr))->sin_port = htons(HTTPStd_SECURE_PORT); + + cli = HTTPCli_create(); + if (cli == NULL) { + return (NULL); + } + + ret = HTTPCli_connect(cli, &addr, HTTPCli_TYPE_TLS, NULL); + if (ret < 0) { + HTTPCli_delete(&cli); + return (NULL); + } + + return ((HTTP_HANDLE) cli); +} + +void HTTPAPI_CloseConnection(HTTP_HANDLE handle) +{ + HTTPCli_Handle cli = (HTTPCli_Handle) handle; + + if (cli) { + HTTPCli_disconnect(cli); + HTTPCli_delete(&cli); + } +} + +HTTPAPI_RESULT HTTPAPI_ExecuteRequest(HTTP_HANDLE handle, + HTTPAPI_REQUEST_TYPE requestType, const char* relativePath, + HTTP_HEADERS_HANDLE httpHeadersHandle, const unsigned char* content, + size_t contentLength, unsigned int* statusCode, + HTTP_HEADERS_HANDLE responseHeadersHandle, + BUFFER_HANDLE responseContent) +{ + HTTPCli_Handle cli = (HTTPCli_Handle) handle; + int ret; + int offset; + size_t cnt; + char contentBuf[CONTENT_BUF_LEN] = {0}; + char *hname; + char *hvalue; + const char *method; + bool moreFlag; + + method = getHttpMethod(requestType); + + if ((cli == NULL) || (method == NULL) || (relativePath == NULL) + || (statusCode == NULL) || (responseHeadersHandle == NULL)) { + return (HTTPAPI_INVALID_ARG); + } + else if (HTTPHeaders_GetHeaderCount(httpHeadersHandle, &cnt) + != HTTP_HEADERS_OK) { + return (HTTPAPI_QUERY_HEADERS_FAILED); + } + + /* Send the request line */ + ret = HTTPCli_sendRequest(cli, method, relativePath, true); + if (ret < 0) { + return (HTTPAPI_SEND_REQUEST_FAILED); + } + + /* Send the request headers */ + while (cnt--) { + ret = HTTPHeaders_GetHeader(httpHeadersHandle, cnt, &hname); + if (ret != HTTP_HEADERS_OK) { + return (HTTPAPI_QUERY_HEADERS_FAILED); + } + + ret = splitHeader(hname, &hvalue); + + if (ret == 0) { + ret = HTTPCli_sendField(cli, hname, hvalue, false); + } + + free(hname); + hname = NULL; + + if (ret < 0) { + return (HTTPAPI_SEND_REQUEST_FAILED); + } + } + + /* Send the last header and request body */ + ret = HTTPCli_sendField(cli, NULL, NULL, true); + if (ret < 0) { + return (HTTPAPI_SEND_REQUEST_FAILED); + } + + if (content && contentLength != 0) { + ret = HTTPCli_sendRequestBody(cli, (const char *)content, + contentLength); + if (ret < 0) { + return (HTTPAPI_SEND_REQUEST_FAILED); + } + } + + /* Get the response status code */ + ret = HTTPCli_getResponseStatus(cli); + if (ret < 0) { + return (HTTPAPI_RECEIVE_RESPONSE_FAILED); + } + *statusCode = (unsigned int)ret; + + /* Get the response headers */ + hname = NULL; + cnt = 0; + offset = 0; + do { + ret = HTTPCli_readResponseHeader(cli, contentBuf, CONTENT_BUF_LEN, + &moreFlag); + if (ret < 0) { + ret = HTTPAPI_RECEIVE_RESPONSE_FAILED; + goto headersDone; + } + else if (ret == 0) { + /* All headers read */ + goto headersDone; + } + + if (cnt < offset + ret) { + hname = (char *)realloc(hname, offset + ret); + if (hname == NULL) { + ret = HTTPAPI_ALLOC_FAILED; + goto headersDone; + } + cnt = offset + ret; + } + + memcpy(hname + offset, contentBuf, ret); + offset += ret; + + if (moreFlag) { + continue; + } + + ret = splitHeader(hname, &hvalue); + if (ret < 0) { + ret = HTTPAPI_HTTP_HEADERS_FAILED; + goto headersDone; + } + + ret = HTTPHeaders_AddHeaderNameValuePair(responseHeadersHandle, + hname, hvalue); + if (ret != HTTP_HEADERS_OK) { + ret = HTTPAPI_HTTP_HEADERS_FAILED; + goto headersDone; + } + offset = 0; + } while (1); + +headersDone: + free(hname); + hname = NULL; + if (ret != 0) { + return ((HTTPAPI_RESULT)ret); + } + + /* Get response body */ + if (responseContent != NULL) { + offset = 0; + cnt = 0; + + do { + ret = HTTPCli_readResponseBody(cli, contentBuf, CONTENT_BUF_LEN, + &moreFlag); + + if (ret < 0) { + ret = HTTPAPI_RECEIVE_RESPONSE_FAILED; + goto contentDone; + } + + if (ret != 0) { + cnt = ret; + ret = BUFFER_enlarge(responseContent, cnt); + if (ret != 0) { + ret = HTTPAPI_ALLOC_FAILED; + goto contentDone; + } + + ret = BUFFER_content(responseContent, + (const unsigned char **)&hname); + if (ret != 0) { + ret = HTTPAPI_ALLOC_FAILED; + goto contentDone; + } + + memcpy(hname + offset, contentBuf, cnt); + offset += cnt; + } + } while (moreFlag); + + contentDone: + if (ret < 0) { + BUFFER_unbuild(responseContent); + return ((HTTPAPI_RESULT)ret); + } + } + + return (HTTPAPI_OK); +} + +HTTPAPI_RESULT HTTPAPI_SetOption(HTTP_HANDLE handle, const char* optionName, + const void* value) +{ + return (HTTPAPI_INVALID_ARG); +} + +HTTPAPI_RESULT HTTPAPI_CloneOption(const char* optionName, const void* value, + const void** savedValue) +{ + return (HTTPAPI_INVALID_ARG); +} diff --git a/c/sharedutil/adapters/httpapi_winhttp.c b/c/sharedutil/adapters/httpapi_winhttp.c new file mode 100644 index 00000000..b6dfac70 --- /dev/null +++ b/c/sharedutil/adapters/httpapi_winhttp.c @@ -0,0 +1,769 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include +#ifdef _CRTDBG_MAP_ALLOC +#include +#endif +#include "gballoc.h" + +#include +#include "windows.h" +#include "winhttp.h" +#include "string.h" +#include "httpapi.h" +#include "httpheaders.h" +#include "iot_logging.h" +#include "strings.h" + +#define TEMP_BUFFER_SIZE 1024 +#define MESSAGE_BUFFER_SIZE 260 + +#define LogErrorWinHTTPWithGetLastErrorAsString(FORMAT, ...) { \ + DWORD errorMessageID = GetLastError(); \ + LogError(FORMAT, __VA_ARGS__); \ + CHAR messageBuffer[MESSAGE_BUFFER_SIZE]; \ + if (errorMessageID == 0) \ + {\ + LogError("GetLastError() returned 0. Make sure you are calling this right after the code that failed. \r\n"); \ + } \ + else\ + {\ + int size = FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, \ + GetModuleHandle("WinHttp"), errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), messageBuffer, MESSAGE_BUFFER_SIZE, NULL); \ + if (size == 0)\ + {\ + size = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), messageBuffer, MESSAGE_BUFFER_SIZE, NULL); \ + if (size == 0)\ + {\ + LogError("GetLastError Code: %d. \r\n", errorMessageID); \ + }\ + else\ + {\ + LogError("GetLastError: %s.\r\n", messageBuffer); \ + }\ + }\ + else\ + {\ + LogError("GetLastError: %s.\r\n", messageBuffer); \ + }\ + }\ + } \ + +DEFINE_ENUM_STRINGS(HTTPAPI_RESULT, HTTPAPI_RESULT_VALUES) + +typedef enum HTTPAPI_STATE_TAG +{ + HTTPAPI_NOT_INITIALIZED, + HTTPAPI_INITIALIZED +} HTTPAPI_STATE; + +typedef struct HTTP_HANDLE_DATA_TAG +{ + HINTERNET ConnectionHandle; + unsigned int timeout; +} HTTP_HANDLE_DATA; + +static HTTPAPI_STATE g_HTTPAPIState = HTTPAPI_NOT_INITIALIZED; + +/*There's a global SessionHandle for all the connections*/ +static HINTERNET g_SessionHandle; +static size_t nUsersOfHTTPAPI = 0; /*used for reference counting (a weak one)*/ + +/*returns NULL if it failed to construct the headers*/ +static const char* ConstructHeadersString(HTTP_HEADERS_HANDLE httpHeadersHandle) +{ + char* result; + size_t headersCount; + + if (HTTPHeaders_GetHeaderCount(httpHeadersHandle, &headersCount) != HTTP_HEADERS_OK) + { + result = NULL; + LogError("HTTPHeaders_GetHeaderCount failed.\r\n"); + } + else + { + size_t i; + + /*the total size of all the headers is given by sumof(lengthof(everyheader)+2)*/ + size_t toAlloc = 0; + for (i = 0; i < headersCount; i++) + { + char *temp; + if (HTTPHeaders_GetHeader(httpHeadersHandle, i, &temp) == HTTP_HEADERS_OK) + { + toAlloc += strlen(temp); + toAlloc += 2; + free(temp); + } + else + { + LogError("HTTPHeaders_GetHeader failed\r\n"); + break; + } + } + + if (i < headersCount) + { + result = NULL; + } + else + { + result = malloc(toAlloc*sizeof(char) + 1 ); + + if (result == NULL) + { + LogError("unable to malloc\r\n"); + /*let it be returned*/ + } + else + { + result[0] = '\0'; + for (i = 0; i < headersCount; i++) + { + char* temp; + if (HTTPHeaders_GetHeader(httpHeadersHandle, i, &temp) != HTTP_HEADERS_OK) + { + LogError("unable to HTTPHeaders_GetHeader"); + break; + } + else + { + (void)strcat(result, temp); + (void)strcat(result, "\r\n"); + free(temp); + } + } + + if (i < headersCount) + { + free(result); + result = NULL; + } + else + { + /*all is good*/ + } + } + } + } + + return result; +} + +HTTPAPI_RESULT HTTPAPI_Init(void) +{ + HTTPAPI_RESULT result; + + if (nUsersOfHTTPAPI == 0) + { + LogInfo("HTTP_API first init.\r\n"); + if ((g_SessionHandle = WinHttpOpen( + NULL, + WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, + WINHTTP_NO_PROXY_NAME, + WINHTTP_NO_PROXY_BYPASS, + 0)) == NULL) + { + LogErrorWinHTTPWithGetLastErrorAsString("WinHttpOpen failed.\r\n"); + result = HTTPAPI_INIT_FAILED; + } + else + { + nUsersOfHTTPAPI++; + g_HTTPAPIState = HTTPAPI_INITIALIZED; + result = HTTPAPI_OK; + LogInfo("HTTP_API has now %d users\r\n", (int)nUsersOfHTTPAPI); + } + } + else + { + nUsersOfHTTPAPI++; + result = HTTPAPI_OK; + LogInfo("HTTP_API has now %d users\r\n", (int)nUsersOfHTTPAPI); + } + + return result; +} + +void HTTPAPI_Deinit(void) +{ + if (nUsersOfHTTPAPI > 0) + { + nUsersOfHTTPAPI--; + LogInfo("HTTP_API has now %d users\r\n", (int)nUsersOfHTTPAPI); + if (nUsersOfHTTPAPI == 0) + { + LogInfo("Deinitializing HTTP_API\r\n"); + if (g_SessionHandle != NULL) + { + (void)WinHttpCloseHandle(g_SessionHandle); + g_SessionHandle = NULL; + g_HTTPAPIState = HTTPAPI_NOT_INITIALIZED; + } + } + } + + +} + +HTTP_HANDLE HTTPAPI_CreateConnection(const char* hostName) +{ + HTTP_HANDLE_DATA* result; + if (g_HTTPAPIState != HTTPAPI_INITIALIZED) + { + LogError("g_HTTPAPIState not HTTPAPI_INITIALIZED\r\n"); + result = NULL; + } + else + { + result = (HTTP_HANDLE_DATA*)malloc(sizeof(HTTP_HANDLE_DATA)); + if (result == NULL) + { + LogError("malloc returned NULL.\r\n"); + } + else + { + wchar_t* hostNameTemp; + size_t hostNameTemp_size = MultiByteToWideChar(CP_ACP, 0, hostName, -1, NULL, 0); + if (hostNameTemp_size == 0) + { + LogError("MultiByteToWideChar failed\r\n"); + } + else + { + hostNameTemp = malloc(sizeof(wchar_t)*hostNameTemp_size); + if (hostNameTemp == NULL) + { + LogError("malloc failed\r\n"); + } + else + { + if (MultiByteToWideChar(CP_ACP, 0, hostName, -1, hostNameTemp, hostNameTemp_size) == 0) + { + LogError("MultiByteToWideChar failed\r\n"); + free(result); + result = NULL; + } + else + { + result->ConnectionHandle = WinHttpConnect( + g_SessionHandle, + hostNameTemp, + INTERNET_DEFAULT_HTTPS_PORT, + 0); + + if (result->ConnectionHandle == NULL) + { + LogErrorWinHTTPWithGetLastErrorAsString("WinHttpConnect returned NULL.\r\n"); + free(result); + result = NULL; + } + else + { + result->timeout = 30000; /*default from MSDN ( https://msdn.microsoft.com/en-us/library/windows/desktop/aa384116(v=vs.85).aspx )*/ + } + } + free(hostNameTemp); + } + } + } + } + + return (HTTP_HANDLE)result; +} + +void HTTPAPI_CloseConnection(HTTP_HANDLE handle) +{ + if (g_HTTPAPIState != HTTPAPI_INITIALIZED) + { + LogError("g_HTTPAPIState not HTTPAPI_INITIALIZED\r\n"); + } + else + { + HTTP_HANDLE_DATA* handleData = (HTTP_HANDLE_DATA*)handle; + + if (handleData != NULL) + { + if (handleData->ConnectionHandle != NULL) + { + (void)WinHttpCloseHandle(handleData->ConnectionHandle); + handleData->ConnectionHandle = NULL; + } + free(handleData); + } + } +} + +HTTPAPI_RESULT HTTPAPI_ExecuteRequest(HTTP_HANDLE handle, HTTPAPI_REQUEST_TYPE requestType, const char* relativePath, + HTTP_HEADERS_HANDLE httpHeadersHandle, const unsigned char* content, + size_t contentLength, unsigned int* statusCode, + HTTP_HEADERS_HANDLE responseHeadersHandle, BUFFER_HANDLE responseContent) +{ + HTTPAPI_RESULT result; + if (g_HTTPAPIState != HTTPAPI_INITIALIZED) + { + LogError("g_HTTPAPIState not HTTPAPI_INITIALIZED\r\n"); + result = HTTPAPI_NOT_INIT; + } + else + { + HTTP_HANDLE_DATA* handleData = (HTTP_HANDLE_DATA*)handle; + + if ((handleData == NULL) || + (relativePath == NULL) || + (httpHeadersHandle == NULL)) + { + result = HTTPAPI_INVALID_ARG; + LogError("NULL parameter detected (result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + else + { + wchar_t* requestTypeString = NULL; + + switch (requestType) + { + default: + break; + + case HTTPAPI_REQUEST_GET: + requestTypeString = L"GET"; + break; + + case HTTPAPI_REQUEST_POST: + requestTypeString = L"POST"; + break; + + case HTTPAPI_REQUEST_PUT: + requestTypeString = L"PUT"; + break; + + case HTTPAPI_REQUEST_DELETE: + requestTypeString = L"DELETE"; + break; + + case HTTPAPI_REQUEST_PATCH: + requestTypeString = L"PATCH"; + break; + } + + if (requestTypeString == NULL) + { + result = HTTPAPI_INVALID_ARG; + LogError("requestTypeString was NULL (result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + else + { + const char* headers2; + headers2 = ConstructHeadersString(httpHeadersHandle); + if (headers2 != NULL) + { + size_t requiredCharactersForRelativePath = MultiByteToWideChar(CP_ACP, 0, relativePath, -1, NULL, 0); + wchar_t* relativePathTemp = malloc((requiredCharactersForRelativePath+1) * sizeof(wchar_t)); + result = HTTPAPI_OK; /*legacy code*/ + + if (relativePathTemp == NULL) + { + result = HTTPAPI_ALLOC_FAILED; + LogError("malloc failed (result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + else + { + if (MultiByteToWideChar(CP_ACP, 0, relativePath, -1, relativePathTemp, requiredCharactersForRelativePath) == 0) + { + result = HTTPAPI_STRING_PROCESSING_ERROR; + LogError("MultiByteToWideChar was 0. (result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + else + { + size_t requiredCharactersForHeaders = MultiByteToWideChar(CP_ACP, 0, headers2, -1, NULL, 0); + + wchar_t* headersTemp = malloc((requiredCharactersForHeaders +1) * sizeof(wchar_t) ); + if (headersTemp == NULL) + { + result = HTTPAPI_STRING_PROCESSING_ERROR; + LogError("MultiByteToWideChar was 0. (result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + else + { + if (MultiByteToWideChar(CP_ACP, 0, headers2, -1, headersTemp, requiredCharactersForHeaders) == 0) + { + result = HTTPAPI_STRING_PROCESSING_ERROR; + LogError("MultiByteToWideChar was 0(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + else + { + HINTERNET requestHandle = WinHttpOpenRequest( + handleData->ConnectionHandle, + requestTypeString, + relativePathTemp, + NULL, + WINHTTP_NO_REFERER, + WINHTTP_DEFAULT_ACCEPT_TYPES, + WINHTTP_FLAG_SECURE); + if (requestHandle == NULL) + { + result = HTTPAPI_OPEN_REQUEST_FAILED; + LogErrorWinHTTPWithGetLastErrorAsString("WinHttpOpenRequest failed (result = %s).\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + else + { + if (WinHttpSetTimeouts(requestHandle, + 0, /*_In_ int dwResolveTimeout - The initial value is zero, meaning no time-out (infinite). */ + 60000, /*_In_ int dwConnectTimeout, - The initial value is 60,000 (60 seconds).*/ + handleData->timeout, /*_In_ int dwSendTimeout, - The initial value is 30,000 (30 seconds).*/ + handleData->timeout /* int dwReceiveTimeout The initial value is 30,000 (30 seconds).*/ + ) == FALSE) + { + result = HTTPAPI_SET_TIMEOUTS_FAILED; + LogErrorWinHTTPWithGetLastErrorAsString("WinHttpOpenRequest failed (result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + else + { + DWORD dwSecurityFlags = 0; + + if (!WinHttpSetOption( + requestHandle, + WINHTTP_OPTION_SECURITY_FLAGS, + &dwSecurityFlags, + sizeof(dwSecurityFlags))) + { + result = HTTPAPI_SET_OPTION_FAILED; + LogErrorWinHTTPWithGetLastErrorAsString("WinHttpSetOption failed (result = %s).\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + else + { + if (!WinHttpSendRequest( + requestHandle, + headersTemp, + (DWORD)-1L, /*An unsigned long integer value that contains the length, in characters, of the additional headers. If this parameter is -1L ... */ + (void*)content, + (DWORD)contentLength, + (DWORD)contentLength, + 0)) + { + result = HTTPAPI_SEND_REQUEST_FAILED; + LogErrorWinHTTPWithGetLastErrorAsString("WinHttpSendRequest: (result = %s).\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + else + { + if (!WinHttpReceiveResponse( + requestHandle, + 0)) + { + result = HTTPAPI_RECEIVE_RESPONSE_FAILED; + LogErrorWinHTTPWithGetLastErrorAsString("WinHttpReceiveResponse: (result = %s).\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + else + { + DWORD dwStatusCode = 0; + DWORD dwBufferLength = sizeof(DWORD); + DWORD responseBytesAvailable; + + if (!WinHttpQueryHeaders( + requestHandle, + WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, + WINHTTP_HEADER_NAME_BY_INDEX, + &dwStatusCode, + &dwBufferLength, + WINHTTP_NO_HEADER_INDEX)) + { + result = HTTPAPI_QUERY_HEADERS_FAILED; + LogErrorWinHTTPWithGetLastErrorAsString("WinHttpQueryHeaders failed (result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + else + { + BUFFER_HANDLE useToReadAllResponse = (responseContent != NULL) ? responseContent : BUFFER_new(); + + if (statusCode != NULL) + { + *statusCode = dwStatusCode; + } + + if (useToReadAllResponse == NULL) + { + result = HTTPAPI_ERROR; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + else + { + + int goOnAndReadEverything = 1; + do + { + /*from MSDN: If no data is available and the end of the file has not been reached, one of two things happens. If the session is synchronous, the request waits until data becomes available.*/ + if (!WinHttpQueryDataAvailable(requestHandle, &responseBytesAvailable)) + { + result = HTTPAPI_QUERY_DATA_AVAILABLE_FAILED; + LogErrorWinHTTPWithGetLastErrorAsString("WinHttpQueryDataAvailable failed (result = %s).\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + goOnAndReadEverything = 0; + } + else if (responseBytesAvailable == 0) + { + /*end of the stream, go out*/ + if (dwStatusCode >= HTTP_STATUS_AMBIGUOUS) + { + LogError("HTTP status code was: %d \r\n", (int)dwStatusCode); + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + + result = HTTPAPI_OK; + goOnAndReadEverything = 0; + } + else + { + if (BUFFER_enlarge(useToReadAllResponse, responseBytesAvailable) != 0) + { + result = HTTPAPI_ERROR; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + goOnAndReadEverything = 0; + } + else + { + /*Add the read bytes to the response buffer*/ + size_t bufferSize; + const unsigned char* bufferContent; + + if (BUFFER_content(useToReadAllResponse, &bufferContent) != 0) + { + result = HTTPAPI_ERROR; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + goOnAndReadEverything = 0; + } + else if (BUFFER_size(useToReadAllResponse, &bufferSize) != 0) + { + result = HTTPAPI_ERROR; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + goOnAndReadEverything = 0; + } + else + { + DWORD bytesReceived; + if (!WinHttpReadData(requestHandle, (LPVOID)(bufferContent + bufferSize - responseBytesAvailable), responseBytesAvailable, &bytesReceived)) + { + result = HTTPAPI_READ_DATA_FAILED; + LogErrorWinHTTPWithGetLastErrorAsString("WinHttpReadData failed (result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + goOnAndReadEverything = 0; + } + else + { + /*if for some reason bytesReceived is zero If you are using WinHttpReadData synchronously, and the return value is TRUE and the number of bytes read is zero, the transfer has been completed and there are no more bytes to read on the handle.*/ + if (bytesReceived == 0) + { + /*end of everything, but this looks like an error still, or a non-conformance between WinHttpQueryDataAvailable and WinHttpReadData*/ + result = HTTPAPI_READ_DATA_FAILED; + LogError("bytesReceived was unexpectedly zero (result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + goOnAndReadEverything = 0; + } + else + { + /*all is fine, keep going*/ + } + } + } + } + } + + } while (goOnAndReadEverything != 0); + + if (responseContent != NULL) + { + if (BUFFER_u_char(responseContent) != NULL) + { + LogInfo("Buffer Content:\r\n %.*s\r\n", BUFFER_length(responseContent), BUFFER_u_char(responseContent)); + } + } + else if (useToReadAllResponse != NULL) + { + if (BUFFER_u_char(useToReadAllResponse) != NULL) + { + LogInfo("Buffer Content:\r\n %.*s\r\n", BUFFER_length(useToReadAllResponse), BUFFER_u_char(useToReadAllResponse)); + } + BUFFER_delete(useToReadAllResponse); + } + } + } + + if (result == HTTPAPI_OK && responseHeadersHandle != NULL) + { + wchar_t* responseHeadersTemp; + DWORD responseHeadersTempLength = sizeof(responseHeadersTemp); + + (void)WinHttpQueryHeaders( + requestHandle, + WINHTTP_QUERY_RAW_HEADERS_CRLF, + WINHTTP_HEADER_NAME_BY_INDEX, + WINHTTP_NO_OUTPUT_BUFFER, + &responseHeadersTempLength, + WINHTTP_NO_HEADER_INDEX); + + responseHeadersTemp = (wchar_t*)malloc(responseHeadersTempLength + 2); + if (responseHeadersTemp == NULL) + { + result = HTTPAPI_ALLOC_FAILED; + LogError("malloc failed: (result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + else + { + if (WinHttpQueryHeaders( + requestHandle, + WINHTTP_QUERY_RAW_HEADERS_CRLF, + WINHTTP_HEADER_NAME_BY_INDEX, + responseHeadersTemp, + &responseHeadersTempLength, + WINHTTP_NO_HEADER_INDEX)) + { + wchar_t *next_token; + wchar_t* token = wcstok_s(responseHeadersTemp, L"\r\n", &next_token); + while ((token != NULL) && + (token[0] != L'\0')) + { + char* tokenTemp; + size_t tokenTemp_size; + + tokenTemp_size = WideCharToMultiByte(CP_ACP, 0, token, -1, NULL, 0, NULL, NULL); + if (tokenTemp_size == 0) + { + LogError("WideCharToMultiByte failed\r\n"); + } + else + { + tokenTemp = malloc(sizeof(char)*tokenTemp_size); + if (tokenTemp == NULL) + { + LogError("malloc failed\r\n"); + } + else + { + if (WideCharToMultiByte(CP_ACP, 0, token, -1, tokenTemp, tokenTemp_size, NULL, NULL) > 0) + { + /*breaking the token in 2 parts: everything before the first ":" and everything after the first ":"*/ + /* if there is no such character, then skip it*/ + /*if there is a : then replace is by a '\0' and so it breaks the original string in name and value*/ + + char* whereIsColon = strchr(tokenTemp, ':'); + if (whereIsColon != NULL) + { + *whereIsColon = '\0'; + if (HTTPHeaders_AddHeaderNameValuePair(responseHeadersHandle, tokenTemp, whereIsColon + 1) != HTTP_HEADERS_OK) + { + LogError("HTTPHeaders_AddHeaderNameValuePair failed\r\n"); + result = HTTPAPI_HTTP_HEADERS_FAILED; + break; + } + } + } + else + { + LogError("WideCharToMultiByte failed\r\n"); + } + free(tokenTemp); + } + } + + + token = wcstok_s(NULL, L"\r\n", &next_token); + } + } + else + { + LogError("WinHttpQueryHeaders failed\r\n"); + } + + free(responseHeadersTemp); + } + } + } + } + } + } + (void)WinHttpCloseHandle(requestHandle); + } + } + free(headersTemp); + } + } + free(relativePathTemp); + } + free((void*)headers2); + } + else + { + result = HTTPAPI_ALLOC_FAILED; /*likely*/ + LogError("ConstructHeadersString failed\r\n"); + } + } + } + } + + return result; +} + +HTTPAPI_RESULT HTTPAPI_SetOption(HTTP_HANDLE handle, const char* optionName, const void* value) +{ + HTTPAPI_RESULT result; + if ( + (handle == NULL) || + (optionName == NULL) || + (value == NULL) + ) + { + result = HTTPAPI_INVALID_ARG; + LogError("invalid parameter (NULL) passed to HTTPAPI_SetOption\r\n"); + } + else + { + HTTP_HANDLE_DATA* httpHandleData = (HTTP_HANDLE_DATA*)handle; + if (strcmp("timeout", optionName) == 0) + { + long timeout = (long)(*(unsigned int*)value); + httpHandleData->timeout = timeout; + result = HTTPAPI_OK; + } + else + { + result = HTTPAPI_INVALID_ARG; + LogError("unknown option %s\r\n", optionName); + } + } + return result; +} + +HTTPAPI_RESULT HTTPAPI_CloneOption(const char* optionName, const void* value, const void** savedValue) +{ + HTTPAPI_RESULT result; + if ( + (optionName == NULL) || + (value == NULL) || + (savedValue == NULL) + ) + { + result = HTTPAPI_INVALID_ARG; + LogError("invalid argument(NULL) passed to HTTPAPI_CloneOption\r\n"); + } + else + { + if (strcmp("timeout", optionName) == 0) + { + /*by convention value is pointing to an unsigned int */ + unsigned int* temp = malloc(sizeof(unsigned int)); /*shall be freed by HTTPAPIEX*/ + if (temp == NULL) + { + result = HTTPAPI_ERROR; + LogError("malloc failed (result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + else + { + *temp = *(const unsigned int*)value; + *savedValue = temp; + result = HTTPAPI_OK; + } + } + else + { + result = HTTPAPI_INVALID_ARG; + LogError("unknown option %s\r\n", optionName); + } + } + return result; +} \ No newline at end of file diff --git a/c/sharedutil/adapters/httpapi_wininet.c b/c/sharedutil/adapters/httpapi_wininet.c new file mode 100644 index 00000000..3f6d347e --- /dev/null +++ b/c/sharedutil/adapters/httpapi_wininet.c @@ -0,0 +1,459 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include "malloc.h" +#include "stddef.h" +#include "windows.h" +#include "wininet.h" +#include "string.h" +#include "httpapi.h" +#include "httpheaders.h" +#include "iot_logging.h" +#include "macro_utils.h" +#include "strings.h" + +#define TEMP_BUFFER_SIZE 1024 + +DEFINE_ENUM_STRINGS(HTTPAPI_RESULT, HTTPAPI_RESULT_VALUES); + +typedef enum HTTPAPI_STATE_TAG +{ + HTTPAPI_NOT_INITIALIZED, + HTTPAPI_INITIALIZED +} HTTPAPI_STATE; + +typedef struct HTTP_HANDLE_DATA_TAG +{ + HINTERNET SessionHandle; + HINTERNET ConnectionHandle; +} HTTP_HANDLE_DATA; + +static HTTPAPI_STATE g_HTTPAPIState; + +static HTTPAPI_RESULT ConstructHeadersString(HTTP_HEADERS_HANDLE httpHeadersHandle, char* headers, size_t headersBufferSize) +{ + HTTPAPI_RESULT result; + size_t headersCount; + headers[0] = '\0'; + + if (HTTPHeaders_GetHeaderCount(httpHeadersHandle, &headersCount) != HTTP_HEADERS_OK) + { + result = HTTPAPI_HTTP_HEADERS_FAILED; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + else + { + size_t i; + + for (i = 0; i < headersCount; i++) + { + char tempBuffer[TEMP_BUFFER_SIZE]; + if (HTTPHeaders_GetHeader(httpHeadersHandle, i, tempBuffer, TEMP_BUFFER_SIZE) == HTTP_HEADERS_OK) + { + strcat_s(headers, headersBufferSize, tempBuffer); + strcat_s(headers, headersBufferSize, "\r\n"); + } + } + + result = HTTPAPI_OK; + } + + return result; +} +static size_t nUsersOfHTTPAPI = 0; /*used for reference counting (a weak one)*/ + +HTTPAPI_RESULT HTTPAPI_Init(void) +{ + HTTPAPI_RESULT result; + + if (nUsersOfHTTPAPI == 0) + { + LogInfo("HTTP_API first init.\r\n"); + /*do internetOpen here... TFS202146*/ + nUsersOfHTTPAPI++; + g_HTTPAPIState = HTTPAPI_INITIALIZED; + result = HTTPAPI_OK; + LogInfo("HTTP_API has now %d users\r\n", (int)nUsersOfHTTPAPI); + } + else + { + nUsersOfHTTPAPI++; + result = HTTPAPI_OK; + LogInfo("HTTP_API has now %d users\r\n", (int)nUsersOfHTTPAPI); + } + + return result; +} + +void HTTPAPI_Deinit(void) +{ + if (nUsersOfHTTPAPI > 0) + { + nUsersOfHTTPAPI--; + LogInfo("HTTP_API has now %d users\r\n", (int)nUsersOfHTTPAPI); + if (nUsersOfHTTPAPI == 0) + { + LogInfo("Deinitializing HTTP_API\r\n"); + g_HTTPAPIState = HTTPAPI_NOT_INITIALIZED; + + } + } +} + +HTTP_HANDLE HTTPAPI_CreateConnection(const char* hostName) +{ + HTTP_HANDLE_DATA* result = (HTTP_HANDLE_DATA*)malloc(sizeof(HTTP_HANDLE_DATA)); + if (result == NULL) + { + /* error */ + } + else + { + wchar_t hostNameTemp[1024]; + + if (MultiByteToWideChar(CP_ACP, 0, hostName, -1, hostNameTemp, sizeof(hostNameTemp) / sizeof(hostNameTemp[0])) == 0) + { + /* error */ + } + else + { + result->SessionHandle = InternetOpen( + NULL, + INTERNET_OPEN_TYPE_DIRECT, + NULL, + NULL, + 0); + if (result->SessionHandle != NULL) + { + result->ConnectionHandle = InternetConnectW( + result->SessionHandle, + hostNameTemp, + INTERNET_DEFAULT_HTTPS_PORT, + NULL, + NULL, + INTERNET_SERVICE_HTTP, + 0, + 0); + } + + if ((result->SessionHandle == NULL) || + (result->ConnectionHandle == NULL)) + { + HTTPAPI_CloseConnection(result); + result = NULL; + } + } + } + + return (HTTP_HANDLE)result; +} + +void HTTPAPI_CloseConnection(HTTP_HANDLE handle) +{ + HTTP_HANDLE_DATA* handleData = (HTTP_HANDLE_DATA*)handle; + + if (handleData != NULL) + { + if (handleData->ConnectionHandle != NULL) + { + (void)InternetCloseHandle(handleData->ConnectionHandle); + handleData->ConnectionHandle = NULL; + } + if (handleData->SessionHandle != NULL) + { + (void)InternetCloseHandle(handleData->SessionHandle); + handleData->SessionHandle = NULL; + } + free(handleData); + } +} + +HTTPAPI_RESULT HTTPAPI_ExecuteRequest(HTTP_HANDLE handle, HTTPAPI_REQUEST_TYPE requestType, const char* relativePath, + HTTP_HEADERS_HANDLE httpHeadersHandle, const unsigned char* content, + size_t contentLength, unsigned int* statusCode, + HTTP_HEADERS_HANDLE responseHeadersHandle, BUFFER_HANDLE responseContent) +{ + HTTPAPI_RESULT result; + HTTP_HANDLE_DATA* handleData = (HTTP_HANDLE_DATA*)handle; + + if ((handleData == NULL) || + (relativePath == NULL) || + (httpHeadersHandle == NULL)) + { + result = HTTPAPI_INVALID_ARG; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + else + { + wchar_t* requestTypeString = NULL; + + switch (requestType) + { + default: + break; + + case HTTPAPI_REQUEST_GET: + requestTypeString = L"GET"; + break; + + case HTTPAPI_REQUEST_POST: + requestTypeString = L"POST"; + break; + + case HTTPAPI_REQUEST_PUT: + requestTypeString = L"PUT"; + break; + + case HTTPAPI_REQUEST_DELETE: + requestTypeString = L"DELETE"; + break; + + case HTTPAPI_REQUEST_PATCH: + requestTypeString = L"PATCH"; + break; + } + + if (requestTypeString == NULL) + { + result = HTTPAPI_INVALID_ARG; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + else + { + wchar_t relativePathTemp[1024]; + char headers[1024]; + wchar_t headersTemp[1024]; + + result = ConstructHeadersString(httpHeadersHandle, headers, sizeof(headers)); + if (result == HTTPAPI_OK) + { + if (MultiByteToWideChar(CP_ACP, 0, relativePath, -1, relativePathTemp, sizeof(relativePathTemp) / sizeof(relativePathTemp[0])) == 0) + { + result = HTTPAPI_STRING_PROCESSING_ERROR; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + else + { + if (MultiByteToWideChar(CP_ACP, 0, headers, -1, headersTemp, sizeof(headersTemp) / sizeof(headersTemp[0])) == 0) + { + result = HTTPAPI_STRING_PROCESSING_ERROR; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + else + { + PCWSTR rgpszAcceptTypes[] = { L"text/*", NULL }; + HINTERNET requestHandle = HttpOpenRequestW( + handleData->ConnectionHandle, + requestTypeString, + relativePathTemp, + NULL, + NULL, + rgpszAcceptTypes, + INTERNET_FLAG_SECURE, + 0); + if (requestHandle == NULL) + { + result = HTTPAPI_OPEN_REQUEST_FAILED; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + else + { + unsigned long int timeout = 55000; + if (!InternetSetOption( + requestHandle, + INTERNET_OPTION_RECEIVE_TIMEOUT, /*Sets or retrieves an unsigned long integer value that contains the time-out value, in milliseconds, to receive a response to a request.*/ + &timeout, + sizeof(timeout))) + { + result = HTTPAPI_SET_TIMEOUTS_FAILED; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + else + { + DWORD dwSecurityFlags = 0; + if (!InternetSetOption( + requestHandle, + INTERNET_OPTION_SECURITY_FLAGS, + &dwSecurityFlags, + sizeof(dwSecurityFlags))) + { + result = HTTPAPI_SET_OPTION_FAILED; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + else + { + if (!HttpSendRequestW( + requestHandle, + headersTemp, + -1, + (void*)content, + contentLength)) + { + result = HTTPAPI_SEND_REQUEST_FAILED; +LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + else + { + DWORD dwStatusCode = 0; + DWORD dwBufferLength = sizeof(DWORD); + DWORD responseBytesAvailable; + + if (responseHeadersHandle != NULL) + { + wchar_t responseHeadersTemp[16384]; + DWORD responseHeadersTempLength = sizeof(responseHeadersTemp); + + if (HttpQueryInfo( + requestHandle, + HTTP_QUERY_RAW_HEADERS_CRLF, + responseHeadersTemp, + &responseHeadersTempLength, + 0)) + { + wchar_t *next_token; + wchar_t* token = wcstok_s(responseHeadersTemp, L"\r\n", &next_token); + while ((token != NULL) && + (token[0] != L'\0')) + { + char tokenTemp[1024]; + + if (WideCharToMultiByte(CP_ACP, 0, token, -1, tokenTemp, sizeof(tokenTemp), NULL, NULL) > 0) + { + /*breaking the token in 2 parts: everything before the first ":" and everything after the first ":"*/ + /* if there is no such character, then skip it*/ + /*if there is a : then replace is by a '\0' and so it breaks the original string in name and value*/ + + char* whereIsColon = strchr(tokenTemp, ':'); + if (whereIsColon != NULL) + { + *whereIsColon = '\0'; + HTTPHeaders_AddHeaderNameValuePair(responseHeadersHandle, tokenTemp, whereIsColon + 1); + } + } + token = wcstok_s(NULL, L"\r\n", &next_token); + } + } + } + + if (!HttpQueryInfo( + requestHandle, + HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, + &dwStatusCode, + &dwBufferLength, + 0)) + { + result = HTTPAPI_QUERY_HEADERS_FAILED; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + else + { + BUFFER_HANDLE useToReadAllResponse = (responseContent != NULL) ? responseContent : BUFFER_new(); + /*HTTP status code (dwStatusCode) can be either ok (=HTTP_STATUS_AMBIGUOUS)*/ + if (useToReadAllResponse == NULL) + { + result = HTTPAPI_ERROR; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + else + { + int goOnAndReadEverything = 1; + /*set the response code*/ + if (statusCode != NULL) + { + *statusCode = dwStatusCode; + } + + do + { + /*from MSDN: If there is currently no data available and the end of the file has not been reached, the request waits until data becomes available*/ + if (!InternetQueryDataAvailable(requestHandle, &responseBytesAvailable, 0, 0)) + { + result = HTTPAPI_QUERY_DATA_AVAILABLE_FAILED; + LogError("InternetQueryDataAvailable failed (result = %s) GetLastError = %d\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result), GetLastError()); + goOnAndReadEverything = 0; + } + else if (responseBytesAvailable == 0) + { + /*end of the stream, go out*/ + if (dwStatusCode >= HTTP_STATUS_AMBIGUOUS) + { + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + } + + result = HTTPAPI_OK; + goOnAndReadEverything = 0; + } + else + { + /*add the needed space to the buffer*/ + if (BUFFER_enlarge(useToReadAllResponse, responseBytesAvailable) != 0) + { + result = HTTPAPI_ERROR; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + goOnAndReadEverything = 0; + } + else + { + unsigned char* bufferContent; + size_t bufferSize; + /*add the data to the buffer*/ + if (BUFFER_content(useToReadAllResponse, &bufferContent) != 0) + { + result = HTTPAPI_ERROR; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + goOnAndReadEverything = 0; + } + else if (BUFFER_size(useToReadAllResponse, &bufferSize) != 0) + { + result = HTTPAPI_ERROR; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + goOnAndReadEverything = 0; + } + else + { + DWORD bytesReceived; + if (!InternetReadFile(requestHandle, bufferContent + bufferSize - responseBytesAvailable, responseBytesAvailable, &bytesReceived)) + { + result = HTTPAPI_READ_DATA_FAILED; + LogError("InternetReadFile failed (result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + goOnAndReadEverything = 0; + } + else + { + /*if for some reason bytesReceived is zero, MSDN says To ensure all data is retrieved, an application must continue to call the InternetReadFile function until the function returns TRUE and the lpdwNumberOfBytesRead parameter equals zero*/ + if (bytesReceived == 0) + { + /*end of everything, but this looks like an error still, or a non-conformance between InternetQueryDataAvailable and InternetReadFile*/ + result = HTTPAPI_READ_DATA_FAILED; + LogError("InternetReadFile failed (result = %s)\r\n", ENUM_TO_STRING(HTTPAPI_RESULT, result)); + goOnAndReadEverything = 0; + } + else + { + /*all is fine, keep going*/ + } + } + } + } + } + } while (goOnAndReadEverything != 0); + + if (responseContent == NULL) + { + BUFFER_delete(useToReadAllResponse); + } + } + } + } + } + } + (void)InternetCloseHandle(requestHandle); + } + } + } + } + } + } + + return result; +} \ No newline at end of file diff --git a/c/sharedutil/adapters/lock_c11.c b/c/sharedutil/adapters/lock_c11.c new file mode 100644 index 00000000..b481aa70 --- /dev/null +++ b/c/sharedutil/adapters/lock_c11.c @@ -0,0 +1,105 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include +#ifdef _CRTDBG_MAP_ALLOC +#include +#endif +#include "stdlib.h" + +#include "macro_utils.h" +#include "lock.h" +#include +#include "iot_logging.h" + +DEFINE_ENUM_STRINGS(LOCK_RESULT, LOCK_RESULT_VALUES); + +/*SRS_LOCK_99_002:[ This API on success will return a valid lock handle which should be a non NULL value]*/ +LOCK_HANDLE Lock_Init(void) +{ + mtx_t* lock_mtx = (mtx_t*)malloc(sizeof(mtx_t)); + if (NULL != lock_mtx) + { + if (mtx_init(lock_mtx, mtx_plain) != thrd_success) + { + /*SRS_LOCK_99_003:[ On Error Should return NULL]*/ + free(lock_mtx); + lock_mtx = NULL; + LogError("Failed to initialize mutex\r\n"); + } + } + + return (LOCK_HANDLE)lock_mtx; +} + + +LOCK_RESULT Lock(LOCK_HANDLE handle) +{ + LOCK_RESULT result; + if (handle == NULL) + { + /*SRS_LOCK_99_007:[ This API on NULL handle passed returns LOCK_ERROR]*/ + result = LOCK_ERROR; + LogError("(result = %s)\r\n", ENUM_TO_STRING(LOCK_RESULT, result)); + } + else + { + if (mtx_lock((mtx_t*)handle) == thrd_success) + { + /*SRS_LOCK_99_005:[ This API on success should return LOCK_OK]*/ + result = LOCK_OK; + } + else + { + /*SRS_LOCK_99_006:[ This API on error should return LOCK_ERROR]*/ + result = LOCK_ERROR; + LogError("(result = %s)\r\n", ENUM_TO_STRING(LOCK_RESULT, result)); + } + } + return result; +} +LOCK_RESULT Unlock(LOCK_HANDLE handle) +{ + LOCK_RESULT result; + if (handle == NULL) + { + /*SRS_LOCK_99_011:[ This API on NULL handle passed returns LOCK_ERROR]*/ + result = LOCK_ERROR; + LogError("(result = %s)\r\n", ENUM_TO_STRING(LOCK_RESULT, result)); + } + else + { + if (mtx_unlock((mtx_t*)handle) == thrd_success) + { + /*SRS_LOCK_99_009:[ This API on success should return LOCK_OK]*/ + result = LOCK_OK; + } + else + { + /*SRS_LOCK_99_010:[ This API on error should return LOCK_ERROR]*/ + result = LOCK_ERROR; + LogError("(result = %s)\r\n", ENUM_TO_STRING(LOCK_RESULT, result)); + } + } + return result; +} + +LOCK_RESULT Lock_Deinit(LOCK_HANDLE handle) +{ + LOCK_RESULT result=LOCK_OK ; + if (NULL == handle) + { + /*SRS_LOCK_99_013:[ This API on NULL handle passed returns LOCK_ERROR]*/ + result = LOCK_ERROR; + LogError("(result = %s)\r\n", ENUM_TO_STRING(LOCK_RESULT, result)); + } + else + { + /*SRS_LOCK_99_012:[ This API frees the memory pointed by handle]*/ + (void)mtx_destroy((mtx_t*)handle); + free(handle); + handle = NULL; + } + + return result; +} diff --git a/c/sharedutil/adapters/lock_pthreads.c b/c/sharedutil/adapters/lock_pthreads.c new file mode 100644 index 00000000..ec7f58c6 --- /dev/null +++ b/c/sharedutil/adapters/lock_pthreads.c @@ -0,0 +1,108 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include "lock.h" +#include +#include +#include "iot_logging.h" + +DEFINE_ENUM_STRINGS(LOCK_RESULT, LOCK_RESULT_VALUES); + +/*SRS_LOCK_99_002:[ This API on success will return a valid lock handle which should be a non NULL value]*/ +LOCK_HANDLE Lock_Init(void) +{ + pthread_mutex_t* lock_mtx = (pthread_mutex_t*)malloc(sizeof(pthread_mutex_t)); + if (NULL != lock_mtx) + { + if (pthread_mutex_init(lock_mtx, NULL) != 0) + { + /*SRS_LOCK_99_003:[ On Error Should return NULL]*/ + free(lock_mtx); + lock_mtx = NULL; + LogError("Failed to initialize mutex\r\n"); + } + } + + return (LOCK_HANDLE)lock_mtx; +} + + +LOCK_RESULT Lock(LOCK_HANDLE handle) +{ + LOCK_RESULT result; + if (handle == NULL) + { + /*SRS_LOCK_99_007:[ This API on NULL handle passed returns LOCK_ERROR]*/ + result = LOCK_ERROR; + LogError("(result = %s)\r\n", ENUM_TO_STRING(LOCK_RESULT, result)); + } + else + { + if ( pthread_mutex_lock((pthread_mutex_t*)handle) == 0) + { + /*SRS_LOCK_99_005:[ This API on success should return LOCK_OK]*/ + result = LOCK_OK; + } + else + { + /*SRS_LOCK_99_006:[ This API on error should return LOCK_ERROR]*/ + result = LOCK_ERROR; + LogError("(result = %s)\r\n", ENUM_TO_STRING(LOCK_RESULT, result)); + } + } + return result; +} +LOCK_RESULT Unlock(LOCK_HANDLE handle) +{ + LOCK_RESULT result; + if (handle == NULL) + { + /*SRS_LOCK_99_011:[ This API on NULL handle passed returns LOCK_ERROR]*/ + result = LOCK_ERROR; + LogError("(result = %s)\r\n", ENUM_TO_STRING(LOCK_RESULT, result)); + } + else + { + if (pthread_mutex_unlock((pthread_mutex_t*)handle) == 0) + { + /*SRS_LOCK_99_009:[ This API on success should return LOCK_OK]*/ + result = LOCK_OK; + } + else + { + /*SRS_LOCK_99_010:[ This API on error should return LOCK_ERROR]*/ + result = LOCK_ERROR; + LogError("(result = %s)\r\n", ENUM_TO_STRING(LOCK_RESULT, result)); + } + } + return result; +} + +LOCK_RESULT Lock_Deinit(LOCK_HANDLE handle) +{ + LOCK_RESULT result=LOCK_OK ; + if (NULL == handle) + { + /*SRS_LOCK_99_013:[ This API on NULL handle passed returns LOCK_ERROR]*/ + result = LOCK_ERROR; + LogError("(result = %s)\r\n", ENUM_TO_STRING(LOCK_RESULT, result)); + } + else + { + /*SRS_LOCK_99_012:[ This API frees the memory pointed by handle]*/ + if(pthread_mutex_destroy((pthread_mutex_t*)handle)==0) + { + free(handle); + handle = NULL; + } + else + { + result = LOCK_ERROR; + LogError("(result = %s)\r\n", ENUM_TO_STRING(LOCK_RESULT, result)); + } + } + + return result; +} + + diff --git a/c/sharedutil/adapters/lock_rtx_mbed.cpp b/c/sharedutil/adapters/lock_rtx_mbed.cpp new file mode 100644 index 00000000..b88040be --- /dev/null +++ b/c/sharedutil/adapters/lock_rtx_mbed.cpp @@ -0,0 +1,94 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include +#ifdef _CRTDBG_MAP_ALLOC +#include +#endif + +#include "lock.h" +#include "iot_logging.h" +#include "rtos.h" + +DEFINE_ENUM_STRINGS(LOCK_RESULT, LOCK_RESULT_VALUES); + +/*Tests_SRS_LOCK_99_002:[ This API on success will return a valid lock handle which should be a non NULL value]*/ +LOCK_HANDLE Lock_Init(void) +{ + Mutex* lock_mtx = new Mutex(); + + return (LOCK_HANDLE)lock_mtx; +} + + +LOCK_RESULT Lock(LOCK_HANDLE handle) +{ + LOCK_RESULT result; + if (handle == NULL) + { + /*Tests_SRS_LOCK_99_007:[ This API on NULL handle passed returns LOCK_ERROR]*/ + result = LOCK_ERROR; + LogError("(result = %s)\r\n", ENUM_TO_STRING(LOCK_RESULT, result)); + } + else + { + Mutex* lock_mtx = (Mutex*)handle; + if (lock_mtx->lock() == osOK) + { + /*Tests_SRS_LOCK_99_005:[ This API on success should return LOCK_OK]*/ + result = LOCK_OK; + } + else + { + /*Tests_SRS_LOCK_99_006:[ This API on error should return LOCK_ERROR]*/ + result = LOCK_ERROR; + LogError("(result = %s)\r\n", ENUM_TO_STRING(LOCK_RESULT, result)); + } + } + return result; +} +LOCK_RESULT Unlock(LOCK_HANDLE handle) +{ + LOCK_RESULT result; + if (handle == NULL) + { + /*Tests_SRS_LOCK_99_011:[ This API on NULL handle passed returns LOCK_ERROR]*/ + result = LOCK_ERROR; + LogError("(result = %s)\r\n", ENUM_TO_STRING(LOCK_RESULT, result)); + } + else + { + Mutex* lock_mtx = (Mutex*)handle; + if (lock_mtx->unlock() == osOK) + { + /*Tests_SRS_LOCK_99_009:[ This API on success should return LOCK_OK]*/ + result = LOCK_OK; + } + else + { + /*Tests_SRS_LOCK_99_010:[ This API on error should return LOCK_ERROR]*/ + result = LOCK_ERROR; + LogError("(result = %s)\r\n", ENUM_TO_STRING(LOCK_RESULT, result)); + } + } + return result; +} + +LOCK_RESULT Lock_Deinit(LOCK_HANDLE handle) +{ + LOCK_RESULT result=LOCK_OK ; + if (NULL == handle) + { + /*Tests_SRS_LOCK_99_013:[ This API on NULL handle passed returns LOCK_ERROR]*/ + result = LOCK_ERROR; + LogError("(result = %s)\r\n", ENUM_TO_STRING(LOCK_RESULT, result)); + } + else + { + /*Tests_SRS_LOCK_99_012:[ This API frees the memory pointed by handle]*/ + Mutex* lock_mtx = (Mutex*)handle; + delete lock_mtx; + } + + return result; +} diff --git a/c/sharedutil/adapters/lock_win32.c b/c/sharedutil/adapters/lock_win32.c new file mode 100644 index 00000000..fe03d18b --- /dev/null +++ b/c/sharedutil/adapters/lock_win32.c @@ -0,0 +1,76 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include "lock.h" +#include +#include "malloc.h" +#include "iot_logging.h" + +DEFINE_ENUM_STRINGS(LOCK_RESULT, LOCK_RESULT_VALUES); + +/*SRS_LOCK_99_002:[ This API on success will return a valid lock handle which should be a non NULL value]*/ +LOCK_HANDLE Lock_Init(void) +{ + LPCRITICAL_SECTION lpCriticalSection = (LPCRITICAL_SECTION) malloc(sizeof(CRITICAL_SECTION)); + if (!lpCriticalSection) + { + LogError("Could not allocate memory for Critical Section"); + } + else + { + //In low-memory situations, InitializeCriticalSection can raise a STATUS_NO_MEMORY exception. + InitializeCriticalSection( lpCriticalSection ); + } + return (LOCK_HANDLE) lpCriticalSection; +} + + +LOCK_RESULT Lock(LOCK_HANDLE handle) +{ + LOCK_RESULT result = LOCK_OK; + if (handle == NULL) + { + /*SRS_LOCK_99_007:[ This API on NULL handle passed returns LOCK_ERROR]*/ + result = LOCK_ERROR; + LogError("(result = %s)\r\n", Lock_ResultAsString[result]); + } + else + { + EnterCriticalSection( (LPCRITICAL_SECTION) handle ); + } + return result; +} + +LOCK_RESULT Unlock(LOCK_HANDLE handle) +{ + LOCK_RESULT result = LOCK_OK; + if (handle == NULL) + { + /*SRS_LOCK_99_007:[ This API on NULL handle passed returns LOCK_ERROR]*/ + result = LOCK_ERROR; + LogError("(result = %s)\r\n", Lock_ResultAsString[result]); + } + else + { + LeaveCriticalSection( (LPCRITICAL_SECTION) handle ); + } + + return result; +} + +LOCK_RESULT Lock_Deinit(LOCK_HANDLE handle) +{ + LOCK_RESULT result = LOCK_OK; + if (handle == NULL) + { + /*SRS_LOCK_99_007:[ This API on NULL handle passed returns LOCK_ERROR]*/ + result = LOCK_ERROR; + LogError("(result = %s)\r\n", Lock_ResultAsString[result]); + } + else + { + DeleteCriticalSection( (LPCRITICAL_SECTION) handle ); + free( (LPCRITICAL_SECTION) handle ); + } + return result; +} \ No newline at end of file diff --git a/c/sharedutil/adapters/platform_linux.c b/c/sharedutil/adapters/platform_linux.c new file mode 100644 index 00000000..f4eb9298 --- /dev/null +++ b/c/sharedutil/adapters/platform_linux.c @@ -0,0 +1,28 @@ +#include +#ifdef _CRTDBG_MAP_ALLOC +#include +#endif +#include "platform.h" +#include "winsock2.h" + +int platform_init(void) +{ + int result; + + WSADATA wsaData; + if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) + { + result = __LINE__; + } + else + { + result = 0; + } + + return result; +} + +void platform_deinit(void) +{ + (void)WSACleanup(); +} diff --git a/c/sharedutil/adapters/platform_win32.c b/c/sharedutil/adapters/platform_win32.c new file mode 100644 index 00000000..7ad0b119 --- /dev/null +++ b/c/sharedutil/adapters/platform_win32.c @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include +#ifdef _CRTDBG_MAP_ALLOC +#include +#endif +#include "platform.h" +#include "winsock2.h" + +int platform_init(void) +{ + int result; + + WSADATA wsaData; + if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) + { + result = __LINE__; + } + else + { + result = 0; + } + + return result; +} + +void platform_deinit(void) +{ + (void)WSACleanup(); +} diff --git a/c/sharedutil/adapters/socketio_win32.c b/c/sharedutil/adapters/socketio_win32.c new file mode 100644 index 00000000..2394198b --- /dev/null +++ b/c/sharedutil/adapters/socketio_win32.c @@ -0,0 +1,306 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include +#ifdef _CRTDBG_MAP_ALLOC +#include +#endif +#include +#include +#include "socketio.h" +#include "winsock2.h" +#include "ws2tcpip.h" +#include "windows.h" + +typedef struct SOCKET_IO_INSTANCE_TAG +{ + SOCKET socket; + ON_BYTES_RECEIVED on_bytes_received; + ON_IO_STATE_CHANGED on_io_state_changed; + LOGGER_LOG logger_log; + void* callback_context; + char* hostname; + int port; + IO_STATE io_state; + unsigned char* pending_send_bytes; + size_t pending_send_byte_count; +} SOCKET_IO_INSTANCE; + +static const IO_INTERFACE_DESCRIPTION socket_io_interface_description = +{ + socketio_create, + socketio_destroy, + socketio_open, + socketio_close, + socketio_send, + socketio_dowork +}; + +static void set_io_state(SOCKET_IO_INSTANCE* socket_io_instance, IO_STATE io_state) +{ + IO_STATE previous_state = socket_io_instance->io_state; + socket_io_instance->io_state = io_state; + if (socket_io_instance->on_io_state_changed != NULL) + { + socket_io_instance->on_io_state_changed(socket_io_instance->callback_context, io_state, previous_state); + } +} + +IO_HANDLE socketio_create(void* io_create_parameters, LOGGER_LOG logger_log) +{ + SOCKETIO_CONFIG* socket_io_config = io_create_parameters; + SOCKET_IO_INSTANCE* result; + + if (socket_io_config == NULL) + { + result = NULL; + } + else + { + result = malloc(sizeof(SOCKET_IO_INSTANCE)); + if (result != NULL) + { + result->hostname = (char*)malloc(strlen(socket_io_config->hostname) + 1); + if (result->hostname == NULL) + { + free(result); + result = NULL; + } + else + { + strcpy(result->hostname, socket_io_config->hostname); + result->port = socket_io_config->port; + result->on_bytes_received = NULL; + result->on_io_state_changed = NULL; + result->logger_log = logger_log; + result->socket = INVALID_SOCKET; + result->callback_context = NULL; + result->pending_send_byte_count = 0; + result->pending_send_bytes = NULL; + result->io_state = IO_STATE_NOT_OPEN; + } + } + } + + return result; +} + +void socketio_destroy(IO_HANDLE socket_io) +{ + if (socket_io != NULL) + { + SOCKET_IO_INSTANCE* socket_io_instance = (SOCKET_IO_INSTANCE*)socket_io; + /* we cannot do much if the close fails, so just ignore the result */ + (void)closesocket(socket_io_instance->socket); + free(socket_io_instance->hostname); + free(socket_io); + } +} + +int socketio_open(IO_HANDLE socket_io, ON_BYTES_RECEIVED on_bytes_received, ON_IO_STATE_CHANGED on_io_state_changed, void* callback_context) +{ + int result; + + SOCKET_IO_INSTANCE* socket_io_instance = (SOCKET_IO_INSTANCE*)socket_io; + if (socket_io == NULL) + { + result = __LINE__; + } + else + { + ADDRINFO* addrInfo; + char portString[16]; + + socket_io_instance->socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (socket_io_instance->socket == INVALID_SOCKET) + { + set_io_state(socket_io_instance, IO_STATE_ERROR); + result = __LINE__; + } + else + { + sprintf(portString, "%u", socket_io_instance->port); + if (getaddrinfo(socket_io_instance->hostname, portString, NULL, &addrInfo) != 0) + { + closesocket(socket_io_instance->socket); + set_io_state(socket_io_instance, IO_STATE_ERROR); + socket_io_instance->socket = INVALID_SOCKET; + result = __LINE__; + } + else + { + u_long iMode = 1; + + if (connect(socket_io_instance->socket, addrInfo->ai_addr, sizeof(*addrInfo->ai_addr)) != 0) + { + closesocket(socket_io_instance->socket); + set_io_state(socket_io_instance, IO_STATE_ERROR); + socket_io_instance->socket = INVALID_SOCKET; + result = __LINE__; + } + else if (ioctlsocket(socket_io_instance->socket, FIONBIO, &iMode)) + { + closesocket(socket_io_instance->socket); + set_io_state(socket_io_instance, IO_STATE_ERROR); + socket_io_instance->socket = INVALID_SOCKET; + result = __LINE__; + } + else + { + socket_io_instance->on_bytes_received = on_bytes_received; + socket_io_instance->on_io_state_changed = on_io_state_changed; + socket_io_instance->callback_context = callback_context; + + set_io_state(socket_io_instance, IO_STATE_OPEN); + result = 0; + } + } + } + } + + return result; +} + +int socketio_close(IO_HANDLE socket_io) +{ + int result = 0; + + if (socket_io == NULL) + { + result = __LINE__; + } + else + { + SOCKET_IO_INSTANCE* socket_io_instance = (SOCKET_IO_INSTANCE*)socket_io; + + closesocket(socket_io_instance->socket); + socket_io_instance->socket = INVALID_SOCKET; + set_io_state(socket_io_instance, IO_STATE_NOT_OPEN); + result = 0; + } + + return result; +} + +int socketio_send(IO_HANDLE socket_io, const void* buffer, size_t size) +{ + int result; + + if ((socket_io == NULL) || + (buffer == NULL) || + (size == 0)) + { + /* Invalid arguments */ + result = __LINE__; + } + else + { + SOCKET_IO_INSTANCE* socket_io_instance = (SOCKET_IO_INSTANCE*)socket_io; + if (socket_io_instance->io_state != IO_STATE_OPEN) + { + result = __LINE__; + } + else + { + int send_result = send(socket_io_instance->socket, buffer, size, 0); + if (send_result != size) + { + int last_error = WSAGetLastError(); + + if (last_error != WSAEWOULDBLOCK) + { + result = __LINE__; + } + else + { + /* queue data */ + unsigned char* new_pending_send_bytes = realloc(socket_io_instance->pending_send_bytes, socket_io_instance->pending_send_byte_count + size); + if (new_pending_send_bytes == NULL) + { + result = __LINE__; + } + else + { + socket_io_instance->pending_send_bytes = new_pending_send_bytes; + (void)memcpy(socket_io_instance->pending_send_bytes + socket_io_instance->pending_send_byte_count, buffer, size); + socket_io_instance->pending_send_byte_count += size; + + result = 0; + } + } + } + else + { + size_t i; + for (i = 0; i < size; i++) + { + LOG(socket_io_instance->logger_log, 0, "%02x-> ", ((unsigned char*)buffer)[i]); + } + + result = 0; + } + } + } + + return result; +} + +void socketio_dowork(IO_HANDLE socket_io) +{ + if (socket_io != NULL) + { + SOCKET_IO_INSTANCE* socket_io_instance = (SOCKET_IO_INSTANCE*)socket_io; + if (socket_io_instance->io_state == IO_STATE_OPEN) + { + int received = 1; + + if (socket_io_instance->pending_send_byte_count > 0) + { + int send_result = send(socket_io_instance->socket, socket_io_instance->pending_send_bytes, socket_io_instance->pending_send_byte_count, 0); + if (send_result != socket_io_instance->pending_send_byte_count) + { + int last_error = WSAGetLastError(); + if (last_error != WSAEWOULDBLOCK) + { + /* error */ + } + else + { + /* simply wait */ + } + } + else + { + free(socket_io_instance->pending_send_bytes); + socket_io_instance->pending_send_bytes = NULL; + socket_io_instance->pending_send_byte_count = 0; + } + } + + while (received > 0) + { + unsigned char recv_bytes[1]; + received = recv(socket_io_instance->socket, recv_bytes, sizeof(recv_bytes), 0); + if (received > 0) + { + int i; + for (i = 0; i < received; i++) + { + LOG(socket_io_instance->logger_log, 0, "<-%02x ", (unsigned char)recv_bytes[i]); + } + + if (socket_io_instance->on_bytes_received != NULL) + { + /* explictly ignoring here the result of the callback */ + (void)socket_io_instance->on_bytes_received(socket_io_instance->callback_context, recv_bytes, received); + } + } + } + } + } +} + +const IO_INTERFACE_DESCRIPTION* socketio_get_interface_description(void) +{ + return &socket_io_interface_description; +} diff --git a/c/sharedutil/adapters/threadapi_c11.c b/c/sharedutil/adapters/threadapi_c11.c new file mode 100644 index 00000000..3819e316 --- /dev/null +++ b/c/sharedutil/adapters/threadapi_c11.c @@ -0,0 +1,114 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include +#ifdef _CRTDBG_MAP_ALLOC +#include +#endif +#include "gballoc.h" + +#if defined(__cplusplus) +#include +#else +#include +#endif + +#include +#include "threadapi.h" +#include "windows.h" +#include "iot_logging.h" + +DEFINE_ENUM_STRINGS(THREADAPI_RESULT, THREADAPI_RESULT_VALUES); + +THREADAPI_RESULT ThreadAPI_Create(THREAD_HANDLE* threadHandle, THREAD_START_FUNC func, void* arg) +{ + THREADAPI_RESULT result; + int thrd_create_result = thrd_success; + if ((threadHandle == NULL) || + (func == NULL)) + { + result = THREADAPI_INVALID_ARG; + LogError("(result = %s)\r\n", ENUM_TO_STRING(THREADAPI_RESULT, result)); + } + else + { + thrd_t* thrd_t_ptr = (thrd_t*)malloc(sizeof(thrd_t)); + if (thrd_t_ptr == NULL) + { + result = THREADAPI_NO_MEMORY; + LogError("(result = %s)\r\n", ENUM_TO_STRING(THREADAPI_RESULT, result)); + } + else + { + thrd_create_result = thrd_create(thrd_t_ptr, func, arg); + if (thrd_create_result != thrd_success) + { + free(thrd_t_ptr); + result = THREADAPI_ERROR; + LogError("(result = %s)\r\n", ENUM_TO_STRING(THREADAPI_RESULT, result)); + } + else + { + result = THREADAPI_OK; + *threadHandle = (THREAD_HANDLE)thrd_t_ptr; + } + } + } + + return result; +} + +THREADAPI_RESULT ThreadAPI_Join(THREAD_HANDLE threadHandle, int *res) +{ + THREADAPI_RESULT result; + thrd_t* thrd_t_ptr = (thrd_t*)threadHandle; + + if (threadHandle == NULL) + { + result = THREADAPI_INVALID_ARG; + LogError("(result = %s)\r\n", ENUM_TO_STRING(THREADAPI_RESULT, result)); + } + else + { + switch (thrd_join(*thrd_t_ptr, res)) + { + default: + case thrd_error: + result = THREADAPI_ERROR; + LogError("(result = %s)\r\n", ENUM_TO_STRING(THREADAPI_RESULT, result)); + break; + + case thrd_success: + result = THREADAPI_OK; + break; + + case thrd_nomem: + result = THREADAPI_NO_MEMORY; + LogError("(result = %s)\r\n", ENUM_TO_STRING(THREADAPI_RESULT, result)); + break; + } + + free(thrd_t_ptr); + } + + return result; +} + +void ThreadAPI_Exit(int res) +{ + thrd_exit(res); +} + +void ThreadAPI_Sleep(unsigned int milliseconds) +{ + HANDLE handle = CreateEventEx(NULL, NULL, 0, EVENT_ALL_ACCESS); + + if (handle != NULL) + { + /* + * Have to use at least 1 to cause a thread yield in case 0 is passed + */ + (void)WaitForSingleObjectEx(handle, milliseconds == 0 ? 1 : milliseconds, FALSE); + (void)CloseHandle(handle); + } +} diff --git a/c/sharedutil/adapters/threadapi_pthreads.c b/c/sharedutil/adapters/threadapi_pthreads.c new file mode 100644 index 00000000..e80f1c3d --- /dev/null +++ b/c/sharedutil/adapters/threadapi_pthreads.c @@ -0,0 +1,136 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#define _DEFAULT_SOURCE + +#include "threadapi.h" +#include +#include +#include + +#ifdef TI_RTOS +#include +#else +#include +#endif + +#include +#include +#include "iot_logging.h" + +DEFINE_ENUM_STRINGS(THREADAPI_RESULT, THREADAPI_RESULT_VALUES); + +typedef struct THREAD_INSTANCE_TAG +{ + pthread_t Pthread_handle; + THREAD_START_FUNC ThreadStartFunc; + void* Arg; +} THREAD_INSTANCE; + +static void* ThreadWrapper(void* threadInstanceArg) +{ + THREAD_INSTANCE* threadInstance = (THREAD_INSTANCE*)threadInstanceArg; + int result = threadInstance->ThreadStartFunc(threadInstance->Arg); + return (void*)(intptr_t)result; +} + +THREADAPI_RESULT ThreadAPI_Create(THREAD_HANDLE* threadHandle, THREAD_START_FUNC func, void* arg) +{ + THREADAPI_RESULT result; + + if ((threadHandle == NULL) || + (func == NULL)) + { + result = THREADAPI_INVALID_ARG; + LogError("(result = %s)\r\n", ENUM_TO_STRING(THREADAPI_RESULT, result)); + } + else + { + THREAD_INSTANCE* threadInstance = malloc(sizeof(THREAD_INSTANCE)); + if (threadInstance == NULL) + { + result = THREADAPI_NO_MEMORY; + LogError("(result = %s)\r\n", ENUM_TO_STRING(THREADAPI_RESULT, result)); + } + else + { + threadInstance->ThreadStartFunc = func; + threadInstance->Arg = arg; + int createResult = pthread_create(&threadInstance->Pthread_handle, NULL, ThreadWrapper, threadInstance); + switch (createResult) + { + default: + free(threadInstance); + + result = THREADAPI_ERROR; + LogError("(result = %s)\r\n", ENUM_TO_STRING(THREADAPI_RESULT, result)); + break; + + case 0: + *threadHandle = threadInstance; + result = THREADAPI_OK; + break; + + case EAGAIN: + free(threadInstance); + + result = THREADAPI_NO_MEMORY; + LogError("(result = %s)\r\n", ENUM_TO_STRING(THREADAPI_RESULT, result)); + break; + } + } + } + + return result; +} + +THREADAPI_RESULT ThreadAPI_Join(THREAD_HANDLE threadHandle, int* res) +{ + THREADAPI_RESULT result; + + THREAD_INSTANCE* threadInstance = (THREAD_INSTANCE*)threadHandle; + if (threadInstance == NULL) + { + result = THREADAPI_INVALID_ARG; + LogError("(result = %s)\r\n", ENUM_TO_STRING(THREADAPI_RESULT, result)); + } + else + { + void* threadResult; + if (pthread_join(threadInstance->Pthread_handle, &threadResult) != 0) + { + result = THREADAPI_ERROR; + LogError("(result = %s)\r\n", ENUM_TO_STRING(THREADAPI_RESULT, result)); + } + else + { + if (res != NULL) + { + *res = (int)(intptr_t)threadResult; + } + + result = THREADAPI_OK; + } + + free(threadInstance); + } + + return result; +} + +void ThreadAPI_Exit(int res) +{ + pthread_exit((void*)(intptr_t)res); +} + +void ThreadAPI_Sleep(unsigned int milliseconds) +{ +#ifdef TI_RTOS + Task_sleep(milliseconds); +#else + time_t seconds = milliseconds / 1000; + long nsRemainder = (milliseconds % 1000) * 1000000; + struct timespec timeToSleep = { seconds, nsRemainder }; + (void)nanosleep(&timeToSleep, NULL); +#endif +} diff --git a/c/sharedutil/adapters/threadapi_rtx_mbed.cpp b/c/sharedutil/adapters/threadapi_rtx_mbed.cpp new file mode 100644 index 00000000..e30ff5b9 --- /dev/null +++ b/c/sharedutil/adapters/threadapi_rtx_mbed.cpp @@ -0,0 +1,145 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include +#ifdef _CRTDBG_MAP_ALLOC +#include +#endif + +#include "stdlib.h" +#include "threadapi.h" +#include "rtos.h" +#include "iot_logging.h" + +DEFINE_ENUM_STRINGS(THREADAPI_RESULT, THREADAPI_RESULT_VALUES); + +#define MAX_THREADS 4 +#define STACK_SIZE 0x4000 + +typedef struct _thread +{ + Thread* thrd; + osThreadId id; + Queue result; +} mbedThread; +static mbedThread threads[MAX_THREADS] = { 0 }; + +typedef struct _create_param +{ + THREAD_START_FUNC func; + const void* arg; + mbedThread *p_thread; +} create_param; + +static void thread_wrapper(const void* createParamArg) +{ + const create_param* p = (const create_param*)createParamArg; + p->p_thread->id = Thread::gettid(); + (*(p->func))((void*)p->arg); + free((void*)p); +} + +THREADAPI_RESULT ThreadAPI_Create(THREAD_HANDLE* threadHandle, THREAD_START_FUNC func, void* arg) +{ + THREADAPI_RESULT result; + if ((threadHandle == NULL) || + (func == NULL)) + { + result = THREADAPI_INVALID_ARG; + LogError("(result = %s)\r\n", ENUM_TO_STRING(THREADAPI_RESULT, result)); + } + else + { + size_t slot; + for (slot = 0; slot < MAX_THREADS; slot++) + { + if (threads[slot].id == NULL) + break; + } + + if (slot < MAX_THREADS) + { + create_param* param = (create_param*)malloc(sizeof(create_param)); + if (param != NULL) + { + param->func = func; + param->arg = arg; + param->p_thread = threads + slot; + threads[slot].thrd = new Thread(thread_wrapper, param, osPriorityNormal, STACK_SIZE); + *threadHandle = (THREAD_HANDLE)(threads + slot); + result = THREADAPI_OK; + } + else + { + result = THREADAPI_NO_MEMORY; + LogError("(result = %s)\r\n", ENUM_TO_STRING(THREADAPI_RESULT, result)); + } + } + else + { + result = THREADAPI_NO_MEMORY; + LogError("(result = %s)\r\n", ENUM_TO_STRING(THREADAPI_RESULT, result)); + } + } + + return result; +} + +THREADAPI_RESULT ThreadAPI_Join(THREAD_HANDLE thr, int *res) +{ + THREADAPI_RESULT result = THREADAPI_OK; + mbedThread* p = (mbedThread*)thr; + if (p) + { + osEvent evt = p->result.get(); + if (evt.status == osEventMessage) { + Thread* t = p->thrd; + if (res) + { + *res = (int)evt.value.p; + } + (void)t->terminate(); + } + else + { + result = THREADAPI_ERROR; + LogError("(result = %s)\r\n", ENUM_TO_STRING(THREADAPI_RESULT, result)); + } + } + else + { + result = THREADAPI_INVALID_ARG; + LogError("(result = %s)\r\n", ENUM_TO_STRING(THREADAPI_RESULT, result)); + } + return result; +} + +void ThreadAPI_Exit(int res) +{ + mbedThread* p; + for (p = threads; p < &threads[MAX_THREADS]; p++) + { + if (p->id == Thread::gettid()) + { + p->result.put((int*)res); + break; + } + } +} + +void ThreadAPI_Sleep(unsigned int millisec) +{ + // + // The timer on mbed seems to wrap around 65 seconds. Hmmm. + // So we will do our waits in increments of 30 seconds. + // + const int thirtySeconds = 30000; + int numberOfThirtySecondWaits = millisec / thirtySeconds; + int remainderOfThirtySeconds = millisec % thirtySeconds; + int i; + for (i = 1; i <= numberOfThirtySecondWaits; i++) + { + Thread::wait(thirtySeconds); + } + Thread::wait(remainderOfThirtySeconds); +} diff --git a/c/sharedutil/adapters/threadapi_win32.c b/c/sharedutil/adapters/threadapi_win32.c new file mode 100644 index 00000000..9ce6dfda --- /dev/null +++ b/c/sharedutil/adapters/threadapi_win32.c @@ -0,0 +1,78 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include +#ifdef _CRTDBG_MAP_ALLOC +#include +#endif +#include "threadapi.h" +#include "windows.h" +#include "iot_logging.h" + +DEFINE_ENUM_STRINGS(THREADAPI_RESULT, THREADAPI_RESULT_VALUES); + +THREADAPI_RESULT ThreadAPI_Create(THREAD_HANDLE* threadHandle, THREAD_START_FUNC func, void* arg) +{ + THREADAPI_RESULT result; + if ((threadHandle == NULL) || + (func == NULL)) + { + result = THREADAPI_INVALID_ARG; + LogError("(result = %s)\r\n", ENUM_TO_STRING(THREADAPI_RESULT, result)); + } + else + { + *threadHandle = CreateThread(NULL, 0, func, arg, 0, NULL); + if(threadHandle == NULL) + { + result = THREADAPI_ERROR; + LogError("(result = %s)\r\n", ENUM_TO_STRING(THREADAPI_RESULT, result)); + } + else + { + result = THREADAPI_OK; + } + } + + return result; +} + +THREADAPI_RESULT ThreadAPI_Join(THREAD_HANDLE threadHandle, int *res) +{ + THREADAPI_RESULT result = THREADAPI_OK; + + if (threadHandle == NULL) + { + result = THREADAPI_INVALID_ARG; + LogError("(result = %s)\r\n", ENUM_TO_STRING(THREADAPI_RESULT, result)); + } + else + { + DWORD returnCode = WaitForSingleObject(threadHandle, INFINITE); + + if( returnCode != WAIT_OBJECT_0) + { + result = THREADAPI_ERROR; + LogError("Error waiting for Single Object. Return Code: %d. Error Code: %d\r\n", returnCode); + } + else if((res != NULL) && !GetExitCodeThread(threadHandle, res)) //If thread end is signaled we need to get the Thread Exit Code; + { + DWORD errorCode = GetLastError(); + result = THREADAPI_ERROR; + LogError("Error Getting Exit Code. Error Code: %d.\r\n", errorCode); + } + CloseHandle(threadHandle); + } + + return result; +} + +void ThreadAPI_Exit(int res) +{ + ExitThread(res); +} + +void ThreadAPI_Sleep(unsigned int milliseconds) +{ + Sleep(milliseconds); +} diff --git a/c/sharedutil/adapters/tlsio_win32.c b/c/sharedutil/adapters/tlsio_win32.c new file mode 100644 index 00000000..4262ddba --- /dev/null +++ b/c/sharedutil/adapters/tlsio_win32.c @@ -0,0 +1,692 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#define SECURITY_WIN32 + +#include +#ifdef _CRTDBG_MAP_ALLOC +#include +#endif + +#include +#include +#include +#include "tlsio.h" +#include "socketio.h" +#include "windows.h" +#include "sspi.h" +#include "schannel.h" +#include "iot_logging.h" + +typedef enum TLS_STATE_TAG +{ + TLS_STATE_HANDSHAKE_NOT_STARTED, + TLS_STATE_HANDSHAKE_CLIENT_HELLO_SENT, + TLS_STATE_HANDSHAKE_SERVER_HELLO_RECEIVED, + TLS_STATE_HANDSHAKE_DONE, + TLS_STATE_ERROR +} TLS_STATE; + +typedef struct TLS_IO_INSTANCE_TAG +{ + IO_HANDLE socket_io; + ON_BYTES_RECEIVED on_bytes_received; + ON_IO_STATE_CHANGED on_io_state_changed; + void* callback_context; + LOGGER_LOG logger_log; + CtxtHandle security_context; + TLS_STATE tls_state; + SEC_CHAR* host_name; + CredHandle credential_handle; + bool credential_handle_allocated; + unsigned char* received_bytes; + size_t received_byte_count; + size_t buffer_size; + size_t needed_bytes; + size_t consumed_bytes; + IO_STATE io_state; +} TLS_IO_INSTANCE; + +static const IO_INTERFACE_DESCRIPTION tls_io_interface_description = +{ + tlsio_create, + tlsio_destroy, + tlsio_open, + tlsio_close, + tlsio_send, + tlsio_dowork +}; + +static void set_io_state(TLS_IO_INSTANCE* tls_io_instance, IO_STATE io_state) +{ + IO_STATE previous_state = tls_io_instance->io_state; + tls_io_instance->io_state = io_state; + if (tls_io_instance->on_io_state_changed != NULL) + { + tls_io_instance->on_io_state_changed(tls_io_instance->callback_context, io_state, previous_state); + } +} + +static int resize_receive_buffer(TLS_IO_INSTANCE* tls_io_instance, size_t needed_buffer_size) +{ + int result; + + if (needed_buffer_size > tls_io_instance->buffer_size) + { + unsigned char* new_buffer = realloc(tls_io_instance->received_bytes, needed_buffer_size); + if (new_buffer == NULL) + { + result = __LINE__; + } + else + { + tls_io_instance->received_bytes = new_buffer; + tls_io_instance->buffer_size = needed_buffer_size; + result = 0; + } + } + else + { + result = 0; + } + + return result; +} + +static int set_receive_buffer(TLS_IO_INSTANCE* tls_io_instance, size_t buffer_size) +{ + int result; + + unsigned char* new_buffer = realloc(tls_io_instance->received_bytes, buffer_size); + if (new_buffer == NULL) + { + result = __LINE__; + } + else + { + tls_io_instance->received_bytes = new_buffer; + tls_io_instance->buffer_size = buffer_size; + result = 0; + } + + return result; +} + +static void tlsio_on_bytes_received(void* context, const void* buffer, size_t size) +{ + TLS_IO_INSTANCE* tls_io_instance = (TLS_IO_INSTANCE*)context; + + if (resize_receive_buffer(tls_io_instance, tls_io_instance->received_byte_count + size) == 0) + { + memcpy(tls_io_instance->received_bytes + tls_io_instance->received_byte_count, buffer, size); + tls_io_instance->received_byte_count += size; + + if (size > tls_io_instance->needed_bytes) + { + tls_io_instance->needed_bytes = 0; + } + else + { + tls_io_instance->needed_bytes -= size; + } + + switch (tls_io_instance->tls_state) + { + default: + break; + + case TLS_STATE_ERROR: + break; + + case TLS_STATE_HANDSHAKE_CLIENT_HELLO_SENT: + { + if (tls_io_instance->needed_bytes == 0) + { + SecBuffer input_buffers[2]; + SecBuffer output_buffers[2]; + ULONG context_attributes; + + /* we need to try and perform the second (next) step of the init */ + input_buffers[0].cbBuffer = tls_io_instance->received_byte_count; + input_buffers[0].BufferType = SECBUFFER_TOKEN; + input_buffers[0].pvBuffer = (void*)tls_io_instance->received_bytes; + input_buffers[1].cbBuffer = 0; + input_buffers[1].BufferType = SECBUFFER_EMPTY; + input_buffers[1].pvBuffer = 0; + + SecBufferDesc input_buffers_desc; + input_buffers_desc.cBuffers = 2; + input_buffers_desc.pBuffers = input_buffers; + input_buffers_desc.ulVersion = SECBUFFER_VERSION; + + output_buffers[0].cbBuffer = 0; + output_buffers[0].BufferType = SECBUFFER_TOKEN; + output_buffers[0].pvBuffer = NULL; + output_buffers[1].cbBuffer = 0; + output_buffers[1].BufferType = SECBUFFER_EMPTY; + output_buffers[1].pvBuffer = 0; + + SecBufferDesc output_buffers_desc; + output_buffers_desc.cBuffers = 2; + output_buffers_desc.pBuffers = output_buffers; + output_buffers_desc.ulVersion = SECBUFFER_VERSION; + + SECURITY_STATUS status = InitializeSecurityContext(&tls_io_instance->credential_handle, + &tls_io_instance->security_context, (SEC_CHAR*)tls_io_instance->host_name, ISC_REQ_EXTENDED_ERROR | ISC_REQ_STREAM | ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_USE_SUPPLIED_CREDS, 0, 0, &input_buffers_desc, 0, + &tls_io_instance->security_context, &output_buffers_desc, + &context_attributes, NULL); + + switch (status) + { + case SEC_E_INCOMPLETE_MESSAGE: + if (input_buffers[1].BufferType != SECBUFFER_MISSING) + { + tls_io_instance->tls_state = TLS_STATE_ERROR; + } + else + { + tls_io_instance->needed_bytes = input_buffers[1].cbBuffer; + tls_io_instance->consumed_bytes += tls_io_instance->needed_bytes; + if (resize_receive_buffer(tls_io_instance, tls_io_instance->received_byte_count + tls_io_instance->needed_bytes) != 0) + { + tls_io_instance->tls_state = TLS_STATE_ERROR; + } + } + break; + case SEC_E_OK: + memmove(tls_io_instance->received_bytes, tls_io_instance->received_bytes + tls_io_instance->consumed_bytes, tls_io_instance->received_byte_count - tls_io_instance->consumed_bytes); + tls_io_instance->received_byte_count -= tls_io_instance->consumed_bytes; + + tls_io_instance->needed_bytes = 1; + tls_io_instance->consumed_bytes = tls_io_instance->needed_bytes; + + if (set_receive_buffer(tls_io_instance, tls_io_instance->needed_bytes + tls_io_instance->received_byte_count) != 0) + { + tls_io_instance->tls_state = TLS_STATE_ERROR; + } + else + { + tls_io_instance->tls_state = TLS_STATE_HANDSHAKE_DONE; + set_io_state(tls_io_instance, IO_STATE_OPEN); + } + + break; + + case SEC_I_COMPLETE_NEEDED: + case SEC_I_CONTINUE_NEEDED: + case SEC_I_COMPLETE_AND_CONTINUE: + if ((output_buffers[0].cbBuffer > 0) && io_send(tls_io_instance->socket_io, output_buffers[0].pvBuffer, output_buffers[0].cbBuffer) != 0) + { + tls_io_instance->tls_state = TLS_STATE_ERROR; + } + else + { + memmove(tls_io_instance->received_bytes, tls_io_instance->received_bytes + tls_io_instance->consumed_bytes, tls_io_instance->received_byte_count - tls_io_instance->consumed_bytes); + tls_io_instance->received_byte_count -= tls_io_instance->consumed_bytes; + + /* set the needed bytes to 1, to get on the next byte how many we actually need */ + tls_io_instance->needed_bytes = 1; + tls_io_instance->consumed_bytes = tls_io_instance->needed_bytes; + if (set_receive_buffer(tls_io_instance, tls_io_instance->needed_bytes + tls_io_instance->received_byte_count) != 0) + { + FreeCredentialHandle(&tls_io_instance->credential_handle); + tls_io_instance->tls_state = TLS_STATE_ERROR; + } + else + { + tls_io_instance->tls_state = TLS_STATE_HANDSHAKE_CLIENT_HELLO_SENT; + } + } + break; + } + } + + break; + + case TLS_STATE_HANDSHAKE_DONE: + { + if (tls_io_instance->needed_bytes == 0) + { + SecBuffer security_buffers[4]; + SecBufferDesc security_buffers_desc; + + security_buffers[0].BufferType = SECBUFFER_DATA; + security_buffers[0].pvBuffer = tls_io_instance->received_bytes; + security_buffers[0].cbBuffer = tls_io_instance->received_byte_count; + security_buffers[1].BufferType = SECBUFFER_EMPTY; + security_buffers[2].BufferType = SECBUFFER_EMPTY; + security_buffers[3].BufferType = SECBUFFER_EMPTY; + + security_buffers_desc.cBuffers = sizeof(security_buffers) / sizeof(security_buffers[0]); + security_buffers_desc.pBuffers = security_buffers; + security_buffers_desc.ulVersion = SECBUFFER_VERSION; + + SECURITY_STATUS status = DecryptMessage(&tls_io_instance->security_context, &security_buffers_desc, 0, NULL); + switch (status) + { + case SEC_E_INCOMPLETE_MESSAGE: + if (security_buffers[1].BufferType != SECBUFFER_MISSING) + { + tls_io_instance->tls_state = TLS_STATE_ERROR; + } + else + { + tls_io_instance->needed_bytes = security_buffers[1].cbBuffer; + tls_io_instance->consumed_bytes += tls_io_instance->needed_bytes; + if (resize_receive_buffer(tls_io_instance, tls_io_instance->received_byte_count + tls_io_instance->needed_bytes) != 0) + { + tls_io_instance->tls_state = TLS_STATE_ERROR; + } + } + break; + + case SEC_E_OK: + if (security_buffers[1].BufferType != SECBUFFER_DATA) + { + tls_io_instance->tls_state = TLS_STATE_ERROR; + } + else + { + size_t i; + for (i = 0; i < security_buffers[1].cbBuffer; i++) + { + LOG(tls_io_instance->logger_log, 0, "<-%02x ", ((unsigned char*)security_buffers[1].pvBuffer)[i]); + } + + /* notify of the received data */ + if (tls_io_instance->on_bytes_received != NULL) + { + tls_io_instance->on_bytes_received(tls_io_instance->callback_context, security_buffers[1].pvBuffer, security_buffers[1].cbBuffer); + } + + memmove(tls_io_instance->received_bytes, tls_io_instance->received_bytes + tls_io_instance->consumed_bytes, tls_io_instance->received_byte_count - tls_io_instance->consumed_bytes); + tls_io_instance->received_byte_count -= tls_io_instance->consumed_bytes; + + tls_io_instance->needed_bytes = 1; + tls_io_instance->consumed_bytes = tls_io_instance->needed_bytes; + + if (set_receive_buffer(tls_io_instance, tls_io_instance->needed_bytes + tls_io_instance->received_byte_count) != 0) + { + tls_io_instance->tls_state = TLS_STATE_ERROR; + } + else + { + tls_io_instance->tls_state = TLS_STATE_HANDSHAKE_DONE; + set_io_state(tls_io_instance, IO_STATE_OPEN); + } + } + break; + } + } + + break; + } + } + } + } +} + +static void tlsio_on_io_state_changed(void* context, IO_STATE new_io_state, IO_STATE previous_io_state) +{ + TLS_IO_INSTANCE* tls_io_instance = (TLS_IO_INSTANCE*)context; + + if (tls_io_instance->io_state == IO_STATE_OPENING) + { + switch (tls_io_instance->tls_state) + { + default: + break; + case TLS_STATE_HANDSHAKE_NOT_STARTED: + { + SecBuffer init_security_buffers[2]; + ULONG context_attributes; + SECURITY_STATUS status; + SCHANNEL_CRED auth_data; + + auth_data.dwVersion = SCHANNEL_CRED_VERSION; + auth_data.cCreds = 0; + auth_data.paCred = NULL; + auth_data.hRootStore = NULL; + auth_data.cSupportedAlgs = 0; + auth_data.palgSupportedAlgs = NULL; + auth_data.grbitEnabledProtocols = 0; + auth_data.dwMinimumCipherStrength = 0; + auth_data.dwMaximumCipherStrength = 0; + auth_data.dwSessionLifespan = 0; + auth_data.dwFlags = SCH_USE_STRONG_CRYPTO; + auth_data.dwCredFormat = 0; + + status = AcquireCredentialsHandle(NULL, UNISP_NAME, SECPKG_CRED_OUTBOUND, NULL, + &auth_data, NULL, NULL, &tls_io_instance->credential_handle, NULL); + if (status != SEC_E_OK) + { + tls_io_instance->tls_state = TLS_STATE_ERROR; + } + else + { + init_security_buffers[0].cbBuffer = 0; + init_security_buffers[0].BufferType = SECBUFFER_TOKEN; + init_security_buffers[0].pvBuffer = NULL; + init_security_buffers[1].cbBuffer = 0; + init_security_buffers[1].BufferType = SECBUFFER_EMPTY; + init_security_buffers[1].pvBuffer = 0; + + SecBufferDesc security_buffers_desc; + security_buffers_desc.cBuffers = 2; + security_buffers_desc.pBuffers = init_security_buffers; + security_buffers_desc.ulVersion = SECBUFFER_VERSION; + + status = InitializeSecurityContext(&tls_io_instance->credential_handle, + NULL, (SEC_CHAR*)tls_io_instance->host_name, ISC_REQ_EXTENDED_ERROR | ISC_REQ_STREAM | ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_USE_SUPPLIED_CREDS, 0, 0, NULL, 0, + &tls_io_instance->security_context, &security_buffers_desc, + &context_attributes, NULL); + + if ((status == SEC_I_COMPLETE_NEEDED) || (status == SEC_I_CONTINUE_NEEDED) || (status == SEC_I_COMPLETE_AND_CONTINUE)) + { + if (io_send(tls_io_instance->socket_io, init_security_buffers[0].pvBuffer, init_security_buffers[0].cbBuffer) != 0) + { + FreeCredentialHandle(&tls_io_instance->credential_handle); + tls_io_instance->tls_state = TLS_STATE_ERROR; + } + else + { + /* set the needed bytes to 1, to get on the next byte how many we actually need */ + tls_io_instance->needed_bytes = 1; + tls_io_instance->consumed_bytes = tls_io_instance->needed_bytes; + if (resize_receive_buffer(tls_io_instance, tls_io_instance->needed_bytes + tls_io_instance->received_byte_count) != 0) + { + FreeCredentialHandle(&tls_io_instance->credential_handle); + tls_io_instance->tls_state = TLS_STATE_ERROR; + } + else + { + tls_io_instance->tls_state = TLS_STATE_HANDSHAKE_CLIENT_HELLO_SENT; + } + } + } + } + + break; + } + } + } +} + +IO_HANDLE tlsio_create(void* io_create_parameters, LOGGER_LOG logger_log) +{ + TLSIO_CONFIG* tls_io_config = io_create_parameters; + TLS_IO_INSTANCE* result; + + if (tls_io_config == NULL) + { + result = NULL; + } + else + { + result = malloc(sizeof(TLS_IO_INSTANCE)); + if (result != NULL) + { + SOCKETIO_CONFIG socketio_config; + + socketio_config.hostname = tls_io_config->hostname; + socketio_config.port = tls_io_config->port; + + result->on_bytes_received = NULL; + result->on_io_state_changed = NULL; + result->logger_log = logger_log; + result->callback_context = NULL; + + result->host_name = (SEC_CHAR*)malloc(sizeof(SEC_CHAR) * (1 + strlen(tls_io_config->hostname))); + if (result->host_name == NULL) + { + free(result); + result = NULL; + } + else + { + (void)strcpy(result->host_name, tls_io_config->hostname); + + const IO_INTERFACE_DESCRIPTION* socket_io_interface = socketio_get_interface_description(); + if (socket_io_interface == NULL) + { + free(result->host_name); + free(result); + result = NULL; + } + else + { + result->socket_io = io_create(socket_io_interface, &socketio_config, logger_log); + if (result->socket_io == NULL) + { + free(result->host_name); + free(result); + result = NULL; + } + else + { + result->received_bytes = NULL; + result->received_byte_count = 0; + result->buffer_size = 0; + result->consumed_bytes = 0; + result->tls_state = TLS_STATE_HANDSHAKE_NOT_STARTED; + set_io_state(result, IO_STATE_NOT_OPEN); + } + } + } + } + } + + return result; +} + +void tlsio_destroy(IO_HANDLE tls_io) +{ + if (tls_io != NULL) + { + TLS_IO_INSTANCE* tls_io_instance = (TLS_IO_INSTANCE*)tls_io; + if (tls_io_instance->credential_handle_allocated) + { + (void)FreeCredentialHandle(&tls_io_instance->credential_handle); + } + + if (tls_io_instance->received_bytes != NULL) + { + free(tls_io_instance->received_bytes); + } + + io_destroy(tls_io_instance->socket_io); + free(tls_io_instance->host_name); + free(tls_io); + } +} + +int tlsio_open(IO_HANDLE tls_io, ON_BYTES_RECEIVED on_bytes_received, ON_IO_STATE_CHANGED on_io_state_changed, void* callback_context) +{ + int result; + + if (tls_io == NULL) + { + result = __LINE__; + } + else + { + TLS_IO_INSTANCE* tls_io_instance = (TLS_IO_INSTANCE*)tls_io; + + if (tls_io_instance->io_state != IO_STATE_NOT_OPEN) + { + result = __LINE__; + } + else + { + tls_io_instance->on_bytes_received = on_bytes_received; + tls_io_instance->on_io_state_changed = on_io_state_changed; + tls_io_instance->callback_context = callback_context; + + set_io_state(tls_io_instance, IO_STATE_OPENING); + + if (io_open(tls_io_instance->socket_io, tlsio_on_bytes_received, tlsio_on_io_state_changed, tls_io_instance) != 0) + { + set_io_state(tls_io_instance, IO_STATE_ERROR); + result = __LINE__; + } + else + { + result = 0; + } + } + } + + return result; +} + +int tlsio_close(IO_HANDLE tls_io) +{ + int result = 0; + + if (tls_io == NULL) + { + result = __LINE__; + } + else + { + TLS_IO_INSTANCE* tls_io_instance = (TLS_IO_INSTANCE*)tls_io; + (void)io_close(tls_io_instance->socket_io); + set_io_state(tls_io_instance, IO_STATE_NOT_OPEN); + } + + return result; +} + +int send_chunk(IO_HANDLE tls_io, const void* buffer, size_t size) +{ + int result; + + if ((tls_io == NULL) || + (buffer == NULL) || + (size == 0)) + { + /* Invalid arguments */ + result = __LINE__; + } + else + { + TLS_IO_INSTANCE* tls_io_instance = (TLS_IO_INSTANCE*)tls_io; + if (tls_io_instance->io_state != IO_STATE_OPEN) + { + result = __LINE__; + } + else + { + SecPkgContext_StreamSizes sizes; + SECURITY_STATUS status = QueryContextAttributes(&tls_io_instance->security_context, SECPKG_ATTR_STREAM_SIZES, &sizes); + if (status != SEC_E_OK) + { + result = __LINE__; + } + else + { + SecBuffer security_buffers[4]; + SecBufferDesc security_buffers_desc; + size_t needed_buffer = sizes.cbHeader + size + sizes.cbTrailer; + unsigned char* out_buffer = (unsigned char*)malloc(needed_buffer); + if (out_buffer == NULL) + { + result = __LINE__; + } + else + { + memcpy(out_buffer + sizes.cbHeader, buffer, size); + + security_buffers[0].BufferType = SECBUFFER_STREAM_HEADER; + security_buffers[0].cbBuffer = sizes.cbHeader; + security_buffers[0].pvBuffer = out_buffer; + security_buffers[1].BufferType = SECBUFFER_DATA; + security_buffers[1].cbBuffer = size; + security_buffers[1].pvBuffer = out_buffer + sizes.cbHeader; + security_buffers[2].BufferType = SECBUFFER_STREAM_TRAILER; + security_buffers[2].cbBuffer = sizes.cbTrailer; + security_buffers[2].pvBuffer = out_buffer + sizes.cbHeader + size; + security_buffers[3].cbBuffer = 0; + security_buffers[3].BufferType = SECBUFFER_EMPTY; + security_buffers[3].pvBuffer = 0; + + security_buffers_desc.cBuffers = sizeof(security_buffers) / sizeof(security_buffers[0]); + security_buffers_desc.pBuffers = security_buffers; + security_buffers_desc.ulVersion = SECBUFFER_VERSION; + + status = EncryptMessage(&tls_io_instance->security_context, 0, &security_buffers_desc, 0); + if (FAILED(status)) + { + result = __LINE__; + } + else + { + if (io_send(tls_io_instance->socket_io, out_buffer, security_buffers[0].cbBuffer + security_buffers[1].cbBuffer + security_buffers[2].cbBuffer) != 0) + { + result = __LINE__; + } + else + { + size_t i; + for (i = 0; i < size; i++) + { + LOG(tls_io_instance->logger_log, 0, "%02x-> ", ((unsigned char*)buffer)[i]); + } + result = 0; + } + } + free(out_buffer); + } + } + } + } + + return result; +} + +int tlsio_send(IO_HANDLE tls_io, const void* buffer, size_t size) +{ + int result; + + while (size > 0) + { + size_t to_send = 16 * 1024; + if (to_send > size) + { + to_send = size; + } + + if (send_chunk(tls_io, buffer, to_send) != 0) + { + break; + } + + size -= to_send; + buffer = ((const unsigned char*)buffer) + to_send; + } + + if (size > 0) + { + result = __LINE__; + } + else + { + result = 0; + } + + return result; +} + +void tlsio_dowork(IO_HANDLE tls_io) +{ + if (tls_io != NULL) + { + TLS_IO_INSTANCE* tls_io_instance = (TLS_IO_INSTANCE*)tls_io; + io_dowork(tls_io_instance->socket_io); + } +} + +const IO_INTERFACE_DESCRIPTION* tlsio_get_interface_description(void) +{ + return &tls_io_interface_description; +} diff --git a/c/sharedutil/adapters/wolfssl_connection.cpp b/c/sharedutil/adapters/wolfssl_connection.cpp new file mode 100644 index 00000000..49e66279 --- /dev/null +++ b/c/sharedutil/adapters/wolfssl_connection.cpp @@ -0,0 +1,227 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include +#include "wolfssl/ssl.h" +#include "wolfssl_connection.h" +#include "iot_logging.h" + +WolfSSLConnection::WolfSSLConnection() +{ + wolfSSL_Init(); + + WOLFSSL_METHOD* method = wolfTLSv1_2_client_method(); + if(method != NULL) + { + sslContext = wolfSSL_CTX_new(method); + } + else + { + sslContext = NULL; + } + + isConnected = false; +} + +WolfSSLConnection::~WolfSSLConnection() +{ + if (sslContext != NULL) + { + wolfSSL_CTX_free(sslContext); + sslContext = NULL; + } + + wolfSSL_Cleanup(); +} + +static int receiveCallback(WOLFSSL* ssl, char *buf, int sz, void *ctx) +{ + int fd = *(int*)ctx; + int result; + + (void)ssl; + + fd_set rfds; + FD_ZERO(&rfds); + FD_SET(fd, &rfds); + + if (lwip_select(FD_SETSIZE, &rfds, NULL, NULL, NULL) < 0) + { + result = -1; + } + else + { + result = lwip_recv(fd, buf, sz, 0); + } + + return result; +} + +static int sendCallback(WOLFSSL* ssl, char *buf, int sz, void *ctx) +{ + int fd = *(int*)ctx; + int result; + + (void)ssl; + + fd_set wfds; + FD_ZERO(&wfds); + FD_SET(fd, &wfds); + + if (lwip_select(FD_SETSIZE, NULL, &wfds, NULL, NULL) < 0) + { + return -1; + } + else + { + result = lwip_send(fd, buf, sz, 0); + } + + return result; +} + +int WolfSSLConnection::connect(const char* host, const int port) +{ + int result; + + if(sslContext == NULL) + { + LogError("NULL SSL context\r\n"); + result = __LINE__; + } + else + { + if (init_socket(SOCK_STREAM) < 0) + { + LogError("init_socket failed\r\n"); + result = __LINE__; + } + else + { + if (set_address(host, port) != 0) + { + LogError("set_address failed\r\n"); + result = __LINE__; + } + else if (lwip_connect(_sock_fd, (const struct sockaddr *) &_remoteHost, sizeof(_remoteHost)) < 0) + { + close(); + LogError("lwip_connect failed\r\n"); + result = __LINE__; + } + else + { + wolfSSL_SetIOSend(sslContext, &sendCallback); + wolfSSL_SetIORecv(sslContext, &receiveCallback); + + ssl = wolfSSL_new(sslContext); + if(ssl == NULL) + { + LogError("wolfssl new error\r\n"); + result = __LINE__; + } + else + { + wolfSSL_set_fd(ssl, _sock_fd); + + result = wolfSSL_connect(ssl); + if (result != SSL_SUCCESS) + { + LogError("wolfssl connect error=%d\r\n", result); + result = __LINE__; + } + else + { + result = 0; + isConnected = true; + } + } + } + } + } + + return result; +}; + +bool WolfSSLConnection::is_connected(void) +{ + return isConnected; +} + +int WolfSSLConnection::send(char* data, int length) +{ + int result; + + if (!isConnected) + { + result = 0; + } + else + { + result = wolfSSL_write(ssl, data, length); + } + + return result; +} + +int WolfSSLConnection::send_all(char* data, int length) +{ + return send(data, length); +} + +int WolfSSLConnection::receive(char* data, int length) +{ + int result; + + if (!isConnected) + { + result = 0; + } + else + { + result = wolfSSL_read(ssl, data, length); + } + + return result; +} + +int WolfSSLConnection::receive_all(char* data, int length) +{ + return receive(data, length); +} + +bool WolfSSLConnection::close(bool shutdown) +{ + bool result; + + if (!isConnected) + { + result = true; + } + else + { + isConnected = false; + + wolfSSL_CTX_free(sslContext); + result = Socket::close(shutdown) == 0; + } + + return result; +} + +bool WolfSSLConnection::load_certificate(const unsigned char* certificate, size_t size) +{ + bool result; + + if (sslContext == NULL) + { + LogError("NULL SSL context\r\n"); + result = false; + } + else + { + result = (wolfSSL_CTX_load_verify_buffer(sslContext,(unsigned char*)certificate, size, SSL_FILETYPE_PEM) == SSL_SUCCESS); + } + + return result; +} diff --git a/c/sharedutil/adapters/wolfssl_connection.h b/c/sharedutil/adapters/wolfssl_connection.h new file mode 100644 index 00000000..1ce0d1c0 --- /dev/null +++ b/c/sharedutil/adapters/wolfssl_connection.h @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#ifndef WOLFSSL_CONNECTION_H +#define WOLFSSL_CONNECTION_H + +#include "wolfssl/ssl.h" +#include "TCPSocketConnection.h" + +class WolfSSLConnection : public TCPSocketConnection +{ +public: + WolfSSLConnection(); + virtual ~WolfSSLConnection(); + +public: + int connect(const char* host, const int port); + bool is_connected(void); + int send(char* data, int length); + int send_all(char* data, int length); + int receive(char* data, int length); + int receive_all(char* data, int length); + bool close(bool shutdown = true); + bool load_certificate(const unsigned char* certificate, size_t size); + +protected: + WOLFSSL_CTX* sslContext; + WOLFSSL* ssl; + bool isConnected; +}; + +#endif /* WOLFSSL_CONNECTION_H */ diff --git a/c/sharedutil/build/mbed/common_filelist.txt b/c/sharedutil/build/mbed/common_filelist.txt new file mode 100644 index 00000000..03fc5165 --- /dev/null +++ b/c/sharedutil/build/mbed/common_filelist.txt @@ -0,0 +1,8 @@ +..\inc\*.h +..\src\*.c +..\adapters\agenttime_mbed.c +..\adapters\httpapi_mbed.cpp +..\adapters\lock_rtx_mbed.cpp +..\adapters\threadapi_rtx_mbed.cpp +..\adapters\wolfssl_connection.h +..\adapters\wolfssl_connection.cpp diff --git a/c/sharedutil/build/tirtos/package.bld b/c/sharedutil/build/tirtos/package.bld new file mode 100644 index 00000000..fe15ab7c --- /dev/null +++ b/c/sharedutil/build/tirtos/package.bld @@ -0,0 +1,137 @@ +/* + * ======== package.bld ======== + */ + +var Build = xdc.useModule('xdc.bld.BuildEnvironment'); +var Pkg = xdc.useModule('xdc.bld.PackageContents'); + +/* make command to search for the srcs */ +Pkg.makePrologue = "vpath %.c ../../src ../../adapters"; + +/* lib/ is a generated directory that 'xdc clean' should remove */ +Pkg.generatedFiles.$add("lib/"); + +var SRCS = [ + "httpapi_tirtos.c", + "threadapi_pthreads.c", + "lock_pthreads.c", + "agenttime.c", + "base64.c", + "buffer.c", + "certs.c", + "crt_abstractions.c", + "doublylinkedlist.c", + "gballoc.c", + "hmac.c", + "hmacsha256.c", + "httpapiex.c", + "httpapiexsas.c", + "httpheaders.c", + "map.c", + "sastoken.c", + "sha1.c", + "sha224.c", + "sha384-512.c", + "strings.c", + "string_tokenizer.c", + "urlencode.c", + "usha.c", + "vector.c" +]; + +/* Paths to external source libraries */ +xdcargs = java.lang.System.getenv("XDCARGS").split(" "); + +var slIncs = ""; +var ndkIncs = ""; +var wolfsslIncs = ""; +var commonIncs = "-I../../inc "; +var pthreadIncs = ""; + +/* Parse out the XDCARGS options for the library source paths */ +for (x = 0; x < xdcargs.length; x++) { + + if (xdcargs[x].match(/^CC3200SDK=/)) { + slIncs = (xdcargs[x] + "").replace(/'/g, ''); + slIncs = slIncs.substring(slIncs.indexOf('=') + 1); + if (slIncs != "") { + slIncs += "/simplelink"; + slIncs = "-I" + slIncs + " -I" + slIncs + "/include "; + } + } + + if (xdcargs[x].match(/^NDK=/)) { + ndkIncs = (xdcargs[x] + "").replace(/'/g, ''); + ndkIncs = ndkIncs.substring(ndkIncs.indexOf('=') + 1); + if (ndkIncs != "") { + ndkIncs = "-I" + ndkIncs + "/packages/ti/ndk/inc/bsd "; + } + } + + if (xdcargs[x].match(/^BIOS=/)) { + pthreadIncs = (xdcargs[x] + "").replace(/'/g, ''); + pthreadIncs = pthreadIncs.substring(pthreadIncs.indexOf('=') + 1); + if (pthreadIncs != "") { + pthreadIncs = "-I" + pthreadIncs + "/packages/ti/sysbios/posix "; + } + } + + if (xdcargs[x].match(/^WOLFSSL=/)) { + wolfsslIncs = (xdcargs[x] + "").replace(/'/g, ''); + wolfsslIncs = wolfsslIncs.substring(wolfsslIncs.indexOf('=') + 1); + if (wolfsslIncs != "") { + wolfsslIncs = "-I" + wolfsslIncs; + } + } +} + +if (ndkIncs != "") { + + if (wolfsslIncs == "") { + print("Warning: Cannot find WolfSSL directory: '" + wolfsslPath + + "'. Skipping TLS support build."); + wolfsslIncs = ""; + } + + var wolfsslPath = wolfsslIncs.substring(2); + try { + var f = new java.io.File(wolfsslPath); + if (!f.exists()) { + print("Warning: Cannot find WolfSSL directory: '" + wolfsslPath + + "'. Skipping TLS support build."); + wolfsslIncs = ""; + } + } + catch(e) { + print("Warning: Cannot find WolfSSL directory: '" + wolfsslPath + + "'. Skipping TLS support build."); + wolfsslIncs = ""; + } +} + +for (var i = 0; i < Build.targets.length; i++) { + var profile = "release"; + var target = Build.targets[i]; + var extraOpts = commonIncs + pthreadIncs; + + if (slIncs != "") { + Pkg.addLibrary("lib/common_sl", target, { profile: profile, + defs: "-DNET_SL " + extraOpts, incs: slIncs + }).addObjects(SRCS); + } + + if (ndkIncs != "") { + if (wolfsslIncs != "") { + Pkg.addLibrary("lib/common_ndk_wolfssl", target, { + profile: profile, + defs: "-DNET_NDK -DNET_WOLFSSL -DWOLFSSL_TIRTOS " + + extraOpts, + incs: ndkIncs + wolfsslIncs + }).addObjects(SRCS) + } + + Pkg.addLibrary("lib/common_ndk", target, { profile: profile, + defs: "-DNET_NDK " + extraOpts, incs: ndkIncs + }).addObjects(SRCS); + } +} diff --git a/c/sharedutil/build/tirtos/package.xdc b/c/sharedutil/build/tirtos/package.xdc new file mode 100644 index 00000000..72849fcd --- /dev/null +++ b/c/sharedutil/build/tirtos/package.xdc @@ -0,0 +1,5 @@ +/* + * ======== package.xdc ======== + */ +package common.build.tirtos { +} diff --git a/c/sharedutil/devdoc/agenttime_requirements.docm b/c/sharedutil/devdoc/agenttime_requirements.docm new file mode 100644 index 00000000..4a00d3de Binary files /dev/null and b/c/sharedutil/devdoc/agenttime_requirements.docm differ diff --git a/c/sharedutil/devdoc/base64_requirements.docm b/c/sharedutil/devdoc/base64_requirements.docm new file mode 100644 index 00000000..80268b37 Binary files /dev/null and b/c/sharedutil/devdoc/base64_requirements.docm differ diff --git a/c/sharedutil/devdoc/buffer_requirements.docm b/c/sharedutil/devdoc/buffer_requirements.docm new file mode 100644 index 00000000..40a50c5a Binary files /dev/null and b/c/sharedutil/devdoc/buffer_requirements.docm differ diff --git a/c/sharedutil/devdoc/crt_abstractions_requirements.docm b/c/sharedutil/devdoc/crt_abstractions_requirements.docm new file mode 100644 index 00000000..14a25498 Binary files /dev/null and b/c/sharedutil/devdoc/crt_abstractions_requirements.docm differ diff --git a/c/sharedutil/devdoc/doublylinkedlist_requirements.docm b/c/sharedutil/devdoc/doublylinkedlist_requirements.docm new file mode 100644 index 00000000..2d0d9bd5 Binary files /dev/null and b/c/sharedutil/devdoc/doublylinkedlist_requirements.docm differ diff --git a/c/sharedutil/devdoc/gballoc_requirements.docm b/c/sharedutil/devdoc/gballoc_requirements.docm new file mode 100644 index 00000000..eb7ad120 Binary files /dev/null and b/c/sharedutil/devdoc/gballoc_requirements.docm differ diff --git a/c/sharedutil/devdoc/httpapiex_requirements.docm b/c/sharedutil/devdoc/httpapiex_requirements.docm new file mode 100644 index 00000000..a0b923ce Binary files /dev/null and b/c/sharedutil/devdoc/httpapiex_requirements.docm differ diff --git a/c/sharedutil/devdoc/httpapiex_retry_mechanism.vsdx b/c/sharedutil/devdoc/httpapiex_retry_mechanism.vsdx new file mode 100644 index 00000000..634ae69a Binary files /dev/null and b/c/sharedutil/devdoc/httpapiex_retry_mechanism.vsdx differ diff --git a/c/sharedutil/devdoc/httpapiexsas.docm b/c/sharedutil/devdoc/httpapiexsas.docm new file mode 100644 index 00000000..e2af071b Binary files /dev/null and b/c/sharedutil/devdoc/httpapiexsas.docm differ diff --git a/c/sharedutil/devdoc/httpheaders requirements.docm b/c/sharedutil/devdoc/httpheaders requirements.docm new file mode 100644 index 00000000..098d8d99 Binary files /dev/null and b/c/sharedutil/devdoc/httpheaders requirements.docm differ diff --git a/c/sharedutil/devdoc/io_requirements.docm b/c/sharedutil/devdoc/io_requirements.docm new file mode 100644 index 00000000..d7f2eaa0 Binary files /dev/null and b/c/sharedutil/devdoc/io_requirements.docm differ diff --git a/c/sharedutil/devdoc/list_requirements.docm b/c/sharedutil/devdoc/list_requirements.docm new file mode 100644 index 00000000..9aff85c2 Binary files /dev/null and b/c/sharedutil/devdoc/list_requirements.docm differ diff --git a/c/sharedutil/devdoc/lock_requirements.docm b/c/sharedutil/devdoc/lock_requirements.docm new file mode 100644 index 00000000..15ab75d6 Binary files /dev/null and b/c/sharedutil/devdoc/lock_requirements.docm differ diff --git a/c/sharedutil/devdoc/map_requirements.docm b/c/sharedutil/devdoc/map_requirements.docm new file mode 100644 index 00000000..5715faa9 Binary files /dev/null and b/c/sharedutil/devdoc/map_requirements.docm differ diff --git a/c/sharedutil/devdoc/sastoken.docm b/c/sharedutil/devdoc/sastoken.docm new file mode 100644 index 00000000..e65f51b9 Binary files /dev/null and b/c/sharedutil/devdoc/sastoken.docm differ diff --git a/c/sharedutil/devdoc/string_tokenizer_requirements.docm b/c/sharedutil/devdoc/string_tokenizer_requirements.docm new file mode 100644 index 00000000..eaf21e4f Binary files /dev/null and b/c/sharedutil/devdoc/string_tokenizer_requirements.docm differ diff --git a/c/sharedutil/devdoc/strings_requirements.docm b/c/sharedutil/devdoc/strings_requirements.docm new file mode 100644 index 00000000..b1c3f524 Binary files /dev/null and b/c/sharedutil/devdoc/strings_requirements.docm differ diff --git a/c/sharedutil/devdoc/url_encode_requirements.docm b/c/sharedutil/devdoc/url_encode_requirements.docm new file mode 100644 index 00000000..aa7e5159 Binary files /dev/null and b/c/sharedutil/devdoc/url_encode_requirements.docm differ diff --git a/c/sharedutil/inc/agenttime.h b/c/sharedutil/inc/agenttime.h new file mode 100644 index 00000000..3568b05b --- /dev/null +++ b/c/sharedutil/inc/agenttime.h @@ -0,0 +1,55 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/** @file agenttime.h +* @brief Function prototypes for time related functions. +* +* @details These functions are implemented with C standard functions, +* and therefore they are platform independent. But then a platform +* can replace these functions with its own implementation as necessary. +*/ + +#ifndef AGENTTIME_H +#define AGENTTIME_H + +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** @brief Get current calendar time. +* +* @details This function provides the same functionality as the +* standard C @c time() function. +*/ +extern time_t get_time(time_t* currentTime); + +/** @brief Get UTC in @c tm struct. +* +* @details This function provides the same functionality as the +* standard C @c gmtime() function. +*/ +extern struct tm* get_gmtime(time_t* currentTime); + +/** @brief Gets a C-string representation of the given time. +* +* @details This function provides the same functionality as the +* standard C @c ctime() function. +*/ +extern char* get_ctime(time_t* timeToGet); + +/** @brief Gets the difference in seconds between @c stopTime and +* @c startTime. +* +* @details This function provides the same functionality as the +* standard C @c difftime() function. +*/ +extern double get_difftime(time_t stopTime, time_t startTime); + +#ifdef __cplusplus +} +#endif + +#endif // AGENTTIME_H diff --git a/c/sharedutil/inc/base64.h b/c/sharedutil/inc/base64.h new file mode 100644 index 00000000..a6e43763 --- /dev/null +++ b/c/sharedutil/inc/base64.h @@ -0,0 +1,80 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/** @file base64.h +* @brief Prototypes for functions related to encoding/decoding +* a @c buffer using standard base64 encoding. +*/ + +#ifndef BASE64_H +#define BASE64_H + +#include "strings.h" +#include "buffer_.h" + +#ifdef __cplusplus +#include +extern "C" { +#else +#include +#endif + +/** + * @brief Base64 encodes a buffer and returns the resulting string. + * + * @param input The buffer that needs to be base64 encoded. + * + * Base64_Encode takes as a parameter a pointer to a BUFFER. If @p input is @c NULL then + * @c Base64_Encode returns @c NULL. The size of the BUFFER pointed to by @p input may + * be zero. If when allocating memory to produce the encoding a failure occurs, then @c + * Base64_Encode returns @c NULL. Otherwise + * @c Base64_Encode returns a pointer to a STRING. That string contains the + * base 64 encoding of the @p input. This encoding of @p input will not contain embedded + * line feeds. + * + * @return A @c STRING_HANDLE containing the base64 encoding of @p input. + */ +extern STRING_HANDLE Base64_Encode(BUFFER_HANDLE input); + +/** + * @brief Base64 encodes the buffer pointed to by @p source and returns the resulting string. + * + * @param source The buffer that needs to be base64 encoded. + * @param size The size. + * + * This function produces a @c STRING_HANDLE containing the base64 encoding of the + * buffer pointed to by @p source, having the size as given by + * @p size. If @p source is @c NULL then @c Base64_Encode_Bytes returns @c NULL + * If @p source is not @c NULL and @p size is zero, then @c Base64_Encode_Bytes produces + * an empty @c STRING_HANDLE. Otherwise, @c Base64_Encode_Bytes produces a + * @c STRING_HANDLE containing the Base64 representation of the buffer. In case of + * any errors, @c Base64_Encode_Bytes returns @c NULL.]. + * + * @return @c NULL in case an error occurs or a @c STRING_HANDLE containing the base64 encoding + * of @p input. + * + */ +extern STRING_HANDLE Base64_Encode_Bytes(const unsigned char* source, size_t size); + +/** + * @brief Base64 decodes the buffer pointed to by @p source and returns the resulting buffer. + * + * @param source A base64 encoded string buffer. + * + * This function decodes the string pointed at by @p source using base64 decoding and + * returns the resulting buffer. If @p source is @c NULL then + * @c Base64_Decoder returns NULL. If the string pointed to by @p source is zero + * length then the handle returned refers to a zero length buffer. If there is any + * memory allocation failure during the decode or if the source string has an invalid + * length for a base 64 encoded string then @c Base64_Decoder returns @c NULL. + * + * @return A @c BUFFER_HANDLE pointing to a buffer containing the result of base64 decoding @p + * source. + */ +extern BUFFER_HANDLE Base64_Decoder(const char* source); + +#ifdef __cplusplus +} +#endif + +#endif /* BASE64_H */ diff --git a/c/sharedutil/inc/buffer_.h b/c/sharedutil/inc/buffer_.h new file mode 100644 index 00000000..dabbb9fb --- /dev/null +++ b/c/sharedutil/inc/buffer_.h @@ -0,0 +1,36 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#ifndef BUFFER_H +#define BUFFER_H + +#ifdef __cplusplus +#include +extern "C" +{ +#else +#include +#endif + +typedef void* BUFFER_HANDLE; + +extern BUFFER_HANDLE BUFFER_new(void); +extern BUFFER_HANDLE BUFFER_create(const unsigned char* source, size_t size); +extern void BUFFER_delete(BUFFER_HANDLE handle); +extern int BUFFER_pre_build(BUFFER_HANDLE handle, size_t size); +extern int BUFFER_build(BUFFER_HANDLE handle, const unsigned char* source, size_t size); +extern int BUFFER_unbuild(BUFFER_HANDLE handle); +extern int BUFFER_enlarge(BUFFER_HANDLE handle, size_t enlargeSize); +extern int BUFFER_content(BUFFER_HANDLE handle, const unsigned char** content); +extern int BUFFER_size(BUFFER_HANDLE handle, size_t* size); +extern int BUFFER_append(BUFFER_HANDLE handle1, BUFFER_HANDLE handle2); +extern unsigned char* BUFFER_u_char(BUFFER_HANDLE handle); +extern size_t BUFFER_length(BUFFER_HANDLE handle); +extern BUFFER_HANDLE BUFFER_clone(BUFFER_HANDLE handle); + +#ifdef __cplusplus +} +#endif + + +#endif /* BUFFER_H */ diff --git a/c/sharedutil/inc/condition.h b/c/sharedutil/inc/condition.h new file mode 100644 index 00000000..8058cb81 --- /dev/null +++ b/c/sharedutil/inc/condition.h @@ -0,0 +1,69 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#ifndef CONDITION_H +#define CONDITION_H + +#include "macro_utils.h" +#include "lock.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void* COND_HANDLE; + +#define COND_RESULT_VALUES \ + COND_OK, \ + COND_ERROR, \ + COND_TIMEOUT \ + +/** @brief Enumeration specifying the lock status. +*/ +DEFINE_ENUM(COND_RESULT, COND_RESULT_VALUES); + +/** +* @brief This API creates and returns a valid condition handle. +* +* @return A valid @c COND_HANDLE when successful or @c NULL otherwise. +*/ +extern COND_HANDLE Condition_Init(void); + +/** +* @brief unblock all currently working condition. +* +* @param handle A valid handle to the lock. +* +* @return Returns @c COND_OK when the condition object has been +* destroyed and @c COND_ERROR when an error occurs +* and @c COND_TIMEOUT when the handle times out. +*/ +extern COND_RESULT Condition_Post(COND_HANDLE handle); + +/** +* @brief block on the condition handle unti the thread is signalled +* or until the timeout_milliseconds is reached. +* +* @param handle A valid handle to the lock. +* +* @return Returns @c COND_OK when the condition object has been +* destroyed and @c COND_ERROR when an error occurs +* and @c COND_TIMEOUT when the handle times out. +*/ +extern COND_RESULT Condition_Wait(COND_HANDLE handle, LOCK_HANDLE lock, int timeout_milliseconds); + +/** +* @brief The condition instance is deinitialized. +* +* @param handle A valid handle to the condition. +* +* @return Returns @c COND_OK when the condition object has been +* destroyed and @c COND_ERROR when an error occurs. +*/ +extern COND_RESULT Condition_Deinit(COND_HANDLE handle); + +#ifdef __cplusplus +} +#endif + +#endif /* LOCK_H */ diff --git a/c/sharedutil/inc/crt_abstractions.h b/c/sharedutil/inc/crt_abstractions.h new file mode 100644 index 00000000..03539dad --- /dev/null +++ b/c/sharedutil/inc/crt_abstractions.h @@ -0,0 +1,176 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#ifndef CRT_ABSTRACTIONS_H +#define CRT_ABSTRACTIONS_H + +#ifdef __cplusplus +#include +#include +extern "C" { +#else +#include +#include +#endif + +#ifdef _MSC_VER + +#ifdef QUARKGALILEO +#define HAS_STDBOOL +#ifdef __cplusplus +typedef bool _Bool; +#else +/*galileo apparently has _Bool and bool as built in types*/ +#endif +#endif + +#ifndef _WIN32_WCE +#define HAS_STDBOOL +#ifdef __cplusplus +#include +/*because C++ doesn't do anything about _Bool... */ +#define _Bool bool +#else +#include +#endif +#endif +#else +#if defined __STDC_VERSION__ +#if ((__STDC_VERSION__ == 199901L) || (__STDC_VERSION__ == 201112L)) +/*C99 compiler or C11*/ +#define HAS_STDBOOL +#include +#endif +#endif +#endif + +#ifndef HAS_STDBOOL +#ifdef __cplusplus +#define _Bool bool +#else +typedef unsigned char _Bool; +typedef unsigned char bool; +#define false 0 +#define true 1 +#endif +#endif + + +/* Codes_SRS_CRT_ABSTRACTIONS_99_001:[The module shall not redefine the secure functions implemented by Microsoft CRT.] */ +/* Codes_SRS_CRT_ABSTRACTIONS_99_040 : [The module shall still compile when building on a Microsoft platform.] */ +/* Codes_SRS_CRT_ABSTRACTIONS_99_002: [CRTAbstractions module shall expose the following API]*/ +#ifdef _MSC_VER +#else +#include "inttypes.h" + +/* Adding definitions from errno.h & crtdefs.h */ +#if !defined (_TRUNCATE) +#define _TRUNCATE ((size_t)-1) +#endif /* !defined (_TRUNCATE) */ + +#if !defined STRUNCATE +#define STRUNCATE 80 +#endif /* !defined (STRUNCATE) */ + +typedef int errno_t; + +extern int strcpy_s(char* dst, size_t dstSizeInBytes, const char* src); +extern int strcat_s(char* dst, size_t dstSizeInBytes, const char* src); +extern int strncpy_s(char* dst, size_t dstSizeInBytes, const char* src, size_t maxCount); +extern int sprintf_s(char* dst, size_t dstSizeInBytes, const char* format, ...); +#endif + +extern int mallocAndStrcpy_s(char** destination, const char*source); +extern int unsignedIntToString(char* destination, size_t destinationSize, unsigned int value); +extern int size_tToString(char* destination, size_t destinationSize, size_t value); +/*following logic shall define the ISNAN macro*/ +/*if runing on Microsoft Visual C compiler, than ISNAN shall be _isnan*/ +/*else if running on C99 or C11, ISNAN shall be isnan*/ +/*else if running on C89 ... #error and inform user*/ + +#ifdef _MSC_VER +#define ISNAN _isnan +#else +#if defined __STDC_VERSION__ +#if ((__STDC_VERSION__ == 199901L) || (__STDC_VERSION__ == 201112L)) +/*C99 compiler or C11*/ +#define ISNAN isnan +#else +#error update this file to contain the latest C standard. +#endif +#else +#ifdef __cplusplus +/*C++ defines isnan... in C11*/ +#define ISNAN std::isnan +#else +#error unknown (or C89) compiler, provide ISNAN with the same meaning as isnan in C99 standard +#endif + +#endif +#endif + +/*ispositiveinfinity*/ + +#ifdef _MSC_VER +#define ISPOSITIVEINFINITY(x) ((_finite((x))==0) && ((_fpclass((x)) & _FPCLASS_PINF) == _FPCLASS_PINF)) +#else +#if defined __STDC_VERSION__ +#if ((__STDC_VERSION__ == 199901L) || (__STDC_VERSION__ == 201112L)) +/*C99 compiler or C11*/ +#define ISPOSITIVEINFINITY(x) (isinf((x)) && (signbit((x))==0)) +#else +#error update this file to contain the latest C standard. +#endif +#else +#ifdef __cplusplus +#define ISPOSITIVEINFINITY(x) (std::isinf((x)) && (signbit((x))==0)) +#else +#error unknown (or C89) compiler, must provide a definition for ISPOSITIVEINFINITY +#endif +#endif +#endif + +#ifdef _MSC_VER +/*not exactly signbit*/ +#define ISNEGATIVEINFINITY(x) ((_finite((x))==0) && ((_fpclass((x)) & _FPCLASS_NINF) == _FPCLASS_NINF)) +#else +#if defined __STDC_VERSION__ +#if ((__STDC_VERSION__ == 199901L) || (__STDC_VERSION__ == 201112L)) +/*C99 compiler or C11*/ +#define ISNEGATIVEINFINITY(x) (isinf((x)) && (signbit((x))!=0)) +#else +#error update this file to contain the latest C standard. +#endif +#else +#ifdef __cplusplus +#define ISNEGATIVEINFINITY(x) (std::isinf((x)) && (signbit((x)) != 0)) +#else +#error unknown (or C89) compiler, must provide a definition for ISNEGATIVEINFINITY +#endif +#endif +#endif + +#ifdef _MSC_VER +#define INT64_PRINTF "%I64d" +#else +#if defined __STDC_VERSION__ +#if ((__STDC_VERSION__ == 199901L) || (__STDC_VERSION__ == 201112L)) +/*C99 compiler or C11*/ +#define INT64_PRINTF "%" PRId64 "" +#else +#error update this file to contain the latest C standard. +#endif +#else +#ifdef __cplusplus +#define INT64_PRINTF "%" PRId64 "" +#else +#error unknown (or C89) compiler, provide INT64_PRINTF with the same meaning as PRIdN in C99 standard +#endif +#endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* CRT_ABSTRACTIONS_H */ diff --git a/c/sharedutil/inc/doublylinkedlist.h b/c/sharedutil/inc/doublylinkedlist.h new file mode 100644 index 00000000..4a7e020e --- /dev/null +++ b/c/sharedutil/inc/doublylinkedlist.h @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#ifndef DOUBLYLINKEDLIST_H +#define DOUBLYLINKEDLIST_H + +#ifdef __cplusplus +#include +extern "C" +{ +#else +#include +#endif + +typedef struct DLIST_ENTRY_TAG +{ + struct DLIST_ENTRY_TAG *Flink; + struct DLIST_ENTRY_TAG *Blink; +} DLIST_ENTRY, *PDLIST_ENTRY; + +extern void DList_InitializeListHead(PDLIST_ENTRY listHead); +extern int DList_IsListEmpty(const PDLIST_ENTRY listHead); +extern void DList_InsertTailList(PDLIST_ENTRY listHead, PDLIST_ENTRY listEntry); +extern void DList_InsertHeadList(PDLIST_ENTRY listHead, PDLIST_ENTRY listEntry); +extern void DList_AppendTailList(PDLIST_ENTRY listHead, PDLIST_ENTRY ListToAppend); +extern int DList_RemoveEntryList(PDLIST_ENTRY listEntry); +extern PDLIST_ENTRY DList_RemoveHeadList(PDLIST_ENTRY listHead); + +// +// Calculate the address of the base of the structure given its type, and an +// address of a field within the structure. +// +#define containingRecord(address, type, field) ((type *)((uintptr_t)(address) - offsetof(type,field))) + +#ifdef __cplusplus +} +#else +#endif + +#endif /* DOUBLYLINKEDLIST_H */ diff --git a/c/sharedutil/inc/gballoc.h b/c/sharedutil/inc/gballoc.h new file mode 100644 index 00000000..684b141b --- /dev/null +++ b/c/sharedutil/inc/gballoc.h @@ -0,0 +1,66 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#ifndef GBALLOC_H +#define GBALLOC_H + + +#ifdef __cplusplus +#include +extern "C" +{ +#else +#include +#endif +#ifdef _CRTDBG_MAP_ALLOC +#include +#endif + +/* all translation units that need memory measurement need to have GB_MEASURE_MEMORY_FOR_THIS defined */ +/* GB_DEBUG_ALLOC is the switch that turns the measurement on/off, so that it is not on always */ +#if defined(GB_DEBUG_ALLOC) + +extern int gballoc_init(void); +extern void gballoc_deinit(void); +extern void* gballoc_malloc(size_t size); +extern void* gballoc_calloc(size_t nmemb, size_t size); +extern void* gballoc_realloc(void* ptr, size_t size); +extern void gballoc_free(void* ptr); + +extern size_t gballoc_getMaximumMemoryUsed(void); +extern size_t gballoc_getCurrentMemoryUsed(void); + +/* if GB_MEASURE_MEMORY_FOR_THIS is defined then we want to redirect memory allocation functions to gballoc_xxx functions */ +#ifdef GB_MEASURE_MEMORY_FOR_THIS +#if defined(_CRTDBG_MAP_ALLOC) && defined(_DEBUG) +#undef _malloc_dbg +#undef _calloc_dbg +#undef _realloc_dbg +#undef _free_dbg +#define _malloc_dbg(size, ...) gballoc_malloc(size) +#define _calloc_dbg(nmemb, size, ...) gballoc_calloc(nmemb, size) +#define _realloc_dbg(ptr, size, ...) gballoc_realloc(ptr, size) +#define _free_dbg(ptr, ...) gballoc_free(ptr) +#else +#define malloc gballoc_malloc +#define calloc gballoc_calloc +#define realloc gballoc_realloc +#define free gballoc_free +#endif +#endif + +#else /* GB_DEBUG_ALLOC */ + +#define gballoc_init() 0 +#define gballoc_deinit() ((void)0) + +#define gballoc_getMaximumMemoryUsed() SIZE_MAX +#define gballoc_getCurrentMemoryUsed() SIZE_MAX + +#endif /* GB_DEBUG_ALLOC */ + +#ifdef __cplusplus +} +#endif + +#endif /* GBALLOC_H */ diff --git a/c/sharedutil/inc/hmac.h b/c/sharedutil/inc/hmac.h new file mode 100644 index 00000000..42d26337 --- /dev/null +++ b/c/sharedutil/inc/hmac.h @@ -0,0 +1,21 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#ifndef HMAC_H +#define HMAC_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "sha.h" + +extern int hmac(SHAversion whichSha, const unsigned char *text, int text_len, + const unsigned char *key, int key_len, + uint8_t digest[USHAMaxHashSize]); + +#ifdef __cplusplus +} +#endif + +#endif /* HMAC_H */ diff --git a/c/sharedutil/inc/hmacsha256.h b/c/sharedutil/inc/hmacsha256.h new file mode 100644 index 00000000..b7a373aa --- /dev/null +++ b/c/sharedutil/inc/hmacsha256.h @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#ifndef HMACSHA256_H +#define HMACSHA256_H + +#include "macro_utils.h" +#include "buffer_.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define HMACSHA256_RESULT_VALUES \ + HMACSHA256_OK, \ + HMACSHA256_INVALID_ARG, \ + HMACSHA256_ERROR + +DEFINE_ENUM(HMACSHA256_RESULT, HMACSHA256_RESULT_VALUES) + +extern HMACSHA256_RESULT HMACSHA256_ComputeHash(const unsigned char* key, size_t keyLen, const unsigned char* payload, size_t payloadLen, BUFFER_HANDLE hash); + +#ifdef __cplusplus +} +#endif + +#endif /* HMACSHA256_H */ diff --git a/c/sharedutil/inc/httpapi.h b/c/sharedutil/inc/httpapi.h new file mode 100644 index 00000000..07056117 --- /dev/null +++ b/c/sharedutil/inc/httpapi.h @@ -0,0 +1,194 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/** @file httpapi.h + * @brief This module implements the standard HTTP API used by the C IoT client + * library. + * + * @details For example, on the Windows platform the HTTP API code uses + * WinHTTP and for Linux it uses curl and so forth. HTTPAPI must support + * HTTPs (HTTP+SSL). + */ + +#ifndef HTTPAPI_H +#define HTTPAPI_H + +#include "httpheaders.h" +#include "macro_utils.h" +#include "buffer_.h" + +#ifdef __cplusplus +#include +extern "C" { +#else +#include +#endif + +typedef void* HTTP_HANDLE; + +#define AMBIGUOUS_STATUS_CODE (300) + +#define HTTPAPI_RESULT_VALUES \ +HTTPAPI_OK, \ +HTTPAPI_INVALID_ARG, \ +HTTPAPI_ERROR, \ +HTTPAPI_OPEN_REQUEST_FAILED, \ +HTTPAPI_SET_OPTION_FAILED, \ +HTTPAPI_SEND_REQUEST_FAILED, \ +HTTPAPI_RECEIVE_RESPONSE_FAILED, \ +HTTPAPI_QUERY_HEADERS_FAILED, \ +HTTPAPI_QUERY_DATA_AVAILABLE_FAILED, \ +HTTPAPI_READ_DATA_FAILED, \ +HTTPAPI_ALREADY_INIT, \ +HTTPAPI_NOT_INIT, \ +HTTPAPI_HTTP_HEADERS_FAILED, \ +HTTPAPI_STRING_PROCESSING_ERROR, \ +HTTPAPI_ALLOC_FAILED, \ +HTTPAPI_INIT_FAILED, \ +HTTPAPI_INSUFFICIENT_RESPONSE_BUFFER, \ +HTTPAPI_SET_TIMEOUTS_FAILED \ + +/** @brief Enumeration specifying the possible return values for the APIs in + * this module. + */ +DEFINE_ENUM(HTTPAPI_RESULT, HTTPAPI_RESULT_VALUES); + +#define HTTPAPI_REQUEST_TYPE_VALUES\ + HTTPAPI_REQUEST_GET, \ + HTTPAPI_REQUEST_POST, \ + HTTPAPI_REQUEST_PUT, \ + HTTPAPI_REQUEST_DELETE, \ + HTTPAPI_REQUEST_PATCH \ + +/** @brief Enumeration specifying the HTTP request verbs accepted by + * the HTTPAPI module. + */ +DEFINE_ENUM(HTTPAPI_REQUEST_TYPE, HTTPAPI_REQUEST_TYPE_VALUES); + +/** + * @brief Global initialization for the HTTP API component. + * + * Platform specific implementations are expected to initialize + * the underlying HTTP API stacks. + * + * @return @c HTTPAPI_OK if initialization is successful or an error + * code in case it fails. + */ +extern HTTPAPI_RESULT HTTPAPI_Init(void); + +/** @brief Free resources allocated in ::HTTPAPI_Init. */ +extern void HTTPAPI_Deinit(void); + +/** + * @brief Creates an HTTPS connection to the host specified by the @p + * hostName parameter. + * + * @param hostName Name of the host. + * + * This function returns a handle to the newly created connection. + * You can use the handle in subsequent calls to execute specific + * HTTP calls using ::HTTPAPI_ExecuteRequest. + * + * @return A @c HTTP_HANDLE to the newly created connection or @c NULL in + * case an error occurs. + */ +extern HTTP_HANDLE HTTPAPI_CreateConnection(const char* hostName); + +/** + * @brief Closes a connection created with ::HTTPAPI_CreateConnection. + * + * @param handle The handle to the HTTP connection created via ::HTTPAPI_CreateConnection. + * + * All resources allocated by ::HTTPAPI_CreateConnection should be + * freed in ::HTTPAPI_CloseConnection. + */ +extern void HTTPAPI_CloseConnection(HTTP_HANDLE handle); + +/** + * @brief Sends the HTTP request to the host and handles the response for + * the HTTP call. + * + * @param handle The handle to the HTTP connection created + * via ::HTTPAPI_CreateConnection. + * @param requestType Specifies which HTTP method is used (GET, + * POST, DELETE, PUT, PATCH). + * @param relativePath Specifies the relative path of the URL + * excluding the host name. + * @param httpHeadersHandle Specifies a set of HTTP headers (name-value + * pairs) to be added to the + * HTTP request. The @p httpHeadersHandle + * handle can be created and setup with + * the proper name-value pairs by using the + * HTTPHeaders APIs available in @c + * HTTPHeaders.h. + * @param content Specifies a pointer to the request body. + * This value is optional and can be @c NULL. + * @param contentLength Specifies the request body size (this is + * typically added into the HTTP headers as + * the Content-Length header). This value is + * optional and can be 0. + * @param statusCode This is an out parameter, where + * ::HTTPAPI_ExecuteRequest returns the status + * code from the HTTP response (200, 201, 400, + * 401, etc.) + * @param responseHeadersHandle This is an HTTP headers handle to which + * ::HTTPAPI_ExecuteRequest must add all the + * HTTP response headers so that the caller of + * ::HTTPAPI_ExecuteRequest can inspect them. + * You can manipulate @p responseHeadersHandle + * by using the HTTPHeaders APIs available in + * @c HTTPHeaders.h + * @param responseContent This is a buffer that must be filled by + * ::HTTPAPI_ExecuteRequest with the contents + * of the HTTP response body. The buffer size + * must be increased by the + * ::HTTPAPI_ExecuteRequest implementation in + * order to fit the response body. + * ::HTTPAPI_ExecuteRequest must also handle + * chunked transfer encoding for HTTP responses. + * To manipulate the @p responseContent buffer, + * use the APIs available in @c Strings.h. + * + * @return @c HTTPAPI_OK if the API call is successful or an error + * code in case it fails. + */ +extern HTTPAPI_RESULT HTTPAPI_ExecuteRequest(HTTP_HANDLE handle, HTTPAPI_REQUEST_TYPE requestType, const char* relativePath, + HTTP_HEADERS_HANDLE httpHeadersHandle, const unsigned char* content, + size_t contentLength, unsigned int* statusCode, + HTTP_HEADERS_HANDLE responseHeadersHandle, BUFFER_HANDLE responseContent); + +/** + * @brief Sets the option named @p optionName bearing the value + * @p value for the HTTP_HANDLE @p handle. + * + * @param handle The handle to the HTTP connection created via + * ::HTTPAPI_CreateConnection. + * @param optionName A @c NULL terminated string representing the name + * of the option. + * @param value A pointer to the value for the option. + * + * @return @c HTTPAPI_OK if initialization is successful or an error + * code in case it fails. + */ +extern HTTPAPI_RESULT HTTPAPI_SetOption(HTTP_HANDLE handle, const char* optionName, const void* value); + +/** + * @brief Clones the option named @p optionName bearing the value @p value + * into the pointer @p savedValue. + * + * @param optionName A @c NULL terminated string representing the name of + * the option + * @param value A pointer to the value of the option. + * @param savedValue This pointer receives the copy of the value of the + * option. The copy needs to be free-able. + * + * @return @c HTTPAPI_OK if initialization is successful or an error + * code in case it fails. + */ +extern HTTPAPI_RESULT HTTPAPI_CloneOption(const char* optionName, const void* value, const void** savedValue); + +#ifdef __cplusplus +} +#endif + +#endif /* HTTPAPI_H */ diff --git a/c/sharedutil/inc/httpapiex.h b/c/sharedutil/inc/httpapiex.h new file mode 100644 index 00000000..58afd880 --- /dev/null +++ b/c/sharedutil/inc/httpapiex.h @@ -0,0 +1,105 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/** @file httpapiex.h +* @brief This is a utility module that provides HTTP requests with +* build-in retry capabilities. +* +* @details HTTAPIEX is a utility module that provides HTTP requests with build-in +* retry capability to an HTTP server. Features over "regular" HTTPAPI include: +* - Optional parameters +* - Implementation independent +* - Retry mechanism +* - Persistent options +*/ + +#ifndef HTTPAPIEX_H +#define HTTPAPIEX_H + +#include "macro_utils.h" +#include "httpapi.h" + +#ifdef __cplusplus +#include +extern "C" { +#else +#include +#endif + +typedef void* HTTPAPIEX_HANDLE; + +#define HTTPAPIEX_RESULT_VALUES \ + HTTPAPIEX_OK, \ + HTTPAPIEX_ERROR, \ + HTTPAPIEX_INVALID_ARG, \ + HTTPAPIEX_RECOVERYFAILED +/*to be continued*/ + +/** @brief Enumeration specifying the status of calls to various APIs in this module. +*/ +DEFINE_ENUM(HTTPAPIEX_RESULT, HTTPAPIEX_RESULT_VALUES); + +/** + * @brief Creates an @c HTTPAPIEX_HANDLE that can be used in further calls. + * + * @param hostName Pointer to a null-terminated string that contains the host name + * of an HTTP server. + * + * If @p hostName is @c NULL then @c HTTPAPIEX_Create returns @c NULL. The @p + * hostName value is saved and associated with the returned handle. If creating + * the handle fails for any reason, then @c HTTAPIEX_Create returns @c NULL. + * Otherwise, @c HTTPAPIEX_Create returns an @c HTTAPIEX_HANDLE suitable for + * further calls to the module. + * + * @return An @c HTTAPIEX_HANDLE suitable for further calls to the module. + */ +extern HTTPAPIEX_HANDLE HTTPAPIEX_Create(const char* hostName); + +/** + * @brief Tries to execute an HTTP request. + * + * @param handle A valid @c HTTPAPIEX_HANDLE value. + * @param requestType A value from the ::HTTPAPI_REQUEST_TYPE enum. + * @param relativePath Relative path to send the request to on the server. + * @param requestHttpHeadersHandle Handle to the request HTTP headers. + * @param requestContent The request content. + * @param statusCode If non-null, the HTTP status code is written to this + * pointer. + * @param responseHttpHeadersHandle Handle to the response HTTP headers. + * @param responseContent The response content. + * + * @c HTTPAPIEX_ExecuteRequest tries to execute an HTTP request of type @p + * requestType, on the server's @p relativePath, pushing the request HTTP + * headers @p requestHttpHeadersHandle, having the content of the request + * as pointed to by @p requestContent. If successful, @c HTTAPIEX_ExecuteRequest + * writes in the out @p parameter statusCode the HTTP status, populates the @p + * responseHeadersHandle with the response headers and copies the response body + * to @p responseContent. + * + * @return An @c HTTAPIEX_HANDLE suitable for further calls to the module. + */ +extern HTTPAPIEX_RESULT HTTPAPIEX_ExecuteRequest(HTTPAPIEX_HANDLE handle, HTTPAPI_REQUEST_TYPE requestType, const char* relativePath, HTTP_HEADERS_HANDLE requestHttpHeadersHandle, BUFFER_HANDLE requestContent, unsigned int* statusCode, HTTP_HEADERS_HANDLE responseHttpHeadersHandle, BUFFER_HANDLE responseContent); + +/** + * @brief Frees all resources used by the @c HTTPAPIEX_HANDLE object. + * + * @param handle The @c HTTPAPIEX_HANDLE object to be freed. + */ +extern void HTTPAPIEX_Destroy(HTTPAPIEX_HANDLE handle); + +/** + * @brief Sets the option @p optionName to the value pointed to by @p value. + * + * @param handle The @c HTTPAPIEX_HANDLE representing this session. + * @param optionName Name of the option. + * @param value The value to be set for the option. + * + * @return An @c HTTPAPIEX_RESULT indicating the status of the call. + */ +extern HTTPAPIEX_RESULT HTTPAPIEX_SetOption(HTTPAPIEX_HANDLE handle, const char* optionName, const void* value); + +#ifdef __cplusplus +} +#endif + +#endif /* HTTPAPIEX_H */ diff --git a/c/sharedutil/inc/httpapiexsas.h b/c/sharedutil/inc/httpapiexsas.h new file mode 100644 index 00000000..282ba02d --- /dev/null +++ b/c/sharedutil/inc/httpapiexsas.h @@ -0,0 +1,29 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#ifndef HTTPAPIEX_SAS_H +#define HTTPAPIEX_SAS_H + +#include "strings.h" +#include "buffer_.h" +#include "httpheaders.h" +#include "httpapiex.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef void* HTTPAPIEX_SAS_HANDLE; + +extern HTTPAPIEX_SAS_HANDLE HTTPAPIEX_SAS_Create(STRING_HANDLE key, STRING_HANDLE uriResource, STRING_HANDLE keyName); + +extern void HTTPAPIEX_SAS_Destroy(HTTPAPIEX_SAS_HANDLE handle); + +extern HTTPAPIEX_RESULT HTTPAPIEX_SAS_ExecuteRequest(HTTPAPIEX_SAS_HANDLE sasHandle, HTTPAPIEX_HANDLE handle, HTTPAPI_REQUEST_TYPE requestType, const char* relativePath, HTTP_HEADERS_HANDLE requestHttpHeadersHandle, BUFFER_HANDLE requestContent, unsigned int* statusCode, HTTP_HEADERS_HANDLE responseHeadersHandle, BUFFER_HANDLE responseContent); + +#ifdef __cplusplus +} +#endif + +#endif /* HTTPAPIEX_SAS_H */ diff --git a/c/sharedutil/inc/httpheaders.h b/c/sharedutil/inc/httpheaders.h new file mode 100644 index 00000000..a387d8c6 --- /dev/null +++ b/c/sharedutil/inc/httpheaders.h @@ -0,0 +1,157 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/** @file httpheaders.h +* @brief This is a utility module that handles HTTP message-headers. +* +* @details An application would use ::HTTPHeaders_Alloc to create a new set of HTTP headers. +* After getting the handle, the application would build in several headers by +* consecutive calls to ::HTTPHeaders_AddHeaderNameValuePair. When the headers are +* constructed, the application can retrieve the stored data by calling one of the +* following functions: +* - ::HTTPHeaders_FindHeaderValue - when the name of the header is known and it +* wants to know the value of that header +* - ::HTTPHeaders_GetHeaderCount - when the application needs to know the count +* of all the headers +* - ::HTTPHeaders_GetHeader - when the application needs to retrieve the +* name + ": " + value string based on an index. +*/ + +#ifndef HTTPHEADERS_H +#define HTTPHEADERS_H + +#include "macro_utils.h" + +#ifdef __cplusplus +#include +extern "C" { +#else +#include +#endif + +/*Codes_SRS_HTTP_HEADERS_99_001:[ HttpHeaders shall have the following interface]*/ + +#define HTTP_HEADERS_RESULT_VALUES \ +HTTP_HEADERS_OK, \ +HTTP_HEADERS_INVALID_ARG, \ +HTTP_HEADERS_ALLOC_FAILED, \ +HTTP_HEADERS_INSUFFICIENT_BUFFER, \ +HTTP_HEADERS_ERROR \ + +/** @brief Enumeration specifying the status of calls to various APIs in this module. +*/ +DEFINE_ENUM(HTTP_HEADERS_RESULT, HTTP_HEADERS_RESULT_VALUES); +typedef void* HTTP_HEADERS_HANDLE; + +/** + * @brief Produces a @c HTTP_HANDLE that can later be used in subsequent calls to the module. + * + * This function returns @c NULL in case an error occurs. After successful execution + * ::HTTPHeaders_GetHeaderCount will report @c 0 existing headers. + * + * @return A HTTP_HEADERS_HANDLE representing the newly created collection of HTTP headers. + */ +extern HTTP_HEADERS_HANDLE HTTPHeaders_Alloc(void); + +/** + * @brief De-allocates the data structures allocated by previous API calls to the same handle. + * + * @param httpHeadersHandle A valid @c HTTP_HEADERS_HANDLE value. + */ +extern void HTTPHeaders_Free(HTTP_HEADERS_HANDLE httpHeadersHandle); + +/** + * @brief Adds a header record from the @p name and @p value parameters. + * + * @param httpHeadersHandle A valid @c HTTP_HEADERS_HANDLE value. + * @param name The name of the HTTP header to add. It is invalid for + * the name to include the ':' character or character codes + * outside the range 33-126. + * @param value The value to be assigned to the header. + * + * The function stores the @c name:value pair in such a way that when later + * retrieved by a call to ::HTTPHeaders_GetHeader it will return a string + * that is @c strcmp equal to @c name+": "+value. If the name already exists + * in the collection of headers, the function concatenates the new value + * after the existing value, separated by a comma and a space as in: + * old-value+", "+new-value. + * + * @return Returns @c HTTP_HEADERS_OK when execution is successful or an error code from + * the ::HTTPAPIEX_RESULT enum. + */ +extern HTTP_HEADERS_RESULT HTTPHeaders_AddHeaderNameValuePair(HTTP_HEADERS_HANDLE httpHeadersHandle, const char* name, const char* value); + +/** + * @brief This API performs exactly the same as ::HTTPHeaders_AddHeaderNameValuePair + * except that if the header name already exists then the already existing value + * will be replaced as opposed to being concatenated to. + * + * @param httpHeadersHandle A valid @c HTTP_HEADERS_HANDLE value. + * @param name The name of the HTTP header to add/replace. It is invalid for + * the name to include the ':' character or character codes + * outside the range 33-126. + * @param value The value to be assigned to the header. + * + * @return Returns @c HTTP_HEADERS_OK when execution is successful or an error code from + * the ::HTTPAPIEX_RESULT enum. + */ +extern HTTP_HEADERS_RESULT HTTPHeaders_ReplaceHeaderNameValuePair(HTTP_HEADERS_HANDLE httpHeadersHandle, const char* name, const char* value); + +/** + * @brief Retrieves the value for a previously stored name. + * + * @param httpHeadersHandle A valid @c HTTP_HEADERS_HANDLE value. + * @param name The name of the HTTP header to find. + * + * @return The return value points to a string that shall be @c strcmp equal + * to the original stored string. + */ +extern const char* HTTPHeaders_FindHeaderValue(HTTP_HEADERS_HANDLE httpHeadersHandle, const char* name); + +/** + * @brief This API retrieves the number of stored headers. + * + * @param httpHeadersHandle A valid @c HTTP_HEADERS_HANDLE value. + * @param headersCount If non-null, the API writes the number of + * into the memory pointed at by this parameter. + * + * @return Returns @c HTTP_HEADERS_OK when execution is successful or + * @c HTTP_HEADERS_ERROR when an error occurs. + */ +extern HTTP_HEADERS_RESULT HTTPHeaders_GetHeaderCount(HTTP_HEADERS_HANDLE httpHeadersHandle, size_t* headersCount); + +/** + * @brief This API retrieves the string name+": "+value for the header + * element at the given @p index. + * + * @param handle A valid @c HTTP_HEADERS_HANDLE value. + * @param index Zero-based index of the item in the + * headers collection. + * @param destination If non-null, the header value is written into a + * new string a pointer to which is written into this + * parameters. It is the caller's responsibility to free + * this memory. + * + * @return Returns @c HTTP_HEADERS_OK when execution is successful or + * @c HTTP_HEADERS_ERROR when an error occurs. + */ +extern HTTP_HEADERS_RESULT HTTPHeaders_GetHeader(HTTP_HEADERS_HANDLE handle, size_t index, char** destination); + +/** + * @brief This API produces a clone of the @p handle parameter. + * + * @param handle A valid @c HTTP_HEADERS_HANDLE value. + * + * If @p handle is not @c NULL this function clones the content + * of the handle to a new handle and returns it. + * + * @return A @c HTTP_HEADERS_HANDLE containing a cloned copy of the + * contents of @p handle. + */ +extern HTTP_HEADERS_HANDLE HTTPHeaders_Clone(HTTP_HEADERS_HANDLE handle); + +#ifdef __cplusplus +} +#endif + +#endif /* HTTPHEADERS_H */ diff --git a/c/sharedutil/inc/io.h b/c/sharedutil/inc/io.h new file mode 100644 index 00000000..2a579b34 --- /dev/null +++ b/c/sharedutil/inc/io.h @@ -0,0 +1,58 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#ifndef IO_H +#define IO_H + +#include "iot_logging.h" + +#ifdef __cplusplus +#include +extern "C" { +#else +#include +#endif /* __cplusplus */ + + typedef void* IO_HANDLE; + typedef void* CONCRETE_IO_HANDLE; + + typedef enum IO_STATE_TAG + { + IO_STATE_NOT_OPEN, + IO_STATE_OPENING, + IO_STATE_OPEN, + IO_STATE_ERROR + } IO_STATE; + + typedef void(*ON_BYTES_RECEIVED)(void* context, const void* buffer, size_t size); + typedef void(*ON_IO_STATE_CHANGED)(void* context, IO_STATE new_io_state, IO_STATE previous_io_state); + + typedef CONCRETE_IO_HANDLE(*IO_CREATE)(void* io_create_parameters, LOGGER_LOG logger_log); + typedef void(*IO_DESTROY)(CONCRETE_IO_HANDLE handle); + typedef int(*IO_OPEN)(CONCRETE_IO_HANDLE handle, ON_BYTES_RECEIVED on_bytes_received, ON_IO_STATE_CHANGED on_io_state_changed, void* callback_context); + typedef int(*IO_CLOSE)(CONCRETE_IO_HANDLE handle); + typedef int(*IO_SEND)(CONCRETE_IO_HANDLE handle, const void* buffer, size_t size); + typedef void(*IO_DOWORK)(CONCRETE_IO_HANDLE handle); + + typedef struct IO_INTERFACE_DESCRIPTION_TAG + { + IO_CREATE concrete_io_create; + IO_DESTROY concrete_io_destroy; + IO_OPEN concrete_io_open; + IO_CLOSE concrete_io_close; + IO_SEND concrete_io_send; + IO_DOWORK concrete_io_dowork; + } IO_INTERFACE_DESCRIPTION; + + extern IO_HANDLE io_create(const IO_INTERFACE_DESCRIPTION* io_interface_description, const void* io_create_parameters, LOGGER_LOG logger_log); + extern void io_destroy(IO_HANDLE handle); + extern int io_open(IO_HANDLE handle, ON_BYTES_RECEIVED on_bytes_received, ON_IO_STATE_CHANGED on_io_state_changed, void* callback_context); + extern int io_close(IO_HANDLE handle); + extern int io_send(IO_HANDLE handle, const void* buffer, size_t size); + extern void io_dowork(IO_HANDLE handle); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* IO_H */ diff --git a/c/sharedutil/inc/iot_logging.h b/c/sharedutil/inc/iot_logging.h new file mode 100644 index 00000000..2222b6eb --- /dev/null +++ b/c/sharedutil/inc/iot_logging.h @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#ifndef LOGGING_H +#define LOGGING_H +#include +#include "agenttime.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define STRINGIFY(a) (#a) + +typedef void(*LOGGER_LOG)(unsigned int options, char* format, ...); + +#define LOG_LINE 0x01 + +#define LogInfo(...) (void)printf("Info: " __VA_ARGS__) + +#define LOG(logger, ...) if (logger != NULL) logger(__VA_ARGS__) + +#if defined _MSC_VER +#define LogError(FORMAT, ...) { time_t t = time(NULL); (void)fprintf(stderr,"Error: Time:%.24s File:%s Func:%s Line:%d " FORMAT, ctime(&t), __FILE__, __FUNCDNAME__, __LINE__, __VA_ARGS__); } +#else +#define LogError(FORMAT, ...) { time_t t = time(NULL); (void)fprintf(stderr,"Error: Time:%.24s File:%s Func:%s Line:%d " FORMAT, ctime(&t), __FILE__, __func__, __LINE__, ##__VA_ARGS__); } +#endif + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* LOGGING_H */ diff --git a/c/sharedutil/inc/list.h b/c/sharedutil/inc/list.h new file mode 100644 index 00000000..11af6219 --- /dev/null +++ b/c/sharedutil/inc/list.h @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#ifndef LIST_H +#define LIST_H + +#ifdef __cplusplus +extern "C" { +#include "cstdbool" +#else +#include "stdbool.h" +#endif /* __cplusplus */ + + typedef void* LIST_HANDLE; + typedef void* LIST_ITEM_HANDLE; + typedef bool (*LIST_MATCH_FUNCTION)(LIST_ITEM_HANDLE list_item, const void* match_context); + + extern LIST_HANDLE list_create(void); + extern void list_destroy(LIST_HANDLE handle); + extern int list_add(LIST_HANDLE handle, const void* item); + extern LIST_ITEM_HANDLE list_get_head_item(LIST_HANDLE handle); + extern LIST_ITEM_HANDLE list_get_next_item(LIST_ITEM_HANDLE item_handle); + extern const void* list_item_get_value(LIST_ITEM_HANDLE item_handle); + extern LIST_ITEM_HANDLE list_find(LIST_HANDLE handle, LIST_MATCH_FUNCTION match_function, const void* match_context); + extern int list_remove_matching_item(LIST_HANDLE handle, LIST_MATCH_FUNCTION match_function, const void* match_context); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* LIST_H */ diff --git a/c/sharedutil/inc/lock.h b/c/sharedutil/inc/lock.h new file mode 100644 index 00000000..173a47da --- /dev/null +++ b/c/sharedutil/inc/lock.h @@ -0,0 +1,76 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/** @file lock.h +* @brief A minimalistic platform agnostic lock abstraction for thread +* synchronization. +* @details The Lock component is implemented in order to achieve thread +* synchronization, as we may have a requirement to consume locks +* across different platforms. This component exposes some generic +* APIs so that it can be extended for platform specific +* implementations. +*/ + +#ifndef LOCK_H +#define LOCK_H + +#include "macro_utils.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void* LOCK_HANDLE; + +#define LOCK_RESULT_VALUES \ + LOCK_OK, \ + LOCK_ERROR \ + +/** @brief Enumeration specifying the lock status. +*/ +DEFINE_ENUM(LOCK_RESULT, LOCK_RESULT_VALUES); + +/** + * @brief This API creates and returns a valid lock handle. + * + * @return A valid @c LOCK_HANDLE when successful or @c NULL otherwise. + */ +extern LOCK_HANDLE Lock_Init(void); + +/** + * @brief Acquires a lock on the given lock handle. Uses platform + * specific mutex primitives in its implementation. + * + * @param handle A valid handle to the lock. + * + * @return Returns @c LOCK_OK when a lock has been acquired and + * @c LOCK_ERROR when an error occurs. + */ +extern LOCK_RESULT Lock(LOCK_HANDLE handle); + +/** + * @brief Releases the lock on the given lock handle. Uses platform + * specific mutex primitives in its implementation. + * + * @param handle A valid handle to the lock. + * + * @return Returns @c LOCK_OK when the lock has been released and + * @c LOCK_ERROR when an error occurs. + */ +extern LOCK_RESULT Unlock(LOCK_HANDLE handle); + +/** + * @brief The lock instance is destroyed. + * + * @param handle A valid handle to the lock. + * + * @return Returns @c LOCK_OK when the lock object has been + * destroyed and @c LOCK_ERROR when an error occurs. + */ +extern LOCK_RESULT Lock_Deinit(LOCK_HANDLE handle); + +#ifdef __cplusplus +} +#endif + +#endif /* LOCK_H */ diff --git a/c/sharedutil/inc/macro_utils.h b/c/sharedutil/inc/macro_utils.h new file mode 100644 index 00000000..2763b004 --- /dev/null +++ b/c/sharedutil/inc/macro_utils.h @@ -0,0 +1,10996 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*THIS FILE IS GENERATED*/ +/*DO NOT EDIT BY HAND!!!*/ +/*instead edit macro_utils.tt */ + +#ifndef MACRO_UTILS_H +#define MACRO_UTILS_H + +#include + +#define TOSTRING_(x) #x +#define TOSTRING(x) TOSTRING_(x) + +#define IFCOMMA(N) C2(IFCOMMA_, N) +#define IFCOMMA_0 +#define IFCOMMA_2 +#define IFCOMMA_4 , +#define IFCOMMA_6 , +#define IFCOMMA_8 , +#define IFCOMMA_10 , +#define IFCOMMA_12 , +#define IFCOMMA_14 , +#define IFCOMMA_16 , +#define IFCOMMA_18 , +#define IFCOMMA_20 , +#define IFCOMMA_22 , +#define IFCOMMA_24 , +#define IFCOMMA_26 , +#define IFCOMMA_28 , +#define IFCOMMA_30 , +#define IFCOMMA_32 , +#define IFCOMMA_34 , +#define IFCOMMA_36 , +#define IFCOMMA_38 , +#define IFCOMMA_40 , +#define IFCOMMA_42 , +#define IFCOMMA_44 , +#define IFCOMMA_46 , +#define IFCOMMA_48 , +#define IFCOMMA_50 , +#define IFCOMMA_52 , +#define IFCOMMA_54 , +#define IFCOMMA_56 , +#define IFCOMMA_58 , +#define IFCOMMA_60 , +#define IFCOMMA_62 , +#define IFCOMMA_64 , +#define IFCOMMA_66 , +#define IFCOMMA_68 , +#define IFCOMMA_70 , +#define IFCOMMA_72 , +#define IFCOMMA_74 , +#define IFCOMMA_76 , +#define IFCOMMA_78 , +#define IFCOMMA_80 , +#define IFCOMMA_82 , +#define IFCOMMA_84 , +#define IFCOMMA_86 , +#define IFCOMMA_88 , +#define IFCOMMA_90 , +#define IFCOMMA_92 , +#define IFCOMMA_94 , +#define IFCOMMA_96 , +#define IFCOMMA_98 , +#define IFCOMMA_100 , +#define IFCOMMA_102 , +#define IFCOMMA_104 , +#define IFCOMMA_106 , +#define IFCOMMA_108 , +#define IFCOMMA_110 , +#define IFCOMMA_112 , +#define IFCOMMA_114 , +#define IFCOMMA_116 , +#define IFCOMMA_118 , +#define IFCOMMA_120 , +#define IFCOMMA_122 , +#define IFCOMMA_124 , + +#define IFCOMMA_NOFIRST(N) C2(IFCOMMA_NOFIRST, N) +#define IFCOMMA_NOFIRST1 +#define IFCOMMA_NOFIRST2 , +#define IFCOMMA_NOFIRST3 , +#define IFCOMMA_NOFIRST4 , +#define IFCOMMA_NOFIRST5 , +#define IFCOMMA_NOFIRST6 , +#define IFCOMMA_NOFIRST7 , +#define IFCOMMA_NOFIRST8 , +#define IFCOMMA_NOFIRST9 , +#define IFCOMMA_NOFIRST10 , +#define IFCOMMA_NOFIRST11 , +#define IFCOMMA_NOFIRST12 , +#define IFCOMMA_NOFIRST13 , +#define IFCOMMA_NOFIRST14 , +#define IFCOMMA_NOFIRST15 , +#define IFCOMMA_NOFIRST16 , +#define IFCOMMA_NOFIRST17 , +#define IFCOMMA_NOFIRST18 , +#define IFCOMMA_NOFIRST19 , +#define IFCOMMA_NOFIRST20 , +#define IFCOMMA_NOFIRST21 , +#define IFCOMMA_NOFIRST22 , +#define IFCOMMA_NOFIRST23 , +#define IFCOMMA_NOFIRST24 , +#define IFCOMMA_NOFIRST25 , +#define IFCOMMA_NOFIRST26 , +#define IFCOMMA_NOFIRST27 , +#define IFCOMMA_NOFIRST28 , +#define IFCOMMA_NOFIRST29 , +#define IFCOMMA_NOFIRST30 , +#define IFCOMMA_NOFIRST31 , +#define IFCOMMA_NOFIRST32 , +#define IFCOMMA_NOFIRST33 , +#define IFCOMMA_NOFIRST34 , +#define IFCOMMA_NOFIRST35 , +#define IFCOMMA_NOFIRST36 , +#define IFCOMMA_NOFIRST37 , +#define IFCOMMA_NOFIRST38 , +#define IFCOMMA_NOFIRST39 , +#define IFCOMMA_NOFIRST40 , +#define IFCOMMA_NOFIRST41 , +#define IFCOMMA_NOFIRST42 , +#define IFCOMMA_NOFIRST43 , +#define IFCOMMA_NOFIRST44 , +#define IFCOMMA_NOFIRST45 , +#define IFCOMMA_NOFIRST46 , +#define IFCOMMA_NOFIRST47 , +#define IFCOMMA_NOFIRST48 , +#define IFCOMMA_NOFIRST49 , +#define IFCOMMA_NOFIRST50 , +#define IFCOMMA_NOFIRST51 , +#define IFCOMMA_NOFIRST52 , +#define IFCOMMA_NOFIRST53 , +#define IFCOMMA_NOFIRST54 , +#define IFCOMMA_NOFIRST55 , +#define IFCOMMA_NOFIRST56 , +#define IFCOMMA_NOFIRST57 , +#define IFCOMMA_NOFIRST58 , +#define IFCOMMA_NOFIRST59 , +#define IFCOMMA_NOFIRST60 , +#define IFCOMMA_NOFIRST61 , +#define IFCOMMA_NOFIRST62 , +#define IFCOMMA_NOFIRST63 , +#define IFCOMMA_NOFIRST64 , +#define IFCOMMA_NOFIRST65 , +#define IFCOMMA_NOFIRST66 , +#define IFCOMMA_NOFIRST67 , +#define IFCOMMA_NOFIRST68 , +#define IFCOMMA_NOFIRST69 , +#define IFCOMMA_NOFIRST70 , +#define IFCOMMA_NOFIRST71 , +#define IFCOMMA_NOFIRST72 , +#define IFCOMMA_NOFIRST73 , +#define IFCOMMA_NOFIRST74 , +#define IFCOMMA_NOFIRST75 , +#define IFCOMMA_NOFIRST76 , +#define IFCOMMA_NOFIRST77 , +#define IFCOMMA_NOFIRST78 , +#define IFCOMMA_NOFIRST79 , +#define IFCOMMA_NOFIRST80 , +#define IFCOMMA_NOFIRST81 , +#define IFCOMMA_NOFIRST82 , +#define IFCOMMA_NOFIRST83 , +#define IFCOMMA_NOFIRST84 , +#define IFCOMMA_NOFIRST85 , +#define IFCOMMA_NOFIRST86 , +#define IFCOMMA_NOFIRST87 , +#define IFCOMMA_NOFIRST88 , +#define IFCOMMA_NOFIRST89 , +#define IFCOMMA_NOFIRST90 , +#define IFCOMMA_NOFIRST91 , +#define IFCOMMA_NOFIRST92 , +#define IFCOMMA_NOFIRST93 , +#define IFCOMMA_NOFIRST94 , +#define IFCOMMA_NOFIRST95 , +#define IFCOMMA_NOFIRST96 , +#define IFCOMMA_NOFIRST97 , +#define IFCOMMA_NOFIRST98 , +#define IFCOMMA_NOFIRST99 , +#define IFCOMMA_NOFIRST100 , +#define IFCOMMA_NOFIRST101 , +#define IFCOMMA_NOFIRST102 , +#define IFCOMMA_NOFIRST103 , +#define IFCOMMA_NOFIRST104 , +#define IFCOMMA_NOFIRST105 , +#define IFCOMMA_NOFIRST106 , +#define IFCOMMA_NOFIRST107 , +#define IFCOMMA_NOFIRST108 , +#define IFCOMMA_NOFIRST109 , +#define IFCOMMA_NOFIRST110 , +#define IFCOMMA_NOFIRST111 , +#define IFCOMMA_NOFIRST112 , +#define IFCOMMA_NOFIRST113 , +#define IFCOMMA_NOFIRST114 , +#define IFCOMMA_NOFIRST115 , +#define IFCOMMA_NOFIRST116 , +#define IFCOMMA_NOFIRST117 , +#define IFCOMMA_NOFIRST118 , +#define IFCOMMA_NOFIRST119 , +#define IFCOMMA_NOFIRST120 , +#define IFCOMMA_NOFIRST121 , +#define IFCOMMA_NOFIRST122 , +#define IFCOMMA_NOFIRST123 , +#define IFCOMMA_NOFIRST124 , + +#define DEC(x) C2(DEC,x) +#define DEC1024 1023 +#define DEC1023 1022 +#define DEC1022 1021 +#define DEC1021 1020 +#define DEC1020 1019 +#define DEC1019 1018 +#define DEC1018 1017 +#define DEC1017 1016 +#define DEC1016 1015 +#define DEC1015 1014 +#define DEC1014 1013 +#define DEC1013 1012 +#define DEC1012 1011 +#define DEC1011 1010 +#define DEC1010 1009 +#define DEC1009 1008 +#define DEC1008 1007 +#define DEC1007 1006 +#define DEC1006 1005 +#define DEC1005 1004 +#define DEC1004 1003 +#define DEC1003 1002 +#define DEC1002 1001 +#define DEC1001 1000 +#define DEC1000 999 +#define DEC999 998 +#define DEC998 997 +#define DEC997 996 +#define DEC996 995 +#define DEC995 994 +#define DEC994 993 +#define DEC993 992 +#define DEC992 991 +#define DEC991 990 +#define DEC990 989 +#define DEC989 988 +#define DEC988 987 +#define DEC987 986 +#define DEC986 985 +#define DEC985 984 +#define DEC984 983 +#define DEC983 982 +#define DEC982 981 +#define DEC981 980 +#define DEC980 979 +#define DEC979 978 +#define DEC978 977 +#define DEC977 976 +#define DEC976 975 +#define DEC975 974 +#define DEC974 973 +#define DEC973 972 +#define DEC972 971 +#define DEC971 970 +#define DEC970 969 +#define DEC969 968 +#define DEC968 967 +#define DEC967 966 +#define DEC966 965 +#define DEC965 964 +#define DEC964 963 +#define DEC963 962 +#define DEC962 961 +#define DEC961 960 +#define DEC960 959 +#define DEC959 958 +#define DEC958 957 +#define DEC957 956 +#define DEC956 955 +#define DEC955 954 +#define DEC954 953 +#define DEC953 952 +#define DEC952 951 +#define DEC951 950 +#define DEC950 949 +#define DEC949 948 +#define DEC948 947 +#define DEC947 946 +#define DEC946 945 +#define DEC945 944 +#define DEC944 943 +#define DEC943 942 +#define DEC942 941 +#define DEC941 940 +#define DEC940 939 +#define DEC939 938 +#define DEC938 937 +#define DEC937 936 +#define DEC936 935 +#define DEC935 934 +#define DEC934 933 +#define DEC933 932 +#define DEC932 931 +#define DEC931 930 +#define DEC930 929 +#define DEC929 928 +#define DEC928 927 +#define DEC927 926 +#define DEC926 925 +#define DEC925 924 +#define DEC924 923 +#define DEC923 922 +#define DEC922 921 +#define DEC921 920 +#define DEC920 919 +#define DEC919 918 +#define DEC918 917 +#define DEC917 916 +#define DEC916 915 +#define DEC915 914 +#define DEC914 913 +#define DEC913 912 +#define DEC912 911 +#define DEC911 910 +#define DEC910 909 +#define DEC909 908 +#define DEC908 907 +#define DEC907 906 +#define DEC906 905 +#define DEC905 904 +#define DEC904 903 +#define DEC903 902 +#define DEC902 901 +#define DEC901 900 +#define DEC900 899 +#define DEC899 898 +#define DEC898 897 +#define DEC897 896 +#define DEC896 895 +#define DEC895 894 +#define DEC894 893 +#define DEC893 892 +#define DEC892 891 +#define DEC891 890 +#define DEC890 889 +#define DEC889 888 +#define DEC888 887 +#define DEC887 886 +#define DEC886 885 +#define DEC885 884 +#define DEC884 883 +#define DEC883 882 +#define DEC882 881 +#define DEC881 880 +#define DEC880 879 +#define DEC879 878 +#define DEC878 877 +#define DEC877 876 +#define DEC876 875 +#define DEC875 874 +#define DEC874 873 +#define DEC873 872 +#define DEC872 871 +#define DEC871 870 +#define DEC870 869 +#define DEC869 868 +#define DEC868 867 +#define DEC867 866 +#define DEC866 865 +#define DEC865 864 +#define DEC864 863 +#define DEC863 862 +#define DEC862 861 +#define DEC861 860 +#define DEC860 859 +#define DEC859 858 +#define DEC858 857 +#define DEC857 856 +#define DEC856 855 +#define DEC855 854 +#define DEC854 853 +#define DEC853 852 +#define DEC852 851 +#define DEC851 850 +#define DEC850 849 +#define DEC849 848 +#define DEC848 847 +#define DEC847 846 +#define DEC846 845 +#define DEC845 844 +#define DEC844 843 +#define DEC843 842 +#define DEC842 841 +#define DEC841 840 +#define DEC840 839 +#define DEC839 838 +#define DEC838 837 +#define DEC837 836 +#define DEC836 835 +#define DEC835 834 +#define DEC834 833 +#define DEC833 832 +#define DEC832 831 +#define DEC831 830 +#define DEC830 829 +#define DEC829 828 +#define DEC828 827 +#define DEC827 826 +#define DEC826 825 +#define DEC825 824 +#define DEC824 823 +#define DEC823 822 +#define DEC822 821 +#define DEC821 820 +#define DEC820 819 +#define DEC819 818 +#define DEC818 817 +#define DEC817 816 +#define DEC816 815 +#define DEC815 814 +#define DEC814 813 +#define DEC813 812 +#define DEC812 811 +#define DEC811 810 +#define DEC810 809 +#define DEC809 808 +#define DEC808 807 +#define DEC807 806 +#define DEC806 805 +#define DEC805 804 +#define DEC804 803 +#define DEC803 802 +#define DEC802 801 +#define DEC801 800 +#define DEC800 799 +#define DEC799 798 +#define DEC798 797 +#define DEC797 796 +#define DEC796 795 +#define DEC795 794 +#define DEC794 793 +#define DEC793 792 +#define DEC792 791 +#define DEC791 790 +#define DEC790 789 +#define DEC789 788 +#define DEC788 787 +#define DEC787 786 +#define DEC786 785 +#define DEC785 784 +#define DEC784 783 +#define DEC783 782 +#define DEC782 781 +#define DEC781 780 +#define DEC780 779 +#define DEC779 778 +#define DEC778 777 +#define DEC777 776 +#define DEC776 775 +#define DEC775 774 +#define DEC774 773 +#define DEC773 772 +#define DEC772 771 +#define DEC771 770 +#define DEC770 769 +#define DEC769 768 +#define DEC768 767 +#define DEC767 766 +#define DEC766 765 +#define DEC765 764 +#define DEC764 763 +#define DEC763 762 +#define DEC762 761 +#define DEC761 760 +#define DEC760 759 +#define DEC759 758 +#define DEC758 757 +#define DEC757 756 +#define DEC756 755 +#define DEC755 754 +#define DEC754 753 +#define DEC753 752 +#define DEC752 751 +#define DEC751 750 +#define DEC750 749 +#define DEC749 748 +#define DEC748 747 +#define DEC747 746 +#define DEC746 745 +#define DEC745 744 +#define DEC744 743 +#define DEC743 742 +#define DEC742 741 +#define DEC741 740 +#define DEC740 739 +#define DEC739 738 +#define DEC738 737 +#define DEC737 736 +#define DEC736 735 +#define DEC735 734 +#define DEC734 733 +#define DEC733 732 +#define DEC732 731 +#define DEC731 730 +#define DEC730 729 +#define DEC729 728 +#define DEC728 727 +#define DEC727 726 +#define DEC726 725 +#define DEC725 724 +#define DEC724 723 +#define DEC723 722 +#define DEC722 721 +#define DEC721 720 +#define DEC720 719 +#define DEC719 718 +#define DEC718 717 +#define DEC717 716 +#define DEC716 715 +#define DEC715 714 +#define DEC714 713 +#define DEC713 712 +#define DEC712 711 +#define DEC711 710 +#define DEC710 709 +#define DEC709 708 +#define DEC708 707 +#define DEC707 706 +#define DEC706 705 +#define DEC705 704 +#define DEC704 703 +#define DEC703 702 +#define DEC702 701 +#define DEC701 700 +#define DEC700 699 +#define DEC699 698 +#define DEC698 697 +#define DEC697 696 +#define DEC696 695 +#define DEC695 694 +#define DEC694 693 +#define DEC693 692 +#define DEC692 691 +#define DEC691 690 +#define DEC690 689 +#define DEC689 688 +#define DEC688 687 +#define DEC687 686 +#define DEC686 685 +#define DEC685 684 +#define DEC684 683 +#define DEC683 682 +#define DEC682 681 +#define DEC681 680 +#define DEC680 679 +#define DEC679 678 +#define DEC678 677 +#define DEC677 676 +#define DEC676 675 +#define DEC675 674 +#define DEC674 673 +#define DEC673 672 +#define DEC672 671 +#define DEC671 670 +#define DEC670 669 +#define DEC669 668 +#define DEC668 667 +#define DEC667 666 +#define DEC666 665 +#define DEC665 664 +#define DEC664 663 +#define DEC663 662 +#define DEC662 661 +#define DEC661 660 +#define DEC660 659 +#define DEC659 658 +#define DEC658 657 +#define DEC657 656 +#define DEC656 655 +#define DEC655 654 +#define DEC654 653 +#define DEC653 652 +#define DEC652 651 +#define DEC651 650 +#define DEC650 649 +#define DEC649 648 +#define DEC648 647 +#define DEC647 646 +#define DEC646 645 +#define DEC645 644 +#define DEC644 643 +#define DEC643 642 +#define DEC642 641 +#define DEC641 640 +#define DEC640 639 +#define DEC639 638 +#define DEC638 637 +#define DEC637 636 +#define DEC636 635 +#define DEC635 634 +#define DEC634 633 +#define DEC633 632 +#define DEC632 631 +#define DEC631 630 +#define DEC630 629 +#define DEC629 628 +#define DEC628 627 +#define DEC627 626 +#define DEC626 625 +#define DEC625 624 +#define DEC624 623 +#define DEC623 622 +#define DEC622 621 +#define DEC621 620 +#define DEC620 619 +#define DEC619 618 +#define DEC618 617 +#define DEC617 616 +#define DEC616 615 +#define DEC615 614 +#define DEC614 613 +#define DEC613 612 +#define DEC612 611 +#define DEC611 610 +#define DEC610 609 +#define DEC609 608 +#define DEC608 607 +#define DEC607 606 +#define DEC606 605 +#define DEC605 604 +#define DEC604 603 +#define DEC603 602 +#define DEC602 601 +#define DEC601 600 +#define DEC600 599 +#define DEC599 598 +#define DEC598 597 +#define DEC597 596 +#define DEC596 595 +#define DEC595 594 +#define DEC594 593 +#define DEC593 592 +#define DEC592 591 +#define DEC591 590 +#define DEC590 589 +#define DEC589 588 +#define DEC588 587 +#define DEC587 586 +#define DEC586 585 +#define DEC585 584 +#define DEC584 583 +#define DEC583 582 +#define DEC582 581 +#define DEC581 580 +#define DEC580 579 +#define DEC579 578 +#define DEC578 577 +#define DEC577 576 +#define DEC576 575 +#define DEC575 574 +#define DEC574 573 +#define DEC573 572 +#define DEC572 571 +#define DEC571 570 +#define DEC570 569 +#define DEC569 568 +#define DEC568 567 +#define DEC567 566 +#define DEC566 565 +#define DEC565 564 +#define DEC564 563 +#define DEC563 562 +#define DEC562 561 +#define DEC561 560 +#define DEC560 559 +#define DEC559 558 +#define DEC558 557 +#define DEC557 556 +#define DEC556 555 +#define DEC555 554 +#define DEC554 553 +#define DEC553 552 +#define DEC552 551 +#define DEC551 550 +#define DEC550 549 +#define DEC549 548 +#define DEC548 547 +#define DEC547 546 +#define DEC546 545 +#define DEC545 544 +#define DEC544 543 +#define DEC543 542 +#define DEC542 541 +#define DEC541 540 +#define DEC540 539 +#define DEC539 538 +#define DEC538 537 +#define DEC537 536 +#define DEC536 535 +#define DEC535 534 +#define DEC534 533 +#define DEC533 532 +#define DEC532 531 +#define DEC531 530 +#define DEC530 529 +#define DEC529 528 +#define DEC528 527 +#define DEC527 526 +#define DEC526 525 +#define DEC525 524 +#define DEC524 523 +#define DEC523 522 +#define DEC522 521 +#define DEC521 520 +#define DEC520 519 +#define DEC519 518 +#define DEC518 517 +#define DEC517 516 +#define DEC516 515 +#define DEC515 514 +#define DEC514 513 +#define DEC513 512 +#define DEC512 511 +#define DEC511 510 +#define DEC510 509 +#define DEC509 508 +#define DEC508 507 +#define DEC507 506 +#define DEC506 505 +#define DEC505 504 +#define DEC504 503 +#define DEC503 502 +#define DEC502 501 +#define DEC501 500 +#define DEC500 499 +#define DEC499 498 +#define DEC498 497 +#define DEC497 496 +#define DEC496 495 +#define DEC495 494 +#define DEC494 493 +#define DEC493 492 +#define DEC492 491 +#define DEC491 490 +#define DEC490 489 +#define DEC489 488 +#define DEC488 487 +#define DEC487 486 +#define DEC486 485 +#define DEC485 484 +#define DEC484 483 +#define DEC483 482 +#define DEC482 481 +#define DEC481 480 +#define DEC480 479 +#define DEC479 478 +#define DEC478 477 +#define DEC477 476 +#define DEC476 475 +#define DEC475 474 +#define DEC474 473 +#define DEC473 472 +#define DEC472 471 +#define DEC471 470 +#define DEC470 469 +#define DEC469 468 +#define DEC468 467 +#define DEC467 466 +#define DEC466 465 +#define DEC465 464 +#define DEC464 463 +#define DEC463 462 +#define DEC462 461 +#define DEC461 460 +#define DEC460 459 +#define DEC459 458 +#define DEC458 457 +#define DEC457 456 +#define DEC456 455 +#define DEC455 454 +#define DEC454 453 +#define DEC453 452 +#define DEC452 451 +#define DEC451 450 +#define DEC450 449 +#define DEC449 448 +#define DEC448 447 +#define DEC447 446 +#define DEC446 445 +#define DEC445 444 +#define DEC444 443 +#define DEC443 442 +#define DEC442 441 +#define DEC441 440 +#define DEC440 439 +#define DEC439 438 +#define DEC438 437 +#define DEC437 436 +#define DEC436 435 +#define DEC435 434 +#define DEC434 433 +#define DEC433 432 +#define DEC432 431 +#define DEC431 430 +#define DEC430 429 +#define DEC429 428 +#define DEC428 427 +#define DEC427 426 +#define DEC426 425 +#define DEC425 424 +#define DEC424 423 +#define DEC423 422 +#define DEC422 421 +#define DEC421 420 +#define DEC420 419 +#define DEC419 418 +#define DEC418 417 +#define DEC417 416 +#define DEC416 415 +#define DEC415 414 +#define DEC414 413 +#define DEC413 412 +#define DEC412 411 +#define DEC411 410 +#define DEC410 409 +#define DEC409 408 +#define DEC408 407 +#define DEC407 406 +#define DEC406 405 +#define DEC405 404 +#define DEC404 403 +#define DEC403 402 +#define DEC402 401 +#define DEC401 400 +#define DEC400 399 +#define DEC399 398 +#define DEC398 397 +#define DEC397 396 +#define DEC396 395 +#define DEC395 394 +#define DEC394 393 +#define DEC393 392 +#define DEC392 391 +#define DEC391 390 +#define DEC390 389 +#define DEC389 388 +#define DEC388 387 +#define DEC387 386 +#define DEC386 385 +#define DEC385 384 +#define DEC384 383 +#define DEC383 382 +#define DEC382 381 +#define DEC381 380 +#define DEC380 379 +#define DEC379 378 +#define DEC378 377 +#define DEC377 376 +#define DEC376 375 +#define DEC375 374 +#define DEC374 373 +#define DEC373 372 +#define DEC372 371 +#define DEC371 370 +#define DEC370 369 +#define DEC369 368 +#define DEC368 367 +#define DEC367 366 +#define DEC366 365 +#define DEC365 364 +#define DEC364 363 +#define DEC363 362 +#define DEC362 361 +#define DEC361 360 +#define DEC360 359 +#define DEC359 358 +#define DEC358 357 +#define DEC357 356 +#define DEC356 355 +#define DEC355 354 +#define DEC354 353 +#define DEC353 352 +#define DEC352 351 +#define DEC351 350 +#define DEC350 349 +#define DEC349 348 +#define DEC348 347 +#define DEC347 346 +#define DEC346 345 +#define DEC345 344 +#define DEC344 343 +#define DEC343 342 +#define DEC342 341 +#define DEC341 340 +#define DEC340 339 +#define DEC339 338 +#define DEC338 337 +#define DEC337 336 +#define DEC336 335 +#define DEC335 334 +#define DEC334 333 +#define DEC333 332 +#define DEC332 331 +#define DEC331 330 +#define DEC330 329 +#define DEC329 328 +#define DEC328 327 +#define DEC327 326 +#define DEC326 325 +#define DEC325 324 +#define DEC324 323 +#define DEC323 322 +#define DEC322 321 +#define DEC321 320 +#define DEC320 319 +#define DEC319 318 +#define DEC318 317 +#define DEC317 316 +#define DEC316 315 +#define DEC315 314 +#define DEC314 313 +#define DEC313 312 +#define DEC312 311 +#define DEC311 310 +#define DEC310 309 +#define DEC309 308 +#define DEC308 307 +#define DEC307 306 +#define DEC306 305 +#define DEC305 304 +#define DEC304 303 +#define DEC303 302 +#define DEC302 301 +#define DEC301 300 +#define DEC300 299 +#define DEC299 298 +#define DEC298 297 +#define DEC297 296 +#define DEC296 295 +#define DEC295 294 +#define DEC294 293 +#define DEC293 292 +#define DEC292 291 +#define DEC291 290 +#define DEC290 289 +#define DEC289 288 +#define DEC288 287 +#define DEC287 286 +#define DEC286 285 +#define DEC285 284 +#define DEC284 283 +#define DEC283 282 +#define DEC282 281 +#define DEC281 280 +#define DEC280 279 +#define DEC279 278 +#define DEC278 277 +#define DEC277 276 +#define DEC276 275 +#define DEC275 274 +#define DEC274 273 +#define DEC273 272 +#define DEC272 271 +#define DEC271 270 +#define DEC270 269 +#define DEC269 268 +#define DEC268 267 +#define DEC267 266 +#define DEC266 265 +#define DEC265 264 +#define DEC264 263 +#define DEC263 262 +#define DEC262 261 +#define DEC261 260 +#define DEC260 259 +#define DEC259 258 +#define DEC258 257 +#define DEC257 256 +#define DEC256 255 +#define DEC255 254 +#define DEC254 253 +#define DEC253 252 +#define DEC252 251 +#define DEC251 250 +#define DEC250 249 +#define DEC249 248 +#define DEC248 247 +#define DEC247 246 +#define DEC246 245 +#define DEC245 244 +#define DEC244 243 +#define DEC243 242 +#define DEC242 241 +#define DEC241 240 +#define DEC240 239 +#define DEC239 238 +#define DEC238 237 +#define DEC237 236 +#define DEC236 235 +#define DEC235 234 +#define DEC234 233 +#define DEC233 232 +#define DEC232 231 +#define DEC231 230 +#define DEC230 229 +#define DEC229 228 +#define DEC228 227 +#define DEC227 226 +#define DEC226 225 +#define DEC225 224 +#define DEC224 223 +#define DEC223 222 +#define DEC222 221 +#define DEC221 220 +#define DEC220 219 +#define DEC219 218 +#define DEC218 217 +#define DEC217 216 +#define DEC216 215 +#define DEC215 214 +#define DEC214 213 +#define DEC213 212 +#define DEC212 211 +#define DEC211 210 +#define DEC210 209 +#define DEC209 208 +#define DEC208 207 +#define DEC207 206 +#define DEC206 205 +#define DEC205 204 +#define DEC204 203 +#define DEC203 202 +#define DEC202 201 +#define DEC201 200 +#define DEC200 199 +#define DEC199 198 +#define DEC198 197 +#define DEC197 196 +#define DEC196 195 +#define DEC195 194 +#define DEC194 193 +#define DEC193 192 +#define DEC192 191 +#define DEC191 190 +#define DEC190 189 +#define DEC189 188 +#define DEC188 187 +#define DEC187 186 +#define DEC186 185 +#define DEC185 184 +#define DEC184 183 +#define DEC183 182 +#define DEC182 181 +#define DEC181 180 +#define DEC180 179 +#define DEC179 178 +#define DEC178 177 +#define DEC177 176 +#define DEC176 175 +#define DEC175 174 +#define DEC174 173 +#define DEC173 172 +#define DEC172 171 +#define DEC171 170 +#define DEC170 169 +#define DEC169 168 +#define DEC168 167 +#define DEC167 166 +#define DEC166 165 +#define DEC165 164 +#define DEC164 163 +#define DEC163 162 +#define DEC162 161 +#define DEC161 160 +#define DEC160 159 +#define DEC159 158 +#define DEC158 157 +#define DEC157 156 +#define DEC156 155 +#define DEC155 154 +#define DEC154 153 +#define DEC153 152 +#define DEC152 151 +#define DEC151 150 +#define DEC150 149 +#define DEC149 148 +#define DEC148 147 +#define DEC147 146 +#define DEC146 145 +#define DEC145 144 +#define DEC144 143 +#define DEC143 142 +#define DEC142 141 +#define DEC141 140 +#define DEC140 139 +#define DEC139 138 +#define DEC138 137 +#define DEC137 136 +#define DEC136 135 +#define DEC135 134 +#define DEC134 133 +#define DEC133 132 +#define DEC132 131 +#define DEC131 130 +#define DEC130 129 +#define DEC129 128 +#define DEC128 127 +#define DEC127 126 +#define DEC126 125 +#define DEC125 124 +#define DEC124 123 +#define DEC123 122 +#define DEC122 121 +#define DEC121 120 +#define DEC120 119 +#define DEC119 118 +#define DEC118 117 +#define DEC117 116 +#define DEC116 115 +#define DEC115 114 +#define DEC114 113 +#define DEC113 112 +#define DEC112 111 +#define DEC111 110 +#define DEC110 109 +#define DEC109 108 +#define DEC108 107 +#define DEC107 106 +#define DEC106 105 +#define DEC105 104 +#define DEC104 103 +#define DEC103 102 +#define DEC102 101 +#define DEC101 100 +#define DEC100 99 +#define DEC99 98 +#define DEC98 97 +#define DEC97 96 +#define DEC96 95 +#define DEC95 94 +#define DEC94 93 +#define DEC93 92 +#define DEC92 91 +#define DEC91 90 +#define DEC90 89 +#define DEC89 88 +#define DEC88 87 +#define DEC87 86 +#define DEC86 85 +#define DEC85 84 +#define DEC84 83 +#define DEC83 82 +#define DEC82 81 +#define DEC81 80 +#define DEC80 79 +#define DEC79 78 +#define DEC78 77 +#define DEC77 76 +#define DEC76 75 +#define DEC75 74 +#define DEC74 73 +#define DEC73 72 +#define DEC72 71 +#define DEC71 70 +#define DEC70 69 +#define DEC69 68 +#define DEC68 67 +#define DEC67 66 +#define DEC66 65 +#define DEC65 64 +#define DEC64 63 +#define DEC63 62 +#define DEC62 61 +#define DEC61 60 +#define DEC60 59 +#define DEC59 58 +#define DEC58 57 +#define DEC57 56 +#define DEC56 55 +#define DEC55 54 +#define DEC54 53 +#define DEC53 52 +#define DEC52 51 +#define DEC51 50 +#define DEC50 49 +#define DEC49 48 +#define DEC48 47 +#define DEC47 46 +#define DEC46 45 +#define DEC45 44 +#define DEC44 43 +#define DEC43 42 +#define DEC42 41 +#define DEC41 40 +#define DEC40 39 +#define DEC39 38 +#define DEC38 37 +#define DEC37 36 +#define DEC36 35 +#define DEC35 34 +#define DEC34 33 +#define DEC33 32 +#define DEC32 31 +#define DEC31 30 +#define DEC30 29 +#define DEC29 28 +#define DEC28 27 +#define DEC27 26 +#define DEC26 25 +#define DEC25 24 +#define DEC24 23 +#define DEC23 22 +#define DEC22 21 +#define DEC21 20 +#define DEC20 19 +#define DEC19 18 +#define DEC18 17 +#define DEC17 16 +#define DEC16 15 +#define DEC15 14 +#define DEC14 13 +#define DEC13 12 +#define DEC12 11 +#define DEC11 10 +#define DEC10 9 +#define DEC9 8 +#define DEC8 7 +#define DEC7 6 +#define DEC6 5 +#define DEC5 4 +#define DEC4 3 +#define DEC3 2 +#define DEC2 1 +#define DEC1 0 + +#define INC(x) C2(INC,x) +#define INC1024 1025 +#define INC1023 1024 +#define INC1022 1023 +#define INC1021 1022 +#define INC1020 1021 +#define INC1019 1020 +#define INC1018 1019 +#define INC1017 1018 +#define INC1016 1017 +#define INC1015 1016 +#define INC1014 1015 +#define INC1013 1014 +#define INC1012 1013 +#define INC1011 1012 +#define INC1010 1011 +#define INC1009 1010 +#define INC1008 1009 +#define INC1007 1008 +#define INC1006 1007 +#define INC1005 1006 +#define INC1004 1005 +#define INC1003 1004 +#define INC1002 1003 +#define INC1001 1002 +#define INC1000 1001 +#define INC999 1000 +#define INC998 999 +#define INC997 998 +#define INC996 997 +#define INC995 996 +#define INC994 995 +#define INC993 994 +#define INC992 993 +#define INC991 992 +#define INC990 991 +#define INC989 990 +#define INC988 989 +#define INC987 988 +#define INC986 987 +#define INC985 986 +#define INC984 985 +#define INC983 984 +#define INC982 983 +#define INC981 982 +#define INC980 981 +#define INC979 980 +#define INC978 979 +#define INC977 978 +#define INC976 977 +#define INC975 976 +#define INC974 975 +#define INC973 974 +#define INC972 973 +#define INC971 972 +#define INC970 971 +#define INC969 970 +#define INC968 969 +#define INC967 968 +#define INC966 967 +#define INC965 966 +#define INC964 965 +#define INC963 964 +#define INC962 963 +#define INC961 962 +#define INC960 961 +#define INC959 960 +#define INC958 959 +#define INC957 958 +#define INC956 957 +#define INC955 956 +#define INC954 955 +#define INC953 954 +#define INC952 953 +#define INC951 952 +#define INC950 951 +#define INC949 950 +#define INC948 949 +#define INC947 948 +#define INC946 947 +#define INC945 946 +#define INC944 945 +#define INC943 944 +#define INC942 943 +#define INC941 942 +#define INC940 941 +#define INC939 940 +#define INC938 939 +#define INC937 938 +#define INC936 937 +#define INC935 936 +#define INC934 935 +#define INC933 934 +#define INC932 933 +#define INC931 932 +#define INC930 931 +#define INC929 930 +#define INC928 929 +#define INC927 928 +#define INC926 927 +#define INC925 926 +#define INC924 925 +#define INC923 924 +#define INC922 923 +#define INC921 922 +#define INC920 921 +#define INC919 920 +#define INC918 919 +#define INC917 918 +#define INC916 917 +#define INC915 916 +#define INC914 915 +#define INC913 914 +#define INC912 913 +#define INC911 912 +#define INC910 911 +#define INC909 910 +#define INC908 909 +#define INC907 908 +#define INC906 907 +#define INC905 906 +#define INC904 905 +#define INC903 904 +#define INC902 903 +#define INC901 902 +#define INC900 901 +#define INC899 900 +#define INC898 899 +#define INC897 898 +#define INC896 897 +#define INC895 896 +#define INC894 895 +#define INC893 894 +#define INC892 893 +#define INC891 892 +#define INC890 891 +#define INC889 890 +#define INC888 889 +#define INC887 888 +#define INC886 887 +#define INC885 886 +#define INC884 885 +#define INC883 884 +#define INC882 883 +#define INC881 882 +#define INC880 881 +#define INC879 880 +#define INC878 879 +#define INC877 878 +#define INC876 877 +#define INC875 876 +#define INC874 875 +#define INC873 874 +#define INC872 873 +#define INC871 872 +#define INC870 871 +#define INC869 870 +#define INC868 869 +#define INC867 868 +#define INC866 867 +#define INC865 866 +#define INC864 865 +#define INC863 864 +#define INC862 863 +#define INC861 862 +#define INC860 861 +#define INC859 860 +#define INC858 859 +#define INC857 858 +#define INC856 857 +#define INC855 856 +#define INC854 855 +#define INC853 854 +#define INC852 853 +#define INC851 852 +#define INC850 851 +#define INC849 850 +#define INC848 849 +#define INC847 848 +#define INC846 847 +#define INC845 846 +#define INC844 845 +#define INC843 844 +#define INC842 843 +#define INC841 842 +#define INC840 841 +#define INC839 840 +#define INC838 839 +#define INC837 838 +#define INC836 837 +#define INC835 836 +#define INC834 835 +#define INC833 834 +#define INC832 833 +#define INC831 832 +#define INC830 831 +#define INC829 830 +#define INC828 829 +#define INC827 828 +#define INC826 827 +#define INC825 826 +#define INC824 825 +#define INC823 824 +#define INC822 823 +#define INC821 822 +#define INC820 821 +#define INC819 820 +#define INC818 819 +#define INC817 818 +#define INC816 817 +#define INC815 816 +#define INC814 815 +#define INC813 814 +#define INC812 813 +#define INC811 812 +#define INC810 811 +#define INC809 810 +#define INC808 809 +#define INC807 808 +#define INC806 807 +#define INC805 806 +#define INC804 805 +#define INC803 804 +#define INC802 803 +#define INC801 802 +#define INC800 801 +#define INC799 800 +#define INC798 799 +#define INC797 798 +#define INC796 797 +#define INC795 796 +#define INC794 795 +#define INC793 794 +#define INC792 793 +#define INC791 792 +#define INC790 791 +#define INC789 790 +#define INC788 789 +#define INC787 788 +#define INC786 787 +#define INC785 786 +#define INC784 785 +#define INC783 784 +#define INC782 783 +#define INC781 782 +#define INC780 781 +#define INC779 780 +#define INC778 779 +#define INC777 778 +#define INC776 777 +#define INC775 776 +#define INC774 775 +#define INC773 774 +#define INC772 773 +#define INC771 772 +#define INC770 771 +#define INC769 770 +#define INC768 769 +#define INC767 768 +#define INC766 767 +#define INC765 766 +#define INC764 765 +#define INC763 764 +#define INC762 763 +#define INC761 762 +#define INC760 761 +#define INC759 760 +#define INC758 759 +#define INC757 758 +#define INC756 757 +#define INC755 756 +#define INC754 755 +#define INC753 754 +#define INC752 753 +#define INC751 752 +#define INC750 751 +#define INC749 750 +#define INC748 749 +#define INC747 748 +#define INC746 747 +#define INC745 746 +#define INC744 745 +#define INC743 744 +#define INC742 743 +#define INC741 742 +#define INC740 741 +#define INC739 740 +#define INC738 739 +#define INC737 738 +#define INC736 737 +#define INC735 736 +#define INC734 735 +#define INC733 734 +#define INC732 733 +#define INC731 732 +#define INC730 731 +#define INC729 730 +#define INC728 729 +#define INC727 728 +#define INC726 727 +#define INC725 726 +#define INC724 725 +#define INC723 724 +#define INC722 723 +#define INC721 722 +#define INC720 721 +#define INC719 720 +#define INC718 719 +#define INC717 718 +#define INC716 717 +#define INC715 716 +#define INC714 715 +#define INC713 714 +#define INC712 713 +#define INC711 712 +#define INC710 711 +#define INC709 710 +#define INC708 709 +#define INC707 708 +#define INC706 707 +#define INC705 706 +#define INC704 705 +#define INC703 704 +#define INC702 703 +#define INC701 702 +#define INC700 701 +#define INC699 700 +#define INC698 699 +#define INC697 698 +#define INC696 697 +#define INC695 696 +#define INC694 695 +#define INC693 694 +#define INC692 693 +#define INC691 692 +#define INC690 691 +#define INC689 690 +#define INC688 689 +#define INC687 688 +#define INC686 687 +#define INC685 686 +#define INC684 685 +#define INC683 684 +#define INC682 683 +#define INC681 682 +#define INC680 681 +#define INC679 680 +#define INC678 679 +#define INC677 678 +#define INC676 677 +#define INC675 676 +#define INC674 675 +#define INC673 674 +#define INC672 673 +#define INC671 672 +#define INC670 671 +#define INC669 670 +#define INC668 669 +#define INC667 668 +#define INC666 667 +#define INC665 666 +#define INC664 665 +#define INC663 664 +#define INC662 663 +#define INC661 662 +#define INC660 661 +#define INC659 660 +#define INC658 659 +#define INC657 658 +#define INC656 657 +#define INC655 656 +#define INC654 655 +#define INC653 654 +#define INC652 653 +#define INC651 652 +#define INC650 651 +#define INC649 650 +#define INC648 649 +#define INC647 648 +#define INC646 647 +#define INC645 646 +#define INC644 645 +#define INC643 644 +#define INC642 643 +#define INC641 642 +#define INC640 641 +#define INC639 640 +#define INC638 639 +#define INC637 638 +#define INC636 637 +#define INC635 636 +#define INC634 635 +#define INC633 634 +#define INC632 633 +#define INC631 632 +#define INC630 631 +#define INC629 630 +#define INC628 629 +#define INC627 628 +#define INC626 627 +#define INC625 626 +#define INC624 625 +#define INC623 624 +#define INC622 623 +#define INC621 622 +#define INC620 621 +#define INC619 620 +#define INC618 619 +#define INC617 618 +#define INC616 617 +#define INC615 616 +#define INC614 615 +#define INC613 614 +#define INC612 613 +#define INC611 612 +#define INC610 611 +#define INC609 610 +#define INC608 609 +#define INC607 608 +#define INC606 607 +#define INC605 606 +#define INC604 605 +#define INC603 604 +#define INC602 603 +#define INC601 602 +#define INC600 601 +#define INC599 600 +#define INC598 599 +#define INC597 598 +#define INC596 597 +#define INC595 596 +#define INC594 595 +#define INC593 594 +#define INC592 593 +#define INC591 592 +#define INC590 591 +#define INC589 590 +#define INC588 589 +#define INC587 588 +#define INC586 587 +#define INC585 586 +#define INC584 585 +#define INC583 584 +#define INC582 583 +#define INC581 582 +#define INC580 581 +#define INC579 580 +#define INC578 579 +#define INC577 578 +#define INC576 577 +#define INC575 576 +#define INC574 575 +#define INC573 574 +#define INC572 573 +#define INC571 572 +#define INC570 571 +#define INC569 570 +#define INC568 569 +#define INC567 568 +#define INC566 567 +#define INC565 566 +#define INC564 565 +#define INC563 564 +#define INC562 563 +#define INC561 562 +#define INC560 561 +#define INC559 560 +#define INC558 559 +#define INC557 558 +#define INC556 557 +#define INC555 556 +#define INC554 555 +#define INC553 554 +#define INC552 553 +#define INC551 552 +#define INC550 551 +#define INC549 550 +#define INC548 549 +#define INC547 548 +#define INC546 547 +#define INC545 546 +#define INC544 545 +#define INC543 544 +#define INC542 543 +#define INC541 542 +#define INC540 541 +#define INC539 540 +#define INC538 539 +#define INC537 538 +#define INC536 537 +#define INC535 536 +#define INC534 535 +#define INC533 534 +#define INC532 533 +#define INC531 532 +#define INC530 531 +#define INC529 530 +#define INC528 529 +#define INC527 528 +#define INC526 527 +#define INC525 526 +#define INC524 525 +#define INC523 524 +#define INC522 523 +#define INC521 522 +#define INC520 521 +#define INC519 520 +#define INC518 519 +#define INC517 518 +#define INC516 517 +#define INC515 516 +#define INC514 515 +#define INC513 514 +#define INC512 513 +#define INC511 512 +#define INC510 511 +#define INC509 510 +#define INC508 509 +#define INC507 508 +#define INC506 507 +#define INC505 506 +#define INC504 505 +#define INC503 504 +#define INC502 503 +#define INC501 502 +#define INC500 501 +#define INC499 500 +#define INC498 499 +#define INC497 498 +#define INC496 497 +#define INC495 496 +#define INC494 495 +#define INC493 494 +#define INC492 493 +#define INC491 492 +#define INC490 491 +#define INC489 490 +#define INC488 489 +#define INC487 488 +#define INC486 487 +#define INC485 486 +#define INC484 485 +#define INC483 484 +#define INC482 483 +#define INC481 482 +#define INC480 481 +#define INC479 480 +#define INC478 479 +#define INC477 478 +#define INC476 477 +#define INC475 476 +#define INC474 475 +#define INC473 474 +#define INC472 473 +#define INC471 472 +#define INC470 471 +#define INC469 470 +#define INC468 469 +#define INC467 468 +#define INC466 467 +#define INC465 466 +#define INC464 465 +#define INC463 464 +#define INC462 463 +#define INC461 462 +#define INC460 461 +#define INC459 460 +#define INC458 459 +#define INC457 458 +#define INC456 457 +#define INC455 456 +#define INC454 455 +#define INC453 454 +#define INC452 453 +#define INC451 452 +#define INC450 451 +#define INC449 450 +#define INC448 449 +#define INC447 448 +#define INC446 447 +#define INC445 446 +#define INC444 445 +#define INC443 444 +#define INC442 443 +#define INC441 442 +#define INC440 441 +#define INC439 440 +#define INC438 439 +#define INC437 438 +#define INC436 437 +#define INC435 436 +#define INC434 435 +#define INC433 434 +#define INC432 433 +#define INC431 432 +#define INC430 431 +#define INC429 430 +#define INC428 429 +#define INC427 428 +#define INC426 427 +#define INC425 426 +#define INC424 425 +#define INC423 424 +#define INC422 423 +#define INC421 422 +#define INC420 421 +#define INC419 420 +#define INC418 419 +#define INC417 418 +#define INC416 417 +#define INC415 416 +#define INC414 415 +#define INC413 414 +#define INC412 413 +#define INC411 412 +#define INC410 411 +#define INC409 410 +#define INC408 409 +#define INC407 408 +#define INC406 407 +#define INC405 406 +#define INC404 405 +#define INC403 404 +#define INC402 403 +#define INC401 402 +#define INC400 401 +#define INC399 400 +#define INC398 399 +#define INC397 398 +#define INC396 397 +#define INC395 396 +#define INC394 395 +#define INC393 394 +#define INC392 393 +#define INC391 392 +#define INC390 391 +#define INC389 390 +#define INC388 389 +#define INC387 388 +#define INC386 387 +#define INC385 386 +#define INC384 385 +#define INC383 384 +#define INC382 383 +#define INC381 382 +#define INC380 381 +#define INC379 380 +#define INC378 379 +#define INC377 378 +#define INC376 377 +#define INC375 376 +#define INC374 375 +#define INC373 374 +#define INC372 373 +#define INC371 372 +#define INC370 371 +#define INC369 370 +#define INC368 369 +#define INC367 368 +#define INC366 367 +#define INC365 366 +#define INC364 365 +#define INC363 364 +#define INC362 363 +#define INC361 362 +#define INC360 361 +#define INC359 360 +#define INC358 359 +#define INC357 358 +#define INC356 357 +#define INC355 356 +#define INC354 355 +#define INC353 354 +#define INC352 353 +#define INC351 352 +#define INC350 351 +#define INC349 350 +#define INC348 349 +#define INC347 348 +#define INC346 347 +#define INC345 346 +#define INC344 345 +#define INC343 344 +#define INC342 343 +#define INC341 342 +#define INC340 341 +#define INC339 340 +#define INC338 339 +#define INC337 338 +#define INC336 337 +#define INC335 336 +#define INC334 335 +#define INC333 334 +#define INC332 333 +#define INC331 332 +#define INC330 331 +#define INC329 330 +#define INC328 329 +#define INC327 328 +#define INC326 327 +#define INC325 326 +#define INC324 325 +#define INC323 324 +#define INC322 323 +#define INC321 322 +#define INC320 321 +#define INC319 320 +#define INC318 319 +#define INC317 318 +#define INC316 317 +#define INC315 316 +#define INC314 315 +#define INC313 314 +#define INC312 313 +#define INC311 312 +#define INC310 311 +#define INC309 310 +#define INC308 309 +#define INC307 308 +#define INC306 307 +#define INC305 306 +#define INC304 305 +#define INC303 304 +#define INC302 303 +#define INC301 302 +#define INC300 301 +#define INC299 300 +#define INC298 299 +#define INC297 298 +#define INC296 297 +#define INC295 296 +#define INC294 295 +#define INC293 294 +#define INC292 293 +#define INC291 292 +#define INC290 291 +#define INC289 290 +#define INC288 289 +#define INC287 288 +#define INC286 287 +#define INC285 286 +#define INC284 285 +#define INC283 284 +#define INC282 283 +#define INC281 282 +#define INC280 281 +#define INC279 280 +#define INC278 279 +#define INC277 278 +#define INC276 277 +#define INC275 276 +#define INC274 275 +#define INC273 274 +#define INC272 273 +#define INC271 272 +#define INC270 271 +#define INC269 270 +#define INC268 269 +#define INC267 268 +#define INC266 267 +#define INC265 266 +#define INC264 265 +#define INC263 264 +#define INC262 263 +#define INC261 262 +#define INC260 261 +#define INC259 260 +#define INC258 259 +#define INC257 258 +#define INC256 257 +#define INC255 256 +#define INC254 255 +#define INC253 254 +#define INC252 253 +#define INC251 252 +#define INC250 251 +#define INC249 250 +#define INC248 249 +#define INC247 248 +#define INC246 247 +#define INC245 246 +#define INC244 245 +#define INC243 244 +#define INC242 243 +#define INC241 242 +#define INC240 241 +#define INC239 240 +#define INC238 239 +#define INC237 238 +#define INC236 237 +#define INC235 236 +#define INC234 235 +#define INC233 234 +#define INC232 233 +#define INC231 232 +#define INC230 231 +#define INC229 230 +#define INC228 229 +#define INC227 228 +#define INC226 227 +#define INC225 226 +#define INC224 225 +#define INC223 224 +#define INC222 223 +#define INC221 222 +#define INC220 221 +#define INC219 220 +#define INC218 219 +#define INC217 218 +#define INC216 217 +#define INC215 216 +#define INC214 215 +#define INC213 214 +#define INC212 213 +#define INC211 212 +#define INC210 211 +#define INC209 210 +#define INC208 209 +#define INC207 208 +#define INC206 207 +#define INC205 206 +#define INC204 205 +#define INC203 204 +#define INC202 203 +#define INC201 202 +#define INC200 201 +#define INC199 200 +#define INC198 199 +#define INC197 198 +#define INC196 197 +#define INC195 196 +#define INC194 195 +#define INC193 194 +#define INC192 193 +#define INC191 192 +#define INC190 191 +#define INC189 190 +#define INC188 189 +#define INC187 188 +#define INC186 187 +#define INC185 186 +#define INC184 185 +#define INC183 184 +#define INC182 183 +#define INC181 182 +#define INC180 181 +#define INC179 180 +#define INC178 179 +#define INC177 178 +#define INC176 177 +#define INC175 176 +#define INC174 175 +#define INC173 174 +#define INC172 173 +#define INC171 172 +#define INC170 171 +#define INC169 170 +#define INC168 169 +#define INC167 168 +#define INC166 167 +#define INC165 166 +#define INC164 165 +#define INC163 164 +#define INC162 163 +#define INC161 162 +#define INC160 161 +#define INC159 160 +#define INC158 159 +#define INC157 158 +#define INC156 157 +#define INC155 156 +#define INC154 155 +#define INC153 154 +#define INC152 153 +#define INC151 152 +#define INC150 151 +#define INC149 150 +#define INC148 149 +#define INC147 148 +#define INC146 147 +#define INC145 146 +#define INC144 145 +#define INC143 144 +#define INC142 143 +#define INC141 142 +#define INC140 141 +#define INC139 140 +#define INC138 139 +#define INC137 138 +#define INC136 137 +#define INC135 136 +#define INC134 135 +#define INC133 134 +#define INC132 133 +#define INC131 132 +#define INC130 131 +#define INC129 130 +#define INC128 129 +#define INC127 128 +#define INC126 127 +#define INC125 126 +#define INC124 125 +#define INC123 124 +#define INC122 123 +#define INC121 122 +#define INC120 121 +#define INC119 120 +#define INC118 119 +#define INC117 118 +#define INC116 117 +#define INC115 116 +#define INC114 115 +#define INC113 114 +#define INC112 113 +#define INC111 112 +#define INC110 111 +#define INC109 110 +#define INC108 109 +#define INC107 108 +#define INC106 107 +#define INC105 106 +#define INC104 105 +#define INC103 104 +#define INC102 103 +#define INC101 102 +#define INC100 101 +#define INC99 100 +#define INC98 99 +#define INC97 98 +#define INC96 97 +#define INC95 96 +#define INC94 95 +#define INC93 94 +#define INC92 93 +#define INC91 92 +#define INC90 91 +#define INC89 90 +#define INC88 89 +#define INC87 88 +#define INC86 87 +#define INC85 86 +#define INC84 85 +#define INC83 84 +#define INC82 83 +#define INC81 82 +#define INC80 81 +#define INC79 80 +#define INC78 79 +#define INC77 78 +#define INC76 77 +#define INC75 76 +#define INC74 75 +#define INC73 74 +#define INC72 73 +#define INC71 72 +#define INC70 71 +#define INC69 70 +#define INC68 69 +#define INC67 68 +#define INC66 67 +#define INC65 66 +#define INC64 65 +#define INC63 64 +#define INC62 63 +#define INC61 62 +#define INC60 61 +#define INC59 60 +#define INC58 59 +#define INC57 58 +#define INC56 57 +#define INC55 56 +#define INC54 55 +#define INC53 54 +#define INC52 53 +#define INC51 52 +#define INC50 51 +#define INC49 50 +#define INC48 49 +#define INC47 48 +#define INC46 47 +#define INC45 46 +#define INC44 45 +#define INC43 44 +#define INC42 43 +#define INC41 42 +#define INC40 41 +#define INC39 40 +#define INC38 39 +#define INC37 38 +#define INC36 37 +#define INC35 36 +#define INC34 35 +#define INC33 34 +#define INC32 33 +#define INC31 32 +#define INC30 31 +#define INC29 30 +#define INC28 29 +#define INC27 28 +#define INC26 27 +#define INC25 26 +#define INC24 25 +#define INC23 24 +#define INC22 23 +#define INC21 22 +#define INC20 21 +#define INC19 20 +#define INC18 19 +#define INC17 18 +#define INC16 17 +#define INC15 16 +#define INC14 15 +#define INC13 14 +#define INC12 13 +#define INC11 12 +#define INC10 11 +#define INC9 10 +#define INC8 9 +#define INC7 8 +#define INC6 7 +#define INC5 6 +#define INC4 5 +#define INC3 4 +#define INC2 3 +#define INC1 2 +#define INC0 1 + +#define DIV2(x) C2(DIV2_,x) + +#define DIV2_1024 512 +#define DIV2_1023 511 +#define DIV2_1022 511 +#define DIV2_1021 510 +#define DIV2_1020 510 +#define DIV2_1019 509 +#define DIV2_1018 509 +#define DIV2_1017 508 +#define DIV2_1016 508 +#define DIV2_1015 507 +#define DIV2_1014 507 +#define DIV2_1013 506 +#define DIV2_1012 506 +#define DIV2_1011 505 +#define DIV2_1010 505 +#define DIV2_1009 504 +#define DIV2_1008 504 +#define DIV2_1007 503 +#define DIV2_1006 503 +#define DIV2_1005 502 +#define DIV2_1004 502 +#define DIV2_1003 501 +#define DIV2_1002 501 +#define DIV2_1001 500 +#define DIV2_1000 500 +#define DIV2_999 499 +#define DIV2_998 499 +#define DIV2_997 498 +#define DIV2_996 498 +#define DIV2_995 497 +#define DIV2_994 497 +#define DIV2_993 496 +#define DIV2_992 496 +#define DIV2_991 495 +#define DIV2_990 495 +#define DIV2_989 494 +#define DIV2_988 494 +#define DIV2_987 493 +#define DIV2_986 493 +#define DIV2_985 492 +#define DIV2_984 492 +#define DIV2_983 491 +#define DIV2_982 491 +#define DIV2_981 490 +#define DIV2_980 490 +#define DIV2_979 489 +#define DIV2_978 489 +#define DIV2_977 488 +#define DIV2_976 488 +#define DIV2_975 487 +#define DIV2_974 487 +#define DIV2_973 486 +#define DIV2_972 486 +#define DIV2_971 485 +#define DIV2_970 485 +#define DIV2_969 484 +#define DIV2_968 484 +#define DIV2_967 483 +#define DIV2_966 483 +#define DIV2_965 482 +#define DIV2_964 482 +#define DIV2_963 481 +#define DIV2_962 481 +#define DIV2_961 480 +#define DIV2_960 480 +#define DIV2_959 479 +#define DIV2_958 479 +#define DIV2_957 478 +#define DIV2_956 478 +#define DIV2_955 477 +#define DIV2_954 477 +#define DIV2_953 476 +#define DIV2_952 476 +#define DIV2_951 475 +#define DIV2_950 475 +#define DIV2_949 474 +#define DIV2_948 474 +#define DIV2_947 473 +#define DIV2_946 473 +#define DIV2_945 472 +#define DIV2_944 472 +#define DIV2_943 471 +#define DIV2_942 471 +#define DIV2_941 470 +#define DIV2_940 470 +#define DIV2_939 469 +#define DIV2_938 469 +#define DIV2_937 468 +#define DIV2_936 468 +#define DIV2_935 467 +#define DIV2_934 467 +#define DIV2_933 466 +#define DIV2_932 466 +#define DIV2_931 465 +#define DIV2_930 465 +#define DIV2_929 464 +#define DIV2_928 464 +#define DIV2_927 463 +#define DIV2_926 463 +#define DIV2_925 462 +#define DIV2_924 462 +#define DIV2_923 461 +#define DIV2_922 461 +#define DIV2_921 460 +#define DIV2_920 460 +#define DIV2_919 459 +#define DIV2_918 459 +#define DIV2_917 458 +#define DIV2_916 458 +#define DIV2_915 457 +#define DIV2_914 457 +#define DIV2_913 456 +#define DIV2_912 456 +#define DIV2_911 455 +#define DIV2_910 455 +#define DIV2_909 454 +#define DIV2_908 454 +#define DIV2_907 453 +#define DIV2_906 453 +#define DIV2_905 452 +#define DIV2_904 452 +#define DIV2_903 451 +#define DIV2_902 451 +#define DIV2_901 450 +#define DIV2_900 450 +#define DIV2_899 449 +#define DIV2_898 449 +#define DIV2_897 448 +#define DIV2_896 448 +#define DIV2_895 447 +#define DIV2_894 447 +#define DIV2_893 446 +#define DIV2_892 446 +#define DIV2_891 445 +#define DIV2_890 445 +#define DIV2_889 444 +#define DIV2_888 444 +#define DIV2_887 443 +#define DIV2_886 443 +#define DIV2_885 442 +#define DIV2_884 442 +#define DIV2_883 441 +#define DIV2_882 441 +#define DIV2_881 440 +#define DIV2_880 440 +#define DIV2_879 439 +#define DIV2_878 439 +#define DIV2_877 438 +#define DIV2_876 438 +#define DIV2_875 437 +#define DIV2_874 437 +#define DIV2_873 436 +#define DIV2_872 436 +#define DIV2_871 435 +#define DIV2_870 435 +#define DIV2_869 434 +#define DIV2_868 434 +#define DIV2_867 433 +#define DIV2_866 433 +#define DIV2_865 432 +#define DIV2_864 432 +#define DIV2_863 431 +#define DIV2_862 431 +#define DIV2_861 430 +#define DIV2_860 430 +#define DIV2_859 429 +#define DIV2_858 429 +#define DIV2_857 428 +#define DIV2_856 428 +#define DIV2_855 427 +#define DIV2_854 427 +#define DIV2_853 426 +#define DIV2_852 426 +#define DIV2_851 425 +#define DIV2_850 425 +#define DIV2_849 424 +#define DIV2_848 424 +#define DIV2_847 423 +#define DIV2_846 423 +#define DIV2_845 422 +#define DIV2_844 422 +#define DIV2_843 421 +#define DIV2_842 421 +#define DIV2_841 420 +#define DIV2_840 420 +#define DIV2_839 419 +#define DIV2_838 419 +#define DIV2_837 418 +#define DIV2_836 418 +#define DIV2_835 417 +#define DIV2_834 417 +#define DIV2_833 416 +#define DIV2_832 416 +#define DIV2_831 415 +#define DIV2_830 415 +#define DIV2_829 414 +#define DIV2_828 414 +#define DIV2_827 413 +#define DIV2_826 413 +#define DIV2_825 412 +#define DIV2_824 412 +#define DIV2_823 411 +#define DIV2_822 411 +#define DIV2_821 410 +#define DIV2_820 410 +#define DIV2_819 409 +#define DIV2_818 409 +#define DIV2_817 408 +#define DIV2_816 408 +#define DIV2_815 407 +#define DIV2_814 407 +#define DIV2_813 406 +#define DIV2_812 406 +#define DIV2_811 405 +#define DIV2_810 405 +#define DIV2_809 404 +#define DIV2_808 404 +#define DIV2_807 403 +#define DIV2_806 403 +#define DIV2_805 402 +#define DIV2_804 402 +#define DIV2_803 401 +#define DIV2_802 401 +#define DIV2_801 400 +#define DIV2_800 400 +#define DIV2_799 399 +#define DIV2_798 399 +#define DIV2_797 398 +#define DIV2_796 398 +#define DIV2_795 397 +#define DIV2_794 397 +#define DIV2_793 396 +#define DIV2_792 396 +#define DIV2_791 395 +#define DIV2_790 395 +#define DIV2_789 394 +#define DIV2_788 394 +#define DIV2_787 393 +#define DIV2_786 393 +#define DIV2_785 392 +#define DIV2_784 392 +#define DIV2_783 391 +#define DIV2_782 391 +#define DIV2_781 390 +#define DIV2_780 390 +#define DIV2_779 389 +#define DIV2_778 389 +#define DIV2_777 388 +#define DIV2_776 388 +#define DIV2_775 387 +#define DIV2_774 387 +#define DIV2_773 386 +#define DIV2_772 386 +#define DIV2_771 385 +#define DIV2_770 385 +#define DIV2_769 384 +#define DIV2_768 384 +#define DIV2_767 383 +#define DIV2_766 383 +#define DIV2_765 382 +#define DIV2_764 382 +#define DIV2_763 381 +#define DIV2_762 381 +#define DIV2_761 380 +#define DIV2_760 380 +#define DIV2_759 379 +#define DIV2_758 379 +#define DIV2_757 378 +#define DIV2_756 378 +#define DIV2_755 377 +#define DIV2_754 377 +#define DIV2_753 376 +#define DIV2_752 376 +#define DIV2_751 375 +#define DIV2_750 375 +#define DIV2_749 374 +#define DIV2_748 374 +#define DIV2_747 373 +#define DIV2_746 373 +#define DIV2_745 372 +#define DIV2_744 372 +#define DIV2_743 371 +#define DIV2_742 371 +#define DIV2_741 370 +#define DIV2_740 370 +#define DIV2_739 369 +#define DIV2_738 369 +#define DIV2_737 368 +#define DIV2_736 368 +#define DIV2_735 367 +#define DIV2_734 367 +#define DIV2_733 366 +#define DIV2_732 366 +#define DIV2_731 365 +#define DIV2_730 365 +#define DIV2_729 364 +#define DIV2_728 364 +#define DIV2_727 363 +#define DIV2_726 363 +#define DIV2_725 362 +#define DIV2_724 362 +#define DIV2_723 361 +#define DIV2_722 361 +#define DIV2_721 360 +#define DIV2_720 360 +#define DIV2_719 359 +#define DIV2_718 359 +#define DIV2_717 358 +#define DIV2_716 358 +#define DIV2_715 357 +#define DIV2_714 357 +#define DIV2_713 356 +#define DIV2_712 356 +#define DIV2_711 355 +#define DIV2_710 355 +#define DIV2_709 354 +#define DIV2_708 354 +#define DIV2_707 353 +#define DIV2_706 353 +#define DIV2_705 352 +#define DIV2_704 352 +#define DIV2_703 351 +#define DIV2_702 351 +#define DIV2_701 350 +#define DIV2_700 350 +#define DIV2_699 349 +#define DIV2_698 349 +#define DIV2_697 348 +#define DIV2_696 348 +#define DIV2_695 347 +#define DIV2_694 347 +#define DIV2_693 346 +#define DIV2_692 346 +#define DIV2_691 345 +#define DIV2_690 345 +#define DIV2_689 344 +#define DIV2_688 344 +#define DIV2_687 343 +#define DIV2_686 343 +#define DIV2_685 342 +#define DIV2_684 342 +#define DIV2_683 341 +#define DIV2_682 341 +#define DIV2_681 340 +#define DIV2_680 340 +#define DIV2_679 339 +#define DIV2_678 339 +#define DIV2_677 338 +#define DIV2_676 338 +#define DIV2_675 337 +#define DIV2_674 337 +#define DIV2_673 336 +#define DIV2_672 336 +#define DIV2_671 335 +#define DIV2_670 335 +#define DIV2_669 334 +#define DIV2_668 334 +#define DIV2_667 333 +#define DIV2_666 333 +#define DIV2_665 332 +#define DIV2_664 332 +#define DIV2_663 331 +#define DIV2_662 331 +#define DIV2_661 330 +#define DIV2_660 330 +#define DIV2_659 329 +#define DIV2_658 329 +#define DIV2_657 328 +#define DIV2_656 328 +#define DIV2_655 327 +#define DIV2_654 327 +#define DIV2_653 326 +#define DIV2_652 326 +#define DIV2_651 325 +#define DIV2_650 325 +#define DIV2_649 324 +#define DIV2_648 324 +#define DIV2_647 323 +#define DIV2_646 323 +#define DIV2_645 322 +#define DIV2_644 322 +#define DIV2_643 321 +#define DIV2_642 321 +#define DIV2_641 320 +#define DIV2_640 320 +#define DIV2_639 319 +#define DIV2_638 319 +#define DIV2_637 318 +#define DIV2_636 318 +#define DIV2_635 317 +#define DIV2_634 317 +#define DIV2_633 316 +#define DIV2_632 316 +#define DIV2_631 315 +#define DIV2_630 315 +#define DIV2_629 314 +#define DIV2_628 314 +#define DIV2_627 313 +#define DIV2_626 313 +#define DIV2_625 312 +#define DIV2_624 312 +#define DIV2_623 311 +#define DIV2_622 311 +#define DIV2_621 310 +#define DIV2_620 310 +#define DIV2_619 309 +#define DIV2_618 309 +#define DIV2_617 308 +#define DIV2_616 308 +#define DIV2_615 307 +#define DIV2_614 307 +#define DIV2_613 306 +#define DIV2_612 306 +#define DIV2_611 305 +#define DIV2_610 305 +#define DIV2_609 304 +#define DIV2_608 304 +#define DIV2_607 303 +#define DIV2_606 303 +#define DIV2_605 302 +#define DIV2_604 302 +#define DIV2_603 301 +#define DIV2_602 301 +#define DIV2_601 300 +#define DIV2_600 300 +#define DIV2_599 299 +#define DIV2_598 299 +#define DIV2_597 298 +#define DIV2_596 298 +#define DIV2_595 297 +#define DIV2_594 297 +#define DIV2_593 296 +#define DIV2_592 296 +#define DIV2_591 295 +#define DIV2_590 295 +#define DIV2_589 294 +#define DIV2_588 294 +#define DIV2_587 293 +#define DIV2_586 293 +#define DIV2_585 292 +#define DIV2_584 292 +#define DIV2_583 291 +#define DIV2_582 291 +#define DIV2_581 290 +#define DIV2_580 290 +#define DIV2_579 289 +#define DIV2_578 289 +#define DIV2_577 288 +#define DIV2_576 288 +#define DIV2_575 287 +#define DIV2_574 287 +#define DIV2_573 286 +#define DIV2_572 286 +#define DIV2_571 285 +#define DIV2_570 285 +#define DIV2_569 284 +#define DIV2_568 284 +#define DIV2_567 283 +#define DIV2_566 283 +#define DIV2_565 282 +#define DIV2_564 282 +#define DIV2_563 281 +#define DIV2_562 281 +#define DIV2_561 280 +#define DIV2_560 280 +#define DIV2_559 279 +#define DIV2_558 279 +#define DIV2_557 278 +#define DIV2_556 278 +#define DIV2_555 277 +#define DIV2_554 277 +#define DIV2_553 276 +#define DIV2_552 276 +#define DIV2_551 275 +#define DIV2_550 275 +#define DIV2_549 274 +#define DIV2_548 274 +#define DIV2_547 273 +#define DIV2_546 273 +#define DIV2_545 272 +#define DIV2_544 272 +#define DIV2_543 271 +#define DIV2_542 271 +#define DIV2_541 270 +#define DIV2_540 270 +#define DIV2_539 269 +#define DIV2_538 269 +#define DIV2_537 268 +#define DIV2_536 268 +#define DIV2_535 267 +#define DIV2_534 267 +#define DIV2_533 266 +#define DIV2_532 266 +#define DIV2_531 265 +#define DIV2_530 265 +#define DIV2_529 264 +#define DIV2_528 264 +#define DIV2_527 263 +#define DIV2_526 263 +#define DIV2_525 262 +#define DIV2_524 262 +#define DIV2_523 261 +#define DIV2_522 261 +#define DIV2_521 260 +#define DIV2_520 260 +#define DIV2_519 259 +#define DIV2_518 259 +#define DIV2_517 258 +#define DIV2_516 258 +#define DIV2_515 257 +#define DIV2_514 257 +#define DIV2_513 256 +#define DIV2_512 256 +#define DIV2_511 255 +#define DIV2_510 255 +#define DIV2_509 254 +#define DIV2_508 254 +#define DIV2_507 253 +#define DIV2_506 253 +#define DIV2_505 252 +#define DIV2_504 252 +#define DIV2_503 251 +#define DIV2_502 251 +#define DIV2_501 250 +#define DIV2_500 250 +#define DIV2_499 249 +#define DIV2_498 249 +#define DIV2_497 248 +#define DIV2_496 248 +#define DIV2_495 247 +#define DIV2_494 247 +#define DIV2_493 246 +#define DIV2_492 246 +#define DIV2_491 245 +#define DIV2_490 245 +#define DIV2_489 244 +#define DIV2_488 244 +#define DIV2_487 243 +#define DIV2_486 243 +#define DIV2_485 242 +#define DIV2_484 242 +#define DIV2_483 241 +#define DIV2_482 241 +#define DIV2_481 240 +#define DIV2_480 240 +#define DIV2_479 239 +#define DIV2_478 239 +#define DIV2_477 238 +#define DIV2_476 238 +#define DIV2_475 237 +#define DIV2_474 237 +#define DIV2_473 236 +#define DIV2_472 236 +#define DIV2_471 235 +#define DIV2_470 235 +#define DIV2_469 234 +#define DIV2_468 234 +#define DIV2_467 233 +#define DIV2_466 233 +#define DIV2_465 232 +#define DIV2_464 232 +#define DIV2_463 231 +#define DIV2_462 231 +#define DIV2_461 230 +#define DIV2_460 230 +#define DIV2_459 229 +#define DIV2_458 229 +#define DIV2_457 228 +#define DIV2_456 228 +#define DIV2_455 227 +#define DIV2_454 227 +#define DIV2_453 226 +#define DIV2_452 226 +#define DIV2_451 225 +#define DIV2_450 225 +#define DIV2_449 224 +#define DIV2_448 224 +#define DIV2_447 223 +#define DIV2_446 223 +#define DIV2_445 222 +#define DIV2_444 222 +#define DIV2_443 221 +#define DIV2_442 221 +#define DIV2_441 220 +#define DIV2_440 220 +#define DIV2_439 219 +#define DIV2_438 219 +#define DIV2_437 218 +#define DIV2_436 218 +#define DIV2_435 217 +#define DIV2_434 217 +#define DIV2_433 216 +#define DIV2_432 216 +#define DIV2_431 215 +#define DIV2_430 215 +#define DIV2_429 214 +#define DIV2_428 214 +#define DIV2_427 213 +#define DIV2_426 213 +#define DIV2_425 212 +#define DIV2_424 212 +#define DIV2_423 211 +#define DIV2_422 211 +#define DIV2_421 210 +#define DIV2_420 210 +#define DIV2_419 209 +#define DIV2_418 209 +#define DIV2_417 208 +#define DIV2_416 208 +#define DIV2_415 207 +#define DIV2_414 207 +#define DIV2_413 206 +#define DIV2_412 206 +#define DIV2_411 205 +#define DIV2_410 205 +#define DIV2_409 204 +#define DIV2_408 204 +#define DIV2_407 203 +#define DIV2_406 203 +#define DIV2_405 202 +#define DIV2_404 202 +#define DIV2_403 201 +#define DIV2_402 201 +#define DIV2_401 200 +#define DIV2_400 200 +#define DIV2_399 199 +#define DIV2_398 199 +#define DIV2_397 198 +#define DIV2_396 198 +#define DIV2_395 197 +#define DIV2_394 197 +#define DIV2_393 196 +#define DIV2_392 196 +#define DIV2_391 195 +#define DIV2_390 195 +#define DIV2_389 194 +#define DIV2_388 194 +#define DIV2_387 193 +#define DIV2_386 193 +#define DIV2_385 192 +#define DIV2_384 192 +#define DIV2_383 191 +#define DIV2_382 191 +#define DIV2_381 190 +#define DIV2_380 190 +#define DIV2_379 189 +#define DIV2_378 189 +#define DIV2_377 188 +#define DIV2_376 188 +#define DIV2_375 187 +#define DIV2_374 187 +#define DIV2_373 186 +#define DIV2_372 186 +#define DIV2_371 185 +#define DIV2_370 185 +#define DIV2_369 184 +#define DIV2_368 184 +#define DIV2_367 183 +#define DIV2_366 183 +#define DIV2_365 182 +#define DIV2_364 182 +#define DIV2_363 181 +#define DIV2_362 181 +#define DIV2_361 180 +#define DIV2_360 180 +#define DIV2_359 179 +#define DIV2_358 179 +#define DIV2_357 178 +#define DIV2_356 178 +#define DIV2_355 177 +#define DIV2_354 177 +#define DIV2_353 176 +#define DIV2_352 176 +#define DIV2_351 175 +#define DIV2_350 175 +#define DIV2_349 174 +#define DIV2_348 174 +#define DIV2_347 173 +#define DIV2_346 173 +#define DIV2_345 172 +#define DIV2_344 172 +#define DIV2_343 171 +#define DIV2_342 171 +#define DIV2_341 170 +#define DIV2_340 170 +#define DIV2_339 169 +#define DIV2_338 169 +#define DIV2_337 168 +#define DIV2_336 168 +#define DIV2_335 167 +#define DIV2_334 167 +#define DIV2_333 166 +#define DIV2_332 166 +#define DIV2_331 165 +#define DIV2_330 165 +#define DIV2_329 164 +#define DIV2_328 164 +#define DIV2_327 163 +#define DIV2_326 163 +#define DIV2_325 162 +#define DIV2_324 162 +#define DIV2_323 161 +#define DIV2_322 161 +#define DIV2_321 160 +#define DIV2_320 160 +#define DIV2_319 159 +#define DIV2_318 159 +#define DIV2_317 158 +#define DIV2_316 158 +#define DIV2_315 157 +#define DIV2_314 157 +#define DIV2_313 156 +#define DIV2_312 156 +#define DIV2_311 155 +#define DIV2_310 155 +#define DIV2_309 154 +#define DIV2_308 154 +#define DIV2_307 153 +#define DIV2_306 153 +#define DIV2_305 152 +#define DIV2_304 152 +#define DIV2_303 151 +#define DIV2_302 151 +#define DIV2_301 150 +#define DIV2_300 150 +#define DIV2_299 149 +#define DIV2_298 149 +#define DIV2_297 148 +#define DIV2_296 148 +#define DIV2_295 147 +#define DIV2_294 147 +#define DIV2_293 146 +#define DIV2_292 146 +#define DIV2_291 145 +#define DIV2_290 145 +#define DIV2_289 144 +#define DIV2_288 144 +#define DIV2_287 143 +#define DIV2_286 143 +#define DIV2_285 142 +#define DIV2_284 142 +#define DIV2_283 141 +#define DIV2_282 141 +#define DIV2_281 140 +#define DIV2_280 140 +#define DIV2_279 139 +#define DIV2_278 139 +#define DIV2_277 138 +#define DIV2_276 138 +#define DIV2_275 137 +#define DIV2_274 137 +#define DIV2_273 136 +#define DIV2_272 136 +#define DIV2_271 135 +#define DIV2_270 135 +#define DIV2_269 134 +#define DIV2_268 134 +#define DIV2_267 133 +#define DIV2_266 133 +#define DIV2_265 132 +#define DIV2_264 132 +#define DIV2_263 131 +#define DIV2_262 131 +#define DIV2_261 130 +#define DIV2_260 130 +#define DIV2_259 129 +#define DIV2_258 129 +#define DIV2_257 128 +#define DIV2_256 128 +#define DIV2_255 127 +#define DIV2_254 127 +#define DIV2_253 126 +#define DIV2_252 126 +#define DIV2_251 125 +#define DIV2_250 125 +#define DIV2_249 124 +#define DIV2_248 124 +#define DIV2_247 123 +#define DIV2_246 123 +#define DIV2_245 122 +#define DIV2_244 122 +#define DIV2_243 121 +#define DIV2_242 121 +#define DIV2_241 120 +#define DIV2_240 120 +#define DIV2_239 119 +#define DIV2_238 119 +#define DIV2_237 118 +#define DIV2_236 118 +#define DIV2_235 117 +#define DIV2_234 117 +#define DIV2_233 116 +#define DIV2_232 116 +#define DIV2_231 115 +#define DIV2_230 115 +#define DIV2_229 114 +#define DIV2_228 114 +#define DIV2_227 113 +#define DIV2_226 113 +#define DIV2_225 112 +#define DIV2_224 112 +#define DIV2_223 111 +#define DIV2_222 111 +#define DIV2_221 110 +#define DIV2_220 110 +#define DIV2_219 109 +#define DIV2_218 109 +#define DIV2_217 108 +#define DIV2_216 108 +#define DIV2_215 107 +#define DIV2_214 107 +#define DIV2_213 106 +#define DIV2_212 106 +#define DIV2_211 105 +#define DIV2_210 105 +#define DIV2_209 104 +#define DIV2_208 104 +#define DIV2_207 103 +#define DIV2_206 103 +#define DIV2_205 102 +#define DIV2_204 102 +#define DIV2_203 101 +#define DIV2_202 101 +#define DIV2_201 100 +#define DIV2_200 100 +#define DIV2_199 99 +#define DIV2_198 99 +#define DIV2_197 98 +#define DIV2_196 98 +#define DIV2_195 97 +#define DIV2_194 97 +#define DIV2_193 96 +#define DIV2_192 96 +#define DIV2_191 95 +#define DIV2_190 95 +#define DIV2_189 94 +#define DIV2_188 94 +#define DIV2_187 93 +#define DIV2_186 93 +#define DIV2_185 92 +#define DIV2_184 92 +#define DIV2_183 91 +#define DIV2_182 91 +#define DIV2_181 90 +#define DIV2_180 90 +#define DIV2_179 89 +#define DIV2_178 89 +#define DIV2_177 88 +#define DIV2_176 88 +#define DIV2_175 87 +#define DIV2_174 87 +#define DIV2_173 86 +#define DIV2_172 86 +#define DIV2_171 85 +#define DIV2_170 85 +#define DIV2_169 84 +#define DIV2_168 84 +#define DIV2_167 83 +#define DIV2_166 83 +#define DIV2_165 82 +#define DIV2_164 82 +#define DIV2_163 81 +#define DIV2_162 81 +#define DIV2_161 80 +#define DIV2_160 80 +#define DIV2_159 79 +#define DIV2_158 79 +#define DIV2_157 78 +#define DIV2_156 78 +#define DIV2_155 77 +#define DIV2_154 77 +#define DIV2_153 76 +#define DIV2_152 76 +#define DIV2_151 75 +#define DIV2_150 75 +#define DIV2_149 74 +#define DIV2_148 74 +#define DIV2_147 73 +#define DIV2_146 73 +#define DIV2_145 72 +#define DIV2_144 72 +#define DIV2_143 71 +#define DIV2_142 71 +#define DIV2_141 70 +#define DIV2_140 70 +#define DIV2_139 69 +#define DIV2_138 69 +#define DIV2_137 68 +#define DIV2_136 68 +#define DIV2_135 67 +#define DIV2_134 67 +#define DIV2_133 66 +#define DIV2_132 66 +#define DIV2_131 65 +#define DIV2_130 65 +#define DIV2_129 64 +#define DIV2_128 64 +#define DIV2_127 63 +#define DIV2_126 63 +#define DIV2_125 62 +#define DIV2_124 62 +#define DIV2_123 61 +#define DIV2_122 61 +#define DIV2_121 60 +#define DIV2_120 60 +#define DIV2_119 59 +#define DIV2_118 59 +#define DIV2_117 58 +#define DIV2_116 58 +#define DIV2_115 57 +#define DIV2_114 57 +#define DIV2_113 56 +#define DIV2_112 56 +#define DIV2_111 55 +#define DIV2_110 55 +#define DIV2_109 54 +#define DIV2_108 54 +#define DIV2_107 53 +#define DIV2_106 53 +#define DIV2_105 52 +#define DIV2_104 52 +#define DIV2_103 51 +#define DIV2_102 51 +#define DIV2_101 50 +#define DIV2_100 50 +#define DIV2_99 49 +#define DIV2_98 49 +#define DIV2_97 48 +#define DIV2_96 48 +#define DIV2_95 47 +#define DIV2_94 47 +#define DIV2_93 46 +#define DIV2_92 46 +#define DIV2_91 45 +#define DIV2_90 45 +#define DIV2_89 44 +#define DIV2_88 44 +#define DIV2_87 43 +#define DIV2_86 43 +#define DIV2_85 42 +#define DIV2_84 42 +#define DIV2_83 41 +#define DIV2_82 41 +#define DIV2_81 40 +#define DIV2_80 40 +#define DIV2_79 39 +#define DIV2_78 39 +#define DIV2_77 38 +#define DIV2_76 38 +#define DIV2_75 37 +#define DIV2_74 37 +#define DIV2_73 36 +#define DIV2_72 36 +#define DIV2_71 35 +#define DIV2_70 35 +#define DIV2_69 34 +#define DIV2_68 34 +#define DIV2_67 33 +#define DIV2_66 33 +#define DIV2_65 32 +#define DIV2_64 32 +#define DIV2_63 31 +#define DIV2_62 31 +#define DIV2_61 30 +#define DIV2_60 30 +#define DIV2_59 29 +#define DIV2_58 29 +#define DIV2_57 28 +#define DIV2_56 28 +#define DIV2_55 27 +#define DIV2_54 27 +#define DIV2_53 26 +#define DIV2_52 26 +#define DIV2_51 25 +#define DIV2_50 25 +#define DIV2_49 24 +#define DIV2_48 24 +#define DIV2_47 23 +#define DIV2_46 23 +#define DIV2_45 22 +#define DIV2_44 22 +#define DIV2_43 21 +#define DIV2_42 21 +#define DIV2_41 20 +#define DIV2_40 20 +#define DIV2_39 19 +#define DIV2_38 19 +#define DIV2_37 18 +#define DIV2_36 18 +#define DIV2_35 17 +#define DIV2_34 17 +#define DIV2_33 16 +#define DIV2_32 16 +#define DIV2_31 15 +#define DIV2_30 15 +#define DIV2_29 14 +#define DIV2_28 14 +#define DIV2_27 13 +#define DIV2_26 13 +#define DIV2_25 12 +#define DIV2_24 12 +#define DIV2_23 11 +#define DIV2_22 11 +#define DIV2_21 10 +#define DIV2_20 10 +#define DIV2_19 9 +#define DIV2_18 9 +#define DIV2_17 8 +#define DIV2_16 8 +#define DIV2_15 7 +#define DIV2_14 7 +#define DIV2_13 6 +#define DIV2_12 6 +#define DIV2_11 5 +#define DIV2_10 5 +#define DIV2_9 4 +#define DIV2_8 4 +#define DIV2_7 3 +#define DIV2_6 3 +#define DIV2_5 2 +#define DIV2_4 2 +#define DIV2_3 1 +#define DIV2_2 1 +#define DIV2_1 0 +#define DIV2_0 0 + +#define THE_NTH_ARG(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118, P119, P120, P121, P122, P123, P124, ... ) P124 + +#define _TRIGGER_PARENTHESIS_(...) , + +#ifdef _MSC_VER +#define LPAREN ( +#define COUNT_1_OR_MORE_ARG(...) THE_NTH_ARG LPAREN __VA_ARGS__, \ +123, 122, 121, 120, 119, 118, 117, 116, 115, 114, 113, 112, 111, 110, 109, 108, 107, 106, 105, 104, 103, 102, 101, 100, 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, 88, 87, 86, 85, 84, 83, 82, 81, 80, 79, 78, 77, 76, 75, 74, 73, 72, 71, 70, 69, 68, 67, 66, 65, 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1) +#define MORE_THAN_1_ARG(...) THE_NTH_ARG LPAREN __VA_ARGS__, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0) +#else +#define COUNT_1_OR_MORE_ARG(...) THE_NTH_ARG (__VA_ARGS__, \ +123, 122, 121, 120, 119, 118, 117, 116, 115, 114, 113, 112, 111, 110, 109, 108, 107, 106, 105, 104, 103, 102, 101, 100, 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, 88, 87, 86, 85, 84, 83, 82, 81, 80, 79, 78, 77, 76, 75, 74, 73, 72, 71, 70, 69, 68, 67, 66, 65, 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1) +#define MORE_THAN_1_ARG(...) THE_NTH_ARG(__VA_ARGS__, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 0) +#endif + +#define COUNT_ARG(...) C2(COUNT_ARG_, ISEMPTY(__VA_ARGS__))(__VA_ARGS__) +#define COUNT_ARG_1(...) 0 +#define COUNT_ARG_0(...) C1(COUNT_1_OR_MORE_ARG(__VA_ARGS__)) + +#define ISEMPTY(...) C3(DISPTACH_EMPTY_, MORE_THAN_1_ARG(_TRIGGER_PARENTHESIS_ __VA_ARGS__ ()), MORE_THAN_1_ARG(__VA_ARGS__)) +#define DISPTACH_EMPTY_10 1 +#define DISPTACH_EMPTY_00 0 +#define DISPTACH_EMPTY_11 0 + + +#define C2_(x,y) x##y + +#define C2(x,y) C2_(x,y) + +#define C3(x,y,z) C2(x, C2(y,z)) + +#define C4(x,y,z, u) C2(C2(x,y), C2(z,u)) + +#define C5(x,y,z,u, v) C2(C4(x,y, z, u), v) + +#define C1_(x) x + +#define C1(x) C1_(x) + +#define C2STRING(x,y) x y + +#define C3STRING(x,y,z) x y z + +#define C4STRING(x,y,z,u) x y z u + +#define C5STRING(x,y,z,u,v) x y z u v + + +#define FOR_EACH_1_124(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118, P119, P120, P121, P122, P123, P124) \ +X(P1) \ +FOR_EACH_1_123(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118, P119, P120, P121, P122, P123, P124) + +#define FOR_EACH_1_123(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118, P119, P120, P121, P122, P123) \ +X(P1) \ +FOR_EACH_1_122(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118, P119, P120, P121, P122, P123) + +#define FOR_EACH_1_122(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118, P119, P120, P121, P122) \ +X(P1) \ +FOR_EACH_1_121(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118, P119, P120, P121, P122) + +#define FOR_EACH_1_121(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118, P119, P120, P121) \ +X(P1) \ +FOR_EACH_1_120(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118, P119, P120, P121) + +#define FOR_EACH_1_120(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118, P119, P120) \ +X(P1) \ +FOR_EACH_1_119(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118, P119, P120) + +#define FOR_EACH_1_119(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118, P119) \ +X(P1) \ +FOR_EACH_1_118(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118, P119) + +#define FOR_EACH_1_118(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118) \ +X(P1) \ +FOR_EACH_1_117(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118) + +#define FOR_EACH_1_117(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117) \ +X(P1) \ +FOR_EACH_1_116(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117) + +#define FOR_EACH_1_116(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116) \ +X(P1) \ +FOR_EACH_1_115(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116) + +#define FOR_EACH_1_115(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115) \ +X(P1) \ +FOR_EACH_1_114(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115) + +#define FOR_EACH_1_114(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114) \ +X(P1) \ +FOR_EACH_1_113(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114) + +#define FOR_EACH_1_113(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113) \ +X(P1) \ +FOR_EACH_1_112(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113) + +#define FOR_EACH_1_112(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112) \ +X(P1) \ +FOR_EACH_1_111(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112) + +#define FOR_EACH_1_111(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111) \ +X(P1) \ +FOR_EACH_1_110(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111) + +#define FOR_EACH_1_110(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110) \ +X(P1) \ +FOR_EACH_1_109(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110) + +#define FOR_EACH_1_109(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109) \ +X(P1) \ +FOR_EACH_1_108(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109) + +#define FOR_EACH_1_108(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108) \ +X(P1) \ +FOR_EACH_1_107(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108) + +#define FOR_EACH_1_107(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107) \ +X(P1) \ +FOR_EACH_1_106(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107) + +#define FOR_EACH_1_106(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106) \ +X(P1) \ +FOR_EACH_1_105(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106) + +#define FOR_EACH_1_105(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105) \ +X(P1) \ +FOR_EACH_1_104(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105) + +#define FOR_EACH_1_104(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104) \ +X(P1) \ +FOR_EACH_1_103(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104) + +#define FOR_EACH_1_103(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103) \ +X(P1) \ +FOR_EACH_1_102(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103) + +#define FOR_EACH_1_102(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102) \ +X(P1) \ +FOR_EACH_1_101(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102) + +#define FOR_EACH_1_101(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101) \ +X(P1) \ +FOR_EACH_1_100(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101) + +#define FOR_EACH_1_100(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100) \ +X(P1) \ +FOR_EACH_1_99(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100) + +#define FOR_EACH_1_99(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99) \ +X(P1) \ +FOR_EACH_1_98(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99) + +#define FOR_EACH_1_98(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98) \ +X(P1) \ +FOR_EACH_1_97(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98) + +#define FOR_EACH_1_97(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97) \ +X(P1) \ +FOR_EACH_1_96(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97) + +#define FOR_EACH_1_96(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96) \ +X(P1) \ +FOR_EACH_1_95(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96) + +#define FOR_EACH_1_95(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95) \ +X(P1) \ +FOR_EACH_1_94(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95) + +#define FOR_EACH_1_94(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94) \ +X(P1) \ +FOR_EACH_1_93(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94) + +#define FOR_EACH_1_93(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93) \ +X(P1) \ +FOR_EACH_1_92(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93) + +#define FOR_EACH_1_92(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92) \ +X(P1) \ +FOR_EACH_1_91(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92) + +#define FOR_EACH_1_91(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91) \ +X(P1) \ +FOR_EACH_1_90(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91) + +#define FOR_EACH_1_90(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90) \ +X(P1) \ +FOR_EACH_1_89(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90) + +#define FOR_EACH_1_89(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89) \ +X(P1) \ +FOR_EACH_1_88(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89) + +#define FOR_EACH_1_88(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88) \ +X(P1) \ +FOR_EACH_1_87(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88) + +#define FOR_EACH_1_87(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87) \ +X(P1) \ +FOR_EACH_1_86(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87) + +#define FOR_EACH_1_86(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86) \ +X(P1) \ +FOR_EACH_1_85(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86) + +#define FOR_EACH_1_85(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85) \ +X(P1) \ +FOR_EACH_1_84(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85) + +#define FOR_EACH_1_84(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84) \ +X(P1) \ +FOR_EACH_1_83(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84) + +#define FOR_EACH_1_83(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83) \ +X(P1) \ +FOR_EACH_1_82(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83) + +#define FOR_EACH_1_82(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82) \ +X(P1) \ +FOR_EACH_1_81(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82) + +#define FOR_EACH_1_81(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81) \ +X(P1) \ +FOR_EACH_1_80(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81) + +#define FOR_EACH_1_80(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80) \ +X(P1) \ +FOR_EACH_1_79(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80) + +#define FOR_EACH_1_79(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79) \ +X(P1) \ +FOR_EACH_1_78(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79) + +#define FOR_EACH_1_78(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78) \ +X(P1) \ +FOR_EACH_1_77(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78) + +#define FOR_EACH_1_77(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77) \ +X(P1) \ +FOR_EACH_1_76(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77) + +#define FOR_EACH_1_76(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76) \ +X(P1) \ +FOR_EACH_1_75(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76) + +#define FOR_EACH_1_75(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75) \ +X(P1) \ +FOR_EACH_1_74(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75) + +#define FOR_EACH_1_74(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74) \ +X(P1) \ +FOR_EACH_1_73(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74) + +#define FOR_EACH_1_73(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73) \ +X(P1) \ +FOR_EACH_1_72(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73) + +#define FOR_EACH_1_72(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72) \ +X(P1) \ +FOR_EACH_1_71(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72) + +#define FOR_EACH_1_71(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71) \ +X(P1) \ +FOR_EACH_1_70(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71) + +#define FOR_EACH_1_70(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70) \ +X(P1) \ +FOR_EACH_1_69(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70) + +#define FOR_EACH_1_69(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69) \ +X(P1) \ +FOR_EACH_1_68(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69) + +#define FOR_EACH_1_68(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68) \ +X(P1) \ +FOR_EACH_1_67(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68) + +#define FOR_EACH_1_67(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67) \ +X(P1) \ +FOR_EACH_1_66(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67) + +#define FOR_EACH_1_66(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66) \ +X(P1) \ +FOR_EACH_1_65(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66) + +#define FOR_EACH_1_65(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65) \ +X(P1) \ +FOR_EACH_1_64(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65) + +#define FOR_EACH_1_64(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64) \ +X(P1) \ +FOR_EACH_1_63(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64) + +#define FOR_EACH_1_63(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63) \ +X(P1) \ +FOR_EACH_1_62(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63) + +#define FOR_EACH_1_62(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62) \ +X(P1) \ +FOR_EACH_1_61(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62) + +#define FOR_EACH_1_61(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61) \ +X(P1) \ +FOR_EACH_1_60(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61) + +#define FOR_EACH_1_60(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60) \ +X(P1) \ +FOR_EACH_1_59(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60) + +#define FOR_EACH_1_59(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59) \ +X(P1) \ +FOR_EACH_1_58(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59) + +#define FOR_EACH_1_58(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58) \ +X(P1) \ +FOR_EACH_1_57(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58) + +#define FOR_EACH_1_57(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57) \ +X(P1) \ +FOR_EACH_1_56(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57) + +#define FOR_EACH_1_56(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56) \ +X(P1) \ +FOR_EACH_1_55(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56) + +#define FOR_EACH_1_55(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55) \ +X(P1) \ +FOR_EACH_1_54(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55) + +#define FOR_EACH_1_54(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54) \ +X(P1) \ +FOR_EACH_1_53(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54) + +#define FOR_EACH_1_53(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53) \ +X(P1) \ +FOR_EACH_1_52(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53) + +#define FOR_EACH_1_52(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52) \ +X(P1) \ +FOR_EACH_1_51(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52) + +#define FOR_EACH_1_51(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51) \ +X(P1) \ +FOR_EACH_1_50(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51) + +#define FOR_EACH_1_50(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50) \ +X(P1) \ +FOR_EACH_1_49(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50) + +#define FOR_EACH_1_49(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49) \ +X(P1) \ +FOR_EACH_1_48(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49) + +#define FOR_EACH_1_48(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48) \ +X(P1) \ +FOR_EACH_1_47(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48) + +#define FOR_EACH_1_47(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47) \ +X(P1) \ +FOR_EACH_1_46(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47) + +#define FOR_EACH_1_46(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46) \ +X(P1) \ +FOR_EACH_1_45(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46) + +#define FOR_EACH_1_45(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45) \ +X(P1) \ +FOR_EACH_1_44(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45) + +#define FOR_EACH_1_44(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44) \ +X(P1) \ +FOR_EACH_1_43(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44) + +#define FOR_EACH_1_43(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43) \ +X(P1) \ +FOR_EACH_1_42(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43) + +#define FOR_EACH_1_42(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42) \ +X(P1) \ +FOR_EACH_1_41(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42) + +#define FOR_EACH_1_41(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41) \ +X(P1) \ +FOR_EACH_1_40(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41) + +#define FOR_EACH_1_40(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40) \ +X(P1) \ +FOR_EACH_1_39(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40) + +#define FOR_EACH_1_39(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39) \ +X(P1) \ +FOR_EACH_1_38(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39) + +#define FOR_EACH_1_38(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38) \ +X(P1) \ +FOR_EACH_1_37(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38) + +#define FOR_EACH_1_37(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37) \ +X(P1) \ +FOR_EACH_1_36(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37) + +#define FOR_EACH_1_36(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36) \ +X(P1) \ +FOR_EACH_1_35(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36) + +#define FOR_EACH_1_35(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35) \ +X(P1) \ +FOR_EACH_1_34(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35) + +#define FOR_EACH_1_34(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34) \ +X(P1) \ +FOR_EACH_1_33(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34) + +#define FOR_EACH_1_33(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33) \ +X(P1) \ +FOR_EACH_1_32(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33) + +#define FOR_EACH_1_32(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32) \ +X(P1) \ +FOR_EACH_1_31(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32) + +#define FOR_EACH_1_31(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31) \ +X(P1) \ +FOR_EACH_1_30(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31) + +#define FOR_EACH_1_30(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30) \ +X(P1) \ +FOR_EACH_1_29(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30) + +#define FOR_EACH_1_29(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29) \ +X(P1) \ +FOR_EACH_1_28(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29) + +#define FOR_EACH_1_28(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28) \ +X(P1) \ +FOR_EACH_1_27(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28) + +#define FOR_EACH_1_27(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27) \ +X(P1) \ +FOR_EACH_1_26(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27) + +#define FOR_EACH_1_26(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26) \ +X(P1) \ +FOR_EACH_1_25(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26) + +#define FOR_EACH_1_25(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25) \ +X(P1) \ +FOR_EACH_1_24(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25) + +#define FOR_EACH_1_24(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24) \ +X(P1) \ +FOR_EACH_1_23(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24) + +#define FOR_EACH_1_23(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23) \ +X(P1) \ +FOR_EACH_1_22(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23) + +#define FOR_EACH_1_22(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22) \ +X(P1) \ +FOR_EACH_1_21(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22) + +#define FOR_EACH_1_21(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21) \ +X(P1) \ +FOR_EACH_1_20(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21) + +#define FOR_EACH_1_20(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20) \ +X(P1) \ +FOR_EACH_1_19(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20) + +#define FOR_EACH_1_19(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19) \ +X(P1) \ +FOR_EACH_1_18(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19) + +#define FOR_EACH_1_18(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18) \ +X(P1) \ +FOR_EACH_1_17(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18) + +#define FOR_EACH_1_17(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17) \ +X(P1) \ +FOR_EACH_1_16(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17) + +#define FOR_EACH_1_16(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16) \ +X(P1) \ +FOR_EACH_1_15(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16) + +#define FOR_EACH_1_15(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15) \ +X(P1) \ +FOR_EACH_1_14(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15) + +#define FOR_EACH_1_14(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14) \ +X(P1) \ +FOR_EACH_1_13(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14) + +#define FOR_EACH_1_13(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13) \ +X(P1) \ +FOR_EACH_1_12(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13) + +#define FOR_EACH_1_12(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12) \ +X(P1) \ +FOR_EACH_1_11(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12) + +#define FOR_EACH_1_11(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11) \ +X(P1) \ +FOR_EACH_1_10(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11) + +#define FOR_EACH_1_10(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) \ +X(P1) \ +FOR_EACH_1_9(X, P2, P3, P4, P5, P6, P7, P8, P9, P10) + +#define FOR_EACH_1_9(X, P1, P2, P3, P4, P5, P6, P7, P8, P9) \ +X(P1) \ +FOR_EACH_1_8(X, P2, P3, P4, P5, P6, P7, P8, P9) + +#define FOR_EACH_1_8(X, P1, P2, P3, P4, P5, P6, P7, P8) \ +X(P1) \ +FOR_EACH_1_7(X, P2, P3, P4, P5, P6, P7, P8) + +#define FOR_EACH_1_7(X, P1, P2, P3, P4, P5, P6, P7) \ +X(P1) \ +FOR_EACH_1_6(X, P2, P3, P4, P5, P6, P7) + +#define FOR_EACH_1_6(X, P1, P2, P3, P4, P5, P6) \ +X(P1) \ +FOR_EACH_1_5(X, P2, P3, P4, P5, P6) + +#define FOR_EACH_1_5(X, P1, P2, P3, P4, P5) \ +X(P1) \ +FOR_EACH_1_4(X, P2, P3, P4, P5) + +#define FOR_EACH_1_4(X, P1, P2, P3, P4) \ +X(P1) \ +FOR_EACH_1_3(X, P2, P3, P4) + +#define FOR_EACH_1_3(X, P1, P2, P3) \ +X(P1) \ +FOR_EACH_1_2(X, P2, P3) + +#define FOR_EACH_1_2(X, P1, P2) \ +X(P1) \ +FOR_EACH_1_1(X, P2) + +#define FOR_EACH_1_1(X, P1) \ +X(P1) + +#ifdef _MSC_VER +#define FOR_EACH_1(MACRO_TO_INVOKE, ...) C2(FOR_EACH_1_,C1(COUNT_ARG(__VA_ARGS__))) LPAREN MACRO_TO_INVOKE, __VA_ARGS__) +#else +#define FOR_EACH_1(MACRO_TO_INVOKE, ...) C2(FOR_EACH_1_,C1(COUNT_ARG(__VA_ARGS__))) ( MACRO_TO_INVOKE, __VA_ARGS__) +#endif + +#define FOR_EACH_1_KEEP_1_124(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118, P119, P120, P121, P122, P123, P124) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_123(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118, P119, P120, P121, P122, P123, P124) + + +#define FOR_EACH_1_KEEP_1_123(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118, P119, P120, P121, P122, P123) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_122(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118, P119, P120, P121, P122, P123) + + +#define FOR_EACH_1_KEEP_1_122(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118, P119, P120, P121, P122) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_121(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118, P119, P120, P121, P122) + + +#define FOR_EACH_1_KEEP_1_121(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118, P119, P120, P121) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_120(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118, P119, P120, P121) + + +#define FOR_EACH_1_KEEP_1_120(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118, P119, P120) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_119(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118, P119, P120) + + +#define FOR_EACH_1_KEEP_1_119(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118, P119) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_118(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118, P119) + + +#define FOR_EACH_1_KEEP_1_118(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_117(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118) + + +#define FOR_EACH_1_KEEP_1_117(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_116(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117) + + +#define FOR_EACH_1_KEEP_1_116(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_115(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116) + + +#define FOR_EACH_1_KEEP_1_115(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_114(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115) + + +#define FOR_EACH_1_KEEP_1_114(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_113(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114) + + +#define FOR_EACH_1_KEEP_1_113(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_112(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113) + + +#define FOR_EACH_1_KEEP_1_112(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_111(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112) + + +#define FOR_EACH_1_KEEP_1_111(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_110(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111) + + +#define FOR_EACH_1_KEEP_1_110(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_109(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110) + + +#define FOR_EACH_1_KEEP_1_109(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_108(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109) + + +#define FOR_EACH_1_KEEP_1_108(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_107(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108) + + +#define FOR_EACH_1_KEEP_1_107(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_106(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107) + + +#define FOR_EACH_1_KEEP_1_106(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_105(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106) + + +#define FOR_EACH_1_KEEP_1_105(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_104(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105) + + +#define FOR_EACH_1_KEEP_1_104(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_103(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104) + + +#define FOR_EACH_1_KEEP_1_103(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_102(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103) + + +#define FOR_EACH_1_KEEP_1_102(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_101(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102) + + +#define FOR_EACH_1_KEEP_1_101(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_100(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101) + + +#define FOR_EACH_1_KEEP_1_100(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_99(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100) + + +#define FOR_EACH_1_KEEP_1_99(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_98(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99) + + +#define FOR_EACH_1_KEEP_1_98(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_97(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98) + + +#define FOR_EACH_1_KEEP_1_97(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_96(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97) + + +#define FOR_EACH_1_KEEP_1_96(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_95(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96) + + +#define FOR_EACH_1_KEEP_1_95(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_94(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95) + + +#define FOR_EACH_1_KEEP_1_94(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_93(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94) + + +#define FOR_EACH_1_KEEP_1_93(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_92(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93) + + +#define FOR_EACH_1_KEEP_1_92(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_91(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92) + + +#define FOR_EACH_1_KEEP_1_91(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_90(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91) + + +#define FOR_EACH_1_KEEP_1_90(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_89(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90) + + +#define FOR_EACH_1_KEEP_1_89(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_88(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89) + + +#define FOR_EACH_1_KEEP_1_88(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_87(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88) + + +#define FOR_EACH_1_KEEP_1_87(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_86(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87) + + +#define FOR_EACH_1_KEEP_1_86(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_85(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86) + + +#define FOR_EACH_1_KEEP_1_85(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_84(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85) + + +#define FOR_EACH_1_KEEP_1_84(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_83(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84) + + +#define FOR_EACH_1_KEEP_1_83(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_82(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83) + + +#define FOR_EACH_1_KEEP_1_82(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_81(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82) + + +#define FOR_EACH_1_KEEP_1_81(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_80(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81) + + +#define FOR_EACH_1_KEEP_1_80(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_79(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80) + + +#define FOR_EACH_1_KEEP_1_79(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_78(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79) + + +#define FOR_EACH_1_KEEP_1_78(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_77(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78) + + +#define FOR_EACH_1_KEEP_1_77(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_76(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77) + + +#define FOR_EACH_1_KEEP_1_76(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_75(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76) + + +#define FOR_EACH_1_KEEP_1_75(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_74(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75) + + +#define FOR_EACH_1_KEEP_1_74(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_73(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74) + + +#define FOR_EACH_1_KEEP_1_73(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_72(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73) + + +#define FOR_EACH_1_KEEP_1_72(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_71(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72) + + +#define FOR_EACH_1_KEEP_1_71(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_70(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71) + + +#define FOR_EACH_1_KEEP_1_70(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_69(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70) + + +#define FOR_EACH_1_KEEP_1_69(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_68(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69) + + +#define FOR_EACH_1_KEEP_1_68(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_67(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68) + + +#define FOR_EACH_1_KEEP_1_67(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_66(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67) + + +#define FOR_EACH_1_KEEP_1_66(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_65(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66) + + +#define FOR_EACH_1_KEEP_1_65(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_64(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65) + + +#define FOR_EACH_1_KEEP_1_64(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_63(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64) + + +#define FOR_EACH_1_KEEP_1_63(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_62(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63) + + +#define FOR_EACH_1_KEEP_1_62(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_61(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62) + + +#define FOR_EACH_1_KEEP_1_61(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_60(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61) + + +#define FOR_EACH_1_KEEP_1_60(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_59(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60) + + +#define FOR_EACH_1_KEEP_1_59(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_58(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59) + + +#define FOR_EACH_1_KEEP_1_58(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_57(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58) + + +#define FOR_EACH_1_KEEP_1_57(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_56(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57) + + +#define FOR_EACH_1_KEEP_1_56(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_55(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56) + + +#define FOR_EACH_1_KEEP_1_55(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_54(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55) + + +#define FOR_EACH_1_KEEP_1_54(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_53(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54) + + +#define FOR_EACH_1_KEEP_1_53(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_52(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53) + + +#define FOR_EACH_1_KEEP_1_52(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_51(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52) + + +#define FOR_EACH_1_KEEP_1_51(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_50(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51) + + +#define FOR_EACH_1_KEEP_1_50(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_49(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50) + + +#define FOR_EACH_1_KEEP_1_49(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_48(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49) + + +#define FOR_EACH_1_KEEP_1_48(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_47(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48) + + +#define FOR_EACH_1_KEEP_1_47(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_46(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47) + + +#define FOR_EACH_1_KEEP_1_46(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_45(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46) + + +#define FOR_EACH_1_KEEP_1_45(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_44(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45) + + +#define FOR_EACH_1_KEEP_1_44(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_43(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44) + + +#define FOR_EACH_1_KEEP_1_43(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_42(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43) + + +#define FOR_EACH_1_KEEP_1_42(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_41(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42) + + +#define FOR_EACH_1_KEEP_1_41(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_40(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41) + + +#define FOR_EACH_1_KEEP_1_40(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_39(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40) + + +#define FOR_EACH_1_KEEP_1_39(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_38(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39) + + +#define FOR_EACH_1_KEEP_1_38(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_37(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38) + + +#define FOR_EACH_1_KEEP_1_37(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_36(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37) + + +#define FOR_EACH_1_KEEP_1_36(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_35(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36) + + +#define FOR_EACH_1_KEEP_1_35(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_34(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35) + + +#define FOR_EACH_1_KEEP_1_34(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_33(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34) + + +#define FOR_EACH_1_KEEP_1_33(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_32(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33) + + +#define FOR_EACH_1_KEEP_1_32(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_31(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32) + + +#define FOR_EACH_1_KEEP_1_31(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_30(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31) + + +#define FOR_EACH_1_KEEP_1_30(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_29(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30) + + +#define FOR_EACH_1_KEEP_1_29(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_28(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29) + + +#define FOR_EACH_1_KEEP_1_28(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_27(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28) + + +#define FOR_EACH_1_KEEP_1_27(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_26(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27) + + +#define FOR_EACH_1_KEEP_1_26(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_25(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26) + + +#define FOR_EACH_1_KEEP_1_25(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_24(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25) + + +#define FOR_EACH_1_KEEP_1_24(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_23(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24) + + +#define FOR_EACH_1_KEEP_1_23(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_22(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23) + + +#define FOR_EACH_1_KEEP_1_22(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_21(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22) + + +#define FOR_EACH_1_KEEP_1_21(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_20(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21) + + +#define FOR_EACH_1_KEEP_1_20(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_19(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20) + + +#define FOR_EACH_1_KEEP_1_19(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_18(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19) + + +#define FOR_EACH_1_KEEP_1_18(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_17(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18) + + +#define FOR_EACH_1_KEEP_1_17(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_16(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17) + + +#define FOR_EACH_1_KEEP_1_16(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_15(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16) + + +#define FOR_EACH_1_KEEP_1_15(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_14(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15) + + +#define FOR_EACH_1_KEEP_1_14(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_13(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14) + + +#define FOR_EACH_1_KEEP_1_13(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_12(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13) + + +#define FOR_EACH_1_KEEP_1_12(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_11(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12) + + +#define FOR_EACH_1_KEEP_1_11(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_10(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11) + + +#define FOR_EACH_1_KEEP_1_10(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_9(X, keep, P2, P3, P4, P5, P6, P7, P8, P9, P10) + + +#define FOR_EACH_1_KEEP_1_9(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_8(X, keep, P2, P3, P4, P5, P6, P7, P8, P9) + + +#define FOR_EACH_1_KEEP_1_8(X, keep, P1, P2, P3, P4, P5, P6, P7, P8) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_7(X, keep, P2, P3, P4, P5, P6, P7, P8) + + +#define FOR_EACH_1_KEEP_1_7(X, keep, P1, P2, P3, P4, P5, P6, P7) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_6(X, keep, P2, P3, P4, P5, P6, P7) + + +#define FOR_EACH_1_KEEP_1_6(X, keep, P1, P2, P3, P4, P5, P6) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_5(X, keep, P2, P3, P4, P5, P6) + + +#define FOR_EACH_1_KEEP_1_5(X, keep, P1, P2, P3, P4, P5) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_4(X, keep, P2, P3, P4, P5) + + +#define FOR_EACH_1_KEEP_1_4(X, keep, P1, P2, P3, P4) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_3(X, keep, P2, P3, P4) + + +#define FOR_EACH_1_KEEP_1_3(X, keep, P1, P2, P3) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_2(X, keep, P2, P3) + + +#define FOR_EACH_1_KEEP_1_2(X, keep, P1, P2) \ +X(keep, P1) \ +FOR_EACH_1_KEEP_1_1(X, keep, P2) + + + +#define FOR_EACH_1_KEEP_1_1(X, keep, P1) \ +X(keep, P1) + +#ifdef _MSC_VER +#define FOR_EACH_1_KEEP_1(MACRO_TO_INVOKE, ...) C2(FOR_EACH_1_KEEP_1_, C2(DEC,C1(COUNT_ARG(__VA_ARGS__)))) LPAREN MACRO_TO_INVOKE, __VA_ARGS__) +#else +#define FOR_EACH_1_KEEP_1(MACRO_TO_INVOKE, ...) C2(FOR_EACH_1_KEEP_1_, C2(DEC,C1(COUNT_ARG(__VA_ARGS__)))) ( MACRO_TO_INVOKE, __VA_ARGS__) +#endif + +#define FOR_EACH_2_KEEP_1_124(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118, P119, P120, P121, P122, P123, P124) \ +X(keep, P1, P2) \ +FOR_EACH_2_KEEP_1_122(X, keep, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118, P119, P120, P121, P122, P123, P124) + + +#define FOR_EACH_2_KEEP_1_122(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118, P119, P120, P121, P122) \ +X(keep, P1, P2) \ +FOR_EACH_2_KEEP_1_120(X, keep, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118, P119, P120, P121, P122) + + +#define FOR_EACH_2_KEEP_1_120(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118, P119, P120) \ +X(keep, P1, P2) \ +FOR_EACH_2_KEEP_1_118(X, keep, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118, P119, P120) + + +#define FOR_EACH_2_KEEP_1_118(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118) \ +X(keep, P1, P2) \ +FOR_EACH_2_KEEP_1_116(X, keep, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118) + + +#define FOR_EACH_2_KEEP_1_116(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116) \ +X(keep, P1, P2) \ +FOR_EACH_2_KEEP_1_114(X, keep, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116) + + +#define FOR_EACH_2_KEEP_1_114(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114) \ +X(keep, P1, P2) \ +FOR_EACH_2_KEEP_1_112(X, keep, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114) + + +#define FOR_EACH_2_KEEP_1_112(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112) \ +X(keep, P1, P2) \ +FOR_EACH_2_KEEP_1_110(X, keep, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112) + + +#define FOR_EACH_2_KEEP_1_110(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110) \ +X(keep, P1, P2) \ +FOR_EACH_2_KEEP_1_108(X, keep, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110) + + +#define FOR_EACH_2_KEEP_1_108(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108) \ +X(keep, P1, P2) \ +FOR_EACH_2_KEEP_1_106(X, keep, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108) + + +#define FOR_EACH_2_KEEP_1_106(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106) \ +X(keep, P1, P2) \ +FOR_EACH_2_KEEP_1_104(X, keep, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106) + + +#define FOR_EACH_2_KEEP_1_104(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104) \ +X(keep, P1, P2) \ +FOR_EACH_2_KEEP_1_102(X, keep, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104) + + +#define FOR_EACH_2_KEEP_1_102(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102) \ +X(keep, P1, P2) \ +FOR_EACH_2_KEEP_1_100(X, keep, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102) + + +#define FOR_EACH_2_KEEP_1_100(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100) \ +X(keep, P1, P2) \ +FOR_EACH_2_KEEP_1_98(X, keep, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100) + + +#define FOR_EACH_2_KEEP_1_98(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98) \ +X(keep, P1, P2) \ +FOR_EACH_2_KEEP_1_96(X, keep, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98) + + +#define FOR_EACH_2_KEEP_1_96(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96) \ +X(keep, P1, P2) \ +FOR_EACH_2_KEEP_1_94(X, keep, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96) + + +#define FOR_EACH_2_KEEP_1_94(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94) \ +X(keep, P1, P2) \ +FOR_EACH_2_KEEP_1_92(X, keep, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94) + + +#define FOR_EACH_2_KEEP_1_92(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92) \ +X(keep, P1, P2) \ +FOR_EACH_2_KEEP_1_90(X, keep, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92) + + +#define FOR_EACH_2_KEEP_1_90(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90) \ +X(keep, P1, P2) \ +FOR_EACH_2_KEEP_1_88(X, keep, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90) + + +#define FOR_EACH_2_KEEP_1_88(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88) \ +X(keep, P1, P2) \ +FOR_EACH_2_KEEP_1_86(X, keep, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88) + + +#define FOR_EACH_2_KEEP_1_86(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86) \ +X(keep, P1, P2) \ +FOR_EACH_2_KEEP_1_84(X, keep, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86) + + +#define FOR_EACH_2_KEEP_1_84(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84) \ +X(keep, P1, P2) \ +FOR_EACH_2_KEEP_1_82(X, keep, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84) + + +#define FOR_EACH_2_KEEP_1_82(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82) \ +X(keep, P1, P2) \ +FOR_EACH_2_KEEP_1_80(X, keep, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82) + + +#define FOR_EACH_2_KEEP_1_80(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80) \ +X(keep, P1, P2) \ +FOR_EACH_2_KEEP_1_78(X, keep, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80) + + +#define FOR_EACH_2_KEEP_1_78(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78) \ +X(keep, P1, P2) \ +FOR_EACH_2_KEEP_1_76(X, keep, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78) + + +#define FOR_EACH_2_KEEP_1_76(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76) \ +X(keep, P1, P2) \ +FOR_EACH_2_KEEP_1_74(X, keep, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76) + + +#define FOR_EACH_2_KEEP_1_74(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74) \ +X(keep, P1, P2) \ +FOR_EACH_2_KEEP_1_72(X, keep, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74) + + +#define FOR_EACH_2_KEEP_1_72(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72) \ +X(keep, P1, P2) \ +FOR_EACH_2_KEEP_1_70(X, keep, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72) + + +#define FOR_EACH_2_KEEP_1_70(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70) \ +X(keep, P1, P2) \ +FOR_EACH_2_KEEP_1_68(X, keep, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70) + + +#define FOR_EACH_2_KEEP_1_68(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68) \ +X(keep, P1, P2) \ +FOR_EACH_2_KEEP_1_66(X, keep, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68) + + +#define FOR_EACH_2_KEEP_1_66(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66) \ +X(keep, P1, P2) \ +FOR_EACH_2_KEEP_1_64(X, keep, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66) + + +#define FOR_EACH_2_KEEP_1_64(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64) \ +X(keep, P1, P2) \ +FOR_EACH_2_KEEP_1_62(X, keep, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64) + + +#define FOR_EACH_2_KEEP_1_62(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62) \ +X(keep, P1, P2) \ +FOR_EACH_2_KEEP_1_60(X, keep, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62) + + +#define FOR_EACH_2_KEEP_1_60(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60) \ +X(keep, P1, P2) \ +FOR_EACH_2_KEEP_1_58(X, keep, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60) + + +#define FOR_EACH_2_KEEP_1_58(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58) \ +X(keep, P1, P2) \ +FOR_EACH_2_KEEP_1_56(X, keep, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58) + + +#define FOR_EACH_2_KEEP_1_56(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56) \ +X(keep, P1, P2) \ +FOR_EACH_2_KEEP_1_54(X, keep, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56) + + +#define FOR_EACH_2_KEEP_1_54(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54) \ +X(keep, P1, P2) \ +FOR_EACH_2_KEEP_1_52(X, keep, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54) + + +#define FOR_EACH_2_KEEP_1_52(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52) \ +X(keep, P1, P2) \ +FOR_EACH_2_KEEP_1_50(X, keep, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52) + + +#define FOR_EACH_2_KEEP_1_50(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50) \ +X(keep, P1, P2) \ +FOR_EACH_2_KEEP_1_48(X, keep, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50) + + +#define FOR_EACH_2_KEEP_1_48(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48) \ +X(keep, P1, P2) \ +FOR_EACH_2_KEEP_1_46(X, keep, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48) + + +#define FOR_EACH_2_KEEP_1_46(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46) \ +X(keep, P1, P2) \ +FOR_EACH_2_KEEP_1_44(X, keep, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46) + + +#define FOR_EACH_2_KEEP_1_44(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44) \ +X(keep, P1, P2) \ +FOR_EACH_2_KEEP_1_42(X, keep, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44) + + +#define FOR_EACH_2_KEEP_1_42(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42) \ +X(keep, P1, P2) \ +FOR_EACH_2_KEEP_1_40(X, keep, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42) + + +#define FOR_EACH_2_KEEP_1_40(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40) \ +X(keep, P1, P2) \ +FOR_EACH_2_KEEP_1_38(X, keep, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40) + + +#define FOR_EACH_2_KEEP_1_38(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38) \ +X(keep, P1, P2) \ +FOR_EACH_2_KEEP_1_36(X, keep, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38) + + +#define FOR_EACH_2_KEEP_1_36(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36) \ +X(keep, P1, P2) \ +FOR_EACH_2_KEEP_1_34(X, keep, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36) + + +#define FOR_EACH_2_KEEP_1_34(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34) \ +X(keep, P1, P2) \ +FOR_EACH_2_KEEP_1_32(X, keep, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34) + + +#define FOR_EACH_2_KEEP_1_32(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32) \ +X(keep, P1, P2) \ +FOR_EACH_2_KEEP_1_30(X, keep, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32) + + +#define FOR_EACH_2_KEEP_1_30(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30) \ +X(keep, P1, P2) \ +FOR_EACH_2_KEEP_1_28(X, keep, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30) + + +#define FOR_EACH_2_KEEP_1_28(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28) \ +X(keep, P1, P2) \ +FOR_EACH_2_KEEP_1_26(X, keep, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28) + + +#define FOR_EACH_2_KEEP_1_26(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26) \ +X(keep, P1, P2) \ +FOR_EACH_2_KEEP_1_24(X, keep, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26) + + +#define FOR_EACH_2_KEEP_1_24(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24) \ +X(keep, P1, P2) \ +FOR_EACH_2_KEEP_1_22(X, keep, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24) + + +#define FOR_EACH_2_KEEP_1_22(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22) \ +X(keep, P1, P2) \ +FOR_EACH_2_KEEP_1_20(X, keep, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22) + + +#define FOR_EACH_2_KEEP_1_20(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20) \ +X(keep, P1, P2) \ +FOR_EACH_2_KEEP_1_18(X, keep, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20) + + +#define FOR_EACH_2_KEEP_1_18(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18) \ +X(keep, P1, P2) \ +FOR_EACH_2_KEEP_1_16(X, keep, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18) + + +#define FOR_EACH_2_KEEP_1_16(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16) \ +X(keep, P1, P2) \ +FOR_EACH_2_KEEP_1_14(X, keep, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16) + + +#define FOR_EACH_2_KEEP_1_14(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14) \ +X(keep, P1, P2) \ +FOR_EACH_2_KEEP_1_12(X, keep, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14) + + +#define FOR_EACH_2_KEEP_1_12(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12) \ +X(keep, P1, P2) \ +FOR_EACH_2_KEEP_1_10(X, keep, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12) + + +#define FOR_EACH_2_KEEP_1_10(X, keep, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) \ +X(keep, P1, P2) \ +FOR_EACH_2_KEEP_1_8(X, keep, P3, P4, P5, P6, P7, P8, P9, P10) + + +#define FOR_EACH_2_KEEP_1_8(X, keep, P1, P2, P3, P4, P5, P6, P7, P8) \ +X(keep, P1, P2) \ +FOR_EACH_2_KEEP_1_6(X, keep, P3, P4, P5, P6, P7, P8) + + +#define FOR_EACH_2_KEEP_1_6(X, keep, P1, P2, P3, P4, P5, P6) \ +X(keep, P1, P2) \ +FOR_EACH_2_KEEP_1_4(X, keep, P3, P4, P5, P6) + + +#define FOR_EACH_2_KEEP_1_4(X, keep, P1, P2, P3, P4) \ +X(keep, P1, P2) \ +FOR_EACH_2_KEEP_1_2(X, keep, P3, P4) + + + +#define FOR_EACH_2_KEEP_1_2(X, keep, P1, P2) \ + X(keep, P1, P2) \ + +#ifdef _MSC_VER +#define FOR_EACH_2_KEEP_1(MACRO_TO_INVOKE, ...) C2(FOR_EACH_2_KEEP_1_, C2(DEC,C1(COUNT_ARG(__VA_ARGS__)))) LPAREN MACRO_TO_INVOKE, __VA_ARGS__) +#else +#define FOR_EACH_2_KEEP_1(MACRO_TO_INVOKE, ...) C2(FOR_EACH_2_KEEP_1_, C2(DEC,C1(COUNT_ARG(__VA_ARGS__)))) ( MACRO_TO_INVOKE, __VA_ARGS__) +#endif + +#define FOR_EACH_2_0(...) + +#define FOR_EACH_2_2(X, P1, P2) \ +X(P1, P2) + +#define FOR_EACH_2_4(X, P1, P2, P3, P4) \ +X(P1, P2) \ +FOR_EACH_2_2(X, P3, P4) + +#define FOR_EACH_2_6(X, P1, P2, P3, P4, P5, P6) \ +X(P1, P2) \ +FOR_EACH_2_4(X, P3, P4, P5, P6) + +#define FOR_EACH_2_8(X, P1, P2, P3, P4, P5, P6, P7, P8) \ +X(P1, P2) \ +FOR_EACH_2_6(X, P3, P4, P5, P6, P7, P8) + +#define FOR_EACH_2_10(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) \ +X(P1, P2) \ +FOR_EACH_2_8(X, P3, P4, P5, P6, P7, P8, P9, P10) + +#define FOR_EACH_2_12(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12) \ +X(P1, P2) \ +FOR_EACH_2_10(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12) + +#define FOR_EACH_2_14(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14) \ +X(P1, P2) \ +FOR_EACH_2_12(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14) + +#define FOR_EACH_2_16(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16) \ +X(P1, P2) \ +FOR_EACH_2_14(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16) + +#define FOR_EACH_2_18(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18) \ +X(P1, P2) \ +FOR_EACH_2_16(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18) + +#define FOR_EACH_2_20(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20) \ +X(P1, P2) \ +FOR_EACH_2_18(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20) + +#define FOR_EACH_2_22(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22) \ +X(P1, P2) \ +FOR_EACH_2_20(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22) + +#define FOR_EACH_2_24(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24) \ +X(P1, P2) \ +FOR_EACH_2_22(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24) + +#define FOR_EACH_2_26(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26) \ +X(P1, P2) \ +FOR_EACH_2_24(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26) + +#define FOR_EACH_2_28(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28) \ +X(P1, P2) \ +FOR_EACH_2_26(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28) + +#define FOR_EACH_2_30(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30) \ +X(P1, P2) \ +FOR_EACH_2_28(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30) + +#define FOR_EACH_2_32(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32) \ +X(P1, P2) \ +FOR_EACH_2_30(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32) + +#define FOR_EACH_2_34(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34) \ +X(P1, P2) \ +FOR_EACH_2_32(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34) + +#define FOR_EACH_2_36(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36) \ +X(P1, P2) \ +FOR_EACH_2_34(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36) + +#define FOR_EACH_2_38(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38) \ +X(P1, P2) \ +FOR_EACH_2_36(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38) + +#define FOR_EACH_2_40(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40) \ +X(P1, P2) \ +FOR_EACH_2_38(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40) + +#define FOR_EACH_2_42(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42) \ +X(P1, P2) \ +FOR_EACH_2_40(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42) + +#define FOR_EACH_2_44(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44) \ +X(P1, P2) \ +FOR_EACH_2_42(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44) + +#define FOR_EACH_2_46(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46) \ +X(P1, P2) \ +FOR_EACH_2_44(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46) + +#define FOR_EACH_2_48(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48) \ +X(P1, P2) \ +FOR_EACH_2_46(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48) + +#define FOR_EACH_2_50(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50) \ +X(P1, P2) \ +FOR_EACH_2_48(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50) + +#define FOR_EACH_2_52(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52) \ +X(P1, P2) \ +FOR_EACH_2_50(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52) + +#define FOR_EACH_2_54(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54) \ +X(P1, P2) \ +FOR_EACH_2_52(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54) + +#define FOR_EACH_2_56(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56) \ +X(P1, P2) \ +FOR_EACH_2_54(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56) + +#define FOR_EACH_2_58(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58) \ +X(P1, P2) \ +FOR_EACH_2_56(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58) + +#define FOR_EACH_2_60(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60) \ +X(P1, P2) \ +FOR_EACH_2_58(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60) + +#define FOR_EACH_2_62(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62) \ +X(P1, P2) \ +FOR_EACH_2_60(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62) + +#define FOR_EACH_2_64(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64) \ +X(P1, P2) \ +FOR_EACH_2_62(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64) + +#define FOR_EACH_2_66(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66) \ +X(P1, P2) \ +FOR_EACH_2_64(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66) + +#define FOR_EACH_2_68(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68) \ +X(P1, P2) \ +FOR_EACH_2_66(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68) + +#define FOR_EACH_2_70(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70) \ +X(P1, P2) \ +FOR_EACH_2_68(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70) + +#define FOR_EACH_2_72(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72) \ +X(P1, P2) \ +FOR_EACH_2_70(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72) + +#define FOR_EACH_2_74(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74) \ +X(P1, P2) \ +FOR_EACH_2_72(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74) + +#define FOR_EACH_2_76(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76) \ +X(P1, P2) \ +FOR_EACH_2_74(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76) + +#define FOR_EACH_2_78(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78) \ +X(P1, P2) \ +FOR_EACH_2_76(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78) + +#define FOR_EACH_2_80(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80) \ +X(P1, P2) \ +FOR_EACH_2_78(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80) + +#define FOR_EACH_2_82(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82) \ +X(P1, P2) \ +FOR_EACH_2_80(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82) + +#define FOR_EACH_2_84(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84) \ +X(P1, P2) \ +FOR_EACH_2_82(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84) + +#define FOR_EACH_2_86(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86) \ +X(P1, P2) \ +FOR_EACH_2_84(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86) + +#define FOR_EACH_2_88(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88) \ +X(P1, P2) \ +FOR_EACH_2_86(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88) + +#define FOR_EACH_2_90(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90) \ +X(P1, P2) \ +FOR_EACH_2_88(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90) + +#define FOR_EACH_2_92(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92) \ +X(P1, P2) \ +FOR_EACH_2_90(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92) + +#define FOR_EACH_2_94(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94) \ +X(P1, P2) \ +FOR_EACH_2_92(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94) + +#define FOR_EACH_2_96(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96) \ +X(P1, P2) \ +FOR_EACH_2_94(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96) + +#define FOR_EACH_2_98(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98) \ +X(P1, P2) \ +FOR_EACH_2_96(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98) + +#define FOR_EACH_2_100(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100) \ +X(P1, P2) \ +FOR_EACH_2_98(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100) + +#define FOR_EACH_2_102(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102) \ +X(P1, P2) \ +FOR_EACH_2_100(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102) + +#define FOR_EACH_2_104(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104) \ +X(P1, P2) \ +FOR_EACH_2_102(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104) + +#define FOR_EACH_2_106(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106) \ +X(P1, P2) \ +FOR_EACH_2_104(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106) + +#define FOR_EACH_2_108(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108) \ +X(P1, P2) \ +FOR_EACH_2_106(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108) + +#define FOR_EACH_2_110(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110) \ +X(P1, P2) \ +FOR_EACH_2_108(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110) + +#define FOR_EACH_2_112(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112) \ +X(P1, P2) \ +FOR_EACH_2_110(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112) + +#define FOR_EACH_2_114(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114) \ +X(P1, P2) \ +FOR_EACH_2_112(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114) + +#define FOR_EACH_2_116(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116) \ +X(P1, P2) \ +FOR_EACH_2_114(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116) + +#define FOR_EACH_2_118(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118) \ +X(P1, P2) \ +FOR_EACH_2_116(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118) + +#define FOR_EACH_2_120(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118, P119, P120) \ +X(P1, P2) \ +FOR_EACH_2_118(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118, P119, P120) + +#define FOR_EACH_2_122(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118, P119, P120, P121, P122) \ +X(P1, P2) \ +FOR_EACH_2_120(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118, P119, P120, P121, P122) + +#define FOR_EACH_2_124(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118, P119, P120, P121, P122, P123, P124) \ +X(P1, P2) \ +FOR_EACH_2_122(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118, P119, P120, P121, P122, P123, P124) + + +#define FOR_EACH_1_COUNTED_0(...) + +#define FOR_EACH_1_COUNTED_1(X, P1) \ + X(1, P1) + +#define FOR_EACH_1_COUNTED_2(X, P1, P2) \ +X(2, P1) \ +FOR_EACH_1_COUNTED_1(X, P2) + +#define FOR_EACH_1_COUNTED_3(X, P1, P2, P3) \ +X(3, P1) \ +FOR_EACH_1_COUNTED_2(X, P2, P3) + +#define FOR_EACH_1_COUNTED_4(X, P1, P2, P3, P4) \ +X(4, P1) \ +FOR_EACH_1_COUNTED_3(X, P2, P3, P4) + +#define FOR_EACH_1_COUNTED_5(X, P1, P2, P3, P4, P5) \ +X(5, P1) \ +FOR_EACH_1_COUNTED_4(X, P2, P3, P4, P5) + +#define FOR_EACH_1_COUNTED_6(X, P1, P2, P3, P4, P5, P6) \ +X(6, P1) \ +FOR_EACH_1_COUNTED_5(X, P2, P3, P4, P5, P6) + +#define FOR_EACH_1_COUNTED_7(X, P1, P2, P3, P4, P5, P6, P7) \ +X(7, P1) \ +FOR_EACH_1_COUNTED_6(X, P2, P3, P4, P5, P6, P7) + +#define FOR_EACH_1_COUNTED_8(X, P1, P2, P3, P4, P5, P6, P7, P8) \ +X(8, P1) \ +FOR_EACH_1_COUNTED_7(X, P2, P3, P4, P5, P6, P7, P8) + +#define FOR_EACH_1_COUNTED_9(X, P1, P2, P3, P4, P5, P6, P7, P8, P9) \ +X(9, P1) \ +FOR_EACH_1_COUNTED_8(X, P2, P3, P4, P5, P6, P7, P8, P9) + +#define FOR_EACH_1_COUNTED_10(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) \ +X(10, P1) \ +FOR_EACH_1_COUNTED_9(X, P2, P3, P4, P5, P6, P7, P8, P9, P10) + +#define FOR_EACH_1_COUNTED_11(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11) \ +X(11, P1) \ +FOR_EACH_1_COUNTED_10(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11) + +#define FOR_EACH_1_COUNTED_12(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12) \ +X(12, P1) \ +FOR_EACH_1_COUNTED_11(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12) + +#define FOR_EACH_1_COUNTED_13(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13) \ +X(13, P1) \ +FOR_EACH_1_COUNTED_12(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13) + +#define FOR_EACH_1_COUNTED_14(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14) \ +X(14, P1) \ +FOR_EACH_1_COUNTED_13(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14) + +#define FOR_EACH_1_COUNTED_15(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15) \ +X(15, P1) \ +FOR_EACH_1_COUNTED_14(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15) + +#define FOR_EACH_1_COUNTED_16(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16) \ +X(16, P1) \ +FOR_EACH_1_COUNTED_15(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16) + +#define FOR_EACH_1_COUNTED_17(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17) \ +X(17, P1) \ +FOR_EACH_1_COUNTED_16(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17) + +#define FOR_EACH_1_COUNTED_18(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18) \ +X(18, P1) \ +FOR_EACH_1_COUNTED_17(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18) + +#define FOR_EACH_1_COUNTED_19(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19) \ +X(19, P1) \ +FOR_EACH_1_COUNTED_18(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19) + +#define FOR_EACH_1_COUNTED_20(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20) \ +X(20, P1) \ +FOR_EACH_1_COUNTED_19(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20) + +#define FOR_EACH_1_COUNTED_21(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21) \ +X(21, P1) \ +FOR_EACH_1_COUNTED_20(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21) + +#define FOR_EACH_1_COUNTED_22(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22) \ +X(22, P1) \ +FOR_EACH_1_COUNTED_21(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22) + +#define FOR_EACH_1_COUNTED_23(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23) \ +X(23, P1) \ +FOR_EACH_1_COUNTED_22(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23) + +#define FOR_EACH_1_COUNTED_24(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24) \ +X(24, P1) \ +FOR_EACH_1_COUNTED_23(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24) + +#define FOR_EACH_1_COUNTED_25(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25) \ +X(25, P1) \ +FOR_EACH_1_COUNTED_24(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25) + +#define FOR_EACH_1_COUNTED_26(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26) \ +X(26, P1) \ +FOR_EACH_1_COUNTED_25(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26) + +#define FOR_EACH_1_COUNTED_27(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27) \ +X(27, P1) \ +FOR_EACH_1_COUNTED_26(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27) + +#define FOR_EACH_1_COUNTED_28(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28) \ +X(28, P1) \ +FOR_EACH_1_COUNTED_27(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28) + +#define FOR_EACH_1_COUNTED_29(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29) \ +X(29, P1) \ +FOR_EACH_1_COUNTED_28(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29) + +#define FOR_EACH_1_COUNTED_30(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30) \ +X(30, P1) \ +FOR_EACH_1_COUNTED_29(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30) + +#define FOR_EACH_1_COUNTED_31(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31) \ +X(31, P1) \ +FOR_EACH_1_COUNTED_30(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31) + +#define FOR_EACH_1_COUNTED_32(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32) \ +X(32, P1) \ +FOR_EACH_1_COUNTED_31(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32) + +#define FOR_EACH_1_COUNTED_33(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33) \ +X(33, P1) \ +FOR_EACH_1_COUNTED_32(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33) + +#define FOR_EACH_1_COUNTED_34(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34) \ +X(34, P1) \ +FOR_EACH_1_COUNTED_33(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34) + +#define FOR_EACH_1_COUNTED_35(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35) \ +X(35, P1) \ +FOR_EACH_1_COUNTED_34(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35) + +#define FOR_EACH_1_COUNTED_36(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36) \ +X(36, P1) \ +FOR_EACH_1_COUNTED_35(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36) + +#define FOR_EACH_1_COUNTED_37(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37) \ +X(37, P1) \ +FOR_EACH_1_COUNTED_36(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37) + +#define FOR_EACH_1_COUNTED_38(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38) \ +X(38, P1) \ +FOR_EACH_1_COUNTED_37(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38) + +#define FOR_EACH_1_COUNTED_39(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39) \ +X(39, P1) \ +FOR_EACH_1_COUNTED_38(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39) + +#define FOR_EACH_1_COUNTED_40(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40) \ +X(40, P1) \ +FOR_EACH_1_COUNTED_39(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40) + +#define FOR_EACH_1_COUNTED_41(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41) \ +X(41, P1) \ +FOR_EACH_1_COUNTED_40(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41) + +#define FOR_EACH_1_COUNTED_42(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42) \ +X(42, P1) \ +FOR_EACH_1_COUNTED_41(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42) + +#define FOR_EACH_1_COUNTED_43(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43) \ +X(43, P1) \ +FOR_EACH_1_COUNTED_42(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43) + +#define FOR_EACH_1_COUNTED_44(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44) \ +X(44, P1) \ +FOR_EACH_1_COUNTED_43(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44) + +#define FOR_EACH_1_COUNTED_45(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45) \ +X(45, P1) \ +FOR_EACH_1_COUNTED_44(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45) + +#define FOR_EACH_1_COUNTED_46(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46) \ +X(46, P1) \ +FOR_EACH_1_COUNTED_45(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46) + +#define FOR_EACH_1_COUNTED_47(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47) \ +X(47, P1) \ +FOR_EACH_1_COUNTED_46(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47) + +#define FOR_EACH_1_COUNTED_48(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48) \ +X(48, P1) \ +FOR_EACH_1_COUNTED_47(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48) + +#define FOR_EACH_1_COUNTED_49(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49) \ +X(49, P1) \ +FOR_EACH_1_COUNTED_48(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49) + +#define FOR_EACH_1_COUNTED_50(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50) \ +X(50, P1) \ +FOR_EACH_1_COUNTED_49(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50) + +#define FOR_EACH_1_COUNTED_51(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51) \ +X(51, P1) \ +FOR_EACH_1_COUNTED_50(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51) + +#define FOR_EACH_1_COUNTED_52(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52) \ +X(52, P1) \ +FOR_EACH_1_COUNTED_51(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52) + +#define FOR_EACH_1_COUNTED_53(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53) \ +X(53, P1) \ +FOR_EACH_1_COUNTED_52(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53) + +#define FOR_EACH_1_COUNTED_54(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54) \ +X(54, P1) \ +FOR_EACH_1_COUNTED_53(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54) + +#define FOR_EACH_1_COUNTED_55(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55) \ +X(55, P1) \ +FOR_EACH_1_COUNTED_54(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55) + +#define FOR_EACH_1_COUNTED_56(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56) \ +X(56, P1) \ +FOR_EACH_1_COUNTED_55(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56) + +#define FOR_EACH_1_COUNTED_57(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57) \ +X(57, P1) \ +FOR_EACH_1_COUNTED_56(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57) + +#define FOR_EACH_1_COUNTED_58(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58) \ +X(58, P1) \ +FOR_EACH_1_COUNTED_57(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58) + +#define FOR_EACH_1_COUNTED_59(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59) \ +X(59, P1) \ +FOR_EACH_1_COUNTED_58(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59) + +#define FOR_EACH_1_COUNTED_60(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60) \ +X(60, P1) \ +FOR_EACH_1_COUNTED_59(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60) + +#define FOR_EACH_1_COUNTED_61(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61) \ +X(61, P1) \ +FOR_EACH_1_COUNTED_60(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61) + +#define FOR_EACH_1_COUNTED_62(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62) \ +X(62, P1) \ +FOR_EACH_1_COUNTED_61(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62) + +#define FOR_EACH_1_COUNTED_63(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63) \ +X(63, P1) \ +FOR_EACH_1_COUNTED_62(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63) + +#define FOR_EACH_1_COUNTED_64(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64) \ +X(64, P1) \ +FOR_EACH_1_COUNTED_63(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64) + +#define FOR_EACH_1_COUNTED_65(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65) \ +X(65, P1) \ +FOR_EACH_1_COUNTED_64(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65) + +#define FOR_EACH_1_COUNTED_66(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66) \ +X(66, P1) \ +FOR_EACH_1_COUNTED_65(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66) + +#define FOR_EACH_1_COUNTED_67(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67) \ +X(67, P1) \ +FOR_EACH_1_COUNTED_66(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67) + +#define FOR_EACH_1_COUNTED_68(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68) \ +X(68, P1) \ +FOR_EACH_1_COUNTED_67(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68) + +#define FOR_EACH_1_COUNTED_69(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69) \ +X(69, P1) \ +FOR_EACH_1_COUNTED_68(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69) + +#define FOR_EACH_1_COUNTED_70(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70) \ +X(70, P1) \ +FOR_EACH_1_COUNTED_69(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70) + +#define FOR_EACH_1_COUNTED_71(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71) \ +X(71, P1) \ +FOR_EACH_1_COUNTED_70(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71) + +#define FOR_EACH_1_COUNTED_72(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72) \ +X(72, P1) \ +FOR_EACH_1_COUNTED_71(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72) + +#define FOR_EACH_1_COUNTED_73(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73) \ +X(73, P1) \ +FOR_EACH_1_COUNTED_72(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73) + +#define FOR_EACH_1_COUNTED_74(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74) \ +X(74, P1) \ +FOR_EACH_1_COUNTED_73(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74) + +#define FOR_EACH_1_COUNTED_75(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75) \ +X(75, P1) \ +FOR_EACH_1_COUNTED_74(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75) + +#define FOR_EACH_1_COUNTED_76(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76) \ +X(76, P1) \ +FOR_EACH_1_COUNTED_75(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76) + +#define FOR_EACH_1_COUNTED_77(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77) \ +X(77, P1) \ +FOR_EACH_1_COUNTED_76(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77) + +#define FOR_EACH_1_COUNTED_78(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78) \ +X(78, P1) \ +FOR_EACH_1_COUNTED_77(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78) + +#define FOR_EACH_1_COUNTED_79(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79) \ +X(79, P1) \ +FOR_EACH_1_COUNTED_78(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79) + +#define FOR_EACH_1_COUNTED_80(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80) \ +X(80, P1) \ +FOR_EACH_1_COUNTED_79(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80) + +#define FOR_EACH_1_COUNTED_81(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81) \ +X(81, P1) \ +FOR_EACH_1_COUNTED_80(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81) + +#define FOR_EACH_1_COUNTED_82(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82) \ +X(82, P1) \ +FOR_EACH_1_COUNTED_81(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82) + +#define FOR_EACH_1_COUNTED_83(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83) \ +X(83, P1) \ +FOR_EACH_1_COUNTED_82(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83) + +#define FOR_EACH_1_COUNTED_84(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84) \ +X(84, P1) \ +FOR_EACH_1_COUNTED_83(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84) + +#define FOR_EACH_1_COUNTED_85(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85) \ +X(85, P1) \ +FOR_EACH_1_COUNTED_84(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85) + +#define FOR_EACH_1_COUNTED_86(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86) \ +X(86, P1) \ +FOR_EACH_1_COUNTED_85(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86) + +#define FOR_EACH_1_COUNTED_87(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87) \ +X(87, P1) \ +FOR_EACH_1_COUNTED_86(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87) + +#define FOR_EACH_1_COUNTED_88(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88) \ +X(88, P1) \ +FOR_EACH_1_COUNTED_87(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88) + +#define FOR_EACH_1_COUNTED_89(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89) \ +X(89, P1) \ +FOR_EACH_1_COUNTED_88(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89) + +#define FOR_EACH_1_COUNTED_90(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90) \ +X(90, P1) \ +FOR_EACH_1_COUNTED_89(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90) + +#define FOR_EACH_1_COUNTED_91(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91) \ +X(91, P1) \ +FOR_EACH_1_COUNTED_90(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91) + +#define FOR_EACH_1_COUNTED_92(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92) \ +X(92, P1) \ +FOR_EACH_1_COUNTED_91(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92) + +#define FOR_EACH_1_COUNTED_93(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93) \ +X(93, P1) \ +FOR_EACH_1_COUNTED_92(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93) + +#define FOR_EACH_1_COUNTED_94(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94) \ +X(94, P1) \ +FOR_EACH_1_COUNTED_93(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94) + +#define FOR_EACH_1_COUNTED_95(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95) \ +X(95, P1) \ +FOR_EACH_1_COUNTED_94(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95) + +#define FOR_EACH_1_COUNTED_96(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96) \ +X(96, P1) \ +FOR_EACH_1_COUNTED_95(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96) + +#define FOR_EACH_1_COUNTED_97(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97) \ +X(97, P1) \ +FOR_EACH_1_COUNTED_96(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97) + +#define FOR_EACH_1_COUNTED_98(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98) \ +X(98, P1) \ +FOR_EACH_1_COUNTED_97(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98) + +#define FOR_EACH_1_COUNTED_99(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99) \ +X(99, P1) \ +FOR_EACH_1_COUNTED_98(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99) + +#define FOR_EACH_1_COUNTED_100(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100) \ +X(100, P1) \ +FOR_EACH_1_COUNTED_99(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100) + +#define FOR_EACH_1_COUNTED_101(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101) \ +X(101, P1) \ +FOR_EACH_1_COUNTED_100(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101) + +#define FOR_EACH_1_COUNTED_102(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102) \ +X(102, P1) \ +FOR_EACH_1_COUNTED_101(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102) + +#define FOR_EACH_1_COUNTED_103(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103) \ +X(103, P1) \ +FOR_EACH_1_COUNTED_102(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103) + +#define FOR_EACH_1_COUNTED_104(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104) \ +X(104, P1) \ +FOR_EACH_1_COUNTED_103(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104) + +#define FOR_EACH_1_COUNTED_105(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105) \ +X(105, P1) \ +FOR_EACH_1_COUNTED_104(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105) + +#define FOR_EACH_1_COUNTED_106(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106) \ +X(106, P1) \ +FOR_EACH_1_COUNTED_105(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106) + +#define FOR_EACH_1_COUNTED_107(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107) \ +X(107, P1) \ +FOR_EACH_1_COUNTED_106(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107) + +#define FOR_EACH_1_COUNTED_108(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108) \ +X(108, P1) \ +FOR_EACH_1_COUNTED_107(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108) + +#define FOR_EACH_1_COUNTED_109(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109) \ +X(109, P1) \ +FOR_EACH_1_COUNTED_108(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109) + +#define FOR_EACH_1_COUNTED_110(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110) \ +X(110, P1) \ +FOR_EACH_1_COUNTED_109(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110) + +#define FOR_EACH_1_COUNTED_111(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111) \ +X(111, P1) \ +FOR_EACH_1_COUNTED_110(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111) + +#define FOR_EACH_1_COUNTED_112(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112) \ +X(112, P1) \ +FOR_EACH_1_COUNTED_111(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112) + +#define FOR_EACH_1_COUNTED_113(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113) \ +X(113, P1) \ +FOR_EACH_1_COUNTED_112(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113) + +#define FOR_EACH_1_COUNTED_114(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114) \ +X(114, P1) \ +FOR_EACH_1_COUNTED_113(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114) + +#define FOR_EACH_1_COUNTED_115(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115) \ +X(115, P1) \ +FOR_EACH_1_COUNTED_114(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115) + +#define FOR_EACH_1_COUNTED_116(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116) \ +X(116, P1) \ +FOR_EACH_1_COUNTED_115(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116) + +#define FOR_EACH_1_COUNTED_117(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117) \ +X(117, P1) \ +FOR_EACH_1_COUNTED_116(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117) + +#define FOR_EACH_1_COUNTED_118(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118) \ +X(118, P1) \ +FOR_EACH_1_COUNTED_117(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118) + +#define FOR_EACH_1_COUNTED_119(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118, P119) \ +X(119, P1) \ +FOR_EACH_1_COUNTED_118(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118, P119) + +#define FOR_EACH_1_COUNTED_120(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118, P119, P120) \ +X(120, P1) \ +FOR_EACH_1_COUNTED_119(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118, P119, P120) + +#define FOR_EACH_1_COUNTED_121(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118, P119, P120, P121) \ +X(121, P1) \ +FOR_EACH_1_COUNTED_120(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118, P119, P120, P121) + +#define FOR_EACH_1_COUNTED_122(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118, P119, P120, P121, P122) \ +X(122, P1) \ +FOR_EACH_1_COUNTED_121(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118, P119, P120, P121, P122) + +#define FOR_EACH_1_COUNTED_123(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118, P119, P120, P121, P122, P123) \ +X(123, P1) \ +FOR_EACH_1_COUNTED_122(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118, P119, P120, P121, P122, P123) + +#define FOR_EACH_1_COUNTED_124(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118, P119, P120, P121, P122, P123, P124) \ +X(124, P1) \ +FOR_EACH_1_COUNTED_123(X, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118, P119, P120, P121, P122, P123, P124) + + +#define FOR_EACH_2_COUNTED_0(...) + +#define FOR_EACH_2_COUNTED_2(X, P1, P2) \ + X(2, P1, P2) + +#define FOR_EACH_2_COUNTED_4(X, P1, P2, P3, P4) \ +X(4, P1, P2) \ +FOR_EACH_2_COUNTED_2(X, P3, P4) + +#define FOR_EACH_2_COUNTED_6(X, P1, P2, P3, P4, P5, P6) \ +X(6, P1, P2) \ +FOR_EACH_2_COUNTED_4(X, P3, P4, P5, P6) + +#define FOR_EACH_2_COUNTED_8(X, P1, P2, P3, P4, P5, P6, P7, P8) \ +X(8, P1, P2) \ +FOR_EACH_2_COUNTED_6(X, P3, P4, P5, P6, P7, P8) + +#define FOR_EACH_2_COUNTED_10(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) \ +X(10, P1, P2) \ +FOR_EACH_2_COUNTED_8(X, P3, P4, P5, P6, P7, P8, P9, P10) + +#define FOR_EACH_2_COUNTED_12(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12) \ +X(12, P1, P2) \ +FOR_EACH_2_COUNTED_10(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12) + +#define FOR_EACH_2_COUNTED_14(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14) \ +X(14, P1, P2) \ +FOR_EACH_2_COUNTED_12(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14) + +#define FOR_EACH_2_COUNTED_16(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16) \ +X(16, P1, P2) \ +FOR_EACH_2_COUNTED_14(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16) + +#define FOR_EACH_2_COUNTED_18(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18) \ +X(18, P1, P2) \ +FOR_EACH_2_COUNTED_16(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18) + +#define FOR_EACH_2_COUNTED_20(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20) \ +X(20, P1, P2) \ +FOR_EACH_2_COUNTED_18(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20) + +#define FOR_EACH_2_COUNTED_22(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22) \ +X(22, P1, P2) \ +FOR_EACH_2_COUNTED_20(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22) + +#define FOR_EACH_2_COUNTED_24(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24) \ +X(24, P1, P2) \ +FOR_EACH_2_COUNTED_22(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24) + +#define FOR_EACH_2_COUNTED_26(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26) \ +X(26, P1, P2) \ +FOR_EACH_2_COUNTED_24(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26) + +#define FOR_EACH_2_COUNTED_28(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28) \ +X(28, P1, P2) \ +FOR_EACH_2_COUNTED_26(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28) + +#define FOR_EACH_2_COUNTED_30(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30) \ +X(30, P1, P2) \ +FOR_EACH_2_COUNTED_28(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30) + +#define FOR_EACH_2_COUNTED_32(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32) \ +X(32, P1, P2) \ +FOR_EACH_2_COUNTED_30(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32) + +#define FOR_EACH_2_COUNTED_34(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34) \ +X(34, P1, P2) \ +FOR_EACH_2_COUNTED_32(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34) + +#define FOR_EACH_2_COUNTED_36(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36) \ +X(36, P1, P2) \ +FOR_EACH_2_COUNTED_34(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36) + +#define FOR_EACH_2_COUNTED_38(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38) \ +X(38, P1, P2) \ +FOR_EACH_2_COUNTED_36(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38) + +#define FOR_EACH_2_COUNTED_40(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40) \ +X(40, P1, P2) \ +FOR_EACH_2_COUNTED_38(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40) + +#define FOR_EACH_2_COUNTED_42(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42) \ +X(42, P1, P2) \ +FOR_EACH_2_COUNTED_40(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42) + +#define FOR_EACH_2_COUNTED_44(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44) \ +X(44, P1, P2) \ +FOR_EACH_2_COUNTED_42(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44) + +#define FOR_EACH_2_COUNTED_46(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46) \ +X(46, P1, P2) \ +FOR_EACH_2_COUNTED_44(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46) + +#define FOR_EACH_2_COUNTED_48(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48) \ +X(48, P1, P2) \ +FOR_EACH_2_COUNTED_46(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48) + +#define FOR_EACH_2_COUNTED_50(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50) \ +X(50, P1, P2) \ +FOR_EACH_2_COUNTED_48(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50) + +#define FOR_EACH_2_COUNTED_52(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52) \ +X(52, P1, P2) \ +FOR_EACH_2_COUNTED_50(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52) + +#define FOR_EACH_2_COUNTED_54(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54) \ +X(54, P1, P2) \ +FOR_EACH_2_COUNTED_52(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54) + +#define FOR_EACH_2_COUNTED_56(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56) \ +X(56, P1, P2) \ +FOR_EACH_2_COUNTED_54(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56) + +#define FOR_EACH_2_COUNTED_58(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58) \ +X(58, P1, P2) \ +FOR_EACH_2_COUNTED_56(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58) + +#define FOR_EACH_2_COUNTED_60(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60) \ +X(60, P1, P2) \ +FOR_EACH_2_COUNTED_58(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60) + +#define FOR_EACH_2_COUNTED_62(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62) \ +X(62, P1, P2) \ +FOR_EACH_2_COUNTED_60(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62) + +#define FOR_EACH_2_COUNTED_64(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64) \ +X(64, P1, P2) \ +FOR_EACH_2_COUNTED_62(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64) + +#define FOR_EACH_2_COUNTED_66(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66) \ +X(66, P1, P2) \ +FOR_EACH_2_COUNTED_64(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66) + +#define FOR_EACH_2_COUNTED_68(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68) \ +X(68, P1, P2) \ +FOR_EACH_2_COUNTED_66(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68) + +#define FOR_EACH_2_COUNTED_70(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70) \ +X(70, P1, P2) \ +FOR_EACH_2_COUNTED_68(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70) + +#define FOR_EACH_2_COUNTED_72(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72) \ +X(72, P1, P2) \ +FOR_EACH_2_COUNTED_70(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72) + +#define FOR_EACH_2_COUNTED_74(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74) \ +X(74, P1, P2) \ +FOR_EACH_2_COUNTED_72(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74) + +#define FOR_EACH_2_COUNTED_76(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76) \ +X(76, P1, P2) \ +FOR_EACH_2_COUNTED_74(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76) + +#define FOR_EACH_2_COUNTED_78(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78) \ +X(78, P1, P2) \ +FOR_EACH_2_COUNTED_76(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78) + +#define FOR_EACH_2_COUNTED_80(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80) \ +X(80, P1, P2) \ +FOR_EACH_2_COUNTED_78(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80) + +#define FOR_EACH_2_COUNTED_82(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82) \ +X(82, P1, P2) \ +FOR_EACH_2_COUNTED_80(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82) + +#define FOR_EACH_2_COUNTED_84(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84) \ +X(84, P1, P2) \ +FOR_EACH_2_COUNTED_82(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84) + +#define FOR_EACH_2_COUNTED_86(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86) \ +X(86, P1, P2) \ +FOR_EACH_2_COUNTED_84(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86) + +#define FOR_EACH_2_COUNTED_88(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88) \ +X(88, P1, P2) \ +FOR_EACH_2_COUNTED_86(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88) + +#define FOR_EACH_2_COUNTED_90(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90) \ +X(90, P1, P2) \ +FOR_EACH_2_COUNTED_88(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90) + +#define FOR_EACH_2_COUNTED_92(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92) \ +X(92, P1, P2) \ +FOR_EACH_2_COUNTED_90(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92) + +#define FOR_EACH_2_COUNTED_94(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94) \ +X(94, P1, P2) \ +FOR_EACH_2_COUNTED_92(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94) + +#define FOR_EACH_2_COUNTED_96(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96) \ +X(96, P1, P2) \ +FOR_EACH_2_COUNTED_94(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96) + +#define FOR_EACH_2_COUNTED_98(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98) \ +X(98, P1, P2) \ +FOR_EACH_2_COUNTED_96(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98) + +#define FOR_EACH_2_COUNTED_100(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100) \ +X(100, P1, P2) \ +FOR_EACH_2_COUNTED_98(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100) + +#define FOR_EACH_2_COUNTED_102(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102) \ +X(102, P1, P2) \ +FOR_EACH_2_COUNTED_100(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102) + +#define FOR_EACH_2_COUNTED_104(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104) \ +X(104, P1, P2) \ +FOR_EACH_2_COUNTED_102(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104) + +#define FOR_EACH_2_COUNTED_106(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106) \ +X(106, P1, P2) \ +FOR_EACH_2_COUNTED_104(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106) + +#define FOR_EACH_2_COUNTED_108(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108) \ +X(108, P1, P2) \ +FOR_EACH_2_COUNTED_106(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108) + +#define FOR_EACH_2_COUNTED_110(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110) \ +X(110, P1, P2) \ +FOR_EACH_2_COUNTED_108(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110) + +#define FOR_EACH_2_COUNTED_112(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112) \ +X(112, P1, P2) \ +FOR_EACH_2_COUNTED_110(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112) + +#define FOR_EACH_2_COUNTED_114(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114) \ +X(114, P1, P2) \ +FOR_EACH_2_COUNTED_112(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114) + +#define FOR_EACH_2_COUNTED_116(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116) \ +X(116, P1, P2) \ +FOR_EACH_2_COUNTED_114(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116) + +#define FOR_EACH_2_COUNTED_118(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118) \ +X(118, P1, P2) \ +FOR_EACH_2_COUNTED_116(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118) + +#define FOR_EACH_2_COUNTED_120(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118, P119, P120) \ +X(120, P1, P2) \ +FOR_EACH_2_COUNTED_118(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118, P119, P120) + +#define FOR_EACH_2_COUNTED_122(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118, P119, P120, P121, P122) \ +X(122, P1, P2) \ +FOR_EACH_2_COUNTED_120(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118, P119, P120, P121, P122) + +#define FOR_EACH_2_COUNTED_124(X, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118, P119, P120, P121, P122, P123, P124) \ +X(124, P1, P2) \ +FOR_EACH_2_COUNTED_122(X, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, P36, P37, P38, P39, P40, P41, P42, P43, P44, P45, P46, P47, P48, P49, P50, P51, P52, P53, P54, P55, P56, P57, P58, P59, P60, P61, P62, P63, P64, P65, P66, P67, P68, P69, P70, P71, P72, P73, P74, P75, P76, P77, P78, P79, P80, P81, P82, P83, P84, P85, P86, P87, P88, P89, P90, P91, P92, P93, P94, P95, P96, P97, P98, P99, P100, P101, P102, P103, P104, P105, P106, P107, P108, P109, P110, P111, P112, P113, P114, P115, P116, P117, P118, P119, P120, P121, P122, P123, P124) + + +#ifdef _MSC_VER +#define FOR_EACH_2(MACRO_TO_INVOKE, ...) C2(FOR_EACH_2_, C1(COUNT_ARG(__VA_ARGS__))) LPAREN MACRO_TO_INVOKE, __VA_ARGS__) +/*the COUNTED breed of FOR_EACH macro invokes a macro with 3 parameters: 1st being the count of invocation. For example. +FOR_EACH_2_COUNTER(MACRO, a,b,c,d,e,f) will result in +MACRO(6, a,b) +MACRO(4, c,d) +MACRO(2, e,f) +This macro exists because we need a "stop condition" in outputting COMMA... when calling a function f(a,b,c,d) cannot be f(a,b,c,d,) <=doesn't compile (as opposed to enum definition) +*/ +#define FOR_EACH_2_COUNTED(MACRO_TO_INVOKE, ...) C2(FOR_EACH_2_COUNTED_, C1(COUNT_ARG(__VA_ARGS__))) LPAREN MACRO_TO_INVOKE, __VA_ARGS__) +#define FOR_EACH_1_COUNTED(MACRO_TO_INVOKE, ...) C2(FOR_EACH_1_COUNTED_, C1(COUNT_ARG(__VA_ARGS__))) LPAREN MACRO_TO_INVOKE, __VA_ARGS__) +#else +#define FOR_EACH_2(MACRO_TO_INVOKE, ...) C2(FOR_EACH_2_, C1(COUNT_ARG(__VA_ARGS__))) ( MACRO_TO_INVOKE, __VA_ARGS__) +#define FOR_EACH_2_COUNTED(MACRO_TO_INVOKE, ...) C2(FOR_EACH_2_COUNTED_, C1(COUNT_ARG(__VA_ARGS__))) ( MACRO_TO_INVOKE, __VA_ARGS__) +#define FOR_EACH_1_COUNTED(MACRO_TO_INVOKE, ...) C2(FOR_EACH_1_COUNTED_, C1(COUNT_ARG(__VA_ARGS__))) ( MACRO_TO_INVOKE, __VA_ARGS__) +#endif + +#ifdef _MSC_VER +#define EXPAND_OR_C1(x) x +#else +#define EXPAND_OR_C1(...) __VA_ARGS__ +#endif + +#define EXPAND_ARGS(...) __VA_ARGS__ +#define EXPAND_TWICE(...) EXPAND_ARGS(__VA_ARGS__) + +#define DO_0(MACRO, ...) \ +MACRO(0, __VA_ARGS__) + +#define DO_1(MACRO, ...) \ +MACRO(1, __VA_ARGS__) \ +DO_0(MACRO, __VA_ARGS__) + + +#define DO_2(MACRO, ...) \ +MACRO(2, __VA_ARGS__) \ +DO_1(MACRO, __VA_ARGS__) + + +#define DO_3(MACRO, ...) \ +MACRO(3, __VA_ARGS__) \ +DO_2(MACRO, __VA_ARGS__) + + +#define DO_4(MACRO, ...) \ +MACRO(4, __VA_ARGS__) \ +DO_3(MACRO, __VA_ARGS__) + + +#define DO_5(MACRO, ...) \ +MACRO(5, __VA_ARGS__) \ +DO_4(MACRO, __VA_ARGS__) + + +#define DO_6(MACRO, ...) \ +MACRO(6, __VA_ARGS__) \ +DO_5(MACRO, __VA_ARGS__) + + +#define DO_7(MACRO, ...) \ +MACRO(7, __VA_ARGS__) \ +DO_6(MACRO, __VA_ARGS__) + + +#define DO_8(MACRO, ...) \ +MACRO(8, __VA_ARGS__) \ +DO_7(MACRO, __VA_ARGS__) + + +#define DO_9(MACRO, ...) \ +MACRO(9, __VA_ARGS__) \ +DO_8(MACRO, __VA_ARGS__) + + +#define DO_10(MACRO, ...) \ +MACRO(10, __VA_ARGS__) \ +DO_9(MACRO, __VA_ARGS__) + + +#define DO_11(MACRO, ...) \ +MACRO(11, __VA_ARGS__) \ +DO_10(MACRO, __VA_ARGS__) + + +#define DO_12(MACRO, ...) \ +MACRO(12, __VA_ARGS__) \ +DO_11(MACRO, __VA_ARGS__) + + +#define DO_13(MACRO, ...) \ +MACRO(13, __VA_ARGS__) \ +DO_12(MACRO, __VA_ARGS__) + + +#define DO_14(MACRO, ...) \ +MACRO(14, __VA_ARGS__) \ +DO_13(MACRO, __VA_ARGS__) + + +#define DO_15(MACRO, ...) \ +MACRO(15, __VA_ARGS__) \ +DO_14(MACRO, __VA_ARGS__) + + +#define DO_16(MACRO, ...) \ +MACRO(16, __VA_ARGS__) \ +DO_15(MACRO, __VA_ARGS__) + + +#define DO_17(MACRO, ...) \ +MACRO(17, __VA_ARGS__) \ +DO_16(MACRO, __VA_ARGS__) + + +#define DO_18(MACRO, ...) \ +MACRO(18, __VA_ARGS__) \ +DO_17(MACRO, __VA_ARGS__) + + +#define DO_19(MACRO, ...) \ +MACRO(19, __VA_ARGS__) \ +DO_18(MACRO, __VA_ARGS__) + + +#define DO_20(MACRO, ...) \ +MACRO(20, __VA_ARGS__) \ +DO_19(MACRO, __VA_ARGS__) + + +#define DO_21(MACRO, ...) \ +MACRO(21, __VA_ARGS__) \ +DO_20(MACRO, __VA_ARGS__) + + +#define DO_22(MACRO, ...) \ +MACRO(22, __VA_ARGS__) \ +DO_21(MACRO, __VA_ARGS__) + + +#define DO_23(MACRO, ...) \ +MACRO(23, __VA_ARGS__) \ +DO_22(MACRO, __VA_ARGS__) + + +#define DO_24(MACRO, ...) \ +MACRO(24, __VA_ARGS__) \ +DO_23(MACRO, __VA_ARGS__) + + +#define DO_25(MACRO, ...) \ +MACRO(25, __VA_ARGS__) \ +DO_24(MACRO, __VA_ARGS__) + + +#define DO_26(MACRO, ...) \ +MACRO(26, __VA_ARGS__) \ +DO_25(MACRO, __VA_ARGS__) + + +#define DO_27(MACRO, ...) \ +MACRO(27, __VA_ARGS__) \ +DO_26(MACRO, __VA_ARGS__) + + +#define DO_28(MACRO, ...) \ +MACRO(28, __VA_ARGS__) \ +DO_27(MACRO, __VA_ARGS__) + + +#define DO_29(MACRO, ...) \ +MACRO(29, __VA_ARGS__) \ +DO_28(MACRO, __VA_ARGS__) + + +#define DO_30(MACRO, ...) \ +MACRO(30, __VA_ARGS__) \ +DO_29(MACRO, __VA_ARGS__) + + +#define DO_31(MACRO, ...) \ +MACRO(31, __VA_ARGS__) \ +DO_30(MACRO, __VA_ARGS__) + + +#define DO_32(MACRO, ...) \ +MACRO(32, __VA_ARGS__) \ +DO_31(MACRO, __VA_ARGS__) + + +#define DO_33(MACRO, ...) \ +MACRO(33, __VA_ARGS__) \ +DO_32(MACRO, __VA_ARGS__) + + +#define DO_34(MACRO, ...) \ +MACRO(34, __VA_ARGS__) \ +DO_33(MACRO, __VA_ARGS__) + + +#define DO_35(MACRO, ...) \ +MACRO(35, __VA_ARGS__) \ +DO_34(MACRO, __VA_ARGS__) + + +#define DO_36(MACRO, ...) \ +MACRO(36, __VA_ARGS__) \ +DO_35(MACRO, __VA_ARGS__) + + +#define DO_37(MACRO, ...) \ +MACRO(37, __VA_ARGS__) \ +DO_36(MACRO, __VA_ARGS__) + + +#define DO_38(MACRO, ...) \ +MACRO(38, __VA_ARGS__) \ +DO_37(MACRO, __VA_ARGS__) + + +#define DO_39(MACRO, ...) \ +MACRO(39, __VA_ARGS__) \ +DO_38(MACRO, __VA_ARGS__) + + +#define DO_40(MACRO, ...) \ +MACRO(40, __VA_ARGS__) \ +DO_39(MACRO, __VA_ARGS__) + + +#define DO_41(MACRO, ...) \ +MACRO(41, __VA_ARGS__) \ +DO_40(MACRO, __VA_ARGS__) + + +#define DO_42(MACRO, ...) \ +MACRO(42, __VA_ARGS__) \ +DO_41(MACRO, __VA_ARGS__) + + +#define DO_43(MACRO, ...) \ +MACRO(43, __VA_ARGS__) \ +DO_42(MACRO, __VA_ARGS__) + + +#define DO_44(MACRO, ...) \ +MACRO(44, __VA_ARGS__) \ +DO_43(MACRO, __VA_ARGS__) + + +#define DO_45(MACRO, ...) \ +MACRO(45, __VA_ARGS__) \ +DO_44(MACRO, __VA_ARGS__) + + +#define DO_46(MACRO, ...) \ +MACRO(46, __VA_ARGS__) \ +DO_45(MACRO, __VA_ARGS__) + + +#define DO_47(MACRO, ...) \ +MACRO(47, __VA_ARGS__) \ +DO_46(MACRO, __VA_ARGS__) + + +#define DO_48(MACRO, ...) \ +MACRO(48, __VA_ARGS__) \ +DO_47(MACRO, __VA_ARGS__) + + +#define DO_49(MACRO, ...) \ +MACRO(49, __VA_ARGS__) \ +DO_48(MACRO, __VA_ARGS__) + + +#define DO_50(MACRO, ...) \ +MACRO(50, __VA_ARGS__) \ +DO_49(MACRO, __VA_ARGS__) + + +#define DO_51(MACRO, ...) \ +MACRO(51, __VA_ARGS__) \ +DO_50(MACRO, __VA_ARGS__) + + +#define DO_52(MACRO, ...) \ +MACRO(52, __VA_ARGS__) \ +DO_51(MACRO, __VA_ARGS__) + + +#define DO_53(MACRO, ...) \ +MACRO(53, __VA_ARGS__) \ +DO_52(MACRO, __VA_ARGS__) + + +#define DO_54(MACRO, ...) \ +MACRO(54, __VA_ARGS__) \ +DO_53(MACRO, __VA_ARGS__) + + +#define DO_55(MACRO, ...) \ +MACRO(55, __VA_ARGS__) \ +DO_54(MACRO, __VA_ARGS__) + + +#define DO_56(MACRO, ...) \ +MACRO(56, __VA_ARGS__) \ +DO_55(MACRO, __VA_ARGS__) + + +#define DO_57(MACRO, ...) \ +MACRO(57, __VA_ARGS__) \ +DO_56(MACRO, __VA_ARGS__) + + +#define DO_58(MACRO, ...) \ +MACRO(58, __VA_ARGS__) \ +DO_57(MACRO, __VA_ARGS__) + + +#define DO_59(MACRO, ...) \ +MACRO(59, __VA_ARGS__) \ +DO_58(MACRO, __VA_ARGS__) + + +#define DO_60(MACRO, ...) \ +MACRO(60, __VA_ARGS__) \ +DO_59(MACRO, __VA_ARGS__) + + +#define DO_61(MACRO, ...) \ +MACRO(61, __VA_ARGS__) \ +DO_60(MACRO, __VA_ARGS__) + + +#define DO_62(MACRO, ...) \ +MACRO(62, __VA_ARGS__) \ +DO_61(MACRO, __VA_ARGS__) + + +#define DO_63(MACRO, ...) \ +MACRO(63, __VA_ARGS__) \ +DO_62(MACRO, __VA_ARGS__) + + +#define DO_64(MACRO, ...) \ +MACRO(64, __VA_ARGS__) \ +DO_63(MACRO, __VA_ARGS__) + + +#define DO_65(MACRO, ...) \ +MACRO(65, __VA_ARGS__) \ +DO_64(MACRO, __VA_ARGS__) + + +#define DO_66(MACRO, ...) \ +MACRO(66, __VA_ARGS__) \ +DO_65(MACRO, __VA_ARGS__) + + +#define DO_67(MACRO, ...) \ +MACRO(67, __VA_ARGS__) \ +DO_66(MACRO, __VA_ARGS__) + + +#define DO_68(MACRO, ...) \ +MACRO(68, __VA_ARGS__) \ +DO_67(MACRO, __VA_ARGS__) + + +#define DO_69(MACRO, ...) \ +MACRO(69, __VA_ARGS__) \ +DO_68(MACRO, __VA_ARGS__) + + +#define DO_70(MACRO, ...) \ +MACRO(70, __VA_ARGS__) \ +DO_69(MACRO, __VA_ARGS__) + + +#define DO_71(MACRO, ...) \ +MACRO(71, __VA_ARGS__) \ +DO_70(MACRO, __VA_ARGS__) + + +#define DO_72(MACRO, ...) \ +MACRO(72, __VA_ARGS__) \ +DO_71(MACRO, __VA_ARGS__) + + +#define DO_73(MACRO, ...) \ +MACRO(73, __VA_ARGS__) \ +DO_72(MACRO, __VA_ARGS__) + + +#define DO_74(MACRO, ...) \ +MACRO(74, __VA_ARGS__) \ +DO_73(MACRO, __VA_ARGS__) + + +#define DO_75(MACRO, ...) \ +MACRO(75, __VA_ARGS__) \ +DO_74(MACRO, __VA_ARGS__) + + +#define DO_76(MACRO, ...) \ +MACRO(76, __VA_ARGS__) \ +DO_75(MACRO, __VA_ARGS__) + + +#define DO_77(MACRO, ...) \ +MACRO(77, __VA_ARGS__) \ +DO_76(MACRO, __VA_ARGS__) + + +#define DO_78(MACRO, ...) \ +MACRO(78, __VA_ARGS__) \ +DO_77(MACRO, __VA_ARGS__) + + +#define DO_79(MACRO, ...) \ +MACRO(79, __VA_ARGS__) \ +DO_78(MACRO, __VA_ARGS__) + + +#define DO_80(MACRO, ...) \ +MACRO(80, __VA_ARGS__) \ +DO_79(MACRO, __VA_ARGS__) + + +#define DO_81(MACRO, ...) \ +MACRO(81, __VA_ARGS__) \ +DO_80(MACRO, __VA_ARGS__) + + +#define DO_82(MACRO, ...) \ +MACRO(82, __VA_ARGS__) \ +DO_81(MACRO, __VA_ARGS__) + + +#define DO_83(MACRO, ...) \ +MACRO(83, __VA_ARGS__) \ +DO_82(MACRO, __VA_ARGS__) + + +#define DO_84(MACRO, ...) \ +MACRO(84, __VA_ARGS__) \ +DO_83(MACRO, __VA_ARGS__) + + +#define DO_85(MACRO, ...) \ +MACRO(85, __VA_ARGS__) \ +DO_84(MACRO, __VA_ARGS__) + + +#define DO_86(MACRO, ...) \ +MACRO(86, __VA_ARGS__) \ +DO_85(MACRO, __VA_ARGS__) + + +#define DO_87(MACRO, ...) \ +MACRO(87, __VA_ARGS__) \ +DO_86(MACRO, __VA_ARGS__) + + +#define DO_88(MACRO, ...) \ +MACRO(88, __VA_ARGS__) \ +DO_87(MACRO, __VA_ARGS__) + + +#define DO_89(MACRO, ...) \ +MACRO(89, __VA_ARGS__) \ +DO_88(MACRO, __VA_ARGS__) + + +#define DO_90(MACRO, ...) \ +MACRO(90, __VA_ARGS__) \ +DO_89(MACRO, __VA_ARGS__) + + +#define DO_91(MACRO, ...) \ +MACRO(91, __VA_ARGS__) \ +DO_90(MACRO, __VA_ARGS__) + + +#define DO_92(MACRO, ...) \ +MACRO(92, __VA_ARGS__) \ +DO_91(MACRO, __VA_ARGS__) + + +#define DO_93(MACRO, ...) \ +MACRO(93, __VA_ARGS__) \ +DO_92(MACRO, __VA_ARGS__) + + +#define DO_94(MACRO, ...) \ +MACRO(94, __VA_ARGS__) \ +DO_93(MACRO, __VA_ARGS__) + + +#define DO_95(MACRO, ...) \ +MACRO(95, __VA_ARGS__) \ +DO_94(MACRO, __VA_ARGS__) + + +#define DO_96(MACRO, ...) \ +MACRO(96, __VA_ARGS__) \ +DO_95(MACRO, __VA_ARGS__) + + +#define DO_97(MACRO, ...) \ +MACRO(97, __VA_ARGS__) \ +DO_96(MACRO, __VA_ARGS__) + + +#define DO_98(MACRO, ...) \ +MACRO(98, __VA_ARGS__) \ +DO_97(MACRO, __VA_ARGS__) + + +#define DO_99(MACRO, ...) \ +MACRO(99, __VA_ARGS__) \ +DO_98(MACRO, __VA_ARGS__) + + +#define DO_100(MACRO, ...) \ +MACRO(100, __VA_ARGS__) \ +DO_99(MACRO, __VA_ARGS__) + + +#define DO_101(MACRO, ...) \ +MACRO(101, __VA_ARGS__) \ +DO_100(MACRO, __VA_ARGS__) + + +#define DO_102(MACRO, ...) \ +MACRO(102, __VA_ARGS__) \ +DO_101(MACRO, __VA_ARGS__) + + +#define DO_103(MACRO, ...) \ +MACRO(103, __VA_ARGS__) \ +DO_102(MACRO, __VA_ARGS__) + + +#define DO_104(MACRO, ...) \ +MACRO(104, __VA_ARGS__) \ +DO_103(MACRO, __VA_ARGS__) + + +#define DO_105(MACRO, ...) \ +MACRO(105, __VA_ARGS__) \ +DO_104(MACRO, __VA_ARGS__) + + +#define DO_106(MACRO, ...) \ +MACRO(106, __VA_ARGS__) \ +DO_105(MACRO, __VA_ARGS__) + + +#define DO_107(MACRO, ...) \ +MACRO(107, __VA_ARGS__) \ +DO_106(MACRO, __VA_ARGS__) + + +#define DO_108(MACRO, ...) \ +MACRO(108, __VA_ARGS__) \ +DO_107(MACRO, __VA_ARGS__) + + +#define DO_109(MACRO, ...) \ +MACRO(109, __VA_ARGS__) \ +DO_108(MACRO, __VA_ARGS__) + + +#define DO_110(MACRO, ...) \ +MACRO(110, __VA_ARGS__) \ +DO_109(MACRO, __VA_ARGS__) + + +#define DO_111(MACRO, ...) \ +MACRO(111, __VA_ARGS__) \ +DO_110(MACRO, __VA_ARGS__) + + +#define DO_112(MACRO, ...) \ +MACRO(112, __VA_ARGS__) \ +DO_111(MACRO, __VA_ARGS__) + + +#define DO_113(MACRO, ...) \ +MACRO(113, __VA_ARGS__) \ +DO_112(MACRO, __VA_ARGS__) + + +#define DO_114(MACRO, ...) \ +MACRO(114, __VA_ARGS__) \ +DO_113(MACRO, __VA_ARGS__) + + +#define DO_115(MACRO, ...) \ +MACRO(115, __VA_ARGS__) \ +DO_114(MACRO, __VA_ARGS__) + + +#define DO_116(MACRO, ...) \ +MACRO(116, __VA_ARGS__) \ +DO_115(MACRO, __VA_ARGS__) + + +#define DO_117(MACRO, ...) \ +MACRO(117, __VA_ARGS__) \ +DO_116(MACRO, __VA_ARGS__) + + +#define DO_118(MACRO, ...) \ +MACRO(118, __VA_ARGS__) \ +DO_117(MACRO, __VA_ARGS__) + + +#define DO_119(MACRO, ...) \ +MACRO(119, __VA_ARGS__) \ +DO_118(MACRO, __VA_ARGS__) + + +#define DO_120(MACRO, ...) \ +MACRO(120, __VA_ARGS__) \ +DO_119(MACRO, __VA_ARGS__) + + +#define DO_121(MACRO, ...) \ +MACRO(121, __VA_ARGS__) \ +DO_120(MACRO, __VA_ARGS__) + + +#define DO_122(MACRO, ...) \ +MACRO(122, __VA_ARGS__) \ +DO_121(MACRO, __VA_ARGS__) + + +#define DO_123(MACRO, ...) \ +MACRO(123, __VA_ARGS__) \ +DO_122(MACRO, __VA_ARGS__) + + +#define DO_124(MACRO, ...) \ +MACRO(124, __VA_ARGS__) \ +DO_123(MACRO, __VA_ARGS__) + + +#define DO_125(MACRO, ...) \ +MACRO(125, __VA_ARGS__) \ +DO_124(MACRO, __VA_ARGS__) + + +#define DO_126(MACRO, ...) \ +MACRO(126, __VA_ARGS__) \ +DO_125(MACRO, __VA_ARGS__) + + +#define DO_127(MACRO, ...) \ +MACRO(127, __VA_ARGS__) \ +DO_126(MACRO, __VA_ARGS__) + + +#define DO_128(MACRO, ...) \ +MACRO(128, __VA_ARGS__) \ +DO_127(MACRO, __VA_ARGS__) + + +#define DO_129(MACRO, ...) \ +MACRO(129, __VA_ARGS__) \ +DO_128(MACRO, __VA_ARGS__) + + +#define DO_130(MACRO, ...) \ +MACRO(130, __VA_ARGS__) \ +DO_129(MACRO, __VA_ARGS__) + + +#define DO_131(MACRO, ...) \ +MACRO(131, __VA_ARGS__) \ +DO_130(MACRO, __VA_ARGS__) + + +#define DO_132(MACRO, ...) \ +MACRO(132, __VA_ARGS__) \ +DO_131(MACRO, __VA_ARGS__) + + +#define DO_133(MACRO, ...) \ +MACRO(133, __VA_ARGS__) \ +DO_132(MACRO, __VA_ARGS__) + + +#define DO_134(MACRO, ...) \ +MACRO(134, __VA_ARGS__) \ +DO_133(MACRO, __VA_ARGS__) + + +#define DO_135(MACRO, ...) \ +MACRO(135, __VA_ARGS__) \ +DO_134(MACRO, __VA_ARGS__) + + +#define DO_136(MACRO, ...) \ +MACRO(136, __VA_ARGS__) \ +DO_135(MACRO, __VA_ARGS__) + + +#define DO_137(MACRO, ...) \ +MACRO(137, __VA_ARGS__) \ +DO_136(MACRO, __VA_ARGS__) + + +#define DO_138(MACRO, ...) \ +MACRO(138, __VA_ARGS__) \ +DO_137(MACRO, __VA_ARGS__) + + +#define DO_139(MACRO, ...) \ +MACRO(139, __VA_ARGS__) \ +DO_138(MACRO, __VA_ARGS__) + + +#define DO_140(MACRO, ...) \ +MACRO(140, __VA_ARGS__) \ +DO_139(MACRO, __VA_ARGS__) + + +#define DO_141(MACRO, ...) \ +MACRO(141, __VA_ARGS__) \ +DO_140(MACRO, __VA_ARGS__) + + +#define DO_142(MACRO, ...) \ +MACRO(142, __VA_ARGS__) \ +DO_141(MACRO, __VA_ARGS__) + + +#define DO_143(MACRO, ...) \ +MACRO(143, __VA_ARGS__) \ +DO_142(MACRO, __VA_ARGS__) + + +#define DO_144(MACRO, ...) \ +MACRO(144, __VA_ARGS__) \ +DO_143(MACRO, __VA_ARGS__) + + +#define DO_145(MACRO, ...) \ +MACRO(145, __VA_ARGS__) \ +DO_144(MACRO, __VA_ARGS__) + + +#define DO_146(MACRO, ...) \ +MACRO(146, __VA_ARGS__) \ +DO_145(MACRO, __VA_ARGS__) + + +#define DO_147(MACRO, ...) \ +MACRO(147, __VA_ARGS__) \ +DO_146(MACRO, __VA_ARGS__) + + +#define DO_148(MACRO, ...) \ +MACRO(148, __VA_ARGS__) \ +DO_147(MACRO, __VA_ARGS__) + + +#define DO_149(MACRO, ...) \ +MACRO(149, __VA_ARGS__) \ +DO_148(MACRO, __VA_ARGS__) + + +#define DO_150(MACRO, ...) \ +MACRO(150, __VA_ARGS__) \ +DO_149(MACRO, __VA_ARGS__) + + +#define DO_151(MACRO, ...) \ +MACRO(151, __VA_ARGS__) \ +DO_150(MACRO, __VA_ARGS__) + + +#define DO_152(MACRO, ...) \ +MACRO(152, __VA_ARGS__) \ +DO_151(MACRO, __VA_ARGS__) + + +#define DO_153(MACRO, ...) \ +MACRO(153, __VA_ARGS__) \ +DO_152(MACRO, __VA_ARGS__) + + +#define DO_154(MACRO, ...) \ +MACRO(154, __VA_ARGS__) \ +DO_153(MACRO, __VA_ARGS__) + + +#define DO_155(MACRO, ...) \ +MACRO(155, __VA_ARGS__) \ +DO_154(MACRO, __VA_ARGS__) + + +#define DO_156(MACRO, ...) \ +MACRO(156, __VA_ARGS__) \ +DO_155(MACRO, __VA_ARGS__) + + +#define DO_157(MACRO, ...) \ +MACRO(157, __VA_ARGS__) \ +DO_156(MACRO, __VA_ARGS__) + + +#define DO_158(MACRO, ...) \ +MACRO(158, __VA_ARGS__) \ +DO_157(MACRO, __VA_ARGS__) + + +#define DO_159(MACRO, ...) \ +MACRO(159, __VA_ARGS__) \ +DO_158(MACRO, __VA_ARGS__) + + +#define DO_160(MACRO, ...) \ +MACRO(160, __VA_ARGS__) \ +DO_159(MACRO, __VA_ARGS__) + + +#define DO_161(MACRO, ...) \ +MACRO(161, __VA_ARGS__) \ +DO_160(MACRO, __VA_ARGS__) + + +#define DO_162(MACRO, ...) \ +MACRO(162, __VA_ARGS__) \ +DO_161(MACRO, __VA_ARGS__) + + +#define DO_163(MACRO, ...) \ +MACRO(163, __VA_ARGS__) \ +DO_162(MACRO, __VA_ARGS__) + + +#define DO_164(MACRO, ...) \ +MACRO(164, __VA_ARGS__) \ +DO_163(MACRO, __VA_ARGS__) + + +#define DO_165(MACRO, ...) \ +MACRO(165, __VA_ARGS__) \ +DO_164(MACRO, __VA_ARGS__) + + +#define DO_166(MACRO, ...) \ +MACRO(166, __VA_ARGS__) \ +DO_165(MACRO, __VA_ARGS__) + + +#define DO_167(MACRO, ...) \ +MACRO(167, __VA_ARGS__) \ +DO_166(MACRO, __VA_ARGS__) + + +#define DO_168(MACRO, ...) \ +MACRO(168, __VA_ARGS__) \ +DO_167(MACRO, __VA_ARGS__) + + +#define DO_169(MACRO, ...) \ +MACRO(169, __VA_ARGS__) \ +DO_168(MACRO, __VA_ARGS__) + + +#define DO_170(MACRO, ...) \ +MACRO(170, __VA_ARGS__) \ +DO_169(MACRO, __VA_ARGS__) + + +#define DO_171(MACRO, ...) \ +MACRO(171, __VA_ARGS__) \ +DO_170(MACRO, __VA_ARGS__) + + +#define DO_172(MACRO, ...) \ +MACRO(172, __VA_ARGS__) \ +DO_171(MACRO, __VA_ARGS__) + + +#define DO_173(MACRO, ...) \ +MACRO(173, __VA_ARGS__) \ +DO_172(MACRO, __VA_ARGS__) + + +#define DO_174(MACRO, ...) \ +MACRO(174, __VA_ARGS__) \ +DO_173(MACRO, __VA_ARGS__) + + +#define DO_175(MACRO, ...) \ +MACRO(175, __VA_ARGS__) \ +DO_174(MACRO, __VA_ARGS__) + + +#define DO_176(MACRO, ...) \ +MACRO(176, __VA_ARGS__) \ +DO_175(MACRO, __VA_ARGS__) + + +#define DO_177(MACRO, ...) \ +MACRO(177, __VA_ARGS__) \ +DO_176(MACRO, __VA_ARGS__) + + +#define DO_178(MACRO, ...) \ +MACRO(178, __VA_ARGS__) \ +DO_177(MACRO, __VA_ARGS__) + + +#define DO_179(MACRO, ...) \ +MACRO(179, __VA_ARGS__) \ +DO_178(MACRO, __VA_ARGS__) + + +#define DO_180(MACRO, ...) \ +MACRO(180, __VA_ARGS__) \ +DO_179(MACRO, __VA_ARGS__) + + +#define DO_181(MACRO, ...) \ +MACRO(181, __VA_ARGS__) \ +DO_180(MACRO, __VA_ARGS__) + + +#define DO_182(MACRO, ...) \ +MACRO(182, __VA_ARGS__) \ +DO_181(MACRO, __VA_ARGS__) + + +#define DO_183(MACRO, ...) \ +MACRO(183, __VA_ARGS__) \ +DO_182(MACRO, __VA_ARGS__) + + +#define DO_184(MACRO, ...) \ +MACRO(184, __VA_ARGS__) \ +DO_183(MACRO, __VA_ARGS__) + + +#define DO_185(MACRO, ...) \ +MACRO(185, __VA_ARGS__) \ +DO_184(MACRO, __VA_ARGS__) + + +#define DO_186(MACRO, ...) \ +MACRO(186, __VA_ARGS__) \ +DO_185(MACRO, __VA_ARGS__) + + +#define DO_187(MACRO, ...) \ +MACRO(187, __VA_ARGS__) \ +DO_186(MACRO, __VA_ARGS__) + + +#define DO_188(MACRO, ...) \ +MACRO(188, __VA_ARGS__) \ +DO_187(MACRO, __VA_ARGS__) + + +#define DO_189(MACRO, ...) \ +MACRO(189, __VA_ARGS__) \ +DO_188(MACRO, __VA_ARGS__) + + +#define DO_190(MACRO, ...) \ +MACRO(190, __VA_ARGS__) \ +DO_189(MACRO, __VA_ARGS__) + + +#define DO_191(MACRO, ...) \ +MACRO(191, __VA_ARGS__) \ +DO_190(MACRO, __VA_ARGS__) + + +#define DO_192(MACRO, ...) \ +MACRO(192, __VA_ARGS__) \ +DO_191(MACRO, __VA_ARGS__) + + +#define DO_193(MACRO, ...) \ +MACRO(193, __VA_ARGS__) \ +DO_192(MACRO, __VA_ARGS__) + + +#define DO_194(MACRO, ...) \ +MACRO(194, __VA_ARGS__) \ +DO_193(MACRO, __VA_ARGS__) + + +#define DO_195(MACRO, ...) \ +MACRO(195, __VA_ARGS__) \ +DO_194(MACRO, __VA_ARGS__) + + +#define DO_196(MACRO, ...) \ +MACRO(196, __VA_ARGS__) \ +DO_195(MACRO, __VA_ARGS__) + + +#define DO_197(MACRO, ...) \ +MACRO(197, __VA_ARGS__) \ +DO_196(MACRO, __VA_ARGS__) + + +#define DO_198(MACRO, ...) \ +MACRO(198, __VA_ARGS__) \ +DO_197(MACRO, __VA_ARGS__) + + +#define DO_199(MACRO, ...) \ +MACRO(199, __VA_ARGS__) \ +DO_198(MACRO, __VA_ARGS__) + + +#define DO_200(MACRO, ...) \ +MACRO(200, __VA_ARGS__) \ +DO_199(MACRO, __VA_ARGS__) + + +#define DO_201(MACRO, ...) \ +MACRO(201, __VA_ARGS__) \ +DO_200(MACRO, __VA_ARGS__) + + +#define DO_202(MACRO, ...) \ +MACRO(202, __VA_ARGS__) \ +DO_201(MACRO, __VA_ARGS__) + + +#define DO_203(MACRO, ...) \ +MACRO(203, __VA_ARGS__) \ +DO_202(MACRO, __VA_ARGS__) + + +#define DO_204(MACRO, ...) \ +MACRO(204, __VA_ARGS__) \ +DO_203(MACRO, __VA_ARGS__) + + +#define DO_205(MACRO, ...) \ +MACRO(205, __VA_ARGS__) \ +DO_204(MACRO, __VA_ARGS__) + + +#define DO_206(MACRO, ...) \ +MACRO(206, __VA_ARGS__) \ +DO_205(MACRO, __VA_ARGS__) + + +#define DO_207(MACRO, ...) \ +MACRO(207, __VA_ARGS__) \ +DO_206(MACRO, __VA_ARGS__) + + +#define DO_208(MACRO, ...) \ +MACRO(208, __VA_ARGS__) \ +DO_207(MACRO, __VA_ARGS__) + + +#define DO_209(MACRO, ...) \ +MACRO(209, __VA_ARGS__) \ +DO_208(MACRO, __VA_ARGS__) + + +#define DO_210(MACRO, ...) \ +MACRO(210, __VA_ARGS__) \ +DO_209(MACRO, __VA_ARGS__) + + +#define DO_211(MACRO, ...) \ +MACRO(211, __VA_ARGS__) \ +DO_210(MACRO, __VA_ARGS__) + + +#define DO_212(MACRO, ...) \ +MACRO(212, __VA_ARGS__) \ +DO_211(MACRO, __VA_ARGS__) + + +#define DO_213(MACRO, ...) \ +MACRO(213, __VA_ARGS__) \ +DO_212(MACRO, __VA_ARGS__) + + +#define DO_214(MACRO, ...) \ +MACRO(214, __VA_ARGS__) \ +DO_213(MACRO, __VA_ARGS__) + + +#define DO_215(MACRO, ...) \ +MACRO(215, __VA_ARGS__) \ +DO_214(MACRO, __VA_ARGS__) + + +#define DO_216(MACRO, ...) \ +MACRO(216, __VA_ARGS__) \ +DO_215(MACRO, __VA_ARGS__) + + +#define DO_217(MACRO, ...) \ +MACRO(217, __VA_ARGS__) \ +DO_216(MACRO, __VA_ARGS__) + + +#define DO_218(MACRO, ...) \ +MACRO(218, __VA_ARGS__) \ +DO_217(MACRO, __VA_ARGS__) + + +#define DO_219(MACRO, ...) \ +MACRO(219, __VA_ARGS__) \ +DO_218(MACRO, __VA_ARGS__) + + +#define DO_220(MACRO, ...) \ +MACRO(220, __VA_ARGS__) \ +DO_219(MACRO, __VA_ARGS__) + + +#define DO_221(MACRO, ...) \ +MACRO(221, __VA_ARGS__) \ +DO_220(MACRO, __VA_ARGS__) + + +#define DO_222(MACRO, ...) \ +MACRO(222, __VA_ARGS__) \ +DO_221(MACRO, __VA_ARGS__) + + +#define DO_223(MACRO, ...) \ +MACRO(223, __VA_ARGS__) \ +DO_222(MACRO, __VA_ARGS__) + + +#define DO_224(MACRO, ...) \ +MACRO(224, __VA_ARGS__) \ +DO_223(MACRO, __VA_ARGS__) + + +#define DO_225(MACRO, ...) \ +MACRO(225, __VA_ARGS__) \ +DO_224(MACRO, __VA_ARGS__) + + +#define DO_226(MACRO, ...) \ +MACRO(226, __VA_ARGS__) \ +DO_225(MACRO, __VA_ARGS__) + + +#define DO_227(MACRO, ...) \ +MACRO(227, __VA_ARGS__) \ +DO_226(MACRO, __VA_ARGS__) + + +#define DO_228(MACRO, ...) \ +MACRO(228, __VA_ARGS__) \ +DO_227(MACRO, __VA_ARGS__) + + +#define DO_229(MACRO, ...) \ +MACRO(229, __VA_ARGS__) \ +DO_228(MACRO, __VA_ARGS__) + + +#define DO_230(MACRO, ...) \ +MACRO(230, __VA_ARGS__) \ +DO_229(MACRO, __VA_ARGS__) + + +#define DO_231(MACRO, ...) \ +MACRO(231, __VA_ARGS__) \ +DO_230(MACRO, __VA_ARGS__) + + +#define DO_232(MACRO, ...) \ +MACRO(232, __VA_ARGS__) \ +DO_231(MACRO, __VA_ARGS__) + + +#define DO_233(MACRO, ...) \ +MACRO(233, __VA_ARGS__) \ +DO_232(MACRO, __VA_ARGS__) + + +#define DO_234(MACRO, ...) \ +MACRO(234, __VA_ARGS__) \ +DO_233(MACRO, __VA_ARGS__) + + +#define DO_235(MACRO, ...) \ +MACRO(235, __VA_ARGS__) \ +DO_234(MACRO, __VA_ARGS__) + + +#define DO_236(MACRO, ...) \ +MACRO(236, __VA_ARGS__) \ +DO_235(MACRO, __VA_ARGS__) + + +#define DO_237(MACRO, ...) \ +MACRO(237, __VA_ARGS__) \ +DO_236(MACRO, __VA_ARGS__) + + +#define DO_238(MACRO, ...) \ +MACRO(238, __VA_ARGS__) \ +DO_237(MACRO, __VA_ARGS__) + + +#define DO_239(MACRO, ...) \ +MACRO(239, __VA_ARGS__) \ +DO_238(MACRO, __VA_ARGS__) + + +#define DO_240(MACRO, ...) \ +MACRO(240, __VA_ARGS__) \ +DO_239(MACRO, __VA_ARGS__) + + +#define DO_241(MACRO, ...) \ +MACRO(241, __VA_ARGS__) \ +DO_240(MACRO, __VA_ARGS__) + + +#define DO_242(MACRO, ...) \ +MACRO(242, __VA_ARGS__) \ +DO_241(MACRO, __VA_ARGS__) + + +#define DO_243(MACRO, ...) \ +MACRO(243, __VA_ARGS__) \ +DO_242(MACRO, __VA_ARGS__) + + +#define DO_244(MACRO, ...) \ +MACRO(244, __VA_ARGS__) \ +DO_243(MACRO, __VA_ARGS__) + + +#define DO_245(MACRO, ...) \ +MACRO(245, __VA_ARGS__) \ +DO_244(MACRO, __VA_ARGS__) + + +#define DO_246(MACRO, ...) \ +MACRO(246, __VA_ARGS__) \ +DO_245(MACRO, __VA_ARGS__) + + +#define DO_247(MACRO, ...) \ +MACRO(247, __VA_ARGS__) \ +DO_246(MACRO, __VA_ARGS__) + + +#define DO_248(MACRO, ...) \ +MACRO(248, __VA_ARGS__) \ +DO_247(MACRO, __VA_ARGS__) + + +#define DO_249(MACRO, ...) \ +MACRO(249, __VA_ARGS__) \ +DO_248(MACRO, __VA_ARGS__) + + +#define DO_250(MACRO, ...) \ +MACRO(250, __VA_ARGS__) \ +DO_249(MACRO, __VA_ARGS__) + + +#define DO_251(MACRO, ...) \ +MACRO(251, __VA_ARGS__) \ +DO_250(MACRO, __VA_ARGS__) + + +#define DO_252(MACRO, ...) \ +MACRO(252, __VA_ARGS__) \ +DO_251(MACRO, __VA_ARGS__) + + +#define DO_253(MACRO, ...) \ +MACRO(253, __VA_ARGS__) \ +DO_252(MACRO, __VA_ARGS__) + + +#define DO_254(MACRO, ...) \ +MACRO(254, __VA_ARGS__) \ +DO_253(MACRO, __VA_ARGS__) + + +#define DO_255(MACRO, ...) \ +MACRO(255, __VA_ARGS__) \ +DO_254(MACRO, __VA_ARGS__) + + +#define DO_256(MACRO, ...) \ +MACRO(256, __VA_ARGS__) \ +DO_255(MACRO, __VA_ARGS__) + + +#define DO_257(MACRO, ...) \ +MACRO(257, __VA_ARGS__) \ +DO_256(MACRO, __VA_ARGS__) + + +#define DO_258(MACRO, ...) \ +MACRO(258, __VA_ARGS__) \ +DO_257(MACRO, __VA_ARGS__) + + +#define DO_259(MACRO, ...) \ +MACRO(259, __VA_ARGS__) \ +DO_258(MACRO, __VA_ARGS__) + + +#define DO_260(MACRO, ...) \ +MACRO(260, __VA_ARGS__) \ +DO_259(MACRO, __VA_ARGS__) + + +#define DO_261(MACRO, ...) \ +MACRO(261, __VA_ARGS__) \ +DO_260(MACRO, __VA_ARGS__) + + +#define DO_262(MACRO, ...) \ +MACRO(262, __VA_ARGS__) \ +DO_261(MACRO, __VA_ARGS__) + + +#define DO_263(MACRO, ...) \ +MACRO(263, __VA_ARGS__) \ +DO_262(MACRO, __VA_ARGS__) + + +#define DO_264(MACRO, ...) \ +MACRO(264, __VA_ARGS__) \ +DO_263(MACRO, __VA_ARGS__) + + +#define DO_265(MACRO, ...) \ +MACRO(265, __VA_ARGS__) \ +DO_264(MACRO, __VA_ARGS__) + + +#define DO_266(MACRO, ...) \ +MACRO(266, __VA_ARGS__) \ +DO_265(MACRO, __VA_ARGS__) + + +#define DO_267(MACRO, ...) \ +MACRO(267, __VA_ARGS__) \ +DO_266(MACRO, __VA_ARGS__) + + +#define DO_268(MACRO, ...) \ +MACRO(268, __VA_ARGS__) \ +DO_267(MACRO, __VA_ARGS__) + + +#define DO_269(MACRO, ...) \ +MACRO(269, __VA_ARGS__) \ +DO_268(MACRO, __VA_ARGS__) + + +#define DO_270(MACRO, ...) \ +MACRO(270, __VA_ARGS__) \ +DO_269(MACRO, __VA_ARGS__) + + +#define DO_271(MACRO, ...) \ +MACRO(271, __VA_ARGS__) \ +DO_270(MACRO, __VA_ARGS__) + + +#define DO_272(MACRO, ...) \ +MACRO(272, __VA_ARGS__) \ +DO_271(MACRO, __VA_ARGS__) + + +#define DO_273(MACRO, ...) \ +MACRO(273, __VA_ARGS__) \ +DO_272(MACRO, __VA_ARGS__) + + +#define DO_274(MACRO, ...) \ +MACRO(274, __VA_ARGS__) \ +DO_273(MACRO, __VA_ARGS__) + + +#define DO_275(MACRO, ...) \ +MACRO(275, __VA_ARGS__) \ +DO_274(MACRO, __VA_ARGS__) + + +#define DO_276(MACRO, ...) \ +MACRO(276, __VA_ARGS__) \ +DO_275(MACRO, __VA_ARGS__) + + +#define DO_277(MACRO, ...) \ +MACRO(277, __VA_ARGS__) \ +DO_276(MACRO, __VA_ARGS__) + + +#define DO_278(MACRO, ...) \ +MACRO(278, __VA_ARGS__) \ +DO_277(MACRO, __VA_ARGS__) + + +#define DO_279(MACRO, ...) \ +MACRO(279, __VA_ARGS__) \ +DO_278(MACRO, __VA_ARGS__) + + +#define DO_280(MACRO, ...) \ +MACRO(280, __VA_ARGS__) \ +DO_279(MACRO, __VA_ARGS__) + + +#define DO_281(MACRO, ...) \ +MACRO(281, __VA_ARGS__) \ +DO_280(MACRO, __VA_ARGS__) + + +#define DO_282(MACRO, ...) \ +MACRO(282, __VA_ARGS__) \ +DO_281(MACRO, __VA_ARGS__) + + +#define DO_283(MACRO, ...) \ +MACRO(283, __VA_ARGS__) \ +DO_282(MACRO, __VA_ARGS__) + + +#define DO_284(MACRO, ...) \ +MACRO(284, __VA_ARGS__) \ +DO_283(MACRO, __VA_ARGS__) + + +#define DO_285(MACRO, ...) \ +MACRO(285, __VA_ARGS__) \ +DO_284(MACRO, __VA_ARGS__) + + +#define DO_286(MACRO, ...) \ +MACRO(286, __VA_ARGS__) \ +DO_285(MACRO, __VA_ARGS__) + + +#define DO_287(MACRO, ...) \ +MACRO(287, __VA_ARGS__) \ +DO_286(MACRO, __VA_ARGS__) + + +#define DO_288(MACRO, ...) \ +MACRO(288, __VA_ARGS__) \ +DO_287(MACRO, __VA_ARGS__) + + +#define DO_289(MACRO, ...) \ +MACRO(289, __VA_ARGS__) \ +DO_288(MACRO, __VA_ARGS__) + + +#define DO_290(MACRO, ...) \ +MACRO(290, __VA_ARGS__) \ +DO_289(MACRO, __VA_ARGS__) + + +#define DO_291(MACRO, ...) \ +MACRO(291, __VA_ARGS__) \ +DO_290(MACRO, __VA_ARGS__) + + +#define DO_292(MACRO, ...) \ +MACRO(292, __VA_ARGS__) \ +DO_291(MACRO, __VA_ARGS__) + + +#define DO_293(MACRO, ...) \ +MACRO(293, __VA_ARGS__) \ +DO_292(MACRO, __VA_ARGS__) + + +#define DO_294(MACRO, ...) \ +MACRO(294, __VA_ARGS__) \ +DO_293(MACRO, __VA_ARGS__) + + +#define DO_295(MACRO, ...) \ +MACRO(295, __VA_ARGS__) \ +DO_294(MACRO, __VA_ARGS__) + + +#define DO_296(MACRO, ...) \ +MACRO(296, __VA_ARGS__) \ +DO_295(MACRO, __VA_ARGS__) + + +#define DO_297(MACRO, ...) \ +MACRO(297, __VA_ARGS__) \ +DO_296(MACRO, __VA_ARGS__) + + +#define DO_298(MACRO, ...) \ +MACRO(298, __VA_ARGS__) \ +DO_297(MACRO, __VA_ARGS__) + + +#define DO_299(MACRO, ...) \ +MACRO(299, __VA_ARGS__) \ +DO_298(MACRO, __VA_ARGS__) + + +#define DO_300(MACRO, ...) \ +MACRO(300, __VA_ARGS__) \ +DO_299(MACRO, __VA_ARGS__) + + +#define DO_301(MACRO, ...) \ +MACRO(301, __VA_ARGS__) \ +DO_300(MACRO, __VA_ARGS__) + + +#define DO_302(MACRO, ...) \ +MACRO(302, __VA_ARGS__) \ +DO_301(MACRO, __VA_ARGS__) + + +#define DO_303(MACRO, ...) \ +MACRO(303, __VA_ARGS__) \ +DO_302(MACRO, __VA_ARGS__) + + +#define DO_304(MACRO, ...) \ +MACRO(304, __VA_ARGS__) \ +DO_303(MACRO, __VA_ARGS__) + + +#define DO_305(MACRO, ...) \ +MACRO(305, __VA_ARGS__) \ +DO_304(MACRO, __VA_ARGS__) + + +#define DO_306(MACRO, ...) \ +MACRO(306, __VA_ARGS__) \ +DO_305(MACRO, __VA_ARGS__) + + +#define DO_307(MACRO, ...) \ +MACRO(307, __VA_ARGS__) \ +DO_306(MACRO, __VA_ARGS__) + + +#define DO_308(MACRO, ...) \ +MACRO(308, __VA_ARGS__) \ +DO_307(MACRO, __VA_ARGS__) + + +#define DO_309(MACRO, ...) \ +MACRO(309, __VA_ARGS__) \ +DO_308(MACRO, __VA_ARGS__) + + +#define DO_310(MACRO, ...) \ +MACRO(310, __VA_ARGS__) \ +DO_309(MACRO, __VA_ARGS__) + + +#define DO_311(MACRO, ...) \ +MACRO(311, __VA_ARGS__) \ +DO_310(MACRO, __VA_ARGS__) + + +#define DO_312(MACRO, ...) \ +MACRO(312, __VA_ARGS__) \ +DO_311(MACRO, __VA_ARGS__) + + +#define DO_313(MACRO, ...) \ +MACRO(313, __VA_ARGS__) \ +DO_312(MACRO, __VA_ARGS__) + + +#define DO_314(MACRO, ...) \ +MACRO(314, __VA_ARGS__) \ +DO_313(MACRO, __VA_ARGS__) + + +#define DO_315(MACRO, ...) \ +MACRO(315, __VA_ARGS__) \ +DO_314(MACRO, __VA_ARGS__) + + +#define DO_316(MACRO, ...) \ +MACRO(316, __VA_ARGS__) \ +DO_315(MACRO, __VA_ARGS__) + + +#define DO_317(MACRO, ...) \ +MACRO(317, __VA_ARGS__) \ +DO_316(MACRO, __VA_ARGS__) + + +#define DO_318(MACRO, ...) \ +MACRO(318, __VA_ARGS__) \ +DO_317(MACRO, __VA_ARGS__) + + +#define DO_319(MACRO, ...) \ +MACRO(319, __VA_ARGS__) \ +DO_318(MACRO, __VA_ARGS__) + + +#define DO_320(MACRO, ...) \ +MACRO(320, __VA_ARGS__) \ +DO_319(MACRO, __VA_ARGS__) + + +#define DO_321(MACRO, ...) \ +MACRO(321, __VA_ARGS__) \ +DO_320(MACRO, __VA_ARGS__) + + +#define DO_322(MACRO, ...) \ +MACRO(322, __VA_ARGS__) \ +DO_321(MACRO, __VA_ARGS__) + + +#define DO_323(MACRO, ...) \ +MACRO(323, __VA_ARGS__) \ +DO_322(MACRO, __VA_ARGS__) + + +#define DO_324(MACRO, ...) \ +MACRO(324, __VA_ARGS__) \ +DO_323(MACRO, __VA_ARGS__) + + +#define DO_325(MACRO, ...) \ +MACRO(325, __VA_ARGS__) \ +DO_324(MACRO, __VA_ARGS__) + + +#define DO_326(MACRO, ...) \ +MACRO(326, __VA_ARGS__) \ +DO_325(MACRO, __VA_ARGS__) + + +#define DO_327(MACRO, ...) \ +MACRO(327, __VA_ARGS__) \ +DO_326(MACRO, __VA_ARGS__) + + +#define DO_328(MACRO, ...) \ +MACRO(328, __VA_ARGS__) \ +DO_327(MACRO, __VA_ARGS__) + + +#define DO_329(MACRO, ...) \ +MACRO(329, __VA_ARGS__) \ +DO_328(MACRO, __VA_ARGS__) + + +#define DO_330(MACRO, ...) \ +MACRO(330, __VA_ARGS__) \ +DO_329(MACRO, __VA_ARGS__) + + +#define DO_331(MACRO, ...) \ +MACRO(331, __VA_ARGS__) \ +DO_330(MACRO, __VA_ARGS__) + + +#define DO_332(MACRO, ...) \ +MACRO(332, __VA_ARGS__) \ +DO_331(MACRO, __VA_ARGS__) + + +#define DO_333(MACRO, ...) \ +MACRO(333, __VA_ARGS__) \ +DO_332(MACRO, __VA_ARGS__) + + +#define DO_334(MACRO, ...) \ +MACRO(334, __VA_ARGS__) \ +DO_333(MACRO, __VA_ARGS__) + + +#define DO_335(MACRO, ...) \ +MACRO(335, __VA_ARGS__) \ +DO_334(MACRO, __VA_ARGS__) + + +#define DO_336(MACRO, ...) \ +MACRO(336, __VA_ARGS__) \ +DO_335(MACRO, __VA_ARGS__) + + +#define DO_337(MACRO, ...) \ +MACRO(337, __VA_ARGS__) \ +DO_336(MACRO, __VA_ARGS__) + + +#define DO_338(MACRO, ...) \ +MACRO(338, __VA_ARGS__) \ +DO_337(MACRO, __VA_ARGS__) + + +#define DO_339(MACRO, ...) \ +MACRO(339, __VA_ARGS__) \ +DO_338(MACRO, __VA_ARGS__) + + +#define DO_340(MACRO, ...) \ +MACRO(340, __VA_ARGS__) \ +DO_339(MACRO, __VA_ARGS__) + + +#define DO_341(MACRO, ...) \ +MACRO(341, __VA_ARGS__) \ +DO_340(MACRO, __VA_ARGS__) + + +#define DO_342(MACRO, ...) \ +MACRO(342, __VA_ARGS__) \ +DO_341(MACRO, __VA_ARGS__) + + +#define DO_343(MACRO, ...) \ +MACRO(343, __VA_ARGS__) \ +DO_342(MACRO, __VA_ARGS__) + + +#define DO_344(MACRO, ...) \ +MACRO(344, __VA_ARGS__) \ +DO_343(MACRO, __VA_ARGS__) + + +#define DO_345(MACRO, ...) \ +MACRO(345, __VA_ARGS__) \ +DO_344(MACRO, __VA_ARGS__) + + +#define DO_346(MACRO, ...) \ +MACRO(346, __VA_ARGS__) \ +DO_345(MACRO, __VA_ARGS__) + + +#define DO_347(MACRO, ...) \ +MACRO(347, __VA_ARGS__) \ +DO_346(MACRO, __VA_ARGS__) + + +#define DO_348(MACRO, ...) \ +MACRO(348, __VA_ARGS__) \ +DO_347(MACRO, __VA_ARGS__) + + +#define DO_349(MACRO, ...) \ +MACRO(349, __VA_ARGS__) \ +DO_348(MACRO, __VA_ARGS__) + + +#define DO_350(MACRO, ...) \ +MACRO(350, __VA_ARGS__) \ +DO_349(MACRO, __VA_ARGS__) + + +#define DO_351(MACRO, ...) \ +MACRO(351, __VA_ARGS__) \ +DO_350(MACRO, __VA_ARGS__) + + +#define DO_352(MACRO, ...) \ +MACRO(352, __VA_ARGS__) \ +DO_351(MACRO, __VA_ARGS__) + + +#define DO_353(MACRO, ...) \ +MACRO(353, __VA_ARGS__) \ +DO_352(MACRO, __VA_ARGS__) + + +#define DO_354(MACRO, ...) \ +MACRO(354, __VA_ARGS__) \ +DO_353(MACRO, __VA_ARGS__) + + +#define DO_355(MACRO, ...) \ +MACRO(355, __VA_ARGS__) \ +DO_354(MACRO, __VA_ARGS__) + + +#define DO_356(MACRO, ...) \ +MACRO(356, __VA_ARGS__) \ +DO_355(MACRO, __VA_ARGS__) + + +#define DO_357(MACRO, ...) \ +MACRO(357, __VA_ARGS__) \ +DO_356(MACRO, __VA_ARGS__) + + +#define DO_358(MACRO, ...) \ +MACRO(358, __VA_ARGS__) \ +DO_357(MACRO, __VA_ARGS__) + + +#define DO_359(MACRO, ...) \ +MACRO(359, __VA_ARGS__) \ +DO_358(MACRO, __VA_ARGS__) + + +#define DO_360(MACRO, ...) \ +MACRO(360, __VA_ARGS__) \ +DO_359(MACRO, __VA_ARGS__) + + +#define DO_361(MACRO, ...) \ +MACRO(361, __VA_ARGS__) \ +DO_360(MACRO, __VA_ARGS__) + + +#define DO_362(MACRO, ...) \ +MACRO(362, __VA_ARGS__) \ +DO_361(MACRO, __VA_ARGS__) + + +#define DO_363(MACRO, ...) \ +MACRO(363, __VA_ARGS__) \ +DO_362(MACRO, __VA_ARGS__) + + +#define DO_364(MACRO, ...) \ +MACRO(364, __VA_ARGS__) \ +DO_363(MACRO, __VA_ARGS__) + + +#define DO_365(MACRO, ...) \ +MACRO(365, __VA_ARGS__) \ +DO_364(MACRO, __VA_ARGS__) + + +#define DO_366(MACRO, ...) \ +MACRO(366, __VA_ARGS__) \ +DO_365(MACRO, __VA_ARGS__) + + +#define DO_367(MACRO, ...) \ +MACRO(367, __VA_ARGS__) \ +DO_366(MACRO, __VA_ARGS__) + + +#define DO_368(MACRO, ...) \ +MACRO(368, __VA_ARGS__) \ +DO_367(MACRO, __VA_ARGS__) + + +#define DO_369(MACRO, ...) \ +MACRO(369, __VA_ARGS__) \ +DO_368(MACRO, __VA_ARGS__) + + +#define DO_370(MACRO, ...) \ +MACRO(370, __VA_ARGS__) \ +DO_369(MACRO, __VA_ARGS__) + + +#define DO_371(MACRO, ...) \ +MACRO(371, __VA_ARGS__) \ +DO_370(MACRO, __VA_ARGS__) + + +#define DO_372(MACRO, ...) \ +MACRO(372, __VA_ARGS__) \ +DO_371(MACRO, __VA_ARGS__) + + +#define DO_373(MACRO, ...) \ +MACRO(373, __VA_ARGS__) \ +DO_372(MACRO, __VA_ARGS__) + + +#define DO_374(MACRO, ...) \ +MACRO(374, __VA_ARGS__) \ +DO_373(MACRO, __VA_ARGS__) + + +#define DO_375(MACRO, ...) \ +MACRO(375, __VA_ARGS__) \ +DO_374(MACRO, __VA_ARGS__) + + +#define DO_376(MACRO, ...) \ +MACRO(376, __VA_ARGS__) \ +DO_375(MACRO, __VA_ARGS__) + + +#define DO_377(MACRO, ...) \ +MACRO(377, __VA_ARGS__) \ +DO_376(MACRO, __VA_ARGS__) + + +#define DO_378(MACRO, ...) \ +MACRO(378, __VA_ARGS__) \ +DO_377(MACRO, __VA_ARGS__) + + +#define DO_379(MACRO, ...) \ +MACRO(379, __VA_ARGS__) \ +DO_378(MACRO, __VA_ARGS__) + + +#define DO_380(MACRO, ...) \ +MACRO(380, __VA_ARGS__) \ +DO_379(MACRO, __VA_ARGS__) + + +#define DO_381(MACRO, ...) \ +MACRO(381, __VA_ARGS__) \ +DO_380(MACRO, __VA_ARGS__) + + +#define DO_382(MACRO, ...) \ +MACRO(382, __VA_ARGS__) \ +DO_381(MACRO, __VA_ARGS__) + + +#define DO_383(MACRO, ...) \ +MACRO(383, __VA_ARGS__) \ +DO_382(MACRO, __VA_ARGS__) + + +#define DO_384(MACRO, ...) \ +MACRO(384, __VA_ARGS__) \ +DO_383(MACRO, __VA_ARGS__) + + +#define DO_385(MACRO, ...) \ +MACRO(385, __VA_ARGS__) \ +DO_384(MACRO, __VA_ARGS__) + + +#define DO_386(MACRO, ...) \ +MACRO(386, __VA_ARGS__) \ +DO_385(MACRO, __VA_ARGS__) + + +#define DO_387(MACRO, ...) \ +MACRO(387, __VA_ARGS__) \ +DO_386(MACRO, __VA_ARGS__) + + +#define DO_388(MACRO, ...) \ +MACRO(388, __VA_ARGS__) \ +DO_387(MACRO, __VA_ARGS__) + + +#define DO_389(MACRO, ...) \ +MACRO(389, __VA_ARGS__) \ +DO_388(MACRO, __VA_ARGS__) + + +#define DO_390(MACRO, ...) \ +MACRO(390, __VA_ARGS__) \ +DO_389(MACRO, __VA_ARGS__) + + +#define DO_391(MACRO, ...) \ +MACRO(391, __VA_ARGS__) \ +DO_390(MACRO, __VA_ARGS__) + + +#define DO_392(MACRO, ...) \ +MACRO(392, __VA_ARGS__) \ +DO_391(MACRO, __VA_ARGS__) + + +#define DO_393(MACRO, ...) \ +MACRO(393, __VA_ARGS__) \ +DO_392(MACRO, __VA_ARGS__) + + +#define DO_394(MACRO, ...) \ +MACRO(394, __VA_ARGS__) \ +DO_393(MACRO, __VA_ARGS__) + + +#define DO_395(MACRO, ...) \ +MACRO(395, __VA_ARGS__) \ +DO_394(MACRO, __VA_ARGS__) + + +#define DO_396(MACRO, ...) \ +MACRO(396, __VA_ARGS__) \ +DO_395(MACRO, __VA_ARGS__) + + +#define DO_397(MACRO, ...) \ +MACRO(397, __VA_ARGS__) \ +DO_396(MACRO, __VA_ARGS__) + + +#define DO_398(MACRO, ...) \ +MACRO(398, __VA_ARGS__) \ +DO_397(MACRO, __VA_ARGS__) + + +#define DO_399(MACRO, ...) \ +MACRO(399, __VA_ARGS__) \ +DO_398(MACRO, __VA_ARGS__) + + +#define DO_400(MACRO, ...) \ +MACRO(400, __VA_ARGS__) \ +DO_399(MACRO, __VA_ARGS__) + + +#define DO_401(MACRO, ...) \ +MACRO(401, __VA_ARGS__) \ +DO_400(MACRO, __VA_ARGS__) + + +#define DO_402(MACRO, ...) \ +MACRO(402, __VA_ARGS__) \ +DO_401(MACRO, __VA_ARGS__) + + +#define DO_403(MACRO, ...) \ +MACRO(403, __VA_ARGS__) \ +DO_402(MACRO, __VA_ARGS__) + + +#define DO_404(MACRO, ...) \ +MACRO(404, __VA_ARGS__) \ +DO_403(MACRO, __VA_ARGS__) + + +#define DO_405(MACRO, ...) \ +MACRO(405, __VA_ARGS__) \ +DO_404(MACRO, __VA_ARGS__) + + +#define DO_406(MACRO, ...) \ +MACRO(406, __VA_ARGS__) \ +DO_405(MACRO, __VA_ARGS__) + + +#define DO_407(MACRO, ...) \ +MACRO(407, __VA_ARGS__) \ +DO_406(MACRO, __VA_ARGS__) + + +#define DO_408(MACRO, ...) \ +MACRO(408, __VA_ARGS__) \ +DO_407(MACRO, __VA_ARGS__) + + +#define DO_409(MACRO, ...) \ +MACRO(409, __VA_ARGS__) \ +DO_408(MACRO, __VA_ARGS__) + + +#define DO_410(MACRO, ...) \ +MACRO(410, __VA_ARGS__) \ +DO_409(MACRO, __VA_ARGS__) + + +#define DO_411(MACRO, ...) \ +MACRO(411, __VA_ARGS__) \ +DO_410(MACRO, __VA_ARGS__) + + +#define DO_412(MACRO, ...) \ +MACRO(412, __VA_ARGS__) \ +DO_411(MACRO, __VA_ARGS__) + + +#define DO_413(MACRO, ...) \ +MACRO(413, __VA_ARGS__) \ +DO_412(MACRO, __VA_ARGS__) + + +#define DO_414(MACRO, ...) \ +MACRO(414, __VA_ARGS__) \ +DO_413(MACRO, __VA_ARGS__) + + +#define DO_415(MACRO, ...) \ +MACRO(415, __VA_ARGS__) \ +DO_414(MACRO, __VA_ARGS__) + + +#define DO_416(MACRO, ...) \ +MACRO(416, __VA_ARGS__) \ +DO_415(MACRO, __VA_ARGS__) + + +#define DO_417(MACRO, ...) \ +MACRO(417, __VA_ARGS__) \ +DO_416(MACRO, __VA_ARGS__) + + +#define DO_418(MACRO, ...) \ +MACRO(418, __VA_ARGS__) \ +DO_417(MACRO, __VA_ARGS__) + + +#define DO_419(MACRO, ...) \ +MACRO(419, __VA_ARGS__) \ +DO_418(MACRO, __VA_ARGS__) + + +#define DO_420(MACRO, ...) \ +MACRO(420, __VA_ARGS__) \ +DO_419(MACRO, __VA_ARGS__) + + +#define DO_421(MACRO, ...) \ +MACRO(421, __VA_ARGS__) \ +DO_420(MACRO, __VA_ARGS__) + + +#define DO_422(MACRO, ...) \ +MACRO(422, __VA_ARGS__) \ +DO_421(MACRO, __VA_ARGS__) + + +#define DO_423(MACRO, ...) \ +MACRO(423, __VA_ARGS__) \ +DO_422(MACRO, __VA_ARGS__) + + +#define DO_424(MACRO, ...) \ +MACRO(424, __VA_ARGS__) \ +DO_423(MACRO, __VA_ARGS__) + + +#define DO_425(MACRO, ...) \ +MACRO(425, __VA_ARGS__) \ +DO_424(MACRO, __VA_ARGS__) + + +#define DO_426(MACRO, ...) \ +MACRO(426, __VA_ARGS__) \ +DO_425(MACRO, __VA_ARGS__) + + +#define DO_427(MACRO, ...) \ +MACRO(427, __VA_ARGS__) \ +DO_426(MACRO, __VA_ARGS__) + + +#define DO_428(MACRO, ...) \ +MACRO(428, __VA_ARGS__) \ +DO_427(MACRO, __VA_ARGS__) + + +#define DO_429(MACRO, ...) \ +MACRO(429, __VA_ARGS__) \ +DO_428(MACRO, __VA_ARGS__) + + +#define DO_430(MACRO, ...) \ +MACRO(430, __VA_ARGS__) \ +DO_429(MACRO, __VA_ARGS__) + + +#define DO_431(MACRO, ...) \ +MACRO(431, __VA_ARGS__) \ +DO_430(MACRO, __VA_ARGS__) + + +#define DO_432(MACRO, ...) \ +MACRO(432, __VA_ARGS__) \ +DO_431(MACRO, __VA_ARGS__) + + +#define DO_433(MACRO, ...) \ +MACRO(433, __VA_ARGS__) \ +DO_432(MACRO, __VA_ARGS__) + + +#define DO_434(MACRO, ...) \ +MACRO(434, __VA_ARGS__) \ +DO_433(MACRO, __VA_ARGS__) + + +#define DO_435(MACRO, ...) \ +MACRO(435, __VA_ARGS__) \ +DO_434(MACRO, __VA_ARGS__) + + +#define DO_436(MACRO, ...) \ +MACRO(436, __VA_ARGS__) \ +DO_435(MACRO, __VA_ARGS__) + + +#define DO_437(MACRO, ...) \ +MACRO(437, __VA_ARGS__) \ +DO_436(MACRO, __VA_ARGS__) + + +#define DO_438(MACRO, ...) \ +MACRO(438, __VA_ARGS__) \ +DO_437(MACRO, __VA_ARGS__) + + +#define DO_439(MACRO, ...) \ +MACRO(439, __VA_ARGS__) \ +DO_438(MACRO, __VA_ARGS__) + + +#define DO_440(MACRO, ...) \ +MACRO(440, __VA_ARGS__) \ +DO_439(MACRO, __VA_ARGS__) + + +#define DO_441(MACRO, ...) \ +MACRO(441, __VA_ARGS__) \ +DO_440(MACRO, __VA_ARGS__) + + +#define DO_442(MACRO, ...) \ +MACRO(442, __VA_ARGS__) \ +DO_441(MACRO, __VA_ARGS__) + + +#define DO_443(MACRO, ...) \ +MACRO(443, __VA_ARGS__) \ +DO_442(MACRO, __VA_ARGS__) + + +#define DO_444(MACRO, ...) \ +MACRO(444, __VA_ARGS__) \ +DO_443(MACRO, __VA_ARGS__) + + +#define DO_445(MACRO, ...) \ +MACRO(445, __VA_ARGS__) \ +DO_444(MACRO, __VA_ARGS__) + + +#define DO_446(MACRO, ...) \ +MACRO(446, __VA_ARGS__) \ +DO_445(MACRO, __VA_ARGS__) + + +#define DO_447(MACRO, ...) \ +MACRO(447, __VA_ARGS__) \ +DO_446(MACRO, __VA_ARGS__) + + +#define DO_448(MACRO, ...) \ +MACRO(448, __VA_ARGS__) \ +DO_447(MACRO, __VA_ARGS__) + + +#define DO_449(MACRO, ...) \ +MACRO(449, __VA_ARGS__) \ +DO_448(MACRO, __VA_ARGS__) + + +#define DO_450(MACRO, ...) \ +MACRO(450, __VA_ARGS__) \ +DO_449(MACRO, __VA_ARGS__) + + +#define DO_451(MACRO, ...) \ +MACRO(451, __VA_ARGS__) \ +DO_450(MACRO, __VA_ARGS__) + + +#define DO_452(MACRO, ...) \ +MACRO(452, __VA_ARGS__) \ +DO_451(MACRO, __VA_ARGS__) + + +#define DO_453(MACRO, ...) \ +MACRO(453, __VA_ARGS__) \ +DO_452(MACRO, __VA_ARGS__) + + +#define DO_454(MACRO, ...) \ +MACRO(454, __VA_ARGS__) \ +DO_453(MACRO, __VA_ARGS__) + + +#define DO_455(MACRO, ...) \ +MACRO(455, __VA_ARGS__) \ +DO_454(MACRO, __VA_ARGS__) + + +#define DO_456(MACRO, ...) \ +MACRO(456, __VA_ARGS__) \ +DO_455(MACRO, __VA_ARGS__) + + +#define DO_457(MACRO, ...) \ +MACRO(457, __VA_ARGS__) \ +DO_456(MACRO, __VA_ARGS__) + + +#define DO_458(MACRO, ...) \ +MACRO(458, __VA_ARGS__) \ +DO_457(MACRO, __VA_ARGS__) + + +#define DO_459(MACRO, ...) \ +MACRO(459, __VA_ARGS__) \ +DO_458(MACRO, __VA_ARGS__) + + +#define DO_460(MACRO, ...) \ +MACRO(460, __VA_ARGS__) \ +DO_459(MACRO, __VA_ARGS__) + + +#define DO_461(MACRO, ...) \ +MACRO(461, __VA_ARGS__) \ +DO_460(MACRO, __VA_ARGS__) + + +#define DO_462(MACRO, ...) \ +MACRO(462, __VA_ARGS__) \ +DO_461(MACRO, __VA_ARGS__) + + +#define DO_463(MACRO, ...) \ +MACRO(463, __VA_ARGS__) \ +DO_462(MACRO, __VA_ARGS__) + + +#define DO_464(MACRO, ...) \ +MACRO(464, __VA_ARGS__) \ +DO_463(MACRO, __VA_ARGS__) + + +#define DO_465(MACRO, ...) \ +MACRO(465, __VA_ARGS__) \ +DO_464(MACRO, __VA_ARGS__) + + +#define DO_466(MACRO, ...) \ +MACRO(466, __VA_ARGS__) \ +DO_465(MACRO, __VA_ARGS__) + + +#define DO_467(MACRO, ...) \ +MACRO(467, __VA_ARGS__) \ +DO_466(MACRO, __VA_ARGS__) + + +#define DO_468(MACRO, ...) \ +MACRO(468, __VA_ARGS__) \ +DO_467(MACRO, __VA_ARGS__) + + +#define DO_469(MACRO, ...) \ +MACRO(469, __VA_ARGS__) \ +DO_468(MACRO, __VA_ARGS__) + + +#define DO_470(MACRO, ...) \ +MACRO(470, __VA_ARGS__) \ +DO_469(MACRO, __VA_ARGS__) + + +#define DO_471(MACRO, ...) \ +MACRO(471, __VA_ARGS__) \ +DO_470(MACRO, __VA_ARGS__) + + +#define DO_472(MACRO, ...) \ +MACRO(472, __VA_ARGS__) \ +DO_471(MACRO, __VA_ARGS__) + + +#define DO_473(MACRO, ...) \ +MACRO(473, __VA_ARGS__) \ +DO_472(MACRO, __VA_ARGS__) + + +#define DO_474(MACRO, ...) \ +MACRO(474, __VA_ARGS__) \ +DO_473(MACRO, __VA_ARGS__) + + +#define DO_475(MACRO, ...) \ +MACRO(475, __VA_ARGS__) \ +DO_474(MACRO, __VA_ARGS__) + + +#define DO_476(MACRO, ...) \ +MACRO(476, __VA_ARGS__) \ +DO_475(MACRO, __VA_ARGS__) + + +#define DO_477(MACRO, ...) \ +MACRO(477, __VA_ARGS__) \ +DO_476(MACRO, __VA_ARGS__) + + +#define DO_478(MACRO, ...) \ +MACRO(478, __VA_ARGS__) \ +DO_477(MACRO, __VA_ARGS__) + + +#define DO_479(MACRO, ...) \ +MACRO(479, __VA_ARGS__) \ +DO_478(MACRO, __VA_ARGS__) + + +#define DO_480(MACRO, ...) \ +MACRO(480, __VA_ARGS__) \ +DO_479(MACRO, __VA_ARGS__) + + +#define DO_481(MACRO, ...) \ +MACRO(481, __VA_ARGS__) \ +DO_480(MACRO, __VA_ARGS__) + + +#define DO_482(MACRO, ...) \ +MACRO(482, __VA_ARGS__) \ +DO_481(MACRO, __VA_ARGS__) + + +#define DO_483(MACRO, ...) \ +MACRO(483, __VA_ARGS__) \ +DO_482(MACRO, __VA_ARGS__) + + +#define DO_484(MACRO, ...) \ +MACRO(484, __VA_ARGS__) \ +DO_483(MACRO, __VA_ARGS__) + + +#define DO_485(MACRO, ...) \ +MACRO(485, __VA_ARGS__) \ +DO_484(MACRO, __VA_ARGS__) + + +#define DO_486(MACRO, ...) \ +MACRO(486, __VA_ARGS__) \ +DO_485(MACRO, __VA_ARGS__) + + +#define DO_487(MACRO, ...) \ +MACRO(487, __VA_ARGS__) \ +DO_486(MACRO, __VA_ARGS__) + + +#define DO_488(MACRO, ...) \ +MACRO(488, __VA_ARGS__) \ +DO_487(MACRO, __VA_ARGS__) + + +#define DO_489(MACRO, ...) \ +MACRO(489, __VA_ARGS__) \ +DO_488(MACRO, __VA_ARGS__) + + +#define DO_490(MACRO, ...) \ +MACRO(490, __VA_ARGS__) \ +DO_489(MACRO, __VA_ARGS__) + + +#define DO_491(MACRO, ...) \ +MACRO(491, __VA_ARGS__) \ +DO_490(MACRO, __VA_ARGS__) + + +#define DO_492(MACRO, ...) \ +MACRO(492, __VA_ARGS__) \ +DO_491(MACRO, __VA_ARGS__) + + +#define DO_493(MACRO, ...) \ +MACRO(493, __VA_ARGS__) \ +DO_492(MACRO, __VA_ARGS__) + + +#define DO_494(MACRO, ...) \ +MACRO(494, __VA_ARGS__) \ +DO_493(MACRO, __VA_ARGS__) + + +#define DO_495(MACRO, ...) \ +MACRO(495, __VA_ARGS__) \ +DO_494(MACRO, __VA_ARGS__) + + +#define DO_496(MACRO, ...) \ +MACRO(496, __VA_ARGS__) \ +DO_495(MACRO, __VA_ARGS__) + + +#define DO_497(MACRO, ...) \ +MACRO(497, __VA_ARGS__) \ +DO_496(MACRO, __VA_ARGS__) + + +#define DO_498(MACRO, ...) \ +MACRO(498, __VA_ARGS__) \ +DO_497(MACRO, __VA_ARGS__) + + +#define DO_499(MACRO, ...) \ +MACRO(499, __VA_ARGS__) \ +DO_498(MACRO, __VA_ARGS__) + + +#define DO_500(MACRO, ...) \ +MACRO(500, __VA_ARGS__) \ +DO_499(MACRO, __VA_ARGS__) + + +#define DO_501(MACRO, ...) \ +MACRO(501, __VA_ARGS__) \ +DO_500(MACRO, __VA_ARGS__) + + +#define DO_502(MACRO, ...) \ +MACRO(502, __VA_ARGS__) \ +DO_501(MACRO, __VA_ARGS__) + + +#define DO_503(MACRO, ...) \ +MACRO(503, __VA_ARGS__) \ +DO_502(MACRO, __VA_ARGS__) + + +#define DO_504(MACRO, ...) \ +MACRO(504, __VA_ARGS__) \ +DO_503(MACRO, __VA_ARGS__) + + +#define DO_505(MACRO, ...) \ +MACRO(505, __VA_ARGS__) \ +DO_504(MACRO, __VA_ARGS__) + + +#define DO_506(MACRO, ...) \ +MACRO(506, __VA_ARGS__) \ +DO_505(MACRO, __VA_ARGS__) + + +#define DO_507(MACRO, ...) \ +MACRO(507, __VA_ARGS__) \ +DO_506(MACRO, __VA_ARGS__) + + +#define DO_508(MACRO, ...) \ +MACRO(508, __VA_ARGS__) \ +DO_507(MACRO, __VA_ARGS__) + + +#define DO_509(MACRO, ...) \ +MACRO(509, __VA_ARGS__) \ +DO_508(MACRO, __VA_ARGS__) + + +#define DO_510(MACRO, ...) \ +MACRO(510, __VA_ARGS__) \ +DO_509(MACRO, __VA_ARGS__) + + +#define DO_511(MACRO, ...) \ +MACRO(511, __VA_ARGS__) \ +DO_510(MACRO, __VA_ARGS__) + + +#define DO_512(MACRO, ...) \ +MACRO(512, __VA_ARGS__) \ +DO_511(MACRO, __VA_ARGS__) + + +#define DO_513(MACRO, ...) \ +MACRO(513, __VA_ARGS__) \ +DO_512(MACRO, __VA_ARGS__) + + +#define DO_514(MACRO, ...) \ +MACRO(514, __VA_ARGS__) \ +DO_513(MACRO, __VA_ARGS__) + + +#define DO_515(MACRO, ...) \ +MACRO(515, __VA_ARGS__) \ +DO_514(MACRO, __VA_ARGS__) + + +#define DO_516(MACRO, ...) \ +MACRO(516, __VA_ARGS__) \ +DO_515(MACRO, __VA_ARGS__) + + +#define DO_517(MACRO, ...) \ +MACRO(517, __VA_ARGS__) \ +DO_516(MACRO, __VA_ARGS__) + + +#define DO_518(MACRO, ...) \ +MACRO(518, __VA_ARGS__) \ +DO_517(MACRO, __VA_ARGS__) + + +#define DO_519(MACRO, ...) \ +MACRO(519, __VA_ARGS__) \ +DO_518(MACRO, __VA_ARGS__) + + +#define DO_520(MACRO, ...) \ +MACRO(520, __VA_ARGS__) \ +DO_519(MACRO, __VA_ARGS__) + + +#define DO_521(MACRO, ...) \ +MACRO(521, __VA_ARGS__) \ +DO_520(MACRO, __VA_ARGS__) + + +#define DO_522(MACRO, ...) \ +MACRO(522, __VA_ARGS__) \ +DO_521(MACRO, __VA_ARGS__) + + +#define DO_523(MACRO, ...) \ +MACRO(523, __VA_ARGS__) \ +DO_522(MACRO, __VA_ARGS__) + + +#define DO_524(MACRO, ...) \ +MACRO(524, __VA_ARGS__) \ +DO_523(MACRO, __VA_ARGS__) + + +#define DO_525(MACRO, ...) \ +MACRO(525, __VA_ARGS__) \ +DO_524(MACRO, __VA_ARGS__) + + +#define DO_526(MACRO, ...) \ +MACRO(526, __VA_ARGS__) \ +DO_525(MACRO, __VA_ARGS__) + + +#define DO_527(MACRO, ...) \ +MACRO(527, __VA_ARGS__) \ +DO_526(MACRO, __VA_ARGS__) + + +#define DO_528(MACRO, ...) \ +MACRO(528, __VA_ARGS__) \ +DO_527(MACRO, __VA_ARGS__) + + +#define DO_529(MACRO, ...) \ +MACRO(529, __VA_ARGS__) \ +DO_528(MACRO, __VA_ARGS__) + + +#define DO_530(MACRO, ...) \ +MACRO(530, __VA_ARGS__) \ +DO_529(MACRO, __VA_ARGS__) + + +#define DO_531(MACRO, ...) \ +MACRO(531, __VA_ARGS__) \ +DO_530(MACRO, __VA_ARGS__) + + +#define DO_532(MACRO, ...) \ +MACRO(532, __VA_ARGS__) \ +DO_531(MACRO, __VA_ARGS__) + + +#define DO_533(MACRO, ...) \ +MACRO(533, __VA_ARGS__) \ +DO_532(MACRO, __VA_ARGS__) + + +#define DO_534(MACRO, ...) \ +MACRO(534, __VA_ARGS__) \ +DO_533(MACRO, __VA_ARGS__) + + +#define DO_535(MACRO, ...) \ +MACRO(535, __VA_ARGS__) \ +DO_534(MACRO, __VA_ARGS__) + + +#define DO_536(MACRO, ...) \ +MACRO(536, __VA_ARGS__) \ +DO_535(MACRO, __VA_ARGS__) + + +#define DO_537(MACRO, ...) \ +MACRO(537, __VA_ARGS__) \ +DO_536(MACRO, __VA_ARGS__) + + +#define DO_538(MACRO, ...) \ +MACRO(538, __VA_ARGS__) \ +DO_537(MACRO, __VA_ARGS__) + + +#define DO_539(MACRO, ...) \ +MACRO(539, __VA_ARGS__) \ +DO_538(MACRO, __VA_ARGS__) + + +#define DO_540(MACRO, ...) \ +MACRO(540, __VA_ARGS__) \ +DO_539(MACRO, __VA_ARGS__) + + +#define DO_541(MACRO, ...) \ +MACRO(541, __VA_ARGS__) \ +DO_540(MACRO, __VA_ARGS__) + + +#define DO_542(MACRO, ...) \ +MACRO(542, __VA_ARGS__) \ +DO_541(MACRO, __VA_ARGS__) + + +#define DO_543(MACRO, ...) \ +MACRO(543, __VA_ARGS__) \ +DO_542(MACRO, __VA_ARGS__) + + +#define DO_544(MACRO, ...) \ +MACRO(544, __VA_ARGS__) \ +DO_543(MACRO, __VA_ARGS__) + + +#define DO_545(MACRO, ...) \ +MACRO(545, __VA_ARGS__) \ +DO_544(MACRO, __VA_ARGS__) + + +#define DO_546(MACRO, ...) \ +MACRO(546, __VA_ARGS__) \ +DO_545(MACRO, __VA_ARGS__) + + +#define DO_547(MACRO, ...) \ +MACRO(547, __VA_ARGS__) \ +DO_546(MACRO, __VA_ARGS__) + + +#define DO_548(MACRO, ...) \ +MACRO(548, __VA_ARGS__) \ +DO_547(MACRO, __VA_ARGS__) + + +#define DO_549(MACRO, ...) \ +MACRO(549, __VA_ARGS__) \ +DO_548(MACRO, __VA_ARGS__) + + +#define DO_550(MACRO, ...) \ +MACRO(550, __VA_ARGS__) \ +DO_549(MACRO, __VA_ARGS__) + + +#define DO_551(MACRO, ...) \ +MACRO(551, __VA_ARGS__) \ +DO_550(MACRO, __VA_ARGS__) + + +#define DO_552(MACRO, ...) \ +MACRO(552, __VA_ARGS__) \ +DO_551(MACRO, __VA_ARGS__) + + +#define DO_553(MACRO, ...) \ +MACRO(553, __VA_ARGS__) \ +DO_552(MACRO, __VA_ARGS__) + + +#define DO_554(MACRO, ...) \ +MACRO(554, __VA_ARGS__) \ +DO_553(MACRO, __VA_ARGS__) + + +#define DO_555(MACRO, ...) \ +MACRO(555, __VA_ARGS__) \ +DO_554(MACRO, __VA_ARGS__) + + +#define DO_556(MACRO, ...) \ +MACRO(556, __VA_ARGS__) \ +DO_555(MACRO, __VA_ARGS__) + + +#define DO_557(MACRO, ...) \ +MACRO(557, __VA_ARGS__) \ +DO_556(MACRO, __VA_ARGS__) + + +#define DO_558(MACRO, ...) \ +MACRO(558, __VA_ARGS__) \ +DO_557(MACRO, __VA_ARGS__) + + +#define DO_559(MACRO, ...) \ +MACRO(559, __VA_ARGS__) \ +DO_558(MACRO, __VA_ARGS__) + + +#define DO_560(MACRO, ...) \ +MACRO(560, __VA_ARGS__) \ +DO_559(MACRO, __VA_ARGS__) + + +#define DO_561(MACRO, ...) \ +MACRO(561, __VA_ARGS__) \ +DO_560(MACRO, __VA_ARGS__) + + +#define DO_562(MACRO, ...) \ +MACRO(562, __VA_ARGS__) \ +DO_561(MACRO, __VA_ARGS__) + + +#define DO_563(MACRO, ...) \ +MACRO(563, __VA_ARGS__) \ +DO_562(MACRO, __VA_ARGS__) + + +#define DO_564(MACRO, ...) \ +MACRO(564, __VA_ARGS__) \ +DO_563(MACRO, __VA_ARGS__) + + +#define DO_565(MACRO, ...) \ +MACRO(565, __VA_ARGS__) \ +DO_564(MACRO, __VA_ARGS__) + + +#define DO_566(MACRO, ...) \ +MACRO(566, __VA_ARGS__) \ +DO_565(MACRO, __VA_ARGS__) + + +#define DO_567(MACRO, ...) \ +MACRO(567, __VA_ARGS__) \ +DO_566(MACRO, __VA_ARGS__) + + +#define DO_568(MACRO, ...) \ +MACRO(568, __VA_ARGS__) \ +DO_567(MACRO, __VA_ARGS__) + + +#define DO_569(MACRO, ...) \ +MACRO(569, __VA_ARGS__) \ +DO_568(MACRO, __VA_ARGS__) + + +#define DO_570(MACRO, ...) \ +MACRO(570, __VA_ARGS__) \ +DO_569(MACRO, __VA_ARGS__) + + +#define DO_571(MACRO, ...) \ +MACRO(571, __VA_ARGS__) \ +DO_570(MACRO, __VA_ARGS__) + + +#define DO_572(MACRO, ...) \ +MACRO(572, __VA_ARGS__) \ +DO_571(MACRO, __VA_ARGS__) + + +#define DO_573(MACRO, ...) \ +MACRO(573, __VA_ARGS__) \ +DO_572(MACRO, __VA_ARGS__) + + +#define DO_574(MACRO, ...) \ +MACRO(574, __VA_ARGS__) \ +DO_573(MACRO, __VA_ARGS__) + + +#define DO_575(MACRO, ...) \ +MACRO(575, __VA_ARGS__) \ +DO_574(MACRO, __VA_ARGS__) + + +#define DO_576(MACRO, ...) \ +MACRO(576, __VA_ARGS__) \ +DO_575(MACRO, __VA_ARGS__) + + +#define DO_577(MACRO, ...) \ +MACRO(577, __VA_ARGS__) \ +DO_576(MACRO, __VA_ARGS__) + + +#define DO_578(MACRO, ...) \ +MACRO(578, __VA_ARGS__) \ +DO_577(MACRO, __VA_ARGS__) + + +#define DO_579(MACRO, ...) \ +MACRO(579, __VA_ARGS__) \ +DO_578(MACRO, __VA_ARGS__) + + +#define DO_580(MACRO, ...) \ +MACRO(580, __VA_ARGS__) \ +DO_579(MACRO, __VA_ARGS__) + + +#define DO_581(MACRO, ...) \ +MACRO(581, __VA_ARGS__) \ +DO_580(MACRO, __VA_ARGS__) + + +#define DO_582(MACRO, ...) \ +MACRO(582, __VA_ARGS__) \ +DO_581(MACRO, __VA_ARGS__) + + +#define DO_583(MACRO, ...) \ +MACRO(583, __VA_ARGS__) \ +DO_582(MACRO, __VA_ARGS__) + + +#define DO_584(MACRO, ...) \ +MACRO(584, __VA_ARGS__) \ +DO_583(MACRO, __VA_ARGS__) + + +#define DO_585(MACRO, ...) \ +MACRO(585, __VA_ARGS__) \ +DO_584(MACRO, __VA_ARGS__) + + +#define DO_586(MACRO, ...) \ +MACRO(586, __VA_ARGS__) \ +DO_585(MACRO, __VA_ARGS__) + + +#define DO_587(MACRO, ...) \ +MACRO(587, __VA_ARGS__) \ +DO_586(MACRO, __VA_ARGS__) + + +#define DO_588(MACRO, ...) \ +MACRO(588, __VA_ARGS__) \ +DO_587(MACRO, __VA_ARGS__) + + +#define DO_589(MACRO, ...) \ +MACRO(589, __VA_ARGS__) \ +DO_588(MACRO, __VA_ARGS__) + + +#define DO_590(MACRO, ...) \ +MACRO(590, __VA_ARGS__) \ +DO_589(MACRO, __VA_ARGS__) + + +#define DO_591(MACRO, ...) \ +MACRO(591, __VA_ARGS__) \ +DO_590(MACRO, __VA_ARGS__) + + +#define DO_592(MACRO, ...) \ +MACRO(592, __VA_ARGS__) \ +DO_591(MACRO, __VA_ARGS__) + + +#define DO_593(MACRO, ...) \ +MACRO(593, __VA_ARGS__) \ +DO_592(MACRO, __VA_ARGS__) + + +#define DO_594(MACRO, ...) \ +MACRO(594, __VA_ARGS__) \ +DO_593(MACRO, __VA_ARGS__) + + +#define DO_595(MACRO, ...) \ +MACRO(595, __VA_ARGS__) \ +DO_594(MACRO, __VA_ARGS__) + + +#define DO_596(MACRO, ...) \ +MACRO(596, __VA_ARGS__) \ +DO_595(MACRO, __VA_ARGS__) + + +#define DO_597(MACRO, ...) \ +MACRO(597, __VA_ARGS__) \ +DO_596(MACRO, __VA_ARGS__) + + +#define DO_598(MACRO, ...) \ +MACRO(598, __VA_ARGS__) \ +DO_597(MACRO, __VA_ARGS__) + + +#define DO_599(MACRO, ...) \ +MACRO(599, __VA_ARGS__) \ +DO_598(MACRO, __VA_ARGS__) + + +#define DO_600(MACRO, ...) \ +MACRO(600, __VA_ARGS__) \ +DO_599(MACRO, __VA_ARGS__) + + +#define DO_601(MACRO, ...) \ +MACRO(601, __VA_ARGS__) \ +DO_600(MACRO, __VA_ARGS__) + + +#define DO_602(MACRO, ...) \ +MACRO(602, __VA_ARGS__) \ +DO_601(MACRO, __VA_ARGS__) + + +#define DO_603(MACRO, ...) \ +MACRO(603, __VA_ARGS__) \ +DO_602(MACRO, __VA_ARGS__) + + +#define DO_604(MACRO, ...) \ +MACRO(604, __VA_ARGS__) \ +DO_603(MACRO, __VA_ARGS__) + + +#define DO_605(MACRO, ...) \ +MACRO(605, __VA_ARGS__) \ +DO_604(MACRO, __VA_ARGS__) + + +#define DO_606(MACRO, ...) \ +MACRO(606, __VA_ARGS__) \ +DO_605(MACRO, __VA_ARGS__) + + +#define DO_607(MACRO, ...) \ +MACRO(607, __VA_ARGS__) \ +DO_606(MACRO, __VA_ARGS__) + + +#define DO_608(MACRO, ...) \ +MACRO(608, __VA_ARGS__) \ +DO_607(MACRO, __VA_ARGS__) + + +#define DO_609(MACRO, ...) \ +MACRO(609, __VA_ARGS__) \ +DO_608(MACRO, __VA_ARGS__) + + +#define DO_610(MACRO, ...) \ +MACRO(610, __VA_ARGS__) \ +DO_609(MACRO, __VA_ARGS__) + + +#define DO_611(MACRO, ...) \ +MACRO(611, __VA_ARGS__) \ +DO_610(MACRO, __VA_ARGS__) + + +#define DO_612(MACRO, ...) \ +MACRO(612, __VA_ARGS__) \ +DO_611(MACRO, __VA_ARGS__) + + +#define DO_613(MACRO, ...) \ +MACRO(613, __VA_ARGS__) \ +DO_612(MACRO, __VA_ARGS__) + + +#define DO_614(MACRO, ...) \ +MACRO(614, __VA_ARGS__) \ +DO_613(MACRO, __VA_ARGS__) + + +#define DO_615(MACRO, ...) \ +MACRO(615, __VA_ARGS__) \ +DO_614(MACRO, __VA_ARGS__) + + +#define DO_616(MACRO, ...) \ +MACRO(616, __VA_ARGS__) \ +DO_615(MACRO, __VA_ARGS__) + + +#define DO_617(MACRO, ...) \ +MACRO(617, __VA_ARGS__) \ +DO_616(MACRO, __VA_ARGS__) + + +#define DO_618(MACRO, ...) \ +MACRO(618, __VA_ARGS__) \ +DO_617(MACRO, __VA_ARGS__) + + +#define DO_619(MACRO, ...) \ +MACRO(619, __VA_ARGS__) \ +DO_618(MACRO, __VA_ARGS__) + + +#define DO_620(MACRO, ...) \ +MACRO(620, __VA_ARGS__) \ +DO_619(MACRO, __VA_ARGS__) + + +#define DO_621(MACRO, ...) \ +MACRO(621, __VA_ARGS__) \ +DO_620(MACRO, __VA_ARGS__) + + +#define DO_622(MACRO, ...) \ +MACRO(622, __VA_ARGS__) \ +DO_621(MACRO, __VA_ARGS__) + + +#define DO_623(MACRO, ...) \ +MACRO(623, __VA_ARGS__) \ +DO_622(MACRO, __VA_ARGS__) + + +#define DO_624(MACRO, ...) \ +MACRO(624, __VA_ARGS__) \ +DO_623(MACRO, __VA_ARGS__) + + +#define DO_625(MACRO, ...) \ +MACRO(625, __VA_ARGS__) \ +DO_624(MACRO, __VA_ARGS__) + + +#define DO_626(MACRO, ...) \ +MACRO(626, __VA_ARGS__) \ +DO_625(MACRO, __VA_ARGS__) + + +#define DO_627(MACRO, ...) \ +MACRO(627, __VA_ARGS__) \ +DO_626(MACRO, __VA_ARGS__) + + +#define DO_628(MACRO, ...) \ +MACRO(628, __VA_ARGS__) \ +DO_627(MACRO, __VA_ARGS__) + + +#define DO_629(MACRO, ...) \ +MACRO(629, __VA_ARGS__) \ +DO_628(MACRO, __VA_ARGS__) + + +#define DO_630(MACRO, ...) \ +MACRO(630, __VA_ARGS__) \ +DO_629(MACRO, __VA_ARGS__) + + +#define DO_631(MACRO, ...) \ +MACRO(631, __VA_ARGS__) \ +DO_630(MACRO, __VA_ARGS__) + + +#define DO_632(MACRO, ...) \ +MACRO(632, __VA_ARGS__) \ +DO_631(MACRO, __VA_ARGS__) + + +#define DO_633(MACRO, ...) \ +MACRO(633, __VA_ARGS__) \ +DO_632(MACRO, __VA_ARGS__) + + +#define DO_634(MACRO, ...) \ +MACRO(634, __VA_ARGS__) \ +DO_633(MACRO, __VA_ARGS__) + + +#define DO_635(MACRO, ...) \ +MACRO(635, __VA_ARGS__) \ +DO_634(MACRO, __VA_ARGS__) + + +#define DO_636(MACRO, ...) \ +MACRO(636, __VA_ARGS__) \ +DO_635(MACRO, __VA_ARGS__) + + +#define DO_637(MACRO, ...) \ +MACRO(637, __VA_ARGS__) \ +DO_636(MACRO, __VA_ARGS__) + + +#define DO_638(MACRO, ...) \ +MACRO(638, __VA_ARGS__) \ +DO_637(MACRO, __VA_ARGS__) + + +#define DO_639(MACRO, ...) \ +MACRO(639, __VA_ARGS__) \ +DO_638(MACRO, __VA_ARGS__) + + +#define DO_640(MACRO, ...) \ +MACRO(640, __VA_ARGS__) \ +DO_639(MACRO, __VA_ARGS__) + + +#define DO_641(MACRO, ...) \ +MACRO(641, __VA_ARGS__) \ +DO_640(MACRO, __VA_ARGS__) + + +#define DO_642(MACRO, ...) \ +MACRO(642, __VA_ARGS__) \ +DO_641(MACRO, __VA_ARGS__) + + +#define DO_643(MACRO, ...) \ +MACRO(643, __VA_ARGS__) \ +DO_642(MACRO, __VA_ARGS__) + + +#define DO_644(MACRO, ...) \ +MACRO(644, __VA_ARGS__) \ +DO_643(MACRO, __VA_ARGS__) + + +#define DO_645(MACRO, ...) \ +MACRO(645, __VA_ARGS__) \ +DO_644(MACRO, __VA_ARGS__) + + +#define DO_646(MACRO, ...) \ +MACRO(646, __VA_ARGS__) \ +DO_645(MACRO, __VA_ARGS__) + + +#define DO_647(MACRO, ...) \ +MACRO(647, __VA_ARGS__) \ +DO_646(MACRO, __VA_ARGS__) + + +#define DO_648(MACRO, ...) \ +MACRO(648, __VA_ARGS__) \ +DO_647(MACRO, __VA_ARGS__) + + +#define DO_649(MACRO, ...) \ +MACRO(649, __VA_ARGS__) \ +DO_648(MACRO, __VA_ARGS__) + + +#define DO_650(MACRO, ...) \ +MACRO(650, __VA_ARGS__) \ +DO_649(MACRO, __VA_ARGS__) + + +#define DO_651(MACRO, ...) \ +MACRO(651, __VA_ARGS__) \ +DO_650(MACRO, __VA_ARGS__) + + +#define DO_652(MACRO, ...) \ +MACRO(652, __VA_ARGS__) \ +DO_651(MACRO, __VA_ARGS__) + + +#define DO_653(MACRO, ...) \ +MACRO(653, __VA_ARGS__) \ +DO_652(MACRO, __VA_ARGS__) + + +#define DO_654(MACRO, ...) \ +MACRO(654, __VA_ARGS__) \ +DO_653(MACRO, __VA_ARGS__) + + +#define DO_655(MACRO, ...) \ +MACRO(655, __VA_ARGS__) \ +DO_654(MACRO, __VA_ARGS__) + + +#define DO_656(MACRO, ...) \ +MACRO(656, __VA_ARGS__) \ +DO_655(MACRO, __VA_ARGS__) + + +#define DO_657(MACRO, ...) \ +MACRO(657, __VA_ARGS__) \ +DO_656(MACRO, __VA_ARGS__) + + +#define DO_658(MACRO, ...) \ +MACRO(658, __VA_ARGS__) \ +DO_657(MACRO, __VA_ARGS__) + + +#define DO_659(MACRO, ...) \ +MACRO(659, __VA_ARGS__) \ +DO_658(MACRO, __VA_ARGS__) + + +#define DO_660(MACRO, ...) \ +MACRO(660, __VA_ARGS__) \ +DO_659(MACRO, __VA_ARGS__) + + +#define DO_661(MACRO, ...) \ +MACRO(661, __VA_ARGS__) \ +DO_660(MACRO, __VA_ARGS__) + + +#define DO_662(MACRO, ...) \ +MACRO(662, __VA_ARGS__) \ +DO_661(MACRO, __VA_ARGS__) + + +#define DO_663(MACRO, ...) \ +MACRO(663, __VA_ARGS__) \ +DO_662(MACRO, __VA_ARGS__) + + +#define DO_664(MACRO, ...) \ +MACRO(664, __VA_ARGS__) \ +DO_663(MACRO, __VA_ARGS__) + + +#define DO_665(MACRO, ...) \ +MACRO(665, __VA_ARGS__) \ +DO_664(MACRO, __VA_ARGS__) + + +#define DO_666(MACRO, ...) \ +MACRO(666, __VA_ARGS__) \ +DO_665(MACRO, __VA_ARGS__) + + +#define DO_667(MACRO, ...) \ +MACRO(667, __VA_ARGS__) \ +DO_666(MACRO, __VA_ARGS__) + + +#define DO_668(MACRO, ...) \ +MACRO(668, __VA_ARGS__) \ +DO_667(MACRO, __VA_ARGS__) + + +#define DO_669(MACRO, ...) \ +MACRO(669, __VA_ARGS__) \ +DO_668(MACRO, __VA_ARGS__) + + +#define DO_670(MACRO, ...) \ +MACRO(670, __VA_ARGS__) \ +DO_669(MACRO, __VA_ARGS__) + + +#define DO_671(MACRO, ...) \ +MACRO(671, __VA_ARGS__) \ +DO_670(MACRO, __VA_ARGS__) + + +#define DO_672(MACRO, ...) \ +MACRO(672, __VA_ARGS__) \ +DO_671(MACRO, __VA_ARGS__) + + +#define DO_673(MACRO, ...) \ +MACRO(673, __VA_ARGS__) \ +DO_672(MACRO, __VA_ARGS__) + + +#define DO_674(MACRO, ...) \ +MACRO(674, __VA_ARGS__) \ +DO_673(MACRO, __VA_ARGS__) + + +#define DO_675(MACRO, ...) \ +MACRO(675, __VA_ARGS__) \ +DO_674(MACRO, __VA_ARGS__) + + +#define DO_676(MACRO, ...) \ +MACRO(676, __VA_ARGS__) \ +DO_675(MACRO, __VA_ARGS__) + + +#define DO_677(MACRO, ...) \ +MACRO(677, __VA_ARGS__) \ +DO_676(MACRO, __VA_ARGS__) + + +#define DO_678(MACRO, ...) \ +MACRO(678, __VA_ARGS__) \ +DO_677(MACRO, __VA_ARGS__) + + +#define DO_679(MACRO, ...) \ +MACRO(679, __VA_ARGS__) \ +DO_678(MACRO, __VA_ARGS__) + + +#define DO_680(MACRO, ...) \ +MACRO(680, __VA_ARGS__) \ +DO_679(MACRO, __VA_ARGS__) + + +#define DO_681(MACRO, ...) \ +MACRO(681, __VA_ARGS__) \ +DO_680(MACRO, __VA_ARGS__) + + +#define DO_682(MACRO, ...) \ +MACRO(682, __VA_ARGS__) \ +DO_681(MACRO, __VA_ARGS__) + + +#define DO_683(MACRO, ...) \ +MACRO(683, __VA_ARGS__) \ +DO_682(MACRO, __VA_ARGS__) + + +#define DO_684(MACRO, ...) \ +MACRO(684, __VA_ARGS__) \ +DO_683(MACRO, __VA_ARGS__) + + +#define DO_685(MACRO, ...) \ +MACRO(685, __VA_ARGS__) \ +DO_684(MACRO, __VA_ARGS__) + + +#define DO_686(MACRO, ...) \ +MACRO(686, __VA_ARGS__) \ +DO_685(MACRO, __VA_ARGS__) + + +#define DO_687(MACRO, ...) \ +MACRO(687, __VA_ARGS__) \ +DO_686(MACRO, __VA_ARGS__) + + +#define DO_688(MACRO, ...) \ +MACRO(688, __VA_ARGS__) \ +DO_687(MACRO, __VA_ARGS__) + + +#define DO_689(MACRO, ...) \ +MACRO(689, __VA_ARGS__) \ +DO_688(MACRO, __VA_ARGS__) + + +#define DO_690(MACRO, ...) \ +MACRO(690, __VA_ARGS__) \ +DO_689(MACRO, __VA_ARGS__) + + +#define DO_691(MACRO, ...) \ +MACRO(691, __VA_ARGS__) \ +DO_690(MACRO, __VA_ARGS__) + + +#define DO_692(MACRO, ...) \ +MACRO(692, __VA_ARGS__) \ +DO_691(MACRO, __VA_ARGS__) + + +#define DO_693(MACRO, ...) \ +MACRO(693, __VA_ARGS__) \ +DO_692(MACRO, __VA_ARGS__) + + +#define DO_694(MACRO, ...) \ +MACRO(694, __VA_ARGS__) \ +DO_693(MACRO, __VA_ARGS__) + + +#define DO_695(MACRO, ...) \ +MACRO(695, __VA_ARGS__) \ +DO_694(MACRO, __VA_ARGS__) + + +#define DO_696(MACRO, ...) \ +MACRO(696, __VA_ARGS__) \ +DO_695(MACRO, __VA_ARGS__) + + +#define DO_697(MACRO, ...) \ +MACRO(697, __VA_ARGS__) \ +DO_696(MACRO, __VA_ARGS__) + + +#define DO_698(MACRO, ...) \ +MACRO(698, __VA_ARGS__) \ +DO_697(MACRO, __VA_ARGS__) + + +#define DO_699(MACRO, ...) \ +MACRO(699, __VA_ARGS__) \ +DO_698(MACRO, __VA_ARGS__) + + +#define DO_700(MACRO, ...) \ +MACRO(700, __VA_ARGS__) \ +DO_699(MACRO, __VA_ARGS__) + + +#define DO_701(MACRO, ...) \ +MACRO(701, __VA_ARGS__) \ +DO_700(MACRO, __VA_ARGS__) + + +#define DO_702(MACRO, ...) \ +MACRO(702, __VA_ARGS__) \ +DO_701(MACRO, __VA_ARGS__) + + +#define DO_703(MACRO, ...) \ +MACRO(703, __VA_ARGS__) \ +DO_702(MACRO, __VA_ARGS__) + + +#define DO_704(MACRO, ...) \ +MACRO(704, __VA_ARGS__) \ +DO_703(MACRO, __VA_ARGS__) + + +#define DO_705(MACRO, ...) \ +MACRO(705, __VA_ARGS__) \ +DO_704(MACRO, __VA_ARGS__) + + +#define DO_706(MACRO, ...) \ +MACRO(706, __VA_ARGS__) \ +DO_705(MACRO, __VA_ARGS__) + + +#define DO_707(MACRO, ...) \ +MACRO(707, __VA_ARGS__) \ +DO_706(MACRO, __VA_ARGS__) + + +#define DO_708(MACRO, ...) \ +MACRO(708, __VA_ARGS__) \ +DO_707(MACRO, __VA_ARGS__) + + +#define DO_709(MACRO, ...) \ +MACRO(709, __VA_ARGS__) \ +DO_708(MACRO, __VA_ARGS__) + + +#define DO_710(MACRO, ...) \ +MACRO(710, __VA_ARGS__) \ +DO_709(MACRO, __VA_ARGS__) + + +#define DO_711(MACRO, ...) \ +MACRO(711, __VA_ARGS__) \ +DO_710(MACRO, __VA_ARGS__) + + +#define DO_712(MACRO, ...) \ +MACRO(712, __VA_ARGS__) \ +DO_711(MACRO, __VA_ARGS__) + + +#define DO_713(MACRO, ...) \ +MACRO(713, __VA_ARGS__) \ +DO_712(MACRO, __VA_ARGS__) + + +#define DO_714(MACRO, ...) \ +MACRO(714, __VA_ARGS__) \ +DO_713(MACRO, __VA_ARGS__) + + +#define DO_715(MACRO, ...) \ +MACRO(715, __VA_ARGS__) \ +DO_714(MACRO, __VA_ARGS__) + + +#define DO_716(MACRO, ...) \ +MACRO(716, __VA_ARGS__) \ +DO_715(MACRO, __VA_ARGS__) + + +#define DO_717(MACRO, ...) \ +MACRO(717, __VA_ARGS__) \ +DO_716(MACRO, __VA_ARGS__) + + +#define DO_718(MACRO, ...) \ +MACRO(718, __VA_ARGS__) \ +DO_717(MACRO, __VA_ARGS__) + + +#define DO_719(MACRO, ...) \ +MACRO(719, __VA_ARGS__) \ +DO_718(MACRO, __VA_ARGS__) + + +#define DO_720(MACRO, ...) \ +MACRO(720, __VA_ARGS__) \ +DO_719(MACRO, __VA_ARGS__) + + +#define DO_721(MACRO, ...) \ +MACRO(721, __VA_ARGS__) \ +DO_720(MACRO, __VA_ARGS__) + + +#define DO_722(MACRO, ...) \ +MACRO(722, __VA_ARGS__) \ +DO_721(MACRO, __VA_ARGS__) + + +#define DO_723(MACRO, ...) \ +MACRO(723, __VA_ARGS__) \ +DO_722(MACRO, __VA_ARGS__) + + +#define DO_724(MACRO, ...) \ +MACRO(724, __VA_ARGS__) \ +DO_723(MACRO, __VA_ARGS__) + + +#define DO_725(MACRO, ...) \ +MACRO(725, __VA_ARGS__) \ +DO_724(MACRO, __VA_ARGS__) + + +#define DO_726(MACRO, ...) \ +MACRO(726, __VA_ARGS__) \ +DO_725(MACRO, __VA_ARGS__) + + +#define DO_727(MACRO, ...) \ +MACRO(727, __VA_ARGS__) \ +DO_726(MACRO, __VA_ARGS__) + + +#define DO_728(MACRO, ...) \ +MACRO(728, __VA_ARGS__) \ +DO_727(MACRO, __VA_ARGS__) + + +#define DO_729(MACRO, ...) \ +MACRO(729, __VA_ARGS__) \ +DO_728(MACRO, __VA_ARGS__) + + +#define DO_730(MACRO, ...) \ +MACRO(730, __VA_ARGS__) \ +DO_729(MACRO, __VA_ARGS__) + + +#define DO_731(MACRO, ...) \ +MACRO(731, __VA_ARGS__) \ +DO_730(MACRO, __VA_ARGS__) + + +#define DO_732(MACRO, ...) \ +MACRO(732, __VA_ARGS__) \ +DO_731(MACRO, __VA_ARGS__) + + +#define DO_733(MACRO, ...) \ +MACRO(733, __VA_ARGS__) \ +DO_732(MACRO, __VA_ARGS__) + + +#define DO_734(MACRO, ...) \ +MACRO(734, __VA_ARGS__) \ +DO_733(MACRO, __VA_ARGS__) + + +#define DO_735(MACRO, ...) \ +MACRO(735, __VA_ARGS__) \ +DO_734(MACRO, __VA_ARGS__) + + +#define DO_736(MACRO, ...) \ +MACRO(736, __VA_ARGS__) \ +DO_735(MACRO, __VA_ARGS__) + + +#define DO_737(MACRO, ...) \ +MACRO(737, __VA_ARGS__) \ +DO_736(MACRO, __VA_ARGS__) + + +#define DO_738(MACRO, ...) \ +MACRO(738, __VA_ARGS__) \ +DO_737(MACRO, __VA_ARGS__) + + +#define DO_739(MACRO, ...) \ +MACRO(739, __VA_ARGS__) \ +DO_738(MACRO, __VA_ARGS__) + + +#define DO_740(MACRO, ...) \ +MACRO(740, __VA_ARGS__) \ +DO_739(MACRO, __VA_ARGS__) + + +#define DO_741(MACRO, ...) \ +MACRO(741, __VA_ARGS__) \ +DO_740(MACRO, __VA_ARGS__) + + +#define DO_742(MACRO, ...) \ +MACRO(742, __VA_ARGS__) \ +DO_741(MACRO, __VA_ARGS__) + + +#define DO_743(MACRO, ...) \ +MACRO(743, __VA_ARGS__) \ +DO_742(MACRO, __VA_ARGS__) + + +#define DO_744(MACRO, ...) \ +MACRO(744, __VA_ARGS__) \ +DO_743(MACRO, __VA_ARGS__) + + +#define DO_745(MACRO, ...) \ +MACRO(745, __VA_ARGS__) \ +DO_744(MACRO, __VA_ARGS__) + + +#define DO_746(MACRO, ...) \ +MACRO(746, __VA_ARGS__) \ +DO_745(MACRO, __VA_ARGS__) + + +#define DO_747(MACRO, ...) \ +MACRO(747, __VA_ARGS__) \ +DO_746(MACRO, __VA_ARGS__) + + +#define DO_748(MACRO, ...) \ +MACRO(748, __VA_ARGS__) \ +DO_747(MACRO, __VA_ARGS__) + + +#define DO_749(MACRO, ...) \ +MACRO(749, __VA_ARGS__) \ +DO_748(MACRO, __VA_ARGS__) + + +#define DO_750(MACRO, ...) \ +MACRO(750, __VA_ARGS__) \ +DO_749(MACRO, __VA_ARGS__) + + +#define DO_751(MACRO, ...) \ +MACRO(751, __VA_ARGS__) \ +DO_750(MACRO, __VA_ARGS__) + + +#define DO_752(MACRO, ...) \ +MACRO(752, __VA_ARGS__) \ +DO_751(MACRO, __VA_ARGS__) + + +#define DO_753(MACRO, ...) \ +MACRO(753, __VA_ARGS__) \ +DO_752(MACRO, __VA_ARGS__) + + +#define DO_754(MACRO, ...) \ +MACRO(754, __VA_ARGS__) \ +DO_753(MACRO, __VA_ARGS__) + + +#define DO_755(MACRO, ...) \ +MACRO(755, __VA_ARGS__) \ +DO_754(MACRO, __VA_ARGS__) + + +#define DO_756(MACRO, ...) \ +MACRO(756, __VA_ARGS__) \ +DO_755(MACRO, __VA_ARGS__) + + +#define DO_757(MACRO, ...) \ +MACRO(757, __VA_ARGS__) \ +DO_756(MACRO, __VA_ARGS__) + + +#define DO_758(MACRO, ...) \ +MACRO(758, __VA_ARGS__) \ +DO_757(MACRO, __VA_ARGS__) + + +#define DO_759(MACRO, ...) \ +MACRO(759, __VA_ARGS__) \ +DO_758(MACRO, __VA_ARGS__) + + +#define DO_760(MACRO, ...) \ +MACRO(760, __VA_ARGS__) \ +DO_759(MACRO, __VA_ARGS__) + + +#define DO_761(MACRO, ...) \ +MACRO(761, __VA_ARGS__) \ +DO_760(MACRO, __VA_ARGS__) + + +#define DO_762(MACRO, ...) \ +MACRO(762, __VA_ARGS__) \ +DO_761(MACRO, __VA_ARGS__) + + +#define DO_763(MACRO, ...) \ +MACRO(763, __VA_ARGS__) \ +DO_762(MACRO, __VA_ARGS__) + + +#define DO_764(MACRO, ...) \ +MACRO(764, __VA_ARGS__) \ +DO_763(MACRO, __VA_ARGS__) + + +#define DO_765(MACRO, ...) \ +MACRO(765, __VA_ARGS__) \ +DO_764(MACRO, __VA_ARGS__) + + +#define DO_766(MACRO, ...) \ +MACRO(766, __VA_ARGS__) \ +DO_765(MACRO, __VA_ARGS__) + + +#define DO_767(MACRO, ...) \ +MACRO(767, __VA_ARGS__) \ +DO_766(MACRO, __VA_ARGS__) + + +#define DO_768(MACRO, ...) \ +MACRO(768, __VA_ARGS__) \ +DO_767(MACRO, __VA_ARGS__) + + +#define DO_769(MACRO, ...) \ +MACRO(769, __VA_ARGS__) \ +DO_768(MACRO, __VA_ARGS__) + + +#define DO_770(MACRO, ...) \ +MACRO(770, __VA_ARGS__) \ +DO_769(MACRO, __VA_ARGS__) + + +#define DO_771(MACRO, ...) \ +MACRO(771, __VA_ARGS__) \ +DO_770(MACRO, __VA_ARGS__) + + +#define DO_772(MACRO, ...) \ +MACRO(772, __VA_ARGS__) \ +DO_771(MACRO, __VA_ARGS__) + + +#define DO_773(MACRO, ...) \ +MACRO(773, __VA_ARGS__) \ +DO_772(MACRO, __VA_ARGS__) + + +#define DO_774(MACRO, ...) \ +MACRO(774, __VA_ARGS__) \ +DO_773(MACRO, __VA_ARGS__) + + +#define DO_775(MACRO, ...) \ +MACRO(775, __VA_ARGS__) \ +DO_774(MACRO, __VA_ARGS__) + + +#define DO_776(MACRO, ...) \ +MACRO(776, __VA_ARGS__) \ +DO_775(MACRO, __VA_ARGS__) + + +#define DO_777(MACRO, ...) \ +MACRO(777, __VA_ARGS__) \ +DO_776(MACRO, __VA_ARGS__) + + +#define DO_778(MACRO, ...) \ +MACRO(778, __VA_ARGS__) \ +DO_777(MACRO, __VA_ARGS__) + + +#define DO_779(MACRO, ...) \ +MACRO(779, __VA_ARGS__) \ +DO_778(MACRO, __VA_ARGS__) + + +#define DO_780(MACRO, ...) \ +MACRO(780, __VA_ARGS__) \ +DO_779(MACRO, __VA_ARGS__) + + +#define DO_781(MACRO, ...) \ +MACRO(781, __VA_ARGS__) \ +DO_780(MACRO, __VA_ARGS__) + + +#define DO_782(MACRO, ...) \ +MACRO(782, __VA_ARGS__) \ +DO_781(MACRO, __VA_ARGS__) + + +#define DO_783(MACRO, ...) \ +MACRO(783, __VA_ARGS__) \ +DO_782(MACRO, __VA_ARGS__) + + +#define DO_784(MACRO, ...) \ +MACRO(784, __VA_ARGS__) \ +DO_783(MACRO, __VA_ARGS__) + + +#define DO_785(MACRO, ...) \ +MACRO(785, __VA_ARGS__) \ +DO_784(MACRO, __VA_ARGS__) + + +#define DO_786(MACRO, ...) \ +MACRO(786, __VA_ARGS__) \ +DO_785(MACRO, __VA_ARGS__) + + +#define DO_787(MACRO, ...) \ +MACRO(787, __VA_ARGS__) \ +DO_786(MACRO, __VA_ARGS__) + + +#define DO_788(MACRO, ...) \ +MACRO(788, __VA_ARGS__) \ +DO_787(MACRO, __VA_ARGS__) + + +#define DO_789(MACRO, ...) \ +MACRO(789, __VA_ARGS__) \ +DO_788(MACRO, __VA_ARGS__) + + +#define DO_790(MACRO, ...) \ +MACRO(790, __VA_ARGS__) \ +DO_789(MACRO, __VA_ARGS__) + + +#define DO_791(MACRO, ...) \ +MACRO(791, __VA_ARGS__) \ +DO_790(MACRO, __VA_ARGS__) + + +#define DO_792(MACRO, ...) \ +MACRO(792, __VA_ARGS__) \ +DO_791(MACRO, __VA_ARGS__) + + +#define DO_793(MACRO, ...) \ +MACRO(793, __VA_ARGS__) \ +DO_792(MACRO, __VA_ARGS__) + + +#define DO_794(MACRO, ...) \ +MACRO(794, __VA_ARGS__) \ +DO_793(MACRO, __VA_ARGS__) + + +#define DO_795(MACRO, ...) \ +MACRO(795, __VA_ARGS__) \ +DO_794(MACRO, __VA_ARGS__) + + +#define DO_796(MACRO, ...) \ +MACRO(796, __VA_ARGS__) \ +DO_795(MACRO, __VA_ARGS__) + + +#define DO_797(MACRO, ...) \ +MACRO(797, __VA_ARGS__) \ +DO_796(MACRO, __VA_ARGS__) + + +#define DO_798(MACRO, ...) \ +MACRO(798, __VA_ARGS__) \ +DO_797(MACRO, __VA_ARGS__) + + +#define DO_799(MACRO, ...) \ +MACRO(799, __VA_ARGS__) \ +DO_798(MACRO, __VA_ARGS__) + + +#define DO_800(MACRO, ...) \ +MACRO(800, __VA_ARGS__) \ +DO_799(MACRO, __VA_ARGS__) + + +#define DO_801(MACRO, ...) \ +MACRO(801, __VA_ARGS__) \ +DO_800(MACRO, __VA_ARGS__) + + +#define DO_802(MACRO, ...) \ +MACRO(802, __VA_ARGS__) \ +DO_801(MACRO, __VA_ARGS__) + + +#define DO_803(MACRO, ...) \ +MACRO(803, __VA_ARGS__) \ +DO_802(MACRO, __VA_ARGS__) + + +#define DO_804(MACRO, ...) \ +MACRO(804, __VA_ARGS__) \ +DO_803(MACRO, __VA_ARGS__) + + +#define DO_805(MACRO, ...) \ +MACRO(805, __VA_ARGS__) \ +DO_804(MACRO, __VA_ARGS__) + + +#define DO_806(MACRO, ...) \ +MACRO(806, __VA_ARGS__) \ +DO_805(MACRO, __VA_ARGS__) + + +#define DO_807(MACRO, ...) \ +MACRO(807, __VA_ARGS__) \ +DO_806(MACRO, __VA_ARGS__) + + +#define DO_808(MACRO, ...) \ +MACRO(808, __VA_ARGS__) \ +DO_807(MACRO, __VA_ARGS__) + + +#define DO_809(MACRO, ...) \ +MACRO(809, __VA_ARGS__) \ +DO_808(MACRO, __VA_ARGS__) + + +#define DO_810(MACRO, ...) \ +MACRO(810, __VA_ARGS__) \ +DO_809(MACRO, __VA_ARGS__) + + +#define DO_811(MACRO, ...) \ +MACRO(811, __VA_ARGS__) \ +DO_810(MACRO, __VA_ARGS__) + + +#define DO_812(MACRO, ...) \ +MACRO(812, __VA_ARGS__) \ +DO_811(MACRO, __VA_ARGS__) + + +#define DO_813(MACRO, ...) \ +MACRO(813, __VA_ARGS__) \ +DO_812(MACRO, __VA_ARGS__) + + +#define DO_814(MACRO, ...) \ +MACRO(814, __VA_ARGS__) \ +DO_813(MACRO, __VA_ARGS__) + + +#define DO_815(MACRO, ...) \ +MACRO(815, __VA_ARGS__) \ +DO_814(MACRO, __VA_ARGS__) + + +#define DO_816(MACRO, ...) \ +MACRO(816, __VA_ARGS__) \ +DO_815(MACRO, __VA_ARGS__) + + +#define DO_817(MACRO, ...) \ +MACRO(817, __VA_ARGS__) \ +DO_816(MACRO, __VA_ARGS__) + + +#define DO_818(MACRO, ...) \ +MACRO(818, __VA_ARGS__) \ +DO_817(MACRO, __VA_ARGS__) + + +#define DO_819(MACRO, ...) \ +MACRO(819, __VA_ARGS__) \ +DO_818(MACRO, __VA_ARGS__) + + +#define DO_820(MACRO, ...) \ +MACRO(820, __VA_ARGS__) \ +DO_819(MACRO, __VA_ARGS__) + + +#define DO_821(MACRO, ...) \ +MACRO(821, __VA_ARGS__) \ +DO_820(MACRO, __VA_ARGS__) + + +#define DO_822(MACRO, ...) \ +MACRO(822, __VA_ARGS__) \ +DO_821(MACRO, __VA_ARGS__) + + +#define DO_823(MACRO, ...) \ +MACRO(823, __VA_ARGS__) \ +DO_822(MACRO, __VA_ARGS__) + + +#define DO_824(MACRO, ...) \ +MACRO(824, __VA_ARGS__) \ +DO_823(MACRO, __VA_ARGS__) + + +#define DO_825(MACRO, ...) \ +MACRO(825, __VA_ARGS__) \ +DO_824(MACRO, __VA_ARGS__) + + +#define DO_826(MACRO, ...) \ +MACRO(826, __VA_ARGS__) \ +DO_825(MACRO, __VA_ARGS__) + + +#define DO_827(MACRO, ...) \ +MACRO(827, __VA_ARGS__) \ +DO_826(MACRO, __VA_ARGS__) + + +#define DO_828(MACRO, ...) \ +MACRO(828, __VA_ARGS__) \ +DO_827(MACRO, __VA_ARGS__) + + +#define DO_829(MACRO, ...) \ +MACRO(829, __VA_ARGS__) \ +DO_828(MACRO, __VA_ARGS__) + + +#define DO_830(MACRO, ...) \ +MACRO(830, __VA_ARGS__) \ +DO_829(MACRO, __VA_ARGS__) + + +#define DO_831(MACRO, ...) \ +MACRO(831, __VA_ARGS__) \ +DO_830(MACRO, __VA_ARGS__) + + +#define DO_832(MACRO, ...) \ +MACRO(832, __VA_ARGS__) \ +DO_831(MACRO, __VA_ARGS__) + + +#define DO_833(MACRO, ...) \ +MACRO(833, __VA_ARGS__) \ +DO_832(MACRO, __VA_ARGS__) + + +#define DO_834(MACRO, ...) \ +MACRO(834, __VA_ARGS__) \ +DO_833(MACRO, __VA_ARGS__) + + +#define DO_835(MACRO, ...) \ +MACRO(835, __VA_ARGS__) \ +DO_834(MACRO, __VA_ARGS__) + + +#define DO_836(MACRO, ...) \ +MACRO(836, __VA_ARGS__) \ +DO_835(MACRO, __VA_ARGS__) + + +#define DO_837(MACRO, ...) \ +MACRO(837, __VA_ARGS__) \ +DO_836(MACRO, __VA_ARGS__) + + +#define DO_838(MACRO, ...) \ +MACRO(838, __VA_ARGS__) \ +DO_837(MACRO, __VA_ARGS__) + + +#define DO_839(MACRO, ...) \ +MACRO(839, __VA_ARGS__) \ +DO_838(MACRO, __VA_ARGS__) + + +#define DO_840(MACRO, ...) \ +MACRO(840, __VA_ARGS__) \ +DO_839(MACRO, __VA_ARGS__) + + +#define DO_841(MACRO, ...) \ +MACRO(841, __VA_ARGS__) \ +DO_840(MACRO, __VA_ARGS__) + + +#define DO_842(MACRO, ...) \ +MACRO(842, __VA_ARGS__) \ +DO_841(MACRO, __VA_ARGS__) + + +#define DO_843(MACRO, ...) \ +MACRO(843, __VA_ARGS__) \ +DO_842(MACRO, __VA_ARGS__) + + +#define DO_844(MACRO, ...) \ +MACRO(844, __VA_ARGS__) \ +DO_843(MACRO, __VA_ARGS__) + + +#define DO_845(MACRO, ...) \ +MACRO(845, __VA_ARGS__) \ +DO_844(MACRO, __VA_ARGS__) + + +#define DO_846(MACRO, ...) \ +MACRO(846, __VA_ARGS__) \ +DO_845(MACRO, __VA_ARGS__) + + +#define DO_847(MACRO, ...) \ +MACRO(847, __VA_ARGS__) \ +DO_846(MACRO, __VA_ARGS__) + + +#define DO_848(MACRO, ...) \ +MACRO(848, __VA_ARGS__) \ +DO_847(MACRO, __VA_ARGS__) + + +#define DO_849(MACRO, ...) \ +MACRO(849, __VA_ARGS__) \ +DO_848(MACRO, __VA_ARGS__) + + +#define DO_850(MACRO, ...) \ +MACRO(850, __VA_ARGS__) \ +DO_849(MACRO, __VA_ARGS__) + + +#define DO_851(MACRO, ...) \ +MACRO(851, __VA_ARGS__) \ +DO_850(MACRO, __VA_ARGS__) + + +#define DO_852(MACRO, ...) \ +MACRO(852, __VA_ARGS__) \ +DO_851(MACRO, __VA_ARGS__) + + +#define DO_853(MACRO, ...) \ +MACRO(853, __VA_ARGS__) \ +DO_852(MACRO, __VA_ARGS__) + + +#define DO_854(MACRO, ...) \ +MACRO(854, __VA_ARGS__) \ +DO_853(MACRO, __VA_ARGS__) + + +#define DO_855(MACRO, ...) \ +MACRO(855, __VA_ARGS__) \ +DO_854(MACRO, __VA_ARGS__) + + +#define DO_856(MACRO, ...) \ +MACRO(856, __VA_ARGS__) \ +DO_855(MACRO, __VA_ARGS__) + + +#define DO_857(MACRO, ...) \ +MACRO(857, __VA_ARGS__) \ +DO_856(MACRO, __VA_ARGS__) + + +#define DO_858(MACRO, ...) \ +MACRO(858, __VA_ARGS__) \ +DO_857(MACRO, __VA_ARGS__) + + +#define DO_859(MACRO, ...) \ +MACRO(859, __VA_ARGS__) \ +DO_858(MACRO, __VA_ARGS__) + + +#define DO_860(MACRO, ...) \ +MACRO(860, __VA_ARGS__) \ +DO_859(MACRO, __VA_ARGS__) + + +#define DO_861(MACRO, ...) \ +MACRO(861, __VA_ARGS__) \ +DO_860(MACRO, __VA_ARGS__) + + +#define DO_862(MACRO, ...) \ +MACRO(862, __VA_ARGS__) \ +DO_861(MACRO, __VA_ARGS__) + + +#define DO_863(MACRO, ...) \ +MACRO(863, __VA_ARGS__) \ +DO_862(MACRO, __VA_ARGS__) + + +#define DO_864(MACRO, ...) \ +MACRO(864, __VA_ARGS__) \ +DO_863(MACRO, __VA_ARGS__) + + +#define DO_865(MACRO, ...) \ +MACRO(865, __VA_ARGS__) \ +DO_864(MACRO, __VA_ARGS__) + + +#define DO_866(MACRO, ...) \ +MACRO(866, __VA_ARGS__) \ +DO_865(MACRO, __VA_ARGS__) + + +#define DO_867(MACRO, ...) \ +MACRO(867, __VA_ARGS__) \ +DO_866(MACRO, __VA_ARGS__) + + +#define DO_868(MACRO, ...) \ +MACRO(868, __VA_ARGS__) \ +DO_867(MACRO, __VA_ARGS__) + + +#define DO_869(MACRO, ...) \ +MACRO(869, __VA_ARGS__) \ +DO_868(MACRO, __VA_ARGS__) + + +#define DO_870(MACRO, ...) \ +MACRO(870, __VA_ARGS__) \ +DO_869(MACRO, __VA_ARGS__) + + +#define DO_871(MACRO, ...) \ +MACRO(871, __VA_ARGS__) \ +DO_870(MACRO, __VA_ARGS__) + + +#define DO_872(MACRO, ...) \ +MACRO(872, __VA_ARGS__) \ +DO_871(MACRO, __VA_ARGS__) + + +#define DO_873(MACRO, ...) \ +MACRO(873, __VA_ARGS__) \ +DO_872(MACRO, __VA_ARGS__) + + +#define DO_874(MACRO, ...) \ +MACRO(874, __VA_ARGS__) \ +DO_873(MACRO, __VA_ARGS__) + + +#define DO_875(MACRO, ...) \ +MACRO(875, __VA_ARGS__) \ +DO_874(MACRO, __VA_ARGS__) + + +#define DO_876(MACRO, ...) \ +MACRO(876, __VA_ARGS__) \ +DO_875(MACRO, __VA_ARGS__) + + +#define DO_877(MACRO, ...) \ +MACRO(877, __VA_ARGS__) \ +DO_876(MACRO, __VA_ARGS__) + + +#define DO_878(MACRO, ...) \ +MACRO(878, __VA_ARGS__) \ +DO_877(MACRO, __VA_ARGS__) + + +#define DO_879(MACRO, ...) \ +MACRO(879, __VA_ARGS__) \ +DO_878(MACRO, __VA_ARGS__) + + +#define DO_880(MACRO, ...) \ +MACRO(880, __VA_ARGS__) \ +DO_879(MACRO, __VA_ARGS__) + + +#define DO_881(MACRO, ...) \ +MACRO(881, __VA_ARGS__) \ +DO_880(MACRO, __VA_ARGS__) + + +#define DO_882(MACRO, ...) \ +MACRO(882, __VA_ARGS__) \ +DO_881(MACRO, __VA_ARGS__) + + +#define DO_883(MACRO, ...) \ +MACRO(883, __VA_ARGS__) \ +DO_882(MACRO, __VA_ARGS__) + + +#define DO_884(MACRO, ...) \ +MACRO(884, __VA_ARGS__) \ +DO_883(MACRO, __VA_ARGS__) + + +#define DO_885(MACRO, ...) \ +MACRO(885, __VA_ARGS__) \ +DO_884(MACRO, __VA_ARGS__) + + +#define DO_886(MACRO, ...) \ +MACRO(886, __VA_ARGS__) \ +DO_885(MACRO, __VA_ARGS__) + + +#define DO_887(MACRO, ...) \ +MACRO(887, __VA_ARGS__) \ +DO_886(MACRO, __VA_ARGS__) + + +#define DO_888(MACRO, ...) \ +MACRO(888, __VA_ARGS__) \ +DO_887(MACRO, __VA_ARGS__) + + +#define DO_889(MACRO, ...) \ +MACRO(889, __VA_ARGS__) \ +DO_888(MACRO, __VA_ARGS__) + + +#define DO_890(MACRO, ...) \ +MACRO(890, __VA_ARGS__) \ +DO_889(MACRO, __VA_ARGS__) + + +#define DO_891(MACRO, ...) \ +MACRO(891, __VA_ARGS__) \ +DO_890(MACRO, __VA_ARGS__) + + +#define DO_892(MACRO, ...) \ +MACRO(892, __VA_ARGS__) \ +DO_891(MACRO, __VA_ARGS__) + + +#define DO_893(MACRO, ...) \ +MACRO(893, __VA_ARGS__) \ +DO_892(MACRO, __VA_ARGS__) + + +#define DO_894(MACRO, ...) \ +MACRO(894, __VA_ARGS__) \ +DO_893(MACRO, __VA_ARGS__) + + +#define DO_895(MACRO, ...) \ +MACRO(895, __VA_ARGS__) \ +DO_894(MACRO, __VA_ARGS__) + + +#define DO_896(MACRO, ...) \ +MACRO(896, __VA_ARGS__) \ +DO_895(MACRO, __VA_ARGS__) + + +#define DO_897(MACRO, ...) \ +MACRO(897, __VA_ARGS__) \ +DO_896(MACRO, __VA_ARGS__) + + +#define DO_898(MACRO, ...) \ +MACRO(898, __VA_ARGS__) \ +DO_897(MACRO, __VA_ARGS__) + + +#define DO_899(MACRO, ...) \ +MACRO(899, __VA_ARGS__) \ +DO_898(MACRO, __VA_ARGS__) + + +#define DO_900(MACRO, ...) \ +MACRO(900, __VA_ARGS__) \ +DO_899(MACRO, __VA_ARGS__) + + +#define DO_901(MACRO, ...) \ +MACRO(901, __VA_ARGS__) \ +DO_900(MACRO, __VA_ARGS__) + + +#define DO_902(MACRO, ...) \ +MACRO(902, __VA_ARGS__) \ +DO_901(MACRO, __VA_ARGS__) + + +#define DO_903(MACRO, ...) \ +MACRO(903, __VA_ARGS__) \ +DO_902(MACRO, __VA_ARGS__) + + +#define DO_904(MACRO, ...) \ +MACRO(904, __VA_ARGS__) \ +DO_903(MACRO, __VA_ARGS__) + + +#define DO_905(MACRO, ...) \ +MACRO(905, __VA_ARGS__) \ +DO_904(MACRO, __VA_ARGS__) + + +#define DO_906(MACRO, ...) \ +MACRO(906, __VA_ARGS__) \ +DO_905(MACRO, __VA_ARGS__) + + +#define DO_907(MACRO, ...) \ +MACRO(907, __VA_ARGS__) \ +DO_906(MACRO, __VA_ARGS__) + + +#define DO_908(MACRO, ...) \ +MACRO(908, __VA_ARGS__) \ +DO_907(MACRO, __VA_ARGS__) + + +#define DO_909(MACRO, ...) \ +MACRO(909, __VA_ARGS__) \ +DO_908(MACRO, __VA_ARGS__) + + +#define DO_910(MACRO, ...) \ +MACRO(910, __VA_ARGS__) \ +DO_909(MACRO, __VA_ARGS__) + + +#define DO_911(MACRO, ...) \ +MACRO(911, __VA_ARGS__) \ +DO_910(MACRO, __VA_ARGS__) + + +#define DO_912(MACRO, ...) \ +MACRO(912, __VA_ARGS__) \ +DO_911(MACRO, __VA_ARGS__) + + +#define DO_913(MACRO, ...) \ +MACRO(913, __VA_ARGS__) \ +DO_912(MACRO, __VA_ARGS__) + + +#define DO_914(MACRO, ...) \ +MACRO(914, __VA_ARGS__) \ +DO_913(MACRO, __VA_ARGS__) + + +#define DO_915(MACRO, ...) \ +MACRO(915, __VA_ARGS__) \ +DO_914(MACRO, __VA_ARGS__) + + +#define DO_916(MACRO, ...) \ +MACRO(916, __VA_ARGS__) \ +DO_915(MACRO, __VA_ARGS__) + + +#define DO_917(MACRO, ...) \ +MACRO(917, __VA_ARGS__) \ +DO_916(MACRO, __VA_ARGS__) + + +#define DO_918(MACRO, ...) \ +MACRO(918, __VA_ARGS__) \ +DO_917(MACRO, __VA_ARGS__) + + +#define DO_919(MACRO, ...) \ +MACRO(919, __VA_ARGS__) \ +DO_918(MACRO, __VA_ARGS__) + + +#define DO_920(MACRO, ...) \ +MACRO(920, __VA_ARGS__) \ +DO_919(MACRO, __VA_ARGS__) + + +#define DO_921(MACRO, ...) \ +MACRO(921, __VA_ARGS__) \ +DO_920(MACRO, __VA_ARGS__) + + +#define DO_922(MACRO, ...) \ +MACRO(922, __VA_ARGS__) \ +DO_921(MACRO, __VA_ARGS__) + + +#define DO_923(MACRO, ...) \ +MACRO(923, __VA_ARGS__) \ +DO_922(MACRO, __VA_ARGS__) + + +#define DO_924(MACRO, ...) \ +MACRO(924, __VA_ARGS__) \ +DO_923(MACRO, __VA_ARGS__) + + +#define DO_925(MACRO, ...) \ +MACRO(925, __VA_ARGS__) \ +DO_924(MACRO, __VA_ARGS__) + + +#define DO_926(MACRO, ...) \ +MACRO(926, __VA_ARGS__) \ +DO_925(MACRO, __VA_ARGS__) + + +#define DO_927(MACRO, ...) \ +MACRO(927, __VA_ARGS__) \ +DO_926(MACRO, __VA_ARGS__) + + +#define DO_928(MACRO, ...) \ +MACRO(928, __VA_ARGS__) \ +DO_927(MACRO, __VA_ARGS__) + + +#define DO_929(MACRO, ...) \ +MACRO(929, __VA_ARGS__) \ +DO_928(MACRO, __VA_ARGS__) + + +#define DO_930(MACRO, ...) \ +MACRO(930, __VA_ARGS__) \ +DO_929(MACRO, __VA_ARGS__) + + +#define DO_931(MACRO, ...) \ +MACRO(931, __VA_ARGS__) \ +DO_930(MACRO, __VA_ARGS__) + + +#define DO_932(MACRO, ...) \ +MACRO(932, __VA_ARGS__) \ +DO_931(MACRO, __VA_ARGS__) + + +#define DO_933(MACRO, ...) \ +MACRO(933, __VA_ARGS__) \ +DO_932(MACRO, __VA_ARGS__) + + +#define DO_934(MACRO, ...) \ +MACRO(934, __VA_ARGS__) \ +DO_933(MACRO, __VA_ARGS__) + + +#define DO_935(MACRO, ...) \ +MACRO(935, __VA_ARGS__) \ +DO_934(MACRO, __VA_ARGS__) + + +#define DO_936(MACRO, ...) \ +MACRO(936, __VA_ARGS__) \ +DO_935(MACRO, __VA_ARGS__) + + +#define DO_937(MACRO, ...) \ +MACRO(937, __VA_ARGS__) \ +DO_936(MACRO, __VA_ARGS__) + + +#define DO_938(MACRO, ...) \ +MACRO(938, __VA_ARGS__) \ +DO_937(MACRO, __VA_ARGS__) + + +#define DO_939(MACRO, ...) \ +MACRO(939, __VA_ARGS__) \ +DO_938(MACRO, __VA_ARGS__) + + +#define DO_940(MACRO, ...) \ +MACRO(940, __VA_ARGS__) \ +DO_939(MACRO, __VA_ARGS__) + + +#define DO_941(MACRO, ...) \ +MACRO(941, __VA_ARGS__) \ +DO_940(MACRO, __VA_ARGS__) + + +#define DO_942(MACRO, ...) \ +MACRO(942, __VA_ARGS__) \ +DO_941(MACRO, __VA_ARGS__) + + +#define DO_943(MACRO, ...) \ +MACRO(943, __VA_ARGS__) \ +DO_942(MACRO, __VA_ARGS__) + + +#define DO_944(MACRO, ...) \ +MACRO(944, __VA_ARGS__) \ +DO_943(MACRO, __VA_ARGS__) + + +#define DO_945(MACRO, ...) \ +MACRO(945, __VA_ARGS__) \ +DO_944(MACRO, __VA_ARGS__) + + +#define DO_946(MACRO, ...) \ +MACRO(946, __VA_ARGS__) \ +DO_945(MACRO, __VA_ARGS__) + + +#define DO_947(MACRO, ...) \ +MACRO(947, __VA_ARGS__) \ +DO_946(MACRO, __VA_ARGS__) + + +#define DO_948(MACRO, ...) \ +MACRO(948, __VA_ARGS__) \ +DO_947(MACRO, __VA_ARGS__) + + +#define DO_949(MACRO, ...) \ +MACRO(949, __VA_ARGS__) \ +DO_948(MACRO, __VA_ARGS__) + + +#define DO_950(MACRO, ...) \ +MACRO(950, __VA_ARGS__) \ +DO_949(MACRO, __VA_ARGS__) + + +#define DO_951(MACRO, ...) \ +MACRO(951, __VA_ARGS__) \ +DO_950(MACRO, __VA_ARGS__) + + +#define DO_952(MACRO, ...) \ +MACRO(952, __VA_ARGS__) \ +DO_951(MACRO, __VA_ARGS__) + + +#define DO_953(MACRO, ...) \ +MACRO(953, __VA_ARGS__) \ +DO_952(MACRO, __VA_ARGS__) + + +#define DO_954(MACRO, ...) \ +MACRO(954, __VA_ARGS__) \ +DO_953(MACRO, __VA_ARGS__) + + +#define DO_955(MACRO, ...) \ +MACRO(955, __VA_ARGS__) \ +DO_954(MACRO, __VA_ARGS__) + + +#define DO_956(MACRO, ...) \ +MACRO(956, __VA_ARGS__) \ +DO_955(MACRO, __VA_ARGS__) + + +#define DO_957(MACRO, ...) \ +MACRO(957, __VA_ARGS__) \ +DO_956(MACRO, __VA_ARGS__) + + +#define DO_958(MACRO, ...) \ +MACRO(958, __VA_ARGS__) \ +DO_957(MACRO, __VA_ARGS__) + + +#define DO_959(MACRO, ...) \ +MACRO(959, __VA_ARGS__) \ +DO_958(MACRO, __VA_ARGS__) + + +#define DO_960(MACRO, ...) \ +MACRO(960, __VA_ARGS__) \ +DO_959(MACRO, __VA_ARGS__) + + +#define DO_961(MACRO, ...) \ +MACRO(961, __VA_ARGS__) \ +DO_960(MACRO, __VA_ARGS__) + + +#define DO_962(MACRO, ...) \ +MACRO(962, __VA_ARGS__) \ +DO_961(MACRO, __VA_ARGS__) + + +#define DO_963(MACRO, ...) \ +MACRO(963, __VA_ARGS__) \ +DO_962(MACRO, __VA_ARGS__) + + +#define DO_964(MACRO, ...) \ +MACRO(964, __VA_ARGS__) \ +DO_963(MACRO, __VA_ARGS__) + + +#define DO_965(MACRO, ...) \ +MACRO(965, __VA_ARGS__) \ +DO_964(MACRO, __VA_ARGS__) + + +#define DO_966(MACRO, ...) \ +MACRO(966, __VA_ARGS__) \ +DO_965(MACRO, __VA_ARGS__) + + +#define DO_967(MACRO, ...) \ +MACRO(967, __VA_ARGS__) \ +DO_966(MACRO, __VA_ARGS__) + + +#define DO_968(MACRO, ...) \ +MACRO(968, __VA_ARGS__) \ +DO_967(MACRO, __VA_ARGS__) + + +#define DO_969(MACRO, ...) \ +MACRO(969, __VA_ARGS__) \ +DO_968(MACRO, __VA_ARGS__) + + +#define DO_970(MACRO, ...) \ +MACRO(970, __VA_ARGS__) \ +DO_969(MACRO, __VA_ARGS__) + + +#define DO_971(MACRO, ...) \ +MACRO(971, __VA_ARGS__) \ +DO_970(MACRO, __VA_ARGS__) + + +#define DO_972(MACRO, ...) \ +MACRO(972, __VA_ARGS__) \ +DO_971(MACRO, __VA_ARGS__) + + +#define DO_973(MACRO, ...) \ +MACRO(973, __VA_ARGS__) \ +DO_972(MACRO, __VA_ARGS__) + + +#define DO_974(MACRO, ...) \ +MACRO(974, __VA_ARGS__) \ +DO_973(MACRO, __VA_ARGS__) + + +#define DO_975(MACRO, ...) \ +MACRO(975, __VA_ARGS__) \ +DO_974(MACRO, __VA_ARGS__) + + +#define DO_976(MACRO, ...) \ +MACRO(976, __VA_ARGS__) \ +DO_975(MACRO, __VA_ARGS__) + + +#define DO_977(MACRO, ...) \ +MACRO(977, __VA_ARGS__) \ +DO_976(MACRO, __VA_ARGS__) + + +#define DO_978(MACRO, ...) \ +MACRO(978, __VA_ARGS__) \ +DO_977(MACRO, __VA_ARGS__) + + +#define DO_979(MACRO, ...) \ +MACRO(979, __VA_ARGS__) \ +DO_978(MACRO, __VA_ARGS__) + + +#define DO_980(MACRO, ...) \ +MACRO(980, __VA_ARGS__) \ +DO_979(MACRO, __VA_ARGS__) + + +#define DO_981(MACRO, ...) \ +MACRO(981, __VA_ARGS__) \ +DO_980(MACRO, __VA_ARGS__) + + +#define DO_982(MACRO, ...) \ +MACRO(982, __VA_ARGS__) \ +DO_981(MACRO, __VA_ARGS__) + + +#define DO_983(MACRO, ...) \ +MACRO(983, __VA_ARGS__) \ +DO_982(MACRO, __VA_ARGS__) + + +#define DO_984(MACRO, ...) \ +MACRO(984, __VA_ARGS__) \ +DO_983(MACRO, __VA_ARGS__) + + +#define DO_985(MACRO, ...) \ +MACRO(985, __VA_ARGS__) \ +DO_984(MACRO, __VA_ARGS__) + + +#define DO_986(MACRO, ...) \ +MACRO(986, __VA_ARGS__) \ +DO_985(MACRO, __VA_ARGS__) + + +#define DO_987(MACRO, ...) \ +MACRO(987, __VA_ARGS__) \ +DO_986(MACRO, __VA_ARGS__) + + +#define DO_988(MACRO, ...) \ +MACRO(988, __VA_ARGS__) \ +DO_987(MACRO, __VA_ARGS__) + + +#define DO_989(MACRO, ...) \ +MACRO(989, __VA_ARGS__) \ +DO_988(MACRO, __VA_ARGS__) + + +#define DO_990(MACRO, ...) \ +MACRO(990, __VA_ARGS__) \ +DO_989(MACRO, __VA_ARGS__) + + +#define DO_991(MACRO, ...) \ +MACRO(991, __VA_ARGS__) \ +DO_990(MACRO, __VA_ARGS__) + + +#define DO_992(MACRO, ...) \ +MACRO(992, __VA_ARGS__) \ +DO_991(MACRO, __VA_ARGS__) + + +#define DO_993(MACRO, ...) \ +MACRO(993, __VA_ARGS__) \ +DO_992(MACRO, __VA_ARGS__) + + +#define DO_994(MACRO, ...) \ +MACRO(994, __VA_ARGS__) \ +DO_993(MACRO, __VA_ARGS__) + + +#define DO_995(MACRO, ...) \ +MACRO(995, __VA_ARGS__) \ +DO_994(MACRO, __VA_ARGS__) + + +#define DO_996(MACRO, ...) \ +MACRO(996, __VA_ARGS__) \ +DO_995(MACRO, __VA_ARGS__) + + +#define DO_997(MACRO, ...) \ +MACRO(997, __VA_ARGS__) \ +DO_996(MACRO, __VA_ARGS__) + + +#define DO_998(MACRO, ...) \ +MACRO(998, __VA_ARGS__) \ +DO_997(MACRO, __VA_ARGS__) + + +#define DO_999(MACRO, ...) \ +MACRO(999, __VA_ARGS__) \ +DO_998(MACRO, __VA_ARGS__) + + +#define DO_1000(MACRO, ...) \ +MACRO(1000, __VA_ARGS__) \ +DO_999(MACRO, __VA_ARGS__) + + +#define DO_1001(MACRO, ...) \ +MACRO(1001, __VA_ARGS__) \ +DO_1000(MACRO, __VA_ARGS__) + + +#define DO_1002(MACRO, ...) \ +MACRO(1002, __VA_ARGS__) \ +DO_1001(MACRO, __VA_ARGS__) + + +#define DO_1003(MACRO, ...) \ +MACRO(1003, __VA_ARGS__) \ +DO_1002(MACRO, __VA_ARGS__) + + +#define DO_1004(MACRO, ...) \ +MACRO(1004, __VA_ARGS__) \ +DO_1003(MACRO, __VA_ARGS__) + + +#define DO_1005(MACRO, ...) \ +MACRO(1005, __VA_ARGS__) \ +DO_1004(MACRO, __VA_ARGS__) + + +#define DO_1006(MACRO, ...) \ +MACRO(1006, __VA_ARGS__) \ +DO_1005(MACRO, __VA_ARGS__) + + +#define DO_1007(MACRO, ...) \ +MACRO(1007, __VA_ARGS__) \ +DO_1006(MACRO, __VA_ARGS__) + + +#define DO_1008(MACRO, ...) \ +MACRO(1008, __VA_ARGS__) \ +DO_1007(MACRO, __VA_ARGS__) + + +#define DO_1009(MACRO, ...) \ +MACRO(1009, __VA_ARGS__) \ +DO_1008(MACRO, __VA_ARGS__) + + +#define DO_1010(MACRO, ...) \ +MACRO(1010, __VA_ARGS__) \ +DO_1009(MACRO, __VA_ARGS__) + + +#define DO_1011(MACRO, ...) \ +MACRO(1011, __VA_ARGS__) \ +DO_1010(MACRO, __VA_ARGS__) + + +#define DO_1012(MACRO, ...) \ +MACRO(1012, __VA_ARGS__) \ +DO_1011(MACRO, __VA_ARGS__) + + +#define DO_1013(MACRO, ...) \ +MACRO(1013, __VA_ARGS__) \ +DO_1012(MACRO, __VA_ARGS__) + + +#define DO_1014(MACRO, ...) \ +MACRO(1014, __VA_ARGS__) \ +DO_1013(MACRO, __VA_ARGS__) + + +#define DO_1015(MACRO, ...) \ +MACRO(1015, __VA_ARGS__) \ +DO_1014(MACRO, __VA_ARGS__) + + +#define DO_1016(MACRO, ...) \ +MACRO(1016, __VA_ARGS__) \ +DO_1015(MACRO, __VA_ARGS__) + + +#define DO_1017(MACRO, ...) \ +MACRO(1017, __VA_ARGS__) \ +DO_1016(MACRO, __VA_ARGS__) + + +#define DO_1018(MACRO, ...) \ +MACRO(1018, __VA_ARGS__) \ +DO_1017(MACRO, __VA_ARGS__) + + +#define DO_1019(MACRO, ...) \ +MACRO(1019, __VA_ARGS__) \ +DO_1018(MACRO, __VA_ARGS__) + + +#define DO_1020(MACRO, ...) \ +MACRO(1020, __VA_ARGS__) \ +DO_1019(MACRO, __VA_ARGS__) + + +#define DO_1021(MACRO, ...) \ +MACRO(1021, __VA_ARGS__) \ +DO_1020(MACRO, __VA_ARGS__) + + +#define DO_1022(MACRO, ...) \ +MACRO(1022, __VA_ARGS__) \ +DO_1021(MACRO, __VA_ARGS__) + + +#define DO_1023(MACRO, ...) \ +MACRO(1023, __VA_ARGS__) \ +DO_1022(MACRO, __VA_ARGS__) + + +#define DO_1024(MACRO, ...) \ +MACRO(1024, __VA_ARGS__) \ +DO_1023(MACRO, __VA_ARGS__) + + + +#define DO(TIMES, MACRO, ...) C2(DO_, TIMES)(MACRO, __VA_ARGS__) + + +/* we need some sort of macro that does: +IF(0, "true", "false") => "false" +IF(1, "true", "false") => "true" +IF(X, "true", "false") => "true" +*/ + +#define INTERNALIF(x) INTERNALIF##x +#define INTERNALIF0 + +#define ISZERO(x) COUNT_ARG(INTERNALIF(x)) + +#define IF(condition, trueBranch, falseBranch) C2(IF,ISZERO(condition))(trueBranch, falseBranch) +#define IF0(trueBranch, falseBranch) falseBranch +#define IF1(trueBranch, falseBranch) trueBranch + + + +#define DEFINE_ENUMERATION_CONSTANT(x) x, +/*DEFINE_ENUM goes to header*/ +#define DEFINE_ENUM(enumName, ...) typedef enum C2(enumName, _TAG) { FOR_EACH_1(DEFINE_ENUMERATION_CONSTANT, __VA_ARGS__)} enumName; \ + extern const char* C2(enumName,Strings)(enumName value); \ + extern int C2(enumName, _FromString)(const char* enumAsString, enumName* destination); + + +#define DEFINE_ENUMERATION_CONSTANT_AS_WIDESTRING(x) C2(L, TOSTRING(x)) , +#define DEFINE_ENUMERATION_CONSTANT_AS_STRING(x) TOSTRING(x) , +/*DEFINE_ENUM_STRINGS goes to .c*/ +#define DEFINE_ENUM_STRINGS(enumName, ...) const char* C2(enumName, StringStorage)[COUNT_ARG(__VA_ARGS__)] = {FOR_EACH_1(DEFINE_ENUMERATION_CONSTANT_AS_STRING, __VA_ARGS__)}; \ +const char* C2(enumName,Strings)(enumName value) \ +{ \ + if(value>=COUNT_ARG(__VA_ARGS__)) \ + { \ + /*this is an error case*/ \ + return NULL; \ + } \ + else \ + { \ + return C2(enumName, StringStorage)[value]; \ + } \ +} \ +int C2(enumName, _FromString)(const char* enumAsString, enumName* destination) \ +{ \ + if( \ + (enumAsString==NULL) || (destination==NULL) \ + ) \ + { \ + return __LINE__; \ + } \ + else \ + { \ + size_t i; \ + for(i=0;i +extern "C" +{ +#else +#include +#endif + + +#include "macro_utils.h" +#include "strings.h" +#include "crt_abstractions.h" + +#define MAP_RESULT_VALUES \ + MAP_OK, \ + MAP_ERROR, \ + MAP_INVALIDARG, \ + MAP_KEYEXISTS, \ + MAP_KEYNOTFOUND, \ + MAP_FILTER_REJECT + +/** @brief Enumeration specifying the status of calls to various APIs in this + * module. + */ +DEFINE_ENUM(MAP_RESULT, MAP_RESULT_VALUES); + +typedef void* MAP_HANDLE; + +typedef int (*MAP_FILTER_CALLBACK)(const char* mapProperty, const char* mapValue); + +/** + * @brief Creates a new, empty map. + * + * @param mapFilterFunc A callback function supplied by the caller that is + * invoked during calls to ::Map_Add and + * ::Map_AddOrUpdate to provide the caller an + * opportunity to indicate whether the new entry or + * the update to an existing entry can be made or not. + * The callback function can request that the operation + * be canceled by returning a non-zero value from the + * callback. + * + * @return A valid @c MAP_HANDLE or @c NULL in case an error occurs. + */ +extern MAP_HANDLE Map_Create(MAP_FILTER_CALLBACK mapFilterFunc); + +/** + * @brief Release all resources associated with the map. + * + * @param handle The handle to an existing map. + */ +extern void Map_Destroy(MAP_HANDLE handle); + +/** + * @brief Creates a copy of the map indicated by @p handle and returns a + * handle to it. + * + * @param handle The handle to an existing map. + * + * @return A valid @c MAP_HANDLE to the cloned copy of the map or @c NULL + * in case an error occurs. + */ +extern MAP_HANDLE Map_Clone(MAP_HANDLE handle); + +/** + * @brief Adds a key/value pair to the map. + * + * @param handle The handle to an existing map. + * @param key The @c key to be used for this map entry. + * @param value The @c value to be associated with @p key. + * + * If a non-NULL pointer to a callback function was supplied + * via the @c mapFilterFunc parameter when ::Map_Create was + * called then that callback is invoked when a new entry is + * added and if the callback returns a non-zero value then + * the function cancels the add operation and returns + * @c MAP_FILTER_REJECT. + * + * @return If any of the input parameters are @c NULL then this function + * returns @c MAP_INVALID_ARG. If the key already exists in the + * map then @c MAP_KEYEXISTS is returned. If the filter function + * associated with the map rejects the entry then + * @c MAP_FILTER_REJECT is returned. In case an error occurs when + * the new key is added to the map the function returns @c MAP_ERROR. + * If everything goes well then @c MAP_OK is returned. + */ +extern MAP_RESULT Map_Add(MAP_HANDLE handle, const char* key, const char* value); + +/** + * @brief Adds/updates a key/value pair to the map. + * + * @param handle The handle to an existing map. + * @param key The @c key to be used for this map entry. + * @param value The @c value to be associated with @p key. + * + * This function behaves exactly like ::Map_Add except that if the key + * already exists in the map then it overwrites the value with the + * supplied value instead of returning an error. If a non-NULL pointer + * to a callback function was supplied via the @c mapFilterFunc parameter + * when ::Map_Create was called then that callback is invoked when a new + * entry is added or when an existing entry is updated and if the + * callback returns a non-zero value then the function cancels the + * add/update operation and returns @c MAP_FILTER_REJECT. + * + * @return If any of the input parameters are @c NULL then this function + * returns @c MAP_INVALID_ARG. If the filter function associated + * with the map rejects the entry then @c MAP_FILTER_REJECT is + * returned. In case an error occurs when the new key is + * added/updated in the map the function returns @c MAP_ERROR. If + * everything goes well then @c MAP_OK is returned. + */ +extern MAP_RESULT Map_AddOrUpdate(MAP_HANDLE handle, const char* key, const char* value); + +/** + * @brief Removes a key and its associated value from the map. + * + * @param handle The handle to an existing map. + * @param key The @c key of the item to be deleted. + * + * @return Returns @c MAP_OK if the key was deleted successfully or an + * error code otherwise. + */ +extern MAP_RESULT Map_Delete(MAP_HANDLE handle, const char* key); + +/** + * @brief This function returns a boolean value in @p keyExists if the map + * contains a key with the same value the parameter @p key. + * + * @param handle The handle to an existing map. + * @param key The key that the caller wants checked. + * @param keyExists The function writes @c true at the address pointed at + * by this parameter if the key exists in the map and + * @c false otherwise. + * + * @return Returns @c MAP_OK if the check was performed successfully or an + * error code otherwise. + */ +extern MAP_RESULT Map_ContainsKey(MAP_HANDLE handle, const char* key, bool* keyExists); + +/** + * @brief This function returns @c true in @p valueExists if at + * least one pair exists in the map where the entry's + * value is equal to the parameter @c value. + * + * @param handle The handle to an existing map. + * @param value The value that the caller wants checked. + * @param valueExists The function writes @c true at the address pointed at + * by this parameter if the value exists in the map and + * @c false otherwise. + * + * @return Returns @c MAP_OK if the check was performed successfully or an + * error code otherwise. + */ +extern MAP_RESULT Map_ContainsValue(MAP_HANDLE handle, const char* value, bool* valueExists); + +/** + * @brief Retrieves the value of a stored key. + * + * @param handle The handle to an existing map. + * @param key The key to be looked up in the map. + * + * @return Returns @c NULL in case the input arguments are @c NULL or if the + * requested key is not found in the map. Returns a pointer to the + * key's value otherwise. + */ +extern const char* Map_GetValueFromKey(MAP_HANDLE handle, const char* key); + +/** + * @brief Retrieves the complete list of keys and values from the map + * in @p values and @p keys. Also writes the size of the list + * in @p count. + * + * @param handle The handle to an existing map. + * @param keys The location where the list of keys is to be written. + * @param values The location where the list of values is to be written. + * @param count The number of stored keys and values is written at the + * location indicated by this pointer. + * + * @return Returns @c MAP_OK if the keys and values are retrieved and written + * successfully or an error code otherwise. + */ +extern MAP_RESULT Map_GetInternals(MAP_HANDLE handle, const char*const** keys, const char*const** values, size_t* count); + +#ifdef __cplusplus +} +#endif + +#endif /* MAP_H */ diff --git a/c/sharedutil/inc/mqttapi.h b/c/sharedutil/inc/mqttapi.h new file mode 100644 index 00000000..77837b05 --- /dev/null +++ b/c/sharedutil/inc/mqttapi.h @@ -0,0 +1,77 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#ifndef MQTTAPI_H +#define MQTTAPI_H + +#ifdef __cplusplus +extern "C" { +#include +#else +#include +#endif +#include "macro_utils.h" +#include "crt_abstractions.h" + +typedef void* MQTTAPI_HANDLE; +typedef void* MQTTAPI_TOPIC_HANDLE; + +#define MQTTAPI_RESULT_VALUES \ +MQTTAPI_OK, \ +MQTTAPI_INVALID_ARG, \ +MQTTAPI_ERROR_CONNECTED_INSTANCE, \ +MQTTAPI_ERROR \ + +DEFINE_ENUM(MQTTAPI_RESULT, MQTTAPI_RESULT_VALUES); + +#define MQTTAPI_CONFIRMATION_RESULT_VALUES \ + MQTTAPI_CONFIRMATION_OK, \ + MQTTAPI_CONFIRMATION_BECAUSE_DESTROY, \ + MQTTAPI_CONFIRMATION_ERROR \ + +DEFINE_ENUM(MQTTAPI_CONFIRMATION_RESULT, MQTTAPI_CONFIRMATION_RESULT_VALUES); + +typedef struct +{ + /** The length of the MQTT message payload in bytes. */ + size_t payloadlen; + /** A pointer to the payload of the MQTT message. */ + unsigned char* payload; +} MQTTAPI_Message; + +typedef struct +{ + const char* deviceId; + const char* deviceKey; + /** + * String used to connect with a sas token. Format is .\devices\ + */ + const char* sasTokenSr; + /** + * String with the Server URI to be connected. Format required protocol://host:port + */ + const char* serverURI; +} MQTTAPI_ConnectOptions; + +typedef bool MQTTAPI_MessageArrived(void* context, const MQTTAPI_Message* message); +typedef void MQTTAPI_DeliveryComplete(void* context, MQTTAPI_CONFIRMATION_RESULT result); + +extern MQTTAPI_HANDLE MQTTAPI_Create(const MQTTAPI_ConnectOptions* options); +extern MQTTAPI_RESULT MQTTAPI_SetMessageCallback(MQTTAPI_HANDLE instance, void* context, MQTTAPI_MessageArrived * ma); +extern MQTTAPI_RESULT MQTTAPI_SetDeliveryCompletedCallback(MQTTAPI_HANDLE instance, MQTTAPI_DeliveryComplete* dc); + + +extern void MQTTAPI_Destroy(MQTTAPI_HANDLE instance); + +extern MQTTAPI_RESULT MQTTAPI_PublishMessage(MQTTAPI_HANDLE instance, const char* topicName, const MQTTAPI_Message* msg, void* context); + +extern MQTTAPI_TOPIC_HANDLE MQTTAPI_Subscribe(MQTTAPI_HANDLE instance, const char* topic); +extern void MQTTAPI_Unsubscribe(MQTTAPI_TOPIC_HANDLE topicInstance); + +extern void MQTTAPI_DoWork(MQTTAPI_HANDLE instance); + +#ifdef __cplusplus +} +#endif + +#endif /* MQTTAPI_H*/ diff --git a/c/sharedutil/inc/platform.h b/c/sharedutil/inc/platform.h new file mode 100644 index 00000000..22a874b7 --- /dev/null +++ b/c/sharedutil/inc/platform.h @@ -0,0 +1,15 @@ +#ifndef PLATFORM_H +#define PLATFORM_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + extern int platform_init(void); + extern void platform_deinit(void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* PLATFORM_H */ diff --git a/c/sharedutil/inc/sastoken.h b/c/sharedutil/inc/sastoken.h new file mode 100644 index 00000000..e55f012b --- /dev/null +++ b/c/sharedutil/inc/sastoken.h @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#ifndef SASTOKEN_H +#define SASTOKEN_H + +#include "strings.h" +#include "buffer_.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern STRING_HANDLE SASToken_Create(STRING_HANDLE key, STRING_HANDLE scope, STRING_HANDLE keyName, size_t expiry); + +#ifdef __cplusplus +} +#endif + +#endif /* SASTOKEN_H */ diff --git a/c/sharedutil/inc/sha-private.h b/c/sharedutil/inc/sha-private.h new file mode 100644 index 00000000..24616a6f --- /dev/null +++ b/c/sharedutil/inc/sha-private.h @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*************************** sha-private.h ***************************/ +/********************** See RFC 4634 for details *********************/ +#ifndef _SHA_PRIVATE__H +#define _SHA_PRIVATE__H +/* +* These definitions are defined in FIPS-180-2, section 4.1. +* Ch() and Maj() are defined identically in sections 4.1.1, +* 4.1.2 and 4.1.3. +* +* The definitions used in FIPS-180-2 are as follows: +*/ + +#ifndef USE_MODIFIED_MACROS +#define SHA_Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z))) +#define SHA_Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) + +#else /* USE_MODIFIED_MACROS */ +/* +* The following definitions are equivalent and potentially faster. +*/ + +#define SHA_Ch(x, y, z) (((x) & ((y) ^ (z))) ^ (z)) +#define SHA_Maj(x, y, z) (((x) & ((y) | (z))) | ((y) & (z))) + +#endif /* USE_MODIFIED_MACROS */ + +#define SHA_Parity(x, y, z) ((x) ^ (y) ^ (z)) + +#endif /* _SHA_PRIVATE__H */ + diff --git a/c/sharedutil/inc/sha.h b/c/sharedutil/inc/sha.h new file mode 100644 index 00000000..0d1f977c --- /dev/null +++ b/c/sharedutil/inc/sha.h @@ -0,0 +1,267 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/**************************** sha.h ****************************/ +/******************* See RFC 4634 for details ******************/ +#ifndef _SHA_H_ +#define _SHA_H_ + +/* + * Description: + * This file implements the Secure Hash Signature Standard + * algorithms as defined in the National Institute of Standards + * and Technology Federal Information Processing Standards + * Publication (FIPS PUB) 180-1 published on April 17, 1995, 180-2 + * published on August 1, 2002, and the FIPS PUB 180-2 Change + * Notice published on February 28, 2004. + * + * A combined document showing all algorithms is available at + * http://csrc.nist.gov/publications/fips/ + * fips180-2/fips180-2withchangenotice.pdf + * + * The five hashes are defined in these sizes: + * SHA-1 20 byte / 160 bit + * SHA-224 28 byte / 224 bit + * SHA-256 32 byte / 256 bit + * SHA-384 48 byte / 384 bit + * SHA-512 64 byte / 512 bit + */ + +#include +/* + * If you do not have the ISO standard stdint.h header file, then you + * must typedef the following: + * name meaning + * uint64_t unsigned 64 bit integer + * uint32_t unsigned 32 bit integer + * uint8_t unsigned 8 bit integer (i.e., unsigned char) + * int_least16_t integer of >= 16 bits + * + */ + +#ifndef _SHA_enum_ +#define _SHA_enum_ +/* + * All SHA functions return one of these values. + */ +enum { + shaSuccess = 0, + shaNull, /* Null pointer parameter */ + shaInputTooLong, /* input data too long */ + shaStateError, /* called Input after FinalBits or Result */ + shaBadParam /* passed a bad parameter */ +}; +#endif /* _SHA_enum_ */ + +/* + * These constants hold size information for each of the SHA + * hashing operations + */ +enum { + SHA1_Message_Block_Size = 64, SHA224_Message_Block_Size = 64, + SHA256_Message_Block_Size = 64, SHA384_Message_Block_Size = 128, + SHA512_Message_Block_Size = 128, + USHA_Max_Message_Block_Size = SHA512_Message_Block_Size, + + SHA1HashSize = 20, SHA224HashSize = 28, SHA256HashSize = 32, + SHA384HashSize = 48, SHA512HashSize = 64, + USHAMaxHashSize = SHA512HashSize, + + SHA1HashSizeBits = 160, SHA224HashSizeBits = 224, + SHA256HashSizeBits = 256, SHA384HashSizeBits = 384, + SHA512HashSizeBits = 512, USHAMaxHashSizeBits = SHA512HashSizeBits +}; + +/* + * These constants are used in the USHA (unified sha) functions. + */ +typedef enum SHAversion { + SHA1, SHA224, SHA256, SHA384, SHA512 +} SHAversion; + +/* + * This structure will hold context information for the SHA-1 + * hashing operation. + */ +typedef struct SHA1Context { + uint32_t Intermediate_Hash[SHA1HashSize/4]; /* Message Digest */ + + uint32_t Length_Low; /* Message length in bits */ + uint32_t Length_High; /* Message length in bits */ + + int_least16_t Message_Block_Index; /* Message_Block array index */ + /* 512-bit message blocks */ + uint8_t Message_Block[SHA1_Message_Block_Size]; + + int Computed; /* Is the digest computed? */ + int Corrupted; /* Is the digest corrupted? */ +} SHA1Context; + +/* + * This structure will hold context information for the SHA-256 + * hashing operation. + */ +typedef struct SHA256Context { + uint32_t Intermediate_Hash[SHA256HashSize/4]; /* Message Digest */ + + uint32_t Length_Low; /* Message length in bits */ + uint32_t Length_High; /* Message length in bits */ + + int_least16_t Message_Block_Index; /* Message_Block array index */ + /* 512-bit message blocks */ + uint8_t Message_Block[SHA256_Message_Block_Size]; + + int Computed; /* Is the digest computed? */ + int Corrupted; /* Is the digest corrupted? */ +} SHA256Context; + +/* + * This structure will hold context information for the SHA-512 + * hashing operation. + */ +typedef struct SHA512Context { +#ifdef USE_32BIT_ONLY + uint32_t Intermediate_Hash[SHA512HashSize/4]; /* Message Digest */ + uint32_t Length[4]; /* Message length in bits */ +#else /* !USE_32BIT_ONLY */ + uint64_t Intermediate_Hash[SHA512HashSize/8]; /* Message Digest */ + uint64_t Length_Low, Length_High; /* Message length in bits */ +#endif /* USE_32BIT_ONLY */ + + int_least16_t Message_Block_Index; /* Message_Block array index */ + /* 1024-bit message blocks */ + uint8_t Message_Block[SHA512_Message_Block_Size]; + + int Computed; /* Is the digest computed?*/ + int Corrupted; /* Is the digest corrupted? */ +} SHA512Context; + +/* + * This structure will hold context information for the SHA-224 + * hashing operation. It uses the SHA-256 structure for computation. + */ +typedef struct SHA256Context SHA224Context; + +/* + * This structure will hold context information for the SHA-384 + * hashing operation. It uses the SHA-512 structure for computation. + */ +typedef struct SHA512Context SHA384Context; + +/* + * This structure holds context information for all SHA + * hashing operations. + */ +typedef struct USHAContext { + int whichSha; /* which SHA is being used */ + union { + SHA1Context sha1Context; + SHA224Context sha224Context; SHA256Context sha256Context; + SHA384Context sha384Context; SHA512Context sha512Context; + } ctx; +} USHAContext; + +/* + * This structure will hold context information for the HMAC + * keyed hashing operation. + */ +typedef struct HMACContext { + int whichSha; /* which SHA is being used */ + int hashSize; /* hash size of SHA being used */ + int blockSize; /* block size of SHA being used */ + USHAContext shaContext; /* SHA context */ + unsigned char k_opad[USHA_Max_Message_Block_Size]; + /* outer padding - key XORd with opad */ +} HMACContext; + + +/* + * Function Prototypes + */ + +/* SHA-1 */ +extern int SHA1Reset(SHA1Context *); +extern int SHA1Input(SHA1Context *, const uint8_t *bytes, + unsigned int bytecount); +extern int SHA1FinalBits(SHA1Context *, const uint8_t bits, + unsigned int bitcount); +extern int SHA1Result(SHA1Context *, + uint8_t Message_Digest[SHA1HashSize]); + +/* SHA-224 */ +extern int SHA224Reset(SHA224Context *); +extern int SHA224Input(SHA224Context *, const uint8_t *bytes, + unsigned int bytecount); +extern int SHA224FinalBits(SHA224Context *, const uint8_t bits, + unsigned int bitcount); +extern int SHA224Result(SHA224Context *, + uint8_t Message_Digest[SHA224HashSize]); + +/* SHA-256 */ +extern int SHA256Reset(SHA256Context *); +extern int SHA256Input(SHA256Context *, const uint8_t *bytes, + unsigned int bytecount); +extern int SHA256FinalBits(SHA256Context *, const uint8_t bits, + unsigned int bitcount); +extern int SHA256Result(SHA256Context *, + uint8_t Message_Digest[SHA256HashSize]); + +/* SHA-384 */ +extern int SHA384Reset(SHA384Context *); +extern int SHA384Input(SHA384Context *, const uint8_t *bytes, + unsigned int bytecount); +extern int SHA384FinalBits(SHA384Context *, const uint8_t bits, + unsigned int bitcount); +extern int SHA384Result(SHA384Context *, + uint8_t Message_Digest[SHA384HashSize]); + +/* SHA-512 */ +extern int SHA512Reset(SHA512Context *); +extern int SHA512Input(SHA512Context *, const uint8_t *bytes, + unsigned int bytecount); +extern int SHA512FinalBits(SHA512Context *, const uint8_t bits, + unsigned int bitcount); +extern int SHA512Result(SHA512Context *, + uint8_t Message_Digest[SHA512HashSize]); + +/* Unified SHA functions, chosen by whichSha */ +extern int USHAReset(USHAContext *, SHAversion whichSha); +extern int USHAInput(USHAContext *, + const uint8_t *bytes, unsigned int bytecount); +extern int USHAFinalBits(USHAContext *, + const uint8_t bits, unsigned int bitcount); +extern int USHAResult(USHAContext *, + uint8_t Message_Digest[USHAMaxHashSize]); +extern int USHABlockSize(enum SHAversion whichSha); +extern int USHAHashSize(enum SHAversion whichSha); +extern int USHAHashSizeBits(enum SHAversion whichSha); + +/* + * HMAC Keyed-Hashing for Message Authentication, RFC2104, + * for all SHAs. + * This interface allows a fixed-length text input to be used. + */ +extern int hmac(SHAversion whichSha, /* which SHA algorithm to use */ + const unsigned char *text, /* pointer to data stream */ + int text_len, /* length of data stream */ + const unsigned char *key, /* pointer to authentication key */ + int key_len, /* length of authentication key */ + uint8_t digest[USHAMaxHashSize]); /* caller digest to fill in */ + +/* + * HMAC Keyed-Hashing for Message Authentication, RFC2104, + * for all SHAs. + * This interface allows any length of text input to be used. + */ +extern int hmacReset(HMACContext *ctx, enum SHAversion whichSha, + const unsigned char *key, int key_len); +extern int hmacInput(HMACContext *ctx, const unsigned char *text, + int text_len); + +extern int hmacFinalBits(HMACContext *ctx, const uint8_t bits, + unsigned int bitcount); +extern int hmacResult(HMACContext *ctx, + uint8_t digest[USHAMaxHashSize]); + +#endif /* _SHA_H_ */ + diff --git a/c/sharedutil/inc/socketio.h b/c/sharedutil/inc/socketio.h new file mode 100644 index 00000000..30e4be17 --- /dev/null +++ b/c/sharedutil/inc/socketio.h @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#ifndef SOCKETIO_H +#define SOCKETIO_H + +#ifdef __cplusplus +extern "C" { +#include +#else +#include +#endif /* __cplusplus */ + +#include "io.h" +#include "iot_logging.h" + +typedef struct SOCKETIO_CONFIG_TAG +{ + const char* hostname; + int port; +} SOCKETIO_CONFIG; + +extern IO_HANDLE socketio_create(void* io_create_parameters, LOGGER_LOG logger_log); +extern void socketio_destroy(IO_HANDLE socket_io); +extern int socketio_open(IO_HANDLE socket_io, ON_BYTES_RECEIVED on_bytes_received, ON_IO_STATE_CHANGED on_io_state_changed, void* callback_context); +extern int socketio_close(IO_HANDLE socket_io); +extern int socketio_send(IO_HANDLE socket_io, const void* buffer, size_t size); +extern void socketio_dowork(IO_HANDLE socket_io); +extern const IO_INTERFACE_DESCRIPTION* socketio_get_interface_description(void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* SOCKETIO_H */ diff --git a/c/sharedutil/inc/stdint_ce6.h b/c/sharedutil/inc/stdint_ce6.h new file mode 100644 index 00000000..06b3d58f --- /dev/null +++ b/c/sharedutil/inc/stdint_ce6.h @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +typedef signed char int8_t; +typedef signed short int16_t; +typedef signed int int32_t; +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef signed __int64 int64_t; +typedef unsigned __int64 uint64_t; diff --git a/c/sharedutil/inc/string_tokenizer.h b/c/sharedutil/inc/string_tokenizer.h new file mode 100644 index 00000000..179e4afc --- /dev/null +++ b/c/sharedutil/inc/string_tokenizer.h @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#ifndef STRING_TOKENIZER_H +#define STRING_TOKENIZER_H + +#include "strings.h" + +#ifdef __cplusplus +extern "C" +{ +#else +#endif + +typedef void* STRING_TOKENIZER_HANDLE; + +extern STRING_TOKENIZER_HANDLE STRING_TOKENIZER_create(STRING_HANDLE handle); +extern int STRING_TOKENIZER_get_next_token(STRING_TOKENIZER_HANDLE t, STRING_HANDLE output, const char* delimiters); +extern void STRING_TOKENIZER_destroy(STRING_TOKENIZER_HANDLE t); + +#ifdef __cplusplus +} +#else +#endif + +#endif /*STRING_TOKENIZER_H*/ diff --git a/c/sharedutil/inc/strings.h b/c/sharedutil/inc/strings.h new file mode 100644 index 00000000..a691ce8d --- /dev/null +++ b/c/sharedutil/inc/strings.h @@ -0,0 +1,41 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#ifndef STRINGS_H +#define STRINGS_H + +#ifdef __cplusplus +#include +extern "C" +{ +#else +#include +#endif + +typedef void* STRING_HANDLE; + +extern STRING_HANDLE STRING_new(void); +extern STRING_HANDLE STRING_clone(STRING_HANDLE handle); +extern STRING_HANDLE STRING_construct(const char* psz); +extern STRING_HANDLE STRING_construct_n(const char* psz, size_t n); +extern STRING_HANDLE STRING_new_with_memory(const char* memory); +extern STRING_HANDLE STRING_new_quoted(const char* source); +extern STRING_HANDLE STRING_new_JSON(const char* source); +extern void STRING_delete(STRING_HANDLE handle); +extern int STRING_concat(STRING_HANDLE handle, const char* s2); +extern int STRING_concat_with_STRING(STRING_HANDLE s1, STRING_HANDLE s2); +extern int STRING_quote(STRING_HANDLE handle); +extern int STRING_copy(STRING_HANDLE s1, const char* s2); +extern int STRING_copy_n(STRING_HANDLE s1, const char* s2, size_t n); +extern const char* STRING_c_str(STRING_HANDLE handle); +extern int STRING_empty(STRING_HANDLE handle); +extern size_t STRING_length(STRING_HANDLE handle); +extern int STRING_compare(STRING_HANDLE s1, STRING_HANDLE s2); + + +#ifdef __cplusplus +} +#else +#endif + +#endif /*STRINGS_H*/ diff --git a/c/sharedutil/inc/threadapi.h b/c/sharedutil/inc/threadapi.h new file mode 100644 index 00000000..134c5332 --- /dev/null +++ b/c/sharedutil/inc/threadapi.h @@ -0,0 +1,89 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/** @file threadapi.h + * @brief This module implements support for creating new threads, + * terminating threads and sleeping threads. + */ + +#ifndef THREADAPI_H +#define THREADAPI_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "macro_utils.h" + +typedef int(*THREAD_START_FUNC)(void *); + +#define THREADAPI_RESULT_VALUES \ + THREADAPI_OK, \ + THREADAPI_INVALID_ARG, \ + THREADAPI_NO_MEMORY, \ + THREADAPI_ERROR + +/** @brief Enumeration specifying the possible return values for the APIs in + * this module. + */ +DEFINE_ENUM(THREADAPI_RESULT, THREADAPI_RESULT_VALUES); + +typedef void* THREAD_HANDLE; + +/** + * @brief Creates a thread with the entry point specified by the @p func + * argument. + * + * @param threadHandle The handle to the new thread is returned in this + * pointer. + * @param func A function pointer that indicates the entry point + * to the new thread. + * @param arg A void pointer that must be passed to the function + * pointed to by @p func. + * + * @return @c THREADAPI_OK if the API call is successful or an error + * code in case it fails. + */ +extern THREADAPI_RESULT ThreadAPI_Create(THREAD_HANDLE* threadHandle, THREAD_START_FUNC func, void* arg); + +/** + * @brief Blocks the calling thread by waiting on the thread identified by + * the @p threadHandle argument to complete. + * + * @param threadHandle The handle of the thread to wait for completion. + * @param res The result returned by the thread which is passed + * to the ::ThreadAPI_Exit function. + * + * When the @p threadHandle thread completes, all resources associated + * with the thread must be released and the thread handle will no + * longer be valid. + * + * @return @c THREADAPI_OK if the API call is successful or an error + * code in case it fails. + */ +extern THREADAPI_RESULT ThreadAPI_Join(THREAD_HANDLE threadHandle, int* res); + +/** + * @brief This function is called by a thread when the thread exits. + * + * @param res An integer that represents the exit status of the thread. + * + * This function is called by a thread when the thread exits in order + * to return a result value to the caller of the ::ThreadAPI_Join + * function. The @p res value must be copied into the @p res out + * argument passed to the ::ThreadAPI_Join function. + */ +extern void ThreadAPI_Exit(int res); + +/** + * @brief Sleeps the current thread for the given number of milliseconds. + * + * @param milliseconds The number of milliseconds to sleep. + */ +extern void ThreadAPI_Sleep(unsigned int milliseconds); + +#ifdef __cplusplus +} +#endif + +#endif /* THREADAPI_H */ diff --git a/c/sharedutil/inc/tlsio.h b/c/sharedutil/inc/tlsio.h new file mode 100644 index 00000000..42440067 --- /dev/null +++ b/c/sharedutil/inc/tlsio.h @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#ifndef TLSIO_H +#define TLSIO_H + +#ifdef __cplusplus +extern "C" { +#include +#else +#include +#endif /* __cplusplus */ + +#include "io.h" +#include "iot_logging.h" + +typedef struct TLSIO_CONFIG_TAG +{ + const char* hostname; + int port; +} TLSIO_CONFIG; + +extern IO_HANDLE tlsio_create(void* io_create_parameters, LOGGER_LOG logger_log); +extern void tlsio_destroy(IO_HANDLE tls_io); +extern int tlsio_open(IO_HANDLE tls_io, ON_BYTES_RECEIVED on_bytes_received, ON_IO_STATE_CHANGED on_io_state_changed, void* callback_context); +extern int tlsio_close(IO_HANDLE tls_io); +extern int tlsio_send(IO_HANDLE tls_io, const void* buffer, size_t size); +extern void tlsio_dowork(IO_HANDLE tls_io); +extern const IO_INTERFACE_DESCRIPTION* tlsio_get_interface_description(void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* TLSIO_H */ diff --git a/c/sharedutil/inc/urlencode.h b/c/sharedutil/inc/urlencode.h new file mode 100644 index 00000000..65612bc4 --- /dev/null +++ b/c/sharedutil/inc/urlencode.h @@ -0,0 +1,21 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#ifndef URLENCODE_H +#define URLENCODE_H + +#include "strings.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern STRING_HANDLE URL_EncodeString(const char* textEncode); +extern STRING_HANDLE URL_Encode(STRING_HANDLE input); + +#ifdef __cplusplus +} +#endif + +#endif /* URLENCODE_H */ + diff --git a/c/sharedutil/inc/vector.h b/c/sharedutil/inc/vector.h new file mode 100644 index 00000000..c1f58c81 --- /dev/null +++ b/c/sharedutil/inc/vector.h @@ -0,0 +1,46 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#ifndef VECTOR_H +#define VECTOR_H + +#include "crt_abstractions.h" + +#ifdef __cplusplus +#include +extern "C" +{ +#else +#include +#endif + +typedef void* VECTOR_HANDLE; + +typedef bool(*PREDICATE_FUNCTION)(const void* element, const void* value); + +/* creation */ +extern VECTOR_HANDLE VECTOR_create(size_t elementSize); +extern void VECTOR_destroy(VECTOR_HANDLE handle); + +/* insertion */ +extern int VECTOR_push_back(VECTOR_HANDLE handle, const void* elements, size_t numElements); + +/* removal */ +extern void VECTOR_erase(VECTOR_HANDLE handle, void* elements, size_t numElements); +extern void VECTOR_clear(VECTOR_HANDLE handle); + +/* access */ +extern void* VECTOR_element(const VECTOR_HANDLE handle, size_t index); +extern void* VECTOR_front(const VECTOR_HANDLE handle); +extern void* VECTOR_back(const VECTOR_HANDLE handle); +extern void* VECTOR_find_if(const VECTOR_HANDLE handle, PREDICATE_FUNCTION pred, const void* value); + +/* capacity */ +extern size_t VECTOR_size(const VECTOR_HANDLE handle); + +#ifdef __cplusplus +} +#else +#endif + +#endif /* VECTOR_H */ diff --git a/c/sharedutil/readme.txt b/c/sharedutil/readme.txt new file mode 100644 index 00000000..eeac5722 --- /dev/null +++ b/c/sharedutil/readme.txt @@ -0,0 +1 @@ +This folder contains the azure shared utility library used in all the clients. \ No newline at end of file diff --git a/c/sharedutil/src/base64.c b/c/sharedutil/src/base64.c new file mode 100644 index 00000000..f54d321c --- /dev/null +++ b/c/sharedutil/src/base64.c @@ -0,0 +1,349 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// +// PUT NO INCLUDES BEFORE HERE !!!! +// +#include +#ifdef _CRTDBG_MAP_ALLOC +#include +#endif +#include "gballoc.h" + +#include +#include +// +// PUT NO CLIENT LIBRARY INCLUDES BEFORE HERE !!!! +// +#include "base64.h" +#include "iot_logging.h" + +static const char base64char[64] = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', + 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', + 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', + 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', + 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', '+', '/' +}; + +static const char base64b16[16] = { + 'A', 'E', 'I', 'M', 'Q', 'U', 'Y', 'c', 'g', 'k', + 'o', 's', 'w', '0', '4', '8' +}; + +static const char base64b8[4] = { + 'A', 'Q', 'g', 'w' +}; + +static int base64toValue(char base64character, unsigned char* value) +{ + int result = 0; + if (('A' <= base64character) && (base64character <= 'Z')) + { + *value = base64character - 'A'; + } + else if (('a' <= base64character) && (base64character <= 'z')) + { + *value = ('Z' - 'A') + 1 + (base64character - 'a'); + } + else if (('0' <= base64character) && (base64character <= '9')) + { + *value = ('Z' - 'A') + 1 + ('z' - 'a') + 1 + (base64character - '0'); + } + else if ('+' == base64character) + { + *value = 62; + } + else if ('/' == base64character) + { + *value = 63; + } + else + { + *value = 0; + result = -1; + } + return result; +} + +static size_t numberOfBase64Characters(const char* encodedString) +{ + size_t length = 0; + unsigned char junkChar; + while (base64toValue(encodedString[length],&junkChar) != -1) + { + length++; + } + return length; +} +static size_t Base64decode_len(const char *encodedString) +{ + size_t absoluteLengthOfString; + size_t numberOfBytesToAdd = 0; + + absoluteLengthOfString = strlen(encodedString); + if (absoluteLengthOfString) + { + if (encodedString[absoluteLengthOfString - 1] == '=') + { + // See if there are two. + absoluteLengthOfString--; + if (absoluteLengthOfString) + { + if (encodedString[absoluteLengthOfString - 1] == '=') + { + absoluteLengthOfString--; + numberOfBytesToAdd = 1; + } + else + { + numberOfBytesToAdd = 2; + } + } + else + { + numberOfBytesToAdd = 2; + } + } + } + return ((absoluteLengthOfString / 4)*3) + numberOfBytesToAdd; +} + +static void Base64decode(unsigned char *decodedString, const char *base64String) +{ + + size_t numberOfEncodedChars; + size_t indexOfFirstEncodedChar; + size_t decodedIndex; + + // + // We can only operate on individual bytes. If we attempt to work + // on anything larger we could get an alignment fault on some + // architectures + // + + numberOfEncodedChars = numberOfBase64Characters(base64String); + indexOfFirstEncodedChar = 0; + decodedIndex = 0; + while (numberOfEncodedChars >= 4) + { + unsigned char c1; + unsigned char c2; + unsigned char c3; + unsigned char c4; + (void)base64toValue(base64String[indexOfFirstEncodedChar], &c1); + (void)base64toValue(base64String[indexOfFirstEncodedChar + 1], &c2); + (void)base64toValue(base64String[indexOfFirstEncodedChar + 2], &c3); + (void)base64toValue(base64String[indexOfFirstEncodedChar + 3], &c4); + decodedString[decodedIndex] = (c1 << 2) | (c2 >> 4); + decodedIndex++; + decodedString[decodedIndex] = ((c2 & 0x0f) << 4) | (c3 >> 2); + decodedIndex++; + decodedString[decodedIndex] = ((c3 & 0x03) << 6) | c4; + decodedIndex++; + numberOfEncodedChars -= 4; + indexOfFirstEncodedChar += 4; + + } + + if (numberOfEncodedChars == 2) + { + unsigned char c1; + unsigned char c2; + (void)base64toValue(base64String[indexOfFirstEncodedChar], &c1); + (void)base64toValue(base64String[indexOfFirstEncodedChar + 1], &c2); + decodedString[decodedIndex] = (c1 << 2) | (c2 >> 4); + } + else if (numberOfEncodedChars == 3) + { + unsigned char c1; + unsigned char c2; + unsigned char c3; + (void)base64toValue(base64String[indexOfFirstEncodedChar], &c1); + (void)base64toValue(base64String[indexOfFirstEncodedChar + 1], &c2); + (void)base64toValue(base64String[indexOfFirstEncodedChar + 2], &c3); + decodedString[decodedIndex] = (c1 << 2) | (c2 >> 4); + decodedIndex++; + decodedString[decodedIndex] = ((c2 & 0x0f) << 4) | (c3 >> 2); + } +} + +BUFFER_HANDLE Base64_Decoder(const char* source) +{ + BUFFER_HANDLE result = NULL; + /*Codes_SRS_BASE64_06_008: [If source is NULL then Base64_Decode shall return NULL.]*/ + if (source) + { + size_t lengthOfSource = numberOfBase64Characters(source); + if ((lengthOfSource % 4) == 1) + { + /*Codes_SRS_BASE64_06_011: [If the source string has an invalid length for a base 64 encoded string then Base64_Decode shall return NULL.]*/ + LogError("Invalid length Base64 string!\r\n"); + } + else + { + if ((result = BUFFER_new()) == NULL) + { + /*Codes_SRS_BASE64_06_010: [If there is any memory allocation failure during the decode then Base64_Decode shall return NULL.]*/ + LogError("Could not create a buffer to decoding.\r\n"); + } + else + { + size_t sizeOfOutputBuffer = Base64decode_len(source); + /*Codes_SRS_BASE64_06_009: [If the string pointed to by source is zero length then the handle returned shall refer to a zero length buffer.]*/ + if (sizeOfOutputBuffer > 0) + { + if (BUFFER_pre_build(result, sizeOfOutputBuffer) != 0) + { + /*Codes_SRS_BASE64_06_010: [If there is any memory allocation failure during the decode then Base64_Decode shall return NULL.]*/ + LogError("Could not prebuild a buffer for base 64 decoding.\r\n"); + BUFFER_delete(result); + result = NULL; + } + else + { + Base64decode(BUFFER_u_char(result), source); + } + } + } + } + } + return result; +} + + +static STRING_HANDLE Base64_Encode_Internal(const unsigned char* source, size_t size) +{ + STRING_HANDLE result; + size_t neededSize = 0; + char* encoded; + size_t currentPosition = 0; + neededSize += (size == 0) ? (0) : ((((size - 1) / 3) + 1) * 4); + neededSize += 1; /*+1 because \0 at the end of the string*/ + /*Codes_SRS_BASE64_06_006: [If when allocating memory to produce the encoding a failure occurs then Base64_Encode shall return NULL.]*/ + encoded = (char*)malloc(neededSize); + if (encoded == NULL) + { + result = NULL; + LogError("Base64_Encode:: Allocation failed.\r\n"); + } + else + { + /*b0 b1(+1) b2(+2) + 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 + |----c1---| |----c2---| |----c3---| |----c4---| + */ + + size_t destinationPosition = 0; + while (size - currentPosition >= 3) + { + char c1 = base64char[source[currentPosition] >> 2]; + char c2 = base64char[ + ((source[currentPosition] & 3) << 4) | + (source[currentPosition + 1] >> 4) + ]; + char c3 = base64char[ + ((source[currentPosition + 1] & 0x0F) << 2) | + ((source[currentPosition + 2] >> 6) & 3) + ]; + char c4 = base64char[ + source[currentPosition + 2] & 0x3F + ]; + currentPosition += 3; + encoded[destinationPosition++] = c1; + encoded[destinationPosition++] = c2; + encoded[destinationPosition++] = c3; + encoded[destinationPosition++] = c4; + + } + if (size - currentPosition == 2) + { + char c1 = base64char[source[currentPosition] >> 2]; + char c2 = base64char[ + ((source[currentPosition] & 0x03) << 4) | + (source[currentPosition + 1] >> 4) + ]; + char c3 = base64b16[source[currentPosition + 1] & 0x0F]; + encoded[destinationPosition++] = c1; + encoded[destinationPosition++] = c2; + encoded[destinationPosition++] = c3; + encoded[destinationPosition++] = '='; + } + else if (size - currentPosition == 1) + { + char c1 = base64char[source[currentPosition] >> 2]; + char c2 = base64b8[source[currentPosition] & 0x03]; + encoded[destinationPosition++] = c1; + encoded[destinationPosition++] = c2; + encoded[destinationPosition++] = '='; + encoded[destinationPosition++] = '='; + } + + /*null terminating the string*/ + encoded[destinationPosition] = '\0'; + /*Codes_SRS_BASE64_06_007: [Otherwise Base64_Encode shall return a pointer to STRING, that string contains the base 64 encoding of input.]*/ + result = STRING_new_with_memory(encoded); + if (result == NULL) + { + free(encoded); + LogError("Base64_Encode:: Allocation failed for return value.\r\n"); + } + } + return result; +} + +STRING_HANDLE Base64_Encode_Bytes(const unsigned char* source, size_t size) +{ + STRING_HANDLE result; + /*Codes_SRS_BASE64_02_001: [If source is NULL then Base64_Encode_Bytes shall return NULL.] */ + if (source == NULL) + { + result = NULL; + } + /*Codes_SRS_BASE64_02_002: [If source is not NULL and size is zero, then Base64_Encode_Bytes shall produce an empty STRING_HANDLE.] */ + else if (size == 0) + { + result = STRING_new(); /*empty string*/ + } + else + { + result = Base64_Encode_Internal(source, size); + } + return result; +} + +STRING_HANDLE Base64_Encode(BUFFER_HANDLE input) +{ + STRING_HANDLE result; + /*the following will happen*/ + /*1. the "data" of the binary shall be "eaten" 3 characters at a time and produce 4 base64 encoded characters for as long as there are more than 3 characters still to process*/ + /*2. the remaining characters (1 or 2) shall be encoded.*/ + /*there's a level of assumption that 'a' corresponds to 0b000000 and that '_' corresponds to 0b111111*/ + /*the encoding will use the optional [=] or [==] at the end of the encoded string, so that other less standard aware libraries can do their work*/ + /*these are the bits of the 3 normal bytes to be encoded*/ + + /*Codes_SRS_BASE64_06_001: [If input is NULL then Base64_Encode shall return NULL.]*/ + if (input == NULL) + { + result = NULL; + LogError("Base64_Encode:: NULL input\r\n"); + } + else + { + size_t inputSize; + const unsigned char* inputBinary; + if ((BUFFER_content(input, &inputBinary) != 0) || + (BUFFER_size(input, &inputSize) != 0)) + { + result = NULL; + LogError("Base64_Encode:: BUFFER_routines failure.\r\n"); + } + else + { + result = Base64_Encode_Internal(inputBinary, inputSize); + } + } + return result; +} diff --git a/c/sharedutil/src/buffer.c b/c/sharedutil/src/buffer.c new file mode 100644 index 00000000..b16aa467 --- /dev/null +++ b/c/sharedutil/src/buffer.c @@ -0,0 +1,396 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// +// PUT NO INCLUDES BEFORE HERE +// +#include +#ifdef _CRTDBG_MAP_ALLOC +#include +#endif +#include "gballoc.h" + +#include +#include +// +// PUT NO CLIENT LIBRARY INCLUDES BEFORE HERE +// + +#include "buffer_.h" +#include "iot_logging.h" + +typedef struct BUFFER_TAG +{ + unsigned char* buffer; + size_t size; +}BUFFER; + +/* Codes_SRS_BUFFER_07_001: [BUFFER_new shall allocate a BUFFER_HANDLE that will contain a NULL unsigned char*.] */ +BUFFER_HANDLE BUFFER_new(void) +{ + BUFFER* temp = (BUFFER*)malloc(sizeof(BUFFER)); + /* Codes_SRS_BUFFER_07_002: [BUFFER_new shall return NULL on any error that occurs.] */ + if (temp != NULL) + { + temp->buffer = NULL; + temp->size = 0; + } + return (BUFFER_HANDLE)temp; +} + +BUFFER_HANDLE BUFFER_create(const unsigned char* source, size_t size) +{ + BUFFER* result; + /*Codes_SRS_BUFFER_02_001: [If source is NULL then BUFFER_create shall return NULL.]*/ + if (source == NULL) + { + result = NULL; + } + else + { + /*Codes_SRS_BUFFER_02_002: [Otherwise, BUFFER_create shall allocate memory to hold size bytes and shall copy from source size bytes into the newly allocated memory.] */ + result = (BUFFER*)malloc(sizeof(BUFFER)); + if (result == NULL) + { + /*Codes_SRS_BUFFER_02_003: [If allocating memory fails, then BUFFER_create shall return NULL.] */ + /*fallthrough*/ + } + else + { + result->buffer = (unsigned char*)malloc(size); + if (result->buffer == NULL) + { + /*Codes_SRS_BUFFER_02_003: [If allocating memory fails, then BUFFER_create shall return NULL.]*/ + free(result); + result = NULL; + } + else + { + /*Codes_SRS_BUFFER_02_004: [Otherwise, BUFFER_create shall return a non-NULL handle.] */ + memcpy(result->buffer, source, size); + result->size = size; + } + } + } + return (BUFFER_HANDLE)result; +} + +/* Codes_SRS_BUFFER_07_003: [BUFFER_delete shall delete the data associated with the BUFFER_HANDLE along with the Buffer.] */ +void BUFFER_delete(BUFFER_HANDLE handle) +{ + /* Codes_SRS_BUFFER_07_004: [BUFFER_delete shall not delete any BUFFER_HANDLE that is NULL.] */ + if (handle != NULL) + { + BUFFER* b = (BUFFER*)handle; + if (b->buffer != NULL) + { + /* Codes_SRS_BUFFER_07_003: [BUFFER_delete shall delete the data associated with the BUFFER_HANDLE along with the Buffer.] */ + free(b->buffer); + } + free(b); + } +} + +/*return 0 if the buffer was copied*/ +/*else return different than zero*/ +/* Codes_SRS_BUFFER_07_008: [BUFFER_build allocates size_t bytes, copies the unsigned char* into the buffer and returns zero on success.] */ +int BUFFER_build(BUFFER_HANDLE handle, const unsigned char* source, size_t size) +{ + int result; + if (handle == NULL) + { + /* Codes_SRS_BUFFER_07_009: [BUFFER_build shall return nonzero if handle is NULL ] */ + result = __LINE__; + } + /* Codes_SRS_BUFFER_01_002: [The size argument can be zero, in which case the underlying buffer held by the buffer instance shall be freed.] */ + else if (size == 0) + { + /* Codes_SRS_BUFFER_01_003: [If size is zero, source can be NULL.] */ + BUFFER* b = (BUFFER*)handle; + free(b->buffer); + b->buffer = NULL; + b->size = 0; + + result = 0; + } + else + { + if (source == NULL) + { + /* Codes_SRS_BUFFER_01_001: [If size is positive and source is NULL, BUFFER_build shall return nonzero] */ + result = __LINE__; + } + else + { + BUFFER* b = (BUFFER*)handle; + /* Codes_SRS_BUFFER_07_011: [BUFFER_build shall overwrite previous contents if the buffer has been previously allocated.] */ + unsigned char* newBuffer = (unsigned char*)realloc(b->buffer, size); + if (newBuffer == NULL) + { + /* Codes_SRS_BUFFER_07_010: [BUFFER_build shall return nonzero if any error is encountered.] */ + result = __LINE__; + } + else + { + b->buffer = newBuffer; + b->size = size; + /* Codes_SRS_BUFFER_01_002: [The size argument can be zero, in which case nothing shall be copied from source.] */ + (void)memcpy(b->buffer, source, size); + + result = 0; + } + } + } + + return result; +} + +/*return 0 if the buffer was pre-build(that is, had its space allocated)*/ +/*else return different than zero*/ +/* Codes_SRS_BUFFER_07_005: [BUFFER_pre_build allocates size_t bytes of BUFFER_HANDLE and returns zero on success.] */ +int BUFFER_pre_build(BUFFER_HANDLE handle, size_t size) +{ + int result; + if (handle == NULL) + { + /* Codes_SRS_BUFFER_07_006: [If handle is NULL or size is 0 then BUFFER_pre_build shall return a nonzero value.] */ + result = __LINE__; + } + else if (size == 0) + { + /* Codes_SRS_BUFFER_07_006: [If handle is NULL or size is 0 then BUFFER_pre_build shall return a nonzero value.] */ + result = __LINE__; + } + else + { + BUFFER* b = (BUFFER*)handle; + if (b->buffer != NULL) + { + /* Codes_SRS_BUFFER_07_007: [BUFFER_pre_build shall return nonzero if the buffer has been previously allocated and is not NULL.] */ + result = __LINE__; + } + else + { + if ((b->buffer = (unsigned char*)malloc(size)) == NULL) + { + /* Codes_SRS_BUFFER_07_013: [BUFFER_pre_build shall return nonzero if any error is encountered.] */ + result = __LINE__; + } + else + { + b->size = size; + result = 0; + } + } + } + return result; +} + +/* Codes_SRS_BUFFER_07_019: [BUFFER_content shall return the data contained within the BUFFER_HANDLE.] */ +int BUFFER_content(BUFFER_HANDLE handle, const unsigned char** content) +{ + int result; + if ((handle == NULL) || (content == NULL)) + { + /* Codes_SRS_BUFFER_07_020: [If the handle and/or content*is NULL BUFFER_content shall return nonzero.] */ + result = __LINE__; + } + else + { + BUFFER* b = (BUFFER*)handle; + *content = b->buffer; + result = 0; + } + return result; +} + +/*return 0 if everything went ok and whatever was built in the buffer was unbuilt*/ +/* Codes_SRS_BUFFER_07_012: [BUFFER_unbuild shall clear the underlying unsigned char* data associated with the BUFFER_HANDLE this will return zero on success.] */ +extern int BUFFER_unbuild(BUFFER_HANDLE handle) +{ + int result; + if (handle == NULL) + { + /* Codes_SRS_BUFFER_07_014: [BUFFER_unbuild shall return a nonzero value if BUFFER_HANDLE is NULL.] */ + result = __LINE__; + } + else + { + BUFFER* b = (BUFFER*)handle; + if (b->buffer != NULL) + { + free(b->buffer); + b->buffer = NULL; + b->size = 0; + result = 0; + } + else + { + /* Codes_SRS_BUFFER_07_015: [BUFFER_unbuild shall return a nonzero value if the unsigned char* referenced by BUFFER_HANDLE is NULL.] */ + result = __LINE__; + } + } + return result; +} + +/* Codes_SRS_BUFFER_07_016: [BUFFER_enlarge shall increase the size of the unsigned char* referenced by BUFFER_HANDLE.] */ +int BUFFER_enlarge(BUFFER_HANDLE handle, size_t enlargeSize) +{ + int result; + if (handle == NULL) + { + /* Codes_SRS_BUFFER_07_017: [BUFFER_enlarge shall return a nonzero result if any parameters are NULL or zero.] */ + result = __LINE__; + } + else if (enlargeSize == 0) + { + /* Codes_SRS_BUFFER_07_017: [BUFFER_enlarge shall return a nonzero result if any parameters are NULL or zero.] */ + result = __LINE__; + } + else + { + BUFFER* b = (BUFFER*)handle; + unsigned char* temp = (unsigned char*)realloc(b->buffer, b->size + enlargeSize); + if (temp == NULL) + { + /* Codes_SRS_BUFFER_07_018: [BUFFER_enlarge shall return a nonzero result if any error is encountered.] */ + result = __LINE__; + } + else + { + b->buffer = temp; + b->size += enlargeSize; + result = 0; + } + } + return result; +} + +/* Codes_SRS_BUFFER_07_021: [BUFFER_size shall place the size of the associated buffer in the size variable and return zero on success.] */ +int BUFFER_size(BUFFER_HANDLE handle, size_t* size) +{ + int result; + if ((handle == NULL) || (size == NULL)) + { + /* Codes_SRS_BUFFER_07_022: [BUFFER_size shall return a nonzero value for any error that is encountered.] */ + result = __LINE__; + } + else + { + BUFFER* b = (BUFFER*)handle; + *size = b->size; + result = 0; + } + return result; +} + +/* Codes_SRS_BUFFER_07_024: [BUFFER_append concatenates b2 onto b1 without modifying b2 and shall return zero on success.] */ +int BUFFER_append(BUFFER_HANDLE handle1, BUFFER_HANDLE handle2) +{ + int result; + if ( (handle1 == NULL) || (handle2 == NULL) || (handle1 == handle2) ) + { + /* Codes_SRS_BUFFER_07_023: [BUFFER_append shall return a nonzero upon any error that is encountered.] */ + result = __LINE__; + } + else + { + BUFFER* b1 = (BUFFER*)handle1; + BUFFER* b2 = (BUFFER*)handle2; + if (b1->buffer == NULL) + { + /* Codes_SRS_BUFFER_07_023: [BUFFER_append shall return a nonzero upon any error that is encountered.] */ + result = __LINE__; + } + else if (b2->buffer == NULL) + { + /* Codes_SRS_BUFFER_07_023: [BUFFER_append shall return a nonzero upon any error that is encountered.] */ + result = __LINE__; + } + else + { + unsigned char* temp = (unsigned char*)realloc(b1->buffer, b1->size + b2->size); + if (temp == NULL) + { + /* Codes_SRS_BUFFER_07_023: [BUFFER_append shall return a nonzero upon any error that is encountered.] */ + result = __LINE__; + } + else + { + b1->buffer = temp; + // Append the BUFFER + memcpy(&b1->buffer[b1->size], b2->buffer, b2->size); + b1->size += b2->size; + result = 0; + } + } + } + return result; +} + +/* Codes_SRS_BUFFER_07_025: [BUFFER_u_char shall return a pointer to the underlying unsigned char*.] */ +unsigned char* BUFFER_u_char(BUFFER_HANDLE handle) +{ + unsigned char* result; + if (handle == NULL) + { + /* Codes_SRS_BUFFER_07_026: [BUFFER_u_char shall return NULL for any error that is encountered.] */ + result = NULL; + } + else + { + BUFFER* b = (BUFFER*)handle; + result = b->buffer; + } + return result; +} + +/* Codes_SRS_BUFFER_07_027: [BUFFER_length shall return the size of the underlying buffer.] */ +size_t BUFFER_length(BUFFER_HANDLE handle) +{ + size_t result; + if (handle == NULL) + { + /* Codes_SRS_BUFFER_07_028: [BUFFER_length shall return zero for any error that is encountered.] */ + result = 0; + } + else + { + BUFFER* b = (BUFFER*)handle; + result = b->size; + } + return result; +} + +BUFFER_HANDLE BUFFER_clone(BUFFER_HANDLE handle) +{ + BUFFER_HANDLE result; + if (handle == NULL) + { + result = NULL; + } + else + { + BUFFER* suppliedBuff = (BUFFER*)handle; + BUFFER* b = (BUFFER*)malloc(sizeof(BUFFER) ); + if (b != NULL) + { + if ( (b->buffer = (unsigned char*)malloc(suppliedBuff->size) ) == NULL) + { + free(b); + result = NULL; + } + else + { + memcpy(b->buffer, suppliedBuff->buffer, suppliedBuff->size); + b->size = suppliedBuff->size; + result = (BUFFER_HANDLE)b; + } + } + else + { + result = NULL; + } + } + return result; +} diff --git a/c/sharedutil/src/crt_abstractions.c b/c/sharedutil/src/crt_abstractions.c new file mode 100644 index 00000000..26459f9d --- /dev/null +++ b/c/sharedutil/src/crt_abstractions.c @@ -0,0 +1,390 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#define __STDC_WANT_LIB_EXT1__ 1 + +#include +#ifdef _CRTDBG_MAP_ALLOC +#include +#endif +#include "gballoc.h" + +#include "crt_abstractions.h" +#include "errno.h" +#include +#include + +#ifdef _MSC_VER +#else + +#include "stdarg.h" + +/*Codes_SRS_CRT_ABSTRACTIONS_99_008: [strcat_s shall append the src to dst and terminates the resulting string with a null character.]*/ +int strcat_s(char* dst, size_t dstSizeInBytes, const char* src) +{ + int result; + /*Codes_SRS_CRT_ABSTRACTIONS_99_004: [If dst is NULL or unterminated, the error code returned shall be EINVAL & dst shall not be modified.]*/ + if (dst == NULL) + { + result = EINVAL; + } + /*Codes_SRS_CRT_ABSTRACTIONS_99_005: [If src is NULL, the error code returned shall be EINVAL and dst[0] shall be set to 0.]*/ + else if (src == NULL) + { + dst[0] = '\0'; + result = EINVAL; + } + else + { + /*Codes_SRS_CRT_ABSTRACTIONS_99_006: [If the dstSizeInBytes is 0 or smaller than the required size for dst & src, the error code returned shall be ERANGE & dst[0] set to 0.]*/ + if (dstSizeInBytes == 0) + { + result = ERANGE; + dst[0] = '\0'; + } + else + { + size_t dstStrLen = 0; +#ifdef __STDC_LIB_EXT1__ + dstStrLen = strnlen_s(dst, dstSizeInBytes); +#else + size_t i; + for(i=0; (i < dstSizeInBytes) && (dst[i]!= '\0'); i++) + { + } + dstStrLen = i; +#endif + /*Codes_SRS_CRT_ABSTRACTIONS_99_004: [If dst is NULL or unterminated, the error code returned shall be EINVAL & dst shall not be modified.]*/ + if (dstSizeInBytes == dstStrLen) /* this means the dst string is not terminated*/ + { + result = EINVAL; + } + else + { + /*Codes_SRS_CRT_ABSTRACTIONS_99_009: [The initial character of src shall overwrite the terminating null character of dst.]*/ + (void)strncpy(&dst[dstStrLen], src, dstSizeInBytes - dstStrLen); + /*Codes_SRS_CRT_ABSTRACTIONS_99_006: [If the dstSizeInBytes is 0 or smaller than the required size for dst & src, the error code returned shall be ERANGE & dst[0] set to 0.]*/ + if (dst[dstSizeInBytes-1] != '\0') + { + dst[0] = '\0'; + result = ERANGE; + } + else + { + /*Codes_SRS_CRT_ABSTRACTIONS_99_003: [strcat_s shall return Zero upon success.]*/ + result = 0; + } + } + } + } + + return result; +} + +/*Codes_SRS_CRT_ABSTRACTIONS_99_025: [strncpy_s shall copy the first N characters of src to dst, where N is the lesser of MaxCount and the length of src.]*/ +int strncpy_s(char* dst, size_t dstSizeInBytes, const char* src, size_t maxCount) +{ + int result; + int truncationFlag = 0; + /*Codes_SRS_CRT_ABSTRACTIONS_99_020: [If dst is NULL, the error code returned shall be EINVAL and dst shall not be modified.]*/ + if (dst == NULL) + { + result = EINVAL; + } + /*Codes_SRS_CRT_ABSTRACTIONS_99_021: [If src is NULL, the error code returned shall be EINVAL and dst[0] shall be set to 0.]*/ + else if (src == NULL) + { + dst[0] = '\0'; + result = EINVAL; + } + /*Codes_SRS_CRT_ABSTRACTIONS_99_022: [If the dstSizeInBytes is 0, the error code returned shall be EINVAL and dst shall not be modified.]*/ + else if (dstSizeInBytes == 0) + { + result = EINVAL; + } + else + { + size_t srcLength = strlen(src); + if (maxCount != _TRUNCATE) + { + /*Codes_SRS_CRT_ABSTRACTIONS_99_041: [If those N characters will fit within dst (whose size is given as dstSizeInBytes) and still leave room for a null terminator, then those characters shall be copied and a terminating null is appended; otherwise, strDest[0] is set to the null character and ERANGE error code returned.]*/ + if (srcLength > maxCount) + { + srcLength = maxCount; + } + + /*Codes_SRS_CRT_ABSTRACTIONS_99_023: [If dst is not NULL & dstSizeInBytes is smaller than the required size for the src string, the error code returned shall be ERANGE and dst[0] shall be set to 0.]*/ + if (srcLength + 1 > dstSizeInBytes) + { + dst[0] = '\0'; + result = ERANGE; + } + else + { + (void)strncpy(dst, src, srcLength); + dst[srcLength] = '\0'; + /*Codes_SRS_CRT_ABSTRACTIONS_99_018: [strncpy_s shall return Zero upon success]*/ + result = 0; + } + } + /*Codes_SRS_CRT_ABSTRACTIONS_99_026: [If MaxCount is _TRUNCATE (defined as -1), then as much of src as will fit into dst shall be copied while still leaving room for the terminating null to be appended.]*/ + else + { + if (srcLength + 1 > dstSizeInBytes ) + { + srcLength = dstSizeInBytes - 1; + truncationFlag = 1; + } + (void)strncpy(dst, src, srcLength); + dst[srcLength] = '\0'; + result = 0; + } + } + + /*Codes_SRS_CRT_ABSTRACTIONS_99_019: [If truncation occurred as a result of the copy, the error code returned shall be STRUNCATE.]*/ + if (truncationFlag == 1) + { + result = STRUNCATE; + } + + return result; +} + +/* Codes_SRS_CRT_ABSTRACTIONS_99_016: [strcpy_s shall copy the contents in the address of src, including the terminating null character, to the location that's specified by dst.]*/ +int strcpy_s(char* dst, size_t dstSizeInBytes, const char* src) +{ + int result; + + /* Codes_SRS_CRT_ABSTRACTIONS_99_012: [If dst is NULL, the error code returned shall be EINVAL & dst shall not be modified.]*/ + if (dst == NULL) + { + result = EINVAL; + } + /* Codes_SRS_CRT_ABSTRACTIONS_99_013: [If src is NULL, the error code returned shall be EINVAL and dst[0] shall be set to 0.]*/ + else if (src == NULL) + { + dst[0] = '\0'; + result = EINVAL; + } + /* Codes_SRS_CRT_ABSTRACTIONS_99_014: [If the dstSizeInBytes is 0 or smaller than the required size for the src string, the error code returned shall be ERANGE & dst[0] set to 0.]*/ + else if (dstSizeInBytes == 0) + { + dst[0] = '\0'; + result = ERANGE; + } + else + { + size_t neededBuffer = strlen(src); + /* Codes_SRS_CRT_ABSTRACTIONS_99_014: [If the dstSizeInBytes is 0 or smaller than the required size for the src string, the error code returned shall be ERANGE & dst[0] set to 0.]*/ + if (neededBuffer + 1 > dstSizeInBytes) + { + dst[0] = '\0'; + result = ERANGE; + } + else + { + memcpy(dst, src, neededBuffer + 1); + /*Codes_SRS_CRT_ABSTRACTIONS_99_011: [strcpy_s shall return Zero upon success]*/ + result = 0; + } + } + + return result; +} + +/*Codes_SRS_CRT_ABSTRACTIONS_99_029: [The sprintf_s function shall format and store series of characters and values in dst. Each argument (if any) is converted and output according to the corresponding Format Specification in the format variable.]*/ +/*Codes_SRS_CRT_ABSTRACTIONS_99_031: [A null character is appended after the last character written.]*/ +int sprintf_s(char* dst, size_t dstSizeInBytes, const char* format, ...) +{ + int result; + /*Codes_SRS_CRT_ABSTRACTIONS_99_028: [If dst or format is a null pointer, sprintf_s shall return -1 and set errno to EINVAL]*/ + if ((dst == NULL) || + (format == NULL)) + { + errno = EINVAL; + result = -1; + } + else + { + /*Codes_SRS_CRT_ABSTRACTIONS_99_033: [sprintf_s shall check the format string for valid formatting characters. If the check fails, the function returns -1.]*/ + +#if defined _MSC_VER +#error crt_abstractions is not provided for Microsoft Compilers +#else + /*not Microsoft compiler... */ +#if defined __STDC_VERSION__ +#if ((__STDC_VERSION__ == 199901L) || ( __STDC_VERSION__ == 201112L)) + /*C99 compiler*/ + va_list args; + va_start(args, format); + /*Codes_SRS_CRT_ABSTRACTIONS_99_027: [sprintf_s shall return the number of characters stored in dst upon success. This number shall not include the terminating null character.]*/ + result = vsnprintf(dst, dstSizeInBytes, format, args); + va_end(args); + + /*C99: Thus, the null-terminated output has been completely written if and only if the returned value is nonnegative and less than n*/ + if (result < 0) + { + result = -1; + } + else if ((size_t)result >= dstSizeInBytes) + { + /*Codes_SRS_CRT_ABSTRACTIONS_99_034: [If the dst buffer is too small for the text being printed, then dst is set to an empty string and the function shall return -1.]*/ + dst[0] = '\0'; + result = -1; + } + else + { + /*do nothing, all is fine*/ + } +#else +#error STDC_VERSION defined, but of unknown value; unable to sprinf_s, or provide own implementation +#endif +#else +#error for STDC_VERSION undefined (assumed C89), provide own implementation of sprintf_s +#endif +#endif + } + return result; +} +#endif /* _MSC_VER */ + +/*Codes_SRS_CRT_ABSTRACTIONS_99_038: [mallocAndstrcpy_s shall allocate memory for destination buffer to fit the string in the source parameter.]*/ +int mallocAndStrcpy_s(char** destination, const char* source) +{ + int result; + /*Codes_SRS_CRT_ABSTRACTIONS_99_036: [destination parameter or source parameter is NULL, the error code returned shall be EINVAL and destination shall not be modified.]*/ + if ((destination == NULL) || (source == NULL)) + { + /*If strDestination or strSource is a null pointer[...]these functions return EINVAL */ + result = EINVAL; + } + else + { + size_t l = strlen(source); + *destination = (char*)malloc(l + 1); + /*Codes_SRS_CRT_ABSTRACTIONS_99_037: [Upon failure to allocate memory for the destination, the function will return ENOMEM.]*/ + if (*destination == NULL) + { + result = ENOMEM; + } + else + { + /*Codes_SRS_CRT_ABSTRACTIONS_99_039: [mallocAndstrcpy_s shall copy the contents in the address source, including the terminating null character into location specified by the destination pointer after the memory allocation.]*/ + int temp = strcpy_s(*destination, l + 1, source); + if (temp < 0) /*strcpy_s error*/ + { + free(*destination); + *destination = NULL; + result = temp; + } + else + { + /*Codes_SRS_CRT_ABSTRACTIONS_99_035: [mallocAndstrcpy_s shall return Zero upon success]*/ + result = 0; + } + } + } + return result; +} + +/*takes "value" and transforms it into a decimal string*/ +/*10 => "10"*/ +/*return 0 when everything went ok*/ +/*Codes_SRS_CRT_ABSTRACTIONS_02_001: [unsignedIntToString shall convert the parameter value to its decimal representation as a string in the buffer indicated by parameter destination having the size indicated by parameter destinationSize.] */ +int unsignedIntToString(char* destination, size_t destinationSize, unsigned int value) +{ + int result; + size_t pos; + /*the below loop gets the number in reverse order*/ + /*Codes_SRS_CRT_ABSTRACTIONS_02_003: [If destination is NULL then unsignedIntToString shall fail.] */ + /*Codes_SRS_CRT_ABSTRACTIONS_02_002: [If the conversion fails for any reason (for example, insufficient buffer space), a non-zero return value shall be supplied and unsignedIntToString shall fail.] */ + if ( + (destination == NULL) || + (destinationSize < 2) /*because the smallest number is '0\0' which requires 2 characters*/ + ) + { + result = __LINE__; + } + else + { + pos = 0; + do + { + destination[pos++] = '0' + (value % 10); + value /= 10; + } while ((value > 0) && (pos < (destinationSize-1))); + + if (value == 0) + { + size_t w; + destination[pos] = '\0'; + /*all converted and they fit*/ + for (w = 0; w <= (pos-1) >> 1; w++) + { + char temp; + temp = destination[w]; + destination[w] = destination[pos - 1 - w]; + destination[pos -1 - w] = temp; + } + /*Codes_SRS_CRT_ABSTRACTIONS_02_004: [If the conversion has been successfull then unsignedIntToString shall return 0.] */ + result = 0; + } + else + { + /*Codes_SRS_CRT_ABSTRACTIONS_02_002: [If the conversion fails for any reason (for example, insufficient buffer space), a non-zero return value shall be supplied and unsignedIntToString shall fail.] */ + result = __LINE__; + } + } + return result; +} + +/*takes "value" and transforms it into a decimal string*/ +/*10 => "10"*/ +/*return 0 when everything went ok*/ +/*Codes_SRS_CRT_ABSTRACTIONS_02_001: [unsignedIntToString shall convert the parameter value to its decimal representation as a string in the buffer indicated by parameter destination having the size indicated by parameter destinationSize.] */ +int size_tToString(char* destination, size_t destinationSize, size_t value) +{ + int result; + size_t pos; + /*the below loop gets the number in reverse order*/ + /*Codes_SRS_CRT_ABSTRACTIONS_02_003: [If destination is NULL then unsignedIntToString shall fail.] */ + /*Codes_SRS_CRT_ABSTRACTIONS_02_002: [If the conversion fails for any reason (for example, insufficient buffer space), a non-zero return value shall be supplied and unsignedIntToString shall fail.] */ + if ( + (destination == NULL) || + (destinationSize < 2) /*because the smallest number is '0\0' which requires 2 characters*/ + ) + { + result = __LINE__; + } + else + { + pos = 0; + do + { + destination[pos++] = '0' + (value % 10); + value /= 10; + } while ((value > 0) && (pos < (destinationSize - 1))); + + if (value == 0) + { + size_t w; + destination[pos] = '\0'; + /*all converted and they fit*/ + for (w = 0; w <= (pos - 1) >> 1; w++) + { + char temp; + temp = destination[w]; + destination[w] = destination[pos - 1 - w]; + destination[pos - 1 - w] = temp; + } + /*Codes_SRS_CRT_ABSTRACTIONS_02_004: [If the conversion has been successfull then unsignedIntToString shall return 0.] */ + result = 0; + } + else + { + /*Codes_SRS_CRT_ABSTRACTIONS_02_002: [If the conversion fails for any reason (for example, insufficient buffer space), a non-zero return value shall be supplied and unsignedIntToString shall fail.] */ + result = __LINE__; + } + } + return result; +} diff --git a/c/sharedutil/src/doublylinkedlist.c b/c/sharedutil/src/doublylinkedlist.c new file mode 100644 index 00000000..6e629606 --- /dev/null +++ b/c/sharedutil/src/doublylinkedlist.c @@ -0,0 +1,107 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include "doublylinkedlist.h" + +void +DList_InitializeListHead( + PDLIST_ENTRY ListHead +) +{ + /* Codes_SRS_DLIST_06_005: [DList_InitializeListHead will initialize the Flink & Blink to the address of the DLIST_ENTRY.] */ + ListHead->Flink = ListHead->Blink = ListHead; + return; +} + +int +DList_IsListEmpty( + const PDLIST_ENTRY ListHead +) +{ + /* Codes_SRS_DLIST_06_003: [DList_IsListEmpty shall return a non-zero value if there are no DLIST_ENTRY's on this list other than the list head.] */ + /* Codes_SRS_DLIST_06_004: [DList_IsListEmpty shall return 0 if there is one or more items in the list.] */ + return (ListHead->Flink == ListHead); +} + +int +DList_RemoveEntryList( + PDLIST_ENTRY Entry +) +{ + /* Codes_SRS_DLIST_06_008: [DList_RemoveEntryList shall remove a listEntry from whatever list it is properly part of.] */ + /* Codes_SRS_DLIST_06_009: [The remaining list is properly formed.] */ + /* Codes_SRS_DLIST_06_010: [DList_RemoveEntryList shall return non-zero if the remaining list is empty.] */ + /* Codes_SRS_DLIST_06_011: [DList_RemoveEntryList shall return zero if the remaining list is NOT empty.] */ + PDLIST_ENTRY Blink; + PDLIST_ENTRY Flink; + + Flink = Entry->Flink; + Blink = Entry->Blink; + Blink->Flink = Flink; + Flink->Blink = Blink; + return (Flink == Blink); +} + +PDLIST_ENTRY +DList_RemoveHeadList( + PDLIST_ENTRY ListHead +) +{ + /* Codes_SRS_DLIST_06_012: [DList_RemoveHeadList removes the oldest entry from the list defined by the listHead parameter and returns a pointer to that entry.] */ + /* Codes_SRS_DLIST_06_013: [DList_RemoveHeadList shall return listHead if that's the only item in the list.] */ + + PDLIST_ENTRY Flink; + PDLIST_ENTRY Entry; + + Entry = ListHead->Flink; + Flink = Entry->Flink; + ListHead->Flink = Flink; + Flink->Blink = ListHead; + return Entry; +} + + + +void +DList_InsertTailList( + PDLIST_ENTRY ListHead, + PDLIST_ENTRY Entry +) +{ + PDLIST_ENTRY Blink; + + /* Codes_SRS_DLIST_06_006: [DListInsertTailList shall place the DLIST_ENTRY at the end of the list defined by the listHead parameter.] */ + Blink = ListHead->Blink; + Entry->Flink = ListHead; + Entry->Blink = Blink; + Blink->Flink = Entry; + ListHead->Blink = Entry; + return; +} + + +void +DList_AppendTailList( + PDLIST_ENTRY ListHead, + PDLIST_ENTRY ListToAppend +) +{ + /* Codes_SRS_DLIST_06_007: [DList_AppendTailList shall place the list defined by listToAppend at the end of the list defined by the listHead parameter.] */ + PDLIST_ENTRY ListEnd = ListHead->Blink; + + ListHead->Blink->Flink = ListToAppend; + ListHead->Blink = ListToAppend->Blink; + ListToAppend->Blink->Flink = ListHead; + ListToAppend->Blink = ListEnd; + return; +} + + +/*Codes_SRS_DLIST_02_002: [DList_InsertHeadList inserts a singular entry in the list having as head listHead after "head".]*/ +void DList_InsertHeadList(PDLIST_ENTRY listHead, PDLIST_ENTRY entry) +{ + entry->Blink = listHead; + entry->Flink = listHead->Flink; + listHead->Flink->Blink = entry; + listHead->Flink = entry; +} diff --git a/c/sharedutil/src/gballoc.c b/c/sharedutil/src/gballoc.c new file mode 100644 index 00000000..b0e2d59d --- /dev/null +++ b/c/sharedutil/src/gballoc.c @@ -0,0 +1,387 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include +#ifdef _CRTDBG_MAP_ALLOC +#include +#endif +#include "lock.h" +#include "iot_logging.h" +#include + +#ifndef SIZE_MAX +#define SIZE_MAX ((size_t)~(size_t)0) +#endif + +typedef struct ALLOCATION_TAG +{ + size_t size; + void* ptr; + void* next; +} ALLOCATION; + +typedef enum GBALLOC_STATE_TAG +{ + GBALLOC_STATE_INIT, + GBALLOC_STATE_NOT_INIT +} GBALLOC_STATE; + +static ALLOCATION* head = NULL; +static size_t totalSize = 0; +static size_t maxSize = 0; +static GBALLOC_STATE gballocState = GBALLOC_STATE_NOT_INIT; + +static LOCK_HANDLE gballocThreadSafeLock = NULL; + +int gballoc_init(void) +{ + int result; + + if (gballocState != GBALLOC_STATE_NOT_INIT) + { + /* Codes_SRS_GBALLOC_01_025: [Init after Init shall fail and return a non-zero value.] */ + result = __LINE__; + } + /* Codes_SRS_GBALLOC_01_026: [gballoc_Init shall create a lock handle that will be used to make the other gballoc APIs thread-safe.] */ + else if ((gballocThreadSafeLock = Lock_Init()) == NULL) + { + /* Codes_SRS_GBALLOC_01_027: [If the Lock creation fails, gballoc_init shall return a non-zero value.]*/ + result = __LINE__; + } + else + { + gballocState = GBALLOC_STATE_INIT; + + /* Codes_ SRS_GBALLOC_01_002: [Upon initialization the total memory used and maximum total memory used tracked by the module shall be set to 0.] */ + totalSize = 0; + maxSize = 0; + + /* Codes_SRS_GBALLOC_01_024: [gballoc_init shall initialize the gballoc module and return 0 upon success.] */ + result = 0; + } + + return result; +} + +void gballoc_deinit(void) +{ + if (gballocState == GBALLOC_STATE_INIT) + { + /* Codes_SRS_GBALLOC_01_028: [gballoc_deinit shall free all resources allocated by gballoc_init.] */ + (void)Lock_Deinit(gballocThreadSafeLock); + } + + gballocState = GBALLOC_STATE_NOT_INIT; +} + +void* gballoc_malloc(size_t size) +{ + void* result; + + if (gballocState != GBALLOC_STATE_INIT) + { + /* Codes_SRS_GBALLOC_01_039: [If gballoc was not initialized gballoc_malloc shall simply call malloc without any memory tracking being performed.] */ + result = malloc(size); + } + /* Codes_SRS_GBALLOC_01_030: [gballoc_malloc shall ensure thread safety by using the lock created by gballoc_Init.] */ + else if (LOCK_OK != Lock(gballocThreadSafeLock)) + { + /* Codes_SRS_GBALLOC_01_048: [If acquiring the lock fails, gballoc_malloc shall return NULL.] */ + LogError("Failed to get the Lock.\r\n"); + result = NULL; + } + else + { + ALLOCATION* allocation = (ALLOCATION*)malloc(sizeof(ALLOCATION)); + if (allocation == NULL) + { + result = NULL; + } + else + { + /* Codes_SRS_GBALLOC_01_003: [gb_malloc shall call the C99 malloc function and return its result.] */ + result = malloc(size); + if (result == NULL) + { + /* Codes_SRS_GBALLOC_01_012: [When the underlying malloc call fails, gballoc_malloc shall return NULL and size should not be counted towards total memory used.] */ + free(allocation); + } + else + { + /* Codes_SRS_GBALLOC_01_004: [If the underlying malloc call is successful, gb_malloc shall increment the total memory used with the amount indicated by size.] */ + allocation->ptr = result; + allocation->size = size; + allocation->next = head; + head = allocation; + + totalSize += size; + /* Codes_SRS_GBALLOC_01_011: [The maximum total memory used shall be the maximum of the total memory used at any point.] */ + if (maxSize < totalSize) + { + maxSize = totalSize; + } + } + } + + (void)Unlock(gballocThreadSafeLock); + } + + return result; +} + +void* gballoc_calloc(size_t nmemb, size_t size) +{ + void* result; + + if (gballocState != GBALLOC_STATE_INIT) + { + /* Codes_SRS_GBALLOC_01_040: [If gballoc was not initialized gballoc_calloc shall simply call calloc without any memory tracking being performed.] */ + result = calloc(nmemb, size); + } + /* Codes_SRS_GBALLOC_01_031: [gballoc_calloc shall ensure thread safety by using the lock created by gballoc_Init] */ + else if (LOCK_OK != Lock(gballocThreadSafeLock)) + { + /* Codes_SRS_GBALLOC_01_046: [If acquiring the lock fails, gballoc_calloc shall return NULL.] */ + LogError("Failed to get the Lock.\r\n"); + result = NULL; + } + else + { + ALLOCATION* allocation = (ALLOCATION*)malloc(sizeof(ALLOCATION)); + if (allocation == NULL) + { + result = NULL; + } + else + { + /* Codes_SRS_GBALLOC_01_020: [gballoc_calloc shall call the C99 calloc function and return its result.] */ + result = calloc(nmemb, size); + if (result == NULL) + { + /* Codes_SRS_GBALLOC_01_022: [When the underlying calloc call fails, gballoc_calloc shall return NULL and size should not be counted towards total memory used.] */ + free(allocation); + } + else + { + /* Codes_SRS_GBALLOC_01_021: [If the underlying calloc call is successful, gballoc_calloc shall increment the total memory used with nmemb*size.] */ + allocation->ptr = result; + allocation->size = nmemb * size; + allocation->next = head; + head = allocation; + + totalSize += allocation->size; + /* Codes_SRS_GBALLOC_01_011: [The maximum total memory used shall be the maximum of the total memory used at any point.] */ + if (maxSize < totalSize) + { + maxSize = totalSize; + } + } + } + + (void)Unlock(gballocThreadSafeLock); + } + + return result; +} + +void* gballoc_realloc(void* ptr, size_t size) +{ + ALLOCATION* curr; + void* result; + ALLOCATION* allocation = NULL; + + if (gballocState != GBALLOC_STATE_INIT) + { + /* Codes_SRS_GBALLOC_01_041: [If gballoc was not initialized gballoc_realloc shall shall simply call realloc without any memory tracking being performed.] */ + result = realloc(ptr, size); + } + /* Codes_SRS_GBALLOC_01_032: [gballoc_realloc shall ensure thread safety by using the lock created by gballoc_Init.] */ + else if (LOCK_OK != Lock(gballocThreadSafeLock)) + { + /* Codes_SRS_GBALLOC_01_047: [If acquiring the lock fails, gballoc_realloc shall return NULL.] */ + LogError("Failed to get the Lock.\r\n"); + result = NULL; + } + else + { + if (ptr == NULL) + { + /* Codes_SRS_GBALLOC_01_017: [When ptr is NULL, gballoc_realloc shall call the underlying realloc with ptr being NULL and the realloc result shall be tracked by gballoc.] */ + allocation = (ALLOCATION*)malloc(sizeof(ALLOCATION)); + } + else + { + curr = head; + while (curr != NULL) + { + if (curr->ptr == ptr) + { + allocation = curr; + break; + } + else + { + curr = (ALLOCATION*)curr->next; + } + } + } + + if (allocation == NULL) + { + /* Codes_SRS_GBALLOC_01_015: [When allocating memory used for tracking by gballoc_realloc fails, gballoc_realloc shall return NULL and no change should be made to the counted total memory usage.] */ + /* Codes_SRS_GBALLOC_01_016: [When the ptr pointer cannot be found in the pointers tracked by gballoc, gballoc_realloc shall return NULL and the underlying realloc shall not be called.] */ + result = NULL; + } + else + { + result = realloc(ptr, size); + if (result == NULL) + { + /* Codes_SRS_GBALLOC_01_014: [When the underlying realloc call fails, gballoc_realloc shall return NULL and no change should be made to the counted total memory usage.] */ + if (ptr == NULL) + { + free(allocation); + } + } + else + { + if (ptr != NULL) + { + /* Codes_SRS_GBALLOC_01_006: [If the underlying realloc call is successful, gballoc_realloc shall look up the size associated with the pointer ptr and decrease the total memory used with that size.] */ + allocation->ptr = result; + totalSize -= allocation->size; + allocation->size = size; + } + else + { + /* add block */ + allocation->ptr = result; + allocation->size = size; + allocation->next = head; + head = allocation; + } + + /* Codes_SRS_GBALLOC_01_007: [If realloc is successful, gballoc_realloc shall also increment the total memory used value tracked by this module.] */ + totalSize += size; + + /* Codes_SRS_GBALLOC_01_011: [The maximum total memory used shall be the maximum of the total memory used at any point.] */ + if (maxSize < totalSize) + { + maxSize = totalSize; + } + } + } + + (void)Unlock(gballocThreadSafeLock); + } + + return result; +} + +void gballoc_free(void* ptr) +{ + ALLOCATION* curr = head; + ALLOCATION* prev = NULL; + + if (gballocState != GBALLOC_STATE_INIT) + { + /* Codes_SRS_GBALLOC_01_042: [If gballoc was not initialized gballoc_free shall shall simply call free.] */ + free(ptr); + } + /* Codes_SRS_GBALLOC_01_033: [gballoc_free shall ensure thread safety by using the lock created by gballoc_Init.] */ + else if (LOCK_OK != Lock(gballocThreadSafeLock)) + { + /* Codes_SRS_GBALLOC_01_049: [If acquiring the lock fails, gballoc_free shall do nothing.] */ + LogError("Failed to get the Lock.\r\n"); + } + else + { + /* Codes_SRS_GBALLOC_01_009: [gballoc_free shall also look up the size associated with the ptr pointer and decrease the total memory used with the associated size amount.] */ + while (curr != NULL) + { + if (curr->ptr == ptr) + { + /* Codes_SRS_GBALLOC_01_008: [gballoc_free shall call the C99 free function.] */ + free(ptr); + totalSize -= curr->size; + if (prev != NULL) + { + prev->next = curr->next; + } + else + { + head = (ALLOCATION*)curr->next; + } + + free(curr); + break; + } + + prev = curr; + curr = (ALLOCATION*)curr->next; + } + + if ((curr == NULL) && (ptr != NULL)) + { + /* Codes_SRS_GBALLOC_01_019: [When the ptr pointer cannot be found in the pointers tracked by gballoc, gballoc_free shall not free any memory.] */ + + /* could not find the allocation */ + LogError("Could not free allocation for address %p (not found)\r\n", ptr); + } + (void)Unlock(gballocThreadSafeLock); + } +} + +size_t gballoc_getMaximumMemoryUsed(void) +{ + size_t result; + + /* Codes_SRS_GBALLOC_01_038: [If gballoc was not initialized gballoc_getMaximumMemoryUsed shall return MAX_INT_SIZE.] */ + if (gballocState != GBALLOC_STATE_INIT) + { + LogError("gballoc is not initialized.\r\n"); + result = SIZE_MAX; + } + /* Codes_SRS_GBALLOC_01_034: [gballoc_getMaximumMemoryUsed shall ensure thread safety by using the lock created by gballoc_Init.] */ + else if (LOCK_OK != Lock(gballocThreadSafeLock)) + { + /* Codes_SRS_GBALLOC_01_050: [If the lock cannot be acquired, gballoc_getMaximumMemoryUsed shall return SIZE_MAX.] */ + LogError("Failed to get the Lock.\r\n"); + result = SIZE_MAX; + } + else + { + /* Codes_SRS_GBALLOC_01_010: [gballoc_getMaximumMemoryUsed shall return the maximum amount of total memory used recorded since the module initialization.] */ + result = maxSize; + Unlock(gballocThreadSafeLock); +} + + return result; +} + +size_t gballoc_getCurrentMemoryUsed(void) +{ + size_t result; + + /* Codes_SRS_GBALLOC_01_044: [If gballoc was not initialized gballoc_getCurrentMemoryUsed shall return SIZE_MAX.] */ + if (gballocState != GBALLOC_STATE_INIT) + { + LogError("gballoc is not initialized.\r\n"); + result = SIZE_MAX; + } + /* Codes_SRS_GBALLOC_01_036: [gballoc_getCurrentMemoryUsed shall ensure thread safety by using the lock created by gballoc_Init.]*/ + else if (LOCK_OK != Lock(gballocThreadSafeLock)) + { + /* Codes_SRS_GBALLOC_01_051: [If the lock cannot be acquired, gballoc_getCurrentMemoryUsed shall return SIZE_MAX.] */ + LogError("Failed to get the Lock.\r\n"); + result = SIZE_MAX; + } + else + { + /*Codes_SRS_GBALLOC_02_001: [gballoc_getCurrentMemoryUsed shall return the currently used memory size.] */ + result = totalSize; + Unlock(gballocThreadSafeLock); + } + + return result; +} diff --git a/c/sharedutil/src/hmac.c b/c/sharedutil/src/hmac.c new file mode 100644 index 00000000..e6247380 --- /dev/null +++ b/c/sharedutil/src/hmac.c @@ -0,0 +1,239 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/**************************** hmac.c ****************************/ +/******************** See RFC 4634 for details ******************/ +/* +* Description: +* This file implements the HMAC algorithm (Keyed-Hashing for +* Message Authentication, RFC2104), expressed in terms of the +* various SHA algorithms. +*/ + +#include +#ifdef _CRTDBG_MAP_ALLOC +#include +#endif +#include "gballoc.h" + +#include "sha.h" + +/* +* hmac +* +* Description: +* This function will compute an HMAC message digest. +* +* Parameters: +* whichSha: [in] +* One of SHA1, SHA224, SHA256, SHA384, SHA512 +* key: [in] +* The secret shared key. +* key_len: [in] +* The length of the secret shared key. +* message_array: [in] +* An array of characters representing the message. +* length: [in] +* The length of the message in message_array +* digest: [out] +* Where the digest is returned. +* NOTE: The length of the digest is determined by +* the value of whichSha. +* +* Returns: +* sha Error Code. +* +*/ +int hmac(SHAversion whichSha, const unsigned char *text, int text_len, + const unsigned char *key, int key_len, + uint8_t digest[USHAMaxHashSize]) +{ + HMACContext ctx; + return hmacReset(&ctx, whichSha, key, key_len) || + hmacInput(&ctx, text, text_len) || + hmacResult(&ctx, digest); +} + +/* +* hmacReset +* +* Description: +* This function will initialize the hmacContext in preparation +* for computing a new HMAC message digest. +* +* Parameters: +* context: [in/out] +* The context to reset. +* whichSha: [in] +* One of SHA1, SHA224, SHA256, SHA384, SHA512 +* key: [in] +* The secret shared key. +* key_len: [in] +* The length of the secret shared key. +* +* Returns: +* sha Error Code. +* +*/ +int hmacReset(HMACContext *ctx, enum SHAversion whichSha, + const unsigned char *key, int key_len) +{ + int i, blocksize, hashsize; + + /* inner padding - key XORd with ipad */ + unsigned char k_ipad[USHA_Max_Message_Block_Size]; + + /* temporary buffer when keylen > blocksize */ + unsigned char tempkey[USHAMaxHashSize]; + + if (!ctx) return shaNull; + + blocksize = ctx->blockSize = USHABlockSize(whichSha); + hashsize = ctx->hashSize = USHAHashSize(whichSha); + + ctx->whichSha = whichSha; + + /* + * If key is longer than the hash blocksize, + * reset it to key = HASH(key). + */ + if (key_len > blocksize) { + USHAContext tctx; + int err = USHAReset(&tctx, whichSha) || + USHAInput(&tctx, key, key_len) || + USHAResult(&tctx, tempkey); + if (err != shaSuccess) return err; + + key = tempkey; + key_len = hashsize; + } + + /* + * The HMAC transform looks like: + * + * SHA(K XOR opad, SHA(K XOR ipad, text)) + * + * where K is an n byte key. + * ipad is the byte 0x36 repeated blocksize times + * opad is the byte 0x5c repeated blocksize times + * and text is the data being protected. + */ + + /* store key into the pads, XOR'd with ipad and opad values */ + for (i = 0; i < key_len; i++) { + k_ipad[i] = key[i] ^ 0x36; + ctx->k_opad[i] = key[i] ^ 0x5c; + } + /* remaining pad bytes are '\0' XOR'd with ipad and opad values */ + for (; i < blocksize; i++) { + k_ipad[i] = 0x36; + ctx->k_opad[i] = 0x5c; + } + + /* perform inner hash */ + /* init context for 1st pass */ + return USHAReset(&ctx->shaContext, whichSha) || + /* and start with inner pad */ + USHAInput(&ctx->shaContext, k_ipad, blocksize); +} + +/* +* hmacInput +* +* Description: +* This function accepts an array of octets as the next portion +* of the message. +* +* Parameters: +* context: [in/out] +* The HMAC context to update +* message_array: [in] +* An array of characters representing the next portion of +* the message. +* length: [in] +* The length of the message in message_array +* +* Returns: +* sha Error Code. +* +*/ +int hmacInput(HMACContext *ctx, const unsigned char *text, + int text_len) +{ + if (!ctx) return shaNull; + /* then text of datagram */ + return USHAInput(&ctx->shaContext, text, text_len); +} + +/* +* HMACFinalBits +* +* Description: +* This function will add in any final bits of the message. +* +* Parameters: +* context: [in/out] +* The HMAC context to update +* message_bits: [in] +* The final bits of the message, in the upper portion of the +* byte. (Use 0b###00000 instead of 0b00000### to input the +* three bits ###.) +* length: [in] +* The number of bits in message_bits, between 1 and 7. +* +* Returns: +* sha Error Code. +*/ +int hmacFinalBits(HMACContext *ctx, + const uint8_t bits, + unsigned int bitcount) +{ + if (!ctx) return shaNull; + /* then final bits of datagram */ + return USHAFinalBits(&ctx->shaContext, bits, bitcount); +} + +/* +* HMACResult +* +* Description: +* This function will return the N-byte message digest into the +* Message_Digest array provided by the caller. +* NOTE: The first octet of hash is stored in the 0th element, +* the last octet of hash in the Nth element. +* +* Parameters: +* context: [in/out] +* The context to use to calculate the HMAC hash. +* digest: [out] +* Where the digest is returned. +* NOTE 2: The length of the hash is determined by the value of +* whichSha that was passed to hmacReset(). +* +* Returns: +* sha Error Code. +* +*/ +int hmacResult(HMACContext *ctx, uint8_t *digest) +{ + if (!ctx) return shaNull; + + /* finish up 1st pass */ + /* (Use digest here as a temporary buffer.) */ + return USHAResult(&ctx->shaContext, digest) || + + /* perform outer SHA */ + /* init context for 2nd pass */ + USHAReset(&ctx->shaContext, ctx->whichSha) || + + /* start with outer pad */ + USHAInput(&ctx->shaContext, ctx->k_opad, ctx->blockSize) || + + /* then results of 1st hash */ + USHAInput(&ctx->shaContext, digest, ctx->hashSize) || + + /* finish up 2nd pass */ + USHAResult(&ctx->shaContext, digest); +} + + diff --git a/c/sharedutil/src/hmacsha256.c b/c/sharedutil/src/hmacsha256.c new file mode 100644 index 00000000..5ed60b00 --- /dev/null +++ b/c/sharedutil/src/hmacsha256.c @@ -0,0 +1,42 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include +#ifdef _CRTDBG_MAP_ALLOC +#include +#endif +#include "gballoc.h" + +#include "hmacsha256.h" +#include "hmac.h" +#include "strings.h" + + + +HMACSHA256_RESULT HMACSHA256_ComputeHash(const unsigned char* key, size_t keyLen, const unsigned char* payload, size_t payloadLen, BUFFER_HANDLE hash) +{ + HMACSHA256_RESULT result; + + if (key == NULL || + keyLen == 0 || + payload == NULL || + payloadLen == 0 || + hash == NULL) + { + result = HMACSHA256_INVALID_ARG; + } + else + { + if ((BUFFER_enlarge(hash, 32) != 0) || + (hmac(SHA256, payload, payloadLen, key, keyLen, BUFFER_u_char(hash) ) != 0)) + { + result = HMACSHA256_ERROR; + } + else + { + result = HMACSHA256_OK; + } + } + + return result; +} diff --git a/c/sharedutil/src/httpapiex.c b/c/sharedutil/src/httpapiex.c new file mode 100644 index 00000000..bee2ecdf --- /dev/null +++ b/c/sharedutil/src/httpapiex.c @@ -0,0 +1,658 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include +#ifdef _CRTDBG_MAP_ALLOC +#include +#endif +#include "gballoc.h" + +#include "httpapiex.h" +#include "iot_logging.h" +#include "strings.h" +#include "crt_abstractions.h" +#include "vector.h" + +typedef struct HTTPAPIEX_SAVED_OPTION_TAG +{ + const char* optionName; + const void* value; +}HTTPAPIEX_SAVED_OPTION; + +typedef struct HTTPAPIEX_HANDLE_DATA_TAG +{ + STRING_HANDLE hostName; + int k; + HTTP_HANDLE httpHandle; + VECTOR_HANDLE savedOptions; +}HTTPAPIEX_HANDLE_DATA; + +DEFINE_ENUM_STRINGS(HTTPAPIEX_RESULT, HTTPAPIEX_RESULT_VALUES); + +#define LOG_HTTAPIEX_ERROR() LogError("error code = %s\r\n", ENUM_TO_STRING(HTTPAPIEX_RESULT, result)) + +HTTPAPIEX_HANDLE HTTPAPIEX_Create(const char* hostName) +{ + HTTPAPIEX_HANDLE result; + /*Codes_SRS_HTTPAPIEX_02_001: [If parameter hostName is NULL then HTTPAPIEX_Create shall return NULL.]*/ + if (hostName == NULL) + { + LogError("invalid (NULL) parameter\r\n"); + result = NULL; + } + else + { + /*Codes_SRS_HTTPAPIEX_02_005: [If creating the handle fails for any reason, then HTTAPIEX_Create shall return NULL.] */ + HTTPAPIEX_HANDLE_DATA* handleData = (HTTPAPIEX_HANDLE_DATA*)malloc(sizeof(HTTPAPIEX_HANDLE_DATA)); + if (handleData == NULL) + { + LogError("malloc failed.\r\n"); + result = NULL; + } + else + { + /*Codes_SRS_HTTPAPIEX_02_002: [Parameter hostName shall be saved.]*/ + handleData->hostName = STRING_construct(hostName); + if (handleData->hostName == NULL) + { + free(handleData); + LogError("unable to STRING_construct\r\n"); + result = NULL; + } + else + { + /*Codes_SRS_HTTPAPIEX_02_004: [Otherwise, HTTPAPIEX_Create shall return a HTTAPIEX_HANDLE suitable for further calls to the module.] */ + handleData->savedOptions = VECTOR_create(sizeof(HTTPAPIEX_SAVED_OPTION)); + if (handleData->savedOptions == NULL) + { + STRING_delete(handleData->hostName); + free(handleData); + result = NULL; + } + else + { + handleData->k = -1; + handleData->httpHandle = NULL; + result = handleData; + } + } + } + } + return result; +} + +/*this function builds the default request http headers if none are specified*/ +/*returns 0 if no error*/ +/*any other code is error*/ +static int buildRequestHttpHeadersHandle(HTTPAPIEX_HANDLE_DATA *handleData, BUFFER_HANDLE requestContent, HTTP_HEADERS_HANDLE originalRequestHttpHeadersHandle, bool* isOriginalRequestHttpHeadersHandle, HTTP_HEADERS_HANDLE* toBeUsedRequestHttpHeadersHandle) +{ + int result; + + + if (originalRequestHttpHeadersHandle != NULL) + { + *toBeUsedRequestHttpHeadersHandle = originalRequestHttpHeadersHandle; + *isOriginalRequestHttpHeadersHandle = true; + + } + else + { + /*Codes_SRS_HTTPAPIEX_02_009: [If parameter requestHttpHeadersHandle is NULL then HTTPAPIEX_ExecuteRequest shall allocate a temporary internal instance of HTTPHEADERS, shall add to that instance the following headers + Host:{hostname} - as it was indicated by the call to HTTPAPIEX_Create API call + Content-Length:the size of the requestContent parameter, and use this instance to all the subsequent calls to HTTPAPI_ExecuteRequest as parameter httpHeadersHandle.] + */ + *isOriginalRequestHttpHeadersHandle = false; + *toBeUsedRequestHttpHeadersHandle = HTTPHeaders_Alloc(); + } + + if (*toBeUsedRequestHttpHeadersHandle == NULL) + { + result = __LINE__; + LogError("unable to HTTPHeaders_Alloc\r\n"); + } + else + { + char temp[22]; + (void)size_tToString(temp, 22, BUFFER_length(requestContent)); /*cannot fail, MAX_uint64 has 19 digits*/ + /*Codes_SRS_HTTPAPIEX_02_011: [If parameter requestHttpHeadersHandle is not NULL then HTTPAPIEX_ExecuteRequest shall create or update the following headers of the request: + Host:{hostname} + Content-Length:the size of the requestContent parameter, and shall use the so constructed HTTPHEADERS object to all calls to HTTPAPI_ExecuteRequest as parameter httpHeadersHandle.] + */ + /*Codes_SRS_HTTPAPIEX_02_009: [If parameter requestHttpHeadersHandle is NULL then HTTPAPIEX_ExecuteRequest shall allocate a temporary internal instance of HTTPHEADERS, shall add to that instance the following headers + Host:{hostname} - as it was indicated by the call to HTTPAPIEX_Create API call + Content-Length:the size of the requestContent parameter, and use this instance to all the subsequent calls to HTTPAPI_ExecuteRequest as parameter httpHeadersHandle.] + */ + if (!( + (HTTPHeaders_ReplaceHeaderNameValuePair(*toBeUsedRequestHttpHeadersHandle, "Host", STRING_c_str(handleData->hostName)) == HTTP_HEADERS_OK) && + (HTTPHeaders_ReplaceHeaderNameValuePair(*toBeUsedRequestHttpHeadersHandle, "Content-Length", temp) == HTTP_HEADERS_OK) + )) + { + if (! *isOriginalRequestHttpHeadersHandle) + { + HTTPHeaders_Free(*toBeUsedRequestHttpHeadersHandle); + } + *toBeUsedRequestHttpHeadersHandle = NULL; + result = __LINE__; + } + else + { + result = 0; + } + } + return result; +} + +static int buildResponseHttpHeadersHandle(HTTP_HEADERS_HANDLE originalResponsetHttpHeadersHandle, bool* isOriginalResponseHttpHeadersHandle, HTTP_HEADERS_HANDLE* toBeUsedResponsetHttpHeadersHandle) +{ + int result; + if (originalResponsetHttpHeadersHandle == NULL) + { + if ((*toBeUsedResponsetHttpHeadersHandle = HTTPHeaders_Alloc()) == NULL) + { + result = __LINE__; + } + else + { + *isOriginalResponseHttpHeadersHandle = false; + result = 0; + } + } + else + { + *isOriginalResponseHttpHeadersHandle = true; + *toBeUsedResponsetHttpHeadersHandle = originalResponsetHttpHeadersHandle; + result = 0; + } + return result; +} + + +static int buildBufferIfNotExist(BUFFER_HANDLE originalRequestContent, bool* isOriginalRequestContent, BUFFER_HANDLE* toBeUsedRequestContent) +{ + int result; + if (originalRequestContent == NULL) + { + *toBeUsedRequestContent = BUFFER_new(); + if (*toBeUsedRequestContent == NULL) + { + result = __LINE__; + } + else + { + *isOriginalRequestContent = false; + result = 0; + } + } + else + { + *isOriginalRequestContent = true; + *toBeUsedRequestContent = originalRequestContent; + result = 0; + } + return result; +} + +static unsigned int dummyStatusCode; + +static int buildAllRequests(HTTPAPIEX_HANDLE_DATA* handle, HTTPAPI_REQUEST_TYPE requestType, const char* relativePath, + HTTP_HEADERS_HANDLE requestHttpHeadersHandle, BUFFER_HANDLE requestContent, unsigned int* statusCode, + HTTP_HEADERS_HANDLE responseHttpHeadersHandle, BUFFER_HANDLE responseContent, + + const char** toBeUsedRelativePath, + HTTP_HEADERS_HANDLE *toBeUsedRequestHttpHeadersHandle, bool *isOriginalRequestHttpHeadersHandle, + BUFFER_HANDLE *toBeUsedRequestContent, bool *isOriginalRequestContent, + unsigned int** toBeUsedStatusCode, + HTTP_HEADERS_HANDLE *toBeUsedResponseHttpHeadersHandle, bool *isOriginalResponseHttpHeadersHandle, + BUFFER_HANDLE *toBeUsedResponseContent, bool *isOriginalResponseContent) +{ + int result; + (void)requestType; + /*Codes_SRS_HTTPAPIEX_02_013: [If requestContent is NULL then HTTPAPIEX_ExecuteRequest shall behave as if a buffer of zero size would have been used, that is, it shall call HTTPAPI_ExecuteRequest with parameter content = NULL and contentLength = 0.]*/ + /*Codes_SRS_HTTPAPIEX_02_014: [If requestContent is not NULL then its content and its size shall be used for parameters content and contentLength of HTTPAPI_ExecuteRequest.] */ + if (buildBufferIfNotExist(requestContent, isOriginalRequestContent, toBeUsedRequestContent) != 0) + { + result = __LINE__; + LogError("unable to build the request content\r\n"); + } + else + { + if (buildRequestHttpHeadersHandle(handle, *toBeUsedRequestContent, requestHttpHeadersHandle, isOriginalRequestHttpHeadersHandle, toBeUsedRequestHttpHeadersHandle) != 0) + { + /*Codes_SRS_HTTPAPIEX_02_010: [If any of the operations in SRS_HTTAPIEX_02_009 fails, then HTTPAPIEX_ExecuteRequest shall return HTTPAPIEX_ERROR.] */ + result = __LINE__; + if (*isOriginalRequestContent == false) + { + BUFFER_delete(*toBeUsedRequestContent); + } + LogError("unable to build the request http headers handle\r\n"); + } + else + { + /*Codes_SRS_HTTPAPIEX_02_008: [If parameter relativePath is NULL then HTTPAPIEX_INVALID_ARG shall not assume a relative path - that is, it will assume an empty path ("").] */ + if (relativePath == NULL) + { + *toBeUsedRelativePath = ""; + } + else + { + *toBeUsedRelativePath = relativePath; + } + + /*Codes_SRS_HTTPAPIEX_02_015: [If statusCode is NULL then HTTPAPIEX_ExecuteRequest shall not write in statusCode the HTTP status code, and it will use a temporary internal int for parameter statusCode to the calls of HTTPAPI_ExecuteRequest.] */ + if (statusCode == NULL) + { + /*Codes_SRS_HTTPAPIEX_02_016: [If statusCode is not NULL then If statusCode is NULL then HTTPAPIEX_ExecuteRequest shall use it for parameter statusCode to the calls of HTTPAPI_ExecuteRequest.] */ + *toBeUsedStatusCode = &dummyStatusCode; + } + else + { + *toBeUsedStatusCode = statusCode; + } + + /*Codes_SRS_HTTPAPIEX_02_017: [If responseHeaders handle is NULL then HTTPAPIEX_ExecuteRequest shall create a temporary internal instance of HTTPHEADERS object and use that for responseHeaders parameter of HTTPAPI_ExecuteRequest call.] */ + /*Codes_SRS_HTTPAPIEX_02_019: [If responseHeaders is not NULL, then then HTTPAPIEX_ExecuteRequest shall use that object as parameter responseHeaders of HTTPAPI_ExecuteRequest call.] */ + if (buildResponseHttpHeadersHandle(responseHttpHeadersHandle, isOriginalResponseHttpHeadersHandle, toBeUsedResponseHttpHeadersHandle) != 0) + { + /*Codes_SRS_HTTPAPIEX_02_018: [If creating the temporary http headers in SRS_HTTPAPIEX_02_017 fails then HTTPAPIEX_ExecuteRequest shall return HTTPAPIEX_ERROR.] */ + result = __LINE__; + if (*isOriginalRequestContent == false) + { + BUFFER_delete(*toBeUsedRequestContent); + } + if (*isOriginalRequestHttpHeadersHandle == false) + { + HTTPHeaders_Free(*toBeUsedRequestHttpHeadersHandle); + } + LogError("unable to build response content\r\n"); + } + else + { + /*Codes_SRS_HTTPAPIEX_02_020: [If responseContent is NULL then HTTPAPIEX_ExecuteRequest shall create a temporary internal BUFFER object and use that as parameter responseContent of HTTPAPI_ExecuteRequest call.] */ + /*Codes_SRS_HTTPAPIEX_02_022: [If responseContent is not NULL then HTTPAPIEX_ExecuteRequest use that as parameter responseContent of HTTPAPI_ExecuteRequest call.] */ + if (buildBufferIfNotExist(responseContent, isOriginalResponseContent, toBeUsedResponseContent) != 0) + { + /*Codes_SRS_HTTPAPIEX_02_021: [If creating the BUFFER_HANDLE in SRS_HTTPAPIEX_02_020 fails, then HTTPAPIEX_ExecuteRequest shall return HTTPAPIEX_ERROR.] */ + result = __LINE__; + if (*isOriginalRequestContent == false) + { + BUFFER_delete(*toBeUsedRequestContent); + } + if (*isOriginalRequestHttpHeadersHandle == false) + { + HTTPHeaders_Free(*toBeUsedRequestHttpHeadersHandle); + } + if (*isOriginalResponseHttpHeadersHandle == false) + { + HTTPHeaders_Free(*toBeUsedResponseHttpHeadersHandle); + } + LogError("unable to build response content\r\n"); + } + else + { + result = 0; + } + } + } + } + return result; +} + +HTTPAPIEX_RESULT HTTPAPIEX_ExecuteRequest(HTTPAPIEX_HANDLE handle, HTTPAPI_REQUEST_TYPE requestType, const char* relativePath, + HTTP_HEADERS_HANDLE requestHttpHeadersHandle, BUFFER_HANDLE requestContent, unsigned int* statusCode, + HTTP_HEADERS_HANDLE responseHttpHeadersHandle, BUFFER_HANDLE responseContent) +{ + HTTPAPIEX_RESULT result; + /*Codes_SRS_HTTPAPIEX_02_006: [If parameter handle is NULL then HTTPAPIEX_ExecuteRequest shall fail and return HTTPAPIEX_INVALID_ARG.]*/ + if (handle == NULL) + { + result = HTTPAPIEX_INVALID_ARG; + LOG_HTTAPIEX_ERROR(); + } + else + { + /*Codes_SRS_HTTPAPIEX_02_007: [If parameter requestType does not indicate a valid request, HTTPAPIEX_ExecuteRequest shall fail and return HTTPAPIEX_INVALID_ARG.] */ + if (requestType >= COUNT_ARG(HTTPAPI_REQUEST_TYPE_VALUES)) + { + result = HTTPAPIEX_INVALID_ARG; + LOG_HTTAPIEX_ERROR(); + } + else + { + HTTPAPIEX_HANDLE_DATA *handleData = (HTTPAPIEX_HANDLE_DATA *)handle; + + /*call to buildAll*/ + const char* toBeUsedRelativePath; + HTTP_HEADERS_HANDLE toBeUsedRequestHttpHeadersHandle; bool isOriginalRequestHttpHeadersHandle; + BUFFER_HANDLE toBeUsedRequestContent; bool isOriginalRequestContent; + unsigned int* toBeUsedStatusCode; + HTTP_HEADERS_HANDLE toBeUsedResponseHttpHeadersHandle; bool isOriginalResponseHttpHeadersHandle; + BUFFER_HANDLE toBeUsedResponseContent; bool isOriginalResponseContent; + + if (buildAllRequests(handleData, requestType, relativePath, requestHttpHeadersHandle, requestContent, statusCode, responseHttpHeadersHandle, responseContent, + &toBeUsedRelativePath, + &toBeUsedRequestHttpHeadersHandle, &isOriginalRequestHttpHeadersHandle, + &toBeUsedRequestContent, &isOriginalRequestContent, + &toBeUsedStatusCode, + &toBeUsedResponseHttpHeadersHandle, &isOriginalResponseHttpHeadersHandle, + &toBeUsedResponseContent, &isOriginalResponseContent) != 0) + { + result = HTTPAPIEX_ERROR; + LOG_HTTAPIEX_ERROR(); + } + else + { + + /*Codes_SRS_HTTPAPIEX_02_023: [HTTPAPIEX_ExecuteRequest shall try to execute the HTTP call by ensuring the following API call sequence is respected:]*/ + /*Codes_SRS_HTTPAPIEX_02_024: [If any point in the sequence fails, HTTPAPIEX_ExecuteRequest shall attempt to recover by going back to the previous step and retrying that step.]*/ + /*Codes_SRS_HTTPAPIEX_02_025: [If the first step fails, then the sequence fails.]*/ + /*Codes_SRS_HTTPAPIEX_02_026: [A step shall be retried at most once.]*/ + /*Codes_SRS_HTTPAPIEX_02_027: [If a step has been retried then all subsequent steps shall be retried too.]*/ + bool st[3] = { false, false, false }; /*the three levels of possible failure in resilient send: HTTAPI_Init, HTTPAPI_CreateConnection, HTTPAPI_ExecuteRequest*/ + if (handleData->k == -1) + { + handleData->k = 0; + } + + do + { + bool goOn; + + if (handleData->k > 2) + { + /* error */ + break; + } + + if (st[handleData->k] == true) /*already been tried*/ + { + goOn = false; + } + else + { + switch (handleData->k) + { + case 0: + { + if (HTTPAPI_Init() != HTTPAPI_OK) + { + goOn = false; + } + else + { + goOn = true; + } + break; + } + case 1: + { + if ((handleData->httpHandle = HTTPAPI_CreateConnection(STRING_c_str(handleData->hostName))) == NULL) + { + goOn = false; + } + else + { + size_t i; + size_t vectorSize = VECTOR_size(handleData->savedOptions); + for (i = 0; i < vectorSize; i++) + { + /*Codes_SRS_HTTPAPIEX_02_035: [HTTPAPIEX_ExecuteRequest shall pass all the saved options (see HTTPAPIEX_SetOption) to the newly create HTTPAPI_HANDLE in step 2 by calling HTTPAPI_SetOption.]*/ + /*Codes_SRS_HTTPAPIEX_02_036: [If setting the option fails, then the failure shall be ignored.] */ + HTTPAPIEX_SAVED_OPTION* option = VECTOR_element(handleData->savedOptions, i); + if (HTTPAPI_SetOption(handleData->httpHandle, option->optionName, option->value) != HTTPAPI_OK) + { + LogError("HTTPAPI_SetOption failed when called for option %s\r\n", option->optionName); + } + } + goOn = true; + } + break; + } + case 2: + { + if (HTTPAPI_ExecuteRequest(handleData->httpHandle, requestType, toBeUsedRelativePath, toBeUsedRequestHttpHeadersHandle, BUFFER_u_char(toBeUsedRequestContent), BUFFER_length(toBeUsedRequestContent), toBeUsedStatusCode, toBeUsedResponseHttpHeadersHandle, toBeUsedResponseContent) != HTTPAPI_OK) + { + goOn = false; + } + else + { + goOn = true; + } + break; + } + default: + { + /*serious error*/ + goOn = false; + break; + } + } + } + + if (goOn) + { + if (handleData->k == 2) + { + /*Codes_SRS_HTTPAPIEX_02_028: [HTTPAPIEX_ExecuteRequest shall return HTTPAPIEX_OK when a call to HTTPAPI_ExecuteRequest has been completed successfully.]*/ + result = HTTPAPIEX_OK; + goto out; + } + else + { + st[handleData->k] = true; + handleData->k++; + st[handleData->k] = false; + } + } + else + { + st[handleData->k] = false; + handleData->k--; + switch (handleData->k) + { + case 0: + { + HTTPAPI_Deinit(); + break; + } + case 1: + { + HTTPAPI_CloseConnection(handleData->httpHandle); + handleData->httpHandle = NULL; + break; + } + case 2: + { + break; + } + default: + { + break; + } + } + } + } while (handleData->k >= 0); + /*Codes_SRS_HTTPAPIEX_02_029: [Otherwise, HTTAPIEX_ExecuteRequest shall return HTTPAPIEX_RECOVERYFAILED.] */ + result = HTTPAPIEX_RECOVERYFAILED; + LogError("unable to recover sending to a working state\r\n"); + out:; + /*in all cases, unbuild the temporaries*/ + if (isOriginalRequestContent == false) + { + BUFFER_delete(toBeUsedRequestContent); + } + if (isOriginalRequestHttpHeadersHandle == false) + { + HTTPHeaders_Free(toBeUsedRequestHttpHeadersHandle); + } + if (isOriginalResponseContent == false) + { + BUFFER_delete(toBeUsedResponseContent); + } + if (isOriginalResponseHttpHeadersHandle == false) + { + HTTPHeaders_Free(toBeUsedResponseHttpHeadersHandle); + } + } + } + } + return result; +} + + +void HTTPAPIEX_Destroy(HTTPAPIEX_HANDLE handle) +{ + if (handle != NULL) + { + /*Codes_SRS_HTTPAPIEX_02_042: [HTTPAPIEX_Destroy shall free all the resources used by HTTAPIEX_HANDLE.]*/ + size_t i; + size_t vectorSize; + HTTPAPIEX_HANDLE_DATA* handleData = (HTTPAPIEX_HANDLE_DATA*)handle; + + if (handleData->k == 2) + { + HTTPAPI_CloseConnection(handleData->httpHandle); + HTTPAPI_Deinit(); + } + STRING_delete(handleData->hostName); + + vectorSize = VECTOR_size(handleData->savedOptions); + for (i = 0; i < vectorSize; i++) + { + HTTPAPIEX_SAVED_OPTION*savedOption = VECTOR_element(handleData->savedOptions, i); + free((void*)savedOption->optionName); + free((void*)savedOption->value); + } + VECTOR_destroy(handleData->savedOptions); + + free(handle); + } + else + { + /*Codes_SRS_HTTPAPIEX_02_043: [If parameter handle is NULL then HTTPAPIEX_Destroy shall take no action.] */ + } +} + +static bool sameName(const void* element, const void* value) +{ + return (strcmp(((HTTPAPIEX_SAVED_OPTION*)element)->optionName, value) == 0) ? true : false; +} + +/*return 0 on success, any other value is error*/ +/*obs: value is already cloned at the time of calling this function */ +static int createOrUpdateOption(HTTPAPIEX_HANDLE_DATA* handleData, const char* optionName, const void* value) +{ + /*this function is called after the option value has been saved (cloned)*/ + int result; + + /*decide bwtween update or create*/ + HTTPAPIEX_SAVED_OPTION* whereIsIt = VECTOR_find_if(handleData->savedOptions, sameName, optionName); + if (whereIsIt != NULL) + { + free((void*)(whereIsIt->value)); + whereIsIt->value = value; + result = 0; + } + else + { + HTTPAPIEX_SAVED_OPTION newOption; + if (mallocAndStrcpy_s((char**)&(newOption.optionName), optionName) != 0) + { + free((void*)value); + result = __LINE__; + } + else + { + newOption.value = value; + if (VECTOR_push_back(handleData->savedOptions, &newOption, 1) != 0) + { + LogError("unable to VECTOR_push_back\r\n"); + free((void*)newOption.optionName); + free((void*)value); + result = __LINE__; + } + else + { + result = 0; + } + } + } + + return result; +} + +HTTPAPIEX_RESULT HTTPAPIEX_SetOption(HTTPAPIEX_HANDLE handle, const char* optionName, const void* value) +{ + HTTPAPIEX_RESULT result; + /*Codes_SRS_HTTPAPIEX_02_032: [If parameter handle is NULL then HTTPAPIEX_SetOption shall return HTTPAPIEX_INVALID_ARG.] */ + /*Codes_SRS_HTTPAPIEX_02_033: [If parameter optionName is NULL then HTTPAPIEX_SetOption shall return HTTPAPIEX_INVALID_ARG.] */ + /*Codes_SRS_HTTPAPIEX_02_034: [If parameter value is NULL then HTTPAPIEX_SetOption shall return HTTPAPIEX_INVALID_ARG.] */ + if ( + (handle == NULL) || + (optionName == NULL) || + (value == NULL) + ) + { + result = HTTPAPIEX_INVALID_ARG; + LOG_HTTAPIEX_ERROR(); + } + else + { + const void* savedOption; + HTTPAPI_RESULT saveOptionResult; + + /*Codes_SRS_HTTPAPIEX_02_037: [HTTPAPIEX_SetOption shall attempt to save the value of the option by calling HTTPAPI_CloneOption passing optionName and value, irrespective of the existence of a HTTPAPI_HANDLE] */ + saveOptionResult = HTTPAPI_CloneOption(optionName, value, &savedOption); + + if(saveOptionResult == HTTPAPI_INVALID_ARG) + { + /*Codes_SRS_HTTPAPIEX_02_038: [If HTTPAPI_CloneOption returns HTTPAPI_INVALID_ARG then HTTPAPIEX shall return HTTPAPIEX_INVALID_ARG.] */ + result = HTTPAPIEX_INVALID_ARG; + LOG_HTTAPIEX_ERROR(); + } + else if (saveOptionResult != HTTPAPI_OK) + { + /*Codes_SRS_HTTPAPIEX_02_040: [For all other return values of HTTPAPI_SetOption, HTTPIAPIEX_SetOption shall return HTTPAPIEX_ERROR.] */ + result = HTTPAPIEX_ERROR; + LOG_HTTAPIEX_ERROR(); + } + else + { + HTTPAPIEX_HANDLE_DATA* handleData = (HTTPAPIEX_HANDLE_DATA*)handle; + /*Codes_SRS_HTTPAPIEX_02_039: [If HTTPAPI_CloneOption returns HTTPAPI_OK then HTTPAPIEX_SetOption shall create or update the pair optionName/value.]*/ + if (createOrUpdateOption(handleData, optionName, savedOption) != 0) + { + /*Codes_SRS_HTTPAPIEX_02_041: [If creating or updating the pair optionName/value fails then shall return HTTPAPIEX_ERROR.] */ + result = HTTPAPIEX_ERROR; + LOG_HTTAPIEX_ERROR(); + + } + else + { + /*Codes_SRS_HTTPAPIEX_02_031: [If HTTPAPI_HANDLE exists then HTTPAPIEX_SetOption shall call HTTPAPI_SetOption passing the same optionName and value and shall return a value conforming to the below table:] */ + if (handleData->httpHandle != NULL) + { + HTTPAPI_RESULT HTTPAPI_result = HTTPAPI_SetOption(handleData->httpHandle, optionName, value); + if (HTTPAPI_result == HTTPAPI_OK) + { + result = HTTPAPIEX_OK; + } + else if (HTTPAPI_result == HTTPAPI_INVALID_ARG) + { + result = HTTPAPIEX_INVALID_ARG; + LOG_HTTAPIEX_ERROR(); + } + else + { + result = HTTPAPIEX_ERROR; + LOG_HTTAPIEX_ERROR(); + } + } + else + { + result = HTTPAPIEX_OK; + } + } + } + } + return result; +} diff --git a/c/sharedutil/src/httpapiexsas.c b/c/sharedutil/src/httpapiexsas.c new file mode 100644 index 00000000..b2e0c729 --- /dev/null +++ b/c/sharedutil/src/httpapiexsas.c @@ -0,0 +1,142 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include +#ifdef _CRTDBG_MAP_ALLOC +#include +#endif +#include "gballoc.h" + +#include + +#include "strings.h" +#include "buffer_.h" +#include "sastoken.h" +#include "httpheaders.h" +#include "httpapiex.h" +#include "httpapiexsas.h" +#include "iot_logging.h" + +typedef struct HTTPAPIEX_SAS_STATE_TAG +{ + STRING_HANDLE key; + STRING_HANDLE uriResource; + STRING_HANDLE keyName; +}HTTPAPIEX_SAS_STATE; + + +HTTPAPIEX_SAS_HANDLE HTTPAPIEX_SAS_Create(STRING_HANDLE key, STRING_HANDLE uriResource, STRING_HANDLE keyName) +{ + HTTPAPIEX_SAS_HANDLE result = NULL; + if (key == NULL) + { + /*Codes_SRS_HTTPAPIEXSAS_06_001: [If the parameter key is NULL then HTTPAPIEX_SAS_Create shall return NULL.]*/ + LogError("No key passed to HTTPAPIEX_SAS_Create.\r\n"); + } + else if (uriResource == NULL) + { + /*Codes_SRS_HTTPAPIEXSAS_06_002: [If the parameter uriResource is NULL then HTTPAPIEX_SAS_Create shall return NULL.]*/ + LogError("No uri resource passed to HTTPAPIEX_SAS_Create.\r\n"); + } + else if (keyName == NULL) + { + /*Codes_SRS_HTTPAPIEXSAS_06_003: [If the parameter keyName is NULL then HTTPAPIEX_SAS_Create shall return NULL.]*/ + LogError("No key name passed to HTTPAPIEX_SAS_Create.\r\n"); + } + else + { + HTTPAPIEX_SAS_STATE* state = malloc(sizeof(HTTPAPIEX_SAS_STATE)); + /*Codes_SRS_HTTPAPIEXSAS_06_004: [If there are any other errors in the instantiation of this handle then HTTPAPIEX_SAS_Create shall return NULL.]*/ + if (state != NULL) + { + state->key = NULL; + state->uriResource = NULL; + state->keyName = NULL; + if (((state->key = STRING_clone(key)) == NULL) || + ((state->uriResource = STRING_clone(uriResource)) == NULL) || + ((state->keyName = STRING_clone(keyName)) == NULL)) + { + /*Codes_SRS_HTTPAPIEXSAS_06_004: [If there are any other errors in the instantiation of this handle then HTTPAPIEX_SAS_Create shall return NULL.]*/ + LogError("Unable to clone the arguments.\r\n"); + HTTPAPIEX_SAS_Destroy(state); + } + else + { + result = state; + } + } + } + return result; +} + +void HTTPAPIEX_SAS_Destroy(HTTPAPIEX_SAS_HANDLE handle) +{ + /*Codes_SRS_HTTPAPIEXSAS_06_005: [If the parameter handle is NULL then HTTAPIEX_SAS_Destroy shall do nothing and return.]*/ + if (handle) + { + HTTPAPIEX_SAS_STATE* state = (HTTPAPIEX_SAS_STATE*)handle; + /*Codes_SRS_HTTPAPIEXSAS_06_006: [HTTAPIEX_SAS_Destroy shall deallocate any structures denoted by the parameter handle.]*/ + if (state->key) + { + STRING_delete(state->key); + } + if (state->uriResource) + { + STRING_delete(state->uriResource); + } + if (state->keyName) + { + STRING_delete(state->keyName); + } + free(state); + } +} + +HTTPAPIEX_RESULT HTTPAPIEX_SAS_ExecuteRequest(HTTPAPIEX_SAS_HANDLE sasHandle, HTTPAPIEX_HANDLE handle, HTTPAPI_REQUEST_TYPE requestType, const char* relativePath, HTTP_HEADERS_HANDLE requestHttpHeadersHandle, BUFFER_HANDLE requestContent, unsigned int* statusCode, HTTP_HEADERS_HANDLE responseHeadersHandle, BUFFER_HANDLE responseContent) +{ + /*Codes_SRS_HTTPAPIEXSAS_06_007: [If the parameter sasHandle is NULL then HTTPAPIEX_SAS_ExecuteRequest shall simply invoke HTTPAPIEX_ExecuteRequest with the remaining parameters (following sasHandle) as its arguments and shall return immediately with the result of that call as the result of HTTPAPIEX_SAS_ExecuteRequest.]*/ + if (sasHandle != NULL) + { + /*Codes_SRS_HTTPAPIEXSAS_06_008: [if the parameter requestHttpHeadersHandle is NULL then fallthrough.]*/ + if (requestHttpHeadersHandle != NULL) + { + /*Codes_SRS_HTTPAPIEXSAS_06_009: [HTTPHeaders_FindHeaderValue shall be invoked with the requestHttpHeadersHandle as its first argument and the string "Authorization" as its second argument.]*/ + /*Codes_SRS_HTTPAPIEXSAS_06_010: [If the return result of the invocation of HTTPHeaders_FindHeaderValue is NULL then fallthrough.]*/ + if (HTTPHeaders_FindHeaderValue(requestHttpHeadersHandle, "Authorization") != NULL) + { + HTTPAPIEX_SAS_STATE* state = (HTTPAPIEX_SAS_STATE*)sasHandle; + /*Codes_SRS_HTTPAPIEXSAS_06_018: [A value of type time_t that shall be known as currentTime is obtained from calling get_time.]*/ + time_t currentTime = get_time(NULL); + /*Codes_SRS_HTTPAPIEXSAS_06_019: [If the value of currentTime is (time_t)-1 is then fallthrough.]*/ + if (currentTime == (time_t)-1) + { + LogError("Time does not appear to be working.\r\n"); + } + else + { + /*Codes_SRS_HTTPAPIEXSAS_06_011: [SASToken_Create shall be invoked.]*/ + /*Codes_SRS_HTTPAPIEXSAS_06_012: [If the return result of SASToken_Create is NULL then fallthrough.]*/ + size_t expiry = (size_t)(difftime(currentTime, 0) + 3600); + STRING_HANDLE newSASToken = SASToken_Create(state->key, state->uriResource, state->keyName, expiry); + if (newSASToken != NULL) + { + /*Codes_SRS_HTTPAPIEXSAS_06_013: [HTTPHeaders_ReplaceHeaderNameValuePair shall be invoked with "Authorization" as its second argument and STRING_c_str (newSASToken) as its third argument.]*/ + if (HTTPHeaders_ReplaceHeaderNameValuePair(requestHttpHeadersHandle, "Authorization", STRING_c_str(newSASToken)) != HTTP_HEADERS_OK) + { + /*Codes_SRS_HTTPAPIEXSAS_06_014: [If the result of the invocation of HTTPHeaders_ReplaceHeaderNameValuePair is NOT HTTP_HEADERS_OK then fallthrough.]*/ + LogError("Unable to replace the old SAS Token.\r\n"); + } + /*Codes_SRS_HTTPAPIEXSAS_06_015: [STRING_delete(newSASToken) will be invoked.]*/ + STRING_delete(newSASToken); + } + else + { + LogError("Unable to create a new SAS token.\r\n"); + } + } + } + } + } + /*Codes_SRS_HTTPAPIEXSAS_06_016: [HTTPAPIEX_ExecuteRequest with the remaining parameters (following sasHandle) as its arguments will be invoked and the result of that call is the result of HTTPAPIEX_SAS_ExecuteRequest.]*/ + return HTTPAPIEX_ExecuteRequest(handle,requestType,relativePath,requestHttpHeadersHandle,requestContent,statusCode,responseHeadersHandle,responseContent); +} diff --git a/c/sharedutil/src/httpheaders.c b/c/sharedutil/src/httpheaders.c new file mode 100644 index 00000000..961cf1f2 --- /dev/null +++ b/c/sharedutil/src/httpheaders.c @@ -0,0 +1,336 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include +#ifdef _CRTDBG_MAP_ALLOC +#include +#endif +#include "gballoc.h" + +#include "map.h" +#include "httpheaders.h" +#include "string.h" +#include "crt_abstractions.h" +#include "iot_logging.h" + + +static const char COLON_AND_SPACE[] = { ':', ' ', '\0' }; +#define COLON_AND_SPACE_LENGTH ((sizeof(COLON_AND_SPACE)/sizeof(COLON_AND_SPACE[0]))-1) + +static const char COMMA_AND_SPACE[] = { ',', ' ', '\0' }; +#define COMMA_AND_SPACE_LENGTH ((sizeof(COMMA_AND_SPACE)/sizeof(COMMA_AND_SPACE[0]))-1) + +DEFINE_ENUM_STRINGS(HTTP_HEADERS_RESULT, HTTP_HEADERS_RESULT_VALUES); + +typedef struct HTTP_HEADERS_HANDLE_DATA_TAG +{ + MAP_HANDLE headers; +} HTTP_HEADERS_HANDLE_DATA; + +HTTP_HEADERS_HANDLE HTTPHeaders_Alloc(void) +{ + /*Codes_SRS_HTTP_HEADERS_99_002:[ This API shall produce a HTTP_HANDLE that can later be used in subsequent calls to the module.]*/ + HTTP_HEADERS_HANDLE_DATA* result; + result = (HTTP_HEADERS_HANDLE_DATA*)malloc(sizeof(HTTP_HEADERS_HANDLE_DATA)); + + if (result == NULL) + { + LogError("malloc failed\r\n"); + } + else + { + /*Codes_SRS_HTTP_HEADERS_99_004:[ After a successful init, HTTPHeaders_GetHeaderCount shall report 0 existing headers.]*/ + result->headers = Map_Create(NULL); + if (result->headers == NULL) + { + LogError("Map_Create failed\r\n"); + free(result); + result = NULL; + } + else + { + /*all is fine*/ + } + } + + /*Codes_SRS_HTTP_HEADERS_99_003:[ The function shall return NULL when the function cannot execute properly]*/ + return (HTTP_HEADERS_HANDLE)result; +} + +/*Codes_SRS_HTTP_HEADERS_99_005:[ Calling this API shall de-allocate the data structures allocated by previous API calls to the same handle.]*/ +void HTTPHeaders_Free(HTTP_HEADERS_HANDLE handle) +{ + /*Codes_SRS_HTTP_HEADERS_02_001: [If httpHeadersHandle is NULL then HTTPHeaders_Free shall perform no action.] */ + if (handle == NULL) + { + /*do nothing*/ + } + else + { + /*Codes_SRS_HTTP_HEADERS_99_005:[ Calling this API shall de-allocate the data structures allocated by previous API calls to the same handle.]*/ + HTTP_HEADERS_HANDLE_DATA* handleData = (HTTP_HEADERS_HANDLE_DATA*)handle; + + Map_Destroy(handleData->headers); + free(handleData); + } +} + +/*Codes_SRS_HTTP_HEADERS_99_012:[ Calling this API shall record a header from name and value parameters.]*/ +static HTTP_HEADERS_RESULT headers_ReplaceHeaderNameValuePair(HTTP_HEADERS_HANDLE handle, const char* name, const char* value, bool replace) +{ + HTTP_HEADERS_RESULT result; + /*Codes_SRS_HTTP_HEADERS_99_014:[ The function shall return when the handle is not valid or when name parameter is NULL or when value parameter is NULL.]*/ + if ( + (handle == NULL) || + (name == NULL) || + (value == NULL) + ) + { + result = HTTP_HEADERS_INVALID_ARG; + LogError("invalid arg (NULL) , result= %s\r\n", ENUM_TO_STRING(HTTP_HEADERS_RESULT, result)); + } + else + { + /*Codes_SRS_HTTP_HEADERS_99_036:[ If name contains the characters outside character codes 33 to 126 then the return value shall be HTTP_HEADERS_INVALID_ARG]*/ + /*Codes_SRS_HTTP_HEADERS_99_031:[ If name contains the character ":" then the return value shall be HTTP_HEADERS_INVALID_ARG.]*/ + size_t i; + size_t nameLen = strlen(name); + for (i = 0; i < nameLen; i++) + { + if ((name[i] < 33) || (126 < name[i]) || (name[i] == ':')) + { + break; + } + } + + if (i < nameLen) + { + result = HTTP_HEADERS_INVALID_ARG; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTP_HEADERS_RESULT, result)); + } + else + { + HTTP_HEADERS_HANDLE_DATA* handleData = (HTTP_HEADERS_HANDLE_DATA*)handle; + const char* existingValue = Map_GetValueFromKey(handleData->headers, name); + /*eat up the whitespaces from value, as per RFC 2616, chapter 4.2 "The field value MAY be preceded by any amount of LWS, though a single SP is preferred."*/ + /*Codes_SRS_HTTP_HEADERS_02_002: [The LWS from the beginning of the value shall not be stored.] */ + while ((value[0] == ' ') || (value[0] == '\t') || (value[0] == '\r') || (value[0] == '\n')) + { + value++; + } + + if (!replace && (existingValue != NULL)) + { + char* newValue = (char*)malloc(strlen(existingValue) + COMMA_AND_SPACE_LENGTH + strlen(value) + 1); + if (newValue == NULL) + { + /*Codes_SRS_HTTP_HEADERS_99_015:[ The function shall return HTTP_HEADERS_ALLOC_FAILED when an internal request to allocate memory fails.]*/ + result = HTTP_HEADERS_ALLOC_FAILED; + LogError("failed to malloc , result= %s\r\n", ENUM_TO_STRING(HTTP_HEADERS_RESULT, result)); + } + else + { + /*Codes_SRS_HTTP_HEADERS_99_017:[ If the name already exists in the collection of headers, the function shall concatenate the new value after the existing value, separated by a comma and a space as in: old-value+", "+new-value.]*/ + (void)strcpy(newValue, existingValue); + (void)strcat(newValue, COMMA_AND_SPACE); + (void)strcat(newValue, value); + + /*Codes_SRS_HTTP_HEADERS_99_016:[ The function shall store the name:value pair in such a way that when later retrieved by a call to GetHeader it will return a string that shall strcmp equal to the name+": "+value.]*/ + if (Map_AddOrUpdate(handleData->headers, name, newValue) != MAP_OK) + { + /*Codes_SRS_HTTP_HEADERS_99_015:[ The function shall return HTTP_HEADERS_ALLOC_FAILED when an internal request to allocate memory fails.]*/ + result = HTTP_HEADERS_ERROR; + LogError("failed to Map_AddOrUpdate, result= %s\r\n", ENUM_TO_STRING(HTTP_HEADERS_RESULT, result)); + } + else + { + /*Codes_SRS_HTTP_HEADERS_99_013:[ The function shall return HTTP_HEADERS_OK when execution is successful.]*/ + result = HTTP_HEADERS_OK; + } + free(newValue); + } + } + else + { + /*Codes_SRS_HTTP_HEADERS_99_016:[ The function shall store the name:value pair in such a way that when later retrieved by a call to GetHeader it will return a string that shall strcmp equal to the name+": "+value.]*/ + if (Map_AddOrUpdate(handleData->headers, name, value) != MAP_OK) + { + /*Codes_SRS_HTTP_HEADERS_99_015:[ The function shall return HTTP_HEADERS_ALLOC_FAILED when an internal request to allocate memory fails.]*/ + result = HTTP_HEADERS_ALLOC_FAILED; + LogError("failed to Map_AddOrUpdate, result= %s\r\n", ENUM_TO_STRING(HTTP_HEADERS_RESULT, result)); + } + else + { + result = HTTP_HEADERS_OK; + } + } + } + } + + return result; +} + +HTTP_HEADERS_RESULT HTTPHeaders_AddHeaderNameValuePair(HTTP_HEADERS_HANDLE httpHeadersHandle, const char* name, const char* value) +{ + return headers_ReplaceHeaderNameValuePair(httpHeadersHandle, name, value, false); +} + +/* Codes_SRS_HTTP_HEADERS_06_001: [This API will perform exactly as HTTPHeaders_AddHeaderNameValuePair except that if the header name already exists the already existing value will be replaced as opposed to concatenated to.] */ +HTTP_HEADERS_RESULT HTTPHeaders_ReplaceHeaderNameValuePair(HTTP_HEADERS_HANDLE httpHeadersHandle, const char* name, const char* value) +{ + return headers_ReplaceHeaderNameValuePair(httpHeadersHandle, name, value, true); +} + + +const char* HTTPHeaders_FindHeaderValue(HTTP_HEADERS_HANDLE httpHeadersHandle, const char* name) +{ + const char* result; + /*Codes_SRS_HTTP_HEADERS_99_022:[ The return value shall be NULL if name parameter is NULL or if httpHeadersHandle is NULL]*/ + if ( + (httpHeadersHandle == NULL) || + (name == NULL) + ) + { + result = NULL; + } + else + { + /*Codes_SRS_HTTP_HEADERS_99_018:[ Calling this API shall retrieve the value for a previously stored name.]*/ + /*Codes_SRS_HTTP_HEADERS_99_020:[ The return value shall be different than NULL when the name matches the name of a previously stored name:value pair.] */ + /*Codes_SRS_HTTP_HEADERS_99_021:[ In this case the return value shall point to a string that shall strcmp equal to the original stored string.]*/ + HTTP_HEADERS_HANDLE_DATA* handleData = (HTTP_HEADERS_HANDLE_DATA*)httpHeadersHandle; + result = Map_GetValueFromKey(handleData->headers, name); + } + return result; + +} + +HTTP_HEADERS_RESULT HTTPHeaders_GetHeaderCount(HTTP_HEADERS_HANDLE handle, size_t* headerCount) +{ + HTTP_HEADERS_RESULT result; + /*Codes_SRS_HTTP_HEADERS_99_024:[ The function shall return HTTP_HEADERS_INVALID_ARG when an invalid handle is passed.]*/ + /*Codes_SRS_HTTP_HEADERS_99_025:[ The function shall return HTTP_HEADERS_INVALID_ARG when headersCount is NULL.]*/ + if ((handle == NULL) || + (headerCount == NULL)) + { + result = HTTP_HEADERS_INVALID_ARG; + LogError("(result = %s)\r\n", ENUM_TO_STRING(HTTP_HEADERS_RESULT, result)); + } + else + { + HTTP_HEADERS_HANDLE_DATA *handleData = (HTTP_HEADERS_HANDLE_DATA *)handle; + const char*const* keys; + const char*const* values; + /*Codes_SRS_HTTP_HEADERS_99_023:[ Calling this API shall provide the number of stored headers.]*/ + if (Map_GetInternals(handleData->headers, &keys, &values, headerCount) != MAP_OK) + { + /*Codes_SRS_HTTP_HEADERS_99_037:[ The function shall return HTTP_HEADERS_ERROR when an internal error occurs.]*/ + result = HTTP_HEADERS_ERROR; + LogError("Map_GetInternals failed, result= %s\r\n", ENUM_TO_STRING(HTTP_HEADERS_RESULT, result)); + } + else + { + /*Codes_SRS_HTTP_HEADERS_99_026:[ The function shall write in *headersCount the number of currently stored headers and shall return HTTP_HEADERS_OK]*/ + result = HTTP_HEADERS_OK; + } + } + + return result; +} + +/*produces a string in *destination that is equal to name: value*/ +HTTP_HEADERS_RESULT HTTPHeaders_GetHeader(HTTP_HEADERS_HANDLE handle, size_t index, char** destination) +{ + HTTP_HEADERS_RESULT result = HTTP_HEADERS_OK; + + /*Codes_SRS_HTTP_HEADERS_99_028:[ The function shall return NULL if the handle is invalid.]*/ + /*Codes_SRS_HTTP_HEADERS_99_032:[ The function shall return HTTP_HEADERS_INVALID_ARG if the destination is NULL]*/ + if ( + (handle == NULL) || + (destination == NULL) + ) + { + result = HTTP_HEADERS_INVALID_ARG; + LogError("invalid arg (NULL), result= %s\r\n", ENUM_TO_STRING(HTTP_HEADERS_RESULT, result)); + } + /*Codes_SRS_HTTP_HEADERS_99_029:[ The function shall return HTTP_HEADERS_INVALID_ARG if index is not valid (for example, out of range) for the currently stored headers.]*/ + else + { + HTTP_HEADERS_HANDLE_DATA* handleData = (HTTP_HEADERS_HANDLE_DATA*)handle; + const char*const* keys; + const char*const* values; + size_t headerCount; + if (Map_GetInternals(handleData->headers, &keys, &values, &headerCount) != MAP_OK) + { + /*Codes_SRS_HTTP_HEADERS_99_034:[ The function shall return HTTP_HEADERS_ERROR when an internal error occurs]*/ + result = HTTP_HEADERS_ERROR; + LogError("Map_GetInternals failed, result= %s\r\n", ENUM_TO_STRING(HTTP_HEADERS_RESULT, result)); + } + else + { + /*Codes_SRS_HTTP_HEADERS_99_029:[ The function shall return HTTP_HEADERS_INVALID_ARG if index is not valid (for example, out of range) for the currently stored headers.]*/ + if (index >= headerCount) + { + result = HTTP_HEADERS_INVALID_ARG; + LogError("index out of bounds, result= %s\r\n", ENUM_TO_STRING(HTTP_HEADERS_RESULT, result)); + } + else + { + *destination = (char*)malloc(strlen(keys[index]) + COLON_AND_SPACE_LENGTH + strlen(values[index]) + 1); + if (*destination == NULL) + { + /*Codes_SRS_HTTP_HEADERS_99_034:[ The function shall return HTTP_HEADERS_ERROR when an internal error occurs]*/ + result = HTTP_HEADERS_ERROR; + LogError("unable to malloc, result= %s\r\n", ENUM_TO_STRING(HTTP_HEADERS_RESULT, result)); + } + else + { + /*Codes_SRS_HTTP_HEADERS_99_016:[ The function shall store the name:value pair in such a way that when later retrieved by a call to GetHeader it will return a string that shall strcmp equal to the name+": "+value.]*/ + /*Codes_SRS_HTTP_HEADERS_99_027:[ Calling this API shall produce the string value+": "+pair) for the index header in the *destination parameter.]*/ + strcpy(*destination, keys[index]); + strcat(*destination, COLON_AND_SPACE); + strcat(*destination, values[index]); + /*Codes_SRS_HTTP_HEADERS_99_035:[ The function shall return HTTP_HEADERS_OK when the function executed without error.]*/ + result = HTTP_HEADERS_OK; + } + } + } + } + + return result; +} + +HTTP_HEADERS_HANDLE HTTPHeaders_Clone(HTTP_HEADERS_HANDLE handle) +{ + HTTP_HEADERS_HANDLE_DATA* result; + /*Codes_SRS_HTTP_HEADERS_02_003: [If handle is NULL then HTTPHeaders_Clone shall return NULL.] */ + if (handle == NULL) + { + result = NULL; + } + else + { + /*Codes_SRS_HTTP_HEADERS_02_004: [Otherwise HTTPHeaders_Clone shall clone the content of handle to a new handle.] */ + result = malloc(sizeof(HTTP_HEADERS_HANDLE_DATA)); + if (result == NULL) + { + /*Codes_SRS_HTTP_HEADERS_02_005: [If cloning fails for any reason, then HTTPHeaders_Clone shall return NULL.] */ + } + else + { + HTTP_HEADERS_HANDLE_DATA* handleData = handle; + result->headers = Map_Clone(handleData->headers); + if (result->headers == NULL) + { + /*Codes_SRS_HTTP_HEADERS_02_005: [If cloning fails for any reason, then HTTPHeaders_Clone shall return NULL.] */ + free(result); + result = NULL; + } + else + { + /*all is fine*/ + } + } + } + return result; +} diff --git a/c/sharedutil/src/io.c b/c/sharedutil/src/io.c new file mode 100644 index 00000000..6e9c38db --- /dev/null +++ b/c/sharedutil/src/io.c @@ -0,0 +1,161 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include +#ifdef _CRTDBG_MAP_ALLOC +#include +#endif +#include +#include "io.h" + +typedef struct IO_INSTANCE_TAG +{ + const IO_INTERFACE_DESCRIPTION* io_interface_description; + IO_HANDLE concrete_io_handle; +} IO_INSTANCE; + +IO_HANDLE io_create(const IO_INTERFACE_DESCRIPTION* io_interface_description, const void* io_create_parameters, LOGGER_LOG logger_log) +{ + IO_INSTANCE* io_instance; + /* Codes_SRS_IO_01_003: [If the argument io_interface_description is NULL, io_create shall return NULL.] */ + if ((io_interface_description == NULL) || + /* Codes_SRS_IO_01_004: [If any io_interface_description member is NULL, io_create shall return NULL.] */ + (io_interface_description->concrete_io_create == NULL) || + (io_interface_description->concrete_io_destroy == NULL) || + (io_interface_description->concrete_io_open == NULL) || + (io_interface_description->concrete_io_close == NULL) || + (io_interface_description->concrete_io_send == NULL) || + (io_interface_description->concrete_io_dowork == NULL)) + { + io_instance = NULL; + } + else + { + io_instance = (IO_INSTANCE*)malloc(sizeof(IO_INSTANCE)); + + /* Codes_SRS_IO_01_017: [If allocating the memory needed for the IO interface fails then io_create shall return NULL.] */ + if (io_instance != NULL) + { + /* Codes_SRS_IO_01_001: [io_create shall return on success a non-NULL handle to a new IO interface.] */ + io_instance->io_interface_description = io_interface_description; + + /* Codes_SRS_IO_01_002: [In order to instantiate the concrete IO implementation the function concrete_io_create from the io_interface_description shall be called, passing the io_create_parameters and logger_log arguments.] */ + io_instance->concrete_io_handle = io_instance->io_interface_description->concrete_io_create((void*)io_create_parameters, logger_log); + + /* Codes_SRS_IO_01_016: [If the underlying concrete_io_create call fails, io_create shall return NULL.] */ + if (io_instance->concrete_io_handle == NULL) + { + free(io_instance); + io_instance = NULL; + } + } + } + return (IO_HANDLE)io_instance; +} + +void io_destroy(IO_HANDLE io) +{ + if (io != NULL) + { + IO_INSTANCE* io_instance = (IO_INSTANCE*)io; + + /* Codes_SRS_IO_01_006: [io_destroy shall also call the concrete_io_destroy function that is member of the io_interface_description argument passed to io_create, while passing as argument to concrete_io_destroy the result of the underlying concrete_io_create handle that was called as part of the io_create call.] */ + io_instance->io_interface_description->concrete_io_destroy(io_instance->concrete_io_handle); + + /* Codes_SRS_IO_01_005: [io_destroy shall free all resources associated with the IO handle.] */ + free(io_instance); + } +} + +int io_open(IO_HANDLE io, ON_BYTES_RECEIVED on_bytes_received, ON_IO_STATE_CHANGED on_io_state_changed, void* callback_context) +{ + int result; + + if (io == NULL) + { + /* Codes_SRS_IO_01_021: [If handle is NULL, io_open shall return a non-zero value.] */ + result = __LINE__; + } + else + { + IO_INSTANCE* io_instance = (IO_INSTANCE*)io; + + /* Codes_SRS_IO_01_019: [io_open shall call the specific concrete_io_open function specified in io_create, passing the receive_callback and receive_callback_context arguments.] */ + if (io_instance->io_interface_description->concrete_io_open(io_instance->concrete_io_handle, on_bytes_received, on_io_state_changed, callback_context) != 0) + { + /* Codes_SRS_IO_01_022: [If the underlying concrete_io_open fails, io_open shall return a non-zero value.] */ + result = __LINE__; + } + else + { + /* Codes_SRS_IO_01_020: [On success, io_open shall return 0.] */ + result = 0; + } + } + + return result; +} + +int io_close(IO_HANDLE io) +{ + int result; + + if (io == NULL) + { + /* Codes_SRS_IO_01_025: [If handle is NULL, io_close shall return a non-zero value.] */ + result = __LINE__; + } + else + { + IO_INSTANCE* io_instance = (IO_INSTANCE*)io; + + /* Codes_SRS_IO_01_023: [io_close shall call the specific concrete_io_close function specified in io_create.] */ + if (io_instance->io_interface_description->concrete_io_close(io_instance->concrete_io_handle) != 0) + { + /* Codes_SRS_IO_01_026: [If the underlying concrete_io_close fails, io_close shall return a non-zero value.] */ + result = __LINE__; + } + else + { + /* Codes_SRS_IO_01_024: [On success, io_close shall return 0.] */ + result = 0; + } + } + + return result; +} + +int io_send(IO_HANDLE io, const void* buffer, size_t size) +{ + int result; + + /* Codes_SRS_IO_01_011: [No error check shall be performed on buffer and size.] */ + /* Codes_SRS_IO_01_010: [If handle is NULL, io_send shall return a non-zero value.] */ + if (io == NULL) + { + result = __LINE__; + } + else + { + IO_INSTANCE* io_instance = (IO_INSTANCE*)io; + + /* Codes_SRS_IO_01_008: [io_send shall pass the sequence of bytes pointed to by buffer to the concrete IO implementation specified in io_create, by calling the concrete_io_send function while passing down the buffer and size arguments to it.] */ + /* Codes_SRS_IO_01_009: [On success, io_send shall return 0.] */ + /* Codes_SRS_IO_01_015: [If the underlying concrete_io_send fails, io_send shall return a non-zero value.] */ + result = io_instance->io_interface_description->concrete_io_send(io_instance->concrete_io_handle, buffer, size); + } + + return result; +} + +void io_dowork(IO_HANDLE io) +{ + /* Codes_SRS_IO_01_018: [When the handle argument is NULL, io_dowork shall do nothing.] */ + if (io != NULL) + { + IO_INSTANCE* io_instance = (IO_INSTANCE*)io; + + /* Codes_SRS_IO_01_012: [io_dowork shall call the concrete IO implementation specified in io_create, by calling the concrete_io_dowork function.] */ + io_instance->io_interface_description->concrete_io_dowork(io_instance->concrete_io_handle); + } +} diff --git a/c/sharedutil/src/list.c b/c/sharedutil/src/list.c new file mode 100644 index 00000000..ee350a56 --- /dev/null +++ b/c/sharedutil/src/list.c @@ -0,0 +1,232 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include +#ifdef _CRTDBG_MAP_ALLOC +#include +#endif +#include +#include "list.h" + +typedef struct LIST_ITEM_TAG +{ + const void* item; + void* next; +} LIST_ITEM; + +typedef struct LIST_DATA_TAG +{ + LIST_ITEM* head; +} LIST_DATA; + +LIST_HANDLE list_create(void) +{ + LIST_DATA* result; + + /* Codes_SRS_LIST_01_001: [list_create shall create a new list and return a non-NULL handle on success.] */ + result = (LIST_DATA*)malloc(sizeof(LIST_DATA)); + if (result != NULL) + { + /* Codes_SRS_LIST_01_002: [If any error occurs during the list creation, list_create shall return NULL.] */ + result->head = NULL; + } + return result; +} + +void list_destroy(LIST_HANDLE handle) +{ + /* Codes_SRS_LIST_01_004: [If the handle argument is NULL, no freeing of resources shall occur.] */ + if (handle != NULL) + { + /* Codes_SRS_LIST_01_003: [list_destroy shall free all resources associated with the list identified by the handle argument.] */ + free(handle); + } +} + +int list_add(LIST_HANDLE handle, const void* item) +{ + int result; + + /* Codes_SRS_LIST_01_006: [If any of the arguments is NULL, list_add shall not add the item to the list and return a non-zero value.] */ + if ((handle == NULL) || (item == NULL)) + { + result = __LINE__; + } + else + { + LIST_DATA* list = (LIST_DATA*)handle; + LIST_ITEM* new_item = malloc(sizeof(LIST_ITEM)); + + if (new_item == NULL) + { + /* Codes_SRS_LIST_01_007: [If allocating the new list node fails, list_add shall return a non-zero value.] */ + result = __LINE__; + } + else + { + /* Codes_SRS_LIST_01_005: [list_add shall add one item to the tail of the list and on success it shall return 0.] */ + new_item->next = NULL; + new_item->item = item; + + if (list->head == NULL) + { + list->head = new_item; + } + else + { + LIST_ITEM* current = list->head; + while (current->next != NULL) + { + current = current->next; + } + + current->next = new_item; + } + + result = 0; + } + } + return result; +} + +LIST_ITEM_HANDLE list_get_head_item(LIST_HANDLE handle) +{ + LIST_DATA* list = (LIST_DATA*)handle; + LIST_ITEM_HANDLE result; + + if (list == NULL) + { + /* Codes_SRS_LIST_01_009: [If the handle argument is NULL, list_get_head_item shall return NULL.] */ + result = NULL; + } + else + { + /* Codes_SRS_LIST_01_008: [list_get_head_item shall return the head of the list.] */ + /* Codes_SRS_LIST_01_010: [If the list is empty, list_get_head_item_shall_return NULL.] */ + result = list->head; + } + return result; +} + +LIST_ITEM_HANDLE list_get_next_item(LIST_ITEM_HANDLE item_handle) +{ + LIST_ITEM_HANDLE result; + + if (item_handle == NULL) + { + /* Codes_SRS_LIST_01_019: [If item_handle is NULL then list_get_next_item shall return NULL.] */ + result = NULL; + } + else + { + /* Codes_SRS_LIST_01_018: [list_get_next_item shall return the next item in the list following the item item_handle.] */ + result = ((LIST_ITEM*)item_handle)->next; + } + return result; +} + +const void* list_item_get_value(LIST_ITEM_HANDLE item_handle) +{ + const void* result; + + if (item_handle == NULL) + { + /* Codes_SRS_LIST_01_021: [If item_handle is NULL, list_item_get_value shall return NULL.] */ + result = NULL; + } + else + { + /* Codes_SRS_LIST_01_020: [list_item_get_value shall return the value associated with the list item identified by the item_handle argument.] */ + result = ((LIST_ITEM*)item_handle)->item; + } + return result; +} + +LIST_ITEM_HANDLE list_find(LIST_HANDLE handle, LIST_MATCH_FUNCTION match_function, const void* match_context) +{ + LIST_ITEM_HANDLE result; + + if ((handle == NULL) || + (match_function == NULL)) + { + /* Codes_SRS_LIST_01_012: [If the handle or the match_function argument is NULL, list_find shall return NULL.] */ + result = NULL; + } + else + { + LIST_DATA* list = (LIST_DATA*)handle; + LIST_ITEM* current = list->head; + + /* Codes_SRS_LIST_01_011: [list_find shall iterate through all items in a list and return the one that satisfies a certain match function.] */ + while (current != NULL) + { + /* Codes_SRS_LIST_01_014: [list find shall determine whether an item satisfies the match criteria by invoking the match function for each item in the list until a matching item is found.] */ + /* Codes_SRS_LIST_01_013: [The match_function shall get as arguments the list item being attempted to be matched and the match_context as is.] */ + if (match_function((LIST_ITEM_HANDLE)current, match_context) == true) + { + /* Codes_SRS_LIST_01_017: [If the match function returns true, list_find shall consider that item as matching.] */ + break; + } + + /* Codes_SRS_LIST_01_016: [If the match function returns false, list_find shall consider that item as not matching.] */ + current = current->next; + } + + if (current == NULL) + { + /* Codes_SRS_LIST_01_015: [If the list is empty, list_find shall return NULL.] */ + result = NULL; + } + else + { + result = current; + } + } + return result; +} + +int list_remove_matching_item(LIST_HANDLE handle, LIST_MATCH_FUNCTION match_function, const void* match_context) +{ + int result; + if ((handle == NULL) || + (match_function == NULL)) + { + result = __LINE__; + } + else + { + LIST_DATA* list = (LIST_DATA*)handle; + LIST_ITEM* current = list->head; + LIST_ITEM* previous = NULL; + + while (current != NULL) + { + if (match_function((LIST_ITEM_HANDLE)current, match_context) == true) + { + break; + } + current = current->next; + } + + if (current == NULL) + { + result = __LINE__; + } + else + { + if (previous == NULL) + { + list->head = previous; + } + else + { + previous->next = current->next; + } + free((void*)current->item); + free(current); + + result = 0; + } + } + return result; +} diff --git a/c/sharedutil/src/map.c b/c/sharedutil/src/map.c new file mode 100644 index 00000000..3569161a --- /dev/null +++ b/c/sharedutil/src/map.c @@ -0,0 +1,586 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include +#ifdef _CRTDBG_MAP_ALLOC +#include +#endif +#include "gballoc.h" + +#include "map.h" +#include "iot_logging.h" + +DEFINE_ENUM_STRINGS(MAP_RESULT, MAP_RESULT_VALUES); + +typedef struct MAP_HANDLE_DATA_TAG +{ + char** keys; + char** values; + size_t count; + MAP_FILTER_CALLBACK mapFilterCallback; +}MAP_HANDLE_DATA; + +#define LOG_MAP_ERROR LogError("result = %s\r\n", ENUM_TO_STRING(MAP_RESULT, result)); + +MAP_HANDLE Map_Create(MAP_FILTER_CALLBACK mapFilterFunc) +{ + /*Codes_SRS_MAP_02_001: [Map_Create shall create a new, empty map.]*/ + MAP_HANDLE_DATA* result = (MAP_HANDLE_DATA*)malloc(sizeof(MAP_HANDLE_DATA)); + /*Codes_SRS_MAP_02_002: [If during creation there are any error, then Map_Create shall return NULL.]*/ + if (result != NULL) + { + /*Codes_SRS_MAP_02_003: [Otherwise, it shall return a non-NULL handle that can be used in subsequent calls.] */ + result->keys = NULL; + result->values = NULL; + result->count = 0; + result->mapFilterCallback = mapFilterFunc; + } + return result; +} + +void Map_Destroy(MAP_HANDLE handle) +{ + /*Codes_SRS_MAP_02_005: [If parameter handle is NULL then Map_Destroy shall take no action.] */ + if (handle != NULL) + { + /*Codes_SRS_MAP_02_004: [Map_Destroy shall release all resources associated with the map.] */ + MAP_HANDLE_DATA* handleData = (MAP_HANDLE_DATA*)handle; + size_t i; + + for (i = 0; i < handleData->count; i++) + { + free(handleData->keys[i]); + free(handleData->values[i]); + } + free(handleData->keys); + free(handleData->values); + free(handleData); + } +} + +/*makes a copy of a vector of const char*, having size "size". source cannot be NULL*/ +/*returns NULL if it fails*/ +static char** Map_CloneVector(const char*const * source, size_t count) +{ + char** result; + result = (char**)malloc(count *sizeof(char*)); + if (result == NULL) + { + /*do nothing, just return it (NULL)*/ + } + else + { + size_t i; + for (i = 0; i < count; i++) + { + if (mallocAndStrcpy_s(result + i, source[i]) != 0) + { + break; + } + } + + if (i == count) + { + /*it is all good, proceed to return result*/ + } + else + { + size_t j; + for (j = 0; j < i; j++) + { + free(result[j]); + } + free(result); + result = NULL; + } + } + return result; +} + +/*Codes_SRS_MAP_02_039: [Map_Clone shall make a copy of the map indicated by parameter handle and return a non-NULL handle to it.]*/ +MAP_HANDLE Map_Clone(MAP_HANDLE handle) +{ + MAP_HANDLE_DATA* result; + if (handle == NULL) + { + /*Codes_SRS_MAP_02_038: [Map_Clone returns NULL if parameter handle is NULL.]*/ + result = NULL; + LogError("invalid arg to Map_Clone (NULL)\r\n"); + } + else + { + MAP_HANDLE_DATA * handleData = (MAP_HANDLE_DATA *)handle; + result = (MAP_HANDLE_DATA*)malloc(sizeof(MAP_HANDLE_DATA)); + if (result == NULL) + { + /*Codes_SRS_MAP_02_047: [If during cloning, any operation fails, then Map_Clone shall return NULL.] */ + /*do nothing, proceed to return it, this is an error case*/ + LogError("unable to malloc\r\n"); + } + else + { + if (handleData->count == 0) + { + result->count = 0; + result->keys = NULL; + result->values = NULL; + result->mapFilterCallback = NULL; + } + else + { + result->mapFilterCallback = handleData->mapFilterCallback; + result->count = handleData->count; + if( (result->keys = Map_CloneVector((const char* const*)handleData->keys, handleData->count))==NULL) + { + /*Codes_SRS_MAP_02_047: [If during cloning, any operation fails, then Map_Clone shall return NULL.] */ + LogError("unable to clone keys\r\n"); + free(result); + result = NULL; + } + else if ((result->values = Map_CloneVector((const char* const*)handleData->values, handleData->count)) == NULL) + { + /*Codes_SRS_MAP_02_047: [If during cloning, any operation fails, then Map_Clone shall return NULL.] */ + LogError("unable to clone values\r\n"); + size_t i; + for (i = 0; i < result->count; i++) + { + free(result->keys[i]); + } + free(result->keys); + free(result); + result = NULL; + } + else + { + /*all fine, return it*/ + } + } + } + } + return result; +} + +static int Map_IncreaseStorageKeysValues(MAP_HANDLE_DATA* handleData) +{ + int result; + char** newKeys = (char**)realloc(handleData->keys, (handleData->count + 1) * sizeof(char*)); + if (newKeys == NULL) + { + LogError("realloc error\r\n"); + result = __LINE__; + } + else + { + char** newValues; + handleData->keys = newKeys; + handleData->keys[handleData->count] = NULL; + newValues = (char**)realloc(handleData->values, (handleData->count + 1) * sizeof(char*)); + if (newValues == NULL) + { + LogError("realloc error\r\n"); + if (handleData->count == 0) /*avoiding an implementation defined behavior */ + { + free(handleData->keys); + handleData->keys = NULL; + } + else + { + char** undoneKeys = (char**)realloc(handleData->keys, (handleData->count) * sizeof(char*)); + if (undoneKeys == NULL) + { + LogError("CATASTROPHIC error, unable to undo through realloc to a smaller size\r\n"); + } + else + { + handleData->keys = undoneKeys; + } + } + result = __LINE__; + } + else + { + handleData->values = newValues; + handleData->values[handleData->count] = NULL; + handleData->count++; + result = 0; + } + } + return result; +} + +static void Map_DecreaseStorageKeysValues(MAP_HANDLE_DATA* handleData) +{ + if (handleData->count == 1) + { + free(handleData->keys); + handleData->keys = NULL; + free(handleData->values); + handleData->values = NULL; + handleData->count = 0; + handleData->mapFilterCallback = NULL; + } + else + { + /*certainly > 1...*/ + char** undoneKeys = (char**)realloc(handleData->keys, sizeof(char*)* (handleData->count - 1)); + if (undoneKeys == NULL) + { + LogError("CATASTROPHIC error, unable to undo through realloc to a smaller size\r\n"); + } + else + { + handleData->keys = undoneKeys; + } + + char** undoneValues = (char**)realloc(handleData->values, sizeof(char*)* (handleData->count - 1)); + if (undoneValues == NULL) + { + LogError("CATASTROPHIC error, unable to undo through realloc to a smaller size\r\n"); + } + else + { + handleData->values = undoneValues; + } + + handleData->count--; + } +} + +static char** findKey(MAP_HANDLE_DATA* handleData, const char* key) +{ + char** result; + if (handleData->keys == NULL) + { + result = NULL; + } + else + { + size_t i; + result = NULL; + for (i = 0; i < handleData->count; i++) + { + if (strcmp(handleData->keys[i], key) == 0) + { + result = handleData->keys + i; + break; + } + } + } + return result; +} + +static char** findValue(MAP_HANDLE_DATA* handleData, const char* value) +{ + char** result; + if (handleData->values == NULL) + { + result = NULL; + } + else + { + size_t i; + result = NULL; + for (i = 0; i < handleData->count; i++) + { + if (strcmp(handleData->values[i], value) == 0) + { + result = handleData->values + i; + break; + } + } + } + return result; +} + +static int insertNewKeyValue(MAP_HANDLE_DATA* handleData, const char* key, const char* value) +{ + int result; + if (Map_IncreaseStorageKeysValues(handleData) != 0) /*this increases handleData->count*/ + { + result = __LINE__; + } + else + { + if (mallocAndStrcpy_s(&(handleData->keys[handleData->count - 1]), key) != 0) + { + Map_DecreaseStorageKeysValues(handleData); + LogError("unable to mallocAndStrcpy_s\r\n"); + result = __LINE__; + } + else + { + if (mallocAndStrcpy_s(&(handleData->values[handleData->count - 1]), value) != 0) + { + free(handleData->keys[handleData->count - 1]); + Map_DecreaseStorageKeysValues(handleData); + LogError("unable to mallocAndStrcpy_s\r\n"); + result = __LINE__; + } + else + { + result = 0; + } + } + } + return result; +} + +MAP_RESULT Map_Add(MAP_HANDLE handle, const char* key, const char* value) +{ + MAP_RESULT result; + /*Codes_SRS_MAP_02_006: [If parameter handle is NULL then Map_Add shall return MAP_INVALID_ARG.] */ + /*Codes_SRS_MAP_02_007: [If parameter key is NULL then Map_Add shall return MAP_INVALID_ARG.]*/ + /*Codes_SRS_MAP_02_008: [If parameter value is NULL then Map_Add shall return MAP_INVALID_ARG.] */ + if ( + (handle == NULL) || + (key == NULL) || + (value == NULL) + ) + { + result = MAP_INVALIDARG; + LOG_MAP_ERROR; + } + else + { + MAP_HANDLE_DATA* handleData = (MAP_HANDLE_DATA*)handle; + /*Codes_SRS_MAP_02_009: [If the key already exists, then Map_Add shall return MAP_KEYEXISTS.] */ + if (findKey(handleData, key) != NULL) + { + result = MAP_KEYEXISTS; + } + else + { + /* Codes_SRS_MAP_07_009: [If the mapFilterCallback function is not NULL, then the return value will be check and if it is not zero then Map_Add shall return MAP_FILTER_REJECT.] */ + if ( (handleData->mapFilterCallback != NULL) && (handleData->mapFilterCallback(key, value) != 0) ) + { + result = MAP_FILTER_REJECT; + } + else + { + /*Codes_SRS_MAP_02_010: [Otherwise, Map_Add shall add the pair to the map.] */ + if (insertNewKeyValue(handleData, key, value) != 0) + { + /*Codes_SRS_MAP_02_011: [If adding the pair fails then Map_Add shall return MAP_ERROR.] */ + result = MAP_ERROR; + LOG_MAP_ERROR; + } + else + { + /*Codes_SRS_MAP_02_012: [Otherwise, Map_Add shall return MAP_OK.] */ + result = MAP_OK; + } + } + } + } + return result; +} + +MAP_RESULT Map_AddOrUpdate(MAP_HANDLE handle, const char* key, const char* value) +{ + MAP_RESULT result; + /*Codes_SRS_MAP_02_013: [If parameter handle is NULL then Map_AddOrUpdate shall return MAP_INVALID_ARG.]*/ + /*Codes_SRS_MAP_02_014: [If parameter key is NULL then Map_AddOrUpdate shall return MAP_INVALID_ARG.]*/ + /*Codes_SRS_MAP_02_015: [If parameter value is NULL then Map_AddOrUpdate shall return MAP_INVALID_ARG.] */ + if ( + (handle == NULL) || + (key == NULL) || + (value == NULL) + ) + { + result = MAP_INVALIDARG; + LOG_MAP_ERROR; + } + else + { + MAP_HANDLE_DATA* handleData = (MAP_HANDLE_DATA*)handle; + + /* Codes_SRS_MAP_07_008: [If the mapFilterCallback function is not NULL, then the return value will be check and if it is not zero then Map_AddOrUpdate shall return MAP_FILTER_REJECT.] */ + if (handleData->mapFilterCallback != NULL && handleData->mapFilterCallback(key, value) != 0) + { + result = MAP_FILTER_REJECT; + } + else + { + char** whereIsIt = findKey(handleData, key); + if (whereIsIt == NULL) + { + /*Codes_SRS_MAP_02_017: [Otherwise, Map_AddOrUpdate shall add the pair to the map.]*/ + if (insertNewKeyValue(handleData, key, value) != 0) + { + result = MAP_ERROR; + LOG_MAP_ERROR; + } + else + { + result = MAP_OK; + } + } + else + { + /*Codes_SRS_MAP_02_016: [If the key already exists, then Map_AddOrUpdate shall overwrite the value of the existing key with parameter value.]*/ + size_t index = whereIsIt - handleData->keys; + size_t valueLength = strlen(value); + /*try to realloc value of this key*/ + char* newValue = (char*)realloc(handleData->values[index],valueLength + 1); + if (newValue == NULL) + { + result = MAP_ERROR; + LOG_MAP_ERROR; + } + else + { + memcpy(newValue, value, valueLength + 1); + handleData->values[index] = newValue; + /*Codes_SRS_MAP_02_019: [Otherwise, Map_AddOrUpdate shall return MAP_OK.] */ + result = MAP_OK; + } + } + } + } + return result; +} + +MAP_RESULT Map_Delete(MAP_HANDLE handle, const char* key) +{ + MAP_RESULT result; + /*Codes_SRS_MAP_02_020: [If parameter handle is NULL then Map_Delete shall return MAP_INVALIDARG.]*/ + /*Codes_SRS_MAP_02_021: [If parameter key is NULL then Map_Delete shall return MAP_INVALIDARG.]*/ + if ( + (handle == NULL) || + (key == NULL) + ) + { + result = MAP_INVALIDARG; + LOG_MAP_ERROR; + } + else + { + MAP_HANDLE_DATA* handleData = (MAP_HANDLE_DATA*)handle; + char** whereIsIt = findKey(handleData,key); + if (whereIsIt == NULL) + { + /*Codes_SRS_MAP_02_022: [If key does not exist then Map_Delete shall return MAP_KEYNOTFOUND.]*/ + result = MAP_KEYNOTFOUND; + } + else + { + /*Codes_SRS_MAP_02_023: [Otherwise, Map_Delete shall remove the key and its associated value from the map and return MAP_OK.]*/ + size_t index = whereIsIt - handleData->keys; + free(handleData->keys[index]); + free(handleData->values[index]); + memmove(handleData->keys + index, handleData->keys + index + 1, (handleData->count - index - 1)*sizeof(char*)); /*if order doesn't matter... then this can be optimized*/ + memmove(handleData->values + index, handleData->values + index + 1, (handleData->count - index - 1)*sizeof(char*)); + Map_DecreaseStorageKeysValues(handleData); + result = MAP_OK; + } + + } + return result; +} + +MAP_RESULT Map_ContainsKey(MAP_HANDLE handle, const char* key, bool* keyExists) +{ + MAP_RESULT result; + /*Codes_SRS_MAP_02_024: [If parameter handle, key or keyExists are NULL then Map_ContainsKey shall return MAP_INVALIDARG.]*/ + if ( + (handle ==NULL) || + (key == NULL) || + (keyExists == NULL) + ) + { + result = MAP_INVALIDARG; + LOG_MAP_ERROR; + } + else + { + MAP_HANDLE_DATA* handleData = (MAP_HANDLE_DATA*)handle; + /*Codes_SRS_MAP_02_025: [Otherwise if a key exists then Map_ContainsKey shall return MAP_OK and shall write in keyExists "true".]*/ + /*Codes_SRS_MAP_02_026: [If a key doesn't exist, then Map_ContainsKey shall return MAP_OK and write in keyExists "false".] */ + *keyExists = (findKey(handleData, key) != NULL) ? true: false; + result = MAP_OK; + } + return result; +} + +MAP_RESULT Map_ContainsValue(MAP_HANDLE handle, const char* value, bool* valueExists) +{ + MAP_RESULT result; + /*Codes_SRS_MAP_02_027: [If parameter handle, value or valueExists is NULL then Map_ContainsValue shall return MAP_INVALIDARG.] */ + if ( + (handle == NULL) || + (value == NULL) || + (valueExists == NULL) + ) + { + result = MAP_INVALIDARG; + LOG_MAP_ERROR; + } + else + { + MAP_HANDLE_DATA* handleData = (MAP_HANDLE_DATA*)handle; + /*Codes_SRS_MAP_02_028: [Otherwise, if a pair has its value equal to the parameter value, the Map_ContainsValue shall return MAP_OK and shall write in valueExists "true".]*/ + /*Codes_SRS_MAP_02_029: [Otherwise, if such a does not exist, then Map_ContainsValue shall return MAP_OK and shall write in valueExists "false".] */ + *valueExists = (findValue(handleData, value) != NULL) ? true : false; + result = MAP_OK; + } + return result; +} + +const char* Map_GetValueFromKey(MAP_HANDLE handle, const char* key) +{ + const char* result; + /*Codes_SRS_MAP_02_040: [If parameter handle or key is NULL then Map_GetValueFromKey returns NULL.]*/ + if ( + (handle == NULL) || + (key == NULL) + ) + { + result = NULL; + LogError("invalid parameter to Map_GetValueFromKey\r\n"); + } + else + { + MAP_HANDLE_DATA * handleData = (MAP_HANDLE_DATA *)handle; + char** whereIsIt = findKey(handleData, key); + if(whereIsIt == NULL) + { + /*Codes_SRS_MAP_02_041: [If the key is not found, then Map_GetValueFromKey returns NULL.]*/ + result = NULL; + } + else + { + /*Codes_SRS_MAP_02_042: [Otherwise, Map_GetValueFromKey returns the key's value.] */ + size_t index = whereIsIt - handleData->keys; + result = handleData->values[index]; + } + } + return result; +} + +MAP_RESULT Map_GetInternals(MAP_HANDLE handle, const char*const** keys, const char*const** values, size_t* count) +{ + MAP_RESULT result; + /*Codes_SRS_MAP_02_046: [If parameter handle, keys, values or count is NULL then Map_GetInternals shall return MAP_INVALIDARG.] */ + if ( + (handle == NULL) || + (keys == NULL) || + (values == NULL) || + (count == NULL) + ) + { + result = MAP_INVALIDARG; + LOG_MAP_ERROR; + } + else + { + /*Codes_SRS_MAP_02_043: [Map_GetInternals shall produce in *keys an pointer to an array of const char* having all the keys stored so far by the map.]*/ + /*Codes_SRS_MAP_02_044: [Map_GetInternals shall produce in *values a pointer to an array of const char* having all the values stored so far by the map.]*/ + /*Codes_SRS_MAP_02_045: [ Map_GetInternals shall produce in *count the number of stored keys and values.]*/ + MAP_HANDLE_DATA * handleData = (MAP_HANDLE_DATA *)handle; + *keys =(const char* const*)(handleData->keys); + *values = (const char* const*)(handleData->values); + *count = handleData->count; + result = MAP_OK; + } + return result; +} diff --git a/c/sharedutil/src/sastoken.c b/c/sharedutil/src/sastoken.c new file mode 100644 index 00000000..63ad8d9b --- /dev/null +++ b/c/sharedutil/src/sastoken.c @@ -0,0 +1,126 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include +#ifdef _CRTDBG_MAP_ALLOC +#include +#endif +#include "gballoc.h" + +#include +#include + +#include "crt_abstractions.h" +#include "sastoken.h" +#include "urlencode.h" +#include "hmacsha256.h" +#include "base64.h" +#include "agenttime.h" +#include "strings.h" +#include "buffer_.h" +#include "iot_logging.h" + +STRING_HANDLE SASToken_Create(STRING_HANDLE key, STRING_HANDLE scope, STRING_HANDLE keyName, size_t expiry) +{ + STRING_HANDLE result = NULL; + char tokenExpirationTime[32] = { 0 }; + + /*Codes_SRS_SASTOKEN_06_001: [If key is NULL then SASToken_Create shall return NULL.]*/ + /*Codes_SRS_SASTOKEN_06_003: [If scope is NULL then SASToken_Create shall return NULL.]*/ + /*Codes_SRS_SASTOKEN_06_007: [If keyName is NULL then SASToken_Create shall return NULL.]*/ + if ((key == NULL) || + (scope == NULL) || + (keyName == NULL)) + { + LogError("Invalid Parameter to SASToken_Create. handle key: %p, handle scope: %p, handle keyName: %p\r\n", key, scope, keyName); + } + else + { + BUFFER_HANDLE decodedKey; + /*Codes_SRS_SASTOKEN_06_029: [The key parameter is decoded from base64.]*/ + if ((decodedKey = Base64_Decoder(STRING_c_str(key))) == NULL) + { + /*Codes_SRS_SASTOKEN_06_030: [If there is an error in the decoding then SASToken_Create shall return NULL.]*/ + LogError("Unable to decode the key for generating the SAS.\r\n"); + } + else + { + /*Codes_SRS_SASTOKEN_06_026: [If the conversion to string form fails for any reason then SASToken_Create shall return NULL.]*/ + if (size_tToString(tokenExpirationTime, sizeof(tokenExpirationTime), expiry) != 0) + { + LogError("For some reason converting seconds to a string failed. No SAS can be generated.\r\n"); + } + else + { + STRING_HANDLE toBeHashed = NULL; + BUFFER_HANDLE hash = NULL; + if (((hash = BUFFER_new()) == NULL) || + ((toBeHashed = STRING_new()) == NULL) || + ((result = STRING_new()) == NULL)) + { + LogError("Unable to allocate memory to prepare SAS token.\r\n") + } + else + { + /*Codes_SRS_SASTOKEN_06_009: [The scope is the basis for creating a STRING_HANDLE.]*/ + /*Codes_SRS_SASTOKEN_06_010: [A "\n" is appended to that string.]*/ + /*Codes_SRS_SASTOKEN_06_011: [tokenExpirationTime is appended to that string.]*/ + if ((STRING_concat_with_STRING(toBeHashed, scope) != 0) || + (STRING_concat(toBeHashed, "\n") != 0) || + (STRING_concat(toBeHashed, tokenExpirationTime) != 0)) + { + LogError("Unable to build the input to the HMAC to prepare SAS token.\r\n"); + STRING_delete(result); + result = NULL; + } + else + { + STRING_HANDLE base64Signature = NULL; + STRING_HANDLE urlEncodedSignature = NULL; + /*Codes_SRS_SASTOKEN_06_013: [If an error is returned from the HMAC256 function then NULL is returned from SASToken_Create.]*/ + /*Codes_SRS_SASTOKEN_06_012: [An HMAC256 hash is calculated using the decodedKey, over toBeHashed.]*/ + /*Codes_SRS_SASTOKEN_06_014: [If there are any errors from the following operations then NULL shall be returned.]*/ + /*Codes_SRS_SASTOKEN_06_015: [The hash is base 64 encoded.]*/ + /*Codes_SRS_SASTOKEN_06_028: [base64Signature shall be url encoded.]*/ + /*Codes_SRS_SASTOKEN_06_016: [The string "SharedAccessSignature sr=" is the first part of the result of SASToken_Create.]*/ + /*Codes_SRS_SASTOKEN_06_017: [The scope parameter is appended to result.]*/ + /*Codes_SRS_SASTOKEN_06_018: [The string "&sig=" is appended to result.]*/ + /*Codes_SRS_SASTOKEN_06_019: [The string urlEncodedSignature shall be appended to result.]*/ + /*Codes_SRS_SASTOKEN_06_020: [The string "&se=" shall be appended to result.]*/ + /*Codes_SRS_SASTOKEN_06_021: [tokenExpirationTime is appended to result.]*/ + /*Codes_SRS_SASTOKEN_06_022: [The string "&skn=" is appended to result.]*/ + /*Codes_SRS_SASTOKEN_06_023: [The argument keyName is appended to result.]*/ + if ((HMACSHA256_ComputeHash(BUFFER_u_char(decodedKey), BUFFER_length(decodedKey), (const unsigned char*)STRING_c_str(toBeHashed), STRING_length(toBeHashed), hash) != HMACSHA256_OK) || + ((base64Signature = Base64_Encode(hash)) == NULL) || + ((urlEncodedSignature = URL_Encode(base64Signature)) == NULL) || + (STRING_copy(result, "SharedAccessSignature sr=") != 0) || + (STRING_concat_with_STRING(result, scope) != 0) || + (STRING_concat(result, "&sig=") != 0) || + (STRING_concat_with_STRING(result, urlEncodedSignature) != 0) || + (STRING_concat(result, "&se=") != 0) || + (STRING_concat(result, tokenExpirationTime) != 0) || + (STRING_concat(result, "&skn=") != 0) || + (STRING_concat_with_STRING(result, keyName) != 0)) + { + LogError("Unable to build the SAS token.\r\n"); + STRING_delete(result); + result = NULL; + } + else + { + /* everything OK */ + } + STRING_delete(base64Signature); + STRING_delete(urlEncodedSignature); + } + } + STRING_delete(toBeHashed); + BUFFER_delete(hash); + } + BUFFER_delete(decodedKey); + } + } + + return result; +} + diff --git a/c/sharedutil/src/sha1.c b/c/sharedutil/src/sha1.c new file mode 100644 index 00000000..d8fcda49 --- /dev/null +++ b/c/sharedutil/src/sha1.c @@ -0,0 +1,441 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/**************************** sha1.c ****************************/ +/******************** See RFC 4634 for details ******************/ +/* +* Description: +* This file implements the Secure Hash Signature Standard +* algorithms as defined in the National Institute of Standards +* and Technology Federal Information Processing Standards +* Publication (FIPS PUB) 180-1 published on April 17, 1995, 180-2 +* published on August 1, 2002, and the FIPS PUB 180-2 Change +* Notice published on February 28, 2004. +* +* A combined document showing all algorithms is available at +* http://csrc.nist.gov/publications/fips/ +* fips180-2/fips180-2withchangenotice.pdf +* +* The SHA-1 algorithm produces a 160-bit message digest for a +* given data stream. It should take about 2**n steps to find a +* message with the same digest as a given message and +* 2**(n/2) to find any two messages with the same digest, +* when n is the digest size in bits. Therefore, this +* algorithm can serve as a means of providing a +* "fingerprint" for a message. +* +* Portability Issues: +* SHA-1 is defined in terms of 32-bit "words". This code +* uses (included via "sha.h") to define 32 and 8 +* bit unsigned integer types. If your C compiler does not +* support 32 bit unsigned integers, this code is not +* appropriate. +* +* Caveats: +* SHA-1 is designed to work with messages less than 2^64 bits +* long. This implementation uses SHA1Input() to hash the bits +* that are a multiple of the size of an 8-bit character, and then +* uses SHA1FinalBits() to hash the final few bits of the input. +*/ + +#include +#ifdef _CRTDBG_MAP_ALLOC +#include +#endif +#include "gballoc.h" + +#include "sha.h" +#include "sha-private.h" + +/* +* Define the SHA1 circular left shift macro +*/ +#define SHA1_ROTL(bits,word) \ + (((word) << (bits)) | ((word) >> (32-(bits)))) + +/* +* add "length" to the length +*/ +static uint32_t addTemp; +#define SHA1AddLength(context, length) \ + (addTemp = (context)->Length_Low, \ + (context)->Corrupted = \ + (((context)->Length_Low += (length)) < addTemp) && \ + (++(context)->Length_High == 0) ? 1 : 0) + +/* Local Function Prototypes */ +static void SHA1Finalize(SHA1Context *context, uint8_t Pad_Byte); +static void SHA1PadMessage(SHA1Context *, uint8_t Pad_Byte); +static void SHA1ProcessMessageBlock(SHA1Context *); + +/* +* SHA1Reset +* +* Description: +* This function will initialize the SHA1Context in preparation +* for computing a new SHA1 message digest. +* +* Parameters: +* context: [in/out] +* The context to reset. +* +* Returns: +* sha Error Code. +* +*/ +int SHA1Reset(SHA1Context *context) +{ + if (!context) + return shaNull; + + context->Length_Low = 0; + context->Length_High = 0; + context->Message_Block_Index = 0; + + + /* Initial Hash Values: FIPS-180-2 section 5.3.1 */ + context->Intermediate_Hash[0] = 0x67452301; + context->Intermediate_Hash[1] = 0xEFCDAB89; + context->Intermediate_Hash[2] = 0x98BADCFE; + context->Intermediate_Hash[3] = 0x10325476; + context->Intermediate_Hash[4] = 0xC3D2E1F0; + + context->Computed = 0; + context->Corrupted = 0; + + return shaSuccess; +} + +/* +* SHA1Input +* +* Description: +* This function accepts an array of octets as the next portion +* of the message. +* +* Parameters: +* context: [in/out] +* The SHA context to update +* message_array: [in] +* An array of characters representing the next portion of +* the message. +* length: [in] +* The length of the message in message_array +* +* Returns: +* sha Error Code. +* +*/ +int SHA1Input(SHA1Context *context, + const uint8_t *message_array, unsigned length) +{ + if (!length) + return shaSuccess; + + if (!context || !message_array) + return shaNull; + + if (context->Computed) { + context->Corrupted = shaStateError; + return shaStateError; + } + + if (context->Corrupted) + return context->Corrupted; + + while (length-- && !context->Corrupted) { + context->Message_Block[context->Message_Block_Index++] = + (*message_array & 0xFF); + + if (!SHA1AddLength(context, 8) && + (context->Message_Block_Index == SHA1_Message_Block_Size)) + SHA1ProcessMessageBlock(context); + + message_array++; + } + + return shaSuccess; +} + +/* +* SHA1FinalBits +* +* Description: +* This function will add in any final bits of the message. +* +* Parameters: +* context: [in/out] +* The SHA context to update +* message_bits: [in] +* The final bits of the message, in the upper portion of the +* byte. (Use 0b###00000 instead of 0b00000### to input the +* three bits ###.) +* length: [in] +* The number of bits in message_bits, between 1 and 7. +* +* Returns: +* sha Error Code. +*/ +int SHA1FinalBits(SHA1Context *context, const uint8_t message_bits, + unsigned int length) +{ + uint8_t masks[8] = { + /* 0 0b00000000 */ 0x00, /* 1 0b10000000 */ 0x80, + /* 2 0b11000000 */ 0xC0, /* 3 0b11100000 */ 0xE0, + /* 4 0b11110000 */ 0xF0, /* 5 0b11111000 */ 0xF8, + /* 6 0b11111100 */ 0xFC, /* 7 0b11111110 */ 0xFE + }; + uint8_t markbit[8] = { + /* 0 0b10000000 */ 0x80, /* 1 0b01000000 */ 0x40, + /* 2 0b00100000 */ 0x20, /* 3 0b00010000 */ 0x10, + /* 4 0b00001000 */ 0x08, /* 5 0b00000100 */ 0x04, + /* 6 0b00000010 */ 0x02, /* 7 0b00000001 */ 0x01 + }; + + if (!length) + return shaSuccess; + + if (!context) + return shaNull; + + if (context->Computed || (length >= 8) || (length == 0)) { + context->Corrupted = shaStateError; + return shaStateError; + } + + if (context->Corrupted) + return context->Corrupted; + + SHA1AddLength(context, length); + SHA1Finalize(context, + (uint8_t)((message_bits & masks[length]) | markbit[length])); + + return shaSuccess; +} + +/* +* SHA1Result +* +* Description: +* This function will return the 160-bit message digest into the +* Message_Digest array provided by the caller. +* NOTE: The first octet of hash is stored in the 0th element, +* the last octet of hash in the 19th element. +* +* Parameters: +* context: [in/out] +* The context to use to calculate the SHA-1 hash. +* Message_Digest: [out] +* Where the digest is returned. +* +* Returns: +* sha Error Code. +* +*/ +int SHA1Result(SHA1Context *context, + uint8_t Message_Digest[SHA1HashSize]) +{ + int i; + + if (!context || !Message_Digest) + return shaNull; + + if (context->Corrupted) + return context->Corrupted; + + if (!context->Computed) + SHA1Finalize(context, 0x80); + + for (i = 0; i < SHA1HashSize; ++i) + Message_Digest[i] = (uint8_t)(context->Intermediate_Hash[i >> 2] + >> 8 * (3 - (i & 0x03))); + + return shaSuccess; +} + +/* +* SHA1Finalize +* +* Description: +* This helper function finishes off the digest calculations. +* +* Parameters: +* context: [in/out] +* The SHA context to update +* Pad_Byte: [in] +* The last byte to add to the digest before the 0-padding +* and length. This will contain the last bits of the message +* followed by another single bit. If the message was an +* exact multiple of 8-bits long, Pad_Byte will be 0x80. +* +* Returns: +* sha Error Code. +* +*/ +static void SHA1Finalize(SHA1Context *context, uint8_t Pad_Byte) +{ + int i; + SHA1PadMessage(context, Pad_Byte); + /* message may be sensitive, clear it out */ + for (i = 0; i < SHA1_Message_Block_Size; ++i) + context->Message_Block[i] = 0; + context->Length_Low = 0; /* and clear length */ + context->Length_High = 0; + context->Computed = 1; +} + +/* +* SHA1PadMessage +* +* Description: +* According to the standard, the message must be padded to an +* even 512 bits. The first padding bit must be a '1'. The last +* 64 bits represent the length of the original message. All bits +* in between should be 0. This helper function will pad the +* message according to those rules by filling the Message_Block +* array accordingly. When it returns, it can be assumed that the +* message digest has been computed. +* +* Parameters: +* context: [in/out] +* The context to pad +* Pad_Byte: [in] +* The last byte to add to the digest before the 0-padding +* and length. This will contain the last bits of the message +* followed by another single bit. If the message was an +* exact multiple of 8-bits long, Pad_Byte will be 0x80. +* +* Returns: +* Nothing. +*/ +static void SHA1PadMessage(SHA1Context *context, uint8_t Pad_Byte) +{ + /* + * Check to see if the current message block is too small to hold + * the initial padding bits and length. If so, we will pad the + * block, process it, and then continue padding into a second + * block. + */ + if (context->Message_Block_Index >= (SHA1_Message_Block_Size - 8)) { + context->Message_Block[context->Message_Block_Index++] = Pad_Byte; + while (context->Message_Block_Index < SHA1_Message_Block_Size) + context->Message_Block[context->Message_Block_Index++] = 0; + + SHA1ProcessMessageBlock(context); + } + else + context->Message_Block[context->Message_Block_Index++] = Pad_Byte; + + while (context->Message_Block_Index < (SHA1_Message_Block_Size - 8)) + context->Message_Block[context->Message_Block_Index++] = 0; + + /* + * Store the message length as the last 8 octets + */ + context->Message_Block[56] = (uint8_t)(context->Length_High >> 24); + context->Message_Block[57] = (uint8_t)(context->Length_High >> 16); + + context->Message_Block[58] = (uint8_t)(context->Length_High >> 8); + context->Message_Block[59] = (uint8_t)(context->Length_High); + context->Message_Block[60] = (uint8_t)(context->Length_Low >> 24); + context->Message_Block[61] = (uint8_t)(context->Length_Low >> 16); + context->Message_Block[62] = (uint8_t)(context->Length_Low >> 8); + context->Message_Block[63] = (uint8_t)(context->Length_Low); + + SHA1ProcessMessageBlock(context); +} + +/* +* SHA1ProcessMessageBlock +* +* Description: +* This helper function will process the next 512 bits of the +* message stored in the Message_Block array. +* +* Parameters: +* None. +* +* Returns: +* Nothing. +* +* Comments: +* Many of the variable names in this code, especially the +* single character names, were used because those were the +* names used in the publication. +*/ +static void SHA1ProcessMessageBlock(SHA1Context *context) +{ + /* Constants defined in FIPS-180-2, section 4.2.1 */ + const uint32_t K[4] = { + 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6 + }; + int t; /* Loop counter */ + uint32_t temp; /* Temporary word value */ + uint32_t W[80]; /* Word sequence */ + uint32_t A, B, C, D, E; /* Word buffers */ + + /* + * Initialize the first 16 words in the array W + */ + for (t = 0; t < 16; t++) { + W[t] = ((uint32_t)context->Message_Block[t * 4]) << 24; + W[t] |= ((uint32_t)context->Message_Block[t * 4 + 1]) << 16; + W[t] |= ((uint32_t)context->Message_Block[t * 4 + 2]) << 8; + W[t] |= ((uint32_t)context->Message_Block[t * 4 + 3]); + } + + for (t = 16; t < 80; t++) + W[t] = SHA1_ROTL(1, W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16]); + + A = context->Intermediate_Hash[0]; + B = context->Intermediate_Hash[1]; + C = context->Intermediate_Hash[2]; + D = context->Intermediate_Hash[3]; + E = context->Intermediate_Hash[4]; + + for (t = 0; t < 20; t++) { + temp = SHA1_ROTL(5, A) + SHA_Ch(B, C, D) + E + W[t] + K[0]; + E = D; + D = C; + C = SHA1_ROTL(30, B); + B = A; + A = temp; + } + + for (t = 20; t < 40; t++) { + temp = SHA1_ROTL(5, A) + SHA_Parity(B, C, D) + E + W[t] + K[1]; + E = D; + D = C; + C = SHA1_ROTL(30, B); + B = A; + A = temp; + } + + for (t = 40; t < 60; t++) { + temp = SHA1_ROTL(5, A) + SHA_Maj(B, C, D) + E + W[t] + K[2]; + E = D; + D = C; + C = SHA1_ROTL(30, B); + B = A; + A = temp; + } + + for (t = 60; t < 80; t++) { + temp = SHA1_ROTL(5, A) + SHA_Parity(B, C, D) + E + W[t] + K[3]; + E = D; + D = C; + C = SHA1_ROTL(30, B); + B = A; + A = temp; + } + + context->Intermediate_Hash[0] += A; + context->Intermediate_Hash[1] += B; + context->Intermediate_Hash[2] += C; + + context->Intermediate_Hash[3] += D; + context->Intermediate_Hash[4] += E; + + context->Message_Block_Index = 0; +} + diff --git a/c/sharedutil/src/sha224.c b/c/sharedutil/src/sha224.c new file mode 100644 index 00000000..ead6987f --- /dev/null +++ b/c/sharedutil/src/sha224.c @@ -0,0 +1,602 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*************************** sha224-256.c ***************************/ +/********************* See RFC 4634 for details *********************/ +/* +* Description: +* This file implements the Secure Hash Signature Standard +* algorithms as defined in the National Institute of Standards +* and Technology Federal Information Processing Standards +* Publication (FIPS PUB) 180-1 published on April 17, 1995, 180-2 +* published on August 1, 2002, and the FIPS PUB 180-2 Change +* Notice published on February 28, 2004. +* +* A combined document showing all algorithms is available at +* http://csrc.nist.gov/publications/fips/ +* fips180-2/fips180-2withchangenotice.pdf +* +* The SHA-224 and SHA-256 algorithms produce 224-bit and 256-bit +* message digests for a given data stream. It should take about +* 2**n steps to find a message with the same digest as a given +* message and 2**(n/2) to find any two messages with the same +* digest, when n is the digest size in bits. Therefore, this +* algorithm can serve as a means of providing a +* "fingerprint" for a message. +* +* Portability Issues: +* SHA-224 and SHA-256 are defined in terms of 32-bit "words". +* This code uses (included via "sha.h") to define 32 +* and 8 bit unsigned integer types. If your C compiler does not +* support 32 bit unsigned integers, this code is not +* appropriate. +* +* Caveats: +* SHA-224 and SHA-256 are designed to work with messages less +* than 2^64 bits long. This implementation uses SHA224/256Input() +* to hash the bits that are a multiple of the size of an 8-bit +* character, and then uses SHA224/256FinalBits() to hash the +* final few bits of the input. +*/ + +#include +#ifdef _CRTDBG_MAP_ALLOC +#include +#endif +#include "gballoc.h" + +#include "sha.h" +#include "sha-private.h" +/* Define the SHA shift, rotate left and rotate right macro */ +#define SHA256_SHR(bits,word) ((word) >> (bits)) +#define SHA256_ROTL(bits,word) \ + (((word) << (bits)) | ((word) >> (32-(bits)))) +#define SHA256_ROTR(bits,word) \ + (((word) >> (bits)) | ((word) << (32-(bits)))) + +/* Define the SHA SIGMA and sigma macros */ +#define SHA256_SIGMA0(word) \ + (SHA256_ROTR( 2,word) ^ SHA256_ROTR(13,word) ^ SHA256_ROTR(22,word)) +#define SHA256_SIGMA1(word) \ + (SHA256_ROTR( 6,word) ^ SHA256_ROTR(11,word) ^ SHA256_ROTR(25,word)) +#define SHA256_sigma0(word) \ + (SHA256_ROTR( 7,word) ^ SHA256_ROTR(18,word) ^ SHA256_SHR( 3,word)) +#define SHA256_sigma1(word) \ + (SHA256_ROTR(17,word) ^ SHA256_ROTR(19,word) ^ SHA256_SHR(10,word)) + +/* +* add "length" to the length +*/ +static uint32_t addTemp; +#define SHA224_256AddLength(context, length) \ + (addTemp = (context)->Length_Low, (context)->Corrupted = \ + (((context)->Length_Low += (length)) < addTemp) && \ + (++(context)->Length_High == 0) ? 1 : 0) + +/* Local Function Prototypes */ +static void SHA224_256Finalize(SHA256Context *context, + uint8_t Pad_Byte); +static void SHA224_256PadMessage(SHA256Context *context, + uint8_t Pad_Byte); +static void SHA224_256ProcessMessageBlock(SHA256Context *context); +static int SHA224_256Reset(SHA256Context *context, uint32_t *H0); +static int SHA224_256ResultN(SHA256Context *context, + uint8_t Message_Digest[], int HashSize); + +/* Initial Hash Values: FIPS-180-2 Change Notice 1 */ +static uint32_t SHA224_H0[SHA256HashSize / 4] = { + 0xC1059ED8, 0x367CD507, 0x3070DD17, 0xF70E5939, + 0xFFC00B31, 0x68581511, 0x64F98FA7, 0xBEFA4FA4 +}; + +/* Initial Hash Values: FIPS-180-2 section 5.3.2 */ +static uint32_t SHA256_H0[SHA256HashSize / 4] = { + 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, + 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19 +}; + +/* +* SHA224Reset +* +* Description: +* This function will initialize the SHA384Context in preparation +* for computing a new SHA224 message digest. +* +* Parameters: +* context: [in/out] +* The context to reset. +* +* Returns: +* sha Error Code. +*/ +int SHA224Reset(SHA224Context *context) +{ + return SHA224_256Reset(context, SHA224_H0); +} + +/* +* SHA224Input +* +* Description: +* This function accepts an array of octets as the next portion +* of the message. +* +* Parameters: +* context: [in/out] +* The SHA context to update +* message_array: [in] +* An array of characters representing the next portion of +* the message. +* length: [in] +* The length of the message in message_array +* +* Returns: +* sha Error Code. +* +*/ +int SHA224Input(SHA224Context *context, const uint8_t *message_array, + unsigned int length) +{ + return SHA256Input(context, message_array, length); +} + +/* +* SHA224FinalBits +* +* Description: +* This function will add in any final bits of the message. +* +* Parameters: +* context: [in/out] +* The SHA context to update +* message_bits: [in] +* The final bits of the message, in the upper portion of the +* byte. (Use 0b###00000 instead of 0b00000### to input the +* three bits ###.) +* length: [in] +* The number of bits in message_bits, between 1 and 7. +* +* Returns: +* sha Error Code. +*/ +int SHA224FinalBits(SHA224Context *context, + const uint8_t message_bits, unsigned int length) +{ + return SHA256FinalBits(context, message_bits, length); +} + +/* +* SHA224Result +* +* Description: +* This function will return the 224-bit message +* digest into the Message_Digest array provided by the caller. +* NOTE: The first octet of hash is stored in the 0th element, +* the last octet of hash in the 28th element. +* +* Parameters: +* context: [in/out] +* The context to use to calculate the SHA hash. +* Message_Digest: [out] +* Where the digest is returned. +* +* Returns: +* sha Error Code. +*/ +int SHA224Result(SHA224Context *context, + uint8_t Message_Digest[SHA224HashSize]) +{ + return SHA224_256ResultN(context, Message_Digest, SHA224HashSize); +} + +/* +* SHA256Reset +* +* Description: +* This function will initialize the SHA256Context in preparation +* for computing a new SHA256 message digest. +* +* Parameters: +* context: [in/out] +* The context to reset. +* +* Returns: +* sha Error Code. +*/ +int SHA256Reset(SHA256Context *context) +{ + return SHA224_256Reset(context, SHA256_H0); +} + +/* +* SHA256Input +* +* Description: +* This function accepts an array of octets as the next portion +* of the message. +* +* Parameters: +* context: [in/out] +* The SHA context to update +* message_array: [in] +* An array of characters representing the next portion of +* the message. +* length: [in] +* The length of the message in message_array +* +* Returns: +* sha Error Code. +*/ +int SHA256Input(SHA256Context *context, const uint8_t *message_array, + unsigned int length) +{ + if (!length) + return shaSuccess; + + if (!context || !message_array) + return shaNull; + + if (context->Computed) { + context->Corrupted = shaStateError; + return shaStateError; + } + + if (context->Corrupted) + return context->Corrupted; + + while (length-- && !context->Corrupted) { + context->Message_Block[context->Message_Block_Index++] = + (*message_array & 0xFF); + + if (!SHA224_256AddLength(context, 8) && + (context->Message_Block_Index == SHA256_Message_Block_Size)) + SHA224_256ProcessMessageBlock(context); + + message_array++; + } + + return shaSuccess; + +} + +/* +* SHA256FinalBits +* +* Description: +* This function will add in any final bits of the message. +* +* Parameters: +* context: [in/out] +* The SHA context to update +* message_bits: [in] +* The final bits of the message, in the upper portion of the +* byte. (Use 0b###00000 instead of 0b00000### to input the +* three bits ###.) +* length: [in] +* The number of bits in message_bits, between 1 and 7. +* +* Returns: +* sha Error Code. +*/ +int SHA256FinalBits(SHA256Context *context, + const uint8_t message_bits, unsigned int length) +{ + uint8_t masks[8] = { + /* 0 0b00000000 */ 0x00, /* 1 0b10000000 */ 0x80, + /* 2 0b11000000 */ 0xC0, /* 3 0b11100000 */ 0xE0, + /* 4 0b11110000 */ 0xF0, /* 5 0b11111000 */ 0xF8, + /* 6 0b11111100 */ 0xFC, /* 7 0b11111110 */ 0xFE + }; + + uint8_t markbit[8] = { + /* 0 0b10000000 */ 0x80, /* 1 0b01000000 */ 0x40, + /* 2 0b00100000 */ 0x20, /* 3 0b00010000 */ 0x10, + /* 4 0b00001000 */ 0x08, /* 5 0b00000100 */ 0x04, + /* 6 0b00000010 */ 0x02, /* 7 0b00000001 */ 0x01 + }; + + if (!length) + return shaSuccess; + + if (!context) + return shaNull; + + if ((context->Computed) || (length >= 8) || (length == 0)) { + context->Corrupted = shaStateError; + return shaStateError; + } + + if (context->Corrupted) + return context->Corrupted; + + SHA224_256AddLength(context, length); + SHA224_256Finalize(context, (uint8_t) + ((message_bits & masks[length]) | markbit[length])); + + return shaSuccess; +} + +/* +* SHA256Result +* +* Description: +* This function will return the 256-bit message +* digest into the Message_Digest array provided by the caller. +* NOTE: The first octet of hash is stored in the 0th element, +* the last octet of hash in the 32nd element. +* +* Parameters: +* context: [in/out] +* The context to use to calculate the SHA hash. +* Message_Digest: [out] +* Where the digest is returned. +* +* Returns: +* sha Error Code. +*/ +int SHA256Result(SHA256Context *context, uint8_t Message_Digest[]) +{ + return SHA224_256ResultN(context, Message_Digest, SHA256HashSize); +} + +/* +* SHA224_256Finalize +* +* Description: +* This helper function finishes off the digest calculations. +* +* Parameters: +* context: [in/out] +* The SHA context to update +* Pad_Byte: [in] +* The last byte to add to the digest before the 0-padding +* and length. This will contain the last bits of the message +* followed by another single bit. If the message was an +* exact multiple of 8-bits long, Pad_Byte will be 0x80. +* +* Returns: +* sha Error Code. +*/ +static void SHA224_256Finalize(SHA256Context *context, + uint8_t Pad_Byte) +{ + int i; + SHA224_256PadMessage(context, Pad_Byte); + /* message may be sensitive, so clear it out */ + for (i = 0; i < SHA256_Message_Block_Size; ++i) + context->Message_Block[i] = 0; + context->Length_Low = 0; /* and clear length */ + context->Length_High = 0; + context->Computed = 1; +} + +/* +* SHA224_256PadMessage +* +* Description: +* According to the standard, the message must be padded to an +* even 512 bits. The first padding bit must be a '1'. The +* last 64 bits represent the length of the original message. +* All bits in between should be 0. This helper function will pad +* the message according to those rules by filling the +* Message_Block array accordingly. When it returns, it can be +* assumed that the message digest has been computed. +* +* Parameters: +* context: [in/out] +* The context to pad +* Pad_Byte: [in] +* The last byte to add to the digest before the 0-padding +* and length. This will contain the last bits of the message +* followed by another single bit. If the message was an +* exact multiple of 8-bits long, Pad_Byte will be 0x80. +* +* Returns: +* Nothing. +*/ +static void SHA224_256PadMessage(SHA256Context *context, + uint8_t Pad_Byte) +{ + /* + * Check to see if the current message block is too small to hold + * the initial padding bits and length. If so, we will pad the + * block, process it, and then continue padding into a second + * block. + */ + if (context->Message_Block_Index >= (SHA256_Message_Block_Size - 8)) { + context->Message_Block[context->Message_Block_Index++] = Pad_Byte; + while (context->Message_Block_Index < SHA256_Message_Block_Size) + context->Message_Block[context->Message_Block_Index++] = 0; + SHA224_256ProcessMessageBlock(context); + } + else + context->Message_Block[context->Message_Block_Index++] = Pad_Byte; + + while (context->Message_Block_Index < (SHA256_Message_Block_Size - 8)) + context->Message_Block[context->Message_Block_Index++] = 0; + + /* + * Store the message length as the last 8 octets + */ + context->Message_Block[56] = (uint8_t)(context->Length_High >> 24); + context->Message_Block[57] = (uint8_t)(context->Length_High >> 16); + context->Message_Block[58] = (uint8_t)(context->Length_High >> 8); + context->Message_Block[59] = (uint8_t)(context->Length_High); + context->Message_Block[60] = (uint8_t)(context->Length_Low >> 24); + context->Message_Block[61] = (uint8_t)(context->Length_Low >> 16); + context->Message_Block[62] = (uint8_t)(context->Length_Low >> 8); + context->Message_Block[63] = (uint8_t)(context->Length_Low); + + SHA224_256ProcessMessageBlock(context); +} + +/* +* SHA224_256ProcessMessageBlock +* +* Description: +* This function will process the next 512 bits of the message +* stored in the Message_Block array. +* +* Parameters: +* context: [in/out] +* The SHA context to update +* +* Returns: +* Nothing. +* +* Comments: +* Many of the variable names in this code, especially the +* single character names, were used because those were the +* names used in the publication. +*/ +static void SHA224_256ProcessMessageBlock(SHA256Context *context) +{ + /* Constants defined in FIPS-180-2, section 4.2.2 */ + static const uint32_t K[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, + 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, + 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, + 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, + 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, + 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, + 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, + 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, + 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, + 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 + }; + int t, t4; /* Loop counter */ + uint32_t temp1, temp2; /* Temporary word value */ + uint32_t W[64]; /* Word sequence */ + uint32_t A, B, C, D, E, F, G, H; /* Word buffers */ + + /* + * Initialize the first 16 words in the array W + */ + for (t = t4 = 0; t < 16; t++, t4 += 4) + W[t] = (((uint32_t)context->Message_Block[t4]) << 24) | + (((uint32_t)context->Message_Block[t4 + 1]) << 16) | + (((uint32_t)context->Message_Block[t4 + 2]) << 8) | + (((uint32_t)context->Message_Block[t4 + 3])); + + for (t = 16; t < 64; t++) + W[t] = SHA256_sigma1(W[t - 2]) + W[t - 7] + + SHA256_sigma0(W[t - 15]) + W[t - 16]; + + A = context->Intermediate_Hash[0]; + B = context->Intermediate_Hash[1]; + C = context->Intermediate_Hash[2]; + D = context->Intermediate_Hash[3]; + E = context->Intermediate_Hash[4]; + F = context->Intermediate_Hash[5]; + G = context->Intermediate_Hash[6]; + H = context->Intermediate_Hash[7]; + + for (t = 0; t < 64; t++) { + temp1 = H + SHA256_SIGMA1(E) + SHA_Ch(E, F, G) + K[t] + W[t]; + temp2 = SHA256_SIGMA0(A) + SHA_Maj(A, B, C); + H = G; + G = F; + F = E; + E = D + temp1; + D = C; + C = B; + B = A; + A = temp1 + temp2; + } + + context->Intermediate_Hash[0] += A; + context->Intermediate_Hash[1] += B; + context->Intermediate_Hash[2] += C; + context->Intermediate_Hash[3] += D; + context->Intermediate_Hash[4] += E; + context->Intermediate_Hash[5] += F; + context->Intermediate_Hash[6] += G; + context->Intermediate_Hash[7] += H; + + context->Message_Block_Index = 0; +} + +/* +* SHA224_256Reset +* +* Description: +* This helper function will initialize the SHA256Context in +* preparation for computing a new SHA256 message digest. +* +* Parameters: +* context: [in/out] +* The context to reset. +* H0 +* The initial hash value to use. +* +* Returns: +* sha Error Code. +*/ +static int SHA224_256Reset(SHA256Context *context, uint32_t *H0) +{ + if (!context) + return shaNull; + + context->Length_Low = 0; + context->Length_High = 0; + context->Message_Block_Index = 0; + + context->Intermediate_Hash[0] = H0[0]; + context->Intermediate_Hash[1] = H0[1]; + context->Intermediate_Hash[2] = H0[2]; + context->Intermediate_Hash[3] = H0[3]; + context->Intermediate_Hash[4] = H0[4]; + context->Intermediate_Hash[5] = H0[5]; + context->Intermediate_Hash[6] = H0[6]; + context->Intermediate_Hash[7] = H0[7]; + + context->Computed = 0; + context->Corrupted = 0; + + return shaSuccess; +} + +/* +* SHA224_256ResultN +* +* Description: +* This helper function will return the 224-bit or 256-bit message +* digest into the Message_Digest array provided by the caller. +* NOTE: The first octet of hash is stored in the 0th element, +* the last octet of hash in the 28th/32nd element. +* +* Parameters: +* context: [in/out] +* The context to use to calculate the SHA hash. +* Message_Digest: [out] +* Where the digest is returned. +* HashSize: [in] +* The size of the hash, either 28 or 32. +* +* Returns: +* sha Error Code. +*/ +static int SHA224_256ResultN(SHA256Context *context, + uint8_t Message_Digest[], int HashSize) +{ + int i; + + if (!context || !Message_Digest) + return shaNull; + + if (context->Corrupted) + return context->Corrupted; + + if (!context->Computed) + SHA224_256Finalize(context, 0x80); + + for (i = 0; i < HashSize; ++i) + Message_Digest[i] = (uint8_t) + (context->Intermediate_Hash[i >> 2] >> 8 * (3 - (i & 0x03))); + + return shaSuccess; +} + diff --git a/c/sharedutil/src/sha384-512.c b/c/sharedutil/src/sha384-512.c new file mode 100644 index 00000000..c8ee238a --- /dev/null +++ b/c/sharedutil/src/sha384-512.c @@ -0,0 +1,1047 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*************************** sha384-512.c ***************************/ +/********************* See RFC 4634 for details *********************/ +/* +* Description: +* This file implements the Secure Hash Signature Standard +* algorithms as defined in the National Institute of Standards +* and Technology Federal Information Processing Standards +* Publication (FIPS PUB) 180-1 published on April 17, 1995, 180-2 +* published on August 1, 2002, and the FIPS PUB 180-2 Change +* Notice published on February 28, 2004. +* +* A combined document showing all algorithms is available at +* http://csrc.nist.gov/publications/fips/ +* fips180-2/fips180-2withchangenotice.pdf +* +* The SHA-384 and SHA-512 algorithms produce 384-bit and 512-bit +* message digests for a given data stream. It should take about +* 2**n steps to find a message with the same digest as a given +* message and 2**(n/2) to find any two messages with the same +* digest, when n is the digest size in bits. Therefore, this +* algorithm can serve as a means of providing a +* "fingerprint" for a message. +* +* Portability Issues: +* SHA-384 and SHA-512 are defined in terms of 64-bit "words", +* but if USE_32BIT_ONLY is #defined, this code is implemented in +* terms of 32-bit "words". This code uses (included +* via "sha.h") to define the 64, 32 and 8 bit unsigned integer +* types. If your C compiler does not support 64 bit unsigned +* integers, and you do not #define USE_32BIT_ONLY, this code is +* not appropriate. +* +* Caveats: +* SHA-384 and SHA-512 are designed to work with messages less +* than 2^128 bits long. This implementation uses +* SHA384/512Input() to hash the bits that are a multiple of the +* size of an 8-bit character, and then uses SHA384/256FinalBits() +* to hash the final few bits of the input. +* +*/ + +#include +#ifdef _CRTDBG_MAP_ALLOC +#include +#endif +#include "gballoc.h" + +#include "sha.h" +#include "sha-private.h" + +#ifdef USE_32BIT_ONLY +/* +* Define 64-bit arithmetic in terms of 32-bit arithmetic. +* Each 64-bit number is represented in a 2-word array. +* All macros are defined such that the result is the last parameter. +*/ + +/* +* Define shift, rotate left and rotate right functions +*/ +#define SHA512_SHR(bits, word, ret) ( \ + /* (((uint64_t)((word))) >> (bits)) */ \ + (ret)[0] = (((bits) < 32) && ((bits) >= 0)) ? \ + ((word)[0] >> (bits)) : 0, \ + (ret)[1] = ((bits) > 32) ? ((word)[0] >> ((bits) - 32)) : \ + ((bits) == 32) ? (word)[0] : \ + ((bits) >= 0) ? \ + (((word)[0] << (32 - (bits))) | \ + ((word)[1] >> (bits))) : 0 ) + +#define SHA512_SHL(bits, word, ret) ( \ + /* (((uint64_t)(word)) << (bits)) */ \ + (ret)[0] = ((bits) > 32) ? ((word)[1] << ((bits) - 32)) : \ + ((bits) == 32) ? (word)[1] : \ + ((bits) >= 0) ? \ + (((word)[0] << (bits)) | \ + ((word)[1] >> (32 - (bits)))) : \ +0, \ +(ret)[1] = (((bits) < 32) && ((bits) >= 0)) ? \ +((word)[1] << (bits)) : 0) + +/* +* Define 64-bit OR +*/ +#define SHA512_OR(word1, word2, ret) ( \ + (ret)[0] = (word1)[0] | (word2)[0], \ + (ret)[1] = (word1)[1] | (word2)[1] ) + +/* +* Define 64-bit XOR +*/ +#define SHA512_XOR(word1, word2, ret) ( \ + (ret)[0] = (word1)[0] ^ (word2)[0], \ + (ret)[1] = (word1)[1] ^ (word2)[1] ) + +/* +* Define 64-bit AND +*/ +#define SHA512_AND(word1, word2, ret) ( \ + (ret)[0] = (word1)[0] & (word2)[0], \ + (ret)[1] = (word1)[1] & (word2)[1] ) + +/* +* Define 64-bit TILDA +*/ +#define SHA512_TILDA(word, ret) \ + ( (ret)[0] = ~(word)[0], (ret)[1] = ~(word)[1] ) + +/* +* Define 64-bit ADD +*/ +#define SHA512_ADD(word1, word2, ret) ( \ + (ret)[1] = (word1)[1], (ret)[1] += (word2)[1], \ + (ret)[0] = (word1)[0] + (word2)[0] + ((ret)[1] < (word1)[1]) ) + +/* +* Add the 4word value in word2 to word1. +*/ +static uint32_t ADDTO4_temp, ADDTO4_temp2; +#define SHA512_ADDTO4(word1, word2) ( \ + ADDTO4_temp = (word1)[3], \ + (word1)[3] += (word2)[3], \ + ADDTO4_temp2 = (word1)[2], \ + (word1)[2] += (word2)[2] + ((word1)[3] < ADDTO4_temp), \ + ADDTO4_temp = (word1)[1], \ +(word1)[1] += (word2)[1] + ((word1)[2] < ADDTO4_temp2), \ +(word1)[0] += (word2)[0] + ((word1)[1] < ADDTO4_temp)) + +/* +* Add the 2word value in word2 to word1. +*/ +static uint32_t ADDTO2_temp; +#define SHA512_ADDTO2(word1, word2) ( \ + ADDTO2_temp = (word1)[1], \ + (word1)[1] += (word2)[1], \ + (word1)[0] += (word2)[0] + ((word1)[1] < ADDTO2_temp) ) + +/* +* SHA rotate ((word >> bits) | (word << (64-bits))) +*/ +static uint32_t ROTR_temp1[2], ROTR_temp2[2]; +#define SHA512_ROTR(bits, word, ret) ( \ + SHA512_SHR((bits), (word), ROTR_temp1), \ + SHA512_SHL(64-(bits), (word), ROTR_temp2), \ + SHA512_OR(ROTR_temp1, ROTR_temp2, (ret)) ) + +/* +* Define the SHA SIGMA and sigma macros +* SHA512_ROTR(28,word) ^ SHA512_ROTR(34,word) ^ SHA512_ROTR(39,word) +*/ +static uint32_t SIGMA0_temp1[2], SIGMA0_temp2[2], +SIGMA0_temp3[2], SIGMA0_temp4[2]; +#define SHA512_SIGMA0(word, ret) ( \ + SHA512_ROTR(28, (word), SIGMA0_temp1), \ + SHA512_ROTR(34, (word), SIGMA0_temp2), \ + SHA512_ROTR(39, (word), SIGMA0_temp3), \ + SHA512_XOR(SIGMA0_temp2, SIGMA0_temp3, SIGMA0_temp4), \ + SHA512_XOR(SIGMA0_temp1, SIGMA0_temp4, (ret)) ) + +/* +* SHA512_ROTR(14,word) ^ SHA512_ROTR(18,word) ^ SHA512_ROTR(41,word) +*/ +static uint32_t SIGMA1_temp1[2], SIGMA1_temp2[2], +SIGMA1_temp3[2], SIGMA1_temp4[2]; +#define SHA512_SIGMA1(word, ret) ( \ + SHA512_ROTR(14, (word), SIGMA1_temp1), \ + SHA512_ROTR(18, (word), SIGMA1_temp2), \ + SHA512_ROTR(41, (word), SIGMA1_temp3), \ + SHA512_XOR(SIGMA1_temp2, SIGMA1_temp3, SIGMA1_temp4), \ + SHA512_XOR(SIGMA1_temp1, SIGMA1_temp4, (ret)) ) + +/* +* (SHA512_ROTR( 1,word) ^ SHA512_ROTR( 8,word) ^ SHA512_SHR( 7,word)) +*/ +static uint32_t sigma0_temp1[2], sigma0_temp2[2], +sigma0_temp3[2], sigma0_temp4[2]; +#define SHA512_sigma0(word, ret) ( \ + SHA512_ROTR( 1, (word), sigma0_temp1), \ + SHA512_ROTR( 8, (word), sigma0_temp2), \ + SHA512_SHR( 7, (word), sigma0_temp3), \ + SHA512_XOR(sigma0_temp2, sigma0_temp3, sigma0_temp4), \ + SHA512_XOR(sigma0_temp1, sigma0_temp4, (ret)) ) + +/* +* (SHA512_ROTR(19,word) ^ SHA512_ROTR(61,word) ^ SHA512_SHR( 6,word)) +*/ +static uint32_t sigma1_temp1[2], sigma1_temp2[2], +sigma1_temp3[2], sigma1_temp4[2]; +#define SHA512_sigma1(word, ret) ( \ + SHA512_ROTR(19, (word), sigma1_temp1), \ + SHA512_ROTR(61, (word), sigma1_temp2), \ + SHA512_SHR( 6, (word), sigma1_temp3), \ + SHA512_XOR(sigma1_temp2, sigma1_temp3, sigma1_temp4), \ + SHA512_XOR(sigma1_temp1, sigma1_temp4, (ret)) ) + +#undef SHA_Ch +#undef SHA_Maj + +#ifndef USE_MODIFIED_MACROS +/* +* These definitions are the ones used in FIPS-180-2, section 4.1.3 +* Ch(x,y,z) ((x & y) ^ (~x & z)) +*/ +static uint32_t Ch_temp1[2], Ch_temp2[2], Ch_temp3[2]; +#define SHA_Ch(x, y, z, ret) ( \ + SHA512_AND(x, y, Ch_temp1), \ + SHA512_TILDA(x, Ch_temp2), \ + SHA512_AND(Ch_temp2, z, Ch_temp3), \ + SHA512_XOR(Ch_temp1, Ch_temp3, (ret)) ) +/* +* Maj(x,y,z) (((x)&(y)) ^ ((x)&(z)) ^ ((y)&(z))) +*/ +static uint32_t Maj_temp1[2], Maj_temp2[2], +Maj_temp3[2], Maj_temp4[2]; +#define SHA_Maj(x, y, z, ret) ( \ + SHA512_AND(x, y, Maj_temp1), \ + SHA512_AND(x, z, Maj_temp2), \ + SHA512_AND(y, z, Maj_temp3), \ + SHA512_XOR(Maj_temp2, Maj_temp3, Maj_temp4), \ + SHA512_XOR(Maj_temp1, Maj_temp4, (ret)) ) + +#else /* !USE_32BIT_ONLY */ +/* +* These definitions are potentially faster equivalents for the ones +* used in FIPS-180-2, section 4.1.3. +* ((x & y) ^ (~x & z)) becomes +* ((x & (y ^ z)) ^ z) +*/ +#define SHA_Ch(x, y, z, ret) ( \ + (ret)[0] = (((x)[0] & ((y)[0] ^ (z)[0])) ^ (z)[0]), \ + (ret)[1] = (((x)[1] & ((y)[1] ^ (z)[1])) ^ (z)[1]) ) + +/* +* ((x & y) ^ (x & z) ^ (y & z)) becomes +* ((x & (y | z)) | (y & z)) +*/ +#define SHA_Maj(x, y, z, ret) ( \ + ret[0] = (((x)[0] & ((y)[0] | (z)[0])) | ((y)[0] & (z)[0])), \ + ret[1] = (((x)[1] & ((y)[1] | (z)[1])) | ((y)[1] & (z)[1])) ) +#endif /* USE_MODIFIED_MACROS */ + +/* +* add "length" to the length +*/ +static uint32_t addTemp[4] = { 0, 0, 0, 0 }; +#define SHA384_512AddLength(context, length) ( \ + addTemp[3] = (length), SHA512_ADDTO4((context)->Length, addTemp), \ + (context)->Corrupted = (((context)->Length[3] == 0) && \ + ((context)->Length[2] == 0) && ((context)->Length[1] == 0) && \ + ((context)->Length[0] < 8)) ? 1 : 0 ) + +/* Local Function Prototypes */ +static void SHA384_512Finalize(SHA512Context *context, + uint8_t Pad_Byte); +static void SHA384_512PadMessage(SHA512Context *context, + uint8_t Pad_Byte); +static void SHA384_512ProcessMessageBlock(SHA512Context *context); +static int SHA384_512Reset(SHA512Context *context, uint32_t H0[]); +static int SHA384_512ResultN(SHA512Context *context, + uint8_t Message_Digest[], int HashSize); + +/* Initial Hash Values: FIPS-180-2 sections 5.3.3 and 5.3.4 */ +static uint32_t SHA384_H0[SHA512HashSize / 4] = { + 0xCBBB9D5D, 0xC1059ED8, 0x629A292A, 0x367CD507, 0x9159015A, + 0x3070DD17, 0x152FECD8, 0xF70E5939, 0x67332667, 0xFFC00B31, + 0x8EB44A87, 0x68581511, 0xDB0C2E0D, 0x64F98FA7, 0x47B5481D, + 0xBEFA4FA4 +}; + +static uint32_t SHA512_H0[SHA512HashSize / 4] = { + 0x6A09E667, 0xF3BCC908, 0xBB67AE85, 0x84CAA73B, 0x3C6EF372, + 0xFE94F82B, 0xA54FF53A, 0x5F1D36F1, 0x510E527F, 0xADE682D1, + 0x9B05688C, 0x2B3E6C1F, 0x1F83D9AB, 0xFB41BD6B, 0x5BE0CD19, + 0x137E2179 +}; + +#else /* !USE_32BIT_ONLY */ + +/* Define the SHA shift, rotate left and rotate right macro */ +#define SHA512_SHR(bits,word) (((uint64_t)(word)) >> (bits)) +#define SHA512_ROTR(bits,word) ((((uint64_t)(word)) >> (bits)) | \ + (((uint64_t)(word)) << (64-(bits)))) + +/* Define the SHA SIGMA and sigma macros */ +#define SHA512_SIGMA0(word) \ + (SHA512_ROTR(28,word) ^ SHA512_ROTR(34,word) ^ SHA512_ROTR(39,word)) +#define SHA512_SIGMA1(word) \ + (SHA512_ROTR(14,word) ^ SHA512_ROTR(18,word) ^ SHA512_ROTR(41,word)) +#define SHA512_sigma0(word) \ + (SHA512_ROTR( 1,word) ^ SHA512_ROTR( 8,word) ^ SHA512_SHR( 7,word)) +#define SHA512_sigma1(word) \ + (SHA512_ROTR(19,word) ^ SHA512_ROTR(61,word) ^ SHA512_SHR( 6,word)) + +/* +* add "length" to the length +*/ +static uint64_t addTemp; +#define SHA384_512AddLength(context, length) \ + (addTemp = context->Length_Low, context->Corrupted = \ + ((context->Length_Low += length) < addTemp) && \ + (++context->Length_High == 0) ? 1 : 0) + +/* Local Function Prototypes */ +static void SHA384_512Finalize(SHA512Context *context, + uint8_t Pad_Byte); +static void SHA384_512PadMessage(SHA512Context *context, + uint8_t Pad_Byte); +static void SHA384_512ProcessMessageBlock(SHA512Context *context); +static int SHA384_512Reset(SHA512Context *context, uint64_t H0[]); +static int SHA384_512ResultN(SHA512Context *context, + uint8_t Message_Digest[], int HashSize); + +/* Initial Hash Values: FIPS-180-2 sections 5.3.3 and 5.3.4 */ +static uint64_t SHA384_H0[] = { + 0xCBBB9D5DC1059ED8ull, 0x629A292A367CD507ull, 0x9159015A3070DD17ull, + 0x152FECD8F70E5939ull, 0x67332667FFC00B31ull, 0x8EB44A8768581511ull, + 0xDB0C2E0D64F98FA7ull, 0x47B5481DBEFA4FA4ull +}; +static uint64_t SHA512_H0[] = { + 0x6A09E667F3BCC908ull, 0xBB67AE8584CAA73Bull, 0x3C6EF372FE94F82Bull, + 0xA54FF53A5F1D36F1ull, 0x510E527FADE682D1ull, 0x9B05688C2B3E6C1Full, + 0x1F83D9ABFB41BD6Bull, 0x5BE0CD19137E2179ull +}; + +#endif /* USE_32BIT_ONLY */ + +/* +* SHA384Reset +* +* Description: +* This function will initialize the SHA384Context in preparation +* for computing a new SHA384 message digest. +* +* Parameters: +* context: [in/out] +* The context to reset. +* +* Returns: +* sha Error Code. +* +*/ +int SHA384Reset(SHA384Context *context) +{ + return SHA384_512Reset(context, SHA384_H0); +} + +/* +* SHA384Input +* +* Description: +* This function accepts an array of octets as the next portion +* of the message. +* +* Parameters: +* context: [in/out] +* The SHA context to update +* message_array: [in] +* An array of characters representing the next portion of +* the message. +* length: [in] +* The length of the message in message_array +* +* Returns: +* sha Error Code. +* +*/ +int SHA384Input(SHA384Context *context, + const uint8_t *message_array, unsigned int length) +{ + return SHA512Input(context, message_array, length); +} + +/* +* SHA384FinalBits +* +* Description: +* This function will add in any final bits of the message. +* +* Parameters: +* context: [in/out] +* The SHA context to update +* message_bits: [in] +* The final bits of the message, in the upper portion of the +* byte. (Use 0b###00000 instead of 0b00000### to input the +* three bits ###.) +* length: [in] +* The number of bits in message_bits, between 1 and 7. +* +* Returns: +* sha Error Code. +* +*/ +int SHA384FinalBits(SHA384Context *context, + const uint8_t message_bits, unsigned int length) +{ + return SHA512FinalBits(context, message_bits, length); +} + +/* +* SHA384Result +* +* Description: +* This function will return the 384-bit message +* digest into the Message_Digest array provided by the caller. +* NOTE: The first octet of hash is stored in the 0th element, +* the last octet of hash in the 48th element. +* +* Parameters: +* context: [in/out] +* The context to use to calculate the SHA hash. +* Message_Digest: [out] +* Where the digest is returned. +* +* Returns: +* sha Error Code. +* +*/ +int SHA384Result(SHA384Context *context, + uint8_t Message_Digest[SHA384HashSize]) +{ + return SHA384_512ResultN(context, Message_Digest, SHA384HashSize); +} + +/* +* SHA512Reset +* +* Description: +* This function will initialize the SHA512Context in preparation +* for computing a new SHA512 message digest. +* +* Parameters: +* context: [in/out] +* The context to reset. +* +* Returns: +* sha Error Code. +* +*/ +int SHA512Reset(SHA512Context *context) +{ + return SHA384_512Reset(context, SHA512_H0); +} + +/* +* SHA512Input +* +* Description: +* This function accepts an array of octets as the next portion +* of the message. +* +* Parameters: +* context: [in/out] +* The SHA context to update +* message_array: [in] +* An array of characters representing the next portion of +* the message. +* length: [in] +* The length of the message in message_array +* +* Returns: +* sha Error Code. +* +*/ +int SHA512Input(SHA512Context *context, + const uint8_t *message_array, + unsigned int length) +{ + if (!length) + return shaSuccess; + + if (!context || !message_array) + return shaNull; + + if (context->Computed) { + context->Corrupted = shaStateError; + return shaStateError; + } + + if (context->Corrupted) + return context->Corrupted; + + while (length-- && !context->Corrupted) { + context->Message_Block[context->Message_Block_Index++] = + (*message_array & 0xFF); + + if (!SHA384_512AddLength(context, 8) && + (context->Message_Block_Index == SHA512_Message_Block_Size)) + SHA384_512ProcessMessageBlock(context); + + message_array++; + } + + return shaSuccess; +} + +/* +* SHA512FinalBits +* +* Description: +* This function will add in any final bits of the message. +* +* Parameters: +* context: [in/out] +* The SHA context to update +* message_bits: [in] +* The final bits of the message, in the upper portion of the +* byte. (Use 0b###00000 instead of 0b00000### to input the +* three bits ###.) +* length: [in] +* The number of bits in message_bits, between 1 and 7. +* +* Returns: +* sha Error Code. +* +*/ +int SHA512FinalBits(SHA512Context *context, + const uint8_t message_bits, unsigned int length) +{ + uint8_t masks[8] = { + /* 0 0b00000000 */ 0x00, /* 1 0b10000000 */ 0x80, + /* 2 0b11000000 */ 0xC0, /* 3 0b11100000 */ 0xE0, + /* 4 0b11110000 */ 0xF0, /* 5 0b11111000 */ 0xF8, + /* 6 0b11111100 */ 0xFC, /* 7 0b11111110 */ 0xFE + }; + uint8_t markbit[8] = { + /* 0 0b10000000 */ 0x80, /* 1 0b01000000 */ 0x40, + /* 2 0b00100000 */ 0x20, /* 3 0b00010000 */ 0x10, + /* 4 0b00001000 */ 0x08, /* 5 0b00000100 */ 0x04, + /* 6 0b00000010 */ 0x02, /* 7 0b00000001 */ 0x01 + }; + + if (!length) + return shaSuccess; + + if (!context) + return shaNull; + + if ((context->Computed) || (length >= 8) || (length == 0)) { + context->Corrupted = shaStateError; + return shaStateError; + } + + if (context->Corrupted) + return context->Corrupted; + + SHA384_512AddLength(context, length); + SHA384_512Finalize(context, (uint8_t) + ((message_bits & masks[length]) | markbit[length])); + + return shaSuccess; +} + +/* +* SHA384_512Finalize +* +* Description: +* This helper function finishes off the digest calculations. +* +* Parameters: +* context: [in/out] +* The SHA context to update +* Pad_Byte: [in] +* The last byte to add to the digest before the 0-padding +* and length. This will contain the last bits of the message +* followed by another single bit. If the message was an +* exact multiple of 8-bits long, Pad_Byte will be 0x80. +* +* Returns: +* sha Error Code. +* +*/ +static void SHA384_512Finalize(SHA512Context *context, + uint8_t Pad_Byte) +{ + int_least16_t i; + SHA384_512PadMessage(context, Pad_Byte); + /* message may be sensitive, clear it out */ + for (i = 0; i < SHA512_Message_Block_Size; ++i) + context->Message_Block[i] = 0; +#ifdef USE_32BIT_ONLY /* and clear length */ + context->Length[0] = context->Length[1] = 0; + context->Length[2] = context->Length[3] = 0; +#else /* !USE_32BIT_ONLY */ + context->Length_Low = 0; + context->Length_High = 0; +#endif /* USE_32BIT_ONLY */ + context->Computed = 1; +} + +/* +* SHA512Result +* +* Description: +* This function will return the 512-bit message +* digest into the Message_Digest array provided by the caller. +* NOTE: The first octet of hash is stored in the 0th element, +* the last octet of hash in the 64th element. +* +* Parameters: +* context: [in/out] +* The context to use to calculate the SHA hash. +* Message_Digest: [out] +* Where the digest is returned. +* +* Returns: +* sha Error Code. +* +*/ +int SHA512Result(SHA512Context *context, + uint8_t Message_Digest[SHA512HashSize]) +{ + return SHA384_512ResultN(context, Message_Digest, SHA512HashSize); +} + +/* +* SHA384_512PadMessage +* +* Description: +* According to the standard, the message must be padded to an +* even 1024 bits. The first padding bit must be a '1'. The +* last 128 bits represent the length of the original message. +* All bits in between should be 0. This helper function will +* pad the message according to those rules by filling the +* Message_Block array accordingly. When it returns, it can be +* assumed that the message digest has been computed. +* +* Parameters: +* context: [in/out] +* The context to pad +* Pad_Byte: [in] +* The last byte to add to the digest before the 0-padding +* and length. This will contain the last bits of the message +* followed by another single bit. If the message was an +* exact multiple of 8-bits long, Pad_Byte will be 0x80. +* +* Returns: +* Nothing. +* +*/ +static void SHA384_512PadMessage(SHA512Context *context, + uint8_t Pad_Byte) +{ + /* + * Check to see if the current message block is too small to hold + * the initial padding bits and length. If so, we will pad the + * block, process it, and then continue padding into a second + * block. + */ + if (context->Message_Block_Index >= (SHA512_Message_Block_Size - 16)) { + context->Message_Block[context->Message_Block_Index++] = Pad_Byte; + while (context->Message_Block_Index < SHA512_Message_Block_Size) + context->Message_Block[context->Message_Block_Index++] = 0; + + SHA384_512ProcessMessageBlock(context); + } + else + context->Message_Block[context->Message_Block_Index++] = Pad_Byte; + + while (context->Message_Block_Index < (SHA512_Message_Block_Size - 16)) + context->Message_Block[context->Message_Block_Index++] = 0; + + /* + * Store the message length as the last 16 octets + */ +#ifdef USE_32BIT_ONLY + context->Message_Block[112] = (uint8_t)(context->Length[0] >> 24); + context->Message_Block[113] = (uint8_t)(context->Length[0] >> 16); + context->Message_Block[114] = (uint8_t)(context->Length[0] >> 8); + context->Message_Block[115] = (uint8_t)(context->Length[0]); + context->Message_Block[116] = (uint8_t)(context->Length[1] >> 24); + context->Message_Block[117] = (uint8_t)(context->Length[1] >> 16); + context->Message_Block[118] = (uint8_t)(context->Length[1] >> 8); + context->Message_Block[119] = (uint8_t)(context->Length[1]); + + context->Message_Block[120] = (uint8_t)(context->Length[2] >> 24); + context->Message_Block[121] = (uint8_t)(context->Length[2] >> 16); + context->Message_Block[122] = (uint8_t)(context->Length[2] >> 8); + context->Message_Block[123] = (uint8_t)(context->Length[2]); + context->Message_Block[124] = (uint8_t)(context->Length[3] >> 24); + context->Message_Block[125] = (uint8_t)(context->Length[3] >> 16); + context->Message_Block[126] = (uint8_t)(context->Length[3] >> 8); + context->Message_Block[127] = (uint8_t)(context->Length[3]); +#else /* !USE_32BIT_ONLY */ + context->Message_Block[112] = (uint8_t)(context->Length_High >> 56); + context->Message_Block[113] = (uint8_t)(context->Length_High >> 48); + context->Message_Block[114] = (uint8_t)(context->Length_High >> 40); + context->Message_Block[115] = (uint8_t)(context->Length_High >> 32); + context->Message_Block[116] = (uint8_t)(context->Length_High >> 24); + context->Message_Block[117] = (uint8_t)(context->Length_High >> 16); + context->Message_Block[118] = (uint8_t)(context->Length_High >> 8); + context->Message_Block[119] = (uint8_t)(context->Length_High); + + context->Message_Block[120] = (uint8_t)(context->Length_Low >> 56); + context->Message_Block[121] = (uint8_t)(context->Length_Low >> 48); + context->Message_Block[122] = (uint8_t)(context->Length_Low >> 40); + context->Message_Block[123] = (uint8_t)(context->Length_Low >> 32); + context->Message_Block[124] = (uint8_t)(context->Length_Low >> 24); + context->Message_Block[125] = (uint8_t)(context->Length_Low >> 16); + context->Message_Block[126] = (uint8_t)(context->Length_Low >> 8); + context->Message_Block[127] = (uint8_t)(context->Length_Low); +#endif /* USE_32BIT_ONLY */ + + SHA384_512ProcessMessageBlock(context); +} + +/* +* SHA384_512ProcessMessageBlock +* +* Description: +* This helper function will process the next 1024 bits of the +* message stored in the Message_Block array. +* +* Parameters: +* context: [in/out] +* The SHA context to update +* +* Returns: +* Nothing. +* +* Comments: +* Many of the variable names in this code, especially the +* single character names, were used because those were the +* names used in the publication. +* +* +*/ +static void SHA384_512ProcessMessageBlock(SHA512Context *context) +{ + /* Constants defined in FIPS-180-2, section 4.2.3 */ +#ifdef USE_32BIT_ONLY + static const uint32_t K[80 * 2] = { + 0x428A2F98, 0xD728AE22, 0x71374491, 0x23EF65CD, 0xB5C0FBCF, + 0xEC4D3B2F, 0xE9B5DBA5, 0x8189DBBC, 0x3956C25B, 0xF348B538, + 0x59F111F1, 0xB605D019, 0x923F82A4, 0xAF194F9B, 0xAB1C5ED5, + 0xDA6D8118, 0xD807AA98, 0xA3030242, 0x12835B01, 0x45706FBE, + 0x243185BE, 0x4EE4B28C, 0x550C7DC3, 0xD5FFB4E2, 0x72BE5D74, + 0xF27B896F, 0x80DEB1FE, 0x3B1696B1, 0x9BDC06A7, 0x25C71235, + 0xC19BF174, 0xCF692694, 0xE49B69C1, 0x9EF14AD2, 0xEFBE4786, + 0x384F25E3, 0x0FC19DC6, 0x8B8CD5B5, 0x240CA1CC, 0x77AC9C65, + 0x2DE92C6F, 0x592B0275, 0x4A7484AA, 0x6EA6E483, 0x5CB0A9DC, + 0xBD41FBD4, 0x76F988DA, 0x831153B5, 0x983E5152, 0xEE66DFAB, + 0xA831C66D, 0x2DB43210, 0xB00327C8, 0x98FB213F, 0xBF597FC7, + 0xBEEF0EE4, 0xC6E00BF3, 0x3DA88FC2, 0xD5A79147, 0x930AA725, + 0x06CA6351, 0xE003826F, 0x14292967, 0x0A0E6E70, 0x27B70A85, + 0x46D22FFC, 0x2E1B2138, 0x5C26C926, 0x4D2C6DFC, 0x5AC42AED, + 0x53380D13, 0x9D95B3DF, 0x650A7354, 0x8BAF63DE, 0x766A0ABB, + 0x3C77B2A8, 0x81C2C92E, 0x47EDAEE6, 0x92722C85, 0x1482353B, + 0xA2BFE8A1, 0x4CF10364, 0xA81A664B, 0xBC423001, 0xC24B8B70, + 0xD0F89791, 0xC76C51A3, 0x0654BE30, 0xD192E819, 0xD6EF5218, + 0xD6990624, 0x5565A910, 0xF40E3585, 0x5771202A, 0x106AA070, + 0x32BBD1B8, 0x19A4C116, 0xB8D2D0C8, 0x1E376C08, 0x5141AB53, + 0x2748774C, 0xDF8EEB99, 0x34B0BCB5, 0xE19B48A8, 0x391C0CB3, + 0xC5C95A63, 0x4ED8AA4A, 0xE3418ACB, 0x5B9CCA4F, 0x7763E373, + 0x682E6FF3, 0xD6B2B8A3, 0x748F82EE, 0x5DEFB2FC, 0x78A5636F, + 0x43172F60, 0x84C87814, 0xA1F0AB72, 0x8CC70208, 0x1A6439EC, + 0x90BEFFFA, 0x23631E28, 0xA4506CEB, 0xDE82BDE9, 0xBEF9A3F7, + 0xB2C67915, 0xC67178F2, 0xE372532B, 0xCA273ECE, 0xEA26619C, + 0xD186B8C7, 0x21C0C207, 0xEADA7DD6, 0xCDE0EB1E, 0xF57D4F7F, + 0xEE6ED178, 0x06F067AA, 0x72176FBA, 0x0A637DC5, 0xA2C898A6, + 0x113F9804, 0xBEF90DAE, 0x1B710B35, 0x131C471B, 0x28DB77F5, + 0x23047D84, 0x32CAAB7B, 0x40C72493, 0x3C9EBE0A, 0x15C9BEBC, + 0x431D67C4, 0x9C100D4C, 0x4CC5D4BE, 0xCB3E42B6, 0x597F299C, + 0xFC657E2A, 0x5FCB6FAB, 0x3AD6FAEC, 0x6C44198C, 0x4A475817 + }; + int t, t2, t8; /* Loop counter */ + uint32_t temp1[2], temp2[2], /* Temporary word values */ + temp3[2], temp4[2], temp5[2]; + uint32_t W[2 * 80]; /* Word sequence */ + uint32_t A[2], B[2], C[2], D[2], /* Word buffers */ + E[2], F[2], G[2], H[2]; + + /* Initialize the first 16 words in the array W */ + for (t = t2 = t8 = 0; t < 16; t++, t8 += 8) { + W[t2++] = ((((uint32_t)context->Message_Block[t8])) << 24) | + ((((uint32_t)context->Message_Block[t8 + 1])) << 16) | + ((((uint32_t)context->Message_Block[t8 + 2])) << 8) | + ((((uint32_t)context->Message_Block[t8 + 3]))); + W[t2++] = ((((uint32_t)context->Message_Block[t8 + 4])) << 24) | + ((((uint32_t)context->Message_Block[t8 + 5])) << 16) | + ((((uint32_t)context->Message_Block[t8 + 6])) << 8) | + ((((uint32_t)context->Message_Block[t8 + 7]))); + } + + for (t = 16; t < 80; t++, t2 += 2) { + /* W[t] = SHA512_sigma1(W[t-2]) + W[t-7] + + SHA512_sigma0(W[t-15]) + W[t-16]; */ + uint32_t *Wt2 = &W[t2 - 2 * 2]; + uint32_t *Wt7 = &W[t2 - 7 * 2]; + uint32_t *Wt15 = &W[t2 - 15 * 2]; + uint32_t *Wt16 = &W[t2 - 16 * 2]; + SHA512_sigma1(Wt2, temp1); + SHA512_ADD(temp1, Wt7, temp2); + SHA512_sigma0(Wt15, temp1); + SHA512_ADD(temp1, Wt16, temp3); + SHA512_ADD(temp2, temp3, &W[t2]); + } + + A[0] = context->Intermediate_Hash[0]; + A[1] = context->Intermediate_Hash[1]; + B[0] = context->Intermediate_Hash[2]; + B[1] = context->Intermediate_Hash[3]; + C[0] = context->Intermediate_Hash[4]; + C[1] = context->Intermediate_Hash[5]; + D[0] = context->Intermediate_Hash[6]; + D[1] = context->Intermediate_Hash[7]; + E[0] = context->Intermediate_Hash[8]; + E[1] = context->Intermediate_Hash[9]; + F[0] = context->Intermediate_Hash[10]; + F[1] = context->Intermediate_Hash[11]; + G[0] = context->Intermediate_Hash[12]; + G[1] = context->Intermediate_Hash[13]; + H[0] = context->Intermediate_Hash[14]; + H[1] = context->Intermediate_Hash[15]; + + for (t = t2 = 0; t < 80; t++, t2 += 2) { + /* + * temp1 = H + SHA512_SIGMA1(E) + SHA_Ch(E,F,G) + K[t] + W[t]; + */ + SHA512_SIGMA1(E, temp1); + SHA512_ADD(H, temp1, temp2); + SHA_Ch(E, F, G, temp3); + SHA512_ADD(temp2, temp3, temp4); + SHA512_ADD(&K[t2], &W[t2], temp5); + SHA512_ADD(temp4, temp5, temp1); + /* + * temp2 = SHA512_SIGMA0(A) + SHA_Maj(A,B,C); + */ + SHA512_SIGMA0(A, temp3); + SHA_Maj(A, B, C, temp4); + SHA512_ADD(temp3, temp4, temp2); + H[0] = G[0]; H[1] = G[1]; + G[0] = F[0]; G[1] = F[1]; + F[0] = E[0]; F[1] = E[1]; + SHA512_ADD(D, temp1, E); + D[0] = C[0]; D[1] = C[1]; + C[0] = B[0]; C[1] = B[1]; + B[0] = A[0]; B[1] = A[1]; + SHA512_ADD(temp1, temp2, A); + } + + SHA512_ADDTO2(&context->Intermediate_Hash[0], A); + SHA512_ADDTO2(&context->Intermediate_Hash[2], B); + SHA512_ADDTO2(&context->Intermediate_Hash[4], C); + SHA512_ADDTO2(&context->Intermediate_Hash[6], D); + SHA512_ADDTO2(&context->Intermediate_Hash[8], E); + SHA512_ADDTO2(&context->Intermediate_Hash[10], F); + SHA512_ADDTO2(&context->Intermediate_Hash[12], G); + SHA512_ADDTO2(&context->Intermediate_Hash[14], H); + +#else /* !USE_32BIT_ONLY */ + static const uint64_t K[80] = { + 0x428A2F98D728AE22ull, 0x7137449123EF65CDull, 0xB5C0FBCFEC4D3B2Full, + 0xE9B5DBA58189DBBCull, 0x3956C25BF348B538ull, 0x59F111F1B605D019ull, + 0x923F82A4AF194F9Bull, 0xAB1C5ED5DA6D8118ull, 0xD807AA98A3030242ull, + 0x12835B0145706FBEull, 0x243185BE4EE4B28Cull, 0x550C7DC3D5FFB4E2ull, + 0x72BE5D74F27B896Full, 0x80DEB1FE3B1696B1ull, 0x9BDC06A725C71235ull, + 0xC19BF174CF692694ull, 0xE49B69C19EF14AD2ull, 0xEFBE4786384F25E3ull, + 0x0FC19DC68B8CD5B5ull, 0x240CA1CC77AC9C65ull, 0x2DE92C6F592B0275ull, + 0x4A7484AA6EA6E483ull, 0x5CB0A9DCBD41FBD4ull, 0x76F988DA831153B5ull, + 0x983E5152EE66DFABull, 0xA831C66D2DB43210ull, 0xB00327C898FB213Full, + 0xBF597FC7BEEF0EE4ull, 0xC6E00BF33DA88FC2ull, 0xD5A79147930AA725ull, + 0x06CA6351E003826Full, 0x142929670A0E6E70ull, 0x27B70A8546D22FFCull, + 0x2E1B21385C26C926ull, 0x4D2C6DFC5AC42AEDull, 0x53380D139D95B3DFull, + 0x650A73548BAF63DEull, 0x766A0ABB3C77B2A8ull, 0x81C2C92E47EDAEE6ull, + 0x92722C851482353Bull, 0xA2BFE8A14CF10364ull, 0xA81A664BBC423001ull, + 0xC24B8B70D0F89791ull, 0xC76C51A30654BE30ull, 0xD192E819D6EF5218ull, + 0xD69906245565A910ull, 0xF40E35855771202Aull, 0x106AA07032BBD1B8ull, + 0x19A4C116B8D2D0C8ull, 0x1E376C085141AB53ull, 0x2748774CDF8EEB99ull, + 0x34B0BCB5E19B48A8ull, 0x391C0CB3C5C95A63ull, 0x4ED8AA4AE3418ACBull, + 0x5B9CCA4F7763E373ull, 0x682E6FF3D6B2B8A3ull, 0x748F82EE5DEFB2FCull, + 0x78A5636F43172F60ull, 0x84C87814A1F0AB72ull, 0x8CC702081A6439ECull, + 0x90BEFFFA23631E28ull, 0xA4506CEBDE82BDE9ull, 0xBEF9A3F7B2C67915ull, + 0xC67178F2E372532Bull, 0xCA273ECEEA26619Cull, 0xD186B8C721C0C207ull, + 0xEADA7DD6CDE0EB1Eull, 0xF57D4F7FEE6ED178ull, 0x06F067AA72176FBAull, + 0x0A637DC5A2C898A6ull, 0x113F9804BEF90DAEull, 0x1B710B35131C471Bull, + 0x28DB77F523047D84ull, 0x32CAAB7B40C72493ull, 0x3C9EBE0A15C9BEBCull, + 0x431D67C49C100D4Cull, 0x4CC5D4BECB3E42B6ull, 0x597F299CFC657E2Aull, + 0x5FCB6FAB3AD6FAECull, 0x6C44198C4A475817ull + }; + int t, t8; /* Loop counter */ + uint64_t temp1, temp2; /* Temporary word value */ + uint64_t W[80]; /* Word sequence */ + uint64_t A, B, C, D, E, F, G, H; /* Word buffers */ + + /* + * Initialize the first 16 words in the array W + */ + for (t = t8 = 0; t < 16; t++, t8 += 8) + W[t] = ((uint64_t)(context->Message_Block[t8]) << 56) | + ((uint64_t)(context->Message_Block[t8 + 1]) << 48) | + ((uint64_t)(context->Message_Block[t8 + 2]) << 40) | + ((uint64_t)(context->Message_Block[t8 + 3]) << 32) | + ((uint64_t)(context->Message_Block[t8 + 4]) << 24) | + ((uint64_t)(context->Message_Block[t8 + 5]) << 16) | + ((uint64_t)(context->Message_Block[t8 + 6]) << 8) | + ((uint64_t)(context->Message_Block[t8 + 7])); + + for (t = 16; t < 80; t++) + W[t] = SHA512_sigma1(W[t - 2]) + W[t - 7] + + SHA512_sigma0(W[t - 15]) + W[t - 16]; + + A = context->Intermediate_Hash[0]; + B = context->Intermediate_Hash[1]; + C = context->Intermediate_Hash[2]; + D = context->Intermediate_Hash[3]; + E = context->Intermediate_Hash[4]; + F = context->Intermediate_Hash[5]; + G = context->Intermediate_Hash[6]; + H = context->Intermediate_Hash[7]; + + for (t = 0; t < 80; t++) { + temp1 = H + SHA512_SIGMA1(E) + SHA_Ch(E, F, G) + K[t] + W[t]; + temp2 = SHA512_SIGMA0(A) + SHA_Maj(A, B, C); + H = G; + G = F; + F = E; + E = D + temp1; + D = C; + C = B; + B = A; + A = temp1 + temp2; + } + + context->Intermediate_Hash[0] += A; + context->Intermediate_Hash[1] += B; + context->Intermediate_Hash[2] += C; + context->Intermediate_Hash[3] += D; + context->Intermediate_Hash[4] += E; + context->Intermediate_Hash[5] += F; + context->Intermediate_Hash[6] += G; + context->Intermediate_Hash[7] += H; +#endif /* USE_32BIT_ONLY */ + + context->Message_Block_Index = 0; +} + +/* +* SHA384_512Reset +* +* Description: +* This helper function will initialize the SHA512Context in +* preparation for computing a new SHA384 or SHA512 message +* digest. +* +* Parameters: +* context: [in/out] +* The context to reset. +* H0 +* The initial hash value to use. +* +* Returns: +* sha Error Code. +* +*/ +#ifdef USE_32BIT_ONLY +static int SHA384_512Reset(SHA512Context *context, uint32_t H0[]) +#else /* !USE_32BIT_ONLY */ +static int SHA384_512Reset(SHA512Context *context, uint64_t H0[]) +#endif /* USE_32BIT_ONLY */ +{ + int i; + if (!context) + return shaNull; + + context->Message_Block_Index = 0; + +#ifdef USE_32BIT_ONLY + context->Length[0] = context->Length[1] = 0; + context->Length[2] = context->Length[3] = 0; + + for (i = 0; i < SHA512HashSize / 4; i++) + context->Intermediate_Hash[i] = H0[i]; +#else /* !USE_32BIT_ONLY */ + context->Length_High = context->Length_Low = 0; + + for (i = 0; i < SHA512HashSize / 8; i++) + context->Intermediate_Hash[i] = H0[i]; +#endif /* USE_32BIT_ONLY */ + + context->Computed = 0; + context->Corrupted = 0; + + return shaSuccess; +} + +/* +* SHA384_512ResultN +* +* Description: +* This helper function will return the 384-bit or 512-bit message +* digest into the Message_Digest array provided by the caller. +* NOTE: The first octet of hash is stored in the 0th element, +* the last octet of hash in the 48th/64th element. +* +* Parameters: +* context: [in/out] +* The context to use to calculate the SHA hash. +* Message_Digest: [out] +* Where the digest is returned. +* HashSize: [in] +* The size of the hash, either 48 or 64. +* +* Returns: +* sha Error Code. +* +*/ +static int SHA384_512ResultN(SHA512Context *context, + uint8_t Message_Digest[], int HashSize) +{ + int i; + +#ifdef USE_32BIT_ONLY + int i2; +#endif /* USE_32BIT_ONLY */ + + if (!context || !Message_Digest) + return shaNull; + + if (context->Corrupted) + return context->Corrupted; + + if (!context->Computed) + SHA384_512Finalize(context, 0x80); + +#ifdef USE_32BIT_ONLY + for (i = i2 = 0; i < HashSize;) { + Message_Digest[i++] = (uint8_t)(context->Intermediate_Hash[i2] >> 24); + Message_Digest[i++] = (uint8_t)(context->Intermediate_Hash[i2] >> 16); + Message_Digest[i++] = (uint8_t)(context->Intermediate_Hash[i2] >> 8); + Message_Digest[i++] = (uint8_t)(context->Intermediate_Hash[i2++]); + Message_Digest[i++] = (uint8_t)(context->Intermediate_Hash[i2] >> 24); + Message_Digest[i++] = (uint8_t)(context->Intermediate_Hash[i2] >> 16); + Message_Digest[i++] = (uint8_t)(context->Intermediate_Hash[i2] >> 8); + Message_Digest[i++] = (uint8_t)(context->Intermediate_Hash[i2++]); + } +#else /* !USE_32BIT_ONLY */ + for (i = 0; i < HashSize; ++i) + Message_Digest[i] = (uint8_t) + (context->Intermediate_Hash[i >> 3] >> 8 * (7 - (i % 8))); +#endif /* USE_32BIT_ONLY */ + + return shaSuccess; +} + diff --git a/c/sharedutil/src/string_tokenizer.c b/c/sharedutil/src/string_tokenizer.c new file mode 100644 index 00000000..3b578d25 --- /dev/null +++ b/c/sharedutil/src/string_tokenizer.c @@ -0,0 +1,191 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// +// PUT NO INCLUDES BEFORE HERE +// +#ifdef _CRTDBG_MAP_ALLOC +#include +#endif +#include "gballoc.h" + +// +// PUT NO CLIENT LIBRARY INCLUDES BEFORE HERE +// + +#include "string_tokenizer.h" +#include "iot_logging.h" +#include "crt_abstractions.h" +#include + +typedef struct STRING_TOKEN_TAG +{ + const char* inputString; + const char* currentPos; + size_t sizeOfinputString; +} STRING_TOKEN; + +STRING_TOKENIZER_HANDLE STRING_TOKENIZER_create(STRING_HANDLE handle) +{ + STRING_TOKEN *result; + char* inputStringToMalloc; + + /* Codes_SRS_STRING_04_001: [STRING_TOKENIZER_create shall return an NULL STRING_TOKENIZER_HANDLE if parameter handle is NULL] */ + if (handle == NULL) + { + LogError("Invalid Argument. Handle cannot be NULL.\r\n"); + result = NULL; + } + /* Codes_SRS_STRING_04_002: [STRING_TOKENIZER_create shall allocate a new STRING_TOKENIZER_HANDLE having the content of the STRING_HANDLE copied and current position pointing at the beginning of the string] */ + else if((result = (STRING_TOKEN *)malloc(sizeof(STRING_TOKEN))) == NULL) + { + LogError("Memory Allocation failed. Cannot allocate STRING_TOKENIZER.\r\n"); + } + else if ((mallocAndStrcpy_s(&inputStringToMalloc, STRING_c_str(handle))) != 0) + { + LogError("Memory Allocation Failed. Cannot allocate and copy string Content.\r\n"); + free(result); + result = NULL; + } + else + { + result->inputString = inputStringToMalloc; + result->currentPos = result->inputString; //Current Pos will point to the initial position of Token. + result->sizeOfinputString = strlen(result->inputString); //Calculate Size of Current String + } + + return (STRING_TOKENIZER_HANDLE)result; +} + + +int STRING_TOKENIZER_get_next_token(STRING_TOKENIZER_HANDLE tokenizer, STRING_HANDLE output, const char* delimiters) +{ + int result; + /* Codes_SRS_STRING_04_004: [STRING_TOKENIZER_get_next_token shall return a nonzero value if any of the 3 parameters is NULL] */ + if (tokenizer == NULL || output == NULL || delimiters == NULL) + { + result = __LINE__; + } + else + { + STRING_TOKEN* token = (STRING_TOKEN*)tokenizer; + /* Codes_SRS_STRING_04_011: [Each subsequent call to STRING_TOKENIZER_get_next_token starts searching from the saved position on t and behaves as described above.] */ + size_t remainingInputStringSize = token->sizeOfinputString - (token->currentPos - token->inputString); + size_t delimitterSize = strlen(delimiters); + + /* First Check if we reached the end of the string*/ + /* Codes_SRS_STRING_TOKENIZER_04_014: [STRING_TOKENIZER_get_next_token shall return nonzero value if t contains an empty string.] */ + if (remainingInputStringSize == 0) + { + result = __LINE__; + } + else if (delimitterSize == 0) + { + LogError("Empty delimiters parameter.\r\n"); + result = __LINE__; + } + else + { + size_t i; + /* Codes_SRS_STRING_04_005: [STRING_TOKENIZER_get_next_token searches the string inside STRING_TOKENIZER_HANDLE for the first character that is NOT contained in the current delimiter] */ + for (i = 0; i < remainingInputStringSize; i++) + { + bool foundDelimitter = false; + for (size_t j = 0; j < delimitterSize; j++) + { + if (token->currentPos[i] == delimiters[j]) + { + foundDelimitter = true; + break; + } + } + + /* Codes_SRS_STRING_04_007: [If such a character is found, STRING_TOKENIZER_get_next_token consider it as the start of a token.] */ + if (!foundDelimitter) + { + break; + } + } + + /* Codes_SRS_STRING_04_006: [If no such character is found, then STRING_TOKENIZER_get_next_token shall return a nonzero Value (You've reach the end of the string or the string consists with only delimiters).] */ + //At this point update Current Pos to the character of the last token found or end of String. + token->currentPos += i; + + //Update the remainingInputStringSize + remainingInputStringSize -= i; + + /* Codes_SRS_STRING_04_006: [If no such character is found, then STRING_TOKENIZER_get_next_token shall return a nonzero Value (You've reach the end of the string or the string consists with only delimiters).] */ + if (remainingInputStringSize == 0) + { + result = __LINE__; + } + else + { + bool foundDelimitter = false; + char* endOfTokenPosition=NULL; + size_t amountOfCharactersToCopy; + //At this point the Current Pos is pointing to a character that is point to a nonDelimiter. So, now search for a Delimiter, till the end of the String. + /*Codes_SRS_STRING_04_008: [STRING_TOKENIZER_get_next_token than searches from the start of a token for a character that is contained in the delimiters string.] */ + /* Codes_SRS_STRING_04_009: [If no such character is found, STRING_TOKENIZER_get_next_token extends the current token to the end of the string inside t, copies the token to output and returns 0.] */ + /* Codes_SRS_STRING_04_010: [If such a character is found, STRING_TOKENIZER_get_next_token consider it the end of the token and copy it's content to output, updates the current position inside t to the next character and returns 0.] */ + for (size_t j = 0; j < delimitterSize; j++) + { + if ((endOfTokenPosition = strchr(token->currentPos, delimiters[j])) != NULL) + { + foundDelimitter = true; + break; + } + } + + //If token not found, than update the EndOfToken to the end of the inputString; + if (endOfTokenPosition == NULL) + { + amountOfCharactersToCopy = remainingInputStringSize; + } + else + { + amountOfCharactersToCopy = endOfTokenPosition - token->currentPos; + } + + //copy here the string to output. + if (STRING_copy_n(output, token->currentPos, amountOfCharactersToCopy) != 0) + { + LogError("Problem copying token to output String.\r\n"); + result = __LINE__; + } + else + { + //Update the Current position. + //Check if end of String reached so, currentPos points to the end of String. + if (foundDelimitter) + { + token->currentPos += amountOfCharactersToCopy + 1; + } + else + { + token->currentPos += amountOfCharactersToCopy; + } + + result = 0; //Result will be on the output. + } + } + } + } + + return result; +} + + +/* Codes_SRS_STRING_TOKENIZER_04_012: [STRING_TOKENIZER_destroy shall free the memory allocated by the STRING_TOKENIZER_create ] */ +void STRING_TOKENIZER_destroy(STRING_TOKENIZER_HANDLE t) +{ + /* Codes_SRS_STRING_TOKENIZER_04_013: [When the t argument is NULL, then STRING_TOKENIZER_destroy shall not attempt to free] */ + if (t != NULL) + { + STRING_TOKEN* value = (STRING_TOKEN*)t; + free((char*)value->inputString); + value->inputString = NULL; + free(value); + } +} + diff --git a/c/sharedutil/src/strings.c b/c/sharedutil/src/strings.c new file mode 100644 index 00000000..21fc3f8d --- /dev/null +++ b/c/sharedutil/src/strings.c @@ -0,0 +1,618 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// +// PUT NO INCLUDES BEFORE HERE +// +#include +#ifdef _CRTDBG_MAP_ALLOC +#include +#endif +#include "gballoc.h" + +#include +#include +// +// PUT NO CLIENT LIBRARY INCLUDES BEFORE HERE +// + +#include "strings.h" +#include "iot_logging.h" + +static const char hexToASCII[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + +typedef struct STRING_TAG +{ + char* s; +}STRING; + +/*this function will allocate a new string with just '\0' in it*/ +/*return NULL if it fails*/ +/* Codes_SRS_STRING_07_001: [STRING_new shall allocate a new STRING_HANDLE pointing to an empty string.] */ +STRING_HANDLE STRING_new(void) +{ + STRING* result; + if ((result = (STRING*)malloc(sizeof(STRING))) != NULL) + { + if ((result->s = (char*)malloc(1)) != NULL) + { + result->s[0] = '\0'; + } + else + { + /* Codes_SRS_STRING_07_002: [STRING_new shall return an NULL STRING_HANDLE on any error that is encountered.] */ + free(result); + result = NULL; + } + } + return (STRING_HANDLE)result; +} + +/*Codes_SRS_STRING_02_001: [STRING_clone shall produce a new string having the same content as the handle string.*/ +STRING_HANDLE STRING_clone(STRING_HANDLE handle) +{ + STRING* result; + /*Codes_SRS_STRING_02_002: [If parameter handle is NULL then STRING_clone shall return NULL.]*/ + if (handle == NULL) + { + result = NULL; + } + else + { + /*Codes_SRS_STRING_02_003: [If STRING_clone fails for any reason, it shall return NULL.] */ + if ((result = (STRING*)malloc(sizeof(STRING))) != NULL) + { + STRING* source = (STRING*)handle; + /*Codes_SRS_STRING_02_003: [If STRING_clone fails for any reason, it shall return NULL.] */ + size_t sourceLen = strlen(source->s); + if ((result->s = (char*)malloc(sourceLen + 1)) == NULL) + { + free(result); + result = NULL; + } + else + { + memcpy(result->s, source->s, sourceLen + 1); + } + } + else + { + /*not much to do, result is NULL from malloc*/ + } + } + return result; +} + +/* Codes_SRS_STRING_07_003: [STRING_construct shall allocate a new string with the value of the specified const char*.] */ +STRING_HANDLE STRING_construct(const char* psz) +{ + STRING_HANDLE result; + if (psz == NULL) + { + /* Codes_SRS_STRING_07_005: [If the supplied const char* is NULL STRING_construct shall return a NULL value.] */ + result = NULL; + } + else + { + STRING* str; + if ((str = (STRING*)malloc(sizeof(STRING))) != NULL) + { + size_t nLen = strlen(psz) + 1; + if ((str->s = (char*)malloc(nLen)) != NULL) + { + memcpy(str->s, psz, nLen); + result = (STRING_HANDLE)str; + } + /* Codes_SRS_STRING_07_032: [STRING_construct encounters any error it shall return a NULL value.] */ + else + { + free(str); + result = NULL; + } + } + else + { + /* Codes_SRS_STRING_07_032: [STRING_construct encounters any error it shall return a NULL value.] */ + result = NULL; + } + } + return result; +} + +/*this function will return a new STRING with the memory for the actual string passed in as a parameter.*/ +/*return NULL if it fails.*/ +/* The supplied memory must have been allocated with malloc! */ +/* Codes_SRS_STRING_07_006: [STRING_new_with_memory shall return a STRING_HANDLE by using the supplied char* memory.] */ +STRING_HANDLE STRING_new_with_memory(const char* memory) +{ + STRING* result; + if (memory == NULL) + { + /* Codes_SRS_STRING_07_007: [STRING_new_with_memory shall return a NULL STRING_HANDLE if the supplied char* is NULL.] */ + result = NULL; + } + else + { + if ((result = (STRING*)malloc(sizeof(STRING))) != NULL) + { + result->s = (char*)memory; + } + } + return (STRING_HANDLE)result; +} + +/* Codes_SRS_STRING_07_008: [STRING_new_quoted shall return a valid STRING_HANDLE Copying the supplied const char* value surrounded by quotes.] */ +STRING_HANDLE STRING_new_quoted(const char* source) +{ + STRING* result; + if (source == NULL) + { + /* Codes_SRS_STRING_07_009: [STRING_new_quoted shall return a NULL STRING_HANDLE if the supplied const char* is NULL.] */ + result = NULL; + } + else if ((result = (STRING*)malloc(sizeof(STRING))) != NULL) + { + size_t sourceLength = strlen(source); + if ((result->s = (char*)malloc(sourceLength + 3)) != NULL) + { + result->s[0] = '"'; + memcpy(result->s + 1, source, sourceLength); + result->s[sourceLength + 1] = '"'; + result->s[sourceLength + 2] = '\0'; + } + else + { + /* Codes_SRS_STRING_07_031: [STRING_new_quoted shall return a NULL STRING_HANDLE if any error is encountered.] */ + free(result); + result = NULL; + } + } + return (STRING_HANDLE)result; +} + +/*this function takes a regular const char* and turns in into "this is a\"JSON\" strings\u0008" (starting and ending quote included)*/ +/*the newly created handle needs to be disposed of with STRING_delete*/ +/*returns NULL if there are errors*/ +STRING_HANDLE STRING_new_JSON(const char* source) +{ + STRING* result; + if (source == NULL) + { + /*Codes_SRS_STRING_02_011: [If source is NULL then STRING_new_JSON shall return NULL.] */ + result = NULL; + LogError("invalid arg (NULL)\r\n"); + } + else + { + size_t i; + size_t nControlCharacters = 0; /*counts how many characters are to be expanded from 1 character to \uxxxx (6 characters)*/ + size_t nEscapeCharacters = 0; + size_t vlen = strlen(source); + + for (i = 0; i < vlen; i++) + { + /*Codes_SRS_STRING_02_014: [If any character has the value outside [1...127] then STRING_new_JSON shall fail and return NULL.] */ + if ((unsigned char)source[i] >= 128) /*this be a UNICODE character begin*/ + { + break; + } + else + { + if (source[i] <= 0x1F) + { + nControlCharacters++; + } + else if ( + (source[i] == '"') || + (source[i] == '\\') || + (source[i] == '/') + ) + { + nEscapeCharacters++; + } + } + } + + if (i < vlen) + { + result = NULL; + LogError("invalid character in input string\r\n"); + } + else + { + if ((result = (STRING*)malloc(sizeof(STRING))) == NULL) + { + /*Codes_SRS_STRING_02_021: [If the complete JSON representation cannot be produced, then STRING_new_JSON shall fail and return NULL.] */ + LogError("malloc failure\r\n"); + } + else if ((result->s = (char*)malloc(vlen + 5 * nControlCharacters + nEscapeCharacters + 3)) == NULL) + { + /*Codes_SRS_STRING_02_021: [If the complete JSON representation cannot be produced, then STRING_new_JSON shall fail and return NULL.] */ + free(result); + result = NULL; + LogError("malloc failed\r\n"); + } + else + { + size_t pos = 0; + /*Codes_SRS_STRING_02_012: [The string shall begin with the quote character.] */ + result->s[pos++] = '"'; + for (i = 0; i < vlen; i++) + { + if (source[i] <= 0x1F) + { + /*Codes_SRS_STRING_02_019: [If the character code is less than 0x20 then it shall be represented as \u00xx, where xx is the hex representation of the character code.]*/ + result->s[pos++] = '\\'; + result->s[pos++] = 'u'; + result->s[pos++] = '0'; + result->s[pos++] = '0'; + result->s[pos++] = hexToASCII[(source[i] & 0xF0) >> 4]; /*high nibble*/ + result->s[pos++] = hexToASCII[source[i] & 0x0F]; /*low nibble*/ + } + else if (source[i] == '"') + { + /*Codes_SRS_STRING_02_016: [If the character is " (quote) then it shall be repsented as \".] */ + result->s[pos++] = '\\'; + result->s[pos++] = '"'; + } + else if (source[i] == '\\') + { + /*Codes_SRS_STRING_02_017: [If the character is \ (backslash) then it shall represented as \\.] */ + result->s[pos++] = '\\'; + result->s[pos++] = '\\'; + } + else if (source[i] == '/') + { + /*Codes_SRS_STRING_02_018: [If the character is / (slash) then it shall be represented as \/.] */ + result->s[pos++] = '\\'; + result->s[pos++] = '/'; + } + else + { + /*Codes_SRS_STRING_02_013: [The string shall copy the characters of source "as they are" (until the '\0' character) with the following exceptions:] */ + result->s[pos++] = source[i]; + } + } + /*Codes_SRS_STRING_02_020: [The string shall end with " (quote).] */ + result->s[pos++] = '"'; + /*zero terminating it*/ + result->s[pos] = '\0'; + } + } + + } + return result; +} + +/*this function will concatenate to the string s1 the string s2, resulting in s1+s2*/ +/*returns 0 if success*/ +/*any other error code is failure*/ +/* Codes_SRS_STRING_07_012: [STRING_concat shall concatenate the given STRING_HANDLE and the const char* value and place the value in the handle.] */ +int STRING_concat(STRING_HANDLE handle, const char* s2) +{ + int result; + if ((handle == NULL) || (s2 == NULL)) + { + /* Codes_SRS_STRING_07_013: [STRING_concat shall return a nonzero number if an error is encountered.] */ + result = __LINE__; + } + else + { + STRING* s1 = (STRING*)handle; + size_t s1Length = strlen(s1->s); + size_t s2Length = strlen(s2); + char* temp = (char*)realloc(s1->s, s1Length + s2Length + 1); + if (temp == NULL) + { + /* Codes_SRS_STRING_07_013: [STRING_concat shall return a nonzero number if an error is encountered.] */ + result = __LINE__; + } + else + { + s1->s = temp; + memcpy(s1->s + s1Length, s2, s2Length + 1); + result = 0; + } + } + return result; +} + +/*this function will concatenate to the string s1 the string s2, resulting in s1+s2*/ +/*returns 0 if success*/ +/*any other error code is failure*/ +/* Codes_SRS_STRING_07_034: [String_Concat_with_STRING shall concatenate a given STRING_HANDLE variable with a source STRING_HANDLE.] */ +int STRING_concat_with_STRING(STRING_HANDLE s1, STRING_HANDLE s2) +{ + int result; + if ((s1 == NULL) || (s2 == NULL)) + { + /* Codes_SRS_STRING_07_035: [String_Concat_with_STRING shall return a nonzero number if an error is encountered.] */ + result = __LINE__; + } + else + { + STRING* dest = (STRING*)s1; + STRING* src = (STRING*)s2; + + size_t s1Length = strlen(dest->s); + size_t s2Length = strlen(src->s); + char* temp = (char*)realloc(dest->s, s1Length + s2Length + 1); + if (temp == NULL) + { + /* Codes_SRS_STRING_07_035: [String_Concat_with_STRING shall return a nonzero number if an error is encountered.] */ + result = __LINE__; + } + else + { + dest->s = temp; + /* Codes_SRS_STRING_07_034: [String_Concat_with_STRING shall concatenate a given STRING_HANDLE variable with a source STRING_HANDLE.] */ + memcpy(dest->s + s1Length, src->s, s2Length + 1); + result = 0; + } + } + return result; +} + +/*this function will copy the string from s2 to s1*/ +/*returns 0 if success*/ +/*any other error code is failure*/ +/* Codes_SRS_STRING_07_016: [STRING_copy shall copy the const char* into the supplied STRING_HANDLE.] */ +int STRING_copy(STRING_HANDLE handle, const char* s2) +{ + int result; + if ((handle == NULL) || (s2 == NULL)) + { + /* Codes_SRS_STRING_07_017: [STRING_copy shall return a nonzero value if any of the supplied parameters are NULL.] */ + result = __LINE__; + } + else + { + STRING* s1 = (STRING*)handle; + /* Codes_SRS_STRING_07_026: [If the underlying char* refered to by s1 handle is equal to char* s2 than STRING_copy shall be a noop and return 0.] */ + if (s1->s != s2) + { + size_t s2Length = strlen(s2); + char* temp = (char*)realloc(s1->s, s2Length + 1); + if (temp == NULL) + { + /* Codes_SRS_STRING_07_027: [STRING_copy shall return a nonzero value if any error is encountered.] */ + result = __LINE__; + } + else + { + s1->s = temp; + memmove(s1->s, s2, s2Length + 1); + result = 0; + } + } + else + { + /* Codes_SRS_STRING_07_033: [If overlapping pointer address is given to STRING_copy the behavior is undefined.] */ + result = 0; + } + } + return result; +} + +/*this function will copy n chars from s2 to the string s1, resulting in n chars only from s2 being stored in s1.*/ +/*returns 0 if success*/ +/*any other error code is failure*/ +/* Codes_SRS_STRING_07_018: [STRING_copy_n shall copy the number of characters in const char* or the size_t whichever is lesser.] */ +int STRING_copy_n(STRING_HANDLE handle, const char* s2, size_t n) +{ + int result; + if ((handle == NULL) || (s2 == NULL)) + { + /* Codes_SRS_STRING_07_019: [STRING_copy_n shall return a nonzero value if STRING_HANDLE or const char* is NULL.] */ + result = __LINE__; + } + else + { + STRING* s1 = (STRING*)handle; + size_t s2Length = strlen(s2); + char* temp; + if (s2Length > n) + { + s2Length = n; + } + + temp = (char*)realloc(s1->s, s2Length + 1); + if (temp == NULL) + { + /* Codes_SRS_STRING_07_028: [STRING_copy_n shall return a nonzero value if any error is encountered.] */ + result = __LINE__; + } + else + { + s1->s = temp; + memcpy(s1->s, s2, s2Length); + s1->s[s2Length] = 0; + result = 0; + } + + } + return result; +} + +/*this function will quote the string passed as argument string =>"string"*/ +/*returns 0 if success*/ /*doesn't change the string otherwise*/ +/*any other error code is failure*/ +/* Codes_SRS_STRING_07_014: [STRING_quote shall "quote" the supplied STRING_HANDLE and return 0 on success.] */ +int STRING_quote(STRING_HANDLE handle) +{ + int result; + if (handle == NULL) + { + /* Codes_SRS_STRING_07_015: [STRING_quote shall return a nonzero value if any of the supplied parameters are NULL.] */ + result = __LINE__; + } + else + { + STRING* s1 = (STRING*)handle; + size_t s1Length = strlen(s1->s); + char* temp = (char*)realloc(s1->s, s1Length + 2 + 1);/*2 because 2 quotes, 1 because '\0'*/ + if (temp == NULL) + { + /* Codes_SRS_STRING_07_029: [STRING_quote shall return a nonzero value if any error is encountered.] */ + result = __LINE__; + } + else + { + s1->s = temp; + memmove(s1->s + 1, s1->s, s1Length); + s1->s[0] = '"'; + s1->s[s1Length + 1] = '"'; + s1->s[s1Length + 2] = '\0'; + result = 0; + } + } + return result; +} +/*this function will revert a string to an empty state*/ +/*Returns 0 if the revert was succesful*/ +/* Codes_SRS_STRING_07_022: [STRING_empty shall revert the STRING_HANDLE to an empty state.] */ +int STRING_empty(STRING_HANDLE handle) +{ + int result; + if (handle == NULL) + { + /* Codes_SRS_STRING_07_023: [STRING_empty shall return a nonzero value if the STRING_HANDLE is NULL.] */ + result = __LINE__; + } + else + { + STRING* s1 = (STRING*)handle; + char* temp = (char*)realloc(s1->s, 1); + if (temp == NULL) + { + /* Codes_SRS_STRING_07_030: [STRING_empty shall return a nonzero value if the STRING_HANDLE is NULL.] */ + result = __LINE__; + } + else + { + s1->s = temp; + s1->s[0] = '\0'; + result = 0; + } + } + return result; +} + +/*this function will deallocate a string constructed by str_new*/ +/* Codes_SRS_STRING_07_010: [STRING_delete will free the memory allocated by the STRING_HANDLE.] */ +void STRING_delete(STRING_HANDLE handle) +{ + /* Codes_SRS_STRING_07_011: [STRING_delete will not attempt to free anything with a NULL STRING_HANDLE.] */ + if (handle != NULL) + { + STRING* value = (STRING*)handle; + free(value->s); + value->s = NULL; + free(value); + } +} + +/* Codes_SRS_STRING_07_020: [STRING_c_str shall return the const char* associated with the given STRING_HANDLE.] */ +const char* STRING_c_str(STRING_HANDLE handle) +{ + const char* result; + if (handle != NULL) + { + result = ((STRING*)handle)->s; + } + else + { + /* Codes_SRS_STRING_07_021: [STRING_c_str shall return NULL if the STRING_HANDLE is NULL.] */ + result = NULL; + } + return result; +} + +/* Codes_SRS_STRING_07_024: [STRING_length shall return the length of the underlying char* for the given handle] */ +size_t STRING_length(STRING_HANDLE handle) +{ + size_t result = 0; + /* Codes_SRS_STRING_07_025: [STRING_length shall return zero if the given handle is NULL.] */ + if (handle != NULL) + { + STRING* value = (STRING*)handle; + result = strlen(value->s); + } + return result; +} + +/*Codes_SRS_STRING_02_007: [STRING_construct_n shall construct a STRING_HANDLE from first "n" characters of the string pointed to by psz parameter.]*/ +STRING_HANDLE STRING_construct_n(const char* psz, size_t n) +{ + STRING_HANDLE result; + /*Codes_SRS_STRING_02_008: [If psz is NULL then STRING_construct_n shall return NULL.] */ + if (psz == NULL) + { + result = NULL; + LogError("invalid arg (NULL)\r\n"); + } + else + { + size_t len = strlen(psz); + /*Codes_SRS_STRING_02_009: [If n is bigger than the size of the string psz, then STRING_construct_n shall return NULL.] */ + if (n > len) + { + result = NULL; + LogError("invalig arg (n is bigger than the size of the string)\r\n"); + } + else + { + STRING* str; + if ((str = (STRING*)malloc(sizeof(STRING))) != NULL) + { + if ((str->s = (char*)malloc(len + 1)) != NULL) + { + memcpy(str->s, psz, n); + str->s[n] = '\0'; + result = (STRING_HANDLE)str; + } + /* Codes_SRS_STRING_02_010: [In all other error cases, STRING_construct_n shall return NULL.] */ + else + { + free(str); + result = NULL; + } + } + else + { + /* Codes_SRS_STRING_02_010: [In all other error cases, STRING_construct_n shall return NULL.] */ + result = NULL; + } + } + } + return result; +} + +/* Codes_SRS_STRING_07_034: [STRING_compare returns an integer greater than, equal to, or less than zero, accordingly as the string pointed to by s1 is greater than, equal to, or less than the string s2.] */ +int STRING_compare(STRING_HANDLE s1, STRING_HANDLE s2) +{ + int result; + if (s1 == NULL && s2 == NULL) + { + /* Codes_SRS_STRING_07_035: [If h1 and h2 are both NULL then STRING_compare shall return 0.]*/ + result = 0; + } + else if (s1 == NULL) + { + /* Codes_SRS_STRING_07_036: [If h1 is NULL and h2 is nonNULL then STRING_compare shall return 1.]*/ + result = 1; + } + else if (s2 == NULL) + { + /* Codes_SRS_STRING_07_037: [If h2 is NULL and h1 is nonNULL then STRING_compare shall return -1.] */ + result = -1; + } + else + { + /* Codes_SRS_STRING_07_038: [STRING_compare shall compare the char s variable using the strcmp function.] */ + STRING* value1 = (STRING*)s1; + STRING* value2 = (STRING*)s2; + result = strcmp(value1->s, value2->s); + } + return result; +} diff --git a/c/sharedutil/src/urlencode.c b/c/sharedutil/src/urlencode.c new file mode 100644 index 00000000..b9f62f0a --- /dev/null +++ b/c/sharedutil/src/urlencode.c @@ -0,0 +1,356 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// +// PUT NO INCLUDES BEFORE HERE !!!! +// +#include +#ifdef _CRTDBG_MAP_ALLOC +#include +#endif +#include "gballoc.h" + +#include +#include +// +// PUT NO CLIENT LIBRARY INCLUDES BEFORE HERE !!!! +// +#include "urlencode.h" +#include "iot_logging.h" +#include "strings.h" + +static const struct { + size_t numberOfChars; + const char* encoding; +} urlEncoding[] = { + { 1, "\0" }, + { 3, "%01" }, + { 3, "%02" }, + { 3, "%03" }, + { 3, "%04" }, + { 3, "%05" }, + { 3, "%06" }, + { 3, "%07" }, + { 3, "%08" }, + { 3, "%09" }, + { 3, "%0a" }, + { 3, "%0b" }, + { 3, "%0c" }, + { 3, "%0d" }, + { 3, "%0e" }, + { 3, "%0f" }, + { 3, "%10" }, + { 3, "%11" }, + { 3, "%12" }, + { 3, "%13" }, + { 3, "%14" }, + { 3, "%15" }, + { 3, "%16" }, + { 3, "%17" }, + { 3, "%18" }, + { 3, "%19" }, + { 3, "%1a" }, + { 3, "%1b" }, + { 3, "%1c" }, + { 3, "%1d" }, + { 3, "%1e" }, + { 3, "%1f" }, + { 3, "%20" }, + { 1, "!" }, + { 3, "%22" }, + { 3, "%23" }, + { 3, "%24" }, + { 3, "%25" }, + { 3, "%26" }, + { 3, "%27" }, + { 1, "(" }, + { 1, ")" }, + { 1, "*" }, + { 3, "%2b" }, + { 3, "%2c" }, + { 1, "-" }, + { 1, "." }, + { 3, "%2f" }, + { 1, "0" }, + { 1, "1" }, + { 1, "2" }, + { 1, "3" }, + { 1, "4" }, + { 1, "5" }, + { 1, "6" }, + { 1, "7" }, + { 1, "8" }, + { 1, "9" }, + { 3, "%3a" }, + { 3, "%3b" }, + { 3, "%3c" }, + { 3, "%3d" }, + { 3, "%3e" }, + { 3, "%3f" }, + { 3, "%40" }, + { 1, "A" }, + { 1, "B" }, + { 1, "C" }, + { 1, "D" }, + { 1, "E" }, + { 1, "F" }, + { 1, "G" }, + { 1, "H" }, + { 1, "I" }, + { 1, "J" }, + { 1, "K" }, + { 1, "L" }, + { 1, "M" }, + { 1, "N" }, + { 1, "O" }, + { 1, "P" }, + { 1, "Q" }, + { 1, "R" }, + { 1, "S" }, + { 1, "T" }, + { 1, "U" }, + { 1, "V" }, + { 1, "W" }, + { 1, "X" }, + { 1, "Y" }, + { 1, "Z" }, + { 3, "%5b" }, + { 3, "%5c" }, + { 3, "%5d" }, + { 3, "%5e" }, + { 1, "_" }, + { 3, "%60" }, + { 1, "a" }, + { 1, "b" }, + { 1, "c" }, + { 1, "d" }, + { 1, "e" }, + { 1, "f" }, + { 1, "g" }, + { 1, "h" }, + { 1, "i" }, + { 1, "j" }, + { 1, "k" }, + { 1, "l" }, + { 1, "m" }, + { 1, "n" }, + { 1, "o" }, + { 1, "p" }, + { 1, "q" }, + { 1, "r" }, + { 1, "s" }, + { 1, "t" }, + { 1, "u" }, + { 1, "v" }, + { 1, "w" }, + { 1, "x" }, + { 1, "y" }, + { 1, "z" }, + { 3, "%7b" }, + { 3, "%7c" }, + { 3, "%7d" }, + { 3, "%7e" }, + { 3, "%7f" }, + { 6, "%c2%80" }, + { 6, "%c2%81" }, + { 6, "%c2%82" }, + { 6, "%c2%83" }, + { 6, "%c2%84" }, + { 6, "%c2%85" }, + { 6, "%c2%86" }, + { 6, "%c2%87" }, + { 6, "%c2%88" }, + { 6, "%c2%89" }, + { 6, "%c2%8a" }, + { 6, "%c2%8b" }, + { 6, "%c2%8c" }, + { 6, "%c2%8d" }, + { 6, "%c2%8e" }, + { 6, "%c2%8f" }, + { 6, "%c2%90" }, + { 6, "%c2%91" }, + { 6, "%c2%92" }, + { 6, "%c2%93" }, + { 6, "%c2%94" }, + { 6, "%c2%95" }, + { 6, "%c2%96" }, + { 6, "%c2%97" }, + { 6, "%c2%98" }, + { 6, "%c2%99" }, + { 6, "%c2%9a" }, + { 6, "%c2%9b" }, + { 6, "%c2%9c" }, + { 6, "%c2%9d" }, + { 6, "%c2%9e" }, + { 6, "%c2%9f" }, + { 6, "%c2%a0" }, + { 6, "%c2%a1" }, + { 6, "%c2%a2" }, + { 6, "%c2%a3" }, + { 6, "%c2%a4" }, + { 6, "%c2%a5" }, + { 6, "%c2%a6" }, + { 6, "%c2%a7" }, + { 6, "%c2%a8" }, + { 6, "%c2%a9" }, + { 6, "%c2%aa" }, + { 6, "%c2%ab" }, + { 6, "%c2%ac" }, + { 6, "%c2%ad" }, + { 6, "%c2%ae" }, + { 6, "%c2%af" }, + { 6, "%c2%b0" }, + { 6, "%c2%b1" }, + { 6, "%c2%b2" }, + { 6, "%c2%b3" }, + { 6, "%c2%b4" }, + { 6, "%c2%b5" }, + { 6, "%c2%b6" }, + { 6, "%c2%b7" }, + { 6, "%c2%b8" }, + { 6, "%c2%b9" }, + { 6, "%c2%ba" }, + { 6, "%c2%bb" }, + { 6, "%c2%bc" }, + { 6, "%c2%bd" }, + { 6, "%c2%be" }, + { 6, "%c2%bf" }, + { 6, "%c3%80" }, + { 6, "%c3%81" }, + { 6, "%c3%82" }, + { 6, "%c3%83" }, + { 6, "%c3%84" }, + { 6, "%c3%85" }, + { 6, "%c3%86" }, + { 6, "%c3%87" }, + { 6, "%c3%88" }, + { 6, "%c3%89" }, + { 6, "%c3%8a" }, + { 6, "%c3%8b" }, + { 6, "%c3%8c" }, + { 6, "%c3%8d" }, + { 6, "%c3%8e" }, + { 6, "%c3%8f" }, + { 6, "%c3%90" }, + { 6, "%c3%91" }, + { 6, "%c3%92" }, + { 6, "%c3%93" }, + { 6, "%c3%94" }, + { 6, "%c3%95" }, + { 6, "%c3%96" }, + { 6, "%c3%97" }, + { 6, "%c3%98" }, + { 6, "%c3%99" }, + { 6, "%c3%9a" }, + { 6, "%c3%9b" }, + { 6, "%c3%9c" }, + { 6, "%c3%9d" }, + { 6, "%c3%9e" }, + { 6, "%c3%9f" }, + { 6, "%c3%a0" }, + { 6, "%c3%a1" }, + { 6, "%c3%a2" }, + { 6, "%c3%a3" }, + { 6, "%c3%a4" }, + { 6, "%c3%a5" }, + { 6, "%c3%a6" }, + { 6, "%c3%a7" }, + { 6, "%c3%a8" }, + { 6, "%c3%a9" }, + { 6, "%c3%aa" }, + { 6, "%c3%ab" }, + { 6, "%c3%ac" }, + { 6, "%c3%ad" }, + { 6, "%c3%ae" }, + { 6, "%c3%af" }, + { 6, "%c3%b0" }, + { 6, "%c3%b1" }, + { 6, "%c3%b2" }, + { 6, "%c3%b3" }, + { 6, "%c3%b4" }, + { 6, "%c3%b5" }, + { 6, "%c3%b6" }, + { 6, "%c3%b7" }, + { 6, "%c3%b8" }, + { 6, "%c3%b9" }, + { 6, "%c3%ba" }, + { 6, "%c3%bb" }, + { 6, "%c3%bc" }, + { 6, "%c3%bd" }, + { 6, "%c3%be" }, + { 6, "%c3%bf" } +}; + +STRING_HANDLE URL_EncodeString(const char* textEncode) +{ + STRING_HANDLE result; + if (textEncode == NULL) + { + result = NULL; + } + else + { + STRING_HANDLE tempString = STRING_construct(textEncode); + if (tempString == NULL) + { + result = NULL; + } + else + { + result = URL_Encode(tempString); + STRING_delete(tempString); + } + } + return result; +} + +STRING_HANDLE URL_Encode(STRING_HANDLE input) +{ + STRING_HANDLE result; + if (input == NULL) + { + /*Codes_SRS_URL_ENCODE_06_001: [If input is NULL then URL_Encode will return NULL.]*/ + result = NULL; + LogError("URL_Encode:: NULL input\r\n"); + } + else + { + size_t lengthOfResult = 0; + char* encodedURL; + const char* currentInput; + unsigned char currentUnsignedChar; + currentInput = STRING_c_str(input); + /*Codes_SRS_URL_ENCODE_06_003: [If input is a zero length string then URL_Encode will return a zero length string.]*/ + do + { + currentUnsignedChar = (unsigned char)(*currentInput++); + lengthOfResult += urlEncoding[currentUnsignedChar].numberOfChars; + } while (currentUnsignedChar != 0); + if ((encodedURL = malloc(lengthOfResult)) == NULL) + { + /*Codes_SRS_URL_ENCODE_06_002: [If an error occurs during the encoding of input then URL_Encode will return NULL.]*/ + result = NULL; + LogError("URL_Encode:: MALLOC failure on encode.\r\n"); + } + else + { + size_t currentEncodePosition = 0; + currentInput = STRING_c_str(input); + do + { + currentUnsignedChar = (unsigned char)(*currentInput++); + if (urlEncoding[currentUnsignedChar].numberOfChars == 1) + { + encodedURL[currentEncodePosition++] = *(urlEncoding[currentUnsignedChar].encoding); + } + else + { + memcpy(encodedURL + currentEncodePosition, urlEncoding[currentUnsignedChar].encoding, urlEncoding[currentUnsignedChar].numberOfChars); + currentEncodePosition += urlEncoding[currentUnsignedChar].numberOfChars; + } + } while (currentUnsignedChar != 0); + result = STRING_new_with_memory(encodedURL); + } + } + return result; +} diff --git a/c/sharedutil/src/usha.c b/c/sharedutil/src/usha.c new file mode 100644 index 00000000..05553eda --- /dev/null +++ b/c/sharedutil/src/usha.c @@ -0,0 +1,269 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/**************************** usha.c ****************************/ +/******************** See RFC 4634 for details ******************/ +/* +* Description: +* This file implements a unified interface to the SHA algorithms. +*/ + +#include +#ifdef _CRTDBG_MAP_ALLOC +#include +#endif +#include "gballoc.h" + +#include "sha.h" + +/* +* USHAReset +* +* Description: +* This function will initialize the SHA Context in preparation +* for computing a new SHA message digest. +* +* Parameters: +* context: [in/out] +* The context to reset. +* whichSha: [in] +* Selects which SHA reset to call +* +* Returns: +* sha Error Code. +* +*/ +int USHAReset(USHAContext *ctx, enum SHAversion whichSha) +{ + if (ctx) { + ctx->whichSha = whichSha; + switch (whichSha) { + case SHA1: return SHA1Reset((SHA1Context*)&ctx->ctx); + case SHA224: return SHA224Reset((SHA224Context*)&ctx->ctx); + case SHA256: return SHA256Reset((SHA256Context*)&ctx->ctx); + case SHA384: return SHA384Reset((SHA384Context*)&ctx->ctx); + case SHA512: return SHA512Reset((SHA512Context*)&ctx->ctx); + default: return shaBadParam; + } + } + else { + return shaNull; + } +} + +/* +* USHAInput +* +* Description: +* This function accepts an array of octets as the next portion +* of the message. +* +* Parameters: +* context: [in/out] +* The SHA context to update +* message_array: [in] +* An array of characters representing the next portion of +* the message. +* length: [in] +* The length of the message in message_array +* +* Returns: +* sha Error Code. +* +*/ +int USHAInput(USHAContext *ctx, + const uint8_t *bytes, unsigned int bytecount) +{ + if (ctx) { + switch (ctx->whichSha) { + case SHA1: + return SHA1Input((SHA1Context*)&ctx->ctx, bytes, bytecount); + case SHA224: + return SHA224Input((SHA224Context*)&ctx->ctx, bytes, + bytecount); + case SHA256: + return SHA256Input((SHA256Context*)&ctx->ctx, bytes, + bytecount); + case SHA384: + return SHA384Input((SHA384Context*)&ctx->ctx, bytes, + bytecount); + case SHA512: + return SHA512Input((SHA512Context*)&ctx->ctx, bytes, + bytecount); + default: return shaBadParam; + } + } + else { + return shaNull; + } +} + +/* +* USHAFinalBits +* +* Description: +* This function will add in any final bits of the message. +* +* Parameters: +* context: [in/out] +* The SHA context to update +* message_bits: [in] +* The final bits of the message, in the upper portion of the +* byte. (Use 0b###00000 instead of 0b00000### to input the +* three bits ###.) +* length: [in] +* The number of bits in message_bits, between 1 and 7. +* +* Returns: +* sha Error Code. +*/ +int USHAFinalBits(USHAContext *ctx, +const uint8_t bits, unsigned int bitcount) +{ + if (ctx) { + switch (ctx->whichSha) { + case SHA1: + return SHA1FinalBits((SHA1Context*)&ctx->ctx, bits, bitcount); + case SHA224: + return SHA224FinalBits((SHA224Context*)&ctx->ctx, bits, + bitcount); + case SHA256: + return SHA256FinalBits((SHA256Context*)&ctx->ctx, bits, + bitcount); + case SHA384: + return SHA384FinalBits((SHA384Context*)&ctx->ctx, bits, + bitcount); + case SHA512: + return SHA512FinalBits((SHA512Context*)&ctx->ctx, bits, + bitcount); + default: return shaBadParam; + } + } + else { + return shaNull; + } +} + +/* +* USHAResult +* +* Description: +* This function will return the 160-bit message digest into the +* Message_Digest array provided by the caller. +* NOTE: The first octet of hash is stored in the 0th element, +* the last octet of hash in the 19th element. +* +* Parameters: +* context: [in/out] +* The context to use to calculate the SHA-1 hash. +* Message_Digest: [out] +* Where the digest is returned. +* +* Returns: +* sha Error Code. +* +*/ +int USHAResult(USHAContext *ctx, + uint8_t Message_Digest[USHAMaxHashSize]) +{ + if (ctx) { + switch (ctx->whichSha) { + case SHA1: + return SHA1Result((SHA1Context*)&ctx->ctx, Message_Digest); + case SHA224: + return SHA224Result((SHA224Context*)&ctx->ctx, Message_Digest); + case SHA256: + return SHA256Result((SHA256Context*)&ctx->ctx, Message_Digest); + case SHA384: + return SHA384Result((SHA384Context*)&ctx->ctx, Message_Digest); + case SHA512: + return SHA512Result((SHA512Context*)&ctx->ctx, Message_Digest); + default: return shaBadParam; + } + } + else { + return shaNull; + } +} + +/* +* USHABlockSize +* +* Description: +* This function will return the blocksize for the given SHA +* algorithm. +* +* Parameters: +* whichSha: +* which SHA algorithm to query +* +* Returns: +* block size +* +*/ +int USHABlockSize(enum SHAversion whichSha) +{ + switch (whichSha) { + case SHA1: return SHA1_Message_Block_Size; + case SHA224: return SHA224_Message_Block_Size; + case SHA256: return SHA256_Message_Block_Size; + case SHA384: return SHA384_Message_Block_Size; + default: + case SHA512: return SHA512_Message_Block_Size; + } +} + +/* +* USHAHashSize +* +* Description: +* This function will return the hashsize for the given SHA +* algorithm. +* +* Parameters: +* whichSha: +* which SHA algorithm to query +* +* Returns: +* hash size +* +*/ +int USHAHashSize(enum SHAversion whichSha) +{ + switch (whichSha) { + case SHA1: return SHA1HashSize; + case SHA224: return SHA224HashSize; + case SHA256: return SHA256HashSize; + case SHA384: return SHA384HashSize; + default: + case SHA512: return SHA512HashSize; + } +} + +/* +* USHAHashSizeBits +* +* Description: +* This function will return the hashsize for the given SHA +* algorithm, expressed in bits. +* +* Parameters: +* whichSha: +* which SHA algorithm to query +* +* Returns: +* hash size in bits +* +*/ +int USHAHashSizeBits(enum SHAversion whichSha) +{ + switch (whichSha) { + case SHA1: return SHA1HashSizeBits; + case SHA224: return SHA224HashSizeBits; + case SHA256: return SHA256HashSizeBits; + case SHA384: return SHA384HashSizeBits; + default: + case SHA512: return SHA512HashSizeBits; + } +} + diff --git a/c/sharedutil/src/vector.c b/c/sharedutil/src/vector.c new file mode 100644 index 00000000..57c34970 --- /dev/null +++ b/c/sharedutil/src/vector.c @@ -0,0 +1,190 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include +#ifdef _CRTDBG_MAP_ALLOC +#include +#endif +#include "gballoc.h" + +#include "vector.h" +#include + + +typedef struct VECTOR_TAG +{ + void* storage; + size_t count; + size_t elementSize; +} VECTOR; + +VECTOR_HANDLE VECTOR_create(size_t elementSize) +{ + VECTOR_HANDLE result; + + VECTOR* vec = (VECTOR*)malloc(sizeof(VECTOR)); + if (vec == NULL) + { + result = NULL; + } + else + { + vec->storage = NULL; + vec->count = 0; + vec->elementSize = elementSize; + result = (VECTOR_HANDLE)vec; + } + return result; +} + +static void internal_VECTOR_clear(VECTOR* vec) +{ + if (vec->storage != NULL) + { + free(vec->storage); + vec->storage = NULL; + } + vec->count = 0; +} + +void VECTOR_destroy(VECTOR_HANDLE handle) +{ + if (handle != NULL) + { + VECTOR* vec = (VECTOR*)handle; + internal_VECTOR_clear(vec); + free(vec); + } +} + +/* insertion */ +int VECTOR_push_back(VECTOR_HANDLE handle, const void* elements, size_t numElements) +{ + int result; + if (handle == NULL || elements == NULL || numElements == 0) + { + result = __LINE__; + } + else + { + VECTOR* vec = (VECTOR*)handle; + const size_t curSize = vec->elementSize * vec->count; + const size_t appendSize = vec->elementSize * numElements; + + void* temp = realloc(vec->storage, curSize + appendSize); + if (temp == NULL) + { + result = __LINE__; + } + else + { + memcpy((unsigned char*)temp + curSize, elements, appendSize); + vec->storage = temp; + vec->count += numElements; + result = 0; + } + } + return result; +} + +/* removal */ +void VECTOR_erase(VECTOR_HANDLE handle, void* elements, size_t numElements) +{ + if (handle != NULL && elements != NULL && numElements > 0) + { + VECTOR* vec = (VECTOR*)handle; + unsigned char* src = (unsigned char*)elements + (vec->elementSize * numElements); + unsigned char* srcEnd = (unsigned char*)vec->storage + (vec->elementSize * vec->count); + (void)memmove(elements, src, srcEnd - src); + vec->count -= numElements; + if (vec->count == 0) + { + free(vec->storage); + vec->storage = NULL; + } + else + { + vec->storage = realloc(vec->storage, (vec->elementSize * vec->count)); + } + } +} + +void VECTOR_clear(VECTOR_HANDLE handle) +{ + if (handle != NULL) + { + VECTOR* vec = (VECTOR*)handle; + internal_VECTOR_clear(vec); + } +} + +/* access */ + +void* VECTOR_element(const VECTOR_HANDLE handle, size_t index) +{ + void* result = NULL; + if (handle != NULL) + { + const VECTOR* vec = (const VECTOR*)handle; + if (index <= vec->count) + { + result = (unsigned char*)vec->storage + (vec->elementSize * index); + } + } + return result; +} + +void* VECTOR_front(const VECTOR_HANDLE handle) +{ + void* result = NULL; + if (handle != NULL) + { + const VECTOR* vec = (const VECTOR*)handle; + result = vec->storage; + } + return result; +} + +void* VECTOR_back(const VECTOR_HANDLE handle) +{ + void* result = NULL; + if (handle != NULL) + { + const VECTOR* vec = (const VECTOR*)handle; + result = (unsigned char*)vec->storage + (vec->elementSize * (vec->count - 1)); + } + return result; +} + +void* VECTOR_find_if(const VECTOR_HANDLE handle, PREDICATE_FUNCTION pred, const void* value) +{ + void* result = NULL; + size_t i; + VECTOR* handleData = (VECTOR*)handle; + if (handle != NULL && pred != NULL && value != NULL) + { + for (i = 0; i < handleData->count; ++i) + { + void* elem = (unsigned char*)handleData->storage + (handleData->elementSize * i); + if (!!pred(elem, value)) + { + result = elem; + break; + } + } + } + return result; +} + +/* capacity */ + +size_t VECTOR_size(const VECTOR_HANDLE handle) +{ + size_t result = 0; + if (handle != NULL) + { + const VECTOR* vec = (const VECTOR*)handle; + result = vec->count; + } + return result; +} diff --git a/c/sharedutil/tests/CMakeLists.txt b/c/sharedutil/tests/CMakeLists.txt new file mode 100644 index 00000000..b4ca1ab8 --- /dev/null +++ b/c/sharedutil/tests/CMakeLists.txt @@ -0,0 +1,29 @@ +#Copyright (c) Microsoft. All rights reserved. +#Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#this is CMakeLists.txt for the folder tests of common +add_subdirectory(agenttime_unittests) +add_subdirectory(base64_unittests) +add_subdirectory(buffer_unittests) +add_subdirectory(crtabstractions_unittests) +#add_subdirectory(condition_unittests) +add_subdirectory(doublylinkedlist_unittests) +add_subdirectory(gballoc_unittests) +add_subdirectory(gballoc_without_init_unittests) +add_subdirectory(hmacsha256_unittests) + +if(${use_http}) + add_subdirectory(httpapiex_unittests) + add_subdirectory(httpapiexsas_unittests) + add_subdirectory(httpheaders_unittests) +endif() + +add_subdirectory(io_unittests) +add_subdirectory(list_unittests) +add_subdirectory(lock_unittests) +add_subdirectory(map_unittests) +add_subdirectory(sastoken_unittests) +add_subdirectory(string_tokenizer_unittests) +add_subdirectory(strings_unittests) +add_subdirectory(urlencode_unittests) +add_subdirectory(vector_unittests) \ No newline at end of file diff --git a/c/sharedutil/tests/agenttime_unittests/CMakeLists.txt b/c/sharedutil/tests/agenttime_unittests/CMakeLists.txt new file mode 100644 index 00000000..8688bd12 --- /dev/null +++ b/c/sharedutil/tests/agenttime_unittests/CMakeLists.txt @@ -0,0 +1,24 @@ +#Copyright (c) Microsoft. All rights reserved. +#Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#this is CMakeLists.txt for agenttime_unittests +cmake_minimum_required(VERSION 3.0) + +compileAsC99() + +set(theseTestsName agenttime_unittests) + +set(${theseTestsName}_cpp_files +${theseTestsName}.cpp +) + +set(${theseTestsName}_c_files +../../adapters/agenttime.c +) + +set(${theseTestsName}_h_files +) + + +build_test_artifacts(${theseTestsName} ON) + diff --git a/c/sharedutil/tests/agenttime_unittests/agenttime_unittests.cpp b/c/sharedutil/tests/agenttime_unittests/agenttime_unittests.cpp new file mode 100644 index 00000000..c4b80c33 --- /dev/null +++ b/c/sharedutil/tests/agenttime_unittests/agenttime_unittests.cpp @@ -0,0 +1,117 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include +#ifdef _CRTDBG_MAP_ALLOC +#include +#endif + +#include "testrunnerswitcher.h" +#include "micromock.h" +#include "micromockcharstararenullterminatedstrings.h" + +#include "agenttime.h" + + + +static MICROMOCK_MUTEX_HANDLE g_testByTest; + + +time_t my_time64(time_t * _Time) +{ + (void)_Time; + return (int64_t)-1; +} + +struct tm* my_gmtime64(time_t* _Time) +{ + (void)_Time; + return NULL; +} + +struct tm* my_localtime64(time_t * _Time) +{ + (void)_Time; + return NULL; +} + +time_t my_mktime64(struct tm* _Time) +{ + (void)_Time; + return (int64_t)-1; +} + +static MICROMOCK_GLOBAL_SEMAPHORE_HANDLE g_dllByDll; + +BEGIN_TEST_SUITE(agenttime_unittests) + + TEST_SUITE_INITIALIZE(TestClassInitialize) + { + INITIALIZE_MEMORY_DEBUG(g_dllByDll); + + g_testByTest = MicroMockCreateMutex(); + ASSERT_IS_NOT_NULL(g_testByTest); + } + + TEST_SUITE_CLEANUP(TestClassCleanup) + { + MicroMockDestroyMutex(g_testByTest); + DEINITIALIZE_MEMORY_DEBUG(g_dllByDll); + + } + + TEST_FUNCTION_INITIALIZE(TestMethodInitialize) + { + if (!MicroMockAcquireMutex(g_testByTest)) + { + ASSERT_FAIL("our mutex is ABANDONED. Failure in test framework"); + } + } + + TEST_FUNCTION_CLEANUP(TestMethodCleanup) + { + if (!MicroMockReleaseMutex(g_testByTest)) + { + ASSERT_FAIL("failure in test framework at ReleaseMutex"); + } + } + + TEST_FUNCTION(get_time_succeed) + { + ///act + time_t t; + auto result = get_time(&t); + + ///assert + ASSERT_ARE_EQUAL(int, (int)result, (int)t); + } + + TEST_FUNCTION(get_gmtime_success) + { + ///act + time_t now; + struct tm* p; + now = get_time(NULL); + p = get_gmtime(&now); + + ///assert + ASSERT_IS_NOT_NULL(p); + } + + TEST_FUNCTION(get_difftime_success) + { + time_t now, sometimeAfterNow; + now = get_time(NULL); + sometimeAfterNow = now + 42; /*whatever this is*/ + double diff; + + ///act + diff = get_difftime(sometimeAfterNow, now); + + ///assert + ASSERT_ARE_EQUAL(double, difftime(sometimeAfterNow, now), diff); + } + + +END_TEST_SUITE(agenttime_unittests) + diff --git a/c/sharedutil/tests/agenttime_unittests/main.c b/c/sharedutil/tests/agenttime_unittests/main.c new file mode 100644 index 00000000..1377a148 --- /dev/null +++ b/c/sharedutil/tests/agenttime_unittests/main.c @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include "testrunnerswitcher.h" + +int main(void) +{ + size_t failedTestCount = 0; + RUN_TEST_SUITE(agenttime_unittests, failedTestCount); + return failedTestCount; +} diff --git a/c/sharedutil/tests/base64_unittests/CMakeLists.txt b/c/sharedutil/tests/base64_unittests/CMakeLists.txt new file mode 100644 index 00000000..99f5810b --- /dev/null +++ b/c/sharedutil/tests/base64_unittests/CMakeLists.txt @@ -0,0 +1,23 @@ +#Copyright (c) Microsoft. All rights reserved. +#Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#this is CMakeLists.txt for base64_unittests +cmake_minimum_required(VERSION 3.0) + +compileAsC99() +set(theseTestsName base64_unittests ) + +set(${theseTestsName}_cpp_files +${theseTestsName}.cpp +) + +set(${theseTestsName}_c_files +../../src/base64.c +../../src/strings.c +../../src/buffer.c +) + +set(${theseTestsName}_h_files +) + +build_test_artifacts(${theseTestsName} OFF) diff --git a/c/sharedutil/tests/base64_unittests/base64_unittests.cpp b/c/sharedutil/tests/base64_unittests/base64_unittests.cpp new file mode 100644 index 00000000..8dcfa38c --- /dev/null +++ b/c/sharedutil/tests/base64_unittests/base64_unittests.cpp @@ -0,0 +1,1683 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// +// PUT NO INCLUDES BEFORE HERE !!!! +// +#include +#ifdef _CRTDBG_MAP_ALLOC +#include +#endif +#include +#include +// +// PUT NO CLIENT LIBRARY INCLUDES BEFORE HERE !!!! +// + +#include "base64.h" +#include "strings.h" +#include "buffer_.h" + +#include "testrunnerswitcher.h" +#include "micromock.h" + +#ifdef _MSC_VER +#pragma warning(disable:4505) +#endif + +static const struct +{ + size_t inputLength; + const unsigned char* inputData; + const char* expectedOutput; +} testVector_BINARY_with_equal_signs[] = + { + {1,(const unsigned char*)"\x00", "AA==" }, + {1,(const unsigned char*)"\x01", "AQ==" }, + {1,(const unsigned char*)"\x02", "Ag==" }, + {1,(const unsigned char*)"\x03", "Aw==" }, + {1,(const unsigned char*)"\x04", "BA==" }, + {1,(const unsigned char*)"\x05", "BQ==" }, + {1,(const unsigned char*)"\x06", "Bg==" }, + {1,(const unsigned char*)"\x07", "Bw==" }, + {1,(const unsigned char*)"\x08", "CA==" }, + {1,(const unsigned char*)"\x09", "CQ==" }, + {1,(const unsigned char*)"\x0a", "Cg==" }, + {1,(const unsigned char*)"\x0b", "Cw==" }, + {1,(const unsigned char*)"\x0c", "DA==" }, + {1,(const unsigned char*)"\x0d", "DQ==" }, + {1,(const unsigned char*)"\x0e", "Dg==" }, + {1,(const unsigned char*)"\x0f", "Dw==" }, + {1,(const unsigned char*)"\x10", "EA==" }, + {1,(const unsigned char*)"\x11", "EQ==" }, + {1,(const unsigned char*)"\x12", "Eg==" }, + {1,(const unsigned char*)"\x13", "Ew==" }, + {1,(const unsigned char*)"\x14", "FA==" }, + {1,(const unsigned char*)"\x15", "FQ==" }, + {1,(const unsigned char*)"\x16", "Fg==" }, + {1,(const unsigned char*)"\x17", "Fw==" }, + {1,(const unsigned char*)"\x18", "GA==" }, + {1,(const unsigned char*)"\x19", "GQ==" }, + {1,(const unsigned char*)"\x1a", "Gg==" }, + {1,(const unsigned char*)"\x1b", "Gw==" }, + {1,(const unsigned char*)"\x1c", "HA==" }, + {1,(const unsigned char*)"\x1d", "HQ==" }, + {1,(const unsigned char*)"\x1e", "Hg==" }, + {1,(const unsigned char*)"\x1f", "Hw==" }, + {1,(const unsigned char*)"\x20", "IA==" }, + {1,(const unsigned char*)"\x21", "IQ==" }, + {1,(const unsigned char*)"\x22", "Ig==" }, + {1,(const unsigned char*)"\x23", "Iw==" }, + {1,(const unsigned char*)"\x24", "JA==" }, + {1,(const unsigned char*)"\x25", "JQ==" }, + {1,(const unsigned char*)"\x26", "Jg==" }, + {1,(const unsigned char*)"\x27", "Jw==" }, + {1,(const unsigned char*)"\x28", "KA==" }, + {1,(const unsigned char*)"\x29", "KQ==" }, + {1,(const unsigned char*)"\x2a", "Kg==" }, + {1,(const unsigned char*)"\x2b", "Kw==" }, + {1,(const unsigned char*)"\x2c", "LA==" }, + {1,(const unsigned char*)"\x2d", "LQ==" }, + {1,(const unsigned char*)"\x2e", "Lg==" }, + {1,(const unsigned char*)"\x2f", "Lw==" }, + {1,(const unsigned char*)"\x30", "MA==" }, + {1,(const unsigned char*)"\x31", "MQ==" }, + {1,(const unsigned char*)"\x32", "Mg==" }, + {1,(const unsigned char*)"\x33", "Mw==" }, + {1,(const unsigned char*)"\x34", "NA==" }, + {1,(const unsigned char*)"\x35", "NQ==" }, + {1,(const unsigned char*)"\x36", "Ng==" }, + {1,(const unsigned char*)"\x37", "Nw==" }, + {1,(const unsigned char*)"\x38", "OA==" }, + {1,(const unsigned char*)"\x39", "OQ==" }, + {1,(const unsigned char*)"\x3a", "Og==" }, + {1,(const unsigned char*)"\x3b", "Ow==" }, + {1,(const unsigned char*)"\x3c", "PA==" }, + {1,(const unsigned char*)"\x3d", "PQ==" }, + {1,(const unsigned char*)"\x3e", "Pg==" }, + {1,(const unsigned char*)"\x3f", "Pw==" }, + {1,(const unsigned char*)"\x40", "QA==" }, + {1,(const unsigned char*)"\x41", "QQ==" }, + {1,(const unsigned char*)"\x42", "Qg==" }, + {1,(const unsigned char*)"\x43", "Qw==" }, + {1,(const unsigned char*)"\x44", "RA==" }, + {1,(const unsigned char*)"\x45", "RQ==" }, + {1,(const unsigned char*)"\x46", "Rg==" }, + {1,(const unsigned char*)"\x47", "Rw==" }, + {1,(const unsigned char*)"\x48", "SA==" }, + {1,(const unsigned char*)"\x49", "SQ==" }, + {1,(const unsigned char*)"\x4a", "Sg==" }, + {1,(const unsigned char*)"\x4b", "Sw==" }, + {1,(const unsigned char*)"\x4c", "TA==" }, + {1,(const unsigned char*)"\x4d", "TQ==" }, + {1,(const unsigned char*)"\x4e", "Tg==" }, + {1,(const unsigned char*)"\x4f", "Tw==" }, + {1,(const unsigned char*)"\x50", "UA==" }, + {1,(const unsigned char*)"\x51", "UQ==" }, + {1,(const unsigned char*)"\x52", "Ug==" }, + {1,(const unsigned char*)"\x53", "Uw==" }, + {1,(const unsigned char*)"\x54", "VA==" }, + {1,(const unsigned char*)"\x55", "VQ==" }, + {1,(const unsigned char*)"\x56", "Vg==" }, + {1,(const unsigned char*)"\x57", "Vw==" }, + {1,(const unsigned char*)"\x58", "WA==" }, + {1,(const unsigned char*)"\x59", "WQ==" }, + {1,(const unsigned char*)"\x5a", "Wg==" }, + {1,(const unsigned char*)"\x5b", "Ww==" }, + {1,(const unsigned char*)"\x5c", "XA==" }, + {1,(const unsigned char*)"\x5d", "XQ==" }, + {1,(const unsigned char*)"\x5e", "Xg==" }, + {1,(const unsigned char*)"\x5f", "Xw==" }, + {1,(const unsigned char*)"\x60", "YA==" }, + {1,(const unsigned char*)"\x61", "YQ==" }, + {1,(const unsigned char*)"\x62", "Yg==" }, + {1,(const unsigned char*)"\x63", "Yw==" }, + {1,(const unsigned char*)"\x64", "ZA==" }, + {1,(const unsigned char*)"\x65", "ZQ==" }, + {1,(const unsigned char*)"\x66", "Zg==" }, + {1,(const unsigned char*)"\x67", "Zw==" }, + {1,(const unsigned char*)"\x68", "aA==" }, + {1,(const unsigned char*)"\x69", "aQ==" }, + {1,(const unsigned char*)"\x6a", "ag==" }, + {1,(const unsigned char*)"\x6b", "aw==" }, + {1,(const unsigned char*)"\x6c", "bA==" }, + {1,(const unsigned char*)"\x6d", "bQ==" }, + {1,(const unsigned char*)"\x6e", "bg==" }, + {1,(const unsigned char*)"\x6f", "bw==" }, + {1,(const unsigned char*)"\x70", "cA==" }, + {1,(const unsigned char*)"\x71", "cQ==" }, + {1,(const unsigned char*)"\x72", "cg==" }, + {1,(const unsigned char*)"\x73", "cw==" }, + {1,(const unsigned char*)"\x74", "dA==" }, + {1,(const unsigned char*)"\x75", "dQ==" }, + {1,(const unsigned char*)"\x76", "dg==" }, + {1,(const unsigned char*)"\x77", "dw==" }, + {1,(const unsigned char*)"\x78", "eA==" }, + {1,(const unsigned char*)"\x79", "eQ==" }, + {1,(const unsigned char*)"\x7a", "eg==" }, + {1,(const unsigned char*)"\x7b", "ew==" }, + {1,(const unsigned char*)"\x7c", "fA==" }, + {1,(const unsigned char*)"\x7d", "fQ==" }, + {1,(const unsigned char*)"\x7e", "fg==" }, + {1,(const unsigned char*)"\x7f", "fw==" }, + {1,(const unsigned char*)"\x80", "gA==" }, + {1,(const unsigned char*)"\x81", "gQ==" }, + {1,(const unsigned char*)"\x82", "gg==" }, + {1,(const unsigned char*)"\x83", "gw==" }, + {1,(const unsigned char*)"\x84", "hA==" }, + {1,(const unsigned char*)"\x85", "hQ==" }, + {1,(const unsigned char*)"\x86", "hg==" }, + {1,(const unsigned char*)"\x87", "hw==" }, + {1,(const unsigned char*)"\x88", "iA==" }, + {1,(const unsigned char*)"\x89", "iQ==" }, + {1,(const unsigned char*)"\x8a", "ig==" }, + {1,(const unsigned char*)"\x8b", "iw==" }, + {1,(const unsigned char*)"\x8c", "jA==" }, + {1,(const unsigned char*)"\x8d", "jQ==" }, + {1,(const unsigned char*)"\x8e", "jg==" }, + {1,(const unsigned char*)"\x8f", "jw==" }, + {1,(const unsigned char*)"\x90", "kA==" }, + {1,(const unsigned char*)"\x91", "kQ==" }, + {1,(const unsigned char*)"\x92", "kg==" }, + {1,(const unsigned char*)"\x93", "kw==" }, + {1,(const unsigned char*)"\x94", "lA==" }, + {1,(const unsigned char*)"\x95", "lQ==" }, + {1,(const unsigned char*)"\x96", "lg==" }, + {1,(const unsigned char*)"\x97", "lw==" }, + {1,(const unsigned char*)"\x98", "mA==" }, + {1,(const unsigned char*)"\x99", "mQ==" }, + {1,(const unsigned char*)"\x9a", "mg==" }, + {1,(const unsigned char*)"\x9b", "mw==" }, + {1,(const unsigned char*)"\x9c", "nA==" }, + {1,(const unsigned char*)"\x9d", "nQ==" }, + {1,(const unsigned char*)"\x9e", "ng==" }, + {1,(const unsigned char*)"\x9f", "nw==" }, + {1,(const unsigned char*)"\xa0", "oA==" }, + {1,(const unsigned char*)"\xa1", "oQ==" }, + {1,(const unsigned char*)"\xa2", "og==" }, + {1,(const unsigned char*)"\xa3", "ow==" }, + {1,(const unsigned char*)"\xa4", "pA==" }, + {1,(const unsigned char*)"\xa5", "pQ==" }, + {1,(const unsigned char*)"\xa6", "pg==" }, + {1,(const unsigned char*)"\xa7", "pw==" }, + {1,(const unsigned char*)"\xa8", "qA==" }, + {1,(const unsigned char*)"\xa9", "qQ==" }, + {1,(const unsigned char*)"\xaa", "qg==" }, + {1,(const unsigned char*)"\xab", "qw==" }, + {1,(const unsigned char*)"\xac", "rA==" }, + {1,(const unsigned char*)"\xad", "rQ==" }, + {1,(const unsigned char*)"\xae", "rg==" }, + {1,(const unsigned char*)"\xaf", "rw==" }, + {1,(const unsigned char*)"\xb0", "sA==" }, + {1,(const unsigned char*)"\xb1", "sQ==" }, + {1,(const unsigned char*)"\xb2", "sg==" }, + {1,(const unsigned char*)"\xb3", "sw==" }, + {1,(const unsigned char*)"\xb4", "tA==" }, + {1,(const unsigned char*)"\xb5", "tQ==" }, + {1,(const unsigned char*)"\xb6", "tg==" }, + {1,(const unsigned char*)"\xb7", "tw==" }, + {1,(const unsigned char*)"\xb8", "uA==" }, + {1,(const unsigned char*)"\xb9", "uQ==" }, + {1,(const unsigned char*)"\xba", "ug==" }, + {1,(const unsigned char*)"\xbb", "uw==" }, + {1,(const unsigned char*)"\xbc", "vA==" }, + {1,(const unsigned char*)"\xbd", "vQ==" }, + {1,(const unsigned char*)"\xbe", "vg==" }, + {1,(const unsigned char*)"\xbf", "vw==" }, + {1,(const unsigned char*)"\xc0", "wA==" }, + {1,(const unsigned char*)"\xc1", "wQ==" }, + {1,(const unsigned char*)"\xc2", "wg==" }, + {1,(const unsigned char*)"\xc3", "ww==" }, + {1,(const unsigned char*)"\xc4", "xA==" }, + {1,(const unsigned char*)"\xc5", "xQ==" }, + {1,(const unsigned char*)"\xc6", "xg==" }, + {1,(const unsigned char*)"\xc7", "xw==" }, + {1,(const unsigned char*)"\xc8", "yA==" }, + {1,(const unsigned char*)"\xc9", "yQ==" }, + {1,(const unsigned char*)"\xca", "yg==" }, + {1,(const unsigned char*)"\xcb", "yw==" }, + {1,(const unsigned char*)"\xcc", "zA==" }, + {1,(const unsigned char*)"\xcd", "zQ==" }, + {1,(const unsigned char*)"\xce", "zg==" }, + {1,(const unsigned char*)"\xcf", "zw==" }, + {1,(const unsigned char*)"\xd0", "0A==" }, + {1,(const unsigned char*)"\xd1", "0Q==" }, + {1,(const unsigned char*)"\xd2", "0g==" }, + {1,(const unsigned char*)"\xd3", "0w==" }, + {1,(const unsigned char*)"\xd4", "1A==" }, + {1,(const unsigned char*)"\xd5", "1Q==" }, + {1,(const unsigned char*)"\xd6", "1g==" }, + {1,(const unsigned char*)"\xd7", "1w==" }, + {1,(const unsigned char*)"\xd8", "2A==" }, + {1,(const unsigned char*)"\xd9", "2Q==" }, + {1,(const unsigned char*)"\xda", "2g==" }, + {1,(const unsigned char*)"\xdb", "2w==" }, + {1,(const unsigned char*)"\xdc", "3A==" }, + {1,(const unsigned char*)"\xdd", "3Q==" }, + {1,(const unsigned char*)"\xde", "3g==" }, + {1,(const unsigned char*)"\xdf", "3w==" }, + {1,(const unsigned char*)"\xe0", "4A==" }, + {1,(const unsigned char*)"\xe1", "4Q==" }, + {1,(const unsigned char*)"\xe2", "4g==" }, + {1,(const unsigned char*)"\xe3", "4w==" }, + {1,(const unsigned char*)"\xe4", "5A==" }, + {1,(const unsigned char*)"\xe5", "5Q==" }, + {1,(const unsigned char*)"\xe6", "5g==" }, + {1,(const unsigned char*)"\xe7", "5w==" }, + {1,(const unsigned char*)"\xe8", "6A==" }, + {1,(const unsigned char*)"\xe9", "6Q==" }, + {1,(const unsigned char*)"\xea", "6g==" }, + {1,(const unsigned char*)"\xeb", "6w==" }, + {1,(const unsigned char*)"\xec", "7A==" }, + {1,(const unsigned char*)"\xed", "7Q==" }, + {1,(const unsigned char*)"\xee", "7g==" }, + {1,(const unsigned char*)"\xef", "7w==" }, + {1,(const unsigned char*)"\xf0", "8A==" }, + {1,(const unsigned char*)"\xf1", "8Q==" }, + {1,(const unsigned char*)"\xf2", "8g==" }, + {1,(const unsigned char*)"\xf3", "8w==" }, + {1,(const unsigned char*)"\xf4", "9A==" }, + {1,(const unsigned char*)"\xf5", "9Q==" }, + {1,(const unsigned char*)"\xf6", "9g==" }, + {1,(const unsigned char*)"\xf7", "9w==" }, + {1,(const unsigned char*)"\xf8", "+A==" }, + {1,(const unsigned char*)"\xf9", "+Q==" }, + {1,(const unsigned char*)"\xfa", "+g==" }, + {1,(const unsigned char*)"\xfb", "+w==" }, + {1,(const unsigned char*)"\xfc", "/A==" }, + {1,(const unsigned char*)"\xfd", "/Q==" }, + {1,(const unsigned char*)"\xfe", "/g==" }, + {1,(const unsigned char*)"\xff", "/w==" }, + {2,(const unsigned char*)"\x00\x00", "AAA=" }, + {2,(const unsigned char*)"\x00\x11", "ABE=" }, + {2,(const unsigned char*)"\x00\x22", "ACI=" }, + {2,(const unsigned char*)"\x00\x33", "ADM=" }, + {2,(const unsigned char*)"\x00\x44", "AEQ=" }, + {2,(const unsigned char*)"\x00\x55", "AFU=" }, + {2,(const unsigned char*)"\x00\x66", "AGY=" }, + {2,(const unsigned char*)"\x00\x77", "AHc=" }, + {2,(const unsigned char*)"\x00\x88", "AIg=" }, + {2,(const unsigned char*)"\x00\x99", "AJk=" }, + {2,(const unsigned char*)"\x00\xaa", "AKo=" }, + {2,(const unsigned char*)"\x00\xbb", "ALs=" }, + {2,(const unsigned char*)"\x00\xcc", "AMw=" }, + {2,(const unsigned char*)"\x00\xdd", "AN0=" }, + {2,(const unsigned char*)"\x00\xee", "AO4=" }, + {2,(const unsigned char*)"\x00\xff", "AP8=" }, + {2,(const unsigned char*)"\x11\x00", "EQA=" }, + {2,(const unsigned char*)"\x11\x11", "ERE=" }, + {2,(const unsigned char*)"\x11\x22", "ESI=" }, + {2,(const unsigned char*)"\x11\x33", "ETM=" }, + {2,(const unsigned char*)"\x11\x44", "EUQ=" }, + {2,(const unsigned char*)"\x11\x55", "EVU=" }, + {2,(const unsigned char*)"\x11\x66", "EWY=" }, + {2,(const unsigned char*)"\x11\x77", "EXc=" }, + {2,(const unsigned char*)"\x11\x88", "EYg=" }, + {2,(const unsigned char*)"\x11\x99", "EZk=" }, + {2,(const unsigned char*)"\x11\xaa", "Eao=" }, + {2,(const unsigned char*)"\x11\xbb", "Ebs=" }, + {2,(const unsigned char*)"\x11\xcc", "Ecw=" }, + {2,(const unsigned char*)"\x11\xdd", "Ed0=" }, + {2,(const unsigned char*)"\x11\xee", "Ee4=" }, + {2,(const unsigned char*)"\x11\xff", "Ef8=" }, + {2,(const unsigned char*)"\x22\x00", "IgA=" }, + {2,(const unsigned char*)"\x22\x11", "IhE=" }, + {2,(const unsigned char*)"\x22\x22", "IiI=" }, + {2,(const unsigned char*)"\x22\x33", "IjM=" }, + {2,(const unsigned char*)"\x22\x44", "IkQ=" }, + {2,(const unsigned char*)"\x22\x55", "IlU=" }, + {2,(const unsigned char*)"\x22\x66", "ImY=" }, + {2,(const unsigned char*)"\x22\x77", "Inc=" }, + {2,(const unsigned char*)"\x22\x88", "Iog=" }, + {2,(const unsigned char*)"\x22\x99", "Ipk=" }, + {2,(const unsigned char*)"\x22\xaa", "Iqo=" }, + {2,(const unsigned char*)"\x22\xbb", "Irs=" }, + {2,(const unsigned char*)"\x22\xcc", "Isw=" }, + {2,(const unsigned char*)"\x22\xdd", "It0=" }, + {2,(const unsigned char*)"\x22\xee", "Iu4=" }, + {2,(const unsigned char*)"\x22\xff", "Iv8=" }, + {2,(const unsigned char*)"\x33\x00", "MwA=" }, + {2,(const unsigned char*)"\x33\x11", "MxE=" }, + {2,(const unsigned char*)"\x33\x22", "MyI=" }, + {2,(const unsigned char*)"\x33\x33", "MzM=" }, + {2,(const unsigned char*)"\x33\x44", "M0Q=" }, + {2,(const unsigned char*)"\x33\x55", "M1U=" }, + {2,(const unsigned char*)"\x33\x66", "M2Y=" }, + {2,(const unsigned char*)"\x33\x77", "M3c=" }, + {2,(const unsigned char*)"\x33\x88", "M4g=" }, + {2,(const unsigned char*)"\x33\x99", "M5k=" }, + {2,(const unsigned char*)"\x33\xaa", "M6o=" }, + {2,(const unsigned char*)"\x33\xbb", "M7s=" }, + {2,(const unsigned char*)"\x33\xcc", "M8w=" }, + {2,(const unsigned char*)"\x33\xdd", "M90=" }, + {2,(const unsigned char*)"\x33\xee", "M+4=" }, + {2,(const unsigned char*)"\x33\xff", "M/8=" }, + {2,(const unsigned char*)"\x44\x00", "RAA=" }, + {2,(const unsigned char*)"\x44\x11", "RBE=" }, + {2,(const unsigned char*)"\x44\x22", "RCI=" }, + {2,(const unsigned char*)"\x44\x33", "RDM=" }, + {2,(const unsigned char*)"\x44\x44", "REQ=" }, + {2,(const unsigned char*)"\x44\x55", "RFU=" }, + {2,(const unsigned char*)"\x44\x66", "RGY=" }, + {2,(const unsigned char*)"\x44\x77", "RHc=" }, + {2,(const unsigned char*)"\x44\x88", "RIg=" }, + {2,(const unsigned char*)"\x44\x99", "RJk=" }, + {2,(const unsigned char*)"\x44\xaa", "RKo=" }, + {2,(const unsigned char*)"\x44\xbb", "RLs=" }, + {2,(const unsigned char*)"\x44\xcc", "RMw=" }, + {2,(const unsigned char*)"\x44\xdd", "RN0=" }, + {2,(const unsigned char*)"\x44\xee", "RO4=" }, + {2,(const unsigned char*)"\x44\xff", "RP8=" }, + {2,(const unsigned char*)"\x55\x00", "VQA=" }, + {2,(const unsigned char*)"\x55\x11", "VRE=" }, + {2,(const unsigned char*)"\x55\x22", "VSI=" }, + {2,(const unsigned char*)"\x55\x33", "VTM=" }, + {2,(const unsigned char*)"\x55\x44", "VUQ=" }, + {2,(const unsigned char*)"\x55\x55", "VVU=" }, + {2,(const unsigned char*)"\x55\x66", "VWY=" }, + {2,(const unsigned char*)"\x55\x77", "VXc=" }, + {2,(const unsigned char*)"\x55\x88", "VYg=" }, + {2,(const unsigned char*)"\x55\x99", "VZk=" }, + {2,(const unsigned char*)"\x55\xaa", "Vao=" }, + {2,(const unsigned char*)"\x55\xbb", "Vbs=" }, + {2,(const unsigned char*)"\x55\xcc", "Vcw=" }, + {2,(const unsigned char*)"\x55\xdd", "Vd0=" }, + {2,(const unsigned char*)"\x55\xee", "Ve4=" }, + {2,(const unsigned char*)"\x55\xff", "Vf8=" }, + {2,(const unsigned char*)"\x66\x00", "ZgA=" }, + {2,(const unsigned char*)"\x66\x11", "ZhE=" }, + {2,(const unsigned char*)"\x66\x22", "ZiI=" }, + {2,(const unsigned char*)"\x66\x33", "ZjM=" }, + {2,(const unsigned char*)"\x66\x44", "ZkQ=" }, + {2,(const unsigned char*)"\x66\x55", "ZlU=" }, + {2,(const unsigned char*)"\x66\x66", "ZmY=" }, + {2,(const unsigned char*)"\x66\x77", "Znc=" }, + {2,(const unsigned char*)"\x66\x88", "Zog=" }, + {2,(const unsigned char*)"\x66\x99", "Zpk=" }, + {2,(const unsigned char*)"\x66\xaa", "Zqo=" }, + {2,(const unsigned char*)"\x66\xbb", "Zrs=" }, + {2,(const unsigned char*)"\x66\xcc", "Zsw=" }, + {2,(const unsigned char*)"\x66\xdd", "Zt0=" }, + {2,(const unsigned char*)"\x66\xee", "Zu4=" }, + {2,(const unsigned char*)"\x66\xff", "Zv8=" }, + {2,(const unsigned char*)"\x77\x00", "dwA=" }, + {2,(const unsigned char*)"\x77\x11", "dxE=" }, + {2,(const unsigned char*)"\x77\x22", "dyI=" }, + {2,(const unsigned char*)"\x77\x33", "dzM=" }, + {2,(const unsigned char*)"\x77\x44", "d0Q=" }, + {2,(const unsigned char*)"\x77\x55", "d1U=" }, + {2,(const unsigned char*)"\x77\x66", "d2Y=" }, + {2,(const unsigned char*)"\x77\x77", "d3c=" }, + {2,(const unsigned char*)"\x77\x88", "d4g=" }, + {2,(const unsigned char*)"\x77\x99", "d5k=" }, + {2,(const unsigned char*)"\x77\xaa", "d6o=" }, + {2,(const unsigned char*)"\x77\xbb", "d7s=" }, + {2,(const unsigned char*)"\x77\xcc", "d8w=" }, + {2,(const unsigned char*)"\x77\xdd", "d90=" }, + {2,(const unsigned char*)"\x77\xee", "d+4=" }, + {2,(const unsigned char*)"\x77\xff", "d/8=" }, + {2,(const unsigned char*)"\x88\x00", "iAA=" }, + {2,(const unsigned char*)"\x88\x11", "iBE=" }, + {2,(const unsigned char*)"\x88\x22", "iCI=" }, + {2,(const unsigned char*)"\x88\x33", "iDM=" }, + {2,(const unsigned char*)"\x88\x44", "iEQ=" }, + {2,(const unsigned char*)"\x88\x55", "iFU=" }, + {2,(const unsigned char*)"\x88\x66", "iGY=" }, + {2,(const unsigned char*)"\x88\x77", "iHc=" }, + {2,(const unsigned char*)"\x88\x88", "iIg=" }, + {2,(const unsigned char*)"\x88\x99", "iJk=" }, + {2,(const unsigned char*)"\x88\xaa", "iKo=" }, + {2,(const unsigned char*)"\x88\xbb", "iLs=" }, + {2,(const unsigned char*)"\x88\xcc", "iMw=" }, + {2,(const unsigned char*)"\x88\xdd", "iN0=" }, + {2,(const unsigned char*)"\x88\xee", "iO4=" }, + {2,(const unsigned char*)"\x88\xff", "iP8=" }, + {2,(const unsigned char*)"\x99\x00", "mQA=" }, + {2,(const unsigned char*)"\x99\x11", "mRE=" }, + {2,(const unsigned char*)"\x99\x22", "mSI=" }, + {2,(const unsigned char*)"\x99\x33", "mTM=" }, + {2,(const unsigned char*)"\x99\x44", "mUQ=" }, + {2,(const unsigned char*)"\x99\x55", "mVU=" }, + {2,(const unsigned char*)"\x99\x66", "mWY=" }, + {2,(const unsigned char*)"\x99\x77", "mXc=" }, + {2,(const unsigned char*)"\x99\x88", "mYg=" }, + {2,(const unsigned char*)"\x99\x99", "mZk=" }, + {2,(const unsigned char*)"\x99\xaa", "mao=" }, + {2,(const unsigned char*)"\x99\xbb", "mbs=" }, + {2,(const unsigned char*)"\x99\xcc", "mcw=" }, + {2,(const unsigned char*)"\x99\xdd", "md0=" }, + {2,(const unsigned char*)"\x99\xee", "me4=" }, + {2,(const unsigned char*)"\x99\xff", "mf8=" }, + {2,(const unsigned char*)"\xaa\x00", "qgA=" }, + {2,(const unsigned char*)"\xaa\x11", "qhE=" }, + {2,(const unsigned char*)"\xaa\x22", "qiI=" }, + {2,(const unsigned char*)"\xaa\x33", "qjM=" }, + {2,(const unsigned char*)"\xaa\x44", "qkQ=" }, + {2,(const unsigned char*)"\xaa\x55", "qlU=" }, + {2,(const unsigned char*)"\xaa\x66", "qmY=" }, + {2,(const unsigned char*)"\xaa\x77", "qnc=" }, + {2,(const unsigned char*)"\xaa\x88", "qog=" }, + {2,(const unsigned char*)"\xaa\x99", "qpk=" }, + {2,(const unsigned char*)"\xaa\xaa", "qqo=" }, + {2,(const unsigned char*)"\xaa\xbb", "qrs=" }, + {2,(const unsigned char*)"\xaa\xcc", "qsw=" }, + {2,(const unsigned char*)"\xaa\xdd", "qt0=" }, + {2,(const unsigned char*)"\xaa\xee", "qu4=" }, + {2,(const unsigned char*)"\xaa\xff", "qv8=" }, + {2,(const unsigned char*)"\xbb\x00", "uwA=" }, + {2,(const unsigned char*)"\xbb\x11", "uxE=" }, + {2,(const unsigned char*)"\xbb\x22", "uyI=" }, + {2,(const unsigned char*)"\xbb\x33", "uzM=" }, + {2,(const unsigned char*)"\xbb\x44", "u0Q=" }, + {2,(const unsigned char*)"\xbb\x55", "u1U=" }, + {2,(const unsigned char*)"\xbb\x66", "u2Y=" }, + {2,(const unsigned char*)"\xbb\x77", "u3c=" }, + {2,(const unsigned char*)"\xbb\x88", "u4g=" }, + {2,(const unsigned char*)"\xbb\x99", "u5k=" }, + {2,(const unsigned char*)"\xbb\xaa", "u6o=" }, + {2,(const unsigned char*)"\xbb\xbb", "u7s=" }, + {2,(const unsigned char*)"\xbb\xcc", "u8w=" }, + {2,(const unsigned char*)"\xbb\xdd", "u90=" }, + {2,(const unsigned char*)"\xbb\xee", "u+4=" }, + {2,(const unsigned char*)"\xbb\xff", "u/8=" }, + {2,(const unsigned char*)"\xcc\x00", "zAA=" }, + {2,(const unsigned char*)"\xcc\x11", "zBE=" }, + {2,(const unsigned char*)"\xcc\x22", "zCI=" }, + {2,(const unsigned char*)"\xcc\x33", "zDM=" }, + {2,(const unsigned char*)"\xcc\x44", "zEQ=" }, + {2,(const unsigned char*)"\xcc\x55", "zFU=" }, + {2,(const unsigned char*)"\xcc\x66", "zGY=" }, + {2,(const unsigned char*)"\xcc\x77", "zHc=" }, + {2,(const unsigned char*)"\xcc\x88", "zIg=" }, + {2,(const unsigned char*)"\xcc\x99", "zJk=" }, + {2,(const unsigned char*)"\xcc\xaa", "zKo=" }, + {2,(const unsigned char*)"\xcc\xbb", "zLs=" }, + {2,(const unsigned char*)"\xcc\xcc", "zMw=" }, + {2,(const unsigned char*)"\xcc\xdd", "zN0=" }, + {2,(const unsigned char*)"\xcc\xee", "zO4=" }, + {2,(const unsigned char*)"\xcc\xff", "zP8=" }, + {2,(const unsigned char*)"\xdd\x00", "3QA=" }, + {2,(const unsigned char*)"\xdd\x11", "3RE=" }, + {2,(const unsigned char*)"\xdd\x22", "3SI=" }, + {2,(const unsigned char*)"\xdd\x33", "3TM=" }, + {2,(const unsigned char*)"\xdd\x44", "3UQ=" }, + {2,(const unsigned char*)"\xdd\x55", "3VU=" }, + {2,(const unsigned char*)"\xdd\x66", "3WY=" }, + {2,(const unsigned char*)"\xdd\x77", "3Xc=" }, + {2,(const unsigned char*)"\xdd\x88", "3Yg=" }, + {2,(const unsigned char*)"\xdd\x99", "3Zk=" }, + {2,(const unsigned char*)"\xdd\xaa", "3ao=" }, + {2,(const unsigned char*)"\xdd\xbb", "3bs=" }, + {2,(const unsigned char*)"\xdd\xcc", "3cw=" }, + {2,(const unsigned char*)"\xdd\xdd", "3d0=" }, + {2,(const unsigned char*)"\xdd\xee", "3e4=" }, + {2,(const unsigned char*)"\xdd\xff", "3f8=" }, + {2,(const unsigned char*)"\xee\x00", "7gA=" }, + {2,(const unsigned char*)"\xee\x11", "7hE=" }, + {2,(const unsigned char*)"\xee\x22", "7iI=" }, + {2,(const unsigned char*)"\xee\x33", "7jM=" }, + {2,(const unsigned char*)"\xee\x44", "7kQ=" }, + {2,(const unsigned char*)"\xee\x55", "7lU=" }, + {2,(const unsigned char*)"\xee\x66", "7mY=" }, + {2,(const unsigned char*)"\xee\x77", "7nc=" }, + {2,(const unsigned char*)"\xee\x88", "7og=" }, + {2,(const unsigned char*)"\xee\x99", "7pk=" }, + {2,(const unsigned char*)"\xee\xaa", "7qo=" }, + {2,(const unsigned char*)"\xee\xbb", "7rs=" }, + {2,(const unsigned char*)"\xee\xcc", "7sw=" }, + {2,(const unsigned char*)"\xee\xdd", "7t0=" }, + {2,(const unsigned char*)"\xee\xee", "7u4=" }, + {2,(const unsigned char*)"\xee\xff", "7v8=" }, + {2,(const unsigned char*)"\xff\x00", "/wA=" }, + {2,(const unsigned char*)"\xff\x11", "/xE=" }, + {2,(const unsigned char*)"\xff\x22", "/yI=" }, + {2,(const unsigned char*)"\xff\x33", "/zM=" }, + {2,(const unsigned char*)"\xff\x44", "/0Q=" }, + {2,(const unsigned char*)"\xff\x55", "/1U=" }, + {2,(const unsigned char*)"\xff\x66", "/2Y=" }, + {2,(const unsigned char*)"\xff\x77", "/3c=" }, + {2,(const unsigned char*)"\xff\x88", "/4g=" }, + {2,(const unsigned char*)"\xff\x99", "/5k=" }, + {2,(const unsigned char*)"\xff\xaa", "/6o=" }, + {2,(const unsigned char*)"\xff\xbb", "/7s=" }, + {2,(const unsigned char*)"\xff\xcc", "/8w=" }, + {2,(const unsigned char*)"\xff\xdd", "/90=" }, + {2,(const unsigned char*)"\xff\xee", "/+4=" }, + {2,(const unsigned char*)"\xff\xff", "//8=" }, + {3,(const unsigned char*)"\x00\x00\x00", "AAAA" }, + {3,(const unsigned char*)"\x00\x00\x2f", "AAAv" }, + {3,(const unsigned char*)"\x00\x00\x5e", "AABe" }, + {3,(const unsigned char*)"\x00\x00\x8d", "AACN" }, + {3,(const unsigned char*)"\x00\x00\xbc", "AAC8" }, + {3,(const unsigned char*)"\x00\x00\xeb", "AADr" }, + {3,(const unsigned char*)"\x00\x2f\x00", "AC8A" }, + {3,(const unsigned char*)"\x00\x2f\x2f", "AC8v" }, + {3,(const unsigned char*)"\x00\x2f\x5e", "AC9e" }, + {3,(const unsigned char*)"\x00\x2f\x8d", "AC+N" }, + {3,(const unsigned char*)"\x00\x2f\xbc", "AC+8" }, + {3,(const unsigned char*)"\x00\x2f\xeb", "AC/r" }, + {3,(const unsigned char*)"\x00\x5e\x00", "AF4A" }, + {3,(const unsigned char*)"\x00\x5e\x2f", "AF4v" }, + {3,(const unsigned char*)"\x00\x5e\x5e", "AF5e" }, + {3,(const unsigned char*)"\x00\x5e\x8d", "AF6N" }, + {3,(const unsigned char*)"\x00\x5e\xbc", "AF68" }, + {3,(const unsigned char*)"\x00\x5e\xeb", "AF7r" }, + {3,(const unsigned char*)"\x00\x8d\x00", "AI0A" }, + {3,(const unsigned char*)"\x00\x8d\x2f", "AI0v" }, + {3,(const unsigned char*)"\x00\x8d\x5e", "AI1e" }, + {3,(const unsigned char*)"\x00\x8d\x8d", "AI2N" }, + {3,(const unsigned char*)"\x00\x8d\xbc", "AI28" }, + {3,(const unsigned char*)"\x00\x8d\xeb", "AI3r" }, + {3,(const unsigned char*)"\x00\xbc\x00", "ALwA" }, + {3,(const unsigned char*)"\x00\xbc\x2f", "ALwv" }, + {3,(const unsigned char*)"\x00\xbc\x5e", "ALxe" }, + {3,(const unsigned char*)"\x00\xbc\x8d", "ALyN" }, + {3,(const unsigned char*)"\x00\xbc\xbc", "ALy8" }, + {3,(const unsigned char*)"\x00\xbc\xeb", "ALzr" }, + {3,(const unsigned char*)"\x00\xeb\x00", "AOsA" }, + {3,(const unsigned char*)"\x00\xeb\x2f", "AOsv" }, + {3,(const unsigned char*)"\x00\xeb\x5e", "AOte" }, + {3,(const unsigned char*)"\x00\xeb\x8d", "AOuN" }, + {3,(const unsigned char*)"\x00\xeb\xbc", "AOu8" }, + {3,(const unsigned char*)"\x00\xeb\xeb", "AOvr" }, + {3,(const unsigned char*)"\x2f\x00\x00", "LwAA" }, + {3,(const unsigned char*)"\x2f\x00\x2f", "LwAv" }, + {3,(const unsigned char*)"\x2f\x00\x5e", "LwBe" }, + {3,(const unsigned char*)"\x2f\x00\x8d", "LwCN" }, + {3,(const unsigned char*)"\x2f\x00\xbc", "LwC8" }, + {3,(const unsigned char*)"\x2f\x00\xeb", "LwDr" }, + {3,(const unsigned char*)"\x2f\x2f\x00", "Ly8A" }, + {3,(const unsigned char*)"\x2f\x2f\x2f", "Ly8v" }, + {3,(const unsigned char*)"\x2f\x2f\x5e", "Ly9e" }, + {3,(const unsigned char*)"\x2f\x2f\x8d", "Ly+N" }, + {3,(const unsigned char*)"\x2f\x2f\xbc", "Ly+8" }, + {3,(const unsigned char*)"\x2f\x2f\xeb", "Ly/r" }, + {3,(const unsigned char*)"\x2f\x5e\x00", "L14A" }, + {3,(const unsigned char*)"\x2f\x5e\x2f", "L14v" }, + {3,(const unsigned char*)"\x2f\x5e\x5e", "L15e" }, + {3,(const unsigned char*)"\x2f\x5e\x8d", "L16N" }, + {3,(const unsigned char*)"\x2f\x5e\xbc", "L168" }, + {3,(const unsigned char*)"\x2f\x5e\xeb", "L17r" }, + {3,(const unsigned char*)"\x2f\x8d\x00", "L40A" }, + {3,(const unsigned char*)"\x2f\x8d\x2f", "L40v" }, + {3,(const unsigned char*)"\x2f\x8d\x5e", "L41e" }, + {3,(const unsigned char*)"\x2f\x8d\x8d", "L42N" }, + {3,(const unsigned char*)"\x2f\x8d\xbc", "L428" }, + {3,(const unsigned char*)"\x2f\x8d\xeb", "L43r" }, + {3,(const unsigned char*)"\x2f\xbc\x00", "L7wA" }, + {3,(const unsigned char*)"\x2f\xbc\x2f", "L7wv" }, + {3,(const unsigned char*)"\x2f\xbc\x5e", "L7xe" }, + {3,(const unsigned char*)"\x2f\xbc\x8d", "L7yN" }, + {3,(const unsigned char*)"\x2f\xbc\xbc", "L7y8" }, + {3,(const unsigned char*)"\x2f\xbc\xeb", "L7zr" }, + {3,(const unsigned char*)"\x2f\xeb\x00", "L+sA" }, + {3,(const unsigned char*)"\x2f\xeb\x2f", "L+sv" }, + {3,(const unsigned char*)"\x2f\xeb\x5e", "L+te" }, + {3,(const unsigned char*)"\x2f\xeb\x8d", "L+uN" }, + {3,(const unsigned char*)"\x2f\xeb\xbc", "L+u8" }, + {3,(const unsigned char*)"\x2f\xeb\xeb", "L+vr" }, + {3,(const unsigned char*)"\x5e\x00\x00", "XgAA" }, + {3,(const unsigned char*)"\x5e\x00\x2f", "XgAv" }, + {3,(const unsigned char*)"\x5e\x00\x5e", "XgBe" }, + {3,(const unsigned char*)"\x5e\x00\x8d", "XgCN" }, + {3,(const unsigned char*)"\x5e\x00\xbc", "XgC8" }, + {3,(const unsigned char*)"\x5e\x00\xeb", "XgDr" }, + {3,(const unsigned char*)"\x5e\x2f\x00", "Xi8A" }, + {3,(const unsigned char*)"\x5e\x2f\x2f", "Xi8v" }, + {3,(const unsigned char*)"\x5e\x2f\x5e", "Xi9e" }, + {3,(const unsigned char*)"\x5e\x2f\x8d", "Xi+N" }, + {3,(const unsigned char*)"\x5e\x2f\xbc", "Xi+8" }, + {3,(const unsigned char*)"\x5e\x2f\xeb", "Xi/r" }, + {3,(const unsigned char*)"\x5e\x5e\x00", "Xl4A" }, + {3,(const unsigned char*)"\x5e\x5e\x2f", "Xl4v" }, + {3,(const unsigned char*)"\x5e\x5e\x5e", "Xl5e" }, + {3,(const unsigned char*)"\x5e\x5e\x8d", "Xl6N" }, + {3,(const unsigned char*)"\x5e\x5e\xbc", "Xl68" }, + {3,(const unsigned char*)"\x5e\x5e\xeb", "Xl7r" }, + {3,(const unsigned char*)"\x5e\x8d\x00", "Xo0A" }, + {3,(const unsigned char*)"\x5e\x8d\x2f", "Xo0v" }, + {3,(const unsigned char*)"\x5e\x8d\x5e", "Xo1e" }, + {3,(const unsigned char*)"\x5e\x8d\x8d", "Xo2N" }, + {3,(const unsigned char*)"\x5e\x8d\xbc", "Xo28" }, + {3,(const unsigned char*)"\x5e\x8d\xeb", "Xo3r" }, + {3,(const unsigned char*)"\x5e\xbc\x00", "XrwA" }, + {3,(const unsigned char*)"\x5e\xbc\x2f", "Xrwv" }, + {3,(const unsigned char*)"\x5e\xbc\x5e", "Xrxe" }, + {3,(const unsigned char*)"\x5e\xbc\x8d", "XryN" }, + {3,(const unsigned char*)"\x5e\xbc\xbc", "Xry8" }, + {3,(const unsigned char*)"\x5e\xbc\xeb", "Xrzr" }, + {3,(const unsigned char*)"\x5e\xeb\x00", "XusA" }, + {3,(const unsigned char*)"\x5e\xeb\x2f", "Xusv" }, + {3,(const unsigned char*)"\x5e\xeb\x5e", "Xute" }, + {3,(const unsigned char*)"\x5e\xeb\x8d", "XuuN" }, + {3,(const unsigned char*)"\x5e\xeb\xbc", "Xuu8" }, + {3,(const unsigned char*)"\x5e\xeb\xeb", "Xuvr" }, + {3,(const unsigned char*)"\x8d\x00\x00", "jQAA" }, + {3,(const unsigned char*)"\x8d\x00\x2f", "jQAv" }, + {3,(const unsigned char*)"\x8d\x00\x5e", "jQBe" }, + {3,(const unsigned char*)"\x8d\x00\x8d", "jQCN" }, + {3,(const unsigned char*)"\x8d\x00\xbc", "jQC8" }, + {3,(const unsigned char*)"\x8d\x00\xeb", "jQDr" }, + {3,(const unsigned char*)"\x8d\x2f\x00", "jS8A" }, + {3,(const unsigned char*)"\x8d\x2f\x2f", "jS8v" }, + {3,(const unsigned char*)"\x8d\x2f\x5e", "jS9e" }, + {3,(const unsigned char*)"\x8d\x2f\x8d", "jS+N" }, + {3,(const unsigned char*)"\x8d\x2f\xbc", "jS+8" }, + {3,(const unsigned char*)"\x8d\x2f\xeb", "jS/r" }, + {3,(const unsigned char*)"\x8d\x5e\x00", "jV4A" }, + {3,(const unsigned char*)"\x8d\x5e\x2f", "jV4v" }, + {3,(const unsigned char*)"\x8d\x5e\x5e", "jV5e" }, + {3,(const unsigned char*)"\x8d\x5e\x8d", "jV6N" }, + {3,(const unsigned char*)"\x8d\x5e\xbc", "jV68" }, + {3,(const unsigned char*)"\x8d\x5e\xeb", "jV7r" }, + {3,(const unsigned char*)"\x8d\x8d\x00", "jY0A" }, + {3,(const unsigned char*)"\x8d\x8d\x2f", "jY0v" }, + {3,(const unsigned char*)"\x8d\x8d\x5e", "jY1e" }, + {3,(const unsigned char*)"\x8d\x8d\x8d", "jY2N" }, + {3,(const unsigned char*)"\x8d\x8d\xbc", "jY28" }, + {3,(const unsigned char*)"\x8d\x8d\xeb", "jY3r" }, + {3,(const unsigned char*)"\x8d\xbc\x00", "jbwA" }, + {3,(const unsigned char*)"\x8d\xbc\x2f", "jbwv" }, + {3,(const unsigned char*)"\x8d\xbc\x5e", "jbxe" }, + {3,(const unsigned char*)"\x8d\xbc\x8d", "jbyN" }, + {3,(const unsigned char*)"\x8d\xbc\xbc", "jby8" }, + {3,(const unsigned char*)"\x8d\xbc\xeb", "jbzr" }, + {3,(const unsigned char*)"\x8d\xeb\x00", "jesA" }, + {3,(const unsigned char*)"\x8d\xeb\x2f", "jesv" }, + {3,(const unsigned char*)"\x8d\xeb\x5e", "jete" }, + {3,(const unsigned char*)"\x8d\xeb\x8d", "jeuN" }, + {3,(const unsigned char*)"\x8d\xeb\xbc", "jeu8" }, + {3,(const unsigned char*)"\x8d\xeb\xeb", "jevr" }, + {3,(const unsigned char*)"\xbc\x00\x00", "vAAA" }, + {3,(const unsigned char*)"\xbc\x00\x2f", "vAAv" }, + {3,(const unsigned char*)"\xbc\x00\x5e", "vABe" }, + {3,(const unsigned char*)"\xbc\x00\x8d", "vACN" }, + {3,(const unsigned char*)"\xbc\x00\xbc", "vAC8" }, + {3,(const unsigned char*)"\xbc\x00\xeb", "vADr" }, + {3,(const unsigned char*)"\xbc\x2f\x00", "vC8A" }, + {3,(const unsigned char*)"\xbc\x2f\x2f", "vC8v" }, + {3,(const unsigned char*)"\xbc\x2f\x5e", "vC9e" }, + {3,(const unsigned char*)"\xbc\x2f\x8d", "vC+N" }, + {3,(const unsigned char*)"\xbc\x2f\xbc", "vC+8" }, + {3,(const unsigned char*)"\xbc\x2f\xeb", "vC/r" }, + {3,(const unsigned char*)"\xbc\x5e\x00", "vF4A" }, + {3,(const unsigned char*)"\xbc\x5e\x2f", "vF4v" }, + {3,(const unsigned char*)"\xbc\x5e\x5e", "vF5e" }, + {3,(const unsigned char*)"\xbc\x5e\x8d", "vF6N" }, + {3,(const unsigned char*)"\xbc\x5e\xbc", "vF68" }, + {3,(const unsigned char*)"\xbc\x5e\xeb", "vF7r" }, + {3,(const unsigned char*)"\xbc\x8d\x00", "vI0A" }, + {3,(const unsigned char*)"\xbc\x8d\x2f", "vI0v" }, + {3,(const unsigned char*)"\xbc\x8d\x5e", "vI1e" }, + {3,(const unsigned char*)"\xbc\x8d\x8d", "vI2N" }, + {3,(const unsigned char*)"\xbc\x8d\xbc", "vI28" }, + {3,(const unsigned char*)"\xbc\x8d\xeb", "vI3r" }, + {3,(const unsigned char*)"\xbc\xbc\x00", "vLwA" }, + {3,(const unsigned char*)"\xbc\xbc\x2f", "vLwv" }, + {3,(const unsigned char*)"\xbc\xbc\x5e", "vLxe" }, + {3,(const unsigned char*)"\xbc\xbc\x8d", "vLyN" }, + {3,(const unsigned char*)"\xbc\xbc\xbc", "vLy8" }, + {3,(const unsigned char*)"\xbc\xbc\xeb", "vLzr" }, + {3,(const unsigned char*)"\xbc\xeb\x00", "vOsA" }, + {3,(const unsigned char*)"\xbc\xeb\x2f", "vOsv" }, + {3,(const unsigned char*)"\xbc\xeb\x5e", "vOte" }, + {3,(const unsigned char*)"\xbc\xeb\x8d", "vOuN" }, + {3,(const unsigned char*)"\xbc\xeb\xbc", "vOu8" }, + {3,(const unsigned char*)"\xbc\xeb\xeb", "vOvr" }, + {3,(const unsigned char*)"\xeb\x00\x00", "6wAA" }, + {3,(const unsigned char*)"\xeb\x00\x2f", "6wAv" }, + {3,(const unsigned char*)"\xeb\x00\x5e", "6wBe" }, + {3,(const unsigned char*)"\xeb\x00\x8d", "6wCN" }, + {3,(const unsigned char*)"\xeb\x00\xbc", "6wC8" }, + {3,(const unsigned char*)"\xeb\x00\xeb", "6wDr" }, + {3,(const unsigned char*)"\xeb\x2f\x00", "6y8A" }, + {3,(const unsigned char*)"\xeb\x2f\x2f", "6y8v" }, + {3,(const unsigned char*)"\xeb\x2f\x5e", "6y9e" }, + {3,(const unsigned char*)"\xeb\x2f\x8d", "6y+N" }, + {3,(const unsigned char*)"\xeb\x2f\xbc", "6y+8" }, + {3,(const unsigned char*)"\xeb\x2f\xeb", "6y/r" }, + {3,(const unsigned char*)"\xeb\x5e\x00", "614A" }, + {3,(const unsigned char*)"\xeb\x5e\x2f", "614v" }, + {3,(const unsigned char*)"\xeb\x5e\x5e", "615e" }, + {3,(const unsigned char*)"\xeb\x5e\x8d", "616N" }, + {3,(const unsigned char*)"\xeb\x5e\xbc", "6168" }, + {3,(const unsigned char*)"\xeb\x5e\xeb", "617r" }, + {3,(const unsigned char*)"\xeb\x8d\x00", "640A" }, + {3,(const unsigned char*)"\xeb\x8d\x2f", "640v" }, + {3,(const unsigned char*)"\xeb\x8d\x5e", "641e" }, + {3,(const unsigned char*)"\xeb\x8d\x8d", "642N" }, + {3,(const unsigned char*)"\xeb\x8d\xbc", "6428" }, + {3,(const unsigned char*)"\xeb\x8d\xeb", "643r" }, + {3,(const unsigned char*)"\xeb\xbc\x00", "67wA" }, + {3,(const unsigned char*)"\xeb\xbc\x2f", "67wv" }, + {3,(const unsigned char*)"\xeb\xbc\x5e", "67xe" }, + {3,(const unsigned char*)"\xeb\xbc\x8d", "67yN" }, + {3,(const unsigned char*)"\xeb\xbc\xbc", "67y8" }, + {3,(const unsigned char*)"\xeb\xbc\xeb", "67zr" }, + {3,(const unsigned char*)"\xeb\xeb\x00", "6+sA" }, + {3,(const unsigned char*)"\xeb\xeb\x2f", "6+sv" }, + {3,(const unsigned char*)"\xeb\xeb\x5e", "6+te" }, + {3,(const unsigned char*)"\xeb\xeb\x8d", "6+uN" }, + {3,(const unsigned char*)"\xeb\xeb\xbc", "6+u8" }, + {3,(const unsigned char*)"\xeb\xeb\xeb", "6+vr" }, + {4,(const unsigned char*)"\x00\x00\x00\x00", "AAAAAA==" }, + {4,(const unsigned char*)"\x00\x00\x00\x55", "AAAAVQ==" }, + {4,(const unsigned char*)"\x00\x00\x00\xaa", "AAAAqg==" }, + {4,(const unsigned char*)"\x00\x00\x00\xff", "AAAA/w==" }, + {4,(const unsigned char*)"\x00\x00\x55\x00", "AABVAA==" }, + {4,(const unsigned char*)"\x00\x00\x55\x55", "AABVVQ==" }, + {4,(const unsigned char*)"\x00\x00\x55\xaa", "AABVqg==" }, + {4,(const unsigned char*)"\x00\x00\x55\xff", "AABV/w==" }, + {4,(const unsigned char*)"\x00\x00\xaa\x00", "AACqAA==" }, + {4,(const unsigned char*)"\x00\x00\xaa\x55", "AACqVQ==" }, + {4,(const unsigned char*)"\x00\x00\xaa\xaa", "AACqqg==" }, + {4,(const unsigned char*)"\x00\x00\xaa\xff", "AACq/w==" }, + {4,(const unsigned char*)"\x00\x00\xff\x00", "AAD/AA==" }, + {4,(const unsigned char*)"\x00\x00\xff\x55", "AAD/VQ==" }, + {4,(const unsigned char*)"\x00\x00\xff\xaa", "AAD/qg==" }, + {4,(const unsigned char*)"\x00\x00\xff\xff", "AAD//w==" }, + {4,(const unsigned char*)"\x00\x55\x00\x00", "AFUAAA==" }, + {4,(const unsigned char*)"\x00\x55\x00\x55", "AFUAVQ==" }, + {4,(const unsigned char*)"\x00\x55\x00\xaa", "AFUAqg==" }, + {4,(const unsigned char*)"\x00\x55\x00\xff", "AFUA/w==" }, + {4,(const unsigned char*)"\x00\x55\x55\x00", "AFVVAA==" }, + {4,(const unsigned char*)"\x00\x55\x55\x55", "AFVVVQ==" }, + {4,(const unsigned char*)"\x00\x55\x55\xaa", "AFVVqg==" }, + {4,(const unsigned char*)"\x00\x55\x55\xff", "AFVV/w==" }, + {4,(const unsigned char*)"\x00\x55\xaa\x00", "AFWqAA==" }, + {4,(const unsigned char*)"\x00\x55\xaa\x55", "AFWqVQ==" }, + {4,(const unsigned char*)"\x00\x55\xaa\xaa", "AFWqqg==" }, + {4,(const unsigned char*)"\x00\x55\xaa\xff", "AFWq/w==" }, + {4,(const unsigned char*)"\x00\x55\xff\x00", "AFX/AA==" }, + {4,(const unsigned char*)"\x00\x55\xff\x55", "AFX/VQ==" }, + {4,(const unsigned char*)"\x00\x55\xff\xaa", "AFX/qg==" }, + {4,(const unsigned char*)"\x00\x55\xff\xff", "AFX//w==" }, + {4,(const unsigned char*)"\x00\xaa\x00\x00", "AKoAAA==" }, + {4,(const unsigned char*)"\x00\xaa\x00\x55", "AKoAVQ==" }, + {4,(const unsigned char*)"\x00\xaa\x00\xaa", "AKoAqg==" }, + {4,(const unsigned char*)"\x00\xaa\x00\xff", "AKoA/w==" }, + {4,(const unsigned char*)"\x00\xaa\x55\x00", "AKpVAA==" }, + {4,(const unsigned char*)"\x00\xaa\x55\x55", "AKpVVQ==" }, + {4,(const unsigned char*)"\x00\xaa\x55\xaa", "AKpVqg==" }, + {4,(const unsigned char*)"\x00\xaa\x55\xff", "AKpV/w==" }, + {4,(const unsigned char*)"\x00\xaa\xaa\x00", "AKqqAA==" }, + {4,(const unsigned char*)"\x00\xaa\xaa\x55", "AKqqVQ==" }, + {4,(const unsigned char*)"\x00\xaa\xaa\xaa", "AKqqqg==" }, + {4,(const unsigned char*)"\x00\xaa\xaa\xff", "AKqq/w==" }, + {4,(const unsigned char*)"\x00\xaa\xff\x00", "AKr/AA==" }, + {4,(const unsigned char*)"\x00\xaa\xff\x55", "AKr/VQ==" }, + {4,(const unsigned char*)"\x00\xaa\xff\xaa", "AKr/qg==" }, + {4,(const unsigned char*)"\x00\xaa\xff\xff", "AKr//w==" }, + {4,(const unsigned char*)"\x00\xff\x00\x00", "AP8AAA==" }, + {4,(const unsigned char*)"\x00\xff\x00\x55", "AP8AVQ==" }, + {4,(const unsigned char*)"\x00\xff\x00\xaa", "AP8Aqg==" }, + {4,(const unsigned char*)"\x00\xff\x00\xff", "AP8A/w==" }, + {4,(const unsigned char*)"\x00\xff\x55\x00", "AP9VAA==" }, + {4,(const unsigned char*)"\x00\xff\x55\x55", "AP9VVQ==" }, + {4,(const unsigned char*)"\x00\xff\x55\xaa", "AP9Vqg==" }, + {4,(const unsigned char*)"\x00\xff\x55\xff", "AP9V/w==" }, + {4,(const unsigned char*)"\x00\xff\xaa\x00", "AP+qAA==" }, + {4,(const unsigned char*)"\x00\xff\xaa\x55", "AP+qVQ==" }, + {4,(const unsigned char*)"\x00\xff\xaa\xaa", "AP+qqg==" }, + {4,(const unsigned char*)"\x00\xff\xaa\xff", "AP+q/w==" }, + {4,(const unsigned char*)"\x00\xff\xff\x00", "AP//AA==" }, + {4,(const unsigned char*)"\x00\xff\xff\x55", "AP//VQ==" }, + {4,(const unsigned char*)"\x00\xff\xff\xaa", "AP//qg==" }, + {4,(const unsigned char*)"\x00\xff\xff\xff", "AP///w==" }, + {4,(const unsigned char*)"\x55\x00\x00\x00", "VQAAAA==" }, + {4,(const unsigned char*)"\x55\x00\x00\x55", "VQAAVQ==" }, + {4,(const unsigned char*)"\x55\x00\x00\xaa", "VQAAqg==" }, + {4,(const unsigned char*)"\x55\x00\x00\xff", "VQAA/w==" }, + {4,(const unsigned char*)"\x55\x00\x55\x00", "VQBVAA==" }, + {4,(const unsigned char*)"\x55\x00\x55\x55", "VQBVVQ==" }, + {4,(const unsigned char*)"\x55\x00\x55\xaa", "VQBVqg==" }, + {4,(const unsigned char*)"\x55\x00\x55\xff", "VQBV/w==" }, + {4,(const unsigned char*)"\x55\x00\xaa\x00", "VQCqAA==" }, + {4,(const unsigned char*)"\x55\x00\xaa\x55", "VQCqVQ==" }, + {4,(const unsigned char*)"\x55\x00\xaa\xaa", "VQCqqg==" }, + {4,(const unsigned char*)"\x55\x00\xaa\xff", "VQCq/w==" }, + {4,(const unsigned char*)"\x55\x00\xff\x00", "VQD/AA==" }, + {4,(const unsigned char*)"\x55\x00\xff\x55", "VQD/VQ==" }, + {4,(const unsigned char*)"\x55\x00\xff\xaa", "VQD/qg==" }, + {4,(const unsigned char*)"\x55\x00\xff\xff", "VQD//w==" }, + {4,(const unsigned char*)"\x55\x55\x00\x00", "VVUAAA==" }, + {4,(const unsigned char*)"\x55\x55\x00\x55", "VVUAVQ==" }, + {4,(const unsigned char*)"\x55\x55\x00\xaa", "VVUAqg==" }, + {4,(const unsigned char*)"\x55\x55\x00\xff", "VVUA/w==" }, + {4,(const unsigned char*)"\x55\x55\x55\x00", "VVVVAA==" }, + {4,(const unsigned char*)"\x55\x55\x55\x55", "VVVVVQ==" }, + {4,(const unsigned char*)"\x55\x55\x55\xaa", "VVVVqg==" }, + {4,(const unsigned char*)"\x55\x55\x55\xff", "VVVV/w==" }, + {4,(const unsigned char*)"\x55\x55\xaa\x00", "VVWqAA==" }, + {4,(const unsigned char*)"\x55\x55\xaa\x55", "VVWqVQ==" }, + {4,(const unsigned char*)"\x55\x55\xaa\xaa", "VVWqqg==" }, + {4,(const unsigned char*)"\x55\x55\xaa\xff", "VVWq/w==" }, + {4,(const unsigned char*)"\x55\x55\xff\x00", "VVX/AA==" }, + {4,(const unsigned char*)"\x55\x55\xff\x55", "VVX/VQ==" }, + {4,(const unsigned char*)"\x55\x55\xff\xaa", "VVX/qg==" }, + {4,(const unsigned char*)"\x55\x55\xff\xff", "VVX//w==" }, + {4,(const unsigned char*)"\x55\xaa\x00\x00", "VaoAAA==" }, + {4,(const unsigned char*)"\x55\xaa\x00\x55", "VaoAVQ==" }, + {4,(const unsigned char*)"\x55\xaa\x00\xaa", "VaoAqg==" }, + {4,(const unsigned char*)"\x55\xaa\x00\xff", "VaoA/w==" }, + {4,(const unsigned char*)"\x55\xaa\x55\x00", "VapVAA==" }, + {4,(const unsigned char*)"\x55\xaa\x55\x55", "VapVVQ==" }, + {4,(const unsigned char*)"\x55\xaa\x55\xaa", "VapVqg==" }, + {4,(const unsigned char*)"\x55\xaa\x55\xff", "VapV/w==" }, + {4,(const unsigned char*)"\x55\xaa\xaa\x00", "VaqqAA==" }, + {4,(const unsigned char*)"\x55\xaa\xaa\x55", "VaqqVQ==" }, + {4,(const unsigned char*)"\x55\xaa\xaa\xaa", "Vaqqqg==" }, + {4,(const unsigned char*)"\x55\xaa\xaa\xff", "Vaqq/w==" }, + {4,(const unsigned char*)"\x55\xaa\xff\x00", "Var/AA==" }, + {4,(const unsigned char*)"\x55\xaa\xff\x55", "Var/VQ==" }, + {4,(const unsigned char*)"\x55\xaa\xff\xaa", "Var/qg==" }, + {4,(const unsigned char*)"\x55\xaa\xff\xff", "Var//w==" }, + {4,(const unsigned char*)"\x55\xff\x00\x00", "Vf8AAA==" }, + {4,(const unsigned char*)"\x55\xff\x00\x55", "Vf8AVQ==" }, + {4,(const unsigned char*)"\x55\xff\x00\xaa", "Vf8Aqg==" }, + {4,(const unsigned char*)"\x55\xff\x00\xff", "Vf8A/w==" }, + {4,(const unsigned char*)"\x55\xff\x55\x00", "Vf9VAA==" }, + {4,(const unsigned char*)"\x55\xff\x55\x55", "Vf9VVQ==" }, + {4,(const unsigned char*)"\x55\xff\x55\xaa", "Vf9Vqg==" }, + {4,(const unsigned char*)"\x55\xff\x55\xff", "Vf9V/w==" }, + {4,(const unsigned char*)"\x55\xff\xaa\x00", "Vf+qAA==" }, + {4,(const unsigned char*)"\x55\xff\xaa\x55", "Vf+qVQ==" }, + {4,(const unsigned char*)"\x55\xff\xaa\xaa", "Vf+qqg==" }, + {4,(const unsigned char*)"\x55\xff\xaa\xff", "Vf+q/w==" }, + {4,(const unsigned char*)"\x55\xff\xff\x00", "Vf//AA==" }, + {4,(const unsigned char*)"\x55\xff\xff\x55", "Vf//VQ==" }, + {4,(const unsigned char*)"\x55\xff\xff\xaa", "Vf//qg==" }, + {4,(const unsigned char*)"\x55\xff\xff\xff", "Vf///w==" }, + {4,(const unsigned char*)"\xaa\x00\x00\x00", "qgAAAA==" }, + {4,(const unsigned char*)"\xaa\x00\x00\x55", "qgAAVQ==" }, + {4,(const unsigned char*)"\xaa\x00\x00\xaa", "qgAAqg==" }, + {4,(const unsigned char*)"\xaa\x00\x00\xff", "qgAA/w==" }, + {4,(const unsigned char*)"\xaa\x00\x55\x00", "qgBVAA==" }, + {4,(const unsigned char*)"\xaa\x00\x55\x55", "qgBVVQ==" }, + {4,(const unsigned char*)"\xaa\x00\x55\xaa", "qgBVqg==" }, + {4,(const unsigned char*)"\xaa\x00\x55\xff", "qgBV/w==" }, + {4,(const unsigned char*)"\xaa\x00\xaa\x00", "qgCqAA==" }, + {4,(const unsigned char*)"\xaa\x00\xaa\x55", "qgCqVQ==" }, + {4,(const unsigned char*)"\xaa\x00\xaa\xaa", "qgCqqg==" }, + {4,(const unsigned char*)"\xaa\x00\xaa\xff", "qgCq/w==" }, + {4,(const unsigned char*)"\xaa\x00\xff\x00", "qgD/AA==" }, + {4,(const unsigned char*)"\xaa\x00\xff\x55", "qgD/VQ==" }, + {4,(const unsigned char*)"\xaa\x00\xff\xaa", "qgD/qg==" }, + {4,(const unsigned char*)"\xaa\x00\xff\xff", "qgD//w==" }, + {4,(const unsigned char*)"\xaa\x55\x00\x00", "qlUAAA==" }, + {4,(const unsigned char*)"\xaa\x55\x00\x55", "qlUAVQ==" }, + {4,(const unsigned char*)"\xaa\x55\x00\xaa", "qlUAqg==" }, + {4,(const unsigned char*)"\xaa\x55\x00\xff", "qlUA/w==" }, + {4,(const unsigned char*)"\xaa\x55\x55\x00", "qlVVAA==" }, + {4,(const unsigned char*)"\xaa\x55\x55\x55", "qlVVVQ==" }, + {4,(const unsigned char*)"\xaa\x55\x55\xaa", "qlVVqg==" }, + {4,(const unsigned char*)"\xaa\x55\x55\xff", "qlVV/w==" }, + {4,(const unsigned char*)"\xaa\x55\xaa\x00", "qlWqAA==" }, + {4,(const unsigned char*)"\xaa\x55\xaa\x55", "qlWqVQ==" }, + {4,(const unsigned char*)"\xaa\x55\xaa\xaa", "qlWqqg==" }, + {4,(const unsigned char*)"\xaa\x55\xaa\xff", "qlWq/w==" }, + {4,(const unsigned char*)"\xaa\x55\xff\x00", "qlX/AA==" }, + {4,(const unsigned char*)"\xaa\x55\xff\x55", "qlX/VQ==" }, + {4,(const unsigned char*)"\xaa\x55\xff\xaa", "qlX/qg==" }, + {4,(const unsigned char*)"\xaa\x55\xff\xff", "qlX//w==" }, + {4,(const unsigned char*)"\xaa\xaa\x00\x00", "qqoAAA==" }, + {4,(const unsigned char*)"\xaa\xaa\x00\x55", "qqoAVQ==" }, + {4,(const unsigned char*)"\xaa\xaa\x00\xaa", "qqoAqg==" }, + {4,(const unsigned char*)"\xaa\xaa\x00\xff", "qqoA/w==" }, + {4,(const unsigned char*)"\xaa\xaa\x55\x00", "qqpVAA==" }, + {4,(const unsigned char*)"\xaa\xaa\x55\x55", "qqpVVQ==" }, + {4,(const unsigned char*)"\xaa\xaa\x55\xaa", "qqpVqg==" }, + {4,(const unsigned char*)"\xaa\xaa\x55\xff", "qqpV/w==" }, + {4,(const unsigned char*)"\xaa\xaa\xaa\x00", "qqqqAA==" }, + {4,(const unsigned char*)"\xaa\xaa\xaa\x55", "qqqqVQ==" }, + {4,(const unsigned char*)"\xaa\xaa\xaa\xaa", "qqqqqg==" }, + {4,(const unsigned char*)"\xaa\xaa\xaa\xff", "qqqq/w==" }, + {4,(const unsigned char*)"\xaa\xaa\xff\x00", "qqr/AA==" }, + {4,(const unsigned char*)"\xaa\xaa\xff\x55", "qqr/VQ==" }, + {4,(const unsigned char*)"\xaa\xaa\xff\xaa", "qqr/qg==" }, + {4,(const unsigned char*)"\xaa\xaa\xff\xff", "qqr//w==" }, + {4,(const unsigned char*)"\xaa\xff\x00\x00", "qv8AAA==" }, + {4,(const unsigned char*)"\xaa\xff\x00\x55", "qv8AVQ==" }, + {4,(const unsigned char*)"\xaa\xff\x00\xaa", "qv8Aqg==" }, + {4,(const unsigned char*)"\xaa\xff\x00\xff", "qv8A/w==" }, + {4,(const unsigned char*)"\xaa\xff\x55\x00", "qv9VAA==" }, + {4,(const unsigned char*)"\xaa\xff\x55\x55", "qv9VVQ==" }, + {4,(const unsigned char*)"\xaa\xff\x55\xaa", "qv9Vqg==" }, + {4,(const unsigned char*)"\xaa\xff\x55\xff", "qv9V/w==" }, + {4,(const unsigned char*)"\xaa\xff\xaa\x00", "qv+qAA==" }, + {4,(const unsigned char*)"\xaa\xff\xaa\x55", "qv+qVQ==" }, + {4,(const unsigned char*)"\xaa\xff\xaa\xaa", "qv+qqg==" }, + {4,(const unsigned char*)"\xaa\xff\xaa\xff", "qv+q/w==" }, + {4,(const unsigned char*)"\xaa\xff\xff\x00", "qv//AA==" }, + {4,(const unsigned char*)"\xaa\xff\xff\x55", "qv//VQ==" }, + {4,(const unsigned char*)"\xaa\xff\xff\xaa", "qv//qg==" }, + {4,(const unsigned char*)"\xaa\xff\xff\xff", "qv///w==" }, + {4,(const unsigned char*)"\xff\x00\x00\x00", "/wAAAA==" }, + {4,(const unsigned char*)"\xff\x00\x00\x55", "/wAAVQ==" }, + {4,(const unsigned char*)"\xff\x00\x00\xaa", "/wAAqg==" }, + {4,(const unsigned char*)"\xff\x00\x00\xff", "/wAA/w==" }, + {4,(const unsigned char*)"\xff\x00\x55\x00", "/wBVAA==" }, + {4,(const unsigned char*)"\xff\x00\x55\x55", "/wBVVQ==" }, + {4,(const unsigned char*)"\xff\x00\x55\xaa", "/wBVqg==" }, + {4,(const unsigned char*)"\xff\x00\x55\xff", "/wBV/w==" }, + {4,(const unsigned char*)"\xff\x00\xaa\x00", "/wCqAA==" }, + {4,(const unsigned char*)"\xff\x00\xaa\x55", "/wCqVQ==" }, + {4,(const unsigned char*)"\xff\x00\xaa\xaa", "/wCqqg==" }, + {4,(const unsigned char*)"\xff\x00\xaa\xff", "/wCq/w==" }, + {4,(const unsigned char*)"\xff\x00\xff\x00", "/wD/AA==" }, + {4,(const unsigned char*)"\xff\x00\xff\x55", "/wD/VQ==" }, + {4,(const unsigned char*)"\xff\x00\xff\xaa", "/wD/qg==" }, + {4,(const unsigned char*)"\xff\x00\xff\xff", "/wD//w==" }, + {4,(const unsigned char*)"\xff\x55\x00\x00", "/1UAAA==" }, + {4,(const unsigned char*)"\xff\x55\x00\x55", "/1UAVQ==" }, + {4,(const unsigned char*)"\xff\x55\x00\xaa", "/1UAqg==" }, + {4,(const unsigned char*)"\xff\x55\x00\xff", "/1UA/w==" }, + {4,(const unsigned char*)"\xff\x55\x55\x00", "/1VVAA==" }, + {4,(const unsigned char*)"\xff\x55\x55\x55", "/1VVVQ==" }, + {4,(const unsigned char*)"\xff\x55\x55\xaa", "/1VVqg==" }, + {4,(const unsigned char*)"\xff\x55\x55\xff", "/1VV/w==" }, + {4,(const unsigned char*)"\xff\x55\xaa\x00", "/1WqAA==" }, + {4,(const unsigned char*)"\xff\x55\xaa\x55", "/1WqVQ==" }, + {4,(const unsigned char*)"\xff\x55\xaa\xaa", "/1Wqqg==" }, + {4,(const unsigned char*)"\xff\x55\xaa\xff", "/1Wq/w==" }, + {4,(const unsigned char*)"\xff\x55\xff\x00", "/1X/AA==" }, + {4,(const unsigned char*)"\xff\x55\xff\x55", "/1X/VQ==" }, + {4,(const unsigned char*)"\xff\x55\xff\xaa", "/1X/qg==" }, + {4,(const unsigned char*)"\xff\x55\xff\xff", "/1X//w==" }, + {4,(const unsigned char*)"\xff\xaa\x00\x00", "/6oAAA==" }, + {4,(const unsigned char*)"\xff\xaa\x00\x55", "/6oAVQ==" }, + {4,(const unsigned char*)"\xff\xaa\x00\xaa", "/6oAqg==" }, + {4,(const unsigned char*)"\xff\xaa\x00\xff", "/6oA/w==" }, + {4,(const unsigned char*)"\xff\xaa\x55\x00", "/6pVAA==" }, + {4,(const unsigned char*)"\xff\xaa\x55\x55", "/6pVVQ==" }, + {4,(const unsigned char*)"\xff\xaa\x55\xaa", "/6pVqg==" }, + {4,(const unsigned char*)"\xff\xaa\x55\xff", "/6pV/w==" }, + {4,(const unsigned char*)"\xff\xaa\xaa\x00", "/6qqAA==" }, + {4,(const unsigned char*)"\xff\xaa\xaa\x55", "/6qqVQ==" }, + {4,(const unsigned char*)"\xff\xaa\xaa\xaa", "/6qqqg==" }, + {4,(const unsigned char*)"\xff\xaa\xaa\xff", "/6qq/w==" }, + {4,(const unsigned char*)"\xff\xaa\xff\x00", "/6r/AA==" }, + {4,(const unsigned char*)"\xff\xaa\xff\x55", "/6r/VQ==" }, + {4,(const unsigned char*)"\xff\xaa\xff\xaa", "/6r/qg==" }, + {4,(const unsigned char*)"\xff\xaa\xff\xff", "/6r//w==" }, + {4,(const unsigned char*)"\xff\xff\x00\x00", "//8AAA==" }, + {4,(const unsigned char*)"\xff\xff\x00\x55", "//8AVQ==" }, + {4,(const unsigned char*)"\xff\xff\x00\xaa", "//8Aqg==" }, + {4,(const unsigned char*)"\xff\xff\x00\xff", "//8A/w==" }, + {4,(const unsigned char*)"\xff\xff\x55\x00", "//9VAA==" }, + {4,(const unsigned char*)"\xff\xff\x55\x55", "//9VVQ==" }, + {4,(const unsigned char*)"\xff\xff\x55\xaa", "//9Vqg==" }, + {4,(const unsigned char*)"\xff\xff\x55\xff", "//9V/w==" }, + {4,(const unsigned char*)"\xff\xff\xaa\x00", "//+qAA==" }, + {4,(const unsigned char*)"\xff\xff\xaa\x55", "//+qVQ==" }, + {4,(const unsigned char*)"\xff\xff\xaa\xaa", "//+qqg==" }, + {4,(const unsigned char*)"\xff\xff\xaa\xff", "//+q/w==" }, + {4,(const unsigned char*)"\xff\xff\xff\x00", "////AA==" }, + {4,(const unsigned char*)"\xff\xff\xff\x55", "////VQ==" }, + {4,(const unsigned char*)"\xff\xff\xff\xaa", "////qg==" }, + {4,(const unsigned char*)"\xff\xff\xff\xff", "/////w==" }, + {5,(const unsigned char*)"\x00\x00\x00\x00\x00", "AAAAAAA=" }, + {5,(const unsigned char*)"\x00\x00\x00\x00\x7e", "AAAAAH4=" }, + {5,(const unsigned char*)"\x00\x00\x00\x00\xfc", "AAAAAPw=" }, + {5,(const unsigned char*)"\x00\x00\x00\x7e\x00", "AAAAfgA=" }, + {5,(const unsigned char*)"\x00\x00\x00\x7e\x7e", "AAAAfn4=" }, + {5,(const unsigned char*)"\x00\x00\x00\x7e\xfc", "AAAAfvw=" }, + {5,(const unsigned char*)"\x00\x00\x00\xfc\x00", "AAAA/AA=" }, + {5,(const unsigned char*)"\x00\x00\x00\xfc\x7e", "AAAA/H4=" }, + {5,(const unsigned char*)"\x00\x00\x00\xfc\xfc", "AAAA/Pw=" }, + {5,(const unsigned char*)"\x00\x00\x7e\x00\x00", "AAB+AAA=" }, + {5,(const unsigned char*)"\x00\x00\x7e\x00\x7e", "AAB+AH4=" }, + {5,(const unsigned char*)"\x00\x00\x7e\x00\xfc", "AAB+APw=" }, + {5,(const unsigned char*)"\x00\x00\x7e\x7e\x00", "AAB+fgA=" }, + {5,(const unsigned char*)"\x00\x00\x7e\x7e\x7e", "AAB+fn4=" }, + {5,(const unsigned char*)"\x00\x00\x7e\x7e\xfc", "AAB+fvw=" }, + {5,(const unsigned char*)"\x00\x00\x7e\xfc\x00", "AAB+/AA=" }, + {5,(const unsigned char*)"\x00\x00\x7e\xfc\x7e", "AAB+/H4=" }, + {5,(const unsigned char*)"\x00\x00\x7e\xfc\xfc", "AAB+/Pw=" }, + {5,(const unsigned char*)"\x00\x00\xfc\x00\x00", "AAD8AAA=" }, + {5,(const unsigned char*)"\x00\x00\xfc\x00\x7e", "AAD8AH4=" }, + {5,(const unsigned char*)"\x00\x00\xfc\x00\xfc", "AAD8APw=" }, + {5,(const unsigned char*)"\x00\x00\xfc\x7e\x00", "AAD8fgA=" }, + {5,(const unsigned char*)"\x00\x00\xfc\x7e\x7e", "AAD8fn4=" }, + {5,(const unsigned char*)"\x00\x00\xfc\x7e\xfc", "AAD8fvw=" }, + {5,(const unsigned char*)"\x00\x00\xfc\xfc\x00", "AAD8/AA=" }, + {5,(const unsigned char*)"\x00\x00\xfc\xfc\x7e", "AAD8/H4=" }, + {5,(const unsigned char*)"\x00\x00\xfc\xfc\xfc", "AAD8/Pw=" }, + {5,(const unsigned char*)"\x00\x7e\x00\x00\x00", "AH4AAAA=" }, + {5,(const unsigned char*)"\x00\x7e\x00\x00\x7e", "AH4AAH4=" }, + {5,(const unsigned char*)"\x00\x7e\x00\x00\xfc", "AH4AAPw=" }, + {5,(const unsigned char*)"\x00\x7e\x00\x7e\x00", "AH4AfgA=" }, + {5,(const unsigned char*)"\x00\x7e\x00\x7e\x7e", "AH4Afn4=" }, + {5,(const unsigned char*)"\x00\x7e\x00\x7e\xfc", "AH4Afvw=" }, + {5,(const unsigned char*)"\x00\x7e\x00\xfc\x00", "AH4A/AA=" }, + {5,(const unsigned char*)"\x00\x7e\x00\xfc\x7e", "AH4A/H4=" }, + {5,(const unsigned char*)"\x00\x7e\x00\xfc\xfc", "AH4A/Pw=" }, + {5,(const unsigned char*)"\x00\x7e\x7e\x00\x00", "AH5+AAA=" }, + {5,(const unsigned char*)"\x00\x7e\x7e\x00\x7e", "AH5+AH4=" }, + {5,(const unsigned char*)"\x00\x7e\x7e\x00\xfc", "AH5+APw=" }, + {5,(const unsigned char*)"\x00\x7e\x7e\x7e\x00", "AH5+fgA=" }, + {5,(const unsigned char*)"\x00\x7e\x7e\x7e\x7e", "AH5+fn4=" }, + {5,(const unsigned char*)"\x00\x7e\x7e\x7e\xfc", "AH5+fvw=" }, + {5,(const unsigned char*)"\x00\x7e\x7e\xfc\x00", "AH5+/AA=" }, + {5,(const unsigned char*)"\x00\x7e\x7e\xfc\x7e", "AH5+/H4=" }, + {5,(const unsigned char*)"\x00\x7e\x7e\xfc\xfc", "AH5+/Pw=" }, + {5,(const unsigned char*)"\x00\x7e\xfc\x00\x00", "AH78AAA=" }, + {5,(const unsigned char*)"\x00\x7e\xfc\x00\x7e", "AH78AH4=" }, + {5,(const unsigned char*)"\x00\x7e\xfc\x00\xfc", "AH78APw=" }, + {5,(const unsigned char*)"\x00\x7e\xfc\x7e\x00", "AH78fgA=" }, + {5,(const unsigned char*)"\x00\x7e\xfc\x7e\x7e", "AH78fn4=" }, + {5,(const unsigned char*)"\x00\x7e\xfc\x7e\xfc", "AH78fvw=" }, + {5,(const unsigned char*)"\x00\x7e\xfc\xfc\x00", "AH78/AA=" }, + {5,(const unsigned char*)"\x00\x7e\xfc\xfc\x7e", "AH78/H4=" }, + {5,(const unsigned char*)"\x00\x7e\xfc\xfc\xfc", "AH78/Pw=" }, + {5,(const unsigned char*)"\x00\xfc\x00\x00\x00", "APwAAAA=" }, + {5,(const unsigned char*)"\x00\xfc\x00\x00\x7e", "APwAAH4=" }, + {5,(const unsigned char*)"\x00\xfc\x00\x00\xfc", "APwAAPw=" }, + {5,(const unsigned char*)"\x00\xfc\x00\x7e\x00", "APwAfgA=" }, + {5,(const unsigned char*)"\x00\xfc\x00\x7e\x7e", "APwAfn4=" }, + {5,(const unsigned char*)"\x00\xfc\x00\x7e\xfc", "APwAfvw=" }, + {5,(const unsigned char*)"\x00\xfc\x00\xfc\x00", "APwA/AA=" }, + {5,(const unsigned char*)"\x00\xfc\x00\xfc\x7e", "APwA/H4=" }, + {5,(const unsigned char*)"\x00\xfc\x00\xfc\xfc", "APwA/Pw=" }, + {5,(const unsigned char*)"\x00\xfc\x7e\x00\x00", "APx+AAA=" }, + {5,(const unsigned char*)"\x00\xfc\x7e\x00\x7e", "APx+AH4=" }, + {5,(const unsigned char*)"\x00\xfc\x7e\x00\xfc", "APx+APw=" }, + {5,(const unsigned char*)"\x00\xfc\x7e\x7e\x00", "APx+fgA=" }, + {5,(const unsigned char*)"\x00\xfc\x7e\x7e\x7e", "APx+fn4=" }, + {5,(const unsigned char*)"\x00\xfc\x7e\x7e\xfc", "APx+fvw=" }, + {5,(const unsigned char*)"\x00\xfc\x7e\xfc\x00", "APx+/AA=" }, + {5,(const unsigned char*)"\x00\xfc\x7e\xfc\x7e", "APx+/H4=" }, + {5,(const unsigned char*)"\x00\xfc\x7e\xfc\xfc", "APx+/Pw=" }, + {5,(const unsigned char*)"\x00\xfc\xfc\x00\x00", "APz8AAA=" }, + {5,(const unsigned char*)"\x00\xfc\xfc\x00\x7e", "APz8AH4=" }, + {5,(const unsigned char*)"\x00\xfc\xfc\x00\xfc", "APz8APw=" }, + {5,(const unsigned char*)"\x00\xfc\xfc\x7e\x00", "APz8fgA=" }, + {5,(const unsigned char*)"\x00\xfc\xfc\x7e\x7e", "APz8fn4=" }, + {5,(const unsigned char*)"\x00\xfc\xfc\x7e\xfc", "APz8fvw=" }, + {5,(const unsigned char*)"\x00\xfc\xfc\xfc\x00", "APz8/AA=" }, + {5,(const unsigned char*)"\x00\xfc\xfc\xfc\x7e", "APz8/H4=" }, + {5,(const unsigned char*)"\x00\xfc\xfc\xfc\xfc", "APz8/Pw=" }, + {5,(const unsigned char*)"\x7e\x00\x00\x00\x00", "fgAAAAA=" }, + {5,(const unsigned char*)"\x7e\x00\x00\x00\x7e", "fgAAAH4=" }, + {5,(const unsigned char*)"\x7e\x00\x00\x00\xfc", "fgAAAPw=" }, + {5,(const unsigned char*)"\x7e\x00\x00\x7e\x00", "fgAAfgA=" }, + {5,(const unsigned char*)"\x7e\x00\x00\x7e\x7e", "fgAAfn4=" }, + {5,(const unsigned char*)"\x7e\x00\x00\x7e\xfc", "fgAAfvw=" }, + {5,(const unsigned char*)"\x7e\x00\x00\xfc\x00", "fgAA/AA=" }, + {5,(const unsigned char*)"\x7e\x00\x00\xfc\x7e", "fgAA/H4=" }, + {5,(const unsigned char*)"\x7e\x00\x00\xfc\xfc", "fgAA/Pw=" }, + {5,(const unsigned char*)"\x7e\x00\x7e\x00\x00", "fgB+AAA=" }, + {5,(const unsigned char*)"\x7e\x00\x7e\x00\x7e", "fgB+AH4=" }, + {5,(const unsigned char*)"\x7e\x00\x7e\x00\xfc", "fgB+APw=" }, + {5,(const unsigned char*)"\x7e\x00\x7e\x7e\x00", "fgB+fgA=" }, + {5,(const unsigned char*)"\x7e\x00\x7e\x7e\x7e", "fgB+fn4=" }, + {5,(const unsigned char*)"\x7e\x00\x7e\x7e\xfc", "fgB+fvw=" }, + {5,(const unsigned char*)"\x7e\x00\x7e\xfc\x00", "fgB+/AA=" }, + {5,(const unsigned char*)"\x7e\x00\x7e\xfc\x7e", "fgB+/H4=" }, + {5,(const unsigned char*)"\x7e\x00\x7e\xfc\xfc", "fgB+/Pw=" }, + {5,(const unsigned char*)"\x7e\x00\xfc\x00\x00", "fgD8AAA=" }, + {5,(const unsigned char*)"\x7e\x00\xfc\x00\x7e", "fgD8AH4=" }, + {5,(const unsigned char*)"\x7e\x00\xfc\x00\xfc", "fgD8APw=" }, + {5,(const unsigned char*)"\x7e\x00\xfc\x7e\x00", "fgD8fgA=" }, + {5,(const unsigned char*)"\x7e\x00\xfc\x7e\x7e", "fgD8fn4=" }, + {5,(const unsigned char*)"\x7e\x00\xfc\x7e\xfc", "fgD8fvw=" }, + {5,(const unsigned char*)"\x7e\x00\xfc\xfc\x00", "fgD8/AA=" }, + {5,(const unsigned char*)"\x7e\x00\xfc\xfc\x7e", "fgD8/H4=" }, + {5,(const unsigned char*)"\x7e\x00\xfc\xfc\xfc", "fgD8/Pw=" }, + {5,(const unsigned char*)"\x7e\x7e\x00\x00\x00", "fn4AAAA=" }, + {5,(const unsigned char*)"\x7e\x7e\x00\x00\x7e", "fn4AAH4=" }, + {5,(const unsigned char*)"\x7e\x7e\x00\x00\xfc", "fn4AAPw=" }, + {5,(const unsigned char*)"\x7e\x7e\x00\x7e\x00", "fn4AfgA=" }, + {5,(const unsigned char*)"\x7e\x7e\x00\x7e\x7e", "fn4Afn4=" }, + {5,(const unsigned char*)"\x7e\x7e\x00\x7e\xfc", "fn4Afvw=" }, + {5,(const unsigned char*)"\x7e\x7e\x00\xfc\x00", "fn4A/AA=" }, + {5,(const unsigned char*)"\x7e\x7e\x00\xfc\x7e", "fn4A/H4=" }, + {5,(const unsigned char*)"\x7e\x7e\x00\xfc\xfc", "fn4A/Pw=" }, + {5,(const unsigned char*)"\x7e\x7e\x7e\x00\x00", "fn5+AAA=" }, + {5,(const unsigned char*)"\x7e\x7e\x7e\x00\x7e", "fn5+AH4=" }, + {5,(const unsigned char*)"\x7e\x7e\x7e\x00\xfc", "fn5+APw=" }, + {5,(const unsigned char*)"\x7e\x7e\x7e\x7e\x00", "fn5+fgA=" }, + {5,(const unsigned char*)"\x7e\x7e\x7e\x7e\x7e", "fn5+fn4=" }, + {5,(const unsigned char*)"\x7e\x7e\x7e\x7e\xfc", "fn5+fvw=" }, + {5,(const unsigned char*)"\x7e\x7e\x7e\xfc\x00", "fn5+/AA=" }, + {5,(const unsigned char*)"\x7e\x7e\x7e\xfc\x7e", "fn5+/H4=" }, + {5,(const unsigned char*)"\x7e\x7e\x7e\xfc\xfc", "fn5+/Pw=" }, + {5,(const unsigned char*)"\x7e\x7e\xfc\x00\x00", "fn78AAA=" }, + {5,(const unsigned char*)"\x7e\x7e\xfc\x00\x7e", "fn78AH4=" }, + {5,(const unsigned char*)"\x7e\x7e\xfc\x00\xfc", "fn78APw=" }, + {5,(const unsigned char*)"\x7e\x7e\xfc\x7e\x00", "fn78fgA=" }, + {5,(const unsigned char*)"\x7e\x7e\xfc\x7e\x7e", "fn78fn4=" }, + {5,(const unsigned char*)"\x7e\x7e\xfc\x7e\xfc", "fn78fvw=" }, + {5,(const unsigned char*)"\x7e\x7e\xfc\xfc\x00", "fn78/AA=" }, + {5,(const unsigned char*)"\x7e\x7e\xfc\xfc\x7e", "fn78/H4=" }, + {5,(const unsigned char*)"\x7e\x7e\xfc\xfc\xfc", "fn78/Pw=" }, + {5,(const unsigned char*)"\x7e\xfc\x00\x00\x00", "fvwAAAA=" }, + {5,(const unsigned char*)"\x7e\xfc\x00\x00\x7e", "fvwAAH4=" }, + {5,(const unsigned char*)"\x7e\xfc\x00\x00\xfc", "fvwAAPw=" }, + {5,(const unsigned char*)"\x7e\xfc\x00\x7e\x00", "fvwAfgA=" }, + {5,(const unsigned char*)"\x7e\xfc\x00\x7e\x7e", "fvwAfn4=" }, + {5,(const unsigned char*)"\x7e\xfc\x00\x7e\xfc", "fvwAfvw=" }, + {5,(const unsigned char*)"\x7e\xfc\x00\xfc\x00", "fvwA/AA=" }, + {5,(const unsigned char*)"\x7e\xfc\x00\xfc\x7e", "fvwA/H4=" }, + {5,(const unsigned char*)"\x7e\xfc\x00\xfc\xfc", "fvwA/Pw=" }, + {5,(const unsigned char*)"\x7e\xfc\x7e\x00\x00", "fvx+AAA=" }, + {5,(const unsigned char*)"\x7e\xfc\x7e\x00\x7e", "fvx+AH4=" }, + {5,(const unsigned char*)"\x7e\xfc\x7e\x00\xfc", "fvx+APw=" }, + {5,(const unsigned char*)"\x7e\xfc\x7e\x7e\x00", "fvx+fgA=" }, + {5,(const unsigned char*)"\x7e\xfc\x7e\x7e\x7e", "fvx+fn4=" }, + {5,(const unsigned char*)"\x7e\xfc\x7e\x7e\xfc", "fvx+fvw=" }, + {5,(const unsigned char*)"\x7e\xfc\x7e\xfc\x00", "fvx+/AA=" }, + {5,(const unsigned char*)"\x7e\xfc\x7e\xfc\x7e", "fvx+/H4=" }, + {5,(const unsigned char*)"\x7e\xfc\x7e\xfc\xfc", "fvx+/Pw=" }, + {5,(const unsigned char*)"\x7e\xfc\xfc\x00\x00", "fvz8AAA=" }, + {5,(const unsigned char*)"\x7e\xfc\xfc\x00\x7e", "fvz8AH4=" }, + {5,(const unsigned char*)"\x7e\xfc\xfc\x00\xfc", "fvz8APw=" }, + {5,(const unsigned char*)"\x7e\xfc\xfc\x7e\x00", "fvz8fgA=" }, + {5,(const unsigned char*)"\x7e\xfc\xfc\x7e\x7e", "fvz8fn4=" }, + {5,(const unsigned char*)"\x7e\xfc\xfc\x7e\xfc", "fvz8fvw=" }, + {5,(const unsigned char*)"\x7e\xfc\xfc\xfc\x00", "fvz8/AA=" }, + {5,(const unsigned char*)"\x7e\xfc\xfc\xfc\x7e", "fvz8/H4=" }, + {5,(const unsigned char*)"\x7e\xfc\xfc\xfc\xfc", "fvz8/Pw=" }, + {5,(const unsigned char*)"\xfc\x00\x00\x00\x00", "/AAAAAA=" }, + {5,(const unsigned char*)"\xfc\x00\x00\x00\x7e", "/AAAAH4=" }, + {5,(const unsigned char*)"\xfc\x00\x00\x00\xfc", "/AAAAPw=" }, + {5,(const unsigned char*)"\xfc\x00\x00\x7e\x00", "/AAAfgA=" }, + {5,(const unsigned char*)"\xfc\x00\x00\x7e\x7e", "/AAAfn4=" }, + {5,(const unsigned char*)"\xfc\x00\x00\x7e\xfc", "/AAAfvw=" }, + {5,(const unsigned char*)"\xfc\x00\x00\xfc\x00", "/AAA/AA=" }, + {5,(const unsigned char*)"\xfc\x00\x00\xfc\x7e", "/AAA/H4=" }, + {5,(const unsigned char*)"\xfc\x00\x00\xfc\xfc", "/AAA/Pw=" }, + {5,(const unsigned char*)"\xfc\x00\x7e\x00\x00", "/AB+AAA=" }, + {5,(const unsigned char*)"\xfc\x00\x7e\x00\x7e", "/AB+AH4=" }, + {5,(const unsigned char*)"\xfc\x00\x7e\x00\xfc", "/AB+APw=" }, + {5,(const unsigned char*)"\xfc\x00\x7e\x7e\x00", "/AB+fgA=" }, + {5,(const unsigned char*)"\xfc\x00\x7e\x7e\x7e", "/AB+fn4=" }, + {5,(const unsigned char*)"\xfc\x00\x7e\x7e\xfc", "/AB+fvw=" }, + {5,(const unsigned char*)"\xfc\x00\x7e\xfc\x00", "/AB+/AA=" }, + {5,(const unsigned char*)"\xfc\x00\x7e\xfc\x7e", "/AB+/H4=" }, + {5,(const unsigned char*)"\xfc\x00\x7e\xfc\xfc", "/AB+/Pw=" }, + {5,(const unsigned char*)"\xfc\x00\xfc\x00\x00", "/AD8AAA=" }, + {5,(const unsigned char*)"\xfc\x00\xfc\x00\x7e", "/AD8AH4=" }, + {5,(const unsigned char*)"\xfc\x00\xfc\x00\xfc", "/AD8APw=" }, + {5,(const unsigned char*)"\xfc\x00\xfc\x7e\x00", "/AD8fgA=" }, + {5,(const unsigned char*)"\xfc\x00\xfc\x7e\x7e", "/AD8fn4=" }, + {5,(const unsigned char*)"\xfc\x00\xfc\x7e\xfc", "/AD8fvw=" }, + {5,(const unsigned char*)"\xfc\x00\xfc\xfc\x00", "/AD8/AA=" }, + {5,(const unsigned char*)"\xfc\x00\xfc\xfc\x7e", "/AD8/H4=" }, + {5,(const unsigned char*)"\xfc\x00\xfc\xfc\xfc", "/AD8/Pw=" }, + {5,(const unsigned char*)"\xfc\x7e\x00\x00\x00", "/H4AAAA=" }, + {5,(const unsigned char*)"\xfc\x7e\x00\x00\x7e", "/H4AAH4=" }, + {5,(const unsigned char*)"\xfc\x7e\x00\x00\xfc", "/H4AAPw=" }, + {5,(const unsigned char*)"\xfc\x7e\x00\x7e\x00", "/H4AfgA=" }, + {5,(const unsigned char*)"\xfc\x7e\x00\x7e\x7e", "/H4Afn4=" }, + {5,(const unsigned char*)"\xfc\x7e\x00\x7e\xfc", "/H4Afvw=" }, + {5,(const unsigned char*)"\xfc\x7e\x00\xfc\x00", "/H4A/AA=" }, + {5,(const unsigned char*)"\xfc\x7e\x00\xfc\x7e", "/H4A/H4=" }, + {5,(const unsigned char*)"\xfc\x7e\x00\xfc\xfc", "/H4A/Pw=" }, + {5,(const unsigned char*)"\xfc\x7e\x7e\x00\x00", "/H5+AAA=" }, + {5,(const unsigned char*)"\xfc\x7e\x7e\x00\x7e", "/H5+AH4=" }, + {5,(const unsigned char*)"\xfc\x7e\x7e\x00\xfc", "/H5+APw=" }, + {5,(const unsigned char*)"\xfc\x7e\x7e\x7e\x00", "/H5+fgA=" }, + {5,(const unsigned char*)"\xfc\x7e\x7e\x7e\x7e", "/H5+fn4=" }, + {5,(const unsigned char*)"\xfc\x7e\x7e\x7e\xfc", "/H5+fvw=" }, + {5,(const unsigned char*)"\xfc\x7e\x7e\xfc\x00", "/H5+/AA=" }, + {5,(const unsigned char*)"\xfc\x7e\x7e\xfc\x7e", "/H5+/H4=" }, + {5,(const unsigned char*)"\xfc\x7e\x7e\xfc\xfc", "/H5+/Pw=" }, + {5,(const unsigned char*)"\xfc\x7e\xfc\x00\x00", "/H78AAA=" }, + {5,(const unsigned char*)"\xfc\x7e\xfc\x00\x7e", "/H78AH4=" }, + {5,(const unsigned char*)"\xfc\x7e\xfc\x00\xfc", "/H78APw=" }, + {5,(const unsigned char*)"\xfc\x7e\xfc\x7e\x00", "/H78fgA=" }, + {5,(const unsigned char*)"\xfc\x7e\xfc\x7e\x7e", "/H78fn4=" }, + {5,(const unsigned char*)"\xfc\x7e\xfc\x7e\xfc", "/H78fvw=" }, + {5,(const unsigned char*)"\xfc\x7e\xfc\xfc\x00", "/H78/AA=" }, + {5,(const unsigned char*)"\xfc\x7e\xfc\xfc\x7e", "/H78/H4=" }, + {5,(const unsigned char*)"\xfc\x7e\xfc\xfc\xfc", "/H78/Pw=" }, + {5,(const unsigned char*)"\xfc\xfc\x00\x00\x00", "/PwAAAA=" }, + {5,(const unsigned char*)"\xfc\xfc\x00\x00\x7e", "/PwAAH4=" }, + {5,(const unsigned char*)"\xfc\xfc\x00\x00\xfc", "/PwAAPw=" }, + {5,(const unsigned char*)"\xfc\xfc\x00\x7e\x00", "/PwAfgA=" }, + {5,(const unsigned char*)"\xfc\xfc\x00\x7e\x7e", "/PwAfn4=" }, + {5,(const unsigned char*)"\xfc\xfc\x00\x7e\xfc", "/PwAfvw=" }, + {5,(const unsigned char*)"\xfc\xfc\x00\xfc\x00", "/PwA/AA=" }, + {5,(const unsigned char*)"\xfc\xfc\x00\xfc\x7e", "/PwA/H4=" }, + {5,(const unsigned char*)"\xfc\xfc\x00\xfc\xfc", "/PwA/Pw=" }, + {5,(const unsigned char*)"\xfc\xfc\x7e\x00\x00", "/Px+AAA=" }, + {5,(const unsigned char*)"\xfc\xfc\x7e\x00\x7e", "/Px+AH4=" }, + {5,(const unsigned char*)"\xfc\xfc\x7e\x00\xfc", "/Px+APw=" }, + {5,(const unsigned char*)"\xfc\xfc\x7e\x7e\x00", "/Px+fgA=" }, + {5,(const unsigned char*)"\xfc\xfc\x7e\x7e\x7e", "/Px+fn4=" }, + {5,(const unsigned char*)"\xfc\xfc\x7e\x7e\xfc", "/Px+fvw=" }, + {5,(const unsigned char*)"\xfc\xfc\x7e\xfc\x00", "/Px+/AA=" }, + {5,(const unsigned char*)"\xfc\xfc\x7e\xfc\x7e", "/Px+/H4=" }, + {5,(const unsigned char*)"\xfc\xfc\x7e\xfc\xfc", "/Px+/Pw=" }, + {5,(const unsigned char*)"\xfc\xfc\xfc\x00\x00", "/Pz8AAA=" }, + {5,(const unsigned char*)"\xfc\xfc\xfc\x00\x7e", "/Pz8AH4=" }, + {5,(const unsigned char*)"\xfc\xfc\xfc\x00\xfc", "/Pz8APw=" }, + {5,(const unsigned char*)"\xfc\xfc\xfc\x7e\x00", "/Pz8fgA=" }, + {5,(const unsigned char*)"\xfc\xfc\xfc\x7e\x7e", "/Pz8fn4=" }, + {5,(const unsigned char*)"\xfc\xfc\xfc\x7e\xfc", "/Pz8fvw=" }, + {5,(const unsigned char*)"\xfc\xfc\xfc\xfc\x00", "/Pz8/AA=" }, + {5,(const unsigned char*)"\xfc\xfc\xfc\xfc\x7e", "/Pz8/H4=" }, + {5,(const unsigned char*)"\xfc\xfc\xfc\xfc\xfc", "/Pz8/Pw=" }, + {6,(const unsigned char*)"\x00\x00\x00\x00\x00\x00", "AAAAAAAA" }, + {6,(const unsigned char*)"\x00\x00\x00\x00\x00\xa8", "AAAAAACo" }, + {6,(const unsigned char*)"\x00\x00\x00\x00\xa8\x00", "AAAAAKgA" }, + {6,(const unsigned char*)"\x00\x00\x00\x00\xa8\xa8", "AAAAAKio" }, + {6,(const unsigned char*)"\x00\x00\x00\xa8\x00\x00", "AAAAqAAA" }, + {6,(const unsigned char*)"\x00\x00\x00\xa8\x00\xa8", "AAAAqACo" }, + {6,(const unsigned char*)"\x00\x00\x00\xa8\xa8\x00", "AAAAqKgA" }, + {6,(const unsigned char*)"\x00\x00\x00\xa8\xa8\xa8", "AAAAqKio" }, + {6,(const unsigned char*)"\x00\x00\xa8\x00\x00\x00", "AACoAAAA" }, + {6,(const unsigned char*)"\x00\x00\xa8\x00\x00\xa8", "AACoAACo" }, + {6,(const unsigned char*)"\x00\x00\xa8\x00\xa8\x00", "AACoAKgA" }, + {6,(const unsigned char*)"\x00\x00\xa8\x00\xa8\xa8", "AACoAKio" }, + {6,(const unsigned char*)"\x00\x00\xa8\xa8\x00\x00", "AACoqAAA" }, + {6,(const unsigned char*)"\x00\x00\xa8\xa8\x00\xa8", "AACoqACo" }, + {6,(const unsigned char*)"\x00\x00\xa8\xa8\xa8\x00", "AACoqKgA" }, + {6,(const unsigned char*)"\x00\x00\xa8\xa8\xa8\xa8", "AACoqKio" }, + {6,(const unsigned char*)"\x00\xa8\x00\x00\x00\x00", "AKgAAAAA" }, + {6,(const unsigned char*)"\x00\xa8\x00\x00\x00\xa8", "AKgAAACo" }, + {6,(const unsigned char*)"\x00\xa8\x00\x00\xa8\x00", "AKgAAKgA" }, + {6,(const unsigned char*)"\x00\xa8\x00\x00\xa8\xa8", "AKgAAKio" }, + {6,(const unsigned char*)"\x00\xa8\x00\xa8\x00\x00", "AKgAqAAA" }, + {6,(const unsigned char*)"\x00\xa8\x00\xa8\x00\xa8", "AKgAqACo" }, + {6,(const unsigned char*)"\x00\xa8\x00\xa8\xa8\x00", "AKgAqKgA" }, + {6,(const unsigned char*)"\x00\xa8\x00\xa8\xa8\xa8", "AKgAqKio" }, + {6,(const unsigned char*)"\x00\xa8\xa8\x00\x00\x00", "AKioAAAA" }, + {6,(const unsigned char*)"\x00\xa8\xa8\x00\x00\xa8", "AKioAACo" }, + {6,(const unsigned char*)"\x00\xa8\xa8\x00\xa8\x00", "AKioAKgA" }, + {6,(const unsigned char*)"\x00\xa8\xa8\x00\xa8\xa8", "AKioAKio" }, + {6,(const unsigned char*)"\x00\xa8\xa8\xa8\x00\x00", "AKioqAAA" }, + {6,(const unsigned char*)"\x00\xa8\xa8\xa8\x00\xa8", "AKioqACo" }, + {6,(const unsigned char*)"\x00\xa8\xa8\xa8\xa8\x00", "AKioqKgA" }, + {6,(const unsigned char*)"\x00\xa8\xa8\xa8\xa8\xa8", "AKioqKio" }, + {6,(const unsigned char*)"\xa8\x00\x00\x00\x00\x00", "qAAAAAAA" }, + {6,(const unsigned char*)"\xa8\x00\x00\x00\x00\xa8", "qAAAAACo" }, + {6,(const unsigned char*)"\xa8\x00\x00\x00\xa8\x00", "qAAAAKgA" }, + {6,(const unsigned char*)"\xa8\x00\x00\x00\xa8\xa8", "qAAAAKio" }, + {6,(const unsigned char*)"\xa8\x00\x00\xa8\x00\x00", "qAAAqAAA" }, + {6,(const unsigned char*)"\xa8\x00\x00\xa8\x00\xa8", "qAAAqACo" }, + {6,(const unsigned char*)"\xa8\x00\x00\xa8\xa8\x00", "qAAAqKgA" }, + {6,(const unsigned char*)"\xa8\x00\x00\xa8\xa8\xa8", "qAAAqKio" }, + {6,(const unsigned char*)"\xa8\x00\xa8\x00\x00\x00", "qACoAAAA" }, + {6,(const unsigned char*)"\xa8\x00\xa8\x00\x00\xa8", "qACoAACo" }, + {6,(const unsigned char*)"\xa8\x00\xa8\x00\xa8\x00", "qACoAKgA" }, + {6,(const unsigned char*)"\xa8\x00\xa8\x00\xa8\xa8", "qACoAKio" }, + {6,(const unsigned char*)"\xa8\x00\xa8\xa8\x00\x00", "qACoqAAA" }, + {6,(const unsigned char*)"\xa8\x00\xa8\xa8\x00\xa8", "qACoqACo" }, + {6,(const unsigned char*)"\xa8\x00\xa8\xa8\xa8\x00", "qACoqKgA" }, + {6,(const unsigned char*)"\xa8\x00\xa8\xa8\xa8\xa8", "qACoqKio" }, + {6,(const unsigned char*)"\xa8\xa8\x00\x00\x00\x00", "qKgAAAAA" }, + {6,(const unsigned char*)"\xa8\xa8\x00\x00\x00\xa8", "qKgAAACo" }, + {6,(const unsigned char*)"\xa8\xa8\x00\x00\xa8\x00", "qKgAAKgA" }, + {6,(const unsigned char*)"\xa8\xa8\x00\x00\xa8\xa8", "qKgAAKio" }, + {6,(const unsigned char*)"\xa8\xa8\x00\xa8\x00\x00", "qKgAqAAA" }, + {6,(const unsigned char*)"\xa8\xa8\x00\xa8\x00\xa8", "qKgAqACo" }, + {6,(const unsigned char*)"\xa8\xa8\x00\xa8\xa8\x00", "qKgAqKgA" }, + {6,(const unsigned char*)"\xa8\xa8\x00\xa8\xa8\xa8", "qKgAqKio" }, + {6,(const unsigned char*)"\xa8\xa8\xa8\x00\x00\x00", "qKioAAAA" }, + {6,(const unsigned char*)"\xa8\xa8\xa8\x00\x00\xa8", "qKioAACo" }, + {6,(const unsigned char*)"\xa8\xa8\xa8\x00\xa8\x00", "qKioAKgA" }, + {6,(const unsigned char*)"\xa8\xa8\xa8\x00\xa8\xa8", "qKioAKio" }, + {6,(const unsigned char*)"\xa8\xa8\xa8\xa8\x00\x00", "qKioqAAA" }, + {6,(const unsigned char*)"\xa8\xa8\xa8\xa8\x00\xa8", "qKioqACo" }, + {6,(const unsigned char*)"\xa8\xa8\xa8\xa8\xa8\x00", "qKioqKgA" }, + {6,(const unsigned char*)"\xa8\xa8\xa8\xa8\xa8\xa8", "qKioqKio" }, + {7,(const unsigned char*)"\x00\x00\x00\x00\x00\x00\x00", "AAAAAAAAAA==" }, + {7,(const unsigned char*)"\x00\x00\x00\x00\x00\x00\xd3", "AAAAAAAA0w==" }, + {7,(const unsigned char*)"\x00\x00\x00\x00\x00\xd3\x00", "AAAAAADTAA==" }, + {7,(const unsigned char*)"\x00\x00\x00\x00\x00\xd3\xd3", "AAAAAADT0w==" }, + {7,(const unsigned char*)"\x00\x00\x00\x00\xd3\x00\x00", "AAAAANMAAA==" }, + {7,(const unsigned char*)"\x00\x00\x00\x00\xd3\x00\xd3", "AAAAANMA0w==" }, + {7,(const unsigned char*)"\x00\x00\x00\x00\xd3\xd3\x00", "AAAAANPTAA==" }, + {7,(const unsigned char*)"\x00\x00\x00\x00\xd3\xd3\xd3", "AAAAANPT0w==" }, + {7,(const unsigned char*)"\x00\x00\x00\xd3\x00\x00\x00", "AAAA0wAAAA==" }, + {7,(const unsigned char*)"\x00\x00\x00\xd3\x00\x00\xd3", "AAAA0wAA0w==" }, + {7,(const unsigned char*)"\x00\x00\x00\xd3\x00\xd3\x00", "AAAA0wDTAA==" }, + {7,(const unsigned char*)"\x00\x00\x00\xd3\x00\xd3\xd3", "AAAA0wDT0w==" }, + {7,(const unsigned char*)"\x00\x00\x00\xd3\xd3\x00\x00", "AAAA09MAAA==" }, + {7,(const unsigned char*)"\x00\x00\x00\xd3\xd3\x00\xd3", "AAAA09MA0w==" }, + {7,(const unsigned char*)"\x00\x00\x00\xd3\xd3\xd3\x00", "AAAA09PTAA==" }, + {7,(const unsigned char*)"\x00\x00\x00\xd3\xd3\xd3\xd3", "AAAA09PT0w==" }, + {7,(const unsigned char*)"\x00\x00\xd3\x00\x00\x00\x00", "AADTAAAAAA==" }, + {7,(const unsigned char*)"\x00\x00\xd3\x00\x00\x00\xd3", "AADTAAAA0w==" }, + {7,(const unsigned char*)"\x00\x00\xd3\x00\x00\xd3\x00", "AADTAADTAA==" }, + {7,(const unsigned char*)"\x00\x00\xd3\x00\x00\xd3\xd3", "AADTAADT0w==" }, + {7,(const unsigned char*)"\x00\x00\xd3\x00\xd3\x00\x00", "AADTANMAAA==" }, + {7,(const unsigned char*)"\x00\x00\xd3\x00\xd3\x00\xd3", "AADTANMA0w==" }, + {7,(const unsigned char*)"\x00\x00\xd3\x00\xd3\xd3\x00", "AADTANPTAA==" }, + {7,(const unsigned char*)"\x00\x00\xd3\x00\xd3\xd3\xd3", "AADTANPT0w==" }, + {7,(const unsigned char*)"\x00\x00\xd3\xd3\x00\x00\x00", "AADT0wAAAA==" }, + {7,(const unsigned char*)"\x00\x00\xd3\xd3\x00\x00\xd3", "AADT0wAA0w==" }, + {7,(const unsigned char*)"\x00\x00\xd3\xd3\x00\xd3\x00", "AADT0wDTAA==" }, + {7,(const unsigned char*)"\x00\x00\xd3\xd3\x00\xd3\xd3", "AADT0wDT0w==" }, + {7,(const unsigned char*)"\x00\x00\xd3\xd3\xd3\x00\x00", "AADT09MAAA==" }, + {7,(const unsigned char*)"\x00\x00\xd3\xd3\xd3\x00\xd3", "AADT09MA0w==" }, + {7,(const unsigned char*)"\x00\x00\xd3\xd3\xd3\xd3\x00", "AADT09PTAA==" }, + {7,(const unsigned char*)"\x00\x00\xd3\xd3\xd3\xd3\xd3", "AADT09PT0w==" }, + {7,(const unsigned char*)"\x00\xd3\x00\x00\x00\x00\x00", "ANMAAAAAAA==" }, + {7,(const unsigned char*)"\x00\xd3\x00\x00\x00\x00\xd3", "ANMAAAAA0w==" }, + {7,(const unsigned char*)"\x00\xd3\x00\x00\x00\xd3\x00", "ANMAAADTAA==" }, + {7,(const unsigned char*)"\x00\xd3\x00\x00\x00\xd3\xd3", "ANMAAADT0w==" }, + {7,(const unsigned char*)"\x00\xd3\x00\x00\xd3\x00\x00", "ANMAANMAAA==" }, + {7,(const unsigned char*)"\x00\xd3\x00\x00\xd3\x00\xd3", "ANMAANMA0w==" }, + {7,(const unsigned char*)"\x00\xd3\x00\x00\xd3\xd3\x00", "ANMAANPTAA==" }, + {7,(const unsigned char*)"\x00\xd3\x00\x00\xd3\xd3\xd3", "ANMAANPT0w==" }, + {7,(const unsigned char*)"\x00\xd3\x00\xd3\x00\x00\x00", "ANMA0wAAAA==" }, + {7,(const unsigned char*)"\x00\xd3\x00\xd3\x00\x00\xd3", "ANMA0wAA0w==" }, + {7,(const unsigned char*)"\x00\xd3\x00\xd3\x00\xd3\x00", "ANMA0wDTAA==" }, + {7,(const unsigned char*)"\x00\xd3\x00\xd3\x00\xd3\xd3", "ANMA0wDT0w==" }, + {7,(const unsigned char*)"\x00\xd3\x00\xd3\xd3\x00\x00", "ANMA09MAAA==" }, + {7,(const unsigned char*)"\x00\xd3\x00\xd3\xd3\x00\xd3", "ANMA09MA0w==" }, + {7,(const unsigned char*)"\x00\xd3\x00\xd3\xd3\xd3\x00", "ANMA09PTAA==" }, + {7,(const unsigned char*)"\x00\xd3\x00\xd3\xd3\xd3\xd3", "ANMA09PT0w==" }, + {7,(const unsigned char*)"\x00\xd3\xd3\x00\x00\x00\x00", "ANPTAAAAAA==" }, + {7,(const unsigned char*)"\x00\xd3\xd3\x00\x00\x00\xd3", "ANPTAAAA0w==" }, + {7,(const unsigned char*)"\x00\xd3\xd3\x00\x00\xd3\x00", "ANPTAADTAA==" }, + {7,(const unsigned char*)"\x00\xd3\xd3\x00\x00\xd3\xd3", "ANPTAADT0w==" }, + {7,(const unsigned char*)"\x00\xd3\xd3\x00\xd3\x00\x00", "ANPTANMAAA==" }, + {7,(const unsigned char*)"\x00\xd3\xd3\x00\xd3\x00\xd3", "ANPTANMA0w==" }, + {7,(const unsigned char*)"\x00\xd3\xd3\x00\xd3\xd3\x00", "ANPTANPTAA==" }, + {7,(const unsigned char*)"\x00\xd3\xd3\x00\xd3\xd3\xd3", "ANPTANPT0w==" }, + {7,(const unsigned char*)"\x00\xd3\xd3\xd3\x00\x00\x00", "ANPT0wAAAA==" }, + {7,(const unsigned char*)"\x00\xd3\xd3\xd3\x00\x00\xd3", "ANPT0wAA0w==" }, + {7,(const unsigned char*)"\x00\xd3\xd3\xd3\x00\xd3\x00", "ANPT0wDTAA==" }, + {7,(const unsigned char*)"\x00\xd3\xd3\xd3\x00\xd3\xd3", "ANPT0wDT0w==" }, + {7,(const unsigned char*)"\x00\xd3\xd3\xd3\xd3\x00\x00", "ANPT09MAAA==" }, + {7,(const unsigned char*)"\x00\xd3\xd3\xd3\xd3\x00\xd3", "ANPT09MA0w==" }, + {7,(const unsigned char*)"\x00\xd3\xd3\xd3\xd3\xd3\x00", "ANPT09PTAA==" }, + {7,(const unsigned char*)"\x00\xd3\xd3\xd3\xd3\xd3\xd3", "ANPT09PT0w==" }, + {7,(const unsigned char*)"\xd3\x00\x00\x00\x00\x00\x00", "0wAAAAAAAA==" }, + {7,(const unsigned char*)"\xd3\x00\x00\x00\x00\x00\xd3", "0wAAAAAA0w==" }, + {7,(const unsigned char*)"\xd3\x00\x00\x00\x00\xd3\x00", "0wAAAADTAA==" }, + {7,(const unsigned char*)"\xd3\x00\x00\x00\x00\xd3\xd3", "0wAAAADT0w==" }, + {7,(const unsigned char*)"\xd3\x00\x00\x00\xd3\x00\x00", "0wAAANMAAA==" }, + {7,(const unsigned char*)"\xd3\x00\x00\x00\xd3\x00\xd3", "0wAAANMA0w==" }, + {7,(const unsigned char*)"\xd3\x00\x00\x00\xd3\xd3\x00", "0wAAANPTAA==" }, + {7,(const unsigned char*)"\xd3\x00\x00\x00\xd3\xd3\xd3", "0wAAANPT0w==" }, + {7,(const unsigned char*)"\xd3\x00\x00\xd3\x00\x00\x00", "0wAA0wAAAA==" }, + {7,(const unsigned char*)"\xd3\x00\x00\xd3\x00\x00\xd3", "0wAA0wAA0w==" }, + {7,(const unsigned char*)"\xd3\x00\x00\xd3\x00\xd3\x00", "0wAA0wDTAA==" }, + {7,(const unsigned char*)"\xd3\x00\x00\xd3\x00\xd3\xd3", "0wAA0wDT0w==" }, + {7,(const unsigned char*)"\xd3\x00\x00\xd3\xd3\x00\x00", "0wAA09MAAA==" }, + {7,(const unsigned char*)"\xd3\x00\x00\xd3\xd3\x00\xd3", "0wAA09MA0w==" }, + {7,(const unsigned char*)"\xd3\x00\x00\xd3\xd3\xd3\x00", "0wAA09PTAA==" }, + {7,(const unsigned char*)"\xd3\x00\x00\xd3\xd3\xd3\xd3", "0wAA09PT0w==" }, + {7,(const unsigned char*)"\xd3\x00\xd3\x00\x00\x00\x00", "0wDTAAAAAA==" }, + {7,(const unsigned char*)"\xd3\x00\xd3\x00\x00\x00\xd3", "0wDTAAAA0w==" }, + {7,(const unsigned char*)"\xd3\x00\xd3\x00\x00\xd3\x00", "0wDTAADTAA==" }, + {7,(const unsigned char*)"\xd3\x00\xd3\x00\x00\xd3\xd3", "0wDTAADT0w==" }, + {7,(const unsigned char*)"\xd3\x00\xd3\x00\xd3\x00\x00", "0wDTANMAAA==" }, + {7,(const unsigned char*)"\xd3\x00\xd3\x00\xd3\x00\xd3", "0wDTANMA0w==" }, + {7,(const unsigned char*)"\xd3\x00\xd3\x00\xd3\xd3\x00", "0wDTANPTAA==" }, + {7,(const unsigned char*)"\xd3\x00\xd3\x00\xd3\xd3\xd3", "0wDTANPT0w==" }, + {7,(const unsigned char*)"\xd3\x00\xd3\xd3\x00\x00\x00", "0wDT0wAAAA==" }, + {7,(const unsigned char*)"\xd3\x00\xd3\xd3\x00\x00\xd3", "0wDT0wAA0w==" }, + {7,(const unsigned char*)"\xd3\x00\xd3\xd3\x00\xd3\x00", "0wDT0wDTAA==" }, + {7,(const unsigned char*)"\xd3\x00\xd3\xd3\x00\xd3\xd3", "0wDT0wDT0w==" }, + {7,(const unsigned char*)"\xd3\x00\xd3\xd3\xd3\x00\x00", "0wDT09MAAA==" }, + {7,(const unsigned char*)"\xd3\x00\xd3\xd3\xd3\x00\xd3", "0wDT09MA0w==" }, + {7,(const unsigned char*)"\xd3\x00\xd3\xd3\xd3\xd3\x00", "0wDT09PTAA==" }, + {7,(const unsigned char*)"\xd3\x00\xd3\xd3\xd3\xd3\xd3", "0wDT09PT0w==" }, + {7,(const unsigned char*)"\xd3\xd3\x00\x00\x00\x00\x00", "09MAAAAAAA==" }, + {7,(const unsigned char*)"\xd3\xd3\x00\x00\x00\x00\xd3", "09MAAAAA0w==" }, + {7,(const unsigned char*)"\xd3\xd3\x00\x00\x00\xd3\x00", "09MAAADTAA==" }, + {7,(const unsigned char*)"\xd3\xd3\x00\x00\x00\xd3\xd3", "09MAAADT0w==" }, + {7,(const unsigned char*)"\xd3\xd3\x00\x00\xd3\x00\x00", "09MAANMAAA==" }, + {7,(const unsigned char*)"\xd3\xd3\x00\x00\xd3\x00\xd3", "09MAANMA0w==" }, + {7,(const unsigned char*)"\xd3\xd3\x00\x00\xd3\xd3\x00", "09MAANPTAA==" }, + {7,(const unsigned char*)"\xd3\xd3\x00\x00\xd3\xd3\xd3", "09MAANPT0w==" }, + {7,(const unsigned char*)"\xd3\xd3\x00\xd3\x00\x00\x00", "09MA0wAAAA==" }, + {7,(const unsigned char*)"\xd3\xd3\x00\xd3\x00\x00\xd3", "09MA0wAA0w==" }, + {7,(const unsigned char*)"\xd3\xd3\x00\xd3\x00\xd3\x00", "09MA0wDTAA==" }, + {7,(const unsigned char*)"\xd3\xd3\x00\xd3\x00\xd3\xd3", "09MA0wDT0w==" }, + {7,(const unsigned char*)"\xd3\xd3\x00\xd3\xd3\x00\x00", "09MA09MAAA==" }, + {7,(const unsigned char*)"\xd3\xd3\x00\xd3\xd3\x00\xd3", "09MA09MA0w==" }, + {7,(const unsigned char*)"\xd3\xd3\x00\xd3\xd3\xd3\x00", "09MA09PTAA==" }, + {7,(const unsigned char*)"\xd3\xd3\x00\xd3\xd3\xd3\xd3", "09MA09PT0w==" }, + {7,(const unsigned char*)"\xd3\xd3\xd3\x00\x00\x00\x00", "09PTAAAAAA==" }, + {7,(const unsigned char*)"\xd3\xd3\xd3\x00\x00\x00\xd3", "09PTAAAA0w==" }, + {7,(const unsigned char*)"\xd3\xd3\xd3\x00\x00\xd3\x00", "09PTAADTAA==" }, + {7,(const unsigned char*)"\xd3\xd3\xd3\x00\x00\xd3\xd3", "09PTAADT0w==" }, + {7,(const unsigned char*)"\xd3\xd3\xd3\x00\xd3\x00\x00", "09PTANMAAA==" }, + {7,(const unsigned char*)"\xd3\xd3\xd3\x00\xd3\x00\xd3", "09PTANMA0w==" }, + {7,(const unsigned char*)"\xd3\xd3\xd3\x00\xd3\xd3\x00", "09PTANPTAA==" }, + {7,(const unsigned char*)"\xd3\xd3\xd3\x00\xd3\xd3\xd3", "09PTANPT0w==" }, + {7,(const unsigned char*)"\xd3\xd3\xd3\xd3\x00\x00\x00", "09PT0wAAAA==" }, + {7,(const unsigned char*)"\xd3\xd3\xd3\xd3\x00\x00\xd3", "09PT0wAA0w==" }, + {7,(const unsigned char*)"\xd3\xd3\xd3\xd3\x00\xd3\x00", "09PT0wDTAA==" }, + {7,(const unsigned char*)"\xd3\xd3\xd3\xd3\x00\xd3\xd3", "09PT0wDT0w==" }, + {7,(const unsigned char*)"\xd3\xd3\xd3\xd3\xd3\x00\x00", "09PT09MAAA==" }, + {7,(const unsigned char*)"\xd3\xd3\xd3\xd3\xd3\x00\xd3", "09PT09MA0w==" }, + {7,(const unsigned char*)"\xd3\xd3\xd3\xd3\xd3\xd3\x00", "09PT09PTAA==" }, + {7,(const unsigned char*)"\xd3\xd3\xd3\xd3\xd3\xd3\xd3", "09PT09PT0w==" }, + {8,(const unsigned char*)"\x00\x00\x00\x00\x00\x00\x00\x00", "AAAAAAAAAAA=" }, + {9,(const unsigned char*)"\x00\x00\x00\x00\x00\x00\x00\x00\x00", "AAAAAAAAAAAA" }, + {10,(const unsigned char*)"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", "AAAAAAAAAAAAAA==" }, + + }; + + +static MICROMOCK_GLOBAL_SEMAPHORE_HANDLE g_dllByDll; +BEGIN_TEST_SUITE(base64_UnitTests) + +TEST_SUITE_INITIALIZE(TestSuiteInitialize) +{ + INITIALIZE_MEMORY_DEBUG(g_dllByDll); +} + +TEST_SUITE_CLEANUP(TestClassCleanup) +{ + DEINITIALIZE_MEMORY_DEBUG(g_dllByDll); + +} + +/*Tests_SRS_BASE64_06_001: [If input is NULL then Base64_Encode shall return NULL.]*/ +TEST_FUNCTION(Base64_Encode_bad_input) +{ + //arrange + STRING_HANDLE result; + + //act + result = Base64_Encode(NULL); + //assert + ASSERT_IS_NULL( result); + +} + +/*Tests_SRS_BASE64_06_007: [Otherwise Base64_Encode shall return a pointer to STRING, that string contains the base 64 encoding of inpuit.]*/ +TEST_FUNCTION(Base64_Encode_simple_good) +{ + //arrange + BUFFER_HANDLE input = BUFFER_new(); + STRING_HANDLE result; + + //act + result = Base64_Encode(input); + + //assert + ASSERT_ARE_NOT_EQUAL(void_ptr, NULL, result); + ASSERT_ARE_EQUAL(size_t, (size_t)0, strlen(STRING_c_str(result))); + + // Cleanup + STRING_delete(result); + BUFFER_delete(input); +} + +TEST_FUNCTION(Base64_Encode_one_char_encode) +{ + //arrange + BUFFER_HANDLE input = BUFFER_new(); + STRING_HANDLE result; + const char* oneCharacter = "a"; + + BUFFER_build(input, (unsigned char*)oneCharacter,strlen(oneCharacter)); + //act + result = Base64_Encode(input); + + //assert + ASSERT_ARE_NOT_EQUAL(void_ptr, NULL, result); + ASSERT_ARE_EQUAL(char_ptr, "YQ==", STRING_c_str(result)); + + // Cleanup + STRING_delete(result); + BUFFER_delete(input); + +} + +TEST_FUNCTION(Base64_Encode_leviathan_succeeds) +{ + //arrange + BUFFER_HANDLE input = BUFFER_new(); + STRING_HANDLE result; + const char* leviathan = "any carnal pleasure."; + + BUFFER_build(input, (unsigned char*)leviathan, strlen(leviathan)); + //act + result = Base64_Encode(input); + + //assert + ASSERT_ARE_NOT_EQUAL(void_ptr, NULL, result); + ASSERT_ARE_EQUAL(char_ptr, "YW55IGNhcm5hbCBwbGVhc3VyZS4=", STRING_c_str(result)); + + // Cleanup + STRING_delete(result); + BUFFER_delete(input); + +} + +TEST_FUNCTION(Base64_Encode_exhaustive_succeeds) +{ + ///arrange + + for (size_t i = 0; i < sizeof(testVector_BINARY_with_equal_signs) / sizeof(testVector_BINARY_with_equal_signs[0]); i++) + { + ///arrange + BUFFER_HANDLE input = BUFFER_new(); + STRING_HANDLE result; + + ASSERT_ARE_EQUAL(int, 0, BUFFER_build(input, testVector_BINARY_with_equal_signs[i].inputData, testVector_BINARY_with_equal_signs[i].inputLength)); + + ///act + result = Base64_Encode(input); + + ///assert + ASSERT_ARE_NOT_EQUAL(void_ptr, NULL, result); + ASSERT_ARE_EQUAL(char_ptr, testVector_BINARY_with_equal_signs[i].expectedOutput, STRING_c_str(result)); + + + ///cleanup + BUFFER_delete(input); + STRING_delete(result); + } +} + +/*Tests_SRS_BASE64_02_001: [If source is NULL then Base64_Encode_Bytes shall return NULL.] */ +TEST_FUNCTION(Base64_Encode_Bytes_with_NULL_source_returns_NULL) +{ + ///arrange + + ///act + auto result = Base64_Encode_Bytes(NULL, 3); + + ///assert + ASSERT_IS_NULL(result); + + ///cleanup +} + +/*Tests_SRS_BASE64_02_002: [If source is not NULL and size is zero, then Base64_Encode_Bytes shall produce an empty STRING_HANDLE.]*/ +TEST_FUNCTION(Base64_Encode_Bytes_with_zero_size_returns_empty_string) +{ + ///arrange + + ///act + auto result = Base64_Encode_Bytes((const unsigned char*)"a", 0); + + ///assert + ASSERT_IS_NOT_NULL(result); + ASSERT_ARE_EQUAL(size_t, 0, STRING_length(result)); + + ///cleanup + STRING_delete(result); +} + + +/*Tests_SRS_BASE64_02_003: [Otherwise, Base64_Encode_Bytes shall produce a STRING_HANDLE containing the Base64 representation of the buffer.] */ +TEST_FUNCTION(Base64_Encode_Bytes_exhaustive_succeeds) +{ + ///arrange + + for (size_t i = 0; i < sizeof(testVector_BINARY_with_equal_signs) / sizeof(testVector_BINARY_with_equal_signs[0]); i++) + { + ///arrange + STRING_HANDLE result; + + ///act + result = Base64_Encode_Bytes(testVector_BINARY_with_equal_signs[i].inputData, testVector_BINARY_with_equal_signs[i].inputLength); + + ///assert + ASSERT_ARE_NOT_EQUAL(void_ptr, NULL, result); + ASSERT_ARE_EQUAL(char_ptr, testVector_BINARY_with_equal_signs[i].expectedOutput, STRING_c_str(result)); + + ///cleanup + STRING_delete(result); + } +} + +TEST_FUNCTION(Base64_Decoder_exhaustive_succeeds) +{ + for (size_t i = 0; i < sizeof(testVector_BINARY_with_equal_signs) / sizeof(testVector_BINARY_with_equal_signs[0]); i++) + { + ///Arrange + BUFFER_HANDLE result; + + ///act + result = Base64_Decoder(testVector_BINARY_with_equal_signs[i].expectedOutput); + ASSERT_ARE_EQUAL(size_t, testVector_BINARY_with_equal_signs[i].inputLength, BUFFER_length(result)); + ASSERT_ARE_EQUAL(int, (int)0, memcmp(BUFFER_u_char(result), testVector_BINARY_with_equal_signs[i].inputData, BUFFER_length(result))); + + ///Cleanup + BUFFER_delete(result); + } +} + +/*Tests_SRS_BASE64_06_008: [If source is NULL then Base64_Decoder shall return NULL.]*/ +TEST_FUNCTION(Base64_Decoder_null_return_null) +{ + ///Arrange + BUFFER_HANDLE result; + + ///act + result = Base64_Decoder(NULL); + ASSERT_IS_NULL(result); +} + +/*Tests_SRS_BASE64_06_009: [If the string pointed to by source is zero length then the handle returned shall refer to a zero length buffer.]*/ +TEST_FUNCTION(Base64_Decoder_zero_length_returns_zero_length) +{ + ///Arrange + BUFFER_HANDLE result; + + ///act + result = Base64_Decoder(""); + ASSERT_IS_NOT_NULL(result); + ASSERT_ARE_EQUAL(size_t, 0, BUFFER_length(result)); + + ///Cleanup + BUFFER_delete(result); +} + +/*Tests_SRS_BASE64_06_011: [If the source string has an invalid length for a base 64 encoded string then Base64_Decoder shall return NULL.]*/ +TEST_FUNCTION(Base64_Decoder_invalid_length_fails) +{ + ///Arrange + BUFFER_HANDLE result; + + ///act + result = Base64_Decoder("A"); + ASSERT_IS_NULL(result); + +} +END_TEST_SUITE(base64_UnitTests); + diff --git a/c/sharedutil/tests/base64_unittests/main.c b/c/sharedutil/tests/base64_unittests/main.c new file mode 100644 index 00000000..406a6c0a --- /dev/null +++ b/c/sharedutil/tests/base64_unittests/main.c @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include "testrunnerswitcher.h" + +int main(void) +{ + size_t failedTestCount = 0; + RUN_TEST_SUITE(base64_UnitTests, failedTestCount); + return failedTestCount; +} diff --git a/c/sharedutil/tests/buffer_unittests/CMakeLists.txt b/c/sharedutil/tests/buffer_unittests/CMakeLists.txt new file mode 100644 index 00000000..23d0e3bc --- /dev/null +++ b/c/sharedutil/tests/buffer_unittests/CMakeLists.txt @@ -0,0 +1,21 @@ +#Copyright (c) Microsoft. All rights reserved. +#Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#this is CMakeLists.txt for buffer_unittests +cmake_minimum_required(VERSION 3.0) + +compileAsC99() +set(theseTestsName buffer_unittests) + +set(${theseTestsName}_cpp_files +${theseTestsName}.cpp +) + +set(${theseTestsName}_c_files +../../src/buffer.c +) + +set(${theseTestsName}_h_files +) + +build_test_artifacts(${theseTestsName} ON) \ No newline at end of file diff --git a/c/sharedutil/tests/buffer_unittests/buffer_unittests.cpp b/c/sharedutil/tests/buffer_unittests/buffer_unittests.cpp new file mode 100644 index 00000000..9a8f1444 --- /dev/null +++ b/c/sharedutil/tests/buffer_unittests/buffer_unittests.cpp @@ -0,0 +1,1025 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// +// PUT NO INCLUDES BEFORE HERE !!!! +// +#include +#ifdef _CRTDBG_MAP_ALLOC +#include +#endif + +#include + +// +// PUT NO CLIENT LIBRARY INCLUDES BEFORE HERE !!!! +// +#include "testrunnerswitcher.h" +#include "buffer_.h" +#include "micromock.h" +#include "lock.h" + +#ifdef _MSC_VER +#pragma warning(disable:4505) +#endif + +#define ALLOCATION_SIZE 16 +#define TOTAL_ALLOCATION_SIZE 32 + +unsigned char BUFFER_TEST_VALUE[] = {0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x10,0x11,0x12,0x13,0x14,0x15,0x16}; +unsigned char ADDITIONAL_BUFFER[] = {0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26}; +unsigned char TOTAL_BUFFER[] = {0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26}; + +static MICROMOCK_MUTEX_HANDLE g_testByTest; +static MICROMOCK_GLOBAL_SEMAPHORE_HANDLE g_dllByDll; + +#define GBALLOC_H + +extern "C" int gballoc_init(void); +extern "C" void gballoc_deinit(void); +extern "C" void* gballoc_malloc(size_t size); +extern "C" void* gballoc_calloc(size_t nmemb, size_t size); +extern "C" void* gballoc_realloc(void* ptr, size_t size); +extern "C" void gballoc_free(void* ptr); + + +namespace BASEIMPLEMENTATION +{ + /*if malloc is defined as gballoc_malloc at this moment, there'd be serious trouble*/ +#define Lock(x) (LOCK_OK + gballocState - gballocState) /*compiler warning about constant in if condition*/ +#define Unlock(x) (LOCK_OK + gballocState - gballocState) +#define Lock_Init() (LOCK_HANDLE)0x42 +#define Lock_Deinit(x) (LOCK_OK + gballocState - gballocState) +#include "gballoc.c" +#undef Lock +#undef Unlock +#undef Lock_Init +#undef Lock_Deinit + +}; + +static size_t currentmalloc_call = 0; +static size_t whenShallmalloc_fail = 0; + +static size_t currentrealloc_call = 0; +static size_t whenShallrealloc_fail = 0; + +TYPED_MOCK_CLASS(CMocks, CGlobalMock) +{ +public: + + MOCK_STATIC_METHOD_1(, void*, gballoc_malloc, size_t, size) + void* result2; + currentmalloc_call++; + if (whenShallmalloc_fail > 0) + { + if (currentmalloc_call == whenShallmalloc_fail) + { + result2 = NULL; + } + else + { + result2 = BASEIMPLEMENTATION::gballoc_malloc(size); + } + } + else + { + result2 = BASEIMPLEMENTATION::gballoc_malloc(size); + } + MOCK_METHOD_END(void*, result2); + + MOCK_STATIC_METHOD_2(, void*, gballoc_realloc, void*, ptr, size_t, size) + void* result2; + currentrealloc_call++; + if (whenShallrealloc_fail > 0) + { + if (currentrealloc_call == whenShallrealloc_fail) + { + result2 = NULL; + } + else + { + result2 = BASEIMPLEMENTATION::gballoc_realloc(ptr, size); + } + } + else + { + result2 = BASEIMPLEMENTATION::gballoc_realloc(ptr, size); + } + MOCK_METHOD_END(void*, result2); + + MOCK_STATIC_METHOD_1(, void, gballoc_free, void*, ptr) + BASEIMPLEMENTATION::gballoc_free(ptr); + MOCK_VOID_METHOD_END() +}; + +DECLARE_GLOBAL_MOCK_METHOD_1(CMocks, , void*, gballoc_malloc, size_t, size); +DECLARE_GLOBAL_MOCK_METHOD_2(CMocks, , void*, gballoc_realloc, void*, ptr, size_t, size); +DECLARE_GLOBAL_MOCK_METHOD_1(CMocks, , void, gballoc_free, void*, ptr); + +BEGIN_TEST_SUITE(Buffer_UnitTests) + + TEST_SUITE_INITIALIZE(setsBufferTempSize) + { + INITIALIZE_MEMORY_DEBUG(g_dllByDll); + g_testByTest = MicroMockCreateMutex(); + ASSERT_IS_NOT_NULL(g_testByTest); + } + + TEST_SUITE_CLEANUP(TestClassCleanup) + { + MicroMockDestroyMutex(g_testByTest); + DEINITIALIZE_MEMORY_DEBUG(g_dllByDll); + } + + TEST_FUNCTION_INITIALIZE(f) + { + if (!MicroMockAcquireMutex(g_testByTest)) + { + ASSERT_FAIL("our mutex is ABANDONED. Failure in test framework"); + } + + currentmalloc_call = 0; + whenShallmalloc_fail = 0; + + currentrealloc_call = 0; + whenShallrealloc_fail = 0; + } + + TEST_FUNCTION_CLEANUP(cleans) + { + if (!MicroMockReleaseMutex(g_testByTest)) + { + ASSERT_FAIL("failure in test framework at ReleaseMutex"); + } + } + + /* Tests_SRS_BUFFER_07_001: [BUFFER_new shall allocate a BUFFER_HANDLE that will contain a NULL unsigned char*.] */ + TEST_FUNCTION(BUFFER_new_Succeed) + { + ///arrange + CMocks mocks; + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(IGNORED_NUM_ARG)) + .IgnoreArgument(1); + + + ///act + BUFFER_HANDLE g_hBuffer = BUFFER_new(); + + ///assert + ASSERT_IS_NOT_NULL(g_hBuffer); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + BUFFER_delete(g_hBuffer); + } + + /* BUFFER_delete Tests BEGIN */ + /* Tests_SRS_BUFFER_07_003: [BUFFER_delete shall delete the data associated with the BUFFER_HANDLE.] */ + TEST_FUNCTION(BUFFER_delete_Succeed) + { + ///arrange + CMocks mocks; + BUFFER_HANDLE g_hBuffer; + g_hBuffer = BUFFER_new(); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + + ///act + BUFFER_delete(g_hBuffer); + + ///assert + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + //none + } + + /* Tests_SRS_BUFFER_07_003: [BUFFER_delete shall delete the data associated with the BUFFER_HANDLE.] */ + TEST_FUNCTION(BUFFER_delete_Alloc_Succeed) + { + ///arrange + CMocks mocks; + BUFFER_HANDLE g_hBuffer; + g_hBuffer = BUFFER_new(); + BUFFER_build(g_hBuffer, BUFFER_TEST_VALUE, ALLOCATION_SIZE); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + + ///act + BUFFER_delete(g_hBuffer); + + ///assert + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + //none + } + + /* Tests_SRS_BUFFER_07_004: [BUFFER_delete shall not delete any BUFFER_HANDLE that is NULL.] */ + TEST_FUNCTION(BUFFER_delete_NULL_HANDLE_Succeed) + { + ///arrange + + ///act + BUFFER_delete(NULL); + + ///assert + } + + /* BUFFER_pre_Build Tests BEGIN */ + /* Tests_SRS_BUFFER_07_005: [BUFFER_pre_build allocates size_t bytes of BUFFER_HANDLE and returns zero on success.] */ + TEST_FUNCTION(BUFFER_pre_build_Succeed) + { + ///arrange + CMocks mocks; + BUFFER_HANDLE g_hBuffer; + g_hBuffer = BUFFER_new(); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(ALLOCATION_SIZE)); + + ///act + int nResult = BUFFER_pre_build(g_hBuffer, ALLOCATION_SIZE); + + ///assert + ASSERT_ARE_EQUAL(int, nResult, 0); + ASSERT_ARE_EQUAL(int, BUFFER_length(g_hBuffer), ALLOCATION_SIZE); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + BUFFER_delete(g_hBuffer); + } + + /* Tests_SRS_BUFFER_07_006: [If handle is NULL or size is 0 then BUFFER_pre_build shall return a nonzero value.] */ + /* Tests_SRS_BUFFER_07_013: [BUFFER_pre_build shall return nonzero if any error is encountered.] */ + TEST_FUNCTION(BUFFER_pre_build_HANDLE_NULL_Fail) + { + ///arrange + CMocks mocks; + + ///act + int nResult = BUFFER_pre_build(NULL, ALLOCATION_SIZE); + + ///assert + ASSERT_ARE_NOT_EQUAL(int, nResult, 0); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + //none + } + + /* Tests_SRS_BUFFER_07_006: [If handle is NULL or size is 0 then BUFFER_pre_build shall return a nonzero value.] */ + TEST_FUNCTION(BUFFER_pre_Size_Zero_Fail) + { + ///arrange + CMocks mocks; + BUFFER_HANDLE g_hBuffer; + g_hBuffer = BUFFER_new(); + mocks.ResetAllCalls(); + + ///act + int nResult = BUFFER_pre_build(g_hBuffer, 0); + + ///assert + ASSERT_ARE_NOT_EQUAL(int, nResult, 0); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + BUFFER_delete(g_hBuffer); + } + + /* Tests_SRS_BUFFER_07_013: [BUFFER_pre_build shall return nonzero if any error is encountered.] */ + TEST_FUNCTION(BUFFER_pre_build_HANDLE_NULL_Size_Zero_Fail) + { + ///arrange + CMocks mocks; + + ///act + int nResult = BUFFER_pre_build(NULL, 0); + + ///assert + ASSERT_ARE_NOT_EQUAL(int, nResult, 0); + } + + /* Tests_SRS_BUFFER_07_007: [BUFFER_pre_build shall return nonzero if the buffer has been previously allocated and is not NULL.] */ + /* Tests_SRS_BUFFER_07_013: [BUFFER_pre_build shall return nonzero if any error is encountered.] */ + TEST_FUNCTION(BUFFER_pre_build_Multiple_Alloc_Fail) + { + ///arrange + CMocks mocks; + BUFFER_HANDLE g_hBuffer; + g_hBuffer = BUFFER_new(); + int nResult = BUFFER_pre_build(g_hBuffer, ALLOCATION_SIZE); + mocks.ResetAllCalls(); + + ///act + nResult = BUFFER_pre_build(g_hBuffer, ALLOCATION_SIZE); + + ///assert + ASSERT_ARE_NOT_EQUAL(int, nResult, 0); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + BUFFER_delete(g_hBuffer); + } + + /* Tests_SRS_BUFFER_07_008: [BUFFER_build allocates size_t bytes, copies the unsigned char* into the buffer and returns zero on success.] */ + TEST_FUNCTION(BUFFER_build_Succeed) + { + ///arrange + CMocks mocks; + BUFFER_HANDLE g_hBuffer; + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(IGNORED_NUM_ARG)) + .IgnoreArgument(1); + + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(IGNORED_PTR_ARG, ALLOCATION_SIZE)) + .IgnoreArgument(1); + + ///act + g_hBuffer = BUFFER_new(); + + int nResult = BUFFER_build(g_hBuffer, BUFFER_TEST_VALUE, ALLOCATION_SIZE); + + ///assert + ASSERT_ARE_EQUAL(int, BUFFER_length(g_hBuffer), ALLOCATION_SIZE); + ASSERT_ARE_EQUAL(int, 0, memcmp(BUFFER_u_char(g_hBuffer), BUFFER_TEST_VALUE, ALLOCATION_SIZE)); + ASSERT_ARE_EQUAL(int, nResult, 0); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + BUFFER_delete(g_hBuffer); + } + + /* Tests_SRS_BUFFER_07_009: [BUFFER_build shall return nonzero if handle is NULL ] */ + TEST_FUNCTION(BUFFER_build_NULL_HANDLE_Fail) + { + ///arrange + CMocks mocks; + + ///act + int nResult = BUFFER_build(NULL, BUFFER_TEST_VALUE, ALLOCATION_SIZE); + + ///assert + ASSERT_ARE_NOT_EQUAL(int, nResult, 0); + } + + /* Tests_SRS_BUFFER_01_001: [If size is positive and source is NULL, BUFFER_build shall return nonzero] */ + TEST_FUNCTION(BUFFER_build_Content_NULL_Fail) + { + ///arrange + CMocks mocks; + BUFFER_HANDLE g_hBuffer; + g_hBuffer = BUFFER_new(); + mocks.ResetAllCalls(); + + ///act + int nResult = BUFFER_build(g_hBuffer, NULL, ALLOCATION_SIZE); + + ///assert + ASSERT_ARE_NOT_EQUAL(int, nResult, 0); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + BUFFER_delete(g_hBuffer); + } + + /* Tests_SRS_BUFFER_01_002: [The size argument can be zero, in which case the underlying buffer held by the buffer instance shall be freed.] */ + TEST_FUNCTION(BUFFER_build_Size_Zero_non_NULL_buffer_Succeeds) + { + ///arrange + CMocks mocks; + BUFFER_HANDLE g_hBuffer; + g_hBuffer = BUFFER_new(); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + + ///act + int nResult = BUFFER_build(g_hBuffer, BUFFER_TEST_VALUE, 0); + + ///assert + ASSERT_ARE_EQUAL(int, nResult, 0); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + BUFFER_delete(g_hBuffer); + } + + /* Tests_SRS_BUFFER_01_002: [The size argument can be zero, in which case the underlying buffer held by the buffer instance shall be freed.] */ + TEST_FUNCTION(BUFFER_build_Size_Zero_NULL_buffer_Succeeds) + { + ///arrange + CMocks mocks; + BUFFER_HANDLE g_hBuffer; + g_hBuffer = BUFFER_new(); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + + ///act + int nResult = BUFFER_build(g_hBuffer, NULL, 0); + + ///assert + ASSERT_ARE_EQUAL(int, nResult, 0); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + BUFFER_delete(g_hBuffer); + } + + /* Tests_SRS_BUFFER_07_011: [BUFFER_build shall overwrite previous contents if the buffer has been previously allocated.] */ + TEST_FUNCTION(BUFFER_build_when_the_buffer_is_already_allocated_and_the_same_amount_of_bytes_is_needed_succeeds) + { + ///arrange + CMocks mocks; + BUFFER_HANDLE g_hBuffer; + g_hBuffer = BUFFER_new(); + int nResult = BUFFER_build(g_hBuffer, BUFFER_TEST_VALUE, ALLOCATION_SIZE); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(IGNORED_PTR_ARG, ALLOCATION_SIZE)) + .IgnoreArgument(1); + + ///act + nResult = BUFFER_build(g_hBuffer, BUFFER_TEST_VALUE, ALLOCATION_SIZE); + + ///assert + ASSERT_ARE_EQUAL(int, nResult, 0); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + BUFFER_delete(g_hBuffer); + } + + /* Tests_SRS_BUFFER_07_011: [BUFFER_build shall overwrite previous contents if the buffer has been previously allocated.] */ + TEST_FUNCTION(BUFFER_build_when_the_buffer_is_already_allocated_and_more_bytes_are_needed_succeeds) + { + ///arrange + CMocks mocks; + BUFFER_HANDLE g_hBuffer; + g_hBuffer = BUFFER_new(); + int nResult = BUFFER_build(g_hBuffer, BUFFER_TEST_VALUE, ALLOCATION_SIZE - 1); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(IGNORED_PTR_ARG, ALLOCATION_SIZE)) + .IgnoreArgument(1); + + ///act + nResult = BUFFER_build(g_hBuffer, BUFFER_TEST_VALUE, ALLOCATION_SIZE); + + ///assert + ASSERT_ARE_EQUAL(int, nResult, 0); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + BUFFER_delete(g_hBuffer); + } + + /* Tests_SRS_BUFFER_07_011: [BUFFER_build shall overwrite previous contents if the buffer has been previously allocated.] */ + TEST_FUNCTION(BUFFER_build_when_the_buffer_is_already_allocated_and_less_bytes_are_needed_succeeds) + { + ///arrange + CMocks mocks; + BUFFER_HANDLE g_hBuffer; + g_hBuffer = BUFFER_new(); + int nResult = BUFFER_build(g_hBuffer, BUFFER_TEST_VALUE, ALLOCATION_SIZE); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(IGNORED_PTR_ARG, ALLOCATION_SIZE - 1)) + .IgnoreArgument(1); + + ///act + nResult = BUFFER_build(g_hBuffer, BUFFER_TEST_VALUE, ALLOCATION_SIZE - 1); + + ///assert + ASSERT_ARE_EQUAL(int, nResult, 0); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + BUFFER_delete(g_hBuffer); + } + + /* BUFFER_unbuild Tests BEGIN */ + /* Tests_SRS_BUFFER_07_012: [BUFFER_unbuild shall clear the underlying unsigned char* data associated with the BUFFER_HANDLE this will return zero on success.] */ + TEST_FUNCTION(BUFFER_unbuild_Succeed) + { + ///arrange + CMocks mocks; + BUFFER_HANDLE g_hBuffer; + g_hBuffer = BUFFER_new(); + int nResult = BUFFER_build(g_hBuffer, BUFFER_TEST_VALUE, ALLOCATION_SIZE); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + + ///act + nResult = BUFFER_unbuild(g_hBuffer); + + ///assert + ASSERT_ARE_EQUAL(int, nResult, 0); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + BUFFER_delete(g_hBuffer); + } + + /* Tests_SRS_BUFFER_07_014: [BUFFER_unbuild shall return a nonzero value if BUFFER_HANDLE is NULL.] */ + TEST_FUNCTION(BUFFER_unbuild_HANDLE_NULL_Fail) + { + ///arrange + CMocks mocks; + + ///act + int nResult = BUFFER_unbuild(NULL); + + ///assert + ASSERT_ARE_NOT_EQUAL(int, nResult, 0); + } + + /* Tests_SRS_BUFFER_07_015: [BUFFER_unbuild shall return a nonzero value if the unsigned char* referenced by BUFFER_HANDLE is NULL.] */ + TEST_FUNCTION(BUFFER_unbuild_Multiple_Alloc_Fail) + { + ///arrange + CMocks mocks; + BUFFER_HANDLE g_hBuffer; + g_hBuffer = BUFFER_new(); + int nResult = BUFFER_build(g_hBuffer, BUFFER_TEST_VALUE, ALLOCATION_SIZE); + nResult = BUFFER_unbuild(g_hBuffer); + mocks.ResetAllCalls(); + + ///act + nResult = BUFFER_unbuild(g_hBuffer); + + ///assert + ASSERT_ARE_NOT_EQUAL(int, nResult, 0); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + BUFFER_delete(g_hBuffer); + } + + /* BUFFER_enlarge Tests BEGIN */ + /* Tests_SRS_BUFFER_07_016: [BUFFER_enlarge shall increase the size of the unsigned char* referenced by BUFFER_HANDLE.] */ + TEST_FUNCTION(BUFFER_enlarge_Succeed) + { + ///arrange + CMocks mocks; + BUFFER_HANDLE g_hBuffer; + g_hBuffer = BUFFER_new(); + int nResult = BUFFER_build(g_hBuffer, BUFFER_TEST_VALUE, ALLOCATION_SIZE); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(IGNORED_PTR_ARG, 2 * ALLOCATION_SIZE)) + .IgnoreArgument(1); + + ///act + nResult = BUFFER_enlarge(g_hBuffer, ALLOCATION_SIZE); + + ///assert + ASSERT_ARE_EQUAL(int, nResult, 0); + ASSERT_ARE_EQUAL(int, TOTAL_ALLOCATION_SIZE, BUFFER_length(g_hBuffer) ); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + BUFFER_delete(g_hBuffer); + } + + /* Tests_SRS_BUFFER_07_017: [BUFFER_enlarge shall return a nonzero result if any parameters are NULL or zero.] */ + /* Tests_SRS_BUFFER_07_018: [BUFFER_enlarge shall return a nonzero result if any error is encountered.] */ + TEST_FUNCTION(BUFFER_enlarge_NULL_HANDLE_Fail) + { + ///arrange + CMocks mocks; + + ///act + int nResult = BUFFER_enlarge(NULL, ALLOCATION_SIZE); + + ///assert + ASSERT_ARE_NOT_EQUAL(int, nResult, 0); + } + + /* Tests_SRS_BUFFER_07_017: [BUFFER_enlarge shall return a nonzero result if any parameters are NULL or zero.] */ + /* Tests_SRS_BUFFER_07_018: [BUFFER_enlarge shall return a nonzero result if any error is encountered.] */ + TEST_FUNCTION(BUFFER_enlarge_Size_Zero_Fail) + { + ///arrange + CMocks mocks; + BUFFER_HANDLE g_hBuffer; + g_hBuffer = BUFFER_new(); + int nResult = BUFFER_build(g_hBuffer, BUFFER_TEST_VALUE, ALLOCATION_SIZE); + mocks.ResetAllCalls(); + + ///act + nResult = BUFFER_enlarge(g_hBuffer, 0); + + ///assert + ASSERT_ARE_NOT_EQUAL(int, nResult, 0); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + BUFFER_delete(g_hBuffer); + } + + /* BUFFER_content Tests BEGIN */ + /* Tests_SRS_BUFFER_07_019: [BUFFER_content shall return the data contained within the BUFFER_HANDLE.] */ + TEST_FUNCTION(BUFFER_content_Succeed) + { + ///arrange + CMocks mocks; + BUFFER_HANDLE g_hBuffer; + g_hBuffer = BUFFER_new(); + int nResult = BUFFER_build(g_hBuffer, BUFFER_TEST_VALUE, ALLOCATION_SIZE); + mocks.ResetAllCalls(); + + ///act + const unsigned char* content = NULL; + nResult = BUFFER_content(g_hBuffer, &content); + + ///assert + ASSERT_ARE_EQUAL(int, nResult, 0); + ASSERT_ARE_EQUAL(int, 0, memcmp(content, BUFFER_TEST_VALUE, ALLOCATION_SIZE)); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + BUFFER_delete(g_hBuffer); + } + + /* Tests_SRS_BUFFER_07_020: [If the handle and/or content*is NULL BUFFER_content shall return nonzero.] */ + TEST_FUNCTION(BUFFER_content_HANDLE_NULL_Fail) + { + ///arrange + CMocks mocks; + + ///act + const unsigned char* content = NULL; + int nResult = BUFFER_content(NULL, &content); + + ///assert + ASSERT_ARE_NOT_EQUAL(int, nResult, 0); + ASSERT_IS_NULL(content); + + ///cleanup + + } + + /* Tests_SRS_BUFFER_07_020: [If the handle and/or content*is NULL BUFFER_content shall return nonzero.] */ + TEST_FUNCTION(BUFFER_content_Char_NULL_Fail) + { + ///arrange + CMocks mocks; + BUFFER_HANDLE g_hBuffer; + g_hBuffer = BUFFER_new(); + int nResult = BUFFER_build(g_hBuffer, BUFFER_TEST_VALUE, ALLOCATION_SIZE); + mocks.ResetAllCalls(); + + ///act + nResult = BUFFER_content(g_hBuffer, NULL); + + ///assert + ASSERT_ARE_NOT_EQUAL(int, nResult, 0); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + BUFFER_delete(g_hBuffer); + } + + /* BUFFER_size Tests BEGIN */ + /* Tests_SRS_BUFFER_07_021: [BUFFER_size shall place the size of the associated buffer in the size variable and return zero on success.] */ + TEST_FUNCTION(BUFFER_size_Succeed) + { + ///arrange + CMocks mocks; + BUFFER_HANDLE g_hBuffer; + g_hBuffer = BUFFER_new(); + int nResult = BUFFER_build(g_hBuffer, BUFFER_TEST_VALUE, ALLOCATION_SIZE); + mocks.ResetAllCalls(); + + ///act + size_t size = 0; + nResult = BUFFER_size(g_hBuffer, &size); + + ///assert + ASSERT_ARE_EQUAL(int, nResult, 0); + ASSERT_ARE_EQUAL(int, size, ALLOCATION_SIZE); + mocks.AssertActualAndExpectedCalls(); + + + ///cleanup + BUFFER_delete(g_hBuffer); + } + + /* Tests_SRS_BUFFER_07_022: [BUFFER_size shall return a nonzero value for any error that is encountered.] */ + TEST_FUNCTION(BUFFER_size_HANDLE_NULL_Fail) + { + ///arrange + CMocks mocks; + + ///act + size_t size = 0; + int nResult = BUFFER_size(NULL, &size); + + ///assert + ASSERT_ARE_NOT_EQUAL(int, nResult, 0); + } + + /* Tests_SRS_BUFFER_07_022: [BUFFER_size shall return a nonzero value for any error that is encountered.] */ + TEST_FUNCTION(BUFFER_size_Size_t_NULL_Fail) + { + ///arrange + CMocks mocks; + BUFFER_HANDLE g_hBuffer; + g_hBuffer = BUFFER_new(); + int nResult = BUFFER_build(g_hBuffer, BUFFER_TEST_VALUE, ALLOCATION_SIZE); + mocks.ResetAllCalls(); + + ///act + nResult = BUFFER_size(g_hBuffer, NULL); + + ///assert + ASSERT_ARE_NOT_EQUAL(int, nResult, 0); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + BUFFER_delete(g_hBuffer); + } + + /* BUFFER_append Tests BEGIN */ + /* Tests_SRS_BUFFER_07_024: [BUFFER_append concatenates b2 onto b1 without modifying b2 and shall return zero on success.] */ + TEST_FUNCTION(BUFFER_append_Succeed) + { + ///arrange + CMocks mocks; + BUFFER_HANDLE g_hBuffer; + g_hBuffer = BUFFER_new(); + int nResult = BUFFER_build(g_hBuffer, BUFFER_TEST_VALUE, ALLOCATION_SIZE); + BUFFER_HANDLE hAppend = BUFFER_new(); + nResult = BUFFER_build(hAppend, ADDITIONAL_BUFFER, ALLOCATION_SIZE); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(IGNORED_PTR_ARG, ALLOCATION_SIZE + ALLOCATION_SIZE)) + .IgnoreArgument(1); + + ///act + nResult = BUFFER_append(g_hBuffer, hAppend); + + ///assert + ASSERT_ARE_EQUAL(int, nResult, 0); + ASSERT_ARE_EQUAL(int, 0, memcmp(BUFFER_u_char(g_hBuffer), TOTAL_BUFFER, TOTAL_ALLOCATION_SIZE)); + ASSERT_ARE_EQUAL(int, 0, memcmp(BUFFER_u_char(hAppend), ADDITIONAL_BUFFER, ALLOCATION_SIZE)); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + BUFFER_delete(hAppend); + BUFFER_delete(g_hBuffer); + } + + /* Tests_SRS_BUFFER_07_023: [BUFFER_append shall return a nonzero upon any error that is encountered.] */ + TEST_FUNCTION(BUFFER_append_HANDLE_NULL_Fail) + { + ///arrange + CMocks mocks; + BUFFER_HANDLE hAppend = BUFFER_new(); + int nResult = BUFFER_build(hAppend, ADDITIONAL_BUFFER, ALLOCATION_SIZE); + mocks.ResetAllCalls(); + + ///act + nResult = BUFFER_append(NULL, hAppend); + + ///assert + ASSERT_ARE_NOT_EQUAL(int, nResult, 0); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + BUFFER_delete(hAppend); + } + + /* Tests_SRS_BUFFER_07_023: [BUFFER_append shall return a nonzero upon any error that is encountered.] */ + TEST_FUNCTION(BUFFER_append_APPEND_HANDLE_NULL_Fail) + { + ///arrange + CMocks mocks; + BUFFER_HANDLE g_hBuffer; + g_hBuffer = BUFFER_new(); + int nResult = BUFFER_build(g_hBuffer, BUFFER_TEST_VALUE, ALLOCATION_SIZE); + mocks.ResetAllCalls(); + + ///act + nResult = BUFFER_append(g_hBuffer, NULL); + + ///assert + ASSERT_ARE_NOT_EQUAL(int, nResult, 0); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + BUFFER_delete(g_hBuffer); + } + + /* BUFFER_u_char Tests BEGIN */ + /* Tests_SRS_BUFFER_07_025: [BUFFER_u_char shall return a pointer to the underlying unsigned char*.] */ + TEST_FUNCTION(BUFFER_U_CHAR_Succeed) + { + ///arrange + CMocks mocks; + BUFFER_HANDLE g_hBuffer; + g_hBuffer = BUFFER_new(); + (void)BUFFER_build(g_hBuffer, BUFFER_TEST_VALUE, ALLOCATION_SIZE); + mocks.ResetAllCalls(); + + ///act + unsigned char* u = BUFFER_u_char(g_hBuffer); + + ///assert + ASSERT_ARE_EQUAL(int, 0, memcmp(u, BUFFER_TEST_VALUE, ALLOCATION_SIZE) ); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + BUFFER_delete(g_hBuffer); + } + + /* Tests_SRS_BUFFER_07_026: [BUFFER_u_char shall return NULL for any error that is encountered.] */ + TEST_FUNCTION(BUFFER_U_CHAR_HANDLE_NULL_Fail) + { + ///arrange + CMocks mocks; + + ///act + ASSERT_IS_NULL(BUFFER_u_char(NULL) ); + } + + /* BUFFER_length Tests BEGIN */ + /* Tests_SRS_BUFFER_07_027: [BUFFER_length shall return the size of the underlying buffer.] */ + TEST_FUNCTION(BUFFER_length_Succeed) + { + ///arrange + CMocks mocks; + BUFFER_HANDLE g_hBuffer; + g_hBuffer = BUFFER_new(); + (void)BUFFER_build(g_hBuffer, BUFFER_TEST_VALUE, ALLOCATION_SIZE); + mocks.ResetAllCalls(); + + ///act + size_t l = BUFFER_length(g_hBuffer); + + ///assert + ASSERT_ARE_EQUAL(size_t, l, ALLOCATION_SIZE); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + BUFFER_delete(g_hBuffer); + } + + /* Tests_SRS_BUFFER_07_028: [BUFFER_length shall return zero for any error that is encountered.] */ + TEST_FUNCTION(BUFFER_length_HANDLE_NULL_Succeed) + { + ///arrange + CMocks mocks; + + ///act + + ///assert + ASSERT_ARE_EQUAL(int, BUFFER_length(NULL), 0); + } + + TEST_FUNCTION(BUFFER_Clone_Succeed) + { + ///arrange + CMocks mocks; + BUFFER_HANDLE g_hBuffer; + g_hBuffer = BUFFER_new(); + (void)BUFFER_build(g_hBuffer, BUFFER_TEST_VALUE, ALLOCATION_SIZE); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(IGNORED_NUM_ARG)) + .IgnoreArgument(1); + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(ALLOCATION_SIZE)) + .IgnoreArgument(1); + + ///act + BUFFER_HANDLE hclone = BUFFER_clone(g_hBuffer); + + ///assert + ASSERT_ARE_EQUAL(int, 0, memcmp(BUFFER_u_char(hclone), BUFFER_TEST_VALUE, ALLOCATION_SIZE) ); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + BUFFER_delete(g_hBuffer); + BUFFER_delete(hclone); + } + + TEST_FUNCTION(BUFFER_Clone_HANDLE_NULL_Fail) + { + ///arrange + CMocks mocks; + + ///act + + ///assert + ASSERT_IS_NULL(BUFFER_clone(NULL) ); + } + + /*Tests_SRS_BUFFER_02_001: [If source is NULL then BUFFER_create shall return NULL.] */ + TEST_FUNCTION(BUFFER_create_with_NULL_source_fails) + { + ///arrange + CMocks mocks; + + ///act + auto res = BUFFER_create(NULL, 0); + + ///assert + ASSERT_IS_NULL(res); + + ///cleanup + } + + /*Tests_SRS_BUFFER_02_002: [Otherwise, BUFFER_create shall allocate memory to hold size bytes and shall copy from source size bytes into the newly allocated memory.] */ + /*Tests_SRS_BUFFER_02_004: [Otherwise, BUFFER_create shall return a non-NULL handle*/ + TEST_FUNCTION(BUFFER_create_happy_path) + { + ///arrange + CMocks mocks; + char c = '3'; + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(IGNORED_NUM_ARG)) + .IgnoreArgument(1); + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(1)); + + ///act + auto res = BUFFER_create((const unsigned char*)&c, 1); + + ///assert + ASSERT_IS_NOT_NULL(res); + size_t howBig = BUFFER_length(res); + ASSERT_ARE_EQUAL(size_t, 1, howBig); + const unsigned char* data = BUFFER_u_char(res); + ASSERT_ARE_EQUAL(uint8_t, '3', data[0]); + + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + BUFFER_delete(res); + } + + /*Tests_SRS_BUFFER_02_003: [If allocating memory fails, then BUFFER_create shall return NULL.] */ + TEST_FUNCTION(BUFFER_create_fails_when_gballoc_fails_1) + { + ///arrange + CMocks mocks; + char c = '3'; + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(IGNORED_NUM_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + + whenShallmalloc_fail = 2; + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(1)); + + ///act + auto res = BUFFER_create((const unsigned char*)&c, 1); + + ///assert + ASSERT_IS_NULL(res); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + BUFFER_delete(res); + } + + /*Tests_SRS_BUFFER_02_003: [If allocating memory fails, then BUFFER_create shall return NULL.] */ + TEST_FUNCTION(BUFFER_create_fails_when_gballoc_fails_2) + { + ///arrange + CMocks mocks; + char c = '3'; + + whenShallmalloc_fail = 1; + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(IGNORED_NUM_ARG)) + .IgnoreArgument(1); + + ///act + auto res = BUFFER_create((const unsigned char*)&c, 1); + + ///assert + ASSERT_IS_NULL(res); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + BUFFER_delete(res); + } + +END_TEST_SUITE(Buffer_UnitTests) \ No newline at end of file diff --git a/c/sharedutil/tests/buffer_unittests/main.c b/c/sharedutil/tests/buffer_unittests/main.c new file mode 100644 index 00000000..fca3a036 --- /dev/null +++ b/c/sharedutil/tests/buffer_unittests/main.c @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include "testrunnerswitcher.h" + +int main(void) +{ + size_t failedTestCount = 0; + RUN_TEST_SUITE(Buffer_UnitTests, failedTestCount); + return (int)failedTestCount; +} diff --git a/c/sharedutil/tests/condition_unittests/CMakeLists.txt b/c/sharedutil/tests/condition_unittests/CMakeLists.txt new file mode 100644 index 00000000..6d7cf973 --- /dev/null +++ b/c/sharedutil/tests/condition_unittests/CMakeLists.txt @@ -0,0 +1,21 @@ +#Copyright (c) Microsoft. All rights reserved. +#Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#this is CMakeLists.txt for condition_unittests +cmake_minimum_required(VERSION 3.0) + +compileAsC99() +set(theseTestsName condition_unittests) + +set(${theseTestsName}_cpp_files +${theseTestsName}.cpp +) + +set(${theseTestsName}_c_files + ${CONDITION_C_FILE} +) + +set(${theseTestsName}_h_files +) + +build_test_artifacts(${theseTestsName} ON) diff --git a/c/sharedutil/tests/condition_unittests/condition_unittests.cpp b/c/sharedutil/tests/condition_unittests/condition_unittests.cpp new file mode 100644 index 00000000..047c131b --- /dev/null +++ b/c/sharedutil/tests/condition_unittests/condition_unittests.cpp @@ -0,0 +1,58 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include +#ifdef _CRTDBG_MAP_ALLOC +#include +#endif + +#include "micromock.h" +#include "testrunnerswitcher.h" +#include "crt_abstractions.h" +#include "condition.h" + +DEFINE_MICROMOCK_ENUM_TO_STRING(COND_RESULT, COND_RESULT_VALUES); + +COND_RESULT Condition_Handle_ToString(COND_HANDLE handle) +{ + COND_RESULT result = COND_OK; + + if (handle == NULL) + { + result = COND_ERROR; + } + + return result; +} + +static MICROMOCK_GLOBAL_SEMAPHORE_HANDLE g_dllByDll; + +BEGIN_TEST_SUITE(Condition_UnitTests) + +TEST_SUITE_INITIALIZE(a) +{ + INITIALIZE_MEMORY_DEBUG(g_dllByDll); +} +TEST_SUITE_CLEANUP(b) +{ + DEINITIALIZE_MEMORY_DEBUG(g_dllByDll); +} + +TEST_FUNCTION(Test_condition_Init_Success) +{ + //arrange + COND_HANDLE handle = NULL; + COND_RESULT result; + + //act + handle = Condition_Init(); + + //assert + ASSERT_IS_NOT_NULL(handle); + + //free + result = Condition_Deinit(handle); + ASSERT_ARE_EQUAL(COND_RESULT, COND_OK, result); +} + +END_TEST_SUITE(Condition_UnitTests); diff --git a/c/sharedutil/tests/condition_unittests/main.c b/c/sharedutil/tests/condition_unittests/main.c new file mode 100644 index 00000000..c5e60a05 --- /dev/null +++ b/c/sharedutil/tests/condition_unittests/main.c @@ -0,0 +1,12 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include "testrunnerswitcher.h" + +int main(void) +{ + + size_t failedTestCount = 0; + RUN_TEST_SUITE(condition_UnitTests, failedTestCount); + return failedTestCount; +} diff --git a/c/sharedutil/tests/crtabstractions_unittests/CMakeLists.txt b/c/sharedutil/tests/crtabstractions_unittests/CMakeLists.txt new file mode 100644 index 00000000..da41a1d3 --- /dev/null +++ b/c/sharedutil/tests/crtabstractions_unittests/CMakeLists.txt @@ -0,0 +1,24 @@ +#Copyright (c) Microsoft. All rights reserved. +#Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#this is CMakeLists.txt for crt_abstractions_unittests +cmake_minimum_required(VERSION 3.0) + +compileAsC99() + +set(theseTestsName crt_abstractions_unittests) + +set(${theseTestsName}_cpp_files +crtabstractions_unittests.cpp +) + +set(${theseTestsName}_c_files +../../src/crt_abstractions.c +../../src/gballoc.c +${LOCK_C_FILE} +) + +set(${theseTestsName}_h_files +) + +build_test_artifacts(${theseTestsName} ON) \ No newline at end of file diff --git a/c/sharedutil/tests/crtabstractions_unittests/crtabstractions_unittests.cpp b/c/sharedutil/tests/crtabstractions_unittests/crtabstractions_unittests.cpp new file mode 100644 index 00000000..cabdddcb --- /dev/null +++ b/c/sharedutil/tests/crtabstractions_unittests/crtabstractions_unittests.cpp @@ -0,0 +1,1122 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include +#ifdef _CRTDBG_MAP_ALLOC +#include +#endif + +#include "testrunnerswitcher.h" +#include "crt_abstractions.h" +#include "errno.h" +#include +#include "micromock.h" + + +#ifdef _MSC_VER +#pragma warning(disable:4505) +#endif + +#if defined _MSC_VER +#include "crtdbg.h" +static _invalid_parameter_handler oldInvalidParameterHandler; +static int oldReportType; + +static void my_invalid_parameter_handler( + const wchar_t * expression, + const wchar_t * function, + const wchar_t * file, + unsigned int line, + uintptr_t pReserved + ) +{ + (void)expression; + (void)function; + (void)file; + (void)line; + (void)pReserved; + /*do nothing*/ +} +/* The below defines are because on Windows platform, the secure version of the CRT functions will invoke WATSON if no invalid parameter handler provided by the user */ +#define HOOK_INVALID_PARAMETER_HANDLER() {oldInvalidParameterHandler = _set_invalid_parameter_handler(my_invalid_parameter_handler);oldReportType=_CrtSetReportMode(_CRT_ASSERT, 0);} +#define UNHOOK_INVALID_PARAMETER_HANDLER() {(void)_CrtSetReportMode(_CRT_ASSERT, oldReportType); (void)_set_invalid_parameter_handler(oldInvalidParameterHandler);} + +#else /* _MSC_VER */ +#define HOOK_INVALID_PARAMETER_HANDLER() do{}while(0) +#define UNHOOK_INVALID_PARAMETER_HANDLER() do{}while(0) +#endif /* _MSC_VER */ + +static const unsigned int interestingUnsignedIntNumbersToBeConverted[] = +{ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 21, + 32, + 43, + 54, + 65, + 76, + 87, + 98, + 123, + 1234, + 12341, + UINT_MAX / 2, + UINT_MAX -1, + UINT_MAX, + 42, + 0x42 +}; + +#ifndef SIZE_MAX +#define SIZE_MAX ((size_t)~(size_t)0) +#endif + +static const size_t interestingSize_tNumbersToBeConverted[] = +{ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 21, + 32, + 43, + 54, + 65, + 76, + 87, + 98, + 123, + 1234, + 12341, + SIZE_MAX / 2, + SIZE_MAX -1, + SIZE_MAX, + 42, + 0x42 +}; + +static MICROMOCK_GLOBAL_SEMAPHORE_HANDLE g_dllByDll; + +BEGIN_TEST_SUITE(CRTAbstractions_UnitTests) + +TEST_SUITE_INITIALIZE(a) +{ + INITIALIZE_MEMORY_DEBUG(g_dllByDll); +} + +TEST_SUITE_CLEANUP(b) +{ + DEINITIALIZE_MEMORY_DEBUG(g_dllByDll); +} + + /* strcat_s */ + + // Tests_SRS_CRT_ABSTRACTIONS_99_008: [strcat_s shall append the src to dst and terminates the resulting string with a null character.] + // Tests_SRS_CRT_ABSTRACTIONS_99_009: [The initial character of src shall overwrite the terminating null character of dst.] + // Tests_SRS_CRT_ABSTRACTIONS_99_003: [strcat_s shall return Zero upon success.] + TEST_FUNCTION(strcat_s_Appends_Source_To_Destination) + { + // arrange + char dstString[128] = "Destination"; + size_t dstSizeInBytes = sizeof(dstString); + char srcString[] = "Source"; + int result; + + // act + result = strcat_s(dstString, dstSizeInBytes, srcString); + + // assert + ASSERT_ARE_EQUAL(char_ptr, "DestinationSource", dstString); + ASSERT_ARE_EQUAL(int, 0, result); + } + + TEST_FUNCTION(strcat_s_Appends_Empty_Source_To_Destination) + { + // arrange + char dstString[128] = "Destination"; + size_t dstSizeInBytes = sizeof(dstString); + char srcString[] = ""; + int result; + + // act + result = strcat_s(dstString, dstSizeInBytes, srcString); + + // assert + ASSERT_ARE_EQUAL(char_ptr, "Destination", dstString); + ASSERT_ARE_EQUAL(int, 0, result); + } + + TEST_FUNCTION(strcat_s_Appends_Source_To_Empty_Destination) + { + // arrange + char dstString[128] = ""; + size_t dstSizeInBytes = sizeof(dstString); + char srcString[] = "Source"; + int result; + + // act + result = strcat_s(dstString, dstSizeInBytes, srcString); + + // assert + ASSERT_ARE_EQUAL(char_ptr, "Source", dstString); + ASSERT_ARE_EQUAL(int, 0, result); + } + + TEST_FUNCTION(strcat_s_Appends_Empty_Source_To_Empty_Destination) + { + // arrange + char dstString[128] = ""; + size_t dstSizeInBytes = sizeof(dstString); + char srcString[] = ""; + int result; + + // act + result = strcat_s(dstString, dstSizeInBytes, srcString); + + // assert + ASSERT_ARE_EQUAL(char_ptr, "", dstString); + ASSERT_ARE_EQUAL(int, 0, result); + } + + // Tests_SRS_CRT_ABSTRACTIONS_99_004: [If dst is NULL or unterminated, the error code returned shall be EINVAL & dst shall not be modified.] + TEST_FUNCTION(strcat_s_With_NULL_Destination_Fails) + { + // arrange + char* dstString = NULL; + size_t sizeInBytes = sizeof(dstString); + char srcString[] = "Source"; + int result; + + // act + HOOK_INVALID_PARAMETER_HANDLER(); +#ifdef _MSC_VER +#pragma warning(suppress: 6387) /* This is test code, explictly calling with NULL argument */ +#endif + result = strcat_s(dstString, sizeInBytes, srcString); + UNHOOK_INVALID_PARAMETER_HANDLER(); + + // assert + ASSERT_IS_NULL(dstString); + ASSERT_ARE_EQUAL(int, EINVAL, result); + } + + TEST_FUNCTION(strcat_s_With_Unterminated_Destination_Fails) + { + // arrange + char dstString[128]; + size_t dstSizeInBytes = sizeof(dstString); + char srcString[] = "Source"; + int result; + for (size_t i = 0; i < dstSizeInBytes; i++) + { + dstString[i] = 'z'; + } + + // act + HOOK_INVALID_PARAMETER_HANDLER(); + result = strcat_s(dstString, dstSizeInBytes, srcString); + UNHOOK_INVALID_PARAMETER_HANDLER(); + + // assert +#ifndef _MSC_VER /* MSDN claims that content of destination buffer is not modified, but that is not true. Filing bug. */ + for (size_t i = 0; i < dstSizeInBytes; i++) + { + ASSERT_ARE_EQUAL(char, 'z', dstString[i]); + } +#endif + ASSERT_ARE_EQUAL(int, EINVAL, result); + } + + // Tests_SRS_CRT_ABSTRACTIONS_99_005: [If src is NULL, the error code returned shall be EINVAL and dst[0] shall be set to 0.] + TEST_FUNCTION(strcat_s_With_NULL_Source_Fails) + { + // arrange + char dstString[128] = "Source"; + size_t dstSizeInBytes = sizeof(dstString); + char* srcString = NULL; + int result; + + // act + HOOK_INVALID_PARAMETER_HANDLER(); +#ifdef _MSC_VER +#pragma warning(suppress: 6387) /* This is test code, explictly calling with NULL argument */ +#endif + result = strcat_s(dstString, dstSizeInBytes, srcString); + UNHOOK_INVALID_PARAMETER_HANDLER(); + + // assert + ASSERT_ARE_EQUAL(char,'\0', dstString[0]); + ASSERT_ARE_EQUAL(int, EINVAL, result); + } + + // Tests_SRS_CRT_ABSTRACTIONS_99_006: [If the dstSizeInBytes is 0 or smaller than the required size for dst & src, the error code returned shall be ERANGE & dst[0] set to 0.] + TEST_FUNCTION(strcat_s_With_dstSizeInBytes_Equals_Zero_Fails) + { + // arrange + char dstString[128] = "Destination"; + size_t dstSizeInBytes = sizeof(dstString); + char srcString[] = "Source"; + int result; + + // act + dstSizeInBytes = 0; + HOOK_INVALID_PARAMETER_HANDLER(); + result = strcat_s(dstString, dstSizeInBytes, srcString); + UNHOOK_INVALID_PARAMETER_HANDLER(); + + // assert +#ifdef _MSC_VER /*MSDN Claims that destination buffer would be set to empty & ERANGE is the error, but not the case. Filing bug.*/ + ASSERT_ARE_EQUAL(char_ptr, "Destination", dstString); + ASSERT_ARE_EQUAL(int, EINVAL, result); +#else + ASSERT_ARE_EQUAL(char, '\0', dstString[0]); + ASSERT_ARE_EQUAL(int, ERANGE, result); +#endif + } + + TEST_FUNCTION(strcat_s_With_dstSizeInBytes_Smaller_Than_dst_and_src_Fails) + { + // arrange + char dstString[128] = "Destination"; + size_t dstSizeInBytes = sizeof(dstString); + char srcString[] = "Source"; + int result; + + // act + HOOK_INVALID_PARAMETER_HANDLER(); + dstSizeInBytes = strlen(dstString) + (strlen(srcString) - 3); + result = strcat_s(dstString, dstSizeInBytes, srcString); + UNHOOK_INVALID_PARAMETER_HANDLER(); + + // assert + ASSERT_ARE_EQUAL(char,'\0', dstString[0]); + ASSERT_ARE_EQUAL(int, ERANGE, result); + } + + /* strcpy_s */ + + // Tests_SRS_CRT_ABSTRACTIONS_99_016: [strcpy_s shall copy the contents in the address of src, including the terminating null character, to the location that's specified by dst.] + // Tests_SRS_CRT_ABSTRACTIONS_99_011 : [strcpy_s shall return Zero upon success] + TEST_FUNCTION(strcpy_s_copies_Source_into_Destination) + { + // arrange + char dstString[128] = "Destination"; + size_t dstSizeInBytes = sizeof(dstString); + char srcString[] = "Source"; + int result = 0; + + // act + result = strcpy_s(dstString, dstSizeInBytes, srcString); + + // assert + ASSERT_ARE_EQUAL(char_ptr, "Source", dstString); + ASSERT_ARE_EQUAL(int, 0, result); + } + + TEST_FUNCTION(strcpy_s_copies_Empty_Source_into_Destination) + { + // arrange + char dstString[128] = "Destination"; + size_t dstSizeInBytes = sizeof(dstString); + char srcString[] = ""; + int result = 0; + + // act + result = strcpy_s(dstString, dstSizeInBytes, srcString); + + // assert + ASSERT_ARE_EQUAL(char_ptr, "", dstString); + ASSERT_ARE_EQUAL(int, 0, result); + } + + TEST_FUNCTION(strcpy_s_copies_Source_into_Empty_Destination) + { + // arrange + char dstString[128] = ""; + size_t dstSizeInBytes = sizeof(dstString); + char srcString[] = "Source"; + int result = 0; + + // act + result = strcpy_s(dstString, dstSizeInBytes, srcString); + + // assert + ASSERT_ARE_EQUAL(char_ptr, "Source", dstString); + ASSERT_ARE_EQUAL(int, 0, result); + } + + TEST_FUNCTION(strcpy_s_copies_Empty_Source_into_Empty_Destination) + { + // arrange + char dstString[128] = ""; + size_t dstSizeInBytes = sizeof(dstString); + char srcString[] = ""; + int result = 0; + + // act + result = strcpy_s(dstString, dstSizeInBytes, srcString); + + // assert + ASSERT_ARE_EQUAL(char_ptr, "", dstString); + ASSERT_ARE_EQUAL(int, 0, result); + } + + // Tests_SRS_CRT_ABSTRACTIONS_99_012 : [If dst is NULL, the error code returned shall be EINVAL & dst shall not be modified.] + TEST_FUNCTION(strcpy_s_With_NULL_Destination_Fails) + { + // arrange + char* dstString = NULL; + size_t dstSizeInBytes = sizeof(dstString); + char srcString[] = "Source"; + int result = 0; + + // act + HOOK_INVALID_PARAMETER_HANDLER(); +#ifdef _MSC_VER +#pragma warning(suppress: 6387) /* This is test code, explictly calling with NULL argument */ +#endif + result = strcpy_s(dstString, dstSizeInBytes, srcString); + UNHOOK_INVALID_PARAMETER_HANDLER(); + + // assert + ASSERT_ARE_EQUAL(char_ptr, NULL, dstString); + ASSERT_ARE_EQUAL(int, EINVAL, result); + } + + // Tests_SRS_CRT_ABSTRACTIONS_99_013 : [If src is NULL, the error code returned shall be EINVAL and dst[0] shall be set to 0.] + TEST_FUNCTION(strcpy_s_With_NULL_Source_Fails) + { + // arrange + char dstString[128] = "Destination"; + size_t dstSizeInBytes = sizeof(dstString); + char* srcString = NULL; + int result = 0; + + // act + HOOK_INVALID_PARAMETER_HANDLER(); +#ifdef _MSC_VER +#pragma warning(suppress: 6387) /* This is test code, explictly calling with NULL argument */ +#endif + result = strcpy_s(dstString, dstSizeInBytes, srcString); + UNHOOK_INVALID_PARAMETER_HANDLER(); + + // assert + ASSERT_ARE_EQUAL(char,'\0', dstString[0]); + ASSERT_ARE_EQUAL(int, EINVAL, result); + } + + // Tests_SRS_CRT_ABSTRACTIONS_99_014 : [If the dstSizeInBytes is 0 or smaller than the required size for the src string, the error code returned shall be ERANGE & dst[0] set to 0.] + TEST_FUNCTION(strcpy_s_With_dstSizeInBytes_Equals_Zero_Fails) + { + // arrange + char dstString[128] = "Destination"; + size_t dstSizeInBytes = sizeof(dstString); + char srcString[] = "Source"; + int result; + + // act + dstSizeInBytes = 0; + HOOK_INVALID_PARAMETER_HANDLER(); + result = strcpy_s(dstString, dstSizeInBytes, srcString); + UNHOOK_INVALID_PARAMETER_HANDLER(); + + // assert +#ifdef _MSC_VER /*MSDN Claims that destination buffer would be set to empty & ERANGE is the error, but not the case. Filing bug.*/ + ASSERT_ARE_EQUAL(char_ptr, "Destination", dstString); + ASSERT_ARE_EQUAL(int, EINVAL, result); +#else + ASSERT_ARE_EQUAL(char, '\0', dstString[0]); + ASSERT_ARE_EQUAL(int, ERANGE, result); +#endif + } + + TEST_FUNCTION(strcpy_s_With_dstSizeInBytes_Smaller_Than_source_Fails) + { + // arrange + char dstString[128] = "Destination"; + size_t dstSizeInBytes = sizeof(dstString); + char srcString[] = "Source"; + int result; + + // act + HOOK_INVALID_PARAMETER_HANDLER(); + dstSizeInBytes = sizeof(srcString) - 2; + result = strcpy_s(dstString, dstSizeInBytes, srcString); + UNHOOK_INVALID_PARAMETER_HANDLER(); + + // assert + ASSERT_ARE_EQUAL(char,'\0', dstString[0]); + ASSERT_ARE_EQUAL(int, ERANGE, result); + } + + /* strncpy_s */ + + // Tests_SRS_CRT_ABSTRACTIONS_99_025 : [strncpy_s shall copy the first N characters of src to dst, where N is the lesser of MaxCount and the length of src.] + // Tests_SRS_CRT_ABSTRACTIONS_99_041 : [If those N characters will fit within dst(whose size is given as dstSizeInBytes) and still leave room for a null terminator, then those characters shall be copied and a terminating null is appended; otherwise, strDest[0] is set to the null character and ERANGE error code returned per requirement below.] + // Tests_SRS_CRT_ABSTRACTIONS_99_018: [strncpy_s shall return Zero upon success] + TEST_FUNCTION(strncpy_s_copies_N_chars_of_source_to_destination_where_maxCount_equals_source_Length) + { + // arrange + char dstString[] = "Destination"; + size_t dstSizeInBytes = sizeof(dstString); + char srcString[] = "Source"; + size_t maxCount = sizeof(srcString); + int result; + + // act + result = strncpy_s(dstString, dstSizeInBytes, srcString, maxCount); + + // assert + ASSERT_ARE_EQUAL(char_ptr, "Source", dstString); + ASSERT_ARE_EQUAL(int, 0, result); + } + + TEST_FUNCTION(strncpy_s_copies_N_chars_of_source_to_destination_where_maxCount_is_larger_than_Source_Length) + { + // arrange + char dstString[] = "Destination"; + size_t dstSizeInBytes = sizeof(dstString); + char srcString[] = "Source"; + size_t maxCount = sizeof(srcString); + int result; + + // act + result = strncpy_s(dstString, dstSizeInBytes, srcString, maxCount+5); + + // assert + ASSERT_ARE_EQUAL(char_ptr, "Source", dstString); + ASSERT_ARE_EQUAL(int, 0, result); + } + + TEST_FUNCTION(strncpy_s_copies_N_chars_of_source_to_destination_where_maxCount_is_less_than_source_length) + { + // arrange + char dstString[] = "Destination"; + size_t dstSizeInBytes = sizeof(dstString); + char srcString[] = "Source"; + size_t maxCount = sizeof(srcString); + int result; + + // act + result = strncpy_s(dstString, dstSizeInBytes, srcString, maxCount - 3); + + // assert + ASSERT_ARE_EQUAL(char_ptr, "Sour", dstString); + ASSERT_ARE_EQUAL(int, 0, result); + } + + // Tests_SRS_CRT_ABSTRACTIONS_99_026 : [If MaxCount is _TRUNCATE(defined as - 1), then as much of src as will fit into dst shall be copied while still leaving room for the terminating null to be appended.] + TEST_FUNCTION(strncpy_s_with_maxCount_set_to_TRUNCATE_and_destination_fits_source) + { + // arrange + char dstString[] = "Destination"; + size_t dstSizeInBytes = sizeof(dstString); + char srcString[] = "Source"; + size_t maxCount = sizeof(srcString); + int result; + + // act + maxCount = _TRUNCATE; + result = strncpy_s(dstString, dstSizeInBytes, srcString, maxCount); + + // assert + ASSERT_ARE_EQUAL(char_ptr, "Source", dstString); + ASSERT_ARE_EQUAL(int, 0, result); + } + + // Tests_SRS_CRT_ABSTRACTIONS_99_026 : [If MaxCount is _TRUNCATE(defined as - 1), then as much of src as will fit into dst shall be copied while still leaving room for the terminating null to be appended.] + // Tests_SRS_CRT_ABSTRACTIONS_99_019: [If truncation occurred as a result of the copy, the error code returned shall be STRUNCATE .] + TEST_FUNCTION(strncpy_s_with_maxCount_set_to_TRUNCATE_and_destination_is_smaller_than_source) + { + // arrange + char dstString[] = "Dest"; + size_t dstSizeInBytes = sizeof(dstString); + char srcString[] = "Source"; + size_t maxCount = sizeof(srcString); + int result; + + // act + maxCount = _TRUNCATE; + result = strncpy_s(dstString, dstSizeInBytes, srcString, maxCount); + + // assert + ASSERT_ARE_EQUAL(char_ptr, "Sour", dstString); + ASSERT_ARE_EQUAL(int, STRUNCATE, result); + } + + // Tests_SRS_CRT_ABSTRACTIONS_99_020 : [If dst is NULL, the error code returned shall be EINVAL and dst shall not be modified.] + TEST_FUNCTION(strncpy_s_fails_with_destination_set_to_NULL) + { + // arrange + char* dstString = NULL; + size_t dstSizeInBytes = sizeof(dstString); + char srcString[] = "Source"; + size_t maxCount = sizeof(srcString); + int result; + + // act + HOOK_INVALID_PARAMETER_HANDLER(); +#ifdef _MSC_VER +#pragma warning(suppress: 6387) /* This is test code, explictly calling with NULL argument */ +#endif + result = strncpy_s(dstString, dstSizeInBytes, srcString, maxCount); + UNHOOK_INVALID_PARAMETER_HANDLER(); + + // assert + ASSERT_IS_NULL(dstString); + ASSERT_ARE_EQUAL(int, EINVAL, result); + } + + // Tests_SRS_CRT_ABSTRACTIONS_99_021: [If src is NULL, the error code returned shall be EINVAL and dst[0] shall be set to 0.] + TEST_FUNCTION(strncpy_s_fails_with_source_set_to_NULL) + { + // arrange + char dstString[] = "Destination"; + size_t dstSizeInBytes = sizeof(dstString); + char* srcString = NULL; + size_t maxCount = sizeof(srcString); + int result; + + // act + HOOK_INVALID_PARAMETER_HANDLER(); +#ifdef _MSC_VER +#pragma warning(suppress: 6387) /* This is test code, explictly calling with NULL argument */ +#endif + result = strncpy_s(dstString, dstSizeInBytes, srcString, maxCount); + UNHOOK_INVALID_PARAMETER_HANDLER(); + + // assert + ASSERT_ARE_EQUAL(char,'\0', dstString[0]); + ASSERT_ARE_EQUAL(int, EINVAL, result); + } + + // Tests_SRS_CRT_ABSTRACTIONS_99_022: [If the dstSizeInBytes is 0, the error code returned shall be EINVAL and dst shall not be modified.] + TEST_FUNCTION(strncpy_s_fails_with_dstSizeInBytes_set_to_Zero) + { + // arrange + char dstString[] = "Destination"; + size_t dstSizeInBytes = sizeof(dstString); + char srcString[] = "Source"; + size_t maxCount = sizeof(srcString); + int result; + + // act + HOOK_INVALID_PARAMETER_HANDLER(); + dstSizeInBytes = 0; + result = strncpy_s(dstString, dstSizeInBytes, srcString, maxCount); + UNHOOK_INVALID_PARAMETER_HANDLER(); + + // assert + ASSERT_ARE_EQUAL(char_ptr, "Destination", dstString); + ASSERT_ARE_EQUAL(int, EINVAL, result); + } + + // Tests_SRS_CRT_ABSTRACTIONS_99_023 : [If dst is not NULL & dstSizeInBytes is smaller than the required size for the src string, the error code returned shall be ERANGE and dst[0] shall be set to 0.] + TEST_FUNCTION(strncpy_s_dstSizeInBytes_is_smaller_than_the_required_size_for_source) + { + // arrange + char dstString[] = "Dest"; + size_t dstSizeInBytes = sizeof(dstString); + char srcString[] = "Source"; + size_t maxCount = sizeof(srcString); + int result; + + // act + HOOK_INVALID_PARAMETER_HANDLER(); + result = strncpy_s(dstString, dstSizeInBytes, srcString, maxCount); + UNHOOK_INVALID_PARAMETER_HANDLER(); + + // assert + ASSERT_ARE_EQUAL(char,'\0', dstString[0]); + ASSERT_ARE_EQUAL(int, ERANGE, result); + } + + /* sprintf_s */ + + // Tests_SRS_CRT_ABSTRACTIONS_99_029: [The sprintf_s function shall format and store series of characters and values in dst.Each argument(if any) is converted and output according to the corresponding Format Specification in the format variable.] + // Tests_SRS_CRT_ABSTRACTIONS_99_031: [A null character is appended after the last character written.] + // Tests_SRS_CRT_ABSTRACTIONS_99_027: [sprintf_s shall return the number of characters stored in dst upon success. This number shall not include the terminating null character.] + TEST_FUNCTION(sprintf_s_formats_and_stores_chars_and_values_in_destination) + { + // arrange + char dstString[1024]; + size_t dstSizeInBytes = sizeof(dstString); + char expectedString[] = "sprintf_s: 123, hello, Z, 1.5"; + int expectedStringSize = (int)(sizeof(expectedString)); + int result; + + // act + result = sprintf_s(dstString, dstSizeInBytes, "sprintf_s: %d, %s, %c, %3.1f", 123, "hello", 'Z', 1.5f); + + // assert + ASSERT_ARE_EQUAL(char_ptr, expectedString, dstString); + ASSERT_ARE_EQUAL(int, expectedStringSize-1, result); + } + + // Tests_SRS_CRT_ABSTRACTIONS_99_028: [If dst or format is a null pointer, sprintf_s shall return -1.] + TEST_FUNCTION(sprintf_s_fails_with_dst_set_to_null) + { + // arrange + char* dstString = NULL; + size_t dstSizeInBytes = sizeof(dstString); + int result; + + // act + HOOK_INVALID_PARAMETER_HANDLER(); +#ifdef _MSC_VER +#pragma warning(suppress: 6387) /* This is test code, explictly calling with NULL argument */ +#endif + result = sprintf_s(dstString, dstSizeInBytes, "sprintf_s: %d, %s, %c, %3.1f", 123, "hello", 'Z', 1.5f); + UNHOOK_INVALID_PARAMETER_HANDLER(); + + // assert + ASSERT_ARE_EQUAL(int, -1, result); + ASSERT_ARE_EQUAL(int, EINVAL, errno); + } + + TEST_FUNCTION(sprintf_s_fails_with_format_set_to_null) + { + // arrange + char dstString[1024]; + size_t dstSizeInBytes = sizeof(dstString); + int result; + + // act + HOOK_INVALID_PARAMETER_HANDLER(); +#ifdef _MSC_VER +#pragma warning(suppress: 6387) /* This is test code, explictly calling with NULL argument */ +#endif + result = sprintf_s(dstString, dstSizeInBytes, NULL); + UNHOOK_INVALID_PARAMETER_HANDLER(); + + // assert + ASSERT_ARE_EQUAL(int, -1, result); + ASSERT_ARE_EQUAL(int, EINVAL, errno); + } + + // Tests_SRS_CRT_ABSTRACTIONS_99_034 : [If the dst buffer is too small for the text being printed, then dst is set to an empty string and the function shall return -1.] + TEST_FUNCTION(sprintf_s_fails_with_dst_too_small) + { + // arrange + char dstString[5]; + size_t dstSizeInBytes = sizeof(dstString); + int result; + + // act + HOOK_INVALID_PARAMETER_HANDLER(); + result = sprintf_s(dstString, dstSizeInBytes, "sprintf_s: %d, %s, %c, %3.1f", 123, "hello", 'Z', 1.5f); + UNHOOK_INVALID_PARAMETER_HANDLER(); + + // assert + ASSERT_ARE_EQUAL(char_ptr, "", dstString); + ASSERT_ARE_EQUAL(int, -1, result); + } + + TEST_FUNCTION(sprintf_s_fails_with_dst_buffer_size_not_fitting_null_char) + { + // arrange + char dstString[5]; + size_t dstSizeInBytes = sizeof(dstString); + int result; + + // act + HOOK_INVALID_PARAMETER_HANDLER(); + result = sprintf_s(dstString, dstSizeInBytes, "12345"); + UNHOOK_INVALID_PARAMETER_HANDLER(); + + // assert + ASSERT_ARE_EQUAL(char_ptr, "", dstString); + ASSERT_ARE_EQUAL(int, -1, result); + } + + /* mallocAndStrcpy_s */ + + // Tests_SRS_CRT_ABSTRACTIONS_99_038 : [mallocAndstrcpy_s shall allocate memory for destination buffer to fit the string in the source parameter.] + // Tests_SRS_CRT_ABSTRACTIONS_99_039 : [mallocAndstrcpy_s shall copy the contents in the address source, including the terminating null character into location specified by the destination pointer after the memory allocation.] + // Tests_SRS_CRT_ABSTRACTIONS_99_035: [mallocAndstrcpy_s shall return Zero upon success] + TEST_FUNCTION(mallocAndStrcpy_s_copies_source_string_into_allocated_memory) + { + // arrange + char* destString = NULL; + char srcString[] = "Source"; + int result; + + // act + result = mallocAndStrcpy_s(&destString, srcString); + + // assert + ASSERT_ARE_EQUAL(char_ptr, destString, srcString); + ASSERT_ARE_EQUAL(int, 0, result); + + ///cleanup + free(destString); + } + + // Tests_SRS_CRT_ABSTRACTIONS_99_036: [destination parameter or source parameter is NULL, the error code returned shall be EINVAL and destination shall not be modified.] + TEST_FUNCTION(mallocAndStrcpy_s_fails_with_destination_pointer_set_to_null) + { + // arrange + char** destPointer = NULL; + char srcString[] = "Source"; + int result; + + // act + result = mallocAndStrcpy_s(destPointer, srcString); + + // assert + ASSERT_ARE_EQUAL(int, EINVAL, result); + } + + TEST_FUNCTION(mallocAndStrcpy_s_fails_with_source_set_to_null) + { + // arrange + char* destString = (char*)("Destination"); + char* srcString = NULL; + int result; + + // act + result = mallocAndStrcpy_s(&destString, srcString); + + // assert + ASSERT_ARE_EQUAL(char_ptr, "Destination", destString); + ASSERT_ARE_EQUAL(int, EINVAL, result); + } + + /*http://vstfrd:8080/Azure/RD/_workitems/edit/3216760*/ +#if 0 + // Tests_SRS_CRT_ABSTRACTIONS_99_037: [Upon failure to allocate memory for the destination, the function will return ENOMEM.] + TEST_FUNCTION(mallocAndStrcpy_s_fails_upon_failure_to_allocate_memory) + { + // arrange + char* destString = NULL; + char* srcString = "Source"; + int result; + mallocSize = 0; + + // act +#ifdef _CRTDBG_MAP_ALLOC + HOOK_FUNCTION(_malloc_dbg, malloc_null); + result = mallocAndStrcpy_s(&destString, srcString); + UNHOOK_FUNCTION(_malloc_dbg, malloc_null); +#else + HOOK_FUNCTION(malloc, malloc_null); + result = mallocAndStrcpy_s(&destString, srcString); + UNHOOK_FUNCTION(malloc, malloc_null); +#endif + + // assert + ASSERT_ARE_EQUAL(int, ENOMEM, result); + ASSERT_ARE_EQUAL(size_t,strlen(srcString)+1, mallocSize); + } +#endif + + /*Tests_SRS_CRT_ABSTRACTIONS_02_003: [If destination is NULL then unsignedIntToString shall fail.] */ + TEST_FUNCTION(unsignedIntToString_fails_when_destination_is_NULL) + { + // arrange + + // act + auto result = unsignedIntToString(NULL, 100, 43); + + // assert + ASSERT_ARE_NOT_EQUAL(int, 0, result); + } + + /*Tests_SRS_CRT_ABSTRACTIONS_02_002: [If the conversion fails for any reason (for example, insufficient buffer space), a non-zero return value shall be supplied and unsignedIntToString shall fail.] */ + TEST_FUNCTION(unsignedIntToString_fails_when_destination_is_not_sufficient_for_1_digit) + { + // arrange + char destination[1000]; + unsigned int toBeConverted = 1; + size_t destinationSize = 1; + + ///act + int result = unsignedIntToString(destination, destinationSize, toBeConverted); + + ///assert + ASSERT_ARE_NOT_EQUAL(int, 0, result); + + } + + /*Tests_SRS_CRT_ABSTRACTIONS_02_002: [If the conversion fails for any reason (for example, insufficient buffer space), a non-zero return value shall be supplied and unsignedIntToString shall fail.] */ + TEST_FUNCTION(unsignedIntToString_fails_when_destination_is_not_sufficient_for_more_than_1_digit) + { + // arrange + char destination[1000]; + unsigned int toBeConverted = 1; /*7 would not be a right starting digit*/ + size_t destinationSize = 1; + while (toBeConverted <= (UINT_MAX / 10)) + { + ///arrange + destinationSize++; + toBeConverted *= 10; + + ///act + int result = unsignedIntToString(destination, destinationSize, toBeConverted); + + ///assert + ASSERT_ARE_NOT_EQUAL(int, 0, result); + } + } + + /*Tests_SRS_CRT_ABSTRACTIONS_02_001: [unsignedIntToString shall convert the parameter value to its decimal representation as a string in the buffer indicated by parameter destination having the size indicated by parameter destinationSize.] */ + TEST_FUNCTION(unsignedIntToString_succeeds_1_digit) + { + // arrange + char destination[1000]; + unsigned int toBeConverted = 2; + size_t destinationSize = 2; + + ///act + int result = unsignedIntToString(destination, destinationSize, toBeConverted); + + ///assert + ASSERT_ARE_EQUAL(int, 0, result); + ASSERT_ARE_EQUAL(char_ptr, "2", destination); + + } + + /*Tests_SRS_CRT_ABSTRACTIONS_02_001: [unsignedIntToString shall convert the parameter value to its decimal representation as a string in the buffer indicated by parameter destination having the size indicated by parameter destinationSize.] */ + /*Tests_SRS_CRT_ABSTRACTIONS_02_004: [If the conversion has been successfull then unsignedIntToString shall return 0.] */ + TEST_FUNCTION(unsignedIntToString_succeeds_for_interesting_numbers) + { + // arrange + char destination[1000]; + size_t i; + for (i = 0; i (UINT_MAX / 10)) + { + ASSERT_FAIL("string produced was too big... "); + } + else + { + valueFromString *= 10; + valueFromString += (destination[pos] - '0'); + } + pos++; + } + if (interestingUnsignedIntNumbersToBeConverted[i] != valueFromString) + { + ASSERT_FAIL("unexpected value"); + } + } + } + + /*Tests_SRS_CRT_ABSTRACTIONS_02_001: [unsignedIntToString shall convert the parameter value to its decimal representation as a string in the buffer indicated by parameter destination having the size indicated by parameter destinationSize.] */ + /*Tests_SRS_CRT_ABSTRACTIONS_02_004: [If the conversion has been successfull then unsignedIntToString shall return 0.] */ + TEST_FUNCTION(unsignedIntToString_succeeds_for_space_just_about_right) + { + // arrange + char destination[1000]; + unsigned int toBeConverted = 1; /*7 would not be a right starting digit*/ + size_t destinationSize = 2; + while (toBeConverted <= (UINT_MAX / 10)) + { + ///arrange + destinationSize++; + toBeConverted *= 10; + + ///act + int result = unsignedIntToString(destination, destinationSize, toBeConverted); + + ///assert + ASSERT_ARE_EQUAL(int, 0, result); + + unsigned int valueFromString = 0; + size_t pos = 0; + while (destination[pos] != '\0') + { + if (valueFromString > (UINT_MAX / 10)) + { + ASSERT_FAIL("string produced was too big... "); + } + else + { + valueFromString *= 10; + valueFromString += (destination[pos] - '0'); + } + pos++; + } + if (toBeConverted != valueFromString) + { + ASSERT_FAIL("unexpected value"); + } + } + } + + + /*Tests_SRS_CRT_ABSTRACTIONS_02_007: [If destination is NULL then size_tToString shall fail.] */ + TEST_FUNCTION(size_tToString_fails_when_destination_is_NULL) + { + // arrange + + // act + auto result = size_tToString(NULL, 100, 43); + + // assert + ASSERT_ARE_NOT_EQUAL(int, 0, result); + } + + /*Tests_SRS_CRT_ABSTRACTIONS_02_006: [If the conversion fails for any reason (for example, insufficient buffer space), a non-zero return value shall be supplied and size_tToString shall fail.] */ + TEST_FUNCTION(size_tToString_fails_when_destination_is_not_sufficient_for_1_digit) + { + // arrange + char destination[1000]; + size_t toBeConverted = 1; + size_t destinationSize = 1; + + ///act + int result = size_tToString(destination, destinationSize, toBeConverted); + + ///assert + ASSERT_ARE_NOT_EQUAL(int, 0, result); + + } + + /*Tests_SRS_CRT_ABSTRACTIONS_02_006: [If the conversion fails for any reason (for example, insufficient buffer space), a non-zero return value shall be supplied and size_tToString shall fail.] */ + TEST_FUNCTION(size_tToString_fails_when_destination_is_not_sufficient_for_more_than_1_digit) + { + // arrange + char destination[1000]; + size_t toBeConverted = 1; /*7 would not be a right starting digit*/ + size_t destinationSize = 1; + while (toBeConverted <= (UINT_MAX / 10)) + { + ///arrange + destinationSize++; + toBeConverted *= 10; + + ///act + int result = size_tToString(destination, destinationSize, toBeConverted); + + ///assert + ASSERT_ARE_NOT_EQUAL(int, 0, result); + } + } + + /*Tests_SRS_CRT_ABSTRACTIONS_02_001: [size_tToString shall convert the parameter value to its decimal representation as a string in the buffer indicated by parameter destination having the size indicated by parameter destinationSize.] */ + TEST_FUNCTION(size_tToString_succeeds_1_digit) + { + // arrange + char destination[1000]; + size_t toBeConverted = 2; + size_t destinationSize = 2; + + ///act + int result = size_tToString(destination, destinationSize, toBeConverted); + + ///assert + ASSERT_ARE_EQUAL(int, 0, result); + ASSERT_ARE_EQUAL(char_ptr, "2", destination); + + } + + /*Tests_SRS_CRT_ABSTRACTIONS_02_001: [size_tToString shall convert the parameter value to its decimal representation as a string in the buffer indicated by parameter destination having the size indicated by parameter destinationSize.] */ + /*Tests_SRS_CRT_ABSTRACTIONS_02_004: [If the conversion has been successfull then size_tToString shall return 0.] */ + TEST_FUNCTION(size_tToString_succeeds_for_interesting_numbers) + { + // arrange + char destination[1000]; + size_t i; + for (i = 0; i (SIZE_MAX / 10)) + { + ASSERT_FAIL("string produced was too big... "); + } + else + { + valueFromString *= 10; + valueFromString += (destination[pos] - '0'); + } + pos++; + } + if (interestingSize_tNumbersToBeConverted[i] != valueFromString) + { + ASSERT_FAIL("unexpected value"); + } + } + } + + /*Tests_SRS_CRT_ABSTRACTIONS_02_001: [size_tToString shall convert the parameter value to its decimal representation as a string in the buffer indicated by parameter destination having the size indicated by parameter destinationSize.] */ + /*Tests_SRS_CRT_ABSTRACTIONS_02_004: [If the conversion has been successfull then size_tToString shall return 0.] */ + TEST_FUNCTION(size_tToString_succeeds_for_space_just_about_right) + { + // arrange + char destination[1000]; + size_t toBeConverted = 1; /*7 would not be a right starting digit*/ + size_t destinationSize = 2; + while (toBeConverted <= (SIZE_MAX / 10)) + { + ///arrange + destinationSize++; + toBeConverted *= 10; + + ///act + int result = size_tToString(destination, destinationSize, toBeConverted); + + ///assert + ASSERT_ARE_EQUAL(int, 0, result); + + size_t valueFromString = 0; + size_t pos = 0; + while (destination[pos] != '\0') + { + if (valueFromString > (SIZE_MAX / 10)) + { + ASSERT_FAIL("string produced was too big... "); + } + else + { + valueFromString *= 10; + valueFromString += (destination[pos] - '0'); + } + pos++; + } + if (toBeConverted != valueFromString) + { + ASSERT_FAIL("unexpected value"); + } + } + } + + +END_TEST_SUITE(CRTAbstractions_UnitTests) diff --git a/c/sharedutil/tests/crtabstractions_unittests/main.c b/c/sharedutil/tests/crtabstractions_unittests/main.c new file mode 100644 index 00000000..12b19034 --- /dev/null +++ b/c/sharedutil/tests/crtabstractions_unittests/main.c @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include "testrunnerswitcher.h" + +int main(void) +{ + size_t failedTestCount = 0; + RUN_TEST_SUITE(CRTAbstractions_UnitTests, failedTestCount); + return failedTestCount; +} \ No newline at end of file diff --git a/c/sharedutil/tests/doublylinkedlist_unittests/CMakeLists.txt b/c/sharedutil/tests/doublylinkedlist_unittests/CMakeLists.txt new file mode 100644 index 00000000..3375d135 --- /dev/null +++ b/c/sharedutil/tests/doublylinkedlist_unittests/CMakeLists.txt @@ -0,0 +1,24 @@ +#Copyright (c) Microsoft. All rights reserved. +#Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#this is CMakeLists.txt for doublylinkedlist_unittests +cmake_minimum_required(VERSION 3.0) + +compileAsC99() + +set(theseTestsName doublylinkedlist_unittests) + +set(${theseTestsName}_cpp_files +${theseTestsName}.cpp +) + +set(${theseTestsName}_c_files +../../src/doublylinkedlist.c +../../src/gballoc.c +${LOCK_C_FILE} +) + +set(${theseTestsName}_h_files +) + +build_test_artifacts(${theseTestsName} ON) \ No newline at end of file diff --git a/c/sharedutil/tests/doublylinkedlist_unittests/doublylinkedlist_unittests.cpp b/c/sharedutil/tests/doublylinkedlist_unittests/doublylinkedlist_unittests.cpp new file mode 100644 index 00000000..8827e2f6 --- /dev/null +++ b/c/sharedutil/tests/doublylinkedlist_unittests/doublylinkedlist_unittests.cpp @@ -0,0 +1,421 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#ifdef _CRTDBG_MAP_ALLOC +#include +#endif + +#include "doublylinkedlist.h" + +#include "testrunnerswitcher.h" +#include "micromock.h" + + +typedef struct simpleItem_tag +{ + unsigned char index; + DLIST_ENTRY link; +} simpleItem,*pSimpleItem; + +static simpleItem simp1 = { 1 }; +static simpleItem simp2 = { 2 }; +static simpleItem simp3 = { 3 }; +static simpleItem simp4 = { 4 }; +static simpleItem simp5 = { 5 }; + +static MICROMOCK_GLOBAL_SEMAPHORE_HANDLE g_dllByDll; + +BEGIN_TEST_SUITE(doublylinkedlist_unittests) + + TEST_SUITE_INITIALIZE(TestClassInitialize) + { + INITIALIZE_MEMORY_DEBUG(g_dllByDll); + } + + TEST_SUITE_CLEANUP(TestClassCleanup) + { + DEINITIALIZE_MEMORY_DEBUG(g_dllByDll); + } + + TEST_FUNCTION_INITIALIZE(TestMethodInitialize) + { + INITIALIZE_MEMORY_DEBUG(g_dllByDll); + } + + TEST_FUNCTION_CLEANUP(TestMethodCleanup) + { + DEINITIALIZE_MEMORY_DEBUG(g_dllByDll); + } + + /* Tests_SRS_DLIST_06_005: [DList_InitializeListHead will initialize the Flink & Blink to the address of the DLIST_ENTRY.] */ + TEST_FUNCTION(DList_InitializeListHead_with_a_list_head_points_Flink_and_Blink_to_its_address) + { + // arrange + DLIST_ENTRY head = { 0 }; + + // act + DList_InitializeListHead(&head); + + // assert + ASSERT_ARE_EQUAL(void_ptr, &head, head.Flink); + ASSERT_ARE_EQUAL(void_ptr, &head, head.Blink); + } + + /* Tests_SRS_DLIST_06_003: [DList_IsListEmpty shall return a non-zero value if there are no DLIST_ENTRY's on this list other than the list head.] */ + TEST_FUNCTION(DList_IsListEmpty_with_a_list_head_only_returns_empty) + { + // arrange + DLIST_ENTRY local = { 0 }; + int result; + + DList_InitializeListHead(&local); + // act + result = DList_IsListEmpty(&local); + + // assert + ASSERT_ARE_NOT_EQUAL(int, 0, result); + } + + /* Tests_SRS_DLIST_06_004: [DList_IsListEmpty shall return 0 if there is one or more items in the list.]*/ + TEST_FUNCTION(DList_IsListEmpty_with_a_list_head_and_items_returns_empty) + { + // arrange + DLIST_ENTRY head = { 0 }; + int result; + + DList_InitializeListHead(&head); + DList_InsertTailList(&head, &(simp1.link)); + // act + result = DList_IsListEmpty(&head); + + // assert + ASSERT_ARE_EQUAL(int, 0, result); + } + + /* Tests_SRS_DLIST_06_006: [DListInsertTailList shall place the DLIST_ENTRY at the end of the list defined by the listHead parameter.] */ + TEST_FUNCTION(DList_InsertTailList_with_a_list_head_inserts_1st_item_at_the_end_of_the_list) + { + // arrange + DLIST_ENTRY head = { 0 }; + + DList_InitializeListHead(&head); + // act + DList_InsertTailList(&head, &(simp1.link)); + + // assert + ASSERT_ARE_EQUAL(void_ptr, head.Flink, &(simp1.link)); + ASSERT_ARE_EQUAL(void_ptr, head.Blink, &(simp1.link)); + } + + /* Tests_SRS_DLIST_06_006: [DListInsertTailList shall place the DLIST_ENTRY at the end of the list defined by the listHead parameter.] */ + TEST_FUNCTION(DList_InsertTailList_with_a_list_head_inserts_2nd_item_at_the_end_of_the_list) + { + // arrange + DLIST_ENTRY head = { 0 }; + + DList_InitializeListHead(&head); + DList_InsertTailList(&head, &(simp1.link)); + // act + DList_InsertTailList(&head, &(simp2.link)); + + // assert + ASSERT_ARE_EQUAL(void_ptr, head.Flink, &(simp1.link)); + ASSERT_ARE_EQUAL(void_ptr, simp1.link.Flink, &(simp2.link)); + ASSERT_ARE_EQUAL(void_ptr, simp2.link.Flink, &head); + ASSERT_ARE_EQUAL(void_ptr, head.Blink, &(simp2.link)); + ASSERT_ARE_EQUAL(void_ptr, simp1.link.Blink, &head); + ASSERT_ARE_EQUAL(void_ptr, simp2.link.Blink, &(simp1.link)); + } + + /* Tests_SRS_DLIST_06_007: [DList_AppendTailList shall place the list defined by ListToAppend at the end of the list defined by the listHead parameter.] */ + TEST_FUNCTION(DList_AppendTailList_adds_listToAppend_after_listHead) + { + // arrange + DLIST_ENTRY listHead = { 0 }; + PDLIST_ENTRY currentEntry; + + DList_InitializeListHead(&listHead); + DList_InsertTailList(&listHead, &(simp1.link)); + + DList_InitializeListHead(&simp2.link); + DList_InsertTailList(&simp2.link, &simp4.link); + DList_InsertTailList(&simp2.link, &simp5.link); + // act + DList_AppendTailList(&listHead, &simp2.link); + + // assert + // Go forwards + ASSERT_ARE_EQUAL(int, 0, DList_IsListEmpty(&listHead)); + currentEntry = listHead.Flink; + ASSERT_ARE_EQUAL(void_ptr, currentEntry, &simp1.link); + ASSERT_ARE_EQUAL(short, (short)1, containingRecord(currentEntry, simpleItem, link)->index); + currentEntry = currentEntry->Flink; + ASSERT_ARE_EQUAL(void_ptr, currentEntry, &simp2.link); + ASSERT_ARE_EQUAL(short, (short)2, containingRecord(currentEntry, simpleItem, link)->index); + currentEntry = currentEntry->Flink; + ASSERT_ARE_EQUAL(void_ptr, currentEntry, &simp4.link); + ASSERT_ARE_EQUAL(short, (short)4, containingRecord(currentEntry, simpleItem, link)->index); + currentEntry = currentEntry->Flink; + ASSERT_ARE_EQUAL(void_ptr, currentEntry, &simp5.link); + ASSERT_ARE_EQUAL(short, (short)5, containingRecord(currentEntry, simpleItem, link)->index); + currentEntry = currentEntry->Flink; + ASSERT_ARE_EQUAL(void_ptr, currentEntry, &listHead); + + // Now back + currentEntry = listHead.Blink; + ASSERT_ARE_EQUAL(void_ptr, currentEntry, &simp5.link); + ASSERT_ARE_EQUAL(short, (short)5, containingRecord(currentEntry, simpleItem, link)->index); +#ifdef _MSC_VER +#pragma warning(suppress: 6011) /* test code, should crash if this is truly NULL */ +#endif + currentEntry = currentEntry->Blink; + ASSERT_ARE_EQUAL(void_ptr, currentEntry, &simp4.link); + ASSERT_ARE_EQUAL(short, (short)4, containingRecord(currentEntry, simpleItem, link)->index); + currentEntry = currentEntry->Blink; + ASSERT_ARE_EQUAL(void_ptr, currentEntry, &simp2.link); + ASSERT_ARE_EQUAL(short, (short)2, containingRecord(currentEntry, simpleItem, link)->index); + currentEntry = currentEntry->Blink; + ASSERT_ARE_EQUAL(void_ptr, currentEntry, &simp1.link); + ASSERT_ARE_EQUAL(short, (short)1, containingRecord(currentEntry, simpleItem, link)->index); + currentEntry = currentEntry->Blink; + ASSERT_ARE_EQUAL(void_ptr, currentEntry, &listHead); + } + + /* Tests_SRS_DLIST_06_010: [DList_RemoveEntryList shall return non-zero if the remaining list is empty.] */ + TEST_FUNCTION(DList_RemoveEntryList_with_head_only_in_list_shall_return_non_zero) + { + // arrange + DLIST_ENTRY listHead = { 0 }; + int resultOfRemove; + + DList_InitializeListHead(&listHead); + + // act + resultOfRemove = DList_RemoveEntryList(&listHead); + + // assert + ASSERT_ARE_NOT_EQUAL(int, 0, resultOfRemove); + } + + /* Tests_SRS_DLIST_06_008: [DList_RemoveEntryList shall remove a listEntry from whatever list it is properly part of.] */ + /* Tests_SRS_DLIST_06_010: [DList_RemoveEntryList shall return non-zero if the remaining list is empty.] */ + /* Tests_SRS_DLIST_06_009: [The remaining list is properly formed.] */ + TEST_FUNCTION(DList_RemoveEntryList_with_one_element_and_removing_that_one_element_shall_return_non_zero) + { + // arrange + DLIST_ENTRY listHead = { 0 }; + int resultOfRemove; + + DList_InitializeListHead(&listHead); + DList_InsertTailList(&listHead, &(simp1.link)); + + // act + resultOfRemove = DList_RemoveEntryList(&(simp1.link)); + + // assert + ASSERT_ARE_NOT_EQUAL(int, 0, resultOfRemove); + ASSERT_ARE_EQUAL(void_ptr, &listHead, listHead.Blink); + ASSERT_ARE_EQUAL(void_ptr, &listHead, listHead.Flink); + } + + /* Tests_SRS_DLIST_06_008: [DList_RemoveEntryList shall remove a listEntry from whatever list it is properly part of.] */ + /* Tests_SRS_DLIST_06_010: [DList_RemoveEntryList shall return non-zero if the remaining list is empty.] */ + TEST_FUNCTION(DList_RemoveEntryList_with_one_element_and_removing_the_head_shall_return_non_zero) + { + // arrange + DLIST_ENTRY listHead = { 0 }; + int resultOfRemove; + + DList_InitializeListHead(&listHead); + DList_InsertTailList(&listHead, &(simp1.link)); + + // act + resultOfRemove = DList_RemoveEntryList(&listHead); + + // assert + ASSERT_ARE_NOT_EQUAL(int, 0, resultOfRemove); + ASSERT_ARE_EQUAL(void_ptr, &(simp1.link), simp1.link.Blink); + ASSERT_ARE_EQUAL(void_ptr, &(simp1.link), simp1.link.Flink); + } + + /* Tests_SRS_DLIST_06_008: [DList_RemoveEntryList shall remove a listEntry from whatever list it is properly part of.] */ + /* Tests_SRS_DLIST_06_009: [The remaining list is properly formed.] */ + /* Tests_SRS_DLIST_06_010: [DList_RemoveEntryList shall return non-zero if the remaining list is empty.] */ + /* Tests_SRS_DLIST_06_011: [DList_RemoveEntryList shall return zero if the remaining list is NOT empty.] */ + TEST_FUNCTION(DList_RemoveEntryList_with_three_elements_and_removing_the_first_return_zero) + { + // arrange + DLIST_ENTRY listHead = { 0 }; + int resultOfRemove; + + DList_InitializeListHead(&listHead); + DList_InsertTailList(&listHead, &(simp1.link)); + DList_InsertTailList(&listHead, &(simp2.link)); + DList_InsertTailList(&listHead, &(simp3.link)); + + // act + resultOfRemove = DList_RemoveEntryList(&(simp1.link)); + + // assert + ASSERT_ARE_EQUAL(int, 0, resultOfRemove); + ASSERT_ARE_EQUAL(void_ptr, listHead.Flink, &(simp2.link)); + ASSERT_ARE_EQUAL(void_ptr, simp2.link.Flink, &(simp3.link)); + ASSERT_ARE_EQUAL(void_ptr, simp3.link.Flink, &listHead); + ASSERT_ARE_EQUAL(void_ptr, listHead.Blink, &(simp3.link)); + ASSERT_ARE_EQUAL(void_ptr, simp3.link.Blink, &(simp2.link)); + ASSERT_ARE_EQUAL(void_ptr, simp2.link.Blink, &(listHead)); + } + + /* Tests_SRS_DLIST_06_008: [DList_RemoveEntryList shall remove a listEntry from whatever list it is properly part of.] */ + /* Tests_SRS_DLIST_06_009: [The remaining list is properly formed.] */ + /* Tests_SRS_DLIST_06_010: [DList_RemoveEntryList shall return non-zero if the remaining list is empty.] */ + /* Tests_SRS_DLIST_06_011: [DList_RemoveEntryList shall return zero if the remaining list is NOT empty.] */ + TEST_FUNCTION(DList_RemoveEntryList_with_three_elements_and_removing_the_last_return_zero) + { + // arrange + DLIST_ENTRY listHead = { 0 }; + int resultOfRemove; + + DList_InitializeListHead(&listHead); + DList_InsertTailList(&listHead, &(simp1.link)); + DList_InsertTailList(&listHead, &(simp2.link)); + DList_InsertTailList(&listHead, &(simp3.link)); + + // act + resultOfRemove = DList_RemoveEntryList(&(simp3.link)); + + // assert + ASSERT_ARE_EQUAL(int, 0, resultOfRemove); + ASSERT_ARE_EQUAL(void_ptr, listHead.Flink, &(simp1.link)); + ASSERT_ARE_EQUAL(void_ptr, simp1.link.Flink, &(simp2.link)); + ASSERT_ARE_EQUAL(void_ptr, simp2.link.Flink, &listHead); + ASSERT_ARE_EQUAL(void_ptr, listHead.Blink, &(simp2.link)); + ASSERT_ARE_EQUAL(void_ptr, simp2.link.Blink, &(simp1.link)); + ASSERT_ARE_EQUAL(void_ptr, simp1.link.Blink, &(listHead)); + } + + /* Tests_SRS_DLIST_06_008: [DList_RemoveEntryList shall remove a listEntry from whatever list it is properly part of.] */ + /* Tests_SRS_DLIST_06_009: [The remaining list is properly formed.] */ + /* Tests_SRS_DLIST_06_010: [DList_RemoveEntryList shall return non-zero if the remaining list is empty.] */ + /* Tests_SRS_DLIST_06_011: [DList_RemoveEntryList shall return zero if the remaining list is NOT empty.] */ + TEST_FUNCTION(DList_RemoveEntryList_with_three_elements_and_removing_the_middle_return_zero) + { + // arrange + DLIST_ENTRY listHead = { 0 }; + int resultOfRemove; + + DList_InitializeListHead(&listHead); + DList_InsertTailList(&listHead, &(simp1.link)); + DList_InsertTailList(&listHead, &(simp2.link)); + DList_InsertTailList(&listHead, &(simp3.link)); + + // act + resultOfRemove = DList_RemoveEntryList(&(simp2.link)); + + // assert + ASSERT_ARE_EQUAL(int, 0, resultOfRemove); + ASSERT_ARE_EQUAL(void_ptr, listHead.Flink, &(simp1.link)); + ASSERT_ARE_EQUAL(void_ptr, simp1.link.Flink, &(simp3.link)); + ASSERT_ARE_EQUAL(void_ptr, simp3.link.Flink, &listHead); + ASSERT_ARE_EQUAL(void_ptr, listHead.Blink, &(simp3.link)); + ASSERT_ARE_EQUAL(void_ptr, simp3.link.Blink, &(simp1.link)); + ASSERT_ARE_EQUAL(void_ptr, simp1.link.Blink, &(listHead)); + } + + /* Tests_SRS_DLIST_06_013: [DList_RemoveHeadList shall return listHead if that's the only item in the list.] */ + TEST_FUNCTION(DList_RemoveHeadList_with_only_head_shall_return_the_head) + { + // arrange + DLIST_ENTRY head = { 0 }; + PDLIST_ENTRY returnedEntry; + + DList_InitializeListHead(&head); + + // act + returnedEntry = DList_RemoveHeadList(&head); + + // assert + ASSERT_ARE_EQUAL(void_ptr, &head, returnedEntry); + } + + /* Tests_SRS_DLIST_06_012: [DList_RemoveHeadList removes the oldest entry from the list defined by the listHead parameter and returns a pointer to that entry.] */ + TEST_FUNCTION(DList_RemoveHeadList_with_one_entry_returns_entry) + { + // arrange + DLIST_ENTRY listHead = { 0 }; + PDLIST_ENTRY returnedEntry; + + DList_InitializeListHead(&listHead); + DList_InsertTailList(&listHead, &(simp1.link)); + + // act + returnedEntry = DList_RemoveHeadList(&listHead); + + // assert + ASSERT_ARE_NOT_EQUAL(int, 0, DList_IsListEmpty(&listHead)); + ASSERT_ARE_EQUAL(void_ptr, &(simp1.link), returnedEntry); + } + + /* Tests_SRS_DLIST_06_012: [DList_RemoveHeadList removes the oldest entry from the list defined by the listHead parameter and returns a pointer to that entry.] */ + TEST_FUNCTION(DList_RemoveHeadList_with_two_entries_returns_first_entry) + { + // arrange + DLIST_ENTRY listHead = { 0 }; + PDLIST_ENTRY returnedEntry; + + DList_InitializeListHead(&listHead); + DList_InsertTailList(&listHead, &(simp2.link)); + DList_InsertTailList(&listHead, &(simp1.link)); + + // act + returnedEntry = DList_RemoveHeadList(&listHead); + + // assert + ASSERT_ARE_EQUAL(int, 0, DList_IsListEmpty(&listHead)); + ASSERT_ARE_EQUAL(void_ptr, &(simp2.link), returnedEntry); + } + + /*Tests_SRS_DLIST_02_002: [DList_InsertHeadList inserts a singular entry in the list having as head listHead after "head".]*/ + TEST_FUNCTION(DList_InsertHeadList_with_empty_list_succeeds) + { + ///arrange + DLIST_ENTRY listHead; + DList_InitializeListHead(&listHead); + + DLIST_ENTRY toBeInserted; + + ///act + DList_InsertHeadList(&listHead, &toBeInserted); + + ///assert + ASSERT_ARE_EQUAL(void_ptr, listHead.Flink, &toBeInserted); + ASSERT_ARE_EQUAL(void_ptr, listHead.Blink, &toBeInserted); + ASSERT_ARE_EQUAL(void_ptr, toBeInserted.Flink , &listHead); + ASSERT_ARE_EQUAL(void_ptr, toBeInserted.Blink, &listHead); + } + + /*Tests_SRS_DLIST_02_002: [DList_InsertHeadList inserts a singular entry in the list having as head listHead after "head".]*/ + TEST_FUNCTION(DList_InsertHeadList_with_1_item_in_list_succeeds) + { + ///arrange + DLIST_ENTRY listHead; + DList_InitializeListHead(&listHead); + DLIST_ENTRY existingInList; + DLIST_ENTRY toBeInserted; + DList_InsertTailList(&listHead, &existingInList); /*would be same as insertHead when it is the first item... */ + + ///act + DList_InsertHeadList(&listHead, &toBeInserted); + + ///assert + ASSERT_ARE_EQUAL(void_ptr, listHead.Flink, &toBeInserted); + ASSERT_ARE_EQUAL(void_ptr, listHead.Blink, &existingInList); + ASSERT_ARE_EQUAL(void_ptr, existingInList.Flink, &listHead); + ASSERT_ARE_EQUAL(void_ptr, existingInList.Blink, &toBeInserted); + ASSERT_ARE_EQUAL(void_ptr, toBeInserted.Flink, &existingInList); + ASSERT_ARE_EQUAL(void_ptr, toBeInserted.Blink, &listHead); + + } + + +END_TEST_SUITE(doublylinkedlist_unittests) diff --git a/c/sharedutil/tests/doublylinkedlist_unittests/main.c b/c/sharedutil/tests/doublylinkedlist_unittests/main.c new file mode 100644 index 00000000..1913b317 --- /dev/null +++ b/c/sharedutil/tests/doublylinkedlist_unittests/main.c @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include "testrunnerswitcher.h" + +int main(void) +{ + size_t failedTestCount = 0; + RUN_TEST_SUITE(doublylinkedlist_unittests, failedTestCount); + return failedTestCount; +} diff --git a/c/sharedutil/tests/gballoc_unittests/CMakeLists.txt b/c/sharedutil/tests/gballoc_unittests/CMakeLists.txt new file mode 100644 index 00000000..f4d4a9c3 --- /dev/null +++ b/c/sharedutil/tests/gballoc_unittests/CMakeLists.txt @@ -0,0 +1,19 @@ +#Copyright (c) Microsoft. All rights reserved. +#Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#this is CMakeLists.txt for gballoc_unittests +cmake_minimum_required(VERSION 3.0) +set(theseTestsName gballoc_unittests) + +set(${theseTestsName}_cpp_files +${theseTestsName}.cpp +) + +set(${theseTestsName}_c_files +gballoc_undertest.c +) + +set(${theseTestsName}_h_files +) + +build_test_artifacts(${theseTestsName} ON) \ No newline at end of file diff --git a/c/sharedutil/tests/gballoc_unittests/gballoc_undertest.c b/c/sharedutil/tests/gballoc_unittests/gballoc_undertest.c new file mode 100644 index 00000000..00e4ef8f --- /dev/null +++ b/c/sharedutil/tests/gballoc_unittests/gballoc_undertest.c @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include +#define malloc mock_malloc +#define calloc mock_calloc +#define realloc mock_realloc +#define free mock_free + +extern void* mock_malloc(size_t size); +extern void* mock_calloc(size_t nmemb, size_t size); +extern void* mock_realloc(void* ptr, size_t size); +extern void mock_free(void* ptr); + +#undef _CRTDBG_MAP_ALLOC +#include "../src/gballoc.c" diff --git a/c/sharedutil/tests/gballoc_unittests/gballoc_unittests.cpp b/c/sharedutil/tests/gballoc_unittests/gballoc_unittests.cpp new file mode 100644 index 00000000..049b437b --- /dev/null +++ b/c/sharedutil/tests/gballoc_unittests/gballoc_unittests.cpp @@ -0,0 +1,1494 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#if defined(GB_MEASURE_MEMORY_FOR_THIS) +#undef GB_MEASURE_MEMORY_FOR_THIS +#endif + +#include +#ifdef _CRTDBG_MAP_ALLOC +#include +#endif +#include "gballoc.h" +#include "testrunnerswitcher.h" +#include "micromock.h" +#include "lock.h" + +#ifndef SIZE_MAX +#define SIZE_MAX ((size_t)~(size_t)0) +#endif + +static MICROMOCK_MUTEX_HANDLE g_testByTest; + +static void* TEST_ALLOC_PTR1 = (void*)0x4242; +static void* TEST_ALLOC_PTR2 = (void*)0x4243; + +#define OVERHEAD_SIZE 4096 +static const LOCK_HANDLE TEST_LOCK_HANDLE = (LOCK_HANDLE)0x4244; + +TYPED_MOCK_CLASS(CGBAllocMocks, CGlobalMock) +{ +public: + MOCK_STATIC_METHOD_1(, void*, mock_malloc, size_t, size) + MOCK_METHOD_END(void*, TEST_ALLOC_PTR1) + MOCK_STATIC_METHOD_2(, void*, mock_calloc, size_t, nmemb, size_t, size) + MOCK_METHOD_END(void*, TEST_ALLOC_PTR1) + MOCK_STATIC_METHOD_2(, void*, mock_realloc, void*, ptr, size_t, size) + MOCK_METHOD_END(void*, TEST_ALLOC_PTR1) + MOCK_STATIC_METHOD_1(, void, mock_free, void*, ptr) + MOCK_VOID_METHOD_END() + + /* Lock Mocks */ + MOCK_STATIC_METHOD_0(, LOCK_HANDLE, Lock_Init) + MOCK_METHOD_END(LOCK_HANDLE, TEST_LOCK_HANDLE) + MOCK_STATIC_METHOD_1(, LOCK_RESULT, Lock_Deinit, LOCK_HANDLE, handle) + MOCK_METHOD_END(LOCK_RESULT, LOCK_OK) + MOCK_STATIC_METHOD_1(, LOCK_RESULT, Lock, LOCK_HANDLE, handle) + MOCK_METHOD_END(LOCK_RESULT, LOCK_OK) + MOCK_STATIC_METHOD_1(, LOCK_RESULT, Unlock, LOCK_HANDLE, handle) + MOCK_METHOD_END(LOCK_RESULT, LOCK_OK) +}; + +extern "C" +{ + DECLARE_GLOBAL_MOCK_METHOD_1(CGBAllocMocks, , void*, mock_malloc, size_t, size); + DECLARE_GLOBAL_MOCK_METHOD_2(CGBAllocMocks, , void*, mock_calloc, size_t, nmemb, size_t, size); + DECLARE_GLOBAL_MOCK_METHOD_2(CGBAllocMocks, , void*, mock_realloc, void*, ptr, size_t, size); + DECLARE_GLOBAL_MOCK_METHOD_1(CGBAllocMocks, , void, mock_free, void*, ptr); + + DECLARE_GLOBAL_MOCK_METHOD_0(CGBAllocMocks, , LOCK_HANDLE, Lock_Init); + DECLARE_GLOBAL_MOCK_METHOD_1(CGBAllocMocks, , LOCK_RESULT, Lock_Deinit, LOCK_HANDLE, handle); + DECLARE_GLOBAL_MOCK_METHOD_1(CGBAllocMocks, , LOCK_RESULT, Lock, LOCK_HANDLE, handle); + DECLARE_GLOBAL_MOCK_METHOD_1(CGBAllocMocks, , LOCK_RESULT, Unlock, LOCK_HANDLE, handle); +} + +static MICROMOCK_GLOBAL_SEMAPHORE_HANDLE g_dllByDll; + +BEGIN_TEST_SUITE(GBAlloc_UnitTests) + +TEST_SUITE_INITIALIZE(TestClassInitialize) +{ + INITIALIZE_MEMORY_DEBUG(g_dllByDll); + + g_testByTest = MicroMockCreateMutex(); + ASSERT_IS_NOT_NULL(g_testByTest); +} + +TEST_SUITE_CLEANUP(TestClassCleanup) +{ + MicroMockDestroyMutex(g_testByTest); + + DEINITIALIZE_MEMORY_DEBUG(g_dllByDll); + +} + +TEST_FUNCTION_INITIALIZE(TestMethodInitialize) +{ + if (!MicroMockAcquireMutex(g_testByTest)) + { + ASSERT_FAIL("our mutex is ABANDONED. Failure in test framework"); + } +} + +TEST_FUNCTION_CLEANUP(TestMethodCleanup) +{ + CGBAllocMocks mocks; + mocks.SetPerformAutomaticCallComparison(AUTOMATIC_CALL_COMPARISON_OFF); + gballoc_deinit(); + + if (!MicroMockReleaseMutex(g_testByTest)) + { + ASSERT_FAIL("failure in test framework at ReleaseMutex"); + } +} + + +/* gballoc_init */ + +/* Tests_SRS_GBALLOC_01_002: [Upon initialization the total memory used and maximum total memory used tracked by the module shall be set to 0.] */ +TEST_FUNCTION(gballoc_init_resets_memory_used) +{ + //arrange + CGBAllocMocks mocks; + mocks.SetPerformAutomaticCallComparison(AUTOMATIC_CALL_COMPARISON_OFF); + gballoc_init(); + void* allocation = malloc(OVERHEAD_SIZE); + + EXPECTED_CALL(mocks, mock_malloc(0)) + .SetReturn(allocation); + gballoc_free(gballoc_malloc(1)); + + gballoc_deinit(); + + // act + gballoc_init(); + + // assert + ASSERT_ARE_EQUAL(size_t, 0, gballoc_getMaximumMemoryUsed()); + ASSERT_ARE_EQUAL(size_t, 0, gballoc_getCurrentMemoryUsed()); + + ///cleanup + free(allocation); +} + +/* Tests_SRS_GBALLOC_01_024: [gballoc_init shall initialize the gballoc module and return 0 upon success.] */ +/* Tests_SRS_GBALLOC_01_026: [gballoc_Init shall create a lock handle that will be used to make the other gballoc APIs thread-safe.] */ +TEST_FUNCTION(when_gballoc_init_calls_lock_init_and_it_succeeds_then_gballoc_init_succeeds) +{ + // arrange + CGBAllocMocks mocks; + STRICT_EXPECTED_CALL(mocks, Lock_Init()); + + // act + int result = gballoc_init(); + + // assert + ASSERT_ARE_EQUAL(int, 0, result); +} + +/* Tests_SRS_GBALLOC_01_027: [If the Lock creation fails, gballoc_init shall return a non-zero value.] */ +TEST_FUNCTION(when_lock_init_fails_gballoc_init_fails) +{ + // arrange + CGBAllocMocks mocks; + STRICT_EXPECTED_CALL(mocks, Lock_Init()) + .SetReturn((LOCK_HANDLE)NULL); + + // act + int result = gballoc_init(); + + // assert + ASSERT_ARE_NOT_EQUAL(int, 0, result); +} + +/* Tests_SRS_GBALLOC_01_025: [Init after Init shall fail and return a non-zero value.] */ +TEST_FUNCTION(gballoc_init_after_gballoc_init_fails) +{ + // arrange + CGBAllocMocks mocks; + STRICT_EXPECTED_CALL(mocks, Lock_Init()); + gballoc_init(); + + //act + int result = gballoc_init(); + + // assert + ASSERT_ARE_NOT_EQUAL(int, 0, result); +} + +/* gballoc_deinit */ + +/* Tests_SRS_GBALLOC_01_028: [gballoc_deinit shall free all resources allocated by gballoc_init.] */ +TEST_FUNCTION(gballoc_deinit_frees_the_lock_when_the_module_was_initialized) +{ + // arrange + CGBAllocMocks mocks; + gballoc_init(); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, Lock_Deinit(TEST_LOCK_HANDLE)); + + // act + gballoc_deinit(); + + // assert + // no explicit assert, uMock checks the calls +} + +/* Tests_SRS_GBALLOC_01_029: [if gballoc is not initialized gballoc_deinit shall do nothing.] */ +TEST_FUNCTION(gballoc_deinit_after_gballoc_deinit_doesnot_free_lock) +{ + //arrange + CGBAllocMocks mocks; + + // act + gballoc_deinit(); + + // assert + // no explicit assert, uMock checks the calls +} + +/* gballoc_malloc */ + +/* Tests_SRS_GBALLOC_01_048: [If acquiring the lock fails, gballoc_malloc shall return NULL.] */ +TEST_FUNCTION(when_acquiring_the_lock_fails_gballoc_malloc_fails) +{ + // arrange + CGBAllocMocks mocks; + gballoc_init(); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, Lock(TEST_LOCK_HANDLE)) + .SetReturn(LOCK_ERROR); + + // act + void* result = gballoc_malloc(1); + + // assert + ASSERT_IS_NULL(result); +} + +/* Tests_SRS_GBALLOC_01_003: [gballoc_malloc shall call the C99 malloc function and return its result.] */ +/* Tests_SRS_GBALLOC_01_004: [If the underlying malloc call is successful, gballoc_malloc shall increment the total memory used with the amount indicated by size.] */ +/* Tests_SRS_GBALLOC_01_030: [gballoc_malloc shall ensure thread safety by using the lock created by gballoc_Init.] */ +TEST_FUNCTION(gballoc_malloc_with_0_Size_Calls_Underlying_malloc) +{ + // arrange + CGBAllocMocks mocks; + gballoc_init(); + mocks.ResetAllCalls(); + void* allocation = malloc(OVERHEAD_SIZE); + + STRICT_EXPECTED_CALL(mocks, Lock(TEST_LOCK_HANDLE)); + /* don't quite like this, but I'm unsure I want to invest more in this memory counting */ + EXPECTED_CALL(mocks, mock_malloc(0)) + .SetReturn(allocation); + /* This is the call to the underlying malloc with the size we want to allocate */ + STRICT_EXPECTED_CALL(mocks, mock_malloc(0)); + STRICT_EXPECTED_CALL(mocks, Unlock(TEST_LOCK_HANDLE)); + + // act + void* result = gballoc_malloc(0); + + // assert + ASSERT_ARE_EQUAL(void_ptr, TEST_ALLOC_PTR1, result); + mocks.AssertActualAndExpectedCalls(); + ASSERT_ARE_EQUAL(size_t, 0, gballoc_getMaximumMemoryUsed()); + + // cleanup + gballoc_free(result); + free(allocation); +} + +/* Tests_SRS_GBALLOC_01_003: [gballoc_malloc shall call the C99 malloc function and return its result.] */ +/* Tests_SRS_GBALLOC_01_004: [If the underlying malloc call is successful, gballoc_malloc shall increment the total memory used with the amount indicated by size.] */ +TEST_FUNCTION(gballoc_malloc_with_1_Size_Calls_Underlying_malloc_And_Increases_Max_Used) +{ + // arrange + CGBAllocMocks mocks; + gballoc_init(); + mocks.ResetAllCalls(); + void* allocation = malloc(OVERHEAD_SIZE); + + STRICT_EXPECTED_CALL(mocks, Lock(TEST_LOCK_HANDLE)); + /* don't quite like this, but I'm unsure I want to invest more in this memory counting */ + EXPECTED_CALL(mocks, mock_malloc(0)) + .SetReturn(allocation); + /* This is the call to the underlying malloc with the size we want to allocate */ + STRICT_EXPECTED_CALL(mocks, mock_malloc(1)); + STRICT_EXPECTED_CALL(mocks, Unlock(TEST_LOCK_HANDLE)); + + // act + void* result = gballoc_malloc(1); + + // assert + ASSERT_ARE_EQUAL(void_ptr, TEST_ALLOC_PTR1, result); + mocks.AssertActualAndExpectedCalls(); + ASSERT_ARE_EQUAL(size_t, 1, gballoc_getMaximumMemoryUsed()); + + // cleanup + gballoc_free(result); + free(allocation); +} + +/* Tests_SRS_GBALLOC_01_012: [When the underlying malloc call fails, gballoc_malloc shall return NULL and size should not be counted towards total memory used.] */ +TEST_FUNCTION(When_malloc_Fails_Then_gballoc_malloc_fails_too) +{ + // arrange + CGBAllocMocks mocks; + gballoc_init(); + mocks.ResetAllCalls(); + void* allocation = malloc(OVERHEAD_SIZE); + + STRICT_EXPECTED_CALL(mocks, Lock(TEST_LOCK_HANDLE)); + /* don't quite like this, but I'm unsure I want to invest more in this memory counting */ + EXPECTED_CALL(mocks, mock_malloc(0)) + .SetReturn(allocation); + /* This is the call to the underlying malloc with the size we want to allocate */ + STRICT_EXPECTED_CALL(mocks, mock_malloc(1)) + .SetReturn((void*)NULL); + STRICT_EXPECTED_CALL(mocks, mock_free(allocation)); + STRICT_EXPECTED_CALL(mocks, Unlock(TEST_LOCK_HANDLE)); + + // act + void* result = gballoc_malloc(1); + + // assert + ASSERT_IS_NULL(result); + mocks.AssertActualAndExpectedCalls(); + ASSERT_ARE_EQUAL(size_t, 0, gballoc_getMaximumMemoryUsed()); + + // cleanup + free(allocation); +} + +/* Tests_SRS_GBALLOC_01_013: [When gballoc_malloc fails allocating memory for its internal use, gballoc_malloc shall return NULL.] */ +TEST_FUNCTION(When_allocating_memory_for_tracking_information_fails_Then_gballoc_malloc_fails_too) +{ + // arrange + CGBAllocMocks mocks; + gballoc_init(); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, Lock(TEST_LOCK_HANDLE)); + /* don't quite like this, but I'm unsure I want to invest more in this memory counting */ + EXPECTED_CALL(mocks, mock_malloc(0)) + .SetReturn((void*)NULL); + STRICT_EXPECTED_CALL(mocks, Unlock(TEST_LOCK_HANDLE)); + + // act + void* result = gballoc_malloc(1); + + // assert + ASSERT_IS_NULL(result); + mocks.AssertActualAndExpectedCalls(); + ASSERT_ARE_EQUAL(size_t, 0, gballoc_getMaximumMemoryUsed()); +} + +/* Tests_SRS_GBALLOC_01_039: [If gballoc was not initialized gballoc_malloc shall simply call malloc without any memory tracking being performed.] */ +TEST_FUNCTION(gballoc_malloc_after_deinit_calls_crt_malloc) +{ + // arrange + CGBAllocMocks mocks; + + STRICT_EXPECTED_CALL(mocks, mock_malloc(1)); + + //act + void* result = gballoc_malloc(1); + + //assert + ASSERT_IS_NOT_NULL(result); +} + +/* gballoc_calloc */ + +/* Tests_SRS_GBALLOC_01_046: [If acquiring the lock fails, gballoc_calloc shall return NULL.] */ +TEST_FUNCTION(when_acquiring_the_lock_fails_gballoc_calloc_fails) +{ + // arrange + CGBAllocMocks mocks; + gballoc_init(); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, Lock(TEST_LOCK_HANDLE)) + .SetReturn(LOCK_ERROR); + + // act + void* result = gballoc_calloc(1,1); + + // assert + ASSERT_IS_NULL(result); +} + +/* Tests_SRS_GBALLOC_01_020: [gballoc_calloc shall call the C99 calloc function and return its result.] */ +/* Tests_SRS_GBALLOC_01_021: [If the underlying calloc call is successful, gballoc_calloc shall increment the total memory used with nmemb*size.] */ +/* Tests_SRS_GBALLOC_01_031: [gballoc_calloc shall ensure thread safety by using the lock created by gballoc_Init] */ +TEST_FUNCTION(gballoc_calloc_with_0_Size_And_ItemCount_Calls_Underlying_calloc) +{ + // arrange + CGBAllocMocks mocks; + gballoc_init(); + mocks.ResetAllCalls(); + void* allocation = malloc(OVERHEAD_SIZE); + + STRICT_EXPECTED_CALL(mocks, Lock(TEST_LOCK_HANDLE)); + /* don't quite like this, but I'm unsure I want to invest more in this memory counting */ + EXPECTED_CALL(mocks, mock_malloc(0)) + .SetReturn(allocation); + /* This is the call to the underlying malloc with the size we want to allocate */ + STRICT_EXPECTED_CALL(mocks, mock_calloc(0, 0)); + STRICT_EXPECTED_CALL(mocks, Unlock(TEST_LOCK_HANDLE)); + + // act + void* result = gballoc_calloc(0, 0); + + // assert + ASSERT_ARE_EQUAL(void_ptr, TEST_ALLOC_PTR1, result); + mocks.AssertActualAndExpectedCalls(); + ASSERT_ARE_EQUAL(size_t, 0, gballoc_getMaximumMemoryUsed()); + + // cleanup + gballoc_free(result); + free(allocation); +} + +/* Tests_SRS_GBALLOC_01_020: [gballoc_calloc shall call the C99 calloc function and return its result.] */ +/* Tests_SRS_GBALLOC_01_021: [If the underlying calloc call is successful, gballoc_calloc shall increment the total memory used with nmemb*size.] */ +TEST_FUNCTION(gballoc_calloc_with_1_Item_Of_1_Size_Calls_Underlying_malloc_And_Increases_Max_Used) +{ + // arrange + CGBAllocMocks mocks; + gballoc_init(); + mocks.ResetAllCalls(); + void* allocation = malloc(OVERHEAD_SIZE); + + STRICT_EXPECTED_CALL(mocks, Lock(TEST_LOCK_HANDLE)); + /* don't quite like this, but I'm unsure I want to invest more in this memory counting */ + EXPECTED_CALL(mocks, mock_malloc(0)) + .SetReturn(allocation); + /* This is the call to the underlying malloc with the size we want to allocate */ + STRICT_EXPECTED_CALL(mocks, mock_calloc(1, 1)); + STRICT_EXPECTED_CALL(mocks, Unlock(TEST_LOCK_HANDLE)); + + // act + void* result = gballoc_calloc(1, 1); + + // assert + ASSERT_ARE_EQUAL(void_ptr, TEST_ALLOC_PTR1, result); + mocks.AssertActualAndExpectedCalls(); + ASSERT_ARE_EQUAL(size_t, 1, gballoc_getMaximumMemoryUsed()); + + // cleanup + gballoc_free(result); + free(allocation); +} + +/* Tests_SRS_GBALLOC_01_020: [gballoc_calloc shall call the C99 calloc function and return its result.] */ +/* Tests_SRS_GBALLOC_01_021: [If the underlying calloc call is successful, gballoc_calloc shall increment the total memory used with nmemb*size.] */ +TEST_FUNCTION(gballoc_calloc_with_1_Item_Of_0_Size_Calls_Underlying_malloc_And_Does_Not_Increase_Max_Used) +{ + // arrange + CGBAllocMocks mocks; + gballoc_init(); + mocks.ResetAllCalls(); + void* allocation = malloc(OVERHEAD_SIZE); + + STRICT_EXPECTED_CALL(mocks, Lock(TEST_LOCK_HANDLE)); + /* don't quite like this, but I'm unsure I want to invest more in this memory counting */ + EXPECTED_CALL(mocks, mock_malloc(0)) + .SetReturn(allocation); + /* This is the call to the underlying malloc with the size we want to allocate */ + STRICT_EXPECTED_CALL(mocks, mock_calloc(1, 0)); + STRICT_EXPECTED_CALL(mocks, Unlock(TEST_LOCK_HANDLE)); + + // act + void* result = gballoc_calloc(1, 0); + + // assert + ASSERT_ARE_EQUAL(void_ptr, TEST_ALLOC_PTR1, result); + mocks.AssertActualAndExpectedCalls(); + ASSERT_ARE_EQUAL(size_t, 0, gballoc_getMaximumMemoryUsed()); + + // cleanup + gballoc_free(result); + free(allocation); +} + +/* Tests_SRS_GBALLOC_01_020: [gballoc_calloc shall call the C99 calloc function and return its result.] */ +/* Tests_SRS_GBALLOC_01_021: [If the underlying calloc call is successful, gballoc_calloc shall increment the total memory used with nmemb*size.] */ +TEST_FUNCTION(gballoc_calloc_with_0_Items_Of_1_Size_Calls_Underlying_malloc_And_Does_Not_Increase_Max_Used) +{ + // arrange + CGBAllocMocks mocks; + gballoc_init(); + mocks.ResetAllCalls(); + void* allocation = malloc(OVERHEAD_SIZE); + + STRICT_EXPECTED_CALL(mocks, Lock(TEST_LOCK_HANDLE)); + /* don't quite like this, but I'm unsure I want to invest more in this memory counting */ + EXPECTED_CALL(mocks, mock_malloc(0)) + .SetReturn(allocation); + /* This is the call to the underlying malloc with the size we want to allocate */ + STRICT_EXPECTED_CALL(mocks, mock_calloc(0, 1)); + STRICT_EXPECTED_CALL(mocks, Unlock(TEST_LOCK_HANDLE)); + + // act + void* result = gballoc_calloc(0, 1); + + // assert + ASSERT_ARE_EQUAL(void_ptr, TEST_ALLOC_PTR1, result); + mocks.AssertActualAndExpectedCalls(); + ASSERT_ARE_EQUAL(size_t, 0, gballoc_getMaximumMemoryUsed()); + + // cleanup + gballoc_free(result); + free(allocation); +} + +/* Tests_SRS_GBALLOC_01_020: [gballoc_calloc shall call the C99 calloc function and return its result.] */ +/* Tests_SRS_GBALLOC_01_021: [If the underlying calloc call is successful, gballoc_calloc shall increment the total memory used with nmemb*size.] */ +TEST_FUNCTION(gballoc_calloc_with_42_Items_Of_2_Size_Calls_Underlying_malloc_And_Increases_Max_Size) +{ + // arrange + CGBAllocMocks mocks; + gballoc_init(); + mocks.ResetAllCalls(); + void* allocation = malloc(OVERHEAD_SIZE); + + STRICT_EXPECTED_CALL(mocks, Lock(TEST_LOCK_HANDLE)); + /* don't quite like this, but I'm unsure I want to invest more in this memory counting */ + EXPECTED_CALL(mocks, mock_malloc(0)) + .SetReturn(allocation); + /* This is the call to the underlying malloc with the size we want to allocate */ + STRICT_EXPECTED_CALL(mocks, mock_calloc(42, 2)); + STRICT_EXPECTED_CALL(mocks, Unlock(TEST_LOCK_HANDLE)); + + // act + void* result = gballoc_calloc(42, 2); + + // assert + ASSERT_ARE_EQUAL(void_ptr, TEST_ALLOC_PTR1, result); + mocks.AssertActualAndExpectedCalls(); + ASSERT_ARE_EQUAL(size_t, 84, gballoc_getMaximumMemoryUsed()); + + // cleanup + gballoc_free(result); + free(allocation); +} + +/* Tests_SRS_GBALLOC_01_022: [When the underlying calloc call fails, gballoc_calloc shall return NULL and size should not be counted towards total memory used.] */ +TEST_FUNCTION(When_calloc_Fails_Then_gballoc_calloc_fails_too) +{ + // arrange + CGBAllocMocks mocks; + gballoc_init(); + mocks.ResetAllCalls(); + void* allocation = malloc(OVERHEAD_SIZE); + + STRICT_EXPECTED_CALL(mocks, Lock(TEST_LOCK_HANDLE)); + /* don't quite like this, but I'm unsure I want to invest more in this memory counting */ + EXPECTED_CALL(mocks, mock_malloc(0)) + .SetReturn(allocation); + /* This is the call to the underlying malloc with the size we want to allocate */ + STRICT_EXPECTED_CALL(mocks, mock_calloc(1, 1)) + .SetReturn((void*)NULL); + STRICT_EXPECTED_CALL(mocks, mock_free(allocation)); + STRICT_EXPECTED_CALL(mocks, Unlock(TEST_LOCK_HANDLE)); + + // act + void* result = gballoc_calloc(1, 1); + + // assert + ASSERT_IS_NULL(result); + mocks.AssertActualAndExpectedCalls(); + ASSERT_ARE_EQUAL(size_t, 0, gballoc_getMaximumMemoryUsed()); + + // cleanup + free(allocation); +} + +/* Tests_SRS_GBALLOC_01_023: [When gballoc_calloc fails allocating memory for its internal use, gballoc_calloc shall return NULL.] */ +TEST_FUNCTION(When_allocating_memory_for_tracking_information_fails_Then_gballoc_calloc_fails_too) +{ + // arrange + CGBAllocMocks mocks; + gballoc_init(); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, Lock(TEST_LOCK_HANDLE)); + /* don't quite like this, but I'm unsure I want to invest more in this memory counting */ + EXPECTED_CALL(mocks, mock_malloc(0)) + .SetReturn((void*)NULL); + STRICT_EXPECTED_CALL(mocks, Unlock(TEST_LOCK_HANDLE)); + + // act + void* result = gballoc_calloc(1, 1); + + // assert + ASSERT_IS_NULL(result); + mocks.AssertActualAndExpectedCalls(); + ASSERT_ARE_EQUAL(size_t, 0, gballoc_getMaximumMemoryUsed()); +} + +/* Tests_SRS_GBALLOC_01_040: [If gballoc was not initialized gballoc_calloc shall simply call calloc without any memory tracking being performed.] */ +TEST_FUNCTION(gballoc_calloc_after_deinit_calls_crt_calloc) +{ + // arrange + CGBAllocMocks mocks; + + STRICT_EXPECTED_CALL(mocks, mock_calloc(1, 1)); + + // act + void* result = gballoc_calloc(1, 1); + + // assert + ASSERT_IS_NOT_NULL(result); +} + + +/* gballoc_realloc */ + +/* Tests_SRS_GBALLOC_01_047: [If acquiring the lock fails, gballoc_realloc shall return NULL.]*/ +TEST_FUNCTION(when_acquiring_the_lock_fails_gballoc_realloc_fails) +{ + // arrange + CGBAllocMocks mocks; + gballoc_init(); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, Lock(TEST_LOCK_HANDLE)) + .SetReturn(LOCK_ERROR); + + // act + void* result = gballoc_realloc(NULL, 1); + + // assert + ASSERT_IS_NULL(result); +} + +/* Tests_SRS_GBALLOC_01_041: [If gballoc was not initialized gballoc_realloc shall shall simply call realloc without any memory tracking being performed.] */ +TEST_FUNCTION(gballoc_realloc_after_deinit_fails) +{ + // arrange + CGBAllocMocks mocks; + + STRICT_EXPECTED_CALL(mocks, mock_realloc(NULL, 1)); + + // act + void* result = gballoc_realloc(NULL, 1); + + // assert + ASSERT_IS_NOT_NULL(result); +} + +/* Tests_SRS_GBALLOC_01_005: [gballoc_realloc shall call the C99 realloc function and return its result.] */ +/* Tests_SRS_GBALLOC_01_017: [When ptr is NULL, gballoc_realloc shall call the underlying realloc with ptr being NULL and the realloc result shall be tracked by gballoc.] */ +/* Tests_SRS_GBALLOC_01_032: [gballoc_realloc shall ensure thread safety by using the lock created by gballoc_Init.] */ +TEST_FUNCTION(gballoc_realloc_with_NULL_Arg_And_0_Size_Calls_Underlying_realloc) +{ + // arrange + CGBAllocMocks mocks; + gballoc_init(); + mocks.ResetAllCalls(); + void* allocation = malloc(OVERHEAD_SIZE); + + STRICT_EXPECTED_CALL(mocks, Lock(TEST_LOCK_HANDLE)); + /* don't quite like this, but I'm unsure I want to invest more in this memory counting */ + EXPECTED_CALL(mocks, mock_malloc(0)) + .SetReturn(allocation); + /* This is the call to the underlying malloc with the size we want to allocate */ + STRICT_EXPECTED_CALL(mocks, mock_realloc(NULL, 0)); + STRICT_EXPECTED_CALL(mocks, Unlock(TEST_LOCK_HANDLE)); + + // act + void* result = gballoc_realloc(NULL, 0); + + // assert + ASSERT_ARE_EQUAL(void_ptr, TEST_ALLOC_PTR1, result); + mocks.AssertActualAndExpectedCalls(); + ASSERT_ARE_EQUAL(size_t, 0, gballoc_getMaximumMemoryUsed()); + + // cleanup + gballoc_free(result); + free(allocation); +} + +/* Tests_SRS_GBALLOC_01_005: [gballoc_realloc shall call the C99 realloc function and return its result.] */ +/* Tests_SRS_GBALLOC_01_017: [When ptr is NULL, gballoc_realloc shall call the underlying realloc with ptr being NULL and the realloc result shall be tracked by gballoc.] */ +TEST_FUNCTION(gballoc_realloc_with_NULL_Arg_And_1_Size_Calls_Underlying_realloc) +{ + // arrange + CGBAllocMocks mocks; + gballoc_init(); + mocks.ResetAllCalls(); + void* allocation = malloc(OVERHEAD_SIZE); + + STRICT_EXPECTED_CALL(mocks, Lock(TEST_LOCK_HANDLE)); + /* don't quite like this, but I'm unsure I want to invest more in this memory counting */ + EXPECTED_CALL(mocks, mock_malloc(0)) + .SetReturn(allocation); + /* This is the call to the underlying malloc with the size we want to allocate */ + STRICT_EXPECTED_CALL(mocks, mock_realloc(NULL, 1)); + STRICT_EXPECTED_CALL(mocks, Unlock(TEST_LOCK_HANDLE)); + + // act + void* result = gballoc_realloc(NULL, 1); + + // assert + ASSERT_ARE_EQUAL(void_ptr, TEST_ALLOC_PTR1, result); + mocks.AssertActualAndExpectedCalls(); + ASSERT_ARE_EQUAL(size_t, 1, gballoc_getMaximumMemoryUsed()); + + // cleanup + gballoc_free(result); + free(allocation); +} + +/* Tests_SRS_GBALLOC_01_005: [gballoc_realloc shall call the C99 realloc function and return its result.] */ +/* Tests_SRS_GBALLOC_01_006: [If the underlying realloc call is successful, gballoc_realloc shall look up the size associated with the pointer ptr and decrease the total memory used with that size.] */ +TEST_FUNCTION(gballoc_realloc_with_Previous_1_Byte_Block_Ptr_And_2_Size_Calls_Underlying_realloc_And_Increases_Max_Used_Memory) +{ + // arrange + CGBAllocMocks mocks; + gballoc_init(); + mocks.ResetAllCalls(); + void* allocation = malloc(OVERHEAD_SIZE); + + STRICT_EXPECTED_CALL(mocks, Lock(TEST_LOCK_HANDLE)); + /* don't quite like this, but I'm unsure I want to invest more in this memory counting */ + EXPECTED_CALL(mocks, mock_malloc(0)) + .SetReturn(allocation); + /* This is the call to the underlying malloc with the size we want to allocate */ + STRICT_EXPECTED_CALL(mocks, mock_realloc(NULL, 1)); + STRICT_EXPECTED_CALL(mocks, Unlock(TEST_LOCK_HANDLE)); + STRICT_EXPECTED_CALL(mocks, Lock(TEST_LOCK_HANDLE)); + STRICT_EXPECTED_CALL(mocks, mock_realloc(TEST_ALLOC_PTR1, 2)) + .SetReturn(TEST_ALLOC_PTR2); + STRICT_EXPECTED_CALL(mocks, Unlock(TEST_LOCK_HANDLE)); + + void* result = gballoc_realloc(NULL, 1); + + // act + result = gballoc_realloc(result, 2); + + // assert + ASSERT_ARE_EQUAL(void_ptr, TEST_ALLOC_PTR2, result); + mocks.AssertActualAndExpectedCalls(); + ASSERT_ARE_EQUAL(size_t, 2, gballoc_getMaximumMemoryUsed()); + + // cleanup + gballoc_free(result); + free(allocation); +} + +/* Tests_SRS_GBALLOC_01_014: [When the underlying realloc call fails, gballoc_realloc shall return NULL and no change should be made to the counted total memory usage.] */ +TEST_FUNCTION(When_realloc_fails_then_gballoc_realloc_Fails_Too_And_No_Change_Is_Made_To_Memory_Counters) +{ + // arrange + CGBAllocMocks mocks; + gballoc_init(); + mocks.ResetAllCalls(); + void* allocation = malloc(OVERHEAD_SIZE); + + STRICT_EXPECTED_CALL(mocks, Lock(TEST_LOCK_HANDLE)); + /* don't quite like this, but I'm unsure I want to invest more in this memory counting */ + EXPECTED_CALL(mocks, mock_malloc(0)) + .SetReturn(allocation); + /* This is the call to the underlying malloc with the size we want to allocate */ + STRICT_EXPECTED_CALL(mocks, mock_realloc(NULL, 1)); + STRICT_EXPECTED_CALL(mocks, Unlock(TEST_LOCK_HANDLE)); + STRICT_EXPECTED_CALL(mocks, Lock(TEST_LOCK_HANDLE)); + STRICT_EXPECTED_CALL(mocks, mock_realloc(TEST_ALLOC_PTR1, 2)) + .SetReturn((void*)NULL); + STRICT_EXPECTED_CALL(mocks, Unlock(TEST_LOCK_HANDLE)); + + void* result = gballoc_realloc(NULL, 1); + + // act + result = gballoc_realloc(result, 2); + + // assert + ASSERT_IS_NULL(result); + mocks.AssertActualAndExpectedCalls(); + ASSERT_ARE_EQUAL(size_t, 1, gballoc_getMaximumMemoryUsed()); + + // cleanup + gballoc_free(TEST_ALLOC_PTR1); + free(allocation); +} + +/* Tests_SRS_GBALLOC_01_015: [When allocating memory used for tracking by gballoc_realloc fails, gballoc_realloc shall return NULL and no change should be made to the counted total memory usage.] */ +TEST_FUNCTION(When_Allocating_Memory_For_tracking_fails_gballoc_realloc_fails) +{ + // arrange + CGBAllocMocks mocks; + gballoc_init(); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, Lock(TEST_LOCK_HANDLE)); + /* don't quite like this, but I'm unsure I want to invest more in this memory counting */ + EXPECTED_CALL(mocks, mock_malloc(0)) + .SetReturn((void*)NULL); + STRICT_EXPECTED_CALL(mocks, Unlock(TEST_LOCK_HANDLE)); + + // act + void* result = gballoc_realloc(NULL, 1); + + // assert + ASSERT_IS_NULL(result); + mocks.AssertActualAndExpectedCalls(); + ASSERT_ARE_EQUAL(size_t, 0, gballoc_getMaximumMemoryUsed()); +} + +/* Tests_SRS_GBALLOC_01_016: [When the ptr pointer cannot be found in the pointers tracked by gballoc, gballoc_realloc shall return NULL and the underlying realloc shall not be called.] */ +TEST_FUNCTION(When_The_Pointer_Is_Not_Tracked_gballoc_realloc_Returns_NULL) +{ + // arrange + CGBAllocMocks mocks; + gballoc_init(); + mocks.ResetAllCalls(); + void* allocation = malloc(OVERHEAD_SIZE); + + STRICT_EXPECTED_CALL(mocks, Lock(TEST_LOCK_HANDLE)); + /* don't quite like this, but I'm unsure I want to invest more in this memory counting */ + EXPECTED_CALL(mocks, mock_malloc(0)) + .SetReturn(allocation); + /* This is the call to the underlying malloc with the size we want to allocate */ + STRICT_EXPECTED_CALL(mocks, mock_realloc(NULL, 1)); + STRICT_EXPECTED_CALL(mocks, Unlock(TEST_LOCK_HANDLE)); + STRICT_EXPECTED_CALL(mocks, Lock(TEST_LOCK_HANDLE)); + STRICT_EXPECTED_CALL(mocks, Unlock(TEST_LOCK_HANDLE)); + + void* result1 = gballoc_realloc(NULL, 1); + + // act + void* result2 = gballoc_realloc((void*)0xDEADBEEF, 2); + + // assert + ASSERT_IS_NULL(result2); + mocks.AssertActualAndExpectedCalls(); + ASSERT_ARE_EQUAL(size_t, 1, gballoc_getMaximumMemoryUsed()); + + // cleanup + gballoc_free(result1); + free(allocation); +} + +/* Tests_SRS_GBALLOC_01_014: [When the underlying realloc call fails, gballoc_realloc shall return NULL and no change should be made to the counted total memory usage.] */ +TEST_FUNCTION(When_ptr_is_null_and_the_underlying_realloc_fails_then_the_memory_used_for_tracking_is_freed) +{ + // arrange + CGBAllocMocks mocks; + gballoc_init(); + mocks.ResetAllCalls(); + void* allocation = malloc(OVERHEAD_SIZE); + + STRICT_EXPECTED_CALL(mocks, Lock(TEST_LOCK_HANDLE)); + /* don't quite like this, but I'm unsure I want to invest more in this memory counting */ + EXPECTED_CALL(mocks, mock_malloc(0)) + .SetReturn(allocation); + /* This is the call to the underlying malloc with the size we want to allocate */ + STRICT_EXPECTED_CALL(mocks, mock_realloc(NULL, 1)) + .SetReturn((void*)NULL); + STRICT_EXPECTED_CALL(mocks, mock_free(allocation)); + STRICT_EXPECTED_CALL(mocks, Unlock(TEST_LOCK_HANDLE)); + + // act + void* result = gballoc_realloc(NULL, 1); + + // assert + ASSERT_IS_NULL(result); + mocks.AssertActualAndExpectedCalls(); + ASSERT_ARE_EQUAL(size_t, 0, gballoc_getMaximumMemoryUsed()); + + // cleanup + free(allocation); +} + +/* gballoc_free */ + +/* Tests_SRS_GBALLOC_01_042: [If gballoc was not initialized gballoc_free shall shall simply call free.] */ +TEST_FUNCTION(gballoc_free_after_deinit_calls_crt_free) +{ + // arrange + CGBAllocMocks mocks; + + STRICT_EXPECTED_CALL(mocks, mock_free((void*)0x4242)); + + // act + gballoc_free((void*)0x4242); + + // assert + // no explicit assert, uMock checks the calls +} + +/* Tests_SRS_GBALLOC_01_049: [If acquiring the lock fails, gballoc_free shall do nothing.] */ +TEST_FUNCTION(when_acquiring_the_lock_fails_then_gballoc_free_does_nothing) +{ + // arrange + CGBAllocMocks mocks; + gballoc_init(); + mocks.ResetAllCalls(); + void* allocation = malloc(OVERHEAD_SIZE); + + /* don't quite like this, but I'm unsure I want to invest more in this memory counting */ + EXPECTED_CALL(mocks, mock_malloc(0)) + .SetReturn(allocation); + /* This is the call to the underlying malloc with the size we want to allocate */ + STRICT_EXPECTED_CALL(mocks, mock_realloc(NULL, 1)); + void* block = gballoc_realloc(NULL, 1); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, Lock(TEST_LOCK_HANDLE)) + .SetReturn(LOCK_ERROR); + + // act + gballoc_free(block); + + // assert + mocks.AssertActualAndExpectedCalls(); + + // cleanup + gballoc_free(block); + free(allocation); +} + +/* Tests_SRS_GBALLOC_01_008: [gballoc_free shall call the C99 free function.] */ +/* Tests_SRS_GBALLOC_01_009: [gballoc_free shall also look up the size associated with the ptr pointer and decrease the total memory used with the associated size amount.] */ +/* Tests_SRS_GBALLOC_01_010: [gballoc_getMaximumMemoryUsed shall return the maximum amount of total memory used recorded since the module initialization.] */ +/* Tests_SRS_GBALLOC_01_011: [The maximum total memory used shall be the maximum of the total memory used at any point.] */ +/* Tests_SRS_GBALLOC_01_033: [gballoc_free shall ensure thread safety by using the lock created by gballoc_Init.] */ +TEST_FUNCTION(gballoc_free_calls_the_underlying_free) +{ + // arrange + CGBAllocMocks mocks; + gballoc_init(); + mocks.ResetAllCalls(); + void* allocation = malloc(OVERHEAD_SIZE); + + /* don't quite like this, but I'm unsure I want to invest more in this memory counting */ + EXPECTED_CALL(mocks, mock_malloc(0)) + .SetReturn(allocation); + /* This is the call to the underlying malloc with the size we want to allocate */ + STRICT_EXPECTED_CALL(mocks, mock_realloc(NULL, 1)); + void* block = gballoc_realloc(NULL, 1); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, Lock(TEST_LOCK_HANDLE)); + STRICT_EXPECTED_CALL(mocks, mock_free(TEST_ALLOC_PTR1)); + STRICT_EXPECTED_CALL(mocks, mock_free(allocation)); + STRICT_EXPECTED_CALL(mocks, Unlock(TEST_LOCK_HANDLE)); + + // act + gballoc_free(block); + + // assert + mocks.AssertActualAndExpectedCalls(); + ASSERT_ARE_EQUAL(size_t, 1, gballoc_getMaximumMemoryUsed()); + + // cleanup + free(allocation); +} + +/* Tests_SRS_GBALLOC_01_008: [gballoc_free shall call the C99 free function.] */ +/* Tests_SRS_GBALLOC_01_009: [gballoc_free shall also look up the size associated with the ptr pointer and decrease the total memory used with the associated size amount.] */ +/* Tests_SRS_GBALLOC_01_010: [gballoc_getMaximumMemoryUsed shall return the maximum amount of total memory used recorded since the module initialization.] */ +/* Tests_SRS_GBALLOC_01_010: [gballoc_getMaximumMemoryUsed shall return the maximum amount of total memory used recorded since the module initialization.] */ +/* Tests_SRS_GBALLOC_01_011: [The maximum total memory used shall be the maximum of the total memory used at any point.] */ +TEST_FUNCTION(gballoc_malloc_free_2_times_with_1_byte_yields_1_byte_as_max) +{ + // arrange + CGBAllocMocks mocks; + gballoc_init(); + void* allocation = malloc(OVERHEAD_SIZE); + + /* don't quite like this, but I'm unsure I want to invest more in this memory counting */ + EXPECTED_CALL(mocks, mock_malloc(0)) + .SetReturn(allocation); + STRICT_EXPECTED_CALL(mocks, mock_realloc(NULL, 1)); + void* block = gballoc_realloc(NULL, 1); + gballoc_free(block); + + /* don't quite like this, but I'm unsure I want to invest more in this memory counting */ + EXPECTED_CALL(mocks, mock_malloc(0)) + .SetReturn(allocation); + block = gballoc_realloc(NULL, 1); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, Lock(TEST_LOCK_HANDLE)); + STRICT_EXPECTED_CALL(mocks, mock_free(TEST_ALLOC_PTR1)); + STRICT_EXPECTED_CALL(mocks, mock_free(allocation)); + STRICT_EXPECTED_CALL(mocks, Unlock(TEST_LOCK_HANDLE)); + + // act + gballoc_free(block); + + // assert + mocks.AssertActualAndExpectedCalls(); + ASSERT_ARE_EQUAL(size_t, 1, gballoc_getMaximumMemoryUsed()); + + // cleanup + free(allocation); +} + +/* Tests_SRS_GBALLOC_01_019:[When the ptr pointer cannot be found in the pointers tracked by gballoc, gballoc_free shall not free any memory.] */ +TEST_FUNCTION(gballoc_free_with_an_untracked_pointer_does_not_alter_total_memory_used) +{ + // arrange + CGBAllocMocks mocks; + gballoc_init(); + void* allocation = malloc(OVERHEAD_SIZE); + + /* don't quite like this, but I'm unsure I want to invest more in this memory counting */ + EXPECTED_CALL(mocks, mock_malloc(0)) + .SetReturn(allocation); + + gballoc_realloc(NULL, 1); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, Lock(TEST_LOCK_HANDLE)); + STRICT_EXPECTED_CALL(mocks, Unlock(TEST_LOCK_HANDLE)); + + // act + gballoc_free((void*)0xDEADBEEF); + + // assert + mocks.AssertActualAndExpectedCalls(); + gballoc_realloc(TEST_ALLOC_PTR1, 2); + ASSERT_ARE_EQUAL(size_t, 2, gballoc_getMaximumMemoryUsed()); + + // cleanup + gballoc_free(TEST_ALLOC_PTR1); + free(allocation); +} + +/* gballoc_getMaximumMemoryUsed */ + + +/* Tests_SRS_GBALLOC_01_034: [gballoc_getMaximumMemoryUsed shall ensure thread safety by using the lock created by gballoc_Init.] */ +TEST_FUNCTION(when_gballoc_getMaximumMemoryUsed_called_It_Shall_Lock_And_Unlock) +{ + // arrange + CGBAllocMocks mocks; + gballoc_init(); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, Lock(TEST_LOCK_HANDLE)); + STRICT_EXPECTED_CALL(mocks, Unlock(TEST_LOCK_HANDLE)); + // act + (void)gballoc_getMaximumMemoryUsed(); + + // assert + // no explicit assert, uMock checks the calls +} + +/* Tests_SRS_GBALLOC_01_050: [If the lock cannot be acquired, gballoc_getMaximumMemoryUsed shall return SIZE_MAX.] */ +TEST_FUNCTION(when_acquiring_the_lock_fails_then_gballoc_getMaximumMemoryUsed_fails) +{ + // arrange + CGBAllocMocks mocks; + gballoc_init(); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, Lock(TEST_LOCK_HANDLE)) + .SetReturn(LOCK_ERROR); + + // act + size_t result = gballoc_getMaximumMemoryUsed(); + + // assert + ASSERT_ARE_EQUAL(size_t, SIZE_MAX, result); +} + +/* Tests_SRS_GBALLOC_01_038: [If gballoc was not initialized gballoc_getMaximumMemoryUsed shall return MAX_INT_SIZE.] */ +TEST_FUNCTION(gballoc_getMaximumMemoryUsed_after_deinit_fails) +{ + // arrange + CGBAllocMocks mocks; + + // act + size_t result = gballoc_getMaximumMemoryUsed(); + + // assert + ASSERT_ARE_EQUAL(size_t, SIZE_MAX, result); + +} + +/* gballoc_getCurrentMemoryUsed */ + +/*Tests_SRS_GBALLOC_02_001: [gballoc_getCurrentMemoryUsed shall return the currently used memory size.] */ +TEST_FUNCTION(gballoc_getCurrentMemoryUsed_after_1_byte_malloc_returns_1) +{ + // arrange + CGBAllocMocks mocks; + gballoc_init(); + + void* allocation = malloc(OVERHEAD_SIZE); + + EXPECTED_CALL(mocks, mock_malloc(0)) + .SetReturn(allocation); + STRICT_EXPECTED_CALL(mocks, mock_malloc(1)); + void *toBeFreed = gballoc_malloc(1); + mocks.ResetAllCalls(); + STRICT_EXPECTED_CALL(mocks, Lock(TEST_LOCK_HANDLE)); + STRICT_EXPECTED_CALL(mocks, Unlock(TEST_LOCK_HANDLE)); + + // act + size_t result = gballoc_getCurrentMemoryUsed(); + + // assert + ASSERT_ARE_EQUAL(size_t, 1, result); + + ///cleanup + gballoc_free(toBeFreed); + free(allocation); + mocks.ResetAllCalls(); //this is just for mathematics, not for functionality +} + +/*Tests_SRS_GBALLOC_02_001: [gballoc_getCurrentMemoryUsed shall return the currently used memory size.] */ +TEST_FUNCTION(gballoc_getCurrentMemoryUsed_after_2x3_byte_calloc_returns_6) +{ + // arrange + CGBAllocMocks mocks; + gballoc_init(); + void* allocation = malloc(OVERHEAD_SIZE); + + EXPECTED_CALL(mocks, mock_malloc(0)) + .SetReturn(allocation); + void *toBeFreed = gballoc_calloc(2, 3); + mocks.ResetAllCalls(); + STRICT_EXPECTED_CALL(mocks, Lock(TEST_LOCK_HANDLE)); + STRICT_EXPECTED_CALL(mocks, Unlock(TEST_LOCK_HANDLE)); + + // act + size_t result = gballoc_getCurrentMemoryUsed(); + + // assert + ASSERT_ARE_EQUAL(size_t, 6, result); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + gballoc_free(toBeFreed); + free(allocation); + mocks.ResetAllCalls(); //this is just for mathematics, not for functionality +} + +/*Tests_SRS_GBALLOC_02_001: [gballoc_getCurrentMemoryUsed shall return the currently used memory size.] */ +TEST_FUNCTION(gballoc_getCurrentMemoryUsed_after_1_byte_malloc_and_3_bytes_realloc_returns_3) +{ + // arrange + CGBAllocMocks mocks; + gballoc_init(); + void* allocation = malloc(OVERHEAD_SIZE); + + EXPECTED_CALL(mocks, mock_malloc(0)) + .SetReturn(allocation); + STRICT_EXPECTED_CALL(mocks, mock_malloc(1)); + + void *toBeFreed = gballoc_malloc(1); + toBeFreed = gballoc_realloc(toBeFreed, 3); + mocks.ResetAllCalls(); + STRICT_EXPECTED_CALL(mocks, Lock(TEST_LOCK_HANDLE)); + STRICT_EXPECTED_CALL(mocks, Unlock(TEST_LOCK_HANDLE)); + + // act + size_t result = gballoc_getCurrentMemoryUsed(); + + // assert + ASSERT_ARE_EQUAL(size_t, 3, result); + + ///cleanup + gballoc_free(toBeFreed); + free(allocation); + mocks.ResetAllCalls(); //this is just for mathematics, not for functionality +} + +/*Tests_SRS_GBALLOC_02_001: [gballoc_getCurrentMemoryUsed shall return the currently used memory size.] */ +TEST_FUNCTION(gballoc_getCurrentMemoryUsed_after_1_byte_malloc_and_free_returns_0) +{ + // arrange + CGBAllocMocks mocks; + gballoc_init(); + void* allocation = malloc(OVERHEAD_SIZE); + + EXPECTED_CALL(mocks, mock_malloc(0)) + .SetReturn(allocation); + STRICT_EXPECTED_CALL(mocks, mock_malloc(1)); + + void *toBeFreed = gballoc_malloc(1); + gballoc_free(toBeFreed); + mocks.ResetAllCalls(); + STRICT_EXPECTED_CALL(mocks, Lock(TEST_LOCK_HANDLE)); + STRICT_EXPECTED_CALL(mocks, Unlock(TEST_LOCK_HANDLE)); + + // act + size_t result = gballoc_getCurrentMemoryUsed(); + + // assert + ASSERT_ARE_EQUAL(size_t, 0, result); + + ///cleanup + free(allocation); + mocks.ResetAllCalls(); //this is just for mathematics, not for functionality +} + +/*Tests_SRS_GBALLOC_02_001: [gballoc_getCurrentMemoryUsed shall return the currently used memory size.] */ +TEST_FUNCTION(gballoc_getCurrentMemoryUsed_after_2x3_byte_calloc_and_free_returns_0) +{ + // arrange + CGBAllocMocks mocks; + gballoc_init(); + void* allocation = malloc(OVERHEAD_SIZE); + + EXPECTED_CALL(mocks, mock_malloc(0)) + .SetReturn(allocation); + + void *toBeFreed = gballoc_calloc(2, 3); + gballoc_free(toBeFreed); + mocks.ResetAllCalls(); + STRICT_EXPECTED_CALL(mocks, Lock(TEST_LOCK_HANDLE)); + STRICT_EXPECTED_CALL(mocks, Unlock(TEST_LOCK_HANDLE)); + + // act + size_t result = gballoc_getCurrentMemoryUsed(); + + // assert + ASSERT_ARE_EQUAL(size_t, 0, result); + + ///cleanup + free(allocation); + mocks.ResetAllCalls(); //this is just for mathematics, not for functionality +} + +/*Tests_SRS_GBALLOC_02_001: [gballoc_getCurrentMemoryUsed shall return the currently used memory size.] */ +TEST_FUNCTION(gballoc_getCurrentMemoryUsed_after_realloc_and_free_returns_0) +{ + // arrange + CGBAllocMocks mocks; + gballoc_init(); + void* allocation = malloc(OVERHEAD_SIZE); + + EXPECTED_CALL(mocks, mock_malloc(0)) + .SetReturn(allocation); + STRICT_EXPECTED_CALL(mocks, mock_malloc(1)); + + void *toBeFreed = gballoc_malloc(1); + toBeFreed = gballoc_realloc(toBeFreed, 3); + gballoc_free(toBeFreed); + mocks.ResetAllCalls(); + STRICT_EXPECTED_CALL(mocks, Lock(TEST_LOCK_HANDLE)); + STRICT_EXPECTED_CALL(mocks, Unlock(TEST_LOCK_HANDLE)); + + // act + size_t result = gballoc_getCurrentMemoryUsed(); + + // assert + ASSERT_ARE_EQUAL(size_t, 0, result); + + ///cleanup + free(allocation); + mocks.ResetAllCalls(); //this is just for mathematics, not for functionality +} + +/*Tests_SRS_GBALLOC_02_001: [gballoc_getCurrentMemoryUsed shall return the currently used memory size.] */ +TEST_FUNCTION(gballoc_getCurrentMemoryUsed_after_1_byte_malloc_and_1_byte_malloc_returns_2) +{ + // arrange + CGBAllocMocks mocks; + gballoc_init(); + + void* allocation1 = malloc(OVERHEAD_SIZE); + void* allocation2 = malloc(OVERHEAD_SIZE); + + EXPECTED_CALL(mocks, mock_malloc(0)) + .SetReturn(allocation1); + STRICT_EXPECTED_CALL(mocks, mock_malloc(1)); + EXPECTED_CALL(mocks, mock_malloc(0)) + .SetReturn(allocation2); + STRICT_EXPECTED_CALL(mocks, mock_malloc(1)); + + void *toBeFreed1 = gballoc_malloc(1); + void *toBeFreed2 = gballoc_malloc(1); + mocks.ResetAllCalls(); + STRICT_EXPECTED_CALL(mocks, Lock(TEST_LOCK_HANDLE)); + STRICT_EXPECTED_CALL(mocks, Unlock(TEST_LOCK_HANDLE)); + + // act + size_t result = gballoc_getCurrentMemoryUsed(); + + // assert + ASSERT_ARE_EQUAL(size_t, 2, result); + + ///cleanup + gballoc_free(toBeFreed1); + gballoc_free(toBeFreed2); + free(allocation1); + free(allocation2); + mocks.ResetAllCalls(); //this is just for mathematics, not for functionality +} + +/*Tests_SRS_GBALLOC_02_001: [gballoc_getCurrentMemoryUsed shall return the currently used memory size.] */ +TEST_FUNCTION(gballoc_getCurrentMemoryUsed_after_1_byte_malloc_and_1_byte_malloc_and_3_realloc_returns_4) +{ + // arrange + CGBAllocMocks mocks; + gballoc_init(); + mocks.ResetAllCalls(); + + void* allocation1 = malloc(OVERHEAD_SIZE); + void* allocation2 = malloc(OVERHEAD_SIZE); + + EXPECTED_CALL(mocks, mock_malloc(0)) + .SetReturn(allocation1); + STRICT_EXPECTED_CALL(mocks, mock_malloc(1)); + EXPECTED_CALL(mocks, mock_malloc(0)) + .SetReturn(allocation2); + STRICT_EXPECTED_CALL(mocks, mock_malloc(1)); + + void *toBeFreed1 = gballoc_malloc(1); + void *toBeFreed2 = gballoc_malloc(1); + toBeFreed2 = gballoc_realloc(toBeFreed2, 3); + mocks.ResetAllCalls(); + STRICT_EXPECTED_CALL(mocks, Lock(TEST_LOCK_HANDLE)); + STRICT_EXPECTED_CALL(mocks, Unlock(TEST_LOCK_HANDLE)); + + // act + size_t result = gballoc_getCurrentMemoryUsed(); + + // assert + ASSERT_ARE_EQUAL(size_t, 4, result); + + ///cleanup + gballoc_free(toBeFreed1); + gballoc_free(toBeFreed2); + free(allocation1); + free(allocation2); + mocks.ResetAllCalls(); //this is just for mathematics, not for functionality +} + +/*Tests_SRS_GBALLOC_02_001: [gballoc_getCurrentMemoryUsed shall return the currently used memory size.] */ +TEST_FUNCTION(gballoc_getCurrentMemoryUsed_after_1_byte_malloc_and_6_byte_calloc_returns_7) +{ + // arrange + CGBAllocMocks mocks; + gballoc_init(); + + void* allocation1 = malloc(OVERHEAD_SIZE); + void* allocation2 = malloc(OVERHEAD_SIZE); + + EXPECTED_CALL(mocks, mock_malloc(0)) + .SetReturn(allocation1); + STRICT_EXPECTED_CALL(mocks, mock_malloc(1)); + EXPECTED_CALL(mocks, mock_malloc(0)) + .SetReturn(allocation2); + STRICT_EXPECTED_CALL(mocks, mock_calloc(2, 3)); + + void *toBeFreed1 = gballoc_malloc(1); + void *toBeFreed2 = gballoc_calloc(2, 3); + mocks.ResetAllCalls(); + STRICT_EXPECTED_CALL(mocks, Lock(TEST_LOCK_HANDLE)); + STRICT_EXPECTED_CALL(mocks, Unlock(TEST_LOCK_HANDLE)); + + // act + size_t result = gballoc_getCurrentMemoryUsed(); + + // assert + ASSERT_ARE_EQUAL(size_t, 7, result); + + ///cleanup + gballoc_free(toBeFreed1); + gballoc_free(toBeFreed2); + free(allocation1); + free(allocation2); + mocks.ResetAllCalls(); //this is just for mathematics, not for functionality +} + +/*Tests_SRS_GBALLOC_02_001: [gballoc_getCurrentMemoryUsed shall return the currently used memory size.] */ +TEST_FUNCTION(gballoc_getCurrentMemoryUsed_after_1_byte_malloc_and_6_byte_calloc_and_free_returns_6) +{ + // arrange + CGBAllocMocks mocks; + gballoc_init(); + void* allocation1 = malloc(OVERHEAD_SIZE); + void* allocation2 = malloc(OVERHEAD_SIZE); + + EXPECTED_CALL(mocks, mock_malloc(0)) + .SetReturn(allocation1); + STRICT_EXPECTED_CALL(mocks, mock_malloc(1)) + .SetReturn((char*)allocation1 + OVERHEAD_SIZE / 2); /*somewhere in the middle of allocation*/ + EXPECTED_CALL(mocks, mock_malloc(0)) + .SetReturn(allocation2); + STRICT_EXPECTED_CALL(mocks, mock_calloc(2, 3)) + .SetReturn((char*)allocation2 + OVERHEAD_SIZE / 2); + + void *toBeFreed1 = gballoc_malloc(1); + void *toBeFreed2 = gballoc_calloc(2, 3); + gballoc_free(toBeFreed1); + mocks.ResetAllCalls(); + STRICT_EXPECTED_CALL(mocks, Lock(TEST_LOCK_HANDLE)); + STRICT_EXPECTED_CALL(mocks, Unlock(TEST_LOCK_HANDLE)); + + // act + size_t result = gballoc_getCurrentMemoryUsed(); + + // assert + ASSERT_ARE_EQUAL(size_t, 6, result); + + ///cleanup + gballoc_free(toBeFreed2); + free(allocation1); + free(allocation2); + mocks.ResetAllCalls(); //this is just for mathematics, not for functionality +} + +/*Tests_SRS_GBALLOC_02_001: [gballoc_getCurrentMemoryUsed shall return the currently used memory size.] */ +TEST_FUNCTION(gballoc_getCurrentMemoryUsed_after_1_byte_malloc_and_1_byte_malloc_and_3_realloc_and_free_returns_3) +{ + // arrange + CGBAllocMocks mocks; + gballoc_init(); + void* allocation1 = malloc(OVERHEAD_SIZE); + void* allocation2 = malloc(OVERHEAD_SIZE); + + EXPECTED_CALL(mocks, mock_malloc(0)) + .SetReturn(allocation1); + STRICT_EXPECTED_CALL(mocks, mock_malloc(1)) + .SetReturn((char*)allocation1 + OVERHEAD_SIZE / 2); /*somewhere in the middle of allocation*/ + EXPECTED_CALL(mocks, mock_malloc(0)) + .SetReturn(allocation2); + STRICT_EXPECTED_CALL(mocks, mock_realloc(IGNORED_PTR_ARG, 3)) + .IgnoreArgument(1) + .SetReturn((char*)allocation2 + OVERHEAD_SIZE / 2); /*somewhere in the middle of allocation*/ + + void *toBeFreed1 = gballoc_malloc(1); + void *toBeFreed2 = gballoc_malloc(1); + toBeFreed2 = gballoc_realloc(toBeFreed2, 3); + gballoc_free(toBeFreed1); + mocks.ResetAllCalls(); + STRICT_EXPECTED_CALL(mocks, Lock(TEST_LOCK_HANDLE)); + STRICT_EXPECTED_CALL(mocks, Unlock(TEST_LOCK_HANDLE)); + + // act + size_t result = gballoc_getCurrentMemoryUsed(); + + // assert + ASSERT_ARE_EQUAL(size_t, 3, result); + + ///cleanup + gballoc_free(toBeFreed2); + free(allocation1); + free(allocation2); + mocks.ResetAllCalls(); //this is just for mathematics, not for functionality +} + +/* Tests_SRS_GBALLOC_01_036: [gballoc_getCurrentMemoryUsed shall ensure thread safety by using the lock created by gballoc_Init.] */ +TEST_FUNCTION(gballoc_getCurrentMemoryUsed_locks_and_unlocks) +{ + // assert + CGBAllocMocks mocks; + gballoc_init(); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, Lock(TEST_LOCK_HANDLE)); + STRICT_EXPECTED_CALL(mocks, Unlock(TEST_LOCK_HANDLE)); + + // act + size_t result = gballoc_getCurrentMemoryUsed(); + + // assert + ASSERT_ARE_EQUAL(size_t, 0, result); +} + +/* Tests_SRS_GBALLOC_01_044: [If gballoc was not initialized gballoc_getCurrentMemoryUsed shall return SIZE_MAX.] */ +TEST_FUNCTION(gballoc_getCurrentMemoryUsed_after_deinit_fails) +{ + // arrange + CGBAllocMocks mocks; + + // act + size_t result = gballoc_getCurrentMemoryUsed(); + + // assert + ASSERT_ARE_EQUAL(size_t, SIZE_MAX, result); +} + +/* Tests_SRS_GBALLOC_01_051: [If the lock cannot be acquired, gballoc_getCurrentMemoryUsed shall return SIZE_MAX.] */ +TEST_FUNCTION(when_acquiring_the_lock_fails_gballoc_getCurrentMemoryUsed_fails) +{ + // arrange + CGBAllocMocks mocks; + gballoc_init(); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, Lock(TEST_LOCK_HANDLE)) + .SetReturn(LOCK_ERROR); + + // act + size_t result = gballoc_getCurrentMemoryUsed(); + + // assert + ASSERT_ARE_EQUAL(size_t, SIZE_MAX, result); + +} + +END_TEST_SUITE(GBAlloc_UnitTests) diff --git a/c/sharedutil/tests/gballoc_unittests/main.c b/c/sharedutil/tests/gballoc_unittests/main.c new file mode 100644 index 00000000..61078661 --- /dev/null +++ b/c/sharedutil/tests/gballoc_unittests/main.c @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include "testrunnerswitcher.h" + +int main(void) +{ + size_t failedTestCount = 0; + RUN_TEST_SUITE(GBAlloc_UnitTests, failedTestCount); + return failedTestCount; +} diff --git a/c/sharedutil/tests/gballoc_without_init_unittests/CMakeLists.txt b/c/sharedutil/tests/gballoc_without_init_unittests/CMakeLists.txt new file mode 100644 index 00000000..38114018 --- /dev/null +++ b/c/sharedutil/tests/gballoc_without_init_unittests/CMakeLists.txt @@ -0,0 +1,20 @@ +#Copyright (c) Microsoft. All rights reserved. +#Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#this is CMakeLists.txt for gballoc_without_init_unittests +cmake_minimum_required(VERSION 3.0) + +set(theseTestsName gballoc_without_init_unittests) + +set(${theseTestsName}_cpp_files +${theseTestsName}.cpp +) + +set(${theseTestsName}_c_files +gballoc_undertest.c +) + +set(${theseTestsName}_h_files +) + +build_test_artifacts(${theseTestsName} ON) diff --git a/c/sharedutil/tests/gballoc_without_init_unittests/gballoc_undertest.c b/c/sharedutil/tests/gballoc_without_init_unittests/gballoc_undertest.c new file mode 100644 index 00000000..00e4ef8f --- /dev/null +++ b/c/sharedutil/tests/gballoc_without_init_unittests/gballoc_undertest.c @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include +#define malloc mock_malloc +#define calloc mock_calloc +#define realloc mock_realloc +#define free mock_free + +extern void* mock_malloc(size_t size); +extern void* mock_calloc(size_t nmemb, size_t size); +extern void* mock_realloc(void* ptr, size_t size); +extern void mock_free(void* ptr); + +#undef _CRTDBG_MAP_ALLOC +#include "../src/gballoc.c" diff --git a/c/sharedutil/tests/gballoc_without_init_unittests/gballoc_without_init_unittests.cpp b/c/sharedutil/tests/gballoc_without_init_unittests/gballoc_without_init_unittests.cpp new file mode 100644 index 00000000..7bd915a8 --- /dev/null +++ b/c/sharedutil/tests/gballoc_without_init_unittests/gballoc_without_init_unittests.cpp @@ -0,0 +1,208 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include +#ifdef _CRTDBG_MAP_ALLOC +#include +#endif +#include "gballoc.h" +#include "testrunnerswitcher.h" +#include "micromock.h" +#include "lock.h" + +#ifndef SIZE_MAX +#define SIZE_MAX ((size_t)~(size_t)0) +#endif + + +static MICROMOCK_MUTEX_HANDLE g_testByTest; + +static void* TEST_ALLOC_PTR1 = (void*)0x4242; +static const LOCK_HANDLE TEST_LOCK_HANDLE = (LOCK_HANDLE)0x4244; + +TYPED_MOCK_CLASS(CGBAllocMocks, CGlobalMock) +{ +public: + MOCK_STATIC_METHOD_1(, void*, mock_malloc, size_t, size) + MOCK_METHOD_END(void*, TEST_ALLOC_PTR1) + MOCK_STATIC_METHOD_2(, void*, mock_calloc, size_t, nmemb, size_t, size) + MOCK_METHOD_END(void*, TEST_ALLOC_PTR1) + MOCK_STATIC_METHOD_2(, void*, mock_realloc, void*, ptr, size_t, size) + MOCK_METHOD_END(void*, TEST_ALLOC_PTR1) + MOCK_STATIC_METHOD_1(, void, mock_free, void*, ptr) + MOCK_VOID_METHOD_END() + + /* Lock Mocks */ + MOCK_STATIC_METHOD_0(, LOCK_HANDLE, Lock_Init) + MOCK_METHOD_END(LOCK_HANDLE, TEST_LOCK_HANDLE) + MOCK_STATIC_METHOD_1(, LOCK_RESULT, Lock_Deinit, LOCK_HANDLE, handle) + MOCK_METHOD_END(LOCK_RESULT, LOCK_OK) + MOCK_STATIC_METHOD_1(, LOCK_RESULT, Lock, LOCK_HANDLE, handle) + MOCK_METHOD_END(LOCK_RESULT, LOCK_OK) + MOCK_STATIC_METHOD_1(, LOCK_RESULT, Unlock, LOCK_HANDLE, handle) + MOCK_METHOD_END(LOCK_RESULT, LOCK_OK) +}; + +extern "C" +{ + DECLARE_GLOBAL_MOCK_METHOD_1(CGBAllocMocks, , void*, mock_malloc, size_t, size); + DECLARE_GLOBAL_MOCK_METHOD_2(CGBAllocMocks, , void*, mock_calloc, size_t, nmemb, size_t, size); + DECLARE_GLOBAL_MOCK_METHOD_2(CGBAllocMocks, , void*, mock_realloc, void*, ptr, size_t, size); + DECLARE_GLOBAL_MOCK_METHOD_1(CGBAllocMocks, , void, mock_free, void*, ptr); + + DECLARE_GLOBAL_MOCK_METHOD_0(CGBAllocMocks, , LOCK_HANDLE, Lock_Init); + DECLARE_GLOBAL_MOCK_METHOD_1(CGBAllocMocks, , LOCK_RESULT, Lock_Deinit, LOCK_HANDLE, handle); + DECLARE_GLOBAL_MOCK_METHOD_1(CGBAllocMocks, , LOCK_RESULT, Lock, LOCK_HANDLE, handle); + DECLARE_GLOBAL_MOCK_METHOD_1(CGBAllocMocks, , LOCK_RESULT, Unlock, LOCK_HANDLE, handle); +} + +static MICROMOCK_GLOBAL_SEMAPHORE_HANDLE g_dllByDll; + +BEGIN_TEST_SUITE(GBAlloc_For_Init_UnitTests) + +TEST_SUITE_INITIALIZE(TestClassInitialize) +{ + INITIALIZE_MEMORY_DEBUG(g_dllByDll); + + g_testByTest = MicroMockCreateMutex(); + ASSERT_IS_NOT_NULL(g_testByTest); +} + +TEST_SUITE_CLEANUP(TestClassCleanup) +{ + MicroMockDestroyMutex(g_testByTest); + + DEINITIALIZE_MEMORY_DEBUG(g_dllByDll); + +} + +TEST_FUNCTION_INITIALIZE(TestMethodInitialize) +{ + if (!MicroMockAcquireMutex(g_testByTest)) + { + ASSERT_FAIL("our mutex is ABANDONED. Failure in test framework"); + } +} + +TEST_FUNCTION_CLEANUP(TestMethodCleanup) +{ + if (!MicroMockReleaseMutex(g_testByTest)) + { + ASSERT_FAIL("failure in test framework at ReleaseMutex"); + } +} + +/* gballoc_deinit */ + +/* Tests_SRS_GBALLOC_01_029: [if gballoc is not initialized gballoc_deinit shall do nothing.] */ +TEST_FUNCTION(when_gballoc_is_not_initialized_gballoc_deinit_doesnot_free_lock) +{ + //arrange + CGBAllocMocks mocks; + + // act + gballoc_deinit(); + + // assert + // no explicit assert, uMock checks the calls +} + +/* gballoc_malloc */ + +/* Tests_SRS_GBALLOC_01_039: [If gballoc was not initialized gballoc_malloc shall simply call malloc without any memory tracking being performed.] */ +TEST_FUNCTION(when_gballoc_is_not_initialized_gballoc_malloc_calls_crt_malloc) +{ + // arrange + CGBAllocMocks mocks; + + STRICT_EXPECTED_CALL(mocks, mock_malloc(1)); + + //act + void* result = gballoc_malloc(1); + + //assert + ASSERT_IS_NOT_NULL(result); +} + +/* gballoc_calloc */ + +/* Tests_SRS_GBALLOC_01_040: [If gballoc was not initialized gballoc_calloc shall simply call calloc without any memory tracking being performed.] */ +TEST_FUNCTION(when_gballoc_is_not_initialized_then_gballoc_calloc_calls_crt_calloc) +{ + // arrange + CGBAllocMocks mocks; + + STRICT_EXPECTED_CALL(mocks, mock_calloc(1, 1)); + + // act + void* result = gballoc_calloc(1, 1); + + // assert + ASSERT_IS_NOT_NULL(result); +} + +/* gballoc_realloc */ + +/* Tests_SRS_GBALLOC_01_041: [If gballoc was not initialized gballoc_realloc shall shall simply call realloc without any memory tracking being performed.] */ +TEST_FUNCTION(when_gballoc_is_not_initialized_then_gballoc_realloc_calls_crt_realloc) +{ + // arrange + CGBAllocMocks mocks; + + STRICT_EXPECTED_CALL(mocks, mock_realloc(NULL, 1)); + + // act + void* result = gballoc_realloc(NULL, 1); + + // assert + ASSERT_IS_NOT_NULL(result); +} + +/* gballoc_free */ + +/* Tests_SRS_GBALLOC_01_042: [If gballoc was not initialized gballoc_free shall shall simply call free.] */ +TEST_FUNCTION(when_gballoc_is_not_initialized_then_gballoc_free_does_nothing) +{ + // arrange + CGBAllocMocks mocks; + + STRICT_EXPECTED_CALL(mocks, mock_free((void*)0x4242)); + + // act + gballoc_free((void*)0x4242); + + // assert + // no explicit assert, uMock checks the calls +} + +/* gballoc_getMaximumMemoryUsed */ + +/* Tests_SRS_GBALLOC_01_038: [If gballoc was not initialized gballoc_getMaximumMemoryUsed shall return MAX_INT_SIZE.] */ +TEST_FUNCTION(without_gballoc_being_initialized_gballoc_getMaximumMemoryUsed_fails) +{ + // arrange + CGBAllocMocks mocks; + + // act + size_t result = gballoc_getMaximumMemoryUsed(); + + // assert + ASSERT_ARE_EQUAL(size_t, SIZE_MAX, result); +} + +/* gballoc_getCurrentMemoryUsed */ + +/* Tests_SRS_GBALLOC_01_044: [If gballoc was not initialized gballoc_getCurrentMemoryUsed shall return SIZE_MAX.] */ +TEST_FUNCTION(without_gballoc_being_initialized_gballoc_getCurrentMemoryUsed_fails) +{ + // arrange + CGBAllocMocks mocks; + + // act + size_t result = gballoc_getCurrentMemoryUsed(); + + // assert + ASSERT_ARE_EQUAL(size_t, SIZE_MAX, result); +} + +END_TEST_SUITE(GBAlloc_For_Init_UnitTests) diff --git a/c/sharedutil/tests/gballoc_without_init_unittests/main.c b/c/sharedutil/tests/gballoc_without_init_unittests/main.c new file mode 100644 index 00000000..fcd146ec --- /dev/null +++ b/c/sharedutil/tests/gballoc_without_init_unittests/main.c @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include "testrunnerswitcher.h" + +int main(void) +{ + size_t failedTestCount = 0; + RUN_TEST_SUITE(GBAlloc_For_Init_UnitTests, failedTestCount); + return failedTestCount; +} diff --git a/c/sharedutil/tests/hmacsha256_unittests/CMakeLists.txt b/c/sharedutil/tests/hmacsha256_unittests/CMakeLists.txt new file mode 100644 index 00000000..12191e45 --- /dev/null +++ b/c/sharedutil/tests/hmacsha256_unittests/CMakeLists.txt @@ -0,0 +1,30 @@ +#Copyright (c) Microsoft. All rights reserved. +#Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#this is CMakeLists.txt for hmacsha256_unittests +cmake_minimum_required(VERSION 3.0) + +compileAsC99() +set(theseTestsName hmacsha256_unittests) + +set(${theseTestsName}_cpp_files +${theseTestsName}.cpp +) + +set(${theseTestsName}_c_files +../../src/hmacsha256.c +../../src/hmac.c +../../src/usha.c +../../src/sha1.c +../../src/sha224.c +../../src/sha384-512.c + +../../src/gballoc.c +${LOCK_C_FILE} +../../src/buffer.c +) + +set(${theseTestsName}_h_files +) + +build_test_artifacts(${theseTestsName} ON) \ No newline at end of file diff --git a/c/sharedutil/tests/hmacsha256_unittests/hmacsha256_unittests.cpp b/c/sharedutil/tests/hmacsha256_unittests/hmacsha256_unittests.cpp new file mode 100644 index 00000000..066591cd --- /dev/null +++ b/c/sharedutil/tests/hmacsha256_unittests/hmacsha256_unittests.cpp @@ -0,0 +1,141 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include +#ifdef _CRTDBG_MAP_ALLOC +#include +#endif + +#include "testrunnerswitcher.h" +#include "hmacsha256.h" +#include "strings.h" +#include "micromock.h" +#include "micromockcharstararenullterminatedstrings.h" + + +static MICROMOCK_MUTEX_HANDLE g_testByTest; + +DEFINE_MICROMOCK_ENUM_TO_STRING(HMACSHA256_RESULT, HMACSHA256_RESULT_VALUES); + +static BUFFER_HANDLE hash; + +static MICROMOCK_GLOBAL_SEMAPHORE_HANDLE g_dllByDll; + +BEGIN_TEST_SUITE(HMACSHA256_UnitTests) + +TEST_SUITE_INITIALIZE(TestClassInitialize) +{ + INITIALIZE_MEMORY_DEBUG(g_dllByDll); + + g_testByTest = MicroMockCreateMutex(); + ASSERT_IS_NOT_NULL(g_testByTest); +} + +TEST_SUITE_CLEANUP(TestClassCleanup) +{ + MicroMockDestroyMutex(g_testByTest); + DEINITIALIZE_MEMORY_DEBUG(g_dllByDll); + +} + +TEST_FUNCTION_INITIALIZE(TestMethodInitialize) +{ + if (!MicroMockAcquireMutex(g_testByTest)) + { + ASSERT_FAIL("our mutex is ABANDONED. Failure in test framework"); + } + hash = BUFFER_new(); +} + +TEST_FUNCTION_CLEANUP(TestMethodCleanup) +{ + BUFFER_delete(hash); + if (!MicroMockReleaseMutex(g_testByTest)) + { + ASSERT_FAIL("failure in test framework at ReleaseMutex"); + } +} + +/* HMACSHA256_ComputeHash */ + +TEST_FUNCTION(HMACSHA256_ComputeHash_With_NULL_Key_Fails) +{ + // arrange + static const unsigned char key[] = "key"; + static const unsigned char buffer[] = "testPayload"; + + // act + HMACSHA256_RESULT result = HMACSHA256_ComputeHash(NULL, sizeof(key) - 1, buffer, sizeof(buffer) - 1, hash); + + // assert + ASSERT_ARE_EQUAL(HMACSHA256_RESULT, HMACSHA256_INVALID_ARG, result); +} + +TEST_FUNCTION(HMACSHA256_ComputeHash_With_Zero_Key_Buffer_Size_Fails) +{ + // arrange + static const unsigned char key[] = "key"; + static const unsigned char buffer[] = "testPayload"; + + // act + HMACSHA256_RESULT result = HMACSHA256_ComputeHash(key, 0, buffer, sizeof(buffer) - 1, hash); + + // assert + ASSERT_ARE_EQUAL(HMACSHA256_RESULT, HMACSHA256_INVALID_ARG, result); +} + +TEST_FUNCTION(HMACSHA256_ComputeHash_With_NULL_Payload_Fails) +{ + // arrange + static const unsigned char key[] = "key"; + static const unsigned char buffer[] = "testPayload"; + + // act + HMACSHA256_RESULT result = HMACSHA256_ComputeHash(key, sizeof(key) - 1, NULL, sizeof(buffer) - 1, hash); + + // assert + ASSERT_ARE_EQUAL(HMACSHA256_RESULT, HMACSHA256_INVALID_ARG, result); +} + +TEST_FUNCTION(HMACSHA256_ComputeHash_With_Zero_Payload_Buffer_Size_Fails) +{ + // arrange + static const unsigned char key[] = "key"; + static const unsigned char buffer[] = "testPayload"; + + // act + HMACSHA256_RESULT result = HMACSHA256_ComputeHash(key, sizeof(key) - 1, buffer, 0, hash); + + // assert + ASSERT_ARE_EQUAL(HMACSHA256_RESULT, HMACSHA256_INVALID_ARG, result); +} + +TEST_FUNCTION(HMACSHA256_ComputeHash_With_NULL_Hash_Fails) +{ + // arrange + static const unsigned char key[] = "key"; + static const unsigned char buffer[] = "testPayload"; + + // act + HMACSHA256_RESULT result = HMACSHA256_ComputeHash(key, sizeof(key) - 1, buffer, sizeof(buffer) - 1, NULL); + + // assert + ASSERT_ARE_EQUAL(HMACSHA256_RESULT, HMACSHA256_INVALID_ARG, result); +} + +TEST_FUNCTION(HMACSHA256_ComputeHash_Succeeds) +{ + // arrange + static const unsigned char key[] = "key"; + static const unsigned char buffer[] = "testPayload"; + unsigned char expectedHash[32] = { 108, 7, 130, 47, 104, 233, 39, 188, 126, 122, 134, 187, 63, 19, 52, 120, 172, 7, 43, 25, 133, 60, 92, 217, 59, 59, 69, 116, 85, 104, 55, 224 }; + + // act + HMACSHA256_RESULT result = HMACSHA256_ComputeHash(key, sizeof(key) - 1, buffer, sizeof(buffer) - 1, hash); + + // assert + ASSERT_ARE_EQUAL(HMACSHA256_RESULT, HMACSHA256_OK, result); + ASSERT_ARE_EQUAL(int, 0, memcmp(BUFFER_u_char(hash), expectedHash, 8)); +} + +END_TEST_SUITE(HMACSHA256_UnitTests) diff --git a/c/sharedutil/tests/hmacsha256_unittests/main.c b/c/sharedutil/tests/hmacsha256_unittests/main.c new file mode 100644 index 00000000..86d56d60 --- /dev/null +++ b/c/sharedutil/tests/hmacsha256_unittests/main.c @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include "testrunnerswitcher.h" + +int main(void) +{ + size_t failedTestCount = 0; + RUN_TEST_SUITE(HMACSHA256_UnitTests, failedTestCount); + return failedTestCount; +} diff --git a/c/sharedutil/tests/httpapiex_unittests/CMakeLists.txt b/c/sharedutil/tests/httpapiex_unittests/CMakeLists.txt new file mode 100644 index 00000000..e2540709 --- /dev/null +++ b/c/sharedutil/tests/httpapiex_unittests/CMakeLists.txt @@ -0,0 +1,26 @@ +#Copyright (c) Microsoft. All rights reserved. +#Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#this is CMakeLists.txt for httpapiex_unittests +cmake_minimum_required(VERSION 3.0) + +if(NOT ${use_http}) + message(FATAL_ERROR "httpapiex_unittests being generated without HTTP support") +endif() + +compileAsC99() +set(theseTestsName httpapiex_unittests ) + +set(${theseTestsName}_cpp_files +${theseTestsName}.cpp +) + +set(${theseTestsName}_c_files +../../src/httpapiex.c +../../src/crt_abstractions.c +) + +set(${theseTestsName}_h_files +) + +build_test_artifacts(${theseTestsName} ON) \ No newline at end of file diff --git a/c/sharedutil/tests/httpapiex_unittests/httpapiex_unittests.cpp b/c/sharedutil/tests/httpapiex_unittests/httpapiex_unittests.cpp new file mode 100644 index 00000000..d97e7bd3 --- /dev/null +++ b/c/sharedutil/tests/httpapiex_unittests/httpapiex_unittests.cpp @@ -0,0 +1,3452 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include +#ifdef _CRTDBG_MAP_ALLOC +#include +#endif + +#include "testrunnerswitcher.h" +#include "micromock.h" +#include "micromockcharstararenullterminatedstrings.h" +/*the below is a horrible hack*/ +#include "macro_utils.h" +#undef DEFINE_ENUM +#define DEFINE_ENUM(enumName, ...) typedef enum C2(enumName, _TAG) { FOR_EACH_1(DEFINE_ENUMERATION_CONSTANT, __VA_ARGS__)} enumName; + +#include "map.h" +#include "httpapiex.h" +#include "lock.h" +#include "strings.h" +#include "crt_abstractions.h" +#include "vector.h" + + + +DEFINE_MICROMOCK_ENUM_TO_STRING(HTTPAPIEX_RESULT, HTTPAPIEX_RESULT_VALUES); + +#define GBALLOC_H + +extern "C" int gballoc_init(void); +extern "C" void gballoc_deinit(void); +extern "C" void* gballoc_malloc(size_t size); +extern "C" void* gballoc_calloc(size_t nmemb, size_t size); +extern "C" void* gballoc_realloc(void* ptr, size_t size); +extern "C" void gballoc_free(void* ptr); + + +namespace BASEIMPLEMENTATION +{ + /*if malloc is defined as gballoc_malloc at this moment, there'd be serious trouble*/ +#define Lock(x) (LOCK_OK + gballocState - gballocState) /*compiler warning about constant in if condition*/ +#define Unlock(x) (LOCK_OK + gballocState - gballocState) +#define Lock_Init() (LOCK_HANDLE)0x42 +#define Lock_Deinit(x) (LOCK_OK + gballocState - gballocState) +#include "gballoc.c" +#undef Lock +#undef Unlock +#undef Lock_Init +#undef Lock_Deinit + +#include "strings.c" +#include "buffer.c" +#include "vector.c" +}; + +static size_t currentmalloc_call; +static size_t whenShallmalloc_fail; + +static size_t currentrealloc_call; +static size_t whenShallrealloc_fail; + +static size_t currentHTTPAPI_SaveOption_call; +static size_t whenShallHTTPAPI_SaveOption_fail; + +/*different STRING constructors*/ +static size_t currentSTRING_new_call; +static size_t whenShallSTRING_new_fail; + +static size_t currentSTRING_clone_call; +static size_t whenShallSTRING_clone_fail; + +static size_t currentSTRING_construct_call; +static size_t whenShallSTRING_construct_fail; + +static size_t currentSTRING_concat_call; +static size_t whenShallSTRING_concat_fail; + +static size_t currentSTRING_empty_call; +static size_t whenShallSTRING_empty_fail; + +static size_t currentSTRING_concat_with_STRING_call; +static size_t whenShallSTRING_concat_with_STRING_fail; + +static size_t currentBUFFER_new_call; +static size_t whenShallBUFFER_new_fail; + +static size_t currentBUFFER_build_call; +static size_t whenShallBUFFER_build_fail; + +static size_t currentBUFFER_content_call; +static size_t whenShallBUFFER_content_fail; + +static size_t currentBUFFER_size_call; +static size_t whenShallBUFFER_size_fail; + +static size_t currentHTTPHeaders_Alloc_call; +static size_t whenShallHTTPHeaders_Alloc_fail; + +static size_t currentVECTOR_create_call; +static size_t whenShallVECTOR_create_fail; + +static size_t currentVECTOR_push_back_call; +static size_t whenShallVECTOR_push_back_fail; + +#define N_MAX_FAILS 5 +static size_t currentHTTPAPI_CreateConnection_call; +static size_t whenShallHTTPAPI_CreateConnection_fail[N_MAX_FAILS]; + +static size_t currentHTTPAPI_Init_call; +static size_t whenShallHTTPAPI_Init_fail[N_MAX_FAILS]; +static size_t HTTPAPI_Init_calls; + +#define TEST_HOSTNAME "aaa" +#define TEST_RELATIVE_PATH "nothing/to/see/here/devices" +#define TEST_REQUEST_HTTP_HEADERS (HTTP_HEADERS_HANDLE) 0x42 +#define TEST_REQUEST_BODY (BUFFER_HANDLE) 0x43 +#define TEST_RESPONSE_HTTP_HEADERS (HTTP_HEADERS_HANDLE) 0x45 +#define TEST_RESPONSE_BODY (BUFFER_HANDLE) 0x46 +#define TEST_HTTP_HEADERS_HANDLE (HTTP_HEADERS_HANDLE) 0x47 +#define TEST_BUFFER "333333" +#define TEST_BUFFER_SIZE 6 + +TYPED_MOCK_CLASS(CHTTPAPIEXMocks, CGlobalMock) +{ +public: + + MOCK_STATIC_METHOD_1(, void*, gballoc_malloc, size_t, size) + void* result2; + currentmalloc_call++; + if (whenShallmalloc_fail>0) + { + if (currentmalloc_call == whenShallmalloc_fail) + { + result2 = (STRING_HANDLE)NULL; + } + else + { + result2 = BASEIMPLEMENTATION::gballoc_malloc(size); + } + } + else + { + result2 = BASEIMPLEMENTATION::gballoc_malloc(size); + } + MOCK_METHOD_END(void*, result2); + + MOCK_STATIC_METHOD_2(, void*, gballoc_realloc, void*, ptr, size_t, size) + void* result2; + currentrealloc_call++; + if (whenShallrealloc_fail>0) + { + if (currentrealloc_call == whenShallrealloc_fail) + { + result2 = (STRING_HANDLE)NULL; + } + else + { + result2 = BASEIMPLEMENTATION::gballoc_realloc(ptr,size); + } + } + else + { + result2 = BASEIMPLEMENTATION::gballoc_realloc(ptr, size); + } + MOCK_METHOD_END(void*,result2); + + MOCK_STATIC_METHOD_1(, void, gballoc_free, void*, ptr) + BASEIMPLEMENTATION::gballoc_free(ptr); + MOCK_VOID_METHOD_END() + + /*Strings*/ + MOCK_STATIC_METHOD_0(, STRING_HANDLE, STRING_new) + STRING_HANDLE result2; + currentSTRING_new_call++; + if (whenShallSTRING_new_fail > 0) + { + if (currentSTRING_new_call == whenShallSTRING_new_fail) + { + result2 = (STRING_HANDLE)NULL; + } + else + { + result2 = BASEIMPLEMENTATION::STRING_new(); + } + } + else + { + result2 = BASEIMPLEMENTATION::STRING_new(); + } + MOCK_METHOD_END(STRING_HANDLE, result2) + + MOCK_STATIC_METHOD_1(, STRING_HANDLE, STRING_clone, STRING_HANDLE, handle) + STRING_HANDLE result2; + currentSTRING_clone_call++; + if (whenShallSTRING_clone_fail > 0) + { + if (currentSTRING_clone_call == whenShallSTRING_clone_fail) + { + result2 = (STRING_HANDLE)NULL; + } + else + { + result2 = BASEIMPLEMENTATION::STRING_clone(handle); + } + } + else + { + result2 = BASEIMPLEMENTATION::STRING_clone(handle); + } + MOCK_METHOD_END(STRING_HANDLE, result2) + + MOCK_STATIC_METHOD_1(, STRING_HANDLE, STRING_construct, const char*, source) + STRING_HANDLE result2; + currentSTRING_construct_call++; + if (whenShallSTRING_construct_fail > 0) + { + if (currentSTRING_construct_call == whenShallSTRING_construct_fail) + { + result2 = (STRING_HANDLE)NULL; + } + else + { + result2 = BASEIMPLEMENTATION::STRING_construct(source); + } + } + else + { + result2 = BASEIMPLEMENTATION::STRING_construct(source); + } + MOCK_METHOD_END(STRING_HANDLE, result2) + + MOCK_STATIC_METHOD_1(, void, STRING_delete, STRING_HANDLE, s) + BASEIMPLEMENTATION::STRING_delete(s); + MOCK_VOID_METHOD_END() + + MOCK_STATIC_METHOD_2(, int, STRING_concat, STRING_HANDLE, s1, const char*, s2) + currentSTRING_concat_call++; + MOCK_METHOD_END(int, (((whenShallSTRING_concat_fail > 0) && (currentSTRING_concat_call == whenShallSTRING_concat_fail)) ? __LINE__ : BASEIMPLEMENTATION::STRING_concat(s1, s2))); + + MOCK_STATIC_METHOD_2(, int, STRING_concat_with_STRING, STRING_HANDLE, s1, STRING_HANDLE, s2) + currentSTRING_concat_with_STRING_call++; + MOCK_METHOD_END(int, (((currentSTRING_concat_with_STRING_call > 0) && (currentSTRING_concat_with_STRING_call == whenShallSTRING_concat_with_STRING_fail)) ? __LINE__ : BASEIMPLEMENTATION::STRING_concat_with_STRING(s1, s2))); + + MOCK_STATIC_METHOD_1(, int, STRING_empty, STRING_HANDLE, s) + currentSTRING_concat_call++; + MOCK_METHOD_END(int, BASEIMPLEMENTATION::STRING_empty(s)); + + MOCK_STATIC_METHOD_1(, const char*, STRING_c_str, STRING_HANDLE, s) + MOCK_METHOD_END(const char*, BASEIMPLEMENTATION::STRING_c_str(s)) + + /* HTTPHeaders mocks */ + MOCK_STATIC_METHOD_0(, HTTP_HEADERS_HANDLE, HTTPHeaders_Alloc) + HTTP_HEADERS_HANDLE result2; + currentHTTPHeaders_Alloc_call++; + if ((whenShallHTTPHeaders_Alloc_fail > 0) && (whenShallHTTPHeaders_Alloc_fail == currentHTTPHeaders_Alloc_call)) + { + result2 = NULL; + } + else + { + result2 = malloc(1); + } + MOCK_METHOD_END(HTTP_HEADERS_HANDLE, result2) + + MOCK_STATIC_METHOD_1(, void, HTTPHeaders_Free, HTTP_HEADERS_HANDLE, httpHeadersHandle) + free(httpHeadersHandle); + MOCK_VOID_METHOD_END() + + MOCK_STATIC_METHOD_3(, HTTP_HEADERS_RESULT, HTTPHeaders_AddHeaderNameValuePair, HTTP_HEADERS_HANDLE, httpHeadersHandle, const char*, name, const char*, value) + MOCK_METHOD_END(HTTP_HEADERS_RESULT, HTTP_HEADERS_OK) + + MOCK_STATIC_METHOD_3(, HTTP_HEADERS_RESULT, HTTPHeaders_ReplaceHeaderNameValuePair, HTTP_HEADERS_HANDLE, httpHeadersHandle, const char*, name, const char*, value) + MOCK_METHOD_END(HTTP_HEADERS_RESULT, HTTP_HEADERS_OK) + + /* BUFFER Mocks */ + MOCK_STATIC_METHOD_0(, BUFFER_HANDLE, BUFFER_new) + BUFFER_HANDLE result2; + currentBUFFER_new_call++; + if (whenShallBUFFER_new_fail > 0) + { + if (currentBUFFER_new_call == whenShallBUFFER_new_fail) + { + result2 = (BUFFER_HANDLE)NULL; + } + else + { + result2 = BASEIMPLEMENTATION::BUFFER_new(); + } + } + else + { + result2 = BASEIMPLEMENTATION::BUFFER_new(); + } + MOCK_METHOD_END(BUFFER_HANDLE, result2) + + MOCK_STATIC_METHOD_1(, void, BUFFER_delete, BUFFER_HANDLE, s) + BASEIMPLEMENTATION::BUFFER_delete(s); + MOCK_VOID_METHOD_END() + + MOCK_STATIC_METHOD_1(, unsigned char*, BUFFER_u_char, BUFFER_HANDLE, handle); + unsigned char* result2; + result2 = BASEIMPLEMENTATION::BUFFER_u_char(handle); + MOCK_METHOD_END(unsigned char*, result2) + + MOCK_STATIC_METHOD_1(, size_t, BUFFER_length, BUFFER_HANDLE, handle); + size_t result2; + result2 = BASEIMPLEMENTATION::BUFFER_length(handle); + MOCK_METHOD_END(size_t, result2) + + MOCK_STATIC_METHOD_3(, int, BUFFER_build, BUFFER_HANDLE, handle, const unsigned char*, source, size_t, size) + MOCK_METHOD_END(int, BASEIMPLEMENTATION::BUFFER_build(handle, source, size)) + + /* HTTPAPI mocks */ + + MOCK_STATIC_METHOD_0(, HTTPAPI_RESULT, HTTPAPI_Init) + HTTPAPI_RESULT result2; + currentHTTPAPI_Init_call++; + size_t i; + for (i = 0; i < N_MAX_FAILS; i++) + { + if (whenShallHTTPAPI_Init_fail[i] > 0) + { + if (currentHTTPAPI_Init_call == whenShallHTTPAPI_Init_fail[i]) + { + break; + } + } + } + + if (i == N_MAX_FAILS) + { + HTTPAPI_Init_calls++; + result2 = HTTPAPI_OK; + } + else + { + result2 = HTTPAPI_ERROR; + } + MOCK_METHOD_END(HTTPAPI_RESULT, result2) + + MOCK_STATIC_METHOD_0(, void, HTTPAPI_Deinit) + HTTPAPI_Init_calls--; + MOCK_VOID_METHOD_END() + + MOCK_STATIC_METHOD_1(, HTTP_HANDLE, HTTPAPI_CreateConnection, const char*, hostName) + HTTP_HANDLE result2; + currentHTTPAPI_CreateConnection_call++; + size_t i; + for (i = 0; i < N_MAX_FAILS; i++) + { + if (whenShallHTTPAPI_CreateConnection_fail[i] > 0) + { + if (currentHTTPAPI_CreateConnection_call == whenShallHTTPAPI_CreateConnection_fail[i]) + { + result2 = (HTTP_HANDLE)NULL; + break; + } + } + } + + if (i==N_MAX_FAILS) + { + result2 = malloc(1); + } + MOCK_METHOD_END(HTTP_HANDLE, result2) + + MOCK_STATIC_METHOD_1(, void, HTTPAPI_CloseConnection, HTTP_HANDLE, handle) + free(handle); + MOCK_VOID_METHOD_END() + + MOCK_STATIC_METHOD_9(, HTTPAPI_RESULT, HTTPAPI_ExecuteRequest, HTTP_HANDLE, handle, HTTPAPI_REQUEST_TYPE, requestType, const char*, relativePath, + HTTP_HEADERS_HANDLE, httpHeadersHandle, const unsigned char*, content, size_t, contentLength, unsigned int*, statusCode, + HTTP_HEADERS_HANDLE, responseHeadersHandle, BUFFER_HANDLE, responseContent) + MOCK_METHOD_END(HTTPAPI_RESULT, HTTPAPI_OK) + + MOCK_STATIC_METHOD_3(, HTTPAPI_RESULT, HTTPAPI_SetOption, HTTP_HANDLE, handle, const char*, optionName, const void*, value) + MOCK_METHOD_END(HTTPAPI_RESULT, HTTPAPI_OK) + + MOCK_STATIC_METHOD_3(, HTTPAPI_RESULT, HTTPAPI_CloneOption, const char*, optionName, const void*, value, const void**, savedValue) + HTTPAPI_RESULT result2; + currentHTTPAPI_SaveOption_call++; + if (currentHTTPAPI_SaveOption_call == whenShallHTTPAPI_SaveOption_fail) + { + result2 = HTTPAPI_ERROR; + } + else + { + result2 = HTTPAPI_OK; + if (strcmp("someOption", optionName) == 0) + { + char* temp; + temp = (char *)BASEIMPLEMENTATION::gballoc_malloc(strlen((const char*)value) + 1); + strcpy(temp, (const char*)value); + *savedValue = temp; + } + else if (strcmp("someOption1", optionName) == 0) + { + char* temp; + temp = (char *)BASEIMPLEMENTATION::gballoc_malloc(strlen((const char*)value) + 1); + strcpy(temp, (const char*)value); + *savedValue = temp; + } + else if (strcmp("someOption2", optionName) == 0) + { + char* temp; + temp = (char *)BASEIMPLEMENTATION::gballoc_malloc(strlen((const char*)value) + 1); + strcpy(temp, (const char*)value); + *savedValue = temp; + } + else + { + result2 = HTTPAPI_INVALID_ARG; + } + } + MOCK_METHOD_END(HTTPAPI_RESULT, result2) + + MOCK_STATIC_METHOD_1(, VECTOR_HANDLE, VECTOR_create, size_t, elementSize) + VECTOR_HANDLE result2; + currentVECTOR_create_call++; + if (currentVECTOR_create_call == whenShallVECTOR_create_fail) + { + result2 = NULL; + } + else + { + result2 = BASEIMPLEMENTATION::VECTOR_create(elementSize); + } + MOCK_METHOD_END(VECTOR_HANDLE, result2) + + MOCK_STATIC_METHOD_1(, void, VECTOR_destroy, VECTOR_HANDLE, handle) + BASEIMPLEMENTATION::VECTOR_destroy(handle); + MOCK_VOID_METHOD_END() + + MOCK_STATIC_METHOD_3(, int, VECTOR_push_back, VECTOR_HANDLE, handle, const void*, elements, size_t, numElements) + int result2; + currentVECTOR_push_back_call++; + if (currentVECTOR_push_back_call == whenShallVECTOR_push_back_fail) + { + result2 = __LINE__; + } + else + { + result2 = BASEIMPLEMENTATION::VECTOR_push_back(handle, elements, numElements); + } + MOCK_METHOD_END(int, result2) + + MOCK_STATIC_METHOD_2(, void*, VECTOR_element, VECTOR_HANDLE, handle, size_t, index) + MOCK_METHOD_END(void*, BASEIMPLEMENTATION::VECTOR_element(handle, index)) + + MOCK_STATIC_METHOD_3(, void*, VECTOR_find_if, VECTOR_HANDLE, handle, PREDICATE_FUNCTION, pred, const void*, value) + MOCK_METHOD_END(void*, BASEIMPLEMENTATION::VECTOR_find_if(handle, pred, value)) + + MOCK_STATIC_METHOD_1(, size_t, VECTOR_size, VECTOR_HANDLE, handle) + MOCK_METHOD_END(size_t, BASEIMPLEMENTATION::VECTOR_size(handle)) +}; + +DECLARE_GLOBAL_MOCK_METHOD_1(CHTTPAPIEXMocks, , void*, gballoc_malloc, size_t, size); +DECLARE_GLOBAL_MOCK_METHOD_2(CHTTPAPIEXMocks, , void*, gballoc_realloc, void*, ptr, size_t, size); +DECLARE_GLOBAL_MOCK_METHOD_1(CHTTPAPIEXMocks, , void, gballoc_free, void*, ptr); + +DECLARE_GLOBAL_MOCK_METHOD_0(CHTTPAPIEXMocks, , STRING_HANDLE, STRING_new); +DECLARE_GLOBAL_MOCK_METHOD_1(CHTTPAPIEXMocks, , STRING_HANDLE, STRING_clone, STRING_HANDLE, handle); +DECLARE_GLOBAL_MOCK_METHOD_1(CHTTPAPIEXMocks, , STRING_HANDLE, STRING_construct, const char*, s); + +DECLARE_GLOBAL_MOCK_METHOD_1(CHTTPAPIEXMocks, , void, STRING_delete, STRING_HANDLE, s); +DECLARE_GLOBAL_MOCK_METHOD_2(CHTTPAPIEXMocks, , int, STRING_concat, STRING_HANDLE, s1, const char*, s2); +DECLARE_GLOBAL_MOCK_METHOD_2(CHTTPAPIEXMocks, , int, STRING_concat_with_STRING, STRING_HANDLE, s1, STRING_HANDLE, s2); +DECLARE_GLOBAL_MOCK_METHOD_1(CHTTPAPIEXMocks, , int, STRING_empty, STRING_HANDLE, s1); +DECLARE_GLOBAL_MOCK_METHOD_1(CHTTPAPIEXMocks, , const char*, STRING_c_str, STRING_HANDLE, s); + +DECLARE_GLOBAL_MOCK_METHOD_0(CHTTPAPIEXMocks, , HTTP_HEADERS_HANDLE, HTTPHeaders_Alloc); +DECLARE_GLOBAL_MOCK_METHOD_1(CHTTPAPIEXMocks, , void, HTTPHeaders_Free, HTTP_HEADERS_HANDLE, httpHeadersHandle); +DECLARE_GLOBAL_MOCK_METHOD_3(CHTTPAPIEXMocks, , HTTP_HEADERS_RESULT, HTTPHeaders_AddHeaderNameValuePair, HTTP_HEADERS_HANDLE, httpHeadersHandle, const char*, name, const char*, value); +DECLARE_GLOBAL_MOCK_METHOD_3(CHTTPAPIEXMocks, , HTTP_HEADERS_RESULT, HTTPHeaders_ReplaceHeaderNameValuePair, HTTP_HEADERS_HANDLE, httpHeadersHandle, const char*, name, const char*, value); + +DECLARE_GLOBAL_MOCK_METHOD_0(CHTTPAPIEXMocks, , BUFFER_HANDLE, BUFFER_new); +DECLARE_GLOBAL_MOCK_METHOD_1(CHTTPAPIEXMocks, , void, BUFFER_delete, BUFFER_HANDLE, handle); +DECLARE_GLOBAL_MOCK_METHOD_1(CHTTPAPIEXMocks, , unsigned char*, BUFFER_u_char, BUFFER_HANDLE, handle); +DECLARE_GLOBAL_MOCK_METHOD_1(CHTTPAPIEXMocks, , size_t, BUFFER_length, BUFFER_HANDLE, handle); +DECLARE_GLOBAL_MOCK_METHOD_3(CHTTPAPIEXMocks, , int, BUFFER_build, BUFFER_HANDLE, handle, const unsigned char*, source, size_t, size) + +DECLARE_GLOBAL_MOCK_METHOD_0(CHTTPAPIEXMocks, , HTTPAPI_RESULT, HTTPAPI_Init); +DECLARE_GLOBAL_MOCK_METHOD_0(CHTTPAPIEXMocks, , void, HTTPAPI_Deinit); +DECLARE_GLOBAL_MOCK_METHOD_1(CHTTPAPIEXMocks, , HTTP_HANDLE, HTTPAPI_CreateConnection, const char*, hostName); +DECLARE_GLOBAL_MOCK_METHOD_1(CHTTPAPIEXMocks, , void, HTTPAPI_CloseConnection, HTTP_HANDLE, handle); +DECLARE_GLOBAL_MOCK_METHOD_9(CHTTPAPIEXMocks, , HTTPAPI_RESULT, HTTPAPI_ExecuteRequest, HTTP_HANDLE, handle, HTTPAPI_REQUEST_TYPE, requestType, const char*, relativePath,HTTP_HEADERS_HANDLE, httpHeadersHandle, const unsigned char*, content,size_t, contentLength, unsigned int*, statusCode,HTTP_HEADERS_HANDLE, responseHeadersHandle, BUFFER_HANDLE, responseContent); +DECLARE_GLOBAL_MOCK_METHOD_3(CHTTPAPIEXMocks, , HTTPAPI_RESULT, HTTPAPI_SetOption, HTTP_HANDLE, handle, const char*, optionName, const void*, value) +DECLARE_GLOBAL_MOCK_METHOD_3(CHTTPAPIEXMocks, , HTTPAPI_RESULT, HTTPAPI_CloneOption, const char*, optionName, const void*, value, const void**, savedValue); + +DECLARE_GLOBAL_MOCK_METHOD_1(CHTTPAPIEXMocks, , VECTOR_HANDLE, VECTOR_create, size_t, elementSize); +DECLARE_GLOBAL_MOCK_METHOD_1(CHTTPAPIEXMocks, , void, VECTOR_destroy, VECTOR_HANDLE, handle); +DECLARE_GLOBAL_MOCK_METHOD_3(CHTTPAPIEXMocks, , int, VECTOR_push_back, VECTOR_HANDLE, handle, const void*, elements, size_t, numElements) +DECLARE_GLOBAL_MOCK_METHOD_2(CHTTPAPIEXMocks, , void*, VECTOR_element, VECTOR_HANDLE, handle, size_t, index) +DECLARE_GLOBAL_MOCK_METHOD_3(CHTTPAPIEXMocks, , void*, VECTOR_find_if, VECTOR_HANDLE, handle, PREDICATE_FUNCTION, pred, const void*, value) +DECLARE_GLOBAL_MOCK_METHOD_1(CHTTPAPIEXMocks, , size_t, VECTOR_size, VECTOR_HANDLE, handle); + +static MICROMOCK_MUTEX_HANDLE g_testByTest; +static MICROMOCK_GLOBAL_SEMAPHORE_HANDLE g_dllByDll; + + +static void createHttpObjects(HTTP_HEADERS_HANDLE* requestHttpHeaders, BUFFER_HANDLE* requestHttpBody, HTTP_HEADERS_HANDLE* responseHttpHeaders, BUFFER_HANDLE* responseHttpBody) +{ + /*assumed to never fail*/ + *requestHttpHeaders = HTTPHeaders_Alloc(); + *requestHttpBody = BUFFER_new(); + BUFFER_build(*requestHttpBody, (const unsigned char*)TEST_BUFFER, TEST_BUFFER_SIZE); + *responseHttpHeaders = HTTPHeaders_Alloc(); + *responseHttpBody = BUFFER_new(); + if ( + (*requestHttpHeaders == NULL) || + (*requestHttpBody == NULL) || + (*responseHttpHeaders == NULL)|| + (*responseHttpBody == NULL) + ) + { + ASSERT_FAIL("unable to build test prerequisites"); + } +} + +static void destroyHttpObjects(HTTP_HEADERS_HANDLE* requestHttpHeaders, BUFFER_HANDLE* requestHttpBody, HTTP_HEADERS_HANDLE* responseHttpHeaders, BUFFER_HANDLE* responseHttpBody) +{ + HTTPHeaders_Free(*requestHttpHeaders); + *requestHttpHeaders = NULL; + BUFFER_delete(*requestHttpBody); + *requestHttpBody = NULL; + HTTPHeaders_Free(*responseHttpHeaders); + *responseHttpHeaders = NULL; + BUFFER_delete(*responseHttpBody); + *responseHttpBody = NULL; +} + +/*this function takes care of setting expected call for httpapiex_executerequest assuming all the parameters are non-null*/ +static void setupAllCallBeforeHTTPsequence(CHTTPAPIEXMocks* mocks) +{ + (void)(*mocks); + /*this is building the host and content-length for the http request headers*/ + STRICT_EXPECTED_CALL((*mocks), BUFFER_length(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL((*mocks), STRING_c_str(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL((*mocks), HTTPHeaders_ReplaceHeaderNameValuePair(IGNORED_PTR_ARG, "Host", TEST_HOSTNAME)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL((*mocks), HTTPHeaders_ReplaceHeaderNameValuePair(IGNORED_PTR_ARG, "Content-Length", TOSTRING(TEST_BUFFER_SIZE))) + .IgnoreArgument(1); +} + +static void setupAllCallForHTTPsequence(CHTTPAPIEXMocks* mocks, const char* relativePath, HTTP_HEADERS_HANDLE requestHttpHeaders, BUFFER_HANDLE requestHttpBody, HTTP_HEADERS_HANDLE responseHttpHeaders, BUFFER_HANDLE responseHttpBody) +{ + (void)(*mocks, requestHttpBody); + STRICT_EXPECTED_CALL((*mocks), HTTPAPI_Init()); + + /*this is getting the hostname for the HTTAPI_connect call)*/ + STRICT_EXPECTED_CALL((*mocks), STRING_c_str(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL((*mocks), HTTPAPI_CreateConnection(TEST_HOSTNAME)); + STRICT_EXPECTED_CALL((*mocks), VECTOR_size(IGNORED_PTR_ARG)) /*this is passing the options*/ /*there are none saved in the regular sequences*/ + .IgnoreArgument(1); + + STRICT_EXPECTED_CALL((*mocks), BUFFER_length(requestHttpBody)); + STRICT_EXPECTED_CALL((*mocks), BUFFER_length(requestHttpBody)); /*two times because once in here, one in the code under test*/ + size_t requestHttpBodyLength = BUFFER_length(requestHttpBody); + + STRICT_EXPECTED_CALL((*mocks), BUFFER_u_char(requestHttpBody)); + STRICT_EXPECTED_CALL((*mocks), BUFFER_u_char(requestHttpBody)); /*two times because once in here, one in the code under test*/ + const unsigned char* requestHttpBodyContent = BUFFER_u_char(requestHttpBody); + + + + /*this is getting the buffer content and buffer length to pass to httpapi_executerequest*/ + STRICT_EXPECTED_CALL((*mocks), HTTPAPI_ExecuteRequest( + IGNORED_PTR_ARG, + HTTPAPI_REQUEST_PATCH, + relativePath, + requestHttpHeaders, + requestHttpBodyContent, + requestHttpBodyLength, + IGNORED_PTR_ARG, + responseHttpHeaders, + responseHttpBody)) + .IgnoreArgument(1) + .IgnoreArgument(7) + ; + +} + +/*every time HttpApi_Execute request is executed several things will be auto-aupdated by the code*/ +/*request headers to match the content-length, host to match hostname*/ +static void prepareHTTPAPIEX_ExecuteRequest(CHTTPAPIEXMocks* mocks, unsigned int *asGivenyHttpApi, HTTP_HEADERS_HANDLE requestHttpHeaders, HTTP_HEADERS_HANDLE responseHttpHeaders, BUFFER_HANDLE responseHttpBody, HTTPAPI_RESULT resultToBeUsed) +{ + (void)(*mocks); + /*this is building the host and content-length for the http request headers, this happens every time*/ + STRICT_EXPECTED_CALL((*mocks), BUFFER_length(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL((*mocks), STRING_c_str(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL((*mocks), HTTPHeaders_ReplaceHeaderNameValuePair(IGNORED_PTR_ARG, "Host", TEST_HOSTNAME)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL((*mocks), HTTPHeaders_ReplaceHeaderNameValuePair(IGNORED_PTR_ARG, "Content-Length", TOSTRING(TEST_BUFFER_SIZE))) + .IgnoreArgument(1); + + STRICT_EXPECTED_CALL((*mocks), BUFFER_length(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL((*mocks), BUFFER_u_char(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL((*mocks), HTTPAPI_ExecuteRequest( + IGNORED_PTR_ARG, + HTTPAPI_REQUEST_PATCH, + TEST_RELATIVE_PATH, + requestHttpHeaders, + IGNORED_PTR_ARG, + TEST_BUFFER_SIZE, + IGNORED_PTR_ARG, + responseHttpHeaders, + responseHttpBody)) + .IgnoreArgument(1) + .IgnoreArgument(4) + .IgnoreArgument(5) + .IgnoreArgument(7) + .ValidateArgumentBuffer(5, TEST_BUFFER, TEST_BUFFER_SIZE) + .CopyOutArgumentBuffer(7, asGivenyHttpApi, sizeof(*asGivenyHttpApi)) + .SetReturn(resultToBeUsed); + ; +} + +BEGIN_TEST_SUITE(httpapiex_unittests) + +TEST_SUITE_INITIALIZE(TestClassInitialize) +{ + INITIALIZE_MEMORY_DEBUG(g_dllByDll); + g_testByTest = MicroMockCreateMutex(); + ASSERT_IS_NOT_NULL(g_testByTest); +} + +TEST_SUITE_CLEANUP(TestClassCleanup) +{ + MicroMockDestroyMutex(g_testByTest); + DEINITIALIZE_MEMORY_DEBUG(g_dllByDll); +} + +TEST_FUNCTION_INITIALIZE(TestMethodInitialize) +{ + if (!MicroMockAcquireMutex(g_testByTest)) + { + ASSERT_FAIL("our mutex is ABANDONED. Failure in test framework"); + } + + currentmalloc_call = 0; + whenShallmalloc_fail = 0; + + currentrealloc_call = 0; + whenShallrealloc_fail = 0; + + currentHTTPAPI_SaveOption_call = 0; + whenShallHTTPAPI_SaveOption_fail = 0; + + currentSTRING_new_call = 0; + whenShallSTRING_new_fail = 0; + + currentSTRING_clone_call = 0; + whenShallSTRING_clone_fail = 0; + + currentSTRING_construct_call = 0; + whenShallSTRING_construct_fail = 0; + + currentSTRING_concat_call = 0; + whenShallSTRING_concat_fail = 0; + + currentSTRING_empty_call = 0; + whenShallSTRING_empty_fail = 0; + + currentSTRING_concat_with_STRING_call = 0; + whenShallSTRING_concat_with_STRING_fail = 0; + + currentBUFFER_new_call = 0; + whenShallBUFFER_new_fail = 0; + + currentBUFFER_build_call = 0; + whenShallBUFFER_build_fail = 0; + + currentBUFFER_content_call = 0; + whenShallBUFFER_content_fail = 0; + + currentBUFFER_size_call = 0; + whenShallBUFFER_size_fail = 0; + + currentHTTPHeaders_Alloc_call = 0; + whenShallHTTPHeaders_Alloc_fail = 0; + + currentVECTOR_create_call = 0; + whenShallVECTOR_create_fail = 0; + + currentVECTOR_push_back_call = 0; + whenShallVECTOR_push_back_fail = 0; + + HTTPAPI_Init_calls = 0; + + currentHTTPAPI_CreateConnection_call = 0; + for(size_t i=0;i +#ifdef _CRTDBG_MAP_ALLOC +#include +#endif +#include + +#include + +#include "testrunnerswitcher.h" +#include "micromock.h" +#include "micromockcharstararenullterminatedstrings.h" + +#include "agenttime.h" +#include "lock.h" +#include "strings.h" +#include "buffer_.h" +#include "sastoken.h" +#include "httpheaders.h" +#include "httpapiex.h" +#include "httpapiexsas.h" + +DEFINE_MICROMOCK_ENUM_TO_STRING(HTTPAPIEX_RESULT, HTTPAPIEX_RESULT_VALUES); + +#define GBALLOC_H + +extern "C" int gballoc_init(void); +extern "C" void gballoc_deinit(void); +extern "C" void* gballoc_malloc(size_t size); +extern "C" void* gballoc_calloc(size_t nmemb, size_t size); +extern "C" void* gballoc_realloc(void* ptr, size_t size); +extern "C" void gballoc_free(void* ptr); + +namespace BASEIMPLEMENTATION +{ +#define Lock(x) (LOCK_OK + gballocState - gballocState) /*compiler warning about constant in if condition*/ +#define Unlock(x) (LOCK_OK + gballocState - gballocState) +#define Lock_Init() (LOCK_HANDLE)0x42 +#define Lock_Deinit(x) (LOCK_OK + gballocState - gballocState) +#include "gballoc.c" +#undef Lock +#undef Unlock +#undef Lock_Init +#undef Lock_Deinit + +}; + +#define TEST_STRING_HANDLE (STRING_HANDLE)0x46 +#define TEST_NULL_STRING_HANDLE (STRING_HANDLE)0x00 +#define TEST_KEYNAME_HANDLE (STRING_HANDLE)0x48 +#define TEST_KEY_HANDLE (STRING_HANDLE)0x49 +#define TEST_URIRESOURCE_HANDLE (STRING_HANDLE)0x50 +#define TEST_CLONED_KEYNAME_HANDLE (STRING_HANDLE)0x51 +#define TEST_CLONED_URIRESOURCE_HANDLE (STRING_HANDLE)0x52 +#define TEST_CLONED_KEY_HANDLE (STRING_HANDLE)0x53 +#define TEST_HTTPAPIEX_HANDLE (HTTPAPIEX_HANDLE)0x54 +#define TEST_HTTPAPI_REQUEST_TYPE (HTTPAPI_REQUEST_TYPE)0x55 +#define TEST_REQUEST_HTTP_HEADERS_HANDLE (HTTP_HEADERS_HANDLE)0x56 +#define TEST_REQUEST_CONTENT (BUFFER_HANDLE)0x57 +#define TEST_RESPONSE_HTTP_HEADERS_HANDLE (HTTP_HEADERS_HANDLE)0x58 +#define TEST_RESPONSE_CONTENT (BUFFER_HANDLE)0x59 +#define TEST_CONST_CHAR_STAR_NULL (const char*)NULL +#define TEST_SASTOKEN_HANDLE (STRING_HANDLE)0x60 +#define TEST_EXPIRY ((size_t)7200) +#define TEST_TIME_T ((time_t)-1) + +static const char TEST_CHAR_ARRAY[10] = "ABCD"; + +static size_t currentmalloc_call; +static size_t whenShallmalloc_fail; + + +static MICROMOCK_MUTEX_HANDLE g_testByTest; +static MICROMOCK_GLOBAL_SEMAPHORE_HANDLE g_dllByDll; + + +TYPED_MOCK_CLASS(CHTTPAPIEX_SASMocks, CGlobalMock) +{ +public: + + MOCK_STATIC_METHOD_1(, void, STRING_delete, STRING_HANDLE, handle) + MOCK_VOID_METHOD_END() + + MOCK_STATIC_METHOD_1(, const char*, STRING_c_str, STRING_HANDLE, s) + MOCK_METHOD_END(const char*, TEST_CONST_CHAR_STAR_NULL) + + MOCK_STATIC_METHOD_1(, size_t, STRING_length, STRING_HANDLE, s) + MOCK_METHOD_END(size_t, 0) + + MOCK_STATIC_METHOD_1(, STRING_HANDLE, STRING_clone, STRING_HANDLE, s) + MOCK_METHOD_END(STRING_HANDLE, malloc(1)) + + MOCK_STATIC_METHOD_1(, void*, gballoc_malloc, size_t, size) + void* result2; + currentmalloc_call++; + if (whenShallmalloc_fail>0) + { + if (currentmalloc_call == whenShallmalloc_fail) + { + result2 = (STRING_HANDLE)NULL; + } + else + { + result2 = BASEIMPLEMENTATION::gballoc_malloc(size); + } + } + else + { + result2 = BASEIMPLEMENTATION::gballoc_malloc(size); + } + MOCK_METHOD_END(void*, result2); + + MOCK_STATIC_METHOD_1(, void, gballoc_free, void*, ptr) + BASEIMPLEMENTATION::gballoc_free(ptr); + MOCK_VOID_METHOD_END() + + MOCK_STATIC_METHOD_8(, HTTPAPIEX_RESULT, HTTPAPIEX_ExecuteRequest, HTTPAPIEX_HANDLE, handle, HTTPAPI_REQUEST_TYPE, requestType, const char*, relativePath, HTTP_HEADERS_HANDLE, requestHttpHeadersHandle, BUFFER_HANDLE, requestContent, unsigned int*, statusCode, HTTP_HEADERS_HANDLE, responseHttpHeadersHandle, BUFFER_HANDLE, responseContent) + MOCK_METHOD_END(HTTPAPIEX_RESULT, HTTPAPIEX_ERROR) + + MOCK_STATIC_METHOD_2(, const char*, HTTPHeaders_FindHeaderValue,HTTP_HEADERS_HANDLE, httpHeadersHandle, const char*, name) + MOCK_METHOD_END(const char*, TEST_CONST_CHAR_STAR_NULL) + + MOCK_STATIC_METHOD_3(, HTTP_HEADERS_RESULT, HTTPHeaders_ReplaceHeaderNameValuePair, HTTP_HEADERS_HANDLE, httpHeadersHandle, const char*, name, const char*, value) + MOCK_METHOD_END(HTTP_HEADERS_RESULT, HTTP_HEADERS_ERROR) + + MOCK_STATIC_METHOD_4(, STRING_HANDLE, SASToken_Create, STRING_HANDLE, key, STRING_HANDLE, scope, STRING_HANDLE, keyName, size_t, expiry) + MOCK_METHOD_END(STRING_HANDLE, malloc(1)) + + MOCK_STATIC_METHOD_1(, time_t, get_time, time_t*, currentTime) + MOCK_METHOD_END(time_t, TEST_TIME_T) + +}; + +DECLARE_GLOBAL_MOCK_METHOD_1(CHTTPAPIEX_SASMocks, , void, STRING_delete, STRING_HANDLE, handle); +DECLARE_GLOBAL_MOCK_METHOD_1(CHTTPAPIEX_SASMocks, , const char*, STRING_c_str, STRING_HANDLE, s); +DECLARE_GLOBAL_MOCK_METHOD_1(CHTTPAPIEX_SASMocks, , size_t, STRING_length, STRING_HANDLE, s); +DECLARE_GLOBAL_MOCK_METHOD_1(CHTTPAPIEX_SASMocks, , STRING_HANDLE, STRING_clone, STRING_HANDLE, s); +DECLARE_GLOBAL_MOCK_METHOD_1(CHTTPAPIEX_SASMocks, , void*, gballoc_malloc, size_t, size); +DECLARE_GLOBAL_MOCK_METHOD_1(CHTTPAPIEX_SASMocks, , void, gballoc_free, void*, ptr); +DECLARE_GLOBAL_MOCK_METHOD_8(CHTTPAPIEX_SASMocks, , HTTPAPIEX_RESULT, HTTPAPIEX_ExecuteRequest, HTTPAPIEX_HANDLE, handle, HTTPAPI_REQUEST_TYPE, requestType, const char*, relativePath, HTTP_HEADERS_HANDLE, requestHttpHeadersHandle, BUFFER_HANDLE, requestContent, unsigned int*, statusCode, HTTP_HEADERS_HANDLE, responseHttpHeadersHandle, BUFFER_HANDLE, responseContent); +DECLARE_GLOBAL_MOCK_METHOD_2(CHTTPAPIEX_SASMocks, , const char*, HTTPHeaders_FindHeaderValue, HTTP_HEADERS_HANDLE, httpHeadersHandle, const char*, name); +DECLARE_GLOBAL_MOCK_METHOD_4(CHTTPAPIEX_SASMocks, , STRING_HANDLE, SASToken_Create, STRING_HANDLE, key, STRING_HANDLE, scope, STRING_HANDLE, keyName, size_t, expiry); +DECLARE_GLOBAL_MOCK_METHOD_3(CHTTPAPIEX_SASMocks, , HTTP_HEADERS_RESULT, HTTPHeaders_ReplaceHeaderNameValuePair, HTTP_HEADERS_HANDLE, httpHeadersHandle, const char*, name, const char*, value); +DECLARE_GLOBAL_MOCK_METHOD_1(CHTTPAPIEX_SASMocks, , time_t, get_time, time_t*, currentTime); + +static void mocksResetAllCalls(CHTTPAPIEX_SASMocks* mocks) +{ + if (mocks != NULL) + { + mocks->ResetAllCalls(); + } + currentmalloc_call = 0; + whenShallmalloc_fail = 0; + +} + +static void setupSAS_Create_happy_path(CHTTPAPIEX_SASMocks &mocks) +{ + (void)mocks; + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(IGNORED_NUM_ARG)).IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, STRING_clone(TEST_KEY_HANDLE)).SetReturn(TEST_CLONED_KEY_HANDLE); + STRICT_EXPECTED_CALL(mocks, STRING_clone(TEST_URIRESOURCE_HANDLE)).SetReturn(TEST_CLONED_URIRESOURCE_HANDLE); + STRICT_EXPECTED_CALL(mocks, STRING_clone(TEST_KEYNAME_HANDLE)).SetReturn(TEST_CLONED_KEYNAME_HANDLE); + + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)).IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, STRING_delete(TEST_CLONED_KEY_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_delete(TEST_CLONED_KEYNAME_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_delete(TEST_CLONED_URIRESOURCE_HANDLE)); + +} + + +BEGIN_TEST_SUITE(httpapiexsas_unittests) + +TEST_SUITE_INITIALIZE(TestClassInitialize) +{ + INITIALIZE_MEMORY_DEBUG(g_dllByDll); + g_testByTest = MicroMockCreateMutex(); + ASSERT_IS_NOT_NULL(g_testByTest); +} + +TEST_SUITE_CLEANUP(TestClassCleanup) +{ + MicroMockDestroyMutex(g_testByTest); + DEINITIALIZE_MEMORY_DEBUG(g_dllByDll); +} + +TEST_FUNCTION_INITIALIZE(TestMethodInitialize) +{ + if (!MicroMockAcquireMutex(g_testByTest)) + { + ASSERT_FAIL("our mutex is ABANDONED. Failure in test framework"); + } +} + +TEST_FUNCTION_CLEANUP(TestMethodCleanup) +{ + if (!MicroMockReleaseMutex(g_testByTest)) + { + ASSERT_FAIL("failure in test framework at ReleaseMutex"); + } + mocksResetAllCalls(NULL); +} + +TEST_FUNCTION(HTTPAPIEX_SAS_is_zero_the_epoch) +{ + time_t epoch_candidate = 0; + tm broken_down_time; + broken_down_time = *gmtime(&epoch_candidate); + ASSERT_ARE_EQUAL(int, broken_down_time.tm_hour, 0); + ASSERT_ARE_EQUAL(int, broken_down_time.tm_min, 0); + ASSERT_ARE_EQUAL(int, broken_down_time.tm_sec, 0); + ASSERT_ARE_EQUAL(int, broken_down_time.tm_year, 70); + ASSERT_ARE_EQUAL(int, broken_down_time.tm_mon, 0); + ASSERT_ARE_EQUAL(int, broken_down_time.tm_mday, 1); + +} + +/*Tests_SRS_HTTPAPIEXSAS_06_001: [If the parameter key is NULL then HTTPAPIEX_SAS_Create shall return NULL.]*/ +TEST_FUNCTION(HTTPAPIEX_SAS_Create_null_key_fails) +{ + // arrange + HTTPAPIEX_SAS_HANDLE handle; + + // act + handle = HTTPAPIEX_SAS_Create(TEST_NULL_STRING_HANDLE, TEST_STRING_HANDLE, TEST_STRING_HANDLE); + + // assert + ASSERT_IS_NULL(handle); +} + +/*Tests_SRS_HTTPAPIEXSAS_06_002: [If the parameter uriResource is NULL then HTTPAPIEX_SAS_Create shall return NULL.]*/ +TEST_FUNCTION(HTTPAPIEX_SAS_Create_null_uriResource_fails) +{ + // arrange + HTTPAPIEX_SAS_HANDLE handle; + + // act + handle = HTTPAPIEX_SAS_Create(TEST_STRING_HANDLE, TEST_NULL_STRING_HANDLE, TEST_STRING_HANDLE); + + // assert + ASSERT_IS_NULL(handle); +} + +/*Tests_SRS_HTTPAPIEXSAS_06_003: [If the parameter keyName is NULL then HTTPAPIEX_SAS_Create shall return NULL.]*/ +TEST_FUNCTION(HTTPAPIEX_SAS_Create_null_keyName_fails) +{ + // arrange + HTTPAPIEX_SAS_HANDLE handle; + + // act + handle = HTTPAPIEX_SAS_Create(TEST_STRING_HANDLE, TEST_STRING_HANDLE, TEST_NULL_STRING_HANDLE); + + // assert + ASSERT_IS_NULL(handle); +} + +/*Tests_SRS_HTTPAPIEXSAS_06_004: [If there are any other errors in the instantiation of this handle then HTTPAPIEX_SAS_Create shall return NULL.]*/ +TEST_FUNCTION(HTTPAPIEX_SAS_Create_malloc_state_fails) +{ + // arrange + HTTPAPIEX_SAS_HANDLE handle; + CHTTPAPIEX_SASMocks mocks; + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(IGNORED_NUM_ARG)).IgnoreArgument(1); + + whenShallmalloc_fail = 1; + + // act + handle = HTTPAPIEX_SAS_Create(TEST_STRING_HANDLE, TEST_STRING_HANDLE, TEST_KEYNAME_HANDLE); + + // assert + ASSERT_IS_NULL(handle); +} + +/*Tests_SRS_HTTPAPIEXSAS_06_004: [If there are any other errors in the instantiation of this handle then HTTPAPIEX_SAS_Create shall return NULL.]*/ +TEST_FUNCTION(HTTPAPIEX_SAS_Create_first_string_clone_fails) +{ + // arrange + HTTPAPIEX_SAS_HANDLE handle; + CHTTPAPIEX_SASMocks mocks; + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(IGNORED_NUM_ARG)).IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)).IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, STRING_clone(TEST_KEY_HANDLE)).SetReturn(TEST_NULL_STRING_HANDLE); + + // act + handle = HTTPAPIEX_SAS_Create(TEST_KEY_HANDLE, TEST_URIRESOURCE_HANDLE, TEST_KEYNAME_HANDLE); + + // assert + ASSERT_IS_NULL(handle); +} + +/*Tests_SRS_HTTPAPIEXSAS_06_004: [If there are any other errors in the instantiation of this handle then HTTPAPIEX_SAS_Create shall return NULL.]*/ +TEST_FUNCTION(HTTPAPIEX_SAS_Create_second_string_clone_fails) +{ + // arrange + HTTPAPIEX_SAS_HANDLE handle; + CHTTPAPIEX_SASMocks mocks; + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(IGNORED_NUM_ARG)).IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)).IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, STRING_clone(TEST_KEY_HANDLE)).SetReturn(TEST_CLONED_KEY_HANDLE); + STRICT_EXPECTED_CALL(mocks, STRING_delete(TEST_CLONED_KEY_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_clone(TEST_URIRESOURCE_HANDLE)).SetReturn(TEST_NULL_STRING_HANDLE); + + // act + handle = HTTPAPIEX_SAS_Create(TEST_KEY_HANDLE, TEST_URIRESOURCE_HANDLE, TEST_KEYNAME_HANDLE); + + // assert + ASSERT_IS_NULL(handle); +} + +/*Tests_SRS_HTTPAPIEXSAS_06_004: [If there are any other errors in the instantiation of this handle then HTTPAPIEX_SAS_Create shall return NULL.]*/ +TEST_FUNCTION(HTTPAPIEX_SAS_Create_third_string_clone_fails) +{ + // arrange + HTTPAPIEX_SAS_HANDLE handle; + CHTTPAPIEX_SASMocks mocks; + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(IGNORED_NUM_ARG)).IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)).IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, STRING_clone(TEST_KEY_HANDLE)).SetReturn(TEST_CLONED_KEY_HANDLE); + STRICT_EXPECTED_CALL(mocks, STRING_delete(TEST_CLONED_KEY_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_clone(TEST_URIRESOURCE_HANDLE)).SetReturn(TEST_CLONED_URIRESOURCE_HANDLE); + STRICT_EXPECTED_CALL(mocks, STRING_delete(TEST_CLONED_URIRESOURCE_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_clone(TEST_KEYNAME_HANDLE)).SetReturn(TEST_NULL_STRING_HANDLE); + + // act + handle = HTTPAPIEX_SAS_Create(TEST_KEY_HANDLE, TEST_URIRESOURCE_HANDLE, TEST_KEYNAME_HANDLE); + + // assert + ASSERT_IS_NULL(handle); +} + +/*Tests_SRS_HTTPAPIEXSAS_06_006: [HTTAPIEX_SAS_Destroy shall deallocate any structures denoted by the parameter handle.]*/ +TEST_FUNCTION(HTTPAPIEX_SAS_Create_succeeds) +{ + // arrange + HTTPAPIEX_SAS_HANDLE handle; + CHTTPAPIEX_SASMocks mocks; + + setupSAS_Create_happy_path(mocks); + + // act + handle = HTTPAPIEX_SAS_Create(TEST_KEY_HANDLE, TEST_URIRESOURCE_HANDLE, TEST_KEYNAME_HANDLE); + + // assert + ASSERT_IS_NOT_NULL(handle); + + // Cleanup + HTTPAPIEX_SAS_Destroy(handle); +} + +/*Tests_SRS_HTTPAPIEXSAS_06_005: [If the parameter handle is NULL then HTTAPIEX_SAS_Destroy shall do nothing and return.]*/ +TEST_FUNCTION(HTTPAPIEX_SAS_destroy_with_null_succeeds) +{ + // act + HTTPAPIEX_SAS_Destroy(NULL); +} + +/*Tests_SRS_HTTPAPIEXSAS_06_007: [If the parameter sasHandle is NULL then HTTPAPIEX_SAS_ExecuteRequest shall simply invoke HTTPAPIEX_ExecuteRequest with the remaining parameters (following sasHandle) as its arguments and shall return immediately with the result of that call as the result of HTTPAPIEX_SAS_ExecuteRequest.]*/ +TEST_FUNCTION(HTTPAPIEX_SAS_invoke_executerequest_with_null_sas_handle_succeeds) +{ + HTTPAPIEX_RESULT result = HTTPAPIEX_ERROR; + CHTTPAPIEX_SASMocks mocks; + unsigned int statusCode; + + STRICT_EXPECTED_CALL(mocks, HTTPAPIEX_ExecuteRequest(TEST_HTTPAPIEX_HANDLE, TEST_HTTPAPI_REQUEST_TYPE, TEST_CHAR_ARRAY, TEST_REQUEST_HTTP_HEADERS_HANDLE, TEST_REQUEST_CONTENT, &statusCode, TEST_RESPONSE_HTTP_HEADERS_HANDLE, TEST_RESPONSE_CONTENT)).SetReturn(HTTPAPIEX_OK); + // act + result = HTTPAPIEX_SAS_ExecuteRequest(NULL, TEST_HTTPAPIEX_HANDLE, TEST_HTTPAPI_REQUEST_TYPE, TEST_CHAR_ARRAY, TEST_REQUEST_HTTP_HEADERS_HANDLE, TEST_REQUEST_CONTENT, &statusCode, TEST_RESPONSE_HTTP_HEADERS_HANDLE, TEST_RESPONSE_CONTENT); + + // assert + ASSERT_ARE_EQUAL(HTTPAPIEX_RESULT, result, HTTPAPIEX_OK); +} + +/*Tests_SRS_HTTPAPIEXSAS_06_008: [if the parameter requestHttpHeadersHandle is NULL then fallthrough.]*/ +TEST_FUNCTION(HTTPAPIEX_SAS_invoke_executerequest_with_null_request_http_headers_handle_succeeds) +{ + + HTTPAPIEX_RESULT result; + CHTTPAPIEX_SASMocks mocks; + unsigned int statusCode; + HTTPAPIEX_SAS_HANDLE sasHandle; + + // arrange + setupSAS_Create_happy_path(mocks); + sasHandle = HTTPAPIEX_SAS_Create(TEST_KEY_HANDLE, TEST_URIRESOURCE_HANDLE, TEST_KEYNAME_HANDLE); + STRICT_EXPECTED_CALL(mocks, HTTPAPIEX_ExecuteRequest(TEST_HTTPAPIEX_HANDLE, TEST_HTTPAPI_REQUEST_TYPE, TEST_CHAR_ARRAY, NULL, TEST_REQUEST_CONTENT, &statusCode, TEST_RESPONSE_HTTP_HEADERS_HANDLE, TEST_RESPONSE_CONTENT)).SetReturn(HTTPAPIEX_OK); + + // act + result = HTTPAPIEX_SAS_ExecuteRequest(sasHandle, TEST_HTTPAPIEX_HANDLE, TEST_HTTPAPI_REQUEST_TYPE, TEST_CHAR_ARRAY, NULL, TEST_REQUEST_CONTENT, &statusCode, TEST_RESPONSE_HTTP_HEADERS_HANDLE, TEST_RESPONSE_CONTENT); + + // assert + ASSERT_ARE_EQUAL(HTTPAPIEX_RESULT, result, HTTPAPIEX_OK); + + // Cleanup + HTTPAPIEX_SAS_Destroy(sasHandle); +} + +/*Tests_SRS_HTTPAPIEXSAS_06_009: [HTTPHeaders_FindHeaderValue shall be invoked with the requestHttpHeadersHandle as its first argument and the string "Authorization" as its second argument.]*/ +/*Tests_SRS_HTTPAPIEXSAS_06_010: [If the return result of the invocation of HTTPHeaders_FindHeaderValue is NULL then fallthrough.]*/ +TEST_FUNCTION(HTTPAPIEX_SAS_invoke_executerequest_findheadervalues_returns_null_succeeds) +{ + + HTTPAPIEX_RESULT result; + CHTTPAPIEX_SASMocks mocks; + unsigned int statusCode; + HTTPAPIEX_SAS_HANDLE sasHandle; + + // arrange + setupSAS_Create_happy_path(mocks); + sasHandle = HTTPAPIEX_SAS_Create(TEST_KEY_HANDLE, TEST_URIRESOURCE_HANDLE, TEST_KEYNAME_HANDLE); + STRICT_EXPECTED_CALL(mocks, HTTPHeaders_FindHeaderValue(TEST_REQUEST_HTTP_HEADERS_HANDLE, "Authorization")).SetReturn(TEST_CONST_CHAR_STAR_NULL); + STRICT_EXPECTED_CALL(mocks, HTTPAPIEX_ExecuteRequest(TEST_HTTPAPIEX_HANDLE, TEST_HTTPAPI_REQUEST_TYPE, TEST_CHAR_ARRAY, TEST_REQUEST_HTTP_HEADERS_HANDLE, TEST_REQUEST_CONTENT, &statusCode, TEST_RESPONSE_HTTP_HEADERS_HANDLE, TEST_RESPONSE_CONTENT)).SetReturn(HTTPAPIEX_OK); + + // act + result = HTTPAPIEX_SAS_ExecuteRequest(sasHandle, TEST_HTTPAPIEX_HANDLE, TEST_HTTPAPI_REQUEST_TYPE, TEST_CHAR_ARRAY, TEST_REQUEST_HTTP_HEADERS_HANDLE, TEST_REQUEST_CONTENT, &statusCode, TEST_RESPONSE_HTTP_HEADERS_HANDLE, TEST_RESPONSE_CONTENT); + + // assert + ASSERT_ARE_EQUAL(HTTPAPIEX_RESULT, result, HTTPAPIEX_OK); + + // Cleanup + HTTPAPIEX_SAS_Destroy(sasHandle); +} + +/*Tests_SRS_HTTPAPIEXSAS_06_018: [A value of type time_t that shall be known as currentTime is obtained from calling get_time.]*/ +/*Tests_SRS_HTTPAPIEXSAS_06_019: [If the value of currentTime is (time_t)-1 is then fallthrough.]*/ +TEST_FUNCTION(HTTPAPIEX_SAS_invoke_executerequest_get_time_fails) +{ + + HTTPAPIEX_RESULT result; + CHTTPAPIEX_SASMocks mocks; + unsigned int statusCode; + HTTPAPIEX_SAS_HANDLE sasHandle; + + // arrange + setupSAS_Create_happy_path(mocks); + sasHandle = HTTPAPIEX_SAS_Create(TEST_KEY_HANDLE, TEST_URIRESOURCE_HANDLE, TEST_KEYNAME_HANDLE); + STRICT_EXPECTED_CALL(mocks, HTTPHeaders_FindHeaderValue(TEST_REQUEST_HTTP_HEADERS_HANDLE, "Authorization")).SetReturn(TEST_CHAR_ARRAY); + STRICT_EXPECTED_CALL(mocks, get_time(NULL)).SetReturn((time_t)-1); + STRICT_EXPECTED_CALL(mocks, HTTPAPIEX_ExecuteRequest(TEST_HTTPAPIEX_HANDLE, TEST_HTTPAPI_REQUEST_TYPE, TEST_CHAR_ARRAY, TEST_REQUEST_HTTP_HEADERS_HANDLE, TEST_REQUEST_CONTENT, &statusCode, TEST_RESPONSE_HTTP_HEADERS_HANDLE, TEST_RESPONSE_CONTENT)).SetReturn(HTTPAPIEX_OK); + + // act + result = HTTPAPIEX_SAS_ExecuteRequest(sasHandle, TEST_HTTPAPIEX_HANDLE, TEST_HTTPAPI_REQUEST_TYPE, TEST_CHAR_ARRAY, TEST_REQUEST_HTTP_HEADERS_HANDLE, TEST_REQUEST_CONTENT, &statusCode, TEST_RESPONSE_HTTP_HEADERS_HANDLE, TEST_RESPONSE_CONTENT); + + // assert + ASSERT_ARE_EQUAL(HTTPAPIEX_RESULT, result, HTTPAPIEX_OK); + + // Cleanup + HTTPAPIEX_SAS_Destroy(sasHandle); +} + +/*Tests_SRS_HTTPAPIEXSAS_06_011: [SASToken_Create shall be invoked.]*/ +/*Tests_SRS_HTTPAPIEXSAS_06_012: [If the return result of SASToken_Create is NULL then fallthrough.]*/ +TEST_FUNCTION(HTTPAPIEX_SAS_invoke_executerequest_sastoken_create_returns_null_succeeds) +{ + + HTTPAPIEX_RESULT result; + CHTTPAPIEX_SASMocks mocks; + unsigned int statusCode; + HTTPAPIEX_SAS_HANDLE sasHandle; + + // arrange + setupSAS_Create_happy_path(mocks); + sasHandle = HTTPAPIEX_SAS_Create(TEST_KEY_HANDLE, TEST_URIRESOURCE_HANDLE, TEST_KEYNAME_HANDLE); + STRICT_EXPECTED_CALL(mocks, HTTPHeaders_FindHeaderValue(TEST_REQUEST_HTTP_HEADERS_HANDLE, "Authorization")).SetReturn(TEST_CHAR_ARRAY); + STRICT_EXPECTED_CALL(mocks, get_time(NULL)).SetReturn(3600); + STRICT_EXPECTED_CALL(mocks, SASToken_Create(TEST_CLONED_KEY_HANDLE, TEST_CLONED_URIRESOURCE_HANDLE, TEST_CLONED_KEYNAME_HANDLE, TEST_EXPIRY)).SetReturn(TEST_NULL_STRING_HANDLE); + STRICT_EXPECTED_CALL(mocks, HTTPAPIEX_ExecuteRequest(TEST_HTTPAPIEX_HANDLE, TEST_HTTPAPI_REQUEST_TYPE, TEST_CHAR_ARRAY, TEST_REQUEST_HTTP_HEADERS_HANDLE, TEST_REQUEST_CONTENT, &statusCode, TEST_RESPONSE_HTTP_HEADERS_HANDLE, TEST_RESPONSE_CONTENT)).SetReturn(HTTPAPIEX_OK); + + // act + result = HTTPAPIEX_SAS_ExecuteRequest(sasHandle, TEST_HTTPAPIEX_HANDLE, TEST_HTTPAPI_REQUEST_TYPE, TEST_CHAR_ARRAY, TEST_REQUEST_HTTP_HEADERS_HANDLE, TEST_REQUEST_CONTENT, &statusCode, TEST_RESPONSE_HTTP_HEADERS_HANDLE, TEST_RESPONSE_CONTENT); + + // assert + ASSERT_ARE_EQUAL(HTTPAPIEX_RESULT, result, HTTPAPIEX_OK); + + // Cleanup + HTTPAPIEX_SAS_Destroy(sasHandle); +} + +/*Tests_SRS_HTTPAPIEXSAS_06_013: [HTTPHeaders_ReplaceHeaderNameValuePair shall be invoked with "Authorization" as its second argument and STRING_c_str (newSASToken) as its third argument.]*/ +/*Tests_SRS_HTTPAPIEXSAS_06_014: [If the result of the invocation of HTTPHeaders_ReplaceHeaderNameValuePair is NOT HTTP_HEADERS_OK then fallthrough.]*/ +/*Tests_SRS_HTTPAPIEXSAS_06_015: [STRING_delete(newSASToken) will be invoked.]*/ +TEST_FUNCTION(HTTPAPIEX_SAS_invoke_executerequest_replace_header_name_value_pair_fails_succeeds) +{ + + HTTPAPIEX_RESULT result; + CHTTPAPIEX_SASMocks mocks; + unsigned int statusCode; + HTTPAPIEX_SAS_HANDLE sasHandle; + + // arrange + setupSAS_Create_happy_path(mocks); + sasHandle = HTTPAPIEX_SAS_Create(TEST_KEY_HANDLE, TEST_URIRESOURCE_HANDLE, TEST_KEYNAME_HANDLE); + STRICT_EXPECTED_CALL(mocks, HTTPHeaders_FindHeaderValue(TEST_REQUEST_HTTP_HEADERS_HANDLE, "Authorization")).SetReturn(TEST_CHAR_ARRAY); + STRICT_EXPECTED_CALL(mocks, get_time(NULL)).SetReturn(3600); + STRICT_EXPECTED_CALL(mocks, SASToken_Create(TEST_CLONED_KEY_HANDLE, TEST_CLONED_URIRESOURCE_HANDLE, TEST_CLONED_KEYNAME_HANDLE, TEST_EXPIRY)).SetReturn(TEST_SASTOKEN_HANDLE); + STRICT_EXPECTED_CALL(mocks, STRING_delete(TEST_SASTOKEN_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_c_str(TEST_SASTOKEN_HANDLE)).SetReturn(TEST_CHAR_ARRAY); + STRICT_EXPECTED_CALL(mocks, HTTPHeaders_ReplaceHeaderNameValuePair(TEST_REQUEST_HTTP_HEADERS_HANDLE, "Authorization", TEST_CHAR_ARRAY)).SetReturn(HTTP_HEADERS_ERROR); + STRICT_EXPECTED_CALL(mocks, HTTPAPIEX_ExecuteRequest(TEST_HTTPAPIEX_HANDLE, TEST_HTTPAPI_REQUEST_TYPE, TEST_CHAR_ARRAY, TEST_REQUEST_HTTP_HEADERS_HANDLE, TEST_REQUEST_CONTENT, &statusCode, TEST_RESPONSE_HTTP_HEADERS_HANDLE, TEST_RESPONSE_CONTENT)).SetReturn(HTTPAPIEX_OK); + + // act + result = HTTPAPIEX_SAS_ExecuteRequest(sasHandle, TEST_HTTPAPIEX_HANDLE, TEST_HTTPAPI_REQUEST_TYPE, TEST_CHAR_ARRAY, TEST_REQUEST_HTTP_HEADERS_HANDLE, TEST_REQUEST_CONTENT, &statusCode, TEST_RESPONSE_HTTP_HEADERS_HANDLE, TEST_RESPONSE_CONTENT); + + // assert + ASSERT_ARE_EQUAL(HTTPAPIEX_RESULT, result, HTTPAPIEX_OK); + + // Cleanup + HTTPAPIEX_SAS_Destroy(sasHandle); +} + +/*Tests_SRS_HTTPAPIEXSAS_06_016: [HTTPAPIEX_ExecuteRequest with the remaining parameters (following sasHandle) as its arguments will be invoked and the result of that call is the result of HTTPAPIEX_SAS_ExecuteRequest.]*/ +TEST_FUNCTION(HTTPAPIEX_SAS_invoke_executerequest_replace_header_name_value_pair_succeeds_succeeds) +{ + + HTTPAPIEX_RESULT result; + CHTTPAPIEX_SASMocks mocks; + unsigned int statusCode; + HTTPAPIEX_SAS_HANDLE sasHandle; + + // arrange + setupSAS_Create_happy_path(mocks); + sasHandle = HTTPAPIEX_SAS_Create(TEST_KEY_HANDLE, TEST_URIRESOURCE_HANDLE, TEST_KEYNAME_HANDLE); + STRICT_EXPECTED_CALL(mocks, HTTPHeaders_FindHeaderValue(TEST_REQUEST_HTTP_HEADERS_HANDLE, "Authorization")).SetReturn(TEST_CHAR_ARRAY); + STRICT_EXPECTED_CALL(mocks, get_time(NULL)).SetReturn(3600); + STRICT_EXPECTED_CALL(mocks, SASToken_Create(TEST_CLONED_KEY_HANDLE, TEST_CLONED_URIRESOURCE_HANDLE, TEST_CLONED_KEYNAME_HANDLE, TEST_EXPIRY)).SetReturn(TEST_SASTOKEN_HANDLE); + STRICT_EXPECTED_CALL(mocks, STRING_delete(TEST_SASTOKEN_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_c_str(TEST_SASTOKEN_HANDLE)).SetReturn(TEST_CHAR_ARRAY); + STRICT_EXPECTED_CALL(mocks, HTTPHeaders_ReplaceHeaderNameValuePair(TEST_REQUEST_HTTP_HEADERS_HANDLE, "Authorization", TEST_CHAR_ARRAY)).SetReturn(HTTP_HEADERS_OK); + STRICT_EXPECTED_CALL(mocks, HTTPAPIEX_ExecuteRequest(TEST_HTTPAPIEX_HANDLE, TEST_HTTPAPI_REQUEST_TYPE, TEST_CHAR_ARRAY, TEST_REQUEST_HTTP_HEADERS_HANDLE, TEST_REQUEST_CONTENT, &statusCode, TEST_RESPONSE_HTTP_HEADERS_HANDLE, TEST_RESPONSE_CONTENT)).SetReturn(HTTPAPIEX_OK); + + // act + result = HTTPAPIEX_SAS_ExecuteRequest(sasHandle, TEST_HTTPAPIEX_HANDLE, TEST_HTTPAPI_REQUEST_TYPE, TEST_CHAR_ARRAY, TEST_REQUEST_HTTP_HEADERS_HANDLE, TEST_REQUEST_CONTENT, &statusCode, TEST_RESPONSE_HTTP_HEADERS_HANDLE, TEST_RESPONSE_CONTENT); + + // assert + ASSERT_ARE_EQUAL(HTTPAPIEX_RESULT, result, HTTPAPIEX_OK); + + // Cleanup + HTTPAPIEX_SAS_Destroy(sasHandle); +} + +END_TEST_SUITE(httpapiexsas_unittests) diff --git a/c/sharedutil/tests/httpapiexsas_unittests/main.c b/c/sharedutil/tests/httpapiexsas_unittests/main.c new file mode 100644 index 00000000..91aced93 --- /dev/null +++ b/c/sharedutil/tests/httpapiexsas_unittests/main.c @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include "testrunnerswitcher.h" + +int main(void) +{ + size_t failedTestCount = 0; + RUN_TEST_SUITE(httpapiexsas_unittests, failedTestCount); + return failedTestCount; +} diff --git a/c/sharedutil/tests/httpheaders_unittests/CMakeLists.txt b/c/sharedutil/tests/httpheaders_unittests/CMakeLists.txt new file mode 100644 index 00000000..094d4631 --- /dev/null +++ b/c/sharedutil/tests/httpheaders_unittests/CMakeLists.txt @@ -0,0 +1,25 @@ +#Copyright (c) Microsoft. All rights reserved. +#Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#this is CMakeLists.txt for httpheaders_unittests +cmake_minimum_required(VERSION 3.0) + +if(NOT ${use_http}) + message(FATAL_ERROR "httpheaders_unittests being generated without HTTP support") +endif() + +compileAsC99() +set(theseTestsName httpheaders_unittests) + +set(${theseTestsName}_cpp_files +${theseTestsName}.cpp +) + +set(${theseTestsName}_c_files +../../src/httpheaders.c +) + +set(${theseTestsName}_h_files +) + +build_test_artifacts(${theseTestsName} ON) \ No newline at end of file diff --git a/c/sharedutil/tests/httpheaders_unittests/httpheaders_unittests.cpp b/c/sharedutil/tests/httpheaders_unittests/httpheaders_unittests.cpp new file mode 100644 index 00000000..b7362227 --- /dev/null +++ b/c/sharedutil/tests/httpheaders_unittests/httpheaders_unittests.cpp @@ -0,0 +1,1474 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include +#ifdef _CRTDBG_MAP_ALLOC +#include +#endif + +#include + +#include "testrunnerswitcher.h" +#include "micromock.h" +#include "micromockcharstararenullterminatedstrings.h" +#include "httpheaders.h" +#include "map.h" +#include "lock.h" + +#define GBALLOC_H + +extern "C" int gballoc_init(void); +extern "C" void gballoc_deinit(void); +extern "C" void* gballoc_malloc(size_t size); +extern "C" void* gballoc_calloc(size_t nmemb, size_t size); +extern "C" void* gballoc_realloc(void* ptr, size_t size); +extern "C" void gballoc_free(void* ptr); + + +namespace BASEIMPLEMENTATION +{ + /*if malloc is defined as gballoc_malloc at this moment, there'd be serious trouble*/ +#define Lock(x) (LOCK_OK + gballocState - gballocState) /*compiler warning about constant in if condition*/ +#define Unlock(x) (LOCK_OK + gballocState - gballocState) +#define Lock_Init() (LOCK_HANDLE)0x42 +#define Lock_Deinit(x) (LOCK_OK + gballocState - gballocState) +#include "gballoc.c" +#undef Lock +#undef Unlock +#undef Lock_Init +#undef Lock_Deinit +}; + +/*Below tags exists for traceability reasons only, they canot be really tested by automated means, except "this file compiles"*/ +/*Tests_SRS_HTTP_HEADERS_99_001:[ HttpHeaders shall have the following interface]*/ + +static MICROMOCK_MUTEX_HANDLE g_testByTest; + +DEFINE_MICROMOCK_ENUM_TO_STRING(HTTP_HEADERS_RESULT, HTTP_HEADERS_RESULT_VALUES); + +/*test assets*/ +#define NAME1 "name1" +#define VALUE1 "value1" +#define HEADER1 NAME1 ": " VALUE1 +static const char *NAME1_TRICK1 = "name1:"; +static const char *NAME1_TRICK2 = "name1: "; +static const char *NAME1_TRICK3 = "name1: value1"; + +#define NAME2 "name2" +#define VALUE2 "value2" +#define HEADER2 NAME2 ": " VALUE2 + +#define TEMP_BUFFER_SIZE 1024 +static char tempBuffer[TEMP_BUFFER_SIZE]; + +#define MAX_NAME_VALUE_PAIR 100 + +static MICROMOCK_GLOBAL_SEMAPHORE_HANDLE g_dllByDll; + +static size_t currentMap_Create_call; +static size_t whenShallMap_Create_fail; + +static size_t currentMap_Clone_call; +static size_t whenShallMap_Clone_fail; + + +static size_t currentmalloc_call; +static size_t whenShallmalloc_fail; + +static size_t currentrealloc_call; +static size_t whenShallrealloc_fail; + + + + +TYPED_MOCK_CLASS(CHTTPHeadersMocks, CGlobalMock) +{ +public: + MOCK_STATIC_METHOD_1(, MAP_HANDLE, Map_Create, MAP_FILTER_CALLBACK, mapFilterFunc) + MAP_HANDLE result2; + currentMap_Create_call++; + if (currentMap_Create_call == whenShallMap_Create_fail) + { + result2 = (MAP_HANDLE)NULL; + } + else + { + result2 = (MAP_HANDLE)malloc(1); + } + MOCK_METHOD_END(MAP_HANDLE, result2) + + MOCK_STATIC_METHOD_1(, MAP_HANDLE, Map_Clone, MAP_HANDLE, handle) + MAP_HANDLE result2; + currentMap_Clone_call++; + if (currentMap_Clone_call == whenShallMap_Clone_fail) + { + result2 = (MAP_HANDLE)NULL; + } + else + { + result2 = (MAP_HANDLE)malloc(1); + } + MOCK_METHOD_END(MAP_HANDLE, result2) + + + MOCK_STATIC_METHOD_1(, void, Map_Destroy, MAP_HANDLE, handle) + free(handle); + MOCK_VOID_METHOD_END() + + MOCK_STATIC_METHOD_3(, MAP_RESULT, Map_AddOrUpdate, MAP_HANDLE, handle, const char*, key, const char*, value) + MOCK_METHOD_END(MAP_RESULT, MAP_OK) + + MOCK_STATIC_METHOD_2(, const char*, Map_GetValueFromKey, MAP_HANDLE, handle, const char*, key) + MOCK_METHOD_END(const char*, VALUE1) + + MOCK_STATIC_METHOD_4(, MAP_RESULT, Map_GetInternals, MAP_HANDLE, handle, const char*const**, keys, const char*const**, values, size_t*, count) + MOCK_METHOD_END(MAP_RESULT, MAP_OK) + + MOCK_STATIC_METHOD_1(, void*, gballoc_malloc, size_t, size) + void* result2; + currentmalloc_call++; + if (whenShallmalloc_fail>0) + { + if (currentmalloc_call == whenShallmalloc_fail) + { + result2 = (STRING_HANDLE)NULL; + } + else + { + result2 = BASEIMPLEMENTATION::gballoc_malloc(size); + } + } + else + { + result2 = BASEIMPLEMENTATION::gballoc_malloc(size); + } + MOCK_METHOD_END(void*, result2); + + MOCK_STATIC_METHOD_2(, void*, gballoc_realloc, void*, ptr, size_t, size) + void* result2; + currentrealloc_call++; + if (whenShallrealloc_fail>0) + { + if (currentrealloc_call == whenShallrealloc_fail) + { + result2 = (STRING_HANDLE)NULL; + } + else + { + result2 = BASEIMPLEMENTATION::gballoc_realloc(ptr, size); + } + } + else + { + result2 = BASEIMPLEMENTATION::gballoc_realloc(ptr, size); + } + MOCK_METHOD_END(void*, result2); + + MOCK_STATIC_METHOD_1(, void, gballoc_free, void*, ptr) + BASEIMPLEMENTATION::gballoc_free(ptr); + MOCK_VOID_METHOD_END() + +}; + +DECLARE_GLOBAL_MOCK_METHOD_1(CHTTPHeadersMocks, , MAP_HANDLE, Map_Create, MAP_FILTER_CALLBACK, mapFilterFunc); +DECLARE_GLOBAL_MOCK_METHOD_1(CHTTPHeadersMocks, , void, Map_Destroy, MAP_HANDLE, handle) +DECLARE_GLOBAL_MOCK_METHOD_1(CHTTPHeadersMocks, , MAP_HANDLE, Map_Clone, MAP_HANDLE, handle); +DECLARE_GLOBAL_MOCK_METHOD_3(CHTTPHeadersMocks, , MAP_RESULT, Map_AddOrUpdate, MAP_HANDLE, handle, const char*, key, const char*, value); +DECLARE_GLOBAL_MOCK_METHOD_2(CHTTPHeadersMocks, , const char*, Map_GetValueFromKey, MAP_HANDLE, handle, const char*, key); +DECLARE_GLOBAL_MOCK_METHOD_4(CHTTPHeadersMocks, , MAP_RESULT, Map_GetInternals, MAP_HANDLE, handle, const char*const**, keys, const char*const**, values, size_t*, count); + +DECLARE_GLOBAL_MOCK_METHOD_1(CHTTPHeadersMocks, , void*, gballoc_malloc, size_t, size); +DECLARE_GLOBAL_MOCK_METHOD_2(CHTTPHeadersMocks, , void*, gballoc_realloc, void*, ptr, size_t, size); +DECLARE_GLOBAL_MOCK_METHOD_1(CHTTPHeadersMocks, , void, gballoc_free, void*, ptr); + +BEGIN_TEST_SUITE(HTTPHeaders_UnitTests) + + TEST_SUITE_INITIALIZE(TestClassInitialize) + { + INITIALIZE_MEMORY_DEBUG(g_dllByDll); + + g_testByTest = MicroMockCreateMutex(); + ASSERT_IS_NOT_NULL(g_testByTest); + } + + TEST_SUITE_CLEANUP(TestClassCleanup) + { + MicroMockDestroyMutex(g_testByTest); + + DEINITIALIZE_MEMORY_DEBUG(g_dllByDll); + + } + + TEST_FUNCTION_INITIALIZE(TestMethodInitialize) + { + if (!MicroMockAcquireMutex(g_testByTest)) + { + ASSERT_FAIL("our mutex is ABANDONED. Failure in test framework"); + } + + currentMap_Create_call = 0; + whenShallMap_Create_fail = 0; + + currentMap_Clone_call = 0; + whenShallMap_Clone_fail = 0; + + currentmalloc_call = 0; + whenShallmalloc_fail = 0; + + currentrealloc_call = 0; + whenShallrealloc_fail = 0; + } + + TEST_FUNCTION_CLEANUP(TestMethodCleanup) + { + if (!MicroMockReleaseMutex(g_testByTest)) + { + ASSERT_FAIL("failure in test framework at ReleaseMutex"); + } + } + + + /*Tests_SRS_HTTP_HEADERS_99_002:[ This API shall produce a HTTP_HANDLE that can later be used in subsequent calls to the module.]*/ + TEST_FUNCTION(HTTPHeaders_Alloc_happy_path_succeeds) + { + ///arrange + CHTTPHeadersMocks mocks; + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(IGNORED_NUM_ARG)) + .IgnoreArgument(1); + + STRICT_EXPECTED_CALL(mocks, Map_Create(IGNORED_PTR_ARG)); + + ///act + auto handle = HTTPHeaders_Alloc(); + + ///assert + ASSERT_IS_NOT_NULL(handle); + mocks.AssertActualAndExpectedCalls(); + + /// cleanup + HTTPHeaders_Free(handle); + } + + + /*Tests_SRS_HTTP_HEADERS_99_003:[ The function shall return NULL when the function cannot execute properly]*/ + TEST_FUNCTION(HTTPHeaders_Alloc_fails_when_malloc_fails) + { + ///arrange + CHTTPHeadersMocks mocks; + + whenShallmalloc_fail = currentmalloc_call + 1; + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(IGNORED_NUM_ARG)) + .IgnoreArgument(1); + + ///act + auto httpHandle = HTTPHeaders_Alloc(); + + ///assert + ASSERT_IS_NULL(httpHandle); + + } + + /*Tests_SRS_HTTP_HEADERS_02_001: [If httpHeadersHandle is NULL then HTTPHeaders_Free shall perform no action.] */ + TEST_FUNCTION(HTTPHeaders_Free_with_NULL_handle_does_nothing) + { + ///arrange + CHTTPHeadersMocks mocks; + + ///act + HTTPHeaders_Free(NULL); + + ///assert + mocks.AssertActualAndExpectedCalls(); + + } + + /*Tests_SRS_HTTP_HEADERS_99_005:[ Calling this API shall de-allocate the data structures allocated by previous API calls to the same handle.]*/ + TEST_FUNCTION(HTTPHeaders_Free_with_valid_handle_succeeds) + { + ///arrange + CHTTPHeadersMocks mocks; + auto handle = HTTPHeaders_Alloc(); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, Map_Destroy(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + + ///act + HTTPHeaders_Free(handle); + + ///assert + mocks.AssertActualAndExpectedCalls(); + + } + + + /*Tests_SRS_HTTP_HEADERS_99_003:[ The function shall return NULL when the function cannot execute properly]*/ + TEST_FUNCTION(HTTPHeaders_Alloc_fails_when_Map_Create_fails) + { + ///arrange + CHTTPHeadersMocks mocks; + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(IGNORED_NUM_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + + whenShallMap_Create_fail = currentMap_Create_call + 1; + STRICT_EXPECTED_CALL(mocks, Map_Create(IGNORED_PTR_ARG)); + + ///act + auto httpHandle = HTTPHeaders_Alloc(); + + ///assert + ASSERT_IS_NULL(httpHandle); + + } + + /*Tests_SRS_HTTP_HEADERS_99_004:[ After a successful init, HTTPHeaders_GetHeaderCount shall report 0 existing headers.]*/ + TEST_FUNCTION(HTTPHeaders_Alloc_succeeds_and_GetHeaderCount_returns_0) + { + ///arrange + CHTTPHeadersMocks mocks; + auto httpHandle = HTTPHeaders_Alloc(); + size_t nHeaders; + size_t zero = 0; + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, Map_GetInternals(IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG)) + .IgnoreAllArguments() + .CopyOutArgumentBuffer(4, &zero, sizeof(zero)); + + ///act + auto res = HTTPHeaders_GetHeaderCount(httpHandle, &nHeaders); + + ///assert + ASSERT_ARE_EQUAL(HTTP_HEADERS_RESULT, HTTP_HEADERS_OK, res); + ASSERT_ARE_EQUAL(size_t, 0, nHeaders); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + HTTPHeaders_Free(httpHandle); + } + + /*Tests_SRS_HTTP_HEADERS_99_012:[ Calling this API shall record a header from name and value parameters.]*/ + /*Tests_SRS_HTTP_HEADERS_99_013:[ The function shall return HTTP_HEADERS_OK when execution is successful.]*/ + TEST_FUNCTION(HTTPHeaders_AddHeaderNameValuePair_happy_path_succeeds) + { + ///arrange + CHTTPHeadersMocks mocks; + auto httpHandle = HTTPHeaders_Alloc(); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, Map_GetValueFromKey(IGNORED_PTR_ARG, NAME1)) + .IgnoreArgument(1) + .SetReturn((const char*)NULL); /*this key does not exist*/ + + STRICT_EXPECTED_CALL(mocks, Map_AddOrUpdate(IGNORED_PTR_ARG, NAME1, VALUE1)) + .IgnoreArgument(1); + + ///act + auto res = HTTPHeaders_AddHeaderNameValuePair(httpHandle, NAME1, VALUE1); + + ///assert + ASSERT_ARE_EQUAL(HTTP_HEADERS_RESULT, HTTP_HEADERS_OK, res); + mocks.AssertActualAndExpectedCalls(); + + //checking content + + ///cleanup + HTTPHeaders_Free(httpHandle); + } + + /*Codes_SRS_HTTP_HEADERS_99_015:[ The function shall return HTTP_HEADERS_ALLOC_FAILED when an internal request to allocate memory fails.]*/ + TEST_FUNCTION(HTTPHeaders_AddHeaderNameValuePair_fails_when_Map_AddOrUpdate_fails) + { + ///arrange + CHTTPHeadersMocks mocks; + auto httpHandle = HTTPHeaders_Alloc(); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, Map_GetValueFromKey(IGNORED_PTR_ARG, NAME1)) + .IgnoreArgument(1) + .SetReturn((const char*)NULL); /*this key does not exist*/ + + + STRICT_EXPECTED_CALL(mocks, Map_AddOrUpdate(IGNORED_PTR_ARG, NAME1, VALUE1)) + .IgnoreArgument(1) + .SetReturn(MAP_ERROR); + + ///act + auto res = HTTPHeaders_AddHeaderNameValuePair(httpHandle, NAME1, VALUE1); + + ///assert + ASSERT_ARE_EQUAL(HTTP_HEADERS_RESULT, HTTP_HEADERS_ALLOC_FAILED, res); + mocks.AssertActualAndExpectedCalls(); + + //checking content + + ///cleanup + HTTPHeaders_Free(httpHandle); + } + + /*Tests_SRS_HTTP_HEADERS_99_016:[ The function shall store the name:value pair in such a way that when later retrieved by a call to GetHeader it will return a string that shall strcmp equal to the name+": "+value.]*/ + TEST_FUNCTION(HTTPHeaders_AddHeaderNameValuePair_succeeds) + { + ///arrange + CHTTPHeadersMocks mocks; + auto httpHandle = HTTPHeaders_Alloc(); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, Map_GetValueFromKey(IGNORED_PTR_ARG, NAME1)) + .IgnoreArgument(1) + .SetReturn((const char*)NULL); /*this key does not exist*/ + + STRICT_EXPECTED_CALL(mocks, Map_AddOrUpdate(IGNORED_PTR_ARG, NAME1, VALUE1)) + .IgnoreArgument(1); + + ///act + auto res = HTTPHeaders_AddHeaderNameValuePair(httpHandle, NAME1, VALUE1); + + ///assert + ASSERT_ARE_EQUAL(HTTP_HEADERS_RESULT, HTTP_HEADERS_OK, res); + mocks.AssertActualAndExpectedCalls(); + + //checking content + + ///cleanup + HTTPHeaders_Free(httpHandle); + } + + + + /*Tests_SRS_HTTP_HEADERS_99_014:[ The function shall return when the handle is not valid or when name parameter is NULL or when value parameter is NULL.]*/ + TEST_FUNCTION(HTTPHeaders_AddHeaderNameValuePair_with_NULL_handle_fails) + { + ///arrange + CHTTPHeadersMocks mocks; + + ///act + auto res = HTTPHeaders_AddHeaderNameValuePair(NULL, NAME1, VALUE1); + + ///assert + ASSERT_ARE_EQUAL(HTTP_HEADERS_RESULT, HTTP_HEADERS_INVALID_ARG, res); + } + + /*Tests_SRS_HTTP_HEADERS_99_014:[ The function shall return when the handle is not valid or when name parameter is NULL or when value parameter is NULL.]*/ + TEST_FUNCTION(HTTPHeaders_AddHeaderNameValuePair_with_NULL_name_fails) + { + ///arrange + CHTTPHeadersMocks mocks; + auto httpHandle = HTTPHeaders_Alloc(); + mocks.ResetAllCalls(); + + ///act + auto res = HTTPHeaders_AddHeaderNameValuePair(httpHandle, NULL, VALUE1); + + ///assert + ASSERT_ARE_EQUAL(HTTP_HEADERS_RESULT, HTTP_HEADERS_INVALID_ARG, res); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + HTTPHeaders_Free(httpHandle); + } + + /*Tests_SRS_HTTP_HEADERS_99_014:[ The function shall return when the handle is not valid or when name parameter is NULL or when value parameter is NULL.]*/ + TEST_FUNCTION(HTTPHeaders_AddHeaderNameValuePair_with_NULL_value_fails) + { + ///arrange + CHTTPHeadersMocks mocks; + auto httpHandle = HTTPHeaders_Alloc(); + mocks.ResetAllCalls(); + + ///act + auto res = HTTPHeaders_AddHeaderNameValuePair(httpHandle, NAME1, NULL); + + ///assert + ASSERT_ARE_EQUAL(HTTP_HEADERS_RESULT, HTTP_HEADERS_INVALID_ARG, res); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + HTTPHeaders_Free(httpHandle); + } + + /*Tests_SRS_HTTP_HEADERS_99_017:[ If the name already exists in the collection of headers, the function shall concatenate the new value after the existing value, separated by a comma and a space as in: old-value+", "+new-value.]*/ + TEST_FUNCTION(HTTPHeaders_AddHeaderNameValuePair_with_same_Name_appends_to_existing_value_succeeds) + { + ///arrange + CHTTPHeadersMocks mocks; + auto httpHandle = HTTPHeaders_Alloc(); + STRICT_EXPECTED_CALL(mocks, Map_GetValueFromKey(IGNORED_PTR_ARG, NAME1)) + .IgnoreArgument(1) + .SetReturn((const char*)NULL); /*this key does not exist, the line below is adding it*/ + (void)HTTPHeaders_AddHeaderNameValuePair(httpHandle, NAME1, VALUE1); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, Map_GetValueFromKey(IGNORED_PTR_ARG, NAME1)) + .IgnoreArgument(1) + .SetReturn(VALUE1); + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(IGNORED_NUM_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + + STRICT_EXPECTED_CALL(mocks, Map_AddOrUpdate(IGNORED_PTR_ARG, NAME1, VALUE1 ", " VALUE1)) + .IgnoreArgument(1); + + ///act + auto res = HTTPHeaders_AddHeaderNameValuePair(httpHandle, NAME1, VALUE1); + + ///assert + ASSERT_ARE_EQUAL(HTTP_HEADERS_RESULT, HTTP_HEADERS_OK, res); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + HTTPHeaders_Free(httpHandle); + } + + /*Tests_SRS_HTTP_HEADERS_99_015:[ The function shall return HTTP_HEADERS_ALLOC_FAILED when an internal request to allocate memory fails.]*/ + TEST_FUNCTION(HTTPHeaders_AddHeaderNameValuePair_with_same_Name_appends_fails_when_Map_AddOrUpdate_fails) + { + ///arrange + CHTTPHeadersMocks mocks; + auto httpHandle = HTTPHeaders_Alloc(); + STRICT_EXPECTED_CALL(mocks, Map_GetValueFromKey(IGNORED_PTR_ARG, NAME1)) + .IgnoreArgument(1) + .SetReturn((const char*)NULL); /*this key does not exist, the line below is adding it*/ + (void)HTTPHeaders_AddHeaderNameValuePair(httpHandle, NAME1, VALUE1); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, Map_GetValueFromKey(IGNORED_PTR_ARG, NAME1)) + .IgnoreArgument(1) + .SetReturn(VALUE1); + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(IGNORED_NUM_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + + STRICT_EXPECTED_CALL(mocks, Map_AddOrUpdate(IGNORED_PTR_ARG, NAME1, VALUE1 ", " VALUE1)) + .IgnoreArgument(1) + .SetReturn(MAP_ERROR); + + ///act + auto res = HTTPHeaders_AddHeaderNameValuePair(httpHandle, NAME1, VALUE1); + + ///assert + ASSERT_ARE_EQUAL(HTTP_HEADERS_RESULT, HTTP_HEADERS_ERROR, res); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + HTTPHeaders_Free(httpHandle); + } + + /*Tests_SRS_HTTP_HEADERS_99_015:[ The function shall return HTTP_HEADERS_ALLOC_FAILED when an internal request to allocate memory fails.]*/ + TEST_FUNCTION(HTTPHeaders_AddHeaderNameValuePair_with_same_Name_fails_when_gballoc_fails) + { + ///arrange + CHTTPHeadersMocks mocks; + auto httpHandle = HTTPHeaders_Alloc(); + STRICT_EXPECTED_CALL(mocks, Map_GetValueFromKey(IGNORED_PTR_ARG, NAME1)) + .IgnoreArgument(1) + .SetReturn((const char*)NULL); /*this key does not exist, the line below is adding it*/ + (void)HTTPHeaders_AddHeaderNameValuePair(httpHandle, NAME1, VALUE1); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, Map_GetValueFromKey(IGNORED_PTR_ARG, NAME1)) + .IgnoreArgument(1) + .SetReturn(VALUE1); + + whenShallmalloc_fail = currentmalloc_call + 1; + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(IGNORED_NUM_ARG)) + .IgnoreArgument(1); + + ///act + auto res = HTTPHeaders_AddHeaderNameValuePair(httpHandle, NAME1, VALUE1); + + ///assert + ASSERT_ARE_EQUAL(HTTP_HEADERS_RESULT, HTTP_HEADERS_ALLOC_FAILED, res); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + HTTPHeaders_Free(httpHandle); + } + + /*Tests_SRS_HTTP_HEADERS_99_012:[ Calling this API shall record a header from name and value parameters.]*/ + TEST_FUNCTION(HTTPHeaders_AddHeaderNameValuePair_add_two_headers_produces_two_headers) + { + ///arrange + CHTTPHeadersMocks mocks; + auto httpHandle = HTTPHeaders_Alloc(); + STRICT_EXPECTED_CALL(mocks, Map_GetValueFromKey(IGNORED_PTR_ARG, NAME1)) + .IgnoreArgument(1) + .SetReturn((const char*)NULL); /*this key does not exist, the line below is adding it*/ + (void)HTTPHeaders_AddHeaderNameValuePair(httpHandle, NAME1, VALUE1); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, Map_GetValueFromKey(IGNORED_PTR_ARG, NAME2)) + .IgnoreArgument(1) + .SetReturn((const char*)NULL); /*this key does not exist, the line below is adding it*/ + + STRICT_EXPECTED_CALL(mocks, Map_AddOrUpdate(IGNORED_PTR_ARG, NAME2, VALUE2)) + .IgnoreArgument(1); + + ///act + auto res = HTTPHeaders_AddHeaderNameValuePair(httpHandle, NAME2, VALUE2); + + ///assert + ASSERT_ARE_EQUAL(HTTP_HEADERS_RESULT, HTTP_HEADERS_OK, res); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + HTTPHeaders_Free(httpHandle); + } + + /*Tests_SRS_HTTP_HEADERS_99_017:[ If the name already exists in the collection of headers, the function shall concatenate the new value after the existing value, separated by a comma and a space as in: old-value+", "+new-value.]*/ + TEST_FUNCTION(HTTPHeaders_When_Second_Added_Header_Is_A_Substring_Of_An_Existing_Header_2_Headers_Are_Added) + { + ///arrange + CHTTPHeadersMocks mocks; + HTTP_HEADERS_HANDLE httpHandle = HTTPHeaders_Alloc(); + STRICT_EXPECTED_CALL(mocks, Map_GetValueFromKey(IGNORED_PTR_ARG, "ab")) + .IgnoreArgument(1) + .SetReturn((const char*)NULL); /*this key does not exist, the line below is adding it*/ + (void)HTTPHeaders_AddHeaderNameValuePair(httpHandle, "ab", VALUE1); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, Map_GetValueFromKey(IGNORED_PTR_ARG, "a")) + .IgnoreArgument(1) + .SetReturn((const char*)NULL); /*this key does not exist, the line below is adding it*/ + + STRICT_EXPECTED_CALL(mocks, Map_AddOrUpdate(IGNORED_PTR_ARG, "a", VALUE1)) + .IgnoreArgument(1); + + ///act + HTTP_HEADERS_RESULT result = HTTPHeaders_AddHeaderNameValuePair(httpHandle, "a", VALUE1); + + ///assert + ASSERT_ARE_EQUAL(HTTP_HEADERS_RESULT, HTTP_HEADERS_OK, result); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + HTTPHeaders_Free(httpHandle); + } + + /*Tests_SRS_HTTP_HEADERS_99_022:[ The return value shall be NULL if name parameter is NULL or if httpHeadersHandle is NULL]*/ + TEST_FUNCTION(HTTPHeaders_FindHeaderValue_with_NULL_handle_returns_NULL) + { + ///arrange + CHTTPHeadersMocks mocks; + + ///act + auto res = HTTPHeaders_FindHeaderValue(NULL, NAME1); + + ///assert + ASSERT_IS_NULL(res); + mocks.AssertActualAndExpectedCalls(); + } + + /*Tests_SRS_HTTP_HEADERS_99_022:[ The return value shall be NULL if name parameter is NULL or if httpHeadersHandle is NULL]*/ + TEST_FUNCTION(HTTPHeaders_FindHeaderValue_with_NULL_name_returns_NULL) + { + ///arrange + CHTTPHeadersMocks mocks; + auto httpHandle = HTTPHeaders_Alloc(); + mocks.ResetAllCalls(); + + ///act + auto res = HTTPHeaders_FindHeaderValue(httpHandle, NULL); + + ///assert + ASSERT_IS_NULL(res); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + HTTPHeaders_Free(httpHandle); + } + + /*Tests_SRS_HTTP_HEADERS_99_018:[ Calling this API shall retrieve the value for a previously stored name.]*/ + /*Tests_SRS_HTTP_HEADERS_99_021:[ In this case the return value shall point to a string that shall strcmp equal to the original stored string.]*/ + TEST_FUNCTION(HTTPHeaders_FindHeaderValue_retrieves_previously_stored_value_succeeds) + { + ///arrange + CHTTPHeadersMocks mocks; + auto httpHandle = HTTPHeaders_Alloc(); + STRICT_EXPECTED_CALL(mocks, Map_GetValueFromKey(IGNORED_PTR_ARG, NAME1)) + .IgnoreArgument(1) + .SetReturn((const char*)NULL); /*this key does not exist, the line below is adding it*/ + (void)HTTPHeaders_AddHeaderNameValuePair(httpHandle, NAME1, VALUE1); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, Map_GetValueFromKey(IGNORED_PTR_ARG, NAME1)) + .IgnoreArgument(1); + + ///act + auto res1 = HTTPHeaders_FindHeaderValue(httpHandle, NAME1); + + ///assert + ASSERT_ARE_EQUAL(char_ptr, VALUE1, res1); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + HTTPHeaders_Free(httpHandle); + } + + /*Tests_SRS_HTTP_HEADERS_99_018:[ Calling this API shall retrieve the value for a previously stored name.]*/ + /*Tests_SRS_HTTP_HEADERS_99_021:[ In this case the return value shall point to a string that shall strcmp equal to the original stored string.]*/ + TEST_FUNCTION(HTTPHeaders_FindHeaderValue_retrieves_previously_stored_value_for_two_headers_succeeds) + { + ///arrange + CHTTPHeadersMocks mocks; + auto httpHandle = HTTPHeaders_Alloc(); + STRICT_EXPECTED_CALL(mocks, Map_GetValueFromKey(IGNORED_PTR_ARG, NAME1)) + .IgnoreArgument(1) + .SetReturn((const char*)NULL); /*this key does not exist, the line below is adding it*/ + (void)HTTPHeaders_AddHeaderNameValuePair(httpHandle, NAME1, VALUE1); + STRICT_EXPECTED_CALL(mocks, Map_GetValueFromKey(IGNORED_PTR_ARG, NAME2)) + .IgnoreArgument(1) + .SetReturn((const char*)NULL); /*this key does not exist, the line below is adding it*/ + (void)HTTPHeaders_AddHeaderNameValuePair(httpHandle, NAME2, VALUE2); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, Map_GetValueFromKey(IGNORED_PTR_ARG, NAME1)) + .IgnoreArgument(1) + .SetReturn(VALUE1); + STRICT_EXPECTED_CALL(mocks, Map_GetValueFromKey(IGNORED_PTR_ARG, NAME2)) + .IgnoreArgument(1) + .SetReturn(VALUE2); + + ///act + auto res1 = HTTPHeaders_FindHeaderValue(httpHandle, NAME1); + auto res2 = HTTPHeaders_FindHeaderValue(httpHandle, NAME2); + + ///assert + ASSERT_ARE_EQUAL(char_ptr, VALUE1, res1); + ASSERT_ARE_EQUAL(char_ptr, VALUE2, res2); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + HTTPHeaders_Free(httpHandle); + } + + /*Tests_SRS_HTTP_HEADERS_99_018:[ Calling this API shall retrieve the value for a previously stored name.]*/ + /*Tests_SRS_HTTP_HEADERS_99_021:[ In this case the return value shall point to a string that shall strcmp equal to the original stored string.]*/ + TEST_FUNCTION(HTTPHeaders_FindHeaderValue_retrieves_concatenation_of_previously_stored_values_for_header_name_succeeds) + { + CHTTPHeadersMocks mocks; + auto httpHandle = HTTPHeaders_Alloc(); + STRICT_EXPECTED_CALL(mocks, Map_GetValueFromKey(IGNORED_PTR_ARG, NAME1)) + .IgnoreArgument(1) + .SetReturn((const char*)NULL); /*this key does not exist, the line below is adding it*/ + (void)HTTPHeaders_AddHeaderNameValuePair(httpHandle, NAME1, VALUE1); + STRICT_EXPECTED_CALL(mocks, Map_GetValueFromKey(IGNORED_PTR_ARG, NAME1)) + .IgnoreArgument(1) + .SetReturn(VALUE1); /*this key exists, was added above*/ + (void)HTTPHeaders_AddHeaderNameValuePair(httpHandle, NAME1, VALUE2); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, Map_GetValueFromKey(IGNORED_PTR_ARG, NAME1)) + .IgnoreArgument(1) + .SetReturn(VALUE1 ", " VALUE2); + + ///act + auto res = HTTPHeaders_FindHeaderValue(httpHandle, NAME1); + + ///assert + ASSERT_ARE_EQUAL(char_ptr,VALUE1 ", " VALUE2, res); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + HTTPHeaders_Free(httpHandle); + } + + /*Tests_SRS_HTTP_HEADERS_99_020:[ The return value shall be different than NULL when the name matches the name of a previously stored name:value pair.]*/ + /*actually we are trying to see that finding a nonexisting value produces NULL*/ + TEST_FUNCTION(HTTPHeaders_FindHeaderValue_returns_NULL_for_nonexistent_value) + { + ///arrange + CHTTPHeadersMocks mocks; + auto httpHandle = HTTPHeaders_Alloc(); + STRICT_EXPECTED_CALL(mocks, Map_GetValueFromKey(IGNORED_PTR_ARG, NAME1)) + .IgnoreArgument(1) + .SetReturn((const char*)NULL); /*this key does not exist, the line below is adding it*/ + (void)HTTPHeaders_AddHeaderNameValuePair(httpHandle, NAME1, VALUE1); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, Map_GetValueFromKey(IGNORED_PTR_ARG, NAME2)) + .IgnoreArgument(1) + .SetReturn((const char*)NULL); + + ///act + auto res2 = HTTPHeaders_FindHeaderValue(httpHandle, NAME2); + + ///assert + ASSERT_IS_NULL(res2); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + HTTPHeaders_Free(httpHandle); + } + + /*trying to catch some errors here*/ + /*Tests_SRS_HTTP_HEADERS_99_020:[ The return value shall be different than NULL when the name matches the name of a previously stored name:value pair.]*/ + TEST_FUNCTION(HTTPHeaders_FindHeaderValue_with_nonexistent_header_succeeds) + { + ///arrange + CHTTPHeadersMocks mocks; + auto httpHandle = HTTPHeaders_Alloc(); + STRICT_EXPECTED_CALL(mocks, Map_GetValueFromKey(IGNORED_PTR_ARG, NAME1)) + .IgnoreArgument(1) + .SetReturn((const char*)NULL); /*this key does not exist, the line below is adding it*/ + (void)HTTPHeaders_AddHeaderNameValuePair(httpHandle, NAME1, VALUE1); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, Map_GetValueFromKey(IGNORED_PTR_ARG, NAME1_TRICK1)) + .IgnoreArgument(1) + .SetReturn((const char*)NULL); + STRICT_EXPECTED_CALL(mocks, Map_GetValueFromKey(IGNORED_PTR_ARG, NAME1_TRICK2)) + .IgnoreArgument(1) + .SetReturn((const char*)NULL); + STRICT_EXPECTED_CALL(mocks, Map_GetValueFromKey(IGNORED_PTR_ARG, NAME1_TRICK3)) + .IgnoreArgument(1) + .SetReturn((const char*)NULL); + + ///act + auto res1 = HTTPHeaders_FindHeaderValue(httpHandle, NAME1_TRICK1); + auto res2 = HTTPHeaders_FindHeaderValue(httpHandle, NAME1_TRICK2); + auto res3 = HTTPHeaders_FindHeaderValue(httpHandle, NAME1_TRICK3); + + ///assert + ASSERT_IS_NULL(res1); + ASSERT_IS_NULL(res2); + ASSERT_IS_NULL(res3); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + HTTPHeaders_Free(httpHandle); + } + + /* Tests_SRS_HTTP_HEADERS_06_001: [This API will perform exactly as HTTPHeaders_AddHeaderNameValuePair except that if the header name already exists the already existing value will be replaced as opposed to concatenated to.] */ + TEST_FUNCTION(HTTPHeaders_ReplaceHeaderNameValuePair_succeeds) + { + ///arrange + CHTTPHeadersMocks mocks; + auto httpHandle = HTTPHeaders_Alloc(); + STRICT_EXPECTED_CALL(mocks, Map_GetValueFromKey(IGNORED_PTR_ARG, NAME1)) + .IgnoreArgument(1) + .SetReturn((const char*)NULL); /*this key does not exist, the line below is adding it*/ + (void)HTTPHeaders_AddHeaderNameValuePair(httpHandle, NAME1, VALUE1); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, Map_GetValueFromKey(IGNORED_PTR_ARG, NAME1)) + .IgnoreArgument(1) + .SetReturn(VALUE1); /*this key does not exist, the line below is adding it*/ + + STRICT_EXPECTED_CALL(mocks, Map_AddOrUpdate(IGNORED_PTR_ARG, NAME1, VALUE2)) + .IgnoreArgument(1); + + ///act + auto res = HTTPHeaders_ReplaceHeaderNameValuePair(httpHandle, NAME1, VALUE2); + + ///assert + ASSERT_ARE_EQUAL(HTTP_HEADERS_RESULT, HTTP_HEADERS_OK, res); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + HTTPHeaders_Free(httpHandle); + } + + /* Tests_SRS_HTTP_HEADERS_06_001: [This API will perform exactly as HTTPHeaders_AddHeaderNameValuePair except that if the header name already exists the already existing value will be replaced as opposed to concatenated to.] */ + TEST_FUNCTION(HTTPHeaders_ReplaceHeaderNameValuePair_for_none_existing_header_succeeds) + { + ///arrange + CHTTPHeadersMocks mocks; + auto httpHandle = HTTPHeaders_Alloc(); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, Map_GetValueFromKey(IGNORED_PTR_ARG, NAME1)) + .IgnoreArgument(1) + .SetReturn((const char*)NULL); + + STRICT_EXPECTED_CALL(mocks, Map_AddOrUpdate(IGNORED_PTR_ARG, NAME1, VALUE2)) + .IgnoreArgument(1); + + ///act + auto res = HTTPHeaders_ReplaceHeaderNameValuePair(httpHandle, NAME1, VALUE2); + + ///assert + ASSERT_ARE_EQUAL(HTTP_HEADERS_RESULT, HTTP_HEADERS_OK, res); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + HTTPHeaders_Free(httpHandle); + } + + /*Tests_SRS_HTTP_HEADERS_99_024:[ The function shall return HTTP_HEADERS_INVALID_ARG when an invalid handle is passed.]*/ + TEST_FUNCTION(HTTPHeaders_GetHeaderCount_with_NULL_handle_fails) + { + ///arrange + size_t nHeaders; + + ///act + auto res1 = HTTPHeaders_GetHeaderCount(NULL, &nHeaders); + + ///assert + ASSERT_ARE_EQUAL(HTTP_HEADERS_RESULT, HTTP_HEADERS_INVALID_ARG, res1); + } + + /*Tests_SRS_HTTP_HEADERS_99_025:[ The function shall return HTTP_HEADERS_INVALID_ARG when headersCount is NULL.]*/ + TEST_FUNCTION(HTTPHeaders_GetHeaderCount_with_NULL_headersCount_fails) + { + ///arrange + CHTTPHeadersMocks mocks; + auto httpHandle = HTTPHeaders_Alloc(); + mocks.ResetAllCalls(); + + ///act + auto res1 = HTTPHeaders_GetHeaderCount(httpHandle, NULL); + + ///assert + ASSERT_ARE_EQUAL(HTTP_HEADERS_RESULT, HTTP_HEADERS_INVALID_ARG, res1); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + HTTPHeaders_Free(httpHandle); + } + + /*Tests_SRS_HTTP_HEADERS_99_026:[ The function shall write in *headersCount the number of currently stored headers and shall return HTTP_HEADERS_OK]*/ + /*Tests_SRS_HTTP_HEADERS_99_023:[ Calling this API shall provide the number of stored headers.]*/ + /*Tests_SRS_HTTP_HEADERS_99_016:[ The function shall store the name:value pair in such a way that when later retrieved by a call to GetHeader it will return a string that shall strcmp equal to the name+": "+value.]*/ + TEST_FUNCTION(HTTPHeaders_GetHeaderCount_with_1_header_produces_1) + { + ///arrange + CHTTPHeadersMocks mocks; + auto httpHandle = HTTPHeaders_Alloc(); + STRICT_EXPECTED_CALL(mocks, Map_GetValueFromKey(IGNORED_PTR_ARG, NAME1)) + .IgnoreArgument(1) + .SetReturn((const char*)NULL); /*this key does not exist, the line below is adding it*/ + (void)HTTPHeaders_AddHeaderNameValuePair(httpHandle, NAME1, VALUE1); + size_t nHeaders; + const char* keys[] = { "NAME1" }; + const char* values[] = { "VALUE1" }; + const char* const ** pKeys = (const char* const **)&keys; + const char* const ** pValues = (const char* const **)&values; + const size_t one = 1; + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, Map_GetInternals(IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG)) + .IgnoreArgument(1) + .CopyOutArgumentBuffer(2, &pKeys, sizeof(pKeys)) + .CopyOutArgumentBuffer(3, &pValues, sizeof(pValues)) + .CopyOutArgumentBuffer(4, &one, sizeof(one)); + + + ///act + auto res = HTTPHeaders_GetHeaderCount(httpHandle, &nHeaders); + + ///assert + ASSERT_ARE_EQUAL(HTTP_HEADERS_RESULT, HTTP_HEADERS_OK, res); + ASSERT_ARE_EQUAL(size_t, (size_t)1, nHeaders); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + HTTPHeaders_Free(httpHandle); + } + + /*Tests_SRS_HTTP_HEADERS_99_037:[ The function shall return HTTP_HEADERS_ERROR when an internal error occurs.]*/ + TEST_FUNCTION(HTTPHeaders_GetHeaderCount_fails_when_Map_GetInternals_fails) + { + ///arrange + CHTTPHeadersMocks mocks; + auto httpHandle = HTTPHeaders_Alloc(); + size_t nHeaders; + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, Map_GetInternals(IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG)) + .IgnoreAllArguments() + .SetReturn(MAP_ERROR); + + ///act + auto res = HTTPHeaders_GetHeaderCount(httpHandle, &nHeaders); + + ///assert + ASSERT_ARE_EQUAL(HTTP_HEADERS_RESULT, HTTP_HEADERS_ERROR, res); + mocks.AssertActualAndExpectedCalls(); + + + ///cleanup + HTTPHeaders_Free(httpHandle); + } + + /*Tests_SRS_HTTP_HEADERS_99_026:[ The function shall write in *headersCount the number of currently stored headers and shall return HTTP_HEADERS_OK]*/ + /*Tests_SRS_HTTP_HEADERS_99_023:[ Calling this API shall provide the number of stored headers.]*/ + TEST_FUNCTION(HTTPHeaders_GetHeaderCount_with_2_header_produces_2) + { + ///arrange + CHTTPHeadersMocks mocks; + auto httpHandle = HTTPHeaders_Alloc(); + STRICT_EXPECTED_CALL(mocks, Map_GetValueFromKey(IGNORED_PTR_ARG, NAME1)) + .IgnoreArgument(1) + .SetReturn((const char*)NULL); /*this key does not exist, the line below is adding it*/ + (void)HTTPHeaders_AddHeaderNameValuePair(httpHandle, NAME1, VALUE1); + STRICT_EXPECTED_CALL(mocks, Map_GetValueFromKey(IGNORED_PTR_ARG, NAME2)) + .IgnoreArgument(1) + .SetReturn((const char*)NULL); /*this key does not exist, the line below is adding it*/ + (void)HTTPHeaders_AddHeaderNameValuePair(httpHandle, NAME2, VALUE2); + size_t nHeaders; + const char* keys[2] = { "NAME1", "NAME2" }; + const char* values[2] = { "VALUE1", "VALUE2" }; + const char* const ** pKeys = (const char* const **)&keys; + const char* const ** pValues = (const char* const **)&values; + + const size_t two = 2; + mocks.ResetAllCalls(); + + + STRICT_EXPECTED_CALL(mocks, Map_GetInternals(IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG)) + .IgnoreArgument(1) + .CopyOutArgumentBuffer(2, &pKeys, sizeof(pKeys)) + .CopyOutArgumentBuffer(3, &pValues, sizeof(pValues)) + .CopyOutArgumentBuffer(4, &two, sizeof(two)); + + ///act + auto res = HTTPHeaders_GetHeaderCount(httpHandle, &nHeaders); + + ///assert + ASSERT_ARE_EQUAL(HTTP_HEADERS_RESULT, HTTP_HEADERS_OK, res); + ASSERT_ARE_EQUAL(size_t, 2, nHeaders); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + HTTPHeaders_Free(httpHandle); + } + + /*Tests_SRS_HTTP_HEADERS_99_028:[ The function shall return NULL if the handle is invalid.]*/ + TEST_FUNCTION(HTTPHeaders_GetHeader_with_NULL_handle_fails) + { + ///arrange + char* headerValue; + + ///act + auto res = HTTPHeaders_GetHeader(NULL, 0, &headerValue); + + ///assert + ASSERT_ARE_EQUAL(HTTP_HEADERS_RESULT, HTTP_HEADERS_INVALID_ARG, res); + } + + /*Tests_SRS_HTTP_HEADERS_99_032:[ The function shall return HTTP_HEADERS_INVALID_ARG if the destination is NULL]*/ + TEST_FUNCTION(HTTPHeaders_GetHeader_with_NULL_buffer_fails) + { + ///arrange + CHTTPHeadersMocks mocks; + auto httpHandle = HTTPHeaders_Alloc(); + STRICT_EXPECTED_CALL(mocks, Map_GetValueFromKey(IGNORED_PTR_ARG, NAME1)) + .IgnoreArgument(1) + .SetReturn((const char*)NULL); /*this key does not exist, the line below is adding it*/ + (void)HTTPHeaders_AddHeaderNameValuePair(httpHandle, NAME1, VALUE1); + mocks.ResetAllCalls(); + + ///act + auto res = HTTPHeaders_GetHeader(httpHandle, 0, NULL); + + ///assert + ASSERT_ARE_EQUAL(HTTP_HEADERS_RESULT, HTTP_HEADERS_INVALID_ARG, res); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + HTTPHeaders_Free(httpHandle); + } + + /*Tests_SRS_HTTP_HEADERS_99_029:[ The function shall return HTTP_HEADERS_INVALID_ARG if index is not valid (for example, out of range) for the currently stored headers.]*/ + /*Tests that not adding something to the collection fails tso retrieve for index 0*/ + TEST_FUNCTION(HTTPHeaders_GetHeader_with_index_too_big_fails_1) + { + ///arrange + CHTTPHeadersMocks mocks; + auto httpHandle = HTTPHeaders_Alloc(); + char* headerValue; + const char* thisIsNULL = NULL; + const char* zero = 0; + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, Map_GetInternals(IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG)) + .IgnoreArgument(1) + .CopyOutArgumentBuffer(2, &thisIsNULL, sizeof(thisIsNULL)) + .CopyOutArgumentBuffer(3, &thisIsNULL, sizeof(thisIsNULL)) + .CopyOutArgumentBuffer(4, &zero, sizeof(zero)); + + ///act + auto res1 = HTTPHeaders_GetHeader(httpHandle, 0, &headerValue); + + ///assert + ASSERT_ARE_EQUAL(HTTP_HEADERS_RESULT, HTTP_HEADERS_INVALID_ARG, res1); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + HTTPHeaders_Free(httpHandle); + } + + /*Tests_SRS_HTTP_HEADERS_99_029:[ The function shall return HTTP_HEADERS_INVALID_ARG if index is not valid (for example, out of range) for the currently stored headers.]*/ + /*Tests that not adding something to the collection fails tso retrieve for index 0*/ + TEST_FUNCTION(HTTPHeaders_GetHeader_with_index_too_big_fails_2) + { + ///arrange + CHTTPHeadersMocks mocks; + auto httpHandle = HTTPHeaders_Alloc(); + STRICT_EXPECTED_CALL(mocks, Map_GetValueFromKey(IGNORED_PTR_ARG, NAME1)) + .IgnoreArgument(1) + .SetReturn((const char*)NULL); /*this key does not exist, the line below is adding it*/ + (void)HTTPHeaders_AddHeaderNameValuePair(httpHandle, NAME1, VALUE1); + const char* keys[1] = { "NAME1" }; + const char* values[1] = { "VALUE1" }; + const char* const ** pKeys = (const char* const **)&keys; + const char* const ** pValues = (const char* const **)&values; + const size_t one = 1; + mocks.ResetAllCalls(); + char* headerValue; + + STRICT_EXPECTED_CALL(mocks, Map_GetInternals(IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG)) + .IgnoreArgument(1) + .CopyOutArgumentBuffer(2, pKeys, sizeof(pKeys)) + .CopyOutArgumentBuffer(3, pValues, sizeof(pValues)) + .CopyOutArgumentBuffer(4, &one, sizeof(one)); + + ///act + auto res1 = HTTPHeaders_GetHeader(httpHandle, 1, &headerValue); + + ///assert + ASSERT_ARE_EQUAL(HTTP_HEADERS_RESULT, HTTP_HEADERS_INVALID_ARG, res1); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + HTTPHeaders_Free(httpHandle); + } + + /*Tests_SRS_HTTP_HEADERS_99_027:[ Calling this API shall produce the string value+": "+pair) for the index header in the buffer pointed to by buffer.]*/ + /*Tests_SRS_HTTP_HEADERS_99_035:[ The function shall return HTTP_HEADERS_OK when the function executed without error.]*/ + TEST_FUNCTION(HTTPHeaders_GetHeader_succeeds_1) + { + ///arrange + CHTTPHeadersMocks mocks; + auto httpHandle = HTTPHeaders_Alloc(); + STRICT_EXPECTED_CALL(mocks, Map_GetValueFromKey(IGNORED_PTR_ARG, "a")) + .IgnoreArgument(1) + .SetReturn((const char*)NULL); /*this key does not exist, the line below is adding it*/ + (void)HTTPHeaders_AddHeaderNameValuePair(httpHandle, "a", "b"); + mocks.ResetAllCalls(); + char* headerValue; + const char* keys[1] = { "a" }; + auto pKeys = &keys; + const char* values[1] = { "b" }; + auto pValues = &values; + const size_t one = 1; + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(IGNORED_NUM_ARG)) + .IgnoreArgument(1); + + STRICT_EXPECTED_CALL(mocks, Map_GetInternals(IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG)) + .IgnoreArgument(1) + .CopyOutArgumentBuffer(2, &pKeys, sizeof(pKeys)) + .CopyOutArgumentBuffer(3, &pValues, sizeof(pValues)) + .CopyOutArgumentBuffer(4, &one, sizeof(one)); + + ///act + auto res1 = HTTPHeaders_GetHeader(httpHandle, 0, &headerValue); + + ///assert + ASSERT_ARE_EQUAL(HTTP_HEADERS_RESULT, HTTP_HEADERS_OK, res1); + ASSERT_ARE_EQUAL(char_ptr, "a: b", headerValue); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + HTTPHeaders_Free(httpHandle); + free(headerValue); + } + + /*Tests_SRS_HTTP_HEADERS_99_034:[ The function shall return HTTP_HEADERS_ERROR when an internal error occurs]*/ + TEST_FUNCTION(HTTPHeaders_GetHeader_fails_when_Map_GetInternals_fails) + { + ///arrange + CHTTPHeadersMocks mocks; + auto httpHandle = HTTPHeaders_Alloc(); + STRICT_EXPECTED_CALL(mocks, Map_GetValueFromKey(IGNORED_PTR_ARG, "a")) + .IgnoreArgument(1) + .SetReturn((const char*)NULL); /*this key does not exist, the line below is adding it*/ + (void)HTTPHeaders_AddHeaderNameValuePair(httpHandle, "a", "b"); + mocks.ResetAllCalls(); + char* headerValue; + const char* keys[1] = { "a" }; + auto pKeys = &keys; + const char* values[1] = { "b" }; + auto pValues = &values; + const size_t one = 1; + + STRICT_EXPECTED_CALL(mocks, Map_GetInternals(IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG)) + .IgnoreArgument(1) + .CopyOutArgumentBuffer(2, &pKeys, sizeof(pKeys)) + .CopyOutArgumentBuffer(3, &pValues, sizeof(pValues)) + .CopyOutArgumentBuffer(4, &one, sizeof(one)) + .SetReturn(MAP_ERROR); + + ///act + auto res1 = HTTPHeaders_GetHeader(httpHandle, 0, &headerValue); + + ///assert + ASSERT_ARE_EQUAL(HTTP_HEADERS_RESULT, HTTP_HEADERS_ERROR, res1); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + HTTPHeaders_Free(httpHandle); + } + + /*Tests_SRS_HTTP_HEADERS_99_034:[ The function shall return HTTP_HEADERS_ERROR when an internal error occurs]*/ + TEST_FUNCTION(HTTPHeaders_GetHeader_succeeds_fails_when_malloc_fails) + { + ///arrange + CHTTPHeadersMocks mocks; + auto httpHandle = HTTPHeaders_Alloc(); + STRICT_EXPECTED_CALL(mocks, Map_GetValueFromKey(IGNORED_PTR_ARG, "a")) + .IgnoreArgument(1) + .SetReturn((const char*)NULL); /*this key does not exist, the line below is adding it*/ + (void)HTTPHeaders_AddHeaderNameValuePair(httpHandle, "a", "b"); + mocks.ResetAllCalls(); + char* headerValue; + const char* keys[1] = { "a" }; + auto pKeys = &keys; + const char* values[1] = { "b" }; + auto pValues = &values; + const size_t one = 1; + + STRICT_EXPECTED_CALL(mocks, Map_GetInternals(IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG)) + .IgnoreArgument(1) + .CopyOutArgumentBuffer(2, &pKeys, sizeof(pKeys)) + .CopyOutArgumentBuffer(3, &pValues, sizeof(pValues)) + .CopyOutArgumentBuffer(4, &one, sizeof(one)); + + whenShallmalloc_fail = currentmalloc_call + 1; + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(IGNORED_NUM_ARG)) + .IgnoreArgument(1); + + ///act + auto res1 = HTTPHeaders_GetHeader(httpHandle, 0, &headerValue); + + ///assert + ASSERT_ARE_EQUAL(HTTP_HEADERS_RESULT, HTTP_HEADERS_ERROR, res1); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + HTTPHeaders_Free(httpHandle); + free(headerValue); + } + + /*Tests_SRS_HTTP_HEADERS_99_031:[ If name contains the character ":" then the return value shall be HTTP_HEADERS_INVALID_ARG.]*/ + TEST_FUNCTION(HTTPHeaders_AddHeaderNameValuePair_with_colon_in_name_fails) + { + ///arrange + CHTTPHeadersMocks mocks; + auto httpHandle = HTTPHeaders_Alloc(); + mocks.ResetAllCalls(); + + ///act + auto res = HTTPHeaders_AddHeaderNameValuePair(httpHandle, "a:", "b"); + + ///assert + ASSERT_ARE_EQUAL(HTTP_HEADERS_RESULT, HTTP_HEADERS_INVALID_ARG, res); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + HTTPHeaders_Free(httpHandle); + } + + /*Tests_SRS_HTTP_HEADERS_99_031:[ If name contains the character ":" then the return value shall be HTTP_HEADERS_INVALID_ARG.]*/ + TEST_FUNCTION(HTTPHeaders_AddHeaderNameVAluePair_with_colon_in_value_succeeds_1) + { + ///arrange + CHTTPHeadersMocks mocks; + auto httpHandle = HTTPHeaders_Alloc(); + char* headerValue; + STRICT_EXPECTED_CALL(mocks, Map_GetValueFromKey(IGNORED_PTR_ARG, "a")) + .IgnoreArgument(1) + .SetReturn((const char*)NULL); /*this key does not exist, the line below is adding it*/ + (void)HTTPHeaders_AddHeaderNameValuePair(httpHandle, "a", ":"); + const char* keys[1] = { "a" }; + auto pKeys = &keys; + const char* values[1] = { ":" }; + auto pValues = &values; + const size_t one = 1; + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(IGNORED_NUM_ARG)) + .IgnoreArgument(1); + + STRICT_EXPECTED_CALL(mocks, Map_GetInternals(IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG)) + .IgnoreArgument(1) + .CopyOutArgumentBuffer(2, &pKeys, sizeof(pKeys)) + .CopyOutArgumentBuffer(3, &pValues, sizeof(pValues)) + .CopyOutArgumentBuffer(4, &one, sizeof(one)); + + ///act + auto res1 = HTTPHeaders_GetHeader(httpHandle, 0, &headerValue); + + ///assert + ASSERT_ARE_EQUAL(HTTP_HEADERS_RESULT, HTTP_HEADERS_OK, res1); + ASSERT_ARE_EQUAL(char_ptr, "a: :", headerValue); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + HTTPHeaders_Free(httpHandle); + free(headerValue); + + } + + /*Tests_SRS_HTTP_HEADERS_99_036:[ If name contains the characters outside character codes 33 to 126 then the return value shall be HTTP_HEADERS_INVALID_ARG]*/ + /*so says http://tools.ietf.org/html/rfc822#section-3.1*/ + TEST_FUNCTION(HTTP_HEADERS_AddHeaderNameValuePair_fails_for_every_invalid_character) + { + ///arrange + CNiceCallComparermocks; + auto httpHandle = HTTPHeaders_Alloc(); + char unacceptableString[2]={'\0', '\0'}; + + for(int c=SCHAR_MIN;c <=SCHAR_MAX; c++) + { + if(c=='\0') continue; + + if((c<33) ||( 126 +#include "testrunnerswitcher.h" +#include "micromock.h" +#include "list.h" + +bool fail_alloc_calls; + +TYPED_MOCK_CLASS(list_mocks, CGlobalMock) +{ +public: + /* amqpalloc mocks */ + MOCK_STATIC_METHOD_1(, void*, amqpalloc_malloc, size_t, size) + MOCK_METHOD_END(void*, malloc(size)); + MOCK_STATIC_METHOD_1(, void, amqpalloc_free, void*, ptr) + free(ptr); + MOCK_VOID_METHOD_END(); + + /* test match function mock */ + MOCK_STATIC_METHOD_2(, bool, test_match_function, LIST_ITEM_HANDLE, list_item, const void*, match_context) + MOCK_METHOD_END(bool, true); +}; + +extern "C" +{ + DECLARE_GLOBAL_MOCK_METHOD_1(list_mocks, , void*, amqpalloc_malloc, size_t, size); + DECLARE_GLOBAL_MOCK_METHOD_1(list_mocks, , void, amqpalloc_free, void*, ptr); + + DECLARE_GLOBAL_MOCK_METHOD_2(list_mocks, , bool, test_match_function, LIST_ITEM_HANDLE, list_item, const void*, match_context); +} + +MICROMOCK_MUTEX_HANDLE test_serialize_mutex; + +#define TEST_CONTEXT ((const void*)0x4242) + +BEGIN_TEST_SUITE(list_unittests) + + TEST_SUITE_INITIALIZE(suite_init) + { + test_serialize_mutex = MicroMockCreateMutex(); + ASSERT_IS_NOT_NULL(test_serialize_mutex); + } + + TEST_SUITE_CLEANUP(suite_cleanup) + { + MicroMockDestroyMutex(test_serialize_mutex); + } + + TEST_FUNCTION_INITIALIZE(method_init) + { + if (!MicroMockAcquireMutex(test_serialize_mutex)) + { + ASSERT_FAIL("Could not acquire test serialization mutex."); + } + fail_alloc_calls = false; + } + + TEST_FUNCTION_CLEANUP(method_cleanup) + { + if (!MicroMockReleaseMutex(test_serialize_mutex)) + { + ASSERT_FAIL("Could not release test serialization mutex."); + } + } + + /* list_create */ + + /* Tests_SRS_LIST_01_001: [list_create shall create a new list and return a non-NULL handle on success.] */ + TEST_FUNCTION(when_underlying_calls_suceed_list_create_succeeds) + { + // arrange + list_mocks mocks; + + EXPECTED_CALL(mocks, amqpalloc_malloc(IGNORED_NUM_ARG)); + + // act + LIST_HANDLE result = list_create(); + + // assert + ASSERT_IS_NOT_NULL(result); + } + + /* Tests_SRS_LIST_01_002: [If any error occurs during the list creation, list_create shall return NULL.] */ + TEST_FUNCTION(when_underlying_malloc_fails_list_create_fails) + { + // arrange + list_mocks mocks; + + EXPECTED_CALL(mocks, amqpalloc_malloc(IGNORED_NUM_ARG)) + .SetReturn((void*)NULL); + + // act + LIST_HANDLE result = list_create(); + + // assert + ASSERT_IS_NULL(result); + } + + /* list_destroy */ + + /* Tests_SRS_LIST_01_003: [list_destroy shall free all resources associated with the list identified by the handle argument.] */ + TEST_FUNCTION(list_destroy_on_a_non_null_handle_frees_resources) + { + // arrange + list_mocks mocks; + LIST_HANDLE handle = list_create(); + mocks.ResetAllCalls(); + + EXPECTED_CALL(mocks, amqpalloc_free(IGNORED_PTR_ARG)); + + // act + list_destroy(handle); + + // assert + // uMock checks the calls + } + + /* Tests_SRS_LIST_01_004: [If the handle argument is NULL, no freeing of resources shall occur.] */ + TEST_FUNCTION(list_destroy_on_a_null_handle_frees_nothing) + { + // arrange + list_mocks mocks; + + // act + list_destroy(NULL); + + // assert + // uMock checks the calls + } + + /* list_add */ + + /* Tests_SRS_LIST_01_006: [If any of the arguments is NULL, list_add shall not add the item to the list and return a non-zero value.] */ + TEST_FUNCTION(list_add_with_NULL_handle_fails) + { + // arrange + list_mocks mocks; + int x = 42; + + // act + int result = list_add(NULL, &x); + + // assert + ASSERT_ARE_NOT_EQUAL(int, 0, result); + } + + /* Tests_SRS_LIST_01_006: [If any of the arguments is NULL, list_add shall not add the item to the list and return a non-zero value.] */ + TEST_FUNCTION(list_add_with_NULL_item_fails) + { + // arrange + list_mocks mocks; + LIST_HANDLE handle = list_create(); + mocks.ResetAllCalls(); + + // act + int result = list_add(handle, NULL); + + // assert + ASSERT_ARE_NOT_EQUAL(int, 0, result); + } + + /* Tests_SRS_LIST_01_005: [list_add shall add one item to the tail of the list and on success it shall return 0.] */ + /* Tests_SRS_LIST_01_008: [list_get_head_item shall return the head of the list.] */ + TEST_FUNCTION(list_add_adds_the_item_and_returns_zero) + { + // arrange + list_mocks mocks; + LIST_HANDLE handle = list_create(); + mocks.ResetAllCalls(); + int x = 42; + + EXPECTED_CALL(mocks, amqpalloc_malloc(IGNORED_NUM_ARG)); + + // act + int result = list_add(handle, &x); + + // assert + ASSERT_ARE_EQUAL(int, 0, result); + mocks.AssertActualAndExpectedCalls(); + LIST_ITEM_HANDLE head = list_get_head_item(handle); + ASSERT_IS_NOT_NULL(head); + ASSERT_ARE_EQUAL(int, x, *(const int*)list_item_get_value(head)); + } + + /* Tests_SRS_LIST_01_005: [list_add shall add one item to the tail of the list and on success it shall return 0.] */ + /* Tests_SRS_LIST_01_008: [list_get_head_item shall return the head of the list.] */ + TEST_FUNCTION(list_add_when_an_item_is_in_the_list_adds_at_the_end) + { + // arrange + list_mocks mocks; + LIST_HANDLE handle = list_create(); + int x1 = 42; + int x2 = 43; + + list_add(handle, &x1); + mocks.ResetAllCalls(); + + EXPECTED_CALL(mocks, amqpalloc_malloc(IGNORED_NUM_ARG)); + + // act + int result = list_add(handle, &x2); + + // assert + ASSERT_ARE_EQUAL(int, 0, result); + mocks.AssertActualAndExpectedCalls(); + LIST_ITEM_HANDLE list_item = list_get_head_item(handle); + ASSERT_IS_NOT_NULL(list_item); + ASSERT_ARE_EQUAL(int, x1, *(const int*)list_item_get_value(list_item)); + list_item = list_get_next_item(list_item); + ASSERT_IS_NOT_NULL(list_item); + ASSERT_ARE_EQUAL(int, x2, *(const int*)list_item_get_value(list_item)); + } + + /* Tests_SRS_LIST_01_007: [If allocating the new list node fails, list_add shall return a non-zero value.] */ + TEST_FUNCTION(when_the_underlying_malloc_fails_list_add_fails) + { + // arrange + list_mocks mocks; + LIST_HANDLE handle = list_create(); + int x = 42; + mocks.ResetAllCalls(); + + EXPECTED_CALL(mocks, amqpalloc_malloc(IGNORED_NUM_ARG)) + .SetReturn((void*)NULL); + + // act + int result = list_add(handle, &x); + + // assert + ASSERT_ARE_NOT_EQUAL(int, 0, result); + } + + /* list_get_head_item */ + + /* Tests_SRS_LIST_01_010: [If the list is empty, list_get_head_item_shall_return NULL.] */ + TEST_FUNCTION(when_the_list_is_empty_list_get_head_item_yields_NULL) + { + // arrange + list_mocks mocks; + LIST_HANDLE handle = list_create(); + mocks.ResetAllCalls(); + + // act + LIST_ITEM_HANDLE result = list_get_head_item(handle); + + // assert + ASSERT_IS_NULL(result); + } + + /* Tests_SRS_LIST_01_009: [If the handle argument is NULL, list_get_head_item shall return NULL.] */ + TEST_FUNCTION(list_get_head_item_with_NULL_handle_yields_NULL) + { + // arrange + list_mocks mocks; + + // act + LIST_ITEM_HANDLE result = list_get_head_item(NULL); + + // assert + ASSERT_IS_NULL(result); + } + + /* Tests_SRS_LIST_01_008: [list_get_head_item shall return the head of the list.] */ + TEST_FUNCTION(list_get_head_item_removes_the_item) + { + // arrange + list_mocks mocks; + LIST_HANDLE handle = list_create(); + int x = 42; + (void)list_add(handle, &x); + mocks.ResetAllCalls(); + + // act + LIST_ITEM_HANDLE head = list_get_head_item(handle); + + // assert + ASSERT_IS_NOT_NULL(head); + ASSERT_ARE_EQUAL(int, x, *(const int*)list_item_get_value(head)); + } + + /* list_get_next_item */ + + /* Tests_SRS_LIST_01_018: [list_get_next_item shall return the next item in the list following the item item_handle.] */ + TEST_FUNCTION(list_get_next_item_gets_the_next_item) + { + // arrange + list_mocks mocks; + LIST_HANDLE handle = list_create(); + int x1 = 42; + int x2 = 43; + (void)list_add(handle, &x1); + (void)list_add(handle, &x2); + mocks.ResetAllCalls(); + LIST_ITEM_HANDLE item = list_get_head_item(handle); + + // act + item = list_get_next_item(item); + + // assert + ASSERT_IS_NOT_NULL(item); + ASSERT_ARE_EQUAL(int, x2, *(const int*)list_item_get_value(item)); + } + + /* Tests_SRS_LIST_01_019: [If item_handle is NULL then list_get_next_item shall return NULL.] */ + TEST_FUNCTION(list_get_next_item_with_NULL_item_handle_returns_NULL) + { + // arrange + list_mocks mocks; + LIST_HANDLE handle = list_create(); + mocks.ResetAllCalls(); + + // act + LIST_ITEM_HANDLE item = list_get_next_item(NULL); + + // assert + ASSERT_IS_NULL(item); + } + + /* Tests_SRS_LIST_01_022: [If no more items exist in the list after the item_handle item, list_get_next_item shall return NULL.] */ + TEST_FUNCTION(list_get_next_item_when_no_more_items_in_list_returns_NULL) + { + // arrange + list_mocks mocks; + LIST_HANDLE handle = list_create(); + int x1 = 42; + int x2 = 43; + (void)list_add(handle, &x1); + (void)list_add(handle, &x2); + mocks.ResetAllCalls(); + LIST_ITEM_HANDLE item = list_get_head_item(handle); + item = list_get_next_item(item); + + // act + item = list_get_next_item(item); + + // assert + ASSERT_IS_NULL(item); + } + + /* list_item_get_value */ + + /* Tests_SRS_LIST_01_020: [list_item_get_value shall return the value associated with the list item identified by the item_handle argument.] */ + TEST_FUNCTION(list_item_get_value_returns_the_item_value) + { + // arrange + list_mocks mocks; + LIST_HANDLE handle = list_create(); + int x = 42; + (void)list_add(handle, &x); + mocks.ResetAllCalls(); + LIST_ITEM_HANDLE item = list_get_head_item(handle); + + // act + int result = *(const int*)list_item_get_value(item); + + // assert + ASSERT_ARE_EQUAL(int, x, result); + } + + /* Tests_SRS_LIST_01_021: [If item_handle is NULL, list_item_get_value shall return NULL.] */ + TEST_FUNCTION(list_item_get_value_with_NULL_item_returns_NULL) + { + // arrange + list_mocks mocks; + + // act + const void* result = list_item_get_value(NULL); + + // assert + ASSERT_IS_NULL(result); + } + + /* list_find */ + + /* Tets_SRS_LIST_01_012: [If the handle or the match_function argument is NULL, list_find shall return NULL.] */ + TEST_FUNCTION(list_find_with_NULL_handle_fails_with_NULL) + { + // arrange + list_mocks mocks; + + // act + LIST_ITEM_HANDLE result = list_find(NULL, test_match_function, TEST_CONTEXT); + + // assert + ASSERT_IS_NULL(result); + } + + /* Tets_SRS_LIST_01_012: [If the handle or the match_function argument is NULL, list_find shall return NULL.] */ + TEST_FUNCTION(list_find_with_NULL__fails_with_NULL) + { + // arrange + list_mocks mocks; + LIST_HANDLE handle = list_create(); + int x = 42; + (void)list_add(handle, &x); + mocks.ResetAllCalls(); + + // act + LIST_ITEM_HANDLE result = list_find(handle, NULL, TEST_CONTEXT); + + // assert + ASSERT_IS_NULL(result); + } + + /* Tests_SRS_LIST_01_011: [list_find shall iterate through all items in a list and return the one that satisfies a certain match function.] */ + /* Tests_SRS_LIST_01_014: [list find shall determine whether an item satisfies the match criteria by invoking the match function for each item in the list until a matching item is found.] */ + /* Tests_SRS_LIST_01_013: [The match_function shall get as arguments the list item being attempted to be matched and the match_context as is.] */ + /* Tests_SRS_LIST_01_017: [If the match function returns true, list_find shall consider that item as matching.] */ + TEST_FUNCTION(list_find_on_a_list_with_1_matching_item_yields_that_item) + { + // arrange + list_mocks mocks; + LIST_HANDLE handle = list_create(); + int x = 42; + (void)list_add(handle, &x); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, test_match_function(IGNORED_PTR_ARG, TEST_CONTEXT)) + .IgnoreArgument(1); + + // act + LIST_ITEM_HANDLE result = list_find(handle, test_match_function, TEST_CONTEXT); + + // assert + ASSERT_IS_NOT_NULL(result); + ASSERT_ARE_EQUAL(int, x, *(const int*)list_item_get_value(result)); + } + + /* Tests_SRS_LIST_01_016: [If the match function returns false, list_find shall consider that item as not matching.] */ + TEST_FUNCTION(list_find_on_a_list_with_1_items_that_does_not_match_returns_NULL) + { + // arrange + list_mocks mocks; + LIST_HANDLE handle = list_create(); + int x = 42; + (void)list_add(handle, &x); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, test_match_function(IGNORED_PTR_ARG, TEST_CONTEXT)) + .IgnoreArgument(1).SetReturn(false); + + // act + LIST_ITEM_HANDLE result = list_find(handle, test_match_function, TEST_CONTEXT); + + // assert + ASSERT_IS_NULL(result); + } + + /* Tests_SRS_LIST_01_011: [list_find shall iterate through all items in a list and return the one that satisfies a certain match function.] */ + /* Tests_SRS_LIST_01_014: [list find shall determine whether an item satisfies the match criteria by invoking the match function for each item in the list until a matching item is found.] */ + /* Tests_SRS_LIST_01_013: [The match_function shall get as arguments the list item being attempted to be matched and the match_context as is.] */ + /* Tests_SRS_LIST_01_017: [If the match function returns true, list_find shall consider that item as matching.] */ + TEST_FUNCTION(list_find_on_a_list_with_2_items_where_the_first_matches_yields_the_first_item) + { + // arrange + list_mocks mocks; + LIST_HANDLE handle = list_create(); + int x1 = 42; + int x2 = 43; + (void)list_add(handle, &x1); + (void)list_add(handle, &x2); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, test_match_function(IGNORED_PTR_ARG, TEST_CONTEXT)) + .IgnoreArgument(1); + + // act + LIST_ITEM_HANDLE result = list_find(handle, test_match_function, TEST_CONTEXT); + + // assert + ASSERT_IS_NOT_NULL(result); + ASSERT_ARE_EQUAL(int, x1, *(int*)list_item_get_value(result)); + } + + /* Tests_SRS_LIST_01_011: [list_find shall iterate through all items in a list and return the one that satisfies a certain match function.] */ + /* Tests_SRS_LIST_01_014: [list find shall determine whether an item satisfies the match criteria by invoking the match function for each item in the list until a matching item is found.] */ + /* Tests_SRS_LIST_01_013: [The match_function shall get as arguments the list item being attempted to be matched and the match_context as is.] */ + /* Tests_SRS_LIST_01_017: [If the match function returns true, list_find shall consider that item as matching.] */ + /* Tests_SRS_LIST_01_016: [If the match function returns false, list_find shall consider that item as not matching.] */ + TEST_FUNCTION(list_find_on_a_list_with_2_items_where_the_second_matches_yields_the_second_item) + { + // arrange + list_mocks mocks; + LIST_HANDLE handle = list_create(); + int x1 = 42; + int x2 = 43; + (void)list_add(handle, &x1); + (void)list_add(handle, &x2); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, test_match_function(IGNORED_PTR_ARG, TEST_CONTEXT)) + .IgnoreArgument(1).SetReturn(false); + STRICT_EXPECTED_CALL(mocks, test_match_function(IGNORED_PTR_ARG, TEST_CONTEXT)) + .IgnoreArgument(1); + + // act + LIST_ITEM_HANDLE result = list_find(handle, test_match_function, TEST_CONTEXT); + + // assert + ASSERT_IS_NOT_NULL(result); + ASSERT_ARE_EQUAL(int, x2, *(int*)list_item_get_value(result)); + } + + /* Tests_SRS_LIST_01_016: [If the match function returns false, list_find shall consider that item as not matching.] */ + TEST_FUNCTION(list_find_on_a_list_with_2_items_where_none_matches_returns_NULL) + { + // arrange + list_mocks mocks; + LIST_HANDLE handle = list_create(); + int x1 = 42; + int x2 = 43; + (void)list_add(handle, &x1); + (void)list_add(handle, &x2); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, test_match_function(IGNORED_PTR_ARG, TEST_CONTEXT)) + .IgnoreArgument(1).SetReturn(false); + STRICT_EXPECTED_CALL(mocks, test_match_function(IGNORED_PTR_ARG, TEST_CONTEXT)) + .IgnoreArgument(1).SetReturn(false); + + // act + LIST_ITEM_HANDLE result = list_find(handle, test_match_function, TEST_CONTEXT); + + // assert + ASSERT_IS_NULL(result); + } + + /* Tests_SRS_LIST_01_015: [If the list is empty, list_find shall return NULL.] */ + TEST_FUNCTION(list_find_on_a_list_with_no_items_yields_NULL) + { + // arrange + list_mocks mocks; + LIST_HANDLE handle = list_create(); + mocks.ResetAllCalls(); + + // act + LIST_ITEM_HANDLE result = list_find(handle, test_match_function, TEST_CONTEXT); + + // assert + ASSERT_IS_NULL(result); + } + +END_TEST_SUITE(list_unittests) diff --git a/c/sharedutil/tests/list_unittests/main.c b/c/sharedutil/tests/list_unittests/main.c new file mode 100644 index 00000000..4d6c3242 --- /dev/null +++ b/c/sharedutil/tests/list_unittests/main.c @@ -0,0 +1,8 @@ +#include "testrunnerswitcher.h" + +int main(void) +{ + size_t failedTestCount = 0; + RUN_TEST_SUITE(list_unittests, failedTestCount); + return failedTestCount; +} diff --git a/c/sharedutil/tests/lock_unittests/CMakeLists.txt b/c/sharedutil/tests/lock_unittests/CMakeLists.txt new file mode 100644 index 00000000..68fca45f --- /dev/null +++ b/c/sharedutil/tests/lock_unittests/CMakeLists.txt @@ -0,0 +1,21 @@ +#Copyright (c) Microsoft. All rights reserved. +#Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#this is CMakeLists.txt for lock_unittests +cmake_minimum_required(VERSION 3.0) + +compileAsC99() +set(theseTestsName lock_unittests) + +set(${theseTestsName}_cpp_files +${theseTestsName}.cpp +) + +set(${theseTestsName}_c_files + ${LOCK_C_FILE} +) + +set(${theseTestsName}_h_files +) + +build_test_artifacts(${theseTestsName} ON) diff --git a/c/sharedutil/tests/lock_unittests/lock_unittests.cpp b/c/sharedutil/tests/lock_unittests/lock_unittests.cpp new file mode 100644 index 00000000..c458e559 --- /dev/null +++ b/c/sharedutil/tests/lock_unittests/lock_unittests.cpp @@ -0,0 +1,110 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include +#ifdef _CRTDBG_MAP_ALLOC +#include +#endif + +#include "micromock.h" +#include "testrunnerswitcher.h" +#include "crt_abstractions.h" +#include "lock.h" + + +DEFINE_MICROMOCK_ENUM_TO_STRING(LOCK_RESULT, LOCK_RESULT_VALUES); + +LOCK_RESULT Lock_Handle_ToString(LOCK_HANDLE handle) +{ + LOCK_RESULT result = LOCK_OK; + + if (handle == NULL) + { + result = LOCK_ERROR; + } + + return result; +} + +static MICROMOCK_GLOBAL_SEMAPHORE_HANDLE g_dllByDll; + +BEGIN_TEST_SUITE(Lock_UnitTests) + +TEST_SUITE_INITIALIZE(a) +{ + INITIALIZE_MEMORY_DEBUG(g_dllByDll); +} +TEST_SUITE_CLEANUP(b) +{ + DEINITIALIZE_MEMORY_DEBUG(g_dllByDll); +} +TEST_FUNCTION(Test_Lock_Lock_Unlock) +{ + //arrange + LOCK_HANDLE handle=NULL; + LOCK_RESULT result; + //act + handle =Lock_Init(); + auto res = Lock_Handle_ToString(handle); + //assert + ASSERT_ARE_EQUAL(LOCK_RESULT, LOCK_OK, res); + + result=Lock(handle); + /*Tests_SRS_LOCK_99_005:[ This API on success should return LOCK_OK]*/ + ASSERT_ARE_EQUAL(LOCK_RESULT, LOCK_OK, result); + /*Tests_SRS_LOCK_99_009:[ This API on success should return LOCK_OK]*/ + result = Unlock(handle); + ASSERT_ARE_EQUAL(LOCK_RESULT, LOCK_OK, result); + //free + result = Lock_Deinit(handle); + ASSERT_ARE_EQUAL(LOCK_RESULT, LOCK_OK, result); +} + +TEST_FUNCTION(Test_Lock_Init_DeInit) +{ + //arrange + LOCK_HANDLE handle = NULL; + //act + handle = Lock_Init(); + //assert + /*Tests_SRS_LOCK_99_002:[ This API on success will return a valid lock handle which should be a non NULL value]*/ + auto res = Lock_Handle_ToString(handle); + //assert + ASSERT_ARE_EQUAL(LOCK_RESULT, LOCK_OK, res); + //free + LOCK_RESULT result = Lock_Deinit(handle); + ASSERT_ARE_EQUAL(LOCK_RESULT, LOCK_OK, result); +} + +/*Tests_SRS_LOCK_99_007:[ This API on NULL handle passed returns LOCK_ERROR]*/ +TEST_FUNCTION(Test_Lock_Lock_NULL) +{ + //arrange + //act + LOCK_RESULT result =Lock(NULL); + /*Tests_SRS_LOCK_99_007:[ This API on NULL handle passed returns LOCK_ERROR]*/ + ASSERT_ARE_EQUAL(LOCK_RESULT, LOCK_ERROR, result); +} + +/*Tests_SRS_LOCK_99_011:[ This API on NULL handle passed returns LOCK_ERROR]*/ +TEST_FUNCTION(Test_Lock_Unlock_NULL) +{ + //arrange + //act + LOCK_RESULT result = Unlock(NULL); + /*Tests_SRS_LOCK_99_011:[ This API on NULL handle passed returns LOCK_ERROR]*/ + ASSERT_ARE_EQUAL(LOCK_RESULT, LOCK_ERROR, result); +} + +TEST_FUNCTION(Test_Lock_Init_DeInit_NULL) +{ + //arrange + //act + LOCK_RESULT result = Lock_Deinit(NULL); + //assert + /*Tests_SRS_LOCK_99_013:[ This API on NULL handle passed returns LOCK_ERROR]*/ + ASSERT_ARE_EQUAL(LOCK_RESULT, LOCK_ERROR, result); +} + + +END_TEST_SUITE(Lock_UnitTests); diff --git a/c/sharedutil/tests/lock_unittests/main.c b/c/sharedutil/tests/lock_unittests/main.c new file mode 100644 index 00000000..1027a5e1 --- /dev/null +++ b/c/sharedutil/tests/lock_unittests/main.c @@ -0,0 +1,12 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include "testrunnerswitcher.h" + +int main(void) +{ + + size_t failedTestCount = 0; + RUN_TEST_SUITE(Lock_UnitTests, failedTestCount); + return failedTestCount; +} diff --git a/c/sharedutil/tests/map_unittests/CMakeLists.txt b/c/sharedutil/tests/map_unittests/CMakeLists.txt new file mode 100644 index 00000000..f91bc547 --- /dev/null +++ b/c/sharedutil/tests/map_unittests/CMakeLists.txt @@ -0,0 +1,22 @@ +#Copyright (c) Microsoft. All rights reserved. +#Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#this is CMakeLists.txt for map_unittests +cmake_minimum_required(VERSION 3.0) + +compileAsC99() +set(theseTestsName map_unittests) + +set(${theseTestsName}_cpp_files +${theseTestsName}.cpp +) + +set(${theseTestsName}_c_files +../../src/map.c +../../src/crt_abstractions.c +) + +set(${theseTestsName}_h_files +) + +build_test_artifacts(${theseTestsName} ON) \ No newline at end of file diff --git a/c/sharedutil/tests/map_unittests/main.c b/c/sharedutil/tests/map_unittests/main.c new file mode 100644 index 00000000..ed610c37 --- /dev/null +++ b/c/sharedutil/tests/map_unittests/main.c @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include "testrunnerswitcher.h" + +int main(void) +{ + size_t failedTestCount = 0; + RUN_TEST_SUITE(map_unittests, failedTestCount); + return failedTestCount; +} diff --git a/c/sharedutil/tests/map_unittests/map_unittests.cpp b/c/sharedutil/tests/map_unittests/map_unittests.cpp new file mode 100644 index 00000000..740ea8aa --- /dev/null +++ b/c/sharedutil/tests/map_unittests/map_unittests.cpp @@ -0,0 +1,2661 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include +#ifdef _CRTDBG_MAP_ALLOC +#include +#endif + +#include "testrunnerswitcher.h" +#include "micromock.h" +#include "micromockcharstararenullterminatedstrings.h" +#include "map.h" +#include "lock.h" + +static MICROMOCK_MUTEX_HANDLE g_testByTest; +static MICROMOCK_GLOBAL_SEMAPHORE_HANDLE g_dllByDll; + +#define GBALLOC_H + +extern "C" int gballoc_init(void); +extern "C" void gballoc_deinit(void); +extern "C" void* gballoc_malloc(size_t size); +extern "C" void* gballoc_calloc(size_t nmemb, size_t size); +extern "C" void* gballoc_realloc(void* ptr, size_t size); +extern "C" void gballoc_free(void* ptr); + +namespace BASEIMPLEMENTATION +{ + /*if malloc is defined as gballoc_malloc at this moment, there'd be serious trouble*/ +#define Lock(x) (LOCK_OK + gballocState - gballocState) /*compiler warning about constant in if condition*/ +#define Unlock(x) (LOCK_OK + gballocState - gballocState) +#define Lock_Init() (LOCK_HANDLE)0x42 +#define Lock_Deinit(x) (LOCK_OK + gballocState - gballocState) +#include "gballoc.c" +#undef Lock +#undef Unlock +#undef Lock_Init +#undef Lock_Deinit + +}; + +static size_t currentmalloc_call; +static size_t whenShallmalloc_fail; + +static size_t currentrealloc_call; +static size_t whenShallrealloc_fail; + +DEFINE_MICROMOCK_ENUM_TO_STRING(MAP_RESULT, MAP_RESULT_VALUES); + +static int DontAllowCapitalsFilters(const char* mapProperty, const char* mapValue) +{ + int result = 0; + const char* iterator = mapProperty; + while (iterator != NULL && *iterator != '\0') + { + if (*iterator >= 'A' && *iterator <= 'Z') + { + result = __LINE__; + break; + } + iterator++; + } + + if (result != 0) + { + iterator = mapValue; + while (iterator != NULL && *iterator != '\0') + { + if (*iterator >= 'A' && *iterator <= 'Z') + { + result = __LINE__; + break; + } + iterator++; + } + } + + return result; +} + +TYPED_MOCK_CLASS(CMapMocks, CGlobalMock) +{ +public: + + MOCK_STATIC_METHOD_1(, void*, gballoc_malloc, size_t, size) + void* result2; + currentmalloc_call++; + if (whenShallmalloc_fail>0) + { + if (currentmalloc_call == whenShallmalloc_fail) + { + result2 = NULL; + } + else + { + result2 = BASEIMPLEMENTATION::gballoc_malloc(size); + } + } + else + { + result2 = BASEIMPLEMENTATION::gballoc_malloc(size); + } + MOCK_METHOD_END(void*, result2); + + MOCK_STATIC_METHOD_2(, void*, gballoc_realloc, void*, ptr, size_t, size) + void* result2; + currentrealloc_call++; + if (whenShallrealloc_fail>0) + { + if (currentrealloc_call == whenShallrealloc_fail) + { + result2 = NULL; + } + else + { + result2 = BASEIMPLEMENTATION::gballoc_realloc(ptr, size); + } + } + else + { + result2 = BASEIMPLEMENTATION::gballoc_realloc(ptr, size); + } + MOCK_METHOD_END(void*, result2); + + MOCK_STATIC_METHOD_1(, void, gballoc_free, void*, ptr) + BASEIMPLEMENTATION::gballoc_free(ptr); + MOCK_VOID_METHOD_END() +}; + +DECLARE_GLOBAL_MOCK_METHOD_1(CMapMocks, , void*, gballoc_malloc, size_t, size); + +DECLARE_GLOBAL_MOCK_METHOD_2(CMapMocks, , void*, gballoc_realloc, void*, ptr, size_t, size); +DECLARE_GLOBAL_MOCK_METHOD_1(CMapMocks, , void, gballoc_free, void*, ptr); + +/* capacity */ + +static const char* TEST_REDKEY = "testRedKey"; +static const char* TEST_REDVALUE = "testRedValue"; + +static const char* TEST_YELLOWKEY = "testYellowKey"; +static const char* TEST_YELLOWVALUE = "testYellowValue"; + +static const char* TEST_BLUEKEY = "testBlueKey"; +static const char* TEST_BLUEVALUE = "cyan"; + +static const char* TEST_GREENKEY = "testgreenkey"; +static const char* TEST_GREENVALUE = "green"; + +BEGIN_TEST_SUITE(map_unittests) + + TEST_SUITE_INITIALIZE(TestClassInitialize) + { + INITIALIZE_MEMORY_DEBUG(g_dllByDll); + g_testByTest = MicroMockCreateMutex(); + ASSERT_IS_NOT_NULL(g_testByTest); + } + + TEST_SUITE_CLEANUP(TestClassCleanup) + { + MicroMockDestroyMutex(g_testByTest); + DEINITIALIZE_MEMORY_DEBUG(g_dllByDll); + } + + TEST_FUNCTION_INITIALIZE(TestMethodInitialize) + { + if (!MicroMockAcquireMutex(g_testByTest)) + { + ASSERT_FAIL("our mutex is ABANDONED. Failure in test framework"); + } + currentmalloc_call = 0; + whenShallmalloc_fail = 0; + + currentrealloc_call = 0; + whenShallrealloc_fail = 0; + + } + + TEST_FUNCTION_CLEANUP(TestMethodCleanup) + { + if (!MicroMockReleaseMutex(g_testByTest)) + { + ASSERT_FAIL("failure in test framework at ReleaseMutex"); + } + } + + /*Tests_SRS_MAP_02_001: [Map_Create shall create a new, empty map.]*/ /*this tests "create"*/ + /*Tests_SRS_MAP_02_003: [Otherwise, it shall return a non-NULL handle that can be used in subsequent calls.] */ + /*Tests_SRS_MAP_02_004: [Map_Destroy shall release all resources associated with the map.] */ + TEST_FUNCTION(Map_Create_Destroy_succeeds) + { + ///arrange + CMapMocks mocks; + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(IGNORED_NUM_ARG)) + .IgnoreArgument(1); + + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) /*keys*/ + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) /*values*/ + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) /*handleData*/ + .IgnoreArgument(1); + + ///act + auto handle = Map_Create(NULL); + Map_Destroy(handle); + + ///assert + + ///cleanup + } + + /*Tests_SRS_MAP_02_004: [Map_Destroy shall release all resources associated with the map.] */ + TEST_FUNCTION(Map_Destroy_on_non_empty_map_succeeds_1) + { + ///arrange + CMapMocks mocks; + auto handle = Map_Create(NULL); + Map_AddOrUpdate(handle, TEST_REDKEY, TEST_REDVALUE); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) /*free the red key*/ + .ValidateArgumentBuffer(1, TEST_REDKEY, strlen(TEST_REDKEY)+1); + + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG))/*free the red value*/ + .ValidateArgumentBuffer(1, TEST_REDVALUE, strlen(TEST_REDVALUE)+1); + + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) /*free keys array*/ + .IgnoreArgument(1); + + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) /*free values array*/ + .IgnoreArgument(1); + + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) /*free handle*/ + .IgnoreArgument(1); + + ///act + Map_Destroy(handle); + + ///assert + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + } + + /*Tests_SRS_MAP_02_004: [Map_Destroy shall release all resources associated with the map.] */ + TEST_FUNCTION(Map_Destroy_on_non_empty_map_succeeds_2) + { + ///arrange + CMapMocks mocks; + auto handle = Map_Create(NULL); + Map_AddOrUpdate(handle, TEST_REDKEY, TEST_REDVALUE); + Map_AddOrUpdate(handle, TEST_REDKEY, "a"); /*overwrites to something smaller*/ + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) /*free the red key*/ + .ValidateArgumentBuffer(1, TEST_REDKEY, strlen(TEST_REDKEY)+1); + + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG))/*free the red value*/ + .ValidateArgumentBuffer(1, "a", 2); + + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) /*free keys array*/ + .IgnoreArgument(1); + + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) /*free values array*/ + .IgnoreArgument(1); + + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) /*free handle*/ + .IgnoreArgument(1); + + ///act + Map_Destroy(handle); + + ///assert + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + } + + /*Tests_SRS_MAP_02_001: [Map_Create shall create a new, empty map.]*/ /*this tests "empty"*/ + TEST_FUNCTION(Map_Create_Destroy_succeeds_2) + { + ///arrange + CMapMocks mocks; + auto handle = Map_Create(NULL); + mocks.ResetAllCalls(); + const char*const* keys; + const char*const* values; + size_t count; + + ///act + auto result = Map_GetInternals(handle, &keys, &values, &count); + + ///assert + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_OK, result); + ASSERT_ARE_EQUAL(size_t, 0, count); + ASSERT_ARE_EQUAL(void_ptr, NULL, keys); + ASSERT_ARE_EQUAL(void_ptr, NULL, values); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + } + + /*Tests_SRS_MAP_02_002: [If during creation there are any error, then Map_Create shall return NULL.]*/ + TEST_FUNCTION(Map_Create_fails_when_malloc_fails) + { + ///arrange + CMapMocks mocks; + whenShallmalloc_fail = 1; + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(IGNORED_NUM_ARG)) + .IgnoreArgument(1); + + ///act + auto handle = Map_Create(NULL); + + ///assert + ASSERT_IS_NULL(handle); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + } + + /*Tests_SRS_MAP_02_005: [If parameter handle is NULL then Map_Destroy shall take no action.]*/ + TEST_FUNCTION(Map_Destroy_with_NULL_argument_does_nothing) + { + ///arrange + CMapMocks mocks; + + ///act + Map_Destroy(NULL); + + ///assert + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + } + + /*Tests_SRS_MAP_02_006: [If parameter handle is NULL then Map_Add shall return MAP_INVALID_ARG.]*/ + TEST_FUNCTION(Map_Add_with_NULL_parameter_handle_fails) + { + ///arrange + CMapMocks mocks; + auto handle = Map_Create(NULL); + mocks.ResetAllCalls(); + + ///act + auto result= Map_Add(NULL, TEST_REDKEY, TEST_REDVALUE); + + ///assert + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_INVALIDARG, result); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + } + + /*Tests_SRS_MAP_02_007: [If parameter key is NULL then Map_Add shall return MAP_INVALID_ARG.]*/ + TEST_FUNCTION(Map_Add_with_NULL_parameter_key_fails) + { + ///arrange + CMapMocks mocks; + auto handle = Map_Create(NULL); + mocks.ResetAllCalls(); + + ///act + auto result = Map_Add(handle, NULL, TEST_REDVALUE); + + ///assert + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_INVALIDARG, result); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + } + + /*Tests_SRS_MAP_02_008: [If parameter value is NULL then Map_Add shall return MAP_INVALID_ARG.]*/ + TEST_FUNCTION(Map_Add_with_NULL_parameter_value_fails) + { + ///arrange + CMapMocks mocks; + auto handle = Map_Create(NULL); + mocks.ResetAllCalls(); + + ///act + auto result = Map_Add(handle, TEST_REDKEY, NULL); + + ///assert + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_INVALIDARG, result); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + } + + /*Tests_SRS_MAP_02_010: [Otherwise, Map_Add shall add the pair to the map.] */ + /*Tests_SRS_MAP_02_012: [Otherwise, Map_Add shall return MAP_OK.] */ + TEST_FUNCTION(Map_Add_succeeds_1) + { + ///arrange + CMapMocks mocks; + const char*const* keys; + const char*const* values; + size_t count; + auto handle = Map_Create(NULL); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(NULL, sizeof(const char*))); /*growing keys*/ + + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(NULL, sizeof(const char*))); /*growing values*/ + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_REDKEY) + 1)); /*copy of red key*/ + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_REDVALUE) + 1)); /*copy of red value*/ + + ///act + auto result1 = Map_Add(handle, TEST_REDKEY, TEST_REDVALUE); + auto result2 = Map_GetInternals(handle, &keys, &values, &count); + + ///assert + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_OK, result1); + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_OK, result2); + ASSERT_ARE_EQUAL(size_t, 1, count); + ASSERT_ARE_EQUAL(char_ptr, TEST_REDKEY, keys[0]); + ASSERT_ARE_EQUAL(char_ptr, TEST_REDVALUE, values[0]); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + } + + /*Tests_SRS_MAP_02_010: [Otherwise, Map_Add shall add the pair to the map.] */ + /*Tests_SRS_MAP_02_012: [Otherwise, Map_Add shall return MAP_OK.] */ + /*Tests_SRS_MAP_02_043: [Map_GetInternals shall produce in *keys an pointer to an array of const char* having all the keys stored so far by the map.]*/ + /*Tests_SRS_MAP_02_044: [Map_GetInternals shall produce in *values a pointer to an array of const char* having all the values stored so far by the map.]*/ + /*Tests_SRS_MAP_02_045: [Map_GetInternals shall produce in *count the number of stored keys and values.]*/ + TEST_FUNCTION(Map_Add_succeeds_2) + { + ///arrange + CMapMocks mocks; + const char*const* keys; + const char*const* values; + size_t count; + auto handle = Map_Create(NULL); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(NULL, sizeof(const char*))); /*growing keys*/ + + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(NULL, sizeof(const char*))); /*growing values*/ + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_REDKEY) + 1)); /*copy of red key*/ + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_REDVALUE) + 1)); /*copy of red value*/ + + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(IGNORED_PTR_ARG, 2*sizeof(const char*))) /*growing keys*/ + .IgnoreArgument(1); + + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(IGNORED_PTR_ARG, 2*sizeof(const char*))) /*growing values*/ + .IgnoreArgument(1); + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_BLUEKEY) + 1)); /*copy of blue key*/ + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_BLUEVALUE) + 1)); /*copy of blue value*/ + + ///act + auto result1 = Map_Add(handle, TEST_REDKEY, TEST_REDVALUE); + auto result2 = Map_Add(handle, TEST_BLUEKEY, TEST_BLUEVALUE); + auto result3 = Map_GetInternals(handle, &keys, &values, &count); + + ///assert + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_OK, result1); + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_OK, result2); + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_OK, result3); + ASSERT_ARE_EQUAL(size_t, 2, count); + ASSERT_ARE_EQUAL(char_ptr, TEST_REDKEY, keys[0]); + ASSERT_ARE_EQUAL(char_ptr, TEST_REDVALUE, values[0]); + ASSERT_ARE_EQUAL(char_ptr, TEST_BLUEKEY, keys[1]); + ASSERT_ARE_EQUAL(char_ptr, TEST_BLUEVALUE, values[1]); + + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + } + + /*Tests_SRS_MAP_02_011: [If adding the pair fails then Map_Add shall return MAP_ERROR.] */ + TEST_FUNCTION(Map_Add_fails_when_gballoc_fails_1) + { + ///arrange + CMapMocks mocks; + const char*const* keys; + const char*const* values; + size_t count; + auto handle = Map_Create(NULL); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(NULL, sizeof(const char*))); /*growing keys*/ + + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(NULL, sizeof(const char*))); /*growing values*/ + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_REDKEY) + 1)); /*copy of red key*/ + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_REDVALUE) + 1)); /*copy of red value*/ + + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(IGNORED_PTR_ARG, 2 * sizeof(const char*))) /*growing keys*/ + .IgnoreArgument(1); + + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(IGNORED_PTR_ARG, 2 * sizeof(const char*))) /*growing values*/ + .IgnoreArgument(1); + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_BLUEKEY) + 1)); /*copy of blue key*/ + + whenShallmalloc_fail =currentmalloc_call+ 4; + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_BLUEVALUE) + 1)); /*copy of blue value*/ + + /*below are undo actions*/ + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) /*undo copy of blue key*/ + .ValidateArgumentBuffer(1, TEST_BLUEKEY, strlen(TEST_BLUEKEY) + 1); + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(IGNORED_PTR_ARG, 1 * sizeof(const char*))) /*undo growing keys*/ + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(IGNORED_PTR_ARG, 1 * sizeof(const char*))) /*undo growing values*/ + .IgnoreArgument(1); + + + ///act + auto result1 = Map_Add(handle, TEST_REDKEY, TEST_REDVALUE); + auto result2 = Map_Add(handle, TEST_BLUEKEY, TEST_BLUEVALUE); + auto result3 = Map_GetInternals(handle, &keys, &values, &count); + + ///assert + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_OK, result1); + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_ERROR, result2); + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_OK, result3); + ASSERT_ARE_EQUAL(size_t, 1, count); + ASSERT_ARE_EQUAL(char_ptr, TEST_REDKEY, keys[0]); + ASSERT_ARE_EQUAL(char_ptr, TEST_REDVALUE, values[0]); + + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + } + + /*Tests_SRS_MAP_02_011: [If adding the pair fails then Map_Add shall return MAP_ERROR.] */ + TEST_FUNCTION(Map_Add_fails_when_gballoc_fails_2) + { + ///arrange + CMapMocks mocks; + const char*const* keys; + const char*const* values; + size_t count; + auto handle = Map_Create(NULL); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(NULL, sizeof(const char*))); /*growing keys*/ + + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(NULL, sizeof(const char*))); /*growing values*/ + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_REDKEY) + 1)); /*copy of red key*/ + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_REDVALUE) + 1)); /*copy of red value*/ + + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(IGNORED_PTR_ARG, 2 * sizeof(const char*))) /*growing keys*/ + .IgnoreArgument(1); + + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(IGNORED_PTR_ARG, 2 * sizeof(const char*))) /*growing values*/ + .IgnoreArgument(1); + + whenShallmalloc_fail = currentmalloc_call + 3; + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_BLUEKEY) + 1)); /*copy of blue key*/ + + /*below are undo actions*/ + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(IGNORED_PTR_ARG, 1 * sizeof(const char*))) /*undo growing keys*/ + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(IGNORED_PTR_ARG, 1 * sizeof(const char*))) /*undo growing values*/ + .IgnoreArgument(1); + + + ///act + auto result1 = Map_Add(handle, TEST_REDKEY, TEST_REDVALUE); + auto result2 = Map_Add(handle, TEST_BLUEKEY, TEST_BLUEVALUE); + auto result3 = Map_GetInternals(handle, &keys, &values, &count); + + ///assert + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_OK, result1); + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_ERROR, result2); + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_OK, result3); + ASSERT_ARE_EQUAL(size_t, 1, count); + ASSERT_ARE_EQUAL(char_ptr, TEST_REDKEY, keys[0]); + ASSERT_ARE_EQUAL(char_ptr, TEST_REDVALUE, values[0]); + + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + } + + /*Tests_SRS_MAP_02_011: [If adding the pair fails then Map_Add shall return MAP_ERROR.] */ + TEST_FUNCTION(Map_Add_fails_when_gballoc_fails_3) + { + ///arrange + CMapMocks mocks; + const char*const* keys; + const char*const* values; + size_t count; + auto handle = Map_Create(NULL); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(NULL, sizeof(const char*))); /*growing keys*/ + + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(NULL, sizeof(const char*))); /*growing values*/ + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_REDKEY) + 1)); /*copy of red key*/ + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_REDVALUE) + 1)); /*copy of red value*/ + + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(IGNORED_PTR_ARG, 2 * sizeof(const char*))) /*growing keys*/ + .IgnoreArgument(1); + + whenShallrealloc_fail = currentrealloc_call + 4; + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(IGNORED_PTR_ARG, 2 * sizeof(const char*))) /*growing values*/ + .IgnoreArgument(1); + + /*below are undo actions*/ + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(IGNORED_PTR_ARG, 1 * sizeof(const char*))) /*undo growing keys*/ + .IgnoreArgument(1); + + ///act + auto result1 = Map_Add(handle, TEST_REDKEY, TEST_REDVALUE); + auto result2 = Map_Add(handle, TEST_BLUEKEY, TEST_BLUEVALUE); + auto result3 = Map_GetInternals(handle, &keys, &values, &count); + + ///assert + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_OK, result1); + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_ERROR, result2); + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_OK, result3); + ASSERT_ARE_EQUAL(size_t, 1, count); + ASSERT_ARE_EQUAL(char_ptr, TEST_REDKEY, keys[0]); + ASSERT_ARE_EQUAL(char_ptr, TEST_REDVALUE, values[0]); + + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + } + + /*Tests_SRS_MAP_02_011: [If adding the pair fails then Map_Add shall return MAP_ERROR.] */ + TEST_FUNCTION(Map_Add_fails_when_gballoc_fails_4) + { + ///arrange + CMapMocks mocks; + const char*const* keys; + const char*const* values; + size_t count; + auto handle = Map_Create(NULL); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(NULL, sizeof(const char*))); /*growing keys*/ + + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(NULL, sizeof(const char*))); /*growing values*/ + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_REDKEY) + 1)); /*copy of red key*/ + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_REDVALUE) + 1)); /*copy of red value*/ + + whenShallrealloc_fail = currentrealloc_call + 3; + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(IGNORED_PTR_ARG, 2 * sizeof(const char*))) /*growing keys*/ + .IgnoreArgument(1); + + /*below are undo actions*/ + + ///act + auto result1 = Map_Add(handle, TEST_REDKEY, TEST_REDVALUE); + auto result2 = Map_Add(handle, TEST_BLUEKEY, TEST_BLUEVALUE); + auto result3 = Map_GetInternals(handle, &keys, &values, &count); + + ///assert + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_OK, result1); + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_ERROR, result2); + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_OK, result3); + ASSERT_ARE_EQUAL(size_t, 1, count); + ASSERT_ARE_EQUAL(char_ptr, TEST_REDKEY, keys[0]); + ASSERT_ARE_EQUAL(char_ptr, TEST_REDVALUE, values[0]); + + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + } + + /*Tests_SRS_MAP_02_011: [If adding the pair fails then Map_Add shall return MAP_ERROR.] */ + TEST_FUNCTION(Map_Add_fails_when_gballoc_fails_5) + { + ///arrange + CMapMocks mocks; + const char*const* keys; + const char*const* values; + size_t count; + auto handle = Map_Create(NULL); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(NULL, sizeof(const char*))); /*growing keys*/ + + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(NULL, sizeof(const char*))); /*growing values*/ + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_REDKEY) + 1)); /*copy of red key*/ + + whenShallmalloc_fail = currentmalloc_call + 2; + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_REDVALUE) + 1)); /*copy of red value*/ + + /*below are undo actions*/ + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) /*undo copy of red key*/ + .ValidateArgumentBuffer(1, TEST_REDKEY, strlen(TEST_REDKEY) + 1); + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) /*undo growing keys*/ + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG))/*undo growing values*/ + .IgnoreArgument(1); + + ///act + auto result1 = Map_Add(handle, TEST_REDKEY, TEST_REDVALUE); + auto result3 = Map_GetInternals(handle, &keys, &values, &count); + + ///assert + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_ERROR, result1); + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_OK, result3); + ASSERT_ARE_EQUAL(size_t, 0, count); + + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + } + + /*Tests_SRS_MAP_02_011: [If adding the pair fails then Map_Add shall return MAP_ERROR.] */ + TEST_FUNCTION(Map_Add_fails_when_gballoc_fails_6) + { + ///arrange + CMapMocks mocks; + const char*const* keys; + const char*const* values; + size_t count; + auto handle = Map_Create(NULL); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(NULL, sizeof(const char*))); /*growing keys*/ + + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(NULL, sizeof(const char*))); /*growing values*/ + + whenShallmalloc_fail = currentmalloc_call + 1; + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_REDKEY) + 1)); /*copy of red key*/ + + /*below are undo actions*/ + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) /*undo growing keys*/ + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG))/*undo growing values*/ + .IgnoreArgument(1); + + ///act + auto result1 = Map_Add(handle, TEST_REDKEY, TEST_REDVALUE); + auto result3 = Map_GetInternals(handle, &keys, &values, &count); + + ///assert + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_ERROR, result1); + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_OK, result3); + ASSERT_ARE_EQUAL(size_t, 0, count); + + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + } + + /*Tests_SRS_MAP_02_011: [If adding the pair fails then Map_Add shall return MAP_ERROR.] */ + TEST_FUNCTION(Map_Add_fails_when_gballoc_fails_7) + { + ///arrange + CMapMocks mocks; + const char*const* keys; + const char*const* values; + size_t count; + auto handle = Map_Create(NULL); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(NULL, sizeof(const char*))); /*growing keys*/ + + whenShallrealloc_fail = currentrealloc_call + 2; + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(NULL, sizeof(const char*))); /*growing values*/ + + /*below are undo actions*/ + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) /*undo growing keys*/ + .IgnoreArgument(1); + + ///act + auto result1 = Map_Add(handle, TEST_REDKEY, TEST_REDVALUE); + auto result3 = Map_GetInternals(handle, &keys, &values, &count); + + ///assert + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_ERROR, result1); + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_OK, result3); + ASSERT_ARE_EQUAL(size_t, 0, count); + + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + } + + /*Tests_SRS_MAP_02_011: [If adding the pair fails then Map_Add shall return MAP_ERROR.] */ + TEST_FUNCTION(Map_Add_fails_when_gballoc_fails_8) + { + ///arrange + CMapMocks mocks; + const char*const* keys; + const char*const* values; + size_t count; + auto handle = Map_Create(NULL); + mocks.ResetAllCalls(); + + whenShallrealloc_fail = currentrealloc_call + 1; + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(NULL, sizeof(const char*))); /*growing keys*/ + + /*below are undo actions*/ /*none*/ + + ///act + auto result1 = Map_Add(handle, TEST_REDKEY, TEST_REDVALUE); + auto result3 = Map_GetInternals(handle, &keys, &values, &count); + + ///assert + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_ERROR, result1); + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_OK, result3); + ASSERT_ARE_EQUAL(size_t, 0, count); + + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + } + + /*Tests_SRS_MAP_02_009: [If the key already exists, then Map_Add shall return MAP_KEYEXISTS.]*/ + TEST_FUNCTION(Map_Add_with_existing_key_fails_1) + { + ///arrange + CMapMocks mocks; + const char*const* keys; + const char*const* values; + size_t count; + auto handle = Map_Create(NULL); + (void)Map_Add(handle, TEST_REDKEY, TEST_REDVALUE); + mocks.ResetAllCalls(); + + /*below are undo actions*/ /*none*/ + + ///act + auto result1 = Map_Add(handle, TEST_REDKEY, TEST_REDVALUE); + auto result3 = Map_GetInternals(handle, &keys, &values, &count); + + ///assert + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_KEYEXISTS, result1); + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_OK, result3); + ASSERT_ARE_EQUAL(size_t, 1, count); + ASSERT_ARE_EQUAL(char_ptr, TEST_REDKEY, keys[0]); + ASSERT_ARE_EQUAL(char_ptr, TEST_REDVALUE, values[0]); + + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + } + + /*Tests_SRS_MAP_02_009: [If the key already exists, then Map_Add shall return MAP_KEYEXISTS.]*/ + TEST_FUNCTION(Map_Add_with_existing_key_fails_2) + { + ///arrange + CMapMocks mocks; + const char*const* keys; + const char*const* values; + size_t count; + auto handle = Map_Create(NULL); + (void)Map_Add(handle, TEST_REDKEY, TEST_REDVALUE); + (void)Map_Add(handle, TEST_BLUEKEY, TEST_BLUEVALUE); + mocks.ResetAllCalls(); + + /*below are undo actions*/ /*none*/ + + ///act + auto result1 = Map_Add(handle, TEST_BLUEKEY, TEST_YELLOWVALUE); + auto result3 = Map_GetInternals(handle, &keys, &values, &count); + + ///assert + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_KEYEXISTS, result1); + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_OK, result3); + ASSERT_ARE_EQUAL(size_t, 2, count); + ASSERT_ARE_EQUAL(char_ptr, TEST_REDKEY, keys[0]); + ASSERT_ARE_EQUAL(char_ptr, TEST_REDVALUE, values[0]); + ASSERT_ARE_EQUAL(char_ptr, TEST_BLUEKEY, keys[1]); + ASSERT_ARE_EQUAL(char_ptr, TEST_BLUEVALUE, values[1]); + + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + } + + /*Tests_SRS_MAP_02_013: [If parameter handle is NULL then Map_AddOrUpdate shall return MAP_INVALID_ARG.]*/ + TEST_FUNCTION(Map_AddOrUpdate_with_NULL_parameter_handle_fails) + { + ///arrange + CMapMocks mocks; + mocks.ResetAllCalls(); + + ///act + auto result1 = Map_AddOrUpdate(NULL, TEST_BLUEKEY, TEST_YELLOWVALUE); + + ///assert + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_INVALIDARG, result1); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + } + + /*Tests_SRS_MAP_02_014: [If parameter key is NULL then Map_AddOrUpdate shall return MAP_INVALID_ARG.] */ + TEST_FUNCTION(Map_AddOrUpdate_with_NULL_key_handle_fails) + { + ///arrange + CMapMocks mocks; + auto handle = Map_Create(NULL); + mocks.ResetAllCalls(); + + ///act + auto result1 = Map_AddOrUpdate(handle, NULL, TEST_YELLOWVALUE); + + ///assert + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_INVALIDARG, result1); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + } + + /*Tests_SRS_MAP_02_015: [If parameter value is NULL then Map_AddOrUpdate shall return MAP_INVALID_ARG.]*/ + TEST_FUNCTION(Map_AddOrUpdate_with_NULL_value_handle_fails) + { + ///arrange + CMapMocks mocks; + auto handle = Map_Create(NULL); + mocks.ResetAllCalls(); + + ///act + auto result1 = Map_AddOrUpdate(handle, TEST_REDKEY, NULL); + + ///assert + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_INVALIDARG, result1); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + } + + /*Tests_SRS_MAP_02_017: [Otherwise, Map_AddOrUpdate shall add the pair to the map.]*/ + /*Tests_SRS_MAP_02_019: [Otherwise, Map_AddOrUpdate shall return MAP_OK.] */ + TEST_FUNCTION(Map_AddOrUpdate_with_1_pair_succeeded) + { + ///arrange + CMapMocks mocks; + const char*const* keys; + const char*const* values; + size_t count; + auto handle = Map_Create(NULL); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(NULL, sizeof(const char*))); /*growing keys*/ + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(NULL, sizeof(const char*))); /*growing values*/ + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_REDKEY)+1)); /*copy of red key*/ + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_REDVALUE) + 1)); /*copy of red value*/ + + ///act + auto result1 = Map_AddOrUpdate(handle, TEST_REDKEY, TEST_REDVALUE); + auto result2 = Map_GetInternals(handle, &keys, &values, &count); + + ///assert + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_OK, result1); + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_OK, result2); + ASSERT_ARE_EQUAL(size_t, 1, count); + ASSERT_ARE_EQUAL(char_ptr, TEST_REDKEY, keys[0]); + ASSERT_ARE_EQUAL(char_ptr, TEST_REDVALUE, values[0]); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + } + + /*Tests_SRS_MAP_02_017: [Otherwise, Map_AddOrUpdate shall add the pair to the map.]*/ + TEST_FUNCTION(Map_AddOrUpdate_with_2_pair_succeeded) + { + ///arrange + CMapMocks mocks; + const char*const* keys; + const char*const* values; + size_t count; + auto handle = Map_Create(NULL); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(NULL, sizeof(const char*))); /*growing keys*/ + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(NULL, sizeof(const char*))); /*growing values*/ + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_REDKEY) + 1)); /*copy of red key*/ + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_REDVALUE) + 1)); /*copy of red value*/ + + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(IGNORED_PTR_ARG, 2 * sizeof(const char*))) /*growing keys*/ + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(IGNORED_PTR_ARG, 2 * sizeof(const char*))) /*growing values*/ + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_BLUEKEY) + 1)); /*copy of red key*/ + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_BLUEVALUE) + 1)); /*copy of red value*/ + + ///act + auto result1 = Map_AddOrUpdate(handle, TEST_REDKEY, TEST_REDVALUE); + auto result2 = Map_AddOrUpdate(handle, TEST_BLUEKEY, TEST_BLUEVALUE); + auto result3 = Map_GetInternals(handle, &keys, &values, &count); + + ///assert + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_OK, result1); + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_OK, result2); + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_OK, result3); + ASSERT_ARE_EQUAL(size_t, 2, count); + ASSERT_ARE_EQUAL(char_ptr, TEST_REDKEY, keys[0]); + ASSERT_ARE_EQUAL(char_ptr, TEST_REDVALUE, values[0]); + ASSERT_ARE_EQUAL(char_ptr, TEST_BLUEKEY, keys[1]); + ASSERT_ARE_EQUAL(char_ptr, TEST_BLUEVALUE, values[1]); + + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + } + + /*Tests_SRS_MAP_02_018: [If there are any failures then Map_AddOrUpdate shall return MAP_ERROR.] */ + TEST_FUNCTION(Map_AddOrUpdate_with_2_differnt_pair_fails_when_gballoc_fails_1) + { + ///arrange + CMapMocks mocks; + const char*const* keys; + const char*const* values; + size_t count; + auto handle = Map_Create(NULL); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(NULL, sizeof(const char*))); /*growing keys*/ + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(NULL, sizeof(const char*))); /*growing values*/ + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_REDKEY) + 1)); /*copy of red key*/ + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_REDVALUE) + 1)); /*copy of red value*/ + + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(IGNORED_PTR_ARG, 2 * sizeof(const char*))) /*growing keys*/ + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(IGNORED_PTR_ARG, 2 * sizeof(const char*))) /*growing values*/ + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_BLUEKEY) + 1)); /*copy of red key*/ + + whenShallmalloc_fail = currentmalloc_call + 4; + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_BLUEVALUE) + 1)); /*copy of red value*/ + + /*below are undo actions*/ + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) /*undo blue key value*/ + .ValidateArgumentBuffer(1, TEST_BLUEKEY, strlen(TEST_BLUEKEY) + 1); + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(IGNORED_PTR_ARG, 1 * sizeof(const char*))) /*undo growing keys*/ + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(IGNORED_PTR_ARG, 1 * sizeof(const char*))) /*undo growing values*/ + .IgnoreArgument(1); + + ///act + auto result1 = Map_AddOrUpdate(handle, TEST_REDKEY, TEST_REDVALUE); + auto result2 = Map_AddOrUpdate(handle, TEST_BLUEKEY, TEST_BLUEVALUE); + auto result3 = Map_GetInternals(handle, &keys, &values, &count); + + ///assert + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_OK, result1); + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_ERROR, result2); + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_OK, result3); + ASSERT_ARE_EQUAL(size_t, 1, count); + ASSERT_ARE_EQUAL(char_ptr, TEST_REDKEY, keys[0]); + ASSERT_ARE_EQUAL(char_ptr, TEST_REDVALUE, values[0]); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + } + + /*Tests_SRS_MAP_02_018: [If there are any failures then Map_AddOrUpdate shall return MAP_ERROR.] */ + TEST_FUNCTION(Map_AddOrUpdate_with_2_differnt_pair_fails_when_gballoc_fails_2) + { + ///arrange + CMapMocks mocks; + const char*const* keys; + const char*const* values; + size_t count; + auto handle = Map_Create(NULL); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(NULL, sizeof(const char*))); /*growing keys*/ + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(NULL, sizeof(const char*))); /*growing values*/ + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_REDKEY) + 1)); /*copy of red key*/ + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_REDVALUE) + 1)); /*copy of red value*/ + + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(IGNORED_PTR_ARG, 2 * sizeof(const char*))) /*growing keys*/ + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(IGNORED_PTR_ARG, 2 * sizeof(const char*))) /*growing values*/ + .IgnoreArgument(1); + whenShallmalloc_fail = currentmalloc_call + 3; + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_BLUEKEY) + 1)); /*copy of red key*/ + + /*below are undo actions*/ + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(IGNORED_PTR_ARG, 1 * sizeof(const char*))) /*undo growing keys*/ + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(IGNORED_PTR_ARG, 1 * sizeof(const char*))) /*undo growing values*/ + .IgnoreArgument(1); + + ///act + auto result1 = Map_AddOrUpdate(handle, TEST_REDKEY, TEST_REDVALUE); + auto result2 = Map_AddOrUpdate(handle, TEST_BLUEKEY, TEST_BLUEVALUE); + auto result3 = Map_GetInternals(handle, &keys, &values, &count); + + ///assert + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_OK, result1); + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_ERROR, result2); + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_OK, result3); + ASSERT_ARE_EQUAL(size_t, 1, count); + ASSERT_ARE_EQUAL(char_ptr, TEST_REDKEY, keys[0]); + ASSERT_ARE_EQUAL(char_ptr, TEST_REDVALUE, values[0]); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + } + + /*Tests_SRS_MAP_02_018: [If there are any failures then Map_AddOrUpdate shall return MAP_ERROR.] */ + TEST_FUNCTION(Map_AddOrUpdate_with_2_differnt_pair_fails_when_gballoc_fails_3) + { + ///arrange + CMapMocks mocks; + const char*const* keys; + const char*const* values; + size_t count; + auto handle = Map_Create(NULL); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(NULL, sizeof(const char*))); /*growing keys*/ + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(NULL, sizeof(const char*))); /*growing values*/ + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_REDKEY) + 1)); /*copy of red key*/ + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_REDVALUE) + 1)); /*copy of red value*/ + + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(IGNORED_PTR_ARG, 2 * sizeof(const char*))) /*growing keys*/ + .IgnoreArgument(1); + whenShallrealloc_fail = currentrealloc_call + 4; + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(IGNORED_PTR_ARG, 2 * sizeof(const char*))) /*growing values*/ + .IgnoreArgument(1); + + /*below are undo actions*/ + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(IGNORED_PTR_ARG, 1 * sizeof(const char*))) /*undo growing keys*/ + .IgnoreArgument(1); + + ///act + auto result1 = Map_AddOrUpdate(handle, TEST_REDKEY, TEST_REDVALUE); + auto result2 = Map_AddOrUpdate(handle, TEST_BLUEKEY, TEST_BLUEVALUE); + auto result3 = Map_GetInternals(handle, &keys, &values, &count); + + ///assert + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_OK, result1); + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_ERROR, result2); + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_OK, result3); + ASSERT_ARE_EQUAL(size_t, 1, count); + ASSERT_ARE_EQUAL(char_ptr, TEST_REDKEY, keys[0]); + ASSERT_ARE_EQUAL(char_ptr, TEST_REDVALUE, values[0]); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + } + + /*Tests_SRS_MAP_02_018: [If there are any failures then Map_AddOrUpdate shall return MAP_ERROR.] */ + TEST_FUNCTION(Map_AddOrUpdate_with_2_differnt_pair_fails_when_gballoc_fails_4) + { + ///arrange + CMapMocks mocks; + const char*const* keys; + const char*const* values; + size_t count; + auto handle = Map_Create(NULL); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(NULL, sizeof(const char*))); /*growing keys*/ + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(NULL, sizeof(const char*))); /*growing values*/ + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_REDKEY) + 1)); /*copy of red key*/ + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_REDVALUE) + 1)); /*copy of red value*/ + + whenShallrealloc_fail = currentrealloc_call + 3; + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(IGNORED_PTR_ARG, 2 * sizeof(const char*))) /*growing keys*/ + .IgnoreArgument(1); + + /*below are undo actions*/ /*none*/ + + ///act + auto result1 = Map_AddOrUpdate(handle, TEST_REDKEY, TEST_REDVALUE); + auto result2 = Map_AddOrUpdate(handle, TEST_BLUEKEY, TEST_BLUEVALUE); + auto result3 = Map_GetInternals(handle, &keys, &values, &count); + + ///assert + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_OK, result1); + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_ERROR, result2); + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_OK, result3); + ASSERT_ARE_EQUAL(size_t, 1, count); + ASSERT_ARE_EQUAL(char_ptr, TEST_REDKEY, keys[0]); + ASSERT_ARE_EQUAL(char_ptr, TEST_REDVALUE, values[0]); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + } + + /*Tests_SRS_MAP_02_018: [If there are any failures then Map_AddOrUpdate shall return MAP_ERROR.] */ + TEST_FUNCTION(Map_AddOrUpdate_with_2_differnt_pair_fails_when_gballoc_fails_5) + { + ///arrange + CMapMocks mocks; + const char*const* keys; + const char*const* values; + size_t count; + auto handle = Map_Create(NULL); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(NULL, sizeof(const char*))); /*growing keys*/ + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(NULL, sizeof(const char*))); /*growing values*/ + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_REDKEY) + 1)); /*copy of red key*/ + whenShallmalloc_fail = currentmalloc_call + 2; + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_REDVALUE) + 1)); /*copy of red value*/ + + /*below are undo actions*/ + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) /*undo red key value*/ + .ValidateArgumentBuffer(1, TEST_REDKEY, strlen(TEST_REDKEY) + 1); + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) /*undo growing keys*/ + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) /*undo growing values*/ + .IgnoreArgument(1); + + ///act + auto result1 = Map_AddOrUpdate(handle, TEST_REDKEY, TEST_REDVALUE); + auto result3 = Map_GetInternals(handle, &keys, &values, &count); + + ///assert + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_ERROR, result1); + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_OK, result3); + ASSERT_ARE_EQUAL(size_t, 0, count); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + } + + /*Tests_SRS_MAP_02_018: [If there are any failures then Map_AddOrUpdate shall return MAP_ERROR.] */ + TEST_FUNCTION(Map_AddOrUpdate_with_2_differnt_pair_fails_when_gballoc_fails_6) + { + ///arrange + CMapMocks mocks; + const char*const* keys; + const char*const* values; + size_t count; + auto handle = Map_Create(NULL); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(NULL, sizeof(const char*))); /*growing keys*/ + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(NULL, sizeof(const char*))); /*growing values*/ + + whenShallmalloc_fail = currentmalloc_call + 1; + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_REDKEY) + 1)); /*copy of red key*/ + + /*below are undo actions*/ + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) /*undo growing keys*/ + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) /*undo growing values*/ + .IgnoreArgument(1); + + ///act + auto result1 = Map_AddOrUpdate(handle, TEST_REDKEY, TEST_REDVALUE); + auto result3 = Map_GetInternals(handle, &keys, &values, &count); + + ///assert + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_ERROR, result1); + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_OK, result3); + ASSERT_ARE_EQUAL(size_t, 0, count); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + } + + /*Tests_SRS_MAP_02_018: [If there are any failures then Map_AddOrUpdate shall return MAP_ERROR.] */ + TEST_FUNCTION(Map_AddOrUpdate_with_2_differnt_pair_fails_when_gballoc_fails_7) + { + ///arrange + CMapMocks mocks; + const char*const* keys; + const char*const* values; + size_t count; + auto handle = Map_Create(NULL); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(NULL, sizeof(const char*))); /*growing keys*/ + whenShallrealloc_fail = currentrealloc_call + 2; + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(NULL, sizeof(const char*))); /*growing values*/ + + /*below are undo actions*/ + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) /*undo growing keys*/ + .IgnoreArgument(1); + + ///act + auto result1 = Map_AddOrUpdate(handle, TEST_REDKEY, TEST_REDVALUE); + auto result3 = Map_GetInternals(handle, &keys, &values, &count); + + ///assert + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_ERROR, result1); + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_OK, result3); + ASSERT_ARE_EQUAL(size_t, 0, count); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + } + + /*Tests_SRS_MAP_02_018: [If there are any failures then Map_AddOrUpdate shall return MAP_ERROR.] */ + TEST_FUNCTION(Map_AddOrUpdate_with_2_differnt_pair_fails_when_gballoc_fails_8) + { + ///arrange + CMapMocks mocks; + const char*const* keys; + const char*const* values; + size_t count; + auto handle = Map_Create(NULL); + mocks.ResetAllCalls(); + + whenShallrealloc_fail = currentrealloc_call + 1; + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(NULL, sizeof(const char*))); /*growing keys*/ + + /*below are undo actions*/ + + ///act + auto result1 = Map_AddOrUpdate(handle, TEST_REDKEY, TEST_REDVALUE); + auto result3 = Map_GetInternals(handle, &keys, &values, &count); + + ///assert + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_ERROR, result1); + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_OK, result3); + ASSERT_ARE_EQUAL(size_t, 0, count); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + } + + /*Tests_SRS_MAP_02_016: [If the key already exists, then Map_AddOrUpdate shall overwrite the value of the existing key with parameter value.]*/ + TEST_FUNCTION(Map_AddOrUpdate_with_2_pair_overwrites_firstValue_succeeds) + { + ///arrange + CMapMocks mocks; + const char*const* keys; + const char*const* values; + size_t count; + auto handle = Map_Create(NULL); + (void)Map_AddOrUpdate(handle, TEST_REDKEY, TEST_REDVALUE); + (void)Map_AddOrUpdate(handle, TEST_BLUEKEY, TEST_BLUEVALUE); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(IGNORED_PTR_ARG, strlen(TEST_YELLOWVALUE) + 1)) /*changing redkey value to yellow*/ + .ValidateArgumentBuffer(1, TEST_REDVALUE, strlen(TEST_REDVALUE) + 1); + + ///act + auto result1 = Map_AddOrUpdate(handle, TEST_REDKEY, TEST_YELLOWVALUE); + auto result3 = Map_GetInternals(handle, &keys, &values, &count); + + ///assert + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_OK, result1); + + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_OK, result3); + ASSERT_ARE_EQUAL(size_t, 2, count); + ASSERT_ARE_EQUAL(char_ptr, TEST_REDKEY, keys[0]); + ASSERT_ARE_EQUAL(char_ptr, TEST_YELLOWVALUE, values[0]); + ASSERT_ARE_EQUAL(char_ptr, TEST_BLUEKEY, keys[1]); + ASSERT_ARE_EQUAL(char_ptr, TEST_BLUEVALUE, values[1]); + + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + } + + /*Tests_SRS_MAP_02_016: [If the key already exists, then Map_AddOrUpdate shall overwrite the value of the existing key with parameter value.]*/ + TEST_FUNCTION(Map_AddOrUpdate_with_2_pair_overwrites_firstValue_when_gballoc_fails_it_does_not_change_the_value) + { + ///arrange + CMapMocks mocks; + const char*const* keys; + const char*const* values; + size_t count; + auto handle = Map_Create(NULL); + (void)Map_AddOrUpdate(handle, TEST_REDKEY, TEST_REDVALUE); + (void)Map_AddOrUpdate(handle, TEST_BLUEKEY, TEST_BLUEVALUE); + mocks.ResetAllCalls(); + + whenShallrealloc_fail = currentrealloc_call + 1; + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(IGNORED_PTR_ARG, strlen(TEST_YELLOWVALUE) + 1)) /*changing redkey value to yellow*/ + .ValidateArgumentBuffer(1, TEST_REDVALUE, strlen(TEST_REDVALUE) + 1); + + ///act + auto result1 = Map_AddOrUpdate(handle, TEST_REDKEY, TEST_YELLOWVALUE); + auto result3 = Map_GetInternals(handle, &keys, &values, &count); + + ///assert + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_ERROR, result1); + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_OK, result3); + ASSERT_ARE_EQUAL(size_t, 2, count); + ASSERT_ARE_EQUAL(char_ptr, TEST_REDKEY, keys[0]); + ASSERT_ARE_EQUAL(char_ptr, TEST_REDVALUE, values[0]); + ASSERT_ARE_EQUAL(char_ptr, TEST_BLUEKEY, keys[1]); + ASSERT_ARE_EQUAL(char_ptr, TEST_BLUEVALUE, values[1]); + + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + } + + /*Tests_SRS_MAP_02_016: [If the key already exists, then Map_AddOrUpdate shall overwrite the value of the existing key with parameter value.]*/ + TEST_FUNCTION(Map_AddOrUpdate_with_2_pair_overwrites_secondValue) + { + ///arrange + CMapMocks mocks; + const char*const* keys; + const char*const* values; + size_t count; + auto handle = Map_Create(NULL); + (void)Map_AddOrUpdate(handle, TEST_REDKEY, TEST_REDVALUE); + (void)Map_AddOrUpdate(handle, TEST_BLUEKEY, TEST_BLUEVALUE); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(IGNORED_PTR_ARG, strlen(TEST_YELLOWVALUE) + 1)) /*changing bluekey value to yellow*/ + .ValidateArgumentBuffer(1, TEST_BLUEVALUE, strlen(TEST_BLUEVALUE) + 1); + + ///act + auto result1 = Map_AddOrUpdate(handle, TEST_BLUEKEY, TEST_YELLOWVALUE); + auto result3 = Map_GetInternals(handle, &keys, &values, &count); + + ///assert + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_OK, result1); + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_OK, result3); + ASSERT_ARE_EQUAL(size_t, 2, count); + ASSERT_ARE_EQUAL(char_ptr, TEST_REDKEY, keys[0]); + ASSERT_ARE_EQUAL(char_ptr, TEST_REDVALUE, values[0]); + ASSERT_ARE_EQUAL(char_ptr, TEST_BLUEKEY, keys[1]); + ASSERT_ARE_EQUAL(char_ptr, TEST_YELLOWVALUE, values[1]); + + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + } + + /*Tests_SRS_MAP_02_016: [If the key already exists, then Map_AddOrUpdate shall overwrite the value of the existing key with parameter value.]*/ + TEST_FUNCTION(Map_AddOrUpdate_with_2_pair_overwrites_secondValue_doesn_not_change_the_value_when_gballoc_fails) + { + ///arrange + CMapMocks mocks; + const char*const* keys; + const char*const* values; + size_t count; + auto handle = Map_Create(NULL); + (void)Map_AddOrUpdate(handle, TEST_REDKEY, TEST_REDVALUE); + (void)Map_AddOrUpdate(handle, TEST_BLUEKEY, TEST_BLUEVALUE); + mocks.ResetAllCalls(); + + whenShallrealloc_fail = currentrealloc_call + 1; + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(IGNORED_PTR_ARG, strlen(TEST_YELLOWVALUE) + 1)) /*changing bluekey value to yellow*/ + .ValidateArgumentBuffer(1, TEST_BLUEVALUE, strlen(TEST_BLUEVALUE) + 1); + + ///act + auto result1 = Map_AddOrUpdate(handle, TEST_BLUEKEY, TEST_YELLOWVALUE); + auto result3 = Map_GetInternals(handle, &keys, &values, &count); + + ///assert + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_ERROR, result1); + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_OK, result3); + ASSERT_ARE_EQUAL(size_t, 2, count); + ASSERT_ARE_EQUAL(char_ptr, TEST_REDKEY, keys[0]); + ASSERT_ARE_EQUAL(char_ptr, TEST_REDVALUE, values[0]); + ASSERT_ARE_EQUAL(char_ptr, TEST_BLUEKEY, keys[1]); + ASSERT_ARE_EQUAL(char_ptr, TEST_BLUEVALUE, values[1]); + + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + } + + /*Tests_SRS_MAP_02_020: [If parameter handle is NULL then Map_Delete shall return MAP_INVALIDARG.]*/ + TEST_FUNCTION(Map_Delete_with_NULL_handle_fails) + { + ///arrange + CMapMocks mocks; + + ///act + auto result1 = Map_Delete(NULL, TEST_BLUEKEY); + + ///assert + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_INVALIDARG, result1); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + } + + /*Tests_SRS_MAP_02_021: [If parameter key is NULL then Map_Delete shall return MAP_INVALIDARG.]*/ + TEST_FUNCTION(Map_Delete_with_NULL_key_fails) + { + ///arrange + CMapMocks mocks; + auto handle = Map_Create(NULL); + mocks.ResetAllCalls(); + + ///act + auto result1 = Map_Delete(handle, NULL); + + ///assert + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_INVALIDARG, result1); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + } + + /*Tests_SRS_MAP_02_022: [If key does not exist then Map_Delete shall return MAP_KEYNOTFOUND.]*/ + TEST_FUNCTION(Map_Delete_with_not_found_key_succeeds_1) + { + ///arrange + CMapMocks mocks; + auto handle = Map_Create(NULL); + mocks.ResetAllCalls(); + + ///act + auto result1 = Map_Delete(handle, TEST_REDKEY); + + ///assert + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_KEYNOTFOUND, result1); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + } + + /*Tests_SRS_MAP_02_022: [If key does not exist then Map_Delete shall return MAP_KEYNOTFOUND.]*/ + TEST_FUNCTION(Map_Delete_with_not_found_key_succeeds_2) + { + ///arrange + CMapMocks mocks; + auto handle = Map_Create(NULL); + (void)Map_AddOrUpdate(handle, TEST_YELLOWKEY, TEST_YELLOWVALUE); + mocks.ResetAllCalls(); + + ///act + auto result1 = Map_Delete(handle, TEST_REDKEY); + + ///assert + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_KEYNOTFOUND, result1); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + } + + /*Tests_SRS_MAP_02_023: [Otherwise, Map_Delete shall remove the key and its associated value from the map and return MAP_OK.] */ + TEST_FUNCTION(Map_Delete_with_1_found_key_succeeds) + { + ///arrange + CMapMocks mocks; + auto handle = Map_Create(NULL); + const char*const* keys; + const char*const* values; + size_t count; + (void)Map_AddOrUpdate(handle, TEST_YELLOWKEY, TEST_YELLOWVALUE); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) /*freeing yellow value*/ + .ValidateArgumentBuffer(1, TEST_YELLOWVALUE, strlen(TEST_YELLOWVALUE) + 1); + + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) /*freeing yellow key*/ + .ValidateArgumentBuffer(1, TEST_YELLOWKEY, strlen(TEST_YELLOWKEY) + 1); + + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) /*ungrowing values*/ + .IgnoreArgument(1); + + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) /*ungowing keys*/ + .IgnoreArgument(1); + + ///act + auto result1 = Map_Delete(handle, TEST_YELLOWKEY); + auto result3 = Map_GetInternals(handle, &keys, &values, &count); + + ///assert + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_OK, result1); + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_OK, result3); + ASSERT_ARE_EQUAL(size_t, 0, count); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + } + + /*Tests_SRS_MAP_02_023: [Otherwise, Map_Delete shall remove the key and its associated value from the map and return MAP_OK.] */ + TEST_FUNCTION(Map_Delete_with_1_found_key_succeeds_2) + { + ///arrange + CMapMocks mocks; + auto handle = Map_Create(NULL); + const char*const* keys; + const char*const* values; + size_t count; + (void)Map_AddOrUpdate(handle, TEST_REDKEY, TEST_REDVALUE); + (void)Map_AddOrUpdate(handle, TEST_YELLOWKEY, TEST_YELLOWVALUE); + + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) /*freeing yellow value*/ + .ValidateArgumentBuffer(1, TEST_YELLOWVALUE, strlen(TEST_YELLOWVALUE) + 1); + + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) /*freeing yellow key*/ + .ValidateArgumentBuffer(1, TEST_YELLOWKEY, strlen(TEST_YELLOWKEY) + 1); + + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(IGNORED_PTR_ARG, 1* sizeof(const char*))) /*ungrowing values*/ + .IgnoreArgument(1); + + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(IGNORED_PTR_ARG, 1 * sizeof(const char*))) /*ungrowing keys*/ + .IgnoreArgument(1); + + ///act + auto result1 = Map_Delete(handle, TEST_YELLOWKEY); + auto result3 = Map_GetInternals(handle, &keys, &values, &count); + + ///assert + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_OK, result1); + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_OK, result3); + ASSERT_ARE_EQUAL(size_t, 1, count); + ASSERT_ARE_EQUAL(char_ptr, TEST_REDKEY, keys[0]); + ASSERT_ARE_EQUAL(char_ptr, TEST_REDVALUE, values[0]); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + } + + /*Tests_SRS_MAP_02_023: [Otherwise, Map_Delete shall remove the key and its associated value from the map and return MAP_OK.] */ + TEST_FUNCTION(Map_Delete_with_1_found_key_succeeds_3) + { + ///arrange + CMapMocks mocks; + auto handle = Map_Create(NULL); + const char*const* keys; + const char*const* values; + size_t count; + (void)Map_AddOrUpdate(handle, TEST_REDKEY, TEST_REDVALUE); + (void)Map_AddOrUpdate(handle, TEST_YELLOWKEY, TEST_YELLOWVALUE); + + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) /*freeing yellow value*/ + .ValidateArgumentBuffer(1, TEST_REDVALUE, strlen(TEST_REDVALUE) + 1); + + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) /*freeing yellow key*/ + .ValidateArgumentBuffer(1, TEST_REDKEY, strlen(TEST_REDKEY) + 1); + + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(IGNORED_PTR_ARG, 1 * sizeof(const char*))) /*ungrowing values*/ + .IgnoreArgument(1); + + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(IGNORED_PTR_ARG, 1 * sizeof(const char*))) /*ungrowing keys*/ + .IgnoreArgument(1); + + ///act + auto result1 = Map_Delete(handle, TEST_REDKEY); + auto result3 = Map_GetInternals(handle, &keys, &values, &count); + + ///assert + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_OK, result1); + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_OK, result3); + ASSERT_ARE_EQUAL(size_t, 1, count); + ASSERT_ARE_EQUAL(char_ptr, TEST_YELLOWKEY, keys[0]); + ASSERT_ARE_EQUAL(char_ptr, TEST_YELLOWVALUE, values[0]); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + } + + /*Tests_SRS_MAP_02_024: [If parameter handle, key or keyExists are NULL then Map_ContainsKey shall return MAP_INVALIDARG.]*/ + TEST_FUNCTION(Map_ContainsKey_fails_with_invalid_arg_1) + { + ///arrange + CMapMocks mocks; + bool exists; + mocks.ResetAllCalls(); + + ///act + auto result1 = Map_ContainsKey(NULL,TEST_REDKEY, &exists); + + ///assert + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_INVALIDARG, result1); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + } + + /*Tests_SRS_MAP_02_024: [If parameter handle, key or keyExists are NULL then Map_ContainsKey shall return MAP_INVALIDARG.]*/ + TEST_FUNCTION(Map_ContainsKey_fails_with_invalid_arg_2) + { + ///arrange + CMapMocks mocks; + bool exists; + auto handle = Map_Create(NULL); + mocks.ResetAllCalls(); + + ///act + auto result1 = Map_ContainsKey(handle, NULL, &exists); + + ///assert + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_INVALIDARG, result1); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + } + + /*Tests_SRS_MAP_02_024: [If parameter handle, key or keyExists are NULL then Map_ContainsKey shall return MAP_INVALIDARG.]*/ + TEST_FUNCTION(Map_ContainsKey_fails_with_invalid_arg_3) + { + ///arrange + CMapMocks mocks; + auto handle = Map_Create(NULL); + mocks.ResetAllCalls(); + + ///act + auto result1 = Map_ContainsKey(handle, TEST_REDKEY, NULL); + + ///assert + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_INVALIDARG, result1); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + } + + /*Tests_SRS_MAP_02_025: [Otherwise if a key exists then Map_ContainsKey shall return MAP_OK and shall write in keyExists "true".]*/ + /*Tests_SRS_MAP_02_026: [If a key doesn't exist, then Map_ContainsKey shall return MAP_OK and write in keyExists "false".] */ + TEST_FUNCTION(Map_ContainsKey_fails_with_known_key_succeeds) + { + ///arrange + CMapMocks mocks; + auto handle = Map_Create(NULL); + bool e1, e2; + (void)Map_AddOrUpdate(handle, TEST_REDKEY, TEST_REDVALUE); + mocks.ResetAllCalls(); + + ///act + auto result1 = Map_ContainsKey(handle, TEST_REDKEY, &e1); + auto result2 = Map_ContainsKey(handle, TEST_BLUEKEY, &e2); + + ///assert + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_OK, result1); + ASSERT_IS_TRUE(e1); + + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_OK, result2); + ASSERT_IS_FALSE(e2); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + } + + /*Tests_SRS_MAP_02_027: [If parameter handle, value or valueExists is NULL then Map_ContainsValue shall return MAP_INVALIDARG.]*/ + TEST_FUNCTION(Map_ContainsValue_fails_with_NULL_handle) + { + ///arrange + CMapMocks mocks; + bool e1; + mocks.ResetAllCalls(); + + ///act + auto result1 = Map_ContainsValue(NULL, TEST_REDKEY, &e1); + + ///assert + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_INVALIDARG, result1); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + } + + /*Tests_SRS_MAP_02_027: [If parameter handle, value or valueExists is NULL then Map_ContainsValue shall return MAP_INVALIDARG.]*/ + TEST_FUNCTION(Map_ContainsValue_fails_with_NULL_key) + { + ///arrange + CMapMocks mocks; + auto handle = Map_Create(NULL); + bool e1; + mocks.ResetAllCalls(); + + ///act + auto result1 = Map_ContainsValue(handle, NULL, &e1); + + ///assert + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_INVALIDARG, result1); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + } + + /*Tests_SRS_MAP_02_027: [If parameter handle, value or valueExists is NULL then Map_ContainsValue shall return MAP_INVALIDARG.]*/ + TEST_FUNCTION(Map_ContainsValue_fails_with_NULL_exists) + { + ///arrange + CMapMocks mocks; + auto handle = Map_Create(NULL); + mocks.ResetAllCalls(); + + ///act + auto result1 = Map_ContainsValue(handle, TEST_REDKEY, NULL); + + ///assert + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_INVALIDARG, result1); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + } + + /*Tests_SRS_MAP_02_028: [Otherwise, if a pair has its value equal to the parameter value, the Map_ContainsValue shall return MAP_OK and shall write in valueExists "true".]*/ + /*Tests_SRS_MAP_02_029: [Otherwise, if such a does not exist, then Map_ContainsValue shall return MAP_OK and shall write in valueExists "false".] */ + TEST_FUNCTION(Map_ContainsValue_succeeds) + { + ///arrange + CMapMocks mocks; + auto handle = Map_Create(NULL); + bool e1, e2; + (void)Map_AddOrUpdate(handle, TEST_REDKEY, TEST_REDVALUE); + mocks.ResetAllCalls(); + + ///act + auto result1 = Map_ContainsValue(handle, TEST_REDVALUE, &e1); + auto result2 = Map_ContainsValue(handle, TEST_BLUEVALUE, &e2); + + ///assert + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_OK, result1); + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_OK, result2); + ASSERT_IS_TRUE(e1); + ASSERT_IS_FALSE(e2); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + } + + /*Tests_SRS_MAP_02_040: [If parameter handle or key is NULL then Map_GetValueFromKey returns NULL.]*/ + TEST_FUNCTION(Map_GetValueFromKey_returns_NULL__for_invalid_handle) + { + ///arrange + CMapMocks mocks; + mocks.ResetAllCalls(); + + ///act + auto result = Map_GetValueFromKey(NULL, TEST_REDKEY); + + ///assert + ASSERT_IS_NULL(result); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + } + + /*Tests_SRS_MAP_02_040: [If parameter handle or key is NULL then Map_GetValueFromKey returns NULL.]*/ + TEST_FUNCTION(Map_GetValueFromKey_returns_NULL_for_NULL_key) + { + ///arrange + CMapMocks mocks; + auto handle = Map_Create(NULL); + mocks.ResetAllCalls(); + + ///act + auto result = Map_GetValueFromKey(handle, NULL); + + ///assert + ASSERT_IS_NULL(result); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + } + + /*Tests_SRS_MAP_02_041: [If the key is not found, then Map_GetValueFromKey returns NULL.]*/ + TEST_FUNCTION(Map_GetValueFromKey_returns_NULL_for_notfound_key) + { + ///arrange + CMapMocks mocks; + auto handle = Map_Create(NULL); + mocks.ResetAllCalls(); + + ///act + auto result = Map_GetValueFromKey(handle, TEST_REDKEY); + + ///assert + ASSERT_IS_NULL(result); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + } + + /*Tests_SRS_MAP_02_042: [Otherwise, Map_GetValueFromKey returns the key's value.] */ + TEST_FUNCTION(Map_GetValueFromKey_returns_non_NULL_for_found_key) + { + ///arrange + CMapMocks mocks; + auto handle = Map_Create(NULL); + Map_AddOrUpdate(handle, TEST_REDKEY, TEST_REDVALUE); + mocks.ResetAllCalls(); + + ///act + auto result = Map_GetValueFromKey(handle, TEST_REDKEY); + + ///assert + ASSERT_ARE_EQUAL(char_ptr, TEST_REDVALUE, result); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + } + + /*Tests_SRS_MAP_02_046: [If parameter handle, keys, values or count is NULL then Map_GetInternals shall return MAP_INVALIDARG.] */ + TEST_FUNCTION(Map_GetInternals_fails_with_NULL_arg_1) + { + ///arrange + const char*const* keys; + const char*const* values; + size_t size; + + ///act + auto result = Map_GetInternals(NULL, &keys, &values, &size); + + ///assert + ASSERT_ARE_EQUAL(MAP_RESULT,MAP_INVALIDARG, result); + + } + + /*Tests_SRS_MAP_02_046: [If parameter handle, keys, values or count is NULL then Map_GetInternals shall return MAP_INVALIDARG.] */ + TEST_FUNCTION(Map_GetInternals_fails_with_NULL_arg_2) + { + ///arrange + const char*const* values; + size_t size; + CMapMocks mocks; + auto handle = Map_Create(NULL); + mocks.ResetAllCalls(); + + ///act + auto result = Map_GetInternals(handle, NULL, &values, &size); + + ///assert + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_INVALIDARG, result); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + } + + /*Tests_SRS_MAP_02_046: [If parameter handle, keys, values or count is NULL then Map_GetInternals shall return MAP_INVALIDARG.] */ + TEST_FUNCTION(Map_GetInternals_fails_with_NULL_arg_3) + { + ///arrange + const char*const* keys; + size_t size; + CMapMocks mocks; + auto handle = Map_Create(NULL); + mocks.ResetAllCalls(); + + ///act + auto result = Map_GetInternals(handle, &keys, NULL, &size); + + ///assert + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_INVALIDARG, result); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + } + + /*Tests_SRS_MAP_02_046: [If parameter handle, keys, values or count is NULL then Map_GetInternals shall return MAP_INVALIDARG.] */ + TEST_FUNCTION(Map_GetInternals_fails_with_NULL_arg_4) + { + ///arrange + const char*const* keys; + const char*const* values; + CMapMocks mocks; + auto handle = Map_Create(NULL); + mocks.ResetAllCalls(); + + ///act + auto result = Map_GetInternals(handle, &keys, &values, NULL); + + ///assert + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_INVALIDARG, result); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + } + + /*Tests_SRS_MAP_02_043: [Map_GetInternals shall produce in *keys an pointer to an array of const char* having all the keys stored so far by the map.]*/ + /*Tests_SRS_MAP_02_044: [Map_GetInternals shall produce in *values a pointer to an array of const char* having all the values stored so far by the map.]*/ + /*Tests_SRS_MAP_02_045: [ Map_GetInternals shall produce in *count the number of stored keys and values.]*/ + /*tested by every test in this suite... almost*/ + + /*Tests_SRS_MAP_02_038: [Map_Clone returns NULL if parameter handle is NULL.]*/ + TEST_FUNCTION(Map_Clone_with_NULL_handle_returns_NULL) + { + ///arrange + + ///act + auto result = Map_Clone(NULL); + + ///assert + ASSERT_IS_NULL(result); + ///cleanup + } + + /*Tests_SRS_MAP_02_039: [Map_Clone shall make a copy of the map indicated by parameter handle and return a non-NULL handle to it.]*/ + TEST_FUNCTION(Map_Clone_with_empty_map_returns_empty_map) + { + ///arrange + CMapMocks mocks; + const char*const* keys; + const char*const* values; + size_t count; + auto handle = Map_Create(NULL); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(IGNORED_NUM_ARG)) + .IgnoreArgument(1); + + ///act + auto result = Map_Clone(handle); + + ///assert + ASSERT_IS_NOT_NULL(result); + (void)Map_GetInternals(result, &keys, &values, &count); + ASSERT_IS_NULL(keys); + ASSERT_IS_NULL(values); + ASSERT_ARE_EQUAL(size_t, 0, count); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + Map_Destroy(result); + } + + /*Tests_SRS_MAP_02_039: [Map_Clone shall make a copy of the map indicated by parameter handle and return a non-NULL handle to it.]*/ + TEST_FUNCTION(Map_Clone_with_empty_fails_when_malloc_fails) + { + ///arrange + CMapMocks mocks; + auto handle = Map_Create(NULL); + mocks.ResetAllCalls(); + + whenShallmalloc_fail = currentmalloc_call + 1; + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(IGNORED_NUM_ARG)) + .IgnoreArgument(1); + + ///act + auto result = Map_Clone(handle); + + ///assert + ASSERT_IS_NULL(result); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + } + + /*Tests_SRS_MAP_02_039: [Map_Clone shall make a copy of the map indicated by parameter handle and return a non-NULL handle to it.]*/ + TEST_FUNCTION(Map_Clone_with_map_with_1_element_succeeds) + { + ///arrange + CMapMocks mocks; + const char*const* keys; + const char*const* values; + size_t count; + auto handle = Map_Create(NULL); + (void)Map_AddOrUpdate(handle, TEST_REDKEY, TEST_REDVALUE); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(IGNORED_NUM_ARG)) /*this is creating the HANDLE structure*/ + .IgnoreArgument(1); + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(sizeof(char*))); /*this is creating a clone of the storage for keys*/ + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_REDKEY) + 1)); /*this is creating a clone of RED key*/ + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(sizeof(char*))); /*this is creating a clone of the storage for values*/ + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_REDVALUE) + 1)); /*this is creating a clone of RED value*/ + + ///act + auto result = Map_Clone(handle); + + ///assert + ASSERT_IS_NOT_NULL(result); + (void)Map_GetInternals(result, &keys, &values, &count); + ASSERT_IS_NOT_NULL(keys); + ASSERT_IS_NOT_NULL(values); + ASSERT_ARE_EQUAL(size_t, 1, count); + ASSERT_ARE_EQUAL(char_ptr, TEST_REDKEY, keys[0]); + ASSERT_ARE_EQUAL(char_ptr, TEST_REDVALUE, values[0]); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + Map_Destroy(result); + } + + /*Tests_SRS_MAP_02_047: [If during cloning, any operation fails, then Map_Clone shall return NULL.] */ + TEST_FUNCTION(Map_Clone_with_map_with_1_element_fails_when_gbaloc_fails_1) + { + ///arrange + CMapMocks mocks; + auto handle = Map_Create(NULL); + (void)Map_AddOrUpdate(handle, TEST_REDKEY, TEST_REDVALUE); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(IGNORED_NUM_ARG)) /*this is creating the HANDLE structure*/ + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(sizeof(char*))); /*this is creating a clone of the storage for keys*/ + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_REDKEY) + 1)); /*this is creating a clone of RED key*/ + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(sizeof(char*))); /*this is creating a clone of the storage for values*/ + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + + whenShallmalloc_fail = currentmalloc_call + 5; + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_REDVALUE) + 1)); /*this is creating a clone of RED value*/ + + ///act + auto result = Map_Clone(handle); + + ///assert + ASSERT_IS_NULL(result); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + Map_Destroy(result); + } + + /*Tests_SRS_MAP_02_047: [If during cloning, any operation fails, then Map_Clone shall return NULL.] */ + TEST_FUNCTION(Map_Clone_with_map_with_1_element_fails_when_gbaloc_fails_2) + { + ///arrange + CMapMocks mocks; + auto handle = Map_Create(NULL); + (void)Map_AddOrUpdate(handle, TEST_REDKEY, TEST_REDVALUE); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(IGNORED_NUM_ARG)) /*this is creating the HANDLE structure*/ + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(sizeof(char*))); /*this is creating a clone of the storage for keys*/ + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_REDKEY) + 1)); /*this is creating a clone of RED key*/ + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + + whenShallmalloc_fail = currentmalloc_call + 4; + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(sizeof(char*))); /*this is creating a clone of the storage for values*/ + + ///act + auto result = Map_Clone(handle); + + ///assert + ASSERT_IS_NULL(result); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + Map_Destroy(result); + } + + /*Tests_SRS_MAP_02_047: [If during cloning, any operation fails, then Map_Clone shall return NULL.] */ + TEST_FUNCTION(Map_Clone_with_map_with_1_element_fails_when_gbaloc_fails_3) + { + ///arrange + CMapMocks mocks; + auto handle = Map_Create(NULL); + (void)Map_AddOrUpdate(handle, TEST_REDKEY, TEST_REDVALUE); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(IGNORED_NUM_ARG)) /*this is creating the HANDLE structure*/ + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(sizeof(char*))); /*this is creating a clone of the storage for keys*/ + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + + whenShallmalloc_fail = currentmalloc_call + 3; + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_REDKEY) + 1)); /*this is creating a clone of RED key*/ + + ///act + auto result = Map_Clone(handle); + + ///assert + ASSERT_IS_NULL(result); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + Map_Destroy(result); + } + + /*Tests_SRS_MAP_02_047: [If during cloning, any operation fails, then Map_Clone shall return NULL.] */ + TEST_FUNCTION(Map_Clone_with_map_with_1_element_fails_when_gbaloc_fails_4) + { + ///arrange + CMapMocks mocks; + auto handle = Map_Create(NULL); + (void)Map_AddOrUpdate(handle, TEST_REDKEY, TEST_REDVALUE); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(IGNORED_NUM_ARG)) /*this is creating the HANDLE structure*/ + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + + whenShallmalloc_fail = currentmalloc_call + 2; + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(sizeof(char*))); /*this is creating a clone of the storage for keys*/ + + ///act + auto result = Map_Clone(handle); + + ///assert + ASSERT_IS_NULL(result); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + Map_Destroy(result); + } + + /*Tests_SRS_MAP_02_047: [If during cloning, any operation fails, then Map_Clone shall return NULL.] */ + TEST_FUNCTION(Map_Clone_with_map_with_1_element_fails_when_gbaloc_fails_5) + { + ///arrange + CMapMocks mocks; + auto handle = Map_Create(NULL); + (void)Map_AddOrUpdate(handle, TEST_REDKEY, TEST_REDVALUE); + mocks.ResetAllCalls(); + + whenShallmalloc_fail = currentmalloc_call + 1; + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(IGNORED_NUM_ARG)) /*this is creating the HANDLE structure*/ + .IgnoreArgument(1); + + ///act + auto result = Map_Clone(handle); + + ///assert + ASSERT_IS_NULL(result); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + Map_Destroy(result); + } + + /*Tests_SRS_MAP_02_039: [Map_Clone shall make a copy of the map indicated by parameter handle and return a non-NULL handle to it.]*/ + TEST_FUNCTION(Map_Clone_with_map_with_2_element_succeeds) + { + ///arrange + CMapMocks mocks; + const char*const* keys; + const char*const* values; + size_t count; + auto handle = Map_Create(NULL); + (void)Map_AddOrUpdate(handle, TEST_REDKEY, TEST_REDVALUE); + (void)Map_AddOrUpdate(handle, TEST_BLUEKEY, TEST_BLUEVALUE); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(IGNORED_NUM_ARG)) /*this is creating the HANDLE structure*/ + .IgnoreArgument(1); + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(2*sizeof(char*))); /*this is creating a clone of the storage for keys*/ + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_REDKEY) + 1)); /*this is creating a clone of RED key*/ + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_BLUEKEY) + 1)); /*this is creating a clone of BLUE key*/ + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(2*sizeof(char*))); /*this is creating a clone of the storage for values*/ + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_REDVALUE) + 1)); /*this is creating a clone of RED value*/ + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_BLUEVALUE) + 1)); /*this is creating a clone of RED value*/ + + ///act + auto result = Map_Clone(handle); + + ///assert + ASSERT_IS_NOT_NULL(result); + (void)Map_GetInternals(result, &keys, &values, &count); + ASSERT_IS_NOT_NULL(keys); + ASSERT_IS_NOT_NULL(values); + ASSERT_ARE_EQUAL(size_t, 2, count); + ASSERT_ARE_EQUAL(char_ptr, TEST_REDKEY, keys[0]); + ASSERT_ARE_EQUAL(char_ptr, TEST_REDVALUE, values[0]); + ASSERT_ARE_EQUAL(char_ptr, TEST_BLUEKEY, keys[1]); + ASSERT_ARE_EQUAL(char_ptr, TEST_BLUEVALUE, values[1]); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + Map_Destroy(result); + } + + /*Tests_SRS_MAP_02_047: [If during cloning, any operation fails, then Map_Clone shall return NULL.] */ + TEST_FUNCTION(Map_Clone_with_map_with_2_element_fails_when_gballoc_fails_1) + { + ///arrange + CMapMocks mocks; + auto handle = Map_Create(NULL); + (void)Map_AddOrUpdate(handle, TEST_REDKEY, TEST_REDVALUE); + (void)Map_AddOrUpdate(handle, TEST_BLUEKEY, TEST_BLUEVALUE); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(IGNORED_NUM_ARG)) /*this is creating the HANDLE structure*/ + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(2 * sizeof(char*))); /*this is creating a clone of the storage for keys*/ + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_REDKEY) + 1)); /*this is creating a clone of RED key*/ + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_BLUEKEY) + 1)); /*this is creating a clone of BLUE key*/ + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(2 * sizeof(char*))); /*this is creating a clone of the storage for values*/ + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_REDVALUE) + 1)); /*this is creating a clone of RED value*/ + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + + whenShallmalloc_fail = currentmalloc_call + 7; + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_BLUEVALUE) + 1)); /*this is creating a clone of BLUE value*/ + + ///act + auto result = Map_Clone(handle); + + ///assert + ASSERT_IS_NULL(result); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + Map_Destroy(result); + } + + /*Tests_SRS_MAP_02_047: [If during cloning, any operation fails, then Map_Clone shall return NULL.] */ + TEST_FUNCTION(Map_Clone_with_map_with_2_element_fails_when_gballoc_fails_2) + { + ///arrange + CMapMocks mocks; + auto handle = Map_Create(NULL); + (void)Map_AddOrUpdate(handle, TEST_REDKEY, TEST_REDVALUE); + (void)Map_AddOrUpdate(handle, TEST_BLUEKEY, TEST_BLUEVALUE); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(IGNORED_NUM_ARG)) /*this is creating the HANDLE structure*/ + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(2 * sizeof(char*))); /*this is creating a clone of the storage for keys*/ + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_REDKEY) + 1)); /*this is creating a clone of RED key*/ + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_BLUEKEY) + 1)); /*this is creating a clone of BLUE key*/ + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(2 * sizeof(char*))); /*this is creating a clone of the storage for values*/ + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + + whenShallmalloc_fail = currentmalloc_call + 6; + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_REDVALUE) + 1)); /*this is creating a clone of RED value*/ + + ///act + auto result = Map_Clone(handle); + + ///assert + ASSERT_IS_NULL(result); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + Map_Destroy(result); + } + + /*Tests_SRS_MAP_02_047: [If during cloning, any operation fails, then Map_Clone shall return NULL.] */ + TEST_FUNCTION(Map_Clone_with_map_with_2_element_fails_when_gballoc_fails_3) + { + ///arrange + CMapMocks mocks; + auto handle = Map_Create(NULL); + (void)Map_AddOrUpdate(handle, TEST_REDKEY, TEST_REDVALUE); + (void)Map_AddOrUpdate(handle, TEST_BLUEKEY, TEST_BLUEVALUE); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(IGNORED_NUM_ARG)) /*this is creating the HANDLE structure*/ + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(2 * sizeof(char*))); /*this is creating a clone of the storage for keys*/ + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_REDKEY) + 1)); /*this is creating a clone of RED key*/ + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_BLUEKEY) + 1)); /*this is creating a clone of BLUE key*/ + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + + whenShallmalloc_fail = currentmalloc_call + 5; + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(2 * sizeof(char*))); /*this is creating a clone of the storage for values*/ + + ///act + auto result = Map_Clone(handle); + + ///assert + ASSERT_IS_NULL(result); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + Map_Destroy(result); + } + + /*Tests_SRS_MAP_02_047: [If during cloning, any operation fails, then Map_Clone shall return NULL.] */ + TEST_FUNCTION(Map_Clone_with_map_with_2_element_fails_when_gballoc_fails_4) + { + ///arrange + CMapMocks mocks; + auto handle = Map_Create(NULL); + (void)Map_AddOrUpdate(handle, TEST_REDKEY, TEST_REDVALUE); + (void)Map_AddOrUpdate(handle, TEST_BLUEKEY, TEST_BLUEVALUE); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(IGNORED_NUM_ARG)) /*this is creating the HANDLE structure*/ + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(2 * sizeof(char*))); /*this is creating a clone of the storage for keys*/ + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_REDKEY) + 1)); /*this is creating a clone of RED key*/ + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + + whenShallmalloc_fail = currentmalloc_call + 4; + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_BLUEKEY) + 1)); /*this is creating a clone of BLUE key*/ + + ///act + auto result = Map_Clone(handle); + + ///assert + ASSERT_IS_NULL(result); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + Map_Destroy(result); + } + + /*Tests_SRS_MAP_02_047: [If during cloning, any operation fails, then Map_Clone shall return NULL.] */ + TEST_FUNCTION(Map_Clone_with_map_with_2_element_fails_when_gballoc_fails_5) + { + ///arrange + CMapMocks mocks; + auto handle = Map_Create(NULL); + (void)Map_AddOrUpdate(handle, TEST_REDKEY, TEST_REDVALUE); + (void)Map_AddOrUpdate(handle, TEST_BLUEKEY, TEST_BLUEVALUE); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(IGNORED_NUM_ARG)) /*this is creating the HANDLE structure*/ + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(2 * sizeof(char*))); /*this is creating a clone of the storage for keys*/ + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + + whenShallmalloc_fail = currentmalloc_call + 3; + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_REDKEY) + 1)); /*this is creating a clone of RED key*/ + + ///act + auto result = Map_Clone(handle); + + ///assert + ASSERT_IS_NULL(result); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + Map_Destroy(result); + } + + /*Tests_SRS_MAP_02_047: [If during cloning, any operation fails, then Map_Clone shall return NULL.] */ + TEST_FUNCTION(Map_Clone_with_map_with_2_element_fails_when_gballoc_fails_6) + { + ///arrange + CMapMocks mocks; + auto handle = Map_Create(NULL); + (void)Map_AddOrUpdate(handle, TEST_REDKEY, TEST_REDVALUE); + (void)Map_AddOrUpdate(handle, TEST_BLUEKEY, TEST_BLUEVALUE); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(IGNORED_NUM_ARG)) /*this is creating the HANDLE structure*/ + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + + whenShallmalloc_fail = currentmalloc_call + 2; + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(2 * sizeof(char*))); /*this is creating a clone of the storage for keys*/ + + ///act + auto result = Map_Clone(handle); + + ///assert + ASSERT_IS_NULL(result); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + Map_Destroy(result); + } + + /*Tests_SRS_MAP_02_047: [If during cloning, any operation fails, then Map_Clone shall return NULL.] */ + TEST_FUNCTION(Map_Clone_with_map_with_2_element_fails_when_gballoc_fails_7) + { + ///arrange + CMapMocks mocks; + auto handle = Map_Create(NULL); + (void)Map_AddOrUpdate(handle, TEST_REDKEY, TEST_REDVALUE); + (void)Map_AddOrUpdate(handle, TEST_BLUEKEY, TEST_BLUEVALUE); + mocks.ResetAllCalls(); + + whenShallmalloc_fail = currentmalloc_call + 1; + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(IGNORED_NUM_ARG)) /*this is creating the HANDLE structure*/ + .IgnoreArgument(1); + + ///act + auto result = Map_Clone(handle); + + ///assert + ASSERT_IS_NULL(result); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + Map_Destroy(result); + } + + /* Tests_SRS_MAP_07_009: [If the mapFilterCallback function is not NULL, then the return value will be check and if it is not zero then Map_Add shall return MAP_FILTER_REJECT.] */ + TEST_FUNCTION(Map_Add_With_Filter_Succeed) + { + ///arrange + CMapMocks mocks; + auto handle = Map_Create(DontAllowCapitalsFilters); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(NULL, sizeof(const char*))); + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(NULL, sizeof(const char*))); + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_GREENKEY) + 1)); + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_GREENVALUE) + 1)); + + ///act + auto result1 = Map_Add(handle, TEST_REDKEY, TEST_REDVALUE); + auto result2 = Map_Add(handle, TEST_YELLOWKEY, TEST_YELLOWVALUE); + auto result3 = Map_Add(handle, TEST_GREENKEY, TEST_GREENVALUE); + + ///assert + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_FILTER_REJECT, result1); + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_FILTER_REJECT, result2); + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_OK, result3); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + } + + /* Tests_SRS_MAP_07_008: [If the mapFilterCallback function is not NULL, then the return value will be check and if it is not zero then Map_AddOrUpdate shall return MAP_FILTER_REJECT.] */ + TEST_FUNCTION(Map_AddOrUpdate_With_Filter_Succeed) + { + ///arrange + CMapMocks mocks; + auto handle = Map_Create(DontAllowCapitalsFilters); + mocks.ResetAllCalls(); + + EXPECTED_CALL(mocks, gballoc_realloc(NULL, sizeof(const char*))); + EXPECTED_CALL(mocks, gballoc_realloc(NULL, sizeof(const char*))); + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_GREENKEY) + 1)); + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_GREENVALUE) + 1)); + + ///act + auto result1 = Map_AddOrUpdate(handle, TEST_REDKEY, TEST_REDVALUE); + auto result2 = Map_AddOrUpdate(handle, TEST_GREENKEY, TEST_GREENVALUE); + + ///assert + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_FILTER_REJECT, result1); + ASSERT_ARE_EQUAL(MAP_RESULT, MAP_OK, result2); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Map_Destroy(handle); + } + +END_TEST_SUITE(map_unittests) diff --git a/c/sharedutil/tests/sastoken_unittests/CMakeLists.txt b/c/sharedutil/tests/sastoken_unittests/CMakeLists.txt new file mode 100644 index 00000000..43109e20 --- /dev/null +++ b/c/sharedutil/tests/sastoken_unittests/CMakeLists.txt @@ -0,0 +1,20 @@ +#Copyright (c) Microsoft. All rights reserved. +#Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#this is CMakeLists.txt for sastoken_unittests +cmake_minimum_required(VERSION 3.0) + +compileAsC99() +set(theseTestsName sastoken_unittests) +set(${theseTestsName}_cpp_files +${theseTestsName}.cpp +) + +set(${theseTestsName}_c_files +../../src/sastoken.c +) + +set(${theseTestsName}_h_files +) + +build_test_artifacts(${theseTestsName} ON) diff --git a/c/sharedutil/tests/sastoken_unittests/main.c b/c/sharedutil/tests/sastoken_unittests/main.c new file mode 100644 index 00000000..9287f083 --- /dev/null +++ b/c/sharedutil/tests/sastoken_unittests/main.c @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include "testrunnerswitcher.h" + +int main(void) +{ + size_t failedTestCount = 0; + RUN_TEST_SUITE(sastoken_unittests, failedTestCount); + return failedTestCount; +} diff --git a/c/sharedutil/tests/sastoken_unittests/sastoken_unittests.cpp b/c/sharedutil/tests/sastoken_unittests/sastoken_unittests.cpp new file mode 100644 index 00000000..c37dd0a8 --- /dev/null +++ b/c/sharedutil/tests/sastoken_unittests/sastoken_unittests.cpp @@ -0,0 +1,962 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include +#ifdef _CRTDBG_MAP_ALLOC +#include +#endif + +#include +#include + + +#include "agenttime.h" +#include "crt_abstractions.h" +#include "sastoken.h" +#include "hmacsha256.h" +#include "urlencode.h" +#include "base64.h" +#include "buffer_.h" + +#include "testrunnerswitcher.h" +#include "micromock.h" +#include "micromockcharstararenullterminatedstrings.h" + +#define TEST_STRING_HANDLE (STRING_HANDLE)0x46 +#define TEST_NULL_STRING_HANDLE (STRING_HANDLE)0x00 +#define TEST_BUFFER_HANDLE (BUFFER_HANDLE)0x47 +#define TEST_NULL_BUFFER_HANDLE (BUFFER_HANDLE)0x00 +#define TEST_SCOPE_HANDLE (STRING_HANDLE)0x48 +#define TEST_KEY_HANDLE (BUFFER_HANDLE)0x49 +#define TEST_KEYNAME_HANDLE (STRING_HANDLE)0x50 +#define TEST_HASH_HANDLE (BUFFER_HANDLE)0x51 +#define TEST_TOBEHASHED_HANDLE (STRING_HANDLE)0x52 +#define TEST_RESULT_HANDLE (STRING_HANDLE)0x53 +#define TEST_BASE64SIGNATURE_HANDLE (STRING_HANDLE)0x54 +#define TEST_URLENCODEDSIGNATURE_HANDLE (STRING_HANDLE)0x55 +#define TEST_DECODEDKEY_HANDLE (BUFFER_HANDLE)0x56 +#define TEST_TIME_T ((time_t)3600) +#define TEST_PTR_DECODEDKEY (unsigned char*)0x123 +#define TEST_LENGTH_DECODEDKEY (size_t)32 +#define TEST_PTR_TOBEHASHED (const char*)0x456 +#define TEST_LENGTH_TOBEHASHED (size_t)456 +#define TEST_EXPIRY ((size_t)7200) + +static char TEST_CHAR_ARRAY[10] = "ABCD"; + +static unsigned char TEST_UNSIGNED_CHAR_ARRAY[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09 }; +static char TEST_TOKEN_EXPIRATION_TIME[32] = "7200"; + +static MICROMOCK_MUTEX_HANDLE g_testByTest; +static MICROMOCK_GLOBAL_SEMAPHORE_HANDLE g_dllByDll; + +TYPED_MOCK_CLASS(CSASTokenMocks, CGlobalMock) +{ +public: + /* String Mocks*/ + MOCK_STATIC_METHOD_0(, STRING_HANDLE, STRING_new) + MOCK_METHOD_END(STRING_HANDLE, malloc(1)) + + + MOCK_STATIC_METHOD_2(, int, STRING_concat, STRING_HANDLE, handle, const char*, s2) + MOCK_METHOD_END(int, 0) + + MOCK_STATIC_METHOD_2(, int, STRING_concat_with_STRING, STRING_HANDLE, s1, STRING_HANDLE, s2) + MOCK_METHOD_END(int, 0) + + MOCK_STATIC_METHOD_1(, void, STRING_delete, STRING_HANDLE, handle) + MOCK_VOID_METHOD_END() + + MOCK_STATIC_METHOD_1(, const char*, STRING_c_str, STRING_HANDLE, s) + MOCK_METHOD_END(const char*, &TEST_CHAR_ARRAY[0]) + + MOCK_STATIC_METHOD_1(, size_t, STRING_length, STRING_HANDLE, handle); + MOCK_METHOD_END(size_t, 1) + + MOCK_STATIC_METHOD_2(, int, STRING_copy, STRING_HANDLE, handle, const char*, s2) + MOCK_METHOD_END(int, 0) + + + /* BUFFER Mocks */ + MOCK_STATIC_METHOD_0(, BUFFER_HANDLE, BUFFER_new) + MOCK_METHOD_END(BUFFER_HANDLE, malloc(1)) + + MOCK_STATIC_METHOD_1(, void, BUFFER_delete, BUFFER_HANDLE, s) + MOCK_VOID_METHOD_END() + + MOCK_STATIC_METHOD_1(, unsigned char*, BUFFER_u_char, BUFFER_HANDLE, handle); + MOCK_METHOD_END(unsigned char*, &TEST_UNSIGNED_CHAR_ARRAY[0]) + + MOCK_STATIC_METHOD_1(, size_t, BUFFER_length, BUFFER_HANDLE, handle); + MOCK_METHOD_END(size_t, 1) + + /*Sundry mocks*/ + MOCK_STATIC_METHOD_1(, STRING_HANDLE, Base64_Encode, BUFFER_HANDLE, input) + MOCK_METHOD_END(STRING_HANDLE, malloc(1)) + + MOCK_STATIC_METHOD_1(, BUFFER_HANDLE, Base64_Decoder, const char*, input) + MOCK_METHOD_END(BUFFER_HANDLE, malloc(1)) + + MOCK_STATIC_METHOD_1(, STRING_HANDLE, URL_Encode, STRING_HANDLE, input) + MOCK_METHOD_END(STRING_HANDLE, malloc(1)) + + MOCK_STATIC_METHOD_5(, HMACSHA256_RESULT, HMACSHA256_ComputeHash, const unsigned char*, key, size_t, keyLen, const unsigned char*, payload, size_t, payloadLen, BUFFER_HANDLE, hash) + MOCK_METHOD_END(HMACSHA256_RESULT, HMACSHA256_OK) + + MOCK_STATIC_METHOD_3(, int, size_tToString, char*, destination, size_t, destinationSize, size_t, value) + MOCK_METHOD_END(int, 0) + +}; + +DECLARE_GLOBAL_MOCK_METHOD_0(CSASTokenMocks, , STRING_HANDLE, STRING_new); +DECLARE_GLOBAL_MOCK_METHOD_2(CSASTokenMocks, , int, STRING_concat, STRING_HANDLE, handle, const char*, s2); +DECLARE_GLOBAL_MOCK_METHOD_2(CSASTokenMocks, , int, STRING_concat_with_STRING, STRING_HANDLE, s1, STRING_HANDLE, s2); +DECLARE_GLOBAL_MOCK_METHOD_1(CSASTokenMocks, , void, STRING_delete, STRING_HANDLE, handle); +DECLARE_GLOBAL_MOCK_METHOD_1(CSASTokenMocks, , size_t, STRING_length, STRING_HANDLE, handle); +DECLARE_GLOBAL_MOCK_METHOD_1(CSASTokenMocks, , const char*, STRING_c_str, STRING_HANDLE, s); +DECLARE_GLOBAL_MOCK_METHOD_2(CSASTokenMocks, , int, STRING_copy, STRING_HANDLE, handle, const char*, s2); + + +DECLARE_GLOBAL_MOCK_METHOD_0(CSASTokenMocks, , BUFFER_HANDLE, BUFFER_new); +DECLARE_GLOBAL_MOCK_METHOD_1(CSASTokenMocks, , size_t, BUFFER_length, BUFFER_HANDLE, handle); +DECLARE_GLOBAL_MOCK_METHOD_1(CSASTokenMocks, , unsigned char*, BUFFER_u_char, BUFFER_HANDLE, handle); +DECLARE_GLOBAL_MOCK_METHOD_1(CSASTokenMocks, , void, BUFFER_delete, BUFFER_HANDLE, handle); + +DECLARE_GLOBAL_MOCK_METHOD_1(CSASTokenMocks, , STRING_HANDLE, Base64_Encode, BUFFER_HANDLE, input); +DECLARE_GLOBAL_MOCK_METHOD_1(CSASTokenMocks, , BUFFER_HANDLE, Base64_Decoder, const char*, input); + +DECLARE_GLOBAL_MOCK_METHOD_1(CSASTokenMocks, , STRING_HANDLE, URL_Encode, STRING_HANDLE, input); + +DECLARE_GLOBAL_MOCK_METHOD_5(CSASTokenMocks, , HMACSHA256_RESULT, HMACSHA256_ComputeHash, const unsigned char*, key, size_t, keyLen, const unsigned char*, payload, size_t, payloadLen, BUFFER_HANDLE, hash); + +DECLARE_GLOBAL_MOCK_METHOD_3(CSASTokenMocks, , int, size_tToString, char*, destination, size_t, destinationSize, size_t, value); + +BEGIN_TEST_SUITE(sastoken_unittests) + +TEST_SUITE_INITIALIZE(TestClassInitialize) +{ + INITIALIZE_MEMORY_DEBUG(g_dllByDll); + g_testByTest = MicroMockCreateMutex(); + ASSERT_IS_NOT_NULL(g_testByTest); +} + +TEST_SUITE_CLEANUP(TestClassCleanup) +{ + MicroMockDestroyMutex(g_testByTest); + DEINITIALIZE_MEMORY_DEBUG(g_dllByDll); +} + +TEST_FUNCTION_INITIALIZE(TestMethodInitialize) +{ + if (!MicroMockAcquireMutex(g_testByTest)) + { + ASSERT_FAIL("our mutex is ABANDONED. Failure in test framework"); + } +} + +TEST_FUNCTION_CLEANUP(TestMethodCleanup) +{ + if (!MicroMockReleaseMutex(g_testByTest)) + { + ASSERT_FAIL("failure in test framework at ReleaseMutex"); + } +} + +/*Tests_SRS_SASTOKEN_06_001: [If key is NULL then SASToken_Create shall return NULL.]*/ +TEST_FUNCTION(SASToken_Create_null_key_fails) +{ + // arrange + STRING_HANDLE handle; + CSASTokenMocks mocks; + + // act + handle = SASToken_Create(TEST_NULL_STRING_HANDLE, TEST_SCOPE_HANDLE, TEST_KEYNAME_HANDLE, TEST_EXPIRY); + + // assert + ASSERT_IS_NULL(handle); +} + +/*Tests_SRS_SASTOKEN_06_003: [If scope is NULL then SASToken_Create shall return NULL.]*/ +TEST_FUNCTION(SASToken_Create_null_scope_fails) +{ + // arrange + STRING_HANDLE handle; + CSASTokenMocks mocks; + + // act + handle = SASToken_Create(TEST_KEY_HANDLE, TEST_NULL_STRING_HANDLE, TEST_KEYNAME_HANDLE, TEST_EXPIRY); + + // assert + ASSERT_IS_NULL(handle); +} + +/*Tests_SRS_SASTOKEN_06_007: [If keyName is NULL then SASToken_Create shall return NULL.]*/ +TEST_FUNCTION(SASToken_Create_null_keyName_fails) +{ + // arrange + STRING_HANDLE handle; + CSASTokenMocks mocks; + + + // act + handle = SASToken_Create(TEST_KEY_HANDLE, TEST_SCOPE_HANDLE, TEST_NULL_STRING_HANDLE, TEST_EXPIRY); + + // assert + ASSERT_IS_NULL(handle); +} + +/*Tests_SRS_SASTOKEN_06_030: [If there is an error in the decoding then SASToken_Create shall return NULL.]*/ +TEST_FUNCTION(SASToken_Create_decoded_key_fails) +{ + // arrange + STRING_HANDLE handle; + CSASTokenMocks mocks; + + STRICT_EXPECTED_CALL(mocks, STRING_c_str(TEST_KEY_HANDLE)).SetReturn(&TEST_CHAR_ARRAY[0]); + STRICT_EXPECTED_CALL(mocks, Base64_Decoder(&TEST_CHAR_ARRAY[0])).SetReturn(TEST_NULL_BUFFER_HANDLE); + + // act + handle = SASToken_Create(TEST_KEY_HANDLE, TEST_SCOPE_HANDLE, TEST_KEYNAME_HANDLE, TEST_EXPIRY); + + // assert + ASSERT_IS_NULL(handle); + +} + +/*Tests_SRS_SASTOKEN_06_029: [The key parameter is decoded from base64.]*/ +/*Tests_SRS_SASTOKEN_06_026: [If the conversion to string form fails for any reason then SASToken_Create shall return NULL.]*/ +TEST_FUNCTION(SASToken_Create_size_tToString_fails) +{ + // arrange + STRING_HANDLE handle; + CSASTokenMocks mocks; + + STRICT_EXPECTED_CALL(mocks, STRING_c_str(TEST_KEY_HANDLE)).SetReturn(&TEST_CHAR_ARRAY[0]); + STRICT_EXPECTED_CALL(mocks, Base64_Decoder(&TEST_CHAR_ARRAY[0])).SetReturn(TEST_DECODEDKEY_HANDLE); + STRICT_EXPECTED_CALL(mocks, BUFFER_delete(TEST_DECODEDKEY_HANDLE)); + + STRICT_EXPECTED_CALL(mocks, size_tToString(IGNORED_PTR_ARG, sizeof(TEST_TOKEN_EXPIRATION_TIME), TEST_EXPIRY)).IgnoreArgument(1).SetReturn(1); + + // act + handle = SASToken_Create(TEST_KEY_HANDLE, TEST_SCOPE_HANDLE, TEST_KEYNAME_HANDLE, TEST_EXPIRY); + + // assert + ASSERT_IS_NULL(handle); +} + +/*Tests_SRS_SASTOKEN_06_024: [The size_t value ((size_t) (difftime(get_time(NULL),0) + 3600)) is converted to a string form.]*/ +TEST_FUNCTION(SASToken_Create_buffer_new_fails) +{ + // arrange + STRING_HANDLE handle; + CSASTokenMocks mocks; + + STRICT_EXPECTED_CALL(mocks, STRING_c_str(TEST_KEY_HANDLE)).SetReturn(&TEST_CHAR_ARRAY[0]); + STRICT_EXPECTED_CALL(mocks, Base64_Decoder(&TEST_CHAR_ARRAY[0])).SetReturn(TEST_DECODEDKEY_HANDLE); + STRICT_EXPECTED_CALL(mocks, BUFFER_delete(TEST_DECODEDKEY_HANDLE)); + + STRICT_EXPECTED_CALL(mocks, size_tToString(IGNORED_PTR_ARG, sizeof(TEST_TOKEN_EXPIRATION_TIME), TEST_EXPIRY)).IgnoreArgument(1).CopyOutArgumentBuffer(1, TEST_TOKEN_EXPIRATION_TIME, sizeof(TEST_TOKEN_EXPIRATION_TIME) ,0); + STRICT_EXPECTED_CALL(mocks, BUFFER_new()).SetReturn(TEST_NULL_BUFFER_HANDLE); + STRICT_EXPECTED_CALL(mocks, STRING_delete(TEST_NULL_STRING_HANDLE)); + STRICT_EXPECTED_CALL(mocks, BUFFER_delete(TEST_NULL_BUFFER_HANDLE)); + + // act + handle = SASToken_Create(TEST_KEY_HANDLE, TEST_SCOPE_HANDLE, TEST_KEYNAME_HANDLE, TEST_EXPIRY); + + // assert + ASSERT_IS_NULL(handle); +} + +TEST_FUNCTION(SASToken_Create_first_string_new_fails) +{ + // arrange + STRING_HANDLE handle; + CSASTokenMocks mocks; + + STRICT_EXPECTED_CALL(mocks, STRING_c_str(TEST_KEY_HANDLE)).SetReturn(&TEST_CHAR_ARRAY[0]); + STRICT_EXPECTED_CALL(mocks, Base64_Decoder(&TEST_CHAR_ARRAY[0])).SetReturn(TEST_DECODEDKEY_HANDLE); + STRICT_EXPECTED_CALL(mocks, BUFFER_delete(TEST_DECODEDKEY_HANDLE)); + + STRICT_EXPECTED_CALL(mocks, size_tToString(IGNORED_PTR_ARG, sizeof(TEST_TOKEN_EXPIRATION_TIME), TEST_EXPIRY)).IgnoreArgument(1).CopyOutArgumentBuffer(1, TEST_TOKEN_EXPIRATION_TIME, sizeof(TEST_TOKEN_EXPIRATION_TIME), 0); + STRICT_EXPECTED_CALL(mocks, BUFFER_new()).SetReturn(TEST_HASH_HANDLE); + STRICT_EXPECTED_CALL(mocks, STRING_new()).SetReturn(TEST_NULL_STRING_HANDLE); + STRICT_EXPECTED_CALL(mocks, STRING_delete(TEST_NULL_STRING_HANDLE)); + STRICT_EXPECTED_CALL(mocks, BUFFER_delete(TEST_HASH_HANDLE)); + + // act + handle = SASToken_Create(TEST_KEY_HANDLE, TEST_SCOPE_HANDLE, TEST_KEYNAME_HANDLE, TEST_EXPIRY); + + // assert + ASSERT_IS_NULL(handle); +} + +TEST_FUNCTION(SASToken_Create_second_string_new_fails) +{ + // arrange + STRING_HANDLE handle; + CSASTokenMocks mocks; + + STRICT_EXPECTED_CALL(mocks, STRING_c_str(TEST_KEY_HANDLE)).SetReturn(&TEST_CHAR_ARRAY[0]); + STRICT_EXPECTED_CALL(mocks, Base64_Decoder(&TEST_CHAR_ARRAY[0])).SetReturn(TEST_DECODEDKEY_HANDLE); + STRICT_EXPECTED_CALL(mocks, BUFFER_delete(TEST_DECODEDKEY_HANDLE)); + + STRICT_EXPECTED_CALL(mocks, size_tToString(IGNORED_PTR_ARG, sizeof(TEST_TOKEN_EXPIRATION_TIME), TEST_EXPIRY)).IgnoreArgument(1).CopyOutArgumentBuffer(1, TEST_TOKEN_EXPIRATION_TIME, sizeof(TEST_TOKEN_EXPIRATION_TIME), 0); + STRICT_EXPECTED_CALL(mocks, BUFFER_new()).SetReturn(TEST_HASH_HANDLE); + STRICT_EXPECTED_CALL(mocks, STRING_new()).SetReturn(TEST_TOBEHASHED_HANDLE); + STRICT_EXPECTED_CALL(mocks, STRING_new()).SetReturn(TEST_NULL_STRING_HANDLE); + STRICT_EXPECTED_CALL(mocks, STRING_delete(TEST_TOBEHASHED_HANDLE)); + STRICT_EXPECTED_CALL(mocks, BUFFER_delete(TEST_HASH_HANDLE)); + + // act + handle = SASToken_Create(TEST_KEY_HANDLE, TEST_SCOPE_HANDLE, TEST_KEYNAME_HANDLE, TEST_EXPIRY); + + // assert + ASSERT_IS_NULL(handle); +} + +TEST_FUNCTION(SASToken_Create_build_to_be_hashed_part1_fails) +{ + // arrange + STRING_HANDLE handle; + CSASTokenMocks mocks; + + STRICT_EXPECTED_CALL(mocks, STRING_c_str(TEST_KEY_HANDLE)).SetReturn(&TEST_CHAR_ARRAY[0]); + STRICT_EXPECTED_CALL(mocks, Base64_Decoder(&TEST_CHAR_ARRAY[0])).SetReturn(TEST_DECODEDKEY_HANDLE); + STRICT_EXPECTED_CALL(mocks, BUFFER_delete(TEST_DECODEDKEY_HANDLE)); + + STRICT_EXPECTED_CALL(mocks, size_tToString(IGNORED_PTR_ARG, sizeof(TEST_TOKEN_EXPIRATION_TIME), TEST_EXPIRY)).IgnoreArgument(1).CopyOutArgumentBuffer(1, TEST_TOKEN_EXPIRATION_TIME, sizeof(TEST_TOKEN_EXPIRATION_TIME), 0); + STRICT_EXPECTED_CALL(mocks, BUFFER_new()).SetReturn(TEST_HASH_HANDLE); + STRICT_EXPECTED_CALL(mocks, STRING_new()).SetReturn(TEST_TOBEHASHED_HANDLE); + STRICT_EXPECTED_CALL(mocks, STRING_new()).SetReturn(TEST_RESULT_HANDLE); + + STRICT_EXPECTED_CALL(mocks, STRING_concat_with_STRING(TEST_TOBEHASHED_HANDLE, TEST_SCOPE_HANDLE)).SetReturn(1); + + STRICT_EXPECTED_CALL(mocks, STRING_delete(TEST_RESULT_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_delete(TEST_TOBEHASHED_HANDLE)); + STRICT_EXPECTED_CALL(mocks, BUFFER_delete(TEST_HASH_HANDLE)); + + // act + handle = SASToken_Create(TEST_KEY_HANDLE, TEST_SCOPE_HANDLE, TEST_KEYNAME_HANDLE, TEST_EXPIRY); + + // assert + ASSERT_IS_NULL(handle); +} + +/*Tests_SRS_SASTOKEN_06_009: [The scope is the basis for creating a STRING_HANDLE.]*/ +TEST_FUNCTION(SASToken_Create_build_to_be_hashed_part2_fails) +{ + // arrange + STRING_HANDLE handle; + CSASTokenMocks mocks; + + STRICT_EXPECTED_CALL(mocks, STRING_c_str(TEST_KEY_HANDLE)).SetReturn(&TEST_CHAR_ARRAY[0]); + STRICT_EXPECTED_CALL(mocks, Base64_Decoder(&TEST_CHAR_ARRAY[0])).SetReturn(TEST_DECODEDKEY_HANDLE); + STRICT_EXPECTED_CALL(mocks, BUFFER_delete(TEST_DECODEDKEY_HANDLE)); + + STRICT_EXPECTED_CALL(mocks, size_tToString(IGNORED_PTR_ARG, sizeof(TEST_TOKEN_EXPIRATION_TIME), TEST_EXPIRY)).IgnoreArgument(1).CopyOutArgumentBuffer(1, TEST_TOKEN_EXPIRATION_TIME, sizeof(TEST_TOKEN_EXPIRATION_TIME), 0); + STRICT_EXPECTED_CALL(mocks, BUFFER_new()).SetReturn(TEST_HASH_HANDLE); + STRICT_EXPECTED_CALL(mocks, STRING_new()).SetReturn(TEST_TOBEHASHED_HANDLE); + STRICT_EXPECTED_CALL(mocks, STRING_new()).SetReturn(TEST_RESULT_HANDLE); + + STRICT_EXPECTED_CALL(mocks, STRING_concat_with_STRING(TEST_TOBEHASHED_HANDLE, TEST_SCOPE_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_concat(TEST_TOBEHASHED_HANDLE, "\n")).SetReturn(1); + + STRICT_EXPECTED_CALL(mocks, STRING_delete(TEST_RESULT_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_delete(TEST_TOBEHASHED_HANDLE)); + STRICT_EXPECTED_CALL(mocks, BUFFER_delete(TEST_HASH_HANDLE)); + + // act + handle = SASToken_Create(TEST_KEY_HANDLE, TEST_SCOPE_HANDLE, TEST_KEYNAME_HANDLE, TEST_EXPIRY); + + // assert + ASSERT_IS_NULL(handle); +} + +/*Tests_SRS_SASTOKEN_06_010: [A "\n" is appended to that string.]*/ +TEST_FUNCTION(SASToken_Create_build_to_be_hashed_part3_fails) +{ + // arrange + STRING_HANDLE handle; + CSASTokenMocks mocks; + + STRICT_EXPECTED_CALL(mocks, STRING_c_str(TEST_KEY_HANDLE)).SetReturn(&TEST_CHAR_ARRAY[0]); + STRICT_EXPECTED_CALL(mocks, Base64_Decoder(&TEST_CHAR_ARRAY[0])).SetReturn(TEST_DECODEDKEY_HANDLE); + STRICT_EXPECTED_CALL(mocks, BUFFER_delete(TEST_DECODEDKEY_HANDLE)); + + STRICT_EXPECTED_CALL(mocks, size_tToString(IGNORED_PTR_ARG, sizeof(TEST_TOKEN_EXPIRATION_TIME), TEST_EXPIRY)).IgnoreArgument(1).CopyOutArgumentBuffer(1, TEST_TOKEN_EXPIRATION_TIME, sizeof(TEST_TOKEN_EXPIRATION_TIME), 0); + STRICT_EXPECTED_CALL(mocks, BUFFER_new()).SetReturn(TEST_HASH_HANDLE); + STRICT_EXPECTED_CALL(mocks, STRING_new()).SetReturn(TEST_TOBEHASHED_HANDLE); + STRICT_EXPECTED_CALL(mocks, STRING_new()).SetReturn(TEST_RESULT_HANDLE); + + STRICT_EXPECTED_CALL(mocks, STRING_concat_with_STRING(TEST_TOBEHASHED_HANDLE, TEST_SCOPE_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_concat(TEST_TOBEHASHED_HANDLE, "\n")); + STRICT_EXPECTED_CALL(mocks, STRING_concat(TEST_TOBEHASHED_HANDLE, TEST_TOKEN_EXPIRATION_TIME)).SetReturn(1); + + STRICT_EXPECTED_CALL(mocks, STRING_delete(TEST_RESULT_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_delete(TEST_TOBEHASHED_HANDLE)); + STRICT_EXPECTED_CALL(mocks, BUFFER_delete(TEST_HASH_HANDLE)); + + // act + handle = SASToken_Create(TEST_KEY_HANDLE, TEST_SCOPE_HANDLE, TEST_KEYNAME_HANDLE, TEST_EXPIRY); + + // assert + ASSERT_IS_NULL(handle); +} + +/*Tests_SRS_SASTOKEN_06_011: [tokenExpirationTime is appended to that string.]*/ +/*Tests_SRS_SASTOKEN_06_013: [If an error is returned from the HMAC256 function then NULL is returned from SASToken_Create.]*/ +TEST_FUNCTION(SASToken_Create_HMAC256_fails) +{ + // arrange + STRING_HANDLE handle; + CSASTokenMocks mocks; + + STRICT_EXPECTED_CALL(mocks, STRING_c_str(TEST_KEY_HANDLE)).SetReturn(&TEST_CHAR_ARRAY[0]); + STRICT_EXPECTED_CALL(mocks, Base64_Decoder(&TEST_CHAR_ARRAY[0])).SetReturn(TEST_DECODEDKEY_HANDLE); + STRICT_EXPECTED_CALL(mocks, BUFFER_delete(TEST_DECODEDKEY_HANDLE)); + + STRICT_EXPECTED_CALL(mocks, size_tToString(IGNORED_PTR_ARG, sizeof(TEST_TOKEN_EXPIRATION_TIME), TEST_EXPIRY)).IgnoreArgument(1).CopyOutArgumentBuffer(1, TEST_TOKEN_EXPIRATION_TIME, sizeof(TEST_TOKEN_EXPIRATION_TIME), 0); + STRICT_EXPECTED_CALL(mocks, BUFFER_new()).SetReturn(TEST_HASH_HANDLE); + STRICT_EXPECTED_CALL(mocks, STRING_new()).SetReturn(TEST_TOBEHASHED_HANDLE); + STRICT_EXPECTED_CALL(mocks, STRING_new()).SetReturn(TEST_RESULT_HANDLE); + + STRICT_EXPECTED_CALL(mocks, STRING_concat_with_STRING(TEST_TOBEHASHED_HANDLE, TEST_SCOPE_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_concat(TEST_TOBEHASHED_HANDLE, "\n")); + STRICT_EXPECTED_CALL(mocks, STRING_concat(TEST_TOBEHASHED_HANDLE, TEST_TOKEN_EXPIRATION_TIME)); + + STRICT_EXPECTED_CALL(mocks, BUFFER_u_char(TEST_DECODEDKEY_HANDLE)); + STRICT_EXPECTED_CALL(mocks, BUFFER_length(TEST_DECODEDKEY_HANDLE)).SetReturn(TEST_LENGTH_DECODEDKEY); + STRICT_EXPECTED_CALL(mocks, STRING_c_str(TEST_TOBEHASHED_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_length(TEST_TOBEHASHED_HANDLE)).SetReturn(TEST_LENGTH_TOBEHASHED); + + STRICT_EXPECTED_CALL(mocks, HMACSHA256_ComputeHash(IGNORED_PTR_ARG, TEST_LENGTH_DECODEDKEY, IGNORED_PTR_ARG, TEST_LENGTH_TOBEHASHED, TEST_HASH_HANDLE)).IgnoreArgument(1).IgnoreArgument(3).SetReturn(HMACSHA256_ERROR); + STRICT_EXPECTED_CALL(mocks, STRING_delete(TEST_NULL_STRING_HANDLE)); // base64 + STRICT_EXPECTED_CALL(mocks, STRING_delete(TEST_NULL_STRING_HANDLE)); // url signature + + STRICT_EXPECTED_CALL(mocks, STRING_delete(TEST_RESULT_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_delete(TEST_TOBEHASHED_HANDLE)); + STRICT_EXPECTED_CALL(mocks, BUFFER_delete(TEST_HASH_HANDLE)); + + // act + handle = SASToken_Create(TEST_KEY_HANDLE, TEST_SCOPE_HANDLE, TEST_KEYNAME_HANDLE, TEST_EXPIRY); + + // assert + ASSERT_IS_NULL(handle); +} + + +/*Tests_SRS_SASTOKEN_06_012: [An HMAC256 hash is calculated using the decodedKey, over toBeHashed.]*/ +/*Tests_SRS_SASTOKEN_06_014: [If there are any errors from the following operations then NULL shall be returned.]*/ +TEST_FUNCTION(SASToken_Create_HMAC256_passes_signature_encode_fails) +{ + // arrange + STRING_HANDLE handle; + CSASTokenMocks mocks; + + STRICT_EXPECTED_CALL(mocks, STRING_c_str(TEST_KEY_HANDLE)).SetReturn(&TEST_CHAR_ARRAY[0]); + STRICT_EXPECTED_CALL(mocks, Base64_Decoder(&TEST_CHAR_ARRAY[0])).SetReturn(TEST_DECODEDKEY_HANDLE); + STRICT_EXPECTED_CALL(mocks, BUFFER_delete(TEST_DECODEDKEY_HANDLE)); + + STRICT_EXPECTED_CALL(mocks, size_tToString(IGNORED_PTR_ARG, sizeof(TEST_TOKEN_EXPIRATION_TIME), TEST_EXPIRY)).IgnoreArgument(1).CopyOutArgumentBuffer(1, TEST_TOKEN_EXPIRATION_TIME, sizeof(TEST_TOKEN_EXPIRATION_TIME), 0); + STRICT_EXPECTED_CALL(mocks, BUFFER_new()).SetReturn(TEST_HASH_HANDLE); + STRICT_EXPECTED_CALL(mocks, STRING_new()).SetReturn(TEST_TOBEHASHED_HANDLE); + STRICT_EXPECTED_CALL(mocks, STRING_new()).SetReturn(TEST_RESULT_HANDLE); + + STRICT_EXPECTED_CALL(mocks, STRING_concat_with_STRING(TEST_TOBEHASHED_HANDLE, TEST_SCOPE_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_concat(TEST_TOBEHASHED_HANDLE, "\n")); + STRICT_EXPECTED_CALL(mocks, STRING_concat(TEST_TOBEHASHED_HANDLE, TEST_TOKEN_EXPIRATION_TIME)); + + STRICT_EXPECTED_CALL(mocks, BUFFER_u_char(TEST_DECODEDKEY_HANDLE)); + STRICT_EXPECTED_CALL(mocks, BUFFER_length(TEST_DECODEDKEY_HANDLE)).SetReturn(TEST_LENGTH_DECODEDKEY); + STRICT_EXPECTED_CALL(mocks, STRING_c_str(TEST_TOBEHASHED_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_length(TEST_TOBEHASHED_HANDLE)).SetReturn(TEST_LENGTH_TOBEHASHED); + + STRICT_EXPECTED_CALL(mocks, HMACSHA256_ComputeHash(IGNORED_PTR_ARG, TEST_LENGTH_DECODEDKEY, IGNORED_PTR_ARG, TEST_LENGTH_TOBEHASHED, TEST_HASH_HANDLE)).IgnoreArgument(1).IgnoreArgument(3); + STRICT_EXPECTED_CALL(mocks, Base64_Encode(TEST_HASH_HANDLE)).SetReturn(TEST_NULL_BUFFER_HANDLE); + STRICT_EXPECTED_CALL(mocks, STRING_delete(TEST_NULL_STRING_HANDLE)); //base64 + STRICT_EXPECTED_CALL(mocks, STRING_delete(TEST_NULL_STRING_HANDLE)); //url signature + + STRICT_EXPECTED_CALL(mocks, STRING_delete(TEST_RESULT_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_delete(TEST_TOBEHASHED_HANDLE)); + STRICT_EXPECTED_CALL(mocks, BUFFER_delete(TEST_HASH_HANDLE)); + + // act + handle = SASToken_Create(TEST_KEY_HANDLE, TEST_SCOPE_HANDLE, TEST_KEYNAME_HANDLE, TEST_EXPIRY); + + // assert + ASSERT_IS_NULL(handle); +} + +/*Tests_SRS_SASTOKEN_06_014: [If there are any errors from the following operations then NULL shall be returned.]*/ +/*Tests_SRS_SASTOKEN_06_015: [The hash is base 64 encoded.]*/ +TEST_FUNCTION(SASToken_Create_building_token_signature_url_encoding_fails) +{ + // arrange + STRING_HANDLE handle; + CSASTokenMocks mocks; + + STRICT_EXPECTED_CALL(mocks, STRING_c_str(TEST_KEY_HANDLE)).SetReturn(&TEST_CHAR_ARRAY[0]); + STRICT_EXPECTED_CALL(mocks, Base64_Decoder(&TEST_CHAR_ARRAY[0])).SetReturn(TEST_DECODEDKEY_HANDLE); + STRICT_EXPECTED_CALL(mocks, BUFFER_delete(TEST_DECODEDKEY_HANDLE)); + + STRICT_EXPECTED_CALL(mocks, size_tToString(IGNORED_PTR_ARG, sizeof(TEST_TOKEN_EXPIRATION_TIME), TEST_EXPIRY)).IgnoreArgument(1).CopyOutArgumentBuffer(1, TEST_TOKEN_EXPIRATION_TIME, sizeof(TEST_TOKEN_EXPIRATION_TIME), 0); + STRICT_EXPECTED_CALL(mocks, BUFFER_new()).SetReturn(TEST_HASH_HANDLE); + STRICT_EXPECTED_CALL(mocks, STRING_new()).SetReturn(TEST_TOBEHASHED_HANDLE); + STRICT_EXPECTED_CALL(mocks, STRING_new()).SetReturn(TEST_RESULT_HANDLE); + + STRICT_EXPECTED_CALL(mocks, STRING_concat_with_STRING(TEST_TOBEHASHED_HANDLE, TEST_SCOPE_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_concat(TEST_TOBEHASHED_HANDLE, "\n")); + STRICT_EXPECTED_CALL(mocks, STRING_concat(TEST_TOBEHASHED_HANDLE, TEST_TOKEN_EXPIRATION_TIME)); + + STRICT_EXPECTED_CALL(mocks, BUFFER_u_char(TEST_DECODEDKEY_HANDLE)); + STRICT_EXPECTED_CALL(mocks, BUFFER_length(TEST_DECODEDKEY_HANDLE)).SetReturn(TEST_LENGTH_DECODEDKEY); + STRICT_EXPECTED_CALL(mocks, STRING_c_str(TEST_TOBEHASHED_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_length(TEST_TOBEHASHED_HANDLE)).SetReturn(TEST_LENGTH_TOBEHASHED); + + STRICT_EXPECTED_CALL(mocks, HMACSHA256_ComputeHash(IGNORED_PTR_ARG, TEST_LENGTH_DECODEDKEY, IGNORED_PTR_ARG, TEST_LENGTH_TOBEHASHED, TEST_HASH_HANDLE)).IgnoreArgument(1).IgnoreArgument(3); + STRICT_EXPECTED_CALL(mocks, Base64_Encode(TEST_HASH_HANDLE)).SetReturn(TEST_BASE64SIGNATURE_HANDLE); + STRICT_EXPECTED_CALL(mocks, STRING_delete(TEST_BASE64SIGNATURE_HANDLE)); + STRICT_EXPECTED_CALL(mocks, URL_Encode(TEST_BASE64SIGNATURE_HANDLE)).SetReturn(TEST_NULL_STRING_HANDLE); + STRICT_EXPECTED_CALL(mocks, STRING_delete(TEST_NULL_STRING_HANDLE)); + + STRICT_EXPECTED_CALL(mocks, STRING_delete(TEST_RESULT_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_delete(TEST_TOBEHASHED_HANDLE)); + STRICT_EXPECTED_CALL(mocks, BUFFER_delete(TEST_HASH_HANDLE)); + + // act + handle = SASToken_Create(TEST_KEY_HANDLE, TEST_SCOPE_HANDLE, TEST_KEYNAME_HANDLE, TEST_EXPIRY); + + // assert + ASSERT_IS_NULL(handle); +} + +/*Tests_SRS_SASTOKEN_06_014: [If there are any errors from the following operations then NULL shall be returned.]*/ +/*Tests_SRS_SASTOKEN_06_028: [base64Signature shall be url encoded.]*/ +TEST_FUNCTION(SASToken_Create_building_token_copy_scope_identifier_fails) +{ + // arrange + STRING_HANDLE handle; + CSASTokenMocks mocks; + + STRICT_EXPECTED_CALL(mocks, STRING_c_str(TEST_KEY_HANDLE)).SetReturn(&TEST_CHAR_ARRAY[0]); + STRICT_EXPECTED_CALL(mocks, Base64_Decoder(&TEST_CHAR_ARRAY[0])).SetReturn(TEST_DECODEDKEY_HANDLE); + STRICT_EXPECTED_CALL(mocks, BUFFER_delete(TEST_DECODEDKEY_HANDLE)); + + STRICT_EXPECTED_CALL(mocks, size_tToString(IGNORED_PTR_ARG, sizeof(TEST_TOKEN_EXPIRATION_TIME), TEST_EXPIRY)).IgnoreArgument(1).CopyOutArgumentBuffer(1, TEST_TOKEN_EXPIRATION_TIME, sizeof(TEST_TOKEN_EXPIRATION_TIME), 0); + STRICT_EXPECTED_CALL(mocks, BUFFER_new()).SetReturn(TEST_HASH_HANDLE); + STRICT_EXPECTED_CALL(mocks, STRING_new()).SetReturn(TEST_TOBEHASHED_HANDLE); + STRICT_EXPECTED_CALL(mocks, STRING_new()).SetReturn(TEST_RESULT_HANDLE); + + STRICT_EXPECTED_CALL(mocks, STRING_concat_with_STRING(TEST_TOBEHASHED_HANDLE, TEST_SCOPE_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_concat(TEST_TOBEHASHED_HANDLE, "\n")); + STRICT_EXPECTED_CALL(mocks, STRING_concat(TEST_TOBEHASHED_HANDLE, TEST_TOKEN_EXPIRATION_TIME)); + + STRICT_EXPECTED_CALL(mocks, BUFFER_u_char(TEST_DECODEDKEY_HANDLE)); + STRICT_EXPECTED_CALL(mocks, BUFFER_length(TEST_DECODEDKEY_HANDLE)).SetReturn(TEST_LENGTH_DECODEDKEY); + STRICT_EXPECTED_CALL(mocks, STRING_c_str(TEST_TOBEHASHED_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_length(TEST_TOBEHASHED_HANDLE)).SetReturn(TEST_LENGTH_TOBEHASHED); + + STRICT_EXPECTED_CALL(mocks, HMACSHA256_ComputeHash(IGNORED_PTR_ARG, TEST_LENGTH_DECODEDKEY, IGNORED_PTR_ARG, TEST_LENGTH_TOBEHASHED, TEST_HASH_HANDLE)).IgnoreArgument(1).IgnoreArgument(3); + STRICT_EXPECTED_CALL(mocks, Base64_Encode(TEST_HASH_HANDLE)).SetReturn(TEST_BASE64SIGNATURE_HANDLE); + STRICT_EXPECTED_CALL(mocks, STRING_delete(TEST_BASE64SIGNATURE_HANDLE)); + STRICT_EXPECTED_CALL(mocks, URL_Encode(TEST_BASE64SIGNATURE_HANDLE)).SetReturn(TEST_URLENCODEDSIGNATURE_HANDLE); + STRICT_EXPECTED_CALL(mocks, STRING_delete(TEST_URLENCODEDSIGNATURE_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_copy(TEST_RESULT_HANDLE, "SharedAccessSignature sr=")).SetReturn(1); + + STRICT_EXPECTED_CALL(mocks, STRING_delete(TEST_RESULT_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_delete(TEST_TOBEHASHED_HANDLE)); + STRICT_EXPECTED_CALL(mocks, BUFFER_delete(TEST_HASH_HANDLE)); + + // act + handle = SASToken_Create(TEST_KEY_HANDLE, TEST_SCOPE_HANDLE, TEST_KEYNAME_HANDLE, TEST_EXPIRY); + + // assert + ASSERT_IS_NULL(handle); +} + +/*Tests_SRS_SASTOKEN_06_016: [The string "SharedAccessSignature sr=" is the first part of the result of SASToken_Create.]*/ +/*Tests_SRS_SASTOKEN_06_014: [If there are any errors from the following operations then NULL shall be returned.]*/ +TEST_FUNCTION(SASToken_Create_building_token_concat_scope_fails) +{ + // arrange + STRING_HANDLE handle; + CSASTokenMocks mocks; + + STRICT_EXPECTED_CALL(mocks, STRING_c_str(TEST_KEY_HANDLE)).SetReturn(&TEST_CHAR_ARRAY[0]); + STRICT_EXPECTED_CALL(mocks, Base64_Decoder(&TEST_CHAR_ARRAY[0])).SetReturn(TEST_DECODEDKEY_HANDLE); + STRICT_EXPECTED_CALL(mocks, BUFFER_delete(TEST_DECODEDKEY_HANDLE)); + + STRICT_EXPECTED_CALL(mocks, size_tToString(IGNORED_PTR_ARG, sizeof(TEST_TOKEN_EXPIRATION_TIME), TEST_EXPIRY)).IgnoreArgument(1).CopyOutArgumentBuffer(1, TEST_TOKEN_EXPIRATION_TIME, sizeof(TEST_TOKEN_EXPIRATION_TIME), 0); + STRICT_EXPECTED_CALL(mocks, BUFFER_new()).SetReturn(TEST_HASH_HANDLE); + STRICT_EXPECTED_CALL(mocks, STRING_new()).SetReturn(TEST_TOBEHASHED_HANDLE); + STRICT_EXPECTED_CALL(mocks, STRING_new()).SetReturn(TEST_RESULT_HANDLE); + + STRICT_EXPECTED_CALL(mocks, STRING_concat_with_STRING(TEST_TOBEHASHED_HANDLE, TEST_SCOPE_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_concat(TEST_TOBEHASHED_HANDLE, "\n")); + STRICT_EXPECTED_CALL(mocks, STRING_concat(TEST_TOBEHASHED_HANDLE, TEST_TOKEN_EXPIRATION_TIME)); + + STRICT_EXPECTED_CALL(mocks, BUFFER_u_char(TEST_DECODEDKEY_HANDLE)); + STRICT_EXPECTED_CALL(mocks, BUFFER_length(TEST_DECODEDKEY_HANDLE)).SetReturn(TEST_LENGTH_DECODEDKEY); + STRICT_EXPECTED_CALL(mocks, STRING_c_str(TEST_TOBEHASHED_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_length(TEST_TOBEHASHED_HANDLE)).SetReturn(TEST_LENGTH_TOBEHASHED); + + STRICT_EXPECTED_CALL(mocks, HMACSHA256_ComputeHash(IGNORED_PTR_ARG, TEST_LENGTH_DECODEDKEY, IGNORED_PTR_ARG, TEST_LENGTH_TOBEHASHED, TEST_HASH_HANDLE)).IgnoreArgument(1).IgnoreArgument(3); + STRICT_EXPECTED_CALL(mocks, Base64_Encode(TEST_HASH_HANDLE)).SetReturn(TEST_BASE64SIGNATURE_HANDLE); + STRICT_EXPECTED_CALL(mocks, STRING_delete(TEST_BASE64SIGNATURE_HANDLE)); + STRICT_EXPECTED_CALL(mocks, URL_Encode(TEST_BASE64SIGNATURE_HANDLE)).SetReturn(TEST_URLENCODEDSIGNATURE_HANDLE); + STRICT_EXPECTED_CALL(mocks, STRING_delete(TEST_URLENCODEDSIGNATURE_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_copy(TEST_RESULT_HANDLE, "SharedAccessSignature sr=")); + STRICT_EXPECTED_CALL(mocks, STRING_concat_with_STRING(TEST_RESULT_HANDLE, TEST_SCOPE_HANDLE)).SetReturn(1); + + STRICT_EXPECTED_CALL(mocks, STRING_delete(TEST_RESULT_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_delete(TEST_TOBEHASHED_HANDLE)); + STRICT_EXPECTED_CALL(mocks, BUFFER_delete(TEST_HASH_HANDLE)); + + // act + handle = SASToken_Create(TEST_KEY_HANDLE, TEST_SCOPE_HANDLE, TEST_KEYNAME_HANDLE, TEST_EXPIRY); + + // assert + ASSERT_IS_NULL(handle); +} + +/*Tests_SRS_SASTOKEN_06_014: [If there are any errors from the following operations then NULL shall be returned.]*/ +/*Tests_SRS_SASTOKEN_06_017: [The scope parameter is appended to result.]*/ +TEST_FUNCTION(SASToken_Create_building_token_concat_signature_identifier_fails) +{ + // arrange + STRING_HANDLE handle; + CSASTokenMocks mocks; + + STRICT_EXPECTED_CALL(mocks, STRING_c_str(TEST_KEY_HANDLE)).SetReturn(&TEST_CHAR_ARRAY[0]); + STRICT_EXPECTED_CALL(mocks, Base64_Decoder(&TEST_CHAR_ARRAY[0])).SetReturn(TEST_DECODEDKEY_HANDLE); + STRICT_EXPECTED_CALL(mocks, BUFFER_delete(TEST_DECODEDKEY_HANDLE)); + + STRICT_EXPECTED_CALL(mocks, size_tToString(IGNORED_PTR_ARG, sizeof(TEST_TOKEN_EXPIRATION_TIME), TEST_EXPIRY)).IgnoreArgument(1).CopyOutArgumentBuffer(1, TEST_TOKEN_EXPIRATION_TIME, sizeof(TEST_TOKEN_EXPIRATION_TIME), 0); + STRICT_EXPECTED_CALL(mocks, BUFFER_new()).SetReturn(TEST_HASH_HANDLE); + STRICT_EXPECTED_CALL(mocks, STRING_new()).SetReturn(TEST_TOBEHASHED_HANDLE); + STRICT_EXPECTED_CALL(mocks, STRING_new()).SetReturn(TEST_RESULT_HANDLE); + + STRICT_EXPECTED_CALL(mocks, STRING_concat_with_STRING(TEST_TOBEHASHED_HANDLE, TEST_SCOPE_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_concat(TEST_TOBEHASHED_HANDLE, "\n")); + STRICT_EXPECTED_CALL(mocks, STRING_concat(TEST_TOBEHASHED_HANDLE, TEST_TOKEN_EXPIRATION_TIME)); + + STRICT_EXPECTED_CALL(mocks, BUFFER_u_char(TEST_DECODEDKEY_HANDLE)); + STRICT_EXPECTED_CALL(mocks, BUFFER_length(TEST_DECODEDKEY_HANDLE)).SetReturn(TEST_LENGTH_DECODEDKEY); + STRICT_EXPECTED_CALL(mocks, STRING_c_str(TEST_TOBEHASHED_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_length(TEST_TOBEHASHED_HANDLE)).SetReturn(TEST_LENGTH_TOBEHASHED); + + STRICT_EXPECTED_CALL(mocks, HMACSHA256_ComputeHash(IGNORED_PTR_ARG, TEST_LENGTH_DECODEDKEY, IGNORED_PTR_ARG, TEST_LENGTH_TOBEHASHED, TEST_HASH_HANDLE)).IgnoreArgument(1).IgnoreArgument(3); + STRICT_EXPECTED_CALL(mocks, Base64_Encode(TEST_HASH_HANDLE)).SetReturn(TEST_BASE64SIGNATURE_HANDLE); + STRICT_EXPECTED_CALL(mocks, STRING_delete(TEST_BASE64SIGNATURE_HANDLE)); + STRICT_EXPECTED_CALL(mocks, URL_Encode(TEST_BASE64SIGNATURE_HANDLE)).SetReturn(TEST_URLENCODEDSIGNATURE_HANDLE); + STRICT_EXPECTED_CALL(mocks, STRING_delete(TEST_URLENCODEDSIGNATURE_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_copy(TEST_RESULT_HANDLE, "SharedAccessSignature sr=")); + STRICT_EXPECTED_CALL(mocks, STRING_concat_with_STRING(TEST_RESULT_HANDLE, TEST_SCOPE_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_concat(TEST_RESULT_HANDLE, "&sig=")).SetReturn(1); + + STRICT_EXPECTED_CALL(mocks, STRING_delete(TEST_RESULT_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_delete(TEST_TOBEHASHED_HANDLE)); + STRICT_EXPECTED_CALL(mocks, BUFFER_delete(TEST_HASH_HANDLE)); + + // act + handle = SASToken_Create(TEST_KEY_HANDLE, TEST_SCOPE_HANDLE, TEST_KEYNAME_HANDLE, TEST_EXPIRY); + + // assert + ASSERT_IS_NULL(handle); +} + +/*Tests_SRS_SASTOKEN_06_014: [If there are any errors from the following operations then NULL shall be returned.]*/ +/*Tests_SRS_SASTOKEN_06_018: [The string "&sig=" is appended to result.]*/ +TEST_FUNCTION(SASToken_Create_building_token_concat_signature_fails) +{ + // arrange + STRING_HANDLE handle; + CSASTokenMocks mocks; + + STRICT_EXPECTED_CALL(mocks, STRING_c_str(TEST_KEY_HANDLE)).SetReturn(&TEST_CHAR_ARRAY[0]); + STRICT_EXPECTED_CALL(mocks, Base64_Decoder(&TEST_CHAR_ARRAY[0])).SetReturn(TEST_DECODEDKEY_HANDLE); + STRICT_EXPECTED_CALL(mocks, BUFFER_delete(TEST_DECODEDKEY_HANDLE)); + + STRICT_EXPECTED_CALL(mocks, size_tToString(IGNORED_PTR_ARG, sizeof(TEST_TOKEN_EXPIRATION_TIME), TEST_EXPIRY)).IgnoreArgument(1).CopyOutArgumentBuffer(1, TEST_TOKEN_EXPIRATION_TIME, sizeof(TEST_TOKEN_EXPIRATION_TIME), 0); + STRICT_EXPECTED_CALL(mocks, BUFFER_new()).SetReturn(TEST_HASH_HANDLE); + STRICT_EXPECTED_CALL(mocks, STRING_new()).SetReturn(TEST_TOBEHASHED_HANDLE); + STRICT_EXPECTED_CALL(mocks, STRING_new()).SetReturn(TEST_RESULT_HANDLE); + + STRICT_EXPECTED_CALL(mocks, STRING_concat_with_STRING(TEST_TOBEHASHED_HANDLE, TEST_SCOPE_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_concat(TEST_TOBEHASHED_HANDLE, "\n")); + STRICT_EXPECTED_CALL(mocks, STRING_concat(TEST_TOBEHASHED_HANDLE, TEST_TOKEN_EXPIRATION_TIME)); + + STRICT_EXPECTED_CALL(mocks, BUFFER_u_char(TEST_DECODEDKEY_HANDLE)); + STRICT_EXPECTED_CALL(mocks, BUFFER_length(TEST_DECODEDKEY_HANDLE)).SetReturn(TEST_LENGTH_DECODEDKEY); + STRICT_EXPECTED_CALL(mocks, STRING_c_str(TEST_TOBEHASHED_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_length(TEST_TOBEHASHED_HANDLE)).SetReturn(TEST_LENGTH_TOBEHASHED); + + STRICT_EXPECTED_CALL(mocks, HMACSHA256_ComputeHash(IGNORED_PTR_ARG, TEST_LENGTH_DECODEDKEY, IGNORED_PTR_ARG, TEST_LENGTH_TOBEHASHED, TEST_HASH_HANDLE)).IgnoreArgument(1).IgnoreArgument(3); + STRICT_EXPECTED_CALL(mocks, Base64_Encode(TEST_HASH_HANDLE)).SetReturn(TEST_BASE64SIGNATURE_HANDLE); + STRICT_EXPECTED_CALL(mocks, STRING_delete(TEST_BASE64SIGNATURE_HANDLE)); + STRICT_EXPECTED_CALL(mocks, URL_Encode(TEST_BASE64SIGNATURE_HANDLE)).SetReturn(TEST_URLENCODEDSIGNATURE_HANDLE); + STRICT_EXPECTED_CALL(mocks, STRING_delete(TEST_URLENCODEDSIGNATURE_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_copy(TEST_RESULT_HANDLE, "SharedAccessSignature sr=")); + STRICT_EXPECTED_CALL(mocks, STRING_concat_with_STRING(TEST_RESULT_HANDLE, TEST_SCOPE_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_concat(TEST_RESULT_HANDLE, "&sig=")); + STRICT_EXPECTED_CALL(mocks, STRING_concat_with_STRING(TEST_RESULT_HANDLE, TEST_URLENCODEDSIGNATURE_HANDLE)).SetReturn(1); + + STRICT_EXPECTED_CALL(mocks, STRING_delete(TEST_RESULT_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_delete(TEST_TOBEHASHED_HANDLE)); + STRICT_EXPECTED_CALL(mocks, BUFFER_delete(TEST_HASH_HANDLE)); + + // act + handle = SASToken_Create(TEST_KEY_HANDLE, TEST_SCOPE_HANDLE, TEST_KEYNAME_HANDLE, TEST_EXPIRY); + + // assert + ASSERT_IS_NULL(handle); +} + +/*Tests_SRS_SASTOKEN_06_014: [If there are any errors from the following operations then NULL shall be returned.]*/ +/*Tests_SRS_SASTOKEN_06_019: [The string urlEncodedSignature shall be appended to result.]*/ +TEST_FUNCTION(SASToken_Create_building_token_concat_token_expiration_time_identifier_fails) +{ + // arrange + STRING_HANDLE handle; + CSASTokenMocks mocks; + + STRICT_EXPECTED_CALL(mocks, STRING_c_str(TEST_KEY_HANDLE)).SetReturn(&TEST_CHAR_ARRAY[0]); + STRICT_EXPECTED_CALL(mocks, Base64_Decoder(&TEST_CHAR_ARRAY[0])).SetReturn(TEST_DECODEDKEY_HANDLE); + STRICT_EXPECTED_CALL(mocks, BUFFER_delete(TEST_DECODEDKEY_HANDLE)); + + STRICT_EXPECTED_CALL(mocks, size_tToString(IGNORED_PTR_ARG, sizeof(TEST_TOKEN_EXPIRATION_TIME), TEST_EXPIRY)).IgnoreArgument(1).CopyOutArgumentBuffer(1, TEST_TOKEN_EXPIRATION_TIME, sizeof(TEST_TOKEN_EXPIRATION_TIME), 0); + STRICT_EXPECTED_CALL(mocks, BUFFER_new()).SetReturn(TEST_HASH_HANDLE); + STRICT_EXPECTED_CALL(mocks, STRING_new()).SetReturn(TEST_TOBEHASHED_HANDLE); + STRICT_EXPECTED_CALL(mocks, STRING_new()).SetReturn(TEST_RESULT_HANDLE); + + STRICT_EXPECTED_CALL(mocks, STRING_concat_with_STRING(TEST_TOBEHASHED_HANDLE, TEST_SCOPE_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_concat(TEST_TOBEHASHED_HANDLE, "\n")); + STRICT_EXPECTED_CALL(mocks, STRING_concat(TEST_TOBEHASHED_HANDLE, TEST_TOKEN_EXPIRATION_TIME)); + + STRICT_EXPECTED_CALL(mocks, BUFFER_u_char(TEST_DECODEDKEY_HANDLE)); + STRICT_EXPECTED_CALL(mocks, BUFFER_length(TEST_DECODEDKEY_HANDLE)).SetReturn(TEST_LENGTH_DECODEDKEY); + STRICT_EXPECTED_CALL(mocks, STRING_c_str(TEST_TOBEHASHED_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_length(TEST_TOBEHASHED_HANDLE)).SetReturn(TEST_LENGTH_TOBEHASHED); + + STRICT_EXPECTED_CALL(mocks, HMACSHA256_ComputeHash(IGNORED_PTR_ARG, TEST_LENGTH_DECODEDKEY, IGNORED_PTR_ARG, TEST_LENGTH_TOBEHASHED, TEST_HASH_HANDLE)).IgnoreArgument(1).IgnoreArgument(3); + STRICT_EXPECTED_CALL(mocks, Base64_Encode(TEST_HASH_HANDLE)).SetReturn(TEST_BASE64SIGNATURE_HANDLE); + STRICT_EXPECTED_CALL(mocks, STRING_delete(TEST_BASE64SIGNATURE_HANDLE)); + STRICT_EXPECTED_CALL(mocks, URL_Encode(TEST_BASE64SIGNATURE_HANDLE)).SetReturn(TEST_URLENCODEDSIGNATURE_HANDLE); + STRICT_EXPECTED_CALL(mocks, STRING_delete(TEST_URLENCODEDSIGNATURE_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_copy(TEST_RESULT_HANDLE, "SharedAccessSignature sr=")); + STRICT_EXPECTED_CALL(mocks, STRING_concat_with_STRING(TEST_RESULT_HANDLE, TEST_SCOPE_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_concat(TEST_RESULT_HANDLE, "&sig=")); + STRICT_EXPECTED_CALL(mocks, STRING_concat_with_STRING(TEST_RESULT_HANDLE, TEST_URLENCODEDSIGNATURE_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_concat(TEST_RESULT_HANDLE, "&se=")).SetReturn(1); + + STRICT_EXPECTED_CALL(mocks, STRING_delete(TEST_RESULT_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_delete(TEST_TOBEHASHED_HANDLE)); + STRICT_EXPECTED_CALL(mocks, BUFFER_delete(TEST_HASH_HANDLE)); + + // act + handle = SASToken_Create(TEST_KEY_HANDLE, TEST_SCOPE_HANDLE, TEST_KEYNAME_HANDLE, TEST_EXPIRY); + + // assert + ASSERT_IS_NULL(handle); +} + +/*Tests_SRS_SASTOKEN_06_014: [If there are any errors from the following operations then NULL shall be returned.]*/ +/*Tests_SRS_SASTOKEN_06_020: [The string "&se=" shall be appended to result.]*/ +TEST_FUNCTION(SASToken_Create_building_token_concat_token_expiration_time_fails) +{ + // arrange + STRING_HANDLE handle; + CSASTokenMocks mocks; + + STRICT_EXPECTED_CALL(mocks, STRING_c_str(TEST_KEY_HANDLE)).SetReturn(&TEST_CHAR_ARRAY[0]); + STRICT_EXPECTED_CALL(mocks, Base64_Decoder(&TEST_CHAR_ARRAY[0])).SetReturn(TEST_DECODEDKEY_HANDLE); + STRICT_EXPECTED_CALL(mocks, BUFFER_delete(TEST_DECODEDKEY_HANDLE)); + + STRICT_EXPECTED_CALL(mocks, size_tToString(IGNORED_PTR_ARG, sizeof(TEST_TOKEN_EXPIRATION_TIME), TEST_EXPIRY)).IgnoreArgument(1).CopyOutArgumentBuffer(1, TEST_TOKEN_EXPIRATION_TIME, sizeof(TEST_TOKEN_EXPIRATION_TIME), 0); + STRICT_EXPECTED_CALL(mocks, BUFFER_new()).SetReturn(TEST_HASH_HANDLE); + STRICT_EXPECTED_CALL(mocks, STRING_new()).SetReturn(TEST_TOBEHASHED_HANDLE); + STRICT_EXPECTED_CALL(mocks, STRING_new()).SetReturn(TEST_RESULT_HANDLE); + + STRICT_EXPECTED_CALL(mocks, STRING_concat_with_STRING(TEST_TOBEHASHED_HANDLE, TEST_SCOPE_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_concat(TEST_TOBEHASHED_HANDLE, "\n")); + STRICT_EXPECTED_CALL(mocks, STRING_concat(TEST_TOBEHASHED_HANDLE, TEST_TOKEN_EXPIRATION_TIME)); + + STRICT_EXPECTED_CALL(mocks, BUFFER_u_char(TEST_DECODEDKEY_HANDLE)); + STRICT_EXPECTED_CALL(mocks, BUFFER_length(TEST_DECODEDKEY_HANDLE)).SetReturn(TEST_LENGTH_DECODEDKEY); + STRICT_EXPECTED_CALL(mocks, STRING_c_str(TEST_TOBEHASHED_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_length(TEST_TOBEHASHED_HANDLE)).SetReturn(TEST_LENGTH_TOBEHASHED); + + STRICT_EXPECTED_CALL(mocks, HMACSHA256_ComputeHash(IGNORED_PTR_ARG, TEST_LENGTH_DECODEDKEY, IGNORED_PTR_ARG, TEST_LENGTH_TOBEHASHED, TEST_HASH_HANDLE)).IgnoreArgument(1).IgnoreArgument(3); + STRICT_EXPECTED_CALL(mocks, Base64_Encode(TEST_HASH_HANDLE)).SetReturn(TEST_BASE64SIGNATURE_HANDLE); + STRICT_EXPECTED_CALL(mocks, STRING_delete(TEST_BASE64SIGNATURE_HANDLE)); + STRICT_EXPECTED_CALL(mocks, URL_Encode(TEST_BASE64SIGNATURE_HANDLE)).SetReturn(TEST_URLENCODEDSIGNATURE_HANDLE); + STRICT_EXPECTED_CALL(mocks, STRING_delete(TEST_URLENCODEDSIGNATURE_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_copy(TEST_RESULT_HANDLE, "SharedAccessSignature sr=")); + STRICT_EXPECTED_CALL(mocks, STRING_concat_with_STRING(TEST_RESULT_HANDLE, TEST_SCOPE_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_concat(TEST_RESULT_HANDLE, "&sig=")); + STRICT_EXPECTED_CALL(mocks, STRING_concat_with_STRING(TEST_RESULT_HANDLE, TEST_URLENCODEDSIGNATURE_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_concat(TEST_RESULT_HANDLE, "&se=")); + STRICT_EXPECTED_CALL(mocks, STRING_concat(TEST_RESULT_HANDLE, TEST_TOKEN_EXPIRATION_TIME)).SetReturn(1); + + STRICT_EXPECTED_CALL(mocks, STRING_delete(TEST_RESULT_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_delete(TEST_TOBEHASHED_HANDLE)); + STRICT_EXPECTED_CALL(mocks, BUFFER_delete(TEST_HASH_HANDLE)); + + // act + handle = SASToken_Create(TEST_KEY_HANDLE, TEST_SCOPE_HANDLE, TEST_KEYNAME_HANDLE, TEST_EXPIRY); + + // assert + ASSERT_IS_NULL(handle); +} + +/*Tests_SRS_SASTOKEN_06_014: [If there are any errors from the following operations then NULL shall be returned.]*/ +/*Tests_SRS_SASTOKEN_06_021: [tokenExpirationTime is appended to result.]*/ +TEST_FUNCTION(SASToken_Create_building_token_concat_keyname_identifier_fails) +{ + // arrange + STRING_HANDLE handle; + CSASTokenMocks mocks; + + STRICT_EXPECTED_CALL(mocks, STRING_c_str(TEST_KEY_HANDLE)).SetReturn(&TEST_CHAR_ARRAY[0]); + STRICT_EXPECTED_CALL(mocks, Base64_Decoder(&TEST_CHAR_ARRAY[0])).SetReturn(TEST_DECODEDKEY_HANDLE); + STRICT_EXPECTED_CALL(mocks, BUFFER_delete(TEST_DECODEDKEY_HANDLE)); + + STRICT_EXPECTED_CALL(mocks, size_tToString(IGNORED_PTR_ARG, sizeof(TEST_TOKEN_EXPIRATION_TIME), TEST_EXPIRY)).IgnoreArgument(1).CopyOutArgumentBuffer(1, TEST_TOKEN_EXPIRATION_TIME, sizeof(TEST_TOKEN_EXPIRATION_TIME), 0); + STRICT_EXPECTED_CALL(mocks, BUFFER_new()).SetReturn(TEST_HASH_HANDLE); + STRICT_EXPECTED_CALL(mocks, STRING_new()).SetReturn(TEST_TOBEHASHED_HANDLE); + STRICT_EXPECTED_CALL(mocks, STRING_new()).SetReturn(TEST_RESULT_HANDLE); + + STRICT_EXPECTED_CALL(mocks, STRING_concat_with_STRING(TEST_TOBEHASHED_HANDLE, TEST_SCOPE_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_concat(TEST_TOBEHASHED_HANDLE, "\n")); + STRICT_EXPECTED_CALL(mocks, STRING_concat(TEST_TOBEHASHED_HANDLE, TEST_TOKEN_EXPIRATION_TIME)); + + STRICT_EXPECTED_CALL(mocks, BUFFER_u_char(TEST_DECODEDKEY_HANDLE)); + STRICT_EXPECTED_CALL(mocks, BUFFER_length(TEST_DECODEDKEY_HANDLE)).SetReturn(TEST_LENGTH_DECODEDKEY); + STRICT_EXPECTED_CALL(mocks, STRING_c_str(TEST_TOBEHASHED_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_length(TEST_TOBEHASHED_HANDLE)).SetReturn(TEST_LENGTH_TOBEHASHED); + + STRICT_EXPECTED_CALL(mocks, HMACSHA256_ComputeHash(IGNORED_PTR_ARG, TEST_LENGTH_DECODEDKEY, IGNORED_PTR_ARG, TEST_LENGTH_TOBEHASHED, TEST_HASH_HANDLE)).IgnoreArgument(1).IgnoreArgument(3); + STRICT_EXPECTED_CALL(mocks, Base64_Encode(TEST_HASH_HANDLE)).SetReturn(TEST_BASE64SIGNATURE_HANDLE); + STRICT_EXPECTED_CALL(mocks, STRING_delete(TEST_BASE64SIGNATURE_HANDLE)); + STRICT_EXPECTED_CALL(mocks, URL_Encode(TEST_BASE64SIGNATURE_HANDLE)).SetReturn(TEST_URLENCODEDSIGNATURE_HANDLE); + STRICT_EXPECTED_CALL(mocks, STRING_delete(TEST_URLENCODEDSIGNATURE_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_copy(TEST_RESULT_HANDLE, "SharedAccessSignature sr=")); + STRICT_EXPECTED_CALL(mocks, STRING_concat_with_STRING(TEST_RESULT_HANDLE, TEST_SCOPE_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_concat(TEST_RESULT_HANDLE, "&sig=")); + STRICT_EXPECTED_CALL(mocks, STRING_concat_with_STRING(TEST_RESULT_HANDLE, TEST_URLENCODEDSIGNATURE_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_concat(TEST_RESULT_HANDLE, "&se=")); + STRICT_EXPECTED_CALL(mocks, STRING_concat(TEST_RESULT_HANDLE, TEST_TOKEN_EXPIRATION_TIME)); + STRICT_EXPECTED_CALL(mocks, STRING_concat(TEST_RESULT_HANDLE, "&skn=")).SetReturn(1); + + STRICT_EXPECTED_CALL(mocks, STRING_delete(TEST_RESULT_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_delete(TEST_TOBEHASHED_HANDLE)); + STRICT_EXPECTED_CALL(mocks, BUFFER_delete(TEST_HASH_HANDLE)); + + // act + handle = SASToken_Create(TEST_KEY_HANDLE, TEST_SCOPE_HANDLE, TEST_KEYNAME_HANDLE, TEST_EXPIRY); + + // assert + ASSERT_IS_NULL(handle); +} + +/*Tests_SRS_SASTOKEN_06_014: [If there are any errors from the following operations then NULL shall be returned.]*/ +/*Tests_SRS_SASTOKEN_06_022: [The string "&skn=" is appended to result.]*/ +TEST_FUNCTION(SASToken_Create_building_token_concat_keyname_fails) +{ + // arrange + STRING_HANDLE handle; + CSASTokenMocks mocks; + + STRICT_EXPECTED_CALL(mocks, STRING_c_str(TEST_KEY_HANDLE)).SetReturn(&TEST_CHAR_ARRAY[0]); + STRICT_EXPECTED_CALL(mocks, Base64_Decoder(&TEST_CHAR_ARRAY[0])).SetReturn(TEST_DECODEDKEY_HANDLE); + STRICT_EXPECTED_CALL(mocks, BUFFER_delete(TEST_DECODEDKEY_HANDLE)); + + STRICT_EXPECTED_CALL(mocks, size_tToString(IGNORED_PTR_ARG, sizeof(TEST_TOKEN_EXPIRATION_TIME), TEST_EXPIRY)).IgnoreArgument(1).CopyOutArgumentBuffer(1, TEST_TOKEN_EXPIRATION_TIME, sizeof(TEST_TOKEN_EXPIRATION_TIME), 0); + STRICT_EXPECTED_CALL(mocks, BUFFER_new()).SetReturn(TEST_HASH_HANDLE); + STRICT_EXPECTED_CALL(mocks, STRING_new()).SetReturn(TEST_TOBEHASHED_HANDLE); + STRICT_EXPECTED_CALL(mocks, STRING_new()).SetReturn(TEST_RESULT_HANDLE); + + STRICT_EXPECTED_CALL(mocks, STRING_concat_with_STRING(TEST_TOBEHASHED_HANDLE, TEST_SCOPE_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_concat(TEST_TOBEHASHED_HANDLE, "\n")); + STRICT_EXPECTED_CALL(mocks, STRING_concat(TEST_TOBEHASHED_HANDLE, TEST_TOKEN_EXPIRATION_TIME)); + + STRICT_EXPECTED_CALL(mocks, BUFFER_u_char(TEST_DECODEDKEY_HANDLE)); + STRICT_EXPECTED_CALL(mocks, BUFFER_length(TEST_DECODEDKEY_HANDLE)).SetReturn(TEST_LENGTH_DECODEDKEY); + STRICT_EXPECTED_CALL(mocks, STRING_c_str(TEST_TOBEHASHED_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_length(TEST_TOBEHASHED_HANDLE)).SetReturn(TEST_LENGTH_TOBEHASHED); + + STRICT_EXPECTED_CALL(mocks, HMACSHA256_ComputeHash(IGNORED_PTR_ARG, TEST_LENGTH_DECODEDKEY, IGNORED_PTR_ARG, TEST_LENGTH_TOBEHASHED, TEST_HASH_HANDLE)).IgnoreArgument(1).IgnoreArgument(3); + STRICT_EXPECTED_CALL(mocks, Base64_Encode(TEST_HASH_HANDLE)).SetReturn(TEST_BASE64SIGNATURE_HANDLE); + STRICT_EXPECTED_CALL(mocks, STRING_delete(TEST_BASE64SIGNATURE_HANDLE)); + STRICT_EXPECTED_CALL(mocks, URL_Encode(TEST_BASE64SIGNATURE_HANDLE)).SetReturn(TEST_URLENCODEDSIGNATURE_HANDLE); + STRICT_EXPECTED_CALL(mocks, STRING_delete(TEST_URLENCODEDSIGNATURE_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_copy(TEST_RESULT_HANDLE, "SharedAccessSignature sr=")); + STRICT_EXPECTED_CALL(mocks, STRING_concat_with_STRING(TEST_RESULT_HANDLE, TEST_SCOPE_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_concat(TEST_RESULT_HANDLE, "&sig=")); + STRICT_EXPECTED_CALL(mocks, STRING_concat_with_STRING(TEST_RESULT_HANDLE, TEST_URLENCODEDSIGNATURE_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_concat(TEST_RESULT_HANDLE, "&se=")); + STRICT_EXPECTED_CALL(mocks, STRING_concat(TEST_RESULT_HANDLE, TEST_TOKEN_EXPIRATION_TIME)); + STRICT_EXPECTED_CALL(mocks, STRING_concat(TEST_RESULT_HANDLE, "&skn=")); + STRICT_EXPECTED_CALL(mocks, STRING_concat_with_STRING(TEST_RESULT_HANDLE, TEST_KEYNAME_HANDLE)).SetReturn(1); + + STRICT_EXPECTED_CALL(mocks, STRING_delete(TEST_RESULT_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_delete(TEST_TOBEHASHED_HANDLE)); + STRICT_EXPECTED_CALL(mocks, BUFFER_delete(TEST_HASH_HANDLE)); + + // act + handle = SASToken_Create(TEST_KEY_HANDLE, TEST_SCOPE_HANDLE, TEST_KEYNAME_HANDLE, TEST_EXPIRY); + + // assert + ASSERT_IS_NULL(handle); +} + +/*Tests_SRS_SASTOKEN_06_023: [The argument keyName is appended to result.]*/ +TEST_FUNCTION(SASToken_Create_succeeds) +{ + // arrange + STRING_HANDLE handle; + CSASTokenMocks mocks; + + STRICT_EXPECTED_CALL(mocks, STRING_c_str(TEST_KEY_HANDLE)).SetReturn(&TEST_CHAR_ARRAY[0]); + STRICT_EXPECTED_CALL(mocks, Base64_Decoder(&TEST_CHAR_ARRAY[0])).SetReturn(TEST_DECODEDKEY_HANDLE); + STRICT_EXPECTED_CALL(mocks, BUFFER_delete(TEST_DECODEDKEY_HANDLE)); + + STRICT_EXPECTED_CALL(mocks, size_tToString(IGNORED_PTR_ARG, sizeof(TEST_TOKEN_EXPIRATION_TIME), TEST_EXPIRY)).IgnoreArgument(1).CopyOutArgumentBuffer(1, TEST_TOKEN_EXPIRATION_TIME, sizeof(TEST_TOKEN_EXPIRATION_TIME), 0); + STRICT_EXPECTED_CALL(mocks, BUFFER_new()).SetReturn(TEST_HASH_HANDLE); + STRICT_EXPECTED_CALL(mocks, STRING_new()).SetReturn(TEST_TOBEHASHED_HANDLE); + STRICT_EXPECTED_CALL(mocks, STRING_new()).SetReturn(TEST_RESULT_HANDLE); + + STRICT_EXPECTED_CALL(mocks, STRING_concat_with_STRING(TEST_TOBEHASHED_HANDLE, TEST_SCOPE_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_concat(TEST_TOBEHASHED_HANDLE, "\n")); + STRICT_EXPECTED_CALL(mocks, STRING_concat(TEST_TOBEHASHED_HANDLE, TEST_TOKEN_EXPIRATION_TIME)); + + STRICT_EXPECTED_CALL(mocks, BUFFER_u_char(TEST_DECODEDKEY_HANDLE)); + STRICT_EXPECTED_CALL(mocks, BUFFER_length(TEST_DECODEDKEY_HANDLE)).SetReturn(TEST_LENGTH_DECODEDKEY); + STRICT_EXPECTED_CALL(mocks, STRING_c_str(TEST_TOBEHASHED_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_length(TEST_TOBEHASHED_HANDLE)).SetReturn(TEST_LENGTH_TOBEHASHED); + + STRICT_EXPECTED_CALL(mocks, HMACSHA256_ComputeHash(IGNORED_PTR_ARG, TEST_LENGTH_DECODEDKEY, IGNORED_PTR_ARG, TEST_LENGTH_TOBEHASHED, TEST_HASH_HANDLE)).IgnoreArgument(1).IgnoreArgument(3); + STRICT_EXPECTED_CALL(mocks, Base64_Encode(TEST_HASH_HANDLE)).SetReturn(TEST_BASE64SIGNATURE_HANDLE); + STRICT_EXPECTED_CALL(mocks, STRING_delete(TEST_BASE64SIGNATURE_HANDLE)); + STRICT_EXPECTED_CALL(mocks, URL_Encode(TEST_BASE64SIGNATURE_HANDLE)).SetReturn(TEST_URLENCODEDSIGNATURE_HANDLE); + STRICT_EXPECTED_CALL(mocks, STRING_delete(TEST_URLENCODEDSIGNATURE_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_copy(TEST_RESULT_HANDLE, "SharedAccessSignature sr=")); + STRICT_EXPECTED_CALL(mocks, STRING_concat_with_STRING(TEST_RESULT_HANDLE, TEST_SCOPE_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_concat(TEST_RESULT_HANDLE, "&sig=")); + STRICT_EXPECTED_CALL(mocks, STRING_concat_with_STRING(TEST_RESULT_HANDLE, TEST_URLENCODEDSIGNATURE_HANDLE)); + STRICT_EXPECTED_CALL(mocks, STRING_concat(TEST_RESULT_HANDLE, "&se=")); + STRICT_EXPECTED_CALL(mocks, STRING_concat(TEST_RESULT_HANDLE, TEST_TOKEN_EXPIRATION_TIME)); + STRICT_EXPECTED_CALL(mocks, STRING_concat(TEST_RESULT_HANDLE, "&skn=")); + STRICT_EXPECTED_CALL(mocks, STRING_concat_with_STRING(TEST_RESULT_HANDLE, TEST_KEYNAME_HANDLE)); + + STRICT_EXPECTED_CALL(mocks, STRING_delete(TEST_TOBEHASHED_HANDLE)); + STRICT_EXPECTED_CALL(mocks, BUFFER_delete(TEST_HASH_HANDLE)); + + // act + handle = SASToken_Create(TEST_KEY_HANDLE, TEST_SCOPE_HANDLE, TEST_KEYNAME_HANDLE, TEST_EXPIRY); + + // assert + ASSERT_IS_NOT_NULL(handle); +} + +END_TEST_SUITE(sastoken_unittests) diff --git a/c/sharedutil/tests/string_tokenizer_unittests/CMakeLists.txt b/c/sharedutil/tests/string_tokenizer_unittests/CMakeLists.txt new file mode 100644 index 00000000..6b56499b --- /dev/null +++ b/c/sharedutil/tests/string_tokenizer_unittests/CMakeLists.txt @@ -0,0 +1,24 @@ +#Copyright (c) Microsoft. All rights reserved. +#Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#this is CMakeLists.txt for $string_tokenizer_unittests +cmake_minimum_required(VERSION 3.0) + +compileAsC99() +set(theseTestsName string_tokenizer_unittests) + +set(${theseTestsName}_cpp_files +${theseTestsName}.cpp +) + +set(${theseTestsName}_c_files +../../src/string_tokenizer.c + +../../src/strings.c +../../src/crt_abstractions.c +) + +set(${theseTestsName}_h_files +) + +build_test_artifacts(${theseTestsName} ON) \ No newline at end of file diff --git a/c/sharedutil/tests/string_tokenizer_unittests/main.c b/c/sharedutil/tests/string_tokenizer_unittests/main.c new file mode 100644 index 00000000..add37824 --- /dev/null +++ b/c/sharedutil/tests/string_tokenizer_unittests/main.c @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include "testrunnerswitcher.h" + +int main(void) +{ + size_t failedTestCount = 0; + RUN_TEST_SUITE(string_tokenizer_unittests, failedTestCount); + return (int)failedTestCount; +} diff --git a/c/sharedutil/tests/string_tokenizer_unittests/string_tokenizer_unittests.cpp b/c/sharedutil/tests/string_tokenizer_unittests/string_tokenizer_unittests.cpp new file mode 100644 index 00000000..47373208 --- /dev/null +++ b/c/sharedutil/tests/string_tokenizer_unittests/string_tokenizer_unittests.cpp @@ -0,0 +1,783 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// +// PUT NO INCLUDES BEFORE HERE !!!! +// +#include +#ifdef _CRTDBG_MAP_ALLOC +#include +#endif + +#include + + +// +// PUT NO CLIENT LIBRARY INCLUDES BEFORE HERE !!!! +// +#include "testrunnerswitcher.h" +#include "string_tokenizer.h" +#include "strings.h" +#include "micromock.h" +#include "lock.h" + + + +#define GBALLOC_H + +extern "C" int gballoc_init(void); +extern "C" void gballoc_deinit(void); +extern "C" void* gballoc_malloc(size_t size); +extern "C" void* gballoc_calloc(size_t nmemb, size_t size); +extern "C" void* gballoc_realloc(void* ptr, size_t size); +extern "C" void gballoc_free(void* ptr); + +namespace BASEIMPLEMENTATION +{ + /*if malloc is defined as gballoc_malloc at this moment, there'd be serious trouble*/ +#define Lock(x) (LOCK_OK + gballocState - gballocState) /*compiler warning about constant in if condition*/ +#define Unlock(x) (LOCK_OK + gballocState - gballocState) +#define Lock_Init() (LOCK_HANDLE)0x42 +#define Lock_Deinit(x) (LOCK_OK + gballocState - gballocState) +#include "gballoc.c" +#undef Lock +#undef Unlock +#undef Lock_Init +#undef Lock_Deinit +}; + +#ifdef _MSC_VER +#pragma warning(disable:4505) +#endif + +static MICROMOCK_GLOBAL_SEMAPHORE_HANDLE g_dllByDll; +static MICROMOCK_MUTEX_HANDLE g_testByTest; + +#define TEST_STRING_HANDLE (STRING_HANDLE)0x42 +#define FAKE_LOCK_HANDLE (LOCK_HANDLE)0x4f + +static size_t currentmalloc_call; +static size_t whenShallmalloc_fail; + + +// ** Mocks ** +TYPED_MOCK_CLASS(CStringTokenizerMocks, CGlobalMock) +{ +public: + /*Memory allocation*/ + MOCK_STATIC_METHOD_1(, void*, gballoc_malloc, size_t, size) + void* result2; + currentmalloc_call++; + if (whenShallmalloc_fail>0) + { + if (currentmalloc_call == whenShallmalloc_fail) + { + result2 = NULL; + } + else + { + result2 = BASEIMPLEMENTATION::gballoc_malloc(size); + } + } + else + { + result2 = BASEIMPLEMENTATION::gballoc_malloc(size); + } + MOCK_METHOD_END(void*, result2); + + MOCK_STATIC_METHOD_2(, void*, gballoc_realloc, void*, ptr, size_t, size) + MOCK_METHOD_END(void*, BASEIMPLEMENTATION::gballoc_realloc(ptr, size)); + + MOCK_STATIC_METHOD_1(, void, gballoc_free, void*, ptr) + BASEIMPLEMENTATION::gballoc_free(ptr); + MOCK_VOID_METHOD_END(); + + MOCK_STATIC_METHOD_0(, LOCK_HANDLE, Lock_Init) + MOCK_METHOD_END(LOCK_HANDLE, FAKE_LOCK_HANDLE); + MOCK_STATIC_METHOD_1(, LOCK_RESULT, Lock, LOCK_HANDLE, handle) + MOCK_METHOD_END(LOCK_RESULT, LOCK_OK); + MOCK_STATIC_METHOD_1(, LOCK_RESULT, Unlock, LOCK_HANDLE, handle) + MOCK_METHOD_END(LOCK_RESULT, LOCK_OK); + MOCK_STATIC_METHOD_1(, LOCK_RESULT, Lock_Deinit, LOCK_HANDLE, handle) + MOCK_METHOD_END(LOCK_RESULT, LOCK_OK); +}; + +DECLARE_GLOBAL_MOCK_METHOD_1(CStringTokenizerMocks, , void*, gballoc_malloc, size_t, size); +DECLARE_GLOBAL_MOCK_METHOD_2(CStringTokenizerMocks, , void*, gballoc_realloc, void*, ptr, size_t, size); +DECLARE_GLOBAL_MOCK_METHOD_1(CStringTokenizerMocks, , void, gballoc_free, void*, ptr) +DECLARE_GLOBAL_MOCK_METHOD_0(CStringTokenizerMocks, , LOCK_HANDLE, Lock_Init); +DECLARE_GLOBAL_MOCK_METHOD_1(CStringTokenizerMocks, , LOCK_RESULT, Lock, LOCK_HANDLE, handle); +DECLARE_GLOBAL_MOCK_METHOD_1(CStringTokenizerMocks, , LOCK_RESULT, Unlock, LOCK_HANDLE, handle); +DECLARE_GLOBAL_MOCK_METHOD_1(CStringTokenizerMocks, , LOCK_RESULT, Lock_Deinit, LOCK_HANDLE, handle) + +BEGIN_TEST_SUITE(string_tokenizer_unittests) + + TEST_SUITE_CLEANUP(TestClassCleanup) + { + DEINITIALIZE_MEMORY_DEBUG(g_dllByDll); + } + + TEST_SUITE_INITIALIZE(setsBufferTempSize) + { + INITIALIZE_MEMORY_DEBUG(g_dllByDll); + g_testByTest = MicroMockCreateMutex(); + ASSERT_IS_NOT_NULL(g_testByTest); + } + + TEST_FUNCTION_INITIALIZE(TestMethodInitialize) + { + if (!MicroMockAcquireMutex(g_testByTest)) + { + ASSERT_FAIL("our mutex is ABANDONED. Failure in test framework"); + } + + currentmalloc_call = 0; + whenShallmalloc_fail = 0; + } + + TEST_FUNCTION_CLEANUP(TestMethodCleanup) + { + if (!MicroMockReleaseMutex(g_testByTest)) + { + ASSERT_FAIL("failure in test framework at ReleaseMutex"); + } + } + + /* STRING_TOKENIZER_Tests BEGIN */ + + /* STRING_TOKENIZER_CREATE */ + /* Tests_SRS_STRING_04_001: [STRING_TOKENIZER_create shall return an NULL STRING_TOKENIZER_HANDLE if parameter handle is NULL]*/ + TEST_FUNCTION(STRING_TOKENIZER_create_with_null_handle_fail) + { + ///arrange + + ///act + STRING_TOKENIZER_HANDLE t = STRING_TOKENIZER_create(NULL); + + ///assert + ASSERT_IS_NULL(t); + } + + /* Tests_SRS_STRING_04_002: [STRING_TOKENIZER_create shall allocate a new STRING_TOKENIZER _HANDLE having the content of the STRING_HANDLE copied and current position pointing at the beginning of the string] */ + TEST_FUNCTION(STRING_TOKENIZER_create_succeed) + { + ///arrange + CStringTokenizerMocks stMocks; + const char* inputString = "Pirlimpimpim"; + + STRING_HANDLE input_string_handle = STRING_construct(inputString); + + stMocks.ResetAllCalls(); + ///act + + STRICT_EXPECTED_CALL(stMocks, gballoc_malloc(0)) //Token Allocation. + .IgnoreArgument(1); + + STRICT_EXPECTED_CALL(stMocks, gballoc_malloc(0)) //Token Content Allocation. + .IgnoreArgument(1); + + + STRING_TOKENIZER_HANDLE t = STRING_TOKENIZER_create(input_string_handle); + + stMocks.AssertActualAndExpectedCalls(); + ///assert + ASSERT_IS_NOT_NULL(t); + + //Cleanup + STRING_TOKENIZER_destroy(t); + STRING_delete(input_string_handle); + } + + /* Test_SRS_STRING_04_003: [STRING_TOKENIZER_create shall return an NULL STRING_TOKENIZER _HANDLE on any error that is encountered] */ + TEST_FUNCTION(STRING_TOKENIZER_create_when_malloc_fails_then_string_tokenizer_create_fails) + { + ///arrange + CStringTokenizerMocks stMocks; + const char* inputString = "Pirlimpimpim"; + + STRING_HANDLE input_string_handle = STRING_construct(inputString); + + stMocks.ResetAllCalls(); + ///act + + + EXPECTED_CALL(stMocks, gballoc_malloc(0)); //Token Allocation. + + + whenShallmalloc_fail = currentmalloc_call + 1; + STRING_TOKENIZER_HANDLE t = STRING_TOKENIZER_create(input_string_handle); + + ///assert + ASSERT_IS_NULL(t); + stMocks.AssertActualAndExpectedCalls(); + + //Cleanup + STRING_delete(input_string_handle); + } + /* STRING_TOKENIZER_get_next_token */ + /* Tests_SRS_STRING_04_004: [STRING_TOKENIZER_get_next_token shall return a nonzero value if any of the 3 parameters is NULL] */ + TEST_FUNCTION(STRING_TOKENIZER_get_next_token_handle_NULL_Fail) + { + ///arrange + CStringTokenizerMocks stMocks; + + STRING_HANDLE output_string_handle = STRING_new(); + + stMocks.ResetAllCalls(); + + ///act + int r = STRING_TOKENIZER_get_next_token(NULL, output_string_handle, "m"); + + ///assert + ASSERT_ARE_NOT_EQUAL(int, r, 0); + stMocks.AssertActualAndExpectedCalls(); + //Cleanup + STRING_delete(output_string_handle); + } + + /* Tests_SRS_STRING_04_004: [STRING_TOKENIZER_get_next_token shall return a nonzero value if any of the 3 parameters is NULL] */ + TEST_FUNCTION(STRING_TOKENIZER_get_next_token_output_NULL_Fail) + { + ///arrange + CStringTokenizerMocks stMocks; + const char* inputString = "Pirlimpimpim"; + + STRING_HANDLE input_string_handle = STRING_construct(inputString); + + STRING_TOKENIZER_HANDLE t = STRING_TOKENIZER_create(input_string_handle); + + stMocks.ResetAllCalls(); + + ///act + int r = STRING_TOKENIZER_get_next_token(t, NULL, "m"); + + ///assert + ASSERT_ARE_NOT_EQUAL(int, r, 0); + stMocks.AssertActualAndExpectedCalls(); + //Cleanup + STRING_TOKENIZER_destroy(t); + STRING_delete(input_string_handle); + } + + /* Tests_SRS_STRING_04_004: [STRING_TOKENIZER_get_next_token shall return a nonzero value if any of the 3 parameters is NULL] */ + TEST_FUNCTION(STRING_TOKENIZER_get_next_token_delimiters_NULL_Fail) + { + ///arrange + CStringTokenizerMocks stMocks; + const char* inputString = "Pirlimpimpim"; + + STRING_HANDLE input_string_handle = STRING_construct(inputString); + STRING_HANDLE output_string_handle = STRING_new(); + + STRING_TOKENIZER_HANDLE t = STRING_TOKENIZER_create(input_string_handle); + + stMocks.ResetAllCalls(); + + ///act + int r = STRING_TOKENIZER_get_next_token(t, output_string_handle, NULL); + stMocks.AssertActualAndExpectedCalls(); + ///assert + ASSERT_ARE_NOT_EQUAL(int, r, 0); + //Cleanup + STRING_TOKENIZER_destroy(t); + STRING_delete(input_string_handle); + STRING_delete(output_string_handle); + } + + /* Tests_SRS_STRING_04_005: [STRING_TOKENIZER_get_next_token searches the string inside STRING_TOKENIZER_HANDLE for the first character that is NOT contained in the current delimiter] */ + TEST_FUNCTION(STRING_TOKENIZER_get_next_token_PIRLI_Succeed) + { + ///arrange + CStringTokenizerMocks stMocks; + const char* inputString = "Pirlimpimpim"; + + STRING_HANDLE input_string_handle = STRING_construct(inputString); + STRING_HANDLE output_string_handle = STRING_construct(inputString); + + STRING_TOKENIZER_HANDLE t = STRING_TOKENIZER_create(input_string_handle); + + stMocks.ResetAllCalls(); + + EXPECTED_CALL(stMocks, gballoc_realloc(0, 0)) //Alloc memory to copy result. + .IgnoreArgument(1) + .IgnoreArgument(2); + + ///act + int r = STRING_TOKENIZER_get_next_token(t, output_string_handle, "m"); + + ///assert + ASSERT_ARE_EQUAL(char_ptr, "Pirli", STRING_c_str(output_string_handle)); + ASSERT_ARE_EQUAL(int, r, 0); + stMocks.AssertActualAndExpectedCalls(); + //Cleanup + STRING_TOKENIZER_destroy(t); + STRING_delete(input_string_handle); + STRING_delete(output_string_handle); + } + + /* Tests_SRS_STRING_04_005: [STRING_TOKENIZER_get_next_token searches the string inside STRING_TOKENIZER_HANDLE for the first character that is NOT contained in the current delimiter] */ + TEST_FUNCTION(STRING_TOKENIZER_get_next_token_Start_With_Delimiter_Succeed) + { + ///arrange + CStringTokenizerMocks stMocks; + const char* inputString = "Pirlimpimpim"; + + STRING_HANDLE input_string_handle = STRING_construct(inputString); + STRING_HANDLE output_string_handle = STRING_construct(inputString); + + STRING_TOKENIZER_HANDLE t = STRING_TOKENIZER_create(input_string_handle); + + stMocks.ResetAllCalls(); + + EXPECTED_CALL(stMocks, gballoc_realloc(0, 0)) //Alloc memory to copy result. + .IgnoreArgument(1) + .IgnoreArgument(2); + + ///act + int r = STRING_TOKENIZER_get_next_token(t, output_string_handle, "P"); + + ///assert + ASSERT_ARE_EQUAL(char_ptr, "irlimpimpim", STRING_c_str(output_string_handle)); + ASSERT_ARE_EQUAL(int, r, 0); + stMocks.AssertActualAndExpectedCalls(); + //Cleanup + STRING_TOKENIZER_destroy(t); + STRING_delete(input_string_handle); + STRING_delete(output_string_handle); + } + + /* Tests_SRS_STRING_04_005: [STRING_TOKENIZER_get_next_token searches the string inside STRING_TOKENIZER_HANDLE for the first character that is NOT contained in the current delimiter] */ + /* Tests_SRS_STRING_04_008: [STRING_TOKENIZER_get_next_token than searches from the start of a token for a character that is contained in the delimiters string.] */ + TEST_FUNCTION(STRING_TOKENIZER_get_next_token_Start_And_End_With_Delimiter_Succeed) + { + ///arrange + CStringTokenizerMocks stMocks; + const char* inputString = "PirlimP"; + + STRING_HANDLE input_string_handle = STRING_construct(inputString); + STRING_HANDLE output_string_handle = STRING_construct(inputString); + + STRING_TOKENIZER_HANDLE t = STRING_TOKENIZER_create(input_string_handle); + + stMocks.ResetAllCalls(); + + EXPECTED_CALL(stMocks, gballoc_realloc(0, 0)) //Alloc memory to copy result. + .IgnoreArgument(1) + .IgnoreArgument(2); + + ///act + int r = STRING_TOKENIZER_get_next_token(t, output_string_handle, "P"); + + ///assert + ASSERT_ARE_EQUAL(char_ptr, "irlim", STRING_c_str(output_string_handle)); + ASSERT_ARE_EQUAL(int, r, 0); + stMocks.AssertActualAndExpectedCalls(); + //Cleanup + STRING_TOKENIZER_destroy(t); + STRING_delete(input_string_handle); + STRING_delete(output_string_handle); + } + + /* Tests_SRS_STRING_04_006: [If no such character is found, then STRING_TOKENIZER_get_next_token shall return a nonzero Value (You've reach the end of the string or the string consists with only delimiters).] */ + TEST_FUNCTION(STRING_TOKENIZER_get_next_token_with_All_token_String_Fail) + { + ///arrange + CStringTokenizerMocks stMocks; + const char* inputString = "PPPPPP"; + + STRING_HANDLE input_string_handle = STRING_construct(inputString); + STRING_HANDLE output_string_handle = STRING_construct(inputString); + + STRING_TOKENIZER_HANDLE t = STRING_TOKENIZER_create(input_string_handle); + + stMocks.ResetAllCalls(); + + ///act + int r = STRING_TOKENIZER_get_next_token(t, output_string_handle, "P"); + + ///assert + ASSERT_ARE_NOT_EQUAL(int, r, 0); + stMocks.AssertActualAndExpectedCalls(); + //Cleanup + STRING_TOKENIZER_destroy(t); + STRING_delete(input_string_handle); + STRING_delete(output_string_handle); + } + + /* Tests_SRS_STRING_04_006: [If no such character is found, then STRING_TOKENIZER_get_next_token shall return a nonzero Value (You've reach the end of the string or the string consists with only delimiters).] */ + TEST_FUNCTION(STRING_TOKENIZER_get_next_token_2Times_With_Just_1Token_SecondCall_Fail) + { + ///arrange + CStringTokenizerMocks stMocks; + const char* inputString = "TestP"; + + STRING_HANDLE input_string_handle = STRING_construct(inputString); + STRING_HANDLE output_string_handle = STRING_construct(inputString); + + STRING_TOKENIZER_HANDLE t = STRING_TOKENIZER_create(input_string_handle); + + stMocks.ResetAllCalls(); + + EXPECTED_CALL(stMocks, gballoc_realloc(0, 0)) //Alloc memory to copy result. + .IgnoreArgument(1) + .IgnoreArgument(2); + + ///act1 + int r = STRING_TOKENIZER_get_next_token(t, output_string_handle, "P"); + + ///Assert1 + ASSERT_ARE_EQUAL(char_ptr, "Test", STRING_c_str(output_string_handle)); + ASSERT_ARE_EQUAL(int, r, 0); + + ///act2 + r = STRING_TOKENIZER_get_next_token(t, output_string_handle, "P"); + + ///assert + ASSERT_ARE_NOT_EQUAL(int, r, 0); + stMocks.AssertActualAndExpectedCalls(); + //Cleanup + STRING_TOKENIZER_destroy(t); + STRING_delete(input_string_handle); + STRING_delete(output_string_handle); + } + + /* Tests_SRS_STRING_04_007: [If such a character is found, STRING_TOKENIZER_get_next_token consider it as the start of a token.] */ + /* Tests_SRS_STRING_04_009: [If no such character is found, STRING_TOKENIZER_get_next_token extends the current token to the end of the string inside t, copies the token to output and returns 0.] */ + TEST_FUNCTION(STRING_TOKENIZER_get_next_token_2charactersToken_at_begin_of_input_call_1_Time_Succeed) + { + ///arrange + CStringTokenizerMocks stMocks; + const char* inputString = "??This is a Test"; + + STRING_HANDLE input_string_handle = STRING_construct(inputString); + STRING_HANDLE output_string_handle = STRING_construct(inputString); + + STRING_TOKENIZER_HANDLE t = STRING_TOKENIZER_create(input_string_handle); + + stMocks.ResetAllCalls(); + + EXPECTED_CALL(stMocks, gballoc_realloc(0, 0)) //Alloc memory to copy result. + .IgnoreArgument(1) + .IgnoreArgument(2); + + ///act1 + int r = STRING_TOKENIZER_get_next_token(t, output_string_handle, "?"); + + ///Assert1 + ASSERT_ARE_EQUAL(char_ptr, "This is a Test", STRING_c_str(output_string_handle)); + ASSERT_ARE_EQUAL(int, r, 0); + stMocks.AssertActualAndExpectedCalls(); + //Cleanup + STRING_TOKENIZER_destroy(t); + STRING_delete(input_string_handle); + STRING_delete(output_string_handle); + } + + /* Tests_SRS_STRING_04_010: [If such a character is found, STRING_TOKENIZER_get_next_token consider it the end of the token and copy it's content to output, updates the current position inside t to the next character and returns 0.] */ + /* Tests_SRS_STRING_04_011: [Each subsequent call to STRING_TOKENIZER_get_next_token starts searching from the saved position on t and behaves as described above.] */ + TEST_FUNCTION(STRING_TOKENIZER_get_next_token_stringWith3Tokens_Call3Times_Succeed) + { + ///arrange + CStringTokenizerMocks stMocks; + const char* inputString = "Test1PTest2PTest3"; + + STRING_HANDLE input_string_handle = STRING_construct(inputString); + STRING_HANDLE output_string_handle = STRING_construct(inputString); + + STRING_TOKENIZER_HANDLE t = STRING_TOKENIZER_create(input_string_handle); + + stMocks.ResetAllCalls(); + + EXPECTED_CALL(stMocks, gballoc_realloc(0, 0)) //Alloc memory to copy result1. + .IgnoreArgument(1) + .IgnoreArgument(2); + EXPECTED_CALL(stMocks, gballoc_realloc(0, 0)) //Alloc memory to copy result2. + .IgnoreArgument(1) + .IgnoreArgument(2); + EXPECTED_CALL(stMocks, gballoc_realloc(0, 0)) //Alloc memory to copy result3. + .IgnoreArgument(1) + .IgnoreArgument(2); + + ///act1 + int r = STRING_TOKENIZER_get_next_token(t, output_string_handle, "P"); + + ///Assert1 + ASSERT_ARE_EQUAL(char_ptr, "Test1", STRING_c_str(output_string_handle)); + ASSERT_ARE_EQUAL(int, r, 0); + + ///act2 + r = STRING_TOKENIZER_get_next_token(t, output_string_handle, "P"); + + ///Assert2 + ASSERT_ARE_EQUAL(char_ptr,"Test2", STRING_c_str(output_string_handle)); + ASSERT_ARE_EQUAL(int, r, 0); + + ///act3 + r = STRING_TOKENIZER_get_next_token(t, output_string_handle, "P"); + + ///Assert3 + ASSERT_ARE_EQUAL(char_ptr,"Test3", STRING_c_str(output_string_handle)); + ASSERT_ARE_EQUAL(int, r, 0); + stMocks.AssertActualAndExpectedCalls(); + //Cleanup + STRING_TOKENIZER_destroy(t); + STRING_delete(input_string_handle); + STRING_delete(output_string_handle); + } + + /* Tests_SRS_STRING_TOKENIZER_04_014: [STRING_TOKENIZER_get_next_token shall return nonzero value if t contains an empty string.] */ + TEST_FUNCTION(STRING_TOKENIZER_get_next_token_inputEmptyString_Fail) + { + ///arrange + CStringTokenizerMocks stMocks; + const char* inputString = ""; + + STRING_HANDLE input_string_handle = STRING_construct(inputString); + STRING_HANDLE output_string_handle = STRING_construct(inputString); + + STRING_TOKENIZER_HANDLE t = STRING_TOKENIZER_create(input_string_handle); + + stMocks.ResetAllCalls(); + + ///act + int r = STRING_TOKENIZER_get_next_token(t, output_string_handle, "P"); + + ///Assert + ASSERT_ARE_NOT_EQUAL(int, r, 0); + stMocks.AssertActualAndExpectedCalls(); + //Cleanup + STRING_TOKENIZER_destroy(t); + STRING_delete(input_string_handle); + STRING_delete(output_string_handle); + } + + /* Tests_SRS_STRING_04_010: [If such a character is found, STRING_TOKENIZER_get_next_token consider it the end of the token and copy it's content to output, updates the current position inside t to the next character and returns 0.] */ + /* Tests_SRS_STRING_04_011: [Each subsequent call to STRING_TOKENIZER_get_next_token starts searching from the saved position on t and behaves as described above.] */ + TEST_FUNCTION(STRING_TOKENIZER_get_next_token_multipleCalls_DifferentToken_Succeed) + { + ///arrange + CStringTokenizerMocks stMocks; + const char* inputString = "?a???b,,,#c"; + + STRING_HANDLE input_string_handle = STRING_construct(inputString); + STRING_HANDLE output_string_handle = STRING_construct(inputString); + + STRING_TOKENIZER_HANDLE t = STRING_TOKENIZER_create(input_string_handle); + + stMocks.ResetAllCalls(); + + ///act1 + EXPECTED_CALL(stMocks, gballoc_realloc(0, 0)) //Alloc memory to copy result. + .IgnoreArgument(1) + .IgnoreArgument(2); + + + int r = STRING_TOKENIZER_get_next_token(t, output_string_handle, "?"); + + ///Assert1 + ASSERT_ARE_EQUAL(char_ptr,"a", STRING_c_str(output_string_handle)); + ASSERT_ARE_EQUAL(int, r, 0); + + ///act2 + EXPECTED_CALL(stMocks, gballoc_realloc(0, 0)) //Alloc memory to copy result. + .IgnoreArgument(1) + .IgnoreArgument(2); + + + r = STRING_TOKENIZER_get_next_token(t, output_string_handle, ","); + + ///Assert2 + ASSERT_ARE_EQUAL(char_ptr,"??b", STRING_c_str(output_string_handle)); + ASSERT_ARE_EQUAL(int, r, 0); + + ///act3 + EXPECTED_CALL(stMocks, gballoc_realloc(0, 0)) //Alloc memory to copy result. + .IgnoreArgument(1) + .IgnoreArgument(2); + + r = STRING_TOKENIZER_get_next_token(t, output_string_handle, "#,"); + + ///Assert3 + ASSERT_ARE_EQUAL(char_ptr,"c", STRING_c_str(output_string_handle)); + ASSERT_ARE_EQUAL(int, r, 0); + + ///act4 + r = STRING_TOKENIZER_get_next_token(t, output_string_handle, "?"); + + ///Assert4 + ASSERT_ARE_NOT_EQUAL(int, r, 0); + stMocks.AssertActualAndExpectedCalls(); + ///Cleanup + STRING_TOKENIZER_destroy(t); + STRING_delete(input_string_handle); + STRING_delete(output_string_handle); + } + + /* Tests_SRS_STRING_04_010: [If such a character is found, STRING_TOKENIZER_get_next_token consider it the end of the token and copy it's content to output, updates the current position inside t to the next character and returns 0.] */ + /* Tests_SRS_STRING_04_011: [Each subsequent call to STRING_TOKENIZER_get_next_token starts searching from the saved position on t and behaves as described above.] */ + TEST_FUNCTION(STRING_TOKENIZER_get_next_token_inputString_with_SingleCharacter_call2Times_succeed) + { + ///arrange + CStringTokenizerMocks stMocks; + const char* inputString = "c"; + + STRING_HANDLE input_string_handle = STRING_construct(inputString); + STRING_HANDLE output_string_handle = STRING_construct(inputString); + + STRING_TOKENIZER_HANDLE t = STRING_TOKENIZER_create(input_string_handle); + + stMocks.ResetAllCalls(); + + ///act1 + EXPECTED_CALL(stMocks, gballoc_realloc(0, 0)) //Alloc memory to copy result. + .IgnoreArgument(1) + .IgnoreArgument(2); + + + int r = STRING_TOKENIZER_get_next_token(t, output_string_handle, "?"); + + ///Assert1 + ASSERT_ARE_EQUAL(char_ptr,"c", STRING_c_str(output_string_handle)); + ASSERT_ARE_EQUAL(int, r, 0); + + ///act2 + r = STRING_TOKENIZER_get_next_token(t, output_string_handle, "?"); + + ///Assert2 + ASSERT_ARE_NOT_EQUAL(int, r, 0); + stMocks.AssertActualAndExpectedCalls(); + ///Clean Up + STRING_TOKENIZER_destroy(t); + STRING_delete(input_string_handle); + STRING_delete(output_string_handle); + } + + /* Tests_SRS_STRING_04_010: [If such a character is found, STRING_TOKENIZER_get_next_token consider it the end of the token and copy it's content to output, updates the current position inside t to the next character and returns 0.] */ + /* Tests_SRS_STRING_04_011: [Each subsequent call to STRING_TOKENIZER_get_next_token starts searching from the saved position on t and behaves as described above.] */ + TEST_FUNCTION(STRING_TOKENIZER_get_next_token_inputString_with_NULL_in_the_Middle_succeed) + { + ///arrange + CStringTokenizerMocks stMocks; + const char* inputString = "This is a Test \0 1234"; + + STRING_HANDLE input_string_handle = STRING_construct(inputString); + STRING_HANDLE output_string_handle = STRING_construct(inputString); + + STRING_TOKENIZER_HANDLE t = STRING_TOKENIZER_create(input_string_handle); + + stMocks.ResetAllCalls(); + + ///act1 + EXPECTED_CALL(stMocks, gballoc_realloc(0, 0)) //Alloc memory to copy result. + .IgnoreArgument(1) + .IgnoreArgument(2); + + + int r = STRING_TOKENIZER_get_next_token(t, output_string_handle, "1"); + + ///Assert1 + ASSERT_ARE_EQUAL(char_ptr,"This is a Test ", STRING_c_str(output_string_handle)); + ASSERT_ARE_EQUAL(int, r, 0); + + stMocks.AssertActualAndExpectedCalls(); + ///Clean Up + STRING_TOKENIZER_destroy(t); + STRING_delete(input_string_handle); + STRING_delete(output_string_handle); + } + + /* Tests_SRS_STRING_04_010: [If such a character is found, STRING_TOKENIZER_get_next_token consider it the end of the token and copy it's content to output, updates the current position inside t to the next character and returns 0.] */ + /* Tests_SRS_STRING_04_011: [Each subsequent call to STRING_TOKENIZER_get_next_token starts searching from the saved position on t and behaves as described above.] */ + TEST_FUNCTION(STRING_TOKENIZER_get_next_token_inputString_with_specialCharacters_succeed) + { + ///arrange + CStringTokenizerMocks stMocks; + const char* inputString = "This is a Test \r\n 1234 \r\n\t 12345"; + + STRING_HANDLE input_string_handle = STRING_construct(inputString); + STRING_HANDLE output_string_handle = STRING_construct(inputString); + + STRING_TOKENIZER_HANDLE t = STRING_TOKENIZER_create(input_string_handle); + + stMocks.ResetAllCalls(); + + ///act1 + EXPECTED_CALL(stMocks, gballoc_realloc(0, 0)) //Alloc memory to copy result. + .IgnoreArgument(1) + .IgnoreArgument(2); + + + int r = STRING_TOKENIZER_get_next_token(t, output_string_handle, "\r\n"); + + ///Assert1 + ASSERT_ARE_EQUAL(char_ptr,"This is a Test ", STRING_c_str(output_string_handle)); + ASSERT_ARE_EQUAL(int, r, 0); + + ///act2 + EXPECTED_CALL(stMocks, gballoc_realloc(0, 0)) //Alloc memory to copy result. + .IgnoreArgument(1) + .IgnoreArgument(2); + + + r = STRING_TOKENIZER_get_next_token(t, output_string_handle, "\r\n"); + + ///Assert2 + ASSERT_ARE_EQUAL(char_ptr," 1234 ", STRING_c_str(output_string_handle)); + ASSERT_ARE_EQUAL(int, r, 0); + + ///act3 + EXPECTED_CALL(stMocks, gballoc_realloc(0, 0)) //Alloc memory to copy result. + .IgnoreArgument(1) + .IgnoreArgument(2); + + + r = STRING_TOKENIZER_get_next_token(t, output_string_handle, "\r\n\t"); + + ///Assert3 + ASSERT_ARE_EQUAL(char_ptr," 12345", STRING_c_str(output_string_handle)); + ASSERT_ARE_EQUAL(int, r, 0); + + stMocks.AssertActualAndExpectedCalls(); + ///Clean Up + STRING_TOKENIZER_destroy(t); + STRING_delete(input_string_handle); + STRING_delete(output_string_handle); + } + /* STRING_TOKENIZER_delete */ + /*Test_SRS_STRING_TOKENIZER_04_012: [STRING_TOKENIZER_destroy shall free the memory allocated by the STRING_TOKENIZER_create ] */ + TEST_FUNCTION(STRING_TOKENIZER_DESTROY_Succeed) + { + ///arrange + CStringTokenizerMocks stMocks; + const char* inputString = "Pirlimpimpim"; + + STRING_HANDLE input_string_handle = STRING_construct(inputString); + STRING_TOKENIZER_HANDLE t = STRING_TOKENIZER_create(input_string_handle); + + stMocks.ResetAllCalls(); + ///act + + EXPECTED_CALL(stMocks, gballoc_free(0)) //Free Token content. + .IgnoreArgument(1); + + EXPECTED_CALL(stMocks, gballoc_free(0)) //Free Token. + .IgnoreArgument(1); + + + STRING_TOKENIZER_destroy(t); + + ///assert + stMocks.AssertActualAndExpectedCalls(); + //Cleanup + STRING_delete(input_string_handle); + } + + /*Tests_SRS_STRING_TOKENIZER_04_013: [When the t argument is NULL, then STRING_TOKENIZER_destroy shall not attempt to free] */ + TEST_FUNCTION(STRING_TOKENIZER_DESTROY_WITH_NULL_HANDLE_NO_FREE) + { + ///arrange + STRING_TOKENIZER_destroy(NULL); + ///assert + } + +END_TEST_SUITE(string_tokenizer_unittests) \ No newline at end of file diff --git a/c/sharedutil/tests/strings_unittests/CMakeLists.txt b/c/sharedutil/tests/strings_unittests/CMakeLists.txt new file mode 100644 index 00000000..900b9c0a --- /dev/null +++ b/c/sharedutil/tests/strings_unittests/CMakeLists.txt @@ -0,0 +1,21 @@ +#Copyright (c) Microsoft. All rights reserved. +#Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#this is CMakeLists.txt for strings_unittests +cmake_minimum_required(VERSION 3.0) + +compileAsC99() +set(theseTestsName strings_unittests) + +set(${theseTestsName}_cpp_files +${theseTestsName}.cpp +) + +set(${theseTestsName}_c_files +../../src/strings.c +) + +set(${theseTestsName}_h_files +) + +build_test_artifacts(${theseTestsName} ON) \ No newline at end of file diff --git a/c/sharedutil/tests/strings_unittests/main.c b/c/sharedutil/tests/strings_unittests/main.c new file mode 100644 index 00000000..04760f8b --- /dev/null +++ b/c/sharedutil/tests/strings_unittests/main.c @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include "testrunnerswitcher.h" + +int main(void) +{ + size_t failedTestCount = 0; + RUN_TEST_SUITE(strings_unittests, failedTestCount); + return (int)failedTestCount; +} diff --git a/c/sharedutil/tests/strings_unittests/strings_unittests.cpp b/c/sharedutil/tests/strings_unittests/strings_unittests.cpp new file mode 100644 index 00000000..ff05f92a --- /dev/null +++ b/c/sharedutil/tests/strings_unittests/strings_unittests.cpp @@ -0,0 +1,1091 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// +// PUT NO INCLUDES BEFORE HERE !!!! +// +#include +#ifdef _CRTDBG_MAP_ALLOC +#include +#endif + +#include + +// +// PUT NO CLIENT LIBRARY INCLUDES BEFORE HERE !!!! +// +#include "testrunnerswitcher.h" + +#include "micromock.h" +#include "micromockcharstararenullterminatedstrings.h" +#include "lock.h" + +#ifdef _MSC_VER +#pragma warning(disable:4505) +#endif + +#include "strings.h" + + +static const char TEST_STRING_VALUE []= "DataValueTest"; +static const char INITAL_STRING_VALUE []= "Initial_"; +static const char MULTIPLE_TEST_STRING_VALUE[] = "DataValueTestDataValueTest"; +static const char* COMBINED_STRING_VALUE = "Initial_DataValueTest"; +static const char* QUOTED_TEST_STRING_VALUE = "\"DataValueTest\""; +static const char* EMPTY_STRING = ""; + +#define NUMBER_OF_CHAR_TOCOPY 8 + +#define GBALLOC_H + +extern "C" int gballoc_init(void); +extern "C" void gballoc_deinit(void); +extern "C" void* gballoc_malloc(size_t size); +extern "C" void* gballoc_calloc(size_t nmemb, size_t size); +extern "C" void* gballoc_realloc(void* ptr, size_t size); +extern "C" void gballoc_free(void* ptr); + +namespace BASEIMPLEMENTATION +{ + /*if malloc is defined as gballoc_malloc at this moment, there'd be serious trouble*/ +#define Lock(x) (LOCK_OK + gballocState - gballocState) /*compiler warning about constant in if condition*/ +#define Unlock(x) (LOCK_OK + gballocState - gballocState) +#define Lock_Init() (LOCK_HANDLE)0x42 +#define Lock_Deinit(x) (LOCK_OK + gballocState - gballocState) +#include "gballoc.c" +#undef Lock +#undef Unlock +#undef Lock_Init +#undef Lock_Deinit + +}; + +static size_t currentmalloc_call; +static size_t whenShallmalloc_fail; + +TYPED_MOCK_CLASS(CSTRINGSMocks, CGlobalMock) +{ +public: + MOCK_STATIC_METHOD_1(, void*, gballoc_malloc, size_t, size) + void* result2; + currentmalloc_call++; + if (whenShallmalloc_fail > 0) + { + if (currentmalloc_call == whenShallmalloc_fail) + { + result2 = (STRING_HANDLE)NULL; + } + else + { + result2 = BASEIMPLEMENTATION::gballoc_malloc(size); + } + } + else + { + result2 = BASEIMPLEMENTATION::gballoc_malloc(size); + } + MOCK_METHOD_END(void*, result2); + + MOCK_STATIC_METHOD_2(, void*, gballoc_realloc, void*, ptr, size_t, size) + MOCK_METHOD_END(void*, BASEIMPLEMENTATION::gballoc_realloc(ptr, size)); + + MOCK_STATIC_METHOD_1(, void, gballoc_free, void*, ptr) + BASEIMPLEMENTATION::gballoc_free(ptr); + MOCK_VOID_METHOD_END() +}; + +DECLARE_GLOBAL_MOCK_METHOD_1(CSTRINGSMocks, , void*, gballoc_malloc, size_t, size); +DECLARE_GLOBAL_MOCK_METHOD_2(CSTRINGSMocks, , void*, gballoc_realloc, void*, ptr, size_t, size); +DECLARE_GLOBAL_MOCK_METHOD_1(CSTRINGSMocks, , void, gballoc_free, void*, ptr); + +static MICROMOCK_GLOBAL_SEMAPHORE_HANDLE g_dllByDll; +static MICROMOCK_MUTEX_HANDLE g_testByTest; + +static const struct JSONEncoding { + const char* source; + const char* expectedJSON; +} JSONtests[]= + { + { "", "\"\"" }, /*empty string*/ + { "a", "\"a\"" }, /*a => "a"*/ + { "aaslkdjhfalksjh", "\"aaslkdjhfalksjh\"" }, /*aaslkdjhfalksjh => "aaslkdjhfalksjh"*/ + { "\x01", "\"\\u0001\"" }, + { "\x1F", "\"\\u001F\"" }, + { "\x1F", "\"\\u001F\"" }, + { "\"", "\"\\\"\""}, + { "\\", "\"\\\\\"" }, + { "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F some text\"\\a/a", + "\"\\u0001\\u0002\\u0003\\u0004\\u0005\\u0006\\u0007\\u0008\\u0009\\u000A\\u000B\\u000C\\u000D\\u000E\\u000F\\u0010\\u0011\\u0012\\u0013\\u0014\\u0015\\u0016\\u0017\\u0018\\u0019\\u001A\\u001B\\u001C\\u001D\\u001E\\u001F some text\\\"\\\\a\\/a\"" }, + + }; + +BEGIN_TEST_SUITE(strings_unittests) + + TEST_SUITE_INITIALIZE(setsBufferTempSize) + { + INITIALIZE_MEMORY_DEBUG(g_dllByDll); + g_testByTest = MicroMockCreateMutex(); + ASSERT_IS_NOT_NULL(g_testByTest); + } + + TEST_SUITE_CLEANUP(TestClassCleanup) + { + MicroMockDestroyMutex(g_testByTest); + DEINITIALIZE_MEMORY_DEBUG(g_dllByDll); + } + + TEST_FUNCTION_INITIALIZE(a) + { + if (!MicroMockAcquireMutex(g_testByTest)) + { + ASSERT_FAIL("our mutex is ABANDONED. Failure in test framework"); + } + currentmalloc_call = 0; + whenShallmalloc_fail = 0; + + } + + TEST_FUNCTION_CLEANUP(cleans) + { + if (!MicroMockReleaseMutex(g_testByTest)) + { + ASSERT_FAIL("failure in test framework at ReleaseMutex"); + } + } + + /* STRING_Tests BEGIN */ + /* Tests_SRS_STRING_07_001: [STRING_new shall allocate a new STRING_HANDLE pointing to an empty string.] */ + TEST_FUNCTION(STRING_new_Succeed) + { + ///arrange + CSTRINGSMocks mocks; + STRING_HANDLE g_hString; + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(IGNORED_NUM_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(1)); + + ///act + g_hString = STRING_new(); + + ///assert + ASSERT_IS_NOT_NULL(g_hString); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + STRING_delete(g_hString); + } + + /* Tests_SRS_STRING_07_007: [STRING_new_with_memory shall return a NULL STRING_HANDLE if the supplied char* is empty.] */ + TEST_FUNCTION(STRING_new_With_Memory_NULL_Memory_Fail) + { + ///arrange + STRING_HANDLE g_hString; + + ///act + g_hString = STRING_new_with_memory(NULL); + + ///assert + ASSERT_IS_NULL(g_hString); + } + + /* Tests_SRS_STRING_07_006: [STRING_new_with_memory shall return a STRING_HANDLE by using the supplied char* memory.] */ + TEST_FUNCTION(STRING_new_With_Memory_Succeed) + { + ///arrange + CSTRINGSMocks mocks; + STRING_HANDLE g_hString; + size_t nLen = strlen(TEST_STRING_VALUE) + 1; + char* szTestString = (char*)malloc(nLen); + strncpy(szTestString, TEST_STRING_VALUE, nLen); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(IGNORED_NUM_ARG)) + .IgnoreArgument(1); + + ///act + g_hString = STRING_new_with_memory(szTestString); + + ///assert + ASSERT_ARE_EQUAL(char_ptr, TEST_STRING_VALUE, STRING_c_str(g_hString) ); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + STRING_delete(g_hString); + } + + /* Tests_SRS_STRING_07_003: [STRING_construct shall allocate a new string with the value of the specified const char*.] */ + TEST_FUNCTION(STRING_construct_Succeed) + { + ///arrange + CSTRINGSMocks mocks; + STRING_HANDLE g_hString; + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(IGNORED_NUM_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_STRING_VALUE) + 1)); + + ///act + g_hString = STRING_construct(TEST_STRING_VALUE); + + ///assert + ASSERT_ARE_EQUAL(char_ptr, TEST_STRING_VALUE, STRING_c_str(g_hString) ); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + STRING_delete(g_hString); + } + + /* Tests_SRS_STRING_07_005: [If the supplied const char* is NULL STRING_construct shall return a NULL value.] */ + TEST_FUNCTION(STRING_construct_With_NULL_HANDLE_Fail) + { + ///arrange + STRING_HANDLE g_hString; + + ///act + g_hString = STRING_construct(NULL); + + ///assert + ASSERT_IS_NULL(g_hString); + } + + /* Tests_SRS_STRING_07_008: [STRING_new_quoted shall return a valid STRING_HANDLE Copying the supplied const char* value surrounded by quotes.] */ + TEST_FUNCTION(STRING_new_quoted_Succeed) + { + ///arrange + CSTRINGSMocks mocks; + STRING_HANDLE g_hString; + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(IGNORED_NUM_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(2 + strlen(TEST_STRING_VALUE) + 1)); + + ///act + g_hString = STRING_new_quoted(TEST_STRING_VALUE); + + ///assert + ASSERT_ARE_EQUAL(char_ptr, QUOTED_TEST_STRING_VALUE, STRING_c_str(g_hString) ); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + STRING_delete(g_hString); + } + + /* Tests_SRS_STRING_07_009: [STRING_new_quoted shall return a NULL STRING_HANDLE if the supplied const char* is NULL.] */ + TEST_FUNCTION(STRING_new_quoted_NULL_Fail) + { + ///arrange + STRING_HANDLE g_hString; + + ///act + g_hString = STRING_new_quoted(NULL); + + ///assert + ASSERT_IS_NULL(g_hString); + } + + /* Tests_ */ + TEST_FUNCTION(STRING_Concat_Succeed) + { + ///arrange + CSTRINGSMocks mocks; + STRING_HANDLE g_hString; + g_hString = STRING_construct(INITAL_STRING_VALUE); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(IGNORED_PTR_ARG, strlen(INITAL_STRING_VALUE) + strlen(TEST_STRING_VALUE) + 1)) + .IgnoreArgument(1); + + ///act + int nResult = STRING_concat(g_hString, TEST_STRING_VALUE); + + ///assert + ASSERT_ARE_EQUAL(char_ptr, COMBINED_STRING_VALUE, STRING_c_str(g_hString) ); + ASSERT_ARE_EQUAL(int, nResult, 0); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + STRING_delete(g_hString); + } + + /* Tests_SRS_STRING_07_013: [STRING_concat shall return a nonzero number if the STRING_HANDLE and const char* is NULL.] */ + TEST_FUNCTION(STRING_Concat_HANDLE_NULL_Fail) + { + ///arrange + CSTRINGSMocks mocks; + STRING_HANDLE g_hString; + g_hString = STRING_construct(INITAL_STRING_VALUE); + mocks.ResetAllCalls(); + + ///act + int nResult = STRING_concat(NULL, TEST_STRING_VALUE); + + ///assert + ASSERT_ARE_NOT_EQUAL(int, nResult, 0); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + STRING_delete(g_hString); + + } + + /* Tests_SRS_STRING_07_013: [STRING_concat shall return a nonzero number if the STRING_HANDLE and const char* is NULL.] */ + TEST_FUNCTION(STRING_Concat_CharPtr_NULL_Fail) + { + ///arrange + CSTRINGSMocks mocks; + STRING_HANDLE g_hString; + g_hString = STRING_construct(INITAL_STRING_VALUE); + mocks.ResetAllCalls(); + + ///act + int nResult = STRING_concat(g_hString, NULL); + mocks.AssertActualAndExpectedCalls(); + + ///assert + ASSERT_ARE_NOT_EQUAL(int, nResult, 0); + + ///cleanup + STRING_delete(g_hString); + } + + /* Tests_SRS_STRING_07_013: [STRING_concat shall return a nonzero number if the STRING_HANDLE and const char* is NULL.] */ + TEST_FUNCTION(STRING_Concat_HANDLE_and_CharPtr_NULL_Fail) + { + ///arrange + CSTRINGSMocks mocks; + ///act + + int nResult = STRING_concat(NULL, TEST_STRING_VALUE); + + ///assert + ASSERT_ARE_NOT_EQUAL(int, nResult, 0); + + ///cleanup + } + + /* Tests_SRS_STRING_07_013: [STRING_concat shall return a nonzero number if the STRING_HANDLE and const char* is NULL.] */ + TEST_FUNCTION(STRING_Concat_Copy_Multiple_Succeed) + { + ///arrange + CSTRINGSMocks mocks; + STRING_HANDLE g_hString; + g_hString = STRING_new(); + STRING_copy(g_hString, TEST_STRING_VALUE); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(IGNORED_PTR_ARG, strlen(TEST_STRING_VALUE) + strlen(TEST_STRING_VALUE)+1)) + .IgnoreArgument(1) + .IgnoreArgument(2); + + ///act + STRING_concat(g_hString, TEST_STRING_VALUE); + + ///assert + ASSERT_ARE_EQUAL(char_ptr, MULTIPLE_TEST_STRING_VALUE, STRING_c_str(g_hString) ); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + STRING_delete(g_hString); + } + + /* Tests_SRS_STRING_07_034: [String_Concat_with_STRING shall concatenate a given STRING_HANDLE variable with a source STRING_HANDLE.] */ + TEST_FUNCTION(STRING_Concat_With_STRING_SUCCEED) + { + ///arrange + CSTRINGSMocks mocks; + STRING_HANDLE g_hString; + g_hString = STRING_construct(INITAL_STRING_VALUE); + STRING_HANDLE hAppend = STRING_construct(TEST_STRING_VALUE); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(IGNORED_PTR_ARG, strlen(INITAL_STRING_VALUE) + strlen(TEST_STRING_VALUE) + 1)) + .IgnoreArgument(1); + + ///act + int nResult = STRING_concat_with_STRING(g_hString, hAppend); + + ///assert + ASSERT_ARE_EQUAL(char_ptr, COMBINED_STRING_VALUE, STRING_c_str(g_hString) ); + ASSERT_ARE_EQUAL(int, nResult, 0); + mocks.AssertActualAndExpectedCalls(); + + // Clean up + STRING_delete(hAppend); + STRING_delete(g_hString); + } + + /* Tests_SRS_STRING_07_035: [String_Concat_with_STRING shall return a nonzero number if an error is encountered.] */ + TEST_FUNCTION(STRING_Concat_With_STRING_HANDLE_NULL_Fail) + { + ///arrange + CSTRINGSMocks mocks; + STRING_HANDLE hAppend = STRING_construct(TEST_STRING_VALUE); + mocks.ResetAllCalls(); + + ///act + int nResult = STRING_concat_with_STRING(NULL, hAppend); + + ///assert + ASSERT_ARE_NOT_EQUAL(int, nResult, 0); + mocks.AssertActualAndExpectedCalls(); + + // Clean up + STRING_delete(hAppend); + } + + /* Tests_SRS_STRING_07_035: [String_Concat_with_STRING shall return a nonzero number if an error is encountered.] */ + TEST_FUNCTION(STRING_Concat_With_STRING_Append_HANDLE_NULL_Fail) + { + ///arrange + CSTRINGSMocks mocks; + STRING_HANDLE g_hString; + g_hString = STRING_construct(INITAL_STRING_VALUE); + mocks.ResetAllCalls(); + + ///act + int nResult = STRING_concat_with_STRING(g_hString, NULL); + + ///assert + ASSERT_ARE_NOT_EQUAL(int, nResult, 0); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + STRING_delete(g_hString); + } + + /* Tests_SRS_STRING_07_035: [String_Concat_with_STRING shall return a nonzero number if an error is encountered.] */ + TEST_FUNCTION(STRING_Concat_With_STRING_All_HANDLE_NULL_Fail) + { + ///arrange + + ///act + int nResult = STRING_concat_with_STRING(NULL, NULL); + + ///assert + ASSERT_ARE_NOT_EQUAL(int, nResult, 0); + } + + /* Tests_SRS_STRING_07_016: [STRING_copy shall copy the const char* into the supplied STRING_HANDLE.] */ + TEST_FUNCTION(STRING_Copy_Succeed) + { + ///arrange + CSTRINGSMocks mocks; + STRING_HANDLE g_hString; + g_hString = STRING_construct(INITAL_STRING_VALUE); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(IGNORED_PTR_ARG, strlen(TEST_STRING_VALUE) + 1)) + .IgnoreArgument(1); + + ///act + int nResult = STRING_copy(g_hString, TEST_STRING_VALUE); + + ///assert + ASSERT_ARE_EQUAL(char_ptr, TEST_STRING_VALUE, STRING_c_str(g_hString) ); + ASSERT_ARE_EQUAL(int, nResult, 0); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + STRING_delete(g_hString); + } + + /* Tests_SRS_STRING_07_017: [STRING_copy shall return a nonzero value if any of the supplied parameters are NULL.] */ + TEST_FUNCTION(STRING_Copy_NULL_Fail) + { + ///arrange + CSTRINGSMocks mocks; + STRING_HANDLE g_hString; + g_hString = STRING_construct(INITAL_STRING_VALUE); + mocks.ResetAllCalls(); + + ///act + int nResult = STRING_copy(g_hString, NULL); + + ///assert + ASSERT_ARE_NOT_EQUAL(int, nResult, 0); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + STRING_delete(g_hString); + } + + /* Tests_SRS_STRING_07_018: [STRING_copy_n shall copy the number of characters defined in size_t.] */ + TEST_FUNCTION(STRING_Copy_n_Succeed) + { + ///arrange + CSTRINGSMocks mocks; + STRING_HANDLE g_hString; + g_hString = STRING_construct(INITAL_STRING_VALUE); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(IGNORED_PTR_ARG, NUMBER_OF_CHAR_TOCOPY + 1)) + .IgnoreArgument(1); + + ///act + int nResult = STRING_copy_n(g_hString, COMBINED_STRING_VALUE, NUMBER_OF_CHAR_TOCOPY); + + ///assert + ASSERT_ARE_EQUAL(char_ptr, INITAL_STRING_VALUE, STRING_c_str(g_hString) ); + ASSERT_ARE_EQUAL(int, nResult, 0); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + STRING_delete(g_hString); + } + + /* Tests_SRS_STRING_07_019: [STRING_copy_n shall return a nonzero value if STRING_HANDLE or const char* is NULL.] */ + TEST_FUNCTION(STRING_Copy_n_With_HANDLE_NULL_Fail) + { + ///arrange + + ///act + int nResult = STRING_copy_n(NULL, COMBINED_STRING_VALUE, NUMBER_OF_CHAR_TOCOPY); + + ///assert + ASSERT_ARE_NOT_EQUAL(int, nResult, 0); + } + + /* Tests_SRS_STRING_07_019: [STRING_copy_n shall return a nonzero value if STRING_HANDLE or const char* is NULL.] */ + TEST_FUNCTION(STRING_Copy_n_With_CONST_CHAR_NULL_Fail) + { + ///arrange + CSTRINGSMocks mocks; + STRING_HANDLE g_hString; + g_hString = STRING_construct(INITAL_STRING_VALUE); + mocks.ResetAllCalls(); + + ///act + int nResult = STRING_copy_n(g_hString, NULL, NUMBER_OF_CHAR_TOCOPY); + + ///assert + ASSERT_ARE_NOT_EQUAL(int, nResult, 0); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + STRING_delete(g_hString); + } + + /* Tests_SRS_STRING_07_018: [STRING_copy_n shall copy the number of characters defined in size_t.] */ + TEST_FUNCTION(STRING_Copy_n_With_Size_0_Succeed) + { + ///arrange + CSTRINGSMocks mocks; + STRING_HANDLE g_hString; + g_hString = STRING_construct(INITAL_STRING_VALUE); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(IGNORED_PTR_ARG, 1)) + .IgnoreArgument(1); + + ///act + int nResult = STRING_copy_n(g_hString, COMBINED_STRING_VALUE, 0); + + ///assert + ASSERT_ARE_EQUAL(char_ptr, EMPTY_STRING, STRING_c_str(g_hString) ); + ASSERT_ARE_EQUAL(int, nResult, 0); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + STRING_delete(g_hString); + } + + /* Tests_SRS_STRING_07_014: [STRING_quote shall "quote" the supplied STRING_HANDLE and return 0 on success.] */ + TEST_FUNCTION(STRING_quote_Succeed) + { + ///arrange + CSTRINGSMocks mocks; + STRING_HANDLE g_hString; + g_hString = STRING_construct(TEST_STRING_VALUE); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(IGNORED_PTR_ARG, 2 + strlen(TEST_STRING_VALUE) + 1)) + .IgnoreArgument(1); + + ///act + int nResult = STRING_quote(g_hString); + + ///assert + ASSERT_ARE_EQUAL(char_ptr, QUOTED_TEST_STRING_VALUE, STRING_c_str(g_hString) ); + ASSERT_ARE_EQUAL(int, nResult, 0); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + STRING_delete(g_hString); + } + + /* Tests_SRS_STRING_07_015: [STRING_quote shall return a nonzero value if any of the supplied parameters are NULL.] */ + TEST_FUNCTION(STRING_quote_NULL_HANDLE_Fail) + { + ///arrange + + ///act + int nResult = STRING_quote(NULL); + + ///assert + ASSERT_ARE_NOT_EQUAL(int, nResult, 0); + } + + /* Tests_SRS_STRING_07_021: [STRING_c_str shall return NULL if the STRING_HANDLE is NULL.] */ + TEST_FUNCTION(STRING_c_str_NULL_HANDLE_Fail) + { + ///arrange + + ///act + const char* s = STRING_c_str(NULL); + + ///assert + ASSERT_IS_NULL(s); + } + + /* Tests_SRS_STRING_07_020: [STRING_c_str shall return the const char* associated with the given STRING_HANDLE.] */ + TEST_FUNCTION(STRING_c_str_Success) + { + ///arrange + CSTRINGSMocks mocks; + STRING_HANDLE g_hString; + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(IGNORED_NUM_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(TEST_STRING_VALUE) + 1)); + + ///act + g_hString = STRING_construct(TEST_STRING_VALUE); + const char* s = STRING_c_str(g_hString); + + ///assert + ASSERT_ARE_EQUAL(char_ptr, s, TEST_STRING_VALUE); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + STRING_delete(g_hString); + } + + /* Tests_SRS_STRING_07_022: [STRING_empty shall revert the STRING_HANDLE to an empty state.] */ + TEST_FUNCTION(STRING_empty_Succeed) + { + ///arrange + CSTRINGSMocks mocks; + STRING_HANDLE g_hString; + g_hString = STRING_construct(TEST_STRING_VALUE); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, gballoc_realloc(IGNORED_PTR_ARG, 1)) + .IgnoreArgument(1); + + ///act + int nResult = STRING_empty(g_hString); + + ///assert + ASSERT_ARE_EQUAL(int, nResult, 0); + ASSERT_ARE_EQUAL(char_ptr, EMPTY_STRING, STRING_c_str(g_hString) ); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + STRING_delete(g_hString); + } + + /* Tests_SRS_STRING_07_023: [STRING_empty shall return a nonzero value if the STRING_HANDLE is NULL.] */ + TEST_FUNCTION(STRING_empty_NULL_HANDLE_Fail) + { + ///arrange + + ///act + int nResult = STRING_empty(NULL); + + ///assert + ASSERT_ARE_NOT_EQUAL(int, nResult, 0); + } + + /* Tests_SRS_STRING_07_011: [STRING_delete will not attempt to free anything with a NULL STRING_HANDLE.] */ + TEST_FUNCTION(STRING_delete_NULL_Succeed) + { + ///arrange + + ///act + STRING_delete(NULL); + + ///assert + // Just checking for exception here + } + + /* Tests_SRS_STRING_07_011: [STRING_delete will not attempt to free anything with a NULL STRING_HANDLE.] */ + TEST_FUNCTION(STRING_delete_Succeed) + { + ///arrange + CSTRINGSMocks mocks; + STRING_HANDLE g_hString; + g_hString = STRING_new(); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + + ///act + STRING_delete(g_hString); + + ///assert + mocks.AssertActualAndExpectedCalls(); + + + } + + TEST_FUNCTION(STRING_length_Succeed) + { + ///arrange + CSTRINGSMocks mocks; + STRING_HANDLE g_hString; + g_hString = STRING_construct(TEST_STRING_VALUE); + mocks.ResetAllCalls(); + + ///act + int nResult = STRING_length(g_hString); + + ///assert + ASSERT_ARE_EQUAL(int, nResult, strlen(TEST_STRING_VALUE) ); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + STRING_delete(g_hString); + } + + TEST_FUNCTION(STRING_length_NULL_HANDLE_Fail) + { + ///arrange + + ///act + int nResult = STRING_length(NULL); + + ///assert + ASSERT_ARE_EQUAL(int, nResult, 0); + } + + /*Tests_SRS_STRING_02_002: [If parameter handle is NULL then STRING_clone shall return NULL.]*/ + TEST_FUNCTION(STRING_clone_NULL_HANDLE_return_NULL) + { + ///arrange + + ///act + STRING_HANDLE result = STRING_clone(NULL); + + ///assert + ASSERT_IS_NULL( result); + } + + /*Tests_SRS_STRING_02_001: [STRING_clone shall produce a new string having the same content as the handle string.]*/ + TEST_FUNCTION(STRING_clone_succeeds) + { + ///arrange + CSTRINGSMocks mocks; + auto hSource = STRING_construct("aa"); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(IGNORED_NUM_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(sizeof("aa"))); + + ///act + auto result = STRING_clone(hSource); + + ///assert + ASSERT_ARE_NOT_EQUAL(void_ptr, NULL, result); + ASSERT_ARE_NOT_EQUAL(void_ptr, STRING_c_str(hSource), STRING_c_str(result)); + ASSERT_ARE_EQUAL (char_ptr, STRING_c_str(hSource), STRING_c_str(result)); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + STRING_delete(hSource); + STRING_delete(result); + } + + /*Codes_SRS_STRING_02_008: [If psz is NULL then STRING_construct_n shall return NULL*/ + TEST_FUNCTION(STRING_construct_n_with_NULL_argument_fails) + { + ///arrange + + ///act + auto result = STRING_construct_n(NULL, 3); + + ///assert + ASSERT_IS_NULL(result); + } + + /*Codes_SRS_STRING_02_009: [If n is bigger than the size of the string psz, then STRING_construct_n shall return NULL.] */ + TEST_FUNCTION(STRING_construct_n_with_too_big_size_fails) + { + ///arrange + + ///act + auto result = STRING_construct_n("a", 2); + + ///assert + ASSERT_IS_NULL(result); + } + + /*Codes_SRS_STRING_02_007: [STRING_construct_n shall construct a STRING_HANDLE from first "n" characters of the string pointed to by psz parameter.] */ + TEST_FUNCTION(STRING_construct_n_succeeds_with_2_char) + { + ///arrange + CSTRINGSMocks mocks; + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(IGNORED_NUM_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(3)) + .IgnoreArgument(1); + + ///act + auto result = STRING_construct_n("qq", 2); + + ///assert + ASSERT_IS_NOT_NULL(result); + ASSERT_ARE_EQUAL(char_ptr, "qq", STRING_c_str(result)); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + STRING_delete(result); + } + + /*Codes_SRS_STRING_02_007: [STRING_construct_n shall construct a STRING_HANDLE from first "n" characters of the string pointed to by psz parameter.] */ + TEST_FUNCTION(STRING_construct_n_succeeds_with_3_char_out_of_five) + { + ///arrange + CSTRINGSMocks mocks; + + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(IGNORED_NUM_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(4)) + .IgnoreArgument(1); + + ///act + auto result = STRING_construct_n("12345", 3); + + ///assert + ASSERT_IS_NOT_NULL(result); + ASSERT_ARE_EQUAL(char_ptr, "123", STRING_c_str(result)); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + STRING_delete(result); + } + + /* Tests_SRS_STRING_07_036: [If h1 is NULL and h2 is nonNULL then STRING_compare shall return 1.] */ + TEST_FUNCTION(STRING_compare_s1_NULL) + { + ///arrange + CSTRINGSMocks mocks; + auto h2 = STRING_construct("bb"); + mocks.ResetAllCalls(); + + ///act + auto result = STRING_compare(NULL, h2); + + ///assert + ASSERT_ARE_EQUAL(int, 1, result); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + STRING_delete(h2); + } + + /* Tests_SRS_STRING_07_037: [If h2 is NULL and h1 is nonNULL then STRING_compare shall return -1.] */ + TEST_FUNCTION(STRING_compare_s2_NULL) + { + ///arrange + CSTRINGSMocks mocks; + auto h1 = STRING_construct("aa"); + mocks.ResetAllCalls(); + + ///act + auto result = STRING_compare(h1, NULL); + + ///assert + ASSERT_ARE_EQUAL(int, -1, result); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + STRING_delete(h1); + } + + /* Codes_SRS_STRING_07_035: [If h1 and h2 are both NULL then STRING_compare shall return 0.] */ + TEST_FUNCTION(STRING_compare_s1_s2_NULL) + { + ///arrange + + ///act + auto result = STRING_compare(NULL, NULL); + + ///assert + ASSERT_ARE_EQUAL(int, 0, result); + + ///cleanup + } + + /* Tests_SRS_STRING_07_034: [STRING_compare returns an integer greater than, equal to, or less than zero, accordingly as the string pointed to by s1 is greater than, equal to, or less than the string s2.] */ + TEST_FUNCTION(STRING_compare_s1_first_SUCCEED) + { + ///arrange + CSTRINGSMocks mocks; + auto h1 = STRING_construct("aa"); + auto h2 = STRING_construct("bb"); + mocks.ResetAllCalls(); + + ///act + auto result = STRING_compare(h1, h2); + + ///assert + ASSERT_ARE_EQUAL(int, -1, result); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + STRING_delete(h1); + STRING_delete(h2); + } + + /* Tests_SRS_STRING_07_034: [STRING_compare returns an integer greater than, equal to, or less than zero, accordingly as the string pointed to by s1 is greater than, equal to, or less than the string s2.] */ + TEST_FUNCTION(STRING_compare_s2_first_SUCCEED) + { + ///arrange + CSTRINGSMocks mocks; + auto h1 = STRING_construct("aa"); + auto h2 = STRING_construct("bb"); + mocks.ResetAllCalls(); + + ///act + auto result = STRING_compare(h2, h1); + + ///assert + ASSERT_ARE_EQUAL(int, 1, result); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + STRING_delete(h1); + STRING_delete(h2); + } + + /* Tests_SRS_STRING_07_034: [STRING_compare returns an integer greater than, equal to, or less than zero, accordingly as the string pointed to by s1 is greater than, equal to, or less than the string s2.] */ + /* Tests_SRS_STRING_07_038: [STRING_compare shall compare the char s variable using the strcmp function.] */ + TEST_FUNCTION(STRING_compare_Equal_SUCCEED) + { + ///arrange + CSTRINGSMocks mocks; + auto h1 = STRING_construct("a1234"); + auto h2 = STRING_construct("a1234"); + mocks.ResetAllCalls(); + + ///act + auto result = STRING_compare(h1, h2); + + ///assert + ASSERT_ARE_EQUAL(int, 0, result); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + STRING_delete(h1); + STRING_delete(h2); + } + + /*Tests_SRS_STRING_02_011: [If source is NULL then STRING_new_JSON shall return NULL.] */ + TEST_FUNCTION(STRING_new_JSON_with_NULL_input_returns_NULL) + { + ///arrange + + ///act + auto result = STRING_new_JSON(NULL); + + ///assert + ASSERT_IS_NULL(result); + + ///cleanup + } + + /*Tests_SRS_STRING_02_012: [The string shall begin with the quote character.] */ + /*Tests_SRS_STRING_02_013: [The string shall copy the characters of source "as they are" (until the '\0' character) with the following exceptions:] */ + /*Tests_SRS_STRING_02_014: [If any character has the value outside [1...127] then STRING_new_JSON shall fail and return NULL.] */ + /*Tests_SRS_STRING_02_016: [If the character is " (quote) then it shall be repsented as \".] */ + /*Tests_SRS_STRING_02_017: [If the character is \ (backslash) then it shall represented as \\.]*/ + /*Tests_SRS_STRING_02_018: [If the character is / (slash) then it shall be represented as \/.] */ + /*Tests_SRS_STRING_02_019: [If the character code is less than 0x20 then it shall be represented as \\u00xx, where xx is the hex representation of the character code.]*/ + /*Tests_SRS_STRING_02_020: [The string shall end with " (quote).] */ + TEST_FUNCTION(STRING_new_JSON_succeeds) + { + for (size_t i = 0; i < sizeof(JSONtests) / sizeof(JSONtests[0]); i++) + { + ///arrange + CSTRINGSMocks mocks; + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(IGNORED_NUM_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen(JSONtests[i].expectedJSON) + 1)); + + ///act + auto result = STRING_new_JSON(JSONtests[i].source); + + ///assert + ASSERT_ARE_EQUAL(char_ptr, JSONtests[i].expectedJSON, STRING_c_str(result)); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + STRING_delete(result); + } + } + + /*Codes_SRS_STRING_02_021: [If the complete JSON representation cannot be produced, then STRING_new_JSON shall fail and return NULL.] */ + TEST_FUNCTION(STRING_new_JSON_when_gballoc_fails_it_fails_1) + { + ///arrange + CSTRINGSMocks mocks; + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(IGNORED_NUM_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + + whenShallmalloc_fail = 2; + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(strlen("ab") + 2+1)); + + ///act + auto result = STRING_new_JSON("ab"); + + ///assert + ASSERT_IS_NULL(result); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + } + + /*Codes_SRS_STRING_02_021: [If the complete JSON representation cannot be produced, then STRING_new_JSON shall fail and return NULL.] */ + TEST_FUNCTION(STRING_new_JSON_when_gballoc_fails_it_fails_2) + { + ///arrange + CSTRINGSMocks mocks; + whenShallmalloc_fail = 1; + STRICT_EXPECTED_CALL(mocks, gballoc_malloc(IGNORED_NUM_ARG)) + .IgnoreArgument(1); + + ///act + auto result = STRING_new_JSON("wwwa"); + + ///assert + ASSERT_IS_NULL(result); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + } + + /*Tests_SRS_STRING_02_014: [If any character has the value outside [1...127] then STRING_new_JSON shall fail and return NULL.] */ + TEST_FUNCTION(STRING_new_JSON_when_character_not_ASCII_fails) + { + ///arrange + CSTRINGSMocks mocks; + + ///act + auto result = STRING_new_JSON("a\xFF"); + + ///assert + ASSERT_IS_NULL(result); + mocks.ResetAllCalls(); /*not caring of any calls*/ + + ///cleanup + } + +END_TEST_SUITE(strings_unittests) \ No newline at end of file diff --git a/c/sharedutil/tests/urlencode_unittests/CMakeLists.txt b/c/sharedutil/tests/urlencode_unittests/CMakeLists.txt new file mode 100644 index 00000000..4920e7e1 --- /dev/null +++ b/c/sharedutil/tests/urlencode_unittests/CMakeLists.txt @@ -0,0 +1,25 @@ +#Copyright (c) Microsoft. All rights reserved. +#Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#this is CMakeLists.txt for urlencode_unittests +cmake_minimum_required(VERSION 3.0) + +compileAsC99() +set(theseTestsName urlencode_unittests) + +set(${theseTestsName}_cpp_files +${theseTestsName}.cpp +) + +set(${theseTestsName}_c_files +../../src/urlencode.c + +../../src/strings.c +../../src/gballoc.c +${LOCK_C_FILE} +) + +set(${theseTestsName}_h_files +) + +build_test_artifacts(${theseTestsName} ON) \ No newline at end of file diff --git a/c/sharedutil/tests/urlencode_unittests/main.c b/c/sharedutil/tests/urlencode_unittests/main.c new file mode 100644 index 00000000..64ce871f --- /dev/null +++ b/c/sharedutil/tests/urlencode_unittests/main.c @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include "testrunnerswitcher.h" + +int main(void) +{ + size_t failedTestCount = 0; + RUN_TEST_SUITE(URLEncode_UnitTests, failedTestCount); + return failedTestCount; +} diff --git a/c/sharedutil/tests/urlencode_unittests/urlencode_unittests.cpp b/c/sharedutil/tests/urlencode_unittests/urlencode_unittests.cpp new file mode 100644 index 00000000..f238bdd7 --- /dev/null +++ b/c/sharedutil/tests/urlencode_unittests/urlencode_unittests.cpp @@ -0,0 +1,552 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// +// PUT NO INCLUDES BEFORE HERE !!!! +// +#include +#ifdef _CRTDBG_MAP_ALLOC +#include +#endif +#include +// +// PUT NO CLIENT LIBRARY INCLUDES BEFORE HERE !!!! +// +#include "testrunnerswitcher.h" +#include "strings.h" +#include "urlencode.h" +#include "micromock.h" + + +#ifdef _MSC_VER +#pragma warning(disable:4505) +#endif + +static const struct +{ + const char* inputData; + const char* expectedOutput; +} testVector[] = +{ + { "\x01", "%01" }, + { "\x02", "%02" }, + { "\x03", "%03" }, + { "\x04", "%04" }, + { "\x05", "%05" }, + { "\x06", "%06" }, + { "\x07", "%07" }, + { "\x08", "%08" }, + { "\x09", "%09" }, + { "\x0a", "%0a" }, + { "\x0b", "%0b" }, + { "\x0c", "%0c" }, + { "\x0d", "%0d" }, + { "\x0e", "%0e" }, + { "\x0f", "%0f" }, + { "\x10", "%10" }, + { "\x11", "%11" }, + { "\x12", "%12" }, + { "\x13", "%13" }, + { "\x14", "%14" }, + { "\x15", "%15" }, + { "\x16", "%16" }, + { "\x17", "%17" }, + { "\x18", "%18" }, + { "\x19", "%19" }, + { "\x1a", "%1a" }, + { "\x1b", "%1b" }, + { "\x1c", "%1c" }, + { "\x1d", "%1d" }, + { "\x1e", "%1e" }, + { "\x1f", "%1f" }, + { "\x20", "%20" }, + { "\x21", "!" }, + { "\x22", "%22" }, + { "\x23", "%23" }, + { "\x24", "%24" }, + { "\x25", "%25" }, + { "\x26", "%26" }, + { "\x27", "%27" }, + { "\x28", "(" }, + { "\x29", ")" }, + { "\x2a", "*" }, + { "\x2b", "%2b" }, + { "\x2c", "%2c" }, + { "\x2d", "-" }, + { "\x2e", "." }, + { "\x2f", "%2f" }, + { "\x30", "0" }, + { "\x31", "1" }, + { "\x32", "2" }, + { "\x33", "3" }, + { "\x34", "4" }, + { "\x35", "5" }, + { "\x36", "6" }, + { "\x37", "7" }, + { "\x38", "8" }, + { "\x39", "9" }, + { "\x3a", "%3a" }, + { "\x3b", "%3b" }, + { "\x3c", "%3c" }, + { "\x3d", "%3d" }, + { "\x3e", "%3e" }, + { "\x3f", "%3f" }, + { "\x40", "%40" }, + { "\x41", "A" }, + { "\x42", "B" }, + { "\x43", "C" }, + { "\x44", "D" }, + { "\x45", "E" }, + { "\x46", "F" }, + { "\x47", "G" }, + { "\x48", "H" }, + { "\x49", "I" }, + { "\x4a", "J" }, + { "\x4b", "K" }, + { "\x4c", "L" }, + { "\x4d", "M" }, + { "\x4e", "N" }, + { "\x4f", "O" }, + { "\x50", "P" }, + { "\x51", "Q" }, + { "\x52", "R" }, + { "\x53", "S" }, + { "\x54", "T" }, + { "\x55", "U" }, + { "\x56", "V" }, + { "\x57", "W" }, + { "\x58", "X" }, + { "\x59", "Y" }, + { "\x5a", "Z" }, + { "\x5b", "%5b" }, + { "\x5c", "%5c" }, + { "\x5d", "%5d" }, + { "\x5e", "%5e" }, + { "\x5f", "_" }, + { "\x60", "%60" }, + { "\x61", "a" }, + { "\x62", "b" }, + { "\x63", "c" }, + { "\x64", "d" }, + { "\x65", "e" }, + { "\x66", "f" }, + { "\x67", "g" }, + { "\x68", "h" }, + { "\x69", "i" }, + { "\x6a", "j" }, + { "\x6b", "k" }, + { "\x6c", "l" }, + { "\x6d", "m" }, + { "\x6e", "n" }, + { "\x6f", "o" }, + { "\x70", "p" }, + { "\x71", "q" }, + { "\x72", "r" }, + { "\x73", "s" }, + { "\x74", "t" }, + { "\x75", "u" }, + { "\x76", "v" }, + { "\x77", "w" }, + { "\x78", "x" }, + { "\x79", "y" }, + { "\x7a", "z" }, + { "\x7b", "%7b" }, + { "\x7c", "%7c" }, + { "\x7d", "%7d" }, + { "\x7e", "%7e" }, + { "\x7f", "%7f" }, + { "\x80", "%c2%80" }, + { "\x81", "%c2%81" }, + { "\x82", "%c2%82" }, + { "\x83", "%c2%83" }, + { "\x84", "%c2%84" }, + { "\x85", "%c2%85" }, + { "\x86", "%c2%86" }, + { "\x87", "%c2%87" }, + { "\x88", "%c2%88" }, + { "\x89", "%c2%89" }, + { "\x8a", "%c2%8a" }, + { "\x8b", "%c2%8b" }, + { "\x8c", "%c2%8c" }, + { "\x8d", "%c2%8d" }, + { "\x8e", "%c2%8e" }, + { "\x8f", "%c2%8f" }, + { "\x90", "%c2%90" }, + { "\x91", "%c2%91" }, + { "\x92", "%c2%92" }, + { "\x93", "%c2%93" }, + { "\x94", "%c2%94" }, + { "\x95", "%c2%95" }, + { "\x96", "%c2%96" }, + { "\x97", "%c2%97" }, + { "\x98", "%c2%98" }, + { "\x99", "%c2%99" }, + { "\x9a", "%c2%9a" }, + { "\x9b", "%c2%9b" }, + { "\x9c", "%c2%9c" }, + { "\x9d", "%c2%9d" }, + { "\x9e", "%c2%9e" }, + { "\x9f", "%c2%9f" }, + { "\xa0", "%c2%a0" }, + { "\xa1", "%c2%a1" }, + { "\xa2", "%c2%a2" }, + { "\xa3", "%c2%a3" }, + { "\xa4", "%c2%a4" }, + { "\xa5", "%c2%a5" }, + { "\xa6", "%c2%a6" }, + { "\xa7", "%c2%a7" }, + { "\xa8", "%c2%a8" }, + { "\xa9", "%c2%a9" }, + { "\xaa", "%c2%aa" }, + { "\xab", "%c2%ab" }, + { "\xac", "%c2%ac" }, + { "\xad", "%c2%ad" }, + { "\xae", "%c2%ae" }, + { "\xaf", "%c2%af" }, + { "\xb0", "%c2%b0" }, + { "\xb1", "%c2%b1" }, + { "\xb2", "%c2%b2" }, + { "\xb3", "%c2%b3" }, + { "\xb4", "%c2%b4" }, + { "\xb5", "%c2%b5" }, + { "\xb6", "%c2%b6" }, + { "\xb7", "%c2%b7" }, + { "\xb8", "%c2%b8" }, + { "\xb9", "%c2%b9" }, + { "\xba", "%c2%ba" }, + { "\xbb", "%c2%bb" }, + { "\xbc", "%c2%bc" }, + { "\xbd", "%c2%bd" }, + { "\xbe", "%c2%be" }, + { "\xbf", "%c2%bf" }, + { "\xc0", "%c3%80" }, + { "\xc1", "%c3%81" }, + { "\xc2", "%c3%82" }, + { "\xc3", "%c3%83" }, + { "\xc4", "%c3%84" }, + { "\xc5", "%c3%85" }, + { "\xc6", "%c3%86" }, + { "\xc7", "%c3%87" }, + { "\xc8", "%c3%88" }, + { "\xc9", "%c3%89" }, + { "\xca", "%c3%8a" }, + { "\xcb", "%c3%8b" }, + { "\xcc", "%c3%8c" }, + { "\xcd", "%c3%8d" }, + { "\xce", "%c3%8e" }, + { "\xcf", "%c3%8f" }, + { "\xd0", "%c3%90" }, + { "\xd1", "%c3%91" }, + { "\xd2", "%c3%92" }, + { "\xd3", "%c3%93" }, + { "\xd4", "%c3%94" }, + { "\xd5", "%c3%95" }, + { "\xd6", "%c3%96" }, + { "\xd7", "%c3%97" }, + { "\xd8", "%c3%98" }, + { "\xd9", "%c3%99" }, + { "\xda", "%c3%9a" }, + { "\xdb", "%c3%9b" }, + { "\xdc", "%c3%9c" }, + { "\xdd", "%c3%9d" }, + { "\xde", "%c3%9e" }, + { "\xdf", "%c3%9f" }, + { "\xe0", "%c3%a0" }, + { "\xe1", "%c3%a1" }, + { "\xe2", "%c3%a2" }, + { "\xe3", "%c3%a3" }, + { "\xe4", "%c3%a4" }, + { "\xe5", "%c3%a5" }, + { "\xe6", "%c3%a6" }, + { "\xe7", "%c3%a7" }, + { "\xe8", "%c3%a8" }, + { "\xe9", "%c3%a9" }, + { "\xea", "%c3%aa" }, + { "\xeb", "%c3%ab" }, + { "\xec", "%c3%ac" }, + { "\xed", "%c3%ad" }, + { "\xee", "%c3%ae" }, + { "\xef", "%c3%af" }, + { "\xf0", "%c3%b0" }, + { "\xf1", "%c3%b1" }, + { "\xf2", "%c3%b2" }, + { "\xf3", "%c3%b3" }, + { "\xf4", "%c3%b4" }, + { "\xf5", "%c3%b5" }, + { "\xf6", "%c3%b6" }, + { "\xf7", "%c3%b7" }, + { "\xf8", "%c3%b8" }, + { "\xf9", "%c3%b9" }, + { "\xfa", "%c3%ba" }, + { "\xfb", "%c3%bb" }, + { "\xfc", "%c3%bc" }, + { "\xfd", "%c3%bd" }, + { "\xfe", "%c3%be" }, + { "\xff", "%c3%bf" } +}; + +const char* UNRESERVED_CHAR = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._"; + +static MICROMOCK_GLOBAL_SEMAPHORE_HANDLE g_dllByDll; + +BEGIN_TEST_SUITE(URLEncode_UnitTests) +TEST_SUITE_INITIALIZE(zzz) +{ + INITIALIZE_MEMORY_DEBUG(g_dllByDll); +} +TEST_SUITE_CLEANUP(TestClassCleanup) +{ + DEINITIALIZE_MEMORY_DEBUG(g_dllByDll); + +} + +TEST_FUNCTION(URL_EncodeString_is_null_should_yield_NULL) +{ + // arrange + // act + STRING_HANDLE encodedURL = URL_EncodeString(NULL); + + //assert + ASSERT_IS_NULL(encodedURL); +} + +/*Tests_SRS_URL_ENCODE_06_003: [If input is a zero length string then URL_Encode will return a zero length string.]*/ +TEST_FUNCTION(URL_EncodeString_new_should_yield_zeroLengthString) +{ + // arrange + const char* newString = ""; + + // act + STRING_HANDLE encodedURL = URL_EncodeString(newString); + + //assert + ASSERT_IS_NOT_NULL(encodedURL); + ASSERT_ARE_EQUAL(size_t, strlen(STRING_c_str(encodedURL)),0); + STRING_delete(encodedURL); +} + +TEST_FUNCTION(URL_EncodeString_is_hello_world) +{ + // arrange + const char* hello = "hello world"; + + // act + STRING_HANDLE encodedURL = URL_EncodeString(hello); + + //assert + ASSERT_IS_NOT_NULL(encodedURL); + ASSERT_ARE_EQUAL(char_ptr,"hello%20world", STRING_c_str(encodedURL) ); + STRING_delete(encodedURL); +} + +TEST_FUNCTION(URL_EncodeString_unreserved_mapping) +{ + // arrange + + // act + STRING_HANDLE encodedUnreservedURL = URL_EncodeString(UNRESERVED_CHAR); + + //assert + ASSERT_IS_NOT_NULL(encodedUnreservedURL); + ASSERT_ARE_EQUAL(char_ptr, UNRESERVED_CHAR, STRING_c_str(encodedUnreservedURL) ); + STRING_delete(encodedUnreservedURL); +} + +TEST_FUNCTION(URL_EncodeString_path_with_device) +{ + // arrange + const char* pathWithDevice = "/getalarm('Le Pichet')"; + + // act + STRING_HANDLE encodedPathWithDevice = URL_EncodeString(pathWithDevice); + + //assert + ASSERT_IS_NOT_NULL(encodedPathWithDevice); + ASSERT_ARE_EQUAL(char_ptr, "%2fgetalarm(%27Le%20Pichet%27)", STRING_c_str(encodedPathWithDevice)); + STRING_delete(encodedPathWithDevice); +} + +TEST_FUNCTION(URL_EncodeString_a_few_bogus_characters) +{ + // arrange + const char* bogusCharacters = "{}%"; + + // act + STRING_HANDLE encodedBogusCharacters = URL_EncodeString(bogusCharacters); + + //assert + ASSERT_IS_NOT_NULL(encodedBogusCharacters); + ASSERT_ARE_EQUAL(char_ptr, "%7b%7d%25", STRING_c_str(encodedBogusCharacters)); + STRING_delete(encodedBogusCharacters); +} + +TEST_FUNCTION(URL_EncodeString_full_url) +{ + // arrange + const char* fullUrl = "https://one.two.three.four-five.com/six/Seven('EightNine1234567890.Ten_Eleven')?twelve-thirteen=2015-11-31 HTTP/1.1"; + + // act + STRING_HANDLE encodedFullUrl = URL_EncodeString(fullUrl); + + //ASSERT + ASSERT_IS_NOT_NULL(encodedFullUrl); + ASSERT_ARE_EQUAL(char_ptr, "https%3a%2f%2fone.two.three.four-five.com%2fsix%2fSeven(%27EightNine1234567890.Ten_Eleven%27)%3ftwelve-thirteen%3d2015-11-31%20HTTP%2f1.1", STRING_c_str(encodedFullUrl)); + STRING_delete(encodedFullUrl); +} + +TEST_FUNCTION(URL_EncodeString_Exhaustive_chars) +{ + size_t i; + size_t numberOfTests = sizeof(testVector) / sizeof(testVector[i]); + for (i = 0; i < numberOfTests; i++) + { + //arrange + + const char* original = testVector[i].inputData; + + //act + STRING_HANDLE encodedOriginal = URL_EncodeString(original); + + //assert + ASSERT_IS_NOT_NULL(encodedOriginal); + ASSERT_ARE_EQUAL(char_ptr, testVector[i].expectedOutput, STRING_c_str(encodedOriginal)); + STRING_delete(encodedOriginal); + } +} + +/*Tests_SRS_URL_ENCODE_06_001: [If input is NULL then URL_Encode will return NULL.]*/ +TEST_FUNCTION(URL_is_null_should_yield_NULL) +{ + // arrange + // act + STRING_HANDLE encodedURL = URL_Encode(NULL); + + //assert + ASSERT_IS_NULL(encodedURL); +} +/*Tests_SRS_URL_ENCODE_06_003: [If input is a zero length string then URL_Encode will return a zero length string.]*/ +TEST_FUNCTION(URL_new_should_yield_zeroLengthString) +{ + // arrange + STRING_HANDLE newString = STRING_new(); + // act + STRING_HANDLE encodedURL = URL_Encode(newString); + + //assert + ASSERT_IS_NOT_NULL(encodedURL); + ASSERT_ARE_EQUAL(size_t, strlen(STRING_c_str(encodedURL)),0); + STRING_delete(newString); + STRING_delete(encodedURL); +} + +TEST_FUNCTION(URL_is_hello_world) +{ + // arrange + STRING_HANDLE hello = STRING_new(); + + ASSERT_ARE_EQUAL(int, STRING_concat(hello, "hello world"),0); + + // act + STRING_HANDLE encodedURL = URL_Encode(hello); + + + //assert + ASSERT_IS_NOT_NULL(encodedURL); + ASSERT_ARE_EQUAL(char_ptr,"hello%20world",STRING_c_str(encodedURL)); + STRING_delete(hello); + STRING_delete(encodedURL); +} + +TEST_FUNCTION(URL_unreserved_mapping) +{ + // arrange + STRING_HANDLE unreserved = STRING_new(); + + ASSERT_ARE_EQUAL(int, STRING_concat(unreserved, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._"), 0); + + // act + STRING_HANDLE encodedUnreservedURL = URL_Encode(unreserved); + + + //assert + ASSERT_IS_NOT_NULL(encodedUnreservedURL); + ASSERT_ARE_EQUAL(char_ptr, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._", STRING_c_str(encodedUnreservedURL)); + STRING_delete(unreserved); + STRING_delete(encodedUnreservedURL); +} + +TEST_FUNCTION(URL_path_with_device) +{ + // arrange + STRING_HANDLE pathWithDevice = STRING_new(); + + ASSERT_ARE_EQUAL(int, STRING_concat(pathWithDevice, "/getalarm('Le Pichet')"), 0); + + // act + STRING_HANDLE encodedPathWithDevice = URL_Encode(pathWithDevice); + + + //assert + ASSERT_IS_NOT_NULL(encodedPathWithDevice); + ASSERT_ARE_EQUAL(char_ptr, "%2fgetalarm(%27Le%20Pichet%27)", STRING_c_str(encodedPathWithDevice)); + STRING_delete(pathWithDevice); + STRING_delete(encodedPathWithDevice); +} + +TEST_FUNCTION(URL_a_few_bogus_characters) +{ + // arrange + STRING_HANDLE bogusCharacters = STRING_new(); + + ASSERT_ARE_EQUAL(int, STRING_concat(bogusCharacters, "{}%"), 0); + + // act + STRING_HANDLE encodedBogusCharacters = URL_Encode(bogusCharacters); + + + //assert + ASSERT_IS_NOT_NULL(encodedBogusCharacters); + ASSERT_ARE_EQUAL(char_ptr, "%7b%7d%25", STRING_c_str(encodedBogusCharacters)); + STRING_delete(bogusCharacters); + STRING_delete(encodedBogusCharacters); +} + +TEST_FUNCTION(URL_full_IOT_url) +{ + // arrange + STRING_HANDLE fullUrl = STRING_new(); + + ASSERT_ARE_EQUAL(int, STRING_concat(fullUrl, "https://one.two.three.four-five.com/six/Seven('EightNine1234567890.Ten_Eleven')?twelve-thirteen=2015-11-31 HTTP/1.1"), 0); + + // act + STRING_HANDLE encodedFullUrl = URL_Encode(fullUrl); + + //ASSERT + ASSERT_IS_NOT_NULL(encodedFullUrl); + ASSERT_ARE_EQUAL(char_ptr, "https%3a%2f%2fone.two.three.four-five.com%2fsix%2fSeven(%27EightNine1234567890.Ten_Eleven%27)%3ftwelve-thirteen%3d2015-11-31%20HTTP%2f1.1", STRING_c_str(encodedFullUrl)); + STRING_delete(fullUrl); + STRING_delete(encodedFullUrl); +} + +TEST_FUNCTION(URL_Exhaustive_chars) +{ + size_t i; + size_t numberOfTests = sizeof(testVector) / sizeof(testVector[i]); + for (i = 0; i < numberOfTests; i++) + { + //arrange + + STRING_HANDLE original = STRING_new(); + ASSERT_ARE_EQUAL(int, STRING_concat(original, testVector[i].inputData), 0); + + //act + STRING_HANDLE encodedOriginal = URL_Encode(original); + + //assert + ASSERT_IS_NOT_NULL(encodedOriginal); + ASSERT_ARE_EQUAL(char_ptr, testVector[i].expectedOutput, STRING_c_str(encodedOriginal)); + STRING_delete(original); + STRING_delete(encodedOriginal); + } +} +END_TEST_SUITE(URLEncode_UnitTests) diff --git a/c/sharedutil/tests/vector_unittests/CMakeLists.txt b/c/sharedutil/tests/vector_unittests/CMakeLists.txt new file mode 100644 index 00000000..2bd3e92b --- /dev/null +++ b/c/sharedutil/tests/vector_unittests/CMakeLists.txt @@ -0,0 +1,24 @@ +#Copyright (c) Microsoft. All rights reserved. +#Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#this is CMakeLists.txt for vector_unittests +cmake_minimum_required(VERSION 3.0) + +compileAsC99() +set(theseTestsName vector_unittests) + +set(${theseTestsName}_cpp_files +${theseTestsName}.cpp +) + +set(${theseTestsName}_c_files +../../src/vector.c + +../../src/gballoc.c +${LOCK_C_FILE} +) + +set(${theseTestsName}_h_files +) + +build_test_artifacts(${theseTestsName} ON) \ No newline at end of file diff --git a/c/sharedutil/tests/vector_unittests/main.c b/c/sharedutil/tests/vector_unittests/main.c new file mode 100644 index 00000000..1f65b2aa --- /dev/null +++ b/c/sharedutil/tests/vector_unittests/main.c @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include "testrunnerswitcher.h" + +int main(void) +{ + size_t failedTestCount = 0; + RUN_TEST_SUITE(Vector_UnitTests, failedTestCount); + return failedTestCount; +} diff --git a/c/sharedutil/tests/vector_unittests/vector_unittests.cpp b/c/sharedutil/tests/vector_unittests/vector_unittests.cpp new file mode 100644 index 00000000..507f3d2f --- /dev/null +++ b/c/sharedutil/tests/vector_unittests/vector_unittests.cpp @@ -0,0 +1,419 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include +#ifdef _CRTDBG_MAP_ALLOC +#include +#endif + +#include "testrunnerswitcher.h" +#include "micromock.h" + +#include "vector.h" + + +#ifdef _MSC_VER +#pragma warning(disable:4505) +#endif + +typedef struct VECTOR_UNITTEST_TAG +{ + size_t nValue1; + long lValue2; +} VECTOR_UNITTEST; + +static bool PredicateFunction(const VECTOR_UNITTEST* handle, const VECTOR_UNITTEST* otherHandle) +{ + return (handle->nValue1 == otherHandle->nValue1 && handle->lValue2 == otherHandle->lValue2); +} + +VECTOR_HANDLE g_handle; + +#define NUM_ITEM_PUSH_BACK 128 + +static MICROMOCK_GLOBAL_SEMAPHORE_HANDLE g_dllByDll; + +BEGIN_TEST_SUITE(Vector_UnitTests) + + TEST_SUITE_INITIALIZE(a) + { + INITIALIZE_MEMORY_DEBUG(g_dllByDll); + } + + TEST_SUITE_CLEANUP(TestClassCleanup) + { + DEINITIALIZE_MEMORY_DEBUG(g_dllByDll); + } + + TEST_FUNCTION_INITIALIZE(initialize) + { + g_handle = VECTOR_create(sizeof(VECTOR_UNITTEST)); + } + + TEST_FUNCTION_CLEANUP(cleans) + { + /// Clean Up + VECTOR_clear(g_handle); + VECTOR_destroy(g_handle); + } + + /* Vector_Tests BEGIN */ + TEST_FUNCTION(Vector_push_Back_with_NULL_Vector_fails) + { + ///arrange + VECTOR_UNITTEST vItem; + + ///act + int result = VECTOR_push_back(NULL, &vItem, 1); + + ///assert + ASSERT_ARE_NOT_EQUAL(int, 0, result); + } + + TEST_FUNCTION(Vector_push_Back_with_NULL_Element_fails) + { + ///arrange + + ///act + int result = VECTOR_push_back(g_handle, NULL, 1); + + ///assert + ASSERT_ARE_NOT_EQUAL(int, 0, result); + } + + TEST_FUNCTION(Vector_push_Back_with_Zero_numElement_fails) + { + ///arrange + VECTOR_UNITTEST sItem = {1, 2}; + + ///act + int result = VECTOR_push_back(g_handle, &sItem, 0); + + ///assert + ASSERT_ARE_NOT_EQUAL(int, 0, result); + } + + TEST_FUNCTION(Vector_push_Back_Success) + { + ///arrange + VECTOR_UNITTEST sItem = {1, 2}; + + ///act + int result = VECTOR_push_back(g_handle, &sItem, 1); + + ///assert + ASSERT_ARE_EQUAL(int, 0, result); + } + + TEST_FUNCTION(Vector_size_with_NULL_Vector_fails) + { + ///arrange + + ///act + size_t num = VECTOR_size(NULL); + + ///assert + ASSERT_ARE_EQUAL(int, 0, num); + } + + TEST_FUNCTION(Vector_size_Empty_Success) + { + ///arrange + + ///act + size_t num = VECTOR_size(g_handle); + + ///assert + ASSERT_ARE_EQUAL(int, 0, num); + } + + TEST_FUNCTION(Vector_size_Success) + { + ///arrange + VECTOR_UNITTEST sItem = {1, 2}; + + ///act + int result = VECTOR_push_back(g_handle, &sItem, 1); + size_t num = VECTOR_size(g_handle); + + ///assert + ASSERT_ARE_EQUAL(int, 0, result); + ASSERT_ARE_EQUAL(int, 1, num); + } + + TEST_FUNCTION(Vector_Vector_Find_If_NULL_Vector_Fail) + { + ///arrange + VECTOR_UNITTEST sItem = {1, 2}; + + ///act + VECTOR_UNITTEST* pfindItem = (VECTOR_UNITTEST*)VECTOR_find_if(NULL, (PREDICATE_FUNCTION)PredicateFunction, &sItem); + + ///assert + ASSERT_IS_NULL(pfindItem); + } + + TEST_FUNCTION(Vector_Vector_Find_If_NULL_Predicate_Func_Fail) + { + ///arrange + VECTOR_UNITTEST sItem = {1, 2}; + + ///act + VECTOR_UNITTEST* pfindItem = (VECTOR_UNITTEST*)VECTOR_find_if(g_handle, NULL, &sItem); + + ///assert + ASSERT_IS_NULL(pfindItem); + } + + TEST_FUNCTION(Vector_Vector_Find_If_NULL_value_Fail) + { + ///arrange + VECTOR_UNITTEST sItem = {1, 2}; + + (void)VECTOR_push_back(g_handle, &sItem, 1); + + ///act + VECTOR_UNITTEST* pfindItem = (VECTOR_UNITTEST*)VECTOR_find_if(g_handle, (PREDICATE_FUNCTION)PredicateFunction, NULL); + + ///assert + ASSERT_IS_NULL(pfindItem); + } + + TEST_FUNCTION(Vector_Vector_Find_If_Success) + { + ///arrange + VECTOR_UNITTEST sItem = {1, 2}; + + ///act + int result = VECTOR_push_back(g_handle, &sItem, 1); + + VECTOR_UNITTEST* pfindItem = (VECTOR_UNITTEST*)VECTOR_find_if(g_handle, (PREDICATE_FUNCTION)PredicateFunction, &sItem); + + ///assert + ASSERT_ARE_EQUAL(int, 0, result); + ASSERT_ARE_EQUAL(int, sItem.nValue1, pfindItem->nValue1); + ASSERT_ARE_EQUAL(int, sItem.lValue2, pfindItem->lValue2); + } + + TEST_FUNCTION(Vector_Clear_NULL_Vector_Fail) + { + ///arrange + + ///act + VECTOR_clear(NULL); + + ///assert + // Make sure this clear doesn't crash + } + + TEST_FUNCTION(Vector_Clear_Success) + { + ///arrange + VECTOR_UNITTEST sItem = {1, 2}; + + int result = VECTOR_push_back(g_handle, &sItem, 1); + result = VECTOR_push_back(g_handle, &sItem, 1); + + ///act + VECTOR_clear(g_handle); + + size_t num = VECTOR_size(g_handle); + + ///assert + ASSERT_ARE_EQUAL(int, 0, result); + ASSERT_ARE_EQUAL(int, 0, num); + } + + TEST_FUNCTION(Vector_Element_Success) + { + ///arrange + VECTOR_UNITTEST sItem1 = {1, 2}; + VECTOR_UNITTEST sItem2 = {3, 4}; + + (void)VECTOR_push_back(g_handle, &sItem1, 1); + (void)VECTOR_push_back(g_handle, &sItem2, 1); + + ///act + VECTOR_UNITTEST* pResult = (VECTOR_UNITTEST*)VECTOR_element(g_handle, 1); + + ///assert + ASSERT_IS_NOT_NULL(pResult); + ASSERT_ARE_EQUAL(int, sItem2.nValue1, pResult->nValue1); + ASSERT_ARE_EQUAL(int, sItem2.lValue2, pResult->lValue2); + } + + TEST_FUNCTION(Vector_Element_NULL_Vector_Fail) + { + ///arrange + + ///act + void* pResult = VECTOR_element(NULL, 1); + + ///assert + ASSERT_IS_NULL(pResult); + } + + TEST_FUNCTION(Vector_Element_Index_Larger_Than_Size_Fail) + { + ///arrange + VECTOR_UNITTEST sItem = {1, 2}; + + (void)VECTOR_push_back(g_handle, &sItem, 1); + (void)VECTOR_push_back(g_handle, &sItem, 1); + + size_t num = VECTOR_size(g_handle); + + ///act + VECTOR_UNITTEST* pResult = (VECTOR_UNITTEST*)VECTOR_element(g_handle, num+1); + + ///assert + ASSERT_IS_NULL(pResult); + } + + TEST_FUNCTION(Vector_Front_NULL_Vector_Fail) + { + ///arrange + + ///act + void* pResult = VECTOR_front(NULL); + + ///assert + ASSERT_IS_NULL(pResult); + } + + TEST_FUNCTION(Vector_Front_Success) + { + ///arrange + VECTOR_UNITTEST sItem1 = {1, 2}; + VECTOR_UNITTEST sItem2 = {3, 4}; + + (void)VECTOR_push_back(g_handle, &sItem1, 1); + (void)VECTOR_push_back(g_handle, &sItem2, 1); + + ///act + VECTOR_UNITTEST* pResult = (VECTOR_UNITTEST*)VECTOR_front(g_handle); + + ///assert + ASSERT_IS_NOT_NULL(pResult); + ASSERT_ARE_EQUAL(int, sItem1.nValue1, pResult->nValue1); + ASSERT_ARE_EQUAL(int, sItem1.lValue2, pResult->lValue2); + } + + TEST_FUNCTION(Vector_Back_Success) + { + ///arrange + VECTOR_UNITTEST sItem1 = {1, 2}; + VECTOR_UNITTEST sItem2 = {3, 4}; + VECTOR_UNITTEST sItem3 = {5, 6}; + + (void)VECTOR_push_back(g_handle, &sItem1, 1); + (void)VECTOR_push_back(g_handle, &sItem2, 1); + (void)VECTOR_push_back(g_handle, &sItem3, 1); + + ///act + VECTOR_UNITTEST* pResult = (VECTOR_UNITTEST*)VECTOR_back(g_handle); + + ///assert + ASSERT_IS_NOT_NULL(pResult); + ASSERT_ARE_EQUAL(int, sItem3.nValue1, pResult->nValue1); + ASSERT_ARE_EQUAL(int, sItem3.lValue2, pResult->lValue2); + } + + TEST_FUNCTION(Vector_Back_NULL_Vector_Fail) + { + ///arrange + + ///act + void* pResult = VECTOR_back(NULL); + + ///assert + ASSERT_IS_NULL(pResult); + } + + TEST_FUNCTION(Vector_erase_with_NULL_Vector_Fail) + { + ///arrange + VECTOR_UNITTEST vItem; + + ///act + VECTOR_erase(NULL, &vItem, 1); + + ///assert + // Make sure this erase doesn't crash + } + + TEST_FUNCTION(Vector_erase_with_NULL_Element_fails) + { + ///arrange + + ///act + VECTOR_erase(g_handle, NULL, 1); + + ///assert + // Make sure this erase doesn't crash + } + + TEST_FUNCTION(Vector_erase_with_NULL_NumElement_fails) + { + ///arrange + VECTOR_UNITTEST sItem; + + ///act + VECTOR_erase(g_handle, &sItem, 0); + + ///assert + // Make sure this erase doesn't crash + } + + TEST_FUNCTION(Vector_erase_Success) + { + ///arrange + VECTOR_UNITTEST sItem1 = {1, 2}; + VECTOR_UNITTEST sItem2 = {3, 4}; + + ///act + int result = VECTOR_push_back(g_handle, &sItem1, 1); + ASSERT_ARE_EQUAL(int, 0, result); + + result = VECTOR_push_back(g_handle, &sItem2, 1); + ASSERT_ARE_EQUAL(int, 0, result); + + VECTOR_UNITTEST* pfindItem = (VECTOR_UNITTEST*)VECTOR_find_if(g_handle, (PREDICATE_FUNCTION)PredicateFunction, &sItem1); + ASSERT_IS_NOT_NULL(pfindItem); + VECTOR_erase(g_handle, pfindItem, 1); + + pfindItem = (VECTOR_UNITTEST*)VECTOR_find_if(g_handle, (PREDICATE_FUNCTION)PredicateFunction, &sItem2); + ASSERT_IS_NOT_NULL(pfindItem); + VECTOR_erase(g_handle, pfindItem, 1); + + size_t num = VECTOR_size(g_handle); + + ///assert + ASSERT_ARE_EQUAL(int, 0, num); + } + + TEST_FUNCTION(Vector_Multiple_push_back_Success) + { + ///arrange + VECTOR_UNITTEST sItem1 = {1, 2}; + + ///act + for (size_t nIndex = 0; nIndex < NUM_ITEM_PUSH_BACK; nIndex++) + { + sItem1.nValue1++; + sItem1.lValue2++; + int result = VECTOR_push_back(g_handle, &sItem1, 1); + ASSERT_ARE_EQUAL(int, 0, result); + } + + VECTOR_UNITTEST* pResult = (VECTOR_UNITTEST*)VECTOR_back(g_handle); + + ///assert + ASSERT_IS_NOT_NULL(pResult); + ASSERT_ARE_EQUAL(int, sItem1.nValue1, pResult->nValue1); + ASSERT_ARE_EQUAL(int, sItem1.lValue2, pResult->lValue2); + } + + /* Vector_Tests END */ + +END_TEST_SUITE(Vector_UnitTests) diff --git a/c/sharedutil/testtools/CMakeLists.txt b/c/sharedutil/testtools/CMakeLists.txt new file mode 100644 index 00000000..e3fb1c08 --- /dev/null +++ b/c/sharedutil/testtools/CMakeLists.txt @@ -0,0 +1,3 @@ +#Copyright (c) Microsoft. All rights reserved. +#Licensed under the MIT license. See LICENSE file in the project root for full license information. + diff --git a/c/sharedutil/tools/macro_utils_h_generator/app.config b/c/sharedutil/tools/macro_utils_h_generator/app.config new file mode 100644 index 00000000..fad249e4 --- /dev/null +++ b/c/sharedutil/tools/macro_utils_h_generator/app.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/c/sharedutil/tools/macro_utils_h_generator/macro_utils.cs b/c/sharedutil/tools/macro_utils_h_generator/macro_utils.cs new file mode 100644 index 00000000..83724baa --- /dev/null +++ b/c/sharedutil/tools/macro_utils_h_generator/macro_utils.cs @@ -0,0 +1,1234 @@ +// ------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version: 14.0.0.0 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// ------------------------------------------------------------------------------ +namespace macro_utils_h_generator +{ + using System.Linq; + using System.Text; + using System.Collections.Generic; + using System; + + /// + /// Class to produce the template output + /// + + #line 1 "G:\Enlistment\azure-iot-suite-sdks\c\common\tools\macro_utils_h_generator\macro_utils.tt" + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "14.0.0.0")] + public partial class macro_utils : macro_utilsBase + { +#line hidden + /// + /// Create the template output + /// + public virtual string TransformText() + { + this.Write("// Copyright (c) Microsoft. All rights reserved.\r\n// Licensed under the MIT licen" + + "se. See LICENSE file in the project root for full license information.\r\n\r\n/*THIS" + + " FILE IS GENERATED*/\r\n/*DO NOT EDIT BY HAND!!!*/\r\n/*instead edit macro_utils.tt " + + "*/\r\n"); + + #line 13 "G:\Enlistment\azure-iot-suite-sdks\c\common\tools\macro_utils_h_generator\macro_utils.tt" +/*CHANGE BELOW 2 VARIABLES TO GET MORE / LESS */ + + #line default + #line hidden + + #line 14 "G:\Enlistment\azure-iot-suite-sdks\c\common\tools\macro_utils_h_generator\macro_utils.tt" +int nArithmetic=1024; + + #line default + #line hidden + + #line 15 "G:\Enlistment\azure-iot-suite-sdks\c\common\tools\macro_utils_h_generator\macro_utils.tt" +int nMacroParameters=124;/*127 parameters in one macro definition in C99 in chapter 5.2.4.1 Translation limits*/ + + #line default + #line hidden + this.Write("\r\n#ifndef MACRO_UTILS_H\r\n#define MACRO_UTILS_H\r\n\r\n#include \r\n\r\n#define " + + "TOSTRING_(x) #x\r\n#define TOSTRING(x) TOSTRING_(x)\r\n\r\n#define IFCOMMA(N) C2(IFCOM" + + "MA_, N)\r\n#define IFCOMMA_0\r\n#define IFCOMMA_2\r\n"); + + #line 28 "G:\Enlistment\azure-iot-suite-sdks\c\common\tools\macro_utils_h_generator\macro_utils.tt" +for(var i=4;i<=nMacroParameters;i+=2) + + #line default + #line hidden + + #line 29 "G:\Enlistment\azure-iot-suite-sdks\c\common\tools\macro_utils_h_generator\macro_utils.tt" +{ + + #line default + #line hidden + this.Write("#define IFCOMMA_"); + + #line 30 "G:\Enlistment\azure-iot-suite-sdks\c\common\tools\macro_utils_h_generator\macro_utils.tt" + this.Write(this.ToStringHelper.ToStringWithCulture(i)); + + #line default + #line hidden + this.Write(" ,\r\n"); + + #line 31 "G:\Enlistment\azure-iot-suite-sdks\c\common\tools\macro_utils_h_generator\macro_utils.tt" +} + + #line default + #line hidden + this.Write("\r\n#define IFCOMMA_NOFIRST(N) C2(IFCOMMA_NOFIRST, N)\r\n#define IFCOMMA_NOFIRST1 \r\n"); + + #line 35 "G:\Enlistment\azure-iot-suite-sdks\c\common\tools\macro_utils_h_generator\macro_utils.tt" +for(var i=2;i<=nMacroParameters;i++) + + #line default + #line hidden + + #line 36 "G:\Enlistment\azure-iot-suite-sdks\c\common\tools\macro_utils_h_generator\macro_utils.tt" +{ + + #line default + #line hidden + this.Write("#define IFCOMMA_NOFIRST"); + + #line 37 "G:\Enlistment\azure-iot-suite-sdks\c\common\tools\macro_utils_h_generator\macro_utils.tt" + this.Write(this.ToStringHelper.ToStringWithCulture(i)); + + #line default + #line hidden + this.Write(" ,\r\n"); + + #line 38 "G:\Enlistment\azure-iot-suite-sdks\c\common\tools\macro_utils_h_generator\macro_utils.tt" +} + + #line default + #line hidden + this.Write("\r\n#define DEC(x) C2(DEC,x)\r\n"); + + #line 41 "G:\Enlistment\azure-iot-suite-sdks\c\common\tools\macro_utils_h_generator\macro_utils.tt" +for(var i=nArithmetic;i>=1;i--) + + #line default + #line hidden + + #line 42 "G:\Enlistment\azure-iot-suite-sdks\c\common\tools\macro_utils_h_generator\macro_utils.tt" +{ + + #line default + #line hidden + this.Write("#define DEC"); + + #line 43 "G:\Enlistment\azure-iot-suite-sdks\c\common\tools\macro_utils_h_generator\macro_utils.tt" + this.Write(this.ToStringHelper.ToStringWithCulture(i)); + + #line default + #line hidden + this.Write(" "); + + #line 43 "G:\Enlistment\azure-iot-suite-sdks\c\common\tools\macro_utils_h_generator\macro_utils.tt" + this.Write(this.ToStringHelper.ToStringWithCulture(i-1)); + + #line default + #line hidden + this.Write("\r\n"); + + #line 44 "G:\Enlistment\azure-iot-suite-sdks\c\common\tools\macro_utils_h_generator\macro_utils.tt" +} + + #line default + #line hidden + this.Write("\r\n#define INC(x) C2(INC,x)\r\n"); + + #line 47 "G:\Enlistment\azure-iot-suite-sdks\c\common\tools\macro_utils_h_generator\macro_utils.tt" +for(var i=nArithmetic;i>=0;i--) + + #line default + #line hidden + + #line 48 "G:\Enlistment\azure-iot-suite-sdks\c\common\tools\macro_utils_h_generator\macro_utils.tt" +{ + + #line default + #line hidden + this.Write("#define INC"); + + #line 49 "G:\Enlistment\azure-iot-suite-sdks\c\common\tools\macro_utils_h_generator\macro_utils.tt" + this.Write(this.ToStringHelper.ToStringWithCulture(i)); + + #line default + #line hidden + this.Write(" "); + + #line 49 "G:\Enlistment\azure-iot-suite-sdks\c\common\tools\macro_utils_h_generator\macro_utils.tt" + this.Write(this.ToStringHelper.ToStringWithCulture(i+1)); + + #line default + #line hidden + this.Write("\r\n"); + + #line 50 "G:\Enlistment\azure-iot-suite-sdks\c\common\tools\macro_utils_h_generator\macro_utils.tt" +} + + #line default + #line hidden + this.Write("\r\n#define DIV2(x) C2(DIV2_,x)\r\n\r\n"); + + #line 54 "G:\Enlistment\azure-iot-suite-sdks\c\common\tools\macro_utils_h_generator\macro_utils.tt" +for(var i=nArithmetic;i>=0;i--) + + #line default + #line hidden + + #line 55 "G:\Enlistment\azure-iot-suite-sdks\c\common\tools\macro_utils_h_generator\macro_utils.tt" +{ + + #line default + #line hidden + this.Write("#define DIV2_"); + + #line 56 "G:\Enlistment\azure-iot-suite-sdks\c\common\tools\macro_utils_h_generator\macro_utils.tt" + this.Write(this.ToStringHelper.ToStringWithCulture(i)); + + #line default + #line hidden + this.Write(" "); + + #line 56 "G:\Enlistment\azure-iot-suite-sdks\c\common\tools\macro_utils_h_generator\macro_utils.tt" + this.Write(this.ToStringHelper.ToStringWithCulture(i/2)); + + #line default + #line hidden + this.Write("\r\n"); + + #line 57 "G:\Enlistment\azure-iot-suite-sdks\c\common\tools\macro_utils_h_generator\macro_utils.tt" +} + + #line default + #line hidden + this.Write("\r\n#define THE_NTH_ARG("); + + #line 59 "G:\Enlistment\azure-iot-suite-sdks\c\common\tools\macro_utils_h_generator\macro_utils.tt" +for(var i=1;i<=nMacroParameters;i++) + + #line default + #line hidden + + #line 60 "G:\Enlistment\azure-iot-suite-sdks\c\common\tools\macro_utils_h_generator\macro_utils.tt" +{ + + #line default + #line hidden + this.Write("P"); + + #line 60 "G:\Enlistment\azure-iot-suite-sdks\c\common\tools\macro_utils_h_generator\macro_utils.tt" + this.Write(this.ToStringHelper.ToStringWithCulture(i)); + + #line default + #line hidden + this.Write(", "); + + #line 60 "G:\Enlistment\azure-iot-suite-sdks\c\common\tools\macro_utils_h_generator\macro_utils.tt" +} + + #line default + #line hidden + this.Write(" ... ) P"); + + #line 60 "G:\Enlistment\azure-iot-suite-sdks\c\common\tools\macro_utils_h_generator\macro_utils.tt" + this.Write(this.ToStringHelper.ToStringWithCulture(nMacroParameters)); + + #line default + #line hidden + this.Write("\r\n\r\n#define _TRIGGER_PARENTHESIS_(...) ,\r\n\r\n#ifdef _MSC_VER\r\n#define LPAREN (\r\n#d" + + "efine COUNT_1_OR_MORE_ARG(...) THE_NTH_ARG LPAREN __VA_ARGS__, \\\r\n"); + + #line 67 "G:\Enlistment\azure-iot-suite-sdks\c\common\tools\macro_utils_h_generator\macro_utils.tt" +for(var i=nMacroParameters-1;i>=1;i--){ + + #line default + #line hidden + + #line 67 "G:\Enlistment\azure-iot-suite-sdks\c\common\tools\macro_utils_h_generator\macro_utils.tt" + this.Write(this.ToStringHelper.ToStringWithCulture(i.ToString()+((i>1)?", ":""))); + + #line default + #line hidden + + #line 67 "G:\Enlistment\azure-iot-suite-sdks\c\common\tools\macro_utils_h_generator\macro_utils.tt" +} + + #line default + #line hidden + this.Write(")\r\n#define MORE_THAN_1_ARG(...) THE_NTH_ARG LPAREN __VA_ARGS__, "); + + #line 68 "G:\Enlistment\azure-iot-suite-sdks\c\common\tools\macro_utils_h_generator\macro_utils.tt" +for(var i=nMacroParameters-2;i>=1;i--){ + + #line default + #line hidden + + #line 68 "G:\Enlistment\azure-iot-suite-sdks\c\common\tools\macro_utils_h_generator\macro_utils.tt" + this.Write(this.ToStringHelper.ToStringWithCulture(1)); + + #line default + #line hidden + this.Write(","); + + #line 68 "G:\Enlistment\azure-iot-suite-sdks\c\common\tools\macro_utils_h_generator\macro_utils.tt" +} + + #line default + #line hidden + this.Write("0)\r\n#else\r\n#define COUNT_1_OR_MORE_ARG(...) THE_NTH_ARG (__VA_ARGS__, \\\r\n"); + + #line 71 "G:\Enlistment\azure-iot-suite-sdks\c\common\tools\macro_utils_h_generator\macro_utils.tt" +for(var i=nMacroParameters-1;i>=1;i--){ + + #line default + #line hidden + + #line 71 "G:\Enlistment\azure-iot-suite-sdks\c\common\tools\macro_utils_h_generator\macro_utils.tt" + this.Write(this.ToStringHelper.ToStringWithCulture(i.ToString()+((i>1)?", ":""))); + + #line default + #line hidden + + #line 71 "G:\Enlistment\azure-iot-suite-sdks\c\common\tools\macro_utils_h_generator\macro_utils.tt" +} + + #line default + #line hidden + this.Write(")\r\n#define MORE_THAN_1_ARG(...) THE_NTH_ARG(__VA_ARGS__, "); + + #line 72 "G:\Enlistment\azure-iot-suite-sdks\c\common\tools\macro_utils_h_generator\macro_utils.tt" +for(var i=nMacroParameters-2;i>=1;i--){ + + #line default + #line hidden + + #line 72 "G:\Enlistment\azure-iot-suite-sdks\c\common\tools\macro_utils_h_generator\macro_utils.tt" + this.Write(this.ToStringHelper.ToStringWithCulture(1)); + + #line default + #line hidden + this.Write(","); + + #line 72 "G:\Enlistment\azure-iot-suite-sdks\c\common\tools\macro_utils_h_generator\macro_utils.tt" +} + + #line default + #line hidden + this.Write(@" 0) +#endif + +#define COUNT_ARG(...) C2(COUNT_ARG_, ISEMPTY(__VA_ARGS__))(__VA_ARGS__) +#define COUNT_ARG_1(...) 0 +#define COUNT_ARG_0(...) C1(COUNT_1_OR_MORE_ARG(__VA_ARGS__)) + +#define ISEMPTY(...) C3(DISPTACH_EMPTY_, MORE_THAN_1_ARG(_TRIGGER_PARENTHESIS_ __VA_ARGS__ ()), MORE_THAN_1_ARG(__VA_ARGS__)) +#define DISPTACH_EMPTY_10 1 +#define DISPTACH_EMPTY_00 0 +#define DISPTACH_EMPTY_11 0 + + +#define C2_(x,y) x##y + +#define C2(x,y) C2_(x,y) + +#define C3(x,y,z) C2(x, C2(y,z)) + +#define C4(x,y,z, u) C2(C2(x,y), C2(z,u)) + +#define C5(x,y,z,u, v) C2(C4(x,y, z, u), v) + +#define C1_(x) x + +#define C1(x) C1_(x) + +#define C2STRING(x,y) x y + +#define C3STRING(x,y,z) x y z + +#define C4STRING(x,y,z,u) x y z u + +#define C5STRING(x,y,z,u,v) x y z u v + + +"); + + #line 108 "G:\Enlistment\azure-iot-suite-sdks\c\common\tools\macro_utils_h_generator\macro_utils.tt" +for(var i=nMacroParameters;i>=2;i--) + + #line default + #line hidden + + #line 109 "G:\Enlistment\azure-iot-suite-sdks\c\common\tools\macro_utils_h_generator\macro_utils.tt" +{ + + #line default + #line hidden + this.Write("#define FOR_EACH_1_"); + + #line 110 "G:\Enlistment\azure-iot-suite-sdks\c\common\tools\macro_utils_h_generator\macro_utils.tt" + this.Write(this.ToStringHelper.ToStringWithCulture(i)); + + #line default + #line hidden + this.Write("(X, "); + + #line 110 "G:\Enlistment\azure-iot-suite-sdks\c\common\tools\macro_utils_h_generator\macro_utils.tt" +for(var j=1;j<=i;j++){ + + #line default + #line hidden + this.Write("P"); + + #line 110 "G:\Enlistment\azure-iot-suite-sdks\c\common\tools\macro_utils_h_generator\macro_utils.tt" + this.Write(this.ToStringHelper.ToStringWithCulture(j.ToString()+((j