#if HAVE_CRT
#define _CRTDBG_MAP_ALLOC 
#include <stdlib.h> 
#include <crtdbg.h>
#endif //HAVE_CRT
/*
* Copyright (C) 2020, University of the Basque Country (UPV/EHU)
* Contact for licensing options: <licensing-mcpttclient(at)mcopenplatform(dot)com>
*
* The original file was part of Open Source Doubango Framework
* Copyright (C) 2010-2011 Mamadou Diop.
* Copyright (C) 2012 Doubango Telecom <http://doubango.org>
*
* This file is part of Open Source Doubango Framework.
*
* DOUBANGO is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* DOUBANGO is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with DOUBANGO.
*
*/

#include "tinybfcp/tbfcp_pkt.h"

#include "tnet_endianness.h"

#include "tsk_debug.h"

#define SWITCH_CASE_TAKE_ATTR(type, cat, field) \
		case (type): \
		if (!p_self->##field) { \
			p_self->##field = (cat)*pp_attr, *pp_attr = tsk_null; \
            return 0; \
        } \
        break;

static int _tbfcp_pkt_add_attr(tbfcp_pkt_t* p_self, tbfcp_attr_t** pp_attr)
{
    if (!p_self || !pp_attr || !*pp_attr) {
        TSK_DEBUG_ERROR("Invalid parameter");
        return -1;
    }
    tsk_list_push_back_data(p_self->p_list_attrs, (void**)pp_attr);
    return 0;
}

static int _tbfcp_pkt_deinit(tbfcp_pkt_t *p_self)
{
    if (!p_self) {
        TSK_DEBUG_ERROR("Invalid parameter");
        return -1;
    }

    TSK_OBJECT_SAFE_FREE(p_self->p_list_attrs);
    return 0;
}

static int _tbfcp_pkt_init(tbfcp_pkt_t *p_self, tbfcp_primitive_t primitive, uint32_t conf_id, uint16_t transac_id, uint16_t user_id)
{
    if (!p_self) {
        TSK_DEBUG_ERROR("Invalid parameter");
        return -1;
    }

    if (!p_self->p_list_attrs && !(p_self->p_list_attrs = tsk_list_create())) {
        TSK_DEBUG_ERROR("Failed to create list");
        return -2;
    }
    if (!p_self->f_add_attr) {
        p_self->f_add_attr = _tbfcp_pkt_add_attr;
    }

    p_self->hdr.ver = TBFCP_VERSION;
    p_self->hdr.reserved = 0;
    p_self->hdr.primitive = primitive;
    p_self->hdr.conf_id = conf_id;
    p_self->hdr.transac_id = transac_id;
    p_self->hdr.user_id = user_id;

    return 0;
}
#define _tbfcp_pkt_init_empty(p_self, primitive) _tbfcp_pkt_init((p_self), (primitive), 0, 0, 0)

static int _tbfcp_pkt_init_2(tbfcp_pkt_t *p_self, tbfcp_primitive_t primitive)
{
    if (!p_self) {
        TSK_DEBUG_ERROR("Invalid parameter");
        return -1;
    }

    if (!p_self->p_list_attrs && !(p_self->p_list_attrs = tsk_list_create())) {
        TSK_DEBUG_ERROR("Failed to create list");
        return -2;
    }

    p_self->hdr.ver = TBFCP_VERSION;
    p_self->hdr.reserved = 0;
    p_self->hdr.primitive = primitive;

    return 0;
}

int tbfcp_pkt_add_attr(tbfcp_pkt_t* p_self, tbfcp_attr_t** pp_attr)
{
    if (!p_self || !pp_attr || !*pp_attr) {
        TSK_DEBUG_ERROR("Invalid parameter");
        return -1;
    }
    if (p_self->f_add_attr) {
        return p_self->f_add_attr(p_self, pp_attr);
    }
    return _tbfcp_pkt_add_attr(p_self, pp_attr);
}


