doubango/tinyBFCP/src/tbfcp_attr.c
c732d49e
 #if HAVE_CRT
 #define _CRTDBG_MAP_ALLOC 
 #include <stdlib.h> 
 #include <crtdbg.h>
 #endif //HAVE_CRT
 /*
74ca6d11
 * Copyright (C) 2020, University of the Basque Country (UPV/EHU)
c732d49e
 * 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_attr.h"
 
 #include "tnet_endianness.h"
 
 #include "tsk_memory.h"
 #include "tsk_debug.h"
 
 #define kWithoutPadding		tsk_false
 #define kWithPadding		tsk_true
 
 #define ALIGN_ON_32BITS(size_in_octes) if (((size_in_octes) & 3)) (size_in_octes) += (4 - ((size_in_octes) & 3));
 #define ALIGN_ON_32BITS_AND_SET_PADDING_ZEROS(p_buffer, size_in_octes) \
 	if (((size_in_octes) & 3)) { \
 		int c = (4 - ((size_in_octes) & 3)); \
 		memset(p_buffer, 0, c); \
 		(size_in_octes) += c; \
 	}
 
 
 static enum tbfcp_attribute_format_e _tbfcp_attr_get_format(enum tbfcp_attribute_type_e type)
 {
     switch (type) {
     case tbfcp_attribute_type_BENEFICIARY_ID:
         case tbfcp_attribute_type_FLOOR_ID:
             case tbfcp_attribute_type_FLOOR_REQUEST_ID:
                     return tbfcp_attribute_format_Unsigned16;
     case tbfcp_attribute_type_PRIORITY:
     case tbfcp_attribute_type_REQUEST_STATUS:
         return tbfcp_attribute_format_OctetString16;
     case tbfcp_attribute_type_ERROR_CODE:
     case tbfcp_attribute_type_ERROR_INFO:
     case tbfcp_attribute_type_PARTICIPANT_PROVIDED_INFO:
     case tbfcp_attribute_type_STATUS_INFO:
     case tbfcp_attribute_type_SUPPORTED_ATTRIBUTES:
     case tbfcp_attribute_type_SUPPORTED_PRIMITIVES:
     case tbfcp_attribute_type_USER_DISPLAY_NAME:
     case tbfcp_attribute_type_USER_URI:
         return tbfcp_attribute_format_OctetString;
     case tbfcp_attribute_type_BENEFICIARY_INFORMATION:
     case tbfcp_attribute_type_FLOOR_REQUEST_INFORMATION:
     case tbfcp_attribute_type_REQUESTED_BY_INFORMATION:
     case tbfcp_attribute_type_FLOOR_REQUEST_STATUS:
     case tbfcp_attribute_type_OVERALL_REQUEST_STATUS:
         return tbfcp_attribute_format_Grouped;
     default:
         return tbfcp_attribute_format_Unknown;
 
     }
 }
 
 static int _tbfcp_attr_get_size_in_octetunits(const tbfcp_attr_t* pc_self, tsk_bool_t with_padding, tsk_size_t* p_size)
 {
     if (!pc_self || !p_size) {
         TSK_DEBUG_ERROR("Invalid parameter");
         return -1;
     }
     switch (pc_self->format) {
     case tbfcp_attribute_format_Unsigned16:
     case tbfcp_attribute_format_OctetString16: {
         *p_size = (TBFCP_ATTR_HDR_SIZE_IN_OCTETS + 2);
         if (with_padding) {
             ALIGN_ON_32BITS(*p_size);
         }
         return 0;
     }
     case tbfcp_attribute_format_OctetString: {
         *p_size = (TBFCP_ATTR_HDR_SIZE_IN_OCTETS + ((const tbfcp_attr_octetstring_t*)pc_self)->OctetStringLength);
 		if (with_padding) {
 			ALIGN_ON_32BITS(*p_size);
 		}
         return 0;
     }
     case tbfcp_attribute_format_Grouped: {
         int ret;
         tsk_size_t n_size;
         const tbfcp_attr_grouped_t* _pc_self = (const tbfcp_attr_grouped_t*)pc_self;
         const tsk_list_item_t* pc_item;
         const tbfcp_attr_t* pc_attr;
         *p_size = TBFCP_ATTR_HDR_SIZE_IN_OCTETS + _pc_self->extra_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;
             }
         }
         if (with_padding) {
             ALIGN_ON_32BITS(*p_size);
         }
         return 0;
     }
     default: {
         TSK_DEBUG_WARN("Attribute format=%d is unknown. Don't be surprised if something goes wrong.", pc_self->format);
         *p_size = (TBFCP_ATTR_HDR_SIZE_IN_OCTETS + pc_self->hdr.length);
         if (with_padding) {
             ALIGN_ON_32BITS(*p_size);
         }
         return 0;
     }
     }
 }
 
 int tbfcp_attr_get_size_in_octetunits_without_padding(const tbfcp_attr_t* pc_self, tsk_size_t* p_size)
 {
     return _tbfcp_attr_get_size_in_octetunits(pc_self, kWithoutPadding, p_size);
 }
 
 int tbfcp_attr_get_size_in_octetunits_with_padding(const tbfcp_attr_t* pc_self, tsk_size_t* p_size)
 {
     return _tbfcp_attr_get_size_in_octetunits(pc_self, kWithPadding, p_size);
 }
 
 static int _tbfcp_attr_write(const tbfcp_attr_t* pc_self, uint8_t* p_buff_ptr, tsk_size_t n_buff_size, tsk_bool_t with_padding, tsk_size_t *p_written)
 {
     tsk_size_t n_min_req_size;
     int ret;
     if (!pc_self || !p_buff_ptr || !n_buff_size || !p_written) {
         TSK_DEBUG_ERROR("Invalid parameter");
         return -1;
     }
     if ((ret = _tbfcp_attr_get_size_in_octetunits(pc_self, with_padding, &n_min_req_size))) {
         return ret;
     }
     if (n_min_req_size > n_buff_size) {
         TSK_DEBUG_ERROR("Buffer too short %u<%u", n_buff_size, n_min_req_size);
         return -2;
     }
 
     p_buff_ptr[0] = ((uint8_t)pc_self->hdr.type) << 1;
     p_buff_ptr[0] |= (pc_self->hdr.M & 0x01);
 
     switch (pc_self->format) {
     case tbfcp_attribute_format_Unsigned16:
     case tbfcp_attribute_format_OctetString16: {
         *p_written = TBFCP_ATTR_HDR_SIZE_IN_OCTETS + 2;
         p_buff_ptr[1] = (uint8_t)*p_written;
         if (pc_self->format == tbfcp_attribute_format_Unsigned16) {
             *((uint16_t*)&p_buff_ptr[2]) = tnet_htons(((const tbfcp_attr_unsigned16_t*)pc_self)->Unsigned16);
         }
         else {
             p_buff_ptr[2] = ((const tbfcp_attr_octetstring16_t*)pc_self)->OctetString16[0];
             p_buff_ptr[3] = ((const tbfcp_attr_octetstring16_t*)pc_self)->OctetString16[1];
         }
         if (with_padding) {
             ALIGN_ON_32BITS_AND_SET_PADDING_ZEROS(&p_buff_ptr[*p_written], *p_written);
         }
         return 0;
     }
     case tbfcp_attribute_format_OctetString: {
         const tbfcp_attr_octetstring_t* _pc_self = (const tbfcp_attr_octetstring_t*)pc_self;
         *p_written = TBFCP_ATTR_HDR_SIZE_IN_OCTETS + ((_pc_self->OctetStringLength && _pc_self->OctetString) ? _pc_self->OctetStringLength : 0);
         p_buff_ptr[1] = (uint8_t)*p_written;
         if (_pc_self->OctetStringLength && _pc_self->OctetString) {
             memcpy(&p_buff_ptr[2], _pc_self->OctetString, _pc_self->OctetStringLength);
         }
         if (with_padding) {
             ALIGN_ON_32BITS_AND_SET_PADDING_ZEROS(&p_buff_ptr[*p_written], *p_written);
         }
         return 0;
     }
     case tbfcp_attribute_format_Grouped: {
         int ret;
         tsk_size_t n_written;
         const tbfcp_attr_grouped_t* _pc_self = (const tbfcp_attr_grouped_t*)pc_self;
         const tsk_list_item_t* pc_item;
         const tbfcp_attr_t* pc_attr;
         if (_pc_self->extra_hdr_size_in_octets && _pc_self->extra_hdr_size_in_octets != 2) {
             TSK_DEBUG_ERROR("extra_hdr_size_in_octets=%u not valid", _pc_self->extra_hdr_size_in_octets); // for now only 2byte extra values is supported
             return -2;
         }
         if ((ret = tbfcp_attr_get_size_in_octetunits_without_padding(pc_self, p_written))) {
             return ret;
         }
         p_buff_ptr[1] = (uint8_t)*p_written;
         p_buff_ptr += 2;
         n_buff_size -= 2;
         if (_pc_self->extra_hdr_size_in_octets) {
             *((uint16_t*)p_buff_ptr) = tnet_htons_2(&_pc_self->extra_hdr);
             p_buff_ptr += _pc_self->extra_hdr_size_in_octets;
             n_buff_size -= _pc_self->extra_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(pc_attr, p_buff_ptr, n_buff_size, kWithoutPadding, &n_written))) {
                     return ret;
                 }
                 p_buff_ptr += n_written;
                 n_buff_size -= n_written;
             }
         }
         if (with_padding) {
             ALIGN_ON_32BITS_AND_SET_PADDING_ZEROS(&p_buff_ptr[*p_written], *p_written);
         }
         return 0;
     }
     default: {
         TSK_DEBUG_ERROR("Attribute format=%d is unknown.", pc_self->format);
         return -2;
     }
     }
 }
 
 int tbfcp_attr_write_without_padding(const tbfcp_attr_t* pc_self, uint8_t* p_buff_ptr, tsk_size_t n_buff_size, tsk_size_t *p_written)
 {
     return _tbfcp_attr_write(pc_self, p_buff_ptr, n_buff_size, kWithoutPadding, p_written);
 }
 
 int tbfcp_attr_write_with_padding(const tbfcp_attr_t* pc_self, uint8_t* p_buff_ptr, tsk_size_t n_buff_size, tsk_size_t *p_written)
 {
     return _tbfcp_attr_write(pc_self, p_buff_ptr, n_buff_size, kWithPadding, p_written);
 }
 
 int tbfcp_attr_read(const uint8_t* pc_buff_ptr, tsk_size_t n_buff_size, tsk_size_t *p_consumed_octets, tbfcp_attr_t** pp_attr)
 {
     uint8_t M, Length, PadLength;
     tbfcp_attribute_type_t Type;
     tbfcp_attribute_format_t Format;
     int ret;
     if (!pc_buff_ptr || !n_buff_size || !pp_attr || !p_consumed_octets) {
         TSK_DEBUG_ERROR("Invalid parameter");
         return -1;
     }
     if (n_buff_size < TBFCP_ATTR_HDR_SIZE_IN_OCTETS) {
         TSK_DEBUG_ERROR("Buffer too short(%u)", n_buff_size);
         return -2;
     }
 
     Length = pc_buff_ptr[1];
     if (Length > n_buff_size) {
         TSK_DEBUG_ERROR("Buffer too short(%u). Length=%u", n_buff_size, Length);
         return -3;
     }
 
     PadLength = (Length & 0x03) ? (4 - (Length & 0x03)) : 0;
 
     *pp_attr = tsk_null;
     *p_consumed_octets = Length + PadLength;
 
     Type = (pc_buff_ptr[0] >> 1) & 0x7F;
     M = (pc_buff_ptr[0] & 0x01);
     Format = _tbfcp_attr_get_format(Type);
     if (Format == tbfcp_attribute_format_Unknown) {
         return 0;
     }
 
     if (Format == tbfcp_attribute_format_Unsigned16) {
         uint16_t Unsigned16 = tnet_ntohs_2(&pc_buff_ptr[2]);
         if ((ret = tbfcp_attr_unsigned16_create(Type, M, Unsigned16, (tbfcp_attr_unsigned16_t**)pp_attr))) {
             return ret;
         }
     }
     else if (Format == tbfcp_attribute_format_OctetString16) {
         uint8_t OctetString16[2];
         OctetString16[0] = pc_buff_ptr[2];
         OctetString16[1] = pc_buff_ptr[3];
         if ((ret = tbfcp_attr_octetstring16_create(Type, M, OctetString16, (tbfcp_attr_octetstring16_t**)pp_attr))) {
             return ret;
         }
     }
     else if (Format == tbfcp_attribute_format_OctetString) {
         const uint8_t *OctetString = &pc_buff_ptr[TBFCP_ATTR_HDR_SIZE_IN_OCTETS];
         uint8_t OctetStringLength = (Length - TBFCP_ATTR_HDR_SIZE_IN_OCTETS);
         if ((ret = tbfcp_attr_octetstring_create(Type, M, OctetString, OctetStringLength, (tbfcp_attr_octetstring_t**)pp_attr))) {
             return ret;
         }
     }
     else if (Format == tbfcp_attribute_format_Grouped) {
         tbfcp_attr_grouped_t* p_attr;
         if ((ret = tbfcp_attr_grouped_create(Type, M, &p_attr))) {
             return ret;
         }
         *pp_attr = (tbfcp_attr_t*)p_attr;
         switch (Type) {
         case tbfcp_attribute_type_BENEFICIARY_INFORMATION: {
             p_attr->extra_hdr_size_in_octets = 2;
             p_attr->extra_hdr.BeneficiaryID = tnet_ntohs_2(&pc_buff_ptr[2]);
             break;
         }
         case tbfcp_attribute_type_FLOOR_REQUEST_INFORMATION: {
             p_attr->extra_hdr_size_in_octets = 2;
             p_attr->extra_hdr.FloorRequestID = tnet_ntohs_2(&pc_buff_ptr[2]);
             break;
         }
         case tbfcp_attribute_type_REQUESTED_BY_INFORMATION: {
             p_attr->extra_hdr_size_in_octets = 2;
             p_attr->extra_hdr.RequestedbyID = tnet_ntohs_2(&pc_buff_ptr[2]);
             break;
         }
         case tbfcp_attribute_type_FLOOR_REQUEST_STATUS: {
             p_attr->extra_hdr_size_in_octets = 2;
             p_attr->extra_hdr.FloorID = tnet_ntohs_2(&pc_buff_ptr[2]);
             break;
         }
         case tbfcp_attribute_type_OVERALL_REQUEST_STATUS: {
             p_attr->extra_hdr_size_in_octets = 2;
             p_attr->extra_hdr.FloorRequestID = tnet_ntohs_2(&pc_buff_ptr[2]);
             break;
         }
         default: {
             return 0;
         }
         }
         if ((TBFCP_ATTR_HDR_SIZE_IN_OCTETS + p_attr->extra_hdr_size_in_octets) < Length) {
             tsk_size_t n_consumed_octets, PayloadLength = Length;
             PayloadLength -= TBFCP_ATTR_HDR_SIZE_IN_OCTETS + p_attr->extra_hdr_size_in_octets;
             pc_buff_ptr += TBFCP_ATTR_HDR_SIZE_IN_OCTETS + p_attr->extra_hdr_size_in_octets;
             if (PayloadLength >= TBFCP_ATTR_HDR_SIZE_IN_OCTETS) {
                 do {
                     if ((ret = tbfcp_attr_read(pc_buff_ptr, PayloadLength, &n_consumed_octets, (tbfcp_attr_t**)&p_attr))) {
                         break;
                     }
                     if ((ret = tbfcp_attr_grouped_add_attr((tbfcp_attr_grouped_t*)(*pp_attr), (tbfcp_attr_t**)&p_attr))) {
                         TSK_OBJECT_SAFE_FREE(p_attr);
                         break;
                     }
                     pc_buff_ptr += n_consumed_octets;
                     PayloadLength -= n_consumed_octets;
                 }
                 while (PayloadLength >= TBFCP_ATTR_HDR_SIZE_IN_OCTETS);
             }
         }
     }
     else {
         TSK_DEBUG_ERROR("%d not valid attribute format", Format);
         return -4;
     }
     return 0;
 }
 
 
 static int _tbfcp_attr_init(tbfcp_attr_t* p_self, tbfcp_attribute_type_t type, unsigned M, uint8_t length)
 {
     if (!p_self) {
         TSK_DEBUG_ERROR("Invalid parameter");
         return -1;
     }
     if (!p_self->pc_base) {
         p_self->pc_base = p_self;
     }
     p_self->hdr.type = type;
     p_self->hdr.M = M;
     p_self->hdr.length = length;
     if ((p_self->format = _tbfcp_attr_get_format(type)) == tbfcp_attribute_format_Unknown) {
         TSK_DEBUG_WARN("Attribute type=%d is unknown...setting its format to UNKNOWN. Don't be surprised if something goes wrong.", type);
     }
 
     return 0;
 }
 
 
 /*************** tbfcp_attr_unsigned16 *******************/
 int tbfcp_attr_unsigned16_create(tbfcp_attribute_type_t type, unsigned M, uint16_t Unsigned16, tbfcp_attr_unsigned16_t** pp_self)
 {
     extern const tsk_object_def_t *tbfcp_attr_unsigned16_def_t;
     tbfcp_attr_unsigned16_t* p_self;
     int ret;
     if (!pp_self) {
         TSK_DEBUG_ERROR("Invalid parameter");
         return -1;
     }
     if (!(p_self = tsk_object_new(tbfcp_attr_unsigned16_def_t))) {
         TSK_DEBUG_ERROR("Failed to create 'tbfcp_attr_unsigned16_def_t' object");
         return -2;
     }
     if ((ret = _tbfcp_attr_init(TBFCP_ATTR(p_self), type, M, TBFCP_ATTR_HDR_SIZE_IN_OCTETS + 2))) {
         TSK_OBJECT_SAFE_FREE(p_self);
         return -3;
     }
     if (TBFCP_ATTR(p_self)->format != tbfcp_attribute_format_Unsigned16) {
         TSK_DEBUG_ERROR("Format mismatch");
         TSK_OBJECT_SAFE_FREE(p_self);
         return -4;
     }
     p_self->Unsigned16 = Unsigned16;
     *pp_self = p_self;
     return 0;
 }
 
 static tsk_object_t* tbfcp_attr_unsigned16_ctor(tsk_object_t * self, va_list * app)
 {
     tbfcp_attr_unsigned16_t *p_u16 = (tbfcp_attr_unsigned16_t *)self;
     if (p_u16) {
     }
     return self;
 }
 static tsk_object_t* tbfcp_attr_unsigned16_dtor(tsk_object_t * self)
 {
     tbfcp_attr_unsigned16_t *p_u16 = (tbfcp_attr_unsigned16_t *)self;
     if (p_u16) {
         TSK_DEBUG_INFO("*** BFCP Attribute(Unsigned16) destroyed ***");
 
     }
     return self;
 }
 static int tbfcp_attr_unsigned16_cmp(const tsk_object_t *_att1, const tsk_object_t *_att2)
 {
     const tbfcp_attr_unsigned16_t *pc_att1 = (const tbfcp_attr_unsigned16_t *)_att1;
     const tbfcp_attr_unsigned16_t *pc_att2 = (const tbfcp_attr_unsigned16_t *)_att2;
 
     return (int)(pc_att1-pc_att2);
 }
 static const tsk_object_def_t tbfcp_attr_unsigned16_def_s = {
     sizeof(tbfcp_attr_unsigned16_t),
     tbfcp_attr_unsigned16_ctor,
     tbfcp_attr_unsigned16_dtor,
     tbfcp_attr_unsigned16_cmp,
 };
 const tsk_object_def_t *tbfcp_attr_unsigned16_def_t = &tbfcp_attr_unsigned16_def_s;
 
 
 
 
 /*************** tbfcp_attr_octetstring16 *******************/
 int tbfcp_attr_octetstring16_create(tbfcp_attribute_type_t type, unsigned M, uint8_t OctetString16[2], tbfcp_attr_octetstring16_t** pp_self)
 {
     extern const tsk_object_def_t *tbfcp_attr_octetstring16_def_t;
     tbfcp_attr_octetstring16_t* p_self;
     int ret;
     if (!pp_self) {
         TSK_DEBUG_ERROR("Invalid parameter");
         return -1;
     }
     if (!(p_self = tsk_object_new(tbfcp_attr_octetstring16_def_t))) {
         TSK_DEBUG_ERROR("Failed to create 'tbfcp_attr_octetstring16_def_t' object");
         return -2;
     }
     if ((ret = _tbfcp_attr_init(TBFCP_ATTR(p_self), type, M, TBFCP_ATTR_HDR_SIZE_IN_OCTETS + 2))) {
         TSK_OBJECT_SAFE_FREE(p_self);
         return -3;
     }
     if (TBFCP_ATTR(p_self)->format != tbfcp_attribute_format_OctetString16) {
         TSK_DEBUG_ERROR("Format mismatch");
         TSK_OBJECT_SAFE_FREE(p_self);
         return -4;
     }
     p_self->OctetString16[0] = OctetString16[0];
     p_self->OctetString16[1] = OctetString16[1];
     *pp_self = p_self;
     return 0;
 }
 
 static tsk_object_t* tbfcp_attr_octetstring16_ctor(tsk_object_t * self, va_list * app)
 {
     tbfcp_attr_octetstring16_t *p_os16 = (tbfcp_attr_octetstring16_t *)self;
     if (p_os16) {
     }
     return self;
 }
 static tsk_object_t* tbfcp_attr_octetstring16_dtor(tsk_object_t * self)
 {
     tbfcp_attr_octetstring16_t *p_os16 = (tbfcp_attr_octetstring16_t *)self;
     if (p_os16) {
         TSK_DEBUG_INFO("*** BFCP Attribute(OctetString16) destroyed ***");
 
     }
     return self;
 }
 static int tbfcp_attr_octetstring16_cmp(const tsk_object_t *_att1, const tsk_object_t *_att2)
 {
     const tbfcp_attr_octetstring16_t *pc_att1 = (const tbfcp_attr_octetstring16_t *)_att1;
     const tbfcp_attr_octetstring16_t *pc_att2 = (const tbfcp_attr_octetstring16_t *)_att2;
 
     return (int)(pc_att1-pc_att2);
 }
 static const tsk_object_def_t tbfcp_attr_octetstring16_def_s = {
     sizeof(tbfcp_attr_octetstring16_t),
     tbfcp_attr_octetstring16_ctor,
     tbfcp_attr_octetstring16_dtor,
     tbfcp_attr_octetstring16_cmp,
 };
 const tsk_object_def_t *tbfcp_attr_octetstring16_def_t = &tbfcp_attr_octetstring16_def_s;
 
 
 /*************** tbfcp_attr_octetstring *******************/
 int tbfcp_attr_octetstring_create(tbfcp_attribute_type_t type, unsigned M, const uint8_t *OctetString, uint8_t OctetStringLength, tbfcp_attr_octetstring_t** pp_self)
 {
     extern const tsk_object_def_t *tbfcp_attr_octetstring_def_t;
     tbfcp_attr_octetstring_t* p_self;
     int ret;
     if (!pp_self) {
         TSK_DEBUG_ERROR("Invalid parameter");
         return -1;
     }
     if (!(p_self = tsk_object_new(tbfcp_attr_octetstring_def_t))) {
         TSK_DEBUG_ERROR("Failed to create 'tbfcp_attr_octetstring_def_t' object");
         return -2;
     }
     if ((ret = _tbfcp_attr_init(TBFCP_ATTR(p_self), type, M, (TBFCP_ATTR_HDR_SIZE_IN_OCTETS + OctetStringLength)))) {
         TSK_OBJECT_SAFE_FREE(p_self);
         return -3;
     }
     if (TBFCP_ATTR(p_self)->format != tbfcp_attribute_format_OctetString) {
         TSK_DEBUG_ERROR("Format mismatch");
         TSK_OBJECT_SAFE_FREE(p_self);
         return -4;
     }
     if (OctetStringLength) {
 		#if HAVE_CRT //Debug memory
         if (!(p_self->OctetString = malloc(OctetStringLength))) {
 		
 		#else
         if (!(p_self->OctetString = tsk_malloc(OctetStringLength))) {
 		
 		#endif //HAVE_CRT
             TSK_DEBUG_ERROR("Failed to alloc %u octets", OctetStringLength);
             TSK_OBJECT_SAFE_FREE(p_self);
             return -5;
         }
         if (OctetString) {
             memcpy(p_self->OctetString, OctetString, OctetStringLength);
         }
         p_self->OctetStringLength = OctetStringLength;
     }
     else {
         TBFCP_ATTR(p_self)->hdr.length = TBFCP_ATTR_HDR_SIZE_IN_OCTETS;
         p_self->OctetStringLength = 0;
     }
     *pp_self = p_self;
     return 0;
 }
 
 static tsk_object_t* tbfcp_attr_octetstring_ctor(tsk_object_t * self, va_list * app)
 {
     tbfcp_attr_octetstring_t *p_os = (tbfcp_attr_octetstring_t *)self;
     if (p_os) {
     }
     return self;
 }
 static tsk_object_t* tbfcp_attr_octetstring_dtor(tsk_object_t * self)
 {
     tbfcp_attr_octetstring_t *p_os = (tbfcp_attr_octetstring_t *)self;
     if (p_os) {
         TSK_DEBUG_INFO("*** BFCP Attribute(OctetString) destroyed ***");
         TSK_SAFE_FREE(p_os->OctetString);
     }
     return self;
 }
 static int tbfcp_attr_octetstring_cmp(const tsk_object_t *_att1, const tsk_object_t *_att2)
 {
     const tbfcp_attr_octetstring_t *pc_att1 = (const tbfcp_attr_octetstring_t *)_att1;
     const tbfcp_attr_octetstring_t *pc_att2 = (const tbfcp_attr_octetstring_t *)_att2;
 
     return (int)(pc_att1-pc_att2);
 }
 static const tsk_object_def_t tbfcp_attr_octetstring_def_s = {
     sizeof(tbfcp_attr_octetstring_t),
     tbfcp_attr_octetstring_ctor,
     tbfcp_attr_octetstring_dtor,
     tbfcp_attr_octetstring_cmp,
 };
 const tsk_object_def_t *tbfcp_attr_octetstring_def_t = &tbfcp_attr_octetstring_def_s;
 
 
 
 /*************** tbfcp_attr_grouped *******************/
 int tbfcp_attr_grouped_create(tbfcp_attribute_type_t type, unsigned M, tbfcp_attr_grouped_t** pp_self)
 {
     extern const tsk_object_def_t *tbfcp_attr_grouped_def_t;
     tbfcp_attr_grouped_t* p_self;
     int ret;
     if (!pp_self) {
         TSK_DEBUG_ERROR("Invalid parameter");
         return -1;
     }
     if (!(p_self = tsk_object_new(tbfcp_attr_grouped_def_t))) {
         TSK_DEBUG_ERROR("Failed to create 'tbfcp_attr_grouped_def_t' object");
         return -2;
     }
     if ((ret = _tbfcp_attr_init(TBFCP_ATTR(p_self), type, M, TBFCP_ATTR_HDR_SIZE_IN_OCTETS + 0))) {
         TSK_OBJECT_SAFE_FREE(p_self);
         return -3;
     }
     if (TBFCP_ATTR(p_self)->format != tbfcp_attribute_format_Grouped) {
         TSK_DEBUG_ERROR("Format mismatch");
         TSK_OBJECT_SAFE_FREE(p_self);
         return -4;
     }
     if (!(p_self->p_list_attrs = tsk_list_create())) {
         TSK_DEBUG_ERROR("Failed to create empty list");
         TSK_OBJECT_SAFE_FREE(p_self);
         return -5;
     }
 
     *pp_self = p_self;
     return 0;
 }
 
 int tbfcp_attr_grouped_create_u16(tbfcp_attribute_type_t type, unsigned M, uint16_t extra_hdr_u16_val, tbfcp_attr_grouped_t** pp_self)
 {
     int ret;
     if ((ret = tbfcp_attr_grouped_create(type, M, pp_self))) {
         return ret;
     }
     *((uint16_t*)&(*pp_self)->extra_hdr) = extra_hdr_u16_val;
     (*pp_self)->extra_hdr_size_in_octets = 2;
     return 0;
 }
 
 int tbfcp_attr_grouped_add_attr(tbfcp_attr_grouped_t* p_self, tbfcp_attr_t** p_attr)
 {
     if (!p_self || !p_attr) {
         TSK_DEBUG_ERROR("Invalid parameter");
         return -1;
     }
     tsk_list_push_back_data(p_self->p_list_attrs, (void**)p_attr);
     return 0;
 }
 
 int tbfcp_attr_grouped_find_at(const struct tbfcp_attr_grouped_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_attr_grouped_ctor(tsk_object_t * self, va_list * app)
 {
     tbfcp_attr_grouped_t *p_gr = (tbfcp_attr_grouped_t *)self;
     if (p_gr) {
     }
     return self;
 }
 static tsk_object_t* tbfcp_attr_grouped_dtor(tsk_object_t * self)
 {
     tbfcp_attr_grouped_t *p_gr = (tbfcp_attr_grouped_t *)self;
     if (p_gr) {
         TSK_DEBUG_INFO("*** BFCP Attribute(Grouped) destroyed ***");
         TSK_OBJECT_SAFE_FREE(p_gr->p_list_attrs);
     }
     return self;
 }
 static int tbfcp_attr_grouped_cmp(const tsk_object_t *_att1, const tsk_object_t *_att2)
 {
     const tbfcp_attr_grouped_t *pc_att1 = (const tbfcp_attr_grouped_t *)_att1;
     const tbfcp_attr_grouped_t *pc_att2 = (const tbfcp_attr_grouped_t *)_att2;
 
     return (int)(pc_att1-pc_att2);
 }
 static const tsk_object_def_t tbfcp_attr_grouped_def_s = {
     sizeof(tbfcp_attr_grouped_t),
     tbfcp_attr_grouped_ctor,
     tbfcp_attr_grouped_dtor,
     tbfcp_attr_grouped_cmp,
 };
 const tsk_object_def_t *tbfcp_attr_grouped_def_t = &tbfcp_attr_grouped_def_s;