A small memory footprint AMQP implimentation

Dependents:   iothub_client_sample_amqp remote_monitoring simplesample_amqp

amqpvalue_to_string.c

Committer:
AzureIoTClient
Date:
2017-06-30
Revision:
28:add19eb7defa
Parent:
25:1101516ee67d
Child:
30:0407b2db334c

File content as of revision 28:add19eb7defa:

// 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_c_shared_utility/gballoc.h"
#include "azure_uamqp_c/amqpvalue_to_string.h"
#include "azure_uamqp_c/amqpvalue.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
    {
        char* new_string;

        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;

        new_string = (char*)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)
            {
                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))
            {
                free(result);
                result = NULL;
            }
            break;
        }
        case AMQP_TYPE_UBYTE:
        {
            char str_value[4];
            uint8_t value;
            if (amqpvalue_get_ubyte(amqp_value, &value) != 0)
            {
                free(result);
                result = NULL;
            }
            else
            {
                unsigned int uint_value = value;
                if ((sprintf(str_value, "%u", uint_value) < 0) ||
                    (string_concat(&result, str_value) != 0))
                {
                    free(result);
                    result = NULL;
                }
            }
            break;
        }
        case AMQP_TYPE_USHORT:
        {
            char str_value[6];
            uint16_t value;
            if (amqpvalue_get_ushort(amqp_value, &value) != 0)
            {
                free(result);
                result = NULL;
            }
            else
            {
                unsigned int uint_value = value;
                if ((sprintf(str_value, "%u", uint_value) < 0) ||
                    (string_concat(&result, str_value) != 0))
                {
                    free(result);
                    result = NULL;
                }
            }
            break;
        }
        case AMQP_TYPE_UINT:
        {
            char str_value[11];
            uint32_t value;
            if (amqpvalue_get_uint(amqp_value, &value) != 0)
            {
                free(result);
                result = NULL;
            }
            else
            {
                unsigned long uint_value = value;
                if ((sprintf(str_value, "%lu", uint_value) < 0) ||
                    (string_concat(&result, str_value) != 0))
                {
                    free(result);
                    result = NULL;
                }
            }
            break;
        }
        case AMQP_TYPE_ULONG:
        {
            char str_value[21];
            uint64_t value;
            if (amqpvalue_get_ulong(amqp_value, &value) != 0)
            {
                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))
                {
                    free(result);
                    result = NULL;
                }
            }
            break;
        }
        case AMQP_TYPE_BYTE:
        {
            char str_value[5];
            uint8_t value;
            if (amqpvalue_get_ubyte(amqp_value, &value) != 0)
            {
                free(result);
                result = NULL;
            }
            else
            {
                int int_value = value;
                if ((sprintf(str_value, "%d", int_value) < 0) ||
                    (string_concat(&result, str_value) != 0))
                {
                    free(result);
                    result = NULL;
                }
            }
            break;
        }
        case AMQP_TYPE_SHORT:
        {
            char str_value[7];
            uint16_t value;
            if (amqpvalue_get_ushort(amqp_value, &value) != 0)
            {
                free(result);
                result = NULL;
            }
            else
            {
                int int_value = value;
                if ((sprintf(str_value, "%d", int_value) < 0) ||
                    (string_concat(&result, str_value) != 0))
                {
                    free(result);
                    result = NULL;
                }
            }
            break;
        }
        case AMQP_TYPE_INT:
        {
            char str_value[12];
            int32_t value;
            if (amqpvalue_get_int(amqp_value, &value) != 0)
            {
                free(result);
                result = NULL;
            }
            else
            {
                unsigned long int_value = value;
                if ((sprintf(str_value, "%ld", int_value) < 0) ||
                    (string_concat(&result, str_value) != 0))
                {
                    free(result);
                    result = NULL;
                }
            }
            break;
        }
        case AMQP_TYPE_LONG:
        {
            char str_value[21];
            uint64_t value;
            if (amqpvalue_get_ulong(amqp_value, &value) != 0)
            {
                free(result);
                result = NULL;
            }
            else
            {
                long long int_value = value;
                if ((sprintf(str_value, "%lld", int_value) < 0) ||
                    (string_concat(&result, str_value) != 0))
                {
                    free(result);
                    result = NULL;
                }
            }
            break;
        }
        case AMQP_TYPE_FLOAT:
        {
            float float_value;
            if (amqpvalue_get_float(amqp_value, &float_value) != 0)
            {
                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))
                {
                    free(result);
                    result = NULL;
                }
                if (string_concat(&result, str_value) != 0)
                {
                    free(result);
                    result = NULL;
                }
            }
            break;
        }
        case AMQP_TYPE_DOUBLE:
        {
            double double_value;
            if (amqpvalue_get_double(amqp_value, &double_value) != 0)
            {
                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))
                {
                    free(result);
                    result = NULL;
                }
                if (string_concat(&result, str_value) != 0)
                {
                    free(result);
                    result = NULL;
                }
            }
            break;
        }
        case AMQP_TYPE_CHAR:
        {
            uint32_t char_code;
            if (amqpvalue_get_char(amqp_value, &char_code) != 0)
            {
                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))
                {
                    free(result);
                    result = NULL;
                }
                if (string_concat(&result, str_value) != 0)
                {
                    free(result);
                    result = NULL;
                }
            }
            break;
        }
        case AMQP_TYPE_TIMESTAMP:
        {
            char str_value[21];
            int64_t value;
            if (amqpvalue_get_timestamp(amqp_value, &value) != 0)
            {
                free(result);
                result = NULL;
            }
            else
            {
                long long int_value = value;
                if ((sprintf(str_value, "%lld", int_value) < 0) ||
                    (string_concat(&result, str_value) != 0))
                {
                    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)
            {
                free(result);
                result = NULL;
            }
            else
            {
                if (string_concat(&result, "<") != 0)
                {
                    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)
                    {
                        free(result);
                        result = NULL;
                    }
                    else if (string_concat(&result, ">") != 0)
                    {
                        free(result);
                        result = NULL;
                    }
                }
            }
            break;
        }
        case AMQP_TYPE_STRING:
        {
            const char* string_value;
            if (amqpvalue_get_string(amqp_value, &string_value) != 0)
            {
                free(result);
                result = NULL;
            }
            else
            {
                if (string_concat(&result, string_value) != 0)
                {
                    free(result);
                    result = NULL;
                }
            }
            break;
        }
        case AMQP_TYPE_SYMBOL:
        {
            const char* string_value;
            if (amqpvalue_get_symbol(amqp_value, &string_value) != 0)
            {
                free(result);
                result = NULL;
            }
            else
            {
                if (string_concat(&result, string_value) != 0)
                {
                    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))
            {
                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))
                            {
                                free(result);
                                result = NULL;
                                break;
                            }
                            else if (string_concat(&result, item_string) != 0)
                            {
                                free(result);
                                result = NULL;
                                break;
                            }

                            free(item_string);
                        }

                        amqpvalue_destroy(item);
                    }
                }

                if ((i < count) ||
                    (string_concat(&result, "}") != 0))
                {
                    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))
            {
                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)
                            {
                                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))
                                {
                                    free(key_string);
                                    free(value_string);
                                    amqpvalue_destroy(key);
                                    amqpvalue_destroy(value);
                                    break;
                                }

                                free(value_string);
                            }

                            free(key_string);
                        }

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

                if ((i < count) ||
                    (string_concat(&result, "}") != 0))
                {
                    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))
            {
                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))
                            {
                                free(result);
                                result = NULL;
                                break;
                            }
                            else if (string_concat(&result, item_string) != 0)
                            {
                                free(result);
                                result = NULL;
                                break;
                            }

                            free(item_string);
                        }

                        amqpvalue_destroy(item);
                    }
                }

                if ((i < count) ||
                    (string_concat(&result, "}") != 0))
                {
                    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)
            {
                free(result);
                result = NULL;
            }
            else
            {
                if (string_concat(&result, "* ") != 0)
                {
                    free(result);
                    result = NULL;
                }
                else
                {
                    char* described_value_string = amqpvalue_to_string(described_value);
                    if (described_value_string == NULL)
                    {
                        free(result);
                        result = NULL;
                    }
                    else
                    {
                        if (string_concat(&result, described_value_string) != 0)
                        {
                            free(result);
                            result = NULL;
                        }

                        free(described_value_string);
                    }
                }
            }
            break;
        }
        }
    }

    return result;
}