1/*
2 * Copyright (c) 2022-2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16import type { BrowserOperationInterface, CreateParam } from '../../../interface/BrowserOperationInterface';
17import { Log } from '../../../utils/Log';
18import type { FileAsset } from '../../../access/UserFileManagerAccess';
19import { Album, UserFileManagerAccess } from '../../../access/UserFileManagerAccess';
20import fileio from '@ohos.fileio';
21import { AlbumDefine } from '../AlbumDefine';
22import { StringUtil } from '../../../utils/StringUtil';
23import userFileManager from '@ohos.filemanagement.userFileManager';
24
25const TAG: string = 'common_OperationImpl';
26
27export class OperationImpl implements BrowserOperationInterface {
28  async favor(uri: string, isFavor: boolean): Promise<boolean> {
29    Log.info(TAG, `favor, id ${uri}`);
30    try {
31      let fileAsset = (await UserFileManagerAccess.getInstance().getFirstObject(AlbumDefine.getFileFetchOptByUri(uri))).obj
32      fileAsset.favorite(isFavor);
33      return true;
34    } catch (e) {
35      Log.error(TAG, `favor error ${e}`);
36      return false;
37    }
38  }
39
40  async delete(uris: Array<string>): Promise<void> {
41    await UserFileManagerAccess.getInstance().deleteToTrash(uris);
42  }
43
44  async deleteTrash(assets: Array<FileAsset>): Promise<void> {
45    await UserFileManagerAccess.getInstance().deleteFromTrash(assets);
46  }
47
48  async recoverFromTrash(assets: Array<FileAsset>): Promise<void> {
49    await UserFileManagerAccess.getInstance().recoverFromTrash(assets);
50  }
51
52  async copy(source: FileAsset, target: FileAsset): Promise<void> {
53    Log.info(TAG, `copy start: src:${source.uri} target: ${target.uri}`);
54
55    let fd = await UserFileManagerAccess.getInstance().openAsset('R', source);
56    if (fd <= 0) {
57      throw 'fd is invalid'
58      return;
59    }
60
61    let targetFd = await UserFileManagerAccess.getInstance().openAsset('RW', target);
62    if (targetFd <= 0) {
63      throw 'targetFd is invalid'
64      return;
65    }
66
67    await this.readAndWriteData(fd, targetFd);
68
69    await source.close(fd);
70    await target.close(targetFd);
71
72    Log.debug(TAG, 'copy end')
73  }
74
75  async trash(uris: Array<string>): Promise<void> {
76    Log.debug(TAG, `trash start ${JSON.stringify(uris)}`);
77    await UserFileManagerAccess.getInstance().deleteToTrash(uris);
78  }
79
80  async remove(uris: Array<string>, albumUri: string): Promise<void> {
81    Log.debug(TAG, `remove start ${JSON.stringify(uris)} from ${JSON.stringify(albumUri)}`);
82    let album: Album = await UserFileManagerAccess.getInstance().getAlbumByUri(albumUri);
83    if (album) {
84      let fileAssets: Array<FileAsset> = new Array<FileAsset>();
85      for (let i = 0; i < uris.length; i++) {
86        let fileAsset = (await UserFileManagerAccess.getInstance().getFirstObject(AlbumDefine.getFileFetchOptByUri(uris[i]))).obj;
87        if (fileAsset) {
88          fileAssets.push(fileAsset);
89        }
90      }
91      if (fileAssets.length > 0) {
92        await album.removePhotoAssets(fileAssets);
93      }
94    }
95    Log.debug(TAG, `remove end`);
96  }
97
98  async create(param: CreateParam): Promise<FileAsset> {
99    return await UserFileManagerAccess.getInstance().createAsset(param.fileType, param.name);
100  }
101
102  async change(file: FileAsset): Promise<void> {
103    await file.commitModify();
104  }
105
106  setName(source: FileAsset, name: string): void {
107    let displayName = source.displayName;
108    let index = displayName.lastIndexOf('.');
109    displayName = name + displayName.slice(index);
110    source.displayName = displayName;
111    source.set(userFileManager.ImageVideoKey.TITLE.toString(), name);
112    Log.info(TAG, `setName title: ${name}, displayName: ${displayName}`);
113  }
114
115  async readAndWriteData(srcFd: number, targetFd: number) {
116    Log.debug(TAG, 'readAndWriteData start!')
117    let stat = await fileio.fstat(srcFd);
118    Log.debug(TAG, `readAndWriteData read stat.size ${stat.size}`)
119    if (stat.size == 0) {
120      return;
121    }
122    let step = 10000000;
123    let last = stat.size % step;
124    let count = (stat.size - last) / step;
125    if (last > 0) {
126      count = count + 1;
127    }
128    Log.debug(TAG, `readAndWriteData read count ${count} last ${last}`)
129
130    for (let i = 0; i < count; i++) {
131      let rwSize = 0;
132      if (i == (count - 1)) {
133        rwSize = last;
134      } else {
135        rwSize = step;
136      }
137      let buf = new ArrayBuffer(rwSize);
138      let readOptions = {
139        offset: 0,
140        length: rwSize,
141        position: i * step
142      }
143      await fileio.read(srcFd, buf, readOptions);
144      let writeOptions = {
145        offset: 0,
146        length: rwSize,
147        position: i * step,
148        encoding: 'utf-8'
149      }
150      await fileio.write(targetFd, buf, writeOptions);
151    }
152    Log.debug(TAG, 'readAndWriteData end!')
153  }
154}