コード例 #1
0
ファイル: state.c プロジェクト: dmlloyd/Carla
static char*
abstract_path(LV2_State_Map_Path_Handle handle,
              const char*               abs_path)
{
	LilvState*    state     = (LilvState*)handle;
	char*         path      = NULL;
	char*         real_path = lilv_realpath(abs_path);
	const PathMap key       = { (char*)real_path, NULL };
	ZixTreeIter*  iter      = NULL;

	if (abs_path[0] == '\0') {
		return lilv_strdup(abs_path);
	} else if (!zix_tree_find(state->abs2rel, &key, &iter)) {
		// Already mapped path in a previous call
		PathMap* pm = (PathMap*)zix_tree_get(iter);
		free(real_path);
		return lilv_strdup(pm->rel);
	} else if (lilv_path_is_child(real_path, state->dir)) {
		// File in state directory (loaded, or created by plugin during save
		path = lilv_path_relative_to(real_path, state->dir);
	} else if (lilv_path_is_child(real_path, state->file_dir)) {
		// File created by plugin earlier
		path = lilv_path_relative_to(real_path, state->file_dir);
		if (state->copy_dir) {
			if (!lilv_path_exists(state->copy_dir, NULL)) {
				lilv_mkdir_p(state->copy_dir);
			}
			char* cpath = lilv_path_join(state->copy_dir, path);
			char* copy  = lilv_get_latest_copy(real_path, cpath);
			if (!copy || !lilv_file_equals(real_path, copy)) {
				// No recent enough copy, make a new one
				copy = lilv_find_free_path(cpath, lilv_path_exists, NULL);
				lilv_copy_file(real_path, copy);
			}
			free(real_path);
			free(cpath);

			// Refer to the latest copy in plugin state
			real_path = copy;
		}
	} else {
		// New path outside state directory
		const char* slash = strrchr(real_path, '/');
		const char* name  = slash ? (slash + 1) : real_path;

		// Find a free name in the (virtual) state directory
		path = lilv_find_free_path(name, lilv_state_has_path, state);
	}

	// Add record to path mapping
	PathMap* pm = (PathMap*)malloc(sizeof(PathMap));
	pm->abs = real_path;
	pm->rel = lilv_strdup(path);
	zix_tree_insert(state->abs2rel, pm, NULL);
	zix_tree_insert(state->rel2abs, pm, NULL);

	return path;
}
コード例 #2
0
ファイル: ui.c プロジェクト: kayosiii/Cadence
LilvUI*
lilv_ui_new(LilvWorld* world,
            LilvNode* uri,
            LilvNode* type_uri,
            LilvNode* binary_uri)
{
	assert(uri);
	assert(type_uri);
	assert(binary_uri);

	LilvUI* ui = (LilvUI*)malloc(sizeof(LilvUI));
	ui->world      = world;
	ui->uri        = uri;
	ui->binary_uri = binary_uri;

	// FIXME: kludge
	char* bundle     = lilv_strdup(lilv_node_as_string(ui->binary_uri));
	char* last_slash = strrchr(bundle, '/') + 1;
	*last_slash = '\0';
	ui->bundle_uri = lilv_new_uri(world, bundle);
	free(bundle);

	ui->classes = lilv_nodes_new();
	zix_tree_insert((ZixTree*)ui->classes, type_uri, NULL);

	return ui;
}
コード例 #3
0
ファイル: util.c プロジェクト: discokid/Carla
char*
lilv_dirname(const char* path)
{
	const char* s = path + strlen(path) - 1;  // Last character
	for (; s > path && lilv_is_dir_sep(*s); --s) {}  // Last non-slash
	for (; s > path && !lilv_is_dir_sep(*s); --s) {}  // Last internal slash
	for (; s > path && lilv_is_dir_sep(*s); --s) {}  // Skip duplicates

	if (s == path) {  // Hit beginning
		return lilv_is_dir_sep(*s) ? lilv_strdup("/") : lilv_strdup(".");
	} else {  // Pointing to the last character of the result (inclusive)
		char* dirname = (char*)malloc(s - path + 2);
		memcpy(dirname, path, s - path + 1);
		dirname[s - path + 1] = '\0';
		return dirname;
	}
}
コード例 #4
0
ファイル: state.c プロジェクト: dmlloyd/Carla
static char*
absolute_path(LV2_State_Map_Path_Handle handle,
              const char*               state_path)
{
	LilvState* state = (LilvState*)handle;
	char*      path  = NULL;
	if (lilv_path_is_absolute(state_path)) {
		// Absolute path, return identical path
		path = lilv_strdup(state_path);
	} else if (state->dir) {
		// Relative path inside state directory
		path = lilv_path_join(state->dir, state_path);
	} else {
		// State has not been saved, unmap
		path = lilv_strdup(lilv_state_rel2abs(state, state_path));
	}

	return path;
}
コード例 #5
0
ファイル: state.c プロジェクト: dmlloyd/Carla
LILV_API
int
lilv_state_save(LilvWorld*       world,
                LV2_URID_Map*    map,
                LV2_URID_Unmap*  unmap,
                const LilvState* state,
                const char*      uri,
                const char*      dir,
                const char*      filename)
{
	if (!filename || !dir || lilv_mkdir_p(dir)) {
		return 1;
	}

	char*       abs_dir = absolute_dir(dir);
	char* const path    = lilv_path_join(abs_dir, filename);
	FILE*       fd      = fopen(path, "w");
	if (!fd) {
		LILV_ERRORF("Failed to open %s (%s)\n", path, strerror(errno));
		free(abs_dir);
		free(path);
		return 4;
	}

	// FIXME: make parameter non-const?
	if (state->dir && strcmp(state->dir, abs_dir)) {
		free(state->dir);
		((LilvState*)state)->dir = lilv_strdup(abs_dir);
	}

	// Create symlinks to files if necessary
	lilv_state_make_links(state, abs_dir);

	// Write state to Turtle file
	SerdNode    file   = serd_node_new_file_uri(USTR(path), NULL, NULL, false);
	SerdEnv*    env    = NULL;
	SerdWriter* writer = ttl_file_writer(fd, &file, &env);

	SerdNode node = uri ? serd_node_from_string(SERD_URI, USTR(uri)) : file;
	int ret       = lilv_state_write(
		world, map, unmap, state, writer, (const char*)node.buf, dir);

	serd_node_free(&file);
	serd_writer_free(writer);
	serd_env_free(env);
	fclose(fd);

	char* const manifest = lilv_path_join(abs_dir, "manifest.ttl");
	add_state_to_manifest(state->plugin_uri, manifest, uri, path);

	free(manifest);
	free(abs_dir);
	free(path);
	return ret;
}
コード例 #6
0
ファイル: util.c プロジェクト: discokid/Carla
char*
lilv_realpath(const char* path)
{
#ifdef _WIN32
	char* out = (char*)malloc(MAX_PATH);
	GetFullPathName(path, MAX_PATH, out, NULL);
	return out;
#else
	char* real_path = realpath(path, NULL);
	return real_path ? real_path : lilv_strdup(path);
#endif
}
コード例 #7
0
ファイル: util.c プロジェクト: discokid/Carla
char*
lilv_path_absolute(const char* path)
{
	if (lilv_path_is_absolute(path)) {
		return lilv_strdup(path);
	} else {
		char* cwd      = getcwd(NULL, 0);
		char* abs_path = lilv_path_join(cwd, path);
		free(cwd);
		return abs_path;
	}
}
コード例 #8
0
ファイル: util.c プロジェクト: discokid/Carla
char*
lilv_path_join(const char* a, const char* b)
{
	if (!a) {
		return lilv_strdup(b);
	}

	const size_t a_len   = strlen(a);
	const size_t b_len   = b ? strlen(b) : 0;
	const size_t pre_len = a_len - (lilv_is_dir_sep(a[a_len - 1]) ? 1 : 0);
	char*        path    = (char*)calloc(1, a_len + b_len + 2);
	memcpy(path, a, pre_len);
	path[pre_len] = '/';
	if (b) {
		memcpy(path + pre_len + 1,
		       b + (lilv_is_dir_sep(b[0]) ? 1 : 0),
		       lilv_is_dir_sep(b[0]) ? b_len - 1 : b_len);
	}
	return path;
}
コード例 #9
0
ファイル: state.c プロジェクト: dmlloyd/Carla
static PortValue*
append_port_value(LilvState*  state,
                  const char* port_symbol,
                  const void* value,
                  uint32_t    size,
                  uint32_t    type)
{
	if (value) {
		state->values = (PortValue*)realloc(
			state->values, (++state->num_values) * sizeof(PortValue));
		PortValue* pv = &state->values[state->num_values - 1];
		pv->symbol = lilv_strdup(port_symbol);
		pv->value  = malloc(size);
		pv->size   = size;
		pv->type   = type;
		memcpy(pv->value, value, size);
		return pv;
	}
	return NULL;
}
コード例 #10
0
ファイル: util.c プロジェクト: discokid/Carla
int
lilv_mkdir_p(const char* dir_path)
{
	char*        path     = lilv_strdup(dir_path);
	const size_t path_len = strlen(path);
	for (size_t i = 1; i <= path_len; ++i) {
		if (path[i] == LILV_DIR_SEP[0] || path[i] == '\0') {
			path[i] = '\0';
			if (mkdir(path, 0755) && errno != EEXIST) {
				LILV_ERRORF("Failed to create %s (%s)\n",
				            path, strerror(errno));
				free(path);
				return 1;
			}
			path[i] = LILV_DIR_SEP[0];
		}
	}

	free(path);
	return 0;
}
コード例 #11
0
ファイル: util.c プロジェクト: discokid/Carla
char*
lilv_path_relative_to(const char* path, const char* base)
{
	const size_t path_len = strlen(path);
	const size_t base_len = strlen(base);
	const size_t min_len  = (path_len < base_len) ? path_len : base_len;

	// Find the last separator common to both paths
	size_t last_shared_sep = 0;
	for (size_t i = 0; i < min_len && path[i] == base[i]; ++i) {
		if (lilv_is_dir_sep(path[i])) {
			last_shared_sep = i;
		}
	}

	if (last_shared_sep == 0) {
		// No common components, return path
		return lilv_strdup(path);
	}

	// Find the number of up references ("..") required
	size_t up = 0;
	for (size_t i = last_shared_sep + 1; i < base_len; ++i) {
		if (lilv_is_dir_sep(base[i])) {
			++up;
		}
	}

	// Write up references
	const size_t suffix_len = path_len - last_shared_sep;
	char*        rel        = (char*)calloc(1, suffix_len + (up * 3) + 1);
	for (size_t i = 0; i < up; ++i) {
		memcpy(rel + (i * 3), "../", 3);
	}

	// Write suffix
	memcpy(rel + (up * 3), path + last_shared_sep + 1, suffix_len);
	return rel;
}
コード例 #12
0
ファイル: node.c プロジェクト: falkTX/Carla
LILV_API char*
lilv_node_get_turtle_token(const LilvNode* value)
{
	const char* str    = (const char*)sord_node_get_string(value->node);
	size_t      len    = 0;
	char*       result = NULL;
	SerdNode    node;

	switch (value->type) {
	case LILV_VALUE_URI:
		len    = strlen(str) + 3;
		result = (char*)calloc(len, 1);
		snprintf(result, len, "<%s>", str);
		break;
	case LILV_VALUE_BLANK:
		len    = strlen(str) + 3;
		result = (char*)calloc(len, 1);
		snprintf(result, len, "_:%s", str);
		break;
	case LILV_VALUE_STRING:
	case LILV_VALUE_BOOL:
	case LILV_VALUE_BLOB:
		result = lilv_strdup(str);
		break;
	case LILV_VALUE_INT:
		node   = serd_node_new_integer(value->val.int_val);
		result = (char*)node.buf;
		break;
	case LILV_VALUE_FLOAT:
		node   = serd_node_new_decimal(value->val.float_val, 8);
		result = (char*)node.buf;
		break;
	}

	return result;
}
コード例 #13
0
ファイル: state.c プロジェクト: dmlloyd/Carla
static LilvState*
new_state_from_model(LilvWorld*       world,
                     LV2_URID_Map*    map,
                     SordModel*       model,
                     const SordNode*  node,
                     const char*      dir)
{
	LilvState* const state = (LilvState*)malloc(sizeof(LilvState));
	memset(state, '\0', sizeof(LilvState));
	state->dir       = lilv_strdup(dir);
	state->atom_Path = map->map(map->handle, LV2_ATOM__Path);

	// Get the plugin URI this state applies to
	SordIter* i = sord_search(model, node, world->uris.lv2_appliesTo, 0, 0);
	if (i) {
		const SordNode* object = sord_iter_get_node(i, SORD_OBJECT);
		const SordNode* graph  = sord_iter_get_node(i, SORD_GRAPH);
		state->plugin_uri = lilv_node_new_from_node(world, object);
		if (!state->dir && graph) {
			state->dir = lilv_strdup((const char*)sord_node_get_string(graph));
		}
		sord_iter_free(i);
	} else if (sord_ask(model,
	                    node,
	                    world->uris.rdf_a,
	                    world->uris.lv2_Plugin, 0)) {
		// Loading plugin description as state (default state)
		state->plugin_uri = lilv_node_new_from_node(world, node);
	} else {
		LILV_ERRORF("State %s missing lv2:appliesTo property\n",
		            sord_node_get_string(node));
	}

	// Get the state label
	i = sord_search(model, node, world->uris.rdfs_label, NULL, NULL);
	if (i) {
		const SordNode* object = sord_iter_get_node(i, SORD_OBJECT);
		const SordNode* graph  = sord_iter_get_node(i, SORD_GRAPH);
		state->label = lilv_strdup((const char*)sord_node_get_string(object));
		if (!state->dir) {
			state->dir = lilv_strdup((const char*)sord_node_get_string(graph));
		}
		sord_iter_free(i);
	}

	Sratom*        sratom = sratom_new(map);
	SerdChunk      chunk  = { NULL, 0 };
	LV2_Atom_Forge forge;
	lv2_atom_forge_init(&forge, map);
	lv2_atom_forge_set_sink(
		&forge, sratom_forge_sink, sratom_forge_deref, &chunk);

	// Get port values
	SordIter* ports = sord_search(model, node, world->uris.lv2_port, 0, 0);
	FOREACH_MATCH(ports) {
		const SordNode* port = sord_iter_get_node(ports, SORD_OBJECT);

		SordNode* label  = sord_get(model, port, world->uris.rdfs_label, 0, 0);
		SordNode* symbol = sord_get(model, port, world->uris.lv2_symbol, 0, 0);
		SordNode* value  = sord_get(model, port, world->uris.pset_value, 0, 0);
		if (!value) {
			value = sord_get(model, port, world->uris.lv2_default, 0, 0);
		}
		if (!symbol) {
			LILV_ERRORF("State `%s' port missing symbol.\n",
			            sord_node_get_string(node));
		} else if (value) {
			chunk.len = 0;
			sratom_read(sratom, &forge, world->world, model, value);
			LV2_Atom* atom = (LV2_Atom*)chunk.buf;

			append_port_value(state,
			                  (const char*)sord_node_get_string(symbol),
			                  LV2_ATOM_BODY(atom), atom->size, atom->type);

			if (label) {
				lilv_state_set_label(state,
				                     (const char*)sord_node_get_string(label));
			}
		}
		sord_node_free(world->world, value);
		sord_node_free(world->world, symbol);
		sord_node_free(world->world, label);
	}
	sord_iter_free(ports);

	// Get properties
	SordNode* statep     = sord_new_uri(world->world, USTR(LV2_STATE__state));
	SordNode* state_node = sord_get(model, node, statep, NULL, NULL);
	if (state_node) {
		SordIter* props = sord_search(model, state_node, 0, 0, 0);
		FOREACH_MATCH(props) {
			const SordNode* p = sord_iter_get_node(props, SORD_PREDICATE);
			const SordNode* o = sord_iter_get_node(props, SORD_OBJECT);

			chunk.len = 0;
			lv2_atom_forge_set_sink(
				&forge, sratom_forge_sink, sratom_forge_deref, &chunk);

			sratom_read(sratom, &forge, world->world, model, o);
			LV2_Atom* atom  = (LV2_Atom*)chunk.buf;
			uint32_t  flags = LV2_STATE_IS_POD|LV2_STATE_IS_PORTABLE;
			Property  prop  = { NULL, 0, 0, 0, flags };

			prop.key   = map->map(map->handle, (const char*)sord_node_get_string(p));
			prop.type  = atom->type;
			prop.size  = atom->size;
			prop.value = malloc(atom->size);
			memcpy(prop.value, LV2_ATOM_BODY(atom), atom->size);
			if (atom->type == forge.Path) {
				prop.flags = LV2_STATE_IS_PORTABLE;
			}

			if (prop.value) {
				state->props = (Property*)realloc(
					state->props, (++state->num_props) * sizeof(Property));
				state->props[state->num_props - 1] = prop;
			}
		}
		sord_iter_free(props);
	}
	sord_node_free(world->world, state_node);
	sord_node_free(world->world, statep);

	free((void*)chunk.buf);
	sratom_free(sratom);

	qsort(state->props, state->num_props, sizeof(Property), property_cmp);
	qsort(state->values, state->num_values, sizeof(PortValue), value_cmp);

	return state;
}