int tbfcp_pkt_create_empty(tbfcp_primitive_t primitive, tbfcp_pkt_t** pp_self)
{
    extern const tsk_object_def_t *tbfcp_pkt_def_t;
    tbfcp_pkt_t* p_self;
    int ret;

    if (!pp_self) {
        TSK_DEBUG_ERROR("Invalid parameter");
        return -1;
    }
    if (!(p_self = tsk_object_new(tbfcp_pkt_def_t))) {
        TSK_DEBUG_ERROR("Failed to create object 'tbfcp_pkt_def_t'");
        return -2;
    }
    if ((ret = _tbfcp_pkt_init_empty(p_self, primitive))) {
        TSK_OBJECT_SAFE_FREE(p_self);
        return ret;
    }
    *pp_self = p_self;
    return 0;
}

int tbfcp_pkt_create(tbfcp_primitive_t primitive, uint32_t conf_id, uint16_t transac_id, uint16_t user_id, tbfcp_pkt_t** pp_self)
{
    int ret;

    if ((ret = tbfcp_pkt_create_empty(primitive, pp_self))) {
        return ret;
    }
    if ((ret = _tbfcp_pkt_init((*pp_self), primitive, conf_id, transac_id, user_id))) {
        TSK_OBJECT_SAFE_FREE((*pp_self));
        return ret;
    }
    return ret;
}

int tbfcp_pkt_get_size_in_octetunits_without_padding(const tbfcp_pkt_t* pc_self, tsk_size_t* p_size)
{
    const tsk_list_item_t* pc_item;
    const tbfcp_attr_t* pc_attr;
    tsk_size_t n_size;
    int ret;
    if (!pc_self || !p_size) {
        TSK_DEBUG_ERROR("Invalid parameter");
        return -1;
    }
    *p_size = TBFCP_PKT_HDR_SIZE_IN_OCTETS;
    tsk_list_foreach(pc_item, pc_self->p_list_attrs) {
        if ((pc_attr = (const tbfcp_attr_t*)pc_item->data)) {
            if ((ret = tbfcp_attr_get_size_in_octetunits_without_padding(pc_attr, &n_size))) {
                return ret;
            }
            *p_size += n_size;
        }
    }
    return 0;
}

int tbfcp_pkt_get_size_in_octetunits_with_padding(const tbfcp_pkt_t* pc_self, tsk_size_t* p_size)
{
    const tsk_list_item_t* pc_item;
    const tbfcp_attr_t* pc_attr;
    tsk_size_t n_size;
    int ret;
    if (!pc_self || !p_size) {
        TSK_DEBUG_ERROR("Invalid parameter");
        return -1;
    }
    *p_size = TBFCP_PKT_HDR_SIZE_IN_OCTETS;
    tsk_list_foreach(pc_item, pc_self->p_list_attrs) {
        if ((pc_attr = (const tbfcp_attr_t*)pc_item->data)) {
            if ((ret = tbfcp_attr_get_size_in_octetunits_with_padding(pc_attr, &n_size))) {
                return ret;
            }
            *p_size += n_size;
        }
    }
    return 0;
}

