diff --git a/bundle.json b/bundle.json index 2edbfd663a7d9e4d1faf6169501620f2868c0bd5..cecdb6eba6bf20a43ca1a85e68ae6658f4c5a4a1 100644 --- a/bundle.json +++ b/bundle.json @@ -51,6 +51,7 @@ "node", "openssl", "os_account", + "runtime_core", "rust_libc", "samgr" ], diff --git a/interfaces/kits/js/src/common/ani_helper/ani_helper.h b/interfaces/kits/js/src/common/ani_helper/ani_helper.h new file mode 100644 index 0000000000000000000000000000000000000000..c1781d8299b454a85dd16b196509b9d305493cd5 --- /dev/null +++ b/interfaces/kits/js/src/common/ani_helper/ani_helper.h @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FILEMANAGEMENT_ANI_ANI_HELPER_H +#define FILEMANAGEMENT_ANI_ANI_HELPER_H + +#include +#include +#include + +#include + +#include "ani_signature.h" +#include "event_handler.h" +#include "event_runner.h" +#include "file_utils.h" +#include "filemgmt_libhilog.h" +#include "type_converter.h" + +namespace OHOS::FileManagement::ModuleFileIO::ANI { +using namespace std; +using namespace OHOS::FileManagement::ModuleFileIO::ANI::AniSignature; + +static thread_local shared_ptr mainHandler; + +class AniHelper { +public: + template + static ani_status SetFieldValue( + ani_env *env, const ani_class &cls, ani_object &obj, const char *fieldName, const T &value) + { + ani_field field; + auto status = env->Class_FindField(cls, fieldName, &field); + if (status != ANI_OK) { + return status; + } + if constexpr (is_same_v || is_same_v || is_same_v) { + status = env->Object_SetField_Int(obj, field, value); + } else if constexpr (is_same_v || is_same_v) { + status = env->Object_SetField_Long(obj, field, value); + } else if constexpr (is_same_v || is_same_v) { + status = env->Object_SetField_Double(obj, field, value); + } else if constexpr (is_same_v || is_same_v) { + status = env->Object_SetField_Boolean(obj, field, value); + } else if constexpr (is_same_v || is_same_v) { + auto [succ, aniStr] = TypeConverter::ToAniString(env, value); + if (!succ) { + return ANI_ERROR; + } + status = env->Object_SetField_Ref(obj, field, move(aniStr)); + } else if constexpr (is_base_of_v) { + status = env->Object_SetField_Ref(obj, field, value); + } else { + return ANI_INVALID_TYPE; + } + return status; + } + + template + static ani_status SetPropertyValue( + ani_env *env, const ani_class &cls, ani_object &obj, const string &property, const T &value) + { + ani_method method; + string setter = "" + property; + auto status = env->Class_FindMethod(cls, setter.c_str(), nullptr, &method); + if (status != ANI_OK) { + return status; + } + + if constexpr (is_same_v || is_same_v) { + auto [succ, aniStr] = TypeConverter::ToAniString(env, value); + if (!succ) { + return ANI_ERROR; + } + status = env->Object_CallMethod_Void(obj, method, move(aniStr)); + } else if constexpr (is_base_of_v || is_same_v || is_same_v || + is_same_v || is_same_v || is_same_v || + is_same_v || is_same_v || is_same_v || + is_same_v) { + status = env->Object_CallMethod_Void(obj, method, value); + } else { + return ANI_INVALID_TYPE; + } + return status; + } + + static tuple> ParseInt64Option(ani_env *env, ani_object obj, const string &tag) + { + ani_boolean isUndefined = true; + ani_ref property; + ani_status status = ANI_ERROR; + status = env->Object_GetPropertyByName_Ref(obj, tag.c_str(), &property); + if (status != ANI_OK) { + return { false, nullopt }; + } + env->Reference_IsUndefined(property, &isUndefined); + if (isUndefined) { + return { true, nullopt }; + } + static const string longValueSig = Builder::BuildSignatureDescriptor({}, BasicTypes::longType); + ani_long value; + status = env->Object_CallMethodByName_Long( + static_cast(property), "toLong", longValueSig.c_str(), &value); + if (status != ANI_OK) { + return { false, nullopt }; + } + auto result = make_optional(static_cast(value)); + return { true, move(result) }; + } + + static tuple> ParseEncoding(ani_env *env, ani_object obj) + { + ani_boolean isUndefined; + ani_ref property; + if (ANI_OK != env->Object_GetPropertyByName_Ref(obj, "encoding", &property)) { + return { false, nullopt }; + } + env->Reference_IsUndefined(property, &isUndefined); + if (isUndefined) { + return { true, nullopt }; + } + auto [succ, encoding] = TypeConverter::ToUTF8String(env, (ani_string)property); + if (!succ) { + return { false, nullopt }; + } + return { true, make_optional(move(encoding)) }; + } + + static ani_env *&GetThreadEnvStorage() + { + static thread_local ani_env *env { nullptr }; + return env; + } + + static ani_env *GetThreadEnv(ani_vm *vm) + { + auto &env = GetThreadEnvStorage(); + if (env != nullptr) { + return env; + } + + ani_options aniArgs { 0, nullptr }; + auto status = vm->AttachCurrentThread(&aniArgs, ANI_VERSION_1, &env); + if (status != ANI_OK) { + status = vm->GetEnv(ANI_VERSION_1, &env); + if (status != ANI_OK) { + HILOGE("vm GetEnv, err: %{private}d", status); + return nullptr; + } + } + return env; + } + + static void DetachThreadEnv(ani_vm *vm) + { + if (vm && GetThreadEnvStorage()) { + auto status = vm->DetachCurrentThread(); + if (status != ANI_OK) { + HILOGE("Detach thread env from vm failed! status: %{private}d", status); + return; + } + GetThreadEnvStorage() = nullptr; + } + } + + static bool SendEventToMainThread(const function &func) + { + if (func == nullptr) { + HILOGE("func is nullptr!"); + return false; + } + + if (mainHandler == nullptr) { + shared_ptr runner = OHOS::AppExecFwk::EventRunner::GetMainEventRunner(); + if (!runner) { + HILOGE("get main event runner failed!"); + return false; + } + mainHandler = CreateSharedPtr(runner); + if (mainHandler == nullptr) { + HILOGE("Failed to request heap memory."); + return false; + } + } + bool succ = mainHandler->PostTask(func, "", 0, OHOS::AppExecFwk::EventQueue::Priority::HIGH, {}); + if (!succ) { + HILOGE("Failed to post task to main thread."); + return false; + } + return true; + } +}; + +} // namespace OHOS::FileManagement::ModuleFileIO::ANI + +#endif // FILEMANAGEMENT_ANI_ANI_HELPER_H \ No newline at end of file diff --git a/interfaces/kits/js/src/common/ani_helper/ani_signature.cpp b/interfaces/kits/js/src/common/ani_helper/ani_signature.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4a683a78389923e50500cae3dfe396b8b81857c8 --- /dev/null +++ b/interfaces/kits/js/src/common/ani_helper/ani_signature.cpp @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ani_signature.h" + +namespace OHOS::FileManagement::ModuleFileIO::ANI::AniSignature { +// BasicTypes +const Type BasicTypes::undefinedType = Builder::BuildUndefined(); +const Type BasicTypes::nullType = Builder::BuildNull(); +const Type BasicTypes::booleanType = Builder::BuildBoolean(); +const Type BasicTypes::byteType = Builder::BuildByte(); +const Type BasicTypes::charType = Builder::BuildChar(); +const Type BasicTypes::shortType = Builder::BuildShort(); +const Type BasicTypes::intType = Builder::BuildInt(); +const Type BasicTypes::longType = Builder::BuildLong(); +const Type BasicTypes::floatType = Builder::BuildFloat(); +const Type BasicTypes::doubleType = Builder::BuildDouble(); +// BoxedTypes::Boolean +const Type BoxedTypes::Boolean::classType = Builder::BuildClass("std.core.Boolean"); +const string BoxedTypes::Boolean::classDesc = BoxedTypes::Double::classType.Descriptor(); +const string BoxedTypes::Boolean::unboxedDesc = "unboxed"; +const string BoxedTypes::Boolean::unboxedSig = Builder::BuildSignatureDescriptor({}, BasicTypes::booleanType); +// BoxedTypes::Int +const Type BoxedTypes::Int::classType = Builder::BuildClass("std.core.Int"); +const string BoxedTypes::Int::classDesc = BoxedTypes::Int::classType.Descriptor(); +// BoxedTypes::Double +const Type BoxedTypes::Double::classType = Builder::BuildClass("std.core.Double"); +const string BoxedTypes::Double::classDesc = BoxedTypes::Double::classType.Descriptor(); +// BaseType +const string BaseType::ctorDesc = Builder::BuildConstructorName(); +const string BaseType::ctorSig0 = Builder::BuildSignatureDescriptor({}); +// BuiltInTypes::Object +const Type BuiltInTypes::Object::classType = Builder::BuildClass("std.core.Object"); +const string BuiltInTypes::Object::classDesc = BuiltInTypes::Object::classType.Descriptor(); +// BuiltInTypes::String +const Type BuiltInTypes::String::classType = Builder::BuildClass("std.core.String"); +const string BuiltInTypes::String::classDesc = BuiltInTypes::String::classType.Descriptor(); +// BuiltInTypes::Array +const Type BuiltInTypes::Array::classType = Builder::BuildClass("escompat.Array"); +const string BuiltInTypes::Array::classDesc = BuiltInTypes::Array::classType.Descriptor(); +const string BuiltInTypes::Array::ctorSig = Builder::BuildSignatureDescriptor({ BasicTypes::intType }); +const string BuiltInTypes::Array::getterDesc = "$_get"; +const string BuiltInTypes::Array::setterDesc = "$_set"; +const string BuiltInTypes::Array::objectGetterSig = + Builder::BuildSignatureDescriptor({ BasicTypes::intType }, BuiltInTypes::objectType); +const string BuiltInTypes::Array::objectSetterSig = + Builder::BuildSignatureDescriptor({ BasicTypes::intType, BuiltInTypes::objectType }); +// BuiltInTypes::ArrayBuffer +const Type BuiltInTypes::ArrayBuffer::classType = Builder::BuildClass("escompat.ArrayBuffer"); +const string BuiltInTypes::ArrayBuffer::classDesc = BuiltInTypes::ArrayBuffer::classType.Descriptor(); +// BuiltInTypes::BigInt +const Type BuiltInTypes::BigInt::classType = Builder::BuildClass("escompat.BigInt"); +const string BuiltInTypes::BigInt::classDesc = BuiltInTypes::BigInt::classType.Descriptor(); +const string BuiltInTypes::BigInt::ctorSig = Builder::BuildSignatureDescriptor({ BasicTypes::doubleType }); +// BuiltInTypes::BusinessError +const Type BuiltInTypes::BusinessError::classType = Builder::BuildClass("@ohos.base.BusinessError"); +const string BuiltInTypes::BusinessError::classDesc = BuiltInTypes::BusinessError::classType.Descriptor(); +// FS::ConflictFilesInner +const Type FS::ConflictFilesInner::classType = Builder::BuildClass("@ohos.file.fs.ConflictFilesInner"); +const string FS::ConflictFilesInner::classDesc = FS::ConflictFilesInner::classType.Descriptor(); +const string FS::ConflictFilesInner::ctorSig = + Builder::BuildSignatureDescriptor({ BuiltInTypes::stringType, BuiltInTypes::stringType }); +// FS::FileInner +const Type FS::FileInner::classType = Builder::BuildClass("@ohos.file.fs.fileIo.FileInner"); +const string FS::FileInner::classDesc = FS::FileInner::classType.Descriptor(); +const string FS::FileInner::ctorSig = Builder::BuildSignatureDescriptor({ BasicTypes::longType }); +// FS::ProgressInner +const Type FS::ProgressInner::classType = Builder::BuildClass("@ohos.file.fs.fileIo.ProgressInner"); +const string FS::ProgressInner::classDesc = FS::ProgressInner::classType.Descriptor(); +const string FS::ProgressInner::ctorSig = + Builder::BuildSignatureDescriptor({ BasicTypes::doubleType, BasicTypes::doubleType }); +// FS::RandomAccessFileInner +const Type FS::RandomAccessFileInner::classType = Builder::BuildClass("@ohos.file.fs.fileIo.RandomAccessFileInner"); +const string FS::RandomAccessFileInner::classDesc = FS::RandomAccessFileInner::classType.Descriptor(); +const string FS::RandomAccessFileInner::ctorSig = Builder::BuildSignatureDescriptor({ BasicTypes::longType }); +// FS::ReaderIteratorInner +const Type FS::ReaderIteratorInner::classType = Builder::BuildClass("@ohos.file.fs.fileIo.ReaderIteratorInner"); +const string FS::ReaderIteratorInner::classDesc = FS::ReaderIteratorInner::classType.Descriptor(); +const string FS::ReaderIteratorInner::ctorSig = Builder::BuildSignatureDescriptor({ BasicTypes::longType }); +// FS::ReaderIteratorResultInner +const Type FS::ReaderIteratorResultInner::classType = + Builder::BuildClass("@ohos.file.fs.fileIo.ReaderIteratorResultInner"); +const string FS::ReaderIteratorResultInner::classDesc = FS::ReaderIteratorResultInner::classType.Descriptor(); +const string FS::ReaderIteratorResultInner::ctorSig = Builder::BuildSignatureDescriptor({ BasicTypes::longType }); +// FS::StatInner +const Type FS::StatInner::classType = Builder::BuildClass("@ohos.file.fs.fileIo.StatInner"); +const string FS::StatInner::classDesc = FS::StatInner::classType.Descriptor(); +const string FS::StatInner::ctorSig = Builder::BuildSignatureDescriptor({ BasicTypes::longType }); +// FS::StreamInner +const Type FS::StreamInner::classType = Builder::BuildClass("@ohos.file.fs.fileIo.StreamInner"); +const string FS::StreamInner::classDesc = FS::StreamInner::classType.Descriptor(); +const string FS::StreamInner::ctorSig = Builder::BuildSignatureDescriptor({ BasicTypes::longType }); +// FS::TaskSignal +const Type FS::TaskSignal::classType = Builder::BuildClass("@ohos.file.fs.fileIo.TaskSignal"); +const string FS::TaskSignal::classDesc = FS::TaskSignal::classType.Descriptor(); +const string FS::TaskSignal::ctorSig = Builder::BuildSignatureDescriptor({ BasicTypes::longType }); +// FS::WatcherInner +const Type FS::WatcherInner::classType = Builder::BuildClass("@ohos.file.fs.fileIo.WatcherInner"); +const string FS::WatcherInner::classDesc = FS::WatcherInner::classType.Descriptor(); +const string FS::WatcherInner::ctorSig = Builder::BuildSignatureDescriptor({ BasicTypes::longType }); +// FS::WatchEventInner +const Type FS::WatchEventInner::classType = Builder::BuildClass("@ohos.file.fs.WatchEventInner"); +const string FS::WatchEventInner::classDesc = FS::WatchEventInner::classType.Descriptor(); +const string FS::WatchEventInner::ctorSig = + Builder::BuildSignatureDescriptor({ BuiltInTypes::stringType, BasicTypes::doubleType, BasicTypes::doubleType }); +// FS::LocationType +const Type FS::LocationType::classType = Builder::BuildClass("@ohos.file.fs.fileIo.LocationType"); +const string FS::LocationType::classDesc = FS::LocationType::classType.Descriptor(); +// Impl::EnvironmentImpl +const Type Impl::EnvironmentImpl::classType = Builder::BuildClass("@ohos.file.environment.EnvironmentImpl"); +const string Impl::EnvironmentImpl::classDesc = Impl::EnvironmentImpl::classType.Descriptor(); +// Impl::FileIoImpl +const Type Impl::FileIoImpl::classType = Builder::BuildClass("@ohos.file.fs.FileIoImpl"); +const string Impl::FileIoImpl::classDesc = Impl::FileIoImpl::classType.Descriptor(); +// Impl::HashImpl +const Type Impl::HashImpl::classType = Builder::BuildClass("@ohos.file.hash.HashImpl"); +const string Impl::HashImpl::classDesc = Impl::HashImpl::classType.Descriptor(); +// Impl::SecurityLabelImpl +const Type Impl::SecurityLabelImpl::classType = Builder::BuildClass("@ohos.file.securityLabel.SecurityLabelImpl"); +const string Impl::SecurityLabelImpl::classDesc = Impl::SecurityLabelImpl::classType.Descriptor(); +// Impl::StatvfsImpl +const Type Impl::StatvfsImpl::classType = Builder::BuildClass("@ohos.file.statvfs.StatvfsImpl"); +const string Impl::StatvfsImpl::classDesc = Impl::StatvfsImpl::classType.Descriptor(); + +} // namespace OHOS::FileManagement::ModuleFileIO::ANI::AniSignature \ No newline at end of file diff --git a/interfaces/kits/js/src/common/ani_helper/ani_signature.h b/interfaces/kits/js/src/common/ani_helper/ani_signature.h new file mode 100644 index 0000000000000000000000000000000000000000..8b7e4328169b56ae56340086e9ef251da41e2c4c --- /dev/null +++ b/interfaces/kits/js/src/common/ani_helper/ani_signature.h @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef INTERFACES_KITS_JS_SRC_COMMON_ANI_HELPER_ANI_SIGNATURE_H +#define INTERFACES_KITS_JS_SRC_COMMON_ANI_HELPER_ANI_SIGNATURE_H + +#pragma once + +#include +#include + +namespace OHOS::FileManagement::ModuleFileIO::ANI::AniSignature { +using namespace std; +using namespace arkts::ani_signature; + +struct BasicTypes { + static const Type undefinedType; + static const Type nullType; + static const Type booleanType; + static const Type byteType; + static const Type charType; + static const Type shortType; + static const Type intType; + static const Type longType; + static const Type floatType; + static const Type doubleType; +}; + +struct BaseType { + static const string ctorDesc; + static const string ctorSig0; +}; + +namespace BoxedTypes { + +struct Boolean : public BaseType { + static const Type classType; + static const string classDesc; + static const string unboxedDesc; + static const string unboxedSig; +}; + +struct Int : public BaseType { + static const Type classType; + static const string classDesc; +}; + +struct Double : public BaseType { + static const Type classType; + static const string classDesc; +}; + +} // namespace BoxedTypes + +namespace BuiltInTypes { + +struct Object : public BaseType { + static const Type classType; + static const string classDesc; +}; + +inline const Type &objectType = BuiltInTypes::Object::classType; + +struct String : public BaseType { + static const Type classType; + static const string classDesc; +}; + +inline const Type &stringType = BuiltInTypes::String::classType; + +struct Array : public BaseType { + static const Type classType; + static const string classDesc; + static const string ctorSig; + static const string getterDesc; + static const string setterDesc; + static const string objectGetterSig; + static const string objectSetterSig; +}; + +struct ArrayBuffer : public BaseType { + static const Type classType; + static const string classDesc; +}; + +struct BigInt : public BaseType { + static const Type classType; + static const string classDesc; + static const string ctorSig; +}; + +struct BusinessError : public BaseType { + static const Type classType; + static const string classDesc; +}; + +}; // namespace BuiltInTypes + +namespace FS { + +struct ConflictFilesInner : public BaseType { + static const Type classType; + static const string classDesc; + static const string ctorSig; +}; + +struct FileInner : public BaseType { + static const Type classType; + static const string classDesc; + static const string ctorSig; +}; + +struct ProgressInner : public BaseType { + static const Type classType; + static const string classDesc; + static const string ctorSig; +}; + +struct RandomAccessFileInner : public BaseType { + static const Type classType; + static const string classDesc; + static const string ctorSig; +}; + +struct ReaderIteratorInner : public BaseType { + static const Type classType; + static const string classDesc; + static const string ctorSig; +}; + +struct ReaderIteratorResultInner : public BaseType { + static const Type classType; + static const string classDesc; + static const string ctorSig; +}; + +struct StatInner : public BaseType { + static const Type classType; + static const string classDesc; + static const string ctorSig; +}; + +struct StreamInner : public BaseType { + static const Type classType; + static const string classDesc; + static const string ctorSig; +}; + +struct TaskSignal : public BaseType { + static const Type classType; + static const string classDesc; + static const string ctorSig; +}; + +struct WatcherInner : public BaseType { + static const Type classType; + static const string classDesc; + static const string ctorSig; +}; + +struct WatchEventInner : public BaseType { + static const Type classType; + static const string classDesc; + static const string ctorSig; +}; + +struct LocationType : public BaseType { + static const Type classType; + static const string classDesc; +}; + +} // namespace FS + +namespace Impl { + +struct EnvironmentImpl : public BaseType { + static const Type classType; + static const string classDesc; +}; + +struct FileIoImpl : public BaseType { + static const Type classType; + static const string classDesc; +}; + +struct HashImpl : public BaseType { + static const Type classType; + static const string classDesc; +}; + +struct SecurityLabelImpl : public BaseType { + static const Type classType; + static const string classDesc; +}; + +struct StatvfsImpl : public BaseType { + static const Type classType; + static const string classDesc; +}; + +} // namespace Impl + +} // namespace OHOS::FileManagement::ModuleFileIO::ANI::AniSignature + +#endif // INTERFACES_KITS_JS_SRC_COMMON_ANI_HELPER_ANI_SIGNATURE_H \ No newline at end of file diff --git a/interfaces/kits/js/src/common/ani_helper/bind_function.h b/interfaces/kits/js/src/common/ani_helper/bind_function.h new file mode 100644 index 0000000000000000000000000000000000000000..3c951b25125364260b1879851df4f1b832e9b233 --- /dev/null +++ b/interfaces/kits/js/src/common/ani_helper/bind_function.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FILEMANAGEMENT_ANI_BIND_FUNCTION_H +#define FILEMANAGEMENT_ANI_BIND_FUNCTION_H + +#include +#include +#include "filemgmt_libhilog.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +template +ANI_EXPORT ani_status BindClass(ani_env *env, const char *className, const std::array &methods) +{ + if (env == nullptr) { + HILOGE("Invalid parameter env"); + return ANI_INVALID_ARGS; + } + + if (className == nullptr) { + HILOGE("Invalid parameter className"); + return ANI_INVALID_ARGS; + } + + ani_class cls; + if (ANI_OK != env->FindClass(className, &cls)) { + HILOGE("Cannot find class '%{private}s'", className); + return ANI_NOT_FOUND; + } + + if (ANI_OK != env->Class_BindNativeMethods(cls, methods.data(), methods.size())) { + HILOGE("Cannot bind native methods to '%{private}s'", className); + return ANI_ERROR; + }; + return ANI_OK; +} + +template +ANI_EXPORT ani_status BindNamespace( + ani_env *env, const char *namespaceStr, const std::array &methods) +{ + if (env == nullptr) { + HILOGE("Invalid parameter env"); + return ANI_INVALID_ARGS; + } + + if (namespaceStr == nullptr) { + HILOGE("Invalid parameter namespaceStr"); + return ANI_INVALID_ARGS; + } + + ani_namespace ns; + if (ANI_OK != env->FindNamespace(namespaceStr, &ns)) { + HILOGE("Cannot find namespace '%{private}s'", namespaceStr); + return ANI_NOT_FOUND; + } + + if (ANI_OK != env->Namespace_BindNativeFunctions(ns, methods.data(), methods.size())) { + HILOGE("Cannot bind native methods to '%{private}s'", namespaceStr); + return ANI_ERROR; + }; + return ANI_OK; +} + +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS + +#endif // FILEMANAGEMENT_ANI_BIND_FUNCTION_H \ No newline at end of file diff --git a/interfaces/kits/js/src/common/ani_helper/error_handler.cpp b/interfaces/kits/js/src/common/ani_helper/error_handler.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c56a4dc0d26aaacdb2c42811d411d47d4341421d --- /dev/null +++ b/interfaces/kits/js/src/common/ani_helper/error_handler.cpp @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "error_handler.h" + +namespace OHOS::FileManagement::ModuleFileIO::ANI { + +ani_status ErrorHandler::Throw( + ani_env *env, int32_t code, const std::string &errMsg, const std::optional &errData) +{ + auto classDesc = BuiltInTypes::BusinessError::classDesc.c_str(); + return Throw(env, classDesc, code, errMsg, errData); +} + +} // namespace OHOS::FileManagement::ModuleFileIO::ANI \ No newline at end of file diff --git a/interfaces/kits/js/src/common/ani_helper/error_handler.h b/interfaces/kits/js/src/common/ani_helper/error_handler.h new file mode 100644 index 0000000000000000000000000000000000000000..2138f075dbe1e380b84568929445c692e9b99298 --- /dev/null +++ b/interfaces/kits/js/src/common/ani_helper/error_handler.h @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FILEMANAGEMENT_ANI_ERROR_HANDLER_H +#define FILEMANAGEMENT_ANI_ERROR_HANDLER_H + +#include +#include +#include +#include "ani_helper.h" +#include "ani_signature.h" +#include "filemgmt_libhilog.h" +#include "fs_error.h" +#include "type_converter.h" + +namespace OHOS::FileManagement::ModuleFileIO::ANI { +using namespace OHOS::FileManagement::ModuleFileIO::ANI::AniSignature; + +class ErrorHandler { +public: + static ani_status Throw( + ani_env *env, int32_t code, const std::string &errMsg, const std::optional &errData = std::nullopt); + + static ani_status Throw(ani_env *env, int32_t code, const std::optional &errData = std::nullopt) + { + if (env == nullptr) { + HILOGE("Invalid parameter env"); + return ANI_INVALID_ARGS; + } + FsError err(code); + return Throw(env, std::move(err), errData); + } + + static ani_status Throw(ani_env *env, const FsError &err, const std::optional &errData = std::nullopt) + { + if (env == nullptr) { + HILOGE("Invalid parameter env"); + return ANI_INVALID_ARGS; + } + auto code = err.GetErrNo(); + const auto &errMsg = err.GetErrMsg(); + return Throw(env, code, errMsg, errData); + } + +private: + static ani_status Throw(ani_env *env, const char *className, int32_t code, const std::string &errMsg, + const std::optional &errData = std::nullopt) + { + if (env == nullptr) { + HILOGE("Invalid parameter env"); + return ANI_INVALID_ARGS; + } + + if (className == nullptr) { + HILOGE("Invalid parameter className"); + return ANI_INVALID_ARGS; + } + + auto [status, err] = CreateErrorObj(env, className, code, errMsg, errData); + + if (status != ANI_OK) { + HILOGE("Create error object failed!"); + return status; + } + + status = env->ThrowError(err); + if (status != ANI_OK) { + HILOGE("Throw ani error object failed!"); + return status; + } + return ANI_OK; + } + + static std::tuple CreateErrorObj(ani_env *env, const char *className, int32_t code, + const std::string &errMsg, const std::optional &errData = std::nullopt) + { + ani_class cls; + if (ANI_OK != env->FindClass(className, &cls)) { + HILOGE("Cannot find class '%{private}s'", className); + return { ANI_NOT_FOUND, nullptr }; + } + + auto ctorDesc = BaseType::ctorDesc.c_str(); + auto ctorSig = BaseType::ctorSig0.c_str(); + ani_method ctor; + if (ANI_OK != env->Class_FindMethod(cls, ctorDesc, ctorSig, &ctor)) { + HILOGE("Cannot find constructor for class '%{private}s'", className); + return { ANI_NOT_FOUND, nullptr }; + } + + ani_object obj; + if (ANI_OK != env->Object_New(cls, ctor, &obj)) { + HILOGE("Cannot create ani error object"); + return { ANI_ERROR, nullptr }; + } + + auto [succ, message] = TypeConverter::ToAniString(env, errMsg); + if (!succ) { + HILOGE("Convert errMsg to ani string failed"); + return { ANI_ERROR, nullptr }; + } + + ani_status status = ANI_ERROR; + + status = env->Object_SetPropertyByName_Ref(obj, "message", message); + if (status != ANI_OK) { + HILOGE("Set property 'message' value failed"); + return { status, nullptr }; + } + + status = env->Object_SetPropertyByName_Double(obj, "code", static_cast(code)); + if (status != ANI_OK) { + HILOGE("Set property 'code' value failed"); + return { status, nullptr }; + } + + if (errData.has_value()) { + status = env->Object_SetPropertyByName_Ref(obj, "data", errData.value()); + if (status != ANI_OK) { + HILOGE("Set property 'data' value failed"); + return { status, nullptr }; + } + } + + ani_error err = static_cast(obj); + return { ANI_OK, std::move(err) }; + } +}; + +} // namespace OHOS::FileManagement::ModuleFileIO::ANI + +#endif // FILEMANAGEMENT_ANI_ERROR_HANDLER_H \ No newline at end of file diff --git a/interfaces/kits/js/src/common/ani_helper/type_converter.cpp b/interfaces/kits/js/src/common/ani_helper/type_converter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..564d7bc56e1baf1dd65cdcaa42f1521936887de3 --- /dev/null +++ b/interfaces/kits/js/src/common/ani_helper/type_converter.cpp @@ -0,0 +1,297 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "type_converter.h" + +#include +#include +#include + +#include "ani_signature.h" +#include "file_utils.h" +#include "filemgmt_libhilog.h" +#include "securec.h" + +namespace OHOS::FileManagement::ModuleFileIO::ANI { +using namespace OHOS::FileManagement::ModuleFileIO::ANI::AniSignature; + +std::tuple TypeConverter::ToUTF8String(ani_env *env, const ani_string &path) +{ + if (env == nullptr) { + return { false, EMPTY_STRING }; + } + ani_size sz {}; + std::string result; + auto status = env->String_GetUTF8Size(path, &sz); + if (status != ANI_OK) { + return { false, EMPTY_STRING }; + } + result.resize(sz + 1); + status = env->String_GetUTF8SubString(path, 0, sz, result.data(), result.size(), &sz); + if (status != ANI_OK) { + return { false, EMPTY_STRING }; + } + result.resize(sz); + return { true, std::move(result) }; +} + +std::tuple> TypeConverter::ToOptionalInt32(ani_env *env, const ani_object &value) +{ + if (env == nullptr) { + return { false, {} }; + } + ani_boolean isUndefined; + env->Reference_IsUndefined(value, &isUndefined); + if (isUndefined) { + return { true, std::nullopt }; + } + + ani_int intValue; + if (ANI_OK == env->Object_CallMethodByName_Int(value, "toInt", nullptr, &intValue)) { + return { true, std::make_optional(intValue) }; + } + + return { false, {} }; +} + +std::tuple> TypeConverter::ToOptionalInt64(ani_env *env, const ani_object &value) +{ + if (env == nullptr) { + return { false, {} }; + } + + ani_boolean isUndefined; + env->Reference_IsUndefined(value, &isUndefined); + if (isUndefined) { + return { true, std::nullopt }; + } + + ani_long longValue; + if (ANI_OK == env->Object_CallMethodByName_Long(value, "toLong", nullptr, &longValue)) { + return { true, std::make_optional(longValue) }; + } + + return { false, {} }; +} + +std::tuple TypeConverter::ToAniString(ani_env *env, std::string str) +{ + if (env == nullptr) { + return { false, {} }; + } + + ani_string result; + if (ANI_OK != env->String_NewUTF8(str.c_str(), str.size(), &result)) { + return { false, {} }; + } + return { true, std::move(result) }; +} + +std::tuple TypeConverter::ToAniString(ani_env *env, std::string str, size_t size) +{ + if (env == nullptr) { + return { false, {} }; + } + + ani_string result; + if (ANI_OK != env->String_NewUTF8(str.c_str(), size, &result)) { + return { false, {} }; + } + return { true, std::move(result) }; +} + +std::tuple TypeConverter::ToAniString(ani_env *env, const char *str) +{ + if (env == nullptr) { + return { false, {} }; + } + + size_t length = std::strlen(str); + ani_string result; + if (ANI_OK != env->String_NewUTF8(str, length, &result)) { + return { false, {} }; + } + return { true, std::move(result) }; +} + +std::tuple> TypeConverter::EnumToInt32(ani_env *env, const ani_enum_item &enumOp) +{ + ani_boolean isUndefined; + env->Reference_IsUndefined(enumOp, &isUndefined); + if (isUndefined) { + return { true, std::nullopt }; + } + + ani_int result; + if (ANI_OK != env->EnumItem_GetValue_Int(enumOp, &result)) { + return { false, {} }; + } + + return { true, std::make_optional(result) }; +} + +static std::tuple ParseFd(ani_env *env, const ani_object &pathOrFd) +{ + ani_boolean isFd = false; + + auto intClassDesc = BoxedTypes::Int::classDesc.c_str(); + ani_class intClass; + env->FindClass(intClassDesc, &intClass); + env->Object_InstanceOf(pathOrFd, intClass, &isFd); + if (isFd) { + ani_int fd; + if (ANI_OK != env->Object_CallMethodByName_Int(pathOrFd, "toInt", nullptr, &fd)) { + HILOGE("Parse file path failed"); + return { false, 0 }; + } + return { true, fd }; + } + + return { false, 0 }; +} + +std::tuple TypeConverter::ToFileInfo(ani_env *env, const ani_object &pathOrFd) +{ + if (env == nullptr) { + HILOGE("Invalid parameter env"); + return { false, FileInfo { false, {}, {} } }; + } + + auto stringClassDesc = BuiltInTypes::String::classDesc.c_str(); + ani_class stringClass; + env->FindClass(stringClassDesc, &stringClass); + + ani_boolean isPath = false; + env->Object_InstanceOf(pathOrFd, stringClass, &isPath); + if (isPath) { + auto [succ, path] = TypeConverter::ToUTF8String(env, static_cast(pathOrFd)); + if (!succ) { + HILOGE("Parse file path failed"); + return { false, FileInfo { false, {}, {} } }; + } + size_t length = path.length() + 1; + auto chars = std::make_unique(length); + auto ret = strncpy_s(chars.get(), length, path.c_str(), length - 1); + if (ret != EOK) { + HILOGE("Copy file path failed!"); + return { false, FileInfo { false, {}, {} } }; + } + return { true, FileInfo { true, move(chars), {} } }; + } + + auto [isFd, fd] = ParseFd(env, pathOrFd); + if (isFd) { + auto fdg = CreateUniquePtr(fd, false); + if (fdg == nullptr) { + HILOGE("Failed to request heap memory."); + return { false, FileInfo { false, {}, {} } }; + } + return { true, FileInfo { false, {}, move(fdg) } }; + } + + return { false, FileInfo { false, {}, {} } }; +} + +std::tuple TypeConverter::ToArrayBuffer(ani_env *env, ani_arraybuffer &buffer) +{ + if (env == nullptr) { + return { false, ArrayBuffer { nullptr, 0 } }; + } + + void *buf = nullptr; + ani_size length = 0; + + if (ANI_OK != env->ArrayBuffer_GetInfo(buffer, &buf, &length)) { + return { false, ArrayBuffer { nullptr, 0 } }; + } + return { true, ArrayBuffer { std::move(buf), length } }; +} + +std::tuple TypeConverter::ToAniArrayBuffer(ani_env *env, void *buffer, size_t length) +{ + if (env == nullptr) { + return { false, nullptr }; + } + + static const char *className = "Lescompat/ArrayBuffer;"; + ani_status ret; + ani_class cls; + if ((ret = env->FindClass(className, &cls)) != ANI_OK) { + HILOGE("Not found %{private}s, err: %{private}d", className, ret); + return { false, nullptr }; + } + + ani_method ctor; + if ((ret = env->Class_FindMethod(cls, "", "I:V", &ctor)) != ANI_OK) { + HILOGE("Not found ctor, err: %{private}d", ret); + return { false, nullptr }; + } + + ani_object obj; + if ((ret = env->Object_New(cls, ctor, &obj, length)) != ANI_OK) { + HILOGE("New Uint8Array err: %{private}d", ret); + return { false, nullptr }; + } + + if (!buffer || !length) { + return { true, static_cast(obj) }; + } + + void *buf = nullptr; + ani_size len = 0; + + if ((ANI_OK != env->ArrayBuffer_GetInfo(static_cast(obj), &buf, &len)) && (!buf)) { + return { false, nullptr }; + } + + int res = memcpy_s(buf, length, buffer, length); + if (res != 0) { + return { false, nullptr }; + } + len = length; + + return { true, static_cast(obj) }; +} + +std::tuple TypeConverter::ToAniStringList( + ani_env *env, const std::string strList[], const uint32_t length) +{ + if (env == nullptr) { + return { false, nullptr }; + } + + auto classDesc = BuiltInTypes::String::classDesc.c_str(); + ani_array_ref result = nullptr; + ani_class cls = nullptr; + if (env->FindClass(classDesc, &cls) != ANI_OK) { + return { false, result }; + } + if (env->Array_New_Ref(cls, length, nullptr, &result) != ANI_OK) { + return { false, result }; + } + for (uint32_t i = 0; i < length; i++) { + auto [ret, item] = TypeConverter::ToAniString(env, strList[i]); + if (!ret) { + return { false, nullptr }; + } + + if (env->Array_Set_Ref(result, i, item) != ANI_OK) { + return { false, nullptr }; + } + } + return { true, result }; +} + +} // namespace OHOS::FileManagement::ModuleFileIO::ANI \ No newline at end of file diff --git a/interfaces/kits/js/src/common/ani_helper/type_converter.h b/interfaces/kits/js/src/common/ani_helper/type_converter.h new file mode 100644 index 0000000000000000000000000000000000000000..bac25493fda5311c32340a5ce0371dd981a9af1d --- /dev/null +++ b/interfaces/kits/js/src/common/ani_helper/type_converter.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FILEMANAGEMENT_ANI_TYPE_CONVERTER_H +#define FILEMANAGEMENT_ANI_TYPE_CONVERTER_H + +#include +#include + +#include + +#include "fs_array_buffer.h" +#include "fs_utils.h" + +namespace OHOS::FileManagement::ModuleFileIO::ANI { +inline const std::string EMPTY_STRING = ""; + +class TypeConverter { +public: + static std::tuple ToUTF8String(ani_env *env, const ani_string &path); + static std::tuple> ToOptionalInt32(ani_env *env, const ani_object &value); + static std::tuple> ToOptionalInt64(ani_env *env, const ani_object &value); + static std::tuple ToAniArrayBuffer(ani_env *env, void *buffer, size_t length); + static std::tuple ToAniString(ani_env *env, std::string str); + static std::tuple ToAniString(ani_env *env, std::string str, size_t size); + static std::tuple ToAniString(ani_env *env, const char *str); + static std::tuple> EnumToInt32(ani_env *env, const ani_enum_item &enumOp); + static std::tuple ToFileInfo(ani_env *env, const ani_object &pathOrFd); + static std::tuple ToArrayBuffer(ani_env *env, ani_arraybuffer &buffer); + static std::tuple ToAniStringList( + ani_env *env, const std::string strList[], const uint32_t length); +}; + +} // namespace OHOS::FileManagement::ModuleFileIO::ANI + +#endif // FILEMANAGEMENT_ANI_TYPE_CONVERTER_H \ No newline at end of file