#if HAVE_CRT #define _CRTDBG_MAP_ALLOC #include #include #endif //HAVE_CRT /* * Copyright (C) 2020, University of the Basque Country (UPV/EHU) * Contact for licensing options: * * The original file was part of Open Source Doubango Framework * Copyright (C) 2010-2011 Mamadou Diop. * Copyright (C) 2012 Doubango Telecom * * 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;