Explorar o código

csync: Use Qt for encodeing/decoding filesystem strings

Issues:
 - #5661   On mac, iconv did not support all of unicode and some
           files with emoji in the filename could not be uploaded

 - #5719 , #5676  On linux, we will now support non utf-8 locale
Olivier Goffart %!s(int64=8) %!d(string=hai) anos
pai
achega
acf65b4c23
Modificáronse 4 ficheiros con 40 adicións e 36 borrados
  1. 13 0
      CMakeLists.txt
  2. 1 0
      csync/src/std/CMakeLists.txt
  3. 26 23
      csync/src/std/c_utf8.cc
  4. 0 13
      src/CMakeLists.txt

+ 13 - 0
CMakeLists.txt

@@ -191,6 +191,19 @@ add_definitions( -D__USE_MINGW_ANSI_STDIO=1 )
 add_definitions( -DNOMINMAX )
 endif( WIN32 )
 
+include(QtVersionAbstraction)
+setup_qt()
+if (${Qt5Core_VERSION_MAJOR} EQUAL "5")
+    if (${Qt5Core_VERSION_MINOR} EQUAL "6" OR ${Qt5Core_VERSION_MINOR} GREATER 6)
+    else()
+      message(STATUS "If possible compile me with Qt 5.6 or higher.")
+    endif()
+endif()
+
+if (APPLE)
+    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
+endif()
+
 # Handle Translations, pick all client_* files from trans directory.
 file( GLOB TRANS_FILES ${CMAKE_SOURCE_DIR}/translations/client_*.ts)
 set(TRANSLATIONS ${TRANS_FILES})

+ 1 - 0
csync/src/std/CMakeLists.txt

@@ -36,6 +36,7 @@ include_directories(
 add_library(${CSTDLIB_LIBRARY} STATIC ${cstdlib_SRCS})
 if(NOT WIN32)
     add_definitions( -fPIC )
+    qt5_use_modules(${CSTDLIB_LIBRARY} Core)
 endif()
 if(NOT HAVE_FNMATCH AND WIN32)
   # needed for PathMatchSpec for our fnmatch replacement

+ 26 - 23
csync/src/std/c_utf8.cc

@@ -21,18 +21,17 @@
 
 #include "config_csync.h"
 
-#include <assert.h>
-#include <errno.h>
+#ifdef _WIN32
 #include <ctype.h>
 #include <string.h>
 #include <stdlib.h>
-
 #include <limits.h>
 #include <sys/types.h>
 #include <wchar.h>
-
-#ifdef _WIN32
 #include <windows.h>
+#else
+#include <QtCore/QTextCodec>
+#include <QtCore/QFile>
 #endif
 
 extern "C" {
@@ -42,18 +41,15 @@ extern "C" {
 /* Convert a locale String to UTF8 */
 char* c_utf8_from_locale(const mbchar_t *wstr)
 {
-  char *dst = NULL;
-#ifdef _WIN32
-  char *mdst = NULL;
-  int size_needed;
-  size_t len;
-#endif
-
   if (wstr == NULL) {
     return NULL;
   }
 
 #ifdef _WIN32
+  char *dst = NULL;
+  char *mdst = NULL;
+  int size_needed;
+  size_t len;
   len = wcslen(wstr);
   /* Call once to get the required size. */
   size_needed = WideCharToMultiByte(CP_UTF8, 0, wstr, len, NULL, 0, NULL, NULL);
@@ -64,26 +60,33 @@ char* c_utf8_from_locale(const mbchar_t *wstr)
     WideCharToMultiByte(CP_UTF8, 0, wstr, len, mdst, size_needed, NULL, NULL);
     dst = mdst;
   }
+  return dst;
 #else
-  dst = c_strdup(wstr);
+    QTextDecoder dec(QTextCodec::codecForLocale());
+    QString s = dec.toUnicode(wstr, qstrlen(wstr));
+    if (s.isEmpty() || dec.hasFailure()) {
+        /* Conversion error: since we can't report error from this function, just return the original
+            string.  We take care of invalid utf-8 in SyncEngine::treewalkFile */
+        return c_strdup(wstr);
+    }
+#ifdef __APPLE__
+    s = s.normalized(QString::NormalizationForm_C);
+#endif
+    return c_strdup(std::move(s).toUtf8().constData());
 #endif
-  return dst;
 }
 
 /* Convert a an UTF8 string to locale */
 mbchar_t* c_utf8_string_to_locale(const char *str)
 {
-    mbchar_t *dst = NULL;
-#ifdef _WIN32
-    size_t len;
-    int size_needed;
-#endif
-
     if (str == NULL ) {
         return NULL;
     }
-
 #ifdef _WIN32
+    mbchar_t *dst = NULL;
+    size_t len;
+    int size_needed;
+
     len = strlen(str);
     size_needed = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0);
     if (size_needed > 0) {
@@ -92,10 +95,10 @@ mbchar_t* c_utf8_string_to_locale(const char *str)
         memset((void*)dst, 0, size_char);
         MultiByteToWideChar(CP_UTF8, 0, str, -1, dst, size_needed);
     }
+    return dst;
 #else
-    dst = c_strdup(str);
+    return c_strdup(QFile::encodeName(QString::fromUtf8(str)));
 #endif
-    return dst;
 }
 
 }

+ 0 - 13
src/CMakeLists.txt

@@ -4,19 +4,6 @@ endif()
 
 set(synclib_NAME ${APPLICATION_EXECUTABLE}sync)
 
-include(QtVersionAbstraction)
-setup_qt()
-if (${Qt5Core_VERSION_MAJOR} EQUAL "5")
-    if (${Qt5Core_VERSION_MINOR} EQUAL "6" OR ${Qt5Core_VERSION_MINOR} GREATER 6)
-    else()
-      message(STATUS "If possible compile me with Qt 5.6 or higher.")
-    endif()
-endif()
-
-if (APPLE)
-    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
-endif()
-
 if(NOT TOKEN_AUTH_ONLY)
     find_package(Qt5Keychain REQUIRED)
 endif()