int tbfcp_pkt_write_with_padding(const tbfcp_pkt_t* pc_self, uint8_t* p_buff_ptr, tsk_size_t n_buff_size, tsk_size_t *p_written)
{
    const tsk_list_item_t* pc_item;
    const tbfcp_attr_t* pc_attr;
    tsk_size_t n_size;
    int ret;
    if (!pc_self || !p_buff_ptr || !n_buff_size || !p_written) {
        TSK_DEBUG_ERROR("Invalid parameter");
        return -1;
    }
    if ((ret = tbfcp_pkt_get_size_in_octetunits_with_padding(pc_self, p_written))) {
        return ret;
    }
    if ((n_buff_size < *p_written)) {
        TSK_DEBUG_ERROR("Buffer too short: %u<%u", n_buff_size, *p_written);
        return -1;
    }

    p_buff_ptr[0] = (((uint8_t)pc_self->hdr.ver) << 5) | (pc_self->hdr.reserved & 0x7F);
    p_buff_ptr[1] = (uint8_t)pc_self->hdr.primitive;
	*((uint32_t*)&p_buff_ptr[2]) = tnet_htons((unsigned short)((*p_written - TBFCP_PKT_HDR_SIZE_IN_OCTETS) >> 2));
    *((uint32_t*)&p_buff_ptr[4]) = (uint32_t)tnet_htonl(pc_self->hdr.conf_id);
    *((uint16_t*)&p_buff_ptr[8]) = tnet_htons(pc_self->hdr.transac_id);
    *((uint16_t*)&p_buff_ptr[10]) = tnet_htons(pc_self->hdr.user_id);

    p_buff_ptr += TBFCP_PKT_HDR_SIZE_IN_OCTETS;
    n_buff_size -= TBFCP_PKT_HDR_SIZE_IN_OCTETS;

    tsk_list_foreach(pc_item, pc_self->p_list_attrs) {
        if ((pc_attr = (const tbfcp_attr_t*)pc_item->data)) {
            if ((ret = tbfcp_attr_write_with_padding(pc_attr, p_buff_ptr, n_buff_size, &n_size))) {
                return ret;
            }
            p_buff_ptr += n_size;
            n_buff_size -= n_size;
        }
    }
    return 0;
}

// Useful to check TCP stream contains at least a complete BFCP packet
int tbfcp_pkt_is_complete(const uint8_t* pc_buff_ptr, tsk_size_t n_buff_size, tsk_bool_t *pb_is_complete)
{
    if (!pb_is_complete) {
        TSK_DEBUG_ERROR("Invalid parameter");
        return -1;
    }
    *pb_is_complete = tsk_false;
    if (pc_buff_ptr && n_buff_size >= TBFCP_PKT_HDR_SIZE_IN_OCTETS) {
        tsk_size_t n_paylen_in_octets = (tnet_ntohs_2(&pc_buff_ptr[2]) << 2);
        *pb_is_complete = ((n_buff_size - TBFCP_PKT_HDR_SIZE_IN_OCTETS) >= n_paylen_in_octets);
    }
    return 0;
}

int tbfcp_pkt_read(const uint8_t* pc_buff_ptr, tsk_size_t n_buff_size, tbfcp_pkt_t** pp_pkt)
{
    tsk_bool_t b_is_complete;
    tsk_size_t PayloadLengthInOctets;
    tbfcp_primitive_t Primitive;
    uint32_t ConferenceID;
    uint16_t TransactionID, UserID;
    int ret, Ver;
    if (!pc_buff_ptr || !n_buff_size || !pp_pkt) {
        TSK_DEBUG_ERROR("Invalid parameter");
        return -1;
    }
    if ((ret = tbfcp_pkt_is_complete(pc_buff_ptr, n_buff_size, &b_is_complete))) {
        return ret;
    }
    if (!b_is_complete) {
        TSK_DEBUG_ERROR("Buffer too short(%u)", n_buff_size);
        return -2;
    }
    Ver = (pc_buff_ptr[0] >> 5) & 0x07;
    if (Ver != TBFCP_VERSION) {
        TSK_DEBUG_ERROR("Version(%d)<>%d", Ver, TBFCP_VERSION);
        return -3;
    }
    Primitive = (tbfcp_primitive_t)pc_buff_ptr[1];
    PayloadLengthInOctets = (tnet_ntohs_2(&pc_buff_ptr[2]) << 2);
    ConferenceID = (uint32_t)tnet_ntohl_2(&pc_buff_ptr[4]);
    TransactionID = tnet_ntohs_2(&pc_buff_ptr[8]);
    UserID = tnet_ntohs_2(&pc_buff_ptr[10]);

    if((ret = tbfcp_pkt_create(Primitive, ConferenceID, TransactionID, UserID, pp_pkt))) {
        return ret;
    }

    if (PayloadLengthInOctets > 0) {
        tbfcp_attr_t* p_attr;
        tsk_size_t n_consumed_octets;
        pc_buff_ptr += TBFCP_PKT_HDR_SIZE_IN_OCTETS;
        do {
            if ((ret = tbfcp_attr_read(pc_buff_ptr, PayloadLengthInOctets, &n_consumed_octets, &p_attr))) {
                return ret;
            }
            if ((ret = tbfcp_pkt_add_attr((*pp_pkt), &p_attr))) {
                TSK_OBJECT_SAFE_FREE((*pp_pkt));
                return ret;
            }
            PayloadLengthInOctets -= n_consumed_octets;
            pc_buff_ptr += n_consumed_octets;
        }
        while (PayloadLengthInOctets >= TBFCP_ATTR_HDR_SIZE_IN_OCTETS);
    }

    return 0;
}

