OpenSync  0.22
opensync_convert.c
1 /*
2  * libopensync - A synchronization framework
3  * Copyright (C) 2004-2005 Armin Bauer <armin.bauer@opensync.org>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  *
19  */
20 
21 #include "opensync.h"
22 #include "opensync_internals.h"
23 
28 
29 #ifndef DOXYGEN_SHOULD_SKIP_THIS
30 typedef struct conv_tree {
31  OSyncFormatEnv *env;
32  OSyncObjType *type;
33 
34  /* The converters that weren't reached yet */
35  GList *unused;
36  /* The search queue for the Breadth-first search */
37  GList *search;
38 } conv_tree;
39 
40 typedef struct vertice {
41  OSyncObjFormat *format;
42 
43  /* The invoke_decap will return a new change everytime
44  * we run it so that the original change does not get
45  * changed. We also need to track if the data of this change
46  * should be freed or if it contains a reference into data of
47  * a previous change */
48  OSyncChange *change;
49  osync_bool free_change_data;
50  osync_bool free_change;
51 
57  size_t references;
58 
60  GList *path;
61 
62  unsigned losses;
63  unsigned objtype_changes;
64  unsigned conversions;
65 
66 } vertice;
67 #endif
68 
69 static OSyncFormatConverter *osync_conv_find_converter_objformat(OSyncFormatEnv *env, OSyncObjFormat *fmt_src, OSyncObjFormat *fmt_trg)
70 {
71  GList *element = NULL;
72  for (element = env->converters; element; element = element->next) {
73  OSyncFormatConverter *converter = element->data;
74  if (fmt_src == converter->source_format && fmt_trg == converter->target_format)
75  return converter;
76  }
77  return NULL;
78 }
79 
80 osync_bool osync_converter_invoke(OSyncFormatConverter *converter, OSyncChange *change, void *converter_data, OSyncError **error)
81 {
82  osync_trace(TRACE_ENTRY, "osync_converter_invoke(%p, %p, %p)", converter, change, error);
83  osync_trace(TRACE_INTERNAL, "converter: Type: %i, source: %s, target %s", converter->type, converter->source_format->name, converter->target_format->name);
84  char *data = NULL;
85  int datasize = 0;
86  osync_bool ret = TRUE;
87  if (converter->type == CONVERTER_DETECTOR && !converter->convert_func) {
88  change->format = converter->target_format;
89  change->objtype = osync_change_get_objformat(change)->objtype;
90  osync_trace(TRACE_EXIT, "osync_converter_invoke: TRUE: Detector path");
91  return TRUE;
92  }
93 
94  if (!converter->convert_func) {
95  osync_error_set(error, OSYNC_ERROR_GENERIC, "Invalid converter");
96  osync_trace(TRACE_EXIT_ERROR, "osync_converter_invoke: %s", osync_error_print(error));
97  return FALSE;
98  }
99 
100  if (change->data) {
101  //Invoke the converter and all extensions
102  //osync_conv_invoke_extensions(converter->source_format, FALSE, change);
103  osync_bool free_input = FALSE;
104  if ((ret = converter->convert_func(converter_data, change->data, change->size, &data, &datasize, &free_input, error))) {
105 
106  if (converter->type == CONVERTER_DECAP) {
107  if (!free_input) {
108  /* Duplicate the returned data, as the original data will be destroyed */
109  if (!converter->target_format->copy_func) {
110  /* There is nothing we can do, here. The returned data is a reference, but
111  * we can't copy the data before destroying it
112  */
113  osync_debug("OSYNC", 0, "Format %s don't have a copy function, but a no-copy converter was registered", converter->target_format->name);
114  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);
115  osync_trace(TRACE_EXIT_ERROR, "osync_converter_invoke: %s", osync_error_print(error));
116  return FALSE;
117  }
118  converter->target_format->copy_func(data, datasize, &data, &datasize);
119  }
120  }
121  /* Free the data, unless the converter took the ownership of the data */
122  if (free_input) {
123  if (converter->source_format->destroy_func) {
124  converter->source_format->destroy_func(change->data, change->size);
125  } else
126  osync_debug("OSYNC", 1, "Format %s don't have a destroy function. Possible memory leak", converter->source_format->name);
127  }
128  change->data = data;
129  change->size = datasize;
130 
131  //osync_conv_invoke_extensions(converter->target_format, TRUE, change);
132  }
133  }
134 
135  if (ret) {
136  osync_debug("OSYNC", 3, "Converting! replacing format %s with %s", converter->source_format->name, converter->target_format->name);
137  change->format = converter->target_format;
138  change->objtype = osync_change_get_objformat(change)->objtype;
139  osync_trace(TRACE_EXIT, "osync_converter_invoke: TRUE");
140  } else
141  osync_trace(TRACE_EXIT_ERROR, "osync_converter_invoke: %s", osync_error_print(error));
142  return ret;
143 }
144 
145 OSyncChange *osync_converter_invoke_decap(OSyncFormatConverter *converter, OSyncChange *change, osync_bool *free_output)
146 {
147  osync_trace(TRACE_ENTRY, "osync_converter_invoke_decap(%p, %p, %p)", converter, change, free_output);
148 
149  *free_output = FALSE;
150 
151  if (!converter->convert_func) {
152  osync_trace(TRACE_EXIT_ERROR, "osync_converter_invoke_decap: No convert function");
153  return NULL;
154  }
155 
156  if (converter->type != CONVERTER_DECAP) {
157  osync_trace(TRACE_EXIT_ERROR, "osync_converter_invoke_decap: Not a decap");
158  return NULL;
159  }
160 
161  OSyncChange *new_change = osync_change_new();
162 
163 
164  if (change->changetype != CHANGE_DELETED && change->data) {
165  //Invoke the converter and all extensions
166  OSyncError *error = NULL;
167  if (!converter->convert_func(NULL, change->data, change->size, &(new_change->data), &(new_change->size), free_output, &error)) {
168  osync_trace(TRACE_EXIT_ERROR, "osync_converter_invoke_decap: %s", osync_error_print(&error));
169  osync_error_free(&error);
170  return NULL;
171  }
172  new_change->has_data = change->has_data;
173  }
174  osync_debug("OSYNC", 3, "Converting! replacing format %s with %s", converter->source_format->name, converter->target_format->name);
175  new_change->format = converter->target_format;
176  new_change->objtype = osync_change_get_objformat(new_change)->objtype;
177  new_change->changetype = change->changetype;
178  osync_trace(TRACE_EXIT, "osync_converter_invoke_decap: %p", new_change);
179  return new_change;
180 }
181 
189 int compare_vertice_distance(const void *a, const void *b)
190 {
191  const vertice *va = a;
192  const vertice *vb = b;
193  if (va->losses < vb->losses)
194  return -1;
195  else if (va->losses > vb->losses)
196  return 1;
197  else if (va->objtype_changes < vb->objtype_changes)
198  return -1;
199  else if (va->objtype_changes > vb->objtype_changes)
200  return 1;
201  else if (va->conversions < vb->conversions)
202  return -1;
203  else if (va->conversions > vb->conversions)
204  return 1;
205  else
206  return 0;
207 }
208 
210 /*static void ref_vertice(vertice *v)
211 {
212  v->references++;
213 }*/
214 
217 static void deref_vertice(vertice *vertice)
218 {
219  /* Decrement the reference count,
220  * and just return if we still
221  * have a reference
222  */
223  if (--vertice->references > 0)
224  return;
225 
226  g_list_free(vertice->path);
227  if (vertice->change && vertice->free_change) {
228  if (vertice->free_change_data)
229  osync_change_free_data(vertice->change);
230  osync_change_free(vertice->change);
231  }
232 
233  g_free(vertice);
234 }
235 
241 vertice *get_next_vertice_neighbour(OSyncFormatEnv *env, conv_tree *tree, vertice *ve)
242 {
243  GList *c = NULL;
244  osync_trace(TRACE_ENTRY, "get_next_vertice_neighbour(%p, %p, %p:%s)", env, tree, ve, ve->format ? ve->format->name : "None");
245 
246  for (c = tree->unused; c; c = c->next) {
247  OSyncFormatConverter *converter = c->data;
248  OSyncObjFormat *fmt_target = converter->target_format;
249 
250  /* Check only valid converters, from the right format */
251  if (strcmp(converter->source_format->name, ve->format->name))
252  continue;
253 
254  // If the converter type is a detector we need to know wether the input is correct
255  if (converter->detect_func) {
256  if (!ve->change) {
258  "We would call a converter to %s, but there is no change data on vertice", fmt_target->name);
259  continue;
260  }
261 
262  if (ve->change->changetype != CHANGE_DELETED) {
263  if (!converter->detect_func(env, ve->change->data, ve->change->size)) {
264  osync_trace(TRACE_INTERNAL, "Invoked detector for converter from %s to %s: FALSE", converter->source_format->name, converter->target_format->name);
265  continue;
266  }
267  }
268 
269  osync_trace(TRACE_INTERNAL, "Invoked detector for converter from %s to %s: TRUE", converter->source_format->name, converter->target_format->name);
270  }
271 
272  OSyncChange *new_change = NULL;
273  osync_bool free_output = TRUE;
274  if (converter->type == CONVERTER_DECAP) {
275  if (!ve->change) {
276  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);
277  continue;
278  }
279 
280  if (!(new_change = osync_converter_invoke_decap(converter, ve->change, &free_output)))
281  continue;
282  }
283 
284  /* From this point, we already found an edge (i.e. a converter) that may
285  * be used
286  */
287 
288  /* Remove the converter from the unused list */
289  tree->unused = g_list_remove(tree->unused, converter);
290 
291  /* Allocate the new neighbour */
292  vertice *neigh = g_malloc0(sizeof(vertice));
293  /* Start with a reference count = 1 */
294  neigh->references = 1;
295  neigh->format = fmt_target;
296  neigh->path = g_list_copy(ve->path);
297  neigh->path = g_list_append(neigh->path, converter);
298 
299  if (new_change) {
300  neigh->change = new_change;
301  neigh->free_change = TRUE;
302  neigh->free_change_data = free_output;
303  } else {
304  neigh->change = NULL;
305  neigh->free_change = FALSE;
306  neigh->free_change_data = FALSE;
307  }
308 
309  /* Distance calculation */
310  neigh->conversions = ve->conversions + 1;
311  neigh->losses = ve->losses;
312  if (converter->type == CONVERTER_DECAP)
313  neigh->losses++;
314  neigh->objtype_changes = ve->objtype_changes;
315  if (converter->source_format->objtype != converter->target_format->objtype)
316  neigh->objtype_changes++;
317 
318  osync_trace(TRACE_EXIT, "get_next_vertice_neighbour: %p:%s", neigh, neigh->format ? neigh->format->name : "None");
319  return neigh;
320  }
321  osync_trace(TRACE_EXIT, "get_next_vertice_neighbour: None found");
322  return NULL;
323 }
324 
348 static osync_bool osync_conv_find_path_fn(OSyncFormatEnv *env, OSyncChange *start, OSyncPathTargetFn target_fn, const void *fndata, GList/* OSyncConverter * */ **path_edges)
349 {
350  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);
351 
352  g_assert(start->format);
353 
354  *path_edges = NULL;
355  osync_bool ret = FALSE;
356  vertice *result = NULL;
357 
358  //Vertice = Spitze = Format
359  //edge = Kante = Converter
360 
361  //Make a new search tree
362  conv_tree *tree = g_malloc0(sizeof(conv_tree));
363  tree->unused = g_list_copy(env->converters);
364 
365  //We make our starting point (which is the current format of the
366  //change of course
367  vertice *begin = g_malloc0(sizeof(vertice));
368  begin->format = start->format;
369  begin->path = NULL;
370  begin->references = 1;
371  begin->change = start;
372  begin->free_change_data = FALSE;
373  begin->free_change = FALSE;
374 
375  tree->search = g_list_append(NULL, begin);
376 
377  while (g_list_length(tree->search)) {
378  vertice *neighbour = NULL;
379 
380  //Get the first vertice and remove it from the queue
381  vertice *current = tree->search->data;
382  tree->search = g_list_remove(tree->search, current);
383 
384  osync_debug("OSCONV", 4, "Next vertice: %s.", current->format->name);
385  /* Check if we have reached a target format */
386  if (target_fn(fndata, current->format)) {
387  /* Done. return the result */
388  result = current;
389  break;
390  }
391  osync_debug("OSCONV", 4, "Looking at %s's neighbours.", current->format->name);
392  while ((neighbour = get_next_vertice_neighbour(env, tree, current))) {
393  osync_debug("OSCONV", 4, "%s's neighbour: %s", current->format->name, neighbour->format->name);
394  tree->search = g_list_insert_sorted(tree->search, neighbour, compare_vertice_distance);
395  }
396  /* Done, drop the reference to the vertice */
397  deref_vertice(current);
398  }
399  /* Remove the references on the search queue */
400  g_list_foreach(tree->search, (GFunc)deref_vertice, NULL);
401 
402  if (result) {
403  /* Found it. Copy the conversion path */
404  *path_edges = g_list_copy(result->path);
405  /* Drop the reference to the result vertice */
406  deref_vertice(result);
407  ret = TRUE;
408  goto free_tree;
409  }
410 
411 free_tree:
412  g_list_free(tree->unused);
413  g_list_free(tree->search);
414  g_free(tree);
415  if (ret)
416  osync_trace(TRACE_EXIT, "osync_conv_find_path_fn: TRUE");
417  else
418  osync_trace(TRACE_EXIT_ERROR, "osync_conv_find_path_fn: FALSE");
419  return ret;
420 }
421 
422 osync_bool osync_conv_convert_fn(OSyncFormatEnv *env, OSyncChange *change, OSyncPathTargetFn target_fn, const void *fndata, const char *extension_name, OSyncError **error)
423 {
424  osync_trace(TRACE_ENTRY, "osync_conv_convert_fn(%p, %p, %p, %p, %p)", env, change, target_fn, fndata, error);
425  g_assert(change);
426  g_assert(target_fn);
427  OSyncObjFormat *source = osync_change_get_objformat(change);
428  osync_assert_msg(source, "Cannot convert! change has no objformat!");
429  GList *path = NULL;
430  osync_bool ret = TRUE;
431 
432  /* Optimization: check if the format is already valid */
433  if (target_fn(fndata, source)) {
434  osync_trace(TRACE_EXIT, "osync_conv_convert_fn: Target already valid");
435  return TRUE;
436  }
437 
438  //We can convert the deleted change directly since it has no data
439  /*if (change->changetype == CHANGE_DELETED) {
440  change->format = osync_change_get_initial_objformat(change);
441  change->objtype = osync_change_get_objformat(change)->objtype;
442  if (!target_fn(fndata, source)) {
443  osync_error_set(error, OSYNC_ERROR_GENERIC, "converted delete target would not be valid");
444  osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
445  return FALSE;
446  }
447  osync_trace(TRACE_EXIT, "osync_conv_convert_fn: converted deleted change");
448  return TRUE;
449  }*/
450 
451  ret = FALSE;
452  if (!osync_conv_find_path_fn(env, change, target_fn, fndata, &path)) {
453  osync_error_set(error, OSYNC_ERROR_GENERIC, "Unable to find a conversion path to the format requested");
454  osync_trace(TRACE_EXIT_ERROR, "osync_conv_convert_fn: %s", osync_error_print(error));
455  goto out;
456  }
457 
458  if (change->changetype == CHANGE_DELETED) {
459  OSyncFormatConverter *converter = g_list_last(path)->data;
460  change->format = converter->target_format;
461  change->objtype = osync_change_get_objformat(change)->objtype;
462  } else {
463  for (; path; path = path->next) {
464  OSyncFormatConverter *converter = path->data;
465 
466  osync_trace(TRACE_INTERNAL, "initialize converter: %p", converter->init_func);
467 
468  //Initialize the converter
469  void *converter_data = NULL;
470  if (converter->init_func)
471  converter_data = converter->init_func();
472 
473  if (extension_name) {
474  osync_trace(TRACE_INTERNAL, "initialize extension: %s", extension_name);
475 
476  //Initialize the requested extension
477  OSyncFormatExtension *extension = osync_conv_find_extension(env, converter->source_format, converter->target_format, extension_name);
478  osync_trace(TRACE_INTERNAL, "extension: %p", extension);
479  if (extension)
480  extension->init_func(converter_data);
481  } else {
482 
483  osync_trace(TRACE_INTERNAL, "initialize all extensions");
484  //Initialize all available from extensions
485  GList *e;
486  for (e = env->extensions; e; e = e->next) {
487  OSyncFormatExtension *extension = e->data;
488  osync_trace(TRACE_INTERNAL, "extension: %s", extension->name);
489  osync_trace(TRACE_INTERNAL, "%p:%p %p:%p", extension->from_format, converter->source_format, extension->to_format, converter->target_format);
490  if (extension->from_format == converter->source_format && extension->to_format == converter->target_format)
491  extension->init_func(converter_data);
492  }
493  }
494 
495  if (!osync_converter_invoke(converter, change, converter_data, error)) {
496  osync_trace(TRACE_EXIT_ERROR, "osync_conv_convert_fn: %s", osync_error_print(error));
497  goto out_free_path;
498  }
499 
500  //Finalize the converter data
501  if (converter->fin_func)
502  converter->fin_func(converter_data);
503 
504  }
505  }
506  ret = TRUE;
507 
508  osync_trace(TRACE_EXIT, "osync_conv_convert_fn: TRUE");
509 out_free_path:
510  g_list_free(path);
511 out:
512  return ret;
513 }
514 
519 static osync_bool target_fn_fmtlist(const void *data, OSyncObjFormat *fmt)
520 {
521  const GList/*OSyncObjFormat * */ *l = data;
522  const GList *i;
523  for (i = l; i; i = i->next) {
524  OSyncObjFormat *f = i->data;
525  if (!strcmp(fmt->name, f->name))
526  return TRUE;
527  }
528  /* else */
529  return FALSE;
530 }
531 
534 osync_bool osync_conv_convert_fmtlist(OSyncFormatEnv *env, OSyncChange *change, GList/*OSyncObjFormat * */ *targets)
535 {
536  return osync_conv_convert_fn(env, change, target_fn_fmtlist, targets, NULL, NULL);
537 }
538 
539 osync_bool osync_conv_find_path_fmtlist(OSyncFormatEnv *env, OSyncChange *start, GList/*OSyncObjFormat * */ *targets, GList **retlist)
540 {
541  return osync_conv_find_path_fn(env, start, target_fn_fmtlist, targets, retlist);
542 }
543 
544 osync_bool osync_conv_objtype_is_any(const char *objstr)
545 {
546  if (!strcmp(objstr, "data"))
547  return TRUE;
548  return FALSE;
549 }
550 
560 
569 {
570  osync_trace(TRACE_ENTRY, "%s(%p)", __func__, env);
571  OSyncFormatEnv *conv_env = g_malloc0(sizeof(OSyncFormatEnv));
572  GList *o;
573 
574  //Now we resolve all format plugin stuff for the conv env
575  //First the objecttypes
576  OSyncObjType *type = NULL;
577  for (o = env->objtype_templates; o; o = o->next) {
578  OSyncObjTypeTemplate *otempl = o->data;
579  type = g_malloc0(sizeof(OSyncObjType));
580  type->name = g_strdup(otempl->name);
581  type->env = conv_env;
582  conv_env->objtypes = g_list_append(conv_env->objtypes, type);
583  }
584 
585  //The formats
586  GList *f = NULL;
587  for (f = env->format_templates; f; f = f->next) {
588  OSyncObjFormatTemplate *ftempl = f->data;
589  OSyncObjType *type = osync_conv_find_objtype(conv_env, ftempl->objtype);
590  g_assert(type);
591  OSyncObjFormat *format = g_malloc0(sizeof(OSyncObjFormat));
592  format->env = conv_env;
593  format->name = g_strdup(ftempl->name);
594  format->objtype = type;
595 
596  format->cmp_func = ftempl->cmp_func;
597  format->merge_func = ftempl->merge_func;
598  format->duplicate_func = ftempl->duplicate_func;
599  format->copy_func = ftempl->copy_func;
600  format->create_func = ftempl->create_func;
601  format->destroy_func = ftempl->destroy_func;
602  format->print_func = ftempl->print_func;
603  format->revision_func = ftempl->revision_func;
604  format->marshall_func = ftempl->marshall_func;
605  format->demarshall_func = ftempl->demarshall_func;
606  type->formats = g_list_append(type->formats, format);
607  conv_env->objformats = g_list_append(conv_env->objformats, format);
608  }
609 
610  //The extension
611  GList *i;
612  for (i = env->extension_templates; i; i = i->next) {
613  OSyncFormatExtensionTemplate *extension_template = i->data;
614  OSyncObjFormat *from_format = osync_conv_find_objformat(conv_env, extension_template->from_formatname);
615  OSyncObjFormat *to_format = osync_conv_find_objformat(conv_env, extension_template->to_formatname);
616  if (!from_format || !to_format)
617  continue;
618 
619  OSyncFormatExtension *extension = g_malloc0(sizeof(OSyncFormatExtension));
620  extension->name = g_strdup(extension_template->name);
621  extension->init_func = extension_template->init_func;
622  extension->from_format = from_format;
623  extension->to_format = to_format;
624 
625  conv_env->extensions = g_list_append(conv_env->extensions, extension);
626  }
627 
628  //Converter templates
629  for (i = env->converter_templates; i; i = i->next) {
630  OSyncConverterTemplate *convtmpl = i->data;
631 
632  osync_trace(TRACE_INTERNAL, "New converter from %s to %s", convtmpl->source_format, convtmpl->target_format);
633 
634  OSyncObjFormat *fmt_src = osync_conv_find_objformat(conv_env, convtmpl->source_format);
635  OSyncObjFormat *fmt_trg = osync_conv_find_objformat(conv_env, convtmpl->target_format);
636  if (!fmt_src || !fmt_trg)
637  continue;
638  OSyncFormatConverter *converter = g_malloc0(sizeof(OSyncFormatConverter));
639  converter->source_format = fmt_src;
640  converter->target_format = fmt_trg;
641  converter->convert_func = convtmpl->convert_func;
642  converter->type = convtmpl->type;
643  converter->init_func = convtmpl->init_func;
644 
645  conv_env->converters = g_list_append(conv_env->converters, converter);
646  }
647 
648  //The detectors
649  for (i = env->data_detectors; i; i = i->next) {
650  OSyncDataDetector *detector = i->data;
651  OSyncFormatConverter *converter = osync_conv_find_converter(conv_env, detector->sourceformat, detector->targetformat);
652  if (!converter) {
653  OSyncObjFormat *fmt_src = osync_conv_find_objformat(conv_env, detector->sourceformat);
654  OSyncObjFormat *fmt_trg = osync_conv_find_objformat(conv_env, detector->targetformat);
655  if (!fmt_src || !fmt_trg)
656  continue;
657  converter = g_malloc0(sizeof(OSyncFormatConverter));
658  converter->source_format = fmt_src;
659  converter->target_format = fmt_trg;
660  converter->type = CONVERTER_DETECTOR;
661  }
662  converter->detect_func = detector->detect_func;
663  conv_env->converters = g_list_append(conv_env->converters, converter);
664  }
665 
666  //The filters
667  conv_env->filter_functions = g_list_copy(env->filter_functions);
668 
669  osync_conv_set_common_format(conv_env, "contact", "xml-contact", NULL);
670  osync_conv_set_common_format(conv_env, "event", "xml-event", NULL);
671  osync_conv_set_common_format(conv_env, "todo", "xml-todo", NULL);
672  osync_conv_set_common_format(conv_env, "note", "xml-note", NULL);
673 
674  osync_trace(TRACE_EXIT, "%s: %p", __func__, conv_env);
675  return conv_env;
676 }
677 
686 {
687  g_assert(env);
688 
689  //We need to go through the loaded objtypes and free them.
690 
691  g_free(env);
692 }
693 
703 osync_bool osync_conv_set_common_format(OSyncFormatEnv *env, const char *objtypestr, const char *formatname, OSyncError **error)
704 {
705  OSyncObjType *type = osync_conv_find_objtype(env, objtypestr);
706  if (!type) {
707  osync_error_set(error, OSYNC_ERROR_GENERIC, "Unable to set a common format: Unable to find the object-type \"%s\"", objtypestr);
708  return FALSE;
709  }
710  OSyncObjFormat *format = osync_conv_find_objformat(env, formatname);
711  if (!format) {
712  osync_error_set(error, OSYNC_ERROR_GENERIC, "Unable to set a common format: Unable to find the format \"%s\"", formatname);
713  return FALSE;
714  }
715  type->common_format = format;
716  return TRUE;
717 }
718 
727 {
728  g_assert(env);
729  g_assert(name);
730 
731  GList *element = NULL;
732  for (element = env->objtypes; element; element = element->next) {
733  OSyncObjType *type = element->data;
734  if (!strcmp(type->name, name))
735  return type;
736  }
737  osync_debug("CONV", 1, "Unable to find the requested objtype \"%s\"", name);
738  return NULL;
739 }
740 
748 {
749  g_assert(env);
750  return g_list_length(env->objtypes);
751 }
752 
761 {
762  g_assert(env);
763  return g_list_nth_data(env->objtypes, nth);
764 }
765 
774 {
775  g_assert(env);
776  g_assert(name);
777 
778  GList *element = NULL;
779  for (element = env->objformats; element; element = element->next) {
780  OSyncObjFormat *format = element->data;
781  if (!strcmp(format->name, name))
782  return format;
783  }
784  return NULL;
785 }
786 
794 {
795  g_assert(type);
796  return g_list_length(type->formats);
797 }
798 
807 {
808  g_assert(type);
809  return g_list_nth_data(type->formats, nth);
810 }
811 
820 OSyncFormatConverter *osync_conv_find_converter(OSyncFormatEnv *env, const char *sourcename, const char *targetname)
821 {
822  g_assert(env);
823  g_assert(sourcename);
824  g_assert(targetname);
825 
826  OSyncObjFormat *fmt_src = osync_conv_find_objformat(env, sourcename);
827  if (!fmt_src)
828  return NULL;
829  OSyncObjFormat *fmt_trg = osync_conv_find_objformat(env, targetname);
830  if (!fmt_trg)
831  return NULL;
832 
833  return osync_conv_find_converter_objformat(env, fmt_src, fmt_trg);
834 }
835 
845 OSyncFormatExtension *osync_conv_find_extension(OSyncFormatEnv *env, OSyncObjFormat *from_format, OSyncObjFormat *to_format, const char *extension_name)
846 {
847  g_assert(env);
848  g_assert(extension_name);
849 
850  GList *i = NULL;
851  for (i = env->extensions; i; i = i->next) {
852  OSyncFormatExtension *extension = i->data;
853  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);
854  if ((extension->from_format == from_format || !from_format) && (extension->to_format == to_format || !to_format) && !strcmp(extension->name, extension_name))
855  return extension;
856  }
857  return NULL;
858 }
859 
867 {
868  g_assert(type);
869  return type->name;
870 }
871 
879 {
880  g_assert(format);
881  return format->name;
882 }
883 
891 {
892  g_assert(format);
893  return format->objtype;
894 }
895