15bebb993Sopenharmony_ci/*
25bebb993Sopenharmony_ci * Copyright (c) 2024 Huawei Device Co., Ltd.
35bebb993Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
45bebb993Sopenharmony_ci * you may not use this file except in compliance with the License.
55bebb993Sopenharmony_ci * You may obtain a copy of the License at
65bebb993Sopenharmony_ci *
75bebb993Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
85bebb993Sopenharmony_ci *
95bebb993Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
105bebb993Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
115bebb993Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
125bebb993Sopenharmony_ci * See the License for the specific language governing permissions and
135bebb993Sopenharmony_ci * limitations under the License.
145bebb993Sopenharmony_ci */
155bebb993Sopenharmony_ci
165bebb993Sopenharmony_cideclare function requireNapi(napiModuleName: string): any;
175bebb993Sopenharmony_ciconst stream = requireNapi('util.stream');
185bebb993Sopenharmony_ciconst fileIo = requireNapi('file.fs');
195bebb993Sopenharmony_ci
205bebb993Sopenharmony_ciinterface ReadStreamOptions {
215bebb993Sopenharmony_ci    start?: number;
225bebb993Sopenharmony_ci    end?: number;
235bebb993Sopenharmony_ci}
245bebb993Sopenharmony_ci
255bebb993Sopenharmony_ciinterface WriteStreamOptions {
265bebb993Sopenharmony_ci    start?: number;
275bebb993Sopenharmony_ci    mode?: number;
285bebb993Sopenharmony_ci}
295bebb993Sopenharmony_ci
305bebb993Sopenharmony_ciclass ReadStream extends stream.Readable {
315bebb993Sopenharmony_ci    private pathInner: string;
325bebb993Sopenharmony_ci    private bytesReadInner: number;
335bebb993Sopenharmony_ci    private offset: number;
345bebb993Sopenharmony_ci    private start?: number;
355bebb993Sopenharmony_ci    private end?: number;
365bebb993Sopenharmony_ci    // @ts-ignore
375bebb993Sopenharmony_ci    private stream?: fileIo.Stream;
385bebb993Sopenharmony_ci
395bebb993Sopenharmony_ci    constructor(path: string, options?: ReadStreamOptions) {
405bebb993Sopenharmony_ci        super();
415bebb993Sopenharmony_ci        this.pathInner = path;
425bebb993Sopenharmony_ci        this.bytesReadInner = 0;
435bebb993Sopenharmony_ci        this.start = options?.start;
445bebb993Sopenharmony_ci        this.end = options?.end;
455bebb993Sopenharmony_ci        this.stream = fileIo.createStreamSync(this.pathInner, 'r');
465bebb993Sopenharmony_ci        this.offset = this.start ?? 0;
475bebb993Sopenharmony_ci    }
485bebb993Sopenharmony_ci
495bebb993Sopenharmony_ci    get path(): string {
505bebb993Sopenharmony_ci        return this.pathInner;
515bebb993Sopenharmony_ci    }
525bebb993Sopenharmony_ci
535bebb993Sopenharmony_ci    get bytesRead(): number {
545bebb993Sopenharmony_ci        return this.bytesReadInner;
555bebb993Sopenharmony_ci    }
565bebb993Sopenharmony_ci
575bebb993Sopenharmony_ci    // @ts-ignore
585bebb993Sopenharmony_ci    seek(offset: number, whence?: fileIo.WhenceType): number {
595bebb993Sopenharmony_ci        if (whence === undefined) {
605bebb993Sopenharmony_ci            this.offset = this.stream?.seek(offset);
615bebb993Sopenharmony_ci        } else {
625bebb993Sopenharmony_ci            this.offset = this.stream?.seek(offset, whence);
635bebb993Sopenharmony_ci        }
645bebb993Sopenharmony_ci        return this.offset;
655bebb993Sopenharmony_ci    }
665bebb993Sopenharmony_ci
675bebb993Sopenharmony_ci    close(): void {
685bebb993Sopenharmony_ci        this.stream?.close();
695bebb993Sopenharmony_ci    }
705bebb993Sopenharmony_ci
715bebb993Sopenharmony_ci    doInitialize(callback: Function): void {
725bebb993Sopenharmony_ci        callback();
735bebb993Sopenharmony_ci    }
745bebb993Sopenharmony_ci
755bebb993Sopenharmony_ci    doRead(size: number): void {
765bebb993Sopenharmony_ci        let readSize = size;
775bebb993Sopenharmony_ci        if (this.end !== undefined) {
785bebb993Sopenharmony_ci            if (this.offset > this.end) {
795bebb993Sopenharmony_ci                this.push(null);
805bebb993Sopenharmony_ci                return;
815bebb993Sopenharmony_ci            }
825bebb993Sopenharmony_ci            if (this.offset + readSize > this.end) {
835bebb993Sopenharmony_ci                readSize = this.end - this.offset;
845bebb993Sopenharmony_ci            }
855bebb993Sopenharmony_ci        }
865bebb993Sopenharmony_ci        let buffer = new ArrayBuffer(readSize);
875bebb993Sopenharmony_ci        const off = this.offset;
885bebb993Sopenharmony_ci        this.offset += readSize;
895bebb993Sopenharmony_ci        this.stream?.read(buffer, { offset: off, length: readSize })
905bebb993Sopenharmony_ci            .then((readOut: number) => {
915bebb993Sopenharmony_ci                if (readOut > 0) {
925bebb993Sopenharmony_ci                    this.bytesReadInner += readOut;
935bebb993Sopenharmony_ci                    this.push(new Uint8Array(buffer.slice(0, readOut)));
945bebb993Sopenharmony_ci                }
955bebb993Sopenharmony_ci                if (readOut !== readSize || readOut < size) {
965bebb993Sopenharmony_ci                    this.offset = this.offset - readSize + readOut;
975bebb993Sopenharmony_ci                    this.push(null);
985bebb993Sopenharmony_ci                }
995bebb993Sopenharmony_ci            });
1005bebb993Sopenharmony_ci    }
1015bebb993Sopenharmony_ci}
1025bebb993Sopenharmony_ci
1035bebb993Sopenharmony_ciclass WriteStream extends stream.Writable {
1045bebb993Sopenharmony_ci    private pathInner: string;
1055bebb993Sopenharmony_ci    private bytesWrittenInner: number;
1065bebb993Sopenharmony_ci    private offset: number;
1075bebb993Sopenharmony_ci    private mode: string;
1085bebb993Sopenharmony_ci    private start?: number;
1095bebb993Sopenharmony_ci    // @ts-ignore
1105bebb993Sopenharmony_ci    private stream?: fileIo.Stream;
1115bebb993Sopenharmony_ci
1125bebb993Sopenharmony_ci    constructor(path: string, options?: WriteStreamOptions) {
1135bebb993Sopenharmony_ci        super();
1145bebb993Sopenharmony_ci        this.pathInner = path;
1155bebb993Sopenharmony_ci        this.bytesWrittenInner = 0;
1165bebb993Sopenharmony_ci        this.start = options?.start;
1175bebb993Sopenharmony_ci        this.mode = this.convertOpenMode(options?.mode);
1185bebb993Sopenharmony_ci        this.stream = fileIo.createStreamSync(this.pathInner, this.mode);
1195bebb993Sopenharmony_ci        this.offset = this.start ?? 0;
1205bebb993Sopenharmony_ci    }
1215bebb993Sopenharmony_ci
1225bebb993Sopenharmony_ci    get path(): string {
1235bebb993Sopenharmony_ci        return this.pathInner;
1245bebb993Sopenharmony_ci    }
1255bebb993Sopenharmony_ci
1265bebb993Sopenharmony_ci    get bytesWritten(): number {
1275bebb993Sopenharmony_ci        return this.bytesWrittenInner;
1285bebb993Sopenharmony_ci    }
1295bebb993Sopenharmony_ci
1305bebb993Sopenharmony_ci    // @ts-ignore
1315bebb993Sopenharmony_ci    seek(offset: number, whence?: fileIo.WhenceType): number {
1325bebb993Sopenharmony_ci        if (whence === undefined) {
1335bebb993Sopenharmony_ci            this.offset = this.stream?.seek(offset);
1345bebb993Sopenharmony_ci        } else {
1355bebb993Sopenharmony_ci            this.offset = this.stream?.seek(offset, whence);
1365bebb993Sopenharmony_ci        }
1375bebb993Sopenharmony_ci        return this.offset;
1385bebb993Sopenharmony_ci    }
1395bebb993Sopenharmony_ci
1405bebb993Sopenharmony_ci    close(): void {
1415bebb993Sopenharmony_ci        this.stream?.close();
1425bebb993Sopenharmony_ci    }
1435bebb993Sopenharmony_ci
1445bebb993Sopenharmony_ci    doInitialize(callback: Function): void {
1455bebb993Sopenharmony_ci        callback();
1465bebb993Sopenharmony_ci    }
1475bebb993Sopenharmony_ci
1485bebb993Sopenharmony_ci    doWrite(chunk: string | Uint8Array, encoding: string, callback: Function): void {
1495bebb993Sopenharmony_ci        this.stream?.write(chunk, { offset: this.offset })
1505bebb993Sopenharmony_ci            .then((writeIn: number) => {
1515bebb993Sopenharmony_ci                this.offset += writeIn;
1525bebb993Sopenharmony_ci                this.bytesWrittenInner += writeIn;
1535bebb993Sopenharmony_ci                callback();
1545bebb993Sopenharmony_ci            })
1555bebb993Sopenharmony_ci            .finally(() => {
1565bebb993Sopenharmony_ci                this.stream?.flush();
1575bebb993Sopenharmony_ci            });
1585bebb993Sopenharmony_ci    }
1595bebb993Sopenharmony_ci
1605bebb993Sopenharmony_ci    convertOpenMode(mode?: number): string {
1615bebb993Sopenharmony_ci        let modeStr = 'w';
1625bebb993Sopenharmony_ci        if (mode === undefined) {
1635bebb993Sopenharmony_ci            return modeStr;
1645bebb993Sopenharmony_ci        }
1655bebb993Sopenharmony_ci        if (mode & fileIo.OpenMode.WRITE_ONLY) {
1665bebb993Sopenharmony_ci            modeStr = 'w';
1675bebb993Sopenharmony_ci        }
1685bebb993Sopenharmony_ci        if (mode & fileIo.OpenMode.READ_WRITE) {
1695bebb993Sopenharmony_ci            modeStr = 'w+';
1705bebb993Sopenharmony_ci        }
1715bebb993Sopenharmony_ci        if ((mode & fileIo.OpenMode.WRITE_ONLY) && (mode & fileIo.OpenMode.APPEND)) {
1725bebb993Sopenharmony_ci            modeStr = 'a';
1735bebb993Sopenharmony_ci        }
1745bebb993Sopenharmony_ci        if ((mode & fileIo.OpenMode.READ_WRITE) && (mode & fileIo.OpenMode.APPEND)) {
1755bebb993Sopenharmony_ci            modeStr = 'a+';
1765bebb993Sopenharmony_ci        }
1775bebb993Sopenharmony_ci        return modeStr;
1785bebb993Sopenharmony_ci    }
1795bebb993Sopenharmony_ci}
1805bebb993Sopenharmony_ci
1815bebb993Sopenharmony_ciexport default {
1825bebb993Sopenharmony_ci    ReadStream: ReadStream,
1835bebb993Sopenharmony_ci    WriteStream: WriteStream,
1845bebb993Sopenharmony_ci};
185