summaryrefslogtreecommitdiff
path: root/libs/samba
diff options
context:
space:
mode:
authorJoel Klinghed <the_jk@spawned.biz>2024-09-25 21:12:24 +0200
committerJoel Klinghed <the_jk@spawned.biz>2024-09-25 21:12:24 +0200
commit28a55fdc69e31490a4086ecae8cc687f40ba0b94 (patch)
tree9bde6e49eb091f912e8a9f8b2853d87f6a932d27 /libs/samba
parent07d35782b377a8b98cf8dbbb5734d3f2514bccd5 (diff)
Add libs:sftp
sftp implementation using libssh2 and openssl
Diffstat (limited to 'libs/samba')
-rw-r--r--libs/samba/src/main/cpp/jni.cpp134
-rw-r--r--libs/samba/src/main/cpp/jni.hpp7
2 files changed, 140 insertions, 1 deletions
diff --git a/libs/samba/src/main/cpp/jni.cpp b/libs/samba/src/main/cpp/jni.cpp
index 5a69dc5..b7bbd1a 100644
--- a/libs/samba/src/main/cpp/jni.cpp
+++ b/libs/samba/src/main/cpp/jni.cpp
@@ -1,5 +1,8 @@
#include "jni.hpp"
+#include <algorithm>
+#include <optional>
+
#ifdef ANDROID
#include <android/log.h>
#else
@@ -31,6 +34,103 @@ 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) {
+ 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);
+ 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);
+ 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);
+ return str + 2;
+ default: // 1 byte
+ out = static_cast<uint8_t>(str[0]);
+ return str + 1;
+ }
+}
+
+void u8_write(std::string& ret, uint32_t c) {
+ if (c < 0x80) {
+ ret.push_back(static_cast<char>(c));
+ } else if (c < 0x800) {
+ ret.push_back(static_cast<char>(0xc0 | (c >> 6)));
+ ret.push_back(static_cast<char>(0x80 | (c & 0x3f)));
+ } else if (c < 0x10000) {
+ ret.push_back(static_cast<char>(0xe0 | (c >> 12)));
+ ret.push_back(static_cast<char>(0x80 | ((c >> 6) & 0x3f)));
+ ret.push_back(static_cast<char>(0x80 | (c & 0x3f)));
+ } else {
+ ret.push_back(static_cast<char>(0xf0 | (c >> 18)));
+ ret.push_back(static_cast<char>(0x80 | ((c >> 12) & 0x3f)));
+ ret.push_back(static_cast<char>(0x80 | ((c >> 6) & 0x3f)));
+ ret.push_back(static_cast<char>(0x80 | (c & 0x3f)));
+ }
+}
+
+std::string MakeModifiedUTF8(const char* str, const char* ptr, uint32_t c) {
+ std::string ret;
+ while (true) {
+ ret.append(str, ptr - 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);
+ if (c > 0xffff)
+ break;
+ } while (*ptr);
+ }
+ return ret;
+}
+
+std::optional<std::string> MakeModifiedUTF8IfNeeded(const char* str) {
+ auto* ptr = str;
+ while (*ptr) {
+ uint32_t c;
+ ptr = u8_read(ptr, c);
+ if (c > 0xffff) {
+ return MakeModifiedUTF8(str, ptr, c);
+ }
+ }
+ return std::nullopt;
+}
+
+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;
+}
+
+void UnmodifyUTF8(std::string& str) {
+ auto* ptr = str.c_str();
+ while (*ptr) {
+ uint32_t u;
+ auto* next = u8_read(ptr, u);
+ if (u == 0) {
+ next = splice(str, ptr, next, "\0", 1);
+ } else if (u >= 0xd800 && u <= 0xdfff) {
+ uint32_t v;
+ next = u8_read(next, v);
+ u = 0x10000 | ((u - 0xd800) << 10) | (v - 0xdc00);
+ std::string tmp;
+ u8_write(tmp, u);
+ next = splice(str, ptr, next, tmp.data(), tmp.size());
+ }
+ ptr = next;
+ }
+}
+
} // namespace
namespace jni {
@@ -132,14 +232,46 @@ std::string StringToUTF8(JNIEnv* env, const Ref<jstring>& str) {
auto len = env->GetStringUTFLength(str.get());
std::string ret(len, ' ');
env->GetStringUTFRegion(str.get(), 0, len, ret.data());
- // This returns modified UTF-8 encoding, don't care.
+ UnmodifyUTF8(ret);
return ret;
}
LocalRef<jstring> UTF8ToString(JNIEnv* env, const std::string& str) {
+ auto ret = MakeModifiedUTF8IfNeeded(str.c_str());
+ if (ret.has_value()) {
+ return {env, env->NewStringUTF(ret->c_str())};
+ }
return {env, env->NewStringUTF(str.c_str())};
}
+LocalRef<jstring> UTF8ToString(JNIEnv* env, const char* str) {
+ if (str == nullptr) return nullptr;
+ auto ret = MakeModifiedUTF8IfNeeded(str);
+ if (ret.has_value()) {
+ return {env, env->NewStringUTF(ret->c_str())};
+ }
+ return {env, env->NewStringUTF(str)};
+}
+
+LocalRef<jbyteArray> VectorToByteArray(JNIEnv* env, const std::vector<uint8_t>& data) {
+ auto len = static_cast<jsize>(data.size());
+ auto ret = LocalRef<jbyteArray>(env, env->NewByteArray(len));
+ ABORT_IF_NULL(env, ret);
+ auto* ptr = reinterpret_cast<jbyte*>(env->GetPrimitiveArrayCritical(ret.get(), nullptr));
+ std::copy_n(data.data(), data.size(), ptr);
+ env->ReleasePrimitiveArrayCritical(ret.get(), ptr, JNI_COMMIT);
+ return ret;
+}
+
+std::vector<uint8_t> ByteArrayToVector(JNIEnv* env, const Ref<jbyteArray>& data) {
+ if (!data) return {};
+ auto len = env->GetArrayLength(data.get());
+ std::vector<uint8_t> ret(len);
+ static_assert(sizeof(jbyte) == sizeof(uint8_t));
+ env->GetByteArrayRegion(data.get(), 0, len, reinterpret_cast<jbyte*>(ret.data()));
+ return ret;
+}
+
LocalRef<jobjectArray> CreateArray(JNIEnv* env, const Ref<jclass>& element_class, std::vector<LocalRef<jobject>> objects) {
auto ret = LocalRef<jobjectArray>(env, env->NewObjectArray(static_cast<jsize>(objects.size()), element_class.get(), nullptr));
ABORT_IF_NULL(env, ret);
diff --git a/libs/samba/src/main/cpp/jni.hpp b/libs/samba/src/main/cpp/jni.hpp
index 1729828..b9bdb69 100644
--- a/libs/samba/src/main/cpp/jni.hpp
+++ b/libs/samba/src/main/cpp/jni.hpp
@@ -2,6 +2,7 @@
#define CLEVERSYNC_JNI_HPP
#include <jni.h>
+#include <cstdint>
#include <string>
#include <vector>
@@ -186,6 +187,12 @@ std::string StringToUTF8(JNIEnv* env, const Ref<jstring>& str);
LocalRef<jstring> UTF8ToString(JNIEnv* env, const std::string& str);
+LocalRef<jstring> UTF8ToString(JNIEnv* env, const char* str);
+
+LocalRef<jbyteArray> VectorToByteArray(JNIEnv* env, const std::vector<uint8_t>& data);
+
+std::vector<uint8_t> ByteArrayToVector(JNIEnv* env, const Ref<jbyteArray>& data);
+
LocalRef<jobjectArray> CreateArray(JNIEnv* env, const Ref<jclass>& element_class, std::vector<LocalRef<jobject>> objects);
namespace internal {