Re-implement URIMap to tolerate broken plugins that use the wrong context to

map MIDI event types (fix #4889).

All uri-map contexts are now just ignored, and equivalent to urid (which is
equivalent to uri-map with context NULL).  We now just hope that no event types
are mapped after UINT16_MAX URIs have been mapped, and die horribly otherwise.
This is exceedingly unlikely to happen any time in the next several years, if
ever.


git-svn-id: svn://localhost/ardour2/branches/3.0@12462 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
David Robillard 2012-05-27 23:05:45 +00:00
parent 0b21004252
commit 3696f98e6f
5 changed files with 69 additions and 105 deletions

View File

@ -104,10 +104,7 @@ class LV2Plugin : public ARDOUR::Plugin, public ARDOUR::Workee
boost::shared_ptr<Plugin::ScalePoints>
get_scale_points(uint32_t port_index) const;
/// Return the URID of midi:MidiEvent
static uint32_t midi_event_type (bool event_api) {
return event_api ? _midi_event_type_ev : _midi_event_type;
}
static uint32_t midi_event_type() { return _midi_event_type; }
void set_insert_info(const PluginInsert* insert);
@ -140,7 +137,6 @@ class LV2Plugin : public ARDOUR::Plugin, public ARDOUR::Workee
static URIMap _uri_map;
static uint32_t _midi_event_type_ev;
static uint32_t _midi_event_type;
static uint32_t _chunk_type;
static uint32_t _sequence_type;

View File

@ -30,8 +30,10 @@
namespace ARDOUR {
/** Implementation of the LV2 uri-map and urid extensions.
*
* This just uses a pair of std::map and is not so great in the space overhead
* department, but it's fast enough and not really performance critical anyway.
*/
class URIMap : public boost::noncopyable {
public:
@ -44,26 +46,15 @@ public:
LV2_URID_Map* urid_map() { return &_urid_map_feature_data; }
LV2_URID_Unmap* urid_unmap() { return &_urid_unmap_feature_data; }
uint32_t uri_to_id(const char* map, const char* uri);
const char* id_to_uri(const char* map, uint32_t id);
uint32_t uri_to_id(const char* uri);
const char* id_to_uri(uint32_t id) const;
private:
static uint32_t uri_map_uri_to_id(LV2_URI_Map_Callback_Data callback_data,
const char* map,
const char* uri);
typedef std::map<const std::string, uint32_t> Map;
typedef std::map<uint32_t, const std::string> Unmap;
static LV2_URID urid_map(LV2_URID_Map_Handle handle,
const char* uri);
static const char* urid_unmap(LV2_URID_Unmap_Handle handle,
LV2_URID urid);
typedef std::map<uint16_t, uint32_t> EventToGlobal;
typedef std::map<uint32_t, uint16_t> GlobalToEvent;
EventToGlobal _event_to_global;
GlobalToEvent _global_to_event;
Map _map;
Unmap _unmap;
LV2_Feature _uri_map_feature;
LV2_URI_Map_Feature _uri_map_feature_data;
@ -73,7 +64,6 @@ private:
LV2_URID_Unmap _urid_unmap_feature_data;
};
} // namespace ARDOUR
#endif // __ardour_uri_map_h__

View File

@ -269,7 +269,7 @@ BufferSet::get_lv2_midi(bool input, size_t i, bool old_api)
mbuf.size(), (void*) mbuf.data()));
LV2_Evbuf_Iterator i = lv2_evbuf_begin(evbuf);
const uint32_t type = LV2Plugin::midi_event_type(old_api);
const uint32_t type = LV2Plugin::midi_event_type();
for (MidiBuffer::iterator e = mbuf.begin(); e != mbuf.end(); ++e) {
const Evoral::MIDIEvent<framepos_t> ev(*e, false);
#ifndef NDEBUG

View File

@ -68,20 +68,16 @@ using namespace ARDOUR;
using namespace PBD;
URIMap LV2Plugin::_uri_map;
uint32_t LV2Plugin::_midi_event_type_ev = _uri_map.uri_to_id(
"http://lv2plug.in/ns/ext/event",
"http://lv2plug.in/ns/ext/midi#MidiEvent");
uint32_t LV2Plugin::_midi_event_type = _uri_map.uri_to_id(
NULL,
"http://lv2plug.in/ns/ext/midi#MidiEvent");
uint32_t LV2Plugin::_chunk_type = _uri_map.uri_to_id(
NULL, LV2_ATOM__Chunk);
LV2_ATOM__Chunk);
uint32_t LV2Plugin::_sequence_type = _uri_map.uri_to_id(
NULL, LV2_ATOM__Sequence);
LV2_ATOM__Sequence);
uint32_t LV2Plugin::_event_transfer_type = _uri_map.uri_to_id(
NULL, LV2_ATOM__eventTransfer);
LV2_ATOM__eventTransfer);
uint32_t LV2Plugin::_path_type = _uri_map.uri_to_id(
NULL, LV2_ATOM__Path);
LV2_ATOM__Path);
class LV2World : boost::noncopyable {
public:

View File

@ -18,112 +18,94 @@
*/
#include <cassert>
#include <iostream>
#include <string>
#include <utility>
#include <stdint.h>
#include <string.h>
#include <glib.h>
#include "pbd/error.h"
#include "ardour/uri_map.h"
using namespace std;
namespace ARDOUR {
static uint32_t
c_uri_map_uri_to_id(LV2_URI_Map_Callback_Data callback_data,
const char* map,
const char* uri)
{
URIMap* const me = (URIMap*)callback_data;
const uint32_t id = me->uri_to_id(uri);
/* The event context with the uri-map extension guarantees a value in the
range of uint16_t. Ardour used to map to a separate range to achieve
this, but unfortunately some plugins are broken and use the incorrect
context. To compensate, we simply use the same context for everything
and hope that anything in the event context gets mapped before
UINT16_MAX is reached (which will be fine unless something seriously
weird is going on). If this fails there is nothing we can do, die.
*/
assert(!map || strcmp(map, "http://lv2plug.in/ns/ext/event")
|| id < UINT16_MAX);
return id;
}
static LV2_URID
c_urid_map(LV2_URID_Map_Handle handle,
const char* uri)
{
URIMap* const me = (URIMap*)handle;
return me->uri_to_id(uri);
}
static const char*
c_urid_unmap(LV2_URID_Unmap_Handle handle,
LV2_URID urid)
{
URIMap* const me = (URIMap*)handle;
return me->id_to_uri(urid);
}
URIMap::URIMap()
{
_uri_map_feature_data.uri_to_id = &URIMap::uri_map_uri_to_id;
_uri_map_feature_data.uri_to_id = c_uri_map_uri_to_id;
_uri_map_feature_data.callback_data = this;
_uri_map_feature.URI = LV2_URI_MAP_URI;
_uri_map_feature.data = &_uri_map_feature_data;
_urid_map_feature_data.map = &URIMap::urid_map;
_urid_map_feature_data.map = c_urid_map;
_urid_map_feature_data.handle = this;
_urid_map_feature.URI = LV2_URID_MAP_URI;
_urid_map_feature.data = &_urid_map_feature_data;
_urid_unmap_feature_data.unmap = &URIMap::urid_unmap;
_urid_unmap_feature_data.unmap = c_urid_unmap;
_urid_unmap_feature_data.handle = this;
_urid_unmap_feature.URI = LV2_URID_UNMAP_URI;
_urid_unmap_feature.data = &_urid_unmap_feature_data;
}
uint32_t
URIMap::uri_to_id(const char* map,
const char* uri)
URIMap::uri_to_id(const char* uri)
{
const uint32_t id = static_cast<uint32_t>(g_quark_from_string(uri));
if (map && !strcmp(map, "http://lv2plug.in/ns/ext/event")) {
GlobalToEvent::iterator i = _global_to_event.find(id);
if (i != _global_to_event.end()) {
return i->second;
} else {
if (_global_to_event.size() + 1 > UINT16_MAX) {
PBD::error << "Event URI " << uri << " ID out of range." << endl;
return 0;
}
const uint16_t ev_id = _global_to_event.size() + 1;
assert(_event_to_global.find(ev_id) == _event_to_global.end());
_global_to_event.insert(make_pair(id, ev_id));
_event_to_global.insert(make_pair(ev_id, id));
return ev_id;
}
} else {
return id;
const std::string urimm(uri);
const Map::const_iterator i = _map.find(urimm);
if (i != _map.end()) {
return i->second;
}
const uint32_t id = _map.size() + 1;
_map.insert(std::make_pair(urimm, id));
_unmap.insert(std::make_pair(id, urimm));
return id;
}
const char*
URIMap::id_to_uri(const char* map,
const uint32_t id)
URIMap::id_to_uri(const uint32_t id) const
{
if (map && !strcmp(map, "http://lv2plug.in/ns/ext/event")) {
EventToGlobal::iterator i = _event_to_global.find(id);
if (i == _event_to_global.end()) {
PBD::error << "Failed to unmap event URI " << id << endl;
return NULL;
}
return g_quark_to_string(i->second);
} else {
return g_quark_to_string(id);
}
const Unmap::const_iterator i = _unmap.find(id);
return (i != _unmap.end()) ? i->second.c_str() : NULL;
}
uint32_t
URIMap::uri_map_uri_to_id(LV2_URI_Map_Callback_Data callback_data,
const char* map,
const char* uri)
{
URIMap* const me = (URIMap*)callback_data;
return me->uri_to_id(map, uri);
}
LV2_URID
URIMap::urid_map(LV2_URID_Map_Handle handle,
const char* uri)
{
URIMap* const me = (URIMap*)handle;
return me->uri_to_id(NULL, uri);
}
const char*
URIMap::urid_unmap(LV2_URID_Unmap_Handle handle,
LV2_URID urid)
{
URIMap* const me = (URIMap*)handle;
return me->id_to_uri(NULL, urid);
}
} // namespace ARDOUR