/* This file is part of Ingen. * Copyright (C) 2007 Dave Robillard * * Ingen is free software; you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * Ingen is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include // pair, make_pair #include #include #include #include // atof #include #include #include #include "Serializer.h" #include "PatchModel.h" #include "NodeModel.h" #include "ConnectionModel.h" #include "PortModel.h" #include "PresetModel.h" #include "ModelEngineInterface.h" #include "PluginModel.h" #include "raul/Path.h" #include "raul/Atom.h" #include "raul/AtomRaptor.h" using std::string; using std::vector; using std::pair; using std::cerr; using std::cout; using std::endl; using boost::optional; using namespace Raul; namespace Ingen { namespace Client { Serializer::Serializer() { _writer.add_prefix("ingen", "http://drobilla.net/ns/ingen#"); _writer.add_prefix("ingenuity", "http://drobilla.net/ns/ingenuity#"); _writer.add_prefix("lv2", "http://lv2plug.in/ontology#"); _writer.add_prefix("doap", "http://usefulinc.com/ns/doap#"); } /** Begin a serialization to a file. * * This must be called before any serializing methods. */ void Serializer::start_to_filename(const string& filename) throw (std::logic_error) { _base_uri = "file://" + filename; _writer.start_to_filename(filename); } /** Begin a serialization to a string. * * This must be called before any serializing methods. * * The results of the serialization will be returned by the finish() method after * the desired objects have been serialized. */ void Serializer::start_to_string() throw (std::logic_error) { _base_uri = ""; _writer.start_to_string(); } /** Finish a serialization. * * If this was a serialization to a string, the serialization output * will be returned, otherwise the empty string is returned. */ string Serializer::finish() throw(std::logic_error) { return _writer.finish(); _id_map.clear(); } /** Convert a path to an RDF blank node ID for serializing. */ RdfId Serializer::path_to_node_id(const Path& path) { /*string ret = path.substr(1); for (size_t i=0; i < ret.length(); ++i) { if (ret[i] == '/') ret[i] = '_'; } return RdfId(RdfId::ANONYMOUS, ret); */ IDMap::iterator i = _id_map.find(path); if (i != _id_map.end()) { return i->second; } else { const RdfId id = _writer.blank_id(); _id_map[path] = id; return id; } } #if 0 /** Searches for the filename passed in the path, returning the full * path of the file, or the empty string if not found. * * This function tries to be as friendly a black box as possible - if the path * passed is an absolute path and the file is found there, it will return * that path, etc. * * additional_path is a list (colon delimeted as usual) of additional * directories to look in. ie the directory the parent patch resides in would * be a good idea to pass as additional_path, in the case of a subpatch. */ string Serializer::find_file(const string& filename, const string& additional_path) { string search_path = additional_path + ":" + _patch_search_path; // Try to open the raw filename first std::ifstream is(filename.c_str(), std::ios::in); if (is.good()) { is.close(); return filename; } string directory; string full_patch_path = ""; while (search_path != "") { directory = search_path.substr(0, search_path.find(':')); if (search_path.find(':') != string::npos) search_path = search_path.substr(search_path.find(':')+1); else search_path = ""; full_patch_path = directory +"/"+ filename; std::ifstream is; is.open(full_patch_path.c_str(), std::ios::in); if (is.good()) { is.close(); return full_patch_path; } else { cerr << "[Serializer] Could not find patch file " << full_patch_path << endl; } } return ""; } #endif void Serializer::serialize(SharedPtr object) throw (std::logic_error) { if (!_writer.serialization_in_progress()) throw std::logic_error("serialize called without serialization in progress"); SharedPtr patch = PtrCast(object); if (patch) { serialize_patch(patch, RdfId(RdfId::RESOURCE, _base_uri)); return; } SharedPtr node = PtrCast(object); if (node) { serialize_node(node, path_to_node_id(node->path())); return; } SharedPtr port = PtrCast(object); if (port) { serialize_port(port, path_to_node_id(port->path())); return; } cerr << "[Serializer] WARNING: Unsupported object type, " << object->path() << " not serialized." << endl; } void Serializer::serialize_patch(SharedPtr patch, const RdfId& patch_id) { _writer.write( patch_id, NS_RDF("type"), NS_INGEN("Patch")); if (patch->path().name().length() > 0) { _writer.write( patch_id, NS_INGEN("name"), Atom(patch->path().name().c_str())); } _writer.write( patch_id, NS_INGEN("polyphony"), Atom((int)patch->poly())); for (MetadataMap::const_iterator m = patch->metadata().begin(); m != patch->metadata().end(); ++m) { if (_writer.expand_uri(m->first) != "") { _writer.write( patch_id, RdfId(RdfId::RESOURCE, _writer.expand_uri(m->first.c_str()).c_str()), m->second); } } for (NodeModelMap::const_iterator n = patch->nodes().begin(); n != patch->nodes().end(); ++n) { SharedPtr patch = PtrCast(n->second); if (patch) { const RdfId subpatch_id = RdfId(RdfId::RESOURCE, patch_id.to_string() + "#" + patch->path().substr(1)); _writer.write(patch_id, NS_INGEN("node"), subpatch_id); serialize_patch(patch, subpatch_id); } else { const RdfId node_id = path_to_node_id(n->second->path()); _writer.write(patch_id, NS_INGEN("node"), node_id); serialize_node(n->second, node_id); } } for (PortModelList::const_iterator p = patch->ports().begin(); p != patch->ports().end(); ++p) { const RdfId port_id = path_to_node_id((*p)->path()); _writer.write(patch_id, NS_INGEN("port"), port_id); serialize_port(*p, port_id); } for (ConnectionList::const_iterator c = patch->connections().begin(); c != patch->connections().end(); ++c) { serialize_connection(*c); } } void Serializer::serialize_plugin(SharedPtr plugin) { const RdfId plugin_id = RdfId(RdfId::RESOURCE, plugin->uri()); _writer.write( plugin_id, NS_RDF("type"), RdfId(RdfId::RESOURCE, plugin->type_uri())); } void Serializer::serialize_node(SharedPtr node, const RdfId& node_id) { const RdfId plugin_id = RdfId(RdfId::RESOURCE, node->plugin()->uri()); _writer.write( node_id, NS_RDF("type"), NS_INGEN("Node")); _writer.write( node_id, NS_INGEN("name"), node->path().name()); _writer.write( node_id, NS_INGEN("plugin"), plugin_id); //serialize_plugin(node->plugin()); /*_writer.write(_serializer, node_uri_ref.c_str(), NS_INGEN("name"), Atom(node->path().name()));*/ for (PortModelList::const_iterator p = node->ports().begin(); p != node->ports().end(); ++p) { const RdfId port_id = path_to_node_id((*p)->path()); serialize_port(*p, port_id); _writer.write(node_id, NS_INGEN("port"), port_id); } for (MetadataMap::const_iterator m = node->metadata().begin(); m != node->metadata().end(); ++m) { if (_writer.expand_uri(m->first) != "") { _writer.write( node_id, RdfId(RdfId::RESOURCE, _writer.expand_uri(m->first.c_str()).c_str()), m->second); } } } /** Writes a port subject with various information only if there are some * predicate/object pairs to go with it (eg if the port has metadata, or a value, or..). * Audio output ports with no metadata will not be written, for example. */ void Serializer::serialize_port(SharedPtr port, const RdfId& port_id) { if (port->is_input()) _writer.write(port_id, NS_RDF("type"), NS_INGEN("InputPort")); else _writer.write(port_id, NS_RDF("type"), NS_INGEN("OutputPort")); _writer.write(port_id, NS_INGEN("name"), Atom(port->path().name().c_str())); _writer.write(port_id, NS_INGEN("dataType"), Atom(port->type())); if (port->is_control() && port->is_input()) _writer.write(port_id, NS_INGEN("value"), Atom(port->value())); if (port->metadata().size() > 0) { for (MetadataMap::const_iterator m = port->metadata().begin(); m != port->metadata().end(); ++m) { if (_writer.expand_uri(m->first) != "") { _writer.write( port_id, RdfId(RdfId::RESOURCE, _writer.expand_uri(m->first).c_str()), m->second); } } } } void Serializer::serialize_connection(SharedPtr connection) throw (std::logic_error) { const RdfId connection_id = RdfId(RdfId::ANONYMOUS, path_to_node_id(connection->src_port_path()).to_string() + "-" + path_to_node_id(connection->dst_port_path()).to_string()); _writer.write(path_to_node_id(connection->dst_port_path()), NS_INGEN("connectedTo"), path_to_node_id(connection->src_port_path())); /*_writer.write(connection_id, NS_RDF("type"), NS_INGEN("Connection")); _writer.write(connection_id, NS_INGEN("source"), path_to_node_id(connection->src_port_path())); _writer.write(connection_id, NS_INGEN("destination"), path_to_node_id(connection->dst_port_path())); */ } } // namespace Client } // namespace Ingen