From 3f5eddb033c3e133e753606b8de9a20828fcd58b Mon Sep 17 00:00:00 2001 From: Akos Kitta Date: Wed, 22 Feb 2023 16:11:09 +0100 Subject: [PATCH] fix: encoding when reading a cloud sketch Closes #449 Closes #634 Signed-off-by: Akos Kitta --- .../src/browser/create/create-api.ts | 48 ++----------------- .../src/browser/create/create-fs-provider.ts | 3 +- arduino-ide-extension/src/common/utils.ts | 11 +++++ 3 files changed, 16 insertions(+), 46 deletions(-) diff --git a/arduino-ide-extension/src/browser/create/create-api.ts b/arduino-ide-extension/src/browser/create/create-api.ts index 536e7f4bc..4c988f5df 100644 --- a/arduino-ide-extension/src/browser/create/create-api.ts +++ b/arduino-ide-extension/src/browser/create/create-api.ts @@ -2,6 +2,7 @@ import { MaybePromise } from '@theia/core/lib/common/types'; import { inject, injectable } from '@theia/core/shared/inversify'; import { fetch } from 'cross-fetch'; import { SketchesService } from '../../common/protocol'; +import { unit8ArrayToString } from '../../common/utils'; import { ArduinoPreferences } from '../arduino-preferences'; import { AuthenticationClientService } from '../auth/authentication-client-service'; import { SketchCache } from '../widgets/cloud-sketchbook/cloud-sketch-cache'; @@ -19,49 +20,6 @@ export namespace ResponseResultProvider { export const JSON: ResponseResultProvider = (response) => response.json(); } -// TODO: check if this is still needed: https://github.com/electron/electron/issues/18733 -// The original issue was reported for Electron 5.x and 6.x. Theia uses 15.x -export function Utf8ArrayToStr(array: Uint8Array): string { - let out, i, c; - let char2, char3; - - out = ''; - const len = array.length; - i = 0; - while (i < len) { - c = array[i++]; - switch (c >> 4) { - case 0: - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - // 0xxxxxxx - out += String.fromCharCode(c); - break; - case 12: - case 13: - // 110x xxxx 10xx xxxx - char2 = array[i++]; - out += String.fromCharCode(((c & 0x1f) << 6) | (char2 & 0x3f)); - break; - case 14: - // 1110 xxxx 10xx xxxx 10xx xxxx - char2 = array[i++]; - char3 = array[i++]; - out += String.fromCharCode( - ((c & 0x0f) << 12) | ((char2 & 0x3f) << 6) | ((char3 & 0x3f) << 0) - ); - break; - } - } - - return out; -} - type ResourceType = 'f' | 'd'; @injectable() @@ -333,7 +291,7 @@ export class CreateApi { // parse the secret file const secrets = ( - typeof content === 'string' ? content : Utf8ArrayToStr(content) + typeof content === 'string' ? content : unit8ArrayToString(content) ) .split(/\r?\n/) .reduce((prev, curr) => { @@ -397,7 +355,7 @@ export class CreateApi { const headers = await this.headers(); let data: string = - typeof content === 'string' ? content : Utf8ArrayToStr(content); + typeof content === 'string' ? content : unit8ArrayToString(content); data = await this.toggleSecretsInclude(posixPath, data, 'remove'); const payload = { data: btoa(data) }; diff --git a/arduino-ide-extension/src/browser/create/create-fs-provider.ts b/arduino-ide-extension/src/browser/create/create-fs-provider.ts index 41ef5ab04..7908d0556 100644 --- a/arduino-ide-extension/src/browser/create/create-fs-provider.ts +++ b/arduino-ide-extension/src/browser/create/create-fs-provider.ts @@ -29,6 +29,7 @@ import { CreateUri } from './create-uri'; import { SketchesService } from '../../common/protocol'; import { ArduinoPreferences } from '../arduino-preferences'; import { Create } from './typings'; +import { stringToUint8Array } from '../../common/utils'; @injectable() export class CreateFsProvider @@ -154,7 +155,7 @@ export class CreateFsProvider async readFile(uri: URI): Promise { const content = await this.getCreateApi.readFile(uri.path.toString()); - return new TextEncoder().encode(content); + return stringToUint8Array(content); } async writeFile( diff --git a/arduino-ide-extension/src/common/utils.ts b/arduino-ide-extension/src/common/utils.ts index 3fbf98be9..994e02ec0 100644 --- a/arduino-ide-extension/src/common/utils.ts +++ b/arduino-ide-extension/src/common/utils.ts @@ -20,3 +20,14 @@ export function startsWithUpperCase(what: string): boolean { export function isNullOrUndefined(what: unknown): what is undefined | null { return what === undefined || what === null; } + +// Text encoder can crash in electron browser: https://github.com/arduino/arduino-ide/issues/634#issuecomment-1440039171 +export function unit8ArrayToString(uint8Array: Uint8Array): string { + return uint8Array.reduce( + (text, byte) => text + String.fromCharCode(byte), + '' + ); +} +export function stringToUint8Array(text: string): Uint8Array { + return Uint8Array.from(text, (char) => char.charCodeAt(0)); +}