Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: sht15_remote_monitoring f767zi_mqtt remote_monitoring simplesample_amqp ... more
Revision 4:233dd7616d73, committed 2015-10-22
- Comitter:
- AzureIoTClient
- Date:
- Thu Oct 22 18:33:28 2015 -0700
- Parent:
- 3:c0b3d028d117
- Child:
- 5:c08e3ffc68e4
- Commit message:
- v1.0.0-preview.4
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/agenttypesystem.c Thu Oct 22 18:33:28 2015 -0700
@@ -0,0 +1,3624 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+#include <stdlib.h>
+#ifdef _CRTDBG_MAP_ALLOC
+#include <crtdbg.h>
+#endif
+#include "gballoc.h"
+
+#include "agenttypesystem.h"
+
+#ifdef _MSC_VER
+#pragma warning(disable: 4756) /* Known warning for INFINITY */
+#endif
+
+#include <stddef.h>
+
+#include <float.h>
+#include <math.h>
+#include "crt_abstractions.h"
+
+#include "jsonencoder.h"
+#include "multitree.h"
+
+#include "agenttime.h"
+
+#include "iot_logging.h"
+
+#define NaN_STRING "NaN"
+#define MINUSINF_STRING "-INF"
+#define PLUSINF_STRING "INF"
+
+#ifndef _HUGE_ENUF
+#define _HUGE_ENUF 1e+300 /* _HUGE_ENUF*_HUGE_ENUF must overflow */
+#endif /* _HUGE_ENUF */
+
+#ifndef INFINITY
+#define INFINITY ((float)(_HUGE_ENUF * _HUGE_ENUF)) /* causes warning C4756: overflow in constant arithmetic (by design) */
+#endif /* INFINITY */
+
+#ifndef NAN
+#define NAN ((float)(INFINITY * 0.0F))
+#endif /* NAN */
+
+#define GUID_STRING_LENGHT 38
+
+DEFINE_ENUM_STRINGS(AGENT_DATA_TYPES_RESULT, AGENT_DATA_TYPES_RESULT_VALUES);
+
+static int ValidateDate(int year, int month, int day);
+
+static int NoCloneFunction(void** destination, const void* source)
+{
+ *destination = (void*)source;
+ return 0;
+}
+
+static void NoFreeFunction(void* value)
+{
+ (void)value;
+}
+
+
+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'
+};
+
+#define IS_DIGIT(a) (('0'<=(a)) &&((a)<='9'))
+
+/*creates an AGENT_DATA_TYPE containing a EDM_BOOLEAN from a int*/
+AGENT_DATA_TYPES_RESULT Create_EDM_BOOLEAN_from_int(AGENT_DATA_TYPE* agentData, int v)
+{
+ AGENT_DATA_TYPES_RESULT result;
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_013:[All the Create_... functions shall check their parameters for validity.When an invalid parameter is detected, a code of AGENT_DATA_TYPES_INVALID_ARG shall be returned]*/
+ if(agentData==NULL)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_031:[ Creates a AGENT_DATA_TYPE representing an EDM_BOOLEAN.]*/
+ agentData->type = EDM_BOOLEAN_TYPE;
+ agentData->value.edmBoolean.value = (v)?(EDM_TRUE):(EDM_FALSE);
+ result = AGENT_DATA_TYPES_OK;
+ }
+ return result;
+}
+
+/*creates an AGENT_DATA_TYPE containing a UINT8*/
+AGENT_DATA_TYPES_RESULT Create_AGENT_DATA_TYPE_from_UINT8(AGENT_DATA_TYPE* agentData, uint8_t v)
+{
+ AGENT_DATA_TYPES_RESULT result;
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_013:[ All the Create_... functions shall check their parameters for validity. When an invalid parameter is detected, a code of AGENT_DATA_TYPES_INVALID_ARG shall be returned ].*/
+ if (agentData == NULL)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ agentData->type = EDM_BYTE_TYPE;
+ agentData->value.edmByte.value = v;
+ result = AGENT_DATA_TYPES_OK;
+ }
+ return result;
+}
+
+/*Codes_SRS_AGENT_TYPE_SYSTEM_99_091:[Creates an AGENT_DATA_TYPE containing an Edm.DateTimeOffset from an EDM_DATE_TIME_OFFSET.]*/
+AGENT_DATA_TYPES_RESULT Create_AGENT_DATA_TYPE_from_EDM_DATE_TIME_OFFSET(AGENT_DATA_TYPE* agentData, EDM_DATE_TIME_OFFSET v)
+{
+ AGENT_DATA_TYPES_RESULT result;
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_013:[ All the Create_... functions shall check their parameters for validity. When an invalid parameter is detected, a code of AGENT_DATA_TYPES_INVALID_ARG shall be returned ]*/
+ if (agentData == NULL)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ }
+ else if (ValidateDate(v.dateTime.tm_year+1900, v.dateTime.tm_mon +1 , v.dateTime.tm_mday) != 0)
+ {
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_092:[ The structure shall be validated to be conforming to OData specifications (odata-abnf-construction-rules, 2013), and if found invalid, AGENT_DATA_TYPES_INVALID_ARG shall be returned.]*/
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ }
+ else if (
+ (v.dateTime.tm_hour > 23) ||
+ (v.dateTime.tm_hour < 0) ||
+ (v.dateTime.tm_min > 59) ||
+ (v.dateTime.tm_min < 0) ||
+ (v.dateTime.tm_sec > 59) ||
+ (v.dateTime.tm_sec < 0)
+ )
+ {
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_092:[ The structure shall be validated, and if found invalid, AGENT_DATA_TYPES_INVALID_ARG shall be returned.]*/
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ }
+ else if ((v.hasFractionalSecond) && (v.fractionalSecond > 999999999999))
+ {
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_092:[ The structure shall be validated to be conforming to OData specifications (odata-abnf-construction-rules, 2013), and if found invalid, AGENT_DATA_TYPES_INVALID_ARG shall be returned.]*/
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ }
+ else if (
+ (v.hasTimeZone) &&
+ (
+ (v.timeZoneHour<-23) ||
+ (v.timeZoneHour>23) ||
+ (v.timeZoneMinute>59)
+ )
+ )
+ {
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_092:[ The structure shall be validated to be conforming to OData specifications (odata-abnf-construction-rules, 2013), and if found invalid, AGENT_DATA_TYPES_INVALID_ARG shall be returned.]*/
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ }
+ else
+ {
+ agentData->type = EDM_DATE_TIME_OFFSET_TYPE;
+ agentData->value.edmDateTimeOffset = v;
+ result = AGENT_DATA_TYPES_OK;
+ }
+ return result;
+}
+
+/*Codes_SRS_AGENT_TYPE_SYSTEM_99_094:[ Creates and AGENT_DATA_TYPE containing a EDM_GUID from an EDM_GUID]*/
+AGENT_DATA_TYPES_RESULT Create_AGENT_DATA_TYPE_from_EDM_GUID(AGENT_DATA_TYPE* agentData, EDM_GUID v)
+{
+ AGENT_DATA_TYPES_RESULT result;
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_013:[ All the functions shall check their parameters for validity. When an invalid parameter is detected, the value AGENT_DATA_TYPES_INVALID_ARG shall be returned ].*/
+ if (agentData == NULL)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ LogError("result = %s \r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_094:[ Creates and AGENT_DATA_TYPE containing a EDM_GUID from an EDM_GUID]*/
+ agentData->type = EDM_GUID_TYPE;
+ memmove(agentData->value.edmGuid.GUID, v.GUID, 16);
+ result = AGENT_DATA_TYPES_OK;
+ }
+ return result;
+}
+
+/*Codes_SRS_AGENT_TYPE_SYSTEM_99_098:[ Creates an AGENT_DATA_TYPE containing a EDM_BINARY from a EDM_BINARY.]*/
+AGENT_DATA_TYPES_RESULT Create_AGENT_DATA_TYPE_from_EDM_BINARY(AGENT_DATA_TYPE* agentData, EDM_BINARY v)
+{
+ AGENT_DATA_TYPES_RESULT result;
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_013:[ All the functions shall check their parameters for validity. When an invalid parameter is detected, the value AGENT_DATA_TYPES_INVALID_ARG shall be returned ].*/
+ if (agentData == NULL)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ LogError("result = %s\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_098:[ Creates an AGENT_DATA_TYPE containing a EDM_BINARY from a EDM_BINARY.]*/
+ if (v.data == NULL)
+ {
+ if (v.size != 0)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ LogError("result = %s \r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ agentData->type = EDM_BINARY_TYPE;
+ agentData->value.edmBinary.size = 0;
+ agentData->value.edmBinary.data = NULL;
+ result = AGENT_DATA_TYPES_OK;
+ }
+ }
+ else
+ {
+ if (v.size != 0)
+ {
+ /*make a copy*/
+ if ((agentData->value.edmBinary.data = (unsigned char*)malloc(v.size)) == NULL)
+ {
+ result = AGENT_DATA_TYPES_ERROR;
+ LogError("result = %s\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ memcpy(agentData->value.edmBinary.data, v.data, v.size);
+ agentData->type = EDM_BINARY_TYPE;
+ agentData->value.edmBinary.size = v.size;
+ result = AGENT_DATA_TYPES_OK;
+ }
+ }
+ else
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ LogError("result = %s\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ }
+ }
+ return result;
+}
+
+/*scans sign, if any*/
+/*if no sign, then it will set *sign to = +1*/
+/*if sign, then it will set *sign to = +/-1*/
+static void scanOptionalSign(const char* source, size_t sourceSize, size_t* position, int* sign)
+{
+ if (*position < sourceSize)
+ {
+ if (source[*position] == '-')
+ {
+
+ *sign = -1;
+ (*position)++;
+ }
+ else if (source[*position] == '+')
+ {
+ *sign = +1;
+ (*position)++;
+ }
+ else
+ {
+ *sign = +1;
+ }
+ }
+}
+
+/*scans a minus sign, if any*/
+/*if no sign, then it will set *sign to = +1*/
+/*if sign, then it will set *sign to = +/-1*/
+static void scanOptionalMinusSign(const char* source, size_t sourceSize, size_t* position, int* sign)
+{
+ if (*position < sourceSize)
+ {
+ if (source[*position] == '-')
+ {
+
+ *sign = -1;
+ (*position)++;
+ }
+ else
+ {
+ *sign = +1;
+ }
+ }
+}
+
+/*this function alawys returns 0 if it processed 1 digit*/
+/*return 1 when error (such as wrong parameters)*/
+static int scanMandatoryOneDigit(const char* source, size_t sourceSize, size_t* position)
+{
+ int result;
+ if (*position < sourceSize)
+ {
+ if (IS_DIGIT(source[*position]))
+ {
+ (*position)++;
+ result = 0;
+ }
+ else
+ {
+ result = 1;
+ }
+ }
+ else
+ {
+ result = 1;
+ }
+ return result;
+}
+
+/*scans digits, if any*/
+static void scanOptionalNDigits(const char* source, size_t sourceSize, size_t* position)
+{
+ while (*position < sourceSize)
+ {
+ if (IS_DIGIT(source[*position]))
+ {
+ (*position)++;
+ }
+ else
+ {
+ break;
+ }
+ }
+}
+
+/*from the string pointed to by source, having the size sourceSize, starting at initial position *position*/
+/*this function will attempt to read a decimal number having an optional sign(+/-) followed by precisely N digits */
+/*will return 0 if in the string there was a number and that number has been read in the *value parameter*/
+/*will update position parameter to reflect the first character not belonging to the number*/
+static int scanAndReadNDigitsInt(const char* source, size_t sourceSize, size_t* position, int *value, size_t N)
+{
+ N++;
+ *value = 0;
+ while ((*position < sourceSize) &&
+ (N > 0))
+ {
+ if (IS_DIGIT(source[*position]))
+ {
+ *value *= 10;
+ *value += (source[*position] - '0');
+ (*position)++;
+ }
+ else
+ {
+ break;
+ }
+
+ N--;
+ }
+
+ return N != 1;
+}
+
+/*this function alawys returns 0 if it found a dot followed by at least digit*/
+/*return 1 when error (such as wrong parameters)*/
+static int scanOptionalDotAndDigits(const char* source, size_t sourceSize, size_t* position)
+{
+ int result = 0;
+ if (*position < sourceSize)
+ {
+ if (source[*position] == '.')
+ {
+ (*position)++;
+ if (scanMandatoryOneDigit(source, sourceSize, position) != 0)
+ {
+ /* not a digit following the dot... */
+ result = 1;
+ }
+ else
+ {
+ scanOptionalNDigits(source, sourceSize, position);
+ }
+ }
+ else
+ {
+ /*not a dot, don't care*/
+ }
+ }
+ return result;
+}
+
+
+static int scanMandatory1CapitalHexDigit(const char* source, uint8_t* value)
+{
+ int result = 0;
+ if (('0' <= source[0]) && (source[0] <= '9'))
+ {
+ *value = (source[0] - '0');
+ }
+ else if (('A' <= source[0]) && (source[0] <= 'F'))
+ {
+ *value = (source[0] - 'A'+10);
+ }
+ else
+ {
+ result = 1;
+ }
+ return result;
+}
+
+/*this function alawys returns 0 if it found 2 hex digits, also updates the *value parameter*/
+/*return 1 when error (such as wrong parameters)*/
+static int scanMandatory2CapitalHexDigits(const char* source, uint8_t* value)
+{
+ int result;
+ uint8_t temp;
+ if (scanMandatory1CapitalHexDigit(source, &temp) == 0)
+ {
+ *value = temp*16;
+ if (scanMandatory1CapitalHexDigit(source + 1, &temp) == 0)
+ {
+ *value += temp;
+ result = 0;
+ }
+ else
+ {
+ result = 1;
+ }
+ }
+ else
+ {
+ result = 2;
+ }
+
+ return result;
+}
+
+static int ValidateDecimal(const char* v, size_t vlen)
+{
+ int result;
+ int sign = 0;
+ size_t validatePosition = 0;
+ scanOptionalSign(v, vlen, &validatePosition, &sign);
+ if (scanMandatoryOneDigit(v, vlen, &validatePosition) != 0)
+ {
+ result = 1;
+ }
+ else
+ {
+ scanOptionalNDigits(v, vlen, &validatePosition);
+ if (scanOptionalDotAndDigits(v, vlen, &validatePosition) != 0)
+ {
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_067:[ If the string indicated by the parameter v does not match exactly an ODATA string representation, AGENT_DATA_TYPES_INVALID_ARG shall be returned.]*/
+ result = 1;
+ }
+ else if (validatePosition != vlen) /*Trailing wrong characters*/
+ {
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_067:[ If the string indicated by the parameter v does not match exactly an ODATA string representation, AGENT_DATA_TYPES_INVALID_ARG shall be returned.]*/
+ result = 1;
+ }
+ else
+ {
+ result = 0;
+ }
+ }
+
+ return result;
+}
+
+/*return 0 if everything went ok*/
+/*takes 1 base64char and returns its value*/
+static int base64toValue(char base64charSource, unsigned char* value)
+{
+ int result;
+ if (('A' <= base64charSource) && (base64charSource <= 'Z'))
+ {
+ *value = base64charSource - 'A';
+ result = 0;
+ }
+ else if (('a' <= base64charSource) && (base64charSource <= 'z'))
+ {
+ *value = ('Z' - 'A') +1+ (base64charSource - 'a');
+ result = 0;
+ }
+ else if (('0' <= base64charSource) && (base64charSource <= '9'))
+ {
+ *value = ('Z' - 'A') +1+('z'-'a')+1 +(base64charSource - '0');
+ result = 0;
+ }
+ else if ('-' == base64charSource)
+ {
+ *value = 62;
+ result = 0;
+ }
+ else if ('_' == base64charSource)
+ {
+ *value = 63;
+ result = 0;
+ }
+ else
+ {
+ result = 1;
+ }
+ return result;
+}
+
+/*returns 0 if everything went ok*/
+/*scans 4 base64 characters and returns 3 usual bytes*/
+static int scan4base64char(const char* source, size_t sourceSize, unsigned char *destination0, unsigned char* destination1, unsigned char* destination2)
+{
+ int result;
+ if (sourceSize < 4)
+ {
+ result = 1;
+ }
+ else
+ {
+ unsigned char b0, b1, b2, b3;
+ if (
+ (base64toValue(source[0], &b0) == 0) &&
+ (base64toValue(source[1], &b1) == 0) &&
+ (base64toValue(source[2], &b2) == 0) &&
+ (base64toValue(source[3], &b3) == 0)
+ )
+ {
+ *destination0 = (b0 << 2) | ((b1 & 0x30) >> 4);
+ *destination1 = ((b1 & 0x0F)<<4) | ((b2 & 0x3C) >>2 );
+ *destination2 = ((b2 & 0x03) << 6) | (b3);
+ result = 0;
+ }
+ else
+ {
+ result = 2;
+ }
+ }
+ return result;
+}
+
+/*return 0 if the character is one of ( 'A' / 'E' / 'I' / 'M' / 'Q' / 'U' / 'Y' / 'c' / 'g' / 'k' / 'o' / 's' / 'w' / '0' / '4' / '8' )*/
+static int base64b16toValue(unsigned char source, unsigned char* destination)
+{
+ unsigned char i;
+ for (i = 0; i <= 15; i++)
+ {
+ if (base64b16[i] == source)
+ {
+ *destination = i;
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/*return 0 if the character is one of ( 'A' / 'Q' / 'g' / 'w' )*/
+static int base64b8toValue(unsigned char source, unsigned char* destination)
+{
+ unsigned char i;
+ for (i = 0; i <= 3; i++)
+ {
+ if (base64b8[i] == source)
+ {
+ *destination = i;
+ return 0;
+ }
+ }
+ return 1;
+}
+
+
+/*returns 0 if everything went ok*/
+/*scans 2 base64 characters + 1 special + 1 optional = and returns 2 usual bytes*/
+int scanbase64b16(const char* source, size_t sourceSize, size_t *consumed, unsigned char* destination0, unsigned char* destination1)
+{
+ int result;
+ if (sourceSize < 3)
+ {
+ result = 1;
+ }
+ else
+ {
+ unsigned char c0, c1, c2;
+ *consumed = 0;
+ if (
+ (base64toValue(source[0], &c0) == 0) &&
+ (base64toValue(source[1], &c1) == 0) &&
+ (base64b16toValue(source[2], &c2) == 0)
+ )
+ {
+ *consumed = 3 + ((sourceSize>=3)&&(source[3] == '=')); /*== produce 1 or 0 ( in C )*/
+ *destination0 = (c0 << 2) | ((c1 & 0x30) >> 4);
+ *destination1 = ((c1 &0x0F) <<4) | c2;
+ result = 0;
+ }
+ else
+ {
+ result = 2;
+ }
+ }
+ return result;
+}
+
+/*return 0 if everything is ok*/
+/*Reads base64b8 = base64char ( 'A' / 'Q' / 'g' / 'w' ) [ "==" ]*/
+int scanbase64b8(const char* source, size_t sourceSize, size_t *consumed, unsigned char* destination0)
+{
+ int result;
+ if (sourceSize < 2)
+ {
+ result = 1;
+ }
+ else
+ {
+ unsigned char c0, c1;
+ if (
+ (base64toValue(source[0], &c0) == 0) &&
+ (base64b8toValue(source[1], &c1) == 0)
+ )
+ {
+ *consumed = 2 + (((sourceSize>=4) && (source[2] == '=') && (source[3] == '='))?2:0); /*== produce 1 or 0 ( in C )*/
+ *destination0 = (c0 << 2) | (c1 & 3);
+ result = 0;
+ }
+ else
+ {
+ result = 2;
+ }
+ }
+ return result;
+}
+
+/*Codes_SRS_AGENT_TYPE_SYSTEM_99_039:[ Creates an AGENT_DATA_TYPE containing an EDM_DECIMAL from a null-terminated string.]*/
+AGENT_DATA_TYPES_RESULT Create_EDM_DECIMAL_from_charz(AGENT_DATA_TYPE* agentData, const char* v)
+{
+ AGENT_DATA_TYPES_RESULT result;
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_013:[ All the Create_... functions shall check their parameters for validity. When an invalid parameter is detected, a code of AGENT_DATA_TYPES_INVALID_ARG shall be returned ].*/
+ if (agentData == NULL)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else if (v == NULL)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ size_t vlen = strlen(v);
+ /*validate that v has the form [SIGN] 1*DIGIT ["." 1*DIGIT]*/
+ if (vlen == 0)
+ {
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_067:[ If the string indicated by the parameter v does not match exactly an ODATA string representation, AGENT_DATA_TYPES_INVALID_ARG shall be returned.]*/
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ if (ValidateDecimal(v, vlen) != 0)
+ {
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_067:[ If the string indicated by the parameter v does not match exactly an ODATA string representation, AGENT_DATA_TYPES_INVALID_ARG shall be returned.]*/
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else if ((agentData->value.edmDecimal.value = STRING_construct(v)) == NULL)
+ {
+ result = AGENT_DATA_TYPES_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ agentData->type = EDM_DECIMAL_TYPE;
+ result = AGENT_DATA_TYPES_OK;
+ }
+ }
+ }
+ return result;
+}
+
+/*create an AGENT_DATA_TYPE containing an EDM_DOUBLE from a double*/
+AGENT_DATA_TYPES_RESULT Create_AGENT_DATA_TYPE_from_DOUBLE(AGENT_DATA_TYPE* agentData, double v)
+{
+ AGENT_DATA_TYPES_RESULT result;
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_013:[All the Create_... functions shall check their parameters for validity.When an invalid parameter is detected, a code of AGENT_DATA_TYPES_INVALID_ARG shall be returned]*/
+ if(agentData==NULL)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_041:[Creates an AGENT_DATA_TYPE containing an EDM_DOUBLE from double]*/
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_042:[Values of NaN, -INF, +INF are accepted]*/
+ agentData->type = EDM_DOUBLE_TYPE;
+ agentData->value.edmDouble.value = v;
+ result = AGENT_DATA_TYPES_OK;
+ }
+ return result;
+}
+
+/*create an AGENT_DATA_TYPE from INT16_T*/
+/*Codes_SRS_AGENT_TYPE_SYSTEM_99_043:[ Creates an AGENT_DATA_TYPE containing an EDM_INT16 from int16_t]*/
+AGENT_DATA_TYPES_RESULT Create_AGENT_DATA_TYPE_from_SINT16(AGENT_DATA_TYPE* agentData, int16_t v)
+{
+ AGENT_DATA_TYPES_RESULT result;
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_013:[ All the Create_... functions shall check their parameters for validity. When an invalid parameter is detected, a code of AGENT_DATA_TYPES_INVALID_ARG shall be returned ].*/
+ if (agentData == NULL)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ agentData->type = EDM_INT16_TYPE;
+ agentData->value.edmInt16.value = v;
+ result = AGENT_DATA_TYPES_OK;
+ }
+ return result;
+}
+
+/*create an AGENT_DATA_TYPE from INT32_T*/
+AGENT_DATA_TYPES_RESULT Create_AGENT_DATA_TYPE_from_SINT32(AGENT_DATA_TYPE* agentData, int32_t v)
+{
+ AGENT_DATA_TYPES_RESULT result;
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_013:[ All the Create_... functions shall check their parameters for validity. When an invalid parameter is detected, a code of AGENT_DATA_TYPES_INVALID_ARG shall be returned ].*/
+ if (agentData == NULL)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ agentData->type = EDM_INT32_TYPE;
+ agentData->value.edmInt32.value = v;
+ result = AGENT_DATA_TYPES_OK;
+ }
+ return result;
+}
+
+/*create an AGENT_DATA_TYPE from INT64_T*/
+/*Codes_SRS_AGENT_TYPE_SYSTEM_99_045:[ Creates an AGENT_DATA_TYPE containing an EDM_INT64 from int64_t]*/
+AGENT_DATA_TYPES_RESULT Create_AGENT_DATA_TYPE_from_SINT64(AGENT_DATA_TYPE* agentData, int64_t v)
+{
+ AGENT_DATA_TYPES_RESULT result;
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_013:[ All the Create_... functions shall check their parameters for validity. When an invalid parameter is detected, a code of AGENT_DATA_TYPES_INVALID_ARG shall be returned ].*/
+ if (agentData == NULL)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+
+ }
+ else
+ {
+ agentData->type = EDM_INT64_TYPE;
+ agentData->value.edmInt64.value = v;
+ result = AGENT_DATA_TYPES_OK;
+ }
+ return result;
+}
+
+/*create an AGENT_DATA_TYPE from int8_t*/
+AGENT_DATA_TYPES_RESULT Create_AGENT_DATA_TYPE_from_SINT8(AGENT_DATA_TYPE* agentData, int8_t v)
+{
+ AGENT_DATA_TYPES_RESULT result;
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_013:[ All the Create_... functions shall check their parameters for validity. When an invalid parameter is detected, a code of AGENT_DATA_TYPES_INVALID_ARG shall be returned ].*/
+ if (agentData == NULL)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+
+ }
+ else
+ {
+ agentData->type = EDM_SBYTE_TYPE;
+ agentData->value.edmSbyte.value = v;
+ result = AGENT_DATA_TYPES_OK;
+ }
+ return result;
+}
+
+static int ValidateDate(int year, int month, int day)
+{
+ int result;
+
+ if ((year <= -10000) || (year >= 10000))
+ {
+ result = 1;
+ }
+ else
+ {
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_070:[ If year-month-date does not indicate a valid day (for example 31 Feb 2013), then AGENT_DATA_TYPES_INVALID_ARG shall be returned.]*/
+ if (day <= 0)
+ {
+ result = 1;
+ }
+ else
+ {
+ /*the following data will be validated...*/
+ /*leap years are those that can be divided by 4. But if the year can be divided by 100, it is not leap. But if they year can be divided by 400 it is leap*/
+ if (
+ (month == 1) || /*these months have always 31 days*/
+ (month == 3) ||
+ (month == 5) ||
+ (month == 7) ||
+ (month == 8) ||
+ (month == 10) ||
+ (month == 12)
+ )
+ {
+ if (day <= 31)
+ {
+ result = 0;
+ }
+ else
+ {
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_070:[If year - month - date does not indicate a valid day(for example 31 Feb 2013), then AGENT_DATA_TYPES_INVALID_ARG shall be returned.]*/
+ result = 1;
+ }
+ }
+ else if (
+ (month == 4) ||
+ (month == 6) ||
+ (month == 9) ||
+ (month == 11)
+ )
+ {
+ if (day <= 30)
+ {
+ result = 0;
+ }
+ else
+ {
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_070:[If year - month - date does not indicate a valid day(for example 31 Feb 2013), then AGENT_DATA_TYPES_INVALID_ARG shall be returned.]*/
+ result = -1;
+ }
+ }
+ else if (month == 2)/*february*/
+ {
+ if ((year % 400) == 0)
+ {
+ /*these are leap years, suchs as 2000*/
+ if (day <= 29)
+ {
+ result = 0;
+ }
+ else
+ {
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_070:[If year - month - date does not indicate a valid day(for example 31 Feb 2013), then AGENT_DATA_TYPES_INVALID_ARG shall be returned.]*/
+ result = 1;
+ }
+ }
+ else if ((year % 100) == 0)
+ {
+ /*non-leap year, such as 1900*/
+ if (day <= 28)
+ {
+ result = 0;
+ }
+ else
+ {
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_070:[If year - month - date does not indicate a valid day(for example 31 Feb 2013), then AGENT_DATA_TYPES_INVALID_ARG shall be returned.]*/
+ result = 1;
+ }
+ }
+ else if ((year % 4) == 0)
+ {
+ /*these are leap years, such as 2104*/
+ if (day <= 29)
+ {
+ result = 0;
+ }
+ else
+ {
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_070:[If year - month - date does not indicate a valid day(for example 31 Feb 2013), then AGENT_DATA_TYPES_INVALID_ARG shall be returned.]*/
+ result = 1;
+ }
+ }
+ else
+ {
+ /*certainly not a leap year*/
+ if (day <= 28)
+ {
+ result = 0;
+ }
+ else
+ {
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_070:[If year - month - date does not indicate a valid day(for example 31 Feb 2013), then AGENT_DATA_TYPES_INVALID_ARG shall be returned.]*/
+ result = 1;
+ }
+ }
+ }
+ else
+ {
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_070:[If year - month - date does not indicate a valid day(for example 31 Feb 2013), then AGENT_DATA_TYPES_INVALID_ARG shall be returned.]*/
+ result = 1;
+ }
+ }
+ }
+
+ return result;
+}
+
+/*Codes_SRS_AGENT_TYPE_SYSTEM_99_069:[ Creates an AGENT_DATA_TYPE containing an EDM_DATE from a year, a month and a day of the month.]*/
+AGENT_DATA_TYPES_RESULT Create_AGENT_DATA_TYPE_from_date(AGENT_DATA_TYPE* agentData, int16_t year, uint8_t month, uint8_t day)
+{
+ AGENT_DATA_TYPES_RESULT result;
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_013:[ All the Create_... functions shall check their parameters for validity. When an invalid parameter is detected, a code of AGENT_DATA_TYPES_INVALID_ARG shall be returned ].*/
+ if (agentData == NULL)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ /*ODATA-ABNF: year = [ "-" ] ( "0" 3DIGIT / oneToNine 3*DIGIT )*/
+ else if (ValidateDate(year, month, day) != 0)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_069:[ Creates an AGENT_DATA_TYPE containing an EDM_DATE from a year, a month and a day of the month.]*/
+ agentData->type = EDM_DATE_TYPE;
+ agentData->value.edmDate.year = year;
+ agentData->value.edmDate.month = month;
+ agentData->value.edmDate.day = day;
+ result = AGENT_DATA_TYPES_OK;
+ }
+
+ return result;
+}
+
+
+/*create an AGENT_DATA_TYPE from SINGLE*/
+AGENT_DATA_TYPES_RESULT Create_AGENT_DATA_TYPE_from_FLOAT(AGENT_DATA_TYPE* agentData, float v)
+{
+ AGENT_DATA_TYPES_RESULT result;
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_013:[All the Create_... functions shall check their parameters for validity.When an invalid parameter is detected, a code of AGENT_DATA_TYPES_INVALID_ARG shall be returned]*/
+ if(agentData==NULL)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ agentData->type = EDM_SINGLE_TYPE;
+ agentData->value.edmSingle.value = v;
+ result = AGENT_DATA_TYPES_OK;
+ }
+ return result;
+}
+
+const char hexToASCII[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+
+/*create an AGENT_DATA_TYPE from ANSI zero terminated string*/
+AGENT_DATA_TYPES_RESULT Create_AGENT_DATA_TYPE_from_charz(AGENT_DATA_TYPE* agentData, const char* v)
+{
+ AGENT_DATA_TYPES_RESULT result = AGENT_DATA_TYPES_OK;
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_013:[ All the Create_... functions shall check their parameters for validity. When an invalid parameter is detected, a code of AGENT_DATA_TYPES_INVALID_ARG shall be returned ].*/
+ if (agentData == NULL)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else if (v == NULL)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_049:[ Creates an AGENT_DATA_TYPE containing an EDM_STRING from an ASCII zero terminated string.]*/
+ agentData->type = EDM_STRING_TYPE;
+ if (mallocAndStrcpy_s(&agentData->value.edmString.chars, v) != 0)
+ {
+ result = AGENT_DATA_TYPES_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ agentData->value.edmString.length = strlen(agentData->value.edmString.chars);
+ result = AGENT_DATA_TYPES_OK;
+ }
+ }
+ return result;
+}
+
+/*create an AGENT_DATA_TYPE from ANSI zero terminated string (without quotes) */
+AGENT_DATA_TYPES_RESULT Create_AGENT_DATA_TYPE_from_charz_no_quotes(AGENT_DATA_TYPE* agentData, const char* v)
+{
+ AGENT_DATA_TYPES_RESULT result = AGENT_DATA_TYPES_OK;
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_013:[ All the Create_... functions shall check their parameters for validity. When an invalid parameter is detected, a code of AGENT_DATA_TYPES_INVALID_ARG shall be returned ].*/
+ if (agentData == NULL)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else if (v == NULL)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ /* Codes_SRS_AGENT_TYPE_SYSTEM_01_001: [Creates an AGENT_DATA_TYPE containing an EDM_STRING from an ASCII zero terminated string.] */
+ agentData->type = EDM_STRING_NO_QUOTES_TYPE;
+ if (mallocAndStrcpy_s(&agentData->value.edmStringNoQuotes.chars, v) != 0)
+ {
+ result = AGENT_DATA_TYPES_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ agentData->value.edmStringNoQuotes.length = strlen(agentData->value.edmStringNoQuotes.chars);
+ result = AGENT_DATA_TYPES_OK;
+ }
+ }
+ return result;
+}
+
+void Destroy_AGENT_DATA_TYPE(AGENT_DATA_TYPE* agentData)
+{
+ if(agentData==NULL)
+ {
+ LogError("agentData was NULL.\r\n");
+ }
+ else
+ {
+ switch(agentData->type)
+ {
+ default:
+ {
+ LogError("invalid agentData\r\n");
+ break;
+ }
+ case(EDM_NO_TYPE):
+ {
+ LogError("invalid agentData\r\n");
+ break;
+ }
+ case(EDM_BINARY_TYPE):
+ {
+ /*destroying means maybe deallocating some memory*/
+ free(agentData->value.edmBinary.data); /* If ptr is a null pointer, no action occurs*/
+ agentData->value.edmBinary.data = NULL;
+ break;
+ }
+ case(EDM_BOOLEAN_TYPE):
+ {
+ /*nothing to do*/
+ break;
+ }
+ case(EDM_BYTE_TYPE):
+ {
+ /*nothing to do*/
+ break;
+ }
+ case(EDM_DATE_TYPE):
+ {
+ /*nothing to do*/
+ break;
+ }
+ case(EDM_DATE_TIME_OFFSET_TYPE):
+ {
+ /*nothing to do*/
+ break;
+ }
+ case(EDM_DECIMAL_TYPE):
+ {
+ STRING_delete(agentData->value.edmDecimal.value);
+ agentData->value.edmDecimal.value = NULL;
+ break;
+ }
+ case(EDM_DURATION_TYPE):
+ {
+ LogError("EDM_DURATION_TYPE not implemented\r\n");
+ break;
+ }
+ case(EDM_GUID_TYPE):
+ {
+ /*nothing to do*/
+ break;
+ }
+ case(EDM_INT16_TYPE):
+ {
+ /*nothing to do*/
+ break;
+ }
+ case(EDM_INT32_TYPE):
+ {
+ /*nothing to do*/
+ break;
+ }
+ case(EDM_INT64_TYPE):
+ {
+ /*nothing to do*/
+ break;
+ }
+ case(EDM_SBYTE_TYPE):
+ {
+ /*nothing to do*/
+ break;
+ }
+ case(EDM_STREAM):
+ {
+ LogError("EDM_STREAM not implemented\r\n");
+ break;
+ }
+ case(EDM_STRING_TYPE):
+ {
+ if (agentData->value.edmString.chars != NULL)
+ {
+ free(agentData->value.edmString.chars);
+ agentData->value.edmString.chars = NULL;
+ }
+ break;
+ }
+ case(EDM_STRING_NO_QUOTES_TYPE) :
+ {
+ if (agentData->value.edmStringNoQuotes.chars != NULL)
+ {
+ free(agentData->value.edmStringNoQuotes.chars);
+ agentData->value.edmStringNoQuotes.chars = NULL;
+ }
+ break;
+ }
+ case(EDM_TIME_OF_DAY_TYPE) :
+ {
+ LogError("EDM_TIME_OF_DAY_TYPE not implemented\r\n");
+ break;
+ }
+ case(EDM_GEOGRAPHY_TYPE):
+ {
+ LogError("EDM_GEOGRAPHY_TYPE not implemented\r\n");
+ break;
+ }
+ case(EDM_GEOGRAPHY_POINT_TYPE):
+ {
+ LogError("EDM_GEOGRAPHY_POINT_TYPE not implemented\r\n");
+ break;
+ }
+ case(EDM_GEOGRAPHY_LINE_STRING_TYPE):
+ {
+ LogError("EDM_GEOGRAPHY_LINE_STRING_TYPE not implemented\r\n");
+ break;
+ }
+ case(EDM_GEOGRAPHY_POLYGON_TYPE):
+ {
+ LogError("EDM_GEOGRAPHY_POLYGON_TYPE not implemented\r\n");
+ break;
+ }
+ case(EDM_GEOGRAPHY_MULTI_POINT_TYPE):
+ {
+ LogError("EDM_GEOGRAPHY_MULTI_POINT_TYPE not implemented\r\n");
+ break;
+ }
+ case(EDM_GEOGRAPHY_MULTI_LINE_STRING_TYPE):
+ {
+ LogError("EDM_GEOGRAPHY_MULTI_LINE_STRING_TYPE not implemented\r\n");
+ break;
+ }
+ case(EDM_GEOGRAPHY_MULTI_POLYGON_TYPE):
+ {
+ LogError("EDM_GEOGRAPHY_MULTI_POLYGON_TYPE\r\n");
+ break;
+ }
+ case(EDM_GEOGRAPHY_COLLECTION_TYPE):
+ {
+ LogError("EDM_GEOGRAPHY_COLLECTION_TYPE not implemented\r\n");
+ break;
+ }
+ case(EDM_GEOMETRY_TYPE):
+ {
+ LogError("EDM_GEOMETRY_TYPE not implemented\r\n");
+ break;
+ }
+ case(EDM_GEOMETRY_POINT_TYPE):
+ {
+ LogError("EDM_GEOMETRY_POINT_TYPE not implemented\r\n");
+ break;
+ }
+ case(EDM_GEOMETRY_LINE_STRING_TYPE):
+ {
+ LogError("EDM_GEOMETRY_LINE_STRING_TYPE not implemented\r\n");
+ break;
+ }
+ case(EDM_GEOMETRY_POLYGON_TYPE):
+ {
+ LogError("EDM_GEOMETRY_POLYGON_TYPE not implemented\r\n");
+ break;
+ }
+ case(EDM_GEOMETRY_MULTI_POINT_TYPE):
+ {
+ LogError("EDM_GEOMETRY_MULTI_POINT_TYPE not implemented\r\n");
+ break;
+ }
+ case(EDM_GEOMETRY_MULTI_LINE_STRING_TYPE):
+ {
+ LogError("EDM_GEOMETRY_MULTI_LINE_STRING_TYPE not implemented\r\n");
+ break;
+ }
+ case(EDM_GEOMETRY_MULTI_POLYGON_TYPE):
+ {
+ LogError("EDM_GEOMETRY_MULTI_POLYGON_TYPE not implemented\r\n");
+ break;
+ }
+ case(EDM_GEOMETRY_COLLECTION_TYPE):
+ {
+ LogError("EDM_GEOMETRY_COLLECTION_TYPE not implemented\r\n");
+ break;
+ }
+ case(EDM_SINGLE_TYPE):
+ {
+ break;
+ }
+ case(EDM_DOUBLE_TYPE):
+ {
+ break;
+ }
+ case (EDM_COMPLEX_TYPE_TYPE):
+ {
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_050:[Destroy_AGENT_DATA_TYPE shall deallocate all allocated resources used to represent the type.]*/
+ size_t i;
+ for (i = 0; i < agentData->value.edmComplexType.nMembers; i++)
+ {
+ free((void*)(agentData->value.edmComplexType.fields[i].fieldName));
+ agentData->value.edmComplexType.fields[i].fieldName = NULL;
+ Destroy_AGENT_DATA_TYPE(agentData->value.edmComplexType.fields[i].value);
+ free(agentData->value.edmComplexType.fields[i].value);
+ agentData->value.edmComplexType.fields[i].value = NULL;
+ }
+ free(agentData->value.edmComplexType.fields);
+ break;
+ }
+ }
+ agentData->type = EDM_NO_TYPE; /*mark as detroyed*/
+ }
+}
+
+#define tempBufferSize 10240
+static char tempBuffer[tempBufferSize];
+
+static char hexDigitToChar(uint8_t hexDigit)
+{
+ if (hexDigit < 10) return '0' + hexDigit;
+ else return ('A' - 10) + hexDigit;
+}
+
+AGENT_DATA_TYPES_RESULT AgentDataTypes_ToString(STRING_HANDLE destination, const AGENT_DATA_TYPE* value)
+{
+ AGENT_DATA_TYPES_RESULT result;
+
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_015:[If destination parameter is NULL, AgentDataTypes_ToString shall return AGENT_DATA_TYPES_INVALID_ARG.]*/
+ if(destination == NULL)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_053:[ If value is NULL or has been destroyed or otherwise doesn't contain valid data, AGENT_DATA_TYPES_INVALID_ARG shall be returned.]*/
+ else if (value == NULL)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ switch(value->type)
+ {
+ default:
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ break;
+ }
+ case(EDM_NULL_TYPE) :
+ {
+ /*SRS_AGENT_TYPE_SYSTEM_99_101:[ EDM_NULL_TYPE shall return the unquoted string null.]*/
+ if (STRING_concat(destination, "null") != 0)
+ {
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_016:[ When the value cannot be converted to a string AgentDataTypes_ToString shall return AGENT_DATA_TYPES_ERROR.]*/
+ result = AGENT_DATA_TYPES_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_014:[ All functions shall return AGENT_DATA_TYPES_OK when the processing is successful.]*/
+ result = AGENT_DATA_TYPES_OK;
+ }
+ break;
+ }
+ case(EDM_BOOLEAN_TYPE) :
+ {
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_017:[EDM_BOOLEAN:as in(odata - abnf - construction - rules, 2013), booleanValue = "true" / "false"]*/
+ if (value->value.edmBoolean.value == EDM_TRUE)
+ {
+ /*SRS_AGENT_TYPE_SYSTEM_99_030:[If v is different than 0 then the AGENT_DATA_TYPE shall have the value "true".]*/
+ if (STRING_concat(destination, "true") != 0)
+ {
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_016:[ When the value cannot be converted to a string AgentDataTypes_ToString shall return AGENT_DATA_TYPES_ERROR.]*/
+ result = AGENT_DATA_TYPES_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_014:[ All functions shall return AGENT_DATA_TYPES_OK when the processing is successful.]*/
+ result = AGENT_DATA_TYPES_OK;
+ }
+ }
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_017:[EDM_BOOLEAN:as in(odata - abnf - construction - rules, 2013), booleanValue = "true" / "false"]*/
+ else if (value->value.edmBoolean.value == EDM_FALSE)
+ {
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_029:[ If v 0 then the AGENT_DATA_TYPE shall have the value "false" Boolean.]*/
+ if (STRING_concat(destination, "false") != 0)
+ {
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_016:[ When the value cannot be converted to a string AgentDataTypes_ToString shall return AGENT_DATA_TYPES_ERROR.]*/
+ result = AGENT_DATA_TYPES_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_014:[ All functions shall return AGENT_DATA_TYPES_OK when the processing is successful.]*/
+ result = AGENT_DATA_TYPES_OK;
+ }
+ }
+ else
+ {
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_053:[ If value contains invalid data, AgentDataTypes_ToString shall return AGENT_DATA_TYPES_INVALID_ARG.]*/
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+
+ break;
+ }
+ case(EDM_BYTE_TYPE) :
+ {
+ char tempbuffer2[4]; /*because bytes can at most be 255 and that is 3 characters + 1 for '\0'*/
+ size_t pos = 0;
+ if (value->value.edmByte.value >= 100) tempbuffer2[pos++] = '0' + (value->value.edmByte.value / 100);
+ if (value->value.edmByte.value >= 10) tempbuffer2[pos++] = '0' + (value->value.edmByte.value % 100) / 10;
+ tempbuffer2[pos++] = '0' + (value->value.edmByte.value % 10);
+ tempbuffer2[pos++] = '\0';
+
+ if (STRING_concat(destination, tempbuffer2) != 0)
+ {
+ result = AGENT_DATA_TYPES_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ result = AGENT_DATA_TYPES_OK;
+ }
+ break;
+ }
+ case(EDM_DATE_TYPE) :
+ {
+ size_t pos = 0;
+ char tempBuffer2[1 + 5 + 1 + 2 + 1 + 2 + 1+1];
+ int16_t year = value->value.edmDate.year;
+ tempBuffer2[pos++] = '\"';
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_068:[ EDM_DATE: dateValue = year "-" month "-" day.]*/
+ if (year < 0)
+ {
+ tempBuffer2[pos++] = '-';
+ year = -year;
+ }
+
+ tempBuffer2[pos++] = '0' + (char)(year / 1000);
+ tempBuffer2[pos++] = '0' + (char)((year % 1000) / 100);
+ tempBuffer2[pos++] = '0' + (char)((year % 100) / 10);
+ tempBuffer2[pos++] = '0' + (char)(year % 10);
+ tempBuffer2[pos++] = '-';
+ tempBuffer2[pos++] = '0' + value->value.edmDate.month / 10;
+ tempBuffer2[pos++] = '0' + value->value.edmDate.month % 10;
+ tempBuffer2[pos++] = '-';
+ tempBuffer2[pos++] = '0' + value->value.edmDate.day / 10;
+ tempBuffer2[pos++] = '0' + value->value.edmDate.day % 10;
+ tempBuffer2[pos++] = '\"';
+ tempBuffer2[pos++] = '\0';
+
+ if (STRING_concat(destination, tempBuffer2) != 0)
+ {
+ result = AGENT_DATA_TYPES_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ result = AGENT_DATA_TYPES_OK;
+ }
+ break;
+ }
+ case (EDM_DATE_TIME_OFFSET_TYPE):
+ {
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_019:[ EDM_DATETIMEOFFSET: dateTimeOffsetValue = year "-" month "-" day "T" hour ":" minute [ ":" second [ "." fractionalSeconds ] ] ( "Z" / sign hour ":" minute )]*/
+ /*from ABNF seems like these numbers HAVE to be padded with zeroes*/
+ if (value->value.edmDateTimeOffset.hasTimeZone)
+ {
+ if (value->value.edmDateTimeOffset.hasFractionalSecond)
+ {
+ if (sprintf_s(tempBuffer, tempBufferSize, "\"%.4d-%.2d-%.2dT%.2d:%.2d:%.2d.%.12llu%+.2d:%.2d\"", /*+ in printf forces the sign to appear*/
+ value->value.edmDateTimeOffset.dateTime.tm_year+1900,
+ value->value.edmDateTimeOffset.dateTime.tm_mon+1,
+ value->value.edmDateTimeOffset.dateTime.tm_mday,
+ value->value.edmDateTimeOffset.dateTime.tm_hour,
+ value->value.edmDateTimeOffset.dateTime.tm_min,
+ value->value.edmDateTimeOffset.dateTime.tm_sec,
+ value->value.edmDateTimeOffset.fractionalSecond,
+ value->value.edmDateTimeOffset.timeZoneHour,
+ value->value.edmDateTimeOffset.timeZoneMinute) < 0)
+ {
+ result = AGENT_DATA_TYPES_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else if (STRING_concat(destination, tempBuffer) != 0)
+ {
+ result = AGENT_DATA_TYPES_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ result = AGENT_DATA_TYPES_OK;
+ }
+ }
+ else
+ {
+ if (sprintf_s(tempBuffer, tempBufferSize, "\"%.4d-%.2d-%.2dT%.2d:%.2d:%.2d%+.2d:%.2d\"", /*+ in printf forces the sign to appear*/
+ value->value.edmDateTimeOffset.dateTime.tm_year + 1900,
+ value->value.edmDateTimeOffset.dateTime.tm_mon+1,
+ value->value.edmDateTimeOffset.dateTime.tm_mday,
+ value->value.edmDateTimeOffset.dateTime.tm_hour,
+ value->value.edmDateTimeOffset.dateTime.tm_min,
+ value->value.edmDateTimeOffset.dateTime.tm_sec,
+ value->value.edmDateTimeOffset.timeZoneHour,
+ value->value.edmDateTimeOffset.timeZoneMinute) < 0)
+ {
+ result = AGENT_DATA_TYPES_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else if (STRING_concat(destination, tempBuffer) != 0)
+ {
+ result = AGENT_DATA_TYPES_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ result = AGENT_DATA_TYPES_OK;
+ }
+ }
+ }
+ else
+ {
+ if (value->value.edmDateTimeOffset.hasFractionalSecond)
+ {
+ if (sprintf_s(tempBuffer, tempBufferSize, "\"%.4d-%.2d-%.2dT%.2d:%.2d:%.2d.%.12lluZ\"", /*+ in printf forces the sign to appear*/
+ value->value.edmDateTimeOffset.dateTime.tm_year + 1900,
+ value->value.edmDateTimeOffset.dateTime.tm_mon+1,
+ value->value.edmDateTimeOffset.dateTime.tm_mday,
+ value->value.edmDateTimeOffset.dateTime.tm_hour,
+ value->value.edmDateTimeOffset.dateTime.tm_min,
+ value->value.edmDateTimeOffset.dateTime.tm_sec,
+ value->value.edmDateTimeOffset.fractionalSecond) < 0)
+ {
+ result = AGENT_DATA_TYPES_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else if (STRING_concat(destination, tempBuffer) != 0)
+ {
+ result = AGENT_DATA_TYPES_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ result = AGENT_DATA_TYPES_OK;
+ }
+ }
+ else
+ {
+ if (sprintf_s(tempBuffer, tempBufferSize, "\"%.4d-%.2d-%.2dT%.2d:%.2d:%.2dZ\"",
+ value->value.edmDateTimeOffset.dateTime.tm_year + 1900,
+ value->value.edmDateTimeOffset.dateTime.tm_mon+1,
+ value->value.edmDateTimeOffset.dateTime.tm_mday,
+ value->value.edmDateTimeOffset.dateTime.tm_hour,
+ value->value.edmDateTimeOffset.dateTime.tm_min,
+ value->value.edmDateTimeOffset.dateTime.tm_sec) < 0)
+ {
+ result = AGENT_DATA_TYPES_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else if (STRING_concat(destination, tempBuffer) != 0)
+ {
+ result = AGENT_DATA_TYPES_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ result = AGENT_DATA_TYPES_OK;
+ }
+ }
+
+
+ }
+ break;
+ }
+ case(EDM_DECIMAL_TYPE) :
+ {
+ if (STRING_concat_with_STRING(destination, value->value.edmDecimal.value) != 0)
+ {
+ result = AGENT_DATA_TYPES_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ result = AGENT_DATA_TYPES_OK;
+ }
+ break;
+ }
+ case (EDM_INT16_TYPE) :
+ {
+ /*-32768 to +32767*/
+ char buffertemp2[7]; /*because 5 digits and sign and '\0'*/
+ uint16_t positiveValue;
+ size_t pos = 0;
+ uint16_t rank = (uint16_t)10000;
+ bool foundFirstDigit = false;
+
+ if (value->value.edmInt16.value < 0)
+ {
+ buffertemp2[pos++] = '-';
+ positiveValue = -value->value.edmInt16.value;
+ }
+ else
+ {
+ positiveValue = value->value.edmInt16.value;
+ }
+
+ while (rank >= 10)
+ {
+ if ((foundFirstDigit == true) || (positiveValue / rank) > 0)
+ {
+ buffertemp2[pos++] = '0' + (char)(positiveValue / rank);
+ foundFirstDigit = true;
+ }
+ positiveValue %= rank;
+ rank /= 10;
+ }
+ buffertemp2[pos++] = '0' + (char)(positiveValue);
+ buffertemp2[pos++] = '\0';
+
+ if (STRING_concat(destination, buffertemp2) != 0)
+ {
+ result = AGENT_DATA_TYPES_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ result = AGENT_DATA_TYPES_OK;
+ }
+ break;
+ }
+ case (EDM_INT32_TYPE) :
+ {
+ /*-2147483648 to +2147483647*/
+ char buffertemp2[12]; /*because 10 digits and sign and '\0'*/
+ uint32_t positiveValue;
+ size_t pos = 0;
+ uint32_t rank = 1000000000UL;
+ bool foundFirstDigit = false;
+
+ if (value->value.edmInt32.value < 0)
+ {
+ buffertemp2[pos++] = '-';
+ positiveValue = - value->value.edmInt32.value;
+ }
+ else
+ {
+ positiveValue = value->value.edmInt32.value;
+ }
+
+ while (rank >= 10)
+ {
+ if ((foundFirstDigit == true) || (positiveValue / rank) > 0)
+ {
+ buffertemp2[pos++] = '0' + (char)(positiveValue / rank);
+ foundFirstDigit = true;
+ }
+ positiveValue %= rank;
+ rank /= 10;
+ }
+ buffertemp2[pos++] = '0' + (char)(positiveValue);
+ buffertemp2[pos++] = '\0';
+
+ if (STRING_concat(destination, buffertemp2) != 0)
+ {
+ result = AGENT_DATA_TYPES_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ result = AGENT_DATA_TYPES_OK;
+ }
+ break;
+ }
+ case (EDM_INT64_TYPE):
+ {
+ char buffertemp2[21]; /*because 19 digits and sign and '\0'*/
+ uint64_t positiveValue;
+ size_t pos = 0;
+ uint64_t rank = 10000000000000000000ULL;
+ bool foundFirstDigit = false;
+
+ if (value->value.edmInt64.value < 0)
+ {
+ buffertemp2[pos++] = '-';
+ positiveValue = -value->value.edmInt64.value;
+ }
+ else
+ {
+ positiveValue = value->value.edmInt64.value;
+ }
+
+ while (rank >= 10)
+ {
+ if ((foundFirstDigit == true) || (positiveValue / rank) > 0)
+ {
+ buffertemp2[pos++] = '0' + (char)(positiveValue / rank);
+ foundFirstDigit = true;
+ }
+ positiveValue %= rank;
+ rank /= 10;
+ }
+ buffertemp2[pos++] = '0' + (char)(positiveValue);
+ buffertemp2[pos++] = '\0';
+
+ if (STRING_concat(destination, buffertemp2) != 0)
+ {
+ result = AGENT_DATA_TYPES_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ result = AGENT_DATA_TYPES_OK;
+ }
+ break;
+ }
+ case (EDM_SBYTE_TYPE) :
+ {
+ char tempbuffer2[5]; /* because '-' and 3 characters for 127 let's say and '\0'*/
+ int absValue = value->value.edmSbyte.value;
+ size_t pos=0;
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_026:[ EDM_SBYTE: sbyteValue = [ sign ] 1*3DIGIT ; numbers in the range from -128 to 127]*/
+
+ if (value->value.edmSbyte.value < 0)
+ {
+ tempbuffer2[pos++] = '-';
+ absValue = -absValue;
+ }
+
+ if (absValue >= 100 ) tempbuffer2[pos++] = '0' + (char)(absValue / 100);
+ if (absValue >=10) tempbuffer2[pos++] = '0' + (absValue % 100) / 10;
+ tempbuffer2[pos++] = '0' + (absValue % 10);
+ tempbuffer2[pos++] = '\0';
+
+
+ if (STRING_concat(destination, tempbuffer2) != 0)
+ {
+ result = AGENT_DATA_TYPES_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ result = AGENT_DATA_TYPES_OK;
+ }
+ break;
+ }
+ case (EDM_STRING_TYPE):
+ {
+ 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 = value->value.edmString.length;
+ char* v = value->value.edmString.chars;
+
+ for (i = 0; i < vlen; i++)
+ {
+ if ((unsigned char)v[i] >= 128) /*this be a UNICODE character begin*/
+ {
+ break;
+ }
+ else
+ {
+ if (v[i] <= 0x1F)
+ {
+ nControlCharacters++;
+ }
+ else if (
+ (v[i] == '"') ||
+ (v[i] == '\\') ||
+ (v[i] == '/')
+ )
+ {
+ nEscapeCharacters++;
+ }
+ }
+ }
+
+ if (i < vlen)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG; /*don't handle those who do not copy bit by bit to UTF8*/
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ /*forward parse the string to scan for " and for \ that in JSON are \" respectively \\*/
+ if (tempBufferSize < vlen + 5 * nControlCharacters + nEscapeCharacters + 3)
+ {
+ result = AGENT_DATA_TYPES_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ size_t w = 0;
+ tempBuffer[w++] = '"';
+ for (i = 0; i < vlen; i++)
+ {
+ if (v[i] <= 0x1F)
+ {
+ tempBuffer[w++] = '\\';
+ tempBuffer[w++] = 'u';
+ tempBuffer[w++] = '0';
+ tempBuffer[w++] = '0';
+ tempBuffer[w++] = hexToASCII[(v[i] & 0xF0) >> 4]; /*high nibble*/
+ tempBuffer[w++] = hexToASCII[v[i] & 0x0F]; /*lowNibble nibble*/
+ }
+ else if (v[i] == '"')
+ {
+ tempBuffer[w++] = '\\';
+ tempBuffer[w++] = '"';
+ }
+ else if (v[i] == '\\')
+ {
+ tempBuffer[w++] = '\\';
+ tempBuffer[w++] = '\\';
+ }
+ else if (v[i] == '/')
+ {
+ tempBuffer[w++] = '\\';
+ tempBuffer[w++] = '/';
+ }
+ else
+ {
+ tempBuffer[w++] = v[i];
+ }
+ }
+
+#ifdef _MSC_VER
+#pragma warning(suppress: 6386) /* The test Create_AGENT_DATA_TYPE_from_charz_With_2_Slashes_Succeeds verifies that Code Analysis is wrong here */
+#endif
+ tempBuffer[w] = '"';
+ /*zero terminating it*/
+ tempBuffer[vlen + 5 * nControlCharacters + nEscapeCharacters + 3 - 1] = '\0';
+
+ if (STRING_concat(destination, tempBuffer) != 0)
+ {
+ result = AGENT_DATA_TYPES_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ result = AGENT_DATA_TYPES_OK;
+ }
+ }
+ }
+
+ break;
+ }
+
+ /* Codes_SRS_AGENT_TYPE_SYSTEM_01_003: [EDM_STRING_no_quotes: the string is copied as given when the AGENT_DATA_TYPE was created.] */
+ case (EDM_STRING_NO_QUOTES_TYPE) :
+ {
+ /* this is a special case where we just want to copy/paste the contents, no encoding, no quotes */
+ /* Codes_SRS_AGENT_TYPE_SYSTEM_01_002: [When serialized, this type is not enclosed with quotes.] */
+ if (STRING_concat(destination, value->value.edmStringNoQuotes.chars) != 0)
+ {
+ result = AGENT_DATA_TYPES_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ result = AGENT_DATA_TYPES_OK;
+ }
+
+ break;
+ }
+
+ case(EDM_SINGLE_TYPE):
+ {
+ /*C89 standard says: When a float is promoted to double or long double, or a double is promoted to long double, its value is unchanged*/
+ /*I read that as : when a float is NaN or Inf, it will stay NaN or INF in double representation*/
+
+ /*The sprintf function returns the number of characters written in the array, not counting the terminating null character.*/
+
+ if(ISNAN(value->value.edmSingle.value))
+ {
+ if (STRING_concat(destination, NaN_STRING) != 0)
+ {
+ result = AGENT_DATA_TYPES_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ result = AGENT_DATA_TYPES_OK;
+ }
+ }
+ else if (ISNEGATIVEINFINITY(value->value.edmSingle.value))
+ {
+ if (STRING_concat(destination, MINUSINF_STRING) != 0)
+ {
+ result = AGENT_DATA_TYPES_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ result = AGENT_DATA_TYPES_OK;
+ }
+ }
+ else if (ISPOSITIVEINFINITY(value->value.edmSingle.value))
+ {
+ if (STRING_concat(destination, PLUSINF_STRING) != 0)
+ {
+ result = AGENT_DATA_TYPES_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ result = AGENT_DATA_TYPES_OK;
+ }
+ }
+ else if(sprintf_s(tempBuffer, tempBufferSize, "%.*f", FLT_DIG, (double)(value->value.edmSingle.value))<0)
+ {
+ result = AGENT_DATA_TYPES_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else if (STRING_concat(destination, tempBuffer) != 0)
+ {
+ result = AGENT_DATA_TYPES_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ result = AGENT_DATA_TYPES_OK;
+ }
+ break;
+ }
+ case(EDM_DOUBLE_TYPE):
+ {
+ /*The sprintf function returns the number of characters written in the array, not counting the terminating null character.*/
+ /*OData-ABNF says these can be used: nanInfinity = 'NaN' / '-INF' / 'INF'*/
+ /*C90 doesn't declare a NaN or Inf in the standard, however, values might be NaN or Inf...*/
+ /*C99 ... does*/
+ /*C11 is same as C99*/
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_022:[ EDM_DOUBLE: doubleValue = decimalValue [ "e" [SIGN] 1*DIGIT ] / nanInfinity ; IEEE 754 binary64 floating-point number (15-17 decimal digits). The representation shall use DBL_DIG C #define*/
+ if(ISNAN(value->value.edmDouble.value))
+ {
+ if (STRING_concat(destination, NaN_STRING) != 0)
+ {
+ result = AGENT_DATA_TYPES_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ result = AGENT_DATA_TYPES_OK;
+ }
+ }
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_022:[ EDM_DOUBLE: doubleValue = decimalValue [ "e" [SIGN] 1*DIGIT ] / nanInfinity ; IEEE 754 binary64 floating-point number (15-17 decimal digits). The representation shall use DBL_DIG C #define*/
+ else if (ISNEGATIVEINFINITY(value->value.edmDouble.value))
+ {
+ if (STRING_concat(destination, MINUSINF_STRING) != 0)
+ {
+ result = AGENT_DATA_TYPES_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ result = AGENT_DATA_TYPES_OK;
+ }
+ }
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_022:[ EDM_DOUBLE: doubleValue = decimalValue [ "e" [SIGN] 1*DIGIT ] / nanInfinity ; IEEE 754 binary64 floating-point number (15-17 decimal digits). The representation shall use DBL_DIG C #define*/
+ else if (ISPOSITIVEINFINITY(value->value.edmDouble.value))
+ {
+ if (STRING_concat(destination, PLUSINF_STRING) != 0)
+ {
+ result = AGENT_DATA_TYPES_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ result = AGENT_DATA_TYPES_OK;
+ }
+ }
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_022:[ EDM_DOUBLE: doubleValue = decimalValue [ "e" [SIGN] 1*DIGIT ] / nanInfinity ; IEEE 754 binary64 floating-point number (15-17 decimal digits). The representation shall use DBL_DIG C #define*/
+ else if(sprintf_s(tempBuffer, tempBufferSize, "%.*f", DBL_DIG, value->value.edmDouble.value)<0)
+ {
+ result = AGENT_DATA_TYPES_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else if (STRING_concat(destination, tempBuffer) != 0)
+ {
+ result = AGENT_DATA_TYPES_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ result = AGENT_DATA_TYPES_OK;
+ }
+ break;
+ }
+
+ case(EDM_COMPLEX_TYPE_TYPE) :
+ {
+ /*to produce an EDM_COMPLEX_TYPE is a recursive process*/
+ /*uses JSON encoder*/
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_062:[ If the AGENT_DATA_TYPE represents a "complex type", then the JSON marshaller shall produce the following JSON value:[...]*/
+ MULTITREE_HANDLE treeHandle;
+ result = AGENT_DATA_TYPES_OK;
+ /*SRS_AGENT_TYPE_SYSTEM_99_016:[ When the value cannot be converted to a string AgentDataTypes_ToString shall return AGENT_DATA_TYPES_ERROR.]*/
+ treeHandle = MultiTree_Create(NoCloneFunction, NoFreeFunction);
+ if (treeHandle == NULL)
+ {
+ result = AGENT_DATA_TYPES_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ size_t i;
+ for (i = 0; i < value->value.edmComplexType.nMembers; i++)
+ {
+ if (MultiTree_AddLeaf(treeHandle, value->value.edmComplexType.fields[i].fieldName, value->value.edmComplexType.fields[i].value) != MULTITREE_OK)
+ {
+ /*SRS_AGENT_TYPE_SYSTEM_99_016:[ When the value cannot be converted to a string AgentDataTypes_ToString shall return AGENT_DATA_TYPES_ERROR.]*/
+ result = AGENT_DATA_TYPES_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ break;
+ }
+ else
+ {
+ /*all is fine*/
+ }
+ }
+
+ if (result == AGENT_DATA_TYPES_OK)
+ {
+ /*SRS_AGENT_TYPE_SYSTEM_99_016:[ When the value cannot be converted to a string AgentDataTypes_ToString shall return AGENT_DATA_TYPES_ERROR.]*/
+ if (JSONEncoder_EncodeTree(treeHandle, destination, (JSON_ENCODER_TOSTRING_FUNC)AgentDataTypes_ToString) != JSON_ENCODER_OK)
+ {
+ result = AGENT_DATA_TYPES_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ /*all is fine*/
+ }
+
+ }
+
+ MultiTree_Destroy(treeHandle);
+ }
+ break;
+ }
+ case EDM_GUID_TYPE:
+ {
+ char tempBuffer2[1 + 8 + 1 + 4 + 1 + 4 + 1 + 4 + 1 + 12 + 1+ 1];
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_093:[ EDM_GUID: 8HEXDIG "-" 4HEXDIG "-" 4HEXDIG "-" 4HEXDIG "-" 12HEXDIG]*/
+ tempBuffer2[0] = '\"';
+ tempBuffer2[1] = hexDigitToChar(value->value.edmGuid.GUID[0] / 16);
+ tempBuffer2[2] = hexDigitToChar(value->value.edmGuid.GUID[0] % 16);
+ tempBuffer2[3] = hexDigitToChar(value->value.edmGuid.GUID[1] / 16);
+ tempBuffer2[4] = hexDigitToChar(value->value.edmGuid.GUID[1] % 16);
+ tempBuffer2[5] = hexDigitToChar(value->value.edmGuid.GUID[2] / 16);
+ tempBuffer2[6] = hexDigitToChar(value->value.edmGuid.GUID[2] % 16);
+ tempBuffer2[7] = hexDigitToChar(value->value.edmGuid.GUID[3] / 16);
+ tempBuffer2[8] = hexDigitToChar(value->value.edmGuid.GUID[3] % 16);
+
+ tempBuffer2[9] = '-';
+ tempBuffer2[10] = hexDigitToChar(value->value.edmGuid.GUID[4] / 16);
+ tempBuffer2[11] = hexDigitToChar(value->value.edmGuid.GUID[4] % 16);
+ tempBuffer2[12] = hexDigitToChar(value->value.edmGuid.GUID[5] / 16);
+ tempBuffer2[13] = hexDigitToChar(value->value.edmGuid.GUID[5] % 16);
+
+ tempBuffer2[14] = '-';
+ tempBuffer2[15] = hexDigitToChar(value->value.edmGuid.GUID[6] / 16);
+ tempBuffer2[16] = hexDigitToChar(value->value.edmGuid.GUID[6] % 16);
+ tempBuffer2[17] = hexDigitToChar(value->value.edmGuid.GUID[7] / 16);
+ tempBuffer2[18] = hexDigitToChar(value->value.edmGuid.GUID[7] % 16);
+
+ tempBuffer2[19] = '-';
+ tempBuffer2[20] = hexDigitToChar(value->value.edmGuid.GUID[8] / 16);
+ tempBuffer2[21] = hexDigitToChar(value->value.edmGuid.GUID[8] % 16);
+ tempBuffer2[22] = hexDigitToChar(value->value.edmGuid.GUID[9] / 16);
+ tempBuffer2[23] = hexDigitToChar(value->value.edmGuid.GUID[9] % 16);
+
+ tempBuffer2[24] = '-';
+ tempBuffer2[25] = hexDigitToChar(value->value.edmGuid.GUID[10] / 16);
+ tempBuffer2[26] = hexDigitToChar(value->value.edmGuid.GUID[10] % 16);
+ tempBuffer2[27] = hexDigitToChar(value->value.edmGuid.GUID[11] / 16);
+ tempBuffer2[28] = hexDigitToChar(value->value.edmGuid.GUID[11] % 16);
+ tempBuffer2[29] = hexDigitToChar(value->value.edmGuid.GUID[12] / 16);
+ tempBuffer2[30] = hexDigitToChar(value->value.edmGuid.GUID[12] % 16);
+ tempBuffer2[31] = hexDigitToChar(value->value.edmGuid.GUID[13] / 16);
+ tempBuffer2[32] = hexDigitToChar(value->value.edmGuid.GUID[13] % 16);
+ tempBuffer2[33] = hexDigitToChar(value->value.edmGuid.GUID[14] / 16);
+ tempBuffer2[34] = hexDigitToChar(value->value.edmGuid.GUID[14] % 16);
+ tempBuffer2[35] = hexDigitToChar(value->value.edmGuid.GUID[15] / 16);
+ tempBuffer2[36] = hexDigitToChar(value->value.edmGuid.GUID[15] % 16);
+
+ tempBuffer2[37] = '\"';
+ tempBuffer2[38] = '\0';
+
+ if (STRING_concat(destination, tempBuffer2) != 0)
+ {
+ result = AGENT_DATA_TYPES_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ result = AGENT_DATA_TYPES_OK;
+ }
+ break;
+ }
+ case EDM_BINARY_TYPE:
+ {
+ size_t currentPosition = 0;
+ char* temp;
+ /*binary types */
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_099:[EDM_BINARY:= *(4base64char)[base64b16 / base64b8]]*/
+ /*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*/
+ size_t neededSize = 2; /*2 because starting and ending quotes */
+ neededSize += (value->value.edmBinary.size == 0) ? (0) : ((((value->value.edmBinary.size-1) / 3) + 1) * 4);
+ neededSize += 1; /*+1 because \0 at the end of the string*/
+ if ((temp = (char*)malloc(neededSize))==NULL)
+ {
+ result = AGENT_DATA_TYPES_ERROR;
+ }
+ 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 destinationPointer = 0;
+ temp[destinationPointer++] = '"';
+ while (value->value.edmBinary.size - currentPosition >= 3)
+ {
+ char c1 = base64char[value->value.edmBinary.data[currentPosition] >> 2];
+ char c2 = base64char[
+ ((value->value.edmBinary.data[currentPosition] & 3) << 4) |
+ (value->value.edmBinary.data[currentPosition + 1] >> 4)
+ ];
+ char c3 = base64char[
+ ((value->value.edmBinary.data[currentPosition + 1] & 0x0F) << 2) |
+ ((value->value.edmBinary.data[currentPosition + 2] >> 6) & 3)
+ ];
+ char c4 = base64char[
+ value->value.edmBinary.data[currentPosition + 2] & 0x3F
+ ];
+ currentPosition += 3;
+ temp[destinationPointer++] = c1;
+ temp[destinationPointer++] = c2;
+ temp[destinationPointer++] = c3;
+ temp[destinationPointer++] = c4;
+
+ }
+ if (value->value.edmBinary.size - currentPosition == 2)
+ {
+ char c1 = base64char[value->value.edmBinary.data[currentPosition] >> 2];
+ char c2 = base64char[
+ ((value->value.edmBinary.data[currentPosition] & 0x03) << 4) |
+ (value->value.edmBinary.data[currentPosition + 1] >> 4)
+ ];
+ char c3 = base64b16[value->value.edmBinary.data[currentPosition + 1] & 0x0F];
+ temp[destinationPointer++] = c1;
+ temp[destinationPointer++] = c2;
+ temp[destinationPointer++] = c3;
+ temp[destinationPointer++] = '=';
+ }
+ else if (value->value.edmBinary.size - currentPosition == 1)
+ {
+ char c1 = base64char[value->value.edmBinary.data[currentPosition] >> 2];
+ char c2 = base64b8[value->value.edmBinary.data[currentPosition] & 0x03];
+ temp[destinationPointer++] = c1;
+ temp[destinationPointer++] = c2;
+ temp[destinationPointer++] = '=';
+ temp[destinationPointer++] = '=';
+ }
+
+ /*closing quote*/
+ temp[destinationPointer++] = '"';
+ /*null terminating the string*/
+ temp[destinationPointer] = '\0';
+
+ if (STRING_concat(destination, temp) != 0)
+ {
+ result = AGENT_DATA_TYPES_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ result = AGENT_DATA_TYPES_OK;
+ }
+ free(temp);
+ }
+ break;
+ }
+ }
+ }
+ return result;
+}
+
+/*return 0 if all names are different than NULL*/
+static int isOneNameNULL(size_t nMemberNames, const char* const * memberNames)
+{
+ size_t i;
+ int result = 0;
+ for (i = 0; i < nMemberNames; i++)
+ {
+ if (memberNames[i] == NULL)
+ {
+ result = 1;
+ break;
+ }
+ }
+ return result;
+}
+
+/*return 0 if all names are different than NULL*/
+static int areThereTwoSameNames(size_t nMemberNames, const char* const * memberNames)
+{
+ size_t i, j;
+ int result = 0;
+ for (i = 0; i < nMemberNames-1; i++)
+ {
+ for (j = i + 1; j < nMemberNames; j++)
+ {
+ if (strcmp(memberNames[i], memberNames[j]) == 0)
+ {
+ result = 1;
+ goto out;
+ }
+ }
+ }
+out:
+ return result;
+}
+
+static void DestroyHalfBakedComplexType(AGENT_DATA_TYPE* agentData)
+{
+ size_t i;
+ if (agentData != NULL)
+ {
+ if (agentData->type == EDM_COMPLEX_TYPE_TYPE)
+ {
+ if (agentData->value.edmComplexType.fields != NULL)
+ {
+ for (i = 0; i < agentData->value.edmComplexType.nMembers; i++)
+ {
+ if (agentData->value.edmComplexType.fields[i].fieldName != NULL)
+ {
+ free((void*)(agentData->value.edmComplexType.fields[i].fieldName));
+ agentData->value.edmComplexType.fields[i].fieldName = NULL;
+ }
+ if (agentData->value.edmComplexType.fields[i].value != NULL)
+ {
+ Destroy_AGENT_DATA_TYPE(agentData->value.edmComplexType.fields[i].value);
+ free(agentData->value.edmComplexType.fields[i].value);
+ agentData->value.edmComplexType.fields[i].value = NULL;
+ }
+ }
+ free(agentData->value.edmComplexType.fields);
+ agentData->value.edmComplexType.fields = NULL;
+ }
+ agentData->type = EDM_NO_TYPE;
+ }
+ }
+}
+
+/* Creates an object of AGENT_DATA_TYPE_TYPE EDM_NULL_TYPE*/
+AGENT_DATA_TYPES_RESULT Create_NULL_AGENT_DATA_TYPE(AGENT_DATA_TYPE* agentData)
+{
+ AGENT_DATA_TYPES_RESULT result;
+ if (agentData == NULL)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ agentData->type = EDM_NULL_TYPE;
+ result = AGENT_DATA_TYPES_OK;
+ }
+ return result;
+}
+/*creates a copy of the AGENT_DATA_TYPE*/
+AGENT_DATA_TYPES_RESULT Create_AGENT_DATA_TYPE_from_AGENT_DATA_TYPE(AGENT_DATA_TYPE* dest, const AGENT_DATA_TYPE* src)
+{
+ AGENT_DATA_TYPES_RESULT result;
+ size_t i;
+ if ((dest == NULL) || (src == NULL))
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ switch (src->type)
+ {
+ default:
+ {
+ result = AGENT_DATA_TYPES_NOT_IMPLEMENTED;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ break;
+ }
+ case(EDM_NO_TYPE) :
+ case(EDM_NULL_TYPE) :
+ {
+ dest->type = src->type;
+ result = AGENT_DATA_TYPES_OK;
+ break;
+ }
+ case(EDM_BOOLEAN_TYPE) :
+ {
+ dest->type = src->type;
+ dest->value.edmBoolean= src->value.edmBoolean;
+ result = AGENT_DATA_TYPES_OK;
+ break;
+ }
+ case(EDM_BYTE_TYPE) :
+ {
+ dest->type = src->type;
+ dest->value.edmByte= src->value.edmByte;
+ result = AGENT_DATA_TYPES_OK;
+ break;
+ }
+ case(EDM_DATE_TYPE) :
+ {
+ dest->type = src->type;
+ dest->value.edmDate = src->value.edmDate;
+ result = AGENT_DATA_TYPES_OK;
+ break;
+ }
+ case(EDM_DATE_TIME_OFFSET_TYPE) :
+ {
+ dest->type = src->type;
+ dest->value.edmDateTimeOffset = src->value.edmDateTimeOffset;
+ result = AGENT_DATA_TYPES_OK;
+ break;
+ }
+ case(EDM_DECIMAL_TYPE) :
+ {
+ if ((dest->value.edmDecimal.value = STRING_clone(src->value.edmDecimal.value)) == NULL)
+ {
+ result = AGENT_DATA_TYPES_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ dest->type = src->type;
+ result = AGENT_DATA_TYPES_OK;
+ /*all is fine*/
+ }
+ break;
+ }
+ case(EDM_DOUBLE_TYPE) :
+ {
+ dest->type = src->type;
+ dest->value.edmDouble = src->value.edmDouble;
+ result = AGENT_DATA_TYPES_OK;
+ break;
+ }
+ case(EDM_DURATION_TYPE) :
+ {
+ result = AGENT_DATA_TYPES_NOT_IMPLEMENTED;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ break;
+ }
+ case(EDM_GUID_TYPE) :
+ {
+ dest->type = src->type;
+ dest->value.edmGuid = src->value.edmGuid;
+ result = AGENT_DATA_TYPES_OK;
+ break;
+ }
+ case EDM_BINARY_TYPE:
+ {
+ if (src->value.edmBinary.size == 0)
+ {
+ dest->value.edmBinary.size = 0;
+ dest->value.edmBinary.data = NULL;
+ dest->type = EDM_BINARY_TYPE;
+ result = AGENT_DATA_TYPES_OK;
+ }
+ else
+ {
+ if ((dest->value.edmBinary.data = (unsigned char*)malloc(src->value.edmBinary.size)) == NULL)
+ {
+ result = AGENT_DATA_TYPES_ERROR;
+ }
+ else
+ {
+ dest->value.edmBinary.size = src->value.edmBinary.size;
+ memcpy(dest->value.edmBinary.data, src->value.edmBinary.data, src->value.edmBinary.size);
+ dest->type = EDM_BINARY_TYPE;
+ result = AGENT_DATA_TYPES_OK;
+ }
+ }
+ break;
+ }
+ case(EDM_INT16_TYPE) :
+ {
+ dest->type = src->type;
+ dest->value.edmInt16 = src->value.edmInt16;
+ result = AGENT_DATA_TYPES_OK;
+ break;
+ }
+ case(EDM_INT32_TYPE) :
+ {
+ dest->type = src->type;
+ dest->value.edmInt32 = src->value.edmInt32;
+ result = AGENT_DATA_TYPES_OK;
+ break;
+ }
+ case(EDM_INT64_TYPE) :
+ {
+ dest->type = src->type;
+ dest->value.edmInt64 = src->value.edmInt64;
+ result = AGENT_DATA_TYPES_OK;
+ break;
+ }
+ case(EDM_SBYTE_TYPE) :
+ {
+ dest->type = src->type;
+ dest->value.edmSbyte = src->value.edmSbyte;
+ result = AGENT_DATA_TYPES_OK;
+ break;
+ }
+ case(EDM_SINGLE_TYPE) :
+ {
+ dest->type = src->type;
+ dest->value.edmSingle = src->value.edmSingle;
+ result = AGENT_DATA_TYPES_OK;
+ break;
+ }
+ case(EDM_STREAM) :
+ {
+ result = AGENT_DATA_TYPES_NOT_IMPLEMENTED;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ break;
+ } /*not supported, because what is stream?*/
+ case(EDM_STRING_TYPE) :
+ {
+ dest->type = src->type;
+ dest->value.edmString.length = src->value.edmString.length;
+ if (mallocAndStrcpy_s((char**)&(dest->value.edmString.chars), (char*)src->value.edmString.chars) != 0)
+ {
+ result = AGENT_DATA_TYPES_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ result = AGENT_DATA_TYPES_OK;
+ /*all is fine*/
+ }
+ break;
+ }
+ case(EDM_STRING_NO_QUOTES_TYPE) :
+ {
+ dest->type = src->type;
+ dest->value.edmStringNoQuotes.length = src->value.edmStringNoQuotes.length;
+ if (mallocAndStrcpy_s((char**)&(dest->value.edmStringNoQuotes.chars), (char*)src->value.edmStringNoQuotes.chars) != 0)
+ {
+ result = AGENT_DATA_TYPES_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ result = AGENT_DATA_TYPES_OK;
+ /*all is fine*/
+ }
+ break;
+ }
+ case(EDM_TIME_OF_DAY_TYPE) :
+ {
+ result = AGENT_DATA_TYPES_NOT_IMPLEMENTED;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ break;
+ }
+ case(EDM_GEOGRAPHY_TYPE) :
+ {
+ result = AGENT_DATA_TYPES_NOT_IMPLEMENTED;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ break;
+ } /*not supported because what is "abstract base type"*/
+ case(EDM_GEOGRAPHY_POINT_TYPE) :
+ {
+ result = AGENT_DATA_TYPES_NOT_IMPLEMENTED;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ break;
+ }
+ case(EDM_GEOGRAPHY_LINE_STRING_TYPE) :
+ {
+ result = AGENT_DATA_TYPES_NOT_IMPLEMENTED;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ break;
+ }
+ case(EDM_GEOGRAPHY_POLYGON_TYPE) :
+ {
+ result = AGENT_DATA_TYPES_NOT_IMPLEMENTED;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ break;
+ }
+ case(EDM_GEOGRAPHY_MULTI_POINT_TYPE) :
+ {
+ result = AGENT_DATA_TYPES_NOT_IMPLEMENTED;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ break;
+ }
+ case(EDM_GEOGRAPHY_MULTI_LINE_STRING_TYPE) :
+ {
+ result = AGENT_DATA_TYPES_NOT_IMPLEMENTED;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ break;
+ }
+ case(EDM_GEOGRAPHY_MULTI_POLYGON_TYPE) :
+ {
+ result = AGENT_DATA_TYPES_NOT_IMPLEMENTED;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ break;
+ }
+ case(EDM_GEOGRAPHY_COLLECTION_TYPE) :
+ {
+ result = AGENT_DATA_TYPES_NOT_IMPLEMENTED;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ break;
+ }
+ case(EDM_GEOMETRY_TYPE) :
+ {
+ result = AGENT_DATA_TYPES_NOT_IMPLEMENTED;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ break;
+ } /*not supported because what is "abstract base type"*/
+ case(EDM_GEOMETRY_POINT_TYPE) :
+ {
+ result = AGENT_DATA_TYPES_NOT_IMPLEMENTED;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ break;
+ }
+ case(EDM_GEOMETRY_LINE_STRING_TYPE) :
+ {
+ result = AGENT_DATA_TYPES_NOT_IMPLEMENTED;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ break;
+ }
+ case(EDM_GEOMETRY_POLYGON_TYPE) :
+ {
+ result = AGENT_DATA_TYPES_NOT_IMPLEMENTED;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ break;
+ }
+ case(EDM_GEOMETRY_MULTI_POINT_TYPE) :
+ {
+ result = AGENT_DATA_TYPES_NOT_IMPLEMENTED;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ break;
+ }
+ case(EDM_GEOMETRY_MULTI_LINE_STRING_TYPE) :
+ {
+ result = AGENT_DATA_TYPES_NOT_IMPLEMENTED;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ break;
+ }
+ case(EDM_GEOMETRY_MULTI_POLYGON_TYPE) :
+ {
+ result = AGENT_DATA_TYPES_NOT_IMPLEMENTED;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ break;
+ }
+ case(EDM_GEOMETRY_COLLECTION_TYPE) :
+ {
+ result = AGENT_DATA_TYPES_NOT_IMPLEMENTED;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ break;
+ }
+ case(EDM_COMPLEX_TYPE_TYPE) :
+ {
+ result = AGENT_DATA_TYPES_OK;
+ /*copying a COMPLEX_TYPE means to copy all its member names and all its fields*/
+ dest->type = src->type;
+ if (src->value.edmComplexType.nMembers == 0)
+ {
+ /*error*/
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ dest->value.edmComplexType.nMembers = src->value.edmComplexType.nMembers;
+ dest->value.edmComplexType.fields = (COMPLEX_TYPE_FIELD_TYPE*)malloc(dest->value.edmComplexType.nMembers * sizeof(COMPLEX_TYPE_FIELD_TYPE));
+ if (dest->value.edmComplexType.fields == NULL)
+ {
+ result = AGENT_DATA_TYPES_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ for (i = 0; i < dest->value.edmComplexType.nMembers; i++)
+ {
+ dest->value.edmComplexType.fields[i].fieldName = NULL;
+ dest->value.edmComplexType.fields[i].value = NULL;
+ }
+
+ for (i = 0; i < dest->value.edmComplexType.nMembers; i++)
+ {
+ /*copy the name of this field*/
+ if (mallocAndStrcpy_s((char**)(&(dest->value.edmComplexType.fields[i].fieldName)), src->value.edmComplexType.fields[i].fieldName) != 0)
+ {
+ result = AGENT_DATA_TYPES_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ break;
+ }
+ else
+ {
+ /*field name copied success*/
+ /*field value copy follows*/
+ dest->value.edmComplexType.fields[i].value = (AGENT_DATA_TYPE*)malloc(sizeof(AGENT_DATA_TYPE));
+ if (dest->value.edmComplexType.fields[i].value == NULL)
+ {
+ result = AGENT_DATA_TYPES_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ break;
+ }
+ else
+ {
+ if (Create_AGENT_DATA_TYPE_from_AGENT_DATA_TYPE(dest->value.edmComplexType.fields[i].value, src->value.edmComplexType.fields[i].value) != AGENT_DATA_TYPES_OK)
+ {
+ result = AGENT_DATA_TYPES_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ break;
+ }
+ else
+ {
+ /*all is fine*/
+ }
+ }
+ }
+ }
+
+ if (result != AGENT_DATA_TYPES_OK)
+ {
+ /*unbuild*/
+ DestroyHalfBakedComplexType(dest);
+ }
+ }
+ }
+ break;
+ } /*ANY CHANGE (?!) here must be reflected in the tool providing the binary file (XML2BINARY) */
+ }
+
+ if (result != AGENT_DATA_TYPES_OK)
+ {
+ dest->type = EDM_NO_TYPE;
+ }
+ }
+
+ return result;
+}
+
+AGENT_DATA_TYPES_RESULT Create_AGENT_DATA_TYPE_from_MemberPointers(AGENT_DATA_TYPE* agentData, const char* typeName, size_t nMembers, const char* const * memberNames, const AGENT_DATA_TYPE** memberPointerValues)
+{
+ AGENT_DATA_TYPES_RESULT result;
+
+ /* Codes_SRS_AGENT_TYPE_SYSTEM_99_109:[ AGENT_DATA_TYPES_INVALID_ARG shall be returned if memberPointerValues parameter is NULL.] */
+ if (memberPointerValues == NULL)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ LogError("(result: AGENT_DATA_TYPES_INVALID_ARG)\r\n");
+ }
+ else
+ {
+ AGENT_DATA_TYPE* values = (AGENT_DATA_TYPE*)malloc(nMembers* sizeof(AGENT_DATA_TYPE));
+ if (values == NULL)
+ {
+ result = AGENT_DATA_TYPES_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ size_t i;
+ for (i = 0; i < nMembers; i++)
+ {
+ if (Create_AGENT_DATA_TYPE_from_AGENT_DATA_TYPE(values + i, memberPointerValues[i]) != AGENT_DATA_TYPES_OK)
+ {
+ size_t j;
+ for (j = 0; j < i; j++)
+ {
+ Destroy_AGENT_DATA_TYPE(values + j);
+ }
+ break;
+ }
+ }
+
+ if (i != nMembers)
+ {
+ result = AGENT_DATA_TYPES_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ /* SRS_AGENT_TYPE_SYSTEM_99_111:[ AGENT_DATA_TYPES_OK shall be returned upon success.] */
+ result = Create_AGENT_DATA_TYPE_from_Members(agentData, typeName, nMembers, memberNames, values);
+ if (result != AGENT_DATA_TYPES_OK)
+ {
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ for (i = 0; i < nMembers; i++)
+ {
+ Destroy_AGENT_DATA_TYPE(&values[i]);
+ }
+ }
+ free(values);
+ }
+ }
+ return result;
+}
+
+AGENT_DATA_TYPES_RESULT Create_AGENT_DATA_TYPE_from_Members(AGENT_DATA_TYPE* agentData, const char* typeName, size_t nMembers, const char* const * memberNames, const AGENT_DATA_TYPE* memberValues)
+{
+ AGENT_DATA_TYPES_RESULT result;
+ size_t i;
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_013:[ All the functions shall check their parameters for validity. When an invalid parameter is detected, the value AGENT_DATA_TYPES_INVALID_ARG shall be returned ]*/
+ if (agentData == NULL)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ LogError("(result: AGENT_DATA_TYPES_INVALID_ARG)\r\n");
+ }
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_055:[ If typeName is NULL, the function shall return AGENT_DATA_TYPES_INVALID_ARG .]*/
+ else if (typeName==NULL)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ LogError("(result: AGENT_DATA_TYPES_INVALID_ARG)\r\n");
+ }
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_056:[If nMembers is 0, the function shall return AGENT_DATA_TYPES_INVALID_ARG .]*/
+ else if (nMembers == 0)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_057:[ If memberNames is NULL, the function shall return AGENT_DATA_TYPES_INVALID_ARG .]*/
+ else if (memberNames == NULL)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_058:[ If any of the memberNames[i] is NULL, the function shall return AGENT_DATA_TYPES_INVALID_ARG .]*/
+ else if (isOneNameNULL(nMembers, memberNames)!=0)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_059:[ If memberValues is NULL, the function shall return AGENT_DATA_TYPES_INVALID_ARG .]*/
+ else if (memberValues == NULL)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_063:[ If there are two memberNames with the same name, then the function shall return AGENT_DATA_TYPES_INVALID_ARG.]*/
+ else if (areThereTwoSameNames(nMembers, memberNames) != 0)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ agentData->value.edmComplexType.nMembers = nMembers;
+ agentData->value.edmComplexType.fields = (COMPLEX_TYPE_FIELD_TYPE*)malloc(nMembers *sizeof(COMPLEX_TYPE_FIELD_TYPE));
+ if (agentData->value.edmComplexType.fields == NULL)
+ {
+ result = AGENT_DATA_TYPES_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ result = AGENT_DATA_TYPES_OK; /*not liking this, solution might be to use a temp variable*/
+
+ /*initialize the fields*/
+ for (i = 0; i < nMembers; i++)
+ {
+ agentData->value.edmComplexType.fields[i].fieldName = NULL;
+ agentData->value.edmComplexType.fields[i].value = NULL;
+ }
+
+ for (i = 0; i < nMembers; i++)
+ {
+ /*copy the name*/
+ if (mallocAndStrcpy_s((char**)(&(agentData->value.edmComplexType.fields[i].fieldName)), memberNames[i]) != 0)
+ {
+ result = AGENT_DATA_TYPES_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ break;
+ }
+ else
+ {
+ /*field name was transferred successfully*/
+ /*copy the rest*/
+ agentData->value.edmComplexType.fields[i].value = (AGENT_DATA_TYPE*)malloc(sizeof(AGENT_DATA_TYPE));
+ if (agentData->value.edmComplexType.fields[i].value == NULL)
+ {
+ /*deallocate the name*/
+ free((void*)(agentData->value.edmComplexType.fields[i].fieldName));
+ agentData->value.edmComplexType.fields[i].fieldName = NULL;
+ result = AGENT_DATA_TYPES_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ break;
+ }
+ else
+ {
+ /*copy the values*/
+ if (Create_AGENT_DATA_TYPE_from_AGENT_DATA_TYPE(agentData->value.edmComplexType.fields[i].value, &(memberValues[i])) != AGENT_DATA_TYPES_OK)
+ {
+ result = AGENT_DATA_TYPES_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ break;
+ }
+ else
+ {
+ /*all is fine*/
+ }
+ }
+ }
+
+ }
+ }
+
+ if (result != AGENT_DATA_TYPES_OK)
+ {
+ /*dealloc, something went bad*/
+ DestroyHalfBakedComplexType(agentData);
+ }
+ else
+ {
+ agentData->type = EDM_COMPLEX_TYPE_TYPE;
+ }
+ }
+ return result;
+}
+
+#define isLeapYear(y) ((((y) % 400) == 0) || (((y)%4==0)&&(!((y)%100==0))))
+
+const int daysInAllPreviousMonths[12] = {
+ 0,
+ 31,
+ 31 + 28,
+ 31 + 28 + 31,
+ 31 + 28 + 31 + 30,
+ 31 + 28 + 31 + 30 + 31,
+ 31 + 28 + 31 + 30 + 31 + 30,
+ 31 + 28 + 31 + 30 + 31 + 30 + 31,
+ 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31,
+ 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
+ 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
+ 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30
+};
+
+/*this function assumes a correctly filled in tm_year, tm_mon and tm_mday and will fill in tm_yday and tm_wday*/
+static void fill_tm_yday_and_tm_wday(struct tm* source)
+{
+ /*to fill in tm_yday the function shall add the number of days in every month, not including the current one*/
+ /*and then it will add the number of days in the current month*/
+ /*1st of Jan is day "0" in a year*/
+ int year = source->tm_year + 1900 + 10000;
+ int nLeapYearsSinceYearMinus9999 = ((year - 1) / 4) - ((year - 1) / 100) + ((year - 1) / 400);
+ source->tm_yday = (daysInAllPreviousMonths[source->tm_mon]) + (source->tm_mday - 1) + ((source->tm_mon > 1 /*1 is Feb*/) && isLeapYear(year));
+ source->tm_wday = ((365 * year + nLeapYearsSinceYearMinus9999) + source->tm_yday) % 7;
+ /*day "0" is 1st jan -9999 (this is how much odata can span*/
+ /*the function shall count days */
+}
+
+AGENT_DATA_TYPES_RESULT CreateAgentDataType_From_String(const char* source, AGENT_DATA_TYPE_TYPE type, AGENT_DATA_TYPE* agentData)
+{
+
+ AGENT_DATA_TYPES_RESULT result;
+
+ /* Codes_SRS_AGENT_TYPE_SYSTEM_99_073:[ CreateAgentDataType_From_String shall return AGENT_DATA_TYPES_INVALID_ARG if source is NULL.] */
+ if ((source == NULL) ||
+ /* Codes_SRS_AGENT_TYPE_SYSTEM_99_074:[ CreateAgentDataType_From_String shall return AGENT_DATA_TYPES_INVALID_ARG if agentData is NULL.] */
+ (agentData == NULL))
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ /* Codes_SRS_AGENT_TYPE_SYSTEM_99_071:[ CreateAgentDataType_From_String shall create an AGENT_DATA_TYPE from a char* representation of the type indicated by type parameter.] */
+ /* Codes_SRS_AGENT_TYPE_SYSTEM_99_072:[ The implementation for the transformation of the char* source into AGENT_DATA_TYPE shall be type specific.] */
+ switch (type)
+ {
+ default:
+ /* Codes_SRS_AGENT_TYPE_SYSTEM_99_075:[ CreateAgentDataType_From_String shall return AGENT_DATA_TYPES_NOT_IMPLEMENTED if type is not a supported type.] */
+ result = AGENT_DATA_TYPES_NOT_IMPLEMENTED;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ break;
+
+ /* Codes_SRS_AGENT_TYPE_SYSTEM_99_086:[ EDM_STRING] */
+ case EDM_BOOLEAN_TYPE:
+ {
+ if (strcmp(source, "true") == 0)
+ {
+ agentData->type = EDM_BOOLEAN_TYPE;
+ agentData->value.edmBoolean.value = EDM_TRUE;
+ result = AGENT_DATA_TYPES_OK;
+ }
+ else if (strcmp(source, "false") == 0)
+ {
+ agentData->type = EDM_BOOLEAN_TYPE;
+ agentData->value.edmBoolean.value = EDM_FALSE;
+ result = AGENT_DATA_TYPES_OK;
+ }
+ else
+ {
+ /* Codes_SRS_AGENT_TYPE_SYSTEM_99_087:[ CreateAgentDataType_From_String shall return AGENT_DATA_TYPES_INVALID_ARG if source is not a valid string for a value of type type.] */
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+
+ break;
+ }
+ case EDM_NULL_TYPE:
+ {
+ if (strcmp(source, "null") == 0)
+ {
+ agentData->type = EDM_NULL_TYPE;
+ result = AGENT_DATA_TYPES_OK;
+ }
+ else
+ {
+ /* Codes_SRS_AGENT_TYPE_SYSTEM_99_087:[ CreateAgentDataType_From_String shall return AGENT_DATA_TYPES_INVALID_ARG if source is not a valid string for a value of type type.] */
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+
+ break;
+ }
+
+ /* Codes_SRS_AGENT_TYPE_SYSTEM_99_084:[ EDM_SBYTE] */
+ case EDM_SBYTE_TYPE:
+ {
+ int sByteValue;
+ if ((sscanf(source, "%d", &sByteValue) != 1) ||
+ (sByteValue < -128) ||
+ (sByteValue > 127))
+ {
+ /* Codes_SRS_AGENT_TYPE_SYSTEM_99_087:[ CreateAgentDataType_From_String shall return AGENT_DATA_TYPES_INVALID_ARG if source is not a valid string for a value of type type.] */
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ agentData->type = EDM_SBYTE_TYPE;
+ agentData->value.edmSbyte.value = (int8_t)sByteValue;
+ result = AGENT_DATA_TYPES_OK;
+ }
+
+ break;
+ }
+
+ /* Codes_SRS_AGENT_TYPE_SYSTEM_99_077:[ EDM_BYTE] */
+ case EDM_BYTE_TYPE:
+ {
+ int byteValue;
+ if ((sscanf(source, "%d", &byteValue) != 1) ||
+ (byteValue < 0) ||
+ (byteValue > 255))
+ {
+ /* Codes_SRS_AGENT_TYPE_SYSTEM_99_087:[ CreateAgentDataType_From_String shall return AGENT_DATA_TYPES_INVALID_ARG if source is not a valid string for a value of type type.] */
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ agentData->type = EDM_BYTE_TYPE;
+ agentData->value.edmByte.value = (uint8_t)byteValue;
+ result = AGENT_DATA_TYPES_OK;
+ }
+
+ break;
+ }
+
+ /* Codes_SRS_AGENT_TYPE_SYSTEM_99_081:[ EDM_INT16] */
+ case EDM_INT16_TYPE:
+ {
+ int int16Value;
+ if ((sscanf(source, "%d", &int16Value) != 1) ||
+ (int16Value < -32768) ||
+ (int16Value > 32767))
+ {
+ /* Codes_SRS_AGENT_TYPE_SYSTEM_99_087:[ CreateAgentDataType_From_String shall return AGENT_DATA_TYPES_INVALID_ARG if source is not a valid string for a value of type type.] */
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ agentData->type = EDM_INT16_TYPE;
+ agentData->value.edmInt16.value = (int16_t)int16Value;
+ result = AGENT_DATA_TYPES_OK;
+ }
+
+ break;
+ }
+
+ /* Codes_SRS_AGENT_TYPE_SYSTEM_99_082:[ EDM_INT32] */
+ case EDM_INT32_TYPE:
+ {
+ long long int32Value;
+ if ((sscanf(source, "%lld", &int32Value) != 1) ||
+ (int32Value < -2147483648LL) ||
+ (int32Value > 2147483647))
+ {
+ /* Codes_SRS_AGENT_TYPE_SYSTEM_99_087:[ CreateAgentDataType_From_String shall return AGENT_DATA_TYPES_INVALID_ARG if source is not a valid string for a value of type type.] */
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ agentData->type = EDM_INT32_TYPE;
+ agentData->value.edmInt32.value = (int32_t)int32Value;
+ result = AGENT_DATA_TYPES_OK;
+ }
+
+ break;
+ }
+
+ /* Codes_SRS_AGENT_TYPE_SYSTEM_99_083:[ EDM_INT64] */
+ case EDM_INT64_TYPE:
+ {
+ long long int64Value;
+ unsigned char isNegative;
+ unsigned long long ullValue;
+ const char* pos;
+ size_t strLength;
+
+ if (source[0] == '-')
+ {
+ isNegative = 1;
+ pos = &source[1];
+ }
+ else
+ {
+ isNegative = 0;
+ pos = &source[0];
+ }
+
+ strLength = strlen(source);
+
+ if ((sscanf(pos, "%llu", &ullValue) != 1) ||
+ (strLength > 20) ||
+ ((ullValue > 9223372036854775808ULL) && isNegative) ||
+ ((ullValue > 9223372036854775807ULL) && (!isNegative)))
+ {
+ /* Codes_SRS_AGENT_TYPE_SYSTEM_99_087:[ CreateAgentDataType_From_String shall return AGENT_DATA_TYPES_INVALID_ARG if source is not a valid string for a value of type type.] */
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ if (isNegative)
+ {
+ if (ullValue == 9223372036854775808ULL)
+ {
+ int64Value = -9223372036854775807LL - 1LL;
+ }
+ else
+ {
+ int64Value = -(long long)ullValue;
+ }
+ }
+ else
+ {
+ int64Value = ullValue;
+ }
+ agentData->type = EDM_INT64_TYPE;
+ agentData->value.edmInt64.value = (int64_t)int64Value;
+ result = AGENT_DATA_TYPES_OK;
+ }
+
+ break;
+ }
+
+ /* Codes_SRS_AGENT_TYPE_SYSTEM_99_085:[ EDM_DATE] */
+ case EDM_DATE_TYPE:
+ {
+ int year;
+ int month;
+ int day;
+ size_t strLength = strlen(source);
+
+ if ((strLength < 2) ||
+ (source[0] != '"') ||
+ (source[strlen(source) - 1] != '"'))
+ {
+ /* Codes_SRS_AGENT_TYPE_SYSTEM_99_087:[ CreateAgentDataType_From_String shall return AGENT_DATA_TYPES_INVALID_ARG if source is not a valid string for a value of type type.] */
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ size_t pos = 1;
+ int sign;
+ scanOptionalMinusSign(source, 2, &pos, &sign);
+
+ if ((scanAndReadNDigitsInt(source, strLength, &pos, &year, 4) != 0) ||
+ (source[pos++] != '-') ||
+ (scanAndReadNDigitsInt(source, strLength, &pos, &month, 2) != 0) ||
+ (source[pos++] != '-') ||
+ (scanAndReadNDigitsInt(source, strLength, &pos, &day, 2) != 0) ||
+ (Create_AGENT_DATA_TYPE_from_date(agentData, (int16_t)(sign*year), (uint8_t)month, (uint8_t)day) != AGENT_DATA_TYPES_OK))
+ {
+ /* Codes_SRS_AGENT_TYPE_SYSTEM_99_087:[ CreateAgentDataType_From_String shall return AGENT_DATA_TYPES_INVALID_ARG if source is not a valid string for a value of type type.] */
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ result = AGENT_DATA_TYPES_OK;
+ }
+ }
+
+ break;
+ }
+
+ /* Codes_SRS_AGENT_TYPE_SYSTEM_99_078:[ EDM_DATETIMEOFFSET] */
+ case EDM_DATE_TIME_OFFSET_TYPE:
+ {
+ int year;
+ int month;
+ int day;
+ int hour;
+ int min;
+ int sec = 0;
+ int hourOffset;
+ int minOffset;
+ unsigned long long fractionalSeconds = 0;
+ size_t strLength = strlen(source);
+
+ agentData->value.edmDateTimeOffset.hasFractionalSecond = 0;
+ agentData->value.edmDateTimeOffset.hasTimeZone = 0;
+ /* The value of tm_isdst is positive if Daylight Saving Time is in effect, zero if Daylight
+ Saving Time is not in effect, and negative if the information is not available.*/
+ agentData->value.edmDateTimeOffset.dateTime.tm_isdst = -1;
+
+ if ((strLength < 2) ||
+ (source[0] != '"') ||
+ (source[strlen(source) - 1] != '"'))
+ {
+ /* Codes_SRS_AGENT_TYPE_SYSTEM_99_087:[ CreateAgentDataType_From_String shall return AGENT_DATA_TYPES_INVALID_ARG if source is not a valid string for a value of type type.] */
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ size_t pos = 1;
+ int sign;
+ scanOptionalMinusSign(source, 2, &pos, &sign);
+
+ if ((scanAndReadNDigitsInt(source, strLength, &pos, &year, 4) != 0) ||
+ (source[pos++] != '-') ||
+ (scanAndReadNDigitsInt(source, strLength, &pos, &month, 2) != 0) ||
+ (source[pos++] != '-') ||
+ (scanAndReadNDigitsInt(source, strLength, &pos, &day, 2) != 0) ||
+ (source[pos++] != 'T') ||
+ (scanAndReadNDigitsInt(source, strLength, &pos, &hour, 2) != 0) ||
+ (source[pos++] != ':') ||
+ (scanAndReadNDigitsInt(source, strLength, &pos, &min, 2) != 0))
+ {
+ /* Codes_SRS_AGENT_TYPE_SYSTEM_99_087:[ CreateAgentDataType_From_String shall return AGENT_DATA_TYPES_INVALID_ARG if source is not a valid string for a value of type type.] */
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ const char* pos2;
+ year = year*sign;
+ if ((pos2 = strchr(source, ':')) == NULL)
+ {
+ /* Codes_SRS_AGENT_TYPE_SYSTEM_99_087:[ CreateAgentDataType_From_String shall return AGENT_DATA_TYPES_INVALID_ARG if source is not a valid string for a value of type type.] */
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ pos2 += 3;
+ if (*pos2 == ':')
+ {
+ if (sscanf(pos2, ":%02d", &sec) != 1)
+ {
+ pos2 = NULL;
+ }
+ else
+ {
+ pos2 += 3;
+ }
+ }
+
+ if ((pos2 != NULL) &&
+ (*pos2 == '.'))
+ {
+ if (sscanf(pos2, ".%llu", &fractionalSeconds) != 1)
+ {
+ pos2 = NULL;
+ }
+ else
+ {
+ pos2++;
+
+ agentData->value.edmDateTimeOffset.hasFractionalSecond = 1;
+
+ while ((*pos2 != '\0') &&
+ (IS_DIGIT(*pos2)))
+ {
+ pos2++;
+ }
+
+ if (*pos2 == '\0')
+ {
+ pos2 = NULL;
+ }
+ }
+ }
+
+ if (pos2 == NULL)
+ {
+ /* Codes_SRS_AGENT_TYPE_SYSTEM_99_087:[ CreateAgentDataType_From_String shall return AGENT_DATA_TYPES_INVALID_ARG if source is not a valid string for a value of type type.] */
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ hourOffset = 0;
+ minOffset = 0;
+
+ if (sscanf(pos2, "%03d:%02d\"", &hourOffset, &minOffset) == 2)
+ {
+ agentData->value.edmDateTimeOffset.hasTimeZone = 1;
+ }
+
+ if ((strcmp(pos2, "Z\"") == 0) ||
+ agentData->value.edmDateTimeOffset.hasTimeZone)
+ {
+ if ((ValidateDate(year, month, day) != 0) ||
+ (hour < 0) ||
+ (hour > 23) ||
+ (min < 0) ||
+ (min > 59) ||
+ (sec < 0) ||
+ (sec > 59) ||
+ (fractionalSeconds > 999999999999) ||
+ (hourOffset < -23) ||
+ (hourOffset > 23) ||
+ (minOffset < 0) ||
+ (minOffset > 59))
+ {
+ /* Codes_SRS_AGENT_TYPE_SYSTEM_99_087:[ CreateAgentDataType_From_String shall return AGENT_DATA_TYPES_INVALID_ARG if source is not a valid string for a value of type type.] */
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ agentData->type = EDM_DATE_TIME_OFFSET_TYPE;
+ agentData->value.edmDateTimeOffset.dateTime.tm_year= year-1900;
+ agentData->value.edmDateTimeOffset.dateTime.tm_mon = month-1;
+ agentData->value.edmDateTimeOffset.dateTime.tm_mday = day;
+ agentData->value.edmDateTimeOffset.dateTime.tm_hour = hour;
+ agentData->value.edmDateTimeOffset.dateTime.tm_min = min;
+ agentData->value.edmDateTimeOffset.dateTime.tm_sec = sec;
+ /*fill in tm_wday and tm_yday*/
+ fill_tm_yday_and_tm_wday(&agentData->value.edmDateTimeOffset.dateTime);
+ agentData->value.edmDateTimeOffset.fractionalSecond = (uint64_t)fractionalSeconds;
+ agentData->value.edmDateTimeOffset.timeZoneHour = (int8_t)hourOffset;
+ agentData->value.edmDateTimeOffset.timeZoneMinute = (uint8_t)minOffset;
+ result = AGENT_DATA_TYPES_OK;
+ }
+ }
+ else
+ {
+ /* Codes_SRS_AGENT_TYPE_SYSTEM_99_087:[ CreateAgentDataType_From_String shall return AGENT_DATA_TYPES_INVALID_ARG if source is not a valid string for a value of type type.] */
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ }
+ }
+ }
+ }
+
+ break;
+ }
+
+ /* Codes_SRS_AGENT_TYPE_SYSTEM_99_080:[ EDM_DOUBLE] */
+ case EDM_DOUBLE_TYPE:
+ {
+ if (strcmp(source, "\"NaN\"") == 0)
+ {
+ agentData->type = EDM_DOUBLE_TYPE;
+ agentData->value.edmDouble.value = NAN;
+ result = AGENT_DATA_TYPES_OK;
+ }
+ else if (strcmp(source, "\"INF\"") == 0)
+ {
+ agentData->type = EDM_DOUBLE_TYPE;
+ agentData->value.edmDouble.value = INFINITY;
+ result = AGENT_DATA_TYPES_OK;
+ }
+ else if (strcmp(source, "\"-INF\"") == 0)
+ {
+ agentData->type = EDM_DOUBLE_TYPE;
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable: 4056) /* Known warning for INIFNITY */
+#endif
+ agentData->value.edmDouble.value = -INFINITY;
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+ result = AGENT_DATA_TYPES_OK;
+ }
+ else if (sscanf(source, "%lf", &agentData->value.edmDouble.value) != 1)
+ {
+ /* Codes_SRS_AGENT_TYPE_SYSTEM_99_087:[ CreateAgentDataType_From_String shall return AGENT_DATA_TYPES_INVALID_ARG if source is not a valid string for a value of type type.] */
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ }
+ else
+ {
+ agentData->type = EDM_DOUBLE_TYPE;
+ result = AGENT_DATA_TYPES_OK;
+ }
+ break;
+ }
+
+ /* Codes_SRS_AGENT_TYPE_SYSTEM_99_089:[EDM_SINGLE] */
+ case EDM_SINGLE_TYPE:
+ {
+ if (strcmp(source, "\"NaN\"") == 0)
+ {
+ agentData->type = EDM_SINGLE_TYPE;
+ agentData->value.edmSingle.value = NAN;
+ result = AGENT_DATA_TYPES_OK;
+ }
+ else if (strcmp(source, "\"INF\"") == 0)
+ {
+ agentData->type = EDM_SINGLE_TYPE;
+ agentData->value.edmSingle.value = INFINITY;
+ result = AGENT_DATA_TYPES_OK;
+ }
+ else if (strcmp(source, "\"-INF\"") == 0)
+ {
+ agentData->type = EDM_SINGLE_TYPE;
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable: 4056) /* Known warning for INIFNITY */
+#endif
+ agentData->value.edmSingle.value = -INFINITY;
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+result = AGENT_DATA_TYPES_OK;
+ }
+ else if (sscanf(source, "%f", &agentData->value.edmSingle.value) != 1)
+ {
+ /* Codes_SRS_AGENT_TYPE_SYSTEM_99_087:[ CreateAgentDataType_From_String shall return AGENT_DATA_TYPES_INVALID_ARG if source is not a valid string for a value of type type.] */
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ agentData->type = EDM_SINGLE_TYPE;
+ result = AGENT_DATA_TYPES_OK;
+ }
+ break;
+ }
+
+ /* Codes_SRS_AGENT_TYPE_SYSTEM_99_079:[ EDM_DECIMAL] */
+ case EDM_DECIMAL_TYPE:
+ {
+ size_t strLength = strlen(source);
+ if ((strLength < 2) ||
+ (source[0] != '"') ||
+ (source[strLength - 1] != '"') ||
+ (ValidateDecimal(source + 1, strLength - 2) != 0))
+ {
+ /* Codes_SRS_AGENT_TYPE_SYSTEM_99_087:[ CreateAgentDataType_From_String shall return AGENT_DATA_TYPES_INVALID_ARG if source is not a valid string for a value of type type.] */
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ agentData->type = EDM_DECIMAL_TYPE;
+ agentData->value.edmDecimal.value = STRING_construct_n(source + 1, strLength-2);
+ if (agentData->value.edmDecimal.value == NULL)
+ {
+ /* Codes_SRS_AGENT_TYPE_SYSTEM_99_088:[ CreateAgentDataType_From_String shall return AGENT_DATA_TYPES_ERROR if any other error occurs.] */
+ result = AGENT_DATA_TYPES_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ result = AGENT_DATA_TYPES_OK;
+ }
+ }
+ break;
+ }
+
+ /* Codes_SRS_AGENT_TYPE_SYSTEM_99_086:[ EDM_STRING] */
+ case EDM_STRING_TYPE:
+ {
+ size_t strLength = strlen(source);
+ if ((strLength < 2) ||
+ (source[0] != '"') ||
+ (source[strLength - 1] != '"'))
+ {
+ /* Codes_SRS_AGENT_TYPE_SYSTEM_99_087:[ CreateAgentDataType_From_String shall return AGENT_DATA_TYPES_INVALID_ARG if source is not a valid string for a value of type type.] */
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ char* temp;
+ if ((temp = (char*)malloc(strLength - 1)) == NULL)
+ {
+ result = AGENT_DATA_TYPES_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else if (strncpy_s(temp, strLength - 1, source + 1, strLength - 2) != 0)
+ {
+ free(temp);
+
+ result = AGENT_DATA_TYPES_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ temp[strLength - 2] = 0;
+
+ agentData->type = EDM_STRING_TYPE;
+ agentData->value.edmString.chars = temp;
+ agentData->value.edmString.length = strLength - 2;
+ result = AGENT_DATA_TYPES_OK;
+ }
+ }
+ break;
+ }
+ /* Codes_SRS_AGENT_TYPE_SYSTEM_01_004: [EDM_STRING_NO_QUOTES] */
+ case EDM_STRING_NO_QUOTES_TYPE:
+ {
+ char* temp;
+ size_t strLength = strlen(source);
+ if (mallocAndStrcpy_s(&temp, source) != 0)
+ {
+ result = AGENT_DATA_TYPES_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ agentData->type = EDM_STRING_NO_QUOTES_TYPE;
+ agentData->value.edmStringNoQuotes.chars = temp;
+ agentData->value.edmStringNoQuotes.length = strLength;
+ result = AGENT_DATA_TYPES_OK;
+ }
+ break;
+ }
+ /*Codes_SRS_AGENT_TYPE_SYSTEM_99_097:[ EDM_GUID]*/
+ case EDM_GUID_TYPE:
+ {
+ if (strlen(source) != GUID_STRING_LENGHT)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ }
+ else
+ {
+ if (source[0] != '"')
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ }
+ else if (scanMandatory2CapitalHexDigits(source + 1, &(agentData->value.edmGuid.GUID[0])) != 0)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ }
+ else if (scanMandatory2CapitalHexDigits(source + 3, &(agentData->value.edmGuid.GUID[1])) != 0)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ }
+ else if (scanMandatory2CapitalHexDigits(source + 5, &(agentData->value.edmGuid.GUID[2])) != 0)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ }
+ else if (scanMandatory2CapitalHexDigits(source + 7, &(agentData->value.edmGuid.GUID[3])) != 0)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ }
+ else if (source[9] != '-')
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ }
+ else if (scanMandatory2CapitalHexDigits(source + 10, &(agentData->value.edmGuid.GUID[4])) != 0)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ }
+ else if (scanMandatory2CapitalHexDigits(source + 12, &(agentData->value.edmGuid.GUID[5])) != 0)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ }
+ else if (source[14] != '-')
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ }
+ else if (scanMandatory2CapitalHexDigits(source + 15, &(agentData->value.edmGuid.GUID[6])) != 0)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ }
+ else if (scanMandatory2CapitalHexDigits(source + 17, &(agentData->value.edmGuid.GUID[7])) != 0)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ }
+ else if (source[19] != '-')
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ }
+ else if (scanMandatory2CapitalHexDigits(source + 20, &(agentData->value.edmGuid.GUID[8])) != 0)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ }
+ else if (scanMandatory2CapitalHexDigits(source + 22, &(agentData->value.edmGuid.GUID[9])) != 0)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ }
+ else if (source[24] != '-')
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ }
+ else if (scanMandatory2CapitalHexDigits(source + 25, &(agentData->value.edmGuid.GUID[10])) != 0)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ }
+ else if (scanMandatory2CapitalHexDigits(source + 27, &(agentData->value.edmGuid.GUID[11])) != 0)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ }
+ else if (scanMandatory2CapitalHexDigits(source + 29, &(agentData->value.edmGuid.GUID[12])) != 0)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ }
+ else if (scanMandatory2CapitalHexDigits(source + 31, &(agentData->value.edmGuid.GUID[13])) != 0)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ }
+ else if (scanMandatory2CapitalHexDigits(source + 33, &(agentData->value.edmGuid.GUID[14])) != 0)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ }
+ else if (scanMandatory2CapitalHexDigits(source + 35, &(agentData->value.edmGuid.GUID[15])) != 0)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ }
+ else if (source[37] != '"')
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ }
+ else
+ {
+ agentData->type = EDM_GUID_TYPE;
+ result = AGENT_DATA_TYPES_OK;
+ }
+ }
+ break;
+ }
+ case EDM_BINARY_TYPE:
+ {
+ size_t sourceLength = strlen(source);
+ if (sourceLength < 2)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ }
+ else if (sourceLength == 2)
+ {
+ agentData->type = EDM_BINARY_TYPE;
+ agentData->value.edmBinary.data = NULL;
+ agentData->value.edmBinary.size = 0;
+ result = AGENT_DATA_TYPES_OK;
+ }
+ else
+ {
+ size_t sourcePosition = 0;
+ if (source[sourcePosition++] != '"') /*if it doesn't start with a quote then... */
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ }
+ else
+ {
+ /*1. read groups of 4 base64 character and transfer those into groups of 3 "normal" characters.
+ 2. read the end of the string and produce from that the ending characters*/
+
+ /*compute the amount of memory to allocate*/
+ agentData->value.edmBinary.size = (((sourceLength - 2) + 4) / 4) * 3; /*this is overallocation, shall be trimmed later*/
+ agentData->value.edmBinary.data = (unsigned char*)malloc(agentData->value.edmBinary.size); /*this is overallocation, shall be trimmed later*/
+ if (agentData->value.edmBinary.data == NULL)
+ {
+ result = AGENT_DATA_TYPES_ERROR;
+ }
+ else
+ {
+
+ size_t destinationPosition = 0;
+ size_t consumed;
+ /*read and store "solid" groups of 4 base64 chars*/
+ while (scan4base64char(source + sourcePosition, sourceLength - sourcePosition, agentData->value.edmBinary.data + destinationPosition, agentData->value.edmBinary.data + destinationPosition + 1, agentData->value.edmBinary.data + destinationPosition + 2) == 0)
+ {
+ sourcePosition += 4;
+ destinationPosition += 3;
+ }
+
+ if (scanbase64b16(source + sourcePosition, sourceLength - sourcePosition, &consumed, agentData->value.edmBinary.data + destinationPosition, agentData->value.edmBinary.data + destinationPosition + 1) == 0)
+ {
+ sourcePosition += consumed;
+ destinationPosition += 2;
+
+ }
+ else if (scanbase64b8(source + sourcePosition, sourceLength - sourcePosition, &consumed, agentData->value.edmBinary.data + destinationPosition) == 0)
+ {
+ sourcePosition += consumed;
+ destinationPosition += 1;
+ }
+
+ if (source[sourcePosition++] != '"') /*if it doesn't end with " then bail out*/
+ {
+ free(agentData->value.edmBinary.data);
+ agentData->value.edmBinary.data = NULL;
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ }
+ else if (sourcePosition != sourceLength)
+ {
+ free(agentData->value.edmBinary.data);
+ agentData->value.edmBinary.data = NULL;
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ }
+ else
+ {
+ /*trim the result*/
+ void* temp = realloc(agentData->value.edmBinary.data, destinationPosition);
+ if (temp == NULL) /*this is extremely unlikely to happen, but whatever*/
+ {
+ free(agentData->value.edmBinary.data);
+ agentData->value.edmBinary.data = NULL;
+ result = AGENT_DATA_TYPES_ERROR;
+ }
+ else
+ {
+ agentData->type = EDM_BINARY_TYPE;
+ agentData->value.edmBinary.data = (unsigned char*)temp;
+ agentData->value.edmBinary.size = destinationPosition;
+ result = AGENT_DATA_TYPES_OK;
+ }
+ }
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ return result;
+}
+
+// extern AGENT_DATA_TYPES_RESULT AgentDataType_GetComplexTypeField(AGENT_DATA_TYPE* agentData, size_t index, COMPLEX_TYPE_FIELD_TYPE* complexField);
+COMPLEX_TYPE_FIELD_TYPE* AgentDataType_GetComplexTypeField(AGENT_DATA_TYPE* agentData, size_t index)
+{
+ AGENT_DATA_TYPES_RESULT result;
+ COMPLEX_TYPE_FIELD_TYPE* complexField = NULL;
+ if (agentData == NULL)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ if (agentData->type != EDM_COMPLEX_TYPE_TYPE)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+
+ else
+ {
+ if (index >= agentData->value.edmComplexType.nMembers)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ complexField = (COMPLEX_TYPE_FIELD_TYPE*)malloc(sizeof(COMPLEX_TYPE_FIELD_TYPE));
+ if (complexField == NULL)
+ {
+ result = AGENT_DATA_TYPES_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
+ }
+ else
+ {
+ *complexField = agentData->value.edmComplexType.fields[index];
+ result = AGENT_DATA_TYPES_OK;
+ }
+ }
+ }
+ }
+ return complexField;
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/agenttypesystem.h Thu Oct 22 18:33:28 2015 -0700
@@ -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.
+
+#ifndef AGENT_DATA_TYPES_H
+#define AGENT_DATA_TYPES_H
+
+#ifdef __cplusplus
+#include <cstdint>
+#include <ctime>
+#include <cstddef>
+#else
+#if ((defined _WIN32_WCE) && _WIN32_WCE==0x0600)
+#include "stdint_ce6.h"
+#else
+#include <stdint.h>
+#endif
+#include <stddef.h>
+#endif
+
+#include "agenttime.h"
+#include "macro_utils.h"
+#include "strings.h"
+
+/*Codes_SRS_AGENT_TYPE_SYSTEM_99_001:[ AGENT_TYPE_SYSTEM shall have the following interface]*/
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*the following forward declarations the closest implementation to "interface" in OOP*/
+struct AGENT_DATA_TYPE_TAG;
+typedef struct AGENT_DATA_TYPE_TAG AGENT_DATA_TYPE;
+
+/*this file contains the definitions of the data types of EDM*/
+/*the types are taken from */
+/*http://docs.oasis-open.org/odata/odata/v4.0/cos01/part3-csdl/odata-v4.0-cos01-part3-csdl.html*/
+/*chapter 4.4 - "Primitive Data Types" */
+
+/*the C implementation of these types follows:*/
+/*even the simpler types are encapsulated in structs to purposely avoid compiler promotions/casts etc*/
+
+/*Binary data.*/
+typedef struct EDM_BINARY_TAG
+{
+ size_t size;
+ unsigned char* data;
+}EDM_BINARY;
+
+#define EDM_BOOLEANS_VALUES \
+ EDM_TRUE, \
+ EDM_FALSE
+
+DEFINE_ENUM(EDM_BOOLEANS, EDM_BOOLEANS_VALUES);
+
+/*Binary-valued logic.*/
+typedef struct EDM_BOOLEAN_TAG
+{
+ EDM_BOOLEANS value;
+}EDM_BOOLEAN;
+
+/*Unsigned 8-bit integer*/
+typedef struct EDM_BYTE_TAG
+{
+ uint8_t value;
+} EDM_BYTE;
+
+/*Date without a time-zone offset*/
+/*The edm:Date expression evaluates to a primitive date value. A date expression MUST be assigned a
+value of type xs:date, see [XML-Schema-2], section 3.3.9. The value MUST also conform to rule
+dateValue in [OData-ABNF], i.e. it MUST NOT contain a time-zone offset.*/
+/*section 3.3.9: date uses the date/timeSevenPropertyModel, with hour, minute, and second required to be absent.*/
+/*dateValue in OData-ABNF is : dateValue = year "-" month "-" day */
+/*year = [ "-" ] ( "0" 3DIGIT / oneToNine 3*DIGIT )
+month = "0" oneToNine
+/ "1" ( "0" / "1" / "2" )
+day = "0" oneToNine
+/ ( "1" / "2" ) DIGIT
+/ "3" ( "0" / "1" )*/
+typedef struct EDM_DATE_TAG
+{
+ int16_t year; /*can represent all values for a year*/ /*they can be between -9999 and 9999*/
+ uint8_t month;
+ uint8_t day;
+} EDM_DATE;
+
+
+/*The edm:DateTimeOffset expression evaluates to a primitive date/time value with a time-zone offset.
+A date/time expression MUST be assigned a value of type xs:dateTimeStamp, see [XML-Schema-2],
+section 3.4.28. The value MUST also conform to rule dateTimeOffsetValue in [OData-ABNF], i.e. it
+MUST NOT contain an end-of-day fragment (24:00:00).*/
+/*section 3.4.28 says : dateTimeStampLexicalRep ::= yearFrag '-' monthFrag '-' dayFrag 'T' ((hourFrag ':' minuteFrag ':' secondFrag) | endOfDayFrag) timezoneFrag?*/
+/*[OData-ABNF] says: dateTimeOffsetValue = year "-" month "-" day "T" hour ":" minute [ ":" second [ "." fractionalSeconds ] ] ( "Z" / sign hour ":" minute )*/
+/*fractionalSeconds = 1*12DIGIT, FYI*/
+typedef struct EDM_DATE_TIME_OFFSET_TAG
+{
+ struct tm dateTime;
+ uint8_t hasFractionalSecond;
+ uint64_t fractionalSecond; /*because UINT32 only has 10 digits*/
+ uint8_t hasTimeZone;
+ int8_t timeZoneHour;
+ uint8_t timeZoneMinute;
+}EDM_DATE_TIME_OFFSET;
+
+/*Edm.Guid*/
+/*16-byte (128-bit) unique identifier*/
+/*The edm:Guid expression evaluates to a primitive 32-character string value. A guid expression MUST be
+assigned a value conforming to the rule guidValue in [OData-ABNF].*/
+/*guidValue is 8HEXDIG "-" 4HEXDIG "-" 4HEXDIG "-" 4HEXDIG "-" 12HEXDIG*/
+typedef struct EDM_GUID_TAG
+{
+ uint8_t GUID[16];
+}EDM_GUID;
+
+
+/*Edm.Decimal*/
+/*The edm:Decimal expression evaluates to a primitive decimal value. A decimal expression MUST be
+assigned a value conforming to the rule decimalValue in [OData-ABNF].*/
+/*[OData-ABNF] says: decimalValue = [SIGN] 1*DIGIT ["." 1*DIGIT] */
+/* this is binary coded decimal style then*/
+typedef struct EDM_DECIMAL_TAG
+{
+ STRING_HANDLE value;
+} EDM_DECIMAL;
+
+/*Edm.Double*/
+/*IEEE 754 binary64 floating-point number (15-17 decimal digits)*/
+
+typedef struct EDM_DOUBLE_TAG
+{
+ double value;
+} EDM_DOUBLE;
+
+
+/*Edm.Duration*/
+/*Signed duration in days, hours, minutes, and (sub)seconds*/
+/*The edm:Duration expression evaluates to a primitive duration value. A duration expression MUST be
+assigned a value of type xs:dayTimeDuration, see [XML-Schema-2], section 3.4.27.*/
+/*XML-Schema section 3.4.27 says: "[...]leaving only those with day, hour, minutes, and/or seconds fields." */
+/*day is "unsignedNoDecimalPtNumeral" and that can have as many digits... ?*/
+typedef struct EDM_DURATION_TAG
+{
+ size_t nDigits;
+ char* digits;
+}
+EDM_DURATION;
+
+
+/*Edm.Int16*/
+/*Signed 16-bit integer*/
+/*[OData=ABNF] says about Int16: numbers in the range from -32768 to 32767 */
+/*this is not C compliant, because C89 has for (read:guarantees) short SHRT_MIN -32767... (notice how it misses -32768)*/
+/*C99 has the same*/
+/*C11 has the same*/
+/*platform types has to check for -32768 compliance*/
+typedef struct EDM_INT16_TAG
+{
+ int16_t value;
+} EDM_INT16;
+
+/*Edm.Int32*/
+/*Signed 32-bit integer*/
+/*OData-ABNF has for int32Value = [ sign ] 1*10DIGIT ; numbers in the range from -2147483648 to 2147483647*/
+/*same issue as for EDM_16*/
+/*platform types has to check compliance based on LONG_MIN #define*/
+typedef struct EDM_INT32_TAG
+{
+ int32_t value;
+} EDM_INT32;
+
+/*Edm.Int64*/
+/*Signed 64-bit integer*/
+/*OData=ABNF: int64Value = [ sign ] 1*19DIGIT ; numbers in the range from -9223372036854775808 to 9223372036854775807*/
+/*C89 has no mention of anything on 64bits*/
+/*C99 mention LLONG_MIN as -9223372036854775807 and LLONG_MAX as 9223372036854775807*/
+/*C11 is the same as C99*/
+typedef struct EDM_INT64_TAG
+{
+ int64_t value; /*SINT64 might be a single type or s truct provided by platformTypes, depending on C compiler support*/
+} EDM_INT64;
+
+/*Edm.SByte*/
+/*Signed 8-bit integer*/
+/*OData=ABNF: sbyteValue = [ sign ] 1*3DIGIT ; numbers in the range from -128 to 127*/
+/*C89, C99, C11 all have SCHAR_MIN, SCHAR_MAX between -127 and 127 (guaranteed)*/
+/*so platformTypes.h has to check that -128 is attainable*/
+typedef struct EDM_SBYTE_TAG
+{
+ int8_t value;
+} EDM_SBYTE;
+
+/*Edm.Single*/
+/*IEEE 754 binary32 floating-point number (6-9 decimal digits)*/
+/*with the same "fears" as for Edm.Double*/
+typedef struct EDM_SINGLE_TAG
+{
+ float value;
+} EDM_SINGLE;
+
+/*not clear what this is
+typedef EDM_STREAM_TAG
+{
+
+}EDM_STREAM;
+*/
+
+/*Edm.String*/
+/*Sequence of UTF-8 characters*/
+typedef struct EDM_STRING_TAG
+{
+ size_t length; /*number of unsigned char* in the string*/
+ char* chars;
+} EDM_STRING;
+
+/*Edm.TimeOfDay*/
+/*Clock time 00:00-23:59:59.999999999999*/
+/*The edm:TimeOfDay expression evaluates to a primitive time value. A time-of-day expression MUST be
+assigned a value conforming to the rule timeOfDayValue in [OData-ABNF].*/
+/*timeOfDayValue = hour ":" minute [ ":" second [ "." fractionalSeconds ] ]*/
+typedef struct EDM_TIME_OF_DAY_TAG
+{
+ uint8_t hour;
+ uint8_t minute;
+ uint8_t second;
+ uint64_t fractionalSecond;
+}EDM_TIME_OF_DAY;
+
+/*positionLiteral = doubleValue SP doubleValue ; longitude, then latitude*/
+typedef struct EDM_POSITION_LITERAL_TAG
+{
+ double longitude;
+ double latitude;
+}EDM_POSITION_LITERAL;
+
+
+/*sridLiteral = "SRID" EQ 1*5DIGIT SEMI*/
+typedef struct EDM_SRID_LITERAL_TAG
+{
+ uint16_t digits;
+} EDM_SRID_LITERAL;
+
+/*lineStringData = OPEN positionLiteral 1*( COMMA positionLiteral ) CLOSE*/
+typedef struct EDM_LINE_STRING_DATA_TAG
+{
+ size_t nPositionLiterals;
+ EDM_POSITION_LITERAL *positionLiterals;
+}EDM_LINE_STRING_DATA;
+
+/*pointData = OPEN positionLiteral CLOSE*/
+typedef struct EDM_POINT_DATA_TAG
+{
+ EDM_POSITION_LITERAL positionLiteral;
+}EDM_POINT_DATA;
+
+/*ringLiteral = OPEN positionLiteral *( COMMA positionLiteral ) CLOSE*/
+typedef struct EDM_RING_LITERAL_TAG
+{
+ size_t nPositionLiterals;
+ EDM_POSITION_LITERAL *positionLiterals;
+}EDM_RING_LITERAL;
+
+/*pointLiteral ="Point" pointData*/
+typedef struct EDM_POINT_LITERAL_TAG
+{
+ EDM_POINT_DATA pointData;
+} EDM_POINT_LITERAL;
+
+/*polygonData = OPEN ringLiteral *( COMMA ringLiteral ) CLOSE*/
+typedef struct EDM_POLYGON_DATA_TAG
+{
+ size_t nRingLiterals;
+ EDM_RING_LITERAL *ringLiterals;
+}EDM_POLYGON_DATA;
+
+/*polygonLiteral = "Polygon" polygonData*/
+typedef struct EDM_POLYGON_LITERAL_TAG
+{
+ EDM_POLYGON_DATA polygonData;
+}EDM_POLYGON_LITERAL;
+
+/*fullPolygonLiteral = sridLiteral polygonLiteral*/
+typedef struct EDM_FULL_POLYGON_LITERAL_TAG
+{
+ EDM_SRID_LITERAL srid;
+ EDM_POLYGON_LITERAL polygonLiteral;
+}EDM_FULL_POLYGON_LITERAL;
+
+/*fullPointLiteral = sridLiteral pointLiteral*/
+typedef struct EDM_FULL_POINT_LITERAL_TAG
+{
+ EDM_SRID_LITERAL srid;
+ EDM_POINT_LITERAL pointLiteral;
+} EDM_FULL_POINT_LITERAL;
+
+/*geographyPoint = geographyPrefix SQUOTE fullPointLiteral SQUOTE*/
+typedef struct EDM_GEOGRAPHY_POINT_TAG
+{
+ EDM_FULL_POINT_LITERAL fullPointLiteral;
+}EDM_GEOGRAPHY_POINT;
+
+/*multiPolygonLiteral = "MultiPolygon(" [ polygonData *( COMMA polygonData ) ] CLOSE*/
+typedef struct EDM_MULTI_POLYGON_LITERAL_TAG
+{
+ size_t nPolygonDatas;
+ EDM_POLYGON_DATA * polygonDatas;
+}EDM_MULTI_POLYGON_LITERAL;
+
+/*fullMultiPolygonLiteral = sridLiteral multiPolygonLiteral*/
+typedef struct EDM_FULL_MULTI_POLYGON_LITERAL_TAG
+{
+ EDM_SRID_LITERAL srid;
+ EDM_MULTI_POLYGON_LITERAL multiPolygonLiteral;
+}EDM_FULL_MULTI_POLYGON_LITERAL;
+
+/*multiPointLiteral = "MultiPoint(" [ pointData *( COMMA pointData ) ] CLOSE*/
+typedef struct EDM_MULTI_POINT_LITERAL_TAG
+{
+ size_t nPointDatas;
+ EDM_POINT_DATA *pointDatas;
+}EDM_MULTI_POINT_LITERAL;
+
+/*fullMultiPointLiteral = sridLiteral multiPointLiteral*/
+typedef struct EDM_FULL_MULTI_POINT_LITERAL_TAG
+{
+ EDM_SRID_LITERAL srid;
+ EDM_MULTI_POINT_LITERAL multiPointLiteral;
+}EDM_FULL_MULTI_POINT_LITERAL;
+
+/*lineStringLiteral = "LineString" lineStringData*/
+typedef struct EDM_LINE_STRING_LITERAL_TAG
+{
+ EDM_LINE_STRING_DATA lineStringData;
+}EDM_LINE_STRING_LITERAL;
+
+/*fullLineStringLiteral = sridLiteral lineStringLiteral*/
+typedef struct EDM_FULL_LINE_STRING_LITERAL_TAG
+{
+ EDM_SRID_LITERAL srid;
+ EDM_LINE_STRING_LITERAL lineStringLiteral;
+} EDM_FULL_LINE_STRING_LITERAL;
+
+/*multiLineStringLiteral = "MultiLineString(" [ lineStringData *( COMMA lineStringData ) ] CLOSE*/
+typedef struct EDM_MULTI_LINE_STRING_LITERAL_TAG
+{
+ size_t nLineStringDatas;
+ EDM_LINE_STRING_DATA lineStringData;
+}EDM_MULTI_LINE_STRING_LITERAL;
+
+/*fullMultiLineStringLiteral = sridLiteral multiLineStringLiteral*/
+typedef struct EDM_FULL_MULTI_LINE_STRING_LITERAL_TAG
+{
+ EDM_SRID_LITERAL srid;
+ EDM_MULTI_LINE_STRING_LITERAL multiLineStringLiteral;
+}EDM_FULL_MULTI_LINE_STRING_LITERAL;
+
+
+
+/*forward defines*/
+struct EDM_GEO_LITERAL_TAG;
+typedef struct EDM_GEO_LITERAL_TAG EDM_GEO_LITERAL;
+
+/*collectionLiteral = "Collection(" geoLiteral *( COMMA geoLiteral ) CLOSE*/
+typedef struct EDM_COLLECTION_LITERAL_TAG
+{
+ size_t nGeoLiterals;
+ EDM_GEO_LITERAL* geoLiterals;
+} EDM_COLLECTION_LITERAL;
+
+/*geoLiteral = collectionLiteral
+/ lineStringLiteral
+/ multiPointLiteral
+/ multiLineStringLiteral
+/ multiPolygonLiteral
+/ pointLiteral
+/ polygonLiteral
+*/
+typedef enum EDM_GEO_LITERAL_TYPE_TAG
+{
+ EDM_COLLECTION_LITERAL_TYPE,
+ EDM_LINE_STRING_LITERAL_TYPE,
+ EDM_MULTI_POINT_LITERAL_TYPE,
+ EDM_MULTI_LINE_STRING_LITERAL_TYPE,
+ EDM_MULTI_POLIGON_LITERAL_TYPE,
+ EDM_POINT_LITERAL_TYPE,
+ EDM_POLYGON_LITERAL_TYPE
+}EDM_GEO_LITERAL_TYPE;
+
+struct EDM_GEO_LITERAL_TAG
+{
+ EDM_GEO_LITERAL_TYPE literalType;
+ union
+ {
+ EDM_COLLECTION_LITERAL collectionLiteral;
+ EDM_LINE_STRING_LITERAL lineStringLiteral;
+ EDM_MULTI_POINT_LITERAL multiPointLiteral;
+ EDM_MULTI_LINE_STRING_LITERAL multiLineStringLiteral;
+ EDM_MULTI_POLYGON_LITERAL multiPolygonLiteral;
+ EDM_POINT_LITERAL pointLiteral;
+ EDM_POLYGON_LITERAL polygonLiteral;
+ } u;
+};
+
+/*fullCollectionLiteral = sridLiteral collectionLiteral*/
+typedef struct EDM_FULL_COLLECTION_LITERAL_TAG
+{
+ EDM_SRID_LITERAL srid;
+ EDM_COLLECTION_LITERAL collectionLiteral;
+}EDM_FULL_COLLECTION_LITERAL;
+
+/*now geography stuff*/
+
+/*geographyCollection = geographyPrefix SQUOTE fullCollectionLiteral SQUOTE*/
+typedef struct EDM_GEOGRAPHY_COLLECTION_TAG
+{
+ EDM_FULL_COLLECTION_LITERAL fullCollectionLiteral;
+}EDM_GEOGRAPHY_COLLECTION;
+
+/*geographyLineString = geographyPrefix SQUOTE fullLineStringLiteral SQUOTE*/
+typedef struct EDM_GEOGRAPHY_LINE_STRING_TAG
+{
+ EDM_FULL_LINE_STRING_LITERAL fullLineStringLiteral;
+}EDM_GEOGRAPHY_LINE_STRING;
+
+/*geographyMultiLineString = geographyPrefix SQUOTE fullMultiLineStringLiteral SQUOTE*/
+typedef struct EDM_GEOGRAPHY_MULTI_LINE_STRING_TAG
+{
+ EDM_FULL_MULTI_LINE_STRING_LITERAL fullMultiLineStringLiteral;
+}EDM_GEOGRAPHY_MULTI_LINE_STRING;
+
+/*geographyMultiPoint = geographyPrefix SQUOTE fullMultiPointLiteral SQUOTE*/
+typedef struct EDM_GEOGRAPHY_MULTI_POINT_TAG
+{
+ EDM_FULL_MULTI_POINT_LITERAL fullMultiPointLiteral;
+}EDM_GEOGRAPHY_MULTI_POINT;
+
+/*geographyMultiPolygon = geographyPrefix SQUOTE fullMultiPolygonLiteral SQUOTE*/
+typedef struct EDM_GEOGRAPHY_MULTI_POLYGON_TAG
+{
+ EDM_FULL_MULTI_POLYGON_LITERAL fullMultiPolygonLiteral;
+}EDM_GEOGRAPHY_MULTI_POLYGON;
+
+/*geographyPolygon = geographyPrefix SQUOTE fullPolygonLiteral SQUOTE*/
+typedef struct EDM_GEOGRAPHY_POLYGON_TAG
+{
+ EDM_FULL_POLYGON_LITERAL fullPolygonLiteral;
+}EDM_GEOGRAPHY_POLYGON;
+
+/*geometryCollection = geometryPrefix SQUOTE fullCollectionLiteral SQUOTE*/
+/*forward defines*/
+
+
+/*geometryPolygon = geometryPrefix SQUOTE fullPolygonLiteral SQUOTE*/
+typedef struct EDM_GEOMETRY_POLYGON_TAG
+{
+ EDM_FULL_POLYGON_LITERAL fullPolygonLiteral;
+}EDM_GEOMETRY_POLYGON;
+
+/*geometryPoint = geometryPrefix SQUOTE fullPointLiteral SQUOTE*/
+typedef struct EDM_GEOMETRY_POINT_TAG
+{
+ EDM_FULL_POINT_LITERAL fullPointLiteral;
+}EDM_GEOMETRY_POINT;
+
+/*geometryMultiPolygon = geometryPrefix SQUOTE fullMultiPolygonLiteral SQUOTE*/
+typedef struct EDM_GEOMETRY_MULTI_POLYGON_TAG
+{
+ EDM_FULL_MULTI_POLYGON_LITERAL fullMultiPolygonLiteral;
+}
+EDM_GEOMETRY_MULTI_POLYGON;
+
+/*geometryMultiPoint = geometryPrefix SQUOTE fullMultiPointLiteral SQUOTE*/
+typedef struct EDM_GEOMETRY_MULTI_POINT_TAG
+{
+ EDM_FULL_MULTI_POINT_LITERAL fullMultiPointLiteral;
+}EDM_GEOMETRY_MULTI_POINT;
+
+/*geometryMultiLineString = geometryPrefix SQUOTE fullMultiLineStringLiteral SQUOTE*/
+typedef struct EDM_GEOMETRY_MULTI_LINE_STRING_TAG
+{
+ EDM_FULL_MULTI_LINE_STRING_LITERAL fullMultiLineStringLiteral;
+}EDM_GEOMETRY_MULTI_LINE_STRING;
+
+/*geometryLineString = geometryPrefix SQUOTE fullLineStringLiteral SQUOTE*/
+typedef struct EDM_GEOMETRY_LINE_STRING_TAG
+{
+ EDM_FULL_LINE_STRING_LITERAL fullLineStringLiteral;
+}EDM_GEOMETRY_LINE_STRING;
+
+/*geometryCollection = geometryPrefix SQUOTE fullCollectionLiteral SQUOTE*/
+typedef struct EDM_GEOMETRY_COLLECTION_TAG
+{
+ EDM_FULL_COLLECTION_LITERAL fullCollectionLiteral;
+}EDM_GEOMETRY_COLLECTION;
+
+/*holds the name and the value of a COMPLEX_TYPE... field*/
+typedef struct COMPLEX_TYPE_FIELD_TAG
+{
+ const char* fieldName;
+ AGENT_DATA_TYPE* value;
+}COMPLEX_TYPE_FIELD_TYPE;
+
+/*EDM_COMPLEX_TYPE - this type doesn't exist in EDMX as a primitive type*/
+typedef struct EDM_COMPLEX_TYPE_TAG
+{
+ size_t nMembers;
+ COMPLEX_TYPE_FIELD_TYPE *fields;
+}EDM_COMPLEX_TYPE;
+
+#define AGENT_DATA_TYPES_RESULT_VALUES \
+ AGENT_DATA_TYPES_OK, \
+ AGENT_DATA_TYPES_ERROR, \
+ AGENT_DATA_TYPES_INVALID_ARG, \
+ AGENT_DATA_TYPES_NOT_IMPLEMENTED, \
+ AGENT_DATA_TYPES_JSON_ENCODER_ERRROR
+
+DEFINE_ENUM(AGENT_DATA_TYPES_RESULT, AGENT_DATA_TYPES_RESULT_VALUES);
+
+#define AGENT_DATA_TYPE_TYPE_VALUES\
+ EDM_NO_TYPE, \
+ EDM_BINARY_TYPE, \
+ EDM_BOOLEAN_TYPE, \
+ EDM_BYTE_TYPE, \
+ EDM_DATE_TYPE, \
+ EDM_DATE_TIME_OFFSET_TYPE, \
+ EDM_DECIMAL_TYPE, \
+ EDM_DOUBLE_TYPE, \
+ EDM_DURATION_TYPE, \
+ EDM_GUID_TYPE, \
+ EDM_INT16_TYPE, \
+ EDM_INT32_TYPE, \
+ EDM_INT64_TYPE, \
+ EDM_SBYTE_TYPE, \
+ EDM_SINGLE_TYPE, \
+ EDM_STREAM, /*not supported, because what is stream?*/ \
+ EDM_STRING_TYPE, \
+ EDM_TIME_OF_DAY_TYPE, \
+ EDM_GEOGRAPHY_TYPE, /*not supported because what is "abstract base type"*/ \
+ EDM_GEOGRAPHY_POINT_TYPE, \
+ EDM_GEOGRAPHY_LINE_STRING_TYPE, \
+ EDM_GEOGRAPHY_POLYGON_TYPE, \
+ EDM_GEOGRAPHY_MULTI_POINT_TYPE, \
+ EDM_GEOGRAPHY_MULTI_LINE_STRING_TYPE, \
+ EDM_GEOGRAPHY_MULTI_POLYGON_TYPE, \
+ EDM_GEOGRAPHY_COLLECTION_TYPE, \
+ EDM_GEOMETRY_TYPE, /*not supported because what is "abstract base type"*/ \
+ EDM_GEOMETRY_POINT_TYPE, \
+ EDM_GEOMETRY_LINE_STRING_TYPE, \
+ EDM_GEOMETRY_POLYGON_TYPE, \
+ EDM_GEOMETRY_MULTI_POINT_TYPE, \
+ EDM_GEOMETRY_MULTI_LINE_STRING_TYPE, \
+ EDM_GEOMETRY_MULTI_POLYGON_TYPE, \
+ EDM_GEOMETRY_COLLECTION_TYPE, \
+ EDM_COMPLEX_TYPE_TYPE, \
+ EDM_NULL_TYPE, \
+ EDM_ENTITY_TYPE_TYPE, \
+ EDM_STRING_NO_QUOTES_TYPE \
+
+
+DEFINE_ENUM(AGENT_DATA_TYPE_TYPE, AGENT_DATA_TYPE_TYPE_VALUES);
+
+typedef struct AGENT_DATA_TYPE_TAG
+{
+ AGENT_DATA_TYPE_TYPE type;
+ union
+ {
+ EDM_BINARY edmBinary;
+ EDM_BOOLEAN edmBoolean;
+ EDM_BYTE edmByte;
+ EDM_DATE edmDate;
+ EDM_DATE_TIME_OFFSET edmDateTimeOffset;
+ EDM_DECIMAL edmDecimal;
+ EDM_DOUBLE edmDouble;
+ EDM_DURATION edmDuration;
+ EDM_GUID edmGuid;
+ EDM_INT16 edmInt16;
+ EDM_INT32 edmInt32;
+ EDM_INT64 edmInt64;
+ EDM_SBYTE edmSbyte;
+ EDM_SINGLE edmSingle;
+ /*EDM_STREAM, not supported, because what is stream?*/
+ EDM_STRING edmString;
+ EDM_STRING edmStringNoQuotes;
+ EDM_TIME_OF_DAY edmTimeOfDay;
+ /*EDM_GEOGRAPHY_, not supported because what is "abstract base type"*/
+ EDM_GEOGRAPHY_POINT edmGeographyPoint;
+ EDM_GEOGRAPHY_LINE_STRING edmGeographyLineString;
+ EDM_GEOGRAPHY_POLYGON edmGeographyPolygon;
+ EDM_GEOGRAPHY_MULTI_POINT edmGeographyMultiPoint;
+ EDM_GEOGRAPHY_MULTI_LINE_STRING edmGeographyMultiLineString;
+ EDM_GEOGRAPHY_MULTI_POLYGON edmGeographyMultiPolygon;
+ EDM_GEOGRAPHY_COLLECTION edmGeographyCollection;
+ /* EDM_GEOMETRY_, not supported because what is "abstract base type"*/
+ EDM_GEOMETRY_POINT edmGeometryPoint;
+ EDM_GEOMETRY_LINE_STRING edmGeometryLineString;
+ EDM_GEOMETRY_POLYGON edmGeometryPolygon;
+ EDM_GEOMETRY_MULTI_POINT edmGeometryMultiPoint;
+ EDM_GEOMETRY_MULTI_LINE_STRING edmGeoemtryMultiLineString;
+ EDM_GEOMETRY_MULTI_POLYGON edmGeometryMultiPolygon;
+ EDM_GEOMETRY_COLLECTION edmGeometryCollection;
+ EDM_COMPLEX_TYPE edmComplexType;
+ } value;
+}AGENT_DATA_TYPE;
+
+
+extern AGENT_DATA_TYPES_RESULT AgentDataTypes_ToString(STRING_HANDLE destination, const AGENT_DATA_TYPE* value);
+
+/*Create/Destroy work in pairs. For some data type not calling Uncreate might be ok. For some, it will lead to memory leaks*/
+
+/*creates an AGENT_DATA_TYPE containing a EDM_BOOLEAN from a int*/
+extern AGENT_DATA_TYPES_RESULT Create_EDM_BOOLEAN_from_int(AGENT_DATA_TYPE* agentData, int v);
+
+/*creates an AGENT_DATA_TYPE containing a UINT8*/
+extern AGENT_DATA_TYPES_RESULT Create_AGENT_DATA_TYPE_from_UINT8(AGENT_DATA_TYPE* agentData, uint8_t v);
+
+/*creates an AGENT_DATA_TYPE containing a EDM_DATE */
+extern AGENT_DATA_TYPES_RESULT Create_AGENT_DATA_TYPE_from_date(AGENT_DATA_TYPE* agentData, int16_t year, uint8_t month, uint8_t day);
+
+/*create an AGENT_DATA_TYPE containing an EDM_DECIMAL from a string representation*/
+extern AGENT_DATA_TYPES_RESULT Create_EDM_DECIMAL_from_charz(AGENT_DATA_TYPE* agentData, const char* v);
+
+/*create an AGENT_DATA_TYPE containing an EDM_DOUBLE from a double*/
+extern AGENT_DATA_TYPES_RESULT Create_AGENT_DATA_TYPE_from_DOUBLE(AGENT_DATA_TYPE* agentData, double v);
+
+/*create an AGENT_DATA_TYPE from INT16_T*/
+extern AGENT_DATA_TYPES_RESULT Create_AGENT_DATA_TYPE_from_SINT16(AGENT_DATA_TYPE* agentData, int16_t v);
+
+/*create an AGENT_DATA_TYPE from INT32_T*/
+extern AGENT_DATA_TYPES_RESULT Create_AGENT_DATA_TYPE_from_SINT32(AGENT_DATA_TYPE* agentData, int32_t v);
+
+/*create an AGENT_DATA_TYPE from INT64_T*/
+extern AGENT_DATA_TYPES_RESULT Create_AGENT_DATA_TYPE_from_SINT64(AGENT_DATA_TYPE* agentData, int64_t v);
+
+/*create an AGENT_DATA_TYPE from int8_t*/
+extern AGENT_DATA_TYPES_RESULT Create_AGENT_DATA_TYPE_from_SINT8(AGENT_DATA_TYPE* agentData, int8_t v);
+
+/*Codes_SRS_AGENT_TYPE_SYSTEM_99_091:[Creates an AGENT_DATA_TYPE containing an Edm.DateTimeOffset from an EDM_DATE_TIME_OFFSET.]*/
+extern AGENT_DATA_TYPES_RESULT Create_AGENT_DATA_TYPE_from_EDM_DATE_TIME_OFFSET(AGENT_DATA_TYPE* agentData, EDM_DATE_TIME_OFFSET v);
+
+/*creates an AGENT_DATA_TYPE containing a EDM_GUID*/
+extern AGENT_DATA_TYPES_RESULT Create_AGENT_DATA_TYPE_from_EDM_GUID(AGENT_DATA_TYPE* agentData, EDM_GUID v);
+
+/*creates an AGENT_DATA_TYPE containing a EDM_BINARY*/
+extern AGENT_DATA_TYPES_RESULT Create_AGENT_DATA_TYPE_from_EDM_BINARY(AGENT_DATA_TYPE* agentData, EDM_BINARY v);
+
+/*create an AGENT_DATA_TYPE from SINGLE*/
+extern AGENT_DATA_TYPES_RESULT Create_AGENT_DATA_TYPE_from_FLOAT(AGENT_DATA_TYPE* agentData, float v);
+
+/*create an AGENT_DATA_TYPE from ANSI zero terminated string*/
+extern AGENT_DATA_TYPES_RESULT Create_AGENT_DATA_TYPE_from_charz(AGENT_DATA_TYPE* agentData, const char* v);
+
+/*create an AGENT_DATA_TYPE from ANSI zero terminated string (no quotes)*/
+extern AGENT_DATA_TYPES_RESULT Create_AGENT_DATA_TYPE_from_charz_no_quotes(AGENT_DATA_TYPE* agentData, const char* v);
+
+/*create an AGENT_DATA_TYPE of type EDM_NULL_TYPE */
+extern AGENT_DATA_TYPES_RESULT Create_NULL_AGENT_DATA_TYPE(AGENT_DATA_TYPE* agentData);
+
+/*create an AGENT_DATA_TYPE that holds a structs from its fields*/
+extern AGENT_DATA_TYPES_RESULT Create_AGENT_DATA_TYPE_from_Members(AGENT_DATA_TYPE* agentData, const char* typeName, size_t nMembers, const char* const * memberNames, const AGENT_DATA_TYPE*memberValues);
+
+/*create a complex AGENT_DATA_TYPE from pointers to AGENT_DATA_TYPE fields*/
+extern AGENT_DATA_TYPES_RESULT Create_AGENT_DATA_TYPE_from_MemberPointers(AGENT_DATA_TYPE* agentData, const char* typeName, size_t nMembers, const char* const * memberNames, const AGENT_DATA_TYPE** memberPointerValues);
+
+/*creates a copy of the AGENT_DATA_TYPE*/
+extern AGENT_DATA_TYPES_RESULT Create_AGENT_DATA_TYPE_from_AGENT_DATA_TYPE(AGENT_DATA_TYPE* dest, const AGENT_DATA_TYPE* src);
+
+extern void Destroy_AGENT_DATA_TYPE(AGENT_DATA_TYPE* agentData);
+
+extern AGENT_DATA_TYPES_RESULT CreateAgentDataType_From_String(const char* source, AGENT_DATA_TYPE_TYPE type, AGENT_DATA_TYPE* agentData);
+
+extern COMPLEX_TYPE_FIELD_TYPE* AgentDataType_GetComplexTypeField(AGENT_DATA_TYPE* agentData, size_t index);;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/codefirst.c Thu Oct 22 18:33:28 2015 -0700
@@ -0,0 +1,929 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+#include <stdlib.h>
+#ifdef _CRTDBG_MAP_ALLOC
+#include <crtdbg.h>
+#endif
+#include "gballoc.h"
+
+#include "codefirst.h"
+#include "macro_utils.h"
+#include "crt_abstractions.h"
+#include "iot_logging.h"
+#include <stddef.h>
+#include "crt_abstractions.h"
+#include "iotdevice.h"
+
+DEFINE_ENUM_STRINGS(CODEFIRST_RESULT, CODEFIRST_ENUM_VALUES)
+DEFINE_ENUM_STRINGS(EXECUTE_COMMAND_RESULT, EXECUTE_COMMAND_RESULT_VALUES)
+
+#define LOG_CODEFIRST_ERROR \
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(CODEFIRST_RESULT, result))
+
+typedef struct DEVICE_HEADER_DATA_TAG
+{
+ DEVICE_HANDLE DeviceHandle;
+ const REFLECTED_DATA_FROM_DATAPROVIDER* ReflectedData;
+ SCHEMA_MODEL_TYPE_HANDLE ModelHandle;
+ size_t DataSize;
+ unsigned char* data;
+} DEVICE_HEADER_DATA;
+
+#define COUNT_OF(A) (sizeof(A) / sizeof((A)[0]))
+
+typedef enum CODEFIRST_STATE_TAG
+{
+ CODEFIRST_STATE_NOT_INIT,
+ CODEFIRST_STATE_INIT
+}CODEFIRST_STATE;
+
+static CODEFIRST_STATE g_state = CODEFIRST_STATE_NOT_INIT;
+
+static const char* g_OverrideSchemaNamespace;
+static size_t g_DeviceCount = 0;
+static DEVICE_HEADER_DATA** g_Devices = NULL;
+
+static void DestroyDevice(DEVICE_HEADER_DATA* deviceHeader)
+{
+ /* Codes_SRS_CODEFIRST_99_085:[CodeFirst_DestroyDevice shall free all resources associated with a device.] */
+ /* Codes_SRS_CODEFIRST_99_087:[In order to release the device handle, CodeFirst_DestroyDevice shall call Device_Destroy.] */
+ Device_Destroy(deviceHeader->DeviceHandle);
+ free(deviceHeader->data);
+ free(deviceHeader);
+}
+
+static CODEFIRST_RESULT buildStructTypes(SCHEMA_HANDLE schemaHandle, const REFLECTED_DATA_FROM_DATAPROVIDER* reflectedData)
+{
+ CODEFIRST_RESULT result = CODEFIRST_OK;
+
+ const REFLECTED_SOMETHING* something;
+ for (something = reflectedData->reflectedData; something != NULL; something = something->next)
+ {
+ if (something->type == REFLECTION_STRUCT_TYPE)
+ {
+ SCHEMA_STRUCT_TYPE_HANDLE structTypeHandle;
+ structTypeHandle = Schema_CreateStructType(schemaHandle, something->what.structure.name);
+
+ if (structTypeHandle == NULL)
+ {
+ /*Codes_SRS_CODEFIRST_99_076:[If any Schema APIs fail, CODEFIRST_SCHEMA_ERROR shall be returned.]*/
+ result = CODEFIRST_SCHEMA_ERROR;
+ LogError("create struct failed %s\r\n", ENUM_TO_STRING(CODEFIRST_RESULT, result));
+ break;
+ }
+ else
+ {
+ const REFLECTED_SOMETHING* maybeField;
+ /*look for the field... */
+ for (maybeField = reflectedData->reflectedData; maybeField != NULL; maybeField = maybeField->next)
+ {
+ if (maybeField->type == REFLECTION_FIELD_TYPE)
+ {
+ if (strcmp(maybeField->what.field.structName, something->what.structure.name) == 0)
+ {
+ if (Schema_AddStructTypeProperty(structTypeHandle, maybeField->what.field.fieldName, maybeField->what.field.fieldType) != SCHEMA_OK)
+ {
+ /*Codes_SRS_CODEFIRST_99_076:[If any Schema APIs fail, CODEFIRST_SCHEMA_ERROR shall be returned.]*/
+ result = CODEFIRST_SCHEMA_ERROR;
+ LogError("add struct property failed %s\r\n", ENUM_TO_STRING(CODEFIRST_RESULT, result));
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+static CODEFIRST_RESULT buildModel(SCHEMA_HANDLE schemaHandle, const REFLECTED_DATA_FROM_DATAPROVIDER* reflectedData, const REFLECTED_SOMETHING* modelReflectedData)
+{
+ CODEFIRST_RESULT result = CODEFIRST_OK;
+ const REFLECTED_SOMETHING* something;
+ SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle;
+
+ modelTypeHandle = Schema_GetModelByName(schemaHandle, modelReflectedData->what.model.name);
+ if (modelTypeHandle == NULL)
+ {
+ /*Codes_SRS_CODEFIRST_99_076:[If any Schema APIs fail, CODEFIRST_SCHEMA_ERROR shall be returned.]*/
+ result = CODEFIRST_SCHEMA_ERROR;
+ LogError("cannot get model %s %s", modelReflectedData->what.model.name, ENUM_TO_STRING(CODEFIRST_RESULT, result));
+ goto out;
+ }
+
+ for (something = reflectedData->reflectedData; something != NULL; something = something->next)
+ {
+ /* looking for all elements that belong to a model: properties and actions */
+ if ((something->type == REFLECTION_PROPERTY_TYPE) &&
+ (strcmp(something->what.property.modelName, modelReflectedData->what.model.name) == 0))
+ {
+ SCHEMA_MODEL_TYPE_HANDLE childModelHande = Schema_GetModelByName(schemaHandle, something->what.property.type);
+
+ /* if this is a model type use the appropriate APIs for it */
+ if (childModelHande != NULL)
+ {
+ if (Schema_AddModelModel(modelTypeHandle, something->what.property.name, childModelHande) != SCHEMA_OK)
+ {
+ /*Codes_SRS_CODEFIRST_99_076:[If any Schema APIs fail, CODEFIRST_SCHEMA_ERROR shall be returned.]*/
+ result = CODEFIRST_SCHEMA_ERROR;
+ LogError("add model failed %s", ENUM_TO_STRING(CODEFIRST_RESULT, result));
+ goto out;
+ }
+ }
+ else
+ {
+ if (Schema_AddModelProperty(modelTypeHandle, something->what.property.name, something->what.property.type) != SCHEMA_OK)
+ {
+ /*Codes_SRS_CODEFIRST_99_076:[If any Schema APIs fail, CODEFIRST_SCHEMA_ERROR shall be returned.]*/
+ result = CODEFIRST_SCHEMA_ERROR;
+ LogError("add property failed %s", ENUM_TO_STRING(CODEFIRST_RESULT, result));
+ goto out;
+ }
+ }
+ }
+
+ if ((something->type == REFLECTION_ACTION_TYPE) &&
+ (strcmp(something->what.action.modelName, modelReflectedData->what.model.name) == 0))
+ {
+ SCHEMA_ACTION_HANDLE actionHandle;
+ size_t i;
+
+ if ((actionHandle = Schema_CreateModelAction(modelTypeHandle, something->what.action.name)) == NULL)
+ {
+ /*Codes_SRS_CODEFIRST_99_076:[If any Schema APIs fail, CODEFIRST_SCHEMA_ERROR shall be returned.]*/
+ result = CODEFIRST_SCHEMA_ERROR;
+ LogError("add model action failed %s", ENUM_TO_STRING(CODEFIRST_RESULT, result));
+ goto out;
+ }
+
+ for (i = 0; i < something->what.action.nArguments; i++)
+ {
+ if (Schema_AddModelActionArgument(actionHandle, something->what.action.arguments[i].name, something->what.action.arguments[i].type) != SCHEMA_OK)
+ {
+ /*Codes_SRS_CODEFIRST_99_076:[If any Schema APIs fail, CODEFIRST_SCHEMA_ERROR shall be returned.]*/
+ result = CODEFIRST_SCHEMA_ERROR;
+ LogError("add model action argument failed %s", ENUM_TO_STRING(CODEFIRST_RESULT, result));
+ goto out;
+ }
+ }
+ }
+ }
+
+out:
+ return result;
+}
+
+static CODEFIRST_RESULT buildModelTypes(SCHEMA_HANDLE schemaHandle, const REFLECTED_DATA_FROM_DATAPROVIDER* reflectedData)
+{
+ CODEFIRST_RESULT result = CODEFIRST_OK;
+ const REFLECTED_SOMETHING* something;
+
+ /* first have a pass and add all the model types */
+ for (something = reflectedData->reflectedData; something != NULL; something = something->next)
+ {
+ if (something->type == REFLECTION_MODEL_TYPE)
+ {
+ if (Schema_CreateModelType(schemaHandle, something->what.model.name) == NULL)
+ {
+ /*Codes_SRS_CODEFIRST_99_076:[If any Schema APIs fail, CODEFIRST_SCHEMA_ERROR shall be returned.]*/
+ result = CODEFIRST_SCHEMA_ERROR;
+ LogError("create mdoel failed %s", ENUM_TO_STRING(CODEFIRST_RESULT, result));
+ goto out;
+ }
+ }
+ }
+
+ for (something = reflectedData->reflectedData; something != NULL; something = something->next)
+ {
+ if (something->type == REFLECTION_MODEL_TYPE)
+ {
+ result = buildModel(schemaHandle, reflectedData, something);
+ if (result != CODEFIRST_OK)
+ {
+ break;
+ }
+ }
+ }
+
+out:
+ return result;
+}
+
+/*Codes_SRS_CODEFIRST_99_002:[ CodeFirst_Init shall initialize the CodeFirst module. If initialization is successful, it shall return CODEFIRST_OK.]*/
+CODEFIRST_RESULT CodeFirst_Init(const char* overrideSchemaNamespace)
+{
+ /*shall build the default EntityContainer*/
+ CODEFIRST_RESULT result;
+
+ if (g_state != CODEFIRST_STATE_NOT_INIT)
+ {
+ /*Codes_SRS_CODEFIRST_99_003:[ If the module is already initialized, the initialization shall fail and the return value shall be CODEFIRST_ALREADY_INIT.]*/
+ result = CODEFIRST_ALREADY_INIT;
+ LogError("CodeFirst was already init %s", ENUM_TO_STRING(CODEFIRST_RESULT, result));
+ }
+ else
+ {
+ g_DeviceCount = 0;
+ g_OverrideSchemaNamespace = overrideSchemaNamespace;
+ g_Devices = NULL;
+
+ /*Codes_SRS_CODEFIRST_99_002:[ CodeFirst_Init shall initialize the CodeFirst module. If initialization is successful, it shall return CODEFIRST_OK.]*/
+ g_state = CODEFIRST_STATE_INIT;
+ result = CODEFIRST_OK;
+ }
+
+ return result;
+}
+
+void CodeFirst_Deinit(void)
+{
+ /*Codes_SRS_CODEFIRST_99_006:[If the module is not previously initialed, CodeFirst_Deinit shall do nothing.]*/
+ if (g_state != CODEFIRST_STATE_INIT)
+ {
+ LogError("CodeFirst_Deinit called when CodeFirst was not INIT\r\n");
+ }
+ else
+ {
+ size_t i;
+
+ /*Codes_SRS_CODEFIRST_99_005:[ CodeFirst_Deinit shall deinitialize the module, freeing all the resources and placing the module in an uninitialized state.]*/
+ for (i = 0; i < g_DeviceCount; i++)
+ {
+ DestroyDevice(g_Devices[i]);
+ }
+
+ free(g_Devices);
+ g_Devices = NULL;
+ g_DeviceCount = 0;
+
+ g_state = CODEFIRST_STATE_NOT_INIT;
+ }
+}
+
+static const REFLECTED_SOMETHING* FindModelInCodeFirstMetadata(const REFLECTED_SOMETHING* reflectedData, const char* modelName)
+{
+ const REFLECTED_SOMETHING* result;
+
+ for (result = reflectedData; result != NULL; result = result->next)
+ {
+ if ((result->type == REFLECTION_MODEL_TYPE) &&
+ (strcmp(result->what.model.name, modelName) == 0))
+ {
+ /* found model type */
+ break;
+ }
+ }
+
+ return result;
+}
+
+static const REFLECTED_SOMETHING* FindChildModelInCodeFirstMetadata(const REFLECTED_SOMETHING* reflectedData, const REFLECTED_SOMETHING* startModel, const char* relativePath, size_t* offset)
+{
+ const REFLECTED_SOMETHING* result = startModel;
+ *offset = 0;
+
+ /* Codes_SRS_CODEFIRST_99_139:[If the relativeActionPath is empty then the action shall be looked up in the device model.] */
+ while ((*relativePath != 0) && (result != NULL))
+ {
+ /* Codes_SRS_CODEFIRST_99_142:[The relativeActionPath argument shall be in the format "childModel1/childModel2/.../childModelN".] */
+ const REFLECTED_SOMETHING* childModelProperty;
+ size_t propertyNameLength;
+ const char* slashPos = strchr(relativePath, '/');
+ if (slashPos == NULL)
+ {
+ slashPos = &relativePath[strlen(relativePath)];
+ }
+
+ propertyNameLength = slashPos - relativePath;
+
+ for (childModelProperty = reflectedData; childModelProperty != NULL; childModelProperty = childModelProperty->next)
+ {
+ if ((childModelProperty->type == REFLECTION_PROPERTY_TYPE) &&
+ (strcmp(childModelProperty->what.property.modelName, result->what.model.name) == 0) &&
+ (strncmp(childModelProperty->what.property.name, relativePath, propertyNameLength) == 0) &&
+ (strlen(childModelProperty->what.property.name) == propertyNameLength))
+ {
+ /* property found, now let's find the model */
+ /* Codes_SRS_CODEFIRST_99_140:[CodeFirst_InvokeAction shall pass to the action wrapper that it calls a pointer to the model where the action is defined.] */
+ *offset += childModelProperty->what.property.offset;
+ break;
+ }
+ }
+
+ if (childModelProperty == NULL)
+ {
+ /* not found */
+ result = NULL;
+ }
+ else
+ {
+ result = FindModelInCodeFirstMetadata(reflectedData, childModelProperty->what.property.type);
+ }
+
+ relativePath = slashPos;
+ }
+
+ return result;
+}
+
+EXECUTE_COMMAND_RESULT CodeFirst_InvokeAction(void* deviceHandle, void* callbackUserContext, const char* relativeActionPath, const char* actionName, size_t parameterCount, const AGENT_DATA_TYPE* parameterValues)
+{
+ EXECUTE_COMMAND_RESULT result;
+ DEVICE_HEADER_DATA* deviceHeader = (DEVICE_HEADER_DATA*)callbackUserContext;
+
+ /*Codes_SRS_CODEFIRST_99_068:[ If the function is called before CodeFirst is initialized then EXECUTE_COMMAND_ERROR shall be returned.] */
+ if (g_state != CODEFIRST_STATE_INIT)
+ {
+ result = EXECUTE_COMMAND_ERROR;
+ LogError("CodeFirst_InvokeAction called before init has an error %s \r\n", ENUM_TO_STRING(EXECUTE_COMMAND_RESULT, result));
+ }
+ /*Codes_SRS_CODEFIRST_99_066:[ If actionName, relativeActionPath or deviceHandle is NULL then EXECUTE_COMMAND_ERROR shall be returned*/
+ else if ((actionName == NULL) ||
+ (deviceHandle == NULL) ||
+ (relativeActionPath == NULL))
+ {
+ result = EXECUTE_COMMAND_ERROR;
+ LogError("action Name is NULL %s \r\n", ENUM_TO_STRING(EXECUTE_COMMAND_RESULT, result));
+ }
+ /*Codes_SRS_CODEFIRST_99_067:[ If parameterCount is greater than zero and parameterValues is NULL then EXECUTE_COMMAND_ERROR shall be returned.]*/
+ else if ((parameterCount > 0) && (parameterValues == NULL))
+ {
+ result = EXECUTE_COMMAND_ERROR;
+ LogError("parameterValues error %s \r\n", ENUM_TO_STRING(EXECUTE_COMMAND_RESULT, result));
+ }
+ else
+ {
+ const REFLECTED_SOMETHING* something;
+ const REFLECTED_SOMETHING* childModel;
+ const char* modelName;
+ size_t offset;
+
+ modelName = Schema_GetModelName(deviceHeader->ModelHandle);
+
+ if (((childModel = FindModelInCodeFirstMetadata(deviceHeader->ReflectedData->reflectedData, modelName)) == NULL) ||
+ /* Codes_SRS_CODEFIRST_99_138:[The relativeActionPath argument shall be used by CodeFirst_InvokeAction to find the child model where the action is declared.] */
+ ((childModel = FindChildModelInCodeFirstMetadata(deviceHeader->ReflectedData->reflectedData, childModel, relativeActionPath, &offset)) == NULL))
+ {
+ /*Codes_SRS_CODEFIRST_99_141:[If a child model specified in the relativeActionPath argument cannot be found by CodeFirst_InvokeAction, it shall return EXECUTE_COMMAND_ERROR.] */
+ result = EXECUTE_COMMAND_ERROR;
+ LogError("action %s was not found %s \r\n", actionName, ENUM_TO_STRING(EXECUTE_COMMAND_RESULT, result));
+ }
+ else
+ {
+ /* Codes_SRS_CODEFIRST_99_062:[ When CodeFirst_InvokeAction is called it shall look through the codefirst metadata associated with a specific device for a previously declared action (function) named actionName.]*/
+ /* Codes_SRS_CODEFIRST_99_078:[If such a function is not found then the function shall return EXECUTE_COMMAND_ERROR.]*/
+ result = EXECUTE_COMMAND_ERROR;
+ for (something = deviceHeader->ReflectedData->reflectedData; something != NULL; something = something->next)
+ {
+ if ((something->type == REFLECTION_ACTION_TYPE) &&
+ (strcmp(actionName, something->what.action.name) == 0) &&
+ (strcmp(childModel->what.model.name, something->what.action.modelName) == 0))
+ {
+ /*Codes_SRS_CODEFIRST_99_063:[ If the function is found, then CodeFirst shall call the wrapper of the found function inside the data provider. The wrapper is linked in the reflected data to the function name. The wrapper shall be called with the same arguments as CodeFirst_InvokeAction has been called.]*/
+ /*Codes_SRS_CODEFIRST_99_064:[ If the wrapper call succeeds then CODEFIRST_OK shall be returned. ]*/
+ /*Codes_SRS_CODEFIRST_99_065:[ For all the other return values CODEFIRST_ACTION_EXECUTION_ERROR shall be returned.]*/
+ /* Codes_SRS_CODEFIRST_99_140:[CodeFirst_InvokeAction shall pass to the action wrapper that it calls a pointer to the model where the action is defined.] */
+ /*Codes_SRS_CODEFIRST_02_013: [The wrapper's return value shall be returned.]*/
+ result = something->what.action.wrapper(deviceHeader->data + offset, parameterCount, parameterValues);
+ break;
+ }
+ }
+ }
+ }
+
+ if (result == EXECUTE_COMMAND_ERROR)
+ {
+ LogError(" %s \r\n", ENUM_TO_STRING(EXECUTE_COMMAND_RESULT, result));
+ }
+ return result;
+}
+
+/* Codes_SRS_CODEFIRST_99_002:[ CodeFirst_RegisterSchema shall create the schema information and give it to the Schema module for one schema, identified by the metadata argument. On success, it shall return a handle to the schema.] */
+SCHEMA_HANDLE CodeFirst_RegisterSchema(const char* schemaNamespace, const REFLECTED_DATA_FROM_DATAPROVIDER* metadata)
+{
+ SCHEMA_HANDLE result;
+
+ if (g_OverrideSchemaNamespace != NULL)
+ {
+ schemaNamespace = g_OverrideSchemaNamespace;
+ }
+
+ /* Codes_SRS_CODEFIRST_99_121:[If the schema has already been registered, CodeFirst_RegisterSchema shall return its handle.] */
+ result = Schema_GetSchemaByNamespace(schemaNamespace);
+ if (result == NULL)
+ {
+ if ((result = Schema_Create(schemaNamespace)) == NULL)
+ {
+ /* Codes_SRS_CODEFIRST_99_076:[If any Schema APIs fail, CodeFirst_RegisterSchema shall return NULL.] */
+ result = NULL;
+ LogError("schema init failed %s\r\n", ENUM_TO_STRING(CODEFIRST_RESULT, CODEFIRST_SCHEMA_ERROR));
+ }
+ else
+ {
+ if ((buildStructTypes(result, metadata) != CODEFIRST_OK) ||
+ (buildModelTypes(result, metadata) != CODEFIRST_OK))
+ {
+ Schema_Destroy(result);
+ result = NULL;
+ }
+ else
+ {
+ /* do nothing, everything is OK */
+ }
+ }
+ }
+
+ return result;
+}
+
+AGENT_DATA_TYPE_TYPE CodeFirst_GetPrimitiveType(const char* typeName)
+{
+ if (strcmp(typeName, "double") == 0)
+ {
+ return EDM_DOUBLE_TYPE;
+ }
+ else if (strcmp(typeName, "float") == 0)
+ {
+ return EDM_SINGLE_TYPE;
+ }
+ else if (strcmp(typeName, "int") == 0)
+ {
+ return EDM_INT32_TYPE;
+ }
+ else if (strcmp(typeName, "long") == 0)
+ {
+ return EDM_INT64_TYPE;
+ }
+ else if (strcmp(typeName, "int8_t") == 0)
+ {
+ return EDM_SBYTE_TYPE;
+ }
+ else if (strcmp(typeName, "uint8_t") == 0)
+ {
+ return EDM_BYTE_TYPE;
+ }
+ else if (strcmp(typeName, "int16_t") == 0)
+ {
+ return EDM_INT16_TYPE;
+ }
+ else if (strcmp(typeName, "int32_t") == 0)
+ {
+ return EDM_INT32_TYPE;
+ }
+ else if (strcmp(typeName, "int64_t") == 0)
+ {
+ return EDM_INT64_TYPE;
+ }
+ else if (
+ (strcmp(typeName, "_Bool") == 0) ||
+ (strcmp(typeName, "bool") == 0)
+ )
+ {
+ return EDM_BOOLEAN_TYPE;
+ }
+ else if (strcmp(typeName, "ascii_char_ptr") == 0)
+ {
+ return EDM_STRING_TYPE;
+ }
+ else if (strcmp(typeName, "ascii_char_ptr_no_quotes") == 0)
+ {
+ return EDM_STRING_NO_QUOTES_TYPE;
+ }
+ else if (strcmp(typeName, "EDM_DATE_TIME_OFFSET") == 0)
+ {
+ return EDM_DATE_TIME_OFFSET_TYPE;
+ }
+ else if (strcmp(typeName, "EDM_GUID") == 0)
+ {
+ return EDM_GUID_TYPE;
+ }
+ else if (strcmp(typeName, "EDM_BINARY") == 0)
+ {
+ return EDM_BINARY_TYPE;
+ }
+ else
+ {
+ return EDM_NO_TYPE;
+ }
+}
+
+/* Codes_SRS_CODEFIRST_99_079:[CodeFirst_CreateDevice shall create a device and allocate a memory block that should hold the device data.] */
+void* CodeFirst_CreateDevice(SCHEMA_MODEL_TYPE_HANDLE model, const REFLECTED_DATA_FROM_DATAPROVIDER* metadata, size_t dataSize, bool includePropertyPath)
+{
+ void* result;
+ DEVICE_HEADER_DATA* deviceHeader;
+
+ /* Codes_SRS_CODEFIRST_99_080:[If CodeFirst_CreateDevice is invoked with a NULL model, it shall return NULL.]*/
+ if (
+ (model == NULL))
+ {
+ result = NULL;
+ LogError(" %s \r\n", ENUM_TO_STRING(CODEFIRST_RESULT, CODEFIRST_INVALID_ARG));
+ }
+ /* Codes_SRS_CODEFIRST_99_106:[If CodeFirst_CreateDevice is called when the modules is not initialized is shall return NULL.] */
+ else if (g_state != CODEFIRST_STATE_INIT)
+ {
+ result = NULL;
+ LogError(" %s \r\n", ENUM_TO_STRING(CODEFIRST_RESULT, CODEFIRST_NOT_INIT));
+ }
+ else if ((deviceHeader = (DEVICE_HEADER_DATA*)malloc(sizeof(DEVICE_HEADER_DATA))) == NULL)
+ {
+ /* Codes_SRS_CODEFIRST_99_102:[On any other errors, Device_Create shall return NULL.] */
+ result = NULL;
+ LogError(" %s \r\n", ENUM_TO_STRING(CODEFIRST_RESULT, CODEFIRST_ERROR));
+ }
+ /* Codes_SRS_CODEFIRST_99_081:[CodeFirst_CreateDevice shall use Device_Create to create a device handle.] */
+ /* Codes_SRS_CODEFIRST_99_082:[CodeFirst_CreateDevice shall pass to Device_Create the function CodeFirst_InvokeAction as action callback argument.] */
+ else
+ {
+ if ((deviceHeader->data = malloc(dataSize))==NULL)
+ {
+ free(deviceHeader);
+ deviceHeader = NULL;
+ result = NULL;
+ LogError(" %s \r\n", ENUM_TO_STRING(CODEFIRST_RESULT, CODEFIRST_ERROR));
+ }
+ else
+ {
+ DEVICE_HEADER_DATA** newDevices;
+
+ if (Device_Create(model, CodeFirst_InvokeAction, deviceHeader,
+ includePropertyPath, &deviceHeader->DeviceHandle) != DEVICE_OK)
+ {
+ free(deviceHeader->data);
+ free(deviceHeader);
+
+ /* Codes_SRS_CODEFIRST_99_084:[If Device_Create fails, CodeFirst_CreateDevice shall return NULL.] */
+ result = NULL;
+ LogError(" %s \r\n", ENUM_TO_STRING(CODEFIRST_RESULT, CODEFIRST_DEVICE_FAILED));
+ }
+ else if ((newDevices = (DEVICE_HEADER_DATA**)realloc(g_Devices, sizeof(DEVICE_HEADER_DATA*) * (g_DeviceCount + 1))) == NULL)
+ {
+ Device_Destroy(deviceHeader->DeviceHandle);
+ free(deviceHeader->data);
+ free(deviceHeader);
+
+ /* Codes_SRS_CODEFIRST_99_102:[On any other errors, Device_Create shall return NULL.] */
+ result = NULL;
+ LogError(" %s \r\n", ENUM_TO_STRING(CODEFIRST_RESULT, CODEFIRST_ERROR));
+ }
+ else
+ {
+ SCHEMA_RESULT schemaResult;
+ deviceHeader->ReflectedData = metadata;
+ deviceHeader->DataSize = dataSize;
+ deviceHeader->ModelHandle = model;
+ schemaResult = Schema_AddDeviceRef(model);
+ if (schemaResult != SCHEMA_OK)
+ {
+ Device_Destroy(deviceHeader->DeviceHandle);
+ free(deviceHeader->data);
+ free(deviceHeader);
+
+ /* Codes_SRS_CODEFIRST_99_102:[On any other errors, Device_Create shall return NULL.] */
+ result = NULL;
+ }
+ else
+ {
+ g_Devices = newDevices;
+ g_Devices[g_DeviceCount] = deviceHeader;
+ g_DeviceCount++;
+
+ /* Codes_SRS_CODEFIRST_99_101:[On success, CodeFirst_CreateDevice shall return a non NULL pointer to the device data.] */
+ result = deviceHeader->data;
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+void CodeFirst_DestroyDevice(void* device)
+{
+ /* Codes_SRS_CODEFIRST_99_086:[If the argument is NULL, CodeFirst_DestroyDevice shall do nothing.] */
+ if (device != NULL)
+ {
+ size_t i;
+
+ for (i = 0; i < g_DeviceCount; i++)
+ {
+ if (g_Devices[i]->data == device)
+ {
+ Schema_ReleaseDeviceRef(g_Devices[i]->ModelHandle);
+
+ // Delete the Created Schema if all the devices are unassociated
+ Schema_DestroyIfUnused(g_Devices[i]->ModelHandle);
+
+ DestroyDevice(g_Devices[i]);
+ memcpy(&g_Devices[i], &g_Devices[i + 1], (g_DeviceCount - i - 1) * sizeof(DEVICE_HEADER_DATA*));
+ g_DeviceCount--;
+ break;
+ }
+ }
+ }
+}
+
+static DEVICE_HEADER_DATA* FindDevice(void* value)
+{
+ size_t i;
+ DEVICE_HEADER_DATA* result = NULL;
+
+ for (i = 0; i < g_DeviceCount; i++)
+ {
+ if ((g_Devices[i]->data <= (unsigned char*)value) &&
+ (g_Devices[i]->data + g_Devices[i]->DataSize > (unsigned char*)value))
+ {
+ result = g_Devices[i];
+ break;
+ }
+ }
+
+ return result;
+}
+
+static const REFLECTED_SOMETHING* FindValue(DEVICE_HEADER_DATA* deviceHeader, void* value, const char* modelName, size_t startOffset, STRING_HANDLE valuePath)
+{
+ const REFLECTED_SOMETHING* result;
+ size_t valueOffset = (size_t)((unsigned char*)value - (unsigned char*)deviceHeader->data) - startOffset;
+
+ for (result = deviceHeader->ReflectedData->reflectedData; result != NULL; result = result->next)
+ {
+ if (result->type == REFLECTION_PROPERTY_TYPE &&
+ (strcmp(result->what.property.modelName, modelName) == 0) &&
+ (result->what.property.offset <= valueOffset) &&
+ (result->what.property.offset + result->what.property.size > valueOffset))
+ {
+ if (startOffset != 0)
+ {
+ STRING_concat(valuePath, "/");
+ }
+
+ STRING_concat(valuePath, result->what.property.name);
+ break;
+ }
+ }
+
+ if (result != NULL)
+ {
+ /* Codes_SRS_CODEFIRST_99_133:[CodeFirst_SendAsync shall allow sending of properties that are part of a child model.] */
+ if (result->what.property.offset < valueOffset)
+ {
+ /* find recursively the property in the inner model, if there is one */
+ result = FindValue(deviceHeader, value, result->what.property.type, startOffset + result->what.property.offset, valuePath);
+ }
+ }
+
+ return result;
+}
+
+/* Codes_SRS_CODEFIRST_99_130:[If a pointer to the beginning of a device block is passed to CodeFirst_SendAsync instead of a pointer to a property, CodeFirst_SendAsync shall send all the properties that belong to that device.] */
+/* Codes_SRS_CODEFIRST_99_131:[The properties shall be given to Device as one transaction, as if they were all passed as individual arguments to Code_First.] */
+static CODEFIRST_RESULT SendAllDeviceProperties(DEVICE_HEADER_DATA* deviceHeader, TRANSACTION_HANDLE transaction)
+{
+ const char* modelName = Schema_GetModelName(deviceHeader->ModelHandle);
+ const REFLECTED_SOMETHING* something;
+ unsigned char* deviceAddress = (unsigned char*)deviceHeader->data;
+ CODEFIRST_RESULT result = CODEFIRST_OK;
+
+ for (something = deviceHeader->ReflectedData->reflectedData; something != NULL; something = something->next)
+ {
+ if ((something->type == REFLECTION_PROPERTY_TYPE) &&
+ (strcmp(something->what.property.modelName, modelName) == 0))
+ {
+ AGENT_DATA_TYPE agentDataType;
+
+ /* Codes_SRS_CODEFIRST_99_097:[For each value marshalling to AGENT_DATA_TYPE shall be performed.] */
+ /* Codes_SRS_CODEFIRST_99_098:[The marshalling shall be done by calling the Create_AGENT_DATA_TYPE_from_Ptr function associated with the property.] */
+ if (something->what.property.Create_AGENT_DATA_TYPE_from_Ptr(deviceAddress + something->what.property.offset, &agentDataType) != AGENT_DATA_TYPES_OK)
+ {
+ /* Codes_SRS_CODEFIRST_99_099:[If Create_AGENT_DATA_TYPE_from_Ptr fails, CodeFirst_SendAsync shall return CODEFIRST_AGENT_DATA_TYPE_ERROR.] */
+ result = CODEFIRST_AGENT_DATA_TYPE_ERROR;
+ LOG_CODEFIRST_ERROR;
+ break;
+ }
+ else
+ {
+ /* Codes_SRS_CODEFIRST_99_092:[CodeFirst shall publish each value by using Device_PublishTransacted.] */
+ if (Device_PublishTransacted(transaction, something->what.property.name, &agentDataType) != DEVICE_OK)
+ {
+ Destroy_AGENT_DATA_TYPE(&agentDataType);
+
+ /* Codes_SRS_CODEFIRST_99_094:[If any Device API fail, CodeFirst_SendAsync shall return CODEFIRST_DEVICE_PUBLISH_FAILED.] */
+ result = CODEFIRST_DEVICE_PUBLISH_FAILED;
+ LOG_CODEFIRST_ERROR;
+ break;
+ }
+
+ Destroy_AGENT_DATA_TYPE(&agentDataType);
+ }
+ }
+ }
+
+ return result;
+}
+
+/* Codes_SRS_CODEFIRST_99_088:[CodeFirst_SendAsync shall send to the Device module a set of properties, a destination and a destinationSize.]*/
+CODEFIRST_RESULT CodeFirst_SendAsync(unsigned char** destination, size_t* destinationSize, size_t numProperties, ...)
+{
+ CODEFIRST_RESULT result;
+ va_list ap;
+
+ if (
+ (numProperties == 0) ||
+ (destination == NULL) ||
+ (destinationSize == NULL)
+ )
+ {
+ /* Codes_SRS_CODEFIRST_04_002: [If CodeFirst_SendAsync receives destination or destinationSize NULL, CodeFirst_SendAsync shall return Invalid Argument.]*/
+ /* Codes_SRS_CODEFIRST_99_103:[If CodeFirst_SendAsync is called with numProperties being zero, CODEFIRST_INVALID_ARG shall be returned.] */
+ result = CODEFIRST_INVALID_ARG;
+ LOG_CODEFIRST_ERROR;
+ }
+ else
+ {
+ DEVICE_HEADER_DATA* deviceHeader = NULL;
+ size_t i;
+ TRANSACTION_HANDLE transaction = NULL;
+ result = CODEFIRST_OK;
+
+ /* Codes_SRS_CODEFIRST_99_105:[The properties are passed as pointers to the memory locations where the data exists in the device block allocated by CodeFirst_CreateDevice.] */
+ va_start(ap, numProperties);
+
+ /* Codes_SRS_CODEFIRST_99_089:[The numProperties argument shall indicate how many properties are to be sent.] */
+ for (i = 0; i < numProperties; i++)
+ {
+ void* value = (void*)va_arg(ap, void*);
+
+ /* Codes_SRS_CODEFIRST_99_095:[For each value passed to it, CodeFirst_SendAsync shall look up to which device the value belongs.] */
+ DEVICE_HEADER_DATA* currentValueDeviceHeader = FindDevice(value);
+ if (currentValueDeviceHeader == NULL)
+ {
+ /* Codes_SRS_CODEFIRST_99_104:[If a property cannot be associated with a device, CodeFirst_SendAsync shall return CODEFIRST_INVALID_ARG.] */
+ result = CODEFIRST_INVALID_ARG;
+ LOG_CODEFIRST_ERROR;
+ break;
+ }
+ else if ((deviceHeader != NULL) &&
+ (currentValueDeviceHeader != deviceHeader))
+ {
+ /* Codes_SRS_CODEFIRST_99_096:[All values have to belong to the same device, otherwise CodeFirst_SendAsync shall return CODEFIRST_VALUES_FROM_DIFFERENT_DEVICES_ERROR.] */
+ result = CODEFIRST_VALUES_FROM_DIFFERENT_DEVICES_ERROR;
+ LOG_CODEFIRST_ERROR;
+ break;
+ }
+ /* Codes_SRS_CODEFIRST_99_090:[All the properties shall be sent together by using the transacted APIs of the device.] */
+ /* Codes_SRS_CODEFIRST_99_091:[CodeFirst_SendAsync shall start a transaction by calling Device_StartTransaction.] */
+ else if ((deviceHeader == NULL) &&
+ ((transaction = Device_StartTransaction(currentValueDeviceHeader->DeviceHandle)) == NULL))
+ {
+ /* Codes_SRS_CODEFIRST_99_094:[If any Device API fail, CodeFirst_SendAsync shall return CODEFIRST_DEVICE_PUBLISH_FAILED.] */
+ result = CODEFIRST_DEVICE_PUBLISH_FAILED;
+ LOG_CODEFIRST_ERROR;
+ break;
+ }
+ else
+ {
+ deviceHeader = currentValueDeviceHeader;
+
+ if (value == ((unsigned char*)deviceHeader->data))
+ {
+ /* we got a full device, send all its state data */
+ result = SendAllDeviceProperties(deviceHeader, transaction);
+ if (result != CODEFIRST_OK)
+ {
+ LOG_CODEFIRST_ERROR;
+ break;
+ }
+ }
+ else
+ {
+ const REFLECTED_SOMETHING* propertyReflectedData;
+ const char* modelName;
+ STRING_HANDLE valuePath;
+
+ if ((valuePath = STRING_new()) == NULL)
+ {
+ /* Codes_SRS_CODEFIRST_99_134:[If CodeFirst_Notify fails for any other reason it shall return CODEFIRST_ERROR.] */
+ result = CODEFIRST_ERROR;
+ LOG_CODEFIRST_ERROR;
+ break;
+ }
+ else
+ {
+ if ((modelName = Schema_GetModelName(deviceHeader->ModelHandle)) == NULL)
+ {
+ /* Codes_SRS_CODEFIRST_99_134:[If CodeFirst_Notify fails for any other reason it shall return CODEFIRST_ERROR.] */
+ result = CODEFIRST_ERROR;
+ LOG_CODEFIRST_ERROR;
+ STRING_delete(valuePath);
+ break;
+ }
+ else if ((propertyReflectedData = FindValue(deviceHeader, value, modelName, 0, valuePath)) == NULL)
+ {
+ /* Codes_SRS_CODEFIRST_99_104:[If a property cannot be associated with a device, CodeFirst_SendAsync shall return CODEFIRST_INVALID_ARG.] */
+ result = CODEFIRST_INVALID_ARG;
+ LOG_CODEFIRST_ERROR;
+ STRING_delete(valuePath);
+ break;
+ }
+ else
+ {
+ AGENT_DATA_TYPE agentDataType;
+
+ /* Codes_SRS_CODEFIRST_99_097:[For each value marshalling to AGENT_DATA_TYPE shall be performed.] */
+ /* Codes_SRS_CODEFIRST_99_098:[The marshalling shall be done by calling the Create_AGENT_DATA_TYPE_from_Ptr function associated with the property.] */
+ if (propertyReflectedData->what.property.Create_AGENT_DATA_TYPE_from_Ptr(value, &agentDataType) != AGENT_DATA_TYPES_OK)
+ {
+ /* Codes_SRS_CODEFIRST_99_099:[If Create_AGENT_DATA_TYPE_from_Ptr fails, CodeFirst_SendAsync shall return CODEFIRST_AGENT_DATA_TYPE_ERROR.] */
+ result = CODEFIRST_AGENT_DATA_TYPE_ERROR;
+ LOG_CODEFIRST_ERROR;
+ STRING_delete(valuePath);
+ break;
+ }
+ else
+ {
+ /* Codes_SRS_CODEFIRST_99_092:[CodeFirst shall publish each value by using Device_PublishTransacted.] */
+ /* Codes_SRS_CODEFIRST_99_136:[CodeFirst_SendAsync shall build the full path for each property and then pass it to Device_PublishTransacted.] */
+ if (Device_PublishTransacted(transaction, STRING_c_str(valuePath), &agentDataType) != DEVICE_OK)
+ {
+ Destroy_AGENT_DATA_TYPE(&agentDataType);
+
+ /* Codes_SRS_CODEFIRST_99_094:[If any Device API fail, CodeFirst_SendAsync shall return CODEFIRST_DEVICE_PUBLISH_FAILED.] */
+ result = CODEFIRST_DEVICE_PUBLISH_FAILED;
+ LOG_CODEFIRST_ERROR;
+ STRING_delete(valuePath);
+ break;
+ }
+ else
+ {
+ STRING_delete(valuePath); /*anyway*/
+ }
+
+ Destroy_AGENT_DATA_TYPE(&agentDataType);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (i < numProperties)
+ {
+ if (transaction != NULL)
+ {
+ (void)Device_CancelTransaction(transaction);
+ }
+ }
+ /* Codes_SRS_CODEFIRST_99_093:[After all values have been published, Device_EndTransaction shall be called.] */
+ else if (Device_EndTransaction(transaction, destination, destinationSize) != DEVICE_OK)
+ {
+ /* Codes_SRS_CODEFIRST_99_094:[If any Device API fail, CodeFirst_SendAsync shall return CODEFIRST_DEVICE_PUBLISH_FAILED.] */
+ result = CODEFIRST_DEVICE_PUBLISH_FAILED;
+ LOG_CODEFIRST_ERROR;
+ }
+ else
+ {
+ /* Codes_SRS_CODEFIRST_99_117:[On success, CodeFirst_SendAsync shall return CODEFIRST_OK.] */
+ result = CODEFIRST_OK;
+ }
+
+ va_end(ap);
+ }
+
+ return result;
+}
+
+EXECUTE_COMMAND_RESULT CodeFirst_ExecuteCommand(void* device, const char* command)
+{
+ EXECUTE_COMMAND_RESULT result;
+ /*Codes_SRS_CODEFIRST_02_014: [If parameter device or command is NULL then CodeFirst_ExecuteCommand shall return EXECUTE_COMMAND_ERROR.] */
+ if (
+ (device == NULL) ||
+ (command == NULL)
+ )
+ {
+ result = EXECUTE_COMMAND_ERROR;
+ LogError("invalid argument (NULL) passed to CodeFirst_ExecuteCommand void* device = %p, const char* command = %p\r\n", device, command);
+ }
+ else
+ {
+ /*Codes_SRS_CODEFIRST_02_015: [CodeFirst_ExecuteCommand shall find the device.]*/
+ DEVICE_HEADER_DATA* deviceHeader = FindDevice(device);
+ if(deviceHeader == NULL)
+ {
+ /*Codes_SRS_CODEFIRST_02_016: [If finding the device fails, then CodeFirst_ExecuteCommand shall return EXECUTE_COMMAND_ERROR.]*/
+ result = EXECUTE_COMMAND_ERROR;
+ LogError("unable to find the device given by address %p\r\n", device);
+ }
+ else
+ {
+ /*Codes_SRS_CODEFIRST_02_017: [Otherwise CodeFirst_ExecuteCommand shall call Device_ExecuteCommand and return what Device_ExecuteCommand is returning.] */
+ result = Device_ExecuteCommand(deviceHeader->DeviceHandle, command);
+ }
+ }
+ return result;
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/codefirst.h Thu Oct 22 18:33:28 2015 -0700
@@ -0,0 +1,140 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+#ifndef CODEFIRST_H
+#define CODEFIRST_H
+
+#include "agenttypesystem.h"
+#include "schema.h"
+#include "macro_utils.h"
+#include "strings.h"
+#include "iotdevice.h"
+
+#ifdef __cplusplus
+#include <cstddef>
+#include <cstdarg>
+extern "C" {
+#else
+#include <stddef.h>
+#include <stdarg.h>
+#endif
+
+typedef char* ascii_char_ptr;
+typedef char* ascii_char_ptr_no_quotes;
+
+typedef enum REFLECTION_TYPE_TAG
+{
+ REFLECTION_STRUCT_TYPE,
+ REFLECTION_FIELD_TYPE,
+ REFLECTION_PROPERTY_TYPE,
+ REFLECTION_ACTION_TYPE,
+ REFLECTION_MODEL_TYPE,
+ REFLECTION_NOTHING
+}REFLECTION_TYPE;
+
+typedef EXECUTE_COMMAND_RESULT (*actionWrapper)(void* device, size_t ParameterCount, const AGENT_DATA_TYPE* values);
+
+typedef struct REFLECTION_STRUCT_TAG
+{
+ const char* name;
+}REFLECTION_STRUCT;
+
+typedef struct WRAPPER_ARGUMENT_TAG
+{
+ const char* type;
+ const char* name;
+}WRAPPER_ARGUMENT;
+
+typedef struct REFLECTION_ACTION_TAG
+{
+ const char* name;
+ size_t nArguments;
+ const WRAPPER_ARGUMENT* arguments;
+ actionWrapper wrapper;
+ const char* modelName;
+}REFLECTION_ACTION;
+
+typedef struct REFLECTION_FIELD_TAG
+{
+ const char* fieldName;
+ const char* fieldType;
+ const char* structName;
+}REFLECTION_FIELD;
+
+typedef struct REFLECTION_PROPERTY_TAG
+{
+ const char* name;
+ const char* type;
+ int(*Create_AGENT_DATA_TYPE_from_Ptr)(void* param, AGENT_DATA_TYPE* dest);
+ size_t offset;
+ size_t size;
+ const char* modelName;
+} REFLECTION_PROPERTY;
+
+typedef struct REFLECTION_MODEL_TAG
+{
+ const char* name;
+} REFLECTION_MODEL;
+
+typedef struct REFLECTED_SOMETHING_TAG
+{
+ REFLECTION_TYPE type;
+ const struct REFLECTED_SOMETHING_TAG* next;
+ struct what
+ {
+ REFLECTION_STRUCT structure;
+ REFLECTION_FIELD field;
+ REFLECTION_PROPERTY property;
+ REFLECTION_ACTION action;
+ REFLECTION_MODEL model;
+ } what;
+} REFLECTED_SOMETHING;
+
+typedef struct REFLECTED_DATA_FROM_DATAPROVIDER_TAG
+{
+ const REFLECTED_SOMETHING* reflectedData;
+}REFLECTED_DATA_FROM_DATAPROVIDER;
+
+#define ALL_SOMETHING_REFLECTED(schemaNamespace) C2(schemaNamespace, _allSomethingReflected)
+#define ALL_REFLECTED(schemaNamespace) C2(schemaNamespace, _allReflected)
+#define ADDRESS_OF_ALL_REFLECTED(schemaNamespace) & C2(schemaNamespace, _allReflected),
+#define DECLARE_EXTERN_CONST_DATAPROVIDER_DATA(x) extern const REFLECTED_DATA_FROM_DATAPROVIDER ALL_REFLECTED(x);
+
+#define CODEFIRST_ENUM_VALUES \
+CODEFIRST_OK, \
+CODEFIRST_INVALID_ARG, \
+CODEFIRST_ALREADY_INIT, \
+CODEFIRST_NOT_INIT, \
+CODEFIRST_ERROR, \
+CODEFIRST_NOT_ENOUGH_MEMORY, \
+CODEFIRST_ACTION_NOT_FOUND, \
+CODEFIRST_ACTION_EXECUTION_ERROR, \
+CODEFIRST_SCHEMA_ERROR, \
+CODEFIRST_AGENT_DATA_TYPE_ERROR, \
+CODEFIRST_VALUES_FROM_DIFFERENT_DEVICES_ERROR, \
+CODEFIRST_DEVICE_FAILED, \
+CODEFIRST_DEVICE_PUBLISH_FAILED, \
+CODEFIRST_NOT_A_PROPERTY
+
+DEFINE_ENUM(CODEFIRST_RESULT, CODEFIRST_ENUM_VALUES)
+
+extern CODEFIRST_RESULT CodeFirst_Init(const char* overrideSchemaNamespace);
+extern void CodeFirst_Deinit(void);
+extern SCHEMA_HANDLE CodeFirst_RegisterSchema(const char* schemaNamespace, const REFLECTED_DATA_FROM_DATAPROVIDER* metadata);
+
+extern EXECUTE_COMMAND_RESULT CodeFirst_InvokeAction(void* deviceHandle, void* callbackUserContext, const char* relativeActionPath, const char* actionName, size_t parameterCount, const AGENT_DATA_TYPE* parameterValues);
+
+extern EXECUTE_COMMAND_RESULT CodeFirst_ExecuteCommand(void* device, const char* command);
+
+extern void* CodeFirst_CreateDevice(SCHEMA_MODEL_TYPE_HANDLE model, const REFLECTED_DATA_FROM_DATAPROVIDER* metadata, size_t dataSize, bool includePropertyPath);
+extern void CodeFirst_DestroyDevice(void* device);
+
+extern CODEFIRST_RESULT CodeFirst_SendAsync(unsigned char** destination, size_t* destinationSize, size_t numProperties, ...);
+
+extern AGENT_DATA_TYPE_TYPE CodeFirst_GetPrimitiveType(const char* typeName);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CODEFIRST_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/commanddecoder.c Thu Oct 22 18:33:28 2015 -0700
@@ -0,0 +1,524 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+#include <stdlib.h>
+#ifdef _CRTDBG_MAP_ALLOC
+#include <crtdbg.h>
+#endif
+#include "gballoc.h"
+
+#include <stddef.h>
+
+#include "commanddecoder.h"
+#include "multitree.h"
+#include "crt_abstractions.h"
+#include "iot_logging.h"
+#include "schema.h"
+#include "codefirst.h"
+#include "jsondecoder.h"
+
+DEFINE_ENUM_STRINGS(COMMANDDECODER_RESULT, COMMANDDECODER_RESULT_VALUES);
+
+typedef struct COMMAND_DECODER_INSTANCE_TAG
+{
+ SCHEMA_MODEL_TYPE_HANDLE ModelHandle;
+ ACTION_CALLBACK_FUNC ActionCallback;
+ void* ActionCallbackContext;
+} COMMAND_DECODER_INSTANCE;
+
+static int DecodeValueFromNode(SCHEMA_HANDLE schemaHandle, AGENT_DATA_TYPE* agentDataType, MULTITREE_HANDLE node, const char* edmTypeName)
+{
+ /* because "pottentially uninitialized variable on MS compiler" */
+ int result = 0;
+ const char* argStringValue;
+ AGENT_DATA_TYPE_TYPE primitiveType;
+
+ /* Codes_SRS_COMMAND_DECODER_99_029:[ If the argument type is complex then a complex type value shall be built from the child nodes.] */
+ if ((primitiveType = CodeFirst_GetPrimitiveType(edmTypeName)) == EDM_NO_TYPE)
+ {
+ SCHEMA_STRUCT_TYPE_HANDLE structTypeHandle;
+ size_t propertyCount;
+
+ /* Codes_SRS_COMMAND_DECODER_99_033:[ In order to determine which are the members of a complex types, Schema APIs for structure types shall be used.] */
+ if (((structTypeHandle = Schema_GetStructTypeByName(schemaHandle, edmTypeName)) == NULL) ||
+ (Schema_GetStructTypePropertyCount(structTypeHandle, &propertyCount) != SCHEMA_OK))
+ {
+ /* Codes_SRS_COMMAND_DECODER_99_010:[ If any Schema API fails then the command shall not be dispatched and it shall return EXECUTE_COMMAND_ERROR.]*/
+ result = __LINE__;
+ LogError("Getting Struct information failed.\r\n");
+ }
+ else
+ {
+ if (propertyCount == 0)
+ {
+ /* Codes_SRS_COMMAND_DECODER_99_034:[ If Schema APIs indicate that a complex type has 0 members then the command shall not be dispatched and it shall return EXECUTE_COMMAND_ERROR.] */
+ result = __LINE__;
+ LogError("Struct type with 0 members is not allowed\r\n");
+ }
+ else
+ {
+ AGENT_DATA_TYPE* memberValues = (AGENT_DATA_TYPE*)malloc(sizeof(AGENT_DATA_TYPE)* propertyCount);
+ if (memberValues == NULL)
+ {
+ /* Codes_SRS_COMMAND_DECODER_99_021:[ If the parsing of the command fails for any other reason the command shall not be dispatched.] */
+ result = __LINE__;
+ LogError("Failed allocating member values for command argument\r\n");
+ }
+ else
+ {
+ const char** memberNames = (const char**)malloc(sizeof(const char*)* propertyCount);
+ if (memberNames == NULL)
+ {
+ /* Codes_SRS_COMMAND_DECODER_99_021:[ If the parsing of the command fails for any other reason the command shall not be dispatched.] */
+ result = __LINE__;
+ LogError("Failed allocating member names for command argument.\r\n");
+ }
+ else
+ {
+ size_t j;
+ size_t k;
+
+ for (j = 0; j < propertyCount; j++)
+ {
+ SCHEMA_PROPERTY_HANDLE propertyHandle;
+ MULTITREE_HANDLE memberNode;
+ const char* propertyName;
+ const char* propertyType;
+
+ if ((propertyHandle = Schema_GetStructTypePropertyByIndex(structTypeHandle, j)) == NULL)
+ {
+ /* Codes_SRS_COMMAND_DECODER_99_010:[ If any Schema API fails then the command shall not be dispatched and it shall return EXECUTE_COMMAND_ERROR.]*/
+ result = __LINE__;
+ LogError("Getting struct member failed.\r\n");
+ break;
+ }
+ else if (((propertyName = Schema_GetPropertyName(propertyHandle)) == NULL) ||
+ ((propertyType = Schema_GetPropertyType(propertyHandle)) == NULL))
+ {
+ /* Codes_SRS_COMMAND_DECODER_99_010:[ If any Schema API fails then the command shall not be dispatched and it shall return EXECUTE_COMMAND_ERROR.]*/
+ result = __LINE__;
+ LogError("Getting the struct member information failed.\r\n");
+ break;
+ }
+ else
+ {
+ memberNames[j] = propertyName;
+
+ /* Codes_SRS_COMMAND_DECODER_01_014: [CommandDecoder shall use the MultiTree APIs to extract a specific element from the command JSON.] */
+ if (MultiTree_GetChildByName(node, memberNames[j], &memberNode) != MULTITREE_OK)
+ {
+ /* Codes_SRS_COMMAND_DECODER_99_028:[ If decoding the argument fails then the command shall not be dispatched and it shall return EXECUTE_COMMAND_ERROR.] */
+ result = __LINE__;
+ LogError("Getting child %s failed\r\n", propertyName);
+ break;
+ }
+ /* Codes_SRS_COMMAND_DECODER_99_032:[ Nesting shall be supported for complex type.] */
+ else if ((result = DecodeValueFromNode(schemaHandle, &memberValues[j], memberNode, propertyType)) != 0)
+ {
+ break;
+ }
+ }
+ }
+
+ if (j == propertyCount)
+ {
+ /* Codes_SRS_COMMAND_DECODER_99_031:[ The complex type value that aggregates the children shall be built by using the Create_AGENT_DATA_TYPE_from_Members.] */
+ if (Create_AGENT_DATA_TYPE_from_Members(agentDataType, edmTypeName, propertyCount, (const char* const*)memberNames, memberValues) != AGENT_DATA_TYPES_OK)
+ {
+ /* Codes_SRS_COMMAND_DECODER_99_028:[ If decoding the argument fails then the command shall not be dispatched and it shall return EXECUTE_COMMAND_ERROR.] */
+ result = __LINE__;
+ LogError("Creating the agent data type from members failed.\r\n");
+ }
+ else
+ {
+ result = 0;
+ }
+ }
+
+ for (k = 0; k < j; k++)
+ {
+ Destroy_AGENT_DATA_TYPE(&memberValues[k]);
+ }
+
+ free((void*)memberNames);
+ }
+
+ free(memberValues);
+ }
+ }
+ }
+ }
+ else
+ {
+ /* Codes_SRS_COMMAND_DECODER_01_014: [CommandDecoder shall use the MultiTree APIs to extract a specific element from the command JSON.] */
+ if (MultiTree_GetValue(node, (const void **)&argStringValue) != MULTITREE_OK)
+ {
+ /* Codes_SRS_COMMAND_DECODER_99_012:[ If any argument is missing in the command text then the command shall not be dispatched and it shall return EXECUTE_COMMAND_ERROR.] */
+ result = __LINE__;
+ LogError("Getting the string from the multitree failed.\r\n");
+ }
+ /* Codes_SRS_COMMAND_DECODER_99_027:[ The value for an argument of primitive type shall be decoded by using the CreateAgentDataType_From_String API.] */
+ else if (CreateAgentDataType_From_String(argStringValue, primitiveType, agentDataType) != AGENT_DATA_TYPES_OK)
+ {
+ /* Codes_SRS_COMMAND_DECODER_99_028:[ If decoding the argument fails then the command shall not be dispatched and it shall return EXECUTE_COMMAND_ERROR.] */
+ result = __LINE__;
+ LogError("Failed parsing node %s.\r\n", argStringValue);
+ }
+ }
+
+ return result;
+}
+
+static EXECUTE_COMMAND_RESULT DecodeAndExecuteModelAction(COMMAND_DECODER_INSTANCE* commandDecoderInstance, SCHEMA_HANDLE schemaHandle, SCHEMA_MODEL_TYPE_HANDLE modelHandle, const char* relativeActionPath, const char* actionName, MULTITREE_HANDLE commandNode)
+{
+ EXECUTE_COMMAND_RESULT result;
+ char tempStr[128];
+ size_t strLength = strlen(actionName);
+
+ if (strLength <= 1)
+ {
+ /* Codes_SRS_COMMAND_DECODER_99_021:[ If the parsing of the command fails for any other reason the command shall not be dispatched.] */
+ LogError("Invalid action name\r\n");
+ result = EXECUTE_COMMAND_ERROR;
+ }
+ else
+ {
+ /* Codes_SRS_COMMAND_DECODER_99_006:[ The action name shall be decoded from the element "Name" of the command JSON.] */
+ SCHEMA_ACTION_HANDLE modelActionHandle;
+ size_t argCount;
+ MULTITREE_HANDLE parametersTreeNode;
+
+#ifdef _MSC_VER
+#pragma warning(suppress: 6324) /* We intentionally use here strncpy */
+#endif
+ if (strncpy(tempStr, actionName, strLength - 1) == NULL)
+ {
+ /* Codes_SRS_COMMAND_DECODER_99_021:[ If the parsing of the command fails for any other reason the command shall not be dispatched.] */
+ LogError("Invalid action name.\r\n");
+ result = EXECUTE_COMMAND_ERROR;
+ }
+ /* Codes_SRS_COMMAND_DECODER_01_014: [CommandDecoder shall use the MultiTree APIs to extract a specific element from the command JSON.] */
+ else if (MultiTree_GetChildByName(commandNode, "Parameters", ¶metersTreeNode) != MULTITREE_OK)
+ {
+ /* Codes_SRS_COMMAND_DECODER_01_015: [If any MultiTree API call fails then the processing shall stop and the command shall not be dispatched and it shall return EXECUTE_COMMAND_ERROR.] */
+ LogError("Error getting Parameters node.\r\n");
+ result = EXECUTE_COMMAND_ERROR;
+ }
+ else
+ {
+ tempStr[strLength - 1] = 0;
+
+ /* Codes_SRS_COMMAND_DECODER_99_009:[ CommandDecoder shall call Schema_GetModelActionByName to obtain the information about a specific action.] */
+ if (((modelActionHandle = Schema_GetModelActionByName(modelHandle, tempStr)) == NULL) ||
+ (Schema_GetModelActionArgumentCount(modelActionHandle, &argCount) != SCHEMA_OK))
+ {
+ /* Codes_SRS_COMMAND_DECODER_99_010:[ If any Schema API fails then the command shall not be dispatched and it shall return EXECUTE_COMMAND_ERROR.]*/
+ LogError("Failed reading action %s from the schema\r\n", tempStr);
+ result = EXECUTE_COMMAND_ERROR;
+ }
+ else
+ {
+ AGENT_DATA_TYPE* arguments = NULL;
+
+ if (argCount > 0)
+ {
+ arguments = (AGENT_DATA_TYPE*)malloc(sizeof(AGENT_DATA_TYPE)* argCount);
+ }
+
+ if ((argCount > 0) &&
+ (arguments == NULL))
+ {
+ /* Codes_SRS_COMMAND_DECODER_99_021:[ If the parsing of the command fails for any other reason the command shall not be dispatched.] */
+ LogError("Failed allocating arguments array\r\n");
+ result = EXECUTE_COMMAND_ERROR;
+ }
+ else
+ {
+ size_t i;
+ size_t j;
+
+ /* Codes_SRS_COMMAND_DECODER_99_011:[ CommandDecoder shall attempt to extract from the command text the value for each action argument.] */
+ for (i = 0; i < argCount; i++)
+ {
+ SCHEMA_ACTION_ARGUMENT_HANDLE actionArgumentHandle;
+ MULTITREE_HANDLE argumentNode;
+ const char* argName;
+ const char* argType;
+
+ if (((actionArgumentHandle = Schema_GetModelActionArgumentByIndex(modelActionHandle, i)) == NULL) ||
+ ((argName = Schema_GetActionArgumentName(actionArgumentHandle)) == NULL) ||
+ ((argType = Schema_GetActionArgumentType(actionArgumentHandle)) == NULL))
+ {
+ LogError("Failed getting the argument information from the schema\r\n");
+ result = EXECUTE_COMMAND_ERROR;
+ break;
+ }
+ /* Codes_SRS_COMMAND_DECODER_01_014: [CommandDecoder shall use the MultiTree APIs to extract a specific element from the command JSON.] */
+ /* Codes_SRS_COMMAND_DECODER_01_008: [Each argument shall be looked up as a field, member of the "Parameters" node.] */
+ else if (MultiTree_GetChildByName(parametersTreeNode, argName, &argumentNode) != MULTITREE_OK)
+ {
+ /* Codes_SRS_COMMAND_DECODER_99_012:[ If any argument is missing in the command text then the command shall not be dispatched and it shall return EXECUTE_COMMAND_ERROR.] */
+ LogError("Missing argument %s\r\n", argName);
+ result = EXECUTE_COMMAND_ERROR;
+ break;
+ }
+ else if (DecodeValueFromNode(schemaHandle, &arguments[i], argumentNode, argType) != 0)
+ {
+ result = EXECUTE_COMMAND_ERROR;
+ break;
+ }
+ }
+
+ if (i == argCount)
+ {
+ /* Codes_SRS_COMMAND_DECODER_99_005:[ If an Invoke Action is decoded successfully then the callback actionCallback shall be called, passing to it the callback action context, decoded name and arguments.] */
+ result = commandDecoderInstance->ActionCallback(commandDecoderInstance->ActionCallbackContext, relativeActionPath, tempStr, argCount, arguments);
+ }
+
+ for (j = 0; j < i; j++)
+ {
+ Destroy_AGENT_DATA_TYPE(&arguments[j]);
+ }
+
+ if (arguments != NULL)
+ {
+ free(arguments);
+ }
+ }
+ }
+ }
+ }
+ return result;
+}
+
+static EXECUTE_COMMAND_RESULT ScanActionPathAndExecuteAction(COMMAND_DECODER_INSTANCE* commandDecoderInstance, SCHEMA_HANDLE schemaHandle, const char* actionPath, MULTITREE_HANDLE commandNode)
+{
+ EXECUTE_COMMAND_RESULT result;
+ char* relativeActionPath;
+ const char* actionName = actionPath;
+ SCHEMA_MODEL_TYPE_HANDLE modelHandle = commandDecoderInstance->ModelHandle;
+
+ /* Codes_SRS_COMMAND_DECODER_99_035:[ CommandDecoder_ExecuteCommand shall support paths to actions that are in child models (i.e. ChildModel/SomeAction.] */
+ do
+ {
+ /* find the slash */
+ const char* slashPos = strchr(actionName, '/');
+ if (slashPos == NULL)
+ {
+ size_t relativeActionPathLength;
+
+ /* Codes_SRS_COMMAND_DECODER_99_037:[ The relative path passed to the actionCallback shall be in the format "childModel1/childModel2/.../childModelN".] */
+ if (actionName == actionPath)
+ {
+ relativeActionPathLength = 0;
+ }
+ else
+ {
+ relativeActionPathLength = actionName - actionPath - 1;
+ }
+
+ relativeActionPath = (char*)malloc(relativeActionPathLength + 1);
+ if (relativeActionPath == NULL)
+ {
+ /* Codes_SRS_COMMAND_DECODER_99_021:[ If the parsing of the command fails for any other reason the command shall not be dispatched.] */
+ LogError("Failed allocating relative action path\r\n");
+ result = EXECUTE_COMMAND_ERROR;
+ }
+ else
+ {
+ strncpy(relativeActionPath, actionPath, relativeActionPathLength);
+ relativeActionPath[relativeActionPathLength] = 0;
+
+ /* no slash found, this must be an action */
+ result = DecodeAndExecuteModelAction(commandDecoderInstance, schemaHandle, modelHandle, relativeActionPath, actionName, commandNode);
+
+ free(relativeActionPath);
+ actionName = NULL;
+ }
+ break;
+ }
+ else
+ {
+ /* found a slash, get the child model name */
+ size_t modelLength = slashPos - actionName;
+ char* childModelName = (char*)malloc(modelLength + 1);
+ if (childModelName == NULL)
+ {
+ /* Codes_SRS_COMMAND_DECODER_99_021:[ If the parsing of the command fails for any other reason the command shall not be dispatched.] */
+ LogError("Failed allocating child model name\r\n");
+ result = EXECUTE_COMMAND_ERROR;
+ break;
+ }
+ else
+ {
+ strncpy(childModelName, actionName, modelLength);
+ childModelName[modelLength] = 0;
+
+ /* find the model */
+ modelHandle = Schema_GetModelModelByName(modelHandle, childModelName);
+ if (modelHandle == NULL)
+ {
+ /* Codes_SRS_COMMAND_DECODER_99_036:[ If a child model cannot be found by using Schema APIs then the command shall not be dispatched and it shall return EXECUTE_COMMAND_ERROR.] */
+ LogError("Getting the model %s failed\r\n", childModelName);
+ free(childModelName);
+ result = EXECUTE_COMMAND_ERROR;
+ break;
+ }
+ else
+ {
+ free(childModelName);
+ actionName = slashPos + 1;
+ result = EXECUTE_COMMAND_ERROR; /*this only exists to quench a compiler warning about returning an uninitialized variable, which is not possible by design*/
+ }
+ }
+ }
+ } while (actionName != NULL);
+ return result;
+}
+
+static EXECUTE_COMMAND_RESULT DecodeCommand(COMMAND_DECODER_INSTANCE* commandDecoderInstance, MULTITREE_HANDLE commandNode)
+{
+ EXECUTE_COMMAND_RESULT result;
+ SCHEMA_HANDLE schemaHandle;
+
+ /* Codes_SRS_COMMAND_DECODER_99_022:[ CommandDecoder shall use the Schema APIs to obtain the information about the entity set name and namespace] */
+ if ((schemaHandle = Schema_GetSchemaForModelType(commandDecoderInstance->ModelHandle)) == NULL)
+ {
+ /* Codes_SRS_COMMAND_DECODER_99_010:[ If any Schema API fails then the command shall not be dispatched and it shall return EXECUTE_COMMAND_ERROR.]*/
+ LogError("Getting schema information failed\r\n");
+ result = EXECUTE_COMMAND_ERROR;
+ }
+ else
+ {
+ const char* actionName;
+ MULTITREE_HANDLE nameTreeNode;
+
+ /* Codes_SRS_COMMAND_DECODER_01_014: [CommandDecoder shall use the MultiTree APIs to extract a specific element from the command JSON.] */
+ /* Codes_SRS_COMMAND_DECODER_99_006:[ The action name shall be decoded from the element "name" of the command JSON.] */
+ if ((MultiTree_GetChildByName(commandNode, "Name", &nameTreeNode) != MULTITREE_OK) ||
+ (MultiTree_GetValue(nameTreeNode, (const void **)&actionName) != MULTITREE_OK))
+ {
+ /* Codes_SRS_COMMAND_DECODER_01_015: [If any MultiTree API call fails then the processing shall stop and the command shall not be dispatched and it shall return EXECUTE_COMMAND_ERROR.] */
+ LogError("Getting action name failed.\r\n");
+ result = EXECUTE_COMMAND_ERROR;
+ }
+ else if (strlen(actionName) < 2)
+ {
+ /* Codes_SRS_COMMAND_DECODER_99_021:[ If the parsing of the command fails for any other reason the command shall not be dispatched.] */
+ LogError("Invalid action name.\r\n");
+ result = EXECUTE_COMMAND_ERROR;
+ }
+ else
+ {
+ actionName++;
+ result = ScanActionPathAndExecuteAction(commandDecoderInstance, schemaHandle, actionName, commandNode);
+ }
+ }
+ return result;
+}
+
+/*Codes_SRS_COMMAND_DECODER_01_009: [Whenever CommandDecoder_ExecuteCommand is the command shall be decoded and further dispatched to the actionCallback passed in CommandDecoder_Create.]*/
+EXECUTE_COMMAND_RESULT CommandDecoder_ExecuteCommand(COMMAND_DECODER_HANDLE handle, const char* command)
+{
+ EXECUTE_COMMAND_RESULT result;
+ COMMAND_DECODER_INSTANCE* commandDecoderInstance = (COMMAND_DECODER_INSTANCE*)handle;
+ /*Codes_SRS_COMMAND_DECODER_01_010: [If either the buffer or the receiveCallbackContext argument is NULL, the processing shall stop and the command shall not be dispatched and it shall return EXECUTE_COMMAND_ERROR.]*/
+ if (
+ (command == NULL) ||
+ (commandDecoderInstance == NULL)
+ )
+ {
+ LogError("Invalid argument, COMMAND_DECODER_HANDLE handle=%p, const char* command=%p\r\n", handle, command);
+ result = EXECUTE_COMMAND_ERROR;
+ }
+ else
+ {
+ size_t size = strlen(command);
+ char* commandJSON;
+
+ /* Codes_SRS_COMMAND_DECODER_01_011: [If the size of the command is 0 then the processing shall stop and the command shall not be dispatched and it shall return EXECUTE_COMMAND_ERROR.]*/
+ if (
+ (size == 0)
+ )
+ {
+ LogError("Failed because command size is zero\r\n");
+ result = EXECUTE_COMMAND_ERROR;
+ }
+ /*Codes_SRS_COMMAND_DECODER_01_013: [If parsing the JSON to a multi tree fails, the processing shall stop and the command shall not be dispatched and it shall return EXECUTE_COMMAND_ERROR.]*/
+ else if ((commandJSON = (char*)malloc(size + 1)) == NULL)
+ {
+ LogError("Failed to allocate temporary storage for the commands JSON\r\n");
+ result = EXECUTE_COMMAND_ERROR;
+ }
+ else
+ {
+ MULTITREE_HANDLE commandsTree;
+
+ (void)memcpy(commandJSON, command, size);
+ commandJSON[size] = '\0';
+
+ /* Codes_SRS_COMMAND_DECODER_01_012: [CommandDecoder shall decode the command JSON contained in buffer to a multi-tree by using JSONDecoder_JSON_To_MultiTree.] */
+ if (JSONDecoder_JSON_To_MultiTree(commandJSON, &commandsTree) != JSON_DECODER_OK)
+ {
+ /* Codes_SRS_COMMAND_DECODER_01_013: [If parsing the JSON to a multi tree fails, the processing shall stop and the command shall not be dispatched and it shall return EXECUTE_COMMAND_ERROR.] */
+ LogError("Decoding JSON to a multi tree failed\r\n");
+ result = EXECUTE_COMMAND_ERROR;
+ }
+ else
+ {
+ result = DecodeCommand(commandDecoderInstance, commandsTree);
+
+ /* Codes_SRS_COMMAND_DECODER_01_016: [CommandDecoder shall ensure that the multi-tree resulting from JSONDecoder_JSON_To_MultiTree is freed after the commands are executed.] */
+ MultiTree_Destroy(commandsTree);
+ }
+
+ free(commandJSON);
+ }
+ }
+ return result;
+}
+
+COMMAND_DECODER_HANDLE CommandDecoder_Create(SCHEMA_MODEL_TYPE_HANDLE modelHandle, ACTION_CALLBACK_FUNC actionCallback, void* actionCallbackContext)
+{
+ COMMAND_DECODER_INSTANCE* result;
+ /* Codes_SRS_COMMAND_DECODER_99_019:[ For all exposed APIs argument validity checks shall precede other checks.] */
+ /* Codes_SRS_COMMAND_DECODER_01_003: [If any of the arguments modelHandle is NULL, CommandDecoder_Create shall return NULL.]*/
+ if (
+ (modelHandle == NULL)
+ )
+ {
+ LogError("Invalid arguments modelHandle=%p, actionCallback=%p, actionCallbackContext=%p",
+ modelHandle, actionCallback, actionCallbackContext);
+ result = NULL;
+ }
+ else
+ {
+ /* Codes_SRS_COMMAND_DECODER_01_001: [CommandDecoder_Create shall create a new instance of a CommandDecoder.] */
+ result = malloc(sizeof(COMMAND_DECODER_INSTANCE));
+ if (result == NULL)
+ {
+ /* Codes_SRS_COMMAND_DECODER_01_004: [If any error is encountered during CommandDecoder_Create CommandDecoder_Create shall return NULL.] */
+ result = NULL;
+ }
+ else
+ {
+ result->ModelHandle = modelHandle;
+ result->ActionCallback = actionCallback;
+ result->ActionCallbackContext = actionCallbackContext;
+ }
+ }
+
+ return result;
+}
+
+void CommandDecoder_Destroy(COMMAND_DECODER_HANDLE commandDecoderHandle)
+{
+ /* Codes_SRS_COMMAND_DECODER_01_007: [If CommandDecoder_Destroy is called with a NULL handle, CommandDecoder_Destroy shall do nothing.] */
+ if (commandDecoderHandle != NULL)
+ {
+ COMMAND_DECODER_INSTANCE* commandDecoderInstance = (COMMAND_DECODER_INSTANCE*)commandDecoderHandle;
+
+ /* Codes_SRS_COMMAND_DECODER_01_005: [CommandDecoder_Destroy shall free all resources associated with the commandDecoderHandle instance.] */
+ free(commandDecoderInstance);
+ }
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/commanddecoder.h Thu Oct 22 18:33:28 2015 -0700
@@ -0,0 +1,44 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+#ifndef COMMAND_DECODER_H
+#define COMMAND_DECODER_H
+
+#include "multitree.h"
+#include "schema.h"
+#include "agenttypesystem.h"
+#include "macro_utils.h"
+
+#define COMMANDDECODER_RESULT_VALUES \
+ COMMANDDECODER_OK, \
+ COMMANDDECODER_ERROR, \
+ COMMANDDECODER_INVALID_ARG
+
+DEFINE_ENUM(COMMANDDECODER_RESULT, COMMANDDECODER_RESULT_VALUES)
+
+#define EXECUTE_COMMAND_RESULT_VALUES \
+EXECUTE_COMMAND_SUCCESS, /*when the final recipient of the command indicates a successful execution*/ \
+EXECUTE_COMMAND_FAILED, /*when the final recipient of the command indicates a failure*/ \
+EXECUTE_COMMAND_ERROR /*when a transient error either in the final recipient or until the final recipient*/
+
+DEFINE_ENUM(EXECUTE_COMMAND_RESULT, EXECUTE_COMMAND_RESULT_VALUES)
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Codes_SRS_COMMAND_DECODER_99_001:[ The CommandDecoder module shall expose the following API:] */
+
+typedef void* COMMAND_DECODER_HANDLE;
+typedef EXECUTE_COMMAND_RESULT(*ACTION_CALLBACK_FUNC)(void* actionCallbackContext, const char* relativeActionPath, const char* actionName, size_t argCount, const AGENT_DATA_TYPE* args);
+
+extern COMMAND_DECODER_HANDLE CommandDecoder_Create(SCHEMA_MODEL_TYPE_HANDLE modelHandle, ACTION_CALLBACK_FUNC actionCallback, void* actionCallbackContext);
+extern EXECUTE_COMMAND_RESULT CommandDecoder_ExecuteCommand(COMMAND_DECODER_HANDLE handle, const char* command);
+extern void CommandDecoder_Destroy(COMMAND_DECODER_HANDLE commandDecoderHandle);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* COMMAND_DECODER_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/datamarshaller.c Thu Oct 22 18:33:28 2015 -0700
@@ -0,0 +1,223 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+#include <stdlib.h> /*for free*/
+#ifdef _CRTDBG_MAP_ALLOC
+#include <crtdbg.h>
+#endif
+#include "gballoc.h"
+
+#include <stdbool.h>
+#include "datamarshaller.h"
+#include "crt_abstractions.h"
+#include "schema.h"
+#include "jsonencoder.h"
+#include "agenttypesystem.h"
+#include "iot_logging.h"
+
+DEFINE_ENUM_STRINGS(DATA_MARSHALLER_RESULT, DATA_MARSHALLER_RESULT_VALUES);
+
+#define LOG_DATA_MARSHALLER_ERROR \
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(DATA_MARSHALLER_RESULT, result));
+
+typedef struct DATA_MARSHALLER_INSTANCE_TAG
+{
+ SCHEMA_MODEL_TYPE_HANDLE ModelHandle;
+ bool IncludePropertyPath;
+} DATA_MARSHALLER_INSTANCE;
+
+static int NoCloneFunction(void** destination, const void* source)
+{
+ *destination = (void*)source;
+ return 0;
+}
+
+static void NoFreeFunction(void* value)
+{
+ (void)value;
+}
+
+DATA_MARSHALLER_HANDLE DataMarshaller_Create(SCHEMA_MODEL_TYPE_HANDLE modelHandle, bool includePropertyPath)
+{
+ DATA_MARSHALLER_HANDLE result;
+ DATA_MARSHALLER_INSTANCE* dataMarshallerInstance;
+
+ /*Codes_SRS_DATA_MARSHALLER_99_019:[ DataMarshaller_Create shall return NULL if any argument is NULL.]*/
+ if (
+ (modelHandle == NULL)
+ )
+ {
+ result = NULL;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(DATA_MARSHALLER_RESULT, DATA_MARSHALLER_INVALID_ARG));
+ }
+ else if ((dataMarshallerInstance = (DATA_MARSHALLER_INSTANCE*)malloc(sizeof(DATA_MARSHALLER_INSTANCE))) == NULL)
+ {
+ /* Codes_SRS_DATA_MARSHALLER_99_048:[On any other errors not explicitly specified, DataMarshaller_Create shall return NULL.] */
+ result = NULL;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(DATA_MARSHALLER_RESULT, DATA_MARSHALLER_ERROR));
+ }
+ else
+ {
+ /*everything ok*/
+ dataMarshallerInstance->ModelHandle = modelHandle;
+ dataMarshallerInstance->IncludePropertyPath = includePropertyPath;
+
+ /*Codes_SRS_DATA_MARSHALLER_99_018:[ DataMarshaller_Create shall create a new DataMarshaller instance and on success it shall return a non NULL handle.]*/
+ result = dataMarshallerInstance;
+ }
+ return result;
+}
+
+void DataMarshaller_Destroy(DATA_MARSHALLER_HANDLE dataMarshallerHandle)
+{
+ /* Codes_SRS_DATA_MARSHALLER_99_024:[ When called with a NULL handle, DataMarshaller_Destroy shall do nothing.] */
+ if (dataMarshallerHandle != NULL)
+ {
+ /* Codes_SRS_DATA_MARSHALLER_99_022:[ DataMarshaller_Destroy shall free all resources associated with the dataMarshallerHandle argument.] */
+ DATA_MARSHALLER_INSTANCE* dataMarshallerInstance = (DATA_MARSHALLER_INSTANCE*)dataMarshallerHandle;
+ free(dataMarshallerInstance);
+ }
+}
+
+DATA_MARSHALLER_RESULT DataMarshaller_SendData(DATA_MARSHALLER_HANDLE dataMarshallerHandle, size_t valueCount, const DATA_MARSHALLER_VALUE* values, unsigned char** destination, size_t* destinationSize)
+{
+ DATA_MARSHALLER_INSTANCE* dataMarshallerInstance = (DATA_MARSHALLER_INSTANCE*)dataMarshallerHandle;
+ DATA_MARSHALLER_RESULT result;
+ MULTITREE_HANDLE treeHandle;
+
+ /* Codes_SRS_DATA_MARSHALLER_99_034:[All argument checks shall be performed before calling any other modules.] */
+ /* Codes_SRS_DATA_MARSHALLER_99_004:[ DATA_MARSHALLER_INVALID_ARG shall be returned when the function has detected an invalid parameter (NULL) being passed to the function.] */
+ if ((values == NULL) ||
+ (dataMarshallerHandle == NULL) ||
+ (destination == NULL) ||
+ (destinationSize == NULL) ||
+ /* Codes_SRS_DATA_MARSHALLER_99_033:[ DATA_MARSHALLER_INVALID_ARG shall be returned if the valueCount is zero.] */
+ (valueCount == 0))
+ {
+ result = DATA_MARSHALLER_INVALID_ARG;
+ LOG_DATA_MARSHALLER_ERROR
+ }
+ else
+ {
+ size_t i;
+ /* VS complains wrongly that result is not initialized */
+ result = DATA_MARSHALLER_ERROR;
+ bool includePropertyPath = dataMarshallerInstance->IncludePropertyPath;
+
+ for (i = 0; i < valueCount; i++)
+ {
+ if ((values[i].PropertyPath == NULL) ||
+ (values[i].Value == NULL))
+ {
+ /*Codes_SRS_DATA_MARSHALLER_99_007:[ DATA_MARSHALLER_INVALID_MODEL_PROPERTY shall be returned when any of the items in values contain invalid data]*/
+ result = DATA_MARSHALLER_INVALID_MODEL_PROPERTY;
+ LOG_DATA_MARSHALLER_ERROR
+ break;
+ }
+
+ if ((!dataMarshallerInstance->IncludePropertyPath) &&
+ (values[i].Value->type == EDM_COMPLEX_TYPE_TYPE) &&
+ (valueCount > 1))
+ {
+ /* Codes_SRS_DATAMARSHALLER_01_002: [If the includePropertyPath argument passed to DataMarshaller_Create was false and the number of values passed to SendData is greater than 1 and at least one of them is a struct, DataMarshaller_SendData shall fallback to including the complete property path in the output JSON.] */
+ includePropertyPath = true;
+ }
+ }
+
+ if (i == valueCount)
+ {
+ /* Codes_SRS_DATA_MARSHALLER_99_037:[DataMarshaller shall store as MultiTree the data to be encoded by the JSONEncoder module.] */
+ if ((treeHandle = MultiTree_Create(NoCloneFunction, NoFreeFunction)) == NULL)
+ {
+ /* Codes_SRS_DATA_MARSHALLER_99_035:[DATA_MARSHALLER_MULTITREE_ERROR shall be returned in case any MultiTree API call fails.] */
+ result = DATA_MARSHALLER_MULTITREE_ERROR;
+ LOG_DATA_MARSHALLER_ERROR
+ }
+ else
+ {
+ size_t j;
+ result = DATA_MARSHALLER_OK; /* addressing warning in VS compiler */
+ /* Codes_SRS_DATA_MARSHALLER_99_038:[For each pair in the values argument, a string : value pair shall exist in the JSON object in the form of propertyName : value.] */
+ for (j = 0; j < valueCount; j++)
+ {
+ if ((includePropertyPath == false) && (values[j].Value->type == EDM_COMPLEX_TYPE_TYPE))
+ {
+ size_t k;
+
+ /* Codes_SRS_DATAMARSHALLER_01_001: [If the includePropertyPath argument passed to DataMarshaller_Create was false and only one struct is being sent, the relative path of the value passed to DataMarshaller_SendData - including property name - shall be ignored and the value shall be placed at JSON root.] */
+ for (k = 0; k < values[j].Value->value.edmComplexType.nMembers; k++)
+ {
+ /* Codes_SRS_DATAMARSHALLER_01_004: [In this case the members of the struct shall be added as leafs into the MultiTree, each leaf having the name of the struct member.] */
+ if (MultiTree_AddLeaf(treeHandle, values[j].Value->value.edmComplexType.fields[k].fieldName, (void*)values[j].Value->value.edmComplexType.fields[k].value) != MULTITREE_OK)
+ {
+ break;
+ }
+ }
+
+ if (k < values[j].Value->value.edmComplexType.nMembers)
+ {
+ /* Codes_SRS_DATA_MARSHALLER_99_035:[DATA_MARSHALLER_MULTITREE_ERROR shall be returned in case any MultiTree API call fails.] */
+ result = DATA_MARSHALLER_MULTITREE_ERROR;
+ LOG_DATA_MARSHALLER_ERROR
+ break;
+ }
+ }
+ else
+ {
+ /* Codes_SRS_DATA_MARSHALLER_99_039:[ If the includePropertyPath argument passed to DataMarshaller_Create was true each property shall be placed in the appropriate position in the JSON according to its path in the model.] */
+ if (MultiTree_AddLeaf(treeHandle, values[j].PropertyPath, (void*)values[j].Value) != MULTITREE_OK)
+ {
+ /* Codes_SRS_DATA_MARSHALLER_99_035:[DATA_MARSHALLER_MULTITREE_ERROR shall be returned in case any MultiTree API call fails.] */
+ result = DATA_MARSHALLER_MULTITREE_ERROR;
+ LOG_DATA_MARSHALLER_ERROR
+ break;
+ }
+ }
+
+ }
+
+ if (j == valueCount)
+ {
+ STRING_HANDLE payload = STRING_new();
+ if (payload == NULL)
+ {
+ result = DATA_MARSHALLER_ERROR;
+ LOG_DATA_MARSHALLER_ERROR
+ }
+ else
+ {
+ if (JSONEncoder_EncodeTree(treeHandle, payload, (JSON_ENCODER_TOSTRING_FUNC)AgentDataTypes_ToString) != JSON_ENCODER_OK)
+ {
+ /* Codes_SRS_DATA_MARSHALLER_99_027:[ DATA_MARSHALLER_JSON_ENCODER_ERROR shall be returned when JSONEncoder returns an error code.] */
+ result = DATA_MARSHALLER_JSON_ENCODER_ERROR;
+ LOG_DATA_MARSHALLER_ERROR
+ }
+ else
+ {
+ /*Codes_SRS_DATAMARSHALLER_02_007: [DataMarshaller_SendData shall copy in the output parameters *destination, *destinationSize the content and the content length of the encoded JSON tree.] */
+ size_t resultSize = STRING_length(payload);
+ unsigned char* temp = malloc(resultSize);
+ if (temp == NULL)
+ {
+ /*Codes_SRS_DATA_MARSHALLER_99_015:[ DATA_MARSHALLER_ERROR shall be returned in all the other error cases not explicitly defined here.]*/
+ result = DATA_MARSHALLER_ERROR;
+ LOG_DATA_MARSHALLER_ERROR;
+ }
+ else
+ {
+ memcpy(temp, STRING_c_str(payload), resultSize);
+ *destination = temp;
+ *destinationSize = resultSize;
+ result = DATA_MARSHALLER_OK;
+ }
+ }
+ STRING_delete(payload);
+ }
+ } /* if (j==valueCount)*/
+ MultiTree_Destroy(treeHandle);
+ } /* MultiTree_Create */
+ }
+ }
+
+ return result;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/datamarshaller.h Thu Oct 22 18:33:28 2015 -0700
@@ -0,0 +1,48 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+#ifndef DATAMARSHALLER_H
+#define DATAMARSHALLER_H
+
+#include <stdbool.h>
+#include "agenttypesystem.h"
+#include "schema.h"
+#include "macro_utils.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*Codes_SRS_DATA_MARSHALLER_99_002:[ DataMarshaller shall have the following interface]*/
+#define DATA_MARSHALLER_RESULT_VALUES \
+DATA_MARSHALLER_OK, \
+DATA_MARSHALLER_INVALID_ARG, \
+DATA_MARSHALLER_NO_DEVICE_IDENTITY, \
+DATA_MARSHALLER_SCHEMA_FAILED, \
+DATA_MARSHALLER_INVALID_MODEL_PROPERTY, \
+DATA_MARSHALLER_JSON_ENCODER_ERROR, \
+DATA_MARSHALLER_ERROR, \
+DATA_MARSHALLER_AGENT_DATA_TYPES_ERROR, \
+DATA_MARSHALLER_MULTITREE_ERROR, \
+DATA_MARSHALLER_ONLY_ONE_VALUE_ALLOWED \
+
+DEFINE_ENUM(DATA_MARSHALLER_RESULT, DATA_MARSHALLER_RESULT_VALUES);
+
+typedef struct DATA_MARSHALLER_VALUE_TAG
+{
+ const char* PropertyPath;
+ const AGENT_DATA_TYPE* Value;
+} DATA_MARSHALLER_VALUE;
+
+typedef void* DATA_MARSHALLER_HANDLE;
+
+extern DATA_MARSHALLER_HANDLE DataMarshaller_Create(SCHEMA_MODEL_TYPE_HANDLE modelHandle, bool includePropertyPath);
+extern void DataMarshaller_Destroy(DATA_MARSHALLER_HANDLE dataMarshallerHandle);
+extern DATA_MARSHALLER_RESULT DataMarshaller_SendData(DATA_MARSHALLER_HANDLE dataMarshallerHandle, size_t valueCount, const DATA_MARSHALLER_VALUE* values, unsigned char** destination, size_t* destinationSize);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* DATAMARSHALLER_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/datapublisher.c Thu Oct 22 18:33:28 2015 -0700
@@ -0,0 +1,331 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+#include <stdlib.h>
+#ifdef _CRTDBG_MAP_ALLOC
+#include <crtdbg.h>
+#endif
+#include "gballoc.h"
+
+#include <stdbool.h>
+#include "datapublisher.h"
+#include "jsonencoder.h"
+#include "datamarshaller.h"
+#include "agenttypesystem.h"
+#include "schema.h"
+#include "crt_abstractions.h"
+#include "iot_logging.h"
+
+DEFINE_ENUM_STRINGS(DATA_PUBLISHER_RESULT, DATA_PUBLISHER_RESULT_VALUES)
+
+#define LOG_DATA_PUBLISHER_ERROR \
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(DATA_PUBLISHER_RESULT, result))
+
+#define DEFAULT_MAX_BUFFER_SIZE 10240
+/* Codes_SRS_DATA_PUBLISHER_99_066:[ A single value shall be used by all instances of DataPublisher.] */
+/* Codes_SRS_DATA_PUBLISHER_99_067:[ Before any call to DataPublisher_SetMaxBufferSize, the default max buffer size shall be equal to 10KB.] */
+static size_t maxBufferSize_ = DEFAULT_MAX_BUFFER_SIZE;
+
+typedef struct DATA_PUBLISHER_INSTANCE_TAG
+{
+ DATA_MARSHALLER_HANDLE DataMarshallerHandle;
+ SCHEMA_MODEL_TYPE_HANDLE ModelHandle;
+} DATA_PUBLISHER_INSTANCE;
+
+typedef struct TRANSACTION_TAG
+{
+ DATA_PUBLISHER_INSTANCE* DataPublisherInstance;
+ size_t ValueCount;
+ DATA_MARSHALLER_VALUE* Values;
+} TRANSACTION;
+
+DATA_PUBLISHER_HANDLE DataPublisher_Create(SCHEMA_MODEL_TYPE_HANDLE modelHandle, bool includePropertyPath)
+{
+ DATA_PUBLISHER_HANDLE result;
+ DATA_PUBLISHER_INSTANCE* dataPublisherInstance;
+
+ /* Codes_SRS_DATA_PUBLISHER_99_042:[ If a NULL argument is passed to it, DataPublisher_Create shall return NULL.] */
+ if (
+ (modelHandle == NULL)
+ )
+ {
+ result = NULL;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(DATA_PUBLISHER_RESULT, DATA_PUBLISHER_INVALID_ARG));
+ }
+ else if ((dataPublisherInstance = (DATA_PUBLISHER_INSTANCE*)malloc(sizeof(DATA_PUBLISHER_INSTANCE))) == NULL)
+ {
+ /* Codes_SRS_DATA_PUBLISHER_99_047:[ For any other error not specified here, DataPublisher_Create shall return NULL.] */
+ result = NULL;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(DATA_PUBLISHER_RESULT, DATA_PUBLISHER_ERROR));
+ }
+ else
+ {
+ /* Codes_SRS_DATA_PUBLISHER_99_043:[ DataPublisher_Create shall initialize and hold a handle to a DataMarshaller instance.] */
+ /* Codes_SRS_DATA_PUBLISHER_01_001: [DataPublisher_Create shall pass the includePropertyPath argument to DataMarshaller_Create.] */
+ if ((dataPublisherInstance->DataMarshallerHandle = DataMarshaller_Create(modelHandle, includePropertyPath)) == NULL)
+ {
+ free(dataPublisherInstance);
+
+ /* Codes_SRS_DATA_PUBLISHER_99_044:[ If the creation of the DataMarshaller instance fails, DataPublisher_Create shall return NULL.] */
+ result = NULL;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(DATA_PUBLISHER_RESULT, DATA_PUBLISHER_MARSHALLER_ERROR));
+ }
+ else
+ {
+ dataPublisherInstance->ModelHandle = modelHandle;
+
+ /* Codes_SRS_DATA_PUBLISHER_99_041:[ DataPublisher_Create shall create a new DataPublisher instance and return a non-NULL handle in case of success.] */
+ result = dataPublisherInstance;
+ }
+ }
+
+ return result;
+}
+
+void DataPublisher_Destroy(DATA_PUBLISHER_HANDLE dataPublisherHandle)
+{
+ if (dataPublisherHandle != NULL)
+ {
+ DATA_PUBLISHER_INSTANCE* dataPublisherInstance = (DATA_PUBLISHER_INSTANCE*)dataPublisherHandle;
+ DataMarshaller_Destroy(dataPublisherInstance->DataMarshallerHandle);
+
+ free(dataPublisherHandle);
+ }
+}
+
+TRANSACTION_HANDLE DataPublisher_StartTransaction(DATA_PUBLISHER_HANDLE dataPublisherHandle)
+{
+ TRANSACTION* transaction;
+
+ /* Codes_SRS_DATA_PUBLISHER_99_038:[ If DataPublisher_StartTransaction is called with a NULL argument it shall return NULL.] */
+ if (dataPublisherHandle == NULL)
+ {
+ transaction = NULL;
+ LogError("(Error code: %s)\r\n", ENUM_TO_STRING(DATA_PUBLISHER_RESULT, DATA_PUBLISHER_INVALID_ARG));
+ }
+ else
+ {
+ /* Codes_SRS_DATA_PUBLISHER_99_007:[ A call to DataPublisher_StartTransaction shall start a new transaction.] */
+ transaction = (TRANSACTION*)malloc(sizeof(TRANSACTION));
+ if (transaction == NULL)
+ {
+ LogError("Allocating transaction failed (Error code: %s)\r\n", ENUM_TO_STRING(DATA_PUBLISHER_RESULT, DATA_PUBLISHER_ERROR));
+ }
+ else
+ {
+ transaction->ValueCount = 0;
+ transaction->Values = NULL;
+ transaction->DataPublisherInstance = (DATA_PUBLISHER_INSTANCE*)dataPublisherHandle;
+ }
+ }
+
+ /* Codes_SRS_DATA_PUBLISHER_99_008:[ DataPublisher_StartTransaction shall return a non-NULL handle upon success.] */
+ /* Codes_SRS_DATA_PUBLISHER_99_009:[ DataPublisher_StartTransaction shall return NULL upon failure.] */
+ return transaction;
+}
+
+DATA_PUBLISHER_RESULT DataPublisher_PublishTransacted(TRANSACTION_HANDLE transactionHandle, const char* propertyPath, const AGENT_DATA_TYPE* data)
+{
+ DATA_PUBLISHER_RESULT result;
+ char* propertyPathCopy;
+
+ /* Codes_SRS_DATA_PUBLISHER_99_017:[ When one or more NULL parameter(s) are specified, DataPublisher_PublishTransacted is called with a NULL transactionHandle, it shall return DATA_PUBLISHER_INVALID_ARG.] */
+ if ((transactionHandle == NULL) ||
+ (propertyPath == NULL) ||
+ (data == NULL))
+ {
+ result = DATA_PUBLISHER_INVALID_ARG;
+ LOG_DATA_PUBLISHER_ERROR;
+ }
+ else if (mallocAndStrcpy_s(&propertyPathCopy, propertyPath) != 0)
+ {
+ /* Codes_SRS_DATA_PUBLISHER_99_020:[ For any errors not explicitly mentioned here the DataPublisher APIs shall return DATA_PUBLISHER_ERROR.] */
+ result = DATA_PUBLISHER_ERROR;
+ LOG_DATA_PUBLISHER_ERROR;
+ }
+ else
+ {
+ TRANSACTION* transaction = (TRANSACTION*)transactionHandle;
+ AGENT_DATA_TYPE* propertyValue;
+
+ if (!Schema_ModelPropertyByPathExists(transaction->DataPublisherInstance->ModelHandle, propertyPath))
+ {
+ free(propertyPathCopy);
+
+ /* Codes_SRS_DATA_PUBLISHER_99_040:[ When propertyPath does not exist in the supplied model, DataPublisher_Publish shall return DATA_PUBLISHER_SCHEMA_FAILED without dispatching data.] */
+ result = DATA_PUBLISHER_SCHEMA_FAILED;
+ LOG_DATA_PUBLISHER_ERROR;
+ }
+ else if ((propertyValue = (AGENT_DATA_TYPE*)malloc(sizeof(AGENT_DATA_TYPE))) == NULL)
+ {
+ free(propertyPathCopy);
+
+ /* Codes_SRS_DATA_PUBLISHER_99_020:[ For any errors not explicitly mentioned here the DataPublisher APIs shall return DATA_PUBLISHER_ERROR.] */
+ result = DATA_PUBLISHER_ERROR;
+ LOG_DATA_PUBLISHER_ERROR;
+ }
+ else if (Create_AGENT_DATA_TYPE_from_AGENT_DATA_TYPE(propertyValue, data) != AGENT_DATA_TYPES_OK)
+ {
+ free(propertyPathCopy);
+ free(propertyValue);
+
+ /* Codes_SRS_DATA_PUBLISHER_99_028:[ If creating the copy fails then DATA_PUBLISHER_AGENT_DATA_TYPES_ERROR shall be returned.] */
+ result = DATA_PUBLISHER_AGENT_DATA_TYPES_ERROR;
+ LOG_DATA_PUBLISHER_ERROR;
+ }
+ else
+ {
+ size_t i;
+ DATA_MARSHALLER_VALUE* propertySlot = NULL;
+
+ /* Codes_SRS_DATA_PUBLISHER_99_019:[ If the same property is associated twice with a transaction, then the last value shall be kept associated with the transaction.] */
+ for (i = 0; i < transaction->ValueCount; i++)
+ {
+ if (strcmp(transaction->Values[i].PropertyPath, propertyPath) == 0)
+ {
+ propertySlot = &transaction->Values[i];
+ break;
+ }
+ }
+
+ if (propertySlot == NULL)
+ {
+ DATA_MARSHALLER_VALUE* newValues = (DATA_MARSHALLER_VALUE*)realloc(transaction->Values, sizeof(DATA_MARSHALLER_VALUE)* (transaction->ValueCount + 1));
+ if (newValues != NULL)
+ {
+ transaction->Values = newValues;
+ propertySlot = &transaction->Values[transaction->ValueCount];
+ propertySlot->Value = NULL;
+ propertySlot->PropertyPath = NULL;
+ transaction->ValueCount++;
+ }
+ }
+
+ if (propertySlot == NULL)
+ {
+ Destroy_AGENT_DATA_TYPE((AGENT_DATA_TYPE*)propertyValue);
+ free(propertyValue);
+ free(propertyPathCopy);
+
+ /* Codes_SRS_DATA_PUBLISHER_99_020:[ For any errors not explicitly mentioned here the DataPublisher APIs shall return DATA_PUBLISHER_ERROR.] */
+ result = DATA_PUBLISHER_ERROR;
+ LOG_DATA_PUBLISHER_ERROR;
+ }
+ else
+ {
+ if (propertySlot->Value != NULL)
+ {
+ Destroy_AGENT_DATA_TYPE((AGENT_DATA_TYPE*)propertySlot->Value);
+ free((AGENT_DATA_TYPE*)propertySlot->Value);
+ }
+ if (propertySlot->PropertyPath != NULL)
+ {
+ char* existingValue = (char*)propertySlot->PropertyPath;
+ free(existingValue);
+ }
+
+ /* Codes_SRS_DATA_PUBLISHER_99_016:[ When DataPublisher_PublishTransacted is invoked, DataPublisher shall associate the data with the transaction identified by the transactionHandle argument and return DATA_PUBLISHER_OK. No data shall be dispatched at the time of the call.] */
+ propertySlot->PropertyPath = propertyPathCopy;
+ propertySlot->Value = propertyValue;
+
+ result = DATA_PUBLISHER_OK;
+ }
+ }
+ }
+
+ return result;
+}
+
+DATA_PUBLISHER_RESULT DataPublisher_EndTransaction(TRANSACTION_HANDLE transactionHandle, unsigned char** destination, size_t* destinationSize)
+{
+ DATA_PUBLISHER_RESULT result;
+
+ /*Codes_SRS_DATA_PUBLISHER_02_006: [If the destination argument is NULL, DataPublisher_EndTransaction shall return DATA_PUBLISHER_INVALID_ARG.] */
+ /*Codes_SRS_DATA_PUBLISHER_02_007: [If the destinationSize argument is NULL, DataPublisher_EndTransaction shall return DATA_PUBLISHER_INVALID_ARG.] */
+ if (
+ (transactionHandle == NULL) ||
+ (destination == NULL) ||
+ (destinationSize == NULL)
+ )
+ {
+ /* Codes_SRS_DATA_PUBLISHER_99_011:[ If the transactionHandle argument is NULL, DataPublisher_EndTransaction shall return DATA_PUBLISHER_INVALID_ARG.] */
+ result = DATA_PUBLISHER_INVALID_ARG;
+ LOG_DATA_PUBLISHER_ERROR;
+ }
+ else
+ {
+ TRANSACTION* transaction = (TRANSACTION*)transactionHandle;
+
+ if (transaction->ValueCount == 0)
+ {
+ /* Codes_SRS_DATA_PUBLISHER_99_024:[ If no values have been associated with the transaction, no data shall be dispatched
+ to DataMarshaller, the transaction shall be discarded and DataPublisher_EndTransaction shall return DATA_PUBLISHER_EMPTY_TRANSACTION.] */
+ result = DATA_PUBLISHER_EMPTY_TRANSACTION;
+ LOG_DATA_PUBLISHER_ERROR;
+ }
+ /* Codes_SRS_DATA_PUBLISHER_99_010:[ A call to DataPublisher_EndTransaction shall mark the end of a transaction and, trigger a dispatch of all the data grouped by that transaction.] */
+ else if (DataMarshaller_SendData(transaction->DataPublisherInstance->DataMarshallerHandle, transaction->ValueCount, transaction->Values, destination, destinationSize) != DATA_MARSHALLER_OK)
+ {
+ /* Codes_SRS_DATA_PUBLISHER_99_025:[ When the DataMarshaller_SendData call fails, DataPublisher_EndTransaction shall return DATA_PUBLISHER_MARSHALLER_ERROR.] */
+ result = DATA_PUBLISHER_MARSHALLER_ERROR;
+ LOG_DATA_PUBLISHER_ERROR;
+ }
+ else
+ {
+ /* Codes_SRS_DATA_PUBLISHER_99_026:[ On success, DataPublisher_EndTransaction shall return DATA_PUBLISHER_OK.] */
+ result = DATA_PUBLISHER_OK;
+ }
+
+ /* Codes_SRS_DATA_PUBLISHER_99_012:[ DataPublisher_EndTransaction shall dispose of any resources associated with the transaction.] */
+ (void)DataPublisher_CancelTransaction(transactionHandle);
+ }
+
+ return result;
+}
+
+DATA_PUBLISHER_RESULT DataPublisher_CancelTransaction(TRANSACTION_HANDLE transactionHandle)
+{
+ DATA_PUBLISHER_RESULT result;
+
+ if (transactionHandle == NULL)
+ {
+ /* Codes_SRS_DATA_PUBLISHER_99_014:[ If the transactionHandle argument is NULL DataPublisher_CancelTransaction shall return DATA_PUBLISHER_INVALID_ARG.] */
+ result = DATA_PUBLISHER_INVALID_ARG;
+ LOG_DATA_PUBLISHER_ERROR;
+ }
+ else
+ {
+ TRANSACTION* transaction = (TRANSACTION*)transactionHandle;
+ size_t i;
+
+ /* Codes_SRS_DATA_PUBLISHER_99_015:[ DataPublisher_CancelTransaction shall dispose of any resources associated with the transaction.] */
+ for (i = 0; i < transaction->ValueCount; i++)
+ {
+ Destroy_AGENT_DATA_TYPE((AGENT_DATA_TYPE*)transaction->Values[i].Value);
+ free((char*)transaction->Values[i].PropertyPath);
+ free((AGENT_DATA_TYPE*)transaction->Values[i].Value);
+ }
+
+ /* Codes_SRS_DATA_PUBLISHER_99_015:[ DataPublisher_CancelTransaction shall dispose of any resources associated with the transaction.] */
+ free(transaction->Values);
+ free(transaction);
+
+ /* Codes_SRS_DATA_PUBLISHER_99_013:[ A call to DataPublisher_CancelTransaction shall dispose of the transaction without dispatching
+ the data to the DataMarshaller module and it shall return DATA_PUBLISHER_OK.] */
+ result = DATA_PUBLISHER_OK;
+ }
+
+ return result;
+}
+
+/* Codes_SRS_DATA_PUBLISHER_99_065:[ DataPublisher_SetMaxBufferSize shall directly update the value used to limit how much data (in bytes) can be buffered in the BufferStorage instance.] */
+void DataPublisher_SetMaxBufferSize(size_t value)
+{
+ maxBufferSize_ = value;
+}
+
+/* Codes_SRS_DATA_PUBLISHER_99_069:[ DataMarshaller_GetMaxBufferSize shall return the current max buffer size value used by any new instance of DataMarshaller.] */
+size_t DataPublisher_GetMaxBufferSize(void)
+{
+ return maxBufferSize_;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/datapublisher.h Thu Oct 22 18:33:28 2015 -0700
@@ -0,0 +1,45 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+#ifndef DATA_PUBLISHER_H
+#define DATA_PUBLISHER_H
+
+#include "agenttypesystem.h"
+#include "schema.h"
+/* Normally we could include <stdbool> for cpp, but some toolchains are not well behaved and simply don't have it - ARM CC for example */
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define DATA_PUBLISHER_RESULT_VALUES \
+DATA_PUBLISHER_OK, \
+DATA_PUBLISHER_INVALID_ARG, \
+DATA_PUBLISHER_MARSHALLER_ERROR, \
+DATA_PUBLISHER_EMPTY_TRANSACTION, \
+DATA_PUBLISHER_AGENT_DATA_TYPES_ERROR, \
+DATA_PUBLISHER_SCHEMA_FAILED, \
+DATA_PUBLISHER_BUFFER_STORAGE_ERROR, \
+DATA_PUBLISHER_ERROR
+
+DEFINE_ENUM(DATA_PUBLISHER_RESULT, DATA_PUBLISHER_RESULT_VALUES);
+
+typedef void* TRANSACTION_HANDLE;
+typedef void* DATA_PUBLISHER_HANDLE;
+
+extern DATA_PUBLISHER_HANDLE DataPublisher_Create(SCHEMA_MODEL_TYPE_HANDLE modelHandle, bool includePropertyPath);
+extern void DataPublisher_Destroy(DATA_PUBLISHER_HANDLE dataPublisherHandle);
+
+extern TRANSACTION_HANDLE DataPublisher_StartTransaction(DATA_PUBLISHER_HANDLE dataPublisherHandle);
+extern DATA_PUBLISHER_RESULT DataPublisher_PublishTransacted(TRANSACTION_HANDLE transactionHandle, const char* propertyPath, const AGENT_DATA_TYPE* data);
+extern DATA_PUBLISHER_RESULT DataPublisher_EndTransaction(TRANSACTION_HANDLE transactionHandle, unsigned char** destination, size_t* destinationSize);
+extern DATA_PUBLISHER_RESULT DataPublisher_CancelTransaction(TRANSACTION_HANDLE transactionHandle);
+extern void DataPublisher_SetMaxBufferSize(size_t value);
+extern size_t DataPublisher_GetMaxBufferSize(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* DATA_PUBLISHER_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/dataserializer.c Thu Oct 22 18:33:28 2015 -0700
@@ -0,0 +1,62 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+#include <stdlib.h>
+#ifdef _CRTDBG_MAP_ALLOC
+#include <crtdbg.h>
+#endif
+#include "gballoc.h"
+
+#include "dataserializer.h"
+#include "iot_logging.h"
+
+DEFINE_ENUM_STRINGS(DATA_SERIALIZER_RESULT, DATA_SERIALIZER_RESULT_VALUES);
+
+BUFFER_HANDLE DataSerializer_Encode(MULTITREE_HANDLE multiTreeHandle, DATA_SERIALIZER_MULTITREE_TYPE dataType, DATA_SERIALIZER_ENCODE_FUNC encodeFunc)
+{
+ BUFFER_HANDLE pBuffer;
+
+ /* Codes_SRS_DATA_SERIALIZER_07_003: [NULL shall be returned when an invalid parameter is supplied.] */
+ if (multiTreeHandle == NULL || encodeFunc == NULL)
+ {
+ pBuffer = NULL;
+ LogError("(Error code: %s)\r\n", ENUM_TO_STRING(DATA_SERIALIZER_RESULT, DATA_SERIALIZER_INVALID_ARG) );
+ }
+ else
+ {
+ /* Codes_SRS_DATA_SERIALIZER_07_009: [DataSerializer_Encode function shall call into the given DATA_SERIALIZER_ENCODE_FUNC callback with a valid BUFFER object and valid MULTITREE_HANDLE object.] */
+ pBuffer = encodeFunc(multiTreeHandle, dataType);
+ if (pBuffer == NULL)
+ {
+ /* Codes_SRS_DATA_SERIALIZER_07_010: [Upon a DATA_SERIALIZER_ENCODE_FUNC failure the DataSerializer_Encode function shall return NULL.] */
+ LogError("(Error code: %s)\r\n", ENUM_TO_STRING(DATA_SERIALIZER_RESULT, DATA_SERIALIZER_ERROR) );
+ }
+ }
+ /* Codes_SRS_DATA_SERIALIZER_07_002: [DataSerializer_Encode shall return a valid BUFFER_HANDLE when the function executes successfully.] */
+ return pBuffer;
+}
+
+MULTITREE_HANDLE DataSerializer_Decode(BUFFER_HANDLE data, DATA_SERIALIZER_DECODE_FUNC decodeFunc)
+{
+ MULTITREE_HANDLE multiTreeHandle;
+
+ /* Codes_SRS_DATA_SERIALIZER_07_007: [NULL shall be returned when an invalid parameter is supplied.] */
+ if (data == NULL || decodeFunc == NULL)
+ {
+ multiTreeHandle = NULL;
+ LogError("(Error code: %s)\r\n", ENUM_TO_STRING(DATA_SERIALIZER_RESULT, DATA_SERIALIZER_INVALID_ARG) );
+ }
+ else
+ {
+ /* Codes_SRS_DATA_SERIALIZER_07_012: [DataSerializer_Decode function shall call into the given DATA_SERIALIZER_DECODE_FUNC callback with a valid BUFFER object and valid MULTITREE_HANDLE object.] */
+ multiTreeHandle = decodeFunc(data);
+ if (multiTreeHandle == NULL)
+ {
+ /* Codes_SRS_DATA_SERIALIZER_07_013: [Upon a DATA_SERIALIZER_DECODE_FUNC callback failure the DataSerializer_Encode function Shall return NULL.] */
+ LogError("(Error code: %s)\r\n", ENUM_TO_STRING(DATA_SERIALIZER_RESULT, DATA_SERIALIZER_ERROR) );
+ }
+ }
+
+ /* Codes_SRS_DATA_SERIALIZER_07_006: [DataSerializer_Decode shall return a valid MULTITREE_HANDLE when the function executes successfully.] */
+ return multiTreeHandle;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/dataserializer.h Thu Oct 22 18:33:28 2015 -0700
@@ -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.
+
+#ifndef DATASERIALIZER_H
+#define DATASERIALIZER_H
+
+#include "macro_utils.h"
+#include "multitree.h"
+#include "buffer_.h"
+
+#ifdef __cplusplus
+#include <cstddef>
+extern "C"
+{
+#else
+#include <stddef.h>
+#endif
+
+/*Codes_SRS_DATA_SERIALIZER_07_001: [DataSerializer will have the following interface]*/
+#define DATA_SERIALIZER_RESULT_VALUES \
+DATA_SERIALIZER_INVALID_ARG, \
+DATA_SERIALIZER_ERROR \
+
+DEFINE_ENUM(DATA_SERIALIZER_RESULT, DATA_SERIALIZER_RESULT_VALUES);
+
+#define DATA_SERIALIZER_MULTITREE_TYPE_VALUES \
+ DATA_SERIALIZER_TYPE_CHAR_PTR, \
+ DATA_SERIALIZER_TYPE_AGENT_DATA \
+
+DEFINE_ENUM(DATA_SERIALIZER_MULTITREE_TYPE, DATA_SERIALIZER_MULTITREE_TYPE_VALUES);
+
+typedef BUFFER_HANDLE (*DATA_SERIALIZER_ENCODE_FUNC)(MULTITREE_HANDLE multiTreeHandle, DATA_SERIALIZER_MULTITREE_TYPE dataType);
+typedef MULTITREE_HANDLE (*DATA_SERIALIZER_DECODE_FUNC)(BUFFER_HANDLE decodeData);
+
+extern BUFFER_HANDLE DataSerializer_Encode(MULTITREE_HANDLE multiTreeHandle, DATA_SERIALIZER_MULTITREE_TYPE dataType, DATA_SERIALIZER_ENCODE_FUNC encodeFunc);
+extern MULTITREE_HANDLE DataSerializer_Decode(BUFFER_HANDLE data, DATA_SERIALIZER_DECODE_FUNC decodeFunc);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // DATASERIALIZER_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/iotdevice.c Thu Oct 22 18:33:28 2015 -0700
@@ -0,0 +1,256 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+#include <stdlib.h>
+#ifdef _CRTDBG_MAP_ALLOC
+#include <crtdbg.h>
+#endif
+#include "gballoc.h"
+
+#include <stdbool.h>
+#include "iotdevice.h"
+#include "datapublisher.h"
+#include "commanddecoder.h"
+#include "crt_abstractions.h"
+#include "iot_logging.h"
+
+#define LOG_DEVICE_ERROR \
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(DEVICE_RESULT, result))
+
+typedef struct DEVICE_TAG
+{
+ SCHEMA_MODEL_TYPE_HANDLE model;
+ DATA_PUBLISHER_HANDLE dataPublisherHandle;
+ pPfDeviceActionCallback deviceActionCallback;
+ void* callbackUserContext;
+ COMMAND_DECODER_HANDLE commandDecoderHandle;
+} DEVICE;
+
+DEFINE_ENUM_STRINGS(DEVICE_RESULT, DEVICE_RESULT_VALUES);
+
+static EXECUTE_COMMAND_RESULT DeviceInvokeAction(void* actionCallbackContext, const char* relativeActionPath, const char* actionName, size_t argCount, const AGENT_DATA_TYPE* args)
+{
+ EXECUTE_COMMAND_RESULT result;
+
+ /*Codes_SRS_DEVICE_02_011: [If the parameter actionCallbackContent passed the callback is NULL then the callback shall return EXECUTE_COMMAND_ERROR.] */
+ if (actionCallbackContext == NULL)
+ {
+ result = EXECUTE_COMMAND_ERROR;
+ LogError("(Error code = %s)\r\n", ENUM_TO_STRING(DEVICE_RESULT, DEVICE_INVALID_ARG));
+ }
+ else
+ {
+ DEVICE* device = (DEVICE*)actionCallbackContext;
+
+ /* Codes_SRS_DEVICE_01_052: [When the action callback passed to CommandDecoder is called, Device shall call the appropriate user callback associated with the device handle.] */
+ /* Codes_SRS_DEVICE_01_055: [The value passed in callbackUserContext when creating the device shall be passed to the callback as the value for the callbackUserContext argument.] */
+ result = device->deviceActionCallback((DEVICE_HANDLE)device, device->callbackUserContext, relativeActionPath, actionName, argCount, args);
+ }
+
+ return result;
+}
+
+DEVICE_RESULT Device_Create(SCHEMA_MODEL_TYPE_HANDLE modelHandle, pPfDeviceActionCallback deviceActionCallback, void* callbackUserContext, bool includePropertyPath, DEVICE_HANDLE* deviceHandle)
+{
+ DEVICE_RESULT result;
+
+ /* Codes_SRS_DEVICE_05_014: [If any of the modelHandle, deviceHandle or deviceActionCallback arguments are NULL, Device_Create shall return DEVICE_INVALID_ARG.]*/
+ if (modelHandle == NULL || deviceHandle == NULL || deviceActionCallback == NULL )
+ {
+ result = DEVICE_INVALID_ARG;
+ LOG_DEVICE_ERROR;
+ }
+ else
+ {
+ DEVICE* device = (DEVICE*)malloc(sizeof(DEVICE));
+ if (device == NULL)
+ {
+ /* Codes_SRS_DEVICE_05_015: [If an error occurs while trying to create the device, Device_Create shall return DEVICE_ERROR.] */
+ result = DEVICE_ERROR;
+ LOG_DEVICE_ERROR;
+ }
+ else
+ {
+ /* Codes_SRS_DEVICE_01_018: [Device_Create shall create a DataPublisher instance by calling DataPublisher_Create.] */
+ /* Codes_SRS_DEVICE_01_020: [Device_Create shall pass to DataPublisher_Create the FrontDoor instance obtained earlier.] */
+ /* Codes_SRS_DEVICE_01_004: [DeviceCreate shall pass to DataPublisher_create the includePropertyPath argument.] */
+ if ((device->dataPublisherHandle = DataPublisher_Create(modelHandle, includePropertyPath)) == NULL)
+ {
+ free(device);
+
+ /* Codes_SRS_DEVICE_01_019: [If creating the DataPublisher instance fails, Device_Create shall return DEVICE_DATA_PUBLISHER_FAILED.] */
+ result = DEVICE_DATA_PUBLISHER_FAILED;
+ LOG_DEVICE_ERROR;
+ }
+ else
+ {
+ device->model = modelHandle;
+ device->deviceActionCallback = deviceActionCallback;
+ device->callbackUserContext = callbackUserContext;
+
+ /* Codes_SRS_DEVICE_01_001: [Device_Create shall create a CommandDecoder instance by calling CommandDecoder_Create and passing to it the model handle.] */
+ /* Codes_SRS_DEVICE_01_002: [Device_Create shall also pass to CommandDecoder_Create a callback to be invoked when a command is received and a context that shall be the device handle.] */
+ if ((device->commandDecoderHandle = CommandDecoder_Create(modelHandle, DeviceInvokeAction, device)) == NULL)
+ {
+ free(device);
+
+ /* Codes_SRS_DEVICE_01_003: [If CommandDecoder_Create fails, Device_Create shall return DEVICE_COMMAND_DECODER_FAILED.] */
+ result = DEVICE_COMMAND_DECODER_FAILED;
+ LOG_DEVICE_ERROR;
+ }
+ else
+ {
+ /* Codes_SRS_DEVICE_03_003: [The DEVICE_HANDLE shall be provided via the deviceHandle out argument.] */
+ *deviceHandle = (DEVICE_HANDLE)device;
+ /* Codes_SRS_DEVICE_03_004: [Device_Create shall return DEVICE_OK upon success.] */
+ result = DEVICE_OK;
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+/* Codes_SRS_DEVICE_03_006: [Device_Destroy shall free all resources associated with a device.] */
+void Device_Destroy(DEVICE_HANDLE deviceHandle)
+{
+ /* Codes_SRS_DEVICE_03_007: [Device_Destroy will not do anything if deviceHandle is NULL.] */
+ if (deviceHandle != NULL)
+ {
+ DEVICE* device = (DEVICE*)deviceHandle;
+
+ DataPublisher_Destroy(device->dataPublisherHandle);
+ CommandDecoder_Destroy(device->commandDecoderHandle);
+
+ free(device);
+ }
+}
+
+TRANSACTION_HANDLE Device_StartTransaction(DEVICE_HANDLE deviceHandle)
+{
+ TRANSACTION_HANDLE result;
+
+ /* Codes_SRS_DEVICE_01_035: [If any argument is NULL, Device_StartTransaction shall return NULL.] */
+ if (deviceHandle == NULL)
+ {
+ result = NULL;
+ LogError("(Error code = %s)\r\n", ENUM_TO_STRING(DEVICE_RESULT, DEVICE_INVALID_ARG));
+ }
+ else
+ {
+ DEVICE* deviceInstance = (DEVICE*)deviceHandle;
+
+ /* Codes_SRS_DEVICE_01_034: [Device_StartTransaction shall invoke DataPublisher_StartTransaction for the DataPublisher handle associated with the deviceHandle argument.] */
+ /* Codes_SRS_DEVICE_01_043: [On success, Device_StartTransaction shall return a non NULL handle.] */
+ /* Codes_SRS_DEVICE_01_048: [When DataPublisher_StartTransaction fails, Device_StartTransaction shall return NULL.] */
+ result = DataPublisher_StartTransaction(deviceInstance->dataPublisherHandle);
+ }
+
+ return result;
+}
+
+DEVICE_RESULT Device_PublishTransacted(TRANSACTION_HANDLE transactionHandle, const char* propertyPath, const AGENT_DATA_TYPE* data)
+{
+ DEVICE_RESULT result;
+
+ /* Codes_SRS_DEVICE_01_037: [If any argument is NULL, Device_PublishTransacted shall return DEVICE_INVALID_ARG.] */
+ if ((transactionHandle == NULL) ||
+ (propertyPath == NULL) ||
+ (data == NULL))
+ {
+ result = DEVICE_INVALID_ARG;
+ LOG_DEVICE_ERROR;
+ }
+ /* Codes_SRS_DEVICE_01_036: [Device_PublishTransacted shall invoke DataPublisher_PublishTransacted.] */
+ else if (DataPublisher_PublishTransacted(transactionHandle, propertyPath, data) != DATA_PUBLISHER_OK)
+ {
+ /* Codes_SRS_DEVICE_01_049: [When DataPublisher_PublishTransacted fails, Device_PublishTransacted shall return DEVICE_DATA_PUBLISHER_FAILED.] */
+ result = DEVICE_DATA_PUBLISHER_FAILED;
+ LOG_DEVICE_ERROR;
+ }
+ else
+ {
+ /* Codes_SRS_DEVICE_01_044: [On success, Device_PublishTransacted shall return DEVICE_OK.] */
+ result = DEVICE_OK;
+ }
+
+ return result;
+}
+
+DEVICE_RESULT Device_EndTransaction(TRANSACTION_HANDLE transactionHandle, unsigned char** destination, size_t* destinationSize)
+{
+ DEVICE_RESULT result;
+
+ /* Codes_SRS_DEVICE_01_039: [If any parameter is NULL, Device_EndTransaction shall return DEVICE_INVALID_ARG.]*/
+ if (
+ (transactionHandle == NULL) ||
+ (destination == NULL) ||
+ (destinationSize == NULL)
+ )
+ {
+ result = DEVICE_INVALID_ARG;
+ LOG_DEVICE_ERROR;
+ }
+ /* Codes_SRS_DEVICE_01_038: [Device_EndTransaction shall invoke DataPublisher_EndTransaction.] */
+ else if (DataPublisher_EndTransaction(transactionHandle, destination, destinationSize) != DATA_PUBLISHER_OK)
+ {
+ /* Codes_SRS_DEVICE_01_050: [When DataPublisher_EndTransaction fails, Device_EndTransaction shall return DEVICE_DATA_PUBLISHER_FAILED.] */
+ result = DEVICE_DATA_PUBLISHER_FAILED;
+ LOG_DEVICE_ERROR;
+ }
+ else
+ {
+ /* Codes_SRS_DEVICE_01_045: [On success, Device_EndTransaction shall return DEVICE_OK.] */
+ result = DEVICE_OK;
+ }
+
+ return result;
+}
+
+DEVICE_RESULT Device_CancelTransaction(TRANSACTION_HANDLE transactionHandle)
+{
+ DEVICE_RESULT result;
+
+ /* Codes_SRS_DEVICE_01_041: [If any argument is NULL, Device_CancelTransaction shall return DEVICE_INVALID_ARG.] */
+ if (transactionHandle == NULL)
+ {
+ result = DEVICE_INVALID_ARG;
+ LOG_DEVICE_ERROR;
+ }
+ /* Codes_SRS_DEVICE_01_040: [Device_CancelTransaction shall invoke DataPublisher_CancelTransaction.] */
+ else if (DataPublisher_CancelTransaction(transactionHandle) != DATA_PUBLISHER_OK)
+ {
+ /* Codes_SRS_DEVICE_01_051: [When DataPublisher_CancelTransaction fails, Device_CancelTransaction shall return DEVICE_DATA_PUBLISHER_FAILED.] */
+ result = DEVICE_DATA_PUBLISHER_FAILED;
+ LOG_DEVICE_ERROR;
+ }
+ else
+ {
+ /* Codes_SRS_DEVICE_01_046: [On success, Device_PublishTransacted shall return DEVICE_OK.] */
+ result = DEVICE_OK;
+ }
+
+ return result;
+}
+
+EXECUTE_COMMAND_RESULT Device_ExecuteCommand(DEVICE_HANDLE deviceHandle, const char* command)
+{
+ EXECUTE_COMMAND_RESULT result;
+ /*Codes_SRS_DEVICE_02_012: [If any parameters are NULL, then Device_ExecuteCommand shall return EXECUTE_COMMAND_ERROR.] */
+ if (
+ (deviceHandle == NULL) ||
+ (command == NULL)
+ )
+ {
+ result = EXECUTE_COMMAND_ERROR;
+ LogError("invalid parameter (NULL passed to Device_ExecuteCommand DEVICE_HANDLE deviceHandle=%p, const char* command=%p", deviceHandle, command);
+ }
+ else
+ {
+ /*Codes_SRS_DEVICE_02_013: [Otherwise, Device_ExecuteCommand shall call CommandDecoder_ExecuteCommand and return what CommandDecoder_ExecuteCommand is returning.] */
+ DEVICE* device = (DEVICE*)deviceHandle;
+ result = CommandDecoder_ExecuteCommand(device->commandDecoderHandle, command);
+ }
+ return result;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/iotdevice.h Thu Oct 22 18:33:28 2015 -0700
@@ -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 IOTDEVICE_H
+#define IOTDEVICE_H
+
+#include <stdbool.h>
+#include "macro_utils.h"
+#include "schema.h"
+#include "datapublisher.h"
+#include "commanddecoder.h"
+
+#ifdef __cplusplus
+#include <cstddef>
+extern "C" {
+#else
+#include <stddef.h>
+#endif
+
+#define DEVICE_RESULT_VALUES \
+ DEVICE_OK, \
+ DEVICE_INVALID_ARG, \
+ DEVICE_DATA_PUBLISHER_FAILED, \
+ DEVICE_COMMAND_DECODER_FAILED, \
+ DEVICE_ERROR
+
+DEFINE_ENUM(DEVICE_RESULT, DEVICE_RESULT_VALUES)
+
+typedef void* DEVICE_HANDLE;
+typedef EXECUTE_COMMAND_RESULT (*pPfDeviceActionCallback)(DEVICE_HANDLE deviceHandle, void* callbackUserContext, const char* relativeActionPath, const char* actionName, size_t argCount, const AGENT_DATA_TYPE* args);
+
+extern DEVICE_RESULT Device_Create(SCHEMA_MODEL_TYPE_HANDLE modelHandle, pPfDeviceActionCallback deviceActionCallback, void* callbackUserContext, bool includePropertyPath, DEVICE_HANDLE* deviceHandle);
+extern void Device_Destroy(DEVICE_HANDLE deviceHandle);
+
+extern TRANSACTION_HANDLE Device_StartTransaction(DEVICE_HANDLE deviceHandle);
+extern DEVICE_RESULT Device_PublishTransacted(TRANSACTION_HANDLE transactionHandle, const char* propertyPath, const AGENT_DATA_TYPE* data);
+extern DEVICE_RESULT Device_EndTransaction(TRANSACTION_HANDLE transactionHandle, unsigned char** destination, size_t* destinationSize);
+extern DEVICE_RESULT Device_CancelTransaction(TRANSACTION_HANDLE transactionHandle);
+
+extern EXECUTE_COMMAND_RESULT Device_ExecuteCommand(DEVICE_HANDLE deviceHandle, const char* command);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* IOTDEVICE_H */
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jsondecoder.c Thu Oct 22 18:33:28 2015 -0700
@@ -0,0 +1,614 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+#include <stdlib.h>
+#ifdef _CRTDBG_MAP_ALLOC
+#include <crtdbg.h>
+#endif
+#include "gballoc.h"
+
+#include "jsondecoder.h"
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stddef.h>
+
+#define IsWhiteSpace(A) (((A) == 0x20) || ((A) == 0x09) || ((A) == 0x0A) || ((A) == 0x0D))
+
+typedef struct PARSER_STATE_TAG
+{
+ char* json;
+} PARSER_STATE;
+
+static JSON_DECODER_RESULT ParseArray(PARSER_STATE* parserState, MULTITREE_HANDLE currentNode);
+static JSON_DECODER_RESULT ParseObject(PARSER_STATE* parserState, MULTITREE_HANDLE currentNode);
+
+/* Codes_SRS_JSON_DECODER_99_049:[ JSONDecoder shall not allocate new string values for the leafs, but rather point to strings in the original JSON.] */
+static void NoFreeFunction(void* value)
+{
+ (void)value;
+}
+
+static int NOPCloneFunction(void** destination, const void* source)
+{
+ *destination = (void**)source;
+ return 0;
+}
+
+void SkipWhiteSpaces(PARSER_STATE* parserState)
+{
+ while ((*(parserState->json) != '\0') && IsWhiteSpace(*(parserState->json)))
+ {
+ parserState->json++;
+ }
+}
+
+static JSON_DECODER_RESULT ParseString(PARSER_STATE* parserState, char** stringBegin)
+{
+ JSON_DECODER_RESULT result = JSON_DECODER_OK;
+ *stringBegin = parserState->json;
+
+ /* Codes_SRS_JSON_DECODER_99_028:[ A string begins and ends with quotation marks.] */
+ if (*(parserState->json) != '"')
+ {
+ /* Codes_SRS_JSON_DECODER_99_007:[ If parsing the JSON fails due to the JSON string being malformed, JSONDecoder_JSON_To_MultiTree shall return JSON_DECODER_PARSE_ERROR.] */
+ result = JSON_DECODER_PARSE_ERROR;
+ }
+ else
+ {
+ parserState->json++;
+ while ((*(parserState->json) != '"') && (*(parserState->json) != '\0'))
+ {
+ /* Codes_SRS_JSON_DECODER_99_030:[ Any character may be escaped.] */
+ /* Codes_SRS_JSON_DECODER_99_033:[ Alternatively, there are two-character sequence escape representations of some popular characters. So, for example, a string containing only a single reverse solidus character may be represented more compactly as "\\".] */
+ if (*(parserState->json) == '\\')
+ {
+ parserState->json++;
+ if (
+ /* Codes_SRS_JSON_DECODER_99_051:[ %x5C / ; \ reverse solidus U+005C] */
+ (*parserState->json == '\\') ||
+ /* Codes_SRS_JSON_DECODER_99_050:[ %x22 / ; " quotation mark U+0022] */
+ (*parserState->json == '"') ||
+ /* Codes_SRS_JSON_DECODER_99_052:[ %x2F / ; / solidus U+002F] */
+ (*parserState->json == '/') ||
+ /* Codes_SRS_JSON_DECODER_99_053:[ %x62 / ; b backspace U+0008] */
+ (*parserState->json == 'b') ||
+ /* Codes_SRS_JSON_DECODER_99_054:[ %x66 / ; f form feed U+000C] */
+ (*parserState->json == 'f') ||
+ /* Codes_SRS_JSON_DECODER_99_055:[ %x6E / ; n line feed U+000A] */
+ (*parserState->json == 'n') ||
+ /* Codes_SRS_JSON_DECODER_99_056:[ %x72 / ; r carriage return U+000D] */
+ (*parserState->json == 'r') ||
+ /* Codes_SRS_JSON_DECODER_99_057:[ %x74 / ; t tab U+0009] */
+ (*parserState->json == 't'))
+ {
+ parserState->json++;
+ }
+ else
+ {
+ /* Codes_SRS_JSON_DECODER_99_007:[ If parsing the JSON fails due to the JSON string being malformed, JSONDecoder_JSON_To_MultiTree shall return JSON_DECODER_PARSE_ERROR.] */
+ result = JSON_DECODER_PARSE_ERROR;
+ break;
+ }
+ }
+ else
+ {
+ parserState->json++;
+ }
+ }
+
+ if (*(parserState->json) != '"')
+ {
+ /* Codes_SRS_JSON_DECODER_99_007:[ If parsing the JSON fails due to the JSON string being malformed, JSONDecoder_JSON_To_MultiTree shall return JSON_DECODER_PARSE_ERROR.] */
+ result = JSON_DECODER_PARSE_ERROR;
+ }
+ else
+ {
+ parserState->json++;
+ result = JSON_DECODER_OK;
+ }
+ }
+
+ return result;
+}
+
+static JSON_DECODER_RESULT ParseNumber(PARSER_STATE* parserState)
+{
+ JSON_DECODER_RESULT result = JSON_DECODER_OK;
+ size_t digitCount = 0;
+
+ if (*(parserState->json) == '-')
+ {
+ parserState->json++;
+ }
+
+ /* Codes_SRS_JSON_DECODER_99_043:[ A number contains an integer component that may be prefixed with an optional minus sign, which may be followed by a fraction part and/or an exponent part.] */
+ while (*(parserState->json) != '\0')
+ {
+ /* Codes_SRS_JSON_DECODER_99_044:[ Octal and hex forms are not allowed.] */
+ if (isdigit(*(parserState->json)))
+ {
+ digitCount++;
+ /* simply continue */
+ }
+ else
+ {
+ break;
+ }
+
+ parserState->json++;
+ }
+
+ if ((digitCount == 0) ||
+ /* Codes_SRS_JSON_DECODER_99_045:[ Leading zeros are not allowed.] */
+ ((digitCount > 1) && *(parserState->json - digitCount) == '0'))
+ {
+ /* Codes_SRS_JSON_DECODER_99_007:[ If parsing the JSON fails due to the JSON string being malformed, JSONDecoder_JSON_To_MultiTree shall return JSON_DECODER_PARSE_ERROR.] */
+ result = JSON_DECODER_PARSE_ERROR;
+ }
+ else
+ {
+ /* Codes_SRS_JSON_DECODER_99_046:[ A fraction part is a decimal point followed by one or more digits.] */
+ if (*(parserState->json) == '.')
+ {
+ /* optional fractional part */
+ parserState->json++;
+ digitCount = 0;
+
+ while (*(parserState->json) != '\0')
+ {
+ /* Codes_SRS_JSON_DECODER_99_044:[ Octal and hex forms are not allowed.] */
+ if (isdigit(*(parserState->json)))
+ {
+ digitCount++;
+ /* simply continue */
+ }
+ else
+ {
+ break;
+ }
+
+ parserState->json++;
+ }
+
+ if (digitCount == 0)
+ {
+ /* Codes_SRS_JSON_DECODER_99_007:[ If parsing the JSON fails due to the JSON string being malformed, JSONDecoder_JSON_To_MultiTree shall return JSON_DECODER_PARSE_ERROR.] */
+ result = JSON_DECODER_PARSE_ERROR;
+ }
+ }
+
+ /* Codes_SRS_JSON_DECODER_99_047:[ An exponent part begins with the letter E in upper or lowercase, which may be followed by a plus or minus sign.] */
+ if ((*(parserState->json) == 'e') || (*(parserState->json) == 'E'))
+ {
+ parserState->json++;
+
+ /* optional sign */
+ if ((*(parserState->json) == '-') || (*(parserState->json) == '+'))
+ {
+ parserState->json++;
+ }
+
+ digitCount = 0;
+
+ /* Codes_SRS_JSON_DECODER_99_048:[ The E and optional sign are followed by one or more digits.] */
+ while (*(parserState->json) != '\0')
+ {
+ /* Codes_SRS_JSON_DECODER_99_044:[ Octal and hex forms are not allowed.] */
+ if (isdigit(*(parserState->json)))
+ {
+ digitCount++;
+ /* simply continue */
+ }
+ else
+ {
+ break;
+ }
+
+ parserState->json++;
+ }
+
+ if (digitCount == 0)
+ {
+ /* Codes_SRS_JSON_DECODER_99_007:[ If parsing the JSON fails due to the JSON string being malformed, JSONDecoder_JSON_To_MultiTree shall return JSON_DECODER_PARSE_ERROR.] */
+ result = JSON_DECODER_PARSE_ERROR;
+ }
+ }
+ }
+
+ return result;
+}
+
+static JSON_DECODER_RESULT ParseValue(PARSER_STATE* parserState, MULTITREE_HANDLE currentNode, char** stringBegin)
+{
+ JSON_DECODER_RESULT result;
+
+ SkipWhiteSpaces(parserState);
+
+ if (*(parserState->json) == '"')
+ {
+ result = ParseString(parserState, stringBegin);
+ }
+ /* Codes_SRS_JSON_DECODER_99_018:[ A JSON value MUST be an object, array, number, or string, or one of the following three literal names: false null true] */
+ /* Codes_SRS_JSON_DECODER_99_019:[ The literal names MUST be lowercase.] */
+ /* Codes_SRS_JSON_DECODER_99_020:[ No other literal names are allowed.] */
+ else if (strncmp(parserState->json, "false", 5) == 0)
+ {
+ *stringBegin = parserState->json;
+ parserState->json += 5;
+ result = JSON_DECODER_OK;
+ }
+ else if (strncmp(parserState->json, "true", 4) == 0)
+ {
+ *stringBegin = parserState->json;
+ parserState->json += 4;
+ result = JSON_DECODER_OK;
+ }
+ else if (strncmp(parserState->json, "null", 4) == 0)
+ {
+ *stringBegin = parserState->json;
+ parserState->json += 4;
+ result = JSON_DECODER_OK;
+ }
+ /* Tests_SRS_JSON_DECODER_99_018:[ A JSON value MUST be an object, array, number, or string, or one of the following three literal names: false null true] */
+ else if (*(parserState->json) == '[')
+ {
+ result = ParseArray(parserState, currentNode);
+ *stringBegin = NULL;
+ }
+ else if (*(parserState->json) == '{')
+ {
+ result = ParseObject(parserState, currentNode);
+ *stringBegin = NULL;
+ }
+ else if (
+ (
+ isdigit(*(parserState->json))
+ )
+ || (*(parserState->json) == '-'))
+ {
+ *stringBegin = parserState->json;
+ result = ParseNumber(parserState);
+ }
+ else
+ {
+ /* Codes_SRS_JSON_DECODER_99_007:[ If parsing the JSON fails due to the JSON string being malformed, JSONDecoder_JSON_To_MultiTree shall return JSON_DECODER_PARSE_ERROR.] */
+ result = JSON_DECODER_PARSE_ERROR;
+ }
+
+ return result;
+}
+
+static JSON_DECODER_RESULT ParseColon(PARSER_STATE* parserState)
+{
+ JSON_DECODER_RESULT result;
+
+ SkipWhiteSpaces(parserState);
+ /* Codes_SRS_JSON_DECODER_99_023:[ A single colon comes after each name, separating the name from the value.] */
+ if (*(parserState->json) != ':')
+ {
+ /* Codes_SRS_JSON_DECODER_99_007:[ If parsing the JSON fails due to the JSON string being malformed, JSONDecoder_JSON_To_MultiTree shall return JSON_DECODER_PARSE_ERROR.] */
+ result = JSON_DECODER_PARSE_ERROR;
+ }
+ else
+ {
+ parserState->json++;
+ result = JSON_DECODER_OK;
+ }
+
+ return result;
+}
+
+static JSON_DECODER_RESULT ParseOpenCurly(PARSER_STATE* parserState)
+{
+ JSON_DECODER_RESULT result = JSON_DECODER_OK;
+
+ SkipWhiteSpaces(parserState);
+
+ /* Codes_SRS_JSON_DECODER_99_021:[ An object structure is represented as a pair of curly brackets surrounding zero or more name/value pairs (or members).] */
+ if (*(parserState->json) != '{')
+ {
+ /* Codes_SRS_JSON_DECODER_99_007:[ If parsing the JSON fails due to the JSON string being malformed, JSONDecoder_JSON_To_MultiTree shall return JSON_DECODER_PARSE_ERROR.] */
+ result = JSON_DECODER_PARSE_ERROR;
+ }
+ else
+ {
+ parserState->json++;
+ result = JSON_DECODER_OK;
+ }
+
+ return result;
+}
+
+static JSON_DECODER_RESULT ParseNameValuePair(PARSER_STATE* parserState, MULTITREE_HANDLE currentNode)
+{
+ JSON_DECODER_RESULT result;
+ char* memberNameBegin;
+
+ SkipWhiteSpaces(parserState);
+
+ /* Codes_SRS_JSON_DECODER_99_022:[ A name is a string.] */
+ result = ParseString(parserState, &memberNameBegin);
+ if (result == JSON_DECODER_OK)
+ {
+ char* valueBegin;
+ MULTITREE_HANDLE childNode;
+ *(parserState->json - 1) = 0;
+
+ result = ParseColon(parserState);
+ if (result == JSON_DECODER_OK)
+ {
+ /* Codes_SRS_JSON_DECODER_99_025:[ The names within an object SHOULD be unique.] */
+ /* Multi Tree takes care of not having 2 children with the same name */
+ /* Codes_SRS_JSON_DECODER_99_002:[ JSONDecoder_JSON_To_MultiTree shall use the MultiTree APIs to create the multi tree and add leafs to the multi tree.] */
+ /* Codes_SRS_JSON_DECODER_99_003:[ When a JSON element is decoded from the JSON object then a leaf shall be added to the MultiTree.] */
+ /* Codes_SRS_JSON_DECODER_99_004:[ The leaf node name in the multi tree shall be the JSON element name.] */
+ if (MultiTree_AddChild(currentNode, memberNameBegin + 1, &childNode) != MULTITREE_OK)
+ {
+ /* Codes_SRS_JSON_DECODER_99_038:[ If any MultiTree API fails, JSONDecoder_JSON_To_MultiTree shall return JSON_DECODER_MULTITREE_FAILED.] */
+ result = JSON_DECODER_MULTITREE_FAILED;
+ }
+ else
+ {
+ result = ParseValue(parserState, childNode, &valueBegin);
+ if ((result == JSON_DECODER_OK) && (valueBegin != NULL))
+ {
+ /* Codes_SRS_JSON_DECODER_99_005:[ The leaf node added in the multi tree shall have the value the string value of the JSON element as parsed from the JSON object.] */
+ if (MultiTree_SetValue(childNode, valueBegin) != MULTITREE_OK)
+ {
+ /* Codes_SRS_JSON_DECODER_99_038:[ If any MultiTree API fails, JSONDecoder_JSON_To_MultiTree shall return JSON_DECODER_MULTITREE_FAILED.] */
+ result = JSON_DECODER_MULTITREE_FAILED;
+ }
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+static JSON_DECODER_RESULT ParseObject(PARSER_STATE* parserState, MULTITREE_HANDLE currentNode)
+{
+ JSON_DECODER_RESULT result = ParseOpenCurly(parserState);
+ if (result == JSON_DECODER_OK)
+ {
+ char jsonChar;
+
+ SkipWhiteSpaces(parserState);
+
+ jsonChar = *(parserState->json);
+ while ((jsonChar != '}') && (jsonChar != '\0'))
+ {
+ char* valueEnd;
+
+ /* decode each value */
+ result = ParseNameValuePair(parserState, currentNode);
+ if (result != JSON_DECODER_OK)
+ {
+ break;
+ }
+
+ valueEnd = parserState->json;
+
+ SkipWhiteSpaces(parserState);
+ jsonChar = *(parserState->json);
+ *valueEnd = 0;
+
+ /* Codes_SRS_JSON_DECODER_99_024:[ A single comma separates a value from a following name.] */
+ if (jsonChar == ',')
+ {
+ parserState->json++;
+ /* get the next name/value pair */
+ }
+ }
+
+ if (result != JSON_DECODER_OK)
+ {
+ /* already have error */
+ }
+ else
+ {
+ if (jsonChar != '}')
+ {
+ /* Codes_SRS_JSON_DECODER_99_007:[ If parsing the JSON fails due to the JSON string being malformed, JSONDecoder_JSON_To_MultiTree shall return JSON_DECODER_PARSE_ERROR.] */
+ result = JSON_DECODER_PARSE_ERROR;
+ }
+ else
+ {
+ parserState->json++;
+ }
+ }
+ }
+
+ return result;
+}
+
+static JSON_DECODER_RESULT ParseArray(PARSER_STATE* parserState, MULTITREE_HANDLE currentNode)
+{
+ JSON_DECODER_RESULT result = JSON_DECODER_OK;
+
+ SkipWhiteSpaces(parserState);
+
+ /* Codes_SRS_JSON_DECODER_99_026:[ An array structure is represented as square brackets surrounding zero or more values (or elements).] */
+ if (*(parserState->json) != '[')
+ {
+ /* Codes_SRS_JSON_DECODER_99_007:[ If parsing the JSON fails due to the JSON string being malformed, JSONDecoder_JSON_To_MultiTree shall return JSON_DECODER_PARSE_ERROR.] */
+ result = JSON_DECODER_PARSE_ERROR;
+ }
+ else
+ {
+ char* stringBegin;
+ char jsonChar;
+ int arrayIndex = 0;
+ result = JSON_DECODER_OK;
+
+ parserState->json++;
+
+ SkipWhiteSpaces(parserState);
+
+ jsonChar = *parserState->json;
+ while ((jsonChar != ']') && (jsonChar != '\0'))
+ {
+ char arrayIndexStr[22];
+ MULTITREE_HANDLE childNode;
+
+ /* Codes_SRS_JSON_DECODER_99_039:[ For array elements the multi tree node name shall be the string representation of the array index.] */
+ if (sprintf(arrayIndexStr, "%d", arrayIndex++) < 0)
+ {
+ result = JSON_DECODER_ERROR;
+ break;
+ }
+ /* Codes_SRS_JSON_DECODER_99_003:[ When a JSON element is decoded from the JSON object then a leaf shall be added to the MultiTree.] */
+ else if (MultiTree_AddChild(currentNode, arrayIndexStr, &childNode) != MULTITREE_OK)
+ {
+ /* Codes_SRS_JSON_DECODER_99_038:[ If any MultiTree API fails, JSONDecoder_JSON_To_MultiTree shall return JSON_DECODER_MULTITREE_FAILED.] */
+ result = JSON_DECODER_MULTITREE_FAILED;
+ }
+ else
+ {
+ char* valueEnd;
+
+ /* decode each value */
+ result = ParseValue(parserState, childNode, &stringBegin);
+ if (result != JSON_DECODER_OK)
+ {
+ break;
+ }
+
+ if (stringBegin != NULL)
+ {
+ /* Codes_SRS_JSON_DECODER_99_005:[ The leaf node added in the multi tree shall have the value the string value of the JSON element as parsed from the JSON object.] */
+ if (MultiTree_SetValue(childNode, stringBegin) != MULTITREE_OK)
+ {
+ /* Codes_SRS_JSON_DECODER_99_038:[ If any MultiTree API fails, JSONDecoder_JSON_To_MultiTree shall return JSON_DECODER_MULTITREE_FAILED.] */
+ result = JSON_DECODER_MULTITREE_FAILED;
+ break;
+ }
+ }
+
+ valueEnd = parserState->json;
+
+ SkipWhiteSpaces(parserState);
+ jsonChar = *(parserState->json);
+ *valueEnd = 0;
+
+ /* Codes_SRS_JSON_DECODER_99_027:[ Elements are separated by commas.] */
+ if (jsonChar == ',')
+ {
+ parserState->json++;
+ /* get the next value pair */
+ }
+ else if (jsonChar == ']')
+ {
+ break;
+ }
+ else
+ {
+ /* Codes_SRS_JSON_DECODER_99_007:[ If parsing the JSON fails due to the JSON string being malformed, JSONDecoder_JSON_To_MultiTree shall return JSON_DECODER_PARSE_ERROR.] */
+ result = JSON_DECODER_PARSE_ERROR;
+ break;
+ }
+ }
+ }
+
+ if (result != JSON_DECODER_OK)
+ {
+ /* already have error */
+ }
+ else
+ {
+ if (jsonChar != ']')
+ {
+ /* Codes_SRS_JSON_DECODER_99_007:[ If parsing the JSON fails due to the JSON string being malformed, JSONDecoder_JSON_To_MultiTree shall return JSON_DECODER_PARSE_ERROR.] */
+ result = JSON_DECODER_PARSE_ERROR;
+ }
+ else
+ {
+ parserState->json++;
+ SkipWhiteSpaces(parserState);
+ }
+ }
+ }
+
+ return result;
+}
+
+/* Codes_SRS_JSON_DECODER_99_012:[ A JSON text is a serialized object or array.] */
+static JSON_DECODER_RESULT ParseObjectOrArray(PARSER_STATE* parserState, MULTITREE_HANDLE currentNode)
+{
+ JSON_DECODER_RESULT result = JSON_DECODER_PARSE_ERROR;
+
+ SkipWhiteSpaces(parserState);
+
+ if (*(parserState->json) == '{')
+ {
+ result = ParseObject(parserState, currentNode);
+ SkipWhiteSpaces(parserState);
+ }
+ else if (*(parserState->json) == '[')
+ {
+ result = ParseArray(parserState, currentNode);
+ SkipWhiteSpaces(parserState);
+ }
+ else
+ {
+ /* Codes_SRS_JSON_DECODER_99_007:[ If parsing the JSON fails due to the JSON string being malformed, JSONDecoder_JSON_To_MultiTree shall return JSON_DECODER_PARSE_ERROR.] */
+ result = JSON_DECODER_PARSE_ERROR;
+ }
+
+ if ((result == JSON_DECODER_OK) &&
+ (*(parserState->json) != '\0'))
+ {
+ /* Codes_SRS_JSON_DECODER_99_007:[ If parsing the JSON fails due to the JSON string being malformed, JSONDecoder_JSON_To_MultiTree shall return JSON_DECODER_PARSE_ERROR.] */
+ result = JSON_DECODER_PARSE_ERROR;
+ }
+
+ return result;
+}
+
+static JSON_DECODER_RESULT ParseJSON(char* json, MULTITREE_HANDLE currentNode)
+{
+ /* Codes_SRS_JSON_DECODER_99_009:[ On success, JSONDecoder_JSON_To_MultiTree shall return a handle to the multi tree it created in the multiTreeHandle argument and it shall return JSON_DECODER_OK.] */
+ PARSER_STATE parseState;
+ parseState.json = json;
+ return ParseObjectOrArray(&parseState, currentNode);
+}
+
+JSON_DECODER_RESULT JSONDecoder_JSON_To_MultiTree(char* json, MULTITREE_HANDLE* multiTreeHandle)
+{
+ JSON_DECODER_RESULT result;
+
+ if ((json == NULL) ||
+ (multiTreeHandle == NULL))
+ {
+ /* Codes_SRS_JSON_DECODER_99_001:[ If any of the parameters passed to the JSONDecoder_JSON_To_MultiTree function is NULL then the function call shall return JSON_DECODER_INVALID_ARG.] */
+ result = JSON_DECODER_INVALID_ARG;
+ }
+ else if (*json == '\0')
+ {
+ /* Codes_SRS_JSON_DECODER_99_007:[ If parsing the JSON fails due to the JSON string being malformed, JSONDecoder_JSON_To_MultiTree shall return JSON_DECODER_PARSE_ERROR.] */
+ result = JSON_DECODER_PARSE_ERROR;
+ }
+ else
+ {
+ /* Codes_SRS_JSON_DECODER_99_008:[ JSONDecoder_JSON_To_MultiTree shall create a multi tree based on the json string argument.] */
+ /* Codes_SRS_JSON_DECODER_99_002:[ JSONDecoder_JSON_To_MultiTree shall use the MultiTree APIs to create the multi tree and add leafs to the multi tree.] */
+ /* Codes_SRS_JSON_DECODER_99_009:[ On success, JSONDecoder_JSON_To_MultiTree shall return a handle to the multi tree it created in the multiTreeHandle argument and it shall return JSON_DECODER_OK.] */
+ *multiTreeHandle = MultiTree_Create(NOPCloneFunction, NoFreeFunction);
+ if (*multiTreeHandle == NULL)
+ {
+ /* Codes_SRS_JSON_DECODER_99_038:[ If any MultiTree API fails, JSONDecoder_JSON_To_MultiTree shall return JSON_DECODER_MULTITREE_FAILED.] */
+ result = JSON_DECODER_MULTITREE_FAILED;
+ }
+ else
+ {
+ result = ParseJSON(json, *multiTreeHandle);
+ if (result != JSON_DECODER_OK)
+ {
+ MultiTree_Destroy(*multiTreeHandle);
+ }
+ }
+ }
+
+ return result;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jsondecoder.h Thu Oct 22 18:33:28 2015 -0700
@@ -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 JSONDECODER_H
+#define JSONDECODER_H
+
+#include "multitree.h"
+
+#ifdef __cplusplus
+#include <cstddef>
+extern "C" {
+#else
+#include <stddef.h>
+#endif
+
+typedef enum JSON_DECODER_RESULT_TAG
+{
+ JSON_DECODER_OK,
+ JSON_DECODER_INVALID_ARG,
+ JSON_DECODER_PARSE_ERROR,
+ JSON_DECODER_MULTITREE_FAILED,
+ JSON_DECODER_ERROR
+} JSON_DECODER_RESULT;
+
+extern JSON_DECODER_RESULT JSONDecoder_JSON_To_MultiTree(char* json, MULTITREE_HANDLE* multiTreeHandle);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* JSONDECODER_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jsonencoder.c Thu Oct 22 18:33:28 2015 -0700
@@ -0,0 +1,222 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+#include <stdlib.h>
+#ifdef _CRTDBG_MAP_ALLOC
+#include <crtdbg.h>
+#endif
+#include "gballoc.h"
+
+#include "jsonencoder.h"
+#include "crt_abstractions.h"
+#include "iot_logging.h"
+#include "strings.h"
+
+#ifdef _MSC_VER
+#pragma warning(disable: 4701) /* potentially uninitialized local variable 'result' used */ /* the scanner cannot track variable "i" and link it to childCount*/
+#endif
+
+DEFINE_ENUM_STRINGS(JSON_ENCODER_TOSTRING_RESULT, JSON_ENCODER_TOSTRING_RESULT_VALUES);
+DEFINE_ENUM_STRINGS(JSON_ENCODER_RESULT, JSON_ENCODER_RESULT_VALUES);
+
+JSON_ENCODER_RESULT JSONEncoder_EncodeTree(MULTITREE_HANDLE treeHandle, STRING_HANDLE destination, JSON_ENCODER_TOSTRING_FUNC toStringFunc)
+{
+ JSON_ENCODER_RESULT result;
+
+ size_t childCount;
+
+ /* Codes_SRS_JSON_ENCODER_99_032:[If any of the arguments passed to JSONEncoder_EncodeTree is NULL then JSON_ENCODER_INVALID_ARG shall be returned.] */
+ if ((treeHandle == NULL) ||
+ (destination == NULL) ||
+ (toStringFunc == NULL))
+ {
+ result = JSON_ENCODER_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(JSON_ENCODER_RESULT, result));
+ }
+ /*Codes_SRS_JSON_ENCODER_99_035:[ JSON encoder shall inquire the number of child nodes (further called childCount) of the current node (given by parameter treeHandle.]*/
+ else if (MultiTree_GetChildCount(treeHandle, &childCount) != MULTITREE_OK)
+ {
+ result = JSON_ENCODER_MULTITREE_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(JSON_ENCODER_RESULT, result));
+ }
+ else
+ {
+ size_t i;
+ /*Codes_SRS_JSON_ENCODER_99_036:[ The string "{" shall be added to the output;]*/
+ if (STRING_concat(destination, "{") != 0)
+ {
+ result = JSON_ENCODER_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(JSON_ENCODER_RESULT, result));
+ }
+ else
+ {
+ result = JSON_ENCODER_OK;
+ for (i = 0; (i < childCount) && (result == JSON_ENCODER_OK); i++)
+ {
+ MULTITREE_HANDLE childTreeHandle;
+
+ if ((i > 0) &&
+ (STRING_concat(destination, ", ") != 0))
+ {
+ result = JSON_ENCODER_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(JSON_ENCODER_RESULT, result));
+ }
+ else if (STRING_concat(destination, "\"") != 0)
+ {
+ result = JSON_ENCODER_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(JSON_ENCODER_RESULT, result));
+ }
+ else
+ {
+ STRING_HANDLE name = STRING_new();
+ if (name == NULL)
+ {
+ result = JSON_ENCODER_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(JSON_ENCODER_RESULT, result));
+ }
+ else
+ {
+ if (MultiTree_GetChild(treeHandle, i, &childTreeHandle) != MULTITREE_OK)
+ {
+ result = JSON_ENCODER_MULTITREE_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(JSON_ENCODER_RESULT, result));
+ }
+ else if (MultiTree_GetName(childTreeHandle, name) != MULTITREE_OK)
+ {
+ result = JSON_ENCODER_MULTITREE_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(JSON_ENCODER_RESULT, result));
+ }
+ else if (STRING_concat_with_STRING(destination, name) != 0)
+ {
+ result = JSON_ENCODER_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(JSON_ENCODER_RESULT, result));
+ }
+ else if (STRING_concat(destination, "\":") != 0)
+ {
+ result = JSON_ENCODER_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(JSON_ENCODER_RESULT, result));
+ }
+ else
+ {
+ size_t innerChildCount;
+ if (MultiTree_GetChildCount(childTreeHandle, &innerChildCount) != MULTITREE_OK)
+ {
+ result = JSON_ENCODER_MULTITREE_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(JSON_ENCODER_RESULT, result));
+ }
+ else
+ {
+ if (innerChildCount > 0)
+ {
+ STRING_HANDLE child = STRING_new();
+ if (child == NULL)
+ {
+ result = JSON_ENCODER_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(JSON_ENCODER_RESULT, result));
+ }
+ else
+ {
+ if ((result = JSONEncoder_EncodeTree(childTreeHandle, child, toStringFunc)) != JSON_ENCODER_OK)
+ {
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(JSON_ENCODER_RESULT, result));
+ }
+ else if (STRING_concat_with_STRING(destination, child)!=0)
+ {
+ result = JSON_ENCODER_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(JSON_ENCODER_RESULT, result));
+ }
+ STRING_delete(child);
+ }
+ }
+ else
+ {
+ const void* value;
+ if (MultiTree_GetValue(childTreeHandle, &value) != MULTITREE_OK)
+ {
+ result = JSON_ENCODER_MULTITREE_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(JSON_ENCODER_RESULT, result));
+
+ }
+ else
+ {
+ STRING_HANDLE childValue = STRING_new();
+ if (childValue == NULL)
+ {
+ result = JSON_ENCODER_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(JSON_ENCODER_RESULT, result));
+ }
+ else
+ {
+ if (toStringFunc(childValue, value) != JSON_ENCODER_TOSTRING_OK)
+ {
+ result = JSON_ENCODER_TOSTRING_FUNCTION_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(JSON_ENCODER_RESULT, result));
+ }
+ else if (STRING_concat_with_STRING(destination, childValue)!=0)
+ {
+ result = JSON_ENCODER_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(JSON_ENCODER_RESULT, result));
+ }
+ else
+ {
+ /*do nothing, result = JSON_ENCODER_OK is set above at the beginning of the FOR loop*/
+ }
+ STRING_delete(childValue);
+ }
+ }
+ }
+ }
+ }
+ STRING_delete(name);
+ }
+ }
+ }
+
+ if ((i == childCount) && (result == JSON_ENCODER_OK))
+ {
+ if (STRING_concat(destination, "}") != 0)
+ {
+ result = JSON_ENCODER_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(JSON_ENCODER_RESULT, result));
+ }
+ else
+ {
+ /* Codes_SRS_JSON_ENCODER_99_031:[On success, JSONEncoder_EncodeTree shall return JSON_ENCODER_OK.] */
+ result = JSON_ENCODER_OK;
+ }
+ }
+ }
+ }
+
+ return result;
+#ifdef _MSC_VER
+#pragma warning(disable: 4701) /* potentially uninitialized local variable 'result' used */ /* the scanner cannot track variable "i" and link it to childCount*/
+#endif
+}
+
+JSON_ENCODER_TOSTRING_RESULT JSONEncoder_CharPtr_ToString(STRING_HANDLE destination, const void* value)
+{
+ JSON_ENCODER_TOSTRING_RESULT result;
+
+ /*Coes_SRS_JSON_ENCODER_99_047:[ JSONEncoder_CharPtr_ToString shall return JSON_ENCODER_TOSTRING_INVALID_ARG if destination or value parameters passed to it are NULL.]*/
+ if ((destination == NULL) ||
+ (value == NULL))
+ {
+ result = JSON_ENCODER_TOSTRING_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(JSON_ENCODER_TOSTRING_RESULT, result));
+ }
+ /*Codes_SRS_JSON_ENCODER_99_048:[ JSONEncoder_CharPtr_ToString shall use strcpy_s to copy from value to destination.]*/
+ else if (STRING_concat(destination, (const char*)value) != 0)
+ {
+ /*Codes_SRS_JSON_ENCODER_99_049:[ If strcpy_s fails then JSONEncoder_CharPtr_ToString shall return JSON_ENCODER_TOSTRING_ERROR.]*/
+ result = JSON_ENCODER_TOSTRING_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(JSON_ENCODER_TOSTRING_RESULT, result));
+ }
+ else
+ {
+ /*Codes_SRS_JSON_ENCODER_99_050:[ If strcpy_s doesn't fail, then JSONEncoder_CharPtr_ToString shall return JSON_ENCODER_TOSTRING_OK]*/
+ result = JSON_ENCODER_TOSTRING_OK;
+ }
+
+ return result;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jsonencoder.h Thu Oct 22 18:33:28 2015 -0700
@@ -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 JSONENCODER_H
+#define JSONENCODER_H
+
+#include "macro_utils.h"
+#include "strings.h"
+
+#ifdef __cplusplus
+#include "cstddef"
+extern "C" {
+#else
+#include "stddef.h"
+#endif
+
+#include "multitree.h"
+
+#define JSON_ENCODER_RESULT_VALUES \
+JSON_ENCODER_OK, \
+JSON_ENCODER_INVALID_ARG, \
+JSON_ENCODER_ALREADY_EXISTS, \
+JSON_ENCODER_MULTITREE_ERROR, \
+JSON_ENCODER_TOSTRING_FUNCTION_ERROR, \
+JSON_ENCODER_ERROR
+
+DEFINE_ENUM(JSON_ENCODER_RESULT, JSON_ENCODER_RESULT_VALUES);
+
+#define JSON_ENCODER_TOSTRING_RESULT_VALUES \
+JSON_ENCODER_TOSTRING_OK, \
+JSON_ENCODER_TOSTRING_INVALID_ARG, \
+JSON_ENCODER_TOSTRING_ERROR
+
+DEFINE_ENUM(JSON_ENCODER_TOSTRING_RESULT, JSON_ENCODER_TOSTRING_RESULT_VALUES);
+
+typedef JSON_ENCODER_TOSTRING_RESULT(*JSON_ENCODER_TOSTRING_FUNC)(STRING_HANDLE, const void* value);
+
+extern JSON_ENCODER_TOSTRING_RESULT JSONEncoder_CharPtr_ToString(STRING_HANDLE, const void* value);
+extern JSON_ENCODER_RESULT JSONEncoder_EncodeTree(MULTITREE_HANDLE treeHandle, STRING_HANDLE destination, JSON_ENCODER_TOSTRING_FUNC toStringFunc);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* JSONENCODER_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/multitree.c Thu Oct 22 18:33:28 2015 -0700
@@ -0,0 +1,768 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+#include <stdlib.h>
+#ifdef _CRTDBG_MAP_ALLOC
+#include <crtdbg.h>
+#endif
+#include "gballoc.h"
+
+#include "multitree.h"
+#include <string.h>
+#include "crt_abstractions.h"
+#include "iot_logging.h"
+
+/*assume a name cannot be longer than 100 characters*/
+#define INNER_NODE_NAME_SIZE 128
+
+DEFINE_ENUM_STRINGS(MULTITREE_RESULT, MULTITREE_RESULT_VALUES);
+
+typedef struct MULTITREE_NODE_TAG
+{
+ char* name;
+ void* value;
+ MULTITREE_CLONE_FUNCTION cloneFunction;
+ MULTITREE_FREE_FUNCTION freeFunction;
+ size_t nChildren;
+ struct MULTITREE_NODE_TAG** children; /*an array of nChildren count of MULTITREE_NODE* */
+}MULTITREE_NODE;
+
+
+MULTITREE_HANDLE MultiTree_Create(MULTITREE_CLONE_FUNCTION cloneFunction, MULTITREE_FREE_FUNCTION freeFunction)
+{
+ MULTITREE_NODE* result;
+
+ /* Codes_SRS_MULTITREE_99_052:[If any of the arguments passed to MultiTree_Create is NULL, the call shall return NULL.]*/
+ if ((cloneFunction == NULL) ||
+ (freeFunction == NULL))
+ {
+ LogError("CloneFunction or FreeFunction is Null.\r\n");
+ result = NULL;
+ }
+ else
+ {
+ /*Codes_SRS_MULTITREE_99_005:[ MultiTree_Create creates a new tree.]*/
+ /*Codes_SRS_MULTITREE_99_006:[MultiTree_Create returns a non - NULL pointer if the tree has been successfully created.]*/
+ /*Codes_SRS_MULTITREE_99_007:[MultiTree_Create returns NULL if the tree has not been successfully created.]*/
+ result = (MULTITREE_NODE*)malloc(sizeof(MULTITREE_NODE));
+ if (result != NULL)
+ {
+ result->name = NULL;
+ result->value = NULL;
+ result->cloneFunction = cloneFunction;
+ result->freeFunction = freeFunction;
+ result->value = NULL;
+ result->nChildren = 0;
+ result->children = NULL;
+ }
+ else
+ {
+ LogError("MultiTree_Create failed because malloc failed\r\n");
+ }
+ }
+
+ return (MULTITREE_HANDLE)result;
+}
+
+
+/*return NULL if a child with the name "name" doesn't exists*/
+/*returns a pointer to the existing child (if any)*/
+static MULTITREE_NODE* getChildByName(MULTITREE_NODE* node, const char* name)
+{
+ MULTITREE_NODE* result = NULL;
+ size_t i;
+ for (i = 0; i < node->nChildren; i++)
+ {
+ if (strcmp(node->children[i]->name, name) == 0)
+ {
+ result = node->children[i];
+ break;
+ }
+ }
+ return result;
+}
+
+/*helper function to create a child immediately under this node*/
+/*return 0 if it created it, any other number is error*/
+
+typedef enum CREATELEAF_RESULT_TAG
+{
+ CREATELEAF_OK,
+ CREATELEAF_ALREADY_EXISTS,
+ CREATELEAF_EMPTY_NAME,
+ CREATELEAF_ERROR,
+ CREATELEAF_RESULT_COUNT // Used to track the number of elements in the enum
+ // Do not remove, or add new enum values below this one
+}CREATELEAF_RESULT;
+
+static const char* CreateLeaf_ResultAsString[CREATELEAF_RESULT_COUNT] =
+{
+ STRINGIFY(CREATELEAF_OK),
+ STRINGIFY(CREATELEAF_ALREADY_EXISTS),
+ STRINGIFY(CREATELEAF_EMPTY_NAME),
+ STRINGIFY(CREATELEAF_ERROR)
+};
+
+/*name cannot be empty, value can be empty or NULL*/
+#ifdef _MSC_VER
+#pragma warning(disable: 4701) /* potentially uninitialized local variable 'result' used */ /* the scanner cannot track linked "newNode" and "result" therefore the warning*/
+#endif
+static CREATELEAF_RESULT createLeaf(MULTITREE_NODE* node, const char*name, const char*value, MULTITREE_NODE** childNode)
+{
+ CREATELEAF_RESULT result;
+ /*can only create it if it doesn't exist*/
+ if (strlen(name) == 0)
+ {
+ /*Codes_SRS_MULTITREE_99_024:[ if a child name is empty (such as in "/child1//child12"), MULTITREE_EMPTY_CHILD_NAME shall be returned.]*/
+ result = CREATELEAF_EMPTY_NAME;
+ LogError("(result = %s)\r\n", CreateLeaf_ResultAsString[result]);
+ }
+ else if (getChildByName(node, name) != NULL)
+ {
+ result = CREATELEAF_ALREADY_EXISTS;
+ LogError("(result = %s)\r\n", CreateLeaf_ResultAsString[result]);
+ }
+ else
+ {
+ MULTITREE_NODE* newNode = (MULTITREE_NODE*)malloc(sizeof(MULTITREE_NODE));
+ if (newNode == NULL)
+ {
+ result = CREATELEAF_ERROR;
+ LogError("(result = %s)\r\n", CreateLeaf_ResultAsString[result]);
+ }
+ else
+ {
+ newNode->nChildren = 0;
+ newNode->children = NULL;
+ if (mallocAndStrcpy_s(&(newNode->name), name) != 0)
+ {
+ /*not nice*/
+ free(newNode);
+ newNode = NULL;
+ result = CREATELEAF_ERROR;
+ LogError("(result = %s)\r\n", CreateLeaf_ResultAsString[result]);
+ }
+ else
+ {
+ newNode->cloneFunction = node->cloneFunction;
+ newNode->freeFunction = node->freeFunction;
+
+ if (value == NULL)
+ {
+ newNode->value = NULL;
+ }
+ else if (node->cloneFunction(&(newNode->value), value) != 0)
+ {
+ free(newNode->name);
+ newNode->name = NULL;
+ free(newNode);
+ newNode = NULL;
+ result = CREATELEAF_ERROR;
+ LogError("(result = %s)\r\n", CreateLeaf_ResultAsString[result]);
+ }
+ else
+ {
+ /*all is fine until now*/
+ }
+ }
+
+
+ if (newNode!=NULL)
+ {
+ /*allocate space in the father node*/
+ MULTITREE_NODE** newChildren = (MULTITREE_NODE**)realloc(node->children, (node->nChildren + 1)*sizeof(MULTITREE_NODE*));
+ if (newChildren == NULL)
+ {
+ /*no space for the new node*/
+ newNode->value = NULL;
+ free(newNode->name);
+ newNode->name = NULL;
+ free(newNode);
+ newNode = NULL;
+ result = CREATELEAF_ERROR;
+ LogError("(result = %s)\r\n", CreateLeaf_ResultAsString[result]);
+ }
+ else
+ {
+ node->children = newChildren;
+ node->children[node->nChildren] = newNode;
+ node->nChildren++;
+ if (childNode != NULL)
+ {
+ *childNode = newNode;
+ }
+ result = CREATELEAF_OK;
+ }
+ }
+ }
+ }
+
+ return result;
+#ifdef _MSC_VER
+#pragma warning(default: 4701) /* potentially uninitialized local variable 'result' used */ /* the scanner cannot track linked "newNode" and "result" therefore the warning*/
+#endif
+}
+
+MULTITREE_RESULT MultiTree_AddLeaf(MULTITREE_HANDLE treeHandle, const char* destinationPath, const void* value)
+{
+ /*codes_SRS_MULTITREE_99_018:[ If the treeHandle parameter is NULL, MULTITREE_INVALID_ARG shall be returned.]*/
+ MULTITREE_RESULT result;
+ if (treeHandle == NULL)
+ {
+ result = MULTITREE_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(MULTITREE_RESULT, result));
+ }
+ /*Codes_SRS_MULTITREE_99_019:[ If parameter destinationPath is NULL, MULTITREE_INVALID_ARG shall be returned.]*/
+ else if (destinationPath == NULL)
+ {
+ result = MULTITREE_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(MULTITREE_RESULT, result));
+ }
+ /*Codes_SRS_MULTITREE_99_020:[ If parameter value is NULL, MULTITREE_INVALID_ARG shall be returned.]*/
+ else if (value == NULL)
+ {
+ result = MULTITREE_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(MULTITREE_RESULT, result));
+ }
+ /*Codes_SRS_MULTITREE_99_050:[ If destinationPath a string with zero characters, MULTITREE_INVALID_ARG shall be returned.]*/
+ else if (strlen(destinationPath) == 0)
+ {
+ result = MULTITREE_EMPTY_CHILD_NAME;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(MULTITREE_RESULT, result));
+ }
+ else
+ {
+ /*break the path into components*/
+ /*find the first child name*/
+ MULTITREE_NODE * node = (MULTITREE_NODE *)treeHandle;
+ char * whereIsDelimiter;
+ /*if first character is / then skip it*/
+ /*Codes_SRS_MULTITREE_99_014:[DestinationPath is a string in the following format: /child1/child12 or child1/child12] */
+ if (destinationPath[0] == '/')
+ {
+ destinationPath++;
+ }
+ /*if there's just a string, it needs to be created here*/
+ whereIsDelimiter = (char*)strchr(destinationPath, '/');
+ if (whereIsDelimiter == NULL)
+ {
+ /*Codes_SRS_MULTITREE_99_017:[ Subsequent names designate hierarchical children in the tree. The last child designates the child that will receive the value.]*/
+ CREATELEAF_RESULT res = createLeaf(node, destinationPath, (const char*)value, NULL);
+ switch (res)
+ {
+ default:
+ {
+ /*Codes_SRS_MULTITREE_99_025:[The function shall return MULTITREE_ERROR to indicate any other error not specified here.]*/
+ result = MULTITREE_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(MULTITREE_RESULT, result));
+ break;
+ }
+ case CREATELEAF_ALREADY_EXISTS:
+ {
+ /*Codes_SRS_MULTITREE_99_021:[ If the node already has a value assigned to it, MULTITREE_ALREADY_HAS_A_VALUE shall be returned and the existing value shall not be changed.]*/
+ result = MULTITREE_ALREADY_HAS_A_VALUE;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(MULTITREE_RESULT, result));
+ break;
+ }
+ case CREATELEAF_OK:
+ {
+ /*Codes_SRS_MULTITREE_99_034:[ The function returns MULTITREE_OK when data has been stored in the tree.]*/
+ result = MULTITREE_OK;
+ break;
+ }
+ case CREATELEAF_EMPTY_NAME:
+ {
+ /*Codes_SRS_MULTITREE_99_024:[ if a child name is empty (such as in "/child1//child12"), MULTITREE_EMPTY_CHILD_NAME shall be returned.]*/
+ result = MULTITREE_EMPTY_CHILD_NAME;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(MULTITREE_RESULT, result));
+ break;
+ }
+ }
+ }
+ else
+ {
+ /*if there's more or 1 delimiter in the path... */
+ /*Codes_SRS_MULTITREE_99_017:[ Subsequent names designate hierarchical children in the tree. The last child designates the child that will receive the value.]*/
+ char firstInnerNodeName[INNER_NODE_NAME_SIZE];
+ if (strncpy_s(firstInnerNodeName, INNER_NODE_NAME_SIZE, destinationPath, whereIsDelimiter - destinationPath) != 0)
+ {
+ /*Codes_SRS_MULTITREE_99_025:[ The function shall return MULTITREE_ERROR to indicate any other error not specified here.]*/
+ result = MULTITREE_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(MULTITREE_RESULT, result));
+ }
+ else
+ {
+ MULTITREE_NODE *child = getChildByName(node, firstInnerNodeName);
+ if (child == NULL)
+ {
+ /*Codes_SRS_MULTITREE_99_022:[ If a child along the path does not exist, it shall be created.] */
+ /*Codes_SRS_MULTITREE_99_023:[ The newly created children along the path shall have a NULL value by default.]*/
+ CREATELEAF_RESULT res = createLeaf(node, firstInnerNodeName, NULL, NULL);
+ switch (res)
+ {
+ default:
+ {
+ result = MULTITREE_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(MULTITREE_RESULT, result));
+ break;
+ }
+ case(CREATELEAF_EMPTY_NAME):
+ {
+ /*Codes_SRS_MULTITREE_99_024:[ if a child name is empty (such as in "/child1//child12"), MULTITREE_EMPTY_CHILD_NAME shall be returned.]*/
+ result = MULTITREE_EMPTY_CHILD_NAME;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(MULTITREE_RESULT, result));
+ break;
+ }
+ case(CREATELEAF_OK):
+ {
+ MULTITREE_NODE *createdChild = getChildByName(node, firstInnerNodeName);
+ result = MultiTree_AddLeaf(createdChild, whereIsDelimiter, value);
+ break;
+ }
+ };
+ }
+ else
+ {
+ result = MultiTree_AddLeaf(child, whereIsDelimiter, value);
+ }
+ }
+ }
+ }
+ return result;
+}
+
+/* Codes_SRS_MULTITREE_99_053:[ MultiTree_AddChild shall add a new node with the name childName to the multi tree node identified by treeHandle] */
+MULTITREE_RESULT MultiTree_AddChild(MULTITREE_HANDLE treeHandle, const char* childName, MULTITREE_HANDLE* childHandle)
+{
+ MULTITREE_RESULT result;
+ /* Codes_SRS_MULTITREE_99_055:[ If any argument is NULL, MultiTree_AddChild shall return MULTITREE_INVALID_ARG.] */
+ if ((treeHandle == NULL) ||
+ (childName == NULL) ||
+ (childHandle == NULL))
+ {
+ result = MULTITREE_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(MULTITREE_RESULT, result));
+ }
+ else
+ {
+ MULTITREE_NODE* childNode;
+
+ /* Codes_SRS_MULTITREE_99_060:[ The value associated with the new node shall be NULL.] */
+ CREATELEAF_RESULT res = createLeaf((MULTITREE_NODE*)treeHandle, childName, NULL, &childNode);
+ switch (res)
+ {
+ default:
+ {
+ result = MULTITREE_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(MULTITREE_RESULT, result));
+ break;
+ }
+ case CREATELEAF_ALREADY_EXISTS:
+ {
+ /* Codes_SRS_MULTITREE_99_061:[ If a child node with the same name already exists, MultiTree_AddChild shall return MULTITREE_ALREADY_HAS_A_VALUE.] */
+ result = MULTITREE_ALREADY_HAS_A_VALUE;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(MULTITREE_RESULT, result));
+ break;
+ }
+ case CREATELEAF_OK:
+ {
+ /* Codes_SRS_MULTITREE_99_062:[ The new node handle shall be returned in the childHandle argument.] */
+ *childHandle = childNode;
+
+ /* Codes_SRS_MULTITREE_99_054:[ On success, MultiTree_AddChild shall return MULTITREE_OK.] */
+ result = MULTITREE_OK;
+ break;
+ }
+ case CREATELEAF_EMPTY_NAME:
+ {
+ /* Tests_SRS_MULTITREE_99_066:[ If the childName argument is an empty string, MultiTree_AddChild shall return MULTITREE_EMPTY_CHILD_NAME.] */
+ result = MULTITREE_EMPTY_CHILD_NAME;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(MULTITREE_RESULT, result));
+ break;
+ }
+ }
+ }
+
+ return result;
+}
+
+MULTITREE_RESULT MultiTree_GetChildCount(MULTITREE_HANDLE treeHandle, size_t* count)
+{
+ MULTITREE_RESULT result;
+ /*Codes_SRS_MULTITREE_99_027:[If treeHandle is NULL, the function returns MULTITREE_INVALID_ARG.]*/
+ if (treeHandle == NULL)
+ {
+ result = MULTITREE_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(MULTITREE_RESULT, result));
+ }
+ /*Codes_SRS_MULTITREE_99_028:[ If parameter count is NULL, the function returns MULTITREE_INVALID_ARG.]*/
+ else if (count == NULL)
+ {
+ result = MULTITREE_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(MULTITREE_RESULT, result));
+ }
+ else
+ {
+ /*Codes_SRS_MULTITREE_99_029:[ This function writes in *count the number of direct children for a tree node specified by the parameter treeHandle]*/
+ *count = ((MULTITREE_NODE*)treeHandle)->nChildren;
+ /*Codes_SRS_MULTITREE_99_035:[ The function shall return MULTITREE_OK when *count contains the number of children of the node pointed to be parameter treeHandle.]*/
+ result = MULTITREE_OK;
+ }
+ return result;
+}
+
+MULTITREE_RESULT MultiTree_GetChild(MULTITREE_HANDLE treeHandle, size_t index, MULTITREE_HANDLE *childHandle)
+{
+ MULTITREE_RESULT result;
+ /*Codes_SRS_MULTITREE_99_031:[ If parameter treeHandle is NULL, the function returns MULTITREE_INVALID_ARG.]*/
+ if (treeHandle == NULL)
+ {
+ result = MULTITREE_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(MULTITREE_RESULT, result));
+ }
+ /*Codes_SRS_MULTITREE_99_033:[ If parameter childHandle is NULL, the function shall return MULTITREE_INVALID_ARG.]*/
+ else if (childHandle == NULL)
+ {
+ result = MULTITREE_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(MULTITREE_RESULT, result));
+ }
+ else
+ {
+ MULTITREE_NODE * node = (MULTITREE_NODE *)treeHandle;
+ /*Codes_SRS_MULTITREE_99_032:[If parameter index is out of range, the function shall return MULTITREE_OUT_OF_RANGE_INDEX]*/
+ if (node->nChildren <= index)
+ {
+ result = MULTITREE_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(MULTITREE_RESULT, result));
+ }
+ else
+ {
+ /*Codes_SRS_MULTITREE_99_030:[ This function writes in *childHandle parameter the "index"th child of the node pointed to by parameter treeHandle]*/
+ /*Codes_SRS_MULTITREE_99_035:[ The function returns MULTITREE_OK when *childHandle contains a handle to the "index"th child of the tree designated by parameter treeHandle.]*/
+ *childHandle = node->children[index];
+ result = MULTITREE_OK;
+ }
+ }
+ return result;
+}
+
+MULTITREE_RESULT MultiTree_GetName(MULTITREE_HANDLE treeHandle, STRING_HANDLE destination)
+{
+ MULTITREE_RESULT result;
+ /*Codes_SRS_MULTITREE_99_037:[ If treeHandle is NULL, the function shall return MULTITREE_INVALID_ARG.]*/
+ if (treeHandle == NULL)
+ {
+ result = MULTITREE_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(MULTITREE_RESULT, result));
+ }
+ /*Codes_SRS_MULTITREE_99_038:[If destination is NULL, the function shall return MULTITREE_INVALID_ARG.]*/
+ else if (destination == NULL)
+ {
+ result = MULTITREE_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(MULTITREE_RESULT, result));
+ }
+ else
+ {
+ MULTITREE_NODE *node = (MULTITREE_NODE*)treeHandle;
+ /*Codes_SRS_MULTITREE_99_051:[ The function returns MULTITREE_EMPTY_CHILD_NAME when used with the root of the tree.]*/
+ if (node->name == NULL)
+ {
+ result = MULTITREE_EMPTY_CHILD_NAME;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(MULTITREE_RESULT, result));
+ }
+ /*Codes_SRS_MULTITREE_99_036:[ This function fills the buffer pointed to by parameter destination with the name of the root node of the tree designated by parameter treeHandle.]*/
+ else if (STRING_concat(destination, node->name)!=0)
+ {
+ /*Codes_SRS_MULTITREE_99_040:[ The function returns MULTITREE_ERROR to indicate any other error.]*/
+ result = MULTITREE_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(MULTITREE_RESULT, result));
+ }
+ else
+ {
+ /*Codes_SRS_MULTITREE_99_039:[ The function returns MULTITREE_OK when destination contains the name of the root node of the tree designated by treeHandle parameter.]*/
+ result = MULTITREE_OK;
+ }
+ }
+
+ return result;
+}
+
+/* Codes_SRS_MULTITREE_99_063:[ MultiTree_GetChildByName shall retrieve the handle of the child node childName from the treeNode node.] */
+MULTITREE_RESULT MultiTree_GetChildByName(MULTITREE_HANDLE treeHandle, const char* childName, MULTITREE_HANDLE *childHandle)
+{
+ MULTITREE_RESULT result;
+
+ /* Codes_SRS_MULTITREE_99_065:[ If any argument is NULL, MultiTree_GetChildByName shall return MULTITREE_INVALID_ARG.] */
+ if ((treeHandle == NULL) ||
+ (childHandle == NULL) ||
+ (childName == NULL))
+ {
+ result = MULTITREE_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(MULTITREE_RESULT, result));
+ }
+ else
+ {
+ MULTITREE_NODE * node = (MULTITREE_NODE *)treeHandle;
+ size_t i;
+
+ for (i = 0; i < node->nChildren; i++)
+ {
+ if (strcmp(node->children[i]->name, childName) == 0)
+ {
+ break;
+ }
+ }
+
+ if (i == node->nChildren)
+ {
+ /* Codes_SRS_MULTITREE_99_068:[ If the specified child is not found, MultiTree_GetChildByName shall return MULTITREE_CHILD_NOT_FOUND.] */
+ result = MULTITREE_CHILD_NOT_FOUND;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(MULTITREE_RESULT, result));
+ }
+ else
+ {
+ /* Codes_SRS_MULTITREE_99_067:[ The child node handle shall be returned in the childHandle argument.] */
+ *childHandle = node->children[i];
+
+ /* Codes_SRS_MULTITREE_99_064:[ On success, MultiTree_GetChildByName shall return MULTITREE_OK.] */
+ result = MULTITREE_OK;
+ }
+ }
+ return result;
+}
+
+MULTITREE_RESULT MultiTree_GetValue(MULTITREE_HANDLE treeHandle, const void** destination)
+{
+ MULTITREE_RESULT result;
+ /*Codes_SRS_MULTITREE_99_042:[If treeHandle is NULL, the function shall return MULTITREE_INVALID_ARG.]*/
+ if (treeHandle == NULL)
+ {
+ result = MULTITREE_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(MULTITREE_RESULT, result));
+ }
+ /*Codes_SRS_MULTITREE_99_043:[ If destination is NULL, the function shall return MULTITREE_INVALID_ARG.]*/
+ else if (destination == NULL)
+ {
+ result = MULTITREE_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(MULTITREE_RESULT, result));
+ }
+ else
+ {
+ MULTITREE_NODE * node = (MULTITREE_NODE*)treeHandle;
+ /*Codes_SRS_MULTITREE_99_044:[ If there is no value in the node then MULTITREE_EMPTY_VALUE shall be returned.]*/
+ if (node->value == NULL)
+ {
+ result = MULTITREE_EMPTY_VALUE;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(MULTITREE_RESULT, result));
+ }
+ else
+ {
+ /*Codes_SRS_MULTITREE_99_041:[This function updates the *destination parameter to the internally stored value.]*/
+ *destination = node->value;
+ result = MULTITREE_OK;
+ }
+ }
+ return result;
+}
+
+MULTITREE_RESULT MultiTree_SetValue(MULTITREE_HANDLE treeHandle, void* value)
+{
+ MULTITREE_RESULT result;
+
+ /* Codes_SRS_MULTITREE_99_074:[ If any argument is NULL, MultiTree_SetValue shall return MULTITREE_INVALID_ARG.] */
+ if ((treeHandle == NULL) ||
+ (value == NULL))
+ {
+ result = MULTITREE_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(MULTITREE_RESULT, result));
+ }
+ else
+ {
+ MULTITREE_NODE * node = (MULTITREE_NODE*)treeHandle;
+ if (node->value != NULL)
+ {
+ /* Codes_SRS_MULTITREE_99_076:[ If the node already has a value then MultiTree_SetValue shall return MULTITREE_ALREADY_HAS_A_VALUE.] */
+ result = MULTITREE_ALREADY_HAS_A_VALUE;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(MULTITREE_RESULT, result));
+ }
+ else
+ {
+ /* Codes_SRS_MULTITREE_99_072:[ MultiTree_SetValue shall set the value of the node indicated by the treeHandle argument to the value of the argument value.] */
+ if (node->cloneFunction(&node->value, value) != 0)
+ {
+ /* Codes_SRS_MULTITREE_99_075:[ MultiTree_SetValue shall return MULTITREE_ERROR to indicate any other error.] */
+ result = MULTITREE_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(MULTITREE_RESULT, result));
+ }
+ else
+ {
+ /* Codes_SRS_MULTITREE_99_073:[ On success, MultiTree_SetValue shall return MULTITREE_OK.] */
+ result = MULTITREE_OK;
+ }
+ }
+ }
+ return result;
+}
+
+void MultiTree_Destroy(MULTITREE_HANDLE treeHandle)
+{
+ if (treeHandle != NULL)
+ {
+ MULTITREE_NODE* node = (MULTITREE_NODE*)treeHandle;
+ size_t i;
+ for (i = 0; i < node->nChildren;i++)
+ {
+ /*Codes_SRS_MULTITREE_99_047:[ This function frees any system resource used by the tree designated by parameter treeHandle]*/
+ MultiTree_Destroy(node->children[i]);
+ }
+ /*Codes_SRS_MULTITREE_99_047:[ This function frees any system resource used by the tree designated by parameter treeHandle]*/
+ if (node->children != NULL)
+ {
+ free(node->children);
+ node->children = NULL;
+ }
+
+ /*Codes_SRS_MULTITREE_99_047:[ This function frees any system resource used by the tree designated by parameter treeHandle]*/
+ if (node->name != NULL)
+ {
+ free(node->name);
+ node->name = NULL;
+ }
+
+ /*Codes_SRS_MULTITREE_99_047:[ This function frees any system resource used by the tree designated by parameter treeHandle]*/
+ if (node->value != NULL)
+ {
+ node->freeFunction(node->value);
+ node->value = NULL;
+ }
+
+ /*Codes_SRS_MULTITREE_99_047:[ This function frees any system resource used by the tree designated by parameter treeHandle]*/
+ free(node);
+ }
+}
+
+MULTITREE_RESULT MultiTree_GetLeafValue(MULTITREE_HANDLE treeHandle, const char* leafPath, const void** destination)
+{
+ MULTITREE_RESULT result;
+
+ /* Codes_SRS_MULTITREE_99_055:[ If any argument is NULL, MultiTree_GetLeafValue shall return MULTITREE_INVALID_ARG.] */
+ if ((treeHandle == NULL) ||
+ (leafPath == NULL) ||
+ (destination == NULL))
+ {
+ result = MULTITREE_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(MULTITREE_RESULT, result));
+ }
+ /* Codes_SRS_MULTITREE_99_058:[ The last child designates the child that will receive the value. If a child name is empty (such as in "/child1//child12"), MULTITREE_EMPTY_CHILD_NAME shall be returned.] */
+ else if (strlen(leafPath) == 0)
+ {
+ result = MULTITREE_EMPTY_CHILD_NAME;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(MULTITREE_RESULT, result));
+ }
+ else
+ {
+ /*break the path into components*/
+ /*find the first child name*/
+ MULTITREE_NODE* node = (MULTITREE_NODE *)treeHandle;
+ const char* pos = leafPath;
+ const char * whereIsDelimiter;
+
+ /*if first character is / then skip it*/
+ if (*pos == '/')
+ {
+ pos++;
+ }
+
+ if (*pos == '\0')
+ {
+ /* Codes_SRS_MULTITREE_99_069:[ If a child name is empty (such as in "/child1//child12"), MULTITREE_EMPTY_CHILD_NAME shall be returned.] */
+ result = MULTITREE_EMPTY_CHILD_NAME;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(MULTITREE_RESULT, result));
+ }
+ else
+ {
+ result = MULTITREE_OK;
+
+ /* Codes_SRS_MULTITREE_99_056:[ The leafPath argument is a string in the following format: /child1/child12 or child1/child12.] */
+ /* Codes_SRS_MULTITREE_99_058:[ The last child designates the child that will receive the value.] */
+ while (*pos != '\0')
+ {
+ size_t i;
+ size_t childCount = node->nChildren;
+
+ whereIsDelimiter = pos;
+
+ while ((*whereIsDelimiter != '/') && (*whereIsDelimiter != '\0'))
+ {
+ whereIsDelimiter++;
+ }
+
+ if (whereIsDelimiter == pos)
+ {
+ /* Codes_SRS_MULTITREE_99_069:[ If a child name is empty (such as in "/child1//child12"), MULTITREE_EMPTY_CHILD_NAME shall be returned.] */
+ result = MULTITREE_EMPTY_CHILD_NAME;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(MULTITREE_RESULT, result));
+ break;
+ }
+ else if (childCount == 0)
+ {
+ /* Codes_SRS_MULTITREE_99_071:[ When the child node is not found, MultiTree_GetLeafValue shall return MULTITREE_CHILD_NOT_FOUND.] */
+ result = MULTITREE_CHILD_NOT_FOUND;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(MULTITREE_RESULT, result));
+ break;
+ }
+ else
+ {
+ for (i = 0; i < childCount; i++)
+ {
+ if (strncmp(node->children[i]->name, pos, whereIsDelimiter - pos) == 0)
+ {
+ /* Codes_SRS_MULTITREE_99_057:[ Subsequent names designate hierarchical children in the tree.] */
+ node = node->children[i];
+ break;
+ }
+ }
+
+ if (i == childCount)
+ {
+ /* Codes_SRS_MULTITREE_99_071:[ When the child node is not found, MultiTree_GetLeafValue shall return MULTITREE_CHILD_NOT_FOUND.] */
+ result = MULTITREE_CHILD_NOT_FOUND;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(MULTITREE_RESULT, result));
+ break;
+ }
+ else
+ {
+ if (*whereIsDelimiter == '/')
+ {
+ pos = whereIsDelimiter + 1;
+ }
+ else
+ {
+ /* end of path */
+ pos = whereIsDelimiter;
+ break;
+ }
+ }
+ }
+ }
+
+ if (*pos == 0)
+ {
+ if (node->value == NULL)
+ {
+ /* Codes_SRS_MULTITREE_99_070:[ If an attempt is made to get the value for a node that does not have a value set, then MultiTree_GetLeafValue shall return MULTITREE_EMPTY_VALUE.] */
+ result = MULTITREE_EMPTY_VALUE;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(MULTITREE_RESULT, result));
+ }
+ /*Codes_SRS_MULTITREE_99_053:[ MultiTree_GetLeafValue shall copy into the *destination argument the value of the node identified by the leafPath argument.]*/
+ else
+ {
+ *destination = node->value;
+ /* Codes_SRS_MULTITREE_99_054:[ On success, MultiTree_GetLeafValue shall return MULTITREE_OK.] */
+ result = MULTITREE_OK;
+ }
+ }
+ }
+ }
+ return result;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/multitree.h Thu Oct 22 18:33:28 2015 -0700
@@ -0,0 +1,51 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+#ifndef MULTITREE_H
+#define MULTITREE_H
+
+#include "strings.h"
+#include "macro_utils.h"
+
+#ifdef __cplusplus
+#include <cstddef>
+extern "C"
+{
+#else
+#include <stddef.h>
+#endif
+
+typedef void* MULTITREE_HANDLE;
+
+#define MULTITREE_RESULT_VALUES \
+ MULTITREE_OK, \
+ MULTITREE_INVALID_ARG, \
+ MULTITREE_ALREADY_HAS_A_VALUE, \
+ MULTITREE_EMPTY_CHILD_NAME, \
+ MULTITREE_EMPTY_VALUE, \
+ MULTITREE_OUT_OF_RANGE_INDEX, \
+ MULTITREE_ERROR, \
+ MULTITREE_CHILD_NOT_FOUND \
+
+DEFINE_ENUM(MULTITREE_RESULT, MULTITREE_RESULT_VALUES);
+
+typedef void (*MULTITREE_FREE_FUNCTION)(void* value);
+typedef int (*MULTITREE_CLONE_FUNCTION)(void** destination, const void* source);
+
+extern MULTITREE_HANDLE MultiTree_Create(MULTITREE_CLONE_FUNCTION cloneFunction, MULTITREE_FREE_FUNCTION freeFunction);
+extern MULTITREE_RESULT MultiTree_AddLeaf(MULTITREE_HANDLE treeHandle, const char* destinationPath, const void* value);
+extern MULTITREE_RESULT MultiTree_AddChild(MULTITREE_HANDLE treeHandle, const char* childName, MULTITREE_HANDLE* childHandle);
+extern MULTITREE_RESULT MultiTree_GetChildCount(MULTITREE_HANDLE treeHandle, size_t* count);
+extern MULTITREE_RESULT MultiTree_GetChild(MULTITREE_HANDLE treeHandle, size_t index, MULTITREE_HANDLE* childHandle);
+extern MULTITREE_RESULT MultiTree_GetChildByName(MULTITREE_HANDLE treeHandle, const char* childName, MULTITREE_HANDLE* childHandle);
+extern MULTITREE_RESULT MultiTree_GetName(MULTITREE_HANDLE treeHandle, STRING_HANDLE destination);
+extern MULTITREE_RESULT MultiTree_GetValue(MULTITREE_HANDLE treeHandle, const void** destination);
+extern MULTITREE_RESULT MultiTree_GetLeafValue(MULTITREE_HANDLE treeHandle, const char* leafPath, const void** destination);
+extern MULTITREE_RESULT MultiTree_SetValue(MULTITREE_HANDLE treeHandle, void* value);
+extern void MultiTree_Destroy(MULTITREE_HANDLE treeHandle);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/schema.c Thu Oct 22 18:33:28 2015 -0700
@@ -0,0 +1,1908 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+#include <stdlib.h>
+#ifdef _CRTDBG_MAP_ALLOC
+#include <crtdbg.h>
+#endif
+#include "gballoc.h"
+
+#include "schema.h"
+#include "crt_abstractions.h"
+#include "iot_logging.h"
+#include "vector.h"
+
+
+DEFINE_ENUM_STRINGS(SCHEMA_RESULT, SCHEMA_RESULT_VALUES);
+
+typedef struct PROPERTY_TAG
+{
+ const char* PropertyName;
+ const char* PropertyType;
+} PROPERTY;
+
+typedef struct SCHEMA_ACTION_ARGUMENT_TAG
+{
+ const char* Name;
+ const char* Type;
+} SCHEMA_ACTION_ARGUMENT;
+
+typedef struct ACTION_TAG
+{
+ const char* ActionName;
+ size_t ArgumentCount;
+ SCHEMA_ACTION_ARGUMENT_HANDLE* ArgumentHandles;
+} ACTION;
+
+typedef struct MODEL_IN_MODEL_TAG
+{
+ const char* propertyName;
+ SCHEMA_MODEL_TYPE_HANDLE modelHandle;
+} MODEL_IN_MODEL;
+
+typedef struct MODEL_TYPE_TAG
+{
+ const char* Name;
+ SCHEMA_HANDLE SchemaHandle;
+ SCHEMA_PROPERTY_HANDLE* Properties;
+ size_t PropertyCount;
+ SCHEMA_ACTION_HANDLE* Actions;
+ size_t ActionCount;
+ VECTOR_HANDLE models;
+ size_t DeviceCount;
+} MODEL_TYPE;
+
+typedef struct STRUCT_TYPE_TAG
+{
+ const char* Name;
+ SCHEMA_PROPERTY_HANDLE* Properties;
+ size_t PropertyCount;
+} STRUCT_TYPE;
+
+typedef struct SCHEMA_TAG
+{
+ const char* Namespace;
+ SCHEMA_MODEL_TYPE_HANDLE* ModelTypes;
+ size_t ModelTypeCount;
+ SCHEMA_STRUCT_TYPE_HANDLE* StructTypes;
+ size_t StructTypeCount;
+} SCHEMA;
+
+static VECTOR_HANDLE g_schemas = NULL;
+
+static void DestroyProperty(SCHEMA_PROPERTY_HANDLE propertyHandle)
+{
+ PROPERTY* propertyType = (PROPERTY*)propertyHandle;
+ free((void*)propertyType->PropertyName);
+ free((void*)propertyType->PropertyType);
+ free(propertyType);
+}
+
+static void DestroyActionArgument(SCHEMA_ACTION_ARGUMENT_HANDLE actionArgumentHandle)
+{
+ SCHEMA_ACTION_ARGUMENT* actionArgument = (SCHEMA_ACTION_ARGUMENT*)actionArgumentHandle;
+ if (actionArgument != NULL)
+ {
+ free((void*)actionArgument->Name);
+ free((void*)actionArgument->Type);
+ free(actionArgument);
+ }
+}
+
+static void DestroyAction(SCHEMA_ACTION_HANDLE actionHandle)
+{
+ ACTION* action = (ACTION*)actionHandle;
+ if (action != NULL)
+ {
+ size_t j;
+
+ for (j = 0; j < action->ArgumentCount; j++)
+ {
+ DestroyActionArgument(action->ArgumentHandles[j]);
+ }
+ free(action->ArgumentHandles);
+
+ free((void*)action->ActionName);
+ free(action);
+ }
+}
+
+static void DestroyStruct(SCHEMA_STRUCT_TYPE_HANDLE structTypeHandle)
+{
+ size_t i;
+ STRUCT_TYPE* structType = (STRUCT_TYPE*)structTypeHandle;
+ if (structType != NULL)
+ {
+ for (i = 0; i < structType->PropertyCount; i++)
+ {
+ DestroyProperty(structType->Properties[i]);
+ }
+ free(structType->Properties);
+
+ free((void*)structType->Name);
+
+ free(structType);
+ }
+}
+
+static void DestroyModel(SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle)
+{
+ MODEL_TYPE* modelType = (MODEL_TYPE*)modelTypeHandle;
+ size_t i;
+
+ free((void*)modelType->Name);
+ modelType->Name = NULL;
+
+ for (i = 0; i < modelType->PropertyCount; i++)
+ {
+ DestroyProperty(modelType->Properties[i]);
+ }
+
+ free(modelType->Properties);
+
+ for (i = 0; i < modelType->ActionCount; i++)
+ {
+ DestroyAction(modelType->Actions[i]);
+ }
+
+ /*destroy the vector holding the added models. This does not destroy the said models, however, their names shall be*/
+ for (i = 0; i < VECTOR_size(modelType->models); i++)
+ {
+ MODEL_IN_MODEL* temp = (MODEL_IN_MODEL*)VECTOR_element(modelType->models, i);
+ free((void*)temp->propertyName);
+ }
+ VECTOR_clear(modelType->models);
+ VECTOR_destroy(modelType->models);
+
+ free(modelType->Actions);
+ free(modelType);
+}
+
+static SCHEMA_RESULT AddModelProperty(MODEL_TYPE* modelType, const char* name, const char* type)
+{
+ SCHEMA_RESULT result;
+
+ /* Codes_SRS_SCHEMA_99_013:[If any of the arguments is NULL, Schema_AddModelProperty shall return SCHEMA_INVALID_ARG.] */
+ if ((modelType == NULL) ||
+ (name == NULL) ||
+ (type == NULL))
+ {
+ result = SCHEMA_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, result));
+ }
+ else
+ {
+ size_t i;
+
+ /* Codes_SRS_SCHEMA_99_015:[The property name shall be unique per model, if the same property name is added twice to a model, SCHEMA_DUPLICATE_ELEMENT shall be returned.] */
+ for (i = 0; i < modelType->PropertyCount; i++)
+ {
+ PROPERTY* property = (PROPERTY*)modelType->Properties[i];
+ if (strcmp(property->PropertyName, name) == 0)
+ {
+ break;
+ }
+ }
+
+ if (i < modelType->PropertyCount)
+ {
+ result = SCHEMA_DUPLICATE_ELEMENT;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, result));
+ }
+ else
+ {
+ SCHEMA_PROPERTY_HANDLE* newProperties = (SCHEMA_PROPERTY_HANDLE*)realloc(modelType->Properties, sizeof(SCHEMA_PROPERTY_HANDLE) * (modelType->PropertyCount + 1));
+ if (newProperties == NULL)
+ {
+ /* Codes_SRS_SCHEMA_99_014:[On any other error, Schema_AddModelProperty shall return SCHEMA_ERROR.] */
+ result = SCHEMA_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, result));
+ }
+ else
+ {
+ PROPERTY* newProperty;
+
+ modelType->Properties = newProperties;
+ if ((newProperty = (PROPERTY*)malloc(sizeof(PROPERTY))) == NULL)
+ {
+ /* Codes_SRS_SCHEMA_99_014:[On any other error, Schema_AddModelProperty shall return SCHEMA_ERROR.] */
+ result = SCHEMA_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, result));
+ }
+ else
+ {
+ if (mallocAndStrcpy_s((char**)&newProperty->PropertyName, name) != 0)
+ {
+ /* Codes_SRS_SCHEMA_99_014:[On any other error, Schema_AddModelProperty shall return SCHEMA_ERROR.] */
+ free(newProperty);
+ result = SCHEMA_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, result));
+ }
+ else if (mallocAndStrcpy_s((char**)&newProperty->PropertyType, type) != 0)
+ {
+ /* Codes_SRS_SCHEMA_99_014:[On any other error, Schema_AddModelProperty shall return SCHEMA_ERROR.] */
+ free((void*)newProperty->PropertyName);
+ free(newProperty);
+ result = SCHEMA_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, result));
+ }
+ else
+ {
+ modelType->Properties[modelType->PropertyCount] = (SCHEMA_PROPERTY_HANDLE)newProperty;
+ modelType->PropertyCount++;
+
+ /* Codes_SRS_SCHEMA_99_012:[On success, Schema_AddModelProperty shall return SCHEMA_OK.] */
+ result = SCHEMA_OK;
+ }
+ }
+
+ /* If possible, reduce the memory of over allocation */
+ if (result != SCHEMA_OK)
+ {
+ SCHEMA_PROPERTY_HANDLE* oldProperties = (SCHEMA_PROPERTY_HANDLE*)realloc(modelType->Properties, sizeof(SCHEMA_PROPERTY_HANDLE) * modelType->PropertyCount);
+ if (oldProperties == NULL)
+ {
+ result = SCHEMA_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, result));
+ }
+ else
+ {
+ modelType->Properties = oldProperties;
+ }
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+static bool SchemaHandlesMatch(const SCHEMA_HANDLE* handle, const SCHEMA_HANDLE* otherHandle)
+{
+ return (*handle == *otherHandle);
+}
+
+static bool SchemaNamespacesMatch(const SCHEMA_HANDLE* handle, const char* schemaNamespace)
+{
+ const SCHEMA* schema = (SCHEMA*)*handle;
+ return (strcmp(schema->Namespace, schemaNamespace) == 0);
+}
+
+/* Codes_SRS_SCHEMA_99_001:[Schema_Create shall initialize a schema with a given namespace.] */
+SCHEMA_HANDLE Schema_Create(const char* schemaNamespace)
+{
+ SCHEMA* result;
+
+ /* Codes_SRS_SCHEMA_99_004:[If schemaNamespace is NULL, Schema_Create shall fail.] */
+ if (schemaNamespace == NULL)
+ {
+ /* Codes_SRS_SCHEMA_99_003:[On failure, NULL shall be returned.] */
+ result = NULL;
+ LogError("(Error code:%s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, SCHEMA_INVALID_ARG));
+ }
+ else
+ {
+ if (g_schemas == NULL && (g_schemas = VECTOR_create(sizeof(SCHEMA*) ) ) == NULL)
+ {
+ /* Codes_SRS_SCHEMA_99_003:[On failure, NULL shall be returned.] */
+ result = NULL;
+ LogError("(Error code:%s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, SCHEMA_ERROR));
+ }
+ else if ((result = (SCHEMA*)malloc(sizeof(SCHEMA))) == NULL)
+ {
+ /* Codes_SRS_SCHEMA_99_003:[On failure, NULL shall be returned.] */
+ LogError("(Error code:%s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, SCHEMA_ERROR));
+ }
+ else if (mallocAndStrcpy_s((char**)&result->Namespace, schemaNamespace) != 0)
+ {
+ /* Codes_SRS_SCHEMA_99_003:[On failure, NULL shall be returned.] */
+ free(result);
+ result = NULL;
+ LogError("(Error code:%s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, SCHEMA_ERROR));
+ }
+ else if (VECTOR_push_back(g_schemas, &result, 1) != 0)
+ {
+ free((void*)result->Namespace);
+ free(result);
+ result = NULL;
+ LogError("(Error code:%s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, SCHEMA_ERROR));
+ }
+ else
+ {
+ /* Codes_SRS_SCHEMA_99_002:[On success a non-NULL handle to the newly created schema shall be returned.] */
+ result->ModelTypes = NULL;
+ result->ModelTypeCount = 0;
+ result->StructTypes = NULL;
+ result->StructTypeCount = 0;
+ }
+ }
+
+ return (SCHEMA_HANDLE)result;
+}
+
+size_t Schema_GetSchemaCount(void)
+{
+ /* Codes_SRS_SCHEMA_99_153: [Schema_GetSchemaCount shall return the number of "active" schemas (all schemas created with Schema_Create
+ in the current process, for which Schema_Destroy has not been called).] */
+ return VECTOR_size(g_schemas);
+}
+
+SCHEMA_HANDLE Schema_GetSchemaByNamespace(const char* schemaNamespace)
+{
+ /* Codes_SRS_SCHEMA_99_151: [If no active schema matches the schemaNamespace argument, Schema_GetSchemaByNamespace shall return NULL.] */
+ SCHEMA_HANDLE result = NULL;
+
+ /* Codes_SRS_SCHEMA_99_150: [If the schemaNamespace argument is NULL, Schema_GetSchemaByNamespace shall return NULL.] */
+ if (schemaNamespace != NULL)
+ {
+ SCHEMA_HANDLE* handle = (SCHEMA_HANDLE*)VECTOR_find_if(g_schemas, (PREDICATE_FUNCTION)SchemaNamespacesMatch, schemaNamespace);
+ if (handle != NULL)
+ {
+ /* Codes_SRS_SCHEMA_99_148: [Schema_GetSchemaByNamespace shall search all active schemas and return the schema with the
+ namespace given by the schemaNamespace argument.] */
+ result = *handle;
+ }
+ }
+
+ return result;
+}
+
+const char* Schema_GetSchemaNamespace(SCHEMA_HANDLE schemaHandle)
+{
+ const char* result;
+
+ /* Codes_SRS_SCHEMA_99_130: [If the schemaHandle argument is NULL, Schema_GetSchemaNamespace shall return NULL.] */
+ if (schemaHandle == NULL)
+ {
+ result = NULL;
+ }
+ else
+ {
+ /* Codes_SRS_SCHEMA_99_129: [Schema_GetSchemaNamespace shall return the namespace for the schema identified by schemaHandle.] */
+ result = ((SCHEMA*)schemaHandle)->Namespace;
+ }
+
+ return result;
+}
+
+void Schema_Destroy(SCHEMA_HANDLE schemaHandle)
+{
+ /* Codes_SRS_SCHEMA_99_006:[If the schemaHandle is NULL, Schema_Destroy shall do nothing.] */
+ if (schemaHandle != NULL)
+ {
+ SCHEMA* schema = (SCHEMA*)schemaHandle;
+ size_t i;
+
+ /* Codes_SRS_SCHEMA_99_005:[Schema_Destroy shall free all resources associated with a schema.] */
+ for (i = 0; i < schema->ModelTypeCount; i++)
+ {
+ DestroyModel(schema->ModelTypes[i]);
+ }
+
+ free(schema->ModelTypes);
+
+ /* Codes_SRS_SCHEMA_99_005:[Schema_Destroy shall free all resources associated with a schema.] */
+ for (i = 0; i < schema->StructTypeCount; i++)
+ {
+ DestroyStruct(schema->StructTypes[i]);
+ }
+
+ free(schema->StructTypes);
+ free((void*)schema->Namespace);
+ free(schema);
+
+ schema = (SCHEMA*)VECTOR_find_if(g_schemas, (PREDICATE_FUNCTION)SchemaHandlesMatch, &schemaHandle);
+ if (schema != NULL)
+ {
+ VECTOR_erase(g_schemas, schema, 1);
+ }
+ // If the g_schema is empty then destroy it
+ if (VECTOR_size(g_schemas) == 0)
+ {
+ VECTOR_destroy(g_schemas);
+ g_schemas = NULL;
+ }
+ }
+}
+
+SCHEMA_RESULT Schema_DestroyIfUnused(SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle)
+{
+ SCHEMA_RESULT result;
+
+ /* Codes_SRS_SCHEMA_07_189: [If modelHandle variable is NULL Schema_DestroyIfUnused shall do nothing.] */
+ if (modelTypeHandle != NULL)
+ {
+ SCHEMA_HANDLE schemaHandle = Schema_GetSchemaForModelType(modelTypeHandle);
+ if (schemaHandle == NULL)
+ {
+ result = SCHEMA_ERROR;
+ }
+ else
+ {
+ SCHEMA* schema = (SCHEMA*)schemaHandle;
+ size_t nIndex;
+
+ /* Codes_SRS_SCHEMA_07_190: [Schema_DestroyIfUnused shall iterate through the ModuleTypes objects and if all the DeviceCount variables 0 then it will delete the schemaHandle.] */
+ for (nIndex = 0; nIndex < schema->ModelTypeCount; nIndex++)
+ {
+ MODEL_TYPE* modelType = (MODEL_TYPE*)schema->ModelTypes[nIndex];
+ if (modelType->DeviceCount > 0)
+ break;
+ }
+ /* Codes_SRS_SCHEMA_07_191: [If 1 or more DeviceCount variables are > 0 then Schema_DestroyIfUnused shall do nothing.] */
+ if (nIndex == schema->ModelTypeCount)
+ {
+ Schema_Destroy(schemaHandle);
+ result = SCHEMA_OK;
+ }
+ else
+ {
+ result = SCHEMA_MODEL_IN_USE;
+ }
+ }
+ }
+ else
+ {
+ result = SCHEMA_INVALID_ARG;
+ }
+ return result;
+}
+
+SCHEMA_RESULT Schema_AddDeviceRef(SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle)
+{
+ SCHEMA_RESULT result;
+ if (modelTypeHandle == NULL)
+ {
+ /* Codes_SRS_SCHEMA_07_187: [Schema_AddDeviceRef shall return SCHEMA_INVALID_ARG if modelTypeHandle is NULL.] */
+ result = SCHEMA_INVALID_ARG;
+ LogError("(Error code:%s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, result));
+ }
+ else
+ {
+ MODEL_TYPE* model = (MODEL_TYPE*)modelTypeHandle;
+ /* Codes_SRS_SCHEMA_07_188: [If the modelTypeHandle is nonNULL, Schema_AddDeviceRef shall increment the MODEL_TYPE DeviceCount variable.] */
+ model->DeviceCount++;
+ result = SCHEMA_OK;
+ }
+ return result;
+}
+
+SCHEMA_RESULT Schema_ReleaseDeviceRef(SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle)
+{
+ SCHEMA_RESULT result;
+ /* Codes_SRS_SCHEMA_07_184: [Schema_DeviceRelease shall do nothing if the supplied modelHandle is NULL.] */
+ if (modelTypeHandle == NULL)
+ {
+ result = SCHEMA_INVALID_ARG;
+ LogError("(Error code:%s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, result));
+ }
+ else
+ {
+ MODEL_TYPE* model = (MODEL_TYPE*)modelTypeHandle;
+ if (model->DeviceCount > 0)
+ {
+ /* Codes_SRS_SCHEMA_07_186: [On a nonNULL SCHEMA_MODEL_TYPE_HANDLE if the DeviceCount variable is > 0 then the variable will be decremented.] */
+ model->DeviceCount--;
+ result = SCHEMA_OK;
+ }
+ else
+ {
+ result = SCHEMA_DEVICE_COUNT_ZERO;
+ LogError("(Error code:%s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, result));
+ }
+ }
+ return result;
+}
+
+/* Codes_SRS_SCHEMA_99_007:[Schema_CreateModelType shall create a new model type and return a handle to it.] */
+SCHEMA_MODEL_TYPE_HANDLE Schema_CreateModelType(SCHEMA_HANDLE schemaHandle, const char* modelName)
+{
+ SCHEMA_MODEL_TYPE_HANDLE result;
+
+ /* Codes_SRS_SCHEMA_99_010:[If any of the arguments is NULL, Schema_CreateModelType shall fail.] */
+ if ((schemaHandle == NULL) ||
+ (modelName == NULL))
+ {
+ /* Codes_SRS_SCHEMA_99_009:[On failure, Schema_CreateModelType shall return NULL.] */
+ result = NULL;
+ LogError("(Error code:%s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, SCHEMA_INVALID_ARG));
+ }
+ else
+ {
+ SCHEMA* schema = (SCHEMA*)schemaHandle;
+
+ /* Codes_SRS_SCHEMA_99_100: [Schema_CreateModelType shall return SCHEMA_DUPLICATE_ELEMENT if modelName already exists.] */
+ size_t i;
+ for (i = 0; i < schema->ModelTypeCount; i++)
+ {
+ MODEL_TYPE* model = (MODEL_TYPE*)(schema->ModelTypes[i]);
+ if (strcmp(model->Name, modelName) == 0)
+ {
+ break;
+ }
+ }
+
+ if (i < schema->ModelTypeCount)
+ {
+ /* Codes_SRS_SCHEMA_99_009:[On failure, Schema_CreateModelType shall return NULL.] */
+ result = NULL;
+ LogError("%s Model Name already exists", modelName);
+ }
+
+ else
+ {
+ SCHEMA_MODEL_TYPE_HANDLE* newModelTypes = (SCHEMA_MODEL_TYPE_HANDLE*)realloc(schema->ModelTypes, sizeof(SCHEMA_MODEL_TYPE_HANDLE) * (schema->ModelTypeCount + 1));
+ if (newModelTypes == NULL)
+ {
+ /* Codes_SRS_SCHEMA_99_009:[On failure, Schema_CreateModelType shall return NULL.] */
+ result = NULL;
+ LogError("(Error code:%s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, SCHEMA_ERROR));
+ }
+ else
+ {
+ MODEL_TYPE* modelType;
+ schema->ModelTypes = newModelTypes;
+
+ if ((modelType = (MODEL_TYPE*)malloc(sizeof(MODEL_TYPE))) == NULL)
+ {
+
+ /* Codes_SRS_SCHEMA_99_009:[On failure, Schema_CreateModelType shall return NULL.] */
+ result = NULL;
+ LogError("(Error code:%s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, SCHEMA_ERROR));
+ }
+ else if (mallocAndStrcpy_s((char**)&modelType->Name, modelName) != 0)
+ {
+ /* Codes_SRS_SCHEMA_99_009:[On failure, Schema_CreateModelType shall return NULL.] */
+ result = NULL;
+ free(modelType);
+ LogError("(Error code:%s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, SCHEMA_ERROR));
+ }
+ else
+ {
+ modelType->PropertyCount = 0;
+ modelType->Properties = NULL;
+ modelType->ActionCount = 0;
+ modelType->Actions = NULL;
+ modelType->SchemaHandle = schemaHandle;
+ modelType->DeviceCount = 0;
+ modelType->models = VECTOR_create(sizeof(MODEL_IN_MODEL) );
+ schema->ModelTypes[schema->ModelTypeCount] = modelType;
+ schema->ModelTypeCount++;
+
+ /* Codes_SRS_SCHEMA_99_008:[On success, a non-NULL handle shall be returned.] */
+ result = (SCHEMA_MODEL_TYPE_HANDLE)modelType;
+ }
+
+ /* If possible, reduce the memory of over allocation */
+ if (result == NULL)
+ {
+ SCHEMA_MODEL_TYPE_HANDLE* oldModelTypes = (SCHEMA_MODEL_TYPE_HANDLE*)realloc(schema->ModelTypes, sizeof(SCHEMA_MODEL_TYPE_HANDLE) * schema->ModelTypeCount);
+ if (oldModelTypes == NULL)
+ {
+ result = NULL;
+ LogError("(Error code:%s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, SCHEMA_ERROR));
+ }
+ else
+ {
+ schema->ModelTypes = oldModelTypes;
+ }
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+SCHEMA_HANDLE Schema_GetSchemaForModelType(SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle)
+{
+ SCHEMA_HANDLE result;
+
+ if (modelTypeHandle == NULL)
+ {
+ /* Codes_SRS_SCHEMA_99_132: [If the modelTypeHandle argument is NULL, Schema_GetSchemaForModelType shall return NULL.] */
+ result = NULL;
+ }
+ else
+ {
+ /* Codes_SRS_SCHEMA_99_131: [Schema_GetSchemaForModelType returns the schema handle for a given model type.] */
+ result = ((MODEL_TYPE*)modelTypeHandle)->SchemaHandle;
+ }
+
+ return result;
+}
+
+/* Codes_SRS_SCHEMA_99_011:[Schema_AddModelProperty shall add one property to the model type identified by modelTypeHandle.] */
+SCHEMA_RESULT Schema_AddModelProperty(SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle, const char* propertyName, const char* propertyType)
+{
+ return AddModelProperty((MODEL_TYPE*)modelTypeHandle, propertyName, propertyType);
+}
+
+SCHEMA_ACTION_HANDLE Schema_CreateModelAction(SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle, const char* actionName)
+{
+ SCHEMA_ACTION_HANDLE result;
+
+ /* Codes_SRS_SCHEMA_99_104: [If any of the modelTypeHandle or actionName arguments is NULL, Schema_CreateModelAction shall return NULL.] */
+ if ((modelTypeHandle == NULL) ||
+ (actionName == NULL))
+ {
+ result = NULL;
+ LogError("(Error code:%s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, SCHEMA_INVALID_ARG));
+ }
+ else
+ {
+ MODEL_TYPE* modelType = (MODEL_TYPE*)modelTypeHandle;
+ size_t i;
+
+ /* Codes_SRS_SCHEMA_99_105: [The action name shall be unique per model, if the same action name is added twice to a model, Schema_CreateModelAction shall return NULL.] */
+ for (i = 0; i < modelType->ActionCount; i++)
+ {
+ ACTION* action = (ACTION*)modelType->Actions[i];
+ if (strcmp(action->ActionName, actionName) == 0)
+ {
+ break;
+ }
+ }
+
+ if (i < modelType->ActionCount)
+ {
+ result = NULL;
+ LogError("(Error code:%s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, SCHEMA_DUPLICATE_ELEMENT));
+ }
+ else
+ {
+ /* Codes_SRS_SCHEMA_99_102: [Schema_CreateModelAction shall add one action to the model type identified by modelTypeHandle.] */
+ SCHEMA_ACTION_HANDLE* newActions = (SCHEMA_ACTION_HANDLE*)realloc(modelType->Actions, sizeof(SCHEMA_ACTION_HANDLE) * (modelType->ActionCount + 1));
+ if (newActions == NULL)
+ {
+ /* Codes_SRS_SCHEMA_99_106: [On any other error, Schema_CreateModelAction shall return NULL.]*/
+ result = NULL;
+ LogError("(Error code:%s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, SCHEMA_ERROR));
+ }
+ else
+ {
+ ACTION* newAction;
+ modelType->Actions = newActions;
+
+ /* Codes_SRS_SCHEMA_99_103: [On success, Schema_CreateModelAction shall return a none-NULL SCHEMA_ACTION_HANDLE to the newly created action.] */
+ if ((newAction = (ACTION*)malloc(sizeof(ACTION))) == NULL)
+ {
+ /* Codes_SRS_SCHEMA_99_106: [On any other error, Schema_CreateModelAction shall return NULL.]*/
+ result = NULL;
+ LogError("(Error code:%s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, SCHEMA_ERROR));
+ }
+ else
+ {
+ if (mallocAndStrcpy_s((char**)&newAction->ActionName, actionName) != 0)
+ {
+ /* Codes_SRS_SCHEMA_99_106: [On any other error, Schema_CreateModelAction shall return NULL.]*/
+ free(newAction);
+ result = NULL;
+ LogError("(Error code:%s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, SCHEMA_ERROR));
+ }
+ else
+ {
+ newAction->ArgumentCount = 0;
+ newAction->ArgumentHandles = NULL;
+
+ modelType->Actions[modelType->ActionCount] = newAction;
+ modelType->ActionCount++;
+ result = (SCHEMA_ACTION_HANDLE)(newAction);
+ }
+
+ /* If possible, reduce the memory of over allocation */
+ if (result == NULL)
+ {
+ SCHEMA_ACTION_HANDLE* oldActions = (SCHEMA_ACTION_HANDLE*)realloc(modelType->Actions, sizeof(SCHEMA_ACTION_HANDLE) * modelType->ActionCount);
+ if (oldActions == NULL)
+ {
+ LogError("(Error code:%s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, SCHEMA_ERROR));
+ }
+ else
+ {
+ modelType->Actions = oldActions;
+ }
+ }
+ }
+ }
+ }
+ }
+ return result;
+}
+
+SCHEMA_RESULT Schema_AddModelActionArgument(SCHEMA_ACTION_HANDLE actionHandle, const char* argumentName, const char* argumentType)
+{
+ SCHEMA_RESULT result;
+
+ /* Codes_SRS_SCHEMA_99_109: [If any of the arguments is NULL, Schema_AddModelActionArgument shall return SCHEMA_INVALID_ARG.] */
+ if ((actionHandle == NULL) ||
+ (argumentName == NULL) ||
+ (argumentType == NULL))
+ {
+ result = SCHEMA_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, result));
+ }
+ else
+ {
+ ACTION* action = (ACTION*)actionHandle;
+
+ /* Codes_SRS_SCHEMA_99_110: [The argument name shall be unique per action, if the same name is added twice to an action, SCHEMA_DUPLICATE_ELEMENT shall be returned.] */
+ /* Codes_SRS_SCHEMA_99_111: [Schema_AddModelActionArgument shall accept arguments with different names of the same type.] */
+ size_t i;
+ for (i = 0; i < action->ArgumentCount; i++)
+ {
+ SCHEMA_ACTION_ARGUMENT* actionArgument = (SCHEMA_ACTION_ARGUMENT*)action->ArgumentHandles[i];
+ if (strcmp((actionArgument->Name), argumentName) == 0)
+ {
+ break;
+ }
+ }
+
+ if (i < action->ArgumentCount)
+ {
+ result = SCHEMA_DUPLICATE_ELEMENT;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, result));
+ }
+ else
+ {
+ /* Codes_SRS_SCHEMA_99_107: [Schema_AddModelActionArgument shall add one argument name & type to an action identified by actionHandle.] */
+ SCHEMA_ACTION_ARGUMENT_HANDLE* newArguments = (SCHEMA_ACTION_ARGUMENT_HANDLE*)realloc(action->ArgumentHandles, sizeof(SCHEMA_ACTION_ARGUMENT_HANDLE) * (action->ArgumentCount + 1));
+ if (newArguments == NULL)
+ {
+ /* Codes_SRS_SCHEMA_99_112: [On any other error, Schema_ AddModelActionArgumet shall return SCHEMA_ERROR.] */
+ result = SCHEMA_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, result));
+ }
+ else
+ {
+ SCHEMA_ACTION_ARGUMENT* newActionArgument;
+ if ((newActionArgument = (SCHEMA_ACTION_ARGUMENT*)malloc(sizeof(SCHEMA_ACTION_ARGUMENT))) == NULL)
+ {
+ /* Codes_SRS_SCHEMA_99_112: [On any other error, Schema_ AddModelActionArgumet shall return SCHEMA_ERROR.] */
+ result = SCHEMA_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, result));
+ }
+ else
+ {
+ if (mallocAndStrcpy_s((char**)&newActionArgument->Name, argumentName) != 0)
+ {
+ /* Codes_SRS_SCHEMA_99_112: [On any other error, Schema_ AddModelActionArgumet shall return SCHEMA_ERROR.] */
+ free(newActionArgument);
+ result = SCHEMA_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, result));
+ }
+ else if (mallocAndStrcpy_s((char**)&newActionArgument->Type, argumentType) != 0)
+ {
+ /* Codes_SRS_SCHEMA_99_112: [On any other error, Schema_ AddModelActionArgumet shall return SCHEMA_ERROR.] */
+ free((void*)newActionArgument->Name);
+ free(newActionArgument);
+ result = SCHEMA_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, result));
+ }
+ else
+ {
+ action->ArgumentHandles = newArguments;
+ /* Codes_SRS_SCHEMA_99_119: [Schema_AddModelActionArgument shall preserve the order of the action arguments according to the order in which they were added, starting with index 0 for the first added argument.] */
+ action->ArgumentHandles[action->ArgumentCount] = newActionArgument;
+ action->ArgumentCount++;
+
+ /* Codes_SRS_SCHEMA_99_108: [On success, Schema_AddModelActionArgunent shall return SCHEMA_OK.] */
+ result = SCHEMA_OK;
+ }
+ }
+
+ /* If possible, reduce the memory of over allocation */
+ if (result == SCHEMA_ERROR)
+ {
+ SCHEMA_ACTION_ARGUMENT_HANDLE* oldArguments = (SCHEMA_ACTION_ARGUMENT_HANDLE*)realloc(action->ArgumentHandles, sizeof(SCHEMA_ACTION_ARGUMENT_HANDLE) * action->ArgumentCount);
+ if (oldArguments == NULL)
+ {
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, SCHEMA_ERROR));
+ }
+ else
+ {
+ action->ArgumentHandles = oldArguments;
+ }
+ }
+ }
+ }
+ }
+ return result;
+}
+
+SCHEMA_PROPERTY_HANDLE Schema_GetModelPropertyByName(SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle, const char* propertyName)
+{
+ SCHEMA_PROPERTY_HANDLE result;
+
+ /* Codes_SRS_SCHEMA_99_038:[Schema_GetModelPropertyByName shall return NULL if unable to find a matching property or if any of the arguments are NULL.] */
+ if ((modelTypeHandle == NULL) ||
+ (propertyName == NULL))
+ {
+ result = NULL;
+ LogError("(Error code:%s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, SCHEMA_INVALID_ARG));
+ }
+ else
+ {
+ size_t i;
+ MODEL_TYPE* modelType = (MODEL_TYPE*)modelTypeHandle;
+
+ /* Codes_SRS_SCHEMA_99_036:[Schema_GetModelPropertyByName shall return a non-NULL SCHEMA_PROPERTY_HANDLE corresponding to the model type identified by modelTypeHandle and matching the propertyName argument value.] */
+ for (i = 0; i < modelType->PropertyCount; i++)
+ {
+ PROPERTY* modelProperty = (PROPERTY*)modelType->Properties[i];
+ if (strcmp(modelProperty->PropertyName, propertyName) == 0)
+ {
+ break;
+ }
+ }
+
+ if (i == modelType->PropertyCount)
+ {
+ /* Codes_SRS_SCHEMA_99_038:[Schema_GetModelPropertyByName shall return NULL if unable to find a matching property or if any of the arguments are NULL.] */
+ result = NULL;
+ LogError("(Error code:%s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, SCHEMA_ELEMENT_NOT_FOUND));
+ }
+ else
+ {
+ result = (SCHEMA_PROPERTY_HANDLE)(modelType->Properties[i]);
+ }
+ }
+
+ return result;
+}
+
+SCHEMA_RESULT Schema_GetModelPropertyCount(SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle, size_t* propertyCount)
+{
+ SCHEMA_RESULT result;
+
+ /* Codes_SRS_SCHEMA_99_092: [Schema_GetModelPropertyCount shall return SCHEMA_INVALID_ARG if any of the arguments is NULL.] */
+ if ((modelTypeHandle == NULL) ||
+ (propertyCount == NULL))
+ {
+ result = SCHEMA_INVALID_ARG;
+ }
+ else
+ {
+ /* Codes_SRS_SCHEMA_99_089: [Schema_GetModelPropertyCount shall provide the number of properties defined in the model type identified by modelTypeHandle.] */
+ MODEL_TYPE* modelType = (MODEL_TYPE*)modelTypeHandle;
+
+ /* Codes_SRS_SCHEMA_99_090: [The count shall be provided via the out argument propertyCount.]*/
+ *propertyCount = modelType->PropertyCount;
+
+ /* Codes_SRS_SCHEMA_99_091: [On success, Schema_GetModelPropertyCount shall return SCHEMA_OK.] */
+ result = SCHEMA_OK;
+ }
+
+ return result;
+}
+
+SCHEMA_PROPERTY_HANDLE Schema_GetModelPropertyByIndex(SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle, size_t index)
+{
+ SCHEMA_PROPERTY_HANDLE result;
+ MODEL_TYPE* modelType = (MODEL_TYPE*)modelTypeHandle;
+
+ /* Codes_SRS_SCHEMA_99_094: [Schema_GetModelProperty shall return NULL if the index specified is outside the valid range or if modelTypeHandle argument is NULL.] */
+ if ((modelTypeHandle == NULL) ||
+ (index >= modelType->PropertyCount))
+ {
+ result = NULL;
+ LogError("(Error code: %s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, SCHEMA_INVALID_ARG));
+ }
+ else
+ {
+ /* Tests_SRS_SCHEMA_99_093: [Schema_GetModelProperty shall return a non-NULL SCHEMA_PROPERTY_HANDLE corresponding to the model type identified by modelTypeHandle and matching the index number provided by the index argument.] */
+ /* Codes_SRS_SCHEMA_99_097: [index is zero based, and the order in which actions were added shall be the index in which they will be retrieved.] */
+ result = modelType->Properties[index];
+ }
+
+ return result;
+}
+
+SCHEMA_ACTION_HANDLE Schema_GetModelActionByName(SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle, const char* actionName)
+{
+ SCHEMA_ACTION_HANDLE result;
+
+ /* Codes_SRS_SCHEMA_99_041:[Schema_GetModelActionByName shall return NULL if unable to find a matching action, if any of the arguments are NULL.] */
+ if ((modelTypeHandle == NULL) ||
+ (actionName == NULL))
+ {
+ result = NULL;
+ LogError("(Error code:%s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, SCHEMA_INVALID_ARG));
+ }
+ else
+ {
+ size_t i;
+ MODEL_TYPE* modelType = (MODEL_TYPE*)modelTypeHandle;
+
+ /* Codes_SRS_SCHEMA_99_040:[Schema_GetModelActionByName shall return a non-NULL SCHEMA_ACTION_HANDLE corresponding to the model type identified by modelTypeHandle and matching the actionName argument value.] */
+ for (i = 0; i < modelType->ActionCount; i++)
+ {
+ ACTION* modelAction = (ACTION*)modelType->Actions[i];
+ if (strcmp(modelAction->ActionName, actionName) == 0)
+ {
+ break;
+ }
+ }
+
+ if (i == modelType->ActionCount)
+ {
+ /* Codes_SRS_SCHEMA_99_041:[Schema_GetModelActionByName shall return NULL if unable to find a matching action, if any of the arguments are NULL.] */
+ result = NULL;
+ LogError("(Error code:%s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, SCHEMA_ELEMENT_NOT_FOUND));
+ }
+ else
+ {
+ result = modelType->Actions[i];
+ }
+ }
+
+ return result;
+}
+
+SCHEMA_RESULT Schema_GetModelActionCount(SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle, size_t* actionCount)
+{
+ SCHEMA_RESULT result;
+
+ /* Codes_SRS_SCHEMA_99_045:[If any of the modelTypeHandle or actionCount arguments is NULL, Schema_GetModelActionCount shall return SCHEMA_INVALID_ARG.] */
+ if ((modelTypeHandle == NULL) ||
+ (actionCount == NULL))
+ {
+ result = SCHEMA_INVALID_ARG;
+ LogError("(result=%s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, result));
+ }
+ else
+ {
+ /* Codes_SRS_SCHEMA_99_042:[Schema_GetModelActionCount shall provide the total number of actions defined in a model type identified by the modelTypeHandle.] */
+ MODEL_TYPE* modelType = (MODEL_TYPE*)modelTypeHandle;
+
+ /* Codes_SRS_SCHEMA_99_043:[The count shall be provided via the out argument actionCount.] */
+ *actionCount = modelType->ActionCount;
+
+ /* Codes_SRS_SCHEMA_99_044:[On success, Schema_GetModelActionCount shall return SCHEMA_OK.] */
+ result = SCHEMA_OK;
+ }
+
+ return result;
+}
+
+SCHEMA_ACTION_HANDLE Schema_GetModelActionByIndex(SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle, size_t index)
+{
+ SCHEMA_ACTION_HANDLE result;
+ MODEL_TYPE* modelType = (MODEL_TYPE*)modelTypeHandle;
+
+ /* Codes_SRS_SCHEMA_99_048:[Schema_GetModelAction shall return NULL if the index specified is outside the valid range or if modelTypeHandle argument is NULL.] */
+ if ((modelType == NULL) ||
+ (index >= modelType->ActionCount))
+ {
+ result = NULL;
+ LogError("(Error code:%s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, SCHEMA_INVALID_ARG));
+ }
+ else
+ {
+ /* Codes_SRS_SCHEMA_99_047:[Schema_GetModelAction shall return a non-NULL SCHEMA_ACTION_HANDLE corresponding to the model type identified by modelTypeHandle and matching the index number provided by the index argument.] */
+ /* Codes_SRS_SCHEMA_99_096: [index is zero based and the order in which actions were added shall be the index in which they will be retrieved.] */
+ result = modelType->Actions[index];
+ }
+
+ return result;
+}
+
+const char* Schema_GetModelActionName(SCHEMA_ACTION_HANDLE actionHandle)
+{
+ const char* result;
+
+ /* Codes_SRS_SCHEMA_99_050:[If the actionHandle is NULL, Schema_GetModelActionName shall return NULL.] */
+ if (actionHandle == NULL)
+ {
+ result = NULL;
+ LogError("(Error code:%s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, SCHEMA_INVALID_ARG));
+ }
+ else
+ {
+ ACTION* action = (ACTION*)actionHandle;
+ /* Codes_SRS_SCHEMA_99_049:[Schema_GetModelActionName shall return the action name for a given action handle.] */
+ result = action->ActionName;
+ }
+
+ return result;
+}
+
+SCHEMA_RESULT Schema_GetModelActionArgumentCount(SCHEMA_ACTION_HANDLE actionHandle, size_t* argumentCount)
+{
+ SCHEMA_RESULT result;
+
+ /* Codes_SRS_SCHEMA_99_054:[If any argument is NULL, Schema_GetModelActionArgumentCount shall return SCHEMA_INVALID_ARG.] */
+ if ((actionHandle == NULL) ||
+ (argumentCount == NULL))
+ {
+ result = SCHEMA_INVALID_ARG;
+ LogError("(result=%s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, result));
+ }
+ else
+ {
+ ACTION* modelAction = (ACTION*)actionHandle;
+
+ /* Codes_SRS_SCHEMA_99_051:[Schema_GetModelActionArgumentCount shall provide the number of arguments for a specific schema action identified by actionHandle.] */
+ /* Codes_SRS_SCHEMA_99_052:[The argument count shall be provided via the out argument argumentCount.] */
+ *argumentCount = modelAction->ArgumentCount;
+
+ /* Codes_SRS_SCHEMA_99_053:[On success, Schema_GetModelActionArgumentCount shall return SCHEMA_OK.] */
+ result = SCHEMA_OK;
+ }
+
+ return result;
+}
+
+SCHEMA_ACTION_ARGUMENT_HANDLE Schema_GetModelActionArgumentByName(SCHEMA_ACTION_HANDLE actionHandle, const char* actionArgumentName)
+{
+ SCHEMA_ACTION_ARGUMENT_HANDLE result;
+
+ /* Codes_SRS_SCHEMA_99_118: [Schema_GetModelActionArgumentByName shall return NULL if unable to find a matching argument or if any of the arguments are NULL.] */
+ if ((actionHandle == NULL) ||
+ (actionArgumentName == NULL))
+ {
+ result = NULL;
+ LogError("(Error code:%s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, SCHEMA_INVALID_ARG));
+ }
+ else
+ {
+ /* Codes_SRS_SCHEMA_99_118: [Schema_GetModelActionArgumentByName shall return NULL if unable to find a matching argument or if any of the arguments are NULL.] */
+ ACTION* modelAction = (ACTION*)actionHandle;
+ size_t i;
+
+ for (i = 0; i < modelAction->ArgumentCount; i++)
+ {
+ SCHEMA_ACTION_ARGUMENT* actionArgument = (SCHEMA_ACTION_ARGUMENT*)modelAction->ArgumentHandles[i];
+ if (strcmp(actionArgument->Name, actionArgumentName) == 0)
+ {
+ break;
+ }
+ }
+
+ if (i == modelAction->ArgumentCount)
+ {
+ /* Codes_SRS_SCHEMA_99_118: [Schema_GetModelActionArgumentByName shall return NULL if unable to find a matching argument or if any of the arguments are NULL.] */
+ result = NULL;
+ LogError("(Error code:%s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, SCHEMA_ELEMENT_NOT_FOUND));
+ }
+ else
+ {
+ /* Codes_SRS_SCHEMA_99_117: [Schema_GetModelActionArgumentByName shall return a non-NULL handle corresponding to an action argument identified by the actionHandle and actionArgumentName.] */
+ result = modelAction->ArgumentHandles[i];
+ }
+ }
+
+ return result;
+}
+
+SCHEMA_ACTION_ARGUMENT_HANDLE Schema_GetModelActionArgumentByIndex(SCHEMA_ACTION_HANDLE actionHandle, size_t argumentIndex)
+{
+ SCHEMA_ACTION_ARGUMENT_HANDLE result;
+ ACTION* modelAction = (ACTION*)actionHandle;
+
+ /* Codes_SRS_SCHEMA_99_056:[Schema_GetModelActionArgument shall return NULL if the index specified is outside the valid range or if the actionHandle argument is NULL.] */
+ if ((actionHandle == NULL) ||
+ (argumentIndex >= modelAction->ArgumentCount))
+ {
+ result = NULL;
+ LogError("(Error code:%s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, SCHEMA_INVALID_ARG));
+ }
+ else
+ {
+ /* Codes_SRS_SCHEMA_99_055:[Schema_GetModelActionArgument shall return a non-NULL SCHEMA_ACTION_ARGUMENT_HANDLE corresponding to the action type identified by actionHandle and matching the index number provided by the argumentIndex argument.] */
+ result = modelAction->ArgumentHandles[argumentIndex];
+ }
+
+ return result;
+}
+
+const char* Schema_GetActionArgumentName(SCHEMA_ACTION_ARGUMENT_HANDLE actionArgumentHandle)
+{
+ const char* result;
+ /* Codes_SRS_SCHEMA_99_114: [Schema_GetActionArgumentName shall return NULL if actionArgumentHandle is NULL.] */
+ if (actionArgumentHandle == NULL)
+ {
+ result = NULL;
+ LogError("(Error code:%s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, SCHEMA_INVALID_ARG));
+ }
+ else
+ {
+ /* Codes_SRS_SCHEMA_99_113: [Schema_GetActionArgumentName shall return the argument name identified by the actionArgumentHandle.] */
+ SCHEMA_ACTION_ARGUMENT* actionArgument = (SCHEMA_ACTION_ARGUMENT*)actionArgumentHandle;
+ result = actionArgument->Name;
+ }
+ return result;
+}
+
+const char* Schema_GetActionArgumentType(SCHEMA_ACTION_ARGUMENT_HANDLE actionArgumentHandle)
+{
+ const char* result;
+ /* Codes_SRS_SCHEMA_99_116: [Schema_GetActionArgumentType shall return NULL if actionArgumentHandle is NULL.] */
+ if (actionArgumentHandle == NULL)
+ {
+ result = NULL;
+ LogError("(Error code:%s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, SCHEMA_INVALID_ARG));
+ }
+ else
+ {
+ /* Codes_SRS_SCHEMA_99_115: [Schema_GetActionArgumentType shall return the argument type identified by the actionArgumentHandle.] */
+ SCHEMA_ACTION_ARGUMENT* actionArgument = (SCHEMA_ACTION_ARGUMENT*)actionArgumentHandle;
+ result = actionArgument->Type;
+ }
+ return result;
+}
+
+SCHEMA_STRUCT_TYPE_HANDLE Schema_CreateStructType(SCHEMA_HANDLE schemaHandle, const char* typeName)
+{
+ SCHEMA_STRUCT_TYPE_HANDLE result;
+ SCHEMA* schema = (SCHEMA*)schemaHandle;
+
+ /* Codes_SRS_SCHEMA_99_060:[If any of the arguments is NULL, Schema_CreateStructType shall return NULL.] */
+ if ((schema == NULL) ||
+ (typeName == NULL))
+ {
+ result = NULL;
+ LogError("(Error code:%s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, SCHEMA_INVALID_ARG));
+ }
+ else
+ {
+ STRUCT_TYPE* structType;
+ size_t i;
+
+ /* Codes_SRS_SCHEMA_99_061:[If a struct type with the same name already exists, Schema_CreateStructType shall return NULL.] */
+ for (i = 0; i < schema->StructTypeCount; i++)
+ {
+ structType = (STRUCT_TYPE*)schema->StructTypes[i];
+ if (strcmp(structType->Name, typeName) == 0)
+ {
+ break;
+ }
+ }
+
+ if (i < schema->StructTypeCount)
+ {
+ result = NULL;
+ LogError("(Error code:%s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, SCHEMA_DUPLICATE_ELEMENT));
+ }
+ else
+ {
+ SCHEMA_STRUCT_TYPE_HANDLE* newStructTypes = (SCHEMA_STRUCT_TYPE_HANDLE*)realloc(schema->StructTypes, sizeof(SCHEMA_STRUCT_TYPE_HANDLE) * (schema->StructTypeCount + 1));
+ if (newStructTypes == NULL)
+ {
+ /* Codes_SRS_SCHEMA_99_066:[On any other error, Schema_CreateStructType shall return NULL.] */
+ result = NULL;
+ LogError("(Error code:%s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, SCHEMA_ERROR));
+ }
+ else
+ {
+ schema->StructTypes = newStructTypes;
+ if ((structType = (STRUCT_TYPE*)malloc(sizeof(STRUCT_TYPE))) == NULL)
+ {
+ /* Codes_SRS_SCHEMA_99_066:[On any other error, Schema_CreateStructType shall return NULL.] */
+ result = NULL;
+ LogError("(Error code:%s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, SCHEMA_ERROR));
+ }
+ else if (mallocAndStrcpy_s((char**)&structType->Name, typeName) != 0)
+ {
+ /* Codes_SRS_SCHEMA_99_066:[On any other error, Schema_CreateStructType shall return NULL.] */
+ result = NULL;
+ free(structType);
+ LogError("(Error code:%s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, SCHEMA_ERROR));
+ }
+ else
+ {
+ /* Codes_SRS_SCHEMA_99_057:[Schema_CreateStructType shall create a new struct type and return a handle to it.] */
+ schema->StructTypes[schema->StructTypeCount] = structType;
+ schema->StructTypeCount++;
+ structType->PropertyCount = 0;
+ structType->Properties = NULL;
+
+ /* Codes_SRS_SCHEMA_99_058:[On success, a non-NULL handle shall be returned.] */
+ result = (SCHEMA_STRUCT_TYPE_HANDLE)structType;
+ }
+
+ /* If possible, reduce the memory of over allocation */
+ if (result == NULL)
+ {
+ SCHEMA_STRUCT_TYPE_HANDLE* oldStructTypes = (SCHEMA_STRUCT_TYPE_HANDLE*)realloc(schema->StructTypes, sizeof(SCHEMA_STRUCT_TYPE_HANDLE) * schema->StructTypeCount);
+ if (oldStructTypes == NULL)
+ {
+ result = NULL;
+ LogError("(Error code:%s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, SCHEMA_ERROR));
+ }
+ else
+ {
+ schema->StructTypes = oldStructTypes;
+ }
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+const char* Schema_GetStructTypeName(SCHEMA_STRUCT_TYPE_HANDLE structTypeHandle)
+{
+ const char* result;
+
+ /* Codes_SRS_SCHEMA_99_136: [If structTypeHandle is NULL, Schema_GetStructTypeName shall return NULL.] */
+ if (structTypeHandle == NULL)
+ {
+ result = NULL;
+ LogError("(Error code:%s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, SCHEMA_INVALID_ARG));
+ }
+ else
+ {
+ /* Codes_SRS_SCHEMA_99_135: [Schema_GetStructTypeName shall return the name of a struct type identified by the structTypeHandle argument.] */
+ result = ((STRUCT_TYPE*)structTypeHandle)->Name;
+ }
+
+ return result;
+}
+
+SCHEMA_RESULT Schema_GetStructTypeCount(SCHEMA_HANDLE schemaHandle, size_t* structTypeCount)
+{
+ SCHEMA_RESULT result;
+
+ /* Codes_SRS_SCHEMA_99_140: [Schema_GetStructTypeCount shall return SCHEMA_INVALID_ARG if any of the arguments is NULL.] */
+ if ((schemaHandle == NULL) ||
+ (structTypeCount == NULL))
+ {
+ result = SCHEMA_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, result));
+ }
+ else
+ {
+ /* Codes_SRS_SCHEMA_99_137: [Schema_GetStructTypeCount shall provide the number of structs defined in the schema identified by schemaHandle.] */
+ SCHEMA* schema = (SCHEMA*)schemaHandle;
+ /* Codes_SRS_SCHEMA_99_138: [The count shall be provided via the out argument structTypeCount.] */
+ *structTypeCount = schema->StructTypeCount;
+ /* Codes_SRS_SCHEMA_99_139: [On success, Schema_GetStructTypeCount shall return SCHEMA_OK.] */
+ result = SCHEMA_OK;
+ }
+
+ return result;
+}
+
+SCHEMA_STRUCT_TYPE_HANDLE Schema_GetStructTypeByName(SCHEMA_HANDLE schemaHandle, const char* name)
+{
+ SCHEMA_ACTION_HANDLE result;
+ SCHEMA* schema = (SCHEMA*)schemaHandle;
+
+ /* Codes_SRS_SCHEMA_99_069:[Schema_GetStructTypeByName shall return NULL if unable to find a matching struct or if any of the arguments are NULL.] */
+ if ((schemaHandle == NULL) ||
+ (name == NULL))
+ {
+ result = NULL;
+ LogError("(Error code:%s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, SCHEMA_INVALID_ARG));
+ }
+ else
+ {
+ size_t i;
+
+ /* Codes_SRS_SCHEMA_99_068:[Schema_GetStructTypeByName shall return a non-NULL handle corresponding to the struct type identified by the structTypeName in the schemaHandle schema.] */
+ for (i = 0; i < schema->StructTypeCount; i++)
+ {
+ STRUCT_TYPE* structType = (STRUCT_TYPE*)schema->StructTypes[i];
+ if (strcmp(structType->Name, name) == 0)
+ {
+ break;
+ }
+ }
+
+ if (i == schema->StructTypeCount)
+ {
+ /* Codes_SRS_SCHEMA_99_069:[Schema_GetStructTypeByName shall return NULL if unable to find a matching struct or if any of the arguments are NULL.] */
+ result = NULL;
+ LogError("(Error code:%s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, SCHEMA_ELEMENT_NOT_FOUND));
+ }
+ else
+ {
+ result = schema->StructTypes[i];
+ }
+ }
+
+ return result;
+}
+
+SCHEMA_STRUCT_TYPE_HANDLE Schema_GetStructTypeByIndex(SCHEMA_HANDLE schemaHandle, size_t index)
+{
+ SCHEMA_STRUCT_TYPE_HANDLE result;
+ SCHEMA* schema = (SCHEMA*)schemaHandle;
+
+ /* Codes_SRS_SCHEMA_99_143: [Schema_GetStructTypeByIndex shall return NULL if the index specified is outside the valid range or if schemaHandle argument is NULL.] */
+ /* Codes_SRS_SCHEMA_99_142: [The index argument is zero based, and the order in which models were added shall be the index in which they will be retrieved.] */
+ if ((schemaHandle == NULL) ||
+ (index >= schema->StructTypeCount))
+ {
+ result = NULL;
+ LogError("(Error code: %s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, SCHEMA_INVALID_ARG));
+ }
+ else
+ {
+
+ /* Codes_SRS_SCHEMA_99_141: [Schema_GetStructTypeByIndex shall return a non-NULL SCHEMA_STRUCT_TYPE_HANDLE corresponding to the struct type identified by schemaHandle and matching the index number provided by the index argument.] */
+ /* Codes_SRS_SCHEMA_99_142: [The index argument is zero based, and the order in which models were added shall be the index in which they will be retrieved.] */
+ result = schema->StructTypes[index];
+ }
+ return result;
+}
+
+SCHEMA_RESULT Schema_AddStructTypeProperty(SCHEMA_STRUCT_TYPE_HANDLE structTypeHandle, const char* propertyName, const char* propertyType)
+{
+ SCHEMA_RESULT result;
+
+ /* Codes_SRS_SCHEMA_99_072:[If any of the arguments is NULL, Schema_AddStructTypeProperty shall return SCHEMA_INVALID_ARG.] */
+ if ((structTypeHandle == NULL) ||
+ (propertyName == NULL) ||
+ (propertyType == NULL))
+ {
+ result = SCHEMA_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, result));
+ }
+ else
+ {
+ size_t i;
+ STRUCT_TYPE* structType = (STRUCT_TYPE*)structTypeHandle;
+
+ /* Codes_SRS_SCHEMA_99_074:[The property name shall be unique per struct type, if the same property name is added twice to a struct type, SCHEMA_DUPLICATE_ELEMENT shall be returned.] */
+ for (i = 0; i < structType->PropertyCount; i++)
+ {
+ PROPERTY* property = (PROPERTY*)structType->Properties[i];
+ if (strcmp(property->PropertyName, propertyName) == 0)
+ {
+ break;
+ }
+ }
+
+ if (i < structType->PropertyCount)
+ {
+ result = SCHEMA_DUPLICATE_ELEMENT;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, result));
+ }
+ else
+ {
+ SCHEMA_PROPERTY_HANDLE* newProperties = (SCHEMA_PROPERTY_HANDLE*)realloc(structType->Properties, sizeof(SCHEMA_PROPERTY_HANDLE) * (structType->PropertyCount + 1));
+ if (newProperties == NULL)
+ {
+ result = SCHEMA_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, result));
+ }
+ else
+ {
+ PROPERTY* newProperty;
+
+ structType->Properties = newProperties;
+ if ((newProperty = (PROPERTY*)malloc(sizeof(PROPERTY))) == NULL)
+ {
+ result = SCHEMA_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, result));
+ }
+ else
+ {
+ if (mallocAndStrcpy_s((char**)&newProperty->PropertyName, propertyName) != 0)
+ {
+ free(newProperty);
+ result = SCHEMA_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, result));
+ }
+ else if (mallocAndStrcpy_s((char**)&newProperty->PropertyType, propertyType) != 0)
+ {
+ free((void*)newProperty->PropertyName);
+ free(newProperty);
+ result = SCHEMA_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, result));
+ }
+ else
+ {
+ /* Codes_SRS_SCHEMA_99_070:[Schema_AddStructTypeProperty shall add one property to the struct type identified by structTypeHandle.] */
+ structType->Properties[structType->PropertyCount] = (SCHEMA_PROPERTY_HANDLE)newProperty;
+ structType->PropertyCount++;
+
+ /* Codes_SRS_SCHEMA_99_071:[On success, Schema_AddStructTypeProperty shall return SCHEMA_OK.] */
+ result = SCHEMA_OK;
+ }
+ }
+
+ /* If possible, reduce the memory of over allocation */
+ if (result != SCHEMA_OK)
+ {
+ SCHEMA_PROPERTY_HANDLE* oldProperties = (SCHEMA_PROPERTY_HANDLE*)realloc(structType->Properties, sizeof(SCHEMA_PROPERTY_HANDLE) * structType->PropertyCount);
+ if (oldProperties == NULL)
+ {
+ result = SCHEMA_ERROR;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, result));
+ }
+ else
+ {
+ structType->Properties = oldProperties;
+ }
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+SCHEMA_PROPERTY_HANDLE Schema_GetStructTypePropertyByName(SCHEMA_STRUCT_TYPE_HANDLE structTypeHandle, const char* propertyName)
+{
+ SCHEMA_PROPERTY_HANDLE result;
+
+ /* Codes_SRS_SCHEMA_99_076:[Schema_GetStructTypePropertyByName shall return NULL if unable to find a matching property or if any of the arguments are NULL.] */
+ if ((structTypeHandle == NULL) ||
+ (propertyName == NULL))
+ {
+ result = NULL;
+ LogError("(Error code: %s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, SCHEMA_INVALID_ARG));
+ }
+ else
+ {
+ size_t i;
+ STRUCT_TYPE* structType = (STRUCT_TYPE*)structTypeHandle;
+
+ for (i = 0; i < structType->PropertyCount; i++)
+ {
+ PROPERTY* modelProperty = (PROPERTY*)structType->Properties[i];
+ if (strcmp(modelProperty->PropertyName, propertyName) == 0)
+ {
+ break;
+ }
+ }
+
+ /* Codes_SRS_SCHEMA_99_076:[Schema_GetStructTypePropertyByName shall return NULL if unable to find a matching property or if any of the arguments are NULL.] */
+ if (i == structType->PropertyCount)
+ {
+ result = NULL;
+ LogError("(Error code: %s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, SCHEMA_ELEMENT_NOT_FOUND));
+ }
+ /* Codes_SRS_SCHEMA_99_075:[Schema_GetStructTypePropertyByName shall return a non-NULL handle corresponding to a property identified by the structTypeHandle and propertyName.] */
+ else
+ {
+ result = structType->Properties[i];
+ }
+ }
+
+ return result;
+}
+
+SCHEMA_RESULT Schema_GetStructTypePropertyCount(SCHEMA_STRUCT_TYPE_HANDLE structTypeHandle, size_t* propertyCount)
+{
+ SCHEMA_RESULT result;
+
+ /* Codes_SRS_SCHEMA_99_079: [Schema_GetStructTypePropertyCount shall return SCHEMA_INVALID_ARG if any of the structlTypeHandle or propertyCount arguments is NULL.] */
+ if ((structTypeHandle == NULL) ||
+ (propertyCount == NULL))
+ {
+ result = SCHEMA_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, result));
+ }
+ else
+ {
+ STRUCT_TYPE* structType = (STRUCT_TYPE*)structTypeHandle;
+
+ /* Codes_SRS_SCHEMA_99_077: [Schema_GetStructTypePropertyCount shall provide the total number of properties defined in a struct type identified by structTypeHandle. The value is provided via the out argument propertyCount.] */
+ /* Codes_SRS_SCHEMA_99_081: [The count shall be provided via the out argument propertyCount.] */
+ *propertyCount = structType->PropertyCount;
+
+ /* Codes_SRS_SCHEMA_99_078: [On success, Schema_ GetStructTypePropertyCount shall return SCHEMA_OK.] */
+ result = SCHEMA_OK;
+ }
+
+ return result;
+}
+
+SCHEMA_PROPERTY_HANDLE Schema_GetStructTypePropertyByIndex(SCHEMA_STRUCT_TYPE_HANDLE structTypeHandle, size_t index)
+{
+ SCHEMA_PROPERTY_HANDLE result;
+ STRUCT_TYPE* structType = (STRUCT_TYPE*)structTypeHandle;
+
+ /* Codes_SRS_SCHEMA_99_083: [Schema_ GetStructTypeProperty shall return NULL if the index specified is outside the valid range, if structTypeHandle argument is NULL] */
+ if ((structTypeHandle == NULL) ||
+ (index >= structType->PropertyCount))
+ {
+ result = NULL;
+ LogError("(Error code: %s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, SCHEMA_INVALID_ARG));
+ }
+ else
+ {
+ /* Codes_SRS_SCHEMA_99_082: [Schema_GetStructTypeProperty shall return a non-NULL SCHEMA_PROPERTY_HANDLE corresponding to the struct type identified by strutTypeHandle and matching the index number provided by the index argument.] */
+ /* Codes_SRS_SCHEMA_99_098: [index is zero based and the order in which actions were added shall be the index in which they will be retrieved.] */
+ result = structType->Properties[index];
+ }
+
+ return result;
+}
+
+const char* Schema_GetPropertyName(SCHEMA_PROPERTY_HANDLE propertyHandle)
+{
+ const char* result;
+
+ /* Codes_SRS_SCHEMA_99_086: [If propertyHandle is NULL, Schema_GetPropertyName shall return NULL.] */
+ if (propertyHandle == NULL)
+ {
+ result = NULL;
+ LogError("(Error code: %s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, SCHEMA_INVALID_ARG));
+ }
+ else
+ {
+ PROPERTY* propertyType = (PROPERTY*)propertyHandle;
+
+ /* Codes_SRS_SCHEMA_99_085: [Schema_GetPropertyName shall return the property name identified by the propertyHandle.] */
+ result = propertyType->PropertyName;
+ }
+
+ return result;
+}
+
+const char* Schema_GetPropertyType(SCHEMA_PROPERTY_HANDLE propertyHandle)
+{
+ const char* result;
+
+ /* Codes_SRS_SCHEMA_99_088: [If propertyHandle is NULL, Schema_GetPropertyType shall return NULL.] */
+ if (propertyHandle == NULL)
+ {
+ result = NULL;
+ LogError("(Error code: %s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, SCHEMA_INVALID_ARG));
+ }
+ else
+ {
+ PROPERTY* modelProperty = (PROPERTY*)propertyHandle;
+
+ /* Codes_SRS_SCHEMA_99_087: [Schema_GetPropertyType shall return the property type identified by the propertyHandle.] */
+ result = modelProperty->PropertyType;
+ }
+
+ return result;
+}
+
+SCHEMA_RESULT Schema_GetModelCount(SCHEMA_HANDLE schemaHandle, size_t* modelCount)
+{
+ SCHEMA_RESULT result;
+ /* Codes_SRS_SCHEMA_99_123: [Schema_GetModelCount shall return SCHEMA_INVALID_ARG if any of the arguments is NULL.] */
+ if ((schemaHandle == NULL) ||
+ (modelCount == NULL) )
+ {
+ result = SCHEMA_INVALID_ARG;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, result));
+ }
+ else
+ {
+ /* Codes_SRS_SCHEMA_99_120: [Schema_GetModelCount shall provide the number of models defined in the schema identified by schemaHandle.] */
+ SCHEMA* schema = (SCHEMA*)schemaHandle;
+ /* Codes_SRS_SCHEMA_99_121: [The count shall be provided via the out argument modelCount.] */
+ *modelCount = schema->ModelTypeCount;
+ /* Codes_SRS_SCHEMA_99_122: [On success, Schema_GetModelCount shall return SCHEMA_OK.] */
+ result = SCHEMA_OK;
+ }
+ return result;
+}
+
+SCHEMA_MODEL_TYPE_HANDLE Schema_GetModelByName(SCHEMA_HANDLE schemaHandle, const char* modelName)
+{
+ SCHEMA_MODEL_TYPE_HANDLE result;
+
+ /* Codes_SRS_SCHEMA_99_125: [Schema_GetModelByName shall return NULL if unable to find a matching model, or if any of the arguments are NULL.] */
+ if ((schemaHandle == NULL) ||
+ (modelName == NULL))
+ {
+ result = NULL;
+ LogError("(Error code: %s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, SCHEMA_INVALID_ARG));
+ }
+ else
+ {
+ /* Codes_SRS_SCHEMA_99_124: [Schema_GetModelByName shall return a non-NULL SCHEMA_MODEL_TYPE_HANDLE corresponding to the model identified by schemaHandle and matching the modelName argument value.] */
+ SCHEMA* schema = (SCHEMA*)schemaHandle;
+ size_t i;
+ for (i = 0; i < schema->ModelTypeCount; i++)
+ {
+ MODEL_TYPE* modelType = (MODEL_TYPE*)schema->ModelTypes[i];
+ if (strcmp(modelName, modelType->Name)==0)
+ {
+ break;
+ }
+ }
+ if (i == schema->ModelTypeCount)
+ {
+ /* Codes_SRS_SCHEMA_99_125: [Schema_GetModelByName shall return NULL if unable to find a matching model, or if any of the arguments are NULL.] */
+ result = NULL;
+ }
+ else
+ {
+ result = schema->ModelTypes[i];
+ }
+ }
+ return result;
+}
+
+SCHEMA_MODEL_TYPE_HANDLE Schema_GetModelByIndex(SCHEMA_HANDLE schemaHandle, size_t index)
+{
+ SCHEMA_MODEL_TYPE_HANDLE result;
+ SCHEMA* schema = (SCHEMA*)schemaHandle;
+
+ /* Codes_SRS_SCHEMA_99_128: [Schema_GetModelByIndex shall return NULL if the index specified is outside the valid range or if schemaHandle argument is NULL.] */
+ /* Codes_SRS_SCHEMA_99_127: [The index argument is zero based, and the order in which models were added shall be the index in which they will be retrieved.] */
+ if ((schemaHandle == NULL) ||
+ (index >= schema->ModelTypeCount))
+ {
+ result = NULL;
+ LogError("(Error code: %s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, SCHEMA_INVALID_ARG));
+ }
+ else
+ {
+
+ /* Codes_SRS_SCHEMA_99_126: [Schema_GetModelByIndex shall return a non-NULL SCHEMA_MODEL_TYPE_HANDLE corresponding to the model identified by schemaHandle and matching the index number provided by the index argument.] */
+ /* Codes_SRS_SCHEMA_99_127: [The index argument is zero based, and the order in which models were added shall be the index in which they will be retrieved.] */
+ result = schema->ModelTypes[index];
+ }
+ return result;
+}
+
+/*Codes_SRS_SCHEMA_99_160: [Schema_GetModelName shall return the name of the model identified by modelTypeHandle. If the name cannot be retrieved, then NULL shall be returned.]*/
+const char* Schema_GetModelName(SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle)
+{
+ const char* result;
+ if (modelTypeHandle == NULL)
+ {
+ result = NULL;
+ }
+ else
+ {
+ MODEL_TYPE* modelType = (MODEL_TYPE*)modelTypeHandle;
+ result = modelType->Name;
+ }
+ return result;
+}
+
+/*Codes_SRS_SCHEMA_99_163: [Schema_AddModelModel shall insert an existing model, identified by the handle modelType, into the existing model identified by modelTypeHandle under a property having the name propertyName.]*/
+SCHEMA_RESULT Schema_AddModelModel(SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle, const char* propertyName, SCHEMA_MODEL_TYPE_HANDLE modelType)
+{
+ SCHEMA_RESULT result;
+ /*Codes_SRS_SCHEMA_99_165: [If any of the parameters is NULL then Schema_AddModelModel shall return SCHEMA_INVALID_ARG.]*/
+ if (
+ (modelTypeHandle == NULL) ||
+ (propertyName == NULL) ||
+ (modelType == NULL)
+ )
+ {
+ result = SCHEMA_INVALID_ARG;
+ LogError("(Error code: %s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, SCHEMA_INVALID_ARG));
+ }
+ else
+ {
+ MODEL_TYPE* parentModel = (MODEL_TYPE*)modelTypeHandle;
+ MODEL_IN_MODEL temp;
+ temp.modelHandle = modelType;
+ if (mallocAndStrcpy_s((char**)&(temp.propertyName), propertyName) != 0)
+ {
+ result = SCHEMA_ERROR;
+ LogError("(Error code: %s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, result));
+ }
+ else if (VECTOR_push_back(parentModel->models, &temp, 1) != 0)
+ {
+ /*Codes_SRS_SCHEMA_99_174: [The function shall return SCHEMA_ERROR if any other error occurs.]*/
+ free((void*)temp.propertyName);
+ result = SCHEMA_ERROR;
+ LogError("(Error code: %s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, result));
+ }
+ else
+ {
+ /*Codes_SRS_SCHEMA_99_164: [If the function succeeds, then the return value shall be SCHEMA_OK.]*/
+ result = SCHEMA_OK;
+ }
+ }
+ return result;
+}
+
+
+SCHEMA_RESULT Schema_GetModelModelCount(SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle, size_t* modelCount)
+{
+ SCHEMA_RESULT result;
+ /*Codes_SRS_SCHEMA_99_169: [If any of the parameters is NULL, then the function shall return SCHEMA_INVALID_ARG.]*/
+ if (
+ (modelTypeHandle == NULL) ||
+ (modelCount == NULL)
+ )
+ {
+ result = SCHEMA_INVALID_ARG;
+ LogError("(Error code: %s)\r\n", ENUM_TO_STRING(SCHEMA_RESULT, result));
+ }
+ else
+ {
+ MODEL_TYPE* model = (MODEL_TYPE*)modelTypeHandle;
+ /*Codes_SRS_SCHEMA_99_167: [Schema_GetModelModelCount shall return in parameter modelCount the number of models inserted in the model identified by parameter modelTypeHandle.]*/
+ *modelCount = VECTOR_size(model->models);
+ /*SRS_SCHEMA_99_168: [If the function succeeds, it shall return SCHEMA_OK.]*/
+ result = SCHEMA_OK;
+ }
+ return result;
+}
+
+static bool matchModelName(const void* element, const void* value)
+{
+ MODEL_IN_MODEL* decodedElement = (MODEL_IN_MODEL*)element;
+ const char* name = (const char*)value;
+ return (strcmp(decodedElement->propertyName, name) == 0);
+}
+
+SCHEMA_MODEL_TYPE_HANDLE Schema_GetModelModelByName(SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle, const char* propertyName)
+{
+ SCHEMA_MODEL_TYPE_HANDLE result;
+ if (
+ (modelTypeHandle == NULL) ||
+ (propertyName == NULL)
+ )
+ {
+ /*Codes_SRS_SCHEMA_99_171: [If Schema_GetModelModelByName is unable to provide the handle it shall return NULL.]*/
+ result = NULL;
+ LogError("error SCHEMA_INVALID_ARG");
+ }
+ else
+ {
+ MODEL_TYPE* model = (MODEL_TYPE*)modelTypeHandle;
+ /*Codes_SRS_SCHEMA_99_170: [Schema_GetModelModelByName shall return a handle to the model identified by the property with the name propertyName in the model identified by the handle modelTypeHandle.]*/
+ /*Codes_SRS_SCHEMA_99_171: [If Schema_GetModelModelByName is unable to provide the handle it shall return NULL.]*/
+ void* temp = VECTOR_find_if(model->models, matchModelName, propertyName);
+ if (temp == NULL)
+ {
+ LogError("specified propertyName not found (%s)", propertyName);
+ result = NULL;
+ }
+ else
+ {
+ result = ((MODEL_IN_MODEL*)temp)->modelHandle;
+ }
+ }
+ return result;
+}
+
+SCHEMA_MODEL_TYPE_HANDLE Schema_GetModelModelyByIndex(SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle, size_t index)
+{
+ SCHEMA_MODEL_TYPE_HANDLE result;
+ if (
+ (modelTypeHandle == NULL)
+ )
+ {
+ /*Codes_SRS_SCHEMA_99_173: [Schema_GetModelModelyByIndex shall return NULL in the cases when it cannot provide the handle.]*/
+ result = NULL;
+ LogError("error SCHEMA_INVALID_ARG");
+ }
+ else
+ {
+ MODEL_TYPE* model = (MODEL_TYPE*)modelTypeHandle;
+ size_t nModelsInModel;
+ /*Codes_SRS_SCHEMA_99_172: [ Schema_GetModelModelyByIndex shall return a handle to the "index"th model inserted in the model identified by the parameter modelTypeHandle.]*/
+ /*Codes_SRS_SCHEMA_99_173: [Schema_GetModelModelyByIndex shall return NULL in the cases when it cannot provide the handle.]*/
+ nModelsInModel = VECTOR_size(model->models);
+ if (index < nModelsInModel)
+ {
+ result = ((MODEL_IN_MODEL*)VECTOR_element(model->models, index))->modelHandle;
+ }
+ else
+ {
+ LogError("attempted out of bounds access in array.");
+ result = NULL; /*out of bounds array access*/
+ }
+ }
+ return result;
+}
+
+const char* Schema_GetModelModelPropertyNameByIndex(SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle, size_t index)
+{
+ const char* result;
+ if (modelTypeHandle == NULL)
+ {
+ /*Codes_SRS_SCHEMA_99_176: [If Schema_GetModelModelPropertyNameByIndex cannot produce the property name, it shall return NULL.]*/
+ result = NULL;
+ }
+ else
+ {
+ MODEL_TYPE* model = (MODEL_TYPE*)modelTypeHandle;
+ size_t nModelsInModel;
+ /*Codes_SRS_SCHEMA_99_175: [Schema_GetModelModelPropertyNameByIndex shall return the name of the property for the "index"th model in the model identified by modelTypeHandle parameter.]*/
+ /*Codes_SRS_SCHEMA_99_176: [If Schema_GetModelModelPropertyNameByIndex cannot produce the property name, it shall return NULL.]*/
+ nModelsInModel = VECTOR_size(model->models);
+ if (index < nModelsInModel)
+ {
+ result = ((MODEL_IN_MODEL*)VECTOR_element(model->models, index))->propertyName;
+ }
+ else
+ {
+ LogError("attempted out of bounds access in array.");
+ result = NULL; /*out of bounds array access*/
+ }
+ }
+ return result;
+}
+
+bool Schema_ModelPropertyByPathExists(SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle, const char* propertyPath)
+{
+ bool result;
+
+ /* Codes_SRS_SCHEMA_99_180: [If any of the arguments are NULL, Schema_ModelPropertyByPathExists shall return false.] */
+ if ((modelTypeHandle == NULL) ||
+ (propertyPath == NULL))
+ {
+ LogError("error SCHEMA_INVALID_ARG");
+ result = false;
+ }
+ else
+ {
+ const char* slashPos;
+ result = false;
+
+ /* Codes_SRS_SCHEMA_99_182: [A single slash ('/') at the beginning of the path shall be ignored and the path shall still be valid.] */
+ if (*propertyPath == '/')
+ {
+ propertyPath++;
+ }
+
+ do
+ {
+ const char* endPos;
+ size_t i;
+ size_t modelCount;
+ MODEL_TYPE* modelType = (MODEL_TYPE*)modelTypeHandle;
+
+ /* Codes_SRS_SCHEMA_99_179: [The propertyPath shall be assumed to be in the format model1/model2/.../propertyName.] */
+ slashPos = strchr(propertyPath, '/');
+ endPos = slashPos;
+ if (endPos == NULL)
+ {
+ endPos = &propertyPath[strlen(propertyPath)];
+ }
+
+ /* get the child-model */
+ modelCount = VECTOR_size(modelType->models);
+ for (i = 0; i < modelCount; i++)
+ {
+ MODEL_IN_MODEL* childModel = (MODEL_IN_MODEL*)VECTOR_element(modelType->models, i);
+ if ((strncmp(childModel->propertyName, propertyPath, endPos - propertyPath) == 0) &&
+ (strlen(childModel->propertyName) == (size_t)(endPos - propertyPath)))
+ {
+ /* found */
+ modelTypeHandle = childModel->modelHandle;
+ break;
+ }
+ }
+
+ if (i < modelCount)
+ {
+ /* model found, check if there is more in the path */
+ if (slashPos == NULL)
+ {
+ /* this is the last one, so this is the thing we were looking for */
+ result = true;
+ break;
+ }
+ else
+ {
+ /* continue looking, there's more */
+ propertyPath = slashPos + 1;
+ }
+ }
+ else
+ {
+ /* no model found, let's see if this is a property */
+ /* Codes_SRS_SCHEMA_99_178: [The argument propertyPath shall be used to find the leaf property.] */
+ for (i = 0; i < modelType->PropertyCount; i++)
+ {
+ PROPERTY* property = (PROPERTY*)modelType->Properties[i];
+ if ((strncmp(property->PropertyName, propertyPath, endPos - propertyPath) == 0) &&
+ (strlen(property->PropertyName) == (size_t)(endPos - propertyPath)))
+ {
+ /* found property */
+ /* Codes_SRS_SCHEMA_99_177: [Schema_ModelPropertyByPathExists shall return true if a leaf property exists in the model modelTypeHandle.] */
+ result = true;
+ break;
+ }
+ }
+
+ break;
+ }
+ } while (slashPos != NULL);
+ }
+
+ return result;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/schema.h Thu Oct 22 18:33:28 2015 -0700
@@ -0,0 +1,103 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+#ifndef SCHEMA_H
+#define SCHEMA_H
+
+#include "macro_utils.h"
+#include "crt_abstractions.h"
+
+#ifdef __cplusplus
+#include <cstddef>
+extern "C" {
+#else
+#include <stddef.h>
+#endif
+
+/* Codes_SRS_SCHEMA_99_095: [Schema shall expose the following API:] */
+
+typedef void* SCHEMA_HANDLE;
+typedef void* SCHEMA_MODEL_TYPE_HANDLE;
+typedef void* SCHEMA_STRUCT_TYPE_HANDLE;
+typedef void* SCHEMA_PROPERTY_HANDLE;
+typedef void* SCHEMA_ACTION_HANDLE;
+typedef void* SCHEMA_ACTION_ARGUMENT_HANDLE;
+
+#define SCHEMA_RESULT_VALUES \
+SCHEMA_OK, \
+SCHEMA_INVALID_ARG, \
+SCHEMA_DUPLICATE_ELEMENT, \
+SCHEMA_ELEMENT_NOT_FOUND, \
+SCHEMA_MODEL_IN_USE, \
+SCHEMA_DEVICE_COUNT_ZERO, \
+SCHEMA_ERROR
+
+DEFINE_ENUM(SCHEMA_RESULT, SCHEMA_RESULT_VALUES)
+
+extern SCHEMA_HANDLE Schema_Create(const char* schemaNamespace);
+extern size_t Schema_GetSchemaCount(void);
+extern SCHEMA_HANDLE Schema_GetSchemaByNamespace(const char* schemaNamespace);
+extern const char* Schema_GetSchemaNamespace(SCHEMA_HANDLE schemaHandle);
+extern SCHEMA_RESULT Schema_AddDeviceRef(SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle);
+extern SCHEMA_RESULT Schema_ReleaseDeviceRef(SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle);
+
+extern SCHEMA_MODEL_TYPE_HANDLE Schema_CreateModelType(SCHEMA_HANDLE schemaHandle, const char* modelName);
+extern SCHEMA_HANDLE Schema_GetSchemaForModelType(SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle);
+extern const char* Schema_GetModelName(SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle);
+
+extern SCHEMA_STRUCT_TYPE_HANDLE Schema_CreateStructType(SCHEMA_HANDLE schemaHandle, const char* structTypeName);
+
+extern const char* Schema_GetStructTypeName(SCHEMA_STRUCT_TYPE_HANDLE structTypeHandle);
+
+extern SCHEMA_RESULT Schema_AddStructTypeProperty(SCHEMA_STRUCT_TYPE_HANDLE structTypeHandle, const char* propertyName, const char* propertyType);
+
+extern SCHEMA_RESULT Schema_AddModelProperty(SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle, const char* propertyName, const char* propertyType);
+extern SCHEMA_RESULT Schema_AddModelModel(SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle, const char* propertyName, SCHEMA_MODEL_TYPE_HANDLE modelType);
+extern SCHEMA_ACTION_HANDLE Schema_CreateModelAction(SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle, const char* actionName);
+extern SCHEMA_RESULT Schema_AddModelActionArgument(SCHEMA_ACTION_HANDLE actionHandle, const char* argumentName, const char* argumentType);
+
+extern SCHEMA_RESULT Schema_GetModelCount(SCHEMA_HANDLE schemaHandle, size_t* modelCount);
+extern SCHEMA_MODEL_TYPE_HANDLE Schema_GetModelByName(SCHEMA_HANDLE schemaHandle, const char* modelName);
+extern SCHEMA_MODEL_TYPE_HANDLE Schema_GetModelByIndex(SCHEMA_HANDLE schemaHandle, size_t index);
+
+extern SCHEMA_RESULT Schema_GetModelPropertyCount(SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle, size_t* propertyCount);
+extern SCHEMA_PROPERTY_HANDLE Schema_GetModelPropertyByName(SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle, const char* propertyName);
+extern SCHEMA_PROPERTY_HANDLE Schema_GetModelPropertyByIndex(SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle, size_t index);
+
+extern SCHEMA_RESULT Schema_GetModelModelCount(SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle, size_t* modelCount);
+extern SCHEMA_MODEL_TYPE_HANDLE Schema_GetModelModelByName(SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle, const char* propertyName);
+extern SCHEMA_MODEL_TYPE_HANDLE Schema_GetModelModelyByIndex(SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle, size_t index);
+extern const char* Schema_GetModelModelPropertyNameByIndex(SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle, size_t index);
+
+extern bool Schema_ModelPropertyByPathExists(SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle, const char* propertyPath);
+
+extern SCHEMA_RESULT Schema_GetModelActionCount(SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle, size_t* actionCount);
+extern SCHEMA_ACTION_HANDLE Schema_GetModelActionByName(SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle, const char* actionName);
+extern SCHEMA_ACTION_HANDLE Schema_GetModelActionByIndex(SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle, size_t index);
+
+extern SCHEMA_RESULT Schema_GetModelActionArgumentCount(SCHEMA_ACTION_HANDLE actionHandle, size_t* argumentCount);
+extern const char* Schema_GetModelActionName(SCHEMA_ACTION_HANDLE actionHandle);
+
+extern SCHEMA_ACTION_ARGUMENT_HANDLE Schema_GetModelActionArgumentByName(SCHEMA_ACTION_HANDLE actionHandle, const char* actionArgumentName);
+extern SCHEMA_ACTION_ARGUMENT_HANDLE Schema_GetModelActionArgumentByIndex(SCHEMA_ACTION_HANDLE actionHandle, size_t argumentIndex);
+extern const char* Schema_GetActionArgumentName(SCHEMA_ACTION_ARGUMENT_HANDLE actionArgumentHandle);
+extern const char* Schema_GetActionArgumentType(SCHEMA_ACTION_ARGUMENT_HANDLE actionArgumentHandle);
+
+extern SCHEMA_RESULT Schema_GetStructTypeCount(SCHEMA_HANDLE schemaHandle, size_t* structTypeCount);
+extern SCHEMA_STRUCT_TYPE_HANDLE Schema_GetStructTypeByName(SCHEMA_HANDLE schemaHandle, const char* structTypeName);
+extern SCHEMA_STRUCT_TYPE_HANDLE Schema_GetStructTypeByIndex(SCHEMA_HANDLE schemaHandle, size_t index);
+
+extern SCHEMA_RESULT Schema_GetStructTypePropertyCount(SCHEMA_STRUCT_TYPE_HANDLE structTypeHandle, size_t* propertyCount);
+extern SCHEMA_PROPERTY_HANDLE Schema_GetStructTypePropertyByName(SCHEMA_STRUCT_TYPE_HANDLE structTypeHandle, const char* propertyName);
+extern SCHEMA_PROPERTY_HANDLE Schema_GetStructTypePropertyByIndex(SCHEMA_STRUCT_TYPE_HANDLE structTypeHandle, size_t index);
+extern const char* Schema_GetPropertyName(SCHEMA_PROPERTY_HANDLE propertyHandle);
+extern const char* Schema_GetPropertyType(SCHEMA_PROPERTY_HANDLE propertyHandle);
+
+extern void Schema_Destroy(SCHEMA_HANDLE schemaHandle);
+extern SCHEMA_RESULT Schema_DestroyIfUnused(SCHEMA_MODEL_TYPE_HANDLE modelHandle);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SCHEMA_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/schemalib.c Thu Oct 22 18:33:28 2015 -0700
@@ -0,0 +1,98 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+#include <stdlib.h>
+#ifdef _CRTDBG_MAP_ALLOC
+#include <crtdbg.h>
+#endif
+#include "gballoc.h"
+
+#include "schemalib.h"
+#include "codefirst.h"
+#include "schema.h"
+#include "datamarshaller.h"
+#include "datapublisher.h"
+#include <stddef.h>
+#include "iot_logging.h"
+#include "iotdevice.h"
+
+#define DEFAULT_CONTAINER_NAME "Container"
+
+DEFINE_ENUM_STRINGS(SERIALIZER_RESULT, SERIALIZER_RESULT_VALUES);
+
+typedef enum AGENT_STATE_TAG
+{
+ AGENT_NOT_INITIALIZED,
+ AGENT_INITIALIZED
+} AGENT_STATE;
+
+static AGENT_STATE g_AgentState = AGENT_NOT_INITIALIZED;
+
+SERIALIZER_RESULT serializer_init(const char* overrideSchemaNamespace)
+{
+ SERIALIZER_RESULT result;
+
+ /* Codes_SRS_SCHEMALIB_99_074:[serializer_init when already initialized shall return SERIALIZER_ALREADY_INIT.] */
+ if (g_AgentState != AGENT_NOT_INITIALIZED)
+ {
+ result = SERIALIZER_ALREADY_INIT;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(SERIALIZER_RESULT, result));
+ }
+ else
+ {
+ /* Codes_SRS_SCHEMALIB_99_006:[ Initialize CodeFirst by a call to CodeFirst_Init.] */
+ /* Codes_SRS_SCHEMALIB_99_076:[serializer_init shall pass the value of overrideSchemaNamespace argument to CodeFirst_Init.] */
+ if (CodeFirst_Init(overrideSchemaNamespace) != CODEFIRST_OK)
+ {
+ /* Codes_SRS_SCHEMALIB_99_007:[ On error SERIALIZER_CODEFIRST_INIT_FAILED shall be returned.] */
+ result = SERIALIZER_CODEFIRST_INIT_FAILED;
+ LogError("(result = %s)\r\n", ENUM_TO_STRING(SERIALIZER_RESULT, result));
+ }
+ else
+ {
+ /* Codes_SRS_SCHEMALIB_99_075:[When an serializer_init call fails for any reason the previous initialization state shall be preserved. The initialized state shall only be changed on a succesfull Init.] */
+ g_AgentState = AGENT_INITIALIZED;
+
+ /* Codes_SRS_SCHEMALIB_99_073:[On success serializer_init shall return SERIALIZER_OK.] */
+ result = SERIALIZER_OK;
+ }
+ }
+
+ return result;
+}
+
+void serializer_deinit(void)
+{
+ /* Codes_SRS_SCHEMALIB_99_025:[ serializer_deinit shall de-initialize all modules initialized by serializer_init.] */
+ if (g_AgentState == AGENT_INITIALIZED)
+ {
+ CodeFirst_Deinit();
+ }
+
+ /* Codes_SRS_SCHEMALIB_99_026:[ A subsequent call to serializer_start shall succeed.] */
+ g_AgentState = AGENT_NOT_INITIALIZED;
+}
+
+SERIALIZER_RESULT serializer_setconfig(SERIALIZER_CONFIG which, void* value)
+{
+ SERIALIZER_RESULT result;
+
+ /* Codes_SRS_SCHEMALIB_99_137:[ If the value argument is NULL, serializer_setconfig shall return SERIALIZER_INVALID_ARG.] */
+ if (value == NULL)
+ {
+ result = SERIALIZER_INVALID_ARG;
+ }
+ /* Codes_SRS_SCHEMALIB_99_142:[ When the which argument is SerializeDelayedBufferMaxSize, serializer_setconfig shall invoke DataPublisher_SetMaxBufferSize with the dereferenced value argument, and shall return SERIALIZER_OK.] */
+ else if (which == SerializeDelayedBufferMaxSize)
+ {
+ DataPublisher_SetMaxBufferSize(*(size_t*)value);
+ result = SERIALIZER_OK;
+ }
+ /* Codes_SRS_SCHEMALIB_99_138:[ If the which argument is not one of the declared members of the SERIALIZER_CONFIG enum, serializer_setconfig shall return SERIALIZER_INVALID_ARG.] */
+ else
+ {
+ result = SERIALIZER_INVALID_ARG;
+ }
+
+ return result;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/schemalib.h Thu Oct 22 18:33:28 2015 -0700
@@ -0,0 +1,84 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+/** @file schemalib.h
+ * @brief The IoT Hub Serializer APIs allows developers to define models for
+* their devices
+ */
+
+#ifndef SCHEMALIB_H
+#define SCHEMALIB_H
+
+#include "macro_utils.h"
+#include "strings.h"
+#include "iotdevice.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Codes_SRS_SCHEMALIB__99_001:[ IoTHubSchema_Client shall expose the following API: ... ] */
+#define SERIALIZER_RESULT_VALUES \
+ SERIALIZER_OK, \
+ SERIALIZER_INVALID_ARG, \
+ SERIALIZER_CODEFIRST_INIT_FAILED, \
+ SERIALIZER_SCHEMA_FAILED, \
+ SERIALIZER_HTTP_API_INIT_FAILED, \
+ SERIALIZER_ALREADY_INIT, \
+ SERIALIZER_ERROR, \
+ SERIALIZER_NOT_INITIALIZED, \
+ SERIALIZER_ALREADY_STARTED, \
+ SERIALIZER_DEVICE_CREATE_FAILED, \
+ SERIALIZER_GET_MODEL_HANDLE_FAILED, \
+ SERIALIZER_SERVICEBUS_FAILED
+
+/** @brief Enumeration specifying the status of calls to various APIs in this
+ * module.
+ */
+DEFINE_ENUM(SERIALIZER_RESULT, SERIALIZER_RESULT_VALUES);
+
+#define SERIALIZER_CONFIG_VALUES \
+ CommandPollingInterval, \
+ SerializeDelayedBufferMaxSize
+
+/** @brief Enumeration specifying the option to set on the serializer when
+ * calling ::serializer_setconfig.
+ */
+DEFINE_ENUM(SERIALIZER_CONFIG, SERIALIZER_CONFIG_VALUES);
+
+/**
+ * @brief Initializes the library.
+ *
+ * @param overrideSchemaNamespace An override schema namespace to use for all
+ * models. Optional, can be @c NULL.
+ *
+ * If @p schemaNamespace is not @c NULL, its value shall be used
+ * instead of the namespace defined for each model by using the
+ * @c DECLARE_XXX macro.
+ *
+ * @return @c SERIALIZER_OK on success and any other error on failure.
+ */
+extern SERIALIZER_RESULT serializer_init(const char* overrideSchemaNamespace);
+
+/** @brief Shuts down the IOT library.
+ *
+ * The library will track all created devices and upon a call to
+ * ::serializer_deinit it will de-initialize all devices.
+ */
+extern void serializer_deinit(void);
+
+/**
+ * @brief Set serializer options.
+ *
+ * @param which The option to be set.
+ * @param value The value to set for the given option.
+ *
+ * @return @c SERIALIZER_OK on success and any other error on failure.
+ */
+extern SERIALIZER_RESULT serializer_setconfig(SERIALIZER_CONFIG which, void* value);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SCHEMALIB_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/schemaserializer.c Thu Oct 22 18:33:28 2015 -0700
@@ -0,0 +1,177 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+#include <stdlib.h>
+#ifdef _CRTDBG_MAP_ALLOC
+#include <crtdbg.h>
+#endif
+#include "gballoc.h"
+
+#include <stddef.h>
+#include "schemaserializer.h"
+#include "iot_logging.h"
+#include "macro_utils.h"
+
+DEFINE_ENUM_STRINGS(SCHEMA_SERIALIZER_RESULT, SCHEMA_SERIALIZER_RESULT_VALUES);
+
+#define LOG_SCHEMA_SERIALIZER_ERROR(result) LogError("(result = %s)\r\n", ENUM_TO_STRING(SCHEMA_SERIALIZER_RESULT, (result)))
+
+static const char* ConvertType(const char* sourceType)
+{
+ /* Codes_SRS_SCHEMA_SERIALIZER_01_016: ["ascii_char_ptr" shall be translated to "string".] */
+ if (strcmp(sourceType, "ascii_char_ptr") == 0)
+ {
+ return "string";
+ }
+ else
+ {
+ /* Codes_SRS_SCHEMA_SERIALIZER_01_017: [All other types shall be kept as they are.] */
+ return sourceType;
+ }
+}
+
+/* Codes_SRS_SCHEMA_SERIALIZER_01_001: [SchemaSerializer_SerializeCommandMetadata shall serialize a specific model to a string using JSON as format.] */
+SCHEMA_SERIALIZER_RESULT SchemaSerializer_SerializeCommandMetadata(SCHEMA_MODEL_TYPE_HANDLE modelHandle, STRING_HANDLE schemaText)
+{
+ SCHEMA_SERIALIZER_RESULT result;
+
+ /* Codes_SRS_SCHEMA_SERIALIZER_01_013: [If the modelHandle argument is NULL, SchemaSerializer_SerializeCommandMetadata shall return SCHEMA_SERIALIZER_INVALID_ARG.] */
+ if ((modelHandle == NULL) ||
+ /* Codes_SRS_SCHEMA_SERIALIZER_01_014: [If the schemaText argument is NULL, SchemaSerializer_SerializeCommandMetadata shall return SCHEMA_SERIALIZER_INVALID_ARG.] */
+ (schemaText == NULL))
+ {
+ result = SCHEMA_SERIALIZER_INVALID_ARG;
+ LogError("(result = %s), modelHandle = %p, schemaText = %p\r\n", ENUM_TO_STRING(SCHEMA_SERIALIZER_RESULT, result), modelHandle, schemaText);
+ }
+ else
+ {
+ size_t commandCount;
+
+ /* Codes_SRS_SCHEMA_SERIALIZER_01_002: [Only commands shall be serialized, the properties of a model shall be ignored.] */
+
+ /* Codes_SRS_SCHEMA_SERIALIZER_01_003: [The output JSON shall have an array, where each array element shall represent a command.] */
+ /* Codes_SRS_SCHEMA_SERIALIZER_01_011: [The JSON text shall be built into the string indicated by the schemaText argument by using String APIs.] */
+ if ((STRING_concat(schemaText, "[") != 0) ||
+ /* Codes_SRS_SCHEMA_SERIALIZER_01_006: [The object for a command shall have a member named Name, whose value shall be the command name as obtained by using Schema APIs.] */
+ (Schema_GetModelActionCount(modelHandle, &commandCount) != SCHEMA_OK))
+ {
+ /* Codes_SRS_SCHEMA_SERIALIZER_01_015: [If any of the Schema or String APIs fail then SchemaSerializer_SerializeCommandMetadata shall return SCHEMA_SERIALIZER_ERROR.] */
+ result = SCHEMA_SERIALIZER_ERROR;
+ LOG_SCHEMA_SERIALIZER_ERROR(result);
+ }
+ else
+ {
+ size_t i;
+
+ for (i = 0; i < commandCount; i++)
+ {
+ SCHEMA_ACTION_HANDLE actionHandle = Schema_GetModelActionByIndex(modelHandle, i);
+ const char* commandName;
+ size_t argCount;
+ size_t j;
+
+ /* Codes_SRS_SCHEMA_SERIALIZER_01_005: [Each array element shall be a JSON object.] */
+ if ((actionHandle == NULL) ||
+ (STRING_concat(schemaText, "{ \"Name\":\"") != 0) ||
+ ((commandName = Schema_GetModelActionName(actionHandle)) == NULL) ||
+ (STRING_concat(schemaText, commandName) != 0) ||
+ /* Codes_SRS_SCHEMA_SERIALIZER_01_007: [The object for a command shall also have a "Parameters" member.] */
+ (STRING_concat(schemaText, "\", \"Parameters\":[") != 0) ||
+ (Schema_GetModelActionArgumentCount(actionHandle, &argCount) != SCHEMA_OK))
+ {
+ /* Codes_SRS_SCHEMA_SERIALIZER_01_015: [If any of the Schema or String APIs fail then SchemaSerializer_SerializeCommandMetadata shall return SCHEMA_SERIALIZER_ERROR.] */
+ LogError("Failed encoding action.\r\n");
+ break;
+ }
+ else
+ {
+ for (j = 0; j < argCount; j++)
+ {
+ /* Codes_SRS_SCHEMA_SERIALIZER_01_008: [The parameters member shall be an array, where each entry is a command parameter.] */
+ SCHEMA_ACTION_ARGUMENT_HANDLE argHandle = Schema_GetModelActionArgumentByIndex(actionHandle, j);
+ const char* argName;
+ const char* argType;
+
+ /* Codes_SRS_SCHEMA_SERIALIZER_01_009: [Each command parameter shall have a member named "Name", that should have as value the command argument name as obtained by using Schema APIs.] */
+ if ((argHandle == NULL) ||
+ (STRING_concat(schemaText, "{\"Name\":\"") != 0) ||
+ ((argName = Schema_GetActionArgumentName(argHandle)) == NULL) ||
+ (STRING_concat(schemaText, argName) != 0) ||
+ /* Codes_SRS_SCHEMA_SERIALIZER_01_010: [Each command parameter shall have a member named "Type", that should have as value the command argument type as obtained by using Schema APIs.] */
+ (STRING_concat(schemaText, "\",\"Type\":\"") != 0) ||
+ ((argType = Schema_GetActionArgumentType(argHandle)) == NULL) ||
+ (STRING_concat(schemaText, ConvertType(argType)) != 0))
+ {
+ /* Codes_SRS_SCHEMA_SERIALIZER_01_015: [If any of the Schema or String APIs fail then SchemaSerializer_SerializeCommandMetadata shall return SCHEMA_SERIALIZER_ERROR.] */
+ LogError("Failed encoding argument.\r\n");
+ break;
+ }
+ else
+ {
+ if (j + 1 < argCount)
+ {
+ if (STRING_concat(schemaText, "\"},") != 0)
+ {
+ /* Codes_SRS_SCHEMA_SERIALIZER_01_015: [If any of the Schema or String APIs fail then SchemaSerializer_SerializeCommandMetadata shall return SCHEMA_SERIALIZER_ERROR.] */
+ LogError("Failed to concatenate arg end.\r\n");
+ break;
+ }
+ }
+ else
+ {
+ if (STRING_concat(schemaText, "\"}") != 0)
+ {
+ /* Codes_SRS_SCHEMA_SERIALIZER_01_015: [If any of the Schema or String APIs fail then SchemaSerializer_SerializeCommandMetadata shall return SCHEMA_SERIALIZER_ERROR.] */
+ LogError("Failed to concatenate arg end.\r\n");
+ break;
+ }
+ }
+ }
+ }
+
+ if (j < argCount)
+ {
+ break;
+ }
+
+ if (i + 1 < commandCount)
+ {
+ if (STRING_concat(schemaText, "]},") != 0)
+ {
+ /* Codes_SRS_SCHEMA_SERIALIZER_01_015: [If any of the Schema or String APIs fail then SchemaSerializer_SerializeCommandMetadata shall return SCHEMA_SERIALIZER_ERROR.] */
+ LogError("Failed to concatenate.\r\n");
+ break;
+ }
+ }
+ else
+ {
+ if (STRING_concat(schemaText, "]}") != 0)
+ {
+ /* Codes_SRS_SCHEMA_SERIALIZER_01_015: [If any of the Schema or String APIs fail then SchemaSerializer_SerializeCommandMetadata shall return SCHEMA_SERIALIZER_ERROR.] */
+ LogError("Failed to concatenate.\r\n");
+ break;
+ }
+ }
+ }
+ }
+
+ if (i < commandCount)
+ {
+ result = SCHEMA_SERIALIZER_ERROR;
+ }
+ else if (STRING_concat(schemaText, "]") != 0)
+ {
+ /* Codes_SRS_SCHEMA_SERIALIZER_01_015: [If any of the Schema or String APIs fail then SchemaSerializer_SerializeCommandMetadata shall return SCHEMA_SERIALIZER_ERROR.] */
+ LogError("Failed to concatenate commands object end.\r\n");
+ result = SCHEMA_SERIALIZER_ERROR;
+ }
+ else
+ {
+ /* Codes_SRS_SCHEMA_SERIALIZER_01_012: [On success SchemaSerializer_SerializeCommandMetadata shall return SCHEMA_SERIALIZER_OK.] */
+ result = SCHEMA_SERIALIZER_OK;
+ }
+ }
+ }
+
+ return result;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/schemaserializer.h Thu Oct 22 18:33:28 2015 -0700
@@ -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 SCHEMASERIALIZER_H
+#define SCHEMASERIALIZER_H
+
+#include "schema.h"
+#include "strings.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SCHEMA_SERIALIZER_RESULT_VALUES \
+ SCHEMA_SERIALIZER_OK, \
+ SCHEMA_SERIALIZER_INVALID_ARG, \
+ SCHEMA_SERIALIZER_ERROR
+
+DEFINE_ENUM(SCHEMA_SERIALIZER_RESULT, SCHEMA_SERIALIZER_RESULT_VALUES)
+
+extern SCHEMA_SERIALIZER_RESULT SchemaSerializer_SerializeCommandMetadata(SCHEMA_MODEL_TYPE_HANDLE modelHandle, STRING_HANDLE schemaText);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SCHEMASERIALIZER_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/serializer.h Thu Oct 22 18:33:28 2015 -0700
@@ -0,0 +1,1111 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+/** @file serializer.h
+* @brief The IoT Hub Serializer APIs allows developers to define models for
+* their devices
+*
+* @details The IoT Hub Serializer APIs allows developers to quickly and easily define
+* models for their devices directly as code, while supporting the required
+* features for modeling devices (including multiple models and multiple
+* devices within the same application). For example:
+*
+* <pre>
+* BEGIN_NAMESPACE(Contoso);
+*
+* DECLARE_STRUCT(SystemProperties,
+* ascii_char_ptr, DeviceID,
+* _Bool, Enabled
+* );
+*
+* DECLARE_MODEL(VendingMachine,
+*
+* WITH_DATA(int, SensorValue),
+*
+* WITH_DATA(ascii_char_ptr, ObjectName),
+* WITH_DATA(ascii_char_ptr, ObjectType),
+* WITH_DATA(ascii_char_ptr, Version),
+* WITH_DATA(SystemProperties, SystemProperties),
+* WITH_DATA(ascii_char_ptr_no_quotes, Commands),
+*
+* WITH_ACTION(SetItemPrice, ascii_char_ptr, itemId, ascii_char_ptr, price)
+* );
+*
+* END_NAMESPACE(Contoso);
+* </pre>
+*/
+
+#ifndef SERIALIZER_H
+#define SERIALIZER_H
+
+#ifdef __cplusplus
+#include <cstdlib>
+#include <cstdarg>
+
+#else
+#include <stdlib.h>
+#include <stdarg.h>
+#endif
+
+#ifdef _CRTDBG_MAP_ALLOC
+#include <crtdbg.h>
+#endif
+
+#include "gballoc.h"
+#include "macro_utils.h"
+#include "iotdevice.h"
+#include "crt_abstractions.h"
+#include "iot_logging.h"
+#include "schemalib.h"
+#include "codefirst.h"
+#include "agenttypesystem.h"
+#include "schema.h"
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#define IOT_AGENT_RESULT_ENUM_VALUES \
+ IOT_AGENT_OK, \
+ IOT_AGENT_AGENT_DATA_TYPES_ERROR, \
+ IOT_AGENT_COMMAND_EXECUTION_ERROR, \
+ IOT_AGENT_ERROR, \
+ IOT_AGENT_SERIALIZE_FAILED, \
+ IOT_AGENT_INVALID_ARG
+
+DEFINE_ENUM(IOT_AGENT_RESULT, IOT_AGENT_RESULT_ENUM_VALUES);
+
+
+/* IOT Agent Macros */
+
+/**
+ * @def BEGIN_NAMESPACE(schemaNamespace)
+ * This macro marks the start of a section that declares IOT model
+ * elements (like complex types, etc.). Declarations are typically
+ * placed in header files, so that they can be shared between
+ * translation units.
+ */
+/* Codes_SRS_SERIALIZER_99_001:[For each completed schema declaration block, a unique storage container for schema metadata shall be available in the translation unit at runtime.] */
+#define BEGIN_NAMESPACE(schemaNamespace) \
+ REFLECTED_END_OF_LIST
+
+/**
+* @def END_NAMESPACE(schemaNamespace)
+* This macro marks the end of a section that declares IOT model
+* elements.
+*/
+#define END_NAMESPACE(schemaNamespace) \
+ REFLECTED_LIST_HEAD(schemaNamespace)
+
+/**
+* @def DECLARE_STRUCT(name, ...)
+* This macro allows the definition of a struct type that can then be used as
+* part of a model definition.
+*
+* @param name Name of the struct
+* @param element1, element2... Specifies a list of struct members
+*/
+/* Codes_SRS_SERIALIZER_99_080:[ The DECLARE_STRUCT declaration shall insert metadata describing a complex data type.] */
+#define DECLARE_STRUCT(name, ...) \
+ /* Codes_SRS_SERIALIZER_99_096:[ DECLARE_STRUCT shall declare a matching C struct data type named name, which can be referenced from any code that can access the declaration.] */ \
+ typedef struct name##_TAG { \
+ FOR_EACH_2(INSERT_FIELD_INTO_STRUCT, __VA_ARGS__) \
+ } name; \
+ /* Codes_SRS_SERIALIZER_99_081:[ DECLARE_STRUCT's name argument shall uniquely identify the struct within the schema.] */ \
+ REFLECTED_STRUCT(name) \
+ /* Codes_SRS_SERIALIZER_99_082:[ DECLARE_STRUCT's field<n>Name argument shall uniquely name a field within the struct.] */ \
+ FOR_EACH_2_KEEP_1(REFLECTED_FIELD, name, __VA_ARGS__) \
+ TO_AGENT_DATA_TYPE(name, __VA_ARGS__) \
+ /*Codes_SRS_SERIALIZER_99_042:[ The parameter types are either predefined parameter types (specs SRS_SERIALIZER_99_004-SRS_SERIALIZER_99_014) or a type introduced by DECLARE_STRUCT.]*/ \
+ static AGENT_DATA_TYPES_RESULT FromAGENT_DATA_TYPE_##name(const AGENT_DATA_TYPE* source, name* destination) \
+ { \
+ AGENT_DATA_TYPES_RESULT result; \
+ if(source->type != EDM_COMPLEX_TYPE_TYPE) \
+ { \
+ result = AGENT_DATA_TYPES_INVALID_ARG; \
+ } \
+ else if(DIV2(COUNT_ARG(__VA_ARGS__)) != source->value.edmComplexType.nMembers) \
+ { \
+ /*too many or too few fields*/ \
+ result = AGENT_DATA_TYPES_INVALID_ARG; \
+ } \
+ else \
+ { \
+ result = AGENT_DATA_TYPES_OK; \
+ FOR_EACH_2(BUILD_DESTINATION_FIELD, __VA_ARGS__); \
+ } \
+ return result; \
+ } \
+ static void C2(destroyLocalParameter, name)(name * value) \
+ { \
+ FOR_EACH_2_KEEP_1(UNBUILD_DESTINATION_FIELD, value, __VA_ARGS__); \
+ }
+
+/**
+ * @def DECLARE_MODEL(name, ...)
+ * This macro allows declaring a model that can be later used to instantiate
+ * a device.
+ *
+ * @param name Specifies the model name
+ * @param element1, element2... Specifies a model element which can be
+ * a property or an action.
+ * - A property is described in a
+ * model by using the WITH_DATA
+ * - An action is described in a
+ * model by using the ::WITH_ACTION
+ * macro.
+ *
+ */
+/* WITH_DATA's name argument shall be one of the following data types: */
+/* Codes_SRS_SERIALIZER_99_133:[a model type introduced previously by DECLARE_MODEL] */
+#define DECLARE_MODEL(name, ...) \
+ REFLECTED_MODEL(name) \
+ typedef struct name { int :1; FOR_EACH_1(BUILD_MODEL_STRUCT, __VA_ARGS__) } name; \
+ FOR_EACH_1_KEEP_1(CREATE_MODEL_ELEMENT, name, __VA_ARGS__) \
+ TO_AGENT_DATA_TYPE(name, DROP_FIRST_COMMA_FROM_ARGS(EXPAND_MODEL_ARGS(__VA_ARGS__)))
+
+/**
+ * @def WITH_DATA(type, name)
+ * The ::WITH_DATA macro allows declaring a model property in a model. A
+ * property can be published by using the ::SERIALIZE macro.
+ *
+ * @param type Specifies the property type. Can be any of the following
+ * types:
+ * - int
+ * - double
+ * - float
+ * - long
+ * - int8_t
+ * - uint8_t
+ * - int16_t
+ * - int32_t
+ * - int64_t
+ * - bool
+ * - ascii_char_ptr
+ * - EDM_DATE_TIME_OFFSET
+ * - EDM_GUID
+ * - EDM_BINARY
+ * - Any struct type previously introduced by another ::DECLARE_STRUCT.
+ *
+ * @param name Specifies the property name
+ */
+#define WITH_DATA(type, name) MODEL_PROPERTY(type, name)
+
+/**
+ * @def WITH_ACTION(name, ...)
+ * The ::WITH_ACTION macro allows declaring a model action.
+ *
+ * @param name Specifies the action name.
+ * @param argXtype, argXName... Defines the type and name for the X<sup>th</sup>
+ * argument of the action. The type can be any of
+ * the primitive types or a struct type.
+ */
+/*Codes_SRS_SERIALIZER_99_039:[WITH_ACTION shall declare an action of the current data provider called as the first macro parameter(name) and having the first parameter called parameter1Name of type parameter1Type, the second parameter named parameter2Name having the type parameter2Type and so on.]*/
+#define WITH_ACTION(name, ...) MODEL_ACTION(name, __VA_ARGS__)
+
+/**
+ * @def GET_MODEL_HANDLE(schemaNamespace, modelName)
+ * The ::GET_MODEL_HANDLE macro returns a model handle that can be used in
+ * subsequent operations like generating the CSDL schema for the model,
+ * uploading the schema, creating a device, etc.
+ *
+ * @param schemaNamespace The namespace to which the model belongs.
+ * @param modelName The name of the model.
+ */
+/* Codes_SRS_SERIALIZER_99_110:[ The GET_MODEL_HANDLE function macro shall first register the schema by calling CodeFirst_RegisterSchema, passing schemaNamespace and a pointer to the metadata generated in the schema declaration block.] */
+/* Codes_SRS_SERIALIZER_99_094:[ GET_MODEL_HANDLE shall then call Schema_GetModelByName, passing the schemaHandle obtained from CodeFirst_RegisterSchema and modelName arguments, to retrieve the SCHEMA_MODEL_TYPE_HANDLE corresponding to the modelName argument.] */
+/* Codes_SRS_SERIALIZER_99_112:[ GET_MODEL_HANDLE will return the handle for the named model.] */
+#define GET_MODEL_HANDLE(schemaNamespace, modelName) \
+ Schema_GetModelByName(CodeFirst_RegisterSchema(TOSTRING(schemaNamespace), &ALL_REFLECTED(schemaNamespace)), #modelName)
+
+/* Codes_SRS_SERIALIZER_01_002: [If the argument serializerIncludePropertyPath is specified, its value shall be passed to CodeFirst_Create.] */
+#define CREATE_DEVICE_WITH_INCLUDE_PROPERTY_PATH(schemaNamespace, modelName, serializerIncludePropertyPath) \
+ (modelName*)CodeFirst_CreateDevice(GET_MODEL_HANDLE(schemaNamespace, modelName), &ALL_REFLECTED(schemaNamespace), sizeof(modelName), serializerIncludePropertyPath)
+
+/* Codes_SRS_SERIALIZER_01_003: [If the argument serializerIncludePropertyPath is not specified, CREATE_MODEL_INSTANCE shall pass false to CodeFirst_Create.] */
+#define CREATE_DEVICE_WITHOUT_INCLUDE_PROPERTY_PATH(schemaNamespace, modelName) \
+ (modelName*)CodeFirst_CreateDevice(GET_MODEL_HANDLE(schemaNamespace, modelName), &ALL_REFLECTED(schemaNamespace), sizeof(modelName), false)
+
+/* Codes_SRS_SERIALIZER_99_104:[ CREATE_MODEL_INSTANCE shall call GET_MODEL_HANDLE, passing schemaNamespace and modelName, to get a model handle representing the model defined in the corresponding schema declaration block.] */
+/* Codes_SRS_SERIALIZER_99_106:[ CREATE_MODEL_INSTANCE shall call CodeFirst_CreateDevice, passing the model handle (SCHEMA_MODEL_TYPE_HANDLE]*/
+/* Codes_SRS_SERIALIZER_99_107:[ If CodeFirst_CreateDevice fails, CREATE_MODEL_INSTANCE shall return NULL.] */
+/* Codes_SRS_SERIALIZER_99_108:[ If CodeFirst_CreateDevice succeeds, CREATE_MODEL_INSTANCE shall return a pointer to an instance of the C struct representing the model for the device.] */
+#define CREATE_MODEL_INSTANCE(schemaNamespace, ...) \
+ IF(DIV2(COUNT_ARG(__VA_ARGS__)), CREATE_DEVICE_WITH_INCLUDE_PROPERTY_PATH, CREATE_DEVICE_WITHOUT_INCLUDE_PROPERTY_PATH) (schemaNamespace, __VA_ARGS__)
+
+/* Codes_SRS_SERIALIZER_99_109:[ DESTROY_MODEL_INSTANCE shall call CodeFirst_DestroyDevice, passing the pointer returned from CREATE_MODEL_INSTANCE, to release all resources associated with the device.] */
+#define DESTROY_MODEL_INSTANCE(deviceData) \
+ CodeFirst_DestroyDevice(deviceData)
+
+/**
+ * @def SERIALIZE(destination, destinationSize,...)
+ * This macro produces JSON serialized representation of the properties.
+ *
+ * @param destination Pointer to an @c unsigned @c char* that
+ * will receive the serialized data.
+ * @param destinationSize Pointer to a @c size_t that gets
+ * written with the size in bytes of the
+ * serialized data
+ * @param property1, property2... A list of property values to send. The
+ * order in which the properties appear in
+ * the list does not matter, all values
+ * will be sent together.
+ *
+ */
+/*Codes_SRS_SERIALIZER_99_113:[ SERIALIZE shall call CodeFirst_SendAsync, passing a destination, destinationSize, the number of properties to publish, and pointers to the values for each property.] */
+/*Codes_SRS_SERIALIZER_99_117:[ If CodeFirst_SendAsync succeeds, SEND will return IOT_AGENT_OK.] */
+/*Codes_SRS_SERIALIZER_99_114:[ If CodeFirst_SendAsync fails, SEND shall return IOT_AGENT_SERIALIZE_FAILED.] */
+#define SERIALIZE(destination, destinationSize,...) ((CodeFirst_SendAsync(destination, destinationSize, COUNT_ARG(__VA_ARGS__) FOR_EACH_1(ADDRESS_MACRO, __VA_ARGS__)) == CODEFIRST_OK) ? IOT_AGENT_OK : IOT_AGENT_SERIALIZE_FAILED)
+
+/**
+ * @def EXECUTE_COMMAND(device, command)
+ * Any action that is declared in a model must also have an implementation as
+ * a C function.
+ *
+ * @param device Pointer to device data.
+ * @param command Values that match the arguments declared in the model
+ * action.
+ */
+/*Codes_SRS_SERIALIZER_02_018: [EXECUTE_COMMAND macro shall call CodeFirst_ExecuteCommand passing device, commandBuffer and commandBufferSize.]*/
+#define EXECUTE_COMMAND(device, command) (CodeFirst_ExecuteCommand(device, command))
+
+/* Helper macros */
+
+/* These macros remove a useless comma from the beginning of an argument list that looks like:
+,x1,y1,x2,y2 */
+#ifdef _MSC_VER
+
+#define DROP_FIRST_COMMA(N, x) \
+x IFCOMMA_NOFIRST(N)
+
+#define DROP_IF_EMPTY(N, x) \
+IF(COUNT_ARG(x),DROP_FIRST_COMMA(N,x),x)
+
+#define DROP_FIRST_COMMA_FROM_ARGS(...) \
+FOR_EACH_1_COUNTED(DROP_IF_EMPTY, C1(__VA_ARGS__))
+
+#else
+
+#define DROP_FIRST_COMMA_0(N, x) \
+ x IFCOMMA_NOFIRST(N)
+
+#define DROP_FIRST_COMMA_1(N, x) \
+ x
+
+#define DROP_FIRST_COMMA(empty, N, x) \
+ C2(DROP_FIRST_COMMA_,empty)(N,x)
+
+#define DROP_IF_EMPTY(N, x) \
+ DROP_FIRST_COMMA(ISEMPTY(x),N,x)
+
+#define DROP_FIRST_COMMA_FROM_ARGS(...) \
+ FOR_EACH_1_COUNTED(DROP_IF_EMPTY, __VA_ARGS__)
+
+#endif
+
+/* These macros expand a sequence of arguments for DECLARE_MODEL that looks like
+WITH_DATA(x, y), WITH_DATA(x2, y2) to a list of arguments consumed by the macro that marshalls a struct, like:
+x, y, x2, y2
+Actions are discarded, since no marshalling will be done for those when sending state data */
+#define TO_AGENT_DT_EXPAND_MODEL_PROPERTY(x, y) ,x,y
+#define TO_AGENT_DT_EXPAND_MODEL_ACTION(...)
+
+#define TO_AGENT_DT_EXPAND_ELEMENT_ARGS(N, ...) TO_AGENT_DT_EXPAND_##__VA_ARGS__
+
+#define EXPAND_MODEL_ARGS(...) \
+ FOR_EACH_1_COUNTED(TO_AGENT_DT_EXPAND_ELEMENT_ARGS, __VA_ARGS__)
+
+#define TO_AGENT_DATA_TYPE(name, ...) \
+ static AGENT_DATA_TYPES_RESULT ToAGENT_DATA_TYPE_##name(AGENT_DATA_TYPE *destination, const name value) \
+ { \
+ AGENT_DATA_TYPES_RESULT result = AGENT_DATA_TYPES_OK; \
+ size_t iMember = 0; \
+ DEFINITION_THAT_CAN_SUSTAIN_A_COMMA_STEAL(phantomName, 1); \
+ const char* memberNames[IF(DIV2(C1(COUNT_ARG(__VA_ARGS__))), DIV2(C1(COUNT_ARG(__VA_ARGS__))), 1)] = { 0 }; \
+ size_t memberCount = sizeof(memberNames) / sizeof(memberNames[0]); \
+ (void)value; \
+ if (memberCount == 0) \
+ { \
+ result = AGENT_DATA_TYPES_OK; \
+ } \
+ else \
+ { \
+ AGENT_DATA_TYPE members[sizeof(memberNames) / sizeof(memberNames[0])]; \
+ DEFINITION_THAT_CAN_SUSTAIN_A_COMMA_STEAL(phantomName, 2); \
+ FOR_EACH_2(FIELD_AS_STRING, EXPAND_TWICE(__VA_ARGS__)) \
+ iMember = 0; \
+ INSTRUCTION_THAT_CAN_SUSTAIN_A_COMMA_STEAL; \
+ FOR_EACH_2(CREATE_AGENT_DATA_TYPE, EXPAND_TWICE(__VA_ARGS__)) \
+ INSTRUCTION_THAT_CAN_SUSTAIN_A_COMMA_STEAL; \
+ result = ((result == AGENT_DATA_TYPES_OK) && (Create_AGENT_DATA_TYPE_from_Members(destination, #name, sizeof(memberNames) / sizeof(memberNames[0]), memberNames, members) == AGENT_DATA_TYPES_OK)) \
+ ? AGENT_DATA_TYPES_OK \
+ : AGENT_DATA_TYPES_ERROR; \
+ { \
+ size_t jMember; \
+ for (jMember = 0; jMember < iMember; jMember++) \
+ { \
+ Destroy_AGENT_DATA_TYPE(&members[jMember]); \
+ } \
+ } \
+ } \
+ return result; \
+ }
+
+#define FIELD_AS_STRING(x,y) memberNames[iMember++] = #y;
+
+#define REFLECTED_LIST_HEAD(name) \
+ static const REFLECTED_DATA_FROM_DATAPROVIDER ALL_REFLECTED(name) = { &C2(REFLECTED_, C1(DEC(__COUNTER__))) };
+#define REFLECTED_STRUCT(name) \
+ static const REFLECTED_SOMETHING C2(REFLECTED_, C1(INC(__COUNTER__))) = { REFLECTION_STRUCT_TYPE, &C2(REFLECTED_, C1(DEC(DEC(__COUNTER__)))), { {TOSTRING(name)}, {0}, {0}, {0}, {0}} };
+#define REFLECTED_FIELD(XstructName, XfieldType, XfieldName) \
+ static const REFLECTED_SOMETHING C2(REFLECTED_, C1(INC(__COUNTER__))) = { REFLECTION_FIELD_TYPE, &C2(REFLECTED_, C1(DEC(DEC(__COUNTER__)))), { {0}, {TOSTRING(XfieldName), TOSTRING(XfieldType), TOSTRING(XstructName)}, {0}, {0}, {0} } };
+#define REFLECTED_MODEL(name) \
+ static const REFLECTED_SOMETHING C2(REFLECTED_, C1(INC(__COUNTER__))) = { REFLECTION_MODEL_TYPE, &C2(REFLECTED_, C1(DEC(DEC(__COUNTER__)))), { {0}, {0}, {0}, {0}, {TOSTRING(name)} } };
+#define REFLECTED_PROPERTY(type, name, modelName) \
+ static const REFLECTED_SOMETHING C2(REFLECTED_, C1(INC(__COUNTER__))) = { REFLECTION_PROPERTY_TYPE, &C2(REFLECTED_, C1(DEC(DEC(__COUNTER__)))), { {0}, {0}, {TOSTRING(name), TOSTRING(type), Create_AGENT_DATA_TYPE_From_Ptr_##name, offsetof(modelName, name), sizeof(type), TOSTRING(modelName)}, {0}, {0}} };
+#define REFLECTED_ACTION(name, argc, argv, fn, modelName) \
+ static const REFLECTED_SOMETHING C2(REFLECTED_, C1(INC(__COUNTER__))) = { REFLECTION_ACTION_TYPE, &C2(REFLECTED_, C1(DEC(DEC(__COUNTER__)))), { {0}, {0}, {0}, {TOSTRING(name), (0 ? (uintptr_t)("", "") : argc), argv, fn, TOSTRING(modelName)}, {0}} };
+#define REFLECTED_END_OF_LIST \
+ static const REFLECTED_SOMETHING C2(REFLECTED_, __COUNTER__) = { REFLECTION_NOTHING, NULL, { {0}, {0}, {0}, {0}, {0}} };
+
+#define EXPAND_MODEL_PROPERTY(type, name) EXPAND_ARGS(MODEL_PROPERTY, type, name)
+#define EXPAND_MODEL_ACTION(...) EXPAND_ARGS(MODEL_ACTION, __VA_ARGS__)
+
+#define BUILD_MODEL_STRUCT(elem) INSERT_FIELD_FOR_##elem
+
+#define CREATE_MODEL_ENTITY(modelName, callType, ...) EXPAND_ARGS(CREATE_##callType(modelName, __VA_ARGS__))
+#define CREATE_SOMETHING(modelName, ...) EXPAND_ARGS(CREATE_MODEL_ENTITY(modelName, __VA_ARGS__))
+#define CREATE_ELEMENT(modelName, elem) EXPAND_ARGS(CREATE_SOMETHING(modelName, EXPAND_ARGS(EXPAND_##elem)))
+
+#define CREATE_MODEL_ELEMENT(modelName, elem) EXPAND_ARGS(CREATE_ELEMENT(modelName, elem))
+
+#define INSERT_FIELD_INTO_STRUCT(x, y) x y;
+#define INSERT_FIELD_FOR_MODEL_PROPERTY(type, name) INSERT_FIELD_INTO_STRUCT(type, name)
+#define INSERT_FIELD_FOR_MODEL_ACTION(name, ...) /* action isn't a part of the model struct */
+
+#define CREATE_MODEL_PROPERTY(modelName, type, name) \
+ IMPL_PROPERTY(type, name, modelName)
+
+#define IMPL_PROPERTY(propertyType, propertyName, modelName) \
+ static int Create_AGENT_DATA_TYPE_From_Ptr_##propertyName(void* param, AGENT_DATA_TYPE* dest) \
+ { \
+ return C1(ToAGENT_DATA_TYPE_##propertyType)(dest, *(propertyType*)param); \
+ } \
+ REFLECTED_PROPERTY(propertyType, propertyName, modelName)
+
+#define CREATE_MODEL_ACTION(modelName, actionName, ...) \
+ DEFINITION_THAT_CAN_SUSTAIN_A_COMMA_STEAL(modelName##actionName, 1); \
+ EXECUTE_COMMAND_RESULT actionName (modelName* device FOR_EACH_2(DEFINE_FUNCTION_PARAMETER, __VA_ARGS__)); \
+ static EXECUTE_COMMAND_RESULT C2(actionName, WRAPPER)(void* device, size_t ParameterCount, const AGENT_DATA_TYPE* values); \
+ /*for macro purposes, this array always has at least 1 element*/ \
+ /*Codes_SRS_SERIALIZER_99_043:[ It is valid for a method not to have any parameters.]*/ \
+ DEFINITION_THAT_CAN_SUSTAIN_A_COMMA_STEAL(actionName, 1); \
+ static const WRAPPER_ARGUMENT C2(actionName, WRAPPERARGUMENTS)[DIV2(INC(INC(COUNT_ARG(__VA_ARGS__))))] = { FOR_EACH_2_COUNTED(MAKE_WRAPPER_ARGUMENT, __VA_ARGS__) IFCOMMA(INC(INC(COUNT_ARG(__VA_ARGS__)))) {0} }; \
+ REFLECTED_ACTION(actionName, DIV2(COUNT_ARG(__VA_ARGS__)), C2(actionName, WRAPPERARGUMENTS), C2(actionName, WRAPPER), modelName) \
+ /*Codes_SRS_SERIALIZER_99_040:[ In addition to declaring the function, DECLARE_IOT_METHOD shall provide a definition for a wrapper that takes as parameters a size_t parameterCount and const AGENT_DATA_TYPE*.] */ \
+ /*Codes_SRS_SERIALIZER_99_041:[ This wrapper shall convert all the arguments to predefined types and then call the function written by the data provider developer.]*/ \
+ static EXECUTE_COMMAND_RESULT C2(actionName, WRAPPER)(void* device, size_t ParameterCount, const AGENT_DATA_TYPE* values) \
+ { \
+ EXECUTE_COMMAND_RESULT result; \
+ DEFINITION_THAT_CAN_SUSTAIN_A_COMMA_STEAL(actionName, 2); \
+ /*Codes_SRS_SERIALIZER_99_045:[ If the number of passed parameters doesn't match the number of declared parameters, wrapper execution shall fail and return DATA_PROVIDER_INVALID_ARG;]*/ \
+ if(ParameterCount != DIV2(COUNT_ARG(__VA_ARGS__))) \
+ { \
+ result = EXECUTE_COMMAND_ERROR; \
+ } \
+ else \
+ { \
+ /*the below line takes care of initialized but not referenced parameter warning*/ \
+ DEFINITION_THAT_CAN_SUSTAIN_A_COMMA_STEAL(actionName, 3); \
+ IF(DIV2(COUNT_ARG(__VA_ARGS__)), size_t iParameter = 0;, ) \
+ DEFINITION_THAT_CAN_SUSTAIN_A_COMMA_STEAL(actionName, 4); \
+ /*the below line takes care of an unused parameter when values is really never questioned*/ \
+ DEFINITION_THAT_CAN_SUSTAIN_A_COMMA_STEAL(actionName, 5); \
+ FOR_EACH_2(DEFINE_LOCAL_PARAMETER, __VA_ARGS__) \
+ DEFINITION_THAT_CAN_SUSTAIN_A_COMMA_STEAL(actionName, 6); \
+ IF(DIV2(COUNT_ARG(__VA_ARGS__)), , (void)values;) \
+ INSTRUCTION_THAT_CAN_SUSTAIN_A_COMMA_STEAL; \
+ FOR_EACH_2(START_BUILD_LOCAL_PARAMETER, __VA_ARGS__) \
+ INSTRUCTION_THAT_CAN_SUSTAIN_A_COMMA_STEAL; \
+ result = actionName((modelName*)device FOR_EACH_2(PUSH_LOCAL_PARAMETER, __VA_ARGS__)); \
+ FOR_EACH_2(END_BUILD_LOCAL_PARAMETER, __VA_ARGS__) \
+ } \
+ return result; \
+ }
+
+#define CREATE_AGENT_DATA_TYPE(type, name) \
+ result = (( result==AGENT_DATA_TYPES_OK) && (ToAGENT_DATA_TYPE_##type( &(members[iMember]), value.name) == AGENT_DATA_TYPES_OK))?AGENT_DATA_TYPES_OK:AGENT_DATA_TYPES_ERROR; \
+ iMember+= ((result==AGENT_DATA_TYPES_OK)?1:0);
+
+#define BUILD_DESTINATION_FIELD(type, name) \
+ if(result == AGENT_DATA_TYPES_OK) \
+ { \
+ size_t i; \
+ bool wasFieldConverted = false; \
+ for (i = 0; i < source->value.edmComplexType.nMembers; i++) \
+ { \
+ /*the name of the field of the complex type must match the name of the field of the structure (parameter name here)*/ \
+ if (strcmp(source->value.edmComplexType.fields[i].fieldName, TOSTRING(name)) == 0) \
+ { /*Codes_SRS_SERIALIZER_99_017:[ These types can either be one of the types mentioned in WITH_DATA or it can be a type introduced by a previous DECLARE_STRUCT.]*/ \
+ wasFieldConverted = (C2(FromAGENT_DATA_TYPE_, type)(source->value.edmComplexType.fields[i].value, &(destination->name)) == AGENT_DATA_TYPES_OK); \
+ break; \
+ } \
+ } \
+ result = (wasFieldConverted == true)? AGENT_DATA_TYPES_OK: AGENT_DATA_TYPES_INVALID_ARG; \
+ } \
+ else \
+ { \
+ /*fallthrough*/ \
+ }
+
+#define UNBUILD_DESTINATION_FIELD(value, type, name) \
+ C2(destroyLocalParameter, type)(&(value->name));
+
+
+#define ADDRESS_MACRO(x) ,&x
+
+#define KEEP_FIRST_(X, ...) X
+#ifdef _MSC_VER
+#define KEEP_FIRST(X) KEEP_FIRST_ LPAREN X)
+#else
+#define KEEP_FIRST(X) KEEP_FIRST_(X)
+#endif
+
+#define PROMOTIONMAP_float double, double
+#define PROMOTIONMAP_int8_t int, int
+#define PROMOTIONMAP_uint8_t int, int
+#define PROMOTIONMAP_int16_t int, int
+#define PROMOTIONMAP__Bool int, int
+#define PROMOTIONMAP_bool int, int
+
+#define CASTMAP_float (float), (float)
+#define CASTMAP_int8_t (int8_t), (int8_t)
+#define CASTMAP_uint8_t (uint8_t), (uint8_t)
+#define CASTMAP_int16_t (int16_t), (int16_t)
+#define CASTMAP__Bool 0!=, 0!=
+#define CASTMAP_bool 0!=, 0!=
+
+#define EMPTY_TOKEN
+
+#define ANOTHERIF(x) C2(ANOTHERIF,x)
+#define ANOTHERIF0(a,b) a
+#define ANOTHERIF1(a,b) b
+#define ANOTHERIF2(a,b) b
+#define ANOTHERIF3(a,b) b
+#define ANOTHERIF4(a,b) b
+#define ANOTHERIF5(a,b) b
+#define ANOTHERIF6(a,b) b
+#define ANOTHERIF7(a,b) b
+#define ANOTHERIF8(a,b) b
+#define ANOTHERIF9(a,b) b
+#define ANOTHERIF10(a,b) b
+#define ANOTHERIF11(a,b) b
+#define ANOTHERIF12(a,b) b
+
+#define MAP_PROMOTED_TYPE(X) ANOTHERIF(DEC(COUNT_ARG(PROMOTIONMAP_##X))) (X, KEEP_FIRST(PROMOTIONMAP_##X))
+#define MAP_CAST_TYPE(X) ANOTHERIF(DEC(COUNT_ARG(CASTMAP_##X))) (EMPTY_TOKEN, KEEP_FIRST(CASTMAP_##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_126 ,
+#define IFCOMMA_128 ,
+
+#define DEFINE_LOCAL_PARAMETER(type, name) type C2(name,_local);
+
+#define START_BUILD_LOCAL_PARAMETER(type, name) \
+ if (C2(FromAGENT_DATA_TYPE_, type)(&values[iParameter], &C2(name, _local)) != AGENT_DATA_TYPES_OK) \
+ { \
+ /*Codes_SRS_SERIALIZER_99_046:[ If the types of the parameters do not match the declared types, DATAPROVIDER_INVALID_ARG shall be returned.]*/ \
+ result = EXECUTE_COMMAND_ERROR; \
+ }\
+ else \
+ { \
+ iParameter++;
+
+#define END_BUILD_LOCAL_PARAMETER(type, name) \
+ (void)C2(destroyLocalParameter, type)(&C2(name, _local)); \
+ }
+
+/*The following constructs have been devised to work around the precompiler bug of Visual Studio 2005, version 14.00.50727.42*/
+/* The bug is explained in https://connect.microsoft.com/VisualStudio/feedback/details/278752/comma-missing-when-using-va-args */
+/*A short description is: preprocessor is myteriously eating commas ','.
+In order to feed the appetite of the preprocessor, several constructs have
+been devised that can sustain a missing ',' while still compiling and while still doing nothing
+and while hopefully being eliminated from the code based on "doesn't do anything" so no code size penalty
+*/
+
+/*the reason why all these constructs work is:
+if two strings separated by a comma will lose the comma (myteriously) then they will become just one string:
+"a", "b" ------Preprocessor------> "a" "b" -----Compiler----> "ab"
+*/
+
+#define LOTS_OF_COMMA_TO_BE_EATEN /*there were witnesses where as many as THREE commas have been eaten!*/ \
+"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"
+#define DEFINITION_THAT_CAN_SUSTAIN_A_COMMA_STEAL(name, instance) static const char* eatThese_COMMA_##name##instance[] = {LOTS_OF_COMMA_TO_BE_EATEN}
+#define INSTRUCTION_THAT_CAN_SUSTAIN_A_COMMA_STEAL 0?LOTS_OF_COMMA_TO_BE_EATEN:LOTS_OF_COMMA_TO_BE_EATEN
+
+#define PUSH_LOCAL_PARAMETER(type, name) , C2(name, _local)
+#define DEFINE_FUNCTION_PARAMETER(type, name) , type name
+#define MAKE_WRAPPER_ARGUMENT(N, type, name) {TOSTRING(type), TOSTRING(name)} IFCOMMA(N)
+
+/*Codes_SRS_SERIALIZER_99_019:[ Create_AGENT_DATA_TYPE_from_DOUBLE]*/
+/*Codes_SRS_SERIALIZER_99_004:[ The propertyType can be any of the following data types: double]*/
+static AGENT_DATA_TYPES_RESULT C2(ToAGENT_DATA_TYPE_, double)(AGENT_DATA_TYPE* dest, double source)
+{
+ return Create_AGENT_DATA_TYPE_from_DOUBLE(dest, source);
+}
+
+static AGENT_DATA_TYPES_RESULT C2(FromAGENT_DATA_TYPE_, double)(const AGENT_DATA_TYPE* agentData, double* dest)
+{
+ AGENT_DATA_TYPES_RESULT result;
+ if (agentData->type != EDM_DOUBLE_TYPE)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ }
+ else
+ {
+ *dest = agentData->value.edmDouble.value;
+ result = AGENT_DATA_TYPES_OK;
+ }
+ return result;
+}
+
+/*Codes_SRS_SERIALIZER_99_021:[ Create_AGENT_DATA_TYPE_from_FLOAT]*/
+/*Codes_SRS_SERIALIZER_99_006:[ float]*/
+static AGENT_DATA_TYPES_RESULT C2(ToAGENT_DATA_TYPE_, float)(AGENT_DATA_TYPE* dest, float source)
+{
+ return Create_AGENT_DATA_TYPE_from_FLOAT(dest, source);
+}
+
+static AGENT_DATA_TYPES_RESULT C2(FromAGENT_DATA_TYPE_, float)(const AGENT_DATA_TYPE* agentData, float* dest)
+{
+ AGENT_DATA_TYPES_RESULT result;
+ if (agentData->type != EDM_SINGLE_TYPE)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ }
+ else
+ {
+ *dest = agentData->value.edmSingle.value;
+ result = AGENT_DATA_TYPES_OK;
+ }
+ return result;
+}
+
+
+/*Codes_SRS_SERIALIZER_99_020:[ Create_AGENT_DATA_TYPE_from_SINT32]*/
+/*Codes_SRS_SERIALIZER_99_005:[ int], */
+static AGENT_DATA_TYPES_RESULT C2(ToAGENT_DATA_TYPE_, int)(AGENT_DATA_TYPE* dest, int source)
+{
+ return Create_AGENT_DATA_TYPE_from_SINT32(dest, source);
+}
+
+static AGENT_DATA_TYPES_RESULT C2(FromAGENT_DATA_TYPE_, int)(const AGENT_DATA_TYPE* agentData, int* dest)
+{
+ AGENT_DATA_TYPES_RESULT result;
+ if (agentData->type != EDM_INT32_TYPE)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ }
+ else
+ {
+ *dest = agentData->value.edmInt32.value;
+ result = AGENT_DATA_TYPES_OK;
+ }
+ return result;
+}
+
+/*Codes_SRS_SERIALIZER_99_022:[ Create_AGENT_DATA_TYPE_from_SINT64]*/
+/*Codes_SRS_SERIALIZER_99_007:[ long]*/
+static AGENT_DATA_TYPES_RESULT C2(ToAGENT_DATA_TYPE_, long)(AGENT_DATA_TYPE* dest, long source)
+{
+ return Create_AGENT_DATA_TYPE_from_SINT64(dest, source);
+}
+
+static AGENT_DATA_TYPES_RESULT C2(FromAGENT_DATA_TYPE_, long)(const AGENT_DATA_TYPE* agentData, long* dest)
+{
+ AGENT_DATA_TYPES_RESULT result;
+ if (agentData->type != EDM_INT64_TYPE)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ }
+ else
+ {
+ *dest = (long)agentData->value.edmInt64.value;
+ result = AGENT_DATA_TYPES_OK;
+ }
+ return result;
+}
+
+/*Codes_SRS_SERIALIZER_99_023:[ Create_AGENT_DATA_TYPE_from_SINT8]*/
+/*Codes_SRS_SERIALIZER_99_008:[ int8_t]*/
+static AGENT_DATA_TYPES_RESULT C2(ToAGENT_DATA_TYPE_, int8_t)(AGENT_DATA_TYPE* dest, int8_t source)
+{
+ return Create_AGENT_DATA_TYPE_from_SINT8(dest, source);
+}
+
+static AGENT_DATA_TYPES_RESULT C2(FromAGENT_DATA_TYPE_, int8_t)(const AGENT_DATA_TYPE* agentData, int8_t* dest)
+{
+ AGENT_DATA_TYPES_RESULT result;
+ if (agentData->type != EDM_SBYTE_TYPE)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ }
+ else
+ {
+ *dest = agentData->value.edmSbyte.value;
+ result = AGENT_DATA_TYPES_OK;
+ }
+ return result;
+}
+
+/*Codes_SRS_SERIALIZER_99_024:[ Create_AGENT_DATA_TYPE_from_UINT8]*/
+/*Codes_SRS_SERIALIZER_99_009:[ uint8_t]*/
+static AGENT_DATA_TYPES_RESULT C2(ToAGENT_DATA_TYPE_, uint8_t)(AGENT_DATA_TYPE* dest, uint8_t source)
+{
+ return Create_AGENT_DATA_TYPE_from_UINT8(dest, source);
+}
+
+static AGENT_DATA_TYPES_RESULT C2(FromAGENT_DATA_TYPE_, uint8_t)(const AGENT_DATA_TYPE* agentData, uint8_t* dest)
+{
+ AGENT_DATA_TYPES_RESULT result;
+ if (agentData->type != EDM_BYTE_TYPE)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ }
+ else
+ {
+ *dest = agentData->value.edmByte.value;
+ result = AGENT_DATA_TYPES_OK;
+ }
+ return result;
+}
+
+/*Codes_SRS_SERIALIZER_99_025:[ Create_AGENT_DATA_TYPE_from_SINT16]*/
+/*Codes_SRS_SERIALIZER_99_010:[ int16_t]*/
+static AGENT_DATA_TYPES_RESULT C2(ToAGENT_DATA_TYPE_, int16_t)(AGENT_DATA_TYPE* dest, int16_t source)
+{
+ return Create_AGENT_DATA_TYPE_from_SINT16(dest, source);
+}
+
+static AGENT_DATA_TYPES_RESULT C2(FromAGENT_DATA_TYPE_, int16_t)(const AGENT_DATA_TYPE* agentData, int16_t* dest)
+{
+ AGENT_DATA_TYPES_RESULT result;
+ if (agentData->type != EDM_INT16_TYPE)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ }
+ else
+ {
+ *dest = agentData->value.edmInt16.value;
+ result = AGENT_DATA_TYPES_OK;
+ }
+ return result;
+}
+
+/*Codes_SRS_SERIALIZER_99_026:[ Create_AGENT_DATA_TYPE_from_SINT32]*/
+/*Codes_SRS_SERIALIZER_99_011:[ int32_t]*/
+static AGENT_DATA_TYPES_RESULT C2(ToAGENT_DATA_TYPE_, int32_t)(AGENT_DATA_TYPE* dest, int32_t source)
+{
+ return Create_AGENT_DATA_TYPE_from_SINT32(dest, source);
+}
+
+static AGENT_DATA_TYPES_RESULT C2(FromAGENT_DATA_TYPE_, int32_t)(const AGENT_DATA_TYPE* agentData, int32_t* dest)
+{
+ AGENT_DATA_TYPES_RESULT result;
+ if (agentData->type != EDM_INT32_TYPE)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ }
+ else
+ {
+ *dest = agentData->value.edmInt32.value;
+ result = AGENT_DATA_TYPES_OK;
+ }
+ return result;
+}
+
+/*Codes_SRS_SERIALIZER_99_027:[ Create_AGENT_DATA_TYPE_from_SINT64]*/
+/*Codes_SRS_SERIALIZER_99_012:[ int64_t]*/
+static AGENT_DATA_TYPES_RESULT C2(ToAGENT_DATA_TYPE_, int64_t)(AGENT_DATA_TYPE* dest, int64_t source)
+{
+ return Create_AGENT_DATA_TYPE_from_SINT64(dest, source);
+}
+
+static AGENT_DATA_TYPES_RESULT C2(FromAGENT_DATA_TYPE_, int64_t)(const AGENT_DATA_TYPE* agentData, int64_t* dest)
+{
+ AGENT_DATA_TYPES_RESULT result;
+ if (agentData->type != EDM_INT64_TYPE)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ }
+ else
+ {
+ *dest = agentData->value.edmInt64.value;
+ result = AGENT_DATA_TYPES_OK;
+ }
+ return result;
+}
+
+/*Codes_SRS_SERIALIZER_99_013:[ bool]*/
+static AGENT_DATA_TYPES_RESULT C2(ToAGENT_DATA_TYPE_, bool)(AGENT_DATA_TYPE* dest, bool source)
+{
+ return Create_EDM_BOOLEAN_from_int(dest, source == true);
+}
+
+static AGENT_DATA_TYPES_RESULT C2(FromAGENT_DATA_TYPE_, bool)(const AGENT_DATA_TYPE* agentData, bool* dest)
+{
+ AGENT_DATA_TYPES_RESULT result;
+ if (agentData->type != EDM_BOOLEAN_TYPE)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ }
+ else
+ {
+ *dest = (agentData->value.edmBoolean.value == EDM_TRUE) ? true : false;
+ result = AGENT_DATA_TYPES_OK;
+ }
+ return result;
+}
+
+/*Codes_SRS_SERIALIZER_99_014:[ ascii_char_ptr]*/
+static AGENT_DATA_TYPES_RESULT C2(ToAGENT_DATA_TYPE_, ascii_char_ptr)(AGENT_DATA_TYPE* dest, ascii_char_ptr source)
+{
+ return Create_AGENT_DATA_TYPE_from_charz(dest, source);
+}
+
+static AGENT_DATA_TYPES_RESULT C2(FromAGENT_DATA_TYPE_, ascii_char_ptr)(const AGENT_DATA_TYPE* agentData, ascii_char_ptr* dest)
+{
+ AGENT_DATA_TYPES_RESULT result;
+ if (agentData->type != EDM_STRING_TYPE)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ }
+ else
+ {
+ *dest = agentData->value.edmString.chars;
+ result = AGENT_DATA_TYPES_OK;
+ }
+ return result;
+}
+
+static AGENT_DATA_TYPES_RESULT C2(ToAGENT_DATA_TYPE_, ascii_char_ptr_no_quotes)(AGENT_DATA_TYPE* dest, ascii_char_ptr_no_quotes source)
+{
+ return Create_AGENT_DATA_TYPE_from_charz_no_quotes(dest, source);
+}
+
+static AGENT_DATA_TYPES_RESULT C2(FromAGENT_DATA_TYPE_, ascii_char_ptr_no_quotes)(const AGENT_DATA_TYPE* agentData, ascii_char_ptr_no_quotes* dest)
+{
+ AGENT_DATA_TYPES_RESULT result;
+ if (agentData->type != EDM_STRING_NO_QUOTES_TYPE)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ }
+ else
+ {
+ *dest = agentData->value.edmStringNoQuotes.chars;
+ result = AGENT_DATA_TYPES_OK;
+ }
+ return result;
+}
+
+/*Codes_SRS_SERIALIZER_99_051:[ EDM_DATE_TIME_OFFSET*/
+/*Codes_SRS_SERIALIZER_99_053:[Create_AGENT_DATA_TYPE_from_EDM_DATE_TIME_OFFSET]*/
+static AGENT_DATA_TYPES_RESULT C2(ToAGENT_DATA_TYPE_, EDM_DATE_TIME_OFFSET)(AGENT_DATA_TYPE* dest, EDM_DATE_TIME_OFFSET source)
+{
+ return Create_AGENT_DATA_TYPE_from_EDM_DATE_TIME_OFFSET(dest, source);
+}
+
+static AGENT_DATA_TYPES_RESULT C2(FromAGENT_DATA_TYPE_, EDM_DATE_TIME_OFFSET)(const AGENT_DATA_TYPE* agentData, EDM_DATE_TIME_OFFSET* dest)
+{
+ AGENT_DATA_TYPES_RESULT result;
+ if (agentData->type != EDM_DATE_TIME_OFFSET_TYPE)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ }
+ else
+ {
+ *dest = agentData->value.edmDateTimeOffset;
+ result = AGENT_DATA_TYPES_OK;
+ }
+ return result;
+}
+
+/*Codes_SRS_SERIALIZER_99_072:[ EDM_GUID]*/
+/*Codes_SRS_SERIALIZER_99_073:[ Create_AGENT_DATA_TYPE_from_EDM_GUID]*/
+static AGENT_DATA_TYPES_RESULT C2(ToAGENT_DATA_TYPE_, EDM_GUID)(AGENT_DATA_TYPE* dest, EDM_GUID guid)
+{
+ return Create_AGENT_DATA_TYPE_from_EDM_GUID(dest, guid);
+}
+
+static AGENT_DATA_TYPES_RESULT C2(FromAGENT_DATA_TYPE_, EDM_GUID)(const AGENT_DATA_TYPE* agentData, EDM_GUID* dest)
+{
+ AGENT_DATA_TYPES_RESULT result;
+ if (agentData->type != EDM_GUID_TYPE)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ }
+ else
+ {
+ memcpy(dest->GUID, agentData->value.edmGuid.GUID, 16);
+ result = AGENT_DATA_TYPES_OK;
+ }
+ return result;
+}
+
+/*Codes_SRS_SERIALIZER_99_074:[ EDM_BINARY]*/
+/*Codes_SRS_SERIALIZER_99_075:[ Create_AGENT_DATA_TYPE_from_EDM_BINARY]*/
+static AGENT_DATA_TYPES_RESULT C2(ToAGENT_DATA_TYPE_, EDM_BINARY)(AGENT_DATA_TYPE* dest, EDM_BINARY edmBinary)
+{
+ return Create_AGENT_DATA_TYPE_from_EDM_BINARY(dest, edmBinary);
+}
+
+static AGENT_DATA_TYPES_RESULT C2(FromAGENT_DATA_TYPE_, EDM_BINARY)(const AGENT_DATA_TYPE* agentData, EDM_BINARY* dest)
+{
+ AGENT_DATA_TYPES_RESULT result;
+ if (agentData->type != EDM_BINARY_TYPE)
+ {
+ result = AGENT_DATA_TYPES_INVALID_ARG;
+ }
+ else
+ {
+ if ((dest->data = (unsigned char *)malloc(agentData->value.edmBinary.size)) == NULL) /*cast because this get included in a C++ file.*/
+ {
+ result = AGENT_DATA_TYPES_ERROR;
+ }
+ else
+ {
+ memcpy(dest->data, agentData->value.edmBinary.data, agentData->value.edmBinary.size);
+ dest->size = agentData->value.edmBinary.size;
+ result = AGENT_DATA_TYPES_OK;
+ }
+ }
+ return result;
+}
+
+static void C2(destroyLocalParameter, EDM_BINARY)(EDM_BINARY* value)
+{
+ if (value != NULL)
+ {
+ free(value->data);
+ value->data = NULL;
+ value->size = 0;
+ }
+}
+
+static void C2(destroyLocalParameter, EDM_BOOLEAN)(EDM_BOOLEAN* value)
+{
+ (void)value;
+}
+
+static void C2(destroyLocalParameter, EDM_BYTE)(EDM_BYTE* value)
+{
+ (void)value;
+}
+
+static void C2(destroyLocalParameter, EDM_DATE)(EDM_DATE* value)
+{
+ (void)value;
+}
+
+static void C2(destroyLocalParameter, EDM_DATE_TIME_OFFSET)(EDM_DATE_TIME_OFFSET* value)
+{
+ (void)value;
+}
+
+static void C2(destroyLocalParameter, EDM_DECIMAL)(EDM_DECIMAL* value)
+{
+ if (value != NULL)
+ {
+ STRING_delete(value->value);
+ value->value = NULL;
+ }
+}
+
+static void C2(destroyLocalParameter, EDM_DOUBLE)(EDM_DOUBLE* value)
+{
+ (void)value;
+}
+
+static void C2(destroyLocalParameter, EDM_DURATION)(EDM_DURATION* value)
+{
+ if (value != NULL)
+ {
+ free(value->digits);
+ value->digits = NULL;
+ value->nDigits = 0;
+ }
+}
+
+static void C2(destroyLocalParameter, EDM_GUID)(EDM_GUID* value)
+{
+ (void)value;
+}
+
+static void C2(destroyLocalParameter, EDM_INT16)(EDM_INT16* value)
+{
+ (void)value;
+}
+
+static void C2(destroyLocalParameter, EDM_INT32)(EDM_INT32* value)
+{
+ (void)value;
+}
+
+static void C2(destroyLocalParameter, EDM_INT64)(EDM_INT64* value)
+{
+ (void)value;
+}
+
+static void C2(destroyLocalParameter, EDM_SBYTE)(EDM_SBYTE* value)
+{
+ (void)value;
+}
+
+static void C2(destroyLocalParameter, EDM_SINGLE)(EDM_SINGLE* value)
+{
+ (void)value;
+}
+
+static void C2(destroyLocalParameter, EDM_STRING)(EDM_STRING* value)
+{
+ (void)value;
+}
+
+
+static void C2(destroyLocalParameter, EDM_TIME_OF_DAY)(EDM_TIME_OF_DAY* value)
+{
+ (void)value;
+}
+
+static void C2(destroyLocalParameter, int)(int* value)
+{
+ (void)value;
+}
+
+static void C2(destroyLocalParameter, float)(float* value)
+{
+ (void)value;
+}
+
+static void C2(destroyLocalParameter, double)(double* value)
+{
+ (void)value;
+}
+
+static void C2(destroyLocalParameter, long)(long* value)
+{
+ (void)value;
+}
+
+static void C2(destroyLocalParameter, int8_t)(int8_t* value)
+{
+ (void)value;
+}
+
+static void C2(destroyLocalParameter, uint8_t)(uint8_t* value)
+{
+ (void)value;
+}
+
+static void C2(destroyLocalParameter, int16_t)(int16_t* value)
+{
+ (void)value;
+}
+
+static void C2(destroyLocalParameter, int32_t)(int32_t* value)
+{
+ (void)value;
+}
+
+static void C2(destroyLocalParameter, int64_t)(int64_t* value)
+{
+ (void)value;
+}
+
+static void C2(destroyLocalParameter, bool)(bool* value)
+{
+ (void)value;
+}
+
+static void C2(destroyLocalParameter, ascii_char_ptr)(ascii_char_ptr* value)
+{
+ (void)value;
+}
+
+static void C2(destroyLocalParameter, ascii_char_ptr_no_quotes)(ascii_char_ptr_no_quotes* value)
+{
+ (void)value;
+}
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /*SERIALIZER_H*/
+
+
