• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (C) 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16import JSZip from 'jszip';
17import {FunctionUtils, OnProgressUpdateType} from './function_utils';
18
19export type OnFile = (file: File, parentArchive: File | undefined) => void;
20
21class FileUtils {
22  static getFileExtension(file: File) {
23    const split = file.name.split('.');
24    if (split.length > 1) {
25      return split.pop();
26    }
27    return undefined;
28  }
29
30  static removeDirFromFileName(name: string) {
31    if (name.includes('/')) {
32      const startIndex = name.lastIndexOf('/') + 1;
33      return name.slice(startIndex);
34    } else {
35      return name;
36    }
37  }
38
39  static async createZipArchive(files: File[]): Promise<Blob> {
40    const zip = new JSZip();
41    for (let i = 0; i < files.length; i++) {
42      const file = files[i];
43      const blob = await file.arrayBuffer();
44      zip.file(file.name, blob);
45    }
46    return await zip.generateAsync({type: 'blob'});
47  }
48
49  static async unzipFile(
50    file: File,
51    onProgressUpdate: OnProgressUpdateType = FunctionUtils.DO_NOTHING
52  ): Promise<File[]> {
53    const unzippedFiles: File[] = [];
54    const zip = new JSZip();
55    const content = await zip.loadAsync(file);
56
57    const filenames = Object.keys(content.files);
58    for (const [index, filename] of filenames.entries()) {
59      const file = content.files[filename];
60      if (file.dir) {
61        // Ignore directories
62        continue;
63      } else {
64        const fileBlob = await file.async('blob');
65        const unzippedFile = new File([fileBlob], filename);
66        unzippedFiles.push(unzippedFile);
67      }
68
69      onProgressUpdate((100 * (index + 1)) / filenames.length);
70    }
71
72    return unzippedFiles;
73  }
74
75  static async unzipFilesIfNeeded(
76    files: File[],
77    onFile: OnFile,
78    onProgressUpdate: OnProgressUpdateType = FunctionUtils.DO_NOTHING
79  ) {
80    for (let i = 0; i < files.length; i++) {
81      const file = files[i];
82
83      const onSubprogressUpdate = (subPercentage: number) => {
84        const percentage = (100 * i) / files.length + subPercentage / files.length;
85        onProgressUpdate(percentage);
86      };
87
88      if (FileUtils.isZipFile(file)) {
89        const unzippedFile = await FileUtils.unzipFile(file, onSubprogressUpdate);
90        unzippedFile.forEach((unzippedFile) => onFile(unzippedFile, file));
91      } else {
92        onFile(file, undefined);
93      }
94    }
95  }
96
97  static isZipFile(file: File) {
98    return FileUtils.getFileExtension(file) === 'zip';
99  }
100}
101
102export {FileUtils};
103