From: <svn...@op...> - 2009-10-18 10:29:55
|
Author: bellmich Date: Sun Oct 18 12:29:40 2009 New Revision: 1346 URL: http://libsyncml.opensync.org/changeset/1346 Log: fixed CRLF issue within CDATA This is a fix for a expat/libwbxml issue. Expat normalizes all CR and CRLF in cdata sections to LF. This means that all CRs inside of a vCard are lost. This means that libwbxml cannot transport CRs. The result is a wrong length calculation for SyncML data items. The solution is to replace all CRs and CRLFs by LFs. This is fully compliant with the XML specs. The only problem is the SyncML spec. NOTICE: The problem was discovered when I try to recover my mobile. NOTICE: I used syncml-ds-tool for this. NOTICE: The vCard of my girl friend included a photo with CRLFs. Modified: trunk/libsyncml/data_sync_api/sml_data_sync_change_item.c trunk/tests/CMakeLists.txt trunk/tests/check_data_sync_api_change_item.c Modified: trunk/libsyncml/data_sync_api/sml_data_sync_change_item.c ============================================================================== --- trunk/libsyncml/data_sync_api/sml_data_sync_change_item.c Sun Oct 18 12:23:27 2009 (r1345) +++ trunk/libsyncml/data_sync_api/sml_data_sync_change_item.c Sun Oct 18 12:29:40 2009 (r1346) @@ -345,6 +345,31 @@ g_free (self->priv->data); self->priv->data = g_strndup(data, size); + /* Carriage Return and Newlines must be normalized + * because XML / WBXML conversion fails otherwise. + * This is an expat issue inside of libwbxml. + */ + + gsize i = 0; + for (; i < strlen(self->priv->data); i++) + { + if (self->priv->data[i] == '\r') + { + if (i+1 < strlen(self->priv->data) && + self->priv->data[i+1] == '\n') + { + /* \r\n => \n */ + self->priv->data[i] = '\0'; + gchar *help = g_strjoin(NULL, self->priv->data, self->priv->data + i + 1, NULL); + g_free(self->priv->data); + self->priv->data = help; + } else { + /* \r => \n */ + self->priv->data[i] = '\n'; + } + } + } + sml_return_val_error_if_fail (self->priv->data, FALSE, error, SML_ERROR_GENERIC, "Cannot copy the data - out of memory."); return TRUE; Modified: trunk/tests/CMakeLists.txt ============================================================================== --- trunk/tests/CMakeLists.txt Sun Oct 18 12:23:27 2009 (r1345) +++ trunk/tests/CMakeLists.txt Sun Oct 18 12:29:40 2009 (r1346) @@ -119,6 +119,9 @@ SML_ADD_TESTCASE( change_item_attach_fragment ) SML_ADD_TESTCASE( change_item_attach_too_long_fragment ) SML_ADD_TESTCASE( change_item_attach_unnecessary_fragment ) + SML_ADD_TESTCASE( change_item_data_fix_cr ) + SML_ADD_TESTCASE( change_item_data_fix_crlf ) + SML_ADD_TESTCASE( change_item_data_fix_cr_and_crlf ) SML_ADD_TESTCASE( change_item_references ) SML_END_TEST() Modified: trunk/tests/check_data_sync_api_change_item.c ============================================================================== --- trunk/tests/check_data_sync_api_change_item.c Sun Oct 18 12:23:27 2009 (r1345) +++ trunk/tests/check_data_sync_api_change_item.c Sun Oct 18 12:29:40 2009 (r1346) @@ -790,6 +790,104 @@ } END_TEST +START_TEST (change_item_data_fix_cr) +{ + setup_testbed(NULL); + + GError *error = NULL; + + SmlDataSyncChangeItem *item = sml_data_sync_change_item_new(); + sml_fail_unless(item != NULL, NULL); + + const gchar* data = "1\r2"; + const gchar* result = "1\n2"; + sml_fail_unless(sml_data_sync_change_item_set_data(item, data, 0, &error), "%s", error?error->message:"No GError set."); + sml_fail_unless(error == NULL, NULL); + sml_fail_unless(strlen(data) == strlen(sml_data_sync_change_item_get_data(item)), "The length should not change during CR replacement."); + sml_fail_unless(!strcmp(result, sml_data_sync_change_item_get_data(item)), "CR must be replaced by LF."); + + data = "1\r2\r3\r4"; + sml_fail_unless(sml_data_sync_change_item_set_data(item, data, 0, &error), "%s", error?error->message:"No GError set."); + sml_fail_unless(error == NULL, NULL); + sml_fail_unless(strlen(data) == strlen(sml_data_sync_change_item_get_data(item)), "CRs must be replaced by LFs."); + + data = "1\r2\r3\r4\r"; + sml_fail_unless(sml_data_sync_change_item_set_data(item, data, 0, &error), "%s", error?error->message:"No GError set."); + sml_fail_unless(error == NULL, NULL); + sml_fail_unless(strlen(data) == strlen(sml_data_sync_change_item_get_data(item)), "CRs even at the end must be replaced by LFs."); + + data = "1\r2\r\r\r3\r4"; + sml_fail_unless(sml_data_sync_change_item_set_data(item, data, 0, &error), "%s", error?error->message:"No GError set."); + sml_fail_unless(error == NULL, NULL); + sml_fail_unless(strlen(data) == strlen(sml_data_sync_change_item_get_data(item)), "CRs must be replaced by LFs."); + + g_object_unref(item); +} +END_TEST + +START_TEST (change_item_data_fix_crlf) +{ + setup_testbed(NULL); + + GError *error = NULL; + + SmlDataSyncChangeItem *item = sml_data_sync_change_item_new(); + sml_fail_unless(item != NULL, NULL); + + const gchar* data = "1\r\n2"; + const gchar* result = "1\n2"; + sml_fail_unless(sml_data_sync_change_item_set_data(item, data, 0, &error), "%s", error?error->message:"No GError set."); + sml_fail_unless(error == NULL, NULL); + sml_fail_unless(strlen(data) -1 == strlen(sml_data_sync_change_item_get_data(item)), "One CRLF must be replaced by LF (%d != %d).", strlen(data) -1, strlen(sml_data_sync_change_item_get_data(item))); + sml_fail_unless(!strcmp(result, sml_data_sync_change_item_get_data(item)), "CRLF must be replaced by LF."); + + data = "1\r\n2\r\n3\r\n4"; + sml_fail_unless(sml_data_sync_change_item_set_data(item, data, 0, &error), "%s", error?error->message:"No GError set."); + sml_fail_unless(error == NULL, NULL); + sml_fail_unless(strlen(data) -3 == strlen(sml_data_sync_change_item_get_data(item)), "CRLFs must be replaced by LFs."); + + data = "1\r\n2\r\n3\r\n4\r\n"; + sml_fail_unless(sml_data_sync_change_item_set_data(item, data, 0, &error), "%s", error?error->message:"No GError set."); + sml_fail_unless(error == NULL, NULL); + sml_fail_unless(strlen(data) -4 == strlen(sml_data_sync_change_item_get_data(item)), "CRLFs even at the end must be replaced by LFs."); + + data = "1\r\n2\r\n\r\n\r\n3\r\n4"; + sml_fail_unless(sml_data_sync_change_item_set_data(item, data, 0, &error), "%s", error?error->message:"No GError set."); + sml_fail_unless(error == NULL, NULL); + sml_fail_unless(strlen(data) -5 == strlen(sml_data_sync_change_item_get_data(item)), "CRLFs must be replaced by LFs."); + + g_object_unref(item); +} +END_TEST + +START_TEST (change_item_data_fix_cr_and_crlf) +{ + setup_testbed(NULL); + + GError *error = NULL; + + SmlDataSyncChangeItem *item = sml_data_sync_change_item_new(); + sml_fail_unless(item != NULL, NULL); + + const gchar* data = "1\r2\r\n3\r\r\n4\r\n\r5"; + sml_fail_unless(sml_data_sync_change_item_set_data(item, data, 0, &error), "%s", error?error->message:"No GError set."); + sml_fail_unless(error == NULL, NULL); + sml_fail_unless(strlen(data) -3 == strlen(sml_data_sync_change_item_get_data(item)), "CRLF must be replaced by LF."); + + data = "1\r\n\r"; + sml_fail_unless(sml_data_sync_change_item_set_data(item, data, 0, &error), "%s", error?error->message:"No GError set."); + sml_fail_unless(error == NULL, NULL); + sml_fail_unless(strlen(data) -1 == strlen(sml_data_sync_change_item_get_data(item)), "CRLF must be replaced by LF."); + + data = "1\r\r\n"; + sml_fail_unless(sml_data_sync_change_item_set_data(item, data, 0, &error), "%s", error?error->message:"No GError set."); + sml_fail_unless(error == NULL, NULL); + sml_fail_unless(strlen(data) -1 == strlen(sml_data_sync_change_item_get_data(item)), "CRLF must be replaced by LF."); + + g_object_unref(item); +} +END_TEST + START_TEST (change_item_references) { setup_testbed(NULL); |