int coap_parse_option(struct option_context *context, uint8_t **value, uint16_t *vlen) { uint16_t delta, len; uint8_t start; int r; if (context->buf->used - context->pos < 1) return 0; start = ((uint8_t *)sol_buffer_at(context->buf, context->pos))[0]; /* This indicates that options have ended */ if (start == COAP_MARKER) return 0; delta = coap_option_header_get_delta(start); len = coap_option_header_get_len(start); context->pos += 1; context->used += 1; /* In case 'delta' doesn't fit the option fixed header. */ r = decode_delta(delta, sol_buffer_at(context->buf, context->pos), context->buf->used - context->pos, &delta); if (r < 0) return r; context->pos += r; context->used += r; /* In case 'len' doesn't fit the option fixed header. */ r = decode_delta(len, sol_buffer_at(context->buf, context->pos), context->buf->used - context->pos, &len); if (r < 0) return r; if (context->buf->used - context->pos < (size_t)(r + len)) return -EINVAL; if (value) *value = sol_buffer_at(context->buf, context->pos + r); if (vlen) *vlen = len; context->pos += r + len; context->used += r + len; context->delta += delta; return context->used; }
bool midi_processor::process_xmi( std::vector<uint8_t> const& p_file, midi_container & p_out ) { iff_stream xmi_file; if ( !read_iff_stream( p_file, xmi_file ) ) return false; const iff_chunk & form_chunk = xmi_file.find_chunk( "FORM" ); if ( memcmp( form_chunk.m_type, "XDIR", 4 ) ) return false; /*throw exception_io_data( "XMI IFF not XDIR type" );*/ const iff_chunk & cat_chunk = xmi_file.find_chunk( "CAT " ); if ( memcmp( cat_chunk.m_type, "XMID", 4 ) ) return false; /*throw exception_io_data( "XMI CAT chunk not XMID type" );*/ unsigned track_count = cat_chunk.get_chunk_count( "FORM" ); p_out.initialize( track_count > 1 ? 2 : 0, 60 ); for ( unsigned i = 0; i < track_count; ++i ) { const iff_chunk & xmid_form_chunk = cat_chunk.find_sub_chunk( "FORM", i ); if ( memcmp( xmid_form_chunk.m_type, "XMID", 4 ) ) return false; /*throw exception_io_data( "XMI nested FORM chunk not XMID type" );*/ const iff_chunk & event_chunk = xmid_form_chunk.find_sub_chunk( "EVNT" ); if ( memcmp( event_chunk.m_id, "EVNT", 4 ) ) return false; /* EVNT chunk not found */ std::vector<uint8_t> const& event_body = event_chunk.m_data; midi_track track; bool initial_tempo = false; unsigned current_timestamp = 0; unsigned last_event_timestamp = 0; std::vector<uint8_t> buffer; buffer.resize( 3 ); std::vector<uint8_t>::const_iterator it = event_body.begin(), end = event_body.end(); while ( it != end ) { unsigned delta = decode_xmi_delta( it, end ); current_timestamp += delta; if ( current_timestamp > last_event_timestamp ) { last_event_timestamp = current_timestamp; } if ( it == end ) return false; buffer[ 0 ] = *it++; if ( buffer[ 0 ] == 0xFF ) { if ( it == end ) return false; buffer[ 1 ] = *it++; long meta_count; if ( buffer[ 1 ] == 0x2F ) { meta_count = 0; } else { meta_count = decode_delta( it, end ); if ( meta_count < 0 ) return false; /*throw exception_io_data( "Invalid XMI meta message" );*/ if ( end - it < meta_count ) return false; buffer.resize( meta_count + 2 ); std::copy( it, it + meta_count, buffer.begin() + 2 ); it += meta_count; } if ( buffer[ 1 ] == 0x2F && current_timestamp < last_event_timestamp ) { current_timestamp = last_event_timestamp; } if ( buffer[ 1 ] == 0x51 && meta_count == 3 ) { unsigned tempo = buffer[ 2 ] * 0x10000 + buffer[ 3 ] * 0x100 + buffer[ 4 ]; unsigned ppqn = ( tempo * 3 ) / 25000; tempo = tempo * 60 / ppqn; buffer[ 2 ] = tempo / 0x10000; buffer[ 3 ] = tempo / 0x100; buffer[ 4 ] = tempo; if ( current_timestamp == 0 ) initial_tempo = true; } track.add_event( midi_event( current_timestamp, midi_event::extended, 0, &buffer[0], meta_count + 2 ) ); if ( buffer[ 1 ] == 0x2F ) break; } else if ( buffer[ 0 ] == 0xF0 ) { long system_exclusive_count = decode_delta( it, end ); if ( system_exclusive_count < 0 ) return false; /*throw exception_io_data( "Invalid XMI System Exclusive message" );*/ if ( end - it < system_exclusive_count ) return false; buffer.resize( system_exclusive_count + 1 ); std::copy( it, it + system_exclusive_count, buffer.begin() + 1 ); it += system_exclusive_count; track.add_event( midi_event( current_timestamp, midi_event::extended, 0, &buffer[0], system_exclusive_count + 1 ) ); } else if ( buffer[ 0 ] >= 0x80 && buffer[ 0 ] <= 0xEF ) { unsigned bytes_read = 1; if ( it == end ) return false; buffer[ 1 ] = *it++; midi_event::event_type type = (midi_event::event_type)( ( buffer[ 0 ] >> 4 ) - 8 ); unsigned channel = buffer[ 0 ] & 0x0F; if ( type != midi_event::program_change && type != midi_event::channel_aftertouch ) { if ( it == end ) return false; buffer[ 2 ] = *it++; bytes_read = 2; } track.add_event( midi_event( current_timestamp, type, channel, &buffer[1], bytes_read ) ); if ( type == midi_event::note_on ) { buffer[ 2 ] = 0x00; int note_length = decode_delta( it, end ); if ( note_length < 0 ) return false; /*throw exception_io_data( "Invalid XMI note message" );*/ unsigned note_end_timestamp = current_timestamp + note_length; if ( note_end_timestamp > last_event_timestamp ) last_event_timestamp = note_end_timestamp; track.add_event( midi_event( note_end_timestamp, type, channel, &buffer[1], bytes_read ) ); } } else return false; /*throw exception_io_data( "Unexpected XMI status code" );*/ }
bool midi_processor::process_hmi( std::vector<uint8_t> const& p_file, midi_container & p_out ) { std::vector<uint8_t> buffer; std::vector<uint8_t>::const_iterator it = p_file.begin() + 0xE4; uint32_t track_count = it[ 0 ] | ( it[ 1 ] << 8 ) | ( it[ 2 ] << 16 ) | ( it[ 3 ] << 24 ); uint32_t track_table_offset = it[ 4 ] | ( it[ 5 ] << 8 ) | ( it[ 6 ] << 16 ) | ( it[ 7 ] << 24 ); if ( track_table_offset >= p_file.size() || track_table_offset + track_count * 4 > p_file.size() ) return false; it = p_file.begin() + track_table_offset; std::vector<uint32_t> track_offsets; track_offsets.resize( track_count ); for ( unsigned i = 0; i < track_count; ++i ) { track_offsets[ i ] = it[ 0 ] | ( it[ 1 ] << 8 ) | ( it[ 2 ] << 16 ) | ( it[ 3 ] << 24 ); it += 4; } p_out.initialize( 1, 0xC0 ); { midi_track track; track.add_event( midi_event( 0, midi_event::extended, 0, hmp_default_tempo, _countof( hmp_default_tempo ) ) ); track.add_event( midi_event( 0, midi_event::extended, 0, end_of_track, _countof( end_of_track ) ) ); p_out.add_track( track ); } for ( unsigned i = 0; i < track_count; ++i ) { unsigned track_offset = track_offsets[ i ]; unsigned long track_length; if ( i + 1 < track_count ) { track_length = track_offsets[ i + 1 ] - track_offset; } else { track_length = p_file.size() - track_offset; } if ( track_offset >= p_file.size() || track_offset + track_length > p_file.size() ) return false; std::vector<uint8_t>::const_iterator track_body = p_file.begin() + track_offset; std::vector<uint8_t>::const_iterator track_end = track_body + track_length; if ( track_length < 13 ) return false; if ( track_body[ 0 ] != 'H' || track_body[ 1 ] != 'M' || track_body[ 2 ] != 'I' || track_body[ 3 ] != '-' || track_body[ 4 ] != 'M' || track_body[ 5 ] != 'I' || track_body[ 6 ] != 'D' || track_body[ 7 ] != 'I' || track_body[ 8 ] != 'T' || track_body[ 9 ] != 'R' || track_body[ 10 ] != 'A' || track_body[ 11 ] != 'C' || track_body[ 12 ] != 'K' ) return false; midi_track track; unsigned current_timestamp = 0; unsigned char last_event_code = 0xFF; unsigned last_event_timestamp = 0; if ( track_length < 0x4B + 4 ) return false; uint32_t meta_offset = track_body[ 0x4B ] | ( track_body[ 0x4C ] << 8 ) | ( track_body[ 0x4D ] << 16 ) | ( track_body[ 0x4E ] << 24 ); if ( meta_offset && meta_offset + 1 < track_length ) { buffer.resize( 2 ); std::copy( track_body + meta_offset, track_body + meta_offset + 2, buffer.begin() ); unsigned meta_size = buffer[ 1 ]; if ( meta_offset + 2 + meta_size > track_length ) return false; buffer.resize( meta_size + 2 ); std::copy( track_body + meta_offset + 2, track_body + meta_offset + 2 + meta_size, buffer.begin() + 2 ); while ( meta_size > 0 && buffer[ meta_size + 1 ] == ' ' ) --meta_size; if ( meta_size > 0 ) { buffer[ 0 ] = 0xFF; buffer[ 1 ] = 0x01; track.add_event( midi_event( 0, midi_event::extended, 0, &buffer[0], meta_size + 2 ) ); } } if ( track_length < 0x57 + 4 ) return false; uint32_t track_data_offset = track_body[ 0x57 ] | ( track_body[ 0x58 ] << 8 ) | ( track_body[ 0x59 ] << 16 ) | ( track_body[ 0x5A ] << 24 ); it = track_body + track_data_offset; buffer.resize( 3 ); while ( it != track_end ) { int delta = decode_delta( it, track_end ); if ( delta > 0xFFFF || delta < 0 ) { current_timestamp = last_event_timestamp; /*console::formatter() << "[foo_midi] Large HMI delta detected, shunting.";*/ } else { current_timestamp += delta; if ( current_timestamp > last_event_timestamp ) { last_event_timestamp = current_timestamp; } } if ( it == track_end ) return false; buffer[ 0 ] = *it++; if ( buffer[ 0 ] == 0xFF ) { last_event_code = 0xFF; if ( it == track_end ) return false; buffer[ 1 ] = *it++; int meta_count = decode_delta( it, track_end ); if ( meta_count < 0 ) return false; /*throw exception_io_data( "Invalid HMI meta message" );*/ if ( track_end - it < meta_count ) return false; buffer.resize( meta_count + 2 ); std::copy( it, it + meta_count, buffer.begin() + 2 ); it += meta_count; if ( buffer[ 1 ] == 0x2F && last_event_timestamp > current_timestamp ) { current_timestamp = last_event_timestamp; } track.add_event( midi_event( current_timestamp, midi_event::extended, 0, &buffer[0], meta_count + 2 ) ); if ( buffer[ 1 ] == 0x2F ) break; } else if ( buffer[ 0 ] == 0xF0 ) { last_event_code = 0xFF; int system_exclusive_count = decode_delta( it, track_end ); if ( system_exclusive_count < 0 ) return false; /*throw exception_io_data( "Invalid HMI System Exclusive message" );*/ if ( track_end - it < system_exclusive_count ) return false; buffer.resize( system_exclusive_count + 1 ); std::copy( it, it + system_exclusive_count, buffer.begin() + 1 ); it += system_exclusive_count; track.add_event( midi_event( current_timestamp, midi_event::extended, 0, &buffer[0], system_exclusive_count + 1 ) ); } else if ( buffer[ 0 ] == 0xFE ) { last_event_code = 0xFF; if ( it == track_end ) return false; buffer[ 1 ] = *it++; if ( buffer[ 1 ] == 0x10 ) { if ( track_end - it < 3 ) return false; it += 2; buffer[ 2 ] = *it++; if ( track_end - it < buffer[ 2 ] + 4 ) return false; it += buffer[ 2 ] + 4; } else if ( buffer[ 1 ] == 0x12 ) { if ( track_end - it < 2 ) return false; it += 2; } else if ( buffer[ 1 ] == 0x13 ) { if ( track_end - it < 10 ) return false; it += 10; } else if ( buffer[ 1 ] == 0x14 ) { if ( track_end - it < 2 ) return false; it += 2; p_out.add_track_event( 0, midi_event( current_timestamp, midi_event::extended, 0, loop_start, _countof( loop_start ) ) ); } else if ( buffer[ 1 ] == 0x15 ) { if ( track_end - it < 6 ) return false; it += 6; p_out.add_track_event( 0, midi_event( current_timestamp, midi_event::extended, 0, loop_end, _countof( loop_end ) ) ); } else return false; /*throw exception_io_data( "Unexpected HMI meta event" );*/ } else if ( buffer[ 0 ] <= 0xEF ) { unsigned bytes_read = 1; if ( buffer[ 0 ] >= 0x80 ) { if ( it == track_end ) return false; buffer[ 1 ] = *it++; last_event_code = buffer[ 0 ]; } else { if ( last_event_code == 0xFF ) return false; /*throw exception_io_data( "HMI used shortened event after Meta or SysEx message" );*/ buffer[ 1 ] = buffer[ 0 ]; buffer[ 0 ] = last_event_code; } midi_event::event_type type = (midi_event::event_type)( ( buffer[ 0 ] >> 4 ) - 8 ); unsigned channel = buffer[ 0 ] & 0x0F; if ( type != midi_event::program_change && type != midi_event::channel_aftertouch ) { if ( it == track_end ) return false; buffer[ 2 ] = *it++; bytes_read = 2; } track.add_event( midi_event( current_timestamp, type, channel, &buffer[ 1 ], bytes_read ) ); if ( type == midi_event::note_on ) { buffer[ 2 ] = 0x00; int note_length = decode_delta( it, track_end ); if ( note_length < 0 ) return false; /*throw exception_io_data( "Invalid HMI note message" );*/ unsigned note_end_timestamp = current_timestamp + note_length; if ( note_end_timestamp > last_event_timestamp ) last_event_timestamp = note_end_timestamp; track.add_event( midi_event( note_end_timestamp, midi_event::note_on, channel, &buffer[1], bytes_read ) ); } } else return false; /*throw exception_io_data( "Unexpected HMI status code" );*/ }