1
0
mirror of https://github.com/bluekitchen/btstack.git synced 2025-04-17 20:42:47 +00:00

avrcp_controller: fix parsing of attributes with length == 0

This commit is contained in:
Matthias Ringwald 2018-04-16 17:09:58 +02:00 committed by Milanka Ringwald
parent 355ac55311
commit 836408df59

@ -301,64 +301,67 @@ static void avrcp_controller_emit_now_playing_info_event(btstack_packet_handler_
} }
static void avrcp_parser_process_byte(uint8_t byte, avrcp_connection_t * connection, avrcp_command_type_t ctype){ static void avrcp_parser_process_byte(uint8_t byte, avrcp_connection_t * connection, avrcp_command_type_t ctype){
uint16_t attribute_total_value_len;
uint32_t attribute_id;
switch(connection->parser_state){ switch(connection->parser_state){
case AVRCP_PARSER_GET_ATTRIBUTE_HEADER:{ case AVRCP_PARSER_GET_ATTRIBUTE_HEADER:
if (connection->parser_attribute_header_pos < AVRCP_ATTRIBUTE_HEADER_LEN) { if (connection->parser_attribute_header_pos < AVRCP_ATTRIBUTE_HEADER_LEN) {
connection->parser_attribute_header[connection->parser_attribute_header_pos++] = byte; connection->parser_attribute_header[connection->parser_attribute_header_pos++] = byte;
connection->list_offset++; connection->list_offset++;
return;
}
attribute_total_value_len = big_endian_read_16(connection->parser_attribute_header, 6);
connection->attribute_value_len = btstack_min(attribute_total_value_len, AVRCP_MAX_ATTRIBUTTE_SIZE);
if (connection->attribute_value_len == 0){
// emit attribute although len == 0
attribute_id = big_endian_read_32(connection->parser_attribute_header, 0);
avrcp_controller_emit_now_playing_info_event(avrcp_controller_context.avrcp_callback, connection->avrcp_cid, ctype, attribute_id, connection->attribute_value, connection->attribute_value_len);
break; break;
} }
uint16_t attribute_total_value_len = big_endian_read_16(connection->parser_attribute_header, 6);
connection->attribute_value_len = btstack_min(attribute_total_value_len, AVRCP_MAX_ATTRIBUTTE_SIZE);
connection->parser_state = AVRCP_PARSER_GET_ATTRIBUTE_VALUE; connection->parser_state = AVRCP_PARSER_GET_ATTRIBUTE_VALUE;
break; return;
}
case AVRCP_PARSER_GET_ATTRIBUTE_VALUE:{ case AVRCP_PARSER_GET_ATTRIBUTE_VALUE:
if (connection->attribute_value_offset < connection->attribute_value_len){ if (connection->attribute_value_offset < connection->attribute_value_len){
connection->attribute_value[connection->attribute_value_offset++] = byte; connection->attribute_value[connection->attribute_value_offset++] = byte;
connection->list_offset++; connection->list_offset++;
break; return;
} }
uint32_t attribute_id = big_endian_read_32(connection->parser_attribute_header, 0); // emit (potentially partial) attribute
if (attribute_id > AVRCP_MEDIA_ATTR_NONE && attribute_id <= AVRCP_MEDIA_ATTR_SONG_LENGTH_MS){ attribute_id = big_endian_read_32(connection->parser_attribute_header, 0);
avrcp_controller_emit_now_playing_info_event(avrcp_controller_context.avrcp_callback, connection->avrcp_cid, ctype, attribute_id, connection->attribute_value, connection->attribute_value_len); avrcp_controller_emit_now_playing_info_event(avrcp_controller_context.avrcp_callback, connection->avrcp_cid, ctype, attribute_id, connection->attribute_value, connection->attribute_value_len);
}
// ignore rest of attribute
if (connection->attribute_value_offset < big_endian_read_16(connection->parser_attribute_header, 6)){ attribute_total_value_len = big_endian_read_16(connection->parser_attribute_header, 6);
// printf("parse until end of valuE, and ignore it\n"); if (connection->attribute_value_offset < attribute_total_value_len){
connection->parser_state = AVRCP_PARSER_IGNORE_REST_OF_ATTRIBUTE_VALUE; connection->parser_state = AVRCP_PARSER_IGNORE_REST_OF_ATTRIBUTE_VALUE;
break; return;
} }
if (connection->list_offset == connection->list_size){
avrcp_parser_reset(connection);
avrcp_controller_emit_now_playing_info_event_done(avrcp_controller_context.avrcp_callback, connection->avrcp_cid, ctype, 0);
break;
}
connection->parser_state = AVRCP_PARSER_GET_ATTRIBUTE_HEADER;
connection->parser_attribute_header_pos = 0;
break; break;
}
case AVRCP_PARSER_IGNORE_REST_OF_ATTRIBUTE_VALUE: case AVRCP_PARSER_IGNORE_REST_OF_ATTRIBUTE_VALUE:
if (connection->attribute_value_offset < big_endian_read_16(connection->parser_attribute_header, 6)){ attribute_total_value_len = big_endian_read_16(connection->parser_attribute_header, 6);
if (connection->attribute_value_offset < attribute_total_value_len){
connection->list_offset++; connection->list_offset++;
connection->attribute_value_offset++; connection->attribute_value_offset++;
break; return;
} }
// printf("read %d, total %d\n", connection->attribute_value_offset, big_endian_read_16(connection->parser_attribute_header, 6));
if (connection->list_offset == connection->list_size){
avrcp_parser_reset(connection);
avrcp_controller_emit_now_playing_info_event_done(avrcp_controller_context.avrcp_callback, connection->avrcp_cid, ctype, 0);
break;
}
connection->parser_state = AVRCP_PARSER_GET_ATTRIBUTE_HEADER;
connection->parser_attribute_header_pos = 0;
break; break;
default: default:
break; return;
}
// attribute fully read, check if more to come
if (connection->list_offset < connection->list_size){
// more to come
connection->parser_state = AVRCP_PARSER_GET_ATTRIBUTE_HEADER;
connection->parser_attribute_header_pos = 0;
} else {
// fully done
avrcp_parser_reset(connection);
avrcp_controller_emit_now_playing_info_event_done(avrcp_controller_context.avrcp_callback, connection->avrcp_cid, ctype, 0);
} }
} }
@ -1324,4 +1327,4 @@ uint8_t avrcp_controller_set_max_num_fragments(uint16_t avrcp_cid, uint8_t max_n
} }
connection->max_num_fragments = max_num_fragments; connection->max_num_fragments = max_num_fragments;
return ERROR_CODE_SUCCESS; return ERROR_CODE_SUCCESS;
} }