diff options
| author | Joel Klinghed <the_jk@spawned.biz> | 2024-09-25 21:47:01 +0200 |
|---|---|---|
| committer | Joel Klinghed <the_jk@spawned.biz> | 2024-09-25 21:47:01 +0200 |
| commit | 2d8949a0d9333bfda2385e3eab124581704286bf (patch) | |
| tree | 7c8845e80842e9cb88d2ca674b06022574f88444 | |
| parent | 00754eea8d203e34e2a2a52f23231fd7146e0629 (diff) | |
Add unicode filename test
And fix errors in MUTF-8 conversion in jni.cpp
3 files changed, 42 insertions, 19 deletions
diff --git a/libs/documents/src/androidTest/java/org/the_jk/cleversync/documents/DocumentTreeAndroidTest.kt b/libs/documents/src/androidTest/java/org/the_jk/cleversync/documents/DocumentTreeAndroidTest.kt index d0d6bb3..8510ef1 100644 --- a/libs/documents/src/androidTest/java/org/the_jk/cleversync/documents/DocumentTreeAndroidTest.kt +++ b/libs/documents/src/androidTest/java/org/the_jk/cleversync/documents/DocumentTreeAndroidTest.kt @@ -133,6 +133,11 @@ class DocumentTreeAndroidTest : TreeAbstractTest() { runTest { super.lastModified() } } + @Test + override fun unicodeFilename() { + runTest { super.unicodeFilename() } + } + override fun supportSymlinks() = false override fun idle() { diff --git a/libs/samba/src/main/cpp/jni.cpp b/libs/samba/src/main/cpp/jni.cpp index b7bbd1a..d3336ac 100644 --- a/libs/samba/src/main/cpp/jni.cpp +++ b/libs/samba/src/main/cpp/jni.cpp @@ -36,25 +36,26 @@ const char *_jni_error(jint err) { const char* u8_read(const char* str, uint32_t& out) { // Assume valid UTF-8 for speed and so it can be used to read modified utf-8 as well - switch (*str >> 4) { + auto* const d = reinterpret_cast<const uint8_t*>(str); + switch (d[0] >> 4) { case 0xf: // 4 byte - out = (static_cast<uint32_t>(str[0] & 0x7) << 18) | - (static_cast<uint32_t>(str[1] & 0x3f) << 12) | - (static_cast<uint32_t>(str[2] & 0x3f) << 6) | - static_cast<uint8_t>(str[3] & 0x3f); + out = (static_cast<uint32_t>(d[0] & 0x7) << 18) | + (static_cast<uint32_t>(d[1] & 0x3f) << 12) | + (static_cast<uint32_t>(d[2] & 0x3f) << 6) | + static_cast<uint8_t>(d[3] & 0x3f); return str + 4; case 0xe: // 3 byte - out = (static_cast<uint32_t>(str[0] & 0xf) << 12) | - (static_cast<uint32_t>(str[1] & 0x3f) << 6) | - static_cast<uint8_t>(str[2] & 0x3f); + out = (static_cast<uint32_t>(d[0] & 0xf) << 12) | + (static_cast<uint32_t>(d[1] & 0x3f) << 6) | + static_cast<uint8_t>(d[2] & 0x3f); return str + 3; case 0xd: case 0xc: // 2 byte - out = (static_cast<uint32_t>(str[0] & 0x1f) << 6) | - static_cast<uint8_t>(str[1] & 0x3f); + out = (static_cast<uint32_t>(d[0] & 0x1f) << 6) | + static_cast<uint8_t>(d[1] & 0x3f); return str + 2; default: // 1 byte - out = static_cast<uint8_t>(str[0]); + out = static_cast<uint8_t>(d[0]); return str + 1; } } @@ -77,16 +78,17 @@ void u8_write(std::string& ret, uint32_t c) { } } -std::string MakeModifiedUTF8(const char* str, const char* ptr, uint32_t c) { +std::string MakeModifiedUTF8(const char* str, const char* prev, const char* ptr, uint32_t c) { std::string ret; while (true) { - ret.append(str, ptr - str); + ret.append(str, prev - str); str = ptr; u8_write(ret, 0xd800 + ((c & 0xffff) >> 10)); u8_write(ret, 0xdc00 + (c & 0x3ff)); if (!*ptr) break; do { - ptr = u8_read(ptr, c); + prev = ptr; + ptr = u8_read(prev, c); if (c > 0xffff) break; } while (*ptr); @@ -98,15 +100,17 @@ std::optional<std::string> MakeModifiedUTF8IfNeeded(const char* str) { auto* ptr = str; while (*ptr) { uint32_t c; - ptr = u8_read(ptr, c); + auto* next = u8_read(ptr, c); if (c > 0xffff) { - return MakeModifiedUTF8(str, ptr, c); + return MakeModifiedUTF8(str, ptr, next, c); } + ptr = next; } return std::nullopt; } -const char* splice(std::string& str, const char* start, const char* end, const char* insert, size_t size) { +const char* splice(std::string& str, const char* start, const char* end, + const char* insert, size_t size) { auto pos = start - str.c_str(); str.replace(pos, end - start, insert, size); return str.c_str() + pos + size; @@ -229,8 +233,9 @@ LocalRef<jthrowable> ExceptionOccurred(JNIEnv* env) { std::string StringToUTF8(JNIEnv* env, const Ref<jstring>& str) { if (!str) return "null"; - auto len = env->GetStringUTFLength(str.get()); - std::string ret(len, ' '); + auto size = env->GetStringUTFLength(str.get()); + auto len = env->GetStringLength(str.get()); + std::string ret(size, ' '); env->GetStringUTFRegion(str.get(), 0, len, ret.data()); UnmodifyUTF8(ret); return ret; diff --git a/libs/test-utils/src/main/java/org/the_jk/cleversync/TreeAbstractTest.kt b/libs/test-utils/src/main/java/org/the_jk/cleversync/TreeAbstractTest.kt index 396e801..2555195 100644 --- a/libs/test-utils/src/main/java/org/the_jk/cleversync/TreeAbstractTest.kt +++ b/libs/test-utils/src/main/java/org/the_jk/cleversync/TreeAbstractTest.kt @@ -353,6 +353,19 @@ abstract class TreeAbstractTest { assertThat(old.isBefore(new) || old == new).isTrue() } + @Test + open fun unicodeFilename() { + val file = tree.createFile("r\u00E4ksm\u00f6rg\u00E4s") + file.write().use { it.write("Delicious".toByteArray()) } + val dir = tree.createDirectory("\uD83D\uDCA9") + + val content = tree.list() + assertThat(content.directories).hasSize(1) + assertThat(content.directories[0].name).isEqualTo(dir.name) + assertThat(content.files).hasSize(1) + assertThat(content.files[0].name).isEqualTo(file.name) + } + protected abstract fun supportSymlinks(): Boolean protected abstract fun idle() |
