/*
* libopensync - A synchronization framework
* Copyright (C) 2004-2005 Armin Bauer <armin.bauer@opensync.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "opensync.h"
#include "opensync_internals.h"
/**
* @ingroup OSyncConvPrivate
*/
/*@{*/
#ifndef DOXYGEN_SHOULD_SKIP_THIS
typedef struct conv_tree {
OSyncFormatEnv *env;
OSyncObjType *type;
/* The converters that weren't reached yet */
GList *unused;
/* The search queue for the Breadth-first search */
GList *search;
} conv_tree;
typedef struct vertice {
OSyncObjFormat *format;
/* The invoke_decap will return a new change everytime
* we run it so that the original change does not get
* changed. We also need to track if the data of this change
* should be freed or if it contains a reference into data of
* a previous change */
OSyncChange *change;
osync_bool free_change_data;
osync_bool free_change;
/** Keep reference counts because
* the data returned by converters
* can be references to other data,
* and we can't free them too early
*/
size_t references;
/** The path of converters */
GList *path;
unsigned losses;
unsigned objtype_changes;
unsigned conversions;
} vertice;
#endif
static OSyncFormatConverter *osync_conv_find_converter_objformat(OSyncFormatEnv *env, OSyncObjFormat *fmt_src, OSyncObjFormat *fmt_trg)
{
GList *element = NULL;
for (element = env->converters; element; element = element->next) {
OSyncFormatConverter *converter = element->data;
if (fmt_src == converter->source_format && fmt_trg == converter->target_format)
return converter;
}
return NULL;
}
osync_bool osync_converter_invoke(OSyncFormatConverter *converter, OSyncChange *change, void *converter_data, OSyncError **error)
{
osync_trace(TRACE_ENTRY, "osync_converter_invoke(%p, %p, %p)", converter, change, error);
osync_trace(TRACE_INTERNAL, "converter: Type: %i, source: %s, target %s", converter->type, converter->source_format->name, converter->target_format->name);
char *data = NULL;
int datasize = 0;
osync_bool ret = TRUE;
if (converter->type == CONVERTER_DETECTOR && !converter->convert_func) {
change->format = converter->target_format;
change->objtype = osync_change_get_objformat(change)->objtype;
osync_trace(TRACE_EXIT, "osync_converter_invoke: TRUE: Detector path");
return TRUE;
}
if (!converter->convert_func) {
osync_error_set(error, OSYNC_ERROR_GENERIC, "Invalid converter");
osync_trace(TRACE_EXIT_ERROR, "osync_converter_invoke: %s", osync_error_print(error));
return FALSE;
}
if (change->data) {
//Invoke the converter and all extensions
//osync_conv_invoke_extensions(converter->source_format, FALSE, change);
osync_bool free_input = FALSE;
if ((ret = converter->convert_func(converter_data, change->data, change->size, &data, &datasize, &free_input, error))) {
if (converter->type == CONVERTER_DECAP) {
if (!free_input) {
/* Duplicate the returned data, as the original data will be destroyed */
if (!converter->target_format->copy_func) {
/* There is nothing we can do, here. The returned data is a reference, but
* we can't copy the data before destroying it
*/
osync_debug("OSYNC", 0, "Format %s don't have a copy function, but a no-copy converter was registered", converter->target_format->name);
osync_error_set(error, OSYNC_ERROR_GENERIC, "Format %s don't have a copy function, but a no-copy converter was registered", converter->target_format->name);
osync_trace(TRACE_EXIT_ERROR, "osync_converter_invoke: %s", osync_error_print(error));
return FALSE;
}
converter->target_format->copy_func(data, datasize, &data, &datasize);
}
}
/* Free the data, unless the converter took the ownership of the data */
if (free_input) {
if (converter->source_format->destroy_func) {
converter->source_format->destroy_func(change->data, change->size);
} else
osync_debug("OSYNC", 1, "Format %s don't have a destroy function. Possible memory leak", converter->source_format->name);
}
change->data = data;
change->size = datasize;
//osync_conv_invoke_extensions(converter->target_format, TRUE, change);
}
}
if (ret) {
osync_debug("OSYNC", 3, "Converting! replacing format %s with %s", converter->source_format->name, converter->target_format->name);
change->format = converter->target_format;
change->objtype = osync_change_get_objformat(change)->objtype;
osync_trace(TRACE_EXIT, "osync_converter_invoke: TRUE");
} else
osync_trace(TRACE_EXIT_ERROR, "osync_converter_invoke: %s", osync_error_print(error));
return ret;
}
OSyncChange *osync_converter_invoke_decap(OSyncFormatConverter *converter, OSyncChange *change, osync_bool *free_output)
{
osync_trace(TRACE_ENTRY, "osync_converter_invoke_decap(%p, %p, %p)", converter, change, free_output);
*free_output = FALSE;
if (!converter->convert_func) {
osync_trace(TRACE_EXIT_ERROR, "osync_converter_invoke_decap: No convert function");
return NULL;
}
if (converter->type != CONVERTER_DECAP) {
osync_trace(TRACE_EXIT_ERROR, "osync_converter_invoke_decap: Not a decap");
return NULL;
}
OSyncChange *new_change = osync_change_new();
if (change->changetype != CHANGE_DELETED && change->data) {
//Invoke the converter and all extensions
OSyncError *error = NULL;
if (!converter->convert_func(NULL, change->data, change->size, &(new_change->data), &(new_change->size), free_output, &error)) {
osync_trace(TRACE_EXIT_ERROR, "osync_converter_invoke_decap: %s", osync_error_print(&error));
osync_error_free(&error);
return NULL;
}
new_change->has_data = change->has_data;
}
osync_debug("OSYNC", 3, "Converting! replacing format %s with %s", converter->source_format->name, converter->target_format->name);
new_change->format = converter->target_format;
new_change->objtype = osync_change_get_objformat(new_change)->objtype;
new_change->changetype = change->changetype;
osync_trace(TRACE_EXIT, "osync_converter_invoke_decap: %p", new_change);
return new_change;
}
/** Compare the distance of two vertices
*
* First, try to minimize the losses. Then,
* try to minimize the conversions between
* different objtypes. Then, try to minimize
* the total number of conversions.
*/
int compare_vertice_distance(const void *a, const void *b)
{
const vertice *va = a;
const vertice *vb = b;
if (va->losses < vb->losses)
return -1;
else if (va->losses > vb->losses)
return 1;
else if (va->objtype_changes < vb->objtype_changes)
return -1;
else if (va->objtype_changes > vb->objtype_changes)
return 1;
else if (va->conversions < vb->conversions)
return -1;
else if (va->conversions > vb->conversions)
return 1;
else
return 0;
}
/** Increment a vertice reference count */
/*static void ref_vertice(vertice *v)
{
v->references++;
}*/
/** Dereference an vertice
*/
static void deref_vertice(vertice *vertice)
{
/* Decrement the reference count,
* and just return if we still
* have a reference
*/
if (--vertice->references > 0)
return;
g_list_free(vertice->path);
if (vertice->change && vertice->free_change) {
if (vertice->free_change_data)
osync_change_free_data(vertice->change);
osync_change_free(vertice->change);
}
g_free(vertice);
}
/** Returns a neighbour of the vertice ve
*
* Returns a new reference to te vertice. The reference
* should be dropped using deref_vertice(), later.
*/
vertice *get_next_vertice_neighbour(OSyncFormatEnv *env, conv_tree *tree, vertice *ve)
{
GList *c = NULL;
osync_trace(TRACE_ENTRY, "get_next_vertice_neighbour(%p, %p, %p:%s)", env, tree, ve, ve->format ? ve->format->name : "None");
for (c = tree->unused; c; c = c->next) {
OSyncFormatConverter *converter = c->data;
OSyncObjFormat *fmt_target = converter->target_format;
/* Check only valid converters, from the right format */
if (strcmp(converter->source_format->name, ve->format->name))
continue;
// If the converter type is a detector we need to know wether the input is correct
if (converter->detect_func) {
if (!ve->change) {
osync_trace(TRACE_INTERNAL,
"We would call a converter to %s, but there is no change data on vertice", fmt_target->name);
continue;
}
if (ve->change->changetype != CHANGE_DELETED) {
if (!converter->detect_func(env, ve->change->data, ve->change->size)) {
osync_trace(TRACE_INTERNAL, "Invoked detector for converter from %s to %s: FALSE", converter->source_format->name, converter->target_format->name);
continue;
}
}
osync_trace(TRACE_INTERNAL, "Invoked detector for converter from %s to %s: TRUE", converter->source_format->name, converter->target_format->name);
}
OSyncChange *new_change = NULL;
osync_bool free_output = TRUE;
if (converter->type == CONVERTER_DECAP) {
if (!ve->change) {
osync_trace(TRACE_INTERNAL, "A desencapsulator to %s would be called, but we can't because the data on this vertice wasn't converted", fmt_target->name);
continue;
}
if (!(new_change = osync_converter_invoke_decap(converter, ve->change, &free_output)))
continue;
}
/* From this point, we already found an edge (i.e. a converter) that may
* be used
*/
/* Remove the converter from the unused list */
tree->unused = g_list_remove(tree->unused, converter);
/* Allocate the new neighbour */
vertice *neigh = g_malloc0(sizeof(vertice));
/* Start with a reference count = 1 */
neigh->references = 1;
neigh->format = fmt_target;
neigh->path = g_list_copy(ve->path);
neigh->path = g_list_append(neigh->path, converter);
if (new_change) {
neigh->change = new_change;
neigh->free_change = TRUE;
neigh->free_change_data = free_output;
} else {
neigh->change = NULL;
neigh->free_change = FALSE;
neigh->free_change_data = FALSE;
}
/* Distance calculation */
neigh->conversions = ve->conversions + 1;
neigh->losses = ve->losses;
if (converter->type == CONVERTER_DECAP)
neigh->losses++;
neigh->objtype_changes = ve->objtype_changes;
if (converter->source_format->objtype != converter->target_format->objtype)
neigh->objtype_changes++;
osync_trace(TRACE_EXIT, "get_next_vertice_neighbour: %p:%s", neigh, neigh->format ? neigh->format->name : "None");
return neigh;
}
osync_trace(TRACE_EXIT, "get_next_vertice_neighbour: None found");
return NULL;
}
/** Search for the shortest path of conversions to one or more formats
*
* This function search for the shortest path of conversions
* that can be made to a change, considering possible detections
* that may be necessary. The target is given by a function
* that check if a given format is a 'target vertice' or not. The
* function is used to allow the search path code to be used
* to search for 'objtype detection', search for the path
* for an available sink for a format, and maybe other uses.
*
* The list returned on path_edges should be freed by the caller.
*
* Note: NEVER use the detection/conversion functions on
* CHANGE_DELETED changes. Converting and detecting data
* on changes that have no data doesn't make sense
*
* @see osync_conv_convert_fn(), osync_change_convert(),
* osync_conv_convert_fmtlist(), osync_change_convert_member_sink()
*
* @see target_fn_fmtlist(), target_fn_fmtnames(),
* target_fn_simple(), target_fn_fmtname(),
* target_fn_membersink(), target_fn_no_any()
*/
static osync_bool osync_conv_find_path_fn(OSyncFormatEnv *env, OSyncChange *start, OSyncPathTargetFn target_fn, const void *fndata, GList/* OSyncConverter * */ **path_edges)
{
osync_trace(TRACE_ENTRY, "osync_conv_find_path_fn(%p, %p(%s, %s), %p, %p, %p)", env, start, start ? start->uid : "None", start ? start->format->name : "None", target_fn, fndata, path_edges);
g_assert(start->format);
*path_edges = NULL;
osync_bool ret = FALSE;
vertice *result = NULL;
//Vertice = Spitze = Format
//edge = Kante = Converter
//Make a new search tree
conv_tree *tree = g_malloc0(sizeof(conv_tree));
tree->unused = g_list_copy(env->converters);
//We make our starting point (which is the current format of the
//change of course
vertice *begin = g_malloc0(sizeof(vertice));
begin->format = start->format;
begin->path = NULL;
begin->references = 1;
begin->change = start;
begin->free_change_data = FALSE;
begin->free_change = FALSE;
tree->search = g_list_append(NULL, begin);
while (g_list_length(tree->search)) {
vertice *neighbour = NULL;
//Get the first vertice and remove it from the queue
vertice *current = tree->search->data;
tree->search = g_list_remove(tree->search, current);
osync_debug("OSCONV", 4, "Next vertice: %s.", current->format->name);
/* Check if we have reached a target format */
if (target_fn(fndata, current->format)) {
/* Done. return the result */
result = current;
break;
}
osync_debug("OSCONV", 4, "Looking at %s's neighbours.", current->format->name);
while ((neighbour = get_next_vertice_neighbour(env, tree, current))) {
osync_debug("OSCONV", 4, "%s's neighbour: %s", current->format->name, neighbour->format->name);
tree->search = g_list_insert_sorted(tree->search, neighbour, compare_vertice_distance);
}
/* Done, drop the reference to the vertice */
deref_vertice(current);
}
/* Remove the references on the search queue */
g_list_foreach(tree->search, (GFunc)deref_vertice, NULL);
if (result) {
/* Found it. Copy the conversion path */
*path_edges = g_list_copy(result->path);
/* Drop the reference to the result vertice */
deref_vertice(result);
ret = TRUE;
goto free_tree;
}
free_tree:
g_list_free(tree->unused);
g_list_free(tree->search);
g_free(tree);
if (ret)
osync_trace(TRACE_EXIT, "osync_conv_find_path_fn: TRUE");
else
osync_trace(TRACE_EXIT_ERROR, "osync_conv_find_path_fn: FALSE");
return ret;
}
osync_bool osync_conv_convert_fn(OSyncFormatEnv *env, OSyncChange *change, OSyncPathTargetFn target_fn, const void *fndata, const char *extension_name, OSyncError **error)
{
osync_trace(TRACE_ENTRY, "osync_conv_convert_fn(%p, %p, %p, %p, %p)", env, change, target_fn, fndata, error);
g_assert(change);
g_assert(target_fn);
OSyncObjFormat *source = osync_change_get_objformat(change);
osync_assert_msg(source, "Cannot convert! change has no objformat!");
GList *path = NULL;
osync_bool ret = TRUE;
/* Optimization: check if the format is already valid */
if (target_fn(fndata, source)) {
osync_trace(TRACE_EXIT, "osync_conv_convert_fn: Target already valid");
return TRUE;
}
//We can convert the deleted change directly since it has no data
/*if (change->changetype == CHANGE_DELETED) {
change->format = osync_change_get_initial_objformat(change);
change->objtype = osync_change_get_objformat(change)->objtype;
if (!target_fn(fndata, source)) {
osync_error_set(error, OSYNC_ERROR_GENERIC, "converted delete target would not be valid");
osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
return FALSE;
}
osync_trace(TRACE_EXIT, "osync_conv_convert_fn: converted deleted change");
return TRUE;
}*/
ret = FALSE;
if (!osync_conv_find_path_fn(env, change, target_fn, fndata, &path)) {
osync_error_set(error, OSYNC_ERROR_GENERIC, "Unable to find a conversion path to the format requested");
osync_trace(TRACE_EXIT_ERROR, "osync_conv_convert_fn: %s", osync_error_print(error));
goto out;
}
if (change->changetype == CHANGE_DELETED) {
OSyncFormatConverter *converter = g_list_last(path)->data;
change->format = converter->target_format;
change->objtype = osync_change_get_objformat(change)->objtype;
} else {
for (; path; path = path->next) {
OSyncFormatConverter *converter = path->data;
osync_trace(TRACE_INTERNAL, "initialize converter: %p", converter->init_func);
//Initialize the converter
void *converter_data = NULL;
if (converter->init_func)
converter_data = converter->init_func();
if (extension_name) {
osync_trace(TRACE_INTERNAL, "initialize extension: %s", extension_name);
//Initialize the requested extension
OSyncFormatExtension *extension = osync_conv_find_extension(env, converter->source_format, converter->target_format, extension_name);
osync_trace(TRACE_INTERNAL, "extension: %p", extension);
if (extension)
extension->init_func(converter_data);
} else {
osync_trace(TRACE_INTERNAL, "initialize all extensions");
//Initialize all available from extensions
GList *e;
for (e = env->extensions; e; e = e->next) {
OSyncFormatExtension *extension = e->data;
osync_trace(TRACE_INTERNAL, "extension: %s", extension->name);
osync_trace(TRACE_INTERNAL, "%p:%p %p:%p", extension->from_format, converter->source_format, extension->to_format, converter->target_format);
if (extension->from_format == converter->source_format && extension->to_format == converter->target_format)
extension->init_func(converter_data);
}
}
if (!osync_converter_invoke(converter, change, converter_data, error)) {
osync_trace(TRACE_EXIT_ERROR, "osync_conv_convert_fn: %s", osync_error_print(error));
goto out_free_path;
}
//Finalize the converter data
if (converter->fin_func)
converter->fin_func(converter_data);
}
}
ret = TRUE;
osync_trace(TRACE_EXIT, "osync_conv_convert_fn: TRUE");
out_free_path:
g_list_free(path);
out:
return ret;
}
/** Function used on path searchs for a format list
*
* @see osync_conv_find_path_fn(), osync_conv_convert_fmtlist()
*/
static osync_bool target_fn_fmtlist(const void *data, OSyncObjFormat *fmt)
{
const GList/*OSyncObjFormat * */ *l = data;
const GList *i;
for (i = l; i; i = i->next) {
OSyncObjFormat *f = i->data;
if (!strcmp(fmt->name, f->name))
return TRUE;
}
/* else */
return FALSE;
}
/** Convert a change to the nearest format on a list of formats
*/
osync_bool osync_conv_convert_fmtlist(OSyncFormatEnv *env, OSyncChange *change, GList/*OSyncObjFormat * */ *targets)
{
return osync_conv_convert_fn(env, change, target_fn_fmtlist, targets, NULL, NULL);
}
osync_bool osync_conv_find_path_fmtlist(OSyncFormatEnv *env, OSyncChange *start, GList/*OSyncObjFormat * */ *targets, GList **retlist)
{
return osync_conv_find_path_fn(env, start, target_fn_fmtlist, targets, retlist);
}
osync_bool osync_conv_objtype_is_any(const char *objstr)
{
if (!strcmp(objstr, "data"))
return TRUE;
return FALSE;
}
/*@}*/
/**
* @defgroup OSyncConvAPI OpenSync Conversion
* @ingroup OSyncPublic
* @brief Used to convert, compare and detect changes
*
*/
/*@{*/
/*! @brief This will create a new opensync format environment
*
* The environment will hold all information about plugins, formats etc
*
* @returns A pointer to a newly allocated environment. NULL on error.
*
*/
OSyncFormatEnv *osync_conv_env_new(OSyncEnv *env)
{
osync_trace(TRACE_ENTRY, "%s(%p)", __func__, env);
OSyncFormatEnv *conv_env = g_malloc0(sizeof(OSyncFormatEnv));
GList *o;
//Now we resolve all format plugin stuff for the conv env
//First the objecttypes
OSyncObjType *type = NULL;
for (o = env->objtype_templates; o; o = o->next) {
OSyncObjTypeTemplate *otempl = o->data;
type = g_malloc0(sizeof(OSyncObjType));
type->name = g_strdup(otempl->name);
type->env = conv_env;
conv_env->objtypes = g_list_append(conv_env->objtypes, type);
}
//The formats
GList *f = NULL;
for (f = env->format_templates; f; f = f->next) {
OSyncObjFormatTemplate *ftempl = f->data;
OSyncObjType *type = osync_conv_find_objtype(conv_env, ftempl->objtype);
g_assert(type);
OSyncObjFormat *format = g_malloc0(sizeof(OSyncObjFormat));
format->env = conv_env;
format->name = g_strdup(ftempl->name);
format->objtype = type;
format->cmp_func = ftempl->cmp_func;
format->merge_func = ftempl->merge_func;
format->duplicate_func = ftempl->duplicate_func;
format->copy_func = ftempl->copy_func;
format->create_func = ftempl->create_func;
format->destroy_func = ftempl->destroy_func;
format->print_func = ftempl->print_func;
format->revision_func = ftempl->revision_func;
format->marshall_func = ftempl->marshall_func;
format->demarshall_func = ftempl->demarshall_func;
type->formats = g_list_append(type->formats, format);
conv_env->objformats = g_list_append(conv_env->objformats, format);
}
//The extension
GList *i;
for (i = env->extension_templates; i; i = i->next) {
OSyncFormatExtensionTemplate *extension_template = i->data;
OSyncObjFormat *from_format = osync_conv_find_objformat(conv_env, extension_template->from_formatname);
OSyncObjFormat *to_format = osync_conv_find_objformat(conv_env, extension_template->to_formatname);
if (!from_format || !to_format)
continue;
OSyncFormatExtension *extension = g_malloc0(sizeof(OSyncFormatExtension));
extension->name = g_strdup(extension_template->name);
extension->init_func = extension_template->init_func;
extension->from_format = from_format;
extension->to_format = to_format;
conv_env->extensions = g_list_append(conv_env->extensions, extension);
}
//Converter templates
for (i = env->converter_templates; i; i = i->next) {
OSyncConverterTemplate *convtmpl = i->data;
osync_trace(TRACE_INTERNAL, "New converter from %s to %s", convtmpl->source_format, convtmpl->target_format);
OSyncObjFormat *fmt_src = osync_conv_find_objformat(conv_env, convtmpl->source_format);
OSyncObjFormat *fmt_trg = osync_conv_find_objformat(conv_env, convtmpl->target_format);
if (!fmt_src || !fmt_trg)
continue;
OSyncFormatConverter *converter = g_malloc0(sizeof(OSyncFormatConverter));
converter->source_format = fmt_src;
converter->target_format = fmt_trg;
converter->convert_func = convtmpl->convert_func;
converter->type = convtmpl->type;
converter->init_func = convtmpl->init_func;
conv_env->converters = g_list_append(conv_env->converters, converter);
}
//The detectors
for (i = env->data_detectors; i; i = i->next) {
OSyncDataDetector *detector = i->data;
OSyncFormatConverter *converter = osync_conv_find_converter(conv_env, detector->sourceformat, detector->targetformat);
if (!converter) {
OSyncObjFormat *fmt_src = osync_conv_find_objformat(conv_env, detector->sourceformat);
OSyncObjFormat *fmt_trg = osync_conv_find_objformat(conv_env, detector->targetformat);
if (!fmt_src || !fmt_trg)
continue;
converter = g_malloc0(sizeof(OSyncFormatConverter));
converter->source_format = fmt_src;
converter->target_format = fmt_trg;
converter->type = CONVERTER_DETECTOR;
}
converter->detect_func = detector->detect_func;
conv_env->converters = g_list_append(conv_env->converters, converter);
}
//The filters
conv_env->filter_functions = g_list_copy(env->filter_functions);
osync_conv_set_common_format(conv_env, "contact", "xml-contact", NULL);
osync_conv_set_common_format(conv_env, "event", "xml-event", NULL);
osync_conv_set_common_format(conv_env, "todo", "xml-todo", NULL);
osync_conv_set_common_format(conv_env, "note", "xml-note", NULL);
osync_trace(TRACE_EXIT, "%s: %p", __func__, conv_env);
return conv_env;
}
/*! @brief Frees a osync format environment
*
* Frees a osync format environment and all resources.
*
* @param env Pointer to the environment to free
*
*/
void osync_conv_env_free(OSyncFormatEnv *env)
{
g_assert(env);
//We need to go through the loaded objtypes and free them.
g_free(env);
}
/*! @brief Sets the common format for a object type
*
* @param env Pointer to the environment
* @param objtypestr The object type name for which to set the common format
* @param formatname The name of the format
* @param error Pointer to a error struct
* @returns TRUE if the format was successfully set
*
*/
osync_bool osync_conv_set_common_format(OSyncFormatEnv *env, const char *objtypestr, const char *formatname, OSyncError **error)
{
OSyncObjType *type = osync_conv_find_objtype(env, objtypestr);
if (!type) {
osync_error_set(error, OSYNC_ERROR_GENERIC, "Unable to set a common format: Unable to find the object-type \"%s\"", objtypestr);
return FALSE;
}
OSyncObjFormat *format = osync_conv_find_objformat(env, formatname);
if (!format) {
osync_error_set(error, OSYNC_ERROR_GENERIC, "Unable to set a common format: Unable to find the format \"%s\"", formatname);
return FALSE;
}
type->common_format = format;
return TRUE;
}
/*! @brief Finds the object type with the given name
*
* @param env Pointer to the environment
* @param name Name of the object type to find
* @returns The object type, or NULL if not found
*
*/
OSyncObjType *osync_conv_find_objtype(OSyncFormatEnv *env, const char *name)
{
g_assert(env);
g_assert(name);
GList *element = NULL;
for (element = env->objtypes; element; element = element->next) {
OSyncObjType *type = element->data;
if (!strcmp(type->name, name))
return type;
}
osync_debug("CONV", 1, "Unable to find the requested objtype \"%s\"", name);
return NULL;
}
/*! @brief Returns the number of available object types
*
* @param env Pointer to the environment
* @returns The number of object types
*
*/
int osync_conv_num_objtypes(OSyncFormatEnv *env)
{
g_assert(env);
return g_list_length(env->objtypes);
}
/*! @brief Gets the nth object type
*
* @param env Pointer to the environment
* @param nth The number
* @returns The object type, or NULL if there is no such object type
*
*/
OSyncObjType *osync_conv_nth_objtype(OSyncFormatEnv *env, int nth)
{
g_assert(env);
return g_list_nth_data(env->objtypes, nth);
}
/*! @brief Finds the object format with the given name
*
* @param env Pointer to the environment
* @param name Name of the format type to find
* @returns The object format, or NULL if not found
*
*/
OSyncObjFormat *osync_conv_find_objformat(OSyncFormatEnv *env, const char *name)
{
g_assert(env);
g_assert(name);
GList *element = NULL;
for (element = env->objformats; element; element = element->next) {
OSyncObjFormat *format = element->data;
if (!strcmp(format->name, name))
return format;
}
return NULL;
}
/*! @brief Returns the number of available object formats
*
* @param type The object type for whih to lookup the formats
* @returns The number of object formats
*
*/
int osync_conv_num_objformats(OSyncObjType *type)
{
g_assert(type);
return g_list_length(type->formats);
}
/*! @brief Gets the nth object format
*
* @param type The object for which to get the nth format
* @param nth The number
* @returns The object format, or NULL if there is no such object type
*
*/
OSyncObjFormat *osync_conv_nth_objformat(OSyncObjType *type, int nth)
{
g_assert(type);
return g_list_nth_data(type->formats, nth);
}
/*! @brief Finds the converter with the given source and target format
*
* @param env Pointer to the environment
* @param sourcename Name of the source format
* @param targetname Name of the target format
* @returns The converter, or NULL if not found
*
*/
OSyncFormatConverter *osync_conv_find_converter(OSyncFormatEnv *env, const char *sourcename, const char *targetname)
{
g_assert(env);
g_assert(sourcename);
g_assert(targetname);
OSyncObjFormat *fmt_src = osync_conv_find_objformat(env, sourcename);
if (!fmt_src)
return NULL;
OSyncObjFormat *fmt_trg = osync_conv_find_objformat(env, targetname);
if (!fmt_trg)
return NULL;
return osync_conv_find_converter_objformat(env, fmt_src, fmt_trg);
}
/*! @brief Finds the extension that will be invoked when going from the given source to the target format with the given name
*
* @param env Pointer to the environment
* @param from_format From Format
* @param to_format To Format
* @param extension_name The name of the extension to search
* @returns The extension, or NULL if not found
*
*/
OSyncFormatExtension *osync_conv_find_extension(OSyncFormatEnv *env, OSyncObjFormat *from_format, OSyncObjFormat *to_format, const char *extension_name)
{
g_assert(env);
g_assert(extension_name);
GList *i = NULL;
for (i = env->extensions; i; i = i->next) {
OSyncFormatExtension *extension = i->data;
osync_trace(TRACE_INTERNAL, "comparing format %p:%p %p:%p name %s:%s", extension->from_format, from_format, extension->to_format, to_format, extension->name, extension_name);
if ((extension->from_format == from_format || !from_format) && (extension->to_format == to_format || !to_format) && !strcmp(extension->name, extension_name))
return extension;
}
return NULL;
}
/*! @brief Returns the name of a object type
*
* @param type The object type
* @returns The name of the object type
*
*/
const char *osync_objtype_get_name(OSyncObjType *type)
{
g_assert(type);
return type->name;
}
/*! @brief Returns the name of a object format
*
* @param format The object format
* @returns The name of the object format
*
*/
const char *osync_objformat_get_name(OSyncObjFormat *format)
{
g_assert(format);
return format->name;
}
/*! @brief Returns the object type of a format
*
* @param format The object format
* @returns The object type
*
*/
OSyncObjType *osync_objformat_get_objtype(OSyncObjFormat *format)
{
g_assert(format);
return format->objtype;
}
/*@}*/
syntax highlighted by Code2HTML, v. 0.9.1