int tbfcp_pkt_attr_find_at(const struct tbfcp_pkt_s* pc_self, enum tbfcp_attribute_format_e e_format, tsk_size_t u_index, const struct tbfcp_attr_s** ppc_attr)
{
	tsk_size_t _u_index = 0;
	const tsk_list_item_t *pc_item;
	const struct tbfcp_attr_s* pc_attr;
	if (!pc_self || !ppc_attr) {
		TSK_DEBUG_ERROR("Invalid parameter");
		return -1;
	}
	*ppc_attr = tsk_null;
	tsk_list_foreach(pc_item, pc_self->p_list_attrs) {
		pc_attr = (const struct tbfcp_attr_s*)pc_item->data;
		if (!pc_attr || pc_attr->format != e_format) {
			continue;
		}
		if (_u_index++ >= u_index) {
			*ppc_attr = pc_attr;
			break;
		}
	}
	return 0;
}


static tsk_object_t* tbfcp_pkt_ctor(tsk_object_t * self, va_list * app)
{
    tbfcp_pkt_t *p_pkt = (tbfcp_pkt_t *)self;
    if (p_pkt) {
        p_pkt->f_add_attr = _tbfcp_pkt_add_attr;
        if (!(p_pkt->p_list_attrs = tsk_list_create())) {
            TSK_DEBUG_ERROR("Failed to create list");
            return tsk_null;
        }
    }
    return self;
}
static tsk_object_t* tbfcp_pkt_dtor(tsk_object_t * self)
{
    tbfcp_pkt_t *p_pkt = (tbfcp_pkt_t *)self;
    if (p_pkt) {
        TSK_DEBUG_INFO("*** BFCP Packet destroyed ***");
        TSK_OBJECT_SAFE_FREE(p_pkt->p_list_attrs);
    }

    return self;
}
static int tbfcp_pkt_cmp(const tsk_object_t *_pk1, const tsk_object_t *_pk2)
{
    const tbfcp_pkt_t *pc_pk1 = (const tbfcp_pkt_t *)_pk1;
    const tbfcp_pkt_t *pc_pk2 = (const tbfcp_pkt_t *)_pk2;

    return (int)(pc_pk1-pc_pk2);
}
static const tsk_object_def_t tbfcp_pkt_def_s = {
    sizeof(tbfcp_pkt_t),
    tbfcp_pkt_ctor,
    tbfcp_pkt_dtor,
    tbfcp_pkt_cmp,
};
const tsk_object_def_t *tbfcp_pkt_def_t = &tbfcp_pkt_def_s;


/***** rfc4582 - 5.3.1.  FloorRequest *****/
int tbfcp_pkt_create_FloorRequest_2(uint32_t conf_id, uint16_t transac_id, uint16_t user_id, uint16_t floor_id, tbfcp_pkt_t** pp_self)
{
    int ret;
    tbfcp_attr_unsigned16_t* p_floor_id;
    if ((ret = tbfcp_pkt_create_FloorRequest(conf_id, transac_id, user_id, pp_self))) {
        return ret;
    }
    if ((ret = tbfcp_attr_unsigned16_create(tbfcp_attribute_type_FLOOR_ID, kBfcpFieldMYes, floor_id, &p_floor_id))) {
        return ret;
    }
    if ((ret = tbfcp_pkt_add_attr(*pp_self, (tbfcp_attr_t**)&p_floor_id))) {
        TSK_OBJECT_SAFE_FREE(p_floor_id);
        return ret;
    }
    return 0;
}

