/* * Copyright (C) 2019 BlueKitchen GmbH * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * 4. Any redistribution, use, or modification is done solely for * personal benefit and not for any commercial purpose or for * monetary gain. * * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * Please inquire about commercial licensing options at * contact@bluekitchen-gmbh.com * */ #define __BTSTACK_FILE__ "map_util.c" #include "btstack_config.h" #include #include #include #include #include "btstack_util.h" #include "map_util.h" #include "yxml.h" #include "map.h" #include "btstack_defines.h" #include "btstack_util.h" #include "btstack_debug.h" #include "btstack_event.h" static yxml_t xml_parser; static uint8_t xml_buffer[50]; void map_message_str_to_handle(const char * value, map_message_handle_t msg_handle){ int i; for (i = 0; i < MAP_MESSAGE_HANDLE_SIZE; i++) { uint8_t upper_nibble = nibble_for_char(*value++); uint8_t lower_nibble = nibble_for_char(*value++); msg_handle[i] = (upper_nibble << 4) | lower_nibble; } } void map_message_handle_to_str(char * p, const map_message_handle_t msg_handle){ int i; for (i = 0; i < MAP_MESSAGE_HANDLE_SIZE ; i++) { uint8_t byte = msg_handle[i]; *p++ = char_for_nibble(byte >> 4); *p++ = char_for_nibble(byte & 0x0F); } *p = 0; } static void map_client_emit_folder_listing_item_event(btstack_packet_handler_t callback, uint16_t cid, uint8_t * folder_name, uint16_t folder_name_len){ uint8_t event[7 + MAP_MAX_VALUE_LEN]; uint16_t pos = 0; event[pos++] = HCI_EVENT_MAP_META; pos++; // skip len event[pos++] = MAP_SUBEVENT_FOLDER_LISTING_ITEM; little_endian_store_16(event,pos,cid); pos+=2; uint16_t value_len = btstack_min(folder_name_len, sizeof(event) - pos); little_endian_store_16(event, pos, value_len); pos += 2; memcpy(event+pos, folder_name, value_len); pos += value_len; event[1] = pos - 2; if (pos > sizeof(event)) log_error("map_client_emit_folder_listing_item_event size %u", pos); (*callback)(HCI_EVENT_PACKET, cid, &event[0], pos); } static void map_client_emit_message_listing_item_event(btstack_packet_handler_t callback, uint16_t cid, map_message_handle_t message_handle){ uint8_t event[7 + MAP_MESSAGE_HANDLE_SIZE]; uint16_t pos = 0; event[pos++] = HCI_EVENT_MAP_META; pos++; // skip len event[pos++] = MAP_SUBEVENT_MESSAGE_LISTING_ITEM; little_endian_store_16(event,pos,cid); pos+=2; memcpy(event+pos, message_handle, MAP_MESSAGE_HANDLE_SIZE); pos += MAP_MESSAGE_HANDLE_SIZE; event[1] = pos - 2; if (pos > sizeof(event)) log_error("map_client_emit_message_listing_item_event size %u", pos); (*callback)(HCI_EVENT_PACKET, cid, &event[0], pos); } static void map_client_emit_parsing_done_event(btstack_packet_handler_t callback, uint16_t cid){ uint8_t event[5]; int pos = 0; event[pos++] = HCI_EVENT_MAP_META; pos++; // skip len event[pos++] = MAP_SUBEVENT_PARSING_DONE; little_endian_store_16(event,pos,cid); pos += 2; event[1] = pos - 2; if (pos != sizeof(event)) log_error("map_client_emit_parsing_done_event size %u", pos); (*callback)(HCI_EVENT_PACKET, cid, &event[0], pos); } void map_client_parse_folder_listing(btstack_packet_handler_t callback, uint16_t cid, const uint8_t * data, uint16_t data_len){ int folder_found = 0; int name_found = 0; char name[MAP_MAX_VALUE_LEN]; yxml_init(&xml_parser, xml_buffer, sizeof(xml_buffer)); while (data_len--){ yxml_ret_t r = yxml_parse(&xml_parser, *data++); switch (r){ case YXML_ELEMSTART: folder_found = strcmp("folder", xml_parser.elem) == 0; break; case YXML_ELEMEND: if (folder_found){ map_client_emit_folder_listing_item_event(callback, cid, (uint8_t *) name, strlen(name)); } folder_found = 0; break; case YXML_ATTRSTART: if (!folder_found) break; if (strcmp("name", xml_parser.attr) == 0){ name_found = 1; name[0] = 0; break; } break; case YXML_ATTRVAL: if (name_found) { // "In UTF-8, characters from the U+0000..U+10FFFF range (the UTF-16 accessible range) are encoded using sequences of 1 to 4 octets." if (strlen(name) + 4 + 1 >= sizeof(name)) break; strcat(name, xml_parser.data); break; } break; case YXML_ATTREND: name_found = 0; break; default: break; } } map_client_emit_parsing_done_event(callback, cid); } void map_client_parse_message_listing(btstack_packet_handler_t callback, uint16_t cid, const uint8_t * data, uint16_t data_len){ // now try parsing it int message_found = 0; int handle_found = 0; char handle[MAP_MESSAGE_HANDLE_SIZE * 2]; map_message_handle_t msg_handle; yxml_init(&xml_parser, xml_buffer, sizeof(xml_buffer)); while (data_len--){ yxml_ret_t r = yxml_parse(&xml_parser, *data++); switch (r){ case YXML_ELEMSTART: message_found = strcmp("msg", xml_parser.elem) == 0; break; case YXML_ELEMEND: if (!message_found) break; message_found = 0; if (strlen(handle) != MAP_MESSAGE_HANDLE_SIZE * 2){ log_info("message handle string length != 16"); break; } map_message_str_to_handle(handle, msg_handle); map_client_emit_message_listing_item_event(callback, cid, msg_handle); break; case YXML_ATTRSTART: if (!message_found) break; if (strcmp("handle", xml_parser.attr) == 0){ handle_found = 1; handle[0] = 0; break; } break; case YXML_ATTRVAL: if (handle_found) { strcat(handle, xml_parser.data); break; } break; case YXML_ATTREND: handle_found = 0; break; default: break; } } map_client_emit_parsing_done_event(callback, cid); }