From 976c88b9aba9e0786f82d5d815d86cd998dba482 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E9=91=AB?= Date: Sat, 26 Jul 2025 14:10:17 +0800 Subject: [PATCH 1/2] stream MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 周鑫 Change-Id: I06aa41fa8488eb0ed835268104b18a0104fbd4c9 --- .../ani/randomaccessfile_ani.cpp | 488 ++++++++++++++++++ .../mod_fs/class_stream/ani/stream_ani.cpp | 290 +++++++++++ .../src/mod_fs/class_stream/ani/stream_ani.h | 40 ++ .../class_stream/ani/stream_wrapper.cpp | 78 +++ .../mod_fs/class_stream/ani/stream_wrapper.h | 37 ++ .../js/src/mod_fs/class_stream/fs_stream.cpp | 292 +++++++++++ .../js/src/mod_fs/class_stream/fs_stream.h | 74 +++ .../class_stream/stream_instantiator.cpp | 79 +++ .../mod_fs/class_stream/stream_instantiator.h | 35 ++ .../mod_fs/class_stream/stream_n_exporter.cpp | 1 + .../properties/ani/create_stream_ani.cpp | 71 +++ .../mod_fs/properties/ani/create_stream_ani.h | 34 ++ 12 files changed, 1519 insertions(+) create mode 100644 interfaces/kits/js/src/mod_fs/class_randomaccessfile/ani/randomaccessfile_ani.cpp create mode 100644 interfaces/kits/js/src/mod_fs/class_stream/ani/stream_ani.cpp create mode 100644 interfaces/kits/js/src/mod_fs/class_stream/ani/stream_ani.h create mode 100644 interfaces/kits/js/src/mod_fs/class_stream/ani/stream_wrapper.cpp create mode 100644 interfaces/kits/js/src/mod_fs/class_stream/ani/stream_wrapper.h create mode 100644 interfaces/kits/js/src/mod_fs/class_stream/fs_stream.cpp create mode 100644 interfaces/kits/js/src/mod_fs/class_stream/fs_stream.h create mode 100644 interfaces/kits/js/src/mod_fs/class_stream/stream_instantiator.cpp create mode 100644 interfaces/kits/js/src/mod_fs/class_stream/stream_instantiator.h create mode 100644 interfaces/kits/js/src/mod_fs/properties/ani/create_stream_ani.cpp create mode 100644 interfaces/kits/js/src/mod_fs/properties/ani/create_stream_ani.h diff --git a/interfaces/kits/js/src/mod_fs/class_randomaccessfile/ani/randomaccessfile_ani.cpp b/interfaces/kits/js/src/mod_fs/class_randomaccessfile/ani/randomaccessfile_ani.cpp new file mode 100644 index 000000000..604835791 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_randomaccessfile/ani/randomaccessfile_ani.cpp @@ -0,0 +1,488 @@ +/* + * 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 "randomaccessfile_ani.h" + +#include "ani_helper.h" +#include "ani_signature.h" +#include "error_handler.h" +#include "filemgmt_libhilog.h" +#include "fs_randomaccessfile.h" +#include "type_converter.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { +using namespace std; +using namespace OHOS::FileManagement::ModuleFileIO; +using namespace OHOS::FileManagement::ModuleFileIO::ANI::AniSignature; + +const int BUF_SIZE = 1024; +const string READ_STREAM_CLASS = "ReadStream"; +const string WRITE_STREAM_CLASS = "WriteStream"; + +static FsRandomAccessFile *Unwrap(ani_env *env, ani_object object) +{ + ani_long nativePtr; + auto ret = env->Object_GetFieldByName_Long(object, "nativePtr", &nativePtr); + if (ret != ANI_OK) { + HILOGE("Unwrap FsRandomAccessFile err: %{private}d", ret); + return nullptr; + } + uintptr_t ptrValue = static_cast(nativePtr); + FsRandomAccessFile *rafFile = reinterpret_cast(ptrValue); + return rafFile; +} + +static tuple> ToReadOptions(ani_env *env, ani_object obj) +{ + ReadOptions options; + ani_boolean isUndefined; + env->Reference_IsUndefined(obj, &isUndefined); + if (isUndefined) { + return { true, nullopt }; + } + + auto [succOffset, offset] = AniHelper::ParseInt64Option(env, obj, "offset"); + if (!succOffset) { + HILOGE("Illegal option.offset parameter"); + return { false, nullopt }; + } + options.offset = offset; + + auto [succLength, length] = AniHelper::ParseInt64Option(env, obj, "length"); + if (!succLength) { + HILOGE("Illegal option.length parameter"); + return { false, nullopt }; + } + options.length = length; + return { true, make_optional(move(options)) }; +} + +static tuple> ToWriteOptions(ani_env *env, ani_object obj) +{ + WriteOptions options; + ani_boolean isUndefined; + env->Reference_IsUndefined(obj, &isUndefined); + if (isUndefined) { + return { true, nullopt }; + } + + auto [succOffset, offset] = AniHelper::ParseInt64Option(env, obj, "offset"); + if (!succOffset) { + HILOGE("Illegal option.offset parameter"); + return { false, nullopt }; + } + options.offset = offset; + + auto [succLength, length] = AniHelper::ParseInt64Option(env, obj, "length"); + if (!succLength) { + HILOGE("Illegal option.length parameter"); + return { false, nullopt }; + } + options.length = length; + + auto [succEncoding, encoding] = AniHelper::ParseEncoding(env, obj); + if (!succEncoding) { + HILOGE("Illegal option.encoding parameter"); + return { false, nullopt }; + } + options.encoding = encoding; + return { true, make_optional(move(options)) }; +} + +static tuple ParseStringBuffer(ani_env *env, const ani_object &buf) +{ + ani_class cls; + auto classDesc = BuiltInTypes::String::classDesc.c_str(); + env->FindClass(classDesc, &cls); + + ani_boolean isString; + env->Object_InstanceOf(buf, cls, &isString); + if (!isString) { + return { false, {} }; + } + auto result = static_cast(buf); + return { true, move(result) }; +} + +static tuple ParseArrayBuffer(ani_env *env, const ani_object &buf) +{ + ani_class cls; + auto classDesc = BuiltInTypes::ArrayBuffer::classDesc.c_str(); + env->FindClass(classDesc, &cls); + + ani_boolean isArrayBuffer; + env->Object_InstanceOf(buf, cls, &isArrayBuffer); + if (!isArrayBuffer) { + return { false, {} }; + } + auto result = static_cast(buf); + return { true, move(result) }; +} + +void RandomAccessFileAni::SetFilePointer(ani_env *env, [[maybe_unused]] ani_object object, ani_double fp) +{ + auto rafFile = Unwrap(env, object); + if (rafFile == nullptr) { + HILOGE("Cannot unwrap rafFile!"); + ErrorHandler::Throw(env, UNKNOWN_ERR); + return; + } + auto ret = rafFile->SetFilePointerSync(static_cast(fp)); + if (!ret.IsSuccess()) { + HILOGE("SetFilePointerSync failed!"); + const auto &err = ret.GetError(); + ErrorHandler::Throw(env, err); + return; + } +} + +void RandomAccessFileAni::Close(ani_env *env, [[maybe_unused]] ani_object object) +{ + auto rafFile = Unwrap(env, object); + if (rafFile == nullptr) { + HILOGE("Cannot unwrap rafFile!"); + ErrorHandler::Throw(env, UNKNOWN_ERR); + return; + } + auto ret = rafFile->CloseSync(); + if (!ret.IsSuccess()) { + HILOGE("close rafFile failed!"); + const auto &err = ret.GetError(); + ErrorHandler::Throw(env, err); + return; + } +} + +ani_double RandomAccessFileAni::WriteSync( + ani_env *env, [[maybe_unused]] ani_object object, ani_object buf, ani_object options) +{ + auto rafFile = Unwrap(env, object); + if (rafFile == nullptr) { + HILOGE("Cannot unwrap rafFile!"); + ErrorHandler::Throw(env, UNKNOWN_ERR); + return -1; + } + + auto [succOp, op] = ToWriteOptions(env, options); + if (!succOp) { + HILOGE("Failed to resolve options!"); + ErrorHandler::Throw(env, EINVAL); + return -1; + } + + auto [isString, stringBuffer] = ParseStringBuffer(env, buf); + if (isString) { + auto [succBuf, buffer] = TypeConverter::ToUTF8String(env, stringBuffer); + if (!succBuf) { + HILOGE("Failed to resolve stringBuffer!"); + ErrorHandler::Throw(env, EINVAL); + return -1; + } + auto ret = rafFile->WriteSync(buffer, op); + if (!ret.IsSuccess()) { + HILOGE("write buffer failed!"); + ErrorHandler::Throw(env, ret.GetError()); + return -1; + } + return static_cast(ret.GetData().value()); + } + + auto [isArrayBuffer, arrayBuffer] = ParseArrayBuffer(env, buf); + if (isArrayBuffer) { + auto [succBuf, buffer] = TypeConverter::ToArrayBuffer(env, arrayBuffer); + if (!succBuf) { + HILOGE("Failed to resolve arrayBuffer!"); + ErrorHandler::Throw(env, EINVAL); + return -1; + } + auto ret = rafFile->WriteSync(buffer, op); + if (!ret.IsSuccess()) { + HILOGE("write buffer failed!"); + ErrorHandler::Throw(env, ret.GetError()); + return -1; + } + return static_cast(ret.GetData().value()); + } + HILOGE("Unsupported buffer type!"); + ErrorHandler::Throw(env, EINVAL); + return -1; +} + +ani_double RandomAccessFileAni::ReadSync( + ani_env *env, [[maybe_unused]] ani_object object, ani_arraybuffer buf, ani_object options) +{ + auto rafFile = Unwrap(env, object); + if (rafFile == nullptr) { + HILOGE("Cannot unwrap rafFile!"); + ErrorHandler::Throw(env, UNKNOWN_ERR); + return -1; + } + + auto [succBuf, arrayBuffer] = TypeConverter::ToArrayBuffer(env, buf); + if (!succBuf) { + HILOGE("Failed to resolve arrayBuffer!"); + ErrorHandler::Throw(env, EINVAL); + return -1; + } + + auto [succOp, op] = ToReadOptions(env, options); + if (!succOp) { + HILOGE("Failed to resolve options!"); + ErrorHandler::Throw(env, EINVAL); + return -1; + } + + auto ret = rafFile->ReadSync(arrayBuffer, op); + if (!ret.IsSuccess()) { + HILOGE("Read file content failed!"); + const auto &err = ret.GetError(); + ErrorHandler::Throw(env, err); + return -1; + } + return static_cast(ret.GetData().value()); +} + +static ani_string GetFilePath(ani_env *env, const int fd) +{ + auto dstFd = dup(fd); + if (dstFd < 0) { + HILOGE("Failed to get valid fd, fail reason: %{public}s, fd: %{public}d", strerror(errno), fd); + return nullptr; + } + + string path = "/proc/self/fd/" + to_string(dstFd); + auto buf = CreateUniquePtr(BUF_SIZE); + int readLinkRes = readlink(path.c_str(), buf.get(), BUF_SIZE); + if (readLinkRes < 0) { + close(dstFd); + return nullptr; + } + + close(dstFd); + auto [succ, filePath] = TypeConverter::ToAniString(env, string(buf.get())); + if (!succ) { + return nullptr; + } + return move(filePath); +} + +static ani_object CreateReadStreamOptions(ani_env *env, int64_t start, int64_t end) +{ + static const char *className = "L@ohos/file/fs/ReadStreamOptionsInner;"; + ani_class cls; + if (ANI_OK != env->FindClass(className, &cls)) { + HILOGE("Cannot find class %s", className); + return nullptr; + } + ani_method ctor; + if (ANI_OK != env->Class_FindMethod(cls, "", ":V", &ctor)) { + HILOGE("Cannot find constructor method for class %s", className); + return nullptr; + } + ani_object obj; + if (ANI_OK != env->Object_New(cls, ctor, &obj)) { + HILOGE("New %s obj Failed", className); + return nullptr; + } + + ani_field startField = nullptr; + ani_field endField = nullptr; + if (ANI_OK != env->Class_FindField(cls, "start", &startField)) { + HILOGE("Cannot find start in class %s", className); + return nullptr; + } + if (ANI_OK != env->Class_FindField(cls, "end", &endField)) { + HILOGE("Cannot find end in class %s", className); + return nullptr; + } + + if (start >= 0) { + env->Object_SetField_Int(obj, startField, start); + } + if (end >= 0) { + env->Object_SetField_Int(obj, endField, end); + } + if (obj == nullptr) { + HILOGE("CreateReadStreamOptions is nullptr"); + } + + return move(obj); +} + +static ani_object CreateWriteStreamOptions(ani_env *env, int64_t start, int flags) +{ + static const char *className = "L@ohos/file/fs/WriteStreamOptionsInner;"; + ani_class cls; + if (ANI_OK != env->FindClass(className, &cls)) { + HILOGE("Cannot find class %s", className); + return nullptr; + } + ani_method ctor; + if (ANI_OK != env->Class_FindMethod(cls, "", ":V", &ctor)) { + HILOGE("Cannot find constructor method for class %s", className); + return nullptr; + } + ani_object obj; + if (ANI_OK != env->Object_New(cls, ctor, &obj)) { + HILOGE("New %s obj Failed", className); + return nullptr; + } + + ani_field modeField = nullptr; + ani_field startField = nullptr; + if (ANI_OK != env->Class_FindField(cls, "mode", &modeField)) { + HILOGE("Cannot find mode in class %s", className); + return nullptr; + } + if (ANI_OK != env->Class_FindField(cls, "start", &startField)) { + HILOGE("Cannot find start in class %s", className); + return nullptr; + } + + env->Object_SetField_Int(obj, modeField, flags); + if (start >= 0) { + env->Object_SetField_Int(obj, startField, start); + } + + return move(obj); +} + +static ani_object CreateReadStream(ani_env *env, ani_string filePath, ani_object options) +{ + static const char *className = "L@ohos/file/fs/fileIo/ReadStream;"; + ani_class cls; + if (ANI_OK != env->FindClass(className, &cls)) { + HILOGE("Cannot find class %s", className); + return nullptr; + } + ani_method ctor; + if (ANI_OK != env->Class_FindMethod(cls, "", "Lstd/core/String;L@ohos/file/fs/ReadStreamOptions;:V", &ctor)) { + HILOGE("Cannot find constructor method for class %s", className); + return nullptr; + } + ani_object obj; + if (ANI_OK != env->Object_New(cls, ctor, &obj, filePath, options)) { + HILOGE("New %s obj Failed", className); + return nullptr; + } + + return move(obj); +} + +static ani_object CreateWriteStream(ani_env *env, ani_string filePath, ani_object options) +{ + static const char *className = "L@ohos/file/fs/fileIo/WriteStream;"; + ani_class cls; + if (ANI_OK != env->FindClass(className, &cls)) { + HILOGE("Cannot find class %s", className); + return nullptr; + } + ani_method ctor; + if (ANI_OK != + env->Class_FindMethod(cls, "", "Lstd/core/String;L@ohos/file/fs/WriteStreamOptions;:V", &ctor)) { + HILOGE("Cannot find constructor method for class %s", className); + return nullptr; + } + ani_object obj; + if (ANI_OK != env->Object_New(cls, ctor, &obj, filePath, options)) { + HILOGE("New %s obj Failed", className); + return nullptr; + } + + return move(obj); +} + +static ani_object CreateStream(ani_env *env, const string &streamName, RandomAccessFileEntity *rafEntity, int flags) +{ + ani_string filePath = GetFilePath(env, rafEntity->fd.get()->GetFD()); + if (!filePath) { + HILOGE("Get file path failed, errno=%{public}d", errno); + ErrorHandler::Throw(env, errno); + return nullptr; + } + + if (streamName == READ_STREAM_CLASS) { + ani_object obj = CreateReadStreamOptions(env, rafEntity->start, rafEntity->end); + return CreateReadStream(env, filePath, obj); + } + if (streamName == WRITE_STREAM_CLASS) { + ani_object obj = CreateWriteStreamOptions(env, rafEntity->start, flags); + return CreateWriteStream(env, filePath, obj); + } + + return nullptr; +} + +ani_object RandomAccessFileAni::GetReadStream(ani_env *env, [[maybe_unused]] ani_object object) +{ + auto rafFile = Unwrap(env, object); + if (rafFile == nullptr) { + HILOGE("Cannot unwrap rafFile!"); + ErrorHandler::Throw(env, UNKNOWN_ERR); + return nullptr; + } + + auto entity = rafFile->GetRAFEntity(); + if (!entity) { + HILOGE("Get RandomAccessFileEntity failed!"); + ErrorHandler::Throw(env, EIO); + return nullptr; + } + + int flags = fcntl(entity->fd.get()->GetFD(), F_GETFL); + unsigned int uflags = static_cast(flags); + if (((uflags & O_ACCMODE) != O_RDONLY) && ((uflags & O_ACCMODE) != O_RDWR)) { + HILOGE("Failed to check Permission"); + ErrorHandler::Throw(env, EACCES); + return nullptr; + } + + return CreateStream(env, READ_STREAM_CLASS, entity, flags); +} + +ani_object RandomAccessFileAni::GetWriteStream(ani_env *env, [[maybe_unused]] ani_object object) +{ + auto rafFile = Unwrap(env, object); + if (rafFile == nullptr) { + HILOGE("Cannot unwrap rafFile!"); + ErrorHandler::Throw(env, UNKNOWN_ERR); + return nullptr; + } + + auto entity = rafFile->GetRAFEntity(); + if (!entity) { + HILOGE("Get RandomAccessFileEntity failed!"); + ErrorHandler::Throw(env, EIO); + return nullptr; + } + + int flags = fcntl(entity->fd.get()->GetFD(), F_GETFL); + unsigned int uflags = static_cast(flags); + if (((uflags & O_ACCMODE) != O_WRONLY) && ((uflags & O_ACCMODE) != O_RDWR)) { + HILOGE("Failed to check Permission"); + ErrorHandler::Throw(env, EACCES); + return nullptr; + } + + return CreateStream(env, WRITE_STREAM_CLASS, entity, flags); +} + +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_stream/ani/stream_ani.cpp b/interfaces/kits/js/src/mod_fs/class_stream/ani/stream_ani.cpp new file mode 100644 index 000000000..a1d694187 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_stream/ani/stream_ani.cpp @@ -0,0 +1,290 @@ +/* + * 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 "stream_ani.h" + +#include +#include + +#include "ani_helper.h" +#include "ani_signature.h" +#include "error_handler.h" +#include "filemgmt_libhilog.h" +#include "fs_stream.h" +#include "fs_utils.h" +#include "type_converter.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { +using namespace std; +using namespace OHOS::FileManagement::ModuleFileIO; +using namespace OHOS::FileManagement::ModuleFileIO::ANI::AniSignature; + +static tuple> ToReadOptions(ani_env *env, ani_object obj) +{ + ReadOptions options; + ani_boolean isUndefined; + env->Reference_IsUndefined(obj, &isUndefined); + if (isUndefined) { + return { true, nullopt }; + } + + auto [succOffset, offset] = AniHelper::ParseInt64Option(env, obj, "offset"); + if (!succOffset) { + HILOGE("Illegal option.offset parameter"); + return { false, nullopt }; + } + options.offset = offset; + + auto [succLength, length] = AniHelper::ParseInt64Option(env, obj, "length"); + if (!succLength) { + HILOGE("Illegal option.length parameter"); + return { false, nullopt }; + } + options.length = length; + return { true, make_optional(move(options)) }; +} + +static tuple> ToWriteOptions(ani_env *env, ani_object obj) +{ + WriteOptions options; + ani_boolean isUndefined; + env->Reference_IsUndefined(obj, &isUndefined); + if (isUndefined) { + return { true, nullopt }; + } + + auto [succOffset, offset] = AniHelper::ParseInt64Option(env, obj, "offset"); + if (!succOffset) { + HILOGE("Illegal option.offset parameter"); + return { false, nullopt }; + } + options.offset = offset; + + auto [succLength, length] = AniHelper::ParseInt64Option(env, obj, "length"); + if (!succLength) { + HILOGE("Illegal option.length parameter"); + return { false, nullopt }; + } + options.length = length; + + auto [succEncoding, encoding] = AniHelper::ParseEncoding(env, obj); + if (!succEncoding) { + HILOGE("Illegal option.encoding parameter"); + return { false, nullopt }; + } + options.encoding = encoding; + return { true, make_optional(move(options)) }; +} + +static std::tuple ParseStringBuffer(ani_env *env, const ani_object &buf) +{ + auto classDesc = BuiltInTypes::String::classDesc.c_str(); + ani_class cls; + env->FindClass(classDesc, &cls); + + ani_boolean isString; + env->Object_InstanceOf(buf, cls, &isString); + if (!isString) { + return { false, {} }; + } + auto result = static_cast(buf); + return { true, std::move(result) }; +} + +static std::tuple ParseArrayBuffer(ani_env *env, const ani_object &buf) +{ + auto classDesc = BuiltInTypes::ArrayBuffer::classDesc.c_str(); + ani_class cls; + env->FindClass(classDesc, &cls); + + ani_boolean isArrayBuffer; + env->Object_InstanceOf(buf, cls, &isArrayBuffer); + if (!isArrayBuffer) { + return { false, {} }; + } + auto result = static_cast(buf); + return { true, std::move(result) }; +} + +static FsStream *Unwrap(ani_env *env, ani_object object) +{ + ani_long nativePtr; + auto ret = env->Object_GetFieldByName_Long(object, "nativePtr", &nativePtr); + if (ret != ANI_OK) { + HILOGE("Unwrap fsFile err: %{private}d", ret); + return nullptr; + } + uintptr_t ptrValue = static_cast(nativePtr); + FsStream *stream = reinterpret_cast(ptrValue); + return stream; +} + +void StreamAni::Close(ani_env *env, [[maybe_unused]] ani_object object) +{ + auto fsStream = Unwrap(env, object); + if (fsStream == nullptr) { + HILOGE("Cannot unwrap fsStream!"); + ErrorHandler::Throw(env, EINVAL); + return; + } + + auto ret = fsStream->Close(); + if (!ret.IsSuccess()) { + HILOGE("Cannot close fsStream!"); + const auto &err = ret.GetError(); + ErrorHandler::Throw(env, err); + return; + } +} + +void StreamAni::Flush(ani_env *env, [[maybe_unused]] ani_object object) +{ + auto fsStream = Unwrap(env, object); + if (fsStream == nullptr) { + HILOGE("Cannot unwrap fsStream!"); + ErrorHandler::Throw(env, EINVAL); + return; + } + + auto ret = fsStream->Flush(); + if (!ret.IsSuccess()) { + HILOGE("Cannot flush fsStream!"); + const auto &err = ret.GetError(); + ErrorHandler::Throw(env, err); + return; + } +} + +ani_double StreamAni::Write(ani_env *env, [[maybe_unused]] ani_object object, ani_object buf, ani_object options) +{ + auto fsStream = Unwrap(env, object); + if (fsStream == nullptr) { + HILOGE("Cannot unwrap fsStream!"); + return -1; + } + + auto [succOp, op] = ToWriteOptions(env, options); + if (!succOp) { + HILOGE("Failed to resolve options!"); + return -1; + } + + auto [isString, stringBuffer] = ParseStringBuffer(env, buf); + if (isString) { + auto [succBuf, buffer] = TypeConverter::ToUTF8String(env, stringBuffer); + if (!succBuf) { + HILOGE("Failed to resolve stringBuffer!"); + ErrorHandler::Throw(env, EINVAL); + return -1; + } + auto ret = fsStream->Write(buffer, op); + if (!ret.IsSuccess()) { + HILOGE("write string failed!"); + const auto &err = ret.GetError(); + ErrorHandler::Throw(env, err); + return -1; + } + return ret.GetData().value(); + } + + auto [isArrayBuffer, arrayBuffer] = ParseArrayBuffer(env, buf); + if (isArrayBuffer) { + auto [succBuf, buffer] = TypeConverter::ToArrayBuffer(env, arrayBuffer); + if (!succBuf) { + HILOGE("Failed to resolve arrayBuffer!"); + ErrorHandler::Throw(env, EINVAL); + return -1; + } + auto ret = fsStream->Write(buffer, op); + if (!ret.IsSuccess()) { + HILOGE("write buffer failed!"); + const auto &err = ret.GetError(); + ErrorHandler::Throw(env, err); + return -1; + } + return static_cast(ret.GetData().value()); + } + + HILOGE("Unsupported buffer type!"); + ErrorHandler::Throw(env, EINVAL); + return -1; +} + +ani_double StreamAni::Read(ani_env *env, [[maybe_unused]] ani_object object, ani_arraybuffer buffer, ani_object options) +{ + auto fsStream = Unwrap(env, object); + if (fsStream == nullptr) { + HILOGE("Cannot unwrap fsStream!"); + ErrorHandler::Throw(env, EINVAL); + return -1; + } + + auto [succBuf, arrayBuffer] = TypeConverter::ToArrayBuffer(env, buffer); + if (!succBuf) { + HILOGE("Failed to resolve arrayBuffer!"); + ErrorHandler::Throw(env, EINVAL); + return -1; + } + + auto [succOp, op] = ToReadOptions(env, options); + if (!succOp) { + HILOGE("Failed to resolve options!"); + ErrorHandler::Throw(env, EINVAL); + return -1; + } + + auto ret = fsStream->Read(arrayBuffer, op); + if (!ret.IsSuccess()) { + HILOGE("write buffer failed!"); + const auto &err = ret.GetError(); + ErrorHandler::Throw(env, err); + return -1; + } + return static_cast(ret.GetData().value()); +} + +ani_double StreamAni::Seek(ani_env *env, [[maybe_unused]] ani_object object, ani_double offset, ani_object whence) +{ + auto fsStream = Unwrap(env, object); + if (fsStream == nullptr) { + HILOGE("Cannot unwrap fsStream!"); + ErrorHandler::Throw(env, EINVAL); + return -1; + } + + auto [succ, typeOpt] = TypeConverter::ToOptionalInt32(env, whence); + if (!succ) { + HILOGE("Invalied whence type"); + ErrorHandler::Throw(env, EINVAL); + return -1; + } + + auto ret = fsStream->Seek(static_cast(offset), typeOpt); + if (!ret.IsSuccess()) { + HILOGE("seek failed!"); + const auto &err = ret.GetError(); + ErrorHandler::Throw(env, err); + return -1; + } + return static_cast(ret.GetData().value()); +} + +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_stream/ani/stream_ani.h b/interfaces/kits/js/src/mod_fs/class_stream/ani/stream_ani.h new file mode 100644 index 000000000..91fdb9852 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_stream/ani/stream_ani.h @@ -0,0 +1,40 @@ +/* + * 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_MOD_FS_STREAM_ANI_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_STREAM_ANI_H + +#include + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +class StreamAni final { +public: + static void Close(ani_env *env, [[maybe_unused]] ani_object object); + static void Flush(ani_env *env, [[maybe_unused]] ani_object object); + static ani_double Write(ani_env *env, [[maybe_unused]] ani_object object, ani_object buf, ani_object options); + static ani_double Read( + ani_env *env, [[maybe_unused]] ani_object object, ani_arraybuffer buffer, ani_object options); + static ani_double Seek(ani_env *env, [[maybe_unused]] ani_object object, ani_double offset, ani_object whence); +}; +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS + +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_STREAM_ANI_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_stream/ani/stream_wrapper.cpp b/interfaces/kits/js/src/mod_fs/class_stream/ani/stream_wrapper.cpp new file mode 100644 index 000000000..c882f9dda --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_stream/ani/stream_wrapper.cpp @@ -0,0 +1,78 @@ +/* + * 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 "stream_wrapper.h" + +#include + +#include "ani_helper.h" +#include "ani_signature.h" +#include "filemgmt_libhilog.h" +#include "type_converter.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { +using namespace std; +using namespace OHOS::FileManagement::ModuleFileIO; +using namespace OHOS::FileManagement::ModuleFileIO::ANI::AniSignature; + +FsStream *StreamWrapper::Unwrap(ani_env *env, ani_object object) +{ + ani_long nativePtr; + auto ret = env->Object_GetFieldByName_Long(object, "nativePtr", &nativePtr); + if (ret != ANI_OK) { + HILOGE("Unwrap fsFile err: %{private}d", ret); + return nullptr; + } + uintptr_t ptrValue = static_cast(nativePtr); + FsStream *stream = reinterpret_cast(ptrValue); + return stream; +} + +ani_object StreamWrapper::Wrap(ani_env *env, const FsStream *stream) +{ + if (stream == nullptr) { + HILOGE("FsStream pointer is null!"); + return nullptr; + } + auto classDesc = FS::StreamInner::classDesc.c_str(); + ani_class cls; + if (ANI_OK != env->FindClass(classDesc, &cls)) { + HILOGE("Cannot find class %s", classDesc); + return nullptr; + } + auto ctorDesc = FS::StreamInner::ctorDesc.c_str(); + auto ctorSig = FS::StreamInner::ctorSig.c_str(); + ani_method ctor; + if (ANI_OK != env->Class_FindMethod(cls, ctorDesc, ctorSig, &ctor)) { + HILOGE("Cannot find constructor method for class %s", classDesc); + return nullptr; + } + ani_long ptr = static_cast(reinterpret_cast(stream)); + ani_object obj; + if (ANI_OK != env->Object_New(cls, ctor, &obj, ptr)) { + HILOGE("New %s obj Failed!", classDesc); + return nullptr; + } + + return obj; +} + +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_stream/ani/stream_wrapper.h b/interfaces/kits/js/src/mod_fs/class_stream/ani/stream_wrapper.h new file mode 100644 index 000000000..a99f6d4ad --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_stream/ani/stream_wrapper.h @@ -0,0 +1,37 @@ +/* + * 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_MOD_FS_STREAM_WRAPPER_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_STREAM_WRAPPER_H + +#include +#include "fs_stream.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +class StreamWrapper final { +public: + static FsStream *Unwrap(ani_env *env, ani_object object); + static ani_object Wrap(ani_env *env, const FsStream *stream); +}; +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS + +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_STREAM_WRAPPER_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_stream/fs_stream.cpp b/interfaces/kits/js/src/mod_fs/class_stream/fs_stream.cpp new file mode 100644 index 000000000..00a493ed2 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_stream/fs_stream.cpp @@ -0,0 +1,292 @@ +/* + * 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 "fs_stream.h" + +#include +#include + +#include "file_utils.h" +#include "filemgmt_libhilog.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +using namespace std; + +std::shared_ptr FsStream::GetFilePtr() +{ + std::lock_guard lock(mtx); + if (!streamEntity) { + return nullptr; + } + return streamEntity->fp; +} + +static tuple ValidWriteArg(const size_t bufLen, const optional &options) +{ + size_t retLen = 0; + int64_t offset = -1; + bool succ = false; + + if (bufLen > UINT_MAX) { + HILOGE("The Size of buffer is too large"); + return { false, 0, offset }; + } + + optional lengthOp = nullopt; + optional offsetOp = nullopt; + optional encodingOp = nullopt; + if (options.has_value()) { + WriteOptions op = options.value(); + lengthOp = op.length; + offsetOp = op.offset; + encodingOp = op.encoding; + } + + tie(succ, retLen) = FsUtils::GetActualLen(bufLen, 0, lengthOp); + if (!succ) { + HILOGE("Failed to get actual length"); + return { false, 0, offset }; + } + + if (offsetOp.has_value()) { + offset = offsetOp.value(); + if (offset < 0) { + HILOGE("option.offset shall be positive number"); + return { false, 0, offset }; + } + } + + if (encodingOp.has_value()) { + if (encodingOp.value() != "utf-8") { + HILOGE("option.encoding shall be utf-8"); + return { false, 0, offset }; + } + } + return { true, retLen, offset }; +} + +static tuple ValidReadArg(const size_t bufLen, const optional &options) +{ + size_t retLen = 0; + int64_t offset = -1; + bool succ = false; + + if (bufLen > UINT_MAX) { + HILOGE("The Size of buffer is too large"); + return { false, 0, offset }; + } + + optional lengthOp = nullopt; + optional offsetOp = nullopt; + if (options.has_value()) { + ReadOptions op = options.value(); + lengthOp = op.length; + offsetOp = op.offset; + } + + tie(succ, retLen) = FsUtils::GetActualLen(bufLen, 0, lengthOp); + if (!succ) { + HILOGE("Failed to get actual length"); + return { false, 0, offset }; + } + + if (offsetOp.has_value()) { + offset = offsetOp.value(); + if (offset < 0) { + HILOGE("option.offset shall be positive number"); + return { false, 0, offset }; + } + } + return { true, retLen, offset }; +} + +FsResult FsStream::Write(const ArrayBuffer &buf, const optional &options) +{ + auto fp = GetFilePtr(); + if (!fp) { + HILOGE("Failed to get file ptr"); + return FsResult::Error(EIO); + } + + auto [succ, retLen, offset] = ValidWriteArg(buf.length, options); + if (!succ) { + HILOGE("Invalid options"); + return FsResult::Error(EINVAL); + } + + if (offset >= 0) { + int ret = fseek(fp.get(), static_cast(offset), SEEK_SET); + if (ret < 0) { + HILOGE("Failed to set the offset location of the file stream pointer, ret: %{public}d", ret); + return FsResult::Error(errno); + } + } + + size_t writeLen = fwrite(buf.buf, 1, retLen, fp.get()); + if ((writeLen == 0) && (writeLen != retLen)) { + HILOGE("Failed to fwrite stream"); + return FsResult::Error(EIO); + } + return FsResult::Success(writeLen); +} + +FsResult FsStream::Write(const string &buf, const optional &options) +{ + auto fp = GetFilePtr(); + if (!fp) { + HILOGE("Failed to get file ptr"); + return FsResult::Error(EIO); + } + + size_t bufLen = static_cast(buf.length()); + + auto [succ, retLen, offset] = ValidWriteArg(bufLen, options); + if (!succ) { + HILOGE("Invalid options"); + return FsResult::Error(EINVAL); + } + + if (offset >= 0) { + int ret = fseek(fp.get(), static_cast(offset), SEEK_SET); + if (ret < 0) { + HILOGE("Failed to set the offset location of the file stream pointer, ret: %{public}d", ret); + return FsResult::Error(errno); + } + } + + size_t writeLen = fwrite(buf.c_str(), 1, retLen, fp.get()); + if ((writeLen == 0) && (writeLen != retLen)) { + HILOGE("Failed to fwrite stream"); + return FsResult::Error(EIO); + } + return FsResult::Success(writeLen); +} + +FsResult FsStream::Read(ArrayBuffer &buf, const optional &options) +{ + auto fp = GetFilePtr(); + if (!fp) { + HILOGE("Failed to get file ptr"); + return FsResult::Error(EIO); + } + + auto [succ, retLen, offset] = ValidReadArg(buf.length, options); + if (!succ) { + HILOGE("Invalid options"); + return FsResult::Error(EINVAL); + } + + if (offset >= 0) { + int ret = fseek(fp.get(), static_cast(offset), SEEK_SET); + if (ret < 0) { + HILOGE("Failed to set the offset location of the file stream pointer, ret: %{public}d", ret); + return FsResult::Error(errno); + } + } + + size_t actLen = fread(buf.buf, 1, retLen, fp.get()); + if ((actLen != static_cast(retLen) && !feof(fp.get())) || ferror(fp.get())) { + HILOGE("Invalid buffer size or pointer, actlen: %{public}zu", actLen); + return FsResult::Error(EIO); + } + + return FsResult::Success(actLen); +} + +FsResult FsStream::Flush() +{ + auto fp = GetFilePtr(); + if (fp == nullptr) { + HILOGE("Failed to get entity of Stream"); + return FsResult::Error(EIO); + } + + int ret = fflush(fp.get()); + if (ret < 0) { + HILOGE("Failed to fflush file in the stream, ret: %{public}d", ret); + return FsResult::Error(errno); + } + + return FsResult::Success(); +} + +FsResult FsStream::Close() +{ + if (!streamEntity) { + HILOGE("Failed to get entity of Stream, may closed twice"); + return FsResult::Error(EIO); + } + streamEntity = nullptr; + return FsResult::Success(); +} + +FsResult FsStream::Seek(const int64_t &offset, const optional &typeOpt) +{ + int whence = SEEK_SET; + + auto fp = GetFilePtr(); + if (fp == nullptr) { + HILOGE("Failed to get file ptr"); + return FsResult::Error(ENOENT); + } + + if (typeOpt.has_value()) { + int pos = typeOpt.value(); + if (pos < SEEK_SET || pos > SEEK_END) { + HILOGE("Invalid whence"); + return FsResult::Error(EINVAL); + } + whence = pos; + } + + if (offset >= 0) { + int ret = fseek(fp.get(), static_cast(offset), whence); + if (ret < 0) { + HILOGE("Failed to set the offset location of the file stream pointer, ret: %{public}d", ret); + return FsResult::Error(errno); + } + } + + int64_t res = ftell(fp.get()); + if (res < 0) { + HILOGE("Failed to tell, error:%{public}d", errno); + return FsResult::Error(errno); + } + + return FsResult::Success(res); +} + +FsResult FsStream::Constructor() +{ + auto rafEntity = CreateUniquePtr(); + if (rafEntity == nullptr) { + HILOGE("Failed to request heap memory."); + return FsResult::Error(ENOMEM); + } + FsStream *fsStreamPtr = new FsStream(move(rafEntity)); + + if (fsStreamPtr == nullptr) { + HILOGE("Failed to create FsStream object on heap."); + return FsResult::Error(ENOMEM); + } + + return FsResult::Success(move(fsStreamPtr)); +} + +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS diff --git a/interfaces/kits/js/src/mod_fs/class_stream/fs_stream.h b/interfaces/kits/js/src/mod_fs/class_stream/fs_stream.h new file mode 100644 index 000000000..a6b9661e0 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_stream/fs_stream.h @@ -0,0 +1,74 @@ +/* + * 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_MOD_FS_CLASS_STREAM_FS_STREAM_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_STREAM_FS_STREAM_H + +#include "stream_entity.h" + +#include +#include +#include + +#include "filemgmt_libfs.h" +#include "fs_utils.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +using namespace std; + +struct WriteOptions { + optional length = nullopt; + optional offset = nullopt; + optional encoding = nullopt; +}; + +struct ReadOptions { + optional length = nullopt; + optional offset = nullopt; +}; + +class FsStream final { +public: + StreamEntity *GetStreamEntity() const + { + return streamEntity.get(); + } + + FsStream(const FsStream &) = delete; + FsStream &operator=(const FsStream &) = delete; + + std::shared_ptr GetFilePtr(); + FsResult Write(const ArrayBuffer &buf, const optional &options = nullopt); + FsResult Write(const string &buf, const optional &options = nullopt); + FsResult Read(ArrayBuffer &buf, const optional &options = nullopt); + FsResult Close(); + FsResult Flush(); + FsResult Seek(const int64_t &offset, const optional &typeOpt = nullopt); + + ~FsStream() = default; + static FsResult Constructor(); + +private: + std::mutex mtx; + unique_ptr streamEntity; + explicit FsStream(unique_ptr entity) : streamEntity(move(entity)) {} +}; + +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_STREAM_FS_STREAM_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_stream/stream_instantiator.cpp b/interfaces/kits/js/src/mod_fs/class_stream/stream_instantiator.cpp new file mode 100644 index 000000000..e28dfa77c --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_stream/stream_instantiator.cpp @@ -0,0 +1,79 @@ +/* + * 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 "stream_instantiator.h" + +#include "file_utils.h" +#include "filemgmt_libhilog.h" +#include "stream_entity.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +using namespace std; + +FsResult StreamInstantiator::InstantiateStream(FILE *file) +{ + FsResult result = FsStream::Constructor(); + if (!result.IsSuccess()) { + HILOGE("Failed to instantiate class"); + int ret = fclose(file); + if (ret < 0) { + HILOGE("Failed to close file"); + } + return FsResult::Error(EIO); + } + + const FsStream *objStream = result.GetData().value(); + if (!objStream) { + HILOGE("Failed to get FsStream"); + int ret = fclose(file); + if (ret < 0) { + HILOGE("Failed to close file"); + } + return FsResult::Error(EIO); + } + + auto *streamEntity = objStream->GetStreamEntity(); + if (!streamEntity) { + HILOGE("Failed to get streamEntity"); + int ret = fclose(file); + if (ret < 0) { + HILOGE("Failed to close file"); + } + delete objStream; + objStream = nullptr; + return FsResult::Error(EIO); + } + + auto fp = std::shared_ptr(file, fclose); + if (fp == nullptr) { + HILOGE("Failed to request heap memory."); + int ret = fclose(file); + if (ret < 0) { + HILOGE("Failed to close file"); + } + delete objStream; + objStream = nullptr; + return FsResult::Error(ENOMEM); + } + + streamEntity->fp.swap(fp); + return result; +} + +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_stream/stream_instantiator.h b/interfaces/kits/js/src/mod_fs/class_stream/stream_instantiator.h new file mode 100644 index 000000000..bf98d7b53 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_stream/stream_instantiator.h @@ -0,0 +1,35 @@ +/* + * 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_MOD_FS_CLASS_STREAM_INSTANTIATOR_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_STREAM_INSTANTIATOR_H + +#include "filemgmt_libfs.h" +#include "fs_stream.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +using namespace std; + +class StreamInstantiator { +public: + static FsResult InstantiateStream(FILE *file); +}; + +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_STREAM_INSTANTIATOR_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_stream/stream_n_exporter.cpp b/interfaces/kits/js/src/mod_fs/class_stream/stream_n_exporter.cpp index b381e97bf..6f92f562f 100644 --- a/interfaces/kits/js/src/mod_fs/class_stream/stream_n_exporter.cpp +++ b/interfaces/kits/js/src/mod_fs/class_stream/stream_n_exporter.cpp @@ -27,6 +27,7 @@ #include "common_func.h" #include "file_utils.h" #include "filemgmt_libhilog.h" +#include "rust_file.h" #include "stream_entity.h" namespace OHOS { diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/create_stream_ani.cpp b/interfaces/kits/js/src/mod_fs/properties/ani/create_stream_ani.cpp new file mode 100644 index 000000000..d81983404 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/create_stream_ani.cpp @@ -0,0 +1,71 @@ +/* + * 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 "create_stream_ani.h" + +#include "create_stream_core.h" +#include "error_handler.h" +#include "filemgmt_libhilog.h" +#include "stream_wrapper.h" +#include "type_converter.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +using namespace std; +using namespace OHOS::FileManagement::ModuleFileIO; + +ani_object CreateStreamAni::CreateStreamSync( + ani_env *env, [[maybe_unused]] ani_class clazz, ani_string path, ani_string mode) +{ + auto [succPath, srcPath] = TypeConverter::ToUTF8String(env, path); + if (!succPath) { + HILOGE("Invalid path"); + ErrorHandler::Throw(env, EINVAL); + return nullptr; + } + + auto [succMode, openMode] = TypeConverter::ToUTF8String(env, mode); + if (!succMode) { + HILOGE("Invalid mode"); + ErrorHandler::Throw(env, EINVAL); + return nullptr; + } + + FsResult ret = CreateStreamCore::DoCreateStream(srcPath, openMode); + if (!ret.IsSuccess()) { + HILOGE("create stream failed"); + const auto &err = ret.GetError(); + ErrorHandler::Throw(env, err); + return nullptr; + } + + const FsStream *stream = ret.GetData().value(); + auto result = StreamWrapper::Wrap(env, move(stream)); + if (result == nullptr) { + delete stream; + stream = nullptr; + ErrorHandler::Throw(env, UNKNOWN_ERR); + return nullptr; + } + return result; +} + +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/create_stream_ani.h b/interfaces/kits/js/src/mod_fs/properties/ani/create_stream_ani.h new file mode 100644 index 000000000..2052b6b4d --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/create_stream_ani.h @@ -0,0 +1,34 @@ +/* + * 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_MOD_FS_PROPERTIES_CREATE_STREAM_ANI_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_CREATE_STREAM_ANI_H + +#include + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { +class CreateStreamAni final { +public: + static ani_object CreateStreamSync( + ani_env *env, [[maybe_unused]] ani_class clazz, ani_string path, ani_string mode); +}; +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_CREATE_STREAM_ANI_H \ No newline at end of file -- Gitee From 04867558ed7095aa383e7f1b1bb6beb58614c4db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E9=91=AB?= Date: Sat, 26 Jul 2025 16:54:48 +0800 Subject: [PATCH 2/2] =?UTF-8?q?stream=20=E4=BB=A3=E7=A0=81=E4=BF=AE?= =?UTF-8?q?=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 周鑫 Change-Id: If4ba25e02848ccac479b20d0d965537caa59d551 --- .../src/common/ani_helper/ani_signature.cpp | 10 ++++ .../js/src/common/ani_helper/ani_signature.h | 14 +++++ .../ani/randomaccessfile_ani.cpp | 54 ++++++++++--------- .../mod_fs/class_stream/ani/stream_ani.cpp | 1 + .../js/src/mod_fs/class_stream/fs_stream.cpp | 3 +- .../mod_fs/class_stream/stream_n_exporter.cpp | 1 - .../properties/ani/create_stream_ani.cpp | 1 + 7 files changed, 57 insertions(+), 27 deletions(-) diff --git a/interfaces/kits/js/src/common/ani_helper/ani_signature.cpp b/interfaces/kits/js/src/common/ani_helper/ani_signature.cpp index 3b4e5f12d..f46a4fdd4 100644 --- a/interfaces/kits/js/src/common/ani_helper/ani_signature.cpp +++ b/interfaces/kits/js/src/common/ani_helper/ani_signature.cpp @@ -154,5 +154,15 @@ const string Impl::StatvfsImpl::classDesc = Impl::StatvfsImpl::classType.Descrip const Type HASH::HashStreamImpl::classType = Builder::BuildClass("@ohos.file.hash.HashStreamImpl"); const string HASH::HashStreamImpl::classDesc = HASH::HashStreamImpl::classType.Descriptor(); const string HASH::HashStreamImpl::ctorSig = Builder::BuildSignatureDescriptor({ BuiltInTypes::stringType }); +// FS::ReadStreamOptionsInner +const Type FS::ReadStreamOptionsInner::classType = Builder::BuildClass("@ohos.file.fs.ReadStreamOptionsInner"); +const string FS::ReadStreamOptionsInner::classDesc = FS::ReadStreamOptionsInner::classType.Descriptor(); +const string FS::ReadStreamOptionsInner::ctorSig = Builder::BuildSignatureDescriptor({}); +const string FS::ReadStreamOptionsInner::ctorDesc = Builder::BuildConstructorName(); +// FS::WriteStreamOptionsInner +const Type FS::WriteStreamOptionsInner::classType = Builder::BuildClass("@ohos.file.fs.WriteStreamOptionsInner"); +const string FS::WriteStreamOptionsInner::classDesc = FS::ReadStreamOptionsInner::classType.Descriptor(); +const string FS::WriteStreamOptionsInner::ctorSig = Builder::BuildSignatureDescriptor({}); +const string FS::WriteStreamOptionsInner::ctorDesc = Builder::BuildConstructorName(); } // 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 index bb9217942..de58ba8cb 100644 --- a/interfaces/kits/js/src/common/ani_helper/ani_signature.h +++ b/interfaces/kits/js/src/common/ani_helper/ani_signature.h @@ -123,6 +123,20 @@ struct ConflictFilesInner : public BaseType { static const string ctorSig; }; +struct ReadStreamOptionsInner : public BaseType { + static const Type classType; + static const string classDesc; + static const string ctorDesc; + static const string ctorSig; +}; + +struct WriteStreamOptionsInner : public BaseType { + static const Type classType; + static const string classDesc; + static const string ctorDesc; + static const string ctorSig; +}; + struct FileInner : public BaseType { static const Type classType; static const string classDesc; diff --git a/interfaces/kits/js/src/mod_fs/class_randomaccessfile/ani/randomaccessfile_ani.cpp b/interfaces/kits/js/src/mod_fs/class_randomaccessfile/ani/randomaccessfile_ani.cpp index 604835791..a220f84ba 100644 --- a/interfaces/kits/js/src/mod_fs/class_randomaccessfile/ani/randomaccessfile_ani.cpp +++ b/interfaces/kits/js/src/mod_fs/class_randomaccessfile/ani/randomaccessfile_ani.cpp @@ -33,13 +33,15 @@ using namespace OHOS::FileManagement::ModuleFileIO::ANI::AniSignature; const int BUF_SIZE = 1024; const string READ_STREAM_CLASS = "ReadStream"; const string WRITE_STREAM_CLASS = "WriteStream"; +const string OFFSET = "offset"; +const string LENGTH = "length"; static FsRandomAccessFile *Unwrap(ani_env *env, ani_object object) { ani_long nativePtr; auto ret = env->Object_GetFieldByName_Long(object, "nativePtr", &nativePtr); if (ret != ANI_OK) { - HILOGE("Unwrap FsRandomAccessFile err: %{private}d", ret); + HILOGE("Unwrap FsRandomAccessFile err: %{public}d", ret); return nullptr; } uintptr_t ptrValue = static_cast(nativePtr); @@ -56,14 +58,14 @@ static tuple> ToReadOptions(ani_env *env, ani_object return { true, nullopt }; } - auto [succOffset, offset] = AniHelper::ParseInt64Option(env, obj, "offset"); + auto [succOffset, offset] = AniHelper::ParseInt64Option(env, obj, OFFSET); if (!succOffset) { HILOGE("Illegal option.offset parameter"); return { false, nullopt }; } options.offset = offset; - auto [succLength, length] = AniHelper::ParseInt64Option(env, obj, "length"); + auto [succLength, length] = AniHelper::ParseInt64Option(env, obj, LENGTH); if (!succLength) { HILOGE("Illegal option.length parameter"); return { false, nullopt }; @@ -81,14 +83,14 @@ static tuple> ToWriteOptions(ani_env *env, ani_obje return { true, nullopt }; } - auto [succOffset, offset] = AniHelper::ParseInt64Option(env, obj, "offset"); + auto [succOffset, offset] = AniHelper::ParseInt64Option(env, obj, OFFSET); if (!succOffset) { HILOGE("Illegal option.offset parameter"); return { false, nullopt }; } options.offset = offset; - auto [succLength, length] = AniHelper::ParseInt64Option(env, obj, "length"); + auto [succLength, length] = AniHelper::ParseInt64Option(env, obj, LENGTH); if (!succLength) { HILOGE("Illegal option.length parameter"); return { false, nullopt }; @@ -283,31 +285,32 @@ static ani_string GetFilePath(ani_env *env, const int fd) static ani_object CreateReadStreamOptions(ani_env *env, int64_t start, int64_t end) { - static const char *className = "L@ohos/file/fs/ReadStreamOptionsInner;"; + static const char *className = FS::ReadStreamOptionsInner::classType; ani_class cls; if (ANI_OK != env->FindClass(className, &cls)) { - HILOGE("Cannot find class %s", className); + HILOGE("Cannot find class %{public}s", className); return nullptr; } ani_method ctor; - if (ANI_OK != env->Class_FindMethod(cls, "", ":V", &ctor)) { - HILOGE("Cannot find constructor method for class %s", className); + if (ANI_OK != env->Class_FindMethod(cls, FS::ReadStreamOptionsInner::ctorDesc, + FS::ReadStreamOptionsInner::ctorSig, &ctor)) { + HILOGE("Cannot find constructor method for class %{public}s", className); return nullptr; } ani_object obj; if (ANI_OK != env->Object_New(cls, ctor, &obj)) { - HILOGE("New %s obj Failed", className); + HILOGE("New %{public}s obj Failed", className); return nullptr; } ani_field startField = nullptr; ani_field endField = nullptr; if (ANI_OK != env->Class_FindField(cls, "start", &startField)) { - HILOGE("Cannot find start in class %s", className); + HILOGE("Cannot find start in class %{public}s", className); return nullptr; } if (ANI_OK != env->Class_FindField(cls, "end", &endField)) { - HILOGE("Cannot find end in class %s", className); + HILOGE("Cannot find end in class %{public}s", className); return nullptr; } @@ -326,31 +329,32 @@ static ani_object CreateReadStreamOptions(ani_env *env, int64_t start, int64_t e static ani_object CreateWriteStreamOptions(ani_env *env, int64_t start, int flags) { - static const char *className = "L@ohos/file/fs/WriteStreamOptionsInner;"; + static const char *className = FS::WriteStreamOptionsInner::classType; ani_class cls; if (ANI_OK != env->FindClass(className, &cls)) { - HILOGE("Cannot find class %s", className); + HILOGE("Cannot find class %{public}s", className); return nullptr; } ani_method ctor; - if (ANI_OK != env->Class_FindMethod(cls, "", ":V", &ctor)) { - HILOGE("Cannot find constructor method for class %s", className); + if (ANI_OK != env->Class_FindMethod(cls, FS::WriteStreamOptionsInner::ctorDesc, + FS::WriteStreamOptionsInner::ctorSig, &ctor)) { + HILOGE("Cannot find constructor method for class %{public}s", className); return nullptr; } ani_object obj; if (ANI_OK != env->Object_New(cls, ctor, &obj)) { - HILOGE("New %s obj Failed", className); + HILOGE("New %{public}s obj Failed", className); return nullptr; } ani_field modeField = nullptr; ani_field startField = nullptr; if (ANI_OK != env->Class_FindField(cls, "mode", &modeField)) { - HILOGE("Cannot find mode in class %s", className); + HILOGE("Cannot find mode in class %{public}s", className); return nullptr; } if (ANI_OK != env->Class_FindField(cls, "start", &startField)) { - HILOGE("Cannot find start in class %s", className); + HILOGE("Cannot find start in class %{public}s", className); return nullptr; } @@ -367,17 +371,17 @@ static ani_object CreateReadStream(ani_env *env, ani_string filePath, ani_object static const char *className = "L@ohos/file/fs/fileIo/ReadStream;"; ani_class cls; if (ANI_OK != env->FindClass(className, &cls)) { - HILOGE("Cannot find class %s", className); + HILOGE("Cannot find class %{public}s", className); return nullptr; } ani_method ctor; if (ANI_OK != env->Class_FindMethod(cls, "", "Lstd/core/String;L@ohos/file/fs/ReadStreamOptions;:V", &ctor)) { - HILOGE("Cannot find constructor method for class %s", className); + HILOGE("Cannot find constructor method for class %{public}s", className); return nullptr; } ani_object obj; if (ANI_OK != env->Object_New(cls, ctor, &obj, filePath, options)) { - HILOGE("New %s obj Failed", className); + HILOGE("New %{public}s obj Failed", className); return nullptr; } @@ -389,18 +393,18 @@ static ani_object CreateWriteStream(ani_env *env, ani_string filePath, ani_objec static const char *className = "L@ohos/file/fs/fileIo/WriteStream;"; ani_class cls; if (ANI_OK != env->FindClass(className, &cls)) { - HILOGE("Cannot find class %s", className); + HILOGE("Cannot find class %{public}s", className); return nullptr; } ani_method ctor; if (ANI_OK != env->Class_FindMethod(cls, "", "Lstd/core/String;L@ohos/file/fs/WriteStreamOptions;:V", &ctor)) { - HILOGE("Cannot find constructor method for class %s", className); + HILOGE("Cannot find constructor method for class %{public}s", className); return nullptr; } ani_object obj; if (ANI_OK != env->Object_New(cls, ctor, &obj, filePath, options)) { - HILOGE("New %s obj Failed", className); + HILOGE("New %{public}s obj Failed", className); return nullptr; } diff --git a/interfaces/kits/js/src/mod_fs/class_stream/ani/stream_ani.cpp b/interfaces/kits/js/src/mod_fs/class_stream/ani/stream_ani.cpp index a1d694187..39c26d8b7 100644 --- a/interfaces/kits/js/src/mod_fs/class_stream/ani/stream_ani.cpp +++ b/interfaces/kits/js/src/mod_fs/class_stream/ani/stream_ani.cpp @@ -100,6 +100,7 @@ static std::tuple ParseStringBuffer(ani_env *env, const ani_ob ani_boolean isString; env->Object_InstanceOf(buf, cls, &isString); if (!isString) { + HILOGE("Object_InstanceOf is failed"); return { false, {} }; } auto result = static_cast(buf); diff --git a/interfaces/kits/js/src/mod_fs/class_stream/fs_stream.cpp b/interfaces/kits/js/src/mod_fs/class_stream/fs_stream.cpp index 00a493ed2..13dcc47a4 100644 --- a/interfaces/kits/js/src/mod_fs/class_stream/fs_stream.cpp +++ b/interfaces/kits/js/src/mod_fs/class_stream/fs_stream.cpp @@ -25,6 +25,7 @@ namespace OHOS { namespace FileManagement { namespace ModuleFileIO { using namespace std; +const string UTF_8 = "utf-8"; std::shared_ptr FsStream::GetFilePtr() { @@ -71,7 +72,7 @@ static tuple ValidWriteArg(const size_t bufLen, const opt } if (encodingOp.has_value()) { - if (encodingOp.value() != "utf-8") { + if (encodingOp.value() != UTF_8) { HILOGE("option.encoding shall be utf-8"); return { false, 0, offset }; } diff --git a/interfaces/kits/js/src/mod_fs/class_stream/stream_n_exporter.cpp b/interfaces/kits/js/src/mod_fs/class_stream/stream_n_exporter.cpp index 6f92f562f..b381e97bf 100644 --- a/interfaces/kits/js/src/mod_fs/class_stream/stream_n_exporter.cpp +++ b/interfaces/kits/js/src/mod_fs/class_stream/stream_n_exporter.cpp @@ -27,7 +27,6 @@ #include "common_func.h" #include "file_utils.h" #include "filemgmt_libhilog.h" -#include "rust_file.h" #include "stream_entity.h" namespace OHOS { diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/create_stream_ani.cpp b/interfaces/kits/js/src/mod_fs/properties/ani/create_stream_ani.cpp index d81983404..bc0d76728 100644 --- a/interfaces/kits/js/src/mod_fs/properties/ani/create_stream_ani.cpp +++ b/interfaces/kits/js/src/mod_fs/properties/ani/create_stream_ani.cpp @@ -59,6 +59,7 @@ ani_object CreateStreamAni::CreateStreamSync( if (result == nullptr) { delete stream; stream = nullptr; + HILOGE("Wrap failed"); ErrorHandler::Throw(env, UNKNOWN_ERR); return nullptr; } -- Gitee