blob: be3bbde28e7e44a11f70428885a25e87ce73e36f [file] [log] [blame]
Blink Reformat4c46d092018-04-07 15:32:371/*
2 * Copyright (C) 2012 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
Paul Irishd890ac82025-07-16 19:49:2431import * as Common from '../../core/common/common.js';
Kateryna Prokopenko380fdfa2022-03-16 16:39:3232import type * as Platform from '../../core/platform/platform.js';
Benedikt Meurer00488942025-06-17 17:52:2533import * as TextUtils from '../text_utils/text_utils.js';
Tim van der Lippe99aeaf32021-04-09 10:33:3434import * as Workspace from '../workspace/workspace.js';
Tim van der Lippe55cd4ef2020-01-23 17:31:3935
Jan Scheffler2c9d5c32021-02-26 16:51:5636export interface ChunkedReader {
37 fileSize(): number;
Blink Reformat4c46d092018-04-07 15:32:3738
Jan Scheffler2c9d5c32021-02-26 16:51:5639 loadedSize(): number;
Blink Reformat4c46d092018-04-07 15:32:3740
Jan Scheffler2c9d5c32021-02-26 16:51:5641 fileName(): string;
Blink Reformat4c46d092018-04-07 15:32:3742
Jan Scheffler2c9d5c32021-02-26 16:51:5643 cancel(): void;
Blink Reformat4c46d092018-04-07 15:32:3744
Jan Scheffler2c9d5c32021-02-26 16:51:5645 error(): DOMError|null;
Tim van der Lippe07232042019-10-08 15:58:0746}
Blink Reformat4c46d092018-04-07 15:32:3747
Jan Scheffler2c9d5c32021-02-26 16:51:5648export class ChunkedFileReader implements ChunkedReader {
Tim van der Lippe113abec2021-10-12 11:30:3649 #file: File|null;
50 readonly #fileSizeInternal: number;
51 #loadedSizeInternal: number;
Nikolay Vitkov17794ee2025-01-29 20:26:2752 #streamReader: ReadableStreamDefaultReader<Uint8Array<ArrayBuffer>>|null;
Tim van der Lippe113abec2021-10-12 11:30:3653 readonly #chunkSize: number;
54 readonly #chunkTransferredCallback: ((arg0: ChunkedReader) => void)|undefined;
55 readonly #decoder: TextDecoder;
56 #isCanceled: boolean;
57 #errorInternal: DOMException|null;
58 #transferFinished!: (arg0: boolean) => void;
59 #output?: Common.StringOutputStream.OutputStream;
60 #reader?: FileReader|null;
Jan Scheffler2c9d5c32021-02-26 16:51:5661
Alina Varkki2fc2ce82024-03-22 10:49:3162 constructor(file: File, chunkSize?: number, chunkTransferredCallback?: ((arg0: ChunkedReader) => void)) {
Tim van der Lippe113abec2021-10-12 11:30:3663 this.#file = file;
64 this.#fileSizeInternal = file.size;
65 this.#loadedSizeInternal = 0;
Alina Varkki2fc2ce82024-03-22 10:49:3166 this.#chunkSize = (chunkSize) ? chunkSize : Number.MAX_VALUE;
Tim van der Lippe113abec2021-10-12 11:30:3667 this.#chunkTransferredCallback = chunkTransferredCallback;
68 this.#decoder = new TextDecoder();
69 this.#isCanceled = false;
70 this.#errorInternal = null;
71 this.#streamReader = null;
Blink Reformat4c46d092018-04-07 15:32:3772 }
73
Paul Irishfe3cbe62021-04-13 20:51:1974 async read(output: Common.StringOutputStream.OutputStream): Promise<boolean> {
Tim van der Lippe113abec2021-10-12 11:30:3675 if (this.#chunkTransferredCallback) {
76 this.#chunkTransferredCallback(this);
Tim van der Lippe1d6e57a2019-09-30 11:55:3477 }
Paul Irishfe3cbe62021-04-13 20:51:1978
Tim van der Lippe113abec2021-10-12 11:30:3679 if (this.#file?.type.endsWith('gzip')) {
Paul Irishd890ac82025-07-16 19:49:2480 const fileStream = this.#file.stream();
81 const stream = Common.Gzip.decompressStream(fileStream);
Tim van der Lippe113abec2021-10-12 11:30:3682 this.#streamReader = stream.getReader();
Paul Irishfe3cbe62021-04-13 20:51:1983 } else {
Tim van der Lippe113abec2021-10-12 11:30:3684 this.#reader = new FileReader();
85 this.#reader.onload = this.onChunkLoaded.bind(this);
86 this.#reader.onerror = this.onError.bind(this);
Paul Irishfe3cbe62021-04-13 20:51:1987 }
88
Tim van der Lippe113abec2021-10-12 11:30:3689 this.#output = output;
Tim van der Lippe2d9a95c2022-01-04 15:18:0390 void this.loadChunk();
Jan Scheffler2c9d5c32021-02-26 16:51:5691
Nikolay Vitkovd36860c2025-02-19 17:50:2792 return await new Promise(resolve => {
Tim van der Lippe113abec2021-10-12 11:30:3693 this.#transferFinished = resolve;
Patrick Brossete65aaac2020-06-22 08:04:4094 });
Blink Reformat4c46d092018-04-07 15:32:3795 }
96
Jan Scheffler2c9d5c32021-02-26 16:51:5697 cancel(): void {
Tim van der Lippe113abec2021-10-12 11:30:3698 this.#isCanceled = true;
Blink Reformat4c46d092018-04-07 15:32:3799 }
100
Jan Scheffler2c9d5c32021-02-26 16:51:56101 loadedSize(): number {
Tim van der Lippe113abec2021-10-12 11:30:36102 return this.#loadedSizeInternal;
Blink Reformat4c46d092018-04-07 15:32:37103 }
104
Jan Scheffler2c9d5c32021-02-26 16:51:56105 fileSize(): number {
Tim van der Lippe113abec2021-10-12 11:30:36106 return this.#fileSizeInternal;
Blink Reformat4c46d092018-04-07 15:32:37107 }
108
Jan Scheffler2c9d5c32021-02-26 16:51:56109 fileName(): string {
Tim van der Lippe113abec2021-10-12 11:30:36110 if (!this.#file) {
Tim van der Lipped0bc66a2020-08-26 15:02:14111 return '';
112 }
Tim van der Lippe113abec2021-10-12 11:30:36113 return this.#file.name;
Blink Reformat4c46d092018-04-07 15:32:37114 }
115
Sigurd Schneider576ca9a2021-07-16 05:58:04116 error(): DOMException|null {
Tim van der Lippe113abec2021-10-12 11:30:36117 return this.#errorInternal;
Blink Reformat4c46d092018-04-07 15:32:37118 }
119
Jan Scheffler085122e2021-08-07 08:04:40120 private onChunkLoaded(event: Event): void {
Tim van der Lippe113abec2021-10-12 11:30:36121 if (this.#isCanceled) {
Blink Reformat4c46d092018-04-07 15:32:37122 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34123 }
Blink Reformat4c46d092018-04-07 15:32:37124
Jan Scheffler2c9d5c32021-02-26 16:51:56125 const eventTarget = (event.target as FileReader);
Tim van der Lipped0bc66a2020-08-26 15:02:14126 if (eventTarget.readyState !== FileReader.DONE) {
Blink Reformat4c46d092018-04-07 15:32:37127 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34128 }
Blink Reformat4c46d092018-04-07 15:32:37129
Tim van der Lippe113abec2021-10-12 11:30:36130 if (!this.#reader) {
Tim van der Lipped0bc66a2020-08-26 15:02:14131 return;
132 }
133
Tim van der Lippe113abec2021-10-12 11:30:36134 const buffer = (this.#reader.result as ArrayBuffer);
135 this.#loadedSizeInternal += buffer.byteLength;
136 const endOfFile = this.#loadedSizeInternal === this.#fileSizeInternal;
Tim van der Lippe2d9a95c2022-01-04 15:18:03137 void this.decodeChunkBuffer(buffer, endOfFile);
Paul Irishfe3cbe62021-04-13 20:51:19138 }
139
Jan Scheffler085122e2021-08-07 08:04:40140 private async decodeChunkBuffer(buffer: ArrayBuffer, endOfFile: boolean): Promise<void> {
Tim van der Lippe113abec2021-10-12 11:30:36141 if (!this.#output) {
Paul Irishfe3cbe62021-04-13 20:51:19142 return;
143 }
Tim van der Lippe113abec2021-10-12 11:30:36144 const decodedString = this.#decoder.decode(buffer, {stream: !endOfFile});
Alina Varkki2fc2ce82024-03-22 10:49:31145 await this.#output.write(decodedString, endOfFile);
Tim van der Lippe113abec2021-10-12 11:30:36146 if (this.#isCanceled) {
Blink Reformat4c46d092018-04-07 15:32:37147 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34148 }
Tim van der Lippe113abec2021-10-12 11:30:36149 if (this.#chunkTransferredCallback) {
150 this.#chunkTransferredCallback(this);
Tim van der Lippe1d6e57a2019-09-30 11:55:34151 }
Blink Reformat4c46d092018-04-07 15:32:37152
153 if (endOfFile) {
Andrés Olivares435b3eb2022-10-17 11:46:39154 void this.finishRead();
Blink Reformat4c46d092018-04-07 15:32:37155 return;
156 }
Tim van der Lippe2d9a95c2022-01-04 15:18:03157 void this.loadChunk();
Blink Reformat4c46d092018-04-07 15:32:37158 }
159
Andrés Olivares435b3eb2022-10-17 11:46:39160 private async finishRead(): Promise<void> {
Tim van der Lippe113abec2021-10-12 11:30:36161 if (!this.#output) {
Tim van der Lipped0bc66a2020-08-26 15:02:14162 return;
163 }
Tim van der Lippe113abec2021-10-12 11:30:36164 this.#file = null;
165 this.#reader = null;
Andrés Olivares435b3eb2022-10-17 11:46:39166 await this.#output.close();
Tim van der Lippe113abec2021-10-12 11:30:36167 this.#transferFinished(!this.#errorInternal);
Paul Irishfe3cbe62021-04-13 20:51:19168 }
169
Jan Scheffler085122e2021-08-07 08:04:40170 private async loadChunk(): Promise<void> {
Tim van der Lippe113abec2021-10-12 11:30:36171 if (!this.#output || !this.#file) {
Paul Irishfe3cbe62021-04-13 20:51:19172 return;
173 }
Tim van der Lippe113abec2021-10-12 11:30:36174 if (this.#streamReader) {
175 const {value, done} = await this.#streamReader.read();
Paul Irishfe3cbe62021-04-13 20:51:19176 if (done || !value) {
Alina Varkki2fc2ce82024-03-22 10:49:31177 // Write empty string to inform of file end
178 await this.#output.write('', true);
Nikolay Vitkovd36860c2025-02-19 17:50:27179 return await this.finishRead();
Paul Irishfe3cbe62021-04-13 20:51:19180 }
Tim van der Lippe2d9a95c2022-01-04 15:18:03181 void this.decodeChunkBuffer(value.buffer, false);
Paul Irishfe3cbe62021-04-13 20:51:19182 }
Tim van der Lippe113abec2021-10-12 11:30:36183 if (this.#reader) {
184 const chunkStart = this.#loadedSizeInternal;
185 const chunkEnd = Math.min(this.#fileSizeInternal, chunkStart + this.#chunkSize);
186 const nextPart = this.#file.slice(chunkStart, chunkEnd);
187 this.#reader.readAsArrayBuffer(nextPart);
Paul Irishfe3cbe62021-04-13 20:51:19188 }
Blink Reformat4c46d092018-04-07 15:32:37189 }
190
Jan Scheffler085122e2021-08-07 08:04:40191 private onError(event: Event): void {
Jan Scheffler2c9d5c32021-02-26 16:51:56192 const eventTarget = (event.target as FileReader);
Tim van der Lippe113abec2021-10-12 11:30:36193 this.#errorInternal = eventTarget.error;
194 this.#transferFinished(false);
Blink Reformat4c46d092018-04-07 15:32:37195 }
Tim van der Lippe07232042019-10-08 15:58:07196}
Blink Reformat4c46d092018-04-07 15:32:37197
Jan Scheffler2c9d5c32021-02-26 16:51:56198export class FileOutputStream implements Common.StringOutputStream.OutputStream {
Benedikt Meurer84b0fcc2025-02-12 13:57:23199 #writeCallbacks: Array<() => void>;
Kateryna Prokopenko380fdfa2022-03-16 16:39:32200 #fileName!: Platform.DevToolsPath.RawPathString|Platform.DevToolsPath.UrlString;
Tim van der Lippe113abec2021-10-12 11:30:36201 #closed?: boolean;
Tim van der Lipped0bc66a2020-08-26 15:02:14202 constructor() {
Tim van der Lippe113abec2021-10-12 11:30:36203 this.#writeCallbacks = [];
Tim van der Lipped0bc66a2020-08-26 15:02:14204 }
205
Kateryna Prokopenko380fdfa2022-03-16 16:39:32206 async open(fileName: Platform.DevToolsPath.RawPathString|Platform.DevToolsPath.UrlString): Promise<boolean> {
Tim van der Lippe113abec2021-10-12 11:30:36207 this.#closed = false;
Tim van der Lippe113abec2021-10-12 11:30:36208 this.#writeCallbacks = [];
209 this.#fileName = fileName;
Benedikt Meurer00488942025-06-17 17:52:25210 const saveResponse = await Workspace.FileManager.FileManager.instance().save(
211 this.#fileName, TextUtils.ContentData.EMPTY_TEXT_CONTENT_DATA, /* forceSaveAs=*/ true);
Tim van der Lippe1d6e57a2019-09-30 11:55:34212 if (saveResponse) {
Tim van der Lippe696c9262020-08-26 14:39:32213 Workspace.FileManager.FileManager.instance().addEventListener(
Benedikt Meurerb328d472024-08-23 13:41:15214 Workspace.FileManager.Events.APPENDED_TO_URL, this.onAppendDone, this);
Tim van der Lippe1d6e57a2019-09-30 11:55:34215 }
Tim van der Lippeba0e6452021-01-07 13:46:34216 return Boolean(saveResponse);
Blink Reformat4c46d092018-04-07 15:32:37217 }
218
Jan Scheffler2c9d5c32021-02-26 16:51:56219 write(data: string): Promise<void> {
Blink Reformat4c46d092018-04-07 15:32:37220 return new Promise(resolve => {
Tim van der Lippe113abec2021-10-12 11:30:36221 this.#writeCallbacks.push(resolve);
222 Workspace.FileManager.FileManager.instance().append(this.#fileName, data);
Blink Reformat4c46d092018-04-07 15:32:37223 });
224 }
225
Jan Scheffler2c9d5c32021-02-26 16:51:56226 async close(): Promise<void> {
Tim van der Lippe113abec2021-10-12 11:30:36227 this.#closed = true;
228 if (this.#writeCallbacks.length) {
Blink Reformat4c46d092018-04-07 15:32:37229 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34230 }
Tim van der Lippe696c9262020-08-26 14:39:32231 Workspace.FileManager.FileManager.instance().removeEventListener(
Benedikt Meurerb328d472024-08-23 13:41:15232 Workspace.FileManager.Events.APPENDED_TO_URL, this.onAppendDone, this);
Tim van der Lippe113abec2021-10-12 11:30:36233 Workspace.FileManager.FileManager.instance().close(this.#fileName);
Blink Reformat4c46d092018-04-07 15:32:37234 }
235
Kateryna Prokopenko15476322021-08-09 13:15:18236 private onAppendDone(event: Common.EventTarget.EventTargetEvent<string>): void {
Tim van der Lippe113abec2021-10-12 11:30:36237 if (event.data !== this.#fileName) {
Blink Reformat4c46d092018-04-07 15:32:37238 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34239 }
Tim van der Lippe113abec2021-10-12 11:30:36240 const writeCallback = this.#writeCallbacks.shift();
Tim van der Lipped0bc66a2020-08-26 15:02:14241 if (writeCallback) {
242 writeCallback();
243 }
Tim van der Lippe113abec2021-10-12 11:30:36244 if (this.#writeCallbacks.length) {
Blink Reformat4c46d092018-04-07 15:32:37245 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34246 }
Tim van der Lippe113abec2021-10-12 11:30:36247 if (!this.#closed) {
Blink Reformat4c46d092018-04-07 15:32:37248 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34249 }
Tim van der Lippe696c9262020-08-26 14:39:32250 Workspace.FileManager.FileManager.instance().removeEventListener(
Benedikt Meurerb328d472024-08-23 13:41:15251 Workspace.FileManager.Events.APPENDED_TO_URL, this.onAppendDone, this);
Tim van der Lippe113abec2021-10-12 11:30:36252 Workspace.FileManager.FileManager.instance().close(this.#fileName);
Blink Reformat4c46d092018-04-07 15:32:37253 }
Tim van der Lippe07232042019-10-08 15:58:07254}