int frame_codec_encode_frame()

in src/frame_codec.c [579:718]


int frame_codec_encode_frame(FRAME_CODEC_HANDLE frame_codec, uint8_t type, const PAYLOAD* payloads, size_t payload_count, const unsigned char* type_specific_bytes, uint32_t type_specific_size, ON_BYTES_ENCODED on_bytes_encoded, void* callback_context)
{
    int result;

    FRAME_CODEC_INSTANCE* frame_codec_data = (FRAME_CODEC_INSTANCE*)frame_codec;

    /* Codes_SRS_FRAME_CODEC_01_044: [If any of arguments `frame_codec` or `on_bytes_encoded` is NULL, `frame_codec_encode_frame` shall return a non-zero value.] */
    if ((frame_codec == NULL) ||
        (on_bytes_encoded == NULL) ||
        /* Codes_SRS_FRAME_CODEC_01_091: [If the argument type_specific_size is greater than 0 and type_specific_bytes is NULL, frame_codec_encode_frame shall return a non-zero value.] */
        ((type_specific_size > 0) && (type_specific_bytes == NULL)) ||
        /* Codes_SRS_FRAME_CODEC_01_092: [If type_specific_size is too big to allow encoding the frame according to the AMQP ISO then frame_codec_encode_frame shall return a non-zero value.] */
        (type_specific_size > MAX_TYPE_SPECIFIC_SIZE))
    {
        LogError("Bad arguments: frame_codec = %p, on_bytes_encoded = %p, type_specific_size = %u, type_specific_bytes = %p",
            frame_codec, on_bytes_encoded, (unsigned int)type_specific_size, type_specific_bytes);
        result = MU_FAILURE;
    }
    else if ((payloads == NULL) && (payload_count > 0))
    {
        /* Codes_SRS_FRAME_CODEC_01_107: [If the argument `payloads` is NULL and `payload_count` is non-zero, `frame_codec_encode_frame` shall return a non-zero value.]*/
        LogError("NULL payloads argument with non-zero payload count");
        result = MU_FAILURE;
    }
    else
    {
        /* round up to the 4 bytes for doff */
        /* Codes_SRS_FRAME_CODEC_01_067: [The value of the data offset is an unsigned, 8-bit integer specifying a count of 4-byte words.] */
        /* Codes_SRS_FRAME_CODEC_01_068: [Due to the mandatory 8-byte frame header, the frame is malformed if the value is less than 2.] */
        uint8_t padding_byte_count;
        uint32_t frame_body_offset = type_specific_size + 6;
        uint8_t doff = (uint8_t)((frame_body_offset + 3) / 4);
        size_t i;
        size_t frame_size;
        size_t frame_body_size = 0;
        frame_body_offset = doff * 4;
        padding_byte_count = (uint8_t)(frame_body_offset - type_specific_size - 6);

        for (i = 0; i < payload_count; i++)
        {
            /* Codes_SRS_FRAME_CODEC_01_110: [ If the `bytes` member of a payload entry is NULL, `frame_codec_encode_frame` shall fail and return a non-zero value. ] */
            if ((payloads[i].bytes == NULL) ||
                /* Codes_SRS_FRAME_CODEC_01_111: [ If the `length` member of a payload entry is 0, `frame_codec_encode_frame` shall fail and return a non-zero value. ] */
                (payloads[i].length == 0))
            {
                break;
            }

            frame_body_size += payloads[i].length;
        }

        if (i < payload_count)
        {
            LogError("Bad payload entry");
            result = MU_FAILURE;
        }
        else
        {
            /* Codes_SRS_FRAME_CODEC_01_063: [This is an unsigned 32-bit integer that MUST contain the total frame size of the frame header, extended header, and frame body.] */
            frame_size = frame_body_size + frame_body_offset;

            if (frame_size > frame_codec_data->max_frame_size)
            {
                /* Codes_SRS_FRAME_CODEC_01_095: [If the frame_size needed for the frame is bigger than the maximum frame size, frame_codec_encode_frame shall fail and return a non-zero value.] */
                LogError("Encoded frame size exceeds the maximum allowed frame size");
                result = MU_FAILURE;
            }
            else
            {
                /* Codes_SRS_FRAME_CODEC_01_108: [ Memory shall be allocated to hold the entire frame. ]*/
                unsigned char* encoded_frame = (unsigned char*)malloc(frame_size);
                if (encoded_frame == NULL)
                {
                    /* Codes_SRS_FRAME_CODEC_01_109: [ If allocating memory fails, `frame_codec_encode_frame` shall fail and return a non-zero value. ]*/
                    LogError("Cannot allocate memory for frame");
                    result = MU_FAILURE;
                }
                else
                {
                    /* Codes_SRS_FRAME_CODEC_01_042: [frame_codec_encode_frame encodes the header, type specific bytes and frame payload of a frame that has frame_payload_size bytes.]*/
                    /* Codes_SRS_FRAME_CODEC_01_055: [Frames are divided into three distinct areas: a fixed width frame header, a variable width extended header, and a variable width frame body.] */
                    /* Codes_SRS_FRAME_CODEC_01_056: [frame header The frame header is a fixed size (8 byte) structure that precedes each frame.] */
                    /* Codes_SRS_FRAME_CODEC_01_057: [The frame header includes mandatory information necessary to parse the rest of the frame including size and type information.] */
                    /* Codes_SRS_FRAME_CODEC_01_058: [extended header The extended header is a variable width area preceding the frame body.] */
                    /* Codes_SRS_FRAME_CODEC_01_059: [This is an extension point defined for future expansion.] */
                    /* Codes_SRS_FRAME_CODEC_01_060: [The treatment of this area depends on the frame type.]*/
                    /* Codes_SRS_FRAME_CODEC_01_062: [SIZE Bytes 0-3 of the frame header contain the frame size.] */
                    /* Codes_SRS_FRAME_CODEC_01_063: [This is an unsigned 32-bit integer that MUST contain the total frame size of the frame header, extended header, and frame body.] */
                    /* Codes_SRS_FRAME_CODEC_01_064: [The frame is malformed if the size is less than the size of the frame header (8 bytes).] */
                    unsigned char frame_header[6];
                    size_t current_pos = 0;
                    /* Codes_SRS_FRAME_CODEC_01_090: [If the type_specific_size - 2 does not divide by 4, frame_codec_encode_frame shall pad the type_specific bytes with zeroes so that type specific data is according to the AMQP ISO.] */
                    unsigned char padding_bytes[] = { 0x00, 0x00, 0x00 };

                    frame_header[0] = (frame_size >> 24) & 0xFF;
                    frame_header[1] = (frame_size >> 16) & 0xFF;
                    frame_header[2] = (frame_size >> 8) & 0xFF;
                    frame_header[3] = frame_size & 0xFF;
                    /* Codes_SRS_FRAME_CODEC_01_065: [DOFF Byte 4 of the frame header is the data offset.] */
                    frame_header[4] = doff;
                    /* Codes_SRS_FRAME_CODEC_01_069: [TYPE Byte 5 of the frame header is a type code.] */
                    frame_header[5] = type;

                    (void)memcpy(encoded_frame, frame_header, sizeof(frame_header));
                    current_pos += sizeof(frame_header);

                    if (type_specific_size > 0)
                    {
                        (void)memcpy(encoded_frame + current_pos, type_specific_bytes, type_specific_size);
                        current_pos += type_specific_size;
                    }

                    /* send padding bytes */
                    if (padding_byte_count > 0)
                    {
                        (void)memcpy(encoded_frame + current_pos, padding_bytes, padding_byte_count);
                        current_pos += padding_byte_count;
                    }

                    /* Codes_SRS_FRAME_CODEC_01_106: [All payloads shall be encoded in order as part of the frame.] */
                    for (i = 0; i < payload_count; i++)
                    {
                        (void)memcpy(encoded_frame + current_pos, payloads[i].bytes, payloads[i].length);
                        current_pos += payloads[i].length;
                    }

                    /* Codes_SRS_FRAME_CODEC_01_088: [Encoded bytes shall be passed to the `on_bytes_encoded` callback in a single call, while setting the `encode complete` argument to true.] */
                    on_bytes_encoded(callback_context, encoded_frame, frame_size, true);

                    free(encoded_frame);

                    /* Codes_SRS_FRAME_CODEC_01_043: [On success it shall return 0.] */
                    result = 0;
                }
            }
        }
    }

    return result;
}