Skip to content

Commit 4b6ad3c

Browse files
committed
fix(ohos): 修复大于 2MB 图片在 Node-API 传输失败的问题
OpenHarmony Node-API 实现中,napi_create_buffer/napi_create_external_buffer 存在大于 2097152 字节(2MB)返回 napi_invalid_arg 的硬性限制。此前 read_part 和 read_part_async 返回 Buffer 类型,导致超过 2MB 的高清图片在跨语言调用阶段 直接报错被 ImageStore 吞掉返回 null。 改用 sys::napi_create_arraybuffer 直接在 JS 堆中分配 ArrayBuffer, 不受 2MB 外部 Buffer 大小限制,并补充超 2MB 切片读取单元测试。 Signed-off-by: donglua <dongluh@gmail.com>
1 parent bcf14ed commit 4b6ad3c

3 files changed

Lines changed: 46 additions & 13 deletions

File tree

‎core/tests/package_cache.rs‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,16 @@ fn read_part_enforces_media_part_limit() -> TestResult {
9090
Ok(())
9191
}
9292

93+
#[test]
94+
fn read_part_succeeds_for_large_media_over_two_mib() -> TestResult {
95+
// 3 MiB entry (simulating high-res image like image8.png which exceeds OpenHarmony Node-API 2 MiB Buffer threshold)
96+
let archive = TempArchive::new_deflated_padded("image_3mb.png", 3 * 1024 * 1024)?;
97+
98+
let result = read_part(&archive.path, "image_3mb.png")?;
99+
assert_eq!(result.len(), 3 * 1024 * 1024);
100+
Ok(())
101+
}
102+
93103
#[test]
94104
fn read_part_limited_allows_custom_limit() -> TestResult {
95105
let archive = TempArchive::new(&[("small.bin", b"0123456789")])?;

‎viewer-ohos/native/src/lib.rs‎

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,38 @@ fn parse_path_to_json(path: &str) -> Result<String> {
2121
}
2222
}
2323

24-
fn read_zip_part(path: &str, part: &str) -> Result<Buffer> {
24+
fn create_arraybuffer_from_vec(env: &Env, data: Vec<u8>) -> Result<ArrayBuffer<'static>> {
25+
let mut raw_value = std::ptr::null_mut();
26+
let mut data_ptr = std::ptr::null_mut();
27+
let len = data.len();
28+
let status = unsafe {
29+
napi_ohos::sys::napi_create_arraybuffer(
30+
env.raw(),
31+
len,
32+
&mut data_ptr,
33+
&mut raw_value,
34+
)
35+
};
36+
if status != napi_ohos::sys::Status::napi_ok {
37+
return Err(Error::from_status(Status::from(status)));
38+
}
39+
if !data_ptr.is_null() && len > 0 {
40+
unsafe {
41+
std::ptr::copy_nonoverlapping(data.as_ptr(), data_ptr.cast(), len);
42+
}
43+
}
44+
unsafe { ArrayBuffer::from_napi_value(env.raw(), raw_value) }
45+
}
46+
47+
fn read_zip_part_bytes(path: &str, part: &str) -> Result<Vec<u8>> {
2548
let result = catch_unwind(AssertUnwindSafe(
2649
|| -> std::result::Result<Vec<u8>, String> {
2750
jz_office_core::read_part(Path::new(path), part).map_err(|e| e.to_string())
2851
},
2952
));
3053

3154
match result {
32-
Ok(Ok(data)) => Ok(Buffer::from(data)),
55+
Ok(Ok(data)) => Ok(data),
3356
Ok(Err(error)) => Err(Error::from_reason(error)),
3457
Err(_) => Err(Error::from_reason(
3558
"Failed to read document part".to_owned(),
@@ -77,15 +100,15 @@ pub struct ReadPartTask {
77100

78101
#[napi]
79102
impl Task for ReadPartTask {
80-
type Output = Buffer;
81-
type JsValue = Buffer;
103+
type Output = Vec<u8>;
104+
type JsValue = ArrayBuffer<'static>;
82105

83106
fn compute(&mut self) -> Result<Self::Output> {
84-
read_zip_part(&self.path, &self.part)
107+
read_zip_part_bytes(&self.path, &self.part)
85108
}
86109

87-
fn resolve(&mut self, _env: Env, output: Self::Output) -> Result<Self::JsValue> {
88-
Ok(output)
110+
fn resolve(&mut self, env: Env, output: Self::Output) -> Result<Self::JsValue> {
111+
create_arraybuffer_from_vec(&env, output)
89112
}
90113
}
91114

@@ -101,8 +124,9 @@ pub fn read_part_async(
101124

102125
/// 同步读取文档 ZIP 包内指定部件字节流
103126
#[napi]
104-
pub fn read_part(path: String, part: String) -> Result<Buffer> {
105-
read_zip_part(&path, &part)
127+
pub fn read_part(env: Env, path: String, part: String) -> Result<ArrayBuffer<'static>> {
128+
let bytes = read_zip_part_bytes(&path, &part)?;
129+
create_arraybuffer_from_vec(&env, bytes)
106130
}
107131

108132
/// 清除当前缓存的所有文档包及 ZIP 索引句柄

‎viewer-ohos/src/main/cpp/types/libjz_office_ohos/index.d.ts‎

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ export class AbortSignal {
3939
}
4040

4141

42+
/** 清除当前缓存的所有文档包及 ZIP 索引句柄 */
43+
export declare function clearCache(): void
44+
4245
/** 同步解析接口(对齐 Android NativeCore.parse) */
4346
export declare function parse(path: string): string
4447

@@ -51,7 +54,3 @@ export declare function readPart(path: string, part: string): ArrayBuffer
5154
/** 异步读取文档 ZIP 包内指定部件字节流(用于按需加载内嵌图片) */
5255
export declare function readPartAsync(path: string, part: string, abortSignal?: AbortSignal | undefined | null): Promise<ArrayBuffer>
5356

54-
/** 清除当前缓存的所有文档包及 ZIP 索引句柄 */
55-
export declare function clearCache(): void
56-
57-

0 commit comments

Comments
 (0)