test

Revision:
0:cd5404401c2f
diff -r 000000000000 -r cd5404401c2f aws-iot/src/aws_iot_shadow_json.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/aws-iot/src/aws_iot_shadow_json.cpp	Wed Apr 12 14:07:09 2017 +0200
@@ -0,0 +1,471 @@
+/*
+ * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ *  http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file is distributed
+ * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+/**
+ * @file aws_iot_shadow_json.c
+ * @brief Shadow client JSON parsing API definitions
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#include <cinttypes>
+#else
+
+#include <inttypes.h>
+
+#endif
+
+#include "aws_iot_shadow_json.h"
+
+#include <string.h>
+#include <stdbool.h>
+
+#include "aws_iot_json_utils.h"
+#include "aws_iot_log.h"
+#include "aws_iot_shadow_key.h"
+#include "aws_iot_config.h"
+
+extern char mqttClientID[MAX_SIZE_OF_UNIQUE_CLIENT_ID_BYTES];
+
+static uint32_t clientTokenNum = 0;
+
+//helper functions
+static IoT_Error_t convertDataToString(char *pStringBuffer, size_t maxSizoStringBuffer, JsonPrimitiveType type,
+									   void *pData);
+
+void resetClientTokenSequenceNum(void) {
+	clientTokenNum = 0;
+}
+
+static void emptyJsonWithClientToken(char *pJsonDocument) {
+	sprintf(pJsonDocument, "{\"clientToken\":\"");
+	FillWithClientToken(pJsonDocument + strlen(pJsonDocument));
+	sprintf(pJsonDocument + strlen(pJsonDocument), "\"}");
+}
+
+void aws_iot_shadow_internal_get_request_json(char *pJsonDocument) {
+	emptyJsonWithClientToken(pJsonDocument);
+}
+
+void aws_iot_shadow_internal_delete_request_json(char *pJsonDocument) {
+	emptyJsonWithClientToken(pJsonDocument);
+}
+
+static inline IoT_Error_t checkReturnValueOfSnPrintf(int32_t snPrintfReturn, size_t maxSizeOfJsonDocument) {
+	if(snPrintfReturn < 0) {
+		return SHADOW_JSON_ERROR;
+	} else if((size_t) snPrintfReturn >= maxSizeOfJsonDocument) {
+		return SHADOW_JSON_BUFFER_TRUNCATED;
+	}
+	return SUCCESS;
+}
+
+IoT_Error_t aws_iot_shadow_init_json_document(char *pJsonDocument, size_t maxSizeOfJsonDocument) {
+
+	IoT_Error_t ret_val = SUCCESS;
+	int32_t snPrintfReturn = 0;
+
+	if(pJsonDocument == NULL) {
+		return NULL_VALUE_ERROR;
+	}
+	snPrintfReturn = snprintf(pJsonDocument, maxSizeOfJsonDocument, "{\"state\":{");
+
+	ret_val = checkReturnValueOfSnPrintf(snPrintfReturn, maxSizeOfJsonDocument);
+
+	return ret_val;
+
+}
+
+IoT_Error_t aws_iot_shadow_add_desired(char *pJsonDocument, size_t maxSizeOfJsonDocument, uint8_t count, ...) {
+	IoT_Error_t ret_val = SUCCESS;
+	size_t tempSize = 0;
+	int8_t i;
+	size_t remSizeOfJsonBuffer = maxSizeOfJsonDocument;
+	int32_t snPrintfReturn = 0;
+	va_list pArgs;
+	jsonStruct_t *pTemporary = NULL;
+	va_start(pArgs, count);
+
+	if(pJsonDocument == NULL) {
+		return NULL_VALUE_ERROR;
+	}
+
+	tempSize = maxSizeOfJsonDocument - strlen(pJsonDocument);
+	if(tempSize <= 1) {
+		return SHADOW_JSON_ERROR;
+	}
+	remSizeOfJsonBuffer = tempSize;
+
+	snPrintfReturn = snprintf(pJsonDocument + strlen(pJsonDocument), remSizeOfJsonBuffer, "\"desired\":{");
+	ret_val = checkReturnValueOfSnPrintf(snPrintfReturn, remSizeOfJsonBuffer);
+
+	if(ret_val != SUCCESS) {
+		return ret_val;
+	}
+
+	for(i = 0; i < count; i++) {
+		tempSize = maxSizeOfJsonDocument - strlen(pJsonDocument);
+		if(tempSize <= 1) {
+			return SHADOW_JSON_ERROR;
+		}
+		remSizeOfJsonBuffer = tempSize;
+		pTemporary = va_arg (pArgs, jsonStruct_t *);
+		if(pTemporary != NULL) {
+			snPrintfReturn = snprintf(pJsonDocument + strlen(pJsonDocument), remSizeOfJsonBuffer, "\"%s\":",
+									  pTemporary->pKey);
+			ret_val = checkReturnValueOfSnPrintf(snPrintfReturn, remSizeOfJsonBuffer);
+			if(ret_val != SUCCESS) {
+				return ret_val;
+			}
+			if(pTemporary->pKey != NULL && pTemporary->pData != NULL) {
+				ret_val = convertDataToString(pJsonDocument + strlen(pJsonDocument), remSizeOfJsonBuffer,
+											  pTemporary->type, pTemporary->pData);
+			} else {
+				return NULL_VALUE_ERROR;
+			}
+			if(ret_val != SUCCESS) {
+				return ret_val;
+			}
+		} else {
+			return NULL_VALUE_ERROR;
+		}
+	}
+
+	va_end(pArgs);
+	snPrintfReturn = snprintf(pJsonDocument + strlen(pJsonDocument) - 1, remSizeOfJsonBuffer, "},");
+	ret_val = checkReturnValueOfSnPrintf(snPrintfReturn, remSizeOfJsonBuffer);
+	return ret_val;
+}
+
+IoT_Error_t aws_iot_shadow_add_reported(char *pJsonDocument, size_t maxSizeOfJsonDocument, uint8_t count, ...) {
+	IoT_Error_t ret_val = SUCCESS;
+
+	int8_t i;
+	size_t remSizeOfJsonBuffer = maxSizeOfJsonDocument;
+	int32_t snPrintfReturn = 0;
+	size_t tempSize = 0;
+	jsonStruct_t *pTemporary;
+	va_list pArgs;
+	va_start(pArgs, count);
+
+	if(pJsonDocument == NULL) {
+		return NULL_VALUE_ERROR;
+	}
+
+
+	tempSize = maxSizeOfJsonDocument - strlen(pJsonDocument);
+	if(tempSize <= 1) {
+		return SHADOW_JSON_ERROR;
+	}
+	remSizeOfJsonBuffer = tempSize;
+
+	snPrintfReturn = snprintf(pJsonDocument + strlen(pJsonDocument), remSizeOfJsonBuffer, "\"reported\":{");
+	ret_val = checkReturnValueOfSnPrintf(snPrintfReturn, remSizeOfJsonBuffer);
+
+	if(ret_val != SUCCESS) {
+		return ret_val;
+	}
+
+	for(i = 0; i < count; i++) {
+		tempSize = maxSizeOfJsonDocument - strlen(pJsonDocument);
+		if(tempSize <= 1) {
+			return SHADOW_JSON_ERROR;
+		}
+		remSizeOfJsonBuffer = tempSize;
+
+		pTemporary = va_arg (pArgs, jsonStruct_t *);
+		if(pTemporary != NULL) {
+			snPrintfReturn = snprintf(pJsonDocument + strlen(pJsonDocument), remSizeOfJsonBuffer, "\"%s\":",
+									  pTemporary->pKey);
+			ret_val = checkReturnValueOfSnPrintf(snPrintfReturn, remSizeOfJsonBuffer);
+			if(ret_val != SUCCESS) {
+				return ret_val;
+			}
+			if(pTemporary->pKey != NULL && pTemporary->pData != NULL) {
+				ret_val = convertDataToString(pJsonDocument + strlen(pJsonDocument), remSizeOfJsonBuffer,
+											  pTemporary->type, pTemporary->pData);
+			} else {
+				return NULL_VALUE_ERROR;
+			}
+			if(ret_val != SUCCESS) {
+				return ret_val;
+			}
+		} else {
+			return NULL_VALUE_ERROR;
+		}
+	}
+
+	va_end(pArgs);
+	snPrintfReturn = snprintf(pJsonDocument + strlen(pJsonDocument) - 1, remSizeOfJsonBuffer, "},");
+	ret_val = checkReturnValueOfSnPrintf(snPrintfReturn, remSizeOfJsonBuffer);
+	return ret_val;
+}
+
+
+int32_t FillWithClientTokenSize(char *pBufferToBeUpdatedWithClientToken, size_t maxSizeOfJsonDocument) {
+	int32_t snPrintfReturn;
+	snPrintfReturn = snprintf(pBufferToBeUpdatedWithClientToken, maxSizeOfJsonDocument, "%s-%d", mqttClientID,
+							  clientTokenNum++);
+
+	return snPrintfReturn;
+}
+
+IoT_Error_t aws_iot_fill_with_client_token(char *pBufferToBeUpdatedWithClientToken, size_t maxSizeOfJsonDocument) {
+
+	int32_t snPrintfRet = 0;
+	snPrintfRet = FillWithClientTokenSize(pBufferToBeUpdatedWithClientToken, maxSizeOfJsonDocument);
+	return checkReturnValueOfSnPrintf(snPrintfRet, maxSizeOfJsonDocument);
+
+}
+
+IoT_Error_t aws_iot_finalize_json_document(char *pJsonDocument, size_t maxSizeOfJsonDocument) {
+	size_t remSizeOfJsonBuffer = maxSizeOfJsonDocument;
+	int32_t snPrintfReturn = 0;
+	size_t tempSize = 0;
+	IoT_Error_t ret_val = SUCCESS;
+
+	if(pJsonDocument == NULL) {
+		return NULL_VALUE_ERROR;
+	}
+
+	tempSize = maxSizeOfJsonDocument - strlen(pJsonDocument);
+	if(tempSize <= 1) {
+		return SHADOW_JSON_ERROR;
+	}
+	remSizeOfJsonBuffer = tempSize;
+
+	// strlen(ShadowTxBuffer) - 1 is to ensure we remove the last ,(comma) that was added
+	snPrintfReturn = snprintf(pJsonDocument + strlen(pJsonDocument) - 1, remSizeOfJsonBuffer, "}, \"%s\":\"",
+							  SHADOW_CLIENT_TOKEN_STRING);
+	ret_val = checkReturnValueOfSnPrintf(snPrintfReturn, remSizeOfJsonBuffer);
+
+	if(ret_val != SUCCESS) {
+		return ret_val;
+	}
+	// refactor this XXX repeated code
+	tempSize = maxSizeOfJsonDocument - strlen(pJsonDocument);
+	if(tempSize <= 1) {
+		return SHADOW_JSON_ERROR;
+	}
+	remSizeOfJsonBuffer = tempSize;
+
+
+	snPrintfReturn = FillWithClientTokenSize(pJsonDocument + strlen(pJsonDocument), remSizeOfJsonBuffer);
+	ret_val = checkReturnValueOfSnPrintf(snPrintfReturn, remSizeOfJsonBuffer);
+
+	if(ret_val != SUCCESS) {
+		return ret_val;
+	}
+	tempSize = maxSizeOfJsonDocument - strlen(pJsonDocument);
+	if(tempSize <= 1) {
+		return SHADOW_JSON_ERROR;
+	}
+	remSizeOfJsonBuffer = tempSize;
+
+
+	snPrintfReturn = snprintf(pJsonDocument + strlen(pJsonDocument), remSizeOfJsonBuffer, "\"}");
+	ret_val = checkReturnValueOfSnPrintf(snPrintfReturn, remSizeOfJsonBuffer);
+
+	return ret_val;
+}
+
+void FillWithClientToken(char *pBufferToBeUpdatedWithClientToken) {
+	sprintf(pBufferToBeUpdatedWithClientToken, "%s-%d", mqttClientID, clientTokenNum++);
+}
+
+static IoT_Error_t convertDataToString(char *pStringBuffer, size_t maxSizoStringBuffer, JsonPrimitiveType type,
+									   void *pData) {
+	int32_t snPrintfReturn = 0;
+	IoT_Error_t ret_val = SUCCESS;
+
+	if(maxSizoStringBuffer == 0) {
+		return SHADOW_JSON_ERROR;
+	}
+
+	if(type == SHADOW_JSON_INT32) {
+		snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%" PRIi32",", *(int32_t *) (pData));
+	} else if(type == SHADOW_JSON_INT16) {
+		snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%" PRIi16",", *(int16_t *) (pData));
+	} else if(type == SHADOW_JSON_INT8) {
+		snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%" PRIi8",", *(int8_t *) (pData));
+	} else if(type == SHADOW_JSON_UINT32) {
+		snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%" PRIu32",", *(uint32_t *) (pData));
+	} else if(type == SHADOW_JSON_UINT16) {
+		snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%" PRIu16",", *(uint16_t *) (pData));
+	} else if(type == SHADOW_JSON_UINT8) {
+		snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%" PRIu8",", *(uint8_t *) (pData));
+	} else if(type == SHADOW_JSON_DOUBLE) {
+		snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%f,", *(double *) (pData));
+	} else if(type == SHADOW_JSON_FLOAT) {
+		snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%f,", *(float *) (pData));
+	} else if(type == SHADOW_JSON_BOOL) {
+		snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%s,", *(bool *) (pData) ? "true" : "false");
+	} else if(type == SHADOW_JSON_STRING) {
+		snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "\"%s\",", (char *) (pData));
+	}
+
+	ret_val = checkReturnValueOfSnPrintf(snPrintfReturn, maxSizoStringBuffer);
+
+	return ret_val;
+}
+
+static jsmn_parser shadowJsonParser;
+static jsmntok_t jsonTokenStruct[MAX_JSON_TOKEN_EXPECTED];
+
+bool isJsonValidAndParse(const char *pJsonDocument, void *pJsonHandler, int32_t *pTokenCount) {
+	int32_t tokenCount;
+
+	jsmn_init(&shadowJsonParser);
+
+	tokenCount = jsmn_parse(&shadowJsonParser, pJsonDocument, strlen(pJsonDocument), jsonTokenStruct,
+							sizeof(jsonTokenStruct) / sizeof(jsonTokenStruct[0]));
+
+	if(tokenCount < 0) {
+		IOT_WARN("Failed to parse JSON: %d\n", tokenCount);
+		return false;
+	}
+
+	/* Assume the top-level element is an object */
+	if(tokenCount < 1 || jsonTokenStruct[0].type != JSMN_OBJECT) {
+		IOT_WARN("Top Level is not an object\n");
+		return false;
+	}
+
+	pJsonHandler = (void *) jsonTokenStruct;
+	*pTokenCount = tokenCount;
+
+	return true;
+}
+
+static IoT_Error_t UpdateValueIfNoObject(const char *pJsonString, jsonStruct_t *pDataStruct, jsmntok_t token) {
+	IoT_Error_t ret_val = SUCCESS;
+	if(pDataStruct->type == SHADOW_JSON_BOOL) {
+		ret_val = parseBooleanValue((bool *) pDataStruct->pData, pJsonString, &token);
+	} else if(pDataStruct->type == SHADOW_JSON_INT32) {
+		ret_val = parseInteger32Value((int32_t *) pDataStruct->pData, pJsonString, &token);
+	} else if(pDataStruct->type == SHADOW_JSON_INT16) {
+		ret_val = parseInteger16Value((int16_t *) pDataStruct->pData, pJsonString, &token);
+	} else if(pDataStruct->type == SHADOW_JSON_INT8) {
+		ret_val = parseInteger8Value((int8_t *) pDataStruct->pData, pJsonString, &token);
+	} else if(pDataStruct->type == SHADOW_JSON_UINT32) {
+		ret_val = parseUnsignedInteger32Value((uint32_t *) pDataStruct->pData, pJsonString, &token);
+	} else if(pDataStruct->type == SHADOW_JSON_UINT16) {
+		ret_val = parseUnsignedInteger16Value((uint16_t *) pDataStruct->pData, pJsonString, &token);
+	} else if(pDataStruct->type == SHADOW_JSON_UINT8) {
+		ret_val = parseUnsignedInteger8Value((uint8_t *) pDataStruct->pData, pJsonString, &token);
+	} else if(pDataStruct->type == SHADOW_JSON_FLOAT) {
+		ret_val = parseFloatValue((float *) pDataStruct->pData, pJsonString, &token);
+	} else if(pDataStruct->type == SHADOW_JSON_DOUBLE) {
+		ret_val = parseDoubleValue((double *) pDataStruct->pData, pJsonString, &token);
+	}
+
+	return ret_val;
+}
+
+bool isJsonKeyMatchingAndUpdateValue(const char *pJsonDocument, void *pJsonHandler, int32_t tokenCount,
+									 jsonStruct_t *pDataStruct, uint32_t *pDataLength, int32_t *pDataPosition) {
+	int32_t i;
+	uint32_t dataLength;
+	jsmntok_t *pJsonTokenStruct;
+	jsmntok_t dataToken;
+
+	pJsonTokenStruct = (jsmntok_t *) pJsonHandler;
+	for(i = 1; i < tokenCount; i++) {
+		if(jsoneq(pJsonDocument, &(jsonTokenStruct[i]), pDataStruct->pKey) == 0) {
+			dataToken = jsonTokenStruct[i + 1];
+			dataLength = (uint32_t) (dataToken.end - dataToken.start);
+			UpdateValueIfNoObject(pJsonDocument, pDataStruct, dataToken);
+			*pDataPosition = dataToken.start;
+			*pDataLength = dataLength;
+			return true;
+		}
+	}
+	return false;
+}
+
+bool isReceivedJsonValid(const char *pJsonDocument) {
+	int32_t tokenCount;
+
+	jsmn_init(&shadowJsonParser);
+
+	tokenCount = jsmn_parse(&shadowJsonParser, pJsonDocument, strlen(pJsonDocument), jsonTokenStruct,
+							sizeof(jsonTokenStruct) / sizeof(jsonTokenStruct[0]));
+
+	if(tokenCount < 0) {
+		IOT_WARN("Failed to parse JSON: %d\n", tokenCount);
+		return false;
+	}
+
+	/* Assume the top-level element is an object */
+	if(tokenCount < 1 || jsonTokenStruct[0].type != JSMN_OBJECT) {
+		return false;
+	}
+
+	return true;
+}
+
+bool extractClientToken(const char *pJsonDocument, char *pExtractedClientToken) {
+	int32_t tokenCount, i;
+	uint8_t length;
+	jsmntok_t ClientJsonToken;
+	jsmn_init(&shadowJsonParser);
+
+	tokenCount = jsmn_parse(&shadowJsonParser, pJsonDocument, strlen(pJsonDocument), jsonTokenStruct,
+							sizeof(jsonTokenStruct) / sizeof(jsonTokenStruct[0]));
+
+	if(tokenCount < 0) {
+		IOT_WARN("Failed to parse JSON: %d\n", tokenCount);
+		return false;
+	}
+
+	/* Assume the top-level element is an object */
+	if(tokenCount < 1 || jsonTokenStruct[0].type != JSMN_OBJECT) {
+		return false;
+	}
+
+	for(i = 1; i < tokenCount; i++) {
+		if(jsoneq(pJsonDocument, &jsonTokenStruct[i], SHADOW_CLIENT_TOKEN_STRING) == 0) {
+			ClientJsonToken = jsonTokenStruct[i + 1];
+			length = (uint8_t) (ClientJsonToken.end - ClientJsonToken.start);
+			strncpy(pExtractedClientToken, pJsonDocument + ClientJsonToken.start, length);
+			pExtractedClientToken[length] = '\0';
+			return true;
+		}
+	}
+
+	return false;
+}
+
+bool extractVersionNumber(const char *pJsonDocument, void *pJsonHandler, int32_t tokenCount, uint32_t *pVersionNumber) {
+	int32_t i;
+	IoT_Error_t ret_val = SUCCESS;
+
+	IOT_UNUSED(pJsonHandler);
+
+	for(i = 1; i < tokenCount; i++) {
+		if(jsoneq(pJsonDocument, &(jsonTokenStruct[i]), SHADOW_VERSION_STRING) == 0) {
+			ret_val = parseUnsignedInteger32Value(pVersionNumber, pJsonDocument, &jsonTokenStruct[i + 1]);
+			if(ret_val == SUCCESS) {
+				return true;
+			}
+		}
+	}
+	return false;
+}
+
+#ifdef __cplusplus
+}
+#endif
+