/***** rfc4582 - 5.3.2.  FloorRelease  *****/
int tbfcp_pkt_create_FloorRelease_2(uint32_t conf_id, uint16_t transac_id, uint16_t user_id, uint16_t floor_req_id, tbfcp_pkt_t** pp_self)
{
    int ret;
    tbfcp_attr_unsigned16_t* p_floor_req_id;
    if ((ret = tbfcp_pkt_create_FloorRelease(conf_id, transac_id, user_id, pp_self))) {
        return ret;
    }
    if ((ret = tbfcp_attr_unsigned16_create(tbfcp_attribute_type_FLOOR_REQUEST_ID, kBfcpFieldMYes, floor_req_id, &p_floor_req_id))) {
        return ret;
    }
    if ((ret = tbfcp_pkt_add_attr(*pp_self, (tbfcp_attr_t**)&p_floor_req_id))) {
        TSK_OBJECT_SAFE_FREE(p_floor_req_id);
        return ret;
    }
    return 0;
}

/**** rfc4582 - 5.3.4.  FloorRequestStatus *****/
int tbfcp_pkt_create_FloorRequestStatus_2(uint32_t conf_id, uint16_t transac_id, uint16_t user_id, uint16_t floor_req_id, tbfcp_pkt_t** pp_self)
{
    int ret;
    tbfcp_attr_grouped_t* p_floor_req_info;
    if ((ret = tbfcp_pkt_create_FloorRequestStatus(conf_id, transac_id, user_id, pp_self))) {
        return ret;
    }
    if ((ret = tbfcp_attr_grouped_create_u16(tbfcp_attribute_type_FLOOR_REQUEST_INFORMATION, kBfcpFieldMNo, floor_req_id, &p_floor_req_info))) {
        return ret;
    }
    if ((ret = tbfcp_pkt_add_attr(*pp_self, (tbfcp_attr_t**)&p_floor_req_info))) {
        TSK_OBJECT_SAFE_FREE(p_floor_req_info);
        return ret;
    }
    return 0;
}

