A small memory footprint AMQP implimentation

Dependents:   iothub_client_sample_amqp remote_monitoring simplesample_amqp

amqpvalue_to_string.c

Committer:
AzureIoTClient
Date:
2017-02-24
Revision:
19:000ab4e6a2c1
Parent:
17:923575db8b2d
Child:
21:f9c433d8e6ca

File content as of revision 19:000ab4e6a2c1:

// 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>
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include <stdio.h>
#include "azure_c_shared_utility/optimize_size.h"
#include "azure_uamqp_c/amqpvalue_to_string.h"
#include "azure_uamqp_c/amqpvalue.h"
#include "azure_uamqp_c/amqpalloc.h"

#if _WIN32
/* The MS runtime does not have snprintf */
#define snprintf _snprintf
#endif

static int string_concat(char** string, const char* to_concat)
{
	int result;

	if ((string == NULL) ||
		(to_concat == NULL))
	{
		result = __FAILURE__;
	}
	else
	{
		size_t length = strlen(to_concat) + 1;
		size_t src_length;

		if (*string != NULL)
		{
			src_length = strlen(*string);
		}
		else
		{
			src_length = 0;
		}

		length += src_length;

		char* new_string = amqpalloc_realloc(*string, length);
		if (new_string == NULL)
		{
			result = __FAILURE__;
		}
		else
		{
			*string = new_string;
			(void)strcpy(*string + src_length, to_concat);
			result = 0;
		}
	}

	return result;
}

