From d6bd53fe5ca146398e9c3547b6cd9a06cf56d90f Mon Sep 17 00:00:00 2001 From: David Robillard Date: Wed, 25 May 2011 00:32:23 +0000 Subject: Move sanitised serialisation headers to public include directory git-svn-id: http://svn.drobilla.net/lad/trunk/ingen@3320 a436a847-0d15-0410-975c-d299462d15a1 --- src/serialisation/Parser.cpp | 700 +++++++++++++++++++++++-------------------- 1 file changed, 374 insertions(+), 326 deletions(-) (limited to 'src/serialisation/Parser.cpp') diff --git a/src/serialisation/Parser.cpp b/src/serialisation/Parser.cpp index 198a520e..27110c9d 100644 --- a/src/serialisation/Parser.cpp +++ b/src/serialisation/Parser.cpp @@ -38,8 +38,7 @@ #include "shared/World.hpp" #include "shared/LV2URIMap.hpp" -#include "Parser.hpp" -#include "names.hpp" +#include "ingen/serialisation/Parser.hpp" #define LOG(s) s << "[Parser] " @@ -102,226 +101,6 @@ skip_property(const Sord::Node& predicate) || predicate.to_string() == "http://lv2plug.in/ns/lv2core#port"); } -Parser::Parser(Ingen::Shared::World& world) -{ -} - -Parser::PatchRecords -Parser::find_patches(Ingen::Shared::World* world, - SerdEnv* env, - const Glib::ustring& manifest_uri) -{ - const Sord::URI ingen_Patch (*world->rdf_world(), NS_INGEN "Patch"); - const Sord::URI rdf_type (*world->rdf_world(), NS_RDF "type"); - const Sord::URI rdfs_seeAlso(*world->rdf_world(), NS_RDFS "seeAlso"); - - Sord::Model model(*world->rdf_world(), manifest_uri); - model.load_file(env, SERD_TURTLE, manifest_uri); - - std::list records; - for (Sord::Iter i = model.find(nil, rdf_type, ingen_Patch); !i.end(); ++i) { - const Sord::Node patch = i.get_subject(); - Sord::Iter f = model.find(patch, rdfs_seeAlso, nil); - if (!f.end()) { - records.push_back(PatchRecord(patch.to_c_string(), - f.get_object().to_c_string())); - } else { - LOG(error) << "Patch has no rdfs:seeAlso" << endl; - } - } - return records; -} - -/** Parse a patch from RDF into a CommonInterface (engine or client). - * @return whether or not load was successful. - */ -bool -Parser::parse_file(Ingen::Shared::World* world, - Ingen::CommonInterface* target, - Glib::ustring file_uri, - boost::optional parent, - boost::optional symbol, - boost::optional data) -{ - const size_t colon = file_uri.find(":"); - if (colon != Glib::ustring::npos) { - const Glib::ustring scheme = file_uri.substr(0, colon); - if (scheme != "file") { - LOG(error) << (boost::format("Unsupported URI scheme `%1%'") - % scheme) << endl; - return false; - } - } else { - file_uri = Glib::ustring("file://") + file_uri; - } - - const bool is_bundle = (file_uri.substr(file_uri.length() - 4) != ".ttl"); - - if (is_bundle && file_uri[file_uri.length() - 1] != '/') { - file_uri.append("/"); - } - - SerdNode base_node = serd_node_from_string( - SERD_URI, (const uint8_t*)file_uri.c_str()); - SerdEnv* env = serd_env_new(&base_node); - - if (file_uri.substr(file_uri.length() - 4) != ".ttl") { - // Not a Turtle file, try to open it as a bundle - if (file_uri[file_uri.length() - 1] != '/') { - file_uri.append("/"); - } - Parser::PatchRecords records = find_patches(world, env, file_uri + "manifest.ttl"); - if (!records.empty()) { - file_uri = records.front().file_uri; - } - } - - base_node = serd_node_from_string( - SERD_URI, (const uint8_t*)file_uri.c_str()); - serd_env_set_base_uri(env, &base_node); - - // Load patch file into model - Sord::Model model(*world->rdf_world(), file_uri); - model.load_file(env, SERD_TURTLE, file_uri); - - serd_env_free(env); - - LOG(info) << "Parsing " << file_uri << endl; - if (parent) - LOG(info) << "Parent: " << *parent << endl; - if (symbol) - LOG(info) << "Symbol: " << *symbol << endl; - - boost::optional parsed_path - = parse(world, target, model, file_uri, Path("/"), parent, symbol, data); - - if (parsed_path) { - target->set_property(*parsed_path, "http://drobilla.net/ns/ingen#document", - Atom(Atom::URI, file_uri.c_str())); - } else { - LOG(warn) << "Document URI lost" << endl; - } - - return parsed_path; -} - -bool -Parser::parse_string(Ingen::Shared::World* world, - Ingen::CommonInterface* target, - const Glib::ustring& str, - const Glib::ustring& base_uri, - boost::optional parent, - boost::optional symbol, - boost::optional data) -{ - // Load string into model - Sord::Model model(*world->rdf_world(), base_uri); - SerdEnv* env = serd_env_new(NULL); - model.load_string(env, SERD_TURTLE, str.c_str(), str.length(), base_uri); - serd_env_free(env); - - LOG(info) << "Parsing string"; - if (!base_uri.empty()) - info << " (base " << base_uri << ")"; - info << endl; - - boost::optional data_path; - bool ret = parse(world, target, model, base_uri, data_path, parent, symbol, data); - Sord::URI subject(*world->rdf_world(), base_uri); - parse_connections(world, target, model, subject, parent ? *parent : "/"); - - return ret; -} - -boost::optional -Parser::parse(Ingen::Shared::World* world, - Ingen::CommonInterface* target, - Sord::Model& model, - Glib::ustring document_uri, - boost::optional data_path, - boost::optional parent, - boost::optional symbol, - boost::optional data) -{ - const Sord::URI patch_class (*world->rdf_world(), NS_INGEN "Patch"); - const Sord::URI node_class (*world->rdf_world(), NS_INGEN "Node"); - const Sord::URI port_class (*world->rdf_world(), NS_INGEN "Port"); - const Sord::URI internal_class(*world->rdf_world(), NS_INGEN "Internal"); - const Sord::URI in_port_class (*world->rdf_world(), NS_LV2 "InputPort"); - const Sord::URI out_port_class(*world->rdf_world(), NS_LV2 "OutputPort"); - const Sord::URI lv2_class (*world->rdf_world(), NS_LV2 "Plugin"); - const Sord::URI rdf_type (*world->rdf_world(), NS_RDF "type"); - - Sord::Node subject = nil; - if (data_path && data_path->is_root()) { - subject = model.base_uri(); - } else if (data_path) { - subject = Sord::URI(*world->rdf_world(), data_path->chop_start("/")); - } - - Raul::Path path("/"); - if (data_path) { - path = *data_path; - } else if (parent && symbol) { - path = parent->child(*symbol); - } - - // Get all subjects and their types (?subject a ?type) - typedef std::map< Sord::Node, std::set > Subjects; - Subjects subjects; - for (Sord::Iter i = model.find(subject, rdf_type, nil); !i.end(); ++i) { - const Sord::Node& subject = i.get_subject(); - const Sord::Node& rdf_class = i.get_object(); - - assert(rdf_class.is_uri()); - Subjects::iterator s = subjects.find(subject); - if (s == subjects.end()) { - std::set types; - types.insert(rdf_class); - subjects.insert(make_pair(subject, types)); - } else { - s->second.insert(rdf_class); - } - } - - // Parse and create each subject - boost::optional ret; - boost::optional root_path; - for (Subjects::const_iterator i = subjects.begin(); i != subjects.end(); ++i) { - const Sord::Node& subject = i->first; - const std::set& types = i->second; - if (types.find(patch_class) != types.end()) { - ret = parse_patch(world, target, model, subject, parent, symbol, data); - } else if (types.find(node_class) != types.end()) { - ret = parse_node(world, target, model, - subject, path.child(subject.to_string()), - data); - } else if (types.find(port_class) != types.end()) { - parse_properties(world, target, model, subject, path, data); - ret = path; - } else { - LOG(error) << "Subject has no known types" << endl; - } - - if (!ret) { - LOG(error) << "Failed to parse " << path << endl; - LOG(error) << "Types:" << endl; - for (std::set::const_iterator t = types.begin(); - t != types.end(); ++t) { - LOG(error) << " :: " << *t << endl; - assert((*t).is_uri()); - } - return boost::optional(); - } - - if (data_path && subject.to_string() == data_path->str()) { - root_path = ret; - } - } - - return path; -} - static Resource::Properties get_properties(Sord::Model& model, const Sord::Node& subject) @@ -376,14 +155,122 @@ get_port(Ingen::Shared::World* world, return index; } -boost::optional -Parser::parse_patch(Ingen::Shared::World* world, - Ingen::CommonInterface* target, - Sord::Model& model, - const Sord::Node& subject_node, - boost::optional parent, - boost::optional a_symbol, - boost::optional data) +static boost::optional +parse( + Shared::World* world, + CommonInterface* target, + Sord::Model& model, + Glib::ustring document_uri, + boost::optional data_path = boost::optional(), + boost::optional parent = boost::optional(), + boost::optional symbol = boost::optional(), + boost::optional data = boost::optional()); + +static boost::optional +parse_patch( + Shared::World* world, + CommonInterface* target, + Sord::Model& model, + const Sord::Node& subject, + boost::optional parent = boost::optional(), + boost::optional symbol = boost::optional(), + boost::optional data = boost::optional()); + + +static boost::optional +parse_node( + Shared::World* world, + CommonInterface* target, + Sord::Model& model, + const Sord::Node& subject, + const Raul::Path& path, + boost::optional data = boost::optional()); + + +static bool +parse_properties( + Shared::World* world, + CommonInterface* target, + Sord::Model& model, + const Sord::Node& subject, + const Raul::URI& uri, + boost::optional data = boost::optional()); + +static bool +parse_connections( + Shared::World* world, + CommonInterface* target, + Sord::Model& model, + const Sord::Node& subject, + const Raul::Path& patch); + +static boost::optional +parse_node(Ingen::Shared::World* world, + Ingen::CommonInterface* target, + Sord::Model& model, + const Sord::Node& subject, + const Raul::Path& path, + boost::optional data) +{ + const LV2URIMap& uris = *world->uris().get(); + + Sord::URI rdf_instanceOf(*world->rdf_world(), NS_RDF "instanceOf"); + + Sord::Iter i = model.find(subject, rdf_instanceOf, nil); + if (i.end() || i.get_object().type() != Sord::Node::URI) { + LOG(error) << "Node missing mandatory rdf:instanceOf" << endl; + return boost::optional(); + } + + const std::string type_uri = relative_uri( + model.base_uri().to_string(), + i.get_object().to_string(), + false); + + if (!serd_uri_string_has_scheme((const uint8_t*)type_uri.c_str())) { + SerdURI base_uri; + serd_uri_parse(model.base_uri().to_u_string(), &base_uri); + + SerdURI ignored; + SerdNode sub_uri = serd_node_new_uri_from_string( + i.get_object().to_u_string(), + &base_uri, + &ignored); + + const std::string sub_uri_str((const char*)sub_uri.buf); + std::string basename = get_basename(sub_uri_str); + + const std::string sub_file = + string((const char*)sub_uri.buf) + "/" + basename + ".ttl"; + + Sord::Model sub_model(*world->rdf_world(), sub_file); + SerdEnv* env = serd_env_new(NULL); + sub_model.load_file(env, SERD_TURTLE, sub_file); + serd_env_free(env); + + Sord::URI sub_node(*world->rdf_world(), sub_file); + parse_patch(world, target, sub_model, sub_node, + path.parent(), Raul::Symbol(path.symbol())); + + parse_patch(world, target, model, subject, + path.parent(), Raul::Symbol(path.symbol())); + } else { + Resource::Properties props = get_properties(model, subject); + props.insert(make_pair(uris.rdf_type, + Raul::URI(uris.ingen_Node))); + target->put(path, props); + } + return path; +} + +static boost::optional +parse_patch(Ingen::Shared::World* world, + Ingen::CommonInterface* target, + Sord::Model& model, + const Sord::Node& subject_node, + boost::optional parent, + boost::optional a_symbol, + boost::optional data) { const Sord::URI ingen_node(*world->rdf_world(), NS_INGEN "node"); const Sord::URI ingen_polyphony(*world->rdf_world(), NS_INGEN "polyphony"); @@ -463,102 +350,43 @@ Parser::parse_patch(Ingen::Shared::World* world, // Create port and/or set all port properties target->put(port_record.first, port_record.second); - } - } - - // For each port on this patch - typedef std::map PortRecords; - PortRecords ports; - for (Sord::Iter p = model.find(patch, lv2_port, nil); !p.end(); ++p) { - Sord::Node port = p.get_object(); - - // Get all properties - PortRecord port_record; - const int index = get_port(world, model, port, patch_path, port_record); - if (index < 0) { - LOG(error) << "Invalid port " << port << endl; - return boost::optional(); - } - - // Store port information in ports map - ports[index] = port_record; - } - - // Create ports in order by index - for (PortRecords::const_iterator i = ports.begin(); i != ports.end(); ++i) { - target->put(i->second.first, i->second.second); - } - - parse_connections(world, target, model, subject_node, patch_path); - - return patch_path; -} - -boost::optional -Parser::parse_node(Ingen::Shared::World* world, - Ingen::CommonInterface* target, - Sord::Model& model, - const Sord::Node& subject, - const Raul::Path& path, - boost::optional data) -{ - const LV2URIMap& uris = *world->uris().get(); - - Sord::URI rdf_instanceOf(*world->rdf_world(), NS_RDF "instanceOf"); - - Sord::Iter i = model.find(subject, rdf_instanceOf, nil); - if (i.end() || i.get_object().type() != Sord::Node::URI) { - LOG(error) << "Node missing mandatory rdf:instanceOf" << endl; - return boost::optional(); - } - - const std::string type_uri = relative_uri( - model.base_uri().to_string(), - i.get_object().to_string(), - false); - - if (!serd_uri_string_has_scheme((const uint8_t*)type_uri.c_str())) { - SerdURI base_uri; - serd_uri_parse(model.base_uri().to_u_string(), &base_uri); - - SerdURI ignored; - SerdNode sub_uri = serd_node_new_uri_from_string( - i.get_object().to_u_string(), - &base_uri, - &ignored); - - const std::string sub_uri_str((const char*)sub_uri.buf); - std::string basename = get_basename(sub_uri_str); + } + } - const std::string sub_file = - string((const char*)sub_uri.buf) + "/" + basename + ".ttl"; + // For each port on this patch + typedef std::map PortRecords; + PortRecords ports; + for (Sord::Iter p = model.find(patch, lv2_port, nil); !p.end(); ++p) { + Sord::Node port = p.get_object(); - Sord::Model sub_model(*world->rdf_world(), sub_file); - SerdEnv* env = serd_env_new(NULL); - sub_model.load_file(env, SERD_TURTLE, sub_file); - serd_env_free(env); + // Get all properties + PortRecord port_record; + const int index = get_port(world, model, port, patch_path, port_record); + if (index < 0) { + LOG(error) << "Invalid port " << port << endl; + return boost::optional(); + } - Sord::URI sub_node(*world->rdf_world(), sub_file); - parse_patch(world, target, sub_model, sub_node, - path.parent(), Raul::Symbol(path.symbol())); + // Store port information in ports map + ports[index] = port_record; + } - parse_patch(world, target, model, subject, - path.parent(), Raul::Symbol(path.symbol())); - } else { - Resource::Properties props = get_properties(model, subject); - props.insert(make_pair(uris.rdf_type, - Raul::URI(uris.ingen_Node))); - target->put(path, props); + // Create ports in order by index + for (PortRecords::const_iterator i = ports.begin(); i != ports.end(); ++i) { + target->put(i->second.first, i->second.second); } - return path; + + parse_connections(world, target, model, subject_node, patch_path); + + return patch_path; } -bool -Parser::parse_connections(Ingen::Shared::World* world, - Ingen::CommonInterface* target, - Sord::Model& model, - const Sord::Node& subject, - const Raul::Path& parent) +static bool +parse_connections(Ingen::Shared::World* world, + Ingen::CommonInterface* target, + Sord::Model& model, + const Sord::Node& subject, + const Raul::Path& parent) { Sord::URI ingen_connection(*world->rdf_world(), NS_INGEN "connection"); Sord::URI ingen_source(*world->rdf_world(), NS_INGEN "source"); @@ -602,13 +430,13 @@ Parser::parse_connections(Ingen::Shared::World* world, return true; } -bool -Parser::parse_properties(Ingen::Shared::World* world, - Ingen::CommonInterface* target, - Sord::Model& model, - const Sord::Node& subject, - const Raul::URI& uri, - boost::optional data) +static bool +parse_properties(Ingen::Shared::World* world, + Ingen::CommonInterface* target, + Sord::Model& model, + const Sord::Node& subject, + const Raul::URI& uri, + boost::optional data) { Resource::Properties properties; for (Sord::Iter i = model.find(subject, nil, nil); !i.end(); ++i) { @@ -629,6 +457,226 @@ Parser::parse_properties(Ingen::Shared::World* world, return true; } +static boost::optional +parse(Ingen::Shared::World* world, + Ingen::CommonInterface* target, + Sord::Model& model, + Glib::ustring document_uri, + boost::optional data_path, + boost::optional parent, + boost::optional symbol, + boost::optional data) +{ + const Sord::URI patch_class (*world->rdf_world(), NS_INGEN "Patch"); + const Sord::URI node_class (*world->rdf_world(), NS_INGEN "Node"); + const Sord::URI port_class (*world->rdf_world(), NS_INGEN "Port"); + const Sord::URI internal_class(*world->rdf_world(), NS_INGEN "Internal"); + const Sord::URI in_port_class (*world->rdf_world(), NS_LV2 "InputPort"); + const Sord::URI out_port_class(*world->rdf_world(), NS_LV2 "OutputPort"); + const Sord::URI lv2_class (*world->rdf_world(), NS_LV2 "Plugin"); + const Sord::URI rdf_type (*world->rdf_world(), NS_RDF "type"); + + Sord::Node subject = nil; + if (data_path && data_path->is_root()) { + subject = model.base_uri(); + } else if (data_path) { + subject = Sord::URI(*world->rdf_world(), data_path->chop_start("/")); + } + + Raul::Path path("/"); + if (data_path) { + path = *data_path; + } else if (parent && symbol) { + path = parent->child(*symbol); + } + + // Get all subjects and their types (?subject a ?type) + typedef std::map< Sord::Node, std::set > Subjects; + Subjects subjects; + for (Sord::Iter i = model.find(subject, rdf_type, nil); !i.end(); ++i) { + const Sord::Node& subject = i.get_subject(); + const Sord::Node& rdf_class = i.get_object(); + + assert(rdf_class.is_uri()); + Subjects::iterator s = subjects.find(subject); + if (s == subjects.end()) { + std::set types; + types.insert(rdf_class); + subjects.insert(make_pair(subject, types)); + } else { + s->second.insert(rdf_class); + } + } + + // Parse and create each subject + boost::optional ret; + boost::optional root_path; + for (Subjects::const_iterator i = subjects.begin(); i != subjects.end(); ++i) { + const Sord::Node& subject = i->first; + const std::set& types = i->second; + if (types.find(patch_class) != types.end()) { + ret = parse_patch(world, target, model, subject, parent, symbol, data); + } else if (types.find(node_class) != types.end()) { + ret = parse_node(world, target, model, + subject, path.child(subject.to_string()), + data); + } else if (types.find(port_class) != types.end()) { + parse_properties(world, target, model, subject, path, data); + ret = path; + } else { + LOG(error) << "Subject has no known types" << endl; + } + + if (!ret) { + LOG(error) << "Failed to parse " << path << endl; + LOG(error) << "Types:" << endl; + for (std::set::const_iterator t = types.begin(); + t != types.end(); ++t) { + LOG(error) << " :: " << *t << endl; + assert((*t).is_uri()); + } + return boost::optional(); + } + + if (data_path && subject.to_string() == data_path->str()) { + root_path = ret; + } + } + + return path; +} + +Parser::Parser(Ingen::Shared::World& world) +{ +} + +Parser::PatchRecords +Parser::find_patches(Ingen::Shared::World* world, + SerdEnv* env, + const Glib::ustring& manifest_uri) +{ + const Sord::URI ingen_Patch (*world->rdf_world(), NS_INGEN "Patch"); + const Sord::URI rdf_type (*world->rdf_world(), NS_RDF "type"); + const Sord::URI rdfs_seeAlso(*world->rdf_world(), NS_RDFS "seeAlso"); + + Sord::Model model(*world->rdf_world(), manifest_uri); + model.load_file(env, SERD_TURTLE, manifest_uri); + + std::list records; + for (Sord::Iter i = model.find(nil, rdf_type, ingen_Patch); !i.end(); ++i) { + const Sord::Node patch = i.get_subject(); + Sord::Iter f = model.find(patch, rdfs_seeAlso, nil); + if (!f.end()) { + records.push_back(PatchRecord(patch.to_c_string(), + f.get_object().to_c_string())); + } else { + LOG(error) << "Patch has no rdfs:seeAlso" << endl; + } + } + return records; +} + +/** Parse a patch from RDF into a CommonInterface (engine or client). + * @return whether or not load was successful. + */ +bool +Parser::parse_file(Ingen::Shared::World* world, + Ingen::CommonInterface* target, + Glib::ustring file_uri, + boost::optional parent, + boost::optional symbol, + boost::optional data) +{ + const size_t colon = file_uri.find(":"); + if (colon != Glib::ustring::npos) { + const Glib::ustring scheme = file_uri.substr(0, colon); + if (scheme != "file") { + LOG(error) << (boost::format("Unsupported URI scheme `%1%'") + % scheme) << endl; + return false; + } + } else { + file_uri = Glib::ustring("file://") + file_uri; + } + + const bool is_bundle = (file_uri.substr(file_uri.length() - 4) != ".ttl"); + + if (is_bundle && file_uri[file_uri.length() - 1] != '/') { + file_uri.append("/"); + } + + SerdNode base_node = serd_node_from_string( + SERD_URI, (const uint8_t*)file_uri.c_str()); + SerdEnv* env = serd_env_new(&base_node); + + if (file_uri.substr(file_uri.length() - 4) != ".ttl") { + // Not a Turtle file, try to open it as a bundle + if (file_uri[file_uri.length() - 1] != '/') { + file_uri.append("/"); + } + Parser::PatchRecords records = find_patches(world, env, file_uri + "manifest.ttl"); + if (!records.empty()) { + file_uri = records.front().file_uri; + } + } + + base_node = serd_node_from_string( + SERD_URI, (const uint8_t*)file_uri.c_str()); + serd_env_set_base_uri(env, &base_node); + + // Load patch file into model + Sord::Model model(*world->rdf_world(), file_uri); + model.load_file(env, SERD_TURTLE, file_uri); + + serd_env_free(env); + + LOG(info) << "Parsing " << file_uri << endl; + if (parent) + LOG(info) << "Parent: " << *parent << endl; + if (symbol) + LOG(info) << "Symbol: " << *symbol << endl; + + boost::optional parsed_path + = parse(world, target, model, file_uri, Path("/"), parent, symbol, data); + + if (parsed_path) { + target->set_property(*parsed_path, "http://drobilla.net/ns/ingen#document", + Atom(Atom::URI, file_uri.c_str())); + } else { + LOG(warn) << "Document URI lost" << endl; + } + + return parsed_path; +} + +bool +Parser::parse_string(Ingen::Shared::World* world, + Ingen::CommonInterface* target, + const Glib::ustring& str, + const Glib::ustring& base_uri, + boost::optional parent, + boost::optional symbol, + boost::optional data) +{ + // Load string into model + Sord::Model model(*world->rdf_world(), base_uri); + SerdEnv* env = serd_env_new(NULL); + model.load_string(env, SERD_TURTLE, str.c_str(), str.length(), base_uri); + serd_env_free(env); + + LOG(info) << "Parsing string"; + if (!base_uri.empty()) + info << " (base " << base_uri << ")"; + info << endl; + + boost::optional data_path; + bool ret = parse(world, target, model, base_uri, data_path, parent, symbol, data); + Sord::URI subject(*world->rdf_world(), base_uri); + parse_connections(world, target, model, subject, parent ? *parent : "/"); + + return ret; +} + } // namespace Serialisation } // namespace Ingen -- cgit v1.2.1