/**** 5.3.12.  HelloAck ***/
int tbfcp_pkt_create_HelloAck_2(uint32_t conf_id, uint16_t transac_id, uint16_t user_id, struct tbfcp_pkt_s** pp_self)
{
    tsk_size_t u;
    int ret;
    tbfcp_attr_octetstring_t *p_supp_attr, *p_supp_prim;
    static const uint8_t* kNullOctetStringPtr = tsk_null;
    static const tbfcp_primitive_t __supp_prims[] = {
        tbfcp_primitive_FloorRequest,
        tbfcp_primitive_FloorRelease,
        tbfcp_primitive_FloorRequestQuery,
        tbfcp_primitive_FloorRequestStatus,
        tbfcp_primitive_UserQuery,
        tbfcp_primitive_UserStatus,
        tbfcp_primitive_FloorQuery,
        tbfcp_primitive_FloorStatus,
        tbfcp_primitive_ChairAction,
        tbfcp_primitive_ChairActionAck,
        tbfcp_primitive_Hello,
        tbfcp_primitive_HelloAck,
        tbfcp_primitive_Error,
    };
    static const tsk_size_t __supp_prims_count = sizeof(__supp_prims)/sizeof(__supp_prims[0]);
    static const tbfcp_attribute_type_t __supp_attrs[] = {
        tbfcp_attribute_type_BENEFICIARY_ID,
        tbfcp_attribute_type_FLOOR_ID,
        tbfcp_attribute_type_FLOOR_REQUEST_ID,
        tbfcp_attribute_type_PRIORITY,
        tbfcp_attribute_type_REQUEST_STATUS,
        tbfcp_attribute_type_ERROR_CODE,
        tbfcp_attribute_type_ERROR_INFO,
        tbfcp_attribute_type_PARTICIPANT_PROVIDED_INFO,
        tbfcp_attribute_type_STATUS_INFO,
        tbfcp_attribute_type_SUPPORTED_ATTRIBUTES,
        tbfcp_attribute_type_SUPPORTED_PRIMITIVES,
        tbfcp_attribute_type_USER_DISPLAY_NAME,
        tbfcp_attribute_type_USER_URI,
        tbfcp_attribute_type_BENEFICIARY_INFORMATION,
        tbfcp_attribute_type_FLOOR_REQUEST_INFORMATION,
        tbfcp_attribute_type_REQUESTED_BY_INFORMATION,
        tbfcp_attribute_type_FLOOR_REQUEST_STATUS,
        tbfcp_attribute_type_OVERALL_REQUEST_STATUS,
    };
    static const tsk_size_t __supp_attrs_count = sizeof(__supp_attrs)/sizeof(__supp_attrs[0]);

    if ((ret = tbfcp_pkt_create_HelloAck(conf_id, transac_id, user_id, pp_self))) {
        return ret;
    }
    /* SUPPORTED-ATTRIBUTES */
    if ((ret = tbfcp_attr_octetstring_create(tbfcp_attribute_type_SUPPORTED_ATTRIBUTES, kBfcpFieldMNo, kNullOctetStringPtr, (uint8_t)__supp_attrs_count, &p_supp_attr))) {
        return ret;
    }
    for (u = 0; u < p_supp_attr->OctetStringLength; ++u) {
        p_supp_attr->OctetString[u] = (__supp_attrs[u] << 1/*R*/);
    }
    if ((ret = tbfcp_pkt_add_attr(*pp_self, (tbfcp_attr_t**)&p_supp_attr))) {
        TSK_OBJECT_SAFE_FREE(p_supp_attr);
        return ret;
    }
    /* SUPPORTED-PRIMITIVES */
    if ((ret = tbfcp_attr_octetstring_create(tbfcp_attribute_type_SUPPORTED_PRIMITIVES, kBfcpFieldMNo, kNullOctetStringPtr, (uint8_t)__supp_prims_count, &p_supp_prim))) {
        return ret;
    }
    for (u = 0; u < p_supp_prim->OctetStringLength; ++u) {
        p_supp_prim->OctetString[u] = __supp_prims[u];
    }
    if ((ret = tbfcp_pkt_add_attr(*pp_self, (tbfcp_attr_t**)&p_supp_prim))) {
        TSK_OBJECT_SAFE_FREE(p_supp_prim);
        return ret;
    }
    return 0;
}

#if 0
/***** rfc4582 - 5.3.1.  FloorRequest *****/
static int _tbfcp_pkt_FloorRequest_add_attr(tbfcp_pkt_t* _p_self, tbfcp_attr_t** pp_attr)
{
    tbfcp_pkt_FloorRequest_t* p_self = (tbfcp_pkt_FloorRequest_t*)_p_self;
    if (!p_self || !pp_attr || !*pp_attr) {
        TSK_DEBUG_ERROR("Invalid parameter");
        return -1;
    }
    switch ((*pp_attr)->hdr.type) {
        SWITCH_CASE_TAKE_ATTR(tbfcp_attribute_type_FLOOR_ID, struct tbfcp_attr_unsigned16_s*, p_floor_id);
        SWITCH_CASE_TAKE_ATTR(tbfcp_attribute_type_BENEFICIARY_ID, struct tbfcp_attr_unsigned16_s*, p_beneficiary_id);
        SWITCH_CASE_TAKE_ATTR(tbfcp_attribute_type_PARTICIPANT_PROVIDED_INFO, struct tbfcp_attr_octetstring_s*, p_participant_provided_info);
        SWITCH_CASE_TAKE_ATTR(tbfcp_attribute_type_PRIORITY, struct tbfcp_attr_octetstring16_s*, p_priority);
    }
    return _tbfcp_pkt_add_attr(_p_self, pp_attr);
}

