END_TEST START_TEST (detect_smart_no) { OSyncError *error = NULL; OSyncFormatEnv *env = osync_format_env_new(&error); fail_unless(error == NULL); OSyncObjFormat *format1 = osync_objformat_new("Format1", "Type1", &error); OSyncObjFormat *format2 = osync_objformat_new("Format2", "Type1", &error); fail_unless(error == NULL); OSyncFormatConverter *conv = osync_converter_new_detector(format2, format1, detect_false, &error); fail_unless(error == NULL); osync_format_env_register_converter(env, conv, &error); mark_point(); OSyncData *data = osync_data_new("test", 5, format2, &error); fail_unless(error == NULL); OSyncObjFormat *result = osync_format_env_detect_objformat(env, data); fail_unless(!result); fail_unless(osync_data_get_objformat(data) == format2); osync_data_unref(data); osync_format_env_unref(env); }
OSyncObjFormat *osync_format_env_detect_objformat_full(OSyncFormatEnv *env, OSyncData *input, OSyncError **error) { OSyncObjFormat *detected_format = NULL; OSyncData *new_data = NULL; GList *d = NULL; osync_trace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, env, input, error); /* Make a copy of the data */ new_data = osync_data_clone(input, error); if (!new_data) goto error; /* Detect the format while DECAP the change as far as possible. Each DECAP triggers a new detection. */ while (TRUE) { OSyncFormatConverter *converter = NULL; if ((detected_format = osync_format_env_detect_objformat(env, new_data))) { /* We detected the format. So we replace the original format. */ osync_data_set_objformat(new_data, detected_format); } else detected_format = osync_data_get_objformat(new_data); /* Try to decap the change */ for (d = env->converters; d; d = d->next) { converter = d->data; if (osync_converter_matches(converter, new_data) && osync_converter_get_type(converter) == OSYNC_CONVERTER_DECAP) { /* Run the decap */ if (!osync_converter_invoke(converter, new_data, NULL, error)) { osync_error_set(error, OSYNC_ERROR_GENERIC, "Unable to decap the change"); goto error_free_data; } break; } else converter = NULL; } /* We couldnt find a decap, so we quit. */ if (!converter) break; } osync_data_unref(new_data); osync_trace(TRACE_EXIT, "%s: %p", __func__, detected_format); return detected_format; error_free_data: osync_data_unref(new_data); error: osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error)); return NULL; }
osync_bool osync_format_env_convert(OSyncFormatEnv *env, OSyncFormatConverterPath *path, OSyncData *data, OSyncError **error) { OSyncObjFormat *source = NULL; int length = 0; char *buffer = NULL; osync_trace(TRACE_ENTRY, "%s(%p, %p, %p, %p)", __func__, env, path, data, error); osync_assert(data); osync_assert(env); osync_assert(path); source = osync_data_get_objformat(data); osync_assert(source); length = osync_converter_path_num_edges(path); if (length == 0) { osync_trace(TRACE_EXIT, "%s: Path has 0 length", __func__); return TRUE; } osync_data_get_data(data, &buffer, NULL); if (!buffer) { /* Data without any data on them can be converted between any formats. Therefore * we just take the format of the last converter and set it on * the data */ OSyncFormatConverter *converter = osync_converter_path_nth_edge(path, length - 1); osync_data_set_objformat(data, osync_converter_get_targetformat(converter)); osync_data_set_objtype(data, osync_objformat_get_objtype(osync_converter_get_targetformat(converter))); } else { /* Otherwise we go through the conversion path * and call all converters along the way */ int i; for (i = 0; i < length; i++) { OSyncFormatConverter *converter = osync_converter_path_nth_edge(path, i); if (!osync_converter_invoke(converter, data, osync_converter_path_get_config(path), error)) { osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error)); return FALSE; } } } osync_trace(TRACE_EXIT, "%s", __func__); return TRUE; }
void osync_context_report_change(OSyncContext *context, OSyncChange *change) { OSyncData *data; osync_trace(TRACE_ENTRY, "%s(%p, %p)", __func__, context, change); osync_assert(context); osync_assert(change); osync_assert_msg(osync_change_get_uid(change), "You forgot to set a uid on the change you reported!"); osync_assert_msg(osync_change_get_data(change) || osync_change_get_changetype(change) == OSYNC_CHANGE_TYPE_DELETED, "You need to report some data unless you report CHANGE_DELETED"); data = osync_change_get_data(change); osync_assert_msg(((data && osync_data_get_objformat(data) != NULL) || osync_change_get_changetype(change) == OSYNC_CHANGE_TYPE_DELETED), "The reported change did not have a format set"); osync_assert_msg(((data && osync_data_get_objtype(data) != NULL) || osync_change_get_changetype(change) == OSYNC_CHANGE_TYPE_DELETED), "The reported change did not have a objtype set"); osync_trace(TRACE_INTERNAL, "Reporting change with uid %s, changetype %i, data %p", osync_change_get_uid(change), osync_change_get_changetype(change), osync_change_get_data(change)); osync_assert_msg(context->changes_function, "The engine must set a callback to receive changes"); context->changes_function(change, context->callback_data); osync_trace(TRACE_EXIT, "%s", __func__); }
OSyncObjFormat *osync_format_env_detect_objformat(OSyncFormatEnv *env, OSyncData *data) { GList *d = NULL; osync_trace(TRACE_ENTRY, "%s(%p, %p)", __func__, env, data); /* Run all datadetectors for our source type */ for (d = env->converters; d; d = d->next) { OSyncFormatConverter *converter = d->data; /* We check if the converter might be able to converter the change */ if (osync_converter_get_type(converter) == OSYNC_CONVERTER_DETECTOR && osync_converter_matches(converter, data)) { osync_trace(TRACE_INTERNAL, "running detector %s for format %s", osync_objformat_get_name(osync_converter_get_targetformat(converter)), osync_objformat_get_name(osync_data_get_objformat(data))); if (osync_converter_detect(converter, data)) { OSyncObjFormat *detected_format = osync_converter_get_targetformat(converter); osync_trace(TRACE_EXIT, "%s: %p", __func__, detected_format); return detected_format; } } } osync_trace(TRACE_EXIT, "%s: No detector triggered", __func__); return NULL; }
static OSyncFormatConverterPath *osync_format_env_find_path_fn(OSyncFormatEnv *env, OSyncData *sourcedata, OSyncPathTargetFn target_fn, OSyncTargetLastConverterFn last_converter_fn, const void *fndata, const char * preferred_format, OSyncError **error) { OSyncFormatConverterPath *path = NULL; OSyncFormatConverterTree *tree = NULL; OSyncFormatConverterPathVertice *begin = NULL; OSyncFormatConverterPathVertice *result = NULL; OSyncFormatConverterPathVertice *neighbour = NULL; GList *e, *v; guint vertice_id = 0; osync_trace(TRACE_ENTRY, "%s(%p, %p, %p, %p, %p)", __func__, env, sourcedata, target_fn, fndata, error); osync_assert(env); osync_assert(sourcedata); osync_assert(target_fn); //Vertice = Spitze = Format //edge = Kante = Converter /* Optimization: check if the format is already valid */ if (target_fn(fndata, osync_data_get_objformat(sourcedata))) { path = osync_converter_path_new(error); if (!path) goto error; osync_trace(TRACE_EXIT, "%s: Target already valid", __func__); return path; } /* Make a new search tree */ tree = osync_try_malloc0(sizeof(OSyncFormatConverterTree), error); if (!tree) goto error; tree->unused = g_list_copy(env->converters); /* We make our starting point (which is the current format of the * change of course */ begin = osync_format_converter_path_vertice_new(error); if (!begin) goto error_free_tree; begin->format = osync_data_get_objformat(sourcedata); begin->path = NULL; begin->id = vertice_id; begin->neighbour_id = 0; tree->search = g_list_append(NULL, begin); /* While there are still vertices in our * search queue */ while (g_list_length(tree->search)) { /* log current tree search list */ GString *string = g_string_new(""); guint size = g_list_length(tree->search); guint count = 0; guint neighbour_id = 0; OSyncFormatConverterPathVertice *current = NULL; OSyncFormatConverterPath *path_tmp = NULL; for (v = tree->search; v; v = v->next) { OSyncFormatConverterPathVertice *vertice = v->data; GString *string2 = g_string_new(""); guint size2 = g_list_length(vertice->path); guint count2 = 0; count ++; for (e = vertice->path; e; e = e->next) { OSyncFormatConverter *edge = e->data; count2 ++; if (count2 == 1) { g_string_append(string2, osync_objformat_get_name(osync_converter_get_sourceformat(edge))); g_string_append(string2, " -> "); } g_string_append(string2, osync_objformat_get_name(osync_converter_get_targetformat(edge))); if (size2 > 1 && count2 < size2) g_string_append(string2, " -> "); } g_string_append(string, osync_objformat_get_name(vertice->format)); g_string_append(string, " ( "); g_string_append(string, string2->str); g_string_append(string, " ) "); g_string_free(string2, TRUE); if (size > 1 && count < size) g_string_append(string, " -> "); } osync_trace(TRACE_INTERNAL, "Tree : %s", string->str); g_string_free(string, TRUE); /* Get the first OSyncFormatConverterPathVertice from the search queue * and remove it from the queue */ current = tree->search->data; tree->search = g_list_remove(tree->search, current); /* log current OSyncFormatConverterPathVertice */ string = g_string_new(""); size = g_list_length(current->path); count = 0; for (e = current->path; e; e = e->next) { OSyncFormatConverter *edge = e->data; count ++; if (count == 1) { g_string_append(string, osync_objformat_get_name(osync_converter_get_sourceformat(edge))); g_string_append(string, " -> "); } g_string_append(string, osync_objformat_get_name(osync_converter_get_targetformat(edge))); if (size > 1 && count < size) g_string_append(string, " -> "); } osync_trace(TRACE_INTERNAL, "Next vertice : %s (%s).", osync_objformat_get_name(current->format), string->str); g_string_free(string, TRUE); current->neighbour_id = 0; vertice_id++; // current OSyncFormatConverterPathVertice id for its neighbours /* Check if we have reached a target format */ if (target_fn(fndata, current->format)) { osync_trace(TRACE_INTERNAL, "Target %s found", osync_objformat_get_name(current->format)); /* Done. return the result */ result = current; break; } /* * Optimizations : */ if (last_converter_fn(fndata, tree)) { osync_trace(TRACE_INTERNAL, "Last converter for target format reached: %s.", (result)?osync_objformat_get_name(result->format):"null"); osync_format_converter_path_vertice_unref(current); break; } /* Check if saved result is equal to current regarding losses, objtype_changes * and conversions. If yes, we can skip further searches and break here */ if (result) { if (result->losses <= current->losses && result->objtype_changes <= current->objtype_changes && result->conversions <= current->conversions) { osync_trace(TRACE_INTERNAL, "Target %s found in queue", osync_objformat_get_name(result->format)); tree->search = g_list_remove(tree->search, result); break; } else { result = NULL; } } /* * If we dont have reached a target, we look at our neighbours */ osync_trace(TRACE_INTERNAL, "Looking at %s's neighbours.", osync_objformat_get_name(current->format)); /* Convert the "current" data to the last edge found in the "current" conversion path */ current->data = osync_data_clone(sourcedata, error); path_tmp = osync_converter_path_new(error); if (!path_tmp) goto error; for (e = current->path; e; e = e->next) { OSyncFormatConverter *edge = e->data; osync_converter_path_add_edge(path_tmp, edge); } if (!(osync_format_env_convert(env, path_tmp, current->data, error))) { osync_trace(TRACE_INTERNAL, "osync format env convert on this path failed - skipping the conversion"); continue; } osync_converter_path_unref(path_tmp); /* Find all the neighboors or "current" at its current conversion point */ while ((neighbour = osync_format_converter_path_vertice_get_next_vertice_neighbour(env, tree, current, error))) { GString *string = g_string_new(""); guint size = g_list_length(neighbour->path); guint count = 0; neighbour->id = vertice_id; neighbour_id++; neighbour->neighbour_id = neighbour_id; neighbour->preferred = FALSE; if (current->preferred) /* preferred is inherited by the neighbours */ neighbour->preferred = TRUE; if(preferred_format && !strcmp(preferred_format, osync_objformat_get_name(neighbour->format))) neighbour->preferred = TRUE; /* log neighbour to be added to the tree search list */ for (e = neighbour->path; e; e = e->next) { OSyncFormatConverter *edge = e->data; count ++; if (count == 1) { g_string_append(string, osync_objformat_get_name(osync_converter_get_sourceformat(edge))); g_string_append(string, " -> "); } g_string_append(string, osync_objformat_get_name(osync_converter_get_targetformat(edge))); if (size > 1 && count < size) g_string_append(string, " -> "); } osync_trace(TRACE_INTERNAL, "%s's neighbour : %s (%s)", osync_objformat_get_name(current->format), osync_objformat_get_name(neighbour->format), string->str); g_string_free(string, TRUE); /* We found a neighbour and insert it sorted in our search queue If vertices are equals in losses, objtypes and conversions, first registered is inserted before the others in the same OSyncFormatConverterPathVertice group (vertice_id) */ tree->search = g_list_insert_sorted(tree->search, neighbour, osync_format_converter_path_vertice_compare_distance); /* Optimization: * We found a possible target. Save it. */ if (target_fn(fndata, neighbour->format)) { osync_trace(TRACE_INTERNAL, "Possible target found."); result = neighbour; osync_format_converter_path_vertice_ref(result); } } if (osync_error_is_set(error)) goto error_free_tree; /* Done, drop the reference to the OSyncFormatConverterPathVertice */ osync_format_converter_path_vertice_unref(current); } if (!result) { osync_error_set(error, OSYNC_ERROR_GENERIC, "Unable to find conversion path"); goto error_free_tree; } /* Found it. Create a path object */ path = osync_converter_path_new(error); if (!path) goto error; for (e = result->path; e; e = e->next) { OSyncFormatConverter *edge = e->data; osync_converter_path_add_edge(path, edge); } /* Drop the reference to the result OSyncFormatConverterPathVertice */ osync_format_converter_path_vertice_unref(result); /* Free the tree */ osync_converter_tree_free(tree); osync_trace(TRACE_EXIT, "%s: %p", __func__, path); return path; error_free_tree: osync_converter_tree_free(tree); error: osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error)); return NULL; }