--- /dev/null
+/*\r
+ * AWS IoT Common V1.0.0\r
+ * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
+ * this software and associated documentation files (the "Software"), to deal in\r
+ * the Software without restriction, including without limitation the rights to\r
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
+ * the Software, and to permit persons to whom the Software is furnished to do so,\r
+ * subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be included in all\r
+ * copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
+ */\r
+\r
+/**\r
+ * @file aws_iot_parser.c\r
+ * @brief Parses topics for Thing Name and status.\r
+ */\r
+\r
+/* The config header is always included first. */\r
+#include "iot_config.h"\r
+\r
+/* Standard includes. */\r
+#include <string.h>\r
+\r
+/* AWS IoT include. */\r
+#include "aws_iot.h"\r
+\r
+/* Error handling include. */\r
+#include "iot_error.h"\r
+\r
+/* AWS Parser include. */\r
+#include "aws_iot_doc_parser.h"\r
+\r
+/**\r
+ * @brief Minimum allowed topic length for an AWS IoT status topic.\r
+ *\r
+ * Topics must contain at least:\r
+ * - The common prefix\r
+ * - The suffix "/accepted" or "/rejected"\r
+ * - 1 character for the Thing Name\r
+ * - 2 characters for the operation name and the enclosing slashes\r
+ */\r
+#define MINIMUM_TOPIC_NAME_LENGTH \\r
+ ( uint16_t ) ( AWS_IOT_TOPIC_PREFIX_LENGTH + \\r
+ AWS_IOT_ACCEPTED_SUFFIX_LENGTH + \\r
+ 1 + 2 )\r
+\r
+/**\r
+ * @brief The longest client token accepted by AWS IoT service, per AWS IoT\r
+ * service limits.\r
+ */\r
+#define MAX_CLIENT_TOKEN_LENGTH ( 64 )\r
+\r
+/*-----------------------------------------------------------*/\r
+\r
+bool AwsIot_GetClientToken( const char * pJsonDocument,\r
+ size_t jsonDocumentLength,\r
+ const char ** pClientToken,\r
+ size_t * pClientTokenLength )\r
+{\r
+ /* Extract the client token from the JSON document. */\r
+ bool status = AwsIotDocParser_FindValue( pJsonDocument,\r
+ jsonDocumentLength,\r
+ AWS_IOT_CLIENT_TOKEN_KEY,\r
+ AWS_IOT_CLIENT_TOKEN_KEY_LENGTH,\r
+ pClientToken,\r
+ pClientTokenLength );\r
+\r
+ if( status == true )\r
+ {\r
+ /* Check that the length of the client token is valid. */\r
+ if( ( *pClientTokenLength < 2 ) ||\r
+ ( *pClientTokenLength > MAX_CLIENT_TOKEN_LENGTH ) )\r
+ {\r
+ status = false;\r
+ }\r
+ }\r
+\r
+ return status;\r
+}\r
+\r
+/*-----------------------------------------------------------*/\r
+\r
+bool AwsIot_ParseThingName( const char * pTopicName,\r
+ uint16_t topicNameLength,\r
+ const char ** pThingName,\r
+ size_t * pThingNameLength )\r
+{\r
+ IOT_FUNCTION_ENTRY( bool, true );\r
+ const char * pThingNameStart = NULL;\r
+ size_t thingNameLength = 0;\r
+\r
+ /* Check that the topic name is at least as long as the minimum allowed. */\r
+ if( topicNameLength < MINIMUM_TOPIC_NAME_LENGTH )\r
+ {\r
+ IOT_SET_AND_GOTO_CLEANUP( false );\r
+ }\r
+\r
+ /* Check that the given topic starts with the common prefix. */\r
+ if( strncmp( AWS_IOT_TOPIC_PREFIX,\r
+ pTopicName,\r
+ AWS_IOT_TOPIC_PREFIX_LENGTH ) != 0 )\r
+ {\r
+ IOT_SET_AND_GOTO_CLEANUP( false );\r
+ }\r
+\r
+ /* The Thing Name starts immediately after the topic prefix. */\r
+ pThingNameStart = pTopicName + AWS_IOT_TOPIC_PREFIX_LENGTH;\r
+\r
+ /* Calculate the length of the Thing Name, which is terminated with a '/'. */\r
+ while( ( thingNameLength + AWS_IOT_TOPIC_PREFIX_LENGTH < ( size_t ) topicNameLength ) &&\r
+ ( pThingNameStart[ thingNameLength ] != '/' ) )\r
+ {\r
+ thingNameLength++;\r
+ }\r
+\r
+ /* The end of the topic name was reached without finding a '/'. The topic\r
+ * name is invalid. */\r
+ if( thingNameLength + AWS_IOT_TOPIC_PREFIX_LENGTH >= ( size_t ) topicNameLength )\r
+ {\r
+ IOT_SET_AND_GOTO_CLEANUP( false );\r
+ }\r
+\r
+ /* Set the output parameters. */\r
+ *pThingName = pThingNameStart;\r
+ *pThingNameLength = thingNameLength;\r
+\r
+ IOT_FUNCTION_EXIT_NO_CLEANUP();\r
+}\r
+\r
+/*-----------------------------------------------------------*/\r
+\r
+AwsIotStatus_t AwsIot_ParseStatus( const char * pTopicName,\r
+ uint16_t topicNameLength )\r
+{\r
+ IOT_FUNCTION_ENTRY( AwsIotStatus_t, AWS_IOT_UNKNOWN );\r
+ const char * pSuffixStart = NULL;\r
+\r
+ /* Both 'accepted' and 'rejected' topics are of the same length\r
+ * The below is a defensive check at run time to ensure that.\r
+ */\r
+ Iot_DefaultAssert( AWS_IOT_ACCEPTED_SUFFIX_LENGTH == AWS_IOT_REJECTED_SUFFIX_LENGTH );\r
+\r
+ /* Check that the status topic name is at least as long as the\r
+ * "accepted" suffix. This length check will be good for rejected also\r
+ * as both are of 8 characters in length. */\r
+ if( topicNameLength > AWS_IOT_ACCEPTED_SUFFIX_LENGTH )\r
+ {\r
+ /* Calculate where the "accepted" suffix should start. */\r
+ pSuffixStart = pTopicName + topicNameLength - AWS_IOT_ACCEPTED_SUFFIX_LENGTH;\r
+\r
+ /* Check if the end of the status topic name is "/accepted". */\r
+ if( strncmp( pSuffixStart,\r
+ AWS_IOT_ACCEPTED_SUFFIX,\r
+ AWS_IOT_ACCEPTED_SUFFIX_LENGTH ) == 0 )\r
+ {\r
+ IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_ACCEPTED );\r
+ }\r
+\r
+ /* Check if the end of the status topic name is "/rejected". */\r
+ if( strncmp( pSuffixStart,\r
+ AWS_IOT_REJECTED_SUFFIX,\r
+ AWS_IOT_REJECTED_SUFFIX_LENGTH ) == 0 )\r
+ {\r
+ IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_REJECTED );\r
+ }\r
+ }\r
+\r
+ IOT_FUNCTION_EXIT_NO_CLEANUP();\r
+}\r
+\r
+/*-----------------------------------------------------------*/\r