int tbfcp_pkt_FloorRequest_create_empty(tbfcp_pkt_FloorRequest_t** pp_self)
{
    extern const tsk_object_def_t *tbfcp_pkt_FloorRequest_def_t;
    tbfcp_pkt_FloorRequest_t* p_self;
    int ret;

    if (!pp_self) {
        TSK_DEBUG_ERROR("Invalid parameter");
        return -1;
    }
    if (!(p_self = tsk_object_new(tbfcp_pkt_FloorRequest_def_t))) {
        TSK_DEBUG_ERROR("Failed to create object 'tbfcp_pkt_FloorRequest_def_t'");
        return -2;
    }
    if ((ret = _tbfcp_pkt_init_empty_FloorRequest(p_self))) {
        TSK_OBJECT_SAFE_FREE(p_self);
        return ret;
    }
    *pp_self = p_self;
    return 0;
}

int tbfcp_pkt_FloorRequest_create(uint32_t conf_id, uint16_t transac_id, uint16_t user_id, uint16_t floor_id, tbfcp_pkt_FloorRequest_t** pp_self)
{
    int ret;

    if ((ret = tbfcp_pkt_FloorRequest_create_empty(pp_self))) {
        return ret;
    }
    if ((ret = _tbfcp_pkt_init_FloorRequest((*pp_self), conf_id, transac_id, user_id))) {
        TSK_OBJECT_SAFE_FREE((*pp_self));
        return ret;
    }
    if ((ret = tbfcp_attr_unsigned16_create(tbfcp_attribute_type_FLOOR_ID, kBfcpFieldMYes, floor_id, &(*pp_self)->p_floor_id))) {
        TSK_OBJECT_SAFE_FREE((*pp_self));
        return ret;
    }
    return ret;
}

static tsk_object_t* tbfcp_pkt_FloorRequest_ctor(tsk_object_t * self, va_list * app)
{
    tbfcp_pkt_FloorRequest_t *p_pkt = (tbfcp_pkt_FloorRequest_t *)self;
    if (p_pkt) {
        TBFCP_PKT(p_pkt)->f_add_attr = _tbfcp_pkt_FloorRequest_add_attr;
    }
    return self;
}
static tsk_object_t* tbfcp_pkt_FloorRequest_dtor(tsk_object_t * self)
{
    tbfcp_pkt_FloorRequest_t *p_pkt = (tbfcp_pkt_FloorRequest_t *)self;
    if (p_pkt) {
        TSK_DEBUG_INFO("*** BFCP Packet(FloorRequest) destroyed ***");
        _tbfcp_pkt_deinit(TBFCP_PKT(p_pkt)); // dtor(base)
        TSK_OBJECT_SAFE_FREE(p_pkt->p_floor_id);
        TSK_OBJECT_SAFE_FREE(p_pkt->p_beneficiary_id);
        TSK_OBJECT_SAFE_FREE(p_pkt->p_participant_provided_info);
        TSK_OBJECT_SAFE_FREE(p_pkt->p_priority);
    }

    return self;
}
static int tbfcp_pkt_FloorRequest_cmp(const tsk_object_t *_pk1, const tsk_object_t *_pk2)
{
    const tbfcp_pkt_FloorRequest_t *pc_pk1 = (const tbfcp_pkt_FloorRequest_t *)_pk1;
    const tbfcp_pkt_FloorRequest_t *pc_pk2 = (const tbfcp_pkt_FloorRequest_t *)_pk2;

    return (int)(pc_pk1-pc_pk2);
}
static const tsk_object_def_t tbfcp_pkt_FloorRequest_def_s = {
    sizeof(tbfcp_pkt_FloorRequest_t),
    tbfcp_pkt_FloorRequest_ctor,
    tbfcp_pkt_FloorRequest_dtor,
    tbfcp_pkt_FloorRequest_cmp,
};
const tsk_object_def_t *tbfcp_pkt_FloorRequest_def_t = &tbfcp_pkt_FloorRequest_def_s;
#endif