diff --git a/example/android/build.sh b/example/android/build.sh index 91a5c9f4..aa6dddea 100755 --- a/example/android/build.sh +++ b/example/android/build.sh @@ -34,7 +34,7 @@ cd build-$ARCH cmake .. \ - -DCMAKE_TOOLCHAIN_FILE=${ANDROID_NDK_ROOT}/build/cmake/android.toolchain.cmake -DCMAKE_BUILD_TYPE=Release -GNinja -DANDROID_ABI=${ABI} -DOPENSSL_ROOT_DIR=/Users/arseny30/Code/td_android/libtd/src/main/jni/third_party/crypto/${ARCH} -DTON_ARCH="" -DTON_ONLY_TONLIB=ON || exit 1 + -DCMAKE_TOOLCHAIN_FILE=${ANDROID_NDK_ROOT}/build/cmake/android.toolchain.cmake -DCMAKE_BUILD_TYPE=Release -GNinja -DANDROID_ABI=${ABI} -DOPENSSL_ROOT_DIR=${OPENSSL_DIR}/${ARCH} -DTON_ARCH="" -DTON_ONLY_TONLIB=ON || exit 1 ninja native-lib || exit 1 popd diff --git a/tl/generate/tl_writer_java.cpp b/tl/generate/tl_writer_java.cpp index 690d843d..d371c2f8 100644 --- a/tl/generate/tl_writer_java.cpp +++ b/tl/generate/tl_writer_java.cpp @@ -33,7 +33,7 @@ int TD_TL_writer_java::get_max_arity() const { } bool TD_TL_writer_java::is_built_in_simple_type(const std::string &name) const { - return name == "Bool" || name == "Int32" || name == "Int53" || name == "Int64" || name == "Double" || + return name == "Bool" || name == "Int32" || name == "Int53" || name == "Int64" || name == "Int128" || name == "Int256" || name == "Double" || name == "String" || name == "Bytes" || name == "SecureString" || name == "SecureBytes" || name == "Object" || name == "Function"; } @@ -93,9 +93,12 @@ std::string TD_TL_writer_java::gen_base_function_class_name() const { } std::string TD_TL_writer_java::gen_class_name(std::string name) const { - if (name == "Object" || name == "#") { + if (name == "Object") { assert(false); } + if (name == "#") { + return "int"; + } bool next_to_upper = true; std::string result; for (std::size_t i = 0; i < name.size(); i++) { @@ -149,7 +152,7 @@ std::string TD_TL_writer_java::gen_type_name(const tl::tl_tree_type *tree_type) const std::string &name = t->name; if (name == "#") { - assert(false); + return "int"; } if (name == "Bool") { return "boolean"; @@ -166,7 +169,7 @@ std::string TD_TL_writer_java::gen_type_name(const tl::tl_tree_type *tree_type) if (name == "String" || name == "SecureString") { return "String"; } - if (name == "Bytes" || name == "SecureBytes") { + if (name == "Bytes" || name == "SecureBytes" || name == "Int128" || name == "Int256") { return "byte[]"; } if (name == "Object") { @@ -269,9 +272,6 @@ std::string TD_TL_writer_java::gen_vars(const tl::tl_combinator *t, const tl::tl assert(t->args[i].type->get_type() != tl::NODE_TYPE_VAR_TYPE); } - for (std::size_t i = 0; i < vars.size(); i++) { - assert(vars[i].is_type); - } return ""; } @@ -286,12 +286,19 @@ std::string TD_TL_writer_java::gen_function_vars(const tl::tl_combinator *t, } for (std::size_t i = 0; i < t->args.size(); i++) { - assert(t->args[i].type->get_type() != tl::NODE_TYPE_VAR_TYPE); + const tl::arg &a = t->args[i]; + + int arg_type = a.type->get_type(); + if (arg_type == tl::NODE_TYPE_VAR_TYPE) { + const tl::tl_tree_var_type *var_type = static_cast(a.type); + assert(a.flags & tl::FLAG_EXCL); + assert(var_type->var_num >= 0); + assert(!vars[var_type->var_num].is_type); + vars[var_type->var_num].is_type = true; + vars[var_type->var_num].function_arg_num = static_cast(i); + } } - for (std::size_t i = 0; i < vars.size(); i++) { - assert(vars[i].is_type); - } return ""; } @@ -309,19 +316,41 @@ std::string TD_TL_writer_java::gen_field_fetch(int field_num, const tl::arg &a, bool flat, int parser_type) const { assert(parser_type >= 0); - assert(a.exist_var_num == -1); - assert(a.type->get_type() != tl::NODE_TYPE_VAR_TYPE); + if (a.type->get_type() == tl::NODE_TYPE_VAR_TYPE) { + assert(parser_type == 1); + + const tl::tl_tree_var_type *t = static_cast(a.type); + assert(a.flags == tl::FLAG_EXCL); + + assert(a.var_num == -1); + assert(a.exist_var_num == -1); + + assert(t->var_num >= 0); + assert(vars[t->var_num].is_type); + assert(!vars[t->var_num].is_stored); + vars[t->var_num].is_stored = true; + + return ""; + } assert(!(a.flags & tl::FLAG_EXCL)); assert(!(a.flags & tl::FLAG_OPT_VAR)); + if (a.exist_var_num != -1) { + assert(0 <= a.exist_var_num && a.exist_var_num < static_cast(vars.size())); + } + if (flat) { // TODO // return gen_field_fetch(const tl::arg &a, std::vector &vars, int num, bool flat); } - assert(a.var_num == -1); assert(a.type->get_type() == tl::NODE_TYPE_TYPE); + if (a.var_num >= 0) { + assert(static_cast(a.type)->type->id == tl::ID_VAR_NUM); + assert(0 <= a.var_num && a.var_num < static_cast(vars.size())); + } + return ""; } diff --git a/tl/generate/tl_writer_jni_cpp.cpp b/tl/generate/tl_writer_jni_cpp.cpp index 3eacfe77..20afaa89 100644 --- a/tl/generate/tl_writer_jni_cpp.cpp +++ b/tl/generate/tl_writer_jni_cpp.cpp @@ -25,7 +25,7 @@ namespace td { bool TD_TL_writer_jni_cpp::is_built_in_simple_type(const std::string &name) const { assert(name != "function"); - return name == "Bool" || name == "Int32" || name == "Int53" || name == "Int64" || name == "Double" || + return name == "Bool" || name == "Int32" || name == "Int53" || name == "Int64" || name == "Int128" || name == "Int256" || name == "Double" || name == "String" || name == "Bytes" || name == "SecureString" || name == "SecureBytes" || name == "Function" || name == "Object"; } @@ -126,6 +126,8 @@ std::string TD_TL_writer_jni_cpp::gen_vector_fetch(std::string field_name, const } else if (vector_type == bytes_type) { std::fprintf(stderr, "Vector of Bytes is not supported\n"); assert(false); + } else if (vector_type == "td::Bits128" || vector_type == "td::Bits256") { + template_type = vector_type; } else { assert(vector_type.compare(0, 10, "object_ptr") == 0); template_type = gen_main_class_name(t->type); @@ -152,17 +154,11 @@ std::string TD_TL_writer_jni_cpp::gen_type_fetch(const std::string &field_name, assert(is_type_bare(t)); } - std::string res_begin; - if (!field_name.empty()) { - res_begin = field_name + " = "; - } - std::string res; - assert(name != "#"); if (field_name.empty()) { if (name == "Bool") { return "env->CallObjectMethod(p, td::jni::BooleanGetValueMethodID)"; - } else if (name == "Int32") { + } else if (name == "Int32" || name == "#") { return "env->CallObjectMethod(p, td::jni::IntegerGetValueMethodID)"; } else if (name == "Int53" || name == "Int64") { return "env->CallObjectMethod(p, td::jni::LongGetValueMethodID)"; @@ -176,12 +172,16 @@ std::string TD_TL_writer_jni_cpp::gen_type_fetch(const std::string &field_name, return "td::jni::from_jstring_secure(env, (jstring)p)"; } else if (name == "SecureBytes") { return "td::jni::from_bytes_secure(env, (jbyteArray)p)"; + } else if (name == "Int128") { + return "td::jni::from_bits<128>(env, (jbyteArray)p)"; + } else if (name == "Int256") { + return "td::jni::from_bits<256>(env, (jbyteArray)p)"; } } if (name == "Bool") { res = "(env->GetBooleanField(p, " + field_name + "fieldID) != 0)"; - } else if (name == "Int32") { + } else if (name == "Int32" || name == "#") { res = "env->GetIntField(p, " + field_name + "fieldID)"; } else if (name == "Int53" || name == "Int64") { res = "env->GetLongField(p, " + field_name + "fieldID)"; @@ -195,6 +195,10 @@ std::string TD_TL_writer_jni_cpp::gen_type_fetch(const std::string &field_name, res = "td::jni::fetch_string_secure(env, p, " + field_name + "fieldID)"; } else if (name == "SecureBytes") { res = "td::jni::from_bytes_secure(env, (jbyteArray)td::jni::fetch_object(env, p, " + field_name + "fieldID))"; + } else if (name == "Int128") { + res = "td::jni::from_bits<128>(env, (jbyteArray)td::jni::fetch_object(env, p, " + field_name + "fieldID))"; + } else if (name == "Int256") { + res = "td::jni::from_bits<256>(env, (jbyteArray)td::jni::fetch_object(env, p, " + field_name + "fieldID))"; } else if (name == "Vector") { const tl::tl_tree_type *child = static_cast(tree_type->children[0]); res = gen_vector_fetch(field_name, child, vars, parser_type); @@ -206,7 +210,7 @@ std::string TD_TL_writer_jni_cpp::gen_type_fetch(const std::string &field_name, res = "td::jni::fetch_tl_object<" + gen_main_class_name(tree_type->type) + ">(env, td::jni::fetch_object(env, p, " + field_name + "fieldID));"; } - return res_begin + res; + return res; } std::string TD_TL_writer_jni_cpp::gen_field_fetch(int field_num, const tl::arg &a, @@ -215,7 +219,6 @@ std::string TD_TL_writer_jni_cpp::gen_field_fetch(int field_num, const tl::arg & assert(parser_type >= 0); std::string field_name = (parser_type == 0 ? (field_num == 0 ? ": " : ", ") : "res->") + gen_field_name(a.name); - assert(a.exist_var_num == -1); if (a.type->get_type() == tl::NODE_TYPE_VAR_TYPE) { assert(parser_type == 1); @@ -223,6 +226,7 @@ std::string TD_TL_writer_jni_cpp::gen_field_fetch(int field_num, const tl::arg & assert(a.flags == tl::FLAG_EXCL); assert(a.var_num == -1); + assert(a.exist_var_num == -1); assert(t->var_num >= 0); assert(vars[t->var_num].is_type); @@ -236,18 +240,52 @@ std::string TD_TL_writer_jni_cpp::gen_field_fetch(int field_num, const tl::arg & assert(!(a.flags & tl::FLAG_EXCL)); assert(!(a.flags & tl::FLAG_OPT_VAR)); + std::string res = " "; + if (a.exist_var_num != -1) { + assert(0 <= a.exist_var_num && a.exist_var_num < static_cast(vars.size())); + assert(vars[a.exist_var_num].is_stored); + + res += "if (" + gen_var_name(vars[a.exist_var_num]) + " & " + int_to_string(1 << a.exist_var_bit) + ") { "; + } + if (flat) { // TODO // return gen_field_fetch(const tl::arg &a, std::vector &vars, int num, bool flat); } - assert(a.var_num == -1); + bool store_to_var_num = false; + if (a.var_num >= 0) { + assert(a.type->get_type() == tl::NODE_TYPE_TYPE); + assert(static_cast(a.type)->type->id == tl::ID_VAR_NUM); + assert(0 <= a.var_num && a.var_num < static_cast(vars.size())); + if (!vars[a.var_num].is_stored) { + res += "if ((" + gen_var_name(vars[a.var_num]) + " = "; + store_to_var_num = true; + } else { + assert(false); + } + vars[a.var_num].is_stored = true; + } + + res += field_name + (parser_type == 0 ? "(" : " = "); assert(a.type->get_type() == tl::NODE_TYPE_TYPE); const tl::tl_tree_type *tree_type = static_cast(a.type); + res += gen_type_fetch(field_name, tree_type, vars, parser_type); + if (store_to_var_num) { + res += ") < 0) { return nullptr; }"; + } else { + res += (parser_type == 0 ? ")" : ";"); + } - assert(parser_type != 0); - return " " + gen_type_fetch(field_name, tree_type, vars, parser_type) + ";\n"; + if (a.exist_var_num >= 0) { + res += " }"; + if (store_to_var_num) { + res += " else { " + gen_var_name(vars[a.var_num]) + " = 0; }"; + } + } + res += "\n"; + return res; } std::string TD_TL_writer_jni_cpp::get_pretty_field_name(std::string field_name) const { @@ -274,7 +312,7 @@ std::string TD_TL_writer_jni_cpp::gen_vector_store(const std::string &field_name assert(false); // TODO } if (vector_type == "std::int32_t" || vector_type == "std::int64_t" || vector_type == "double" || - vector_type == string_type || vector_type == secure_string_type || + vector_type == string_type || vector_type == secure_string_type || vector_type == "td::Bits128" || vector_type == "td::Bits256" || vector_type.compare(0, 11, "std::vector") == 0 || vector_type.compare(0, 10, "object_ptr") == 0) { return "{ " "auto arr_tmp_ = td::jni::store_vector(env, " + @@ -317,8 +355,8 @@ std::string TD_TL_writer_jni_cpp::gen_type_store(const std::string &field_name, } std::string res; - if (name == "Int32" || name == "Int53" || name == "Int64" || name == "Double" || name == "Bool" || name == "String" || - name == "SecureString") { + if (name == "Int32" || name == "Int53" || name == "Int64" || name == "Int128" || name == "Int256" || name == "Double" || name == "Bool" || name == "String" || + name == "SecureString" || name == "#") { if (storer_type == 1) { res = "s.store_field(\"" + get_pretty_field_name(field_name) + "\", " + field_name + ");"; } else if (name == "Bool") { @@ -337,6 +375,16 @@ std::string TD_TL_writer_jni_cpp::gen_type_store(const std::string &field_name, res = "{ jstring nextString = td::jni::to_jstring_secure(env, " + field_name + "); if (nextString) { env->SetObjectField(s, " + field_name + "fieldID, nextString); env->DeleteLocalRef(nextString); } }"; + } else if (name == "Int128") { + res = "{ jbyteArray nextBytes = td::jni::to_bits<128>(env, " + field_name + + "); if (nextBytes) { env->SetObjectField(s, " + field_name + + "fieldID, nextBytes); env->DeleteLocalRef(nextBytes); } }"; + } else if (name == "Int256") { + res = "{ jbyteArray nextBytes = td::jni::to_bits<256>(env, " + field_name + + "); if (nextBytes) { env->SetObjectField(s, " + field_name + + "fieldID, nextBytes); env->DeleteLocalRef(nextBytes); } }"; + } else if (name == "#") { + res = "env->SetIntField(s, " + TD_TL_writer_cpp::get_pretty_field_name(field_name) + "_fieldID, " + field_name + ");"; } else { assert(false); } @@ -378,12 +426,12 @@ std::string TD_TL_writer_jni_cpp::gen_field_store(const tl::arg &a, std::vector< std::string field_name = gen_field_name(a.name); std::string shift = storer_type == 1 ? " " : " "; - assert(a.exist_var_num == -1); if (a.type->get_type() == tl::NODE_TYPE_VAR_TYPE) { const tl::tl_tree_var_type *t = static_cast(a.type); assert(a.flags == tl::FLAG_EXCL); assert(a.var_num == -1); + assert(a.exist_var_num == -1); assert(t->var_num >= 0); assert(!vars[t->var_num].is_stored); @@ -397,15 +445,39 @@ std::string TD_TL_writer_jni_cpp::gen_field_store(const tl::arg &a, std::vector< assert(!(a.flags & tl::FLAG_EXCL)); assert(!(a.flags & tl::FLAG_OPT_VAR)); + if (a.exist_var_num >= 0) { + assert(a.exist_var_num < static_cast(vars.size())); + assert(vars[a.exist_var_num].is_stored); + + shift += "if (" + gen_var_name(vars[a.exist_var_num]) + " & " + int_to_string(1 << a.exist_var_bit) + ") { "; + } + if (flat) { // TODO // return gen_field_store(const tl::arg &a, std::vector &vars, bool flat, int storer_type); } - assert(a.var_num == -1); + if (a.var_num >= 0) { + assert(a.type->get_type() == tl::NODE_TYPE_TYPE); + assert(static_cast(a.type)->type->id == tl::ID_VAR_NUM); + assert(a.var_num < static_cast(vars.size())); + if (!vars[a.var_num].is_stored) { + field_name = "(" + gen_var_name(vars[a.var_num]) + " = " + field_name + ")"; + vars[a.var_num].is_stored = true; + } else { + assert(false); // need to check value of stored var + field_name = gen_var_name(vars[a.var_num]); + } + } + assert(a.type->get_type() == tl::NODE_TYPE_TYPE); const tl::tl_tree_type *tree_type = static_cast(a.type); - return shift + gen_type_store(field_name, tree_type, vars, storer_type) + "\n"; + shift += gen_type_store(field_name, tree_type, vars, storer_type); + if (a.exist_var_num >= 0) { + shift += " }"; + } + shift += "\n"; + return shift; } std::string TD_TL_writer_jni_cpp::gen_get_id(const std::string &class_name, std::int32_t id, bool is_proxy) const { @@ -568,11 +640,10 @@ std::string TD_TL_writer_jni_cpp::gen_type_signature(const tl::tl_tree_type *tre const tl::tl_type *t = tree_type->type; const std::string &name = t->name; - assert(name != "#"); assert(name != gen_base_tl_class_name()); if (name == "Bool") { return "Z"; - } else if (name == "Int32") { + } else if (name == "Int32" || name == "#") { return "I"; } else if (name == "Int53" || name == "Int64") { return "J"; @@ -580,7 +651,7 @@ std::string TD_TL_writer_jni_cpp::gen_type_signature(const tl::tl_tree_type *tre return "D"; } else if (name == "String" || name == "SecureString") { return "Ljava/lang/String;"; - } else if (name == "Bytes" || name == "SecureBytes") { + } else if (name == "Bytes" || name == "SecureBytes" || name == "Int128" || name == "Int256") { return "[B"; } else if (name == "Vector") { const tl::tl_tree_type *child = static_cast(tree_type->children[0]); diff --git a/tl/generate/tl_writer_jni_h.cpp b/tl/generate/tl_writer_jni_h.cpp index 5c9896bd..dc2551fd 100644 --- a/tl/generate/tl_writer_jni_h.cpp +++ b/tl/generate/tl_writer_jni_h.cpp @@ -23,7 +23,7 @@ namespace td { bool TD_TL_writer_jni_h::is_built_in_simple_type(const std::string &name) const { - return name == "Bool" || name == "Int32" || name == "Int53" || name == "Int64" || name == "Double" || + return name == "Bool" || name == "Int32" || name == "Int53" || name == "Int64" || name == "Int128" || name == "Int256" || name == "Double" || name == "String" || name == "Bytes" || name == "SecureString" || name == "SecureBytes" || name == "Function" || name == "Object"; } diff --git a/tl/tl/tl_jni_object.cpp b/tl/tl/tl_jni_object.cpp index 7f98ed40..e7e69789 100644 --- a/tl/tl/tl_jni_object.cpp +++ b/tl/tl/tl_jni_object.cpp @@ -30,12 +30,6 @@ namespace jni { thread_local bool parse_error; -static jclass BooleanClass; -static jclass IntegerClass; -static jclass LongClass; -static jclass DoubleClass; -static jclass StringClass; -static jclass ObjectClass; jmethodID GetConstructorID; jmethodID BooleanGetValueMethodID; jmethodID IntegerGetValueMethodID; diff --git a/tl/tl/tl_jni_object.h b/tl/tl/tl_jni_object.h index 4ab385f3..e39a063d 100644 --- a/tl/tl/tl_jni_object.h +++ b/tl/tl/tl_jni_object.h @@ -27,12 +27,19 @@ #include "td/utils/Slice.h" #include "td/utils/SharedSlice.h" +#include "common/bitstring.h" namespace td { namespace jni { extern thread_local bool parse_error; +static jclass BooleanClass; +static jclass IntegerClass; +static jclass LongClass; +static jclass DoubleClass; +static jclass StringClass; +static jclass ObjectClass; extern jmethodID GetConstructorID; extern jmethodID BooleanGetValueMethodID; extern jmethodID IntegerGetValueMethodID; @@ -106,6 +113,29 @@ SecureString from_bytes_secure(JNIEnv *env, jbyteArray arr); jbyteArray to_bytes(JNIEnv *env, Slice b); jbyteArray to_bytes_secure(JNIEnv *env, Slice b); +template +td::BitArray from_bits(JNIEnv *env, jbyteArray arr) { + td::BitArray b; + if (arr != nullptr) { + jsize length = env->GetArrayLength(arr); + assert(length * 8 == n); + env->GetByteArrayRegion(arr, 0, length, reinterpret_cast(b.as_slice().begin())); + env->DeleteLocalRef(arr); + } + return b; +} + +template +jbyteArray to_bits(JNIEnv *env, td::BitArray b) { + assert(n % 8 == 0); + jsize length = n / 8; + jbyteArray arr = env->NewByteArray(length); + if (arr != nullptr) { + env->SetByteArrayRegion(arr, 0, length, reinterpret_cast(b.data())); + } + return arr; +} + void init_vars(JNIEnv *env, const char *td_api_java_package); jintArray store_vector(JNIEnv *env, const std::vector &v); @@ -118,6 +148,22 @@ jobjectArray store_vector(JNIEnv *env, const std::vector &v); jobjectArray store_vector(JNIEnv *env, const std::vector &v); +template +jobjectArray store_vector(JNIEnv *env, const std::vector> &v) { + jint length = static_cast(v.size()); + jobjectArray arr = env->NewObjectArray(length, ObjectClass, jobject()); + if (arr != nullptr) { + for (jsize i = 0; i < length; i++) { + jbyteArray bits = to_bits(env, v[i]); + if (bits) { + env->SetObjectArrayElement(arr, i, bits); + env->DeleteLocalRef(bits); + } + } + } + return arr; +} + template jobjectArray store_vector(JNIEnv *env, const std::vector &v) { jint length = static_cast(v.size()); @@ -230,6 +276,26 @@ struct FetchVector { } }; +template +struct FetchVector> { + static std::vector> fetch(JNIEnv *env, jobjectArray arr) { + std::vector> result; + if (arr != nullptr) { + jsize length = env->GetArrayLength(arr); + result.reserve(length); + for (jsize i = 0; i < length; i++) { + jbyteArray bits = (jbyteArray)env->GetObjectArrayElement(arr, i); + result.push_back(jni::from_bits(env, bits)); + if (bits) { + env->DeleteLocalRef(bits); + } + } + env->DeleteLocalRef(arr); + } + return result; + } +}; + template struct FetchVector> { static auto fetch(JNIEnv *env, jobjectArray arr) { diff --git a/tonlib/CMakeLists.txt b/tonlib/CMakeLists.txt index 061778af..c74b24db 100644 --- a/tonlib/CMakeLists.txt +++ b/tonlib/CMakeLists.txt @@ -67,6 +67,7 @@ if (TONLIB_ENABLE_JNI AND NOT ANDROID) # jni is available by default on Android endif() message(STATUS "Found JNI: ${JNI_INCLUDE_DIRS} ${JNI_LIBRARIES}") target_include_directories(tonlib PUBLIC ${JAVA_INCLUDE_PATH} ${JAVA_INCLUDE_PATH2}) + target_include_directories(tl_tonlib_api PUBLIC ${JAVA_INCLUDE_PATH} ${JAVA_INCLUDE_PATH2}) target_link_libraries(tonlib PUBLIC ${JAVA_JVM_LIBRARY}) endif()