char* amqpvalue_to_string(AMQP_VALUE amqp_value)
{
	char* result = NULL;

	if (amqp_value != NULL)
	{
		AMQP_TYPE amqp_type = amqpvalue_get_type(amqp_value);
		switch (amqp_type)
		{
		default:
			result = NULL;
			break;

		case AMQP_TYPE_NULL:
			if (string_concat(&result, "NULL") != 0)
			{
				amqpalloc_free(result);
				result = NULL;
			}
			break;
		case AMQP_TYPE_BOOL:
		{
			bool value;
			if ((amqpvalue_get_boolean(amqp_value, &value) != 0) ||
				(string_concat(&result, (value == true) ? "true" : "false") != 0))
			{
				amqpalloc_free(result);
				result = NULL;
			}
			break;
		}
		case AMQP_TYPE_UBYTE:
		{
			char str_value[4];
			uint8_t value;
			if (amqpvalue_get_ubyte(amqp_value, &value) != 0)
			{
				amqpalloc_free(result);
				result = NULL;
			}
			else
			{
				unsigned int uint_value = value;
				if ((sprintf(str_value, "%u", uint_value) < 0) ||
					(string_concat(&result, str_value) != 0))
				{
					amqpalloc_free(result);
					result = NULL;
				}
			}
			break;
		}
		case AMQP_TYPE_USHORT:
		{
			char str_value[6];
			uint16_t value;
			if (amqpvalue_get_ushort(amqp_value, &value) != 0)
			{
				amqpalloc_free(result);
				result = NULL;
			}
			else
			{
				unsigned int uint_value = value;
				if ((sprintf(str_value, "%u", uint_value) < 0) ||
					(string_concat(&result, str_value) != 0))
				{
					amqpalloc_free(result);
					result = NULL;
				}
			}
			break;
		}
		case AMQP_TYPE_UINT:
		{
			char str_value[11];
			uint32_t value;
			if (amqpvalue_get_uint(amqp_value, &value) != 0)
			{
				amqpalloc_free(result);
				result = NULL;
			}
			else
			{
				unsigned long uint_value = value;
				if ((sprintf(str_value, "%lu", uint_value) < 0) ||
					(string_concat(&result, str_value) != 0))
				{
					amqpalloc_free(result);
					result = NULL;
				}
			}
			break;
		}
		case AMQP_TYPE_ULONG:
		{
			char str_value[21];
			uint64_t value;
			if (amqpvalue_get_ulong(amqp_value, &value) != 0)
			{
				amqpalloc_free(result);
				result = NULL;
			}
			else
			{
				unsigned long long uint_value = value;
				if ((sprintf(str_value, "%llu", uint_value) < 0) ||
					(string_concat(&result, str_value) != 0))
				{
					amqpalloc_free(result);
					result = NULL;
				}
			}
			break;
		}
		case AMQP_TYPE_BYTE:
		{
			char str_value[5];
			uint8_t value;
			if (amqpvalue_get_ubyte(amqp_value, &value) != 0)
			{
				amqpalloc_free(result);
				result = NULL;
			}
			else
			{
				int int_value = value;
				if ((sprintf(str_value, "%d", int_value) < 0) ||
					(string_concat(&result, str_value) != 0))
				{
					amqpalloc_free(result);
					result = NULL;
				}
			}
			break;
		}
		case AMQP_TYPE_SHORT:
		{
			char str_value[7];
			uint16_t value;
			if (amqpvalue_get_ushort(amqp_value, &value) != 0)
			{
				amqpalloc_free(result);
				result = NULL;
			}
			else
			{
				int int_value = value;
				if ((sprintf(str_value, "%d", int_value) < 0) ||
					(string_concat(&result, str_value) != 0))
				{
					amqpalloc_free(result);
					result = NULL;
				}
			}
			break;
		}
		case AMQP_TYPE_INT:
		{
			char str_value[12];
			int32_t value;
			if (amqpvalue_get_int(amqp_value, &value) != 0)
			{
				amqpalloc_free(result);
				result = NULL;
			}
			else
			{
				unsigned long int_value = value;
				if ((sprintf(str_value, "%ld", int_value) < 0) ||
					(string_concat(&result, str_value) != 0))
				{
					amqpalloc_free(result);
					result = NULL;
				}
			}
			break;
		}
		case AMQP_TYPE_LONG:
		{
			char str_value[21];
			uint64_t value;
			if (amqpvalue_get_ulong(amqp_value, &value) != 0)
			{
				amqpalloc_free(result);
				result = NULL;
			}
			else
			{
				long long int_value = value;
				if ((sprintf(str_value, "%lld", int_value) < 0) ||
					(string_concat(&result, str_value) != 0))
				{
					amqpalloc_free(result);
					result = NULL;
				}
			}
			break;
		}
		case AMQP_TYPE_FLOAT:
		{
			float float_value;
			if (amqpvalue_get_float(amqp_value, &float_value) != 0)
			{
				amqpalloc_free(result);
				result = NULL;
			}
			else
			{
				char str_value[25];
				if ((snprintf(str_value, sizeof(str_value), "%.02f", float_value) < 0) ||
					(string_concat(&result, str_value) != 0))
				{
					amqpalloc_free(result);
					result = NULL;
				}
				if (string_concat(&result, str_value) != 0)
				{
					amqpalloc_free(result);
					result = NULL;
				}
			}
			break;
		}
		case AMQP_TYPE_DOUBLE:
		{
			double double_value;
			if (amqpvalue_get_double(amqp_value, &double_value) != 0)
			{
				amqpalloc_free(result);
				result = NULL;
			}
			else
			{
				char str_value[25];
				if ((snprintf(str_value, sizeof(str_value), "%.02lf", double_value) < 0) ||
					(string_concat(&result, str_value) != 0))
				{
					amqpalloc_free(result);
					result = NULL;
				}
				if (string_concat(&result, str_value) != 0)
				{
					amqpalloc_free(result);
					result = NULL;
				}
			}
			break;
		}
		case AMQP_TYPE_CHAR:
		{
			uint32_t char_code;
			if (amqpvalue_get_char(amqp_value, &char_code) != 0)
			{
				amqpalloc_free(result);
				result = NULL;
			}
			else
			{
				char str_value[25];
				if ((snprintf(str_value, sizeof(str_value), "U%02X%02X%02X%02X", char_code >> 24, (char_code >> 16) & 0xFF, (char_code >> 8) & 0xFF, char_code & 0xFF) < 0) ||
					(string_concat(&result, str_value) != 0))
				{
					amqpalloc_free(result);
					result = NULL;
				}
				if (string_concat(&result, str_value) != 0)
				{
					amqpalloc_free(result);
					result = NULL;
				}
			}
			break;
		}
		case AMQP_TYPE_TIMESTAMP:
		{
			char str_value[21];
			int64_t value;
			if (amqpvalue_get_timestamp(amqp_value, &value) != 0)
			{
				amqpalloc_free(result);
				result = NULL;
			}
			else
			{
				long long int_value = value;
				if ((sprintf(str_value, "%lld", int_value) < 0) ||
					(string_concat(&result, str_value) != 0))
				{
					amqpalloc_free(result);
					result = NULL;
				}
			}
			break;
		}
		case AMQP_TYPE_UUID:
			break;
		case AMQP_TYPE_BINARY:
		{
			amqp_binary binary_value;
			if (amqpvalue_get_binary(amqp_value, &binary_value) != 0)
			{
				amqpalloc_free(result);
				result = NULL;
			}
			else
			{
				if (string_concat(&result, "<") != 0)
				{
					amqpalloc_free(result);
					result = NULL;
				}
				else
				{
					uint64_t i;

					for (i = 0; i < binary_value.length; i++)
					{
						char str_value[4];
						if ((snprintf(str_value, sizeof(str_value), "%s%02X", (i > 0) ? " " : "", ((unsigned char*)binary_value.bytes)[i]) < 0) ||
							(string_concat(&result, str_value) != 0))
						{
							break;
						}
					}

					if (i < binary_value.length)
					{
						amqpalloc_free(result);
						result = NULL;
					}
					else if (string_concat(&result, ">") != 0)
					{
						amqpalloc_free(result);
						result = NULL;
					}
				}
			}
			break;
		}
		case AMQP_TYPE_STRING:
		{
			const char* string_value;
			if (amqpvalue_get_string(amqp_value, &string_value) != 0)
			{
				amqpalloc_free(result);
				result = NULL;
			}
			else
			{
				if (string_concat(&result, string_value) != 0)
				{
					amqpalloc_free(result);
					result = NULL;
				}
			}
			break;
		}
		case AMQP_TYPE_SYMBOL:
		{
			const char* string_value;
			if (amqpvalue_get_symbol(amqp_value, &string_value) != 0)
			{
				amqpalloc_free(result);
				result = NULL;
			}
			else
			{
				if (string_concat(&result, string_value) != 0)
				{
					amqpalloc_free(result);
					result = NULL;
				}
			}
			break;
		}
		case AMQP_TYPE_LIST:
		{
			uint32_t count;
			if ((amqpvalue_get_list_item_count(amqp_value, &count) != 0) ||
				(string_concat(&result, "{") != 0))
			{
				amqpalloc_free(result);
				result = NULL;
			}
			else
			{
				size_t i;
				for (i = 0; i < count; i++)
				{
					AMQP_VALUE item = amqpvalue_get_list_item(amqp_value, i);
					if (item == NULL)
					{
						break;
					}
					else
					{
						char* item_string = amqpvalue_to_string(item);
						if (item_string == NULL)
						{
							amqpvalue_destroy(item);
							break;
						}
						else
						{
							if ((i > 0) && (string_concat(&result, ",") != 0))
							{
								amqpalloc_free(result);
								result = NULL;
								break;
							}
							else if (string_concat(&result, item_string) != 0)
							{
								amqpalloc_free(result);
								result = NULL;
								break;
							}

							amqpalloc_free(item_string);
						}

						amqpvalue_destroy(item);
					}
				}

				if ((i < count) ||
					(string_concat(&result, "}") != 0))
				{
					amqpalloc_free(result);
					result = NULL;
				}
			}
			break;
		}
		case AMQP_TYPE_MAP:
		{
			uint32_t count;
			if ((amqpvalue_get_map_pair_count(amqp_value, &count) != 0) ||
				(string_concat(&result, "{") != 0))
			{
				amqpalloc_free(result);
				result = NULL;
			}
			else
			{
				uint32_t i;
				for (i = 0; i < count; i++)
				{
					AMQP_VALUE key;
					AMQP_VALUE value;
					if (amqpvalue_get_map_key_value_pair(amqp_value, i, &key, &value) != 0)
					{
						break;
					}
					else
					{
						char* key_string = amqpvalue_to_string(key);
						if (key_string == NULL)
						{
							amqpvalue_destroy(key);
							amqpvalue_destroy(value);
							break;
						}
						else
						{
							char* value_string = amqpvalue_to_string(value);
							if (key_string == NULL)
							{
								amqpalloc_free(key_string);
								amqpvalue_destroy(key);
								amqpvalue_destroy(value);
								break;
							}
							else
							{
								if (((i > 0) && (string_concat(&result, ",") != 0)) ||
									(string_concat(&result, "[") != 0) ||
									(string_concat(&result, key_string) != 0) ||
									(string_concat(&result, ":") != 0) ||
									(string_concat(&result, value_string) != 0) ||
									(string_concat(&result, "]") != 0))
								{
									amqpalloc_free(key_string);
									amqpalloc_free(value_string);
									amqpvalue_destroy(key);
									amqpvalue_destroy(value);
									break;
								}

								amqpalloc_free(value_string);
							}

							amqpalloc_free(key_string);
						}

						amqpvalue_destroy(key);
						amqpvalue_destroy(value);
					}
				}

				if ((i < count) ||
					(string_concat(&result, "}") != 0))
				{
					amqpalloc_free(result);
					result = NULL;
				}
			}
			break;
		}
		case AMQP_TYPE_ARRAY:
		{
			uint32_t count;
			if ((amqpvalue_get_array_item_count(amqp_value, &count) != 0) ||
				(string_concat(&result, "{") != 0))
			{
				amqpalloc_free(result);
				result = NULL;
			}
			else
			{
				uint32_t i;
				for (i = 0; i < count; i++)
				{
					AMQP_VALUE item = amqpvalue_get_array_item(amqp_value, i);
					if (item == NULL)
					{
						break;
					}
					else
					{
						char* item_string = amqpvalue_to_string(item);
						if (item_string == NULL)
						{
							amqpvalue_destroy(item);
							break;
						}
						else
						{
							if ((i > 0) && (string_concat(&result, ",") != 0))
							{
								amqpalloc_free(result);
								result = NULL;
								break;
							}
							else if (string_concat(&result, item_string) != 0)
							{
								amqpalloc_free(result);
								result = NULL;
								break;
							}

							amqpalloc_free(item_string);
						}

						amqpvalue_destroy(item);
					}
				}

				if ((i < count) ||
					(string_concat(&result, "}") != 0))
				{
					amqpalloc_free(result);
					result = NULL;
				}
			}
			break;
		}
		case AMQP_TYPE_COMPOSITE:
		case AMQP_TYPE_DESCRIBED:
		{
			AMQP_VALUE described_value = amqpvalue_get_inplace_described_value(amqp_value);
			if (described_value == NULL)
			{
				amqpalloc_free(result);
				result = NULL;
			}
			else
			{
				if (string_concat(&result, "* ") != 0)
				{
					amqpalloc_free(result);
					result = NULL;
				}
				else
				{
					char* described_value_string = amqpvalue_to_string(described_value);
					if (described_value_string == NULL)
					{
						amqpalloc_free(result);
						result = NULL;
					}
					else
					{
						if (string_concat(&result, described_value_string) != 0)
						{
							amqpalloc_free(result);
							result = NULL;
						}

						amqpalloc_free(described_value_string);
					}
				}
			}
			break;
		}
		}
	}

	return result;
}