diff --git a/ui-ngx/src/app/core/utils.ts b/ui-ngx/src/app/core/utils.ts index 7f13f08ba6..17458c908a 100644 --- a/ui-ngx/src/app/core/utils.ts +++ b/ui-ngx/src/app/core/utils.ts @@ -226,8 +226,24 @@ export function objToBase64(obj: any): string { })); } +const textDecoderUtf8 = new TextDecoder('UTF-8', { fatal: true }); +const textDecoderLatin1 = new TextDecoder('ISO-8859-1'); + +export function bytesToString(bytes: Uint8Array): string { + try { + return textDecoderUtf8.decode(bytes); + } catch { + return textDecoderLatin1.decode(bytes); + } +} + export function base64toString(b64Encoded: string): string { - return decodeURIComponent(atob(b64Encoded).split('').map((c) => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)).join('')); + const binary = atob(b64Encoded); + const bytes = new Uint8Array(binary.length); + for (let i = 0; i < binary.length; i++) { + bytes[i] = binary.charCodeAt(i); + } + return bytesToString(bytes); } export function objToBase64URI(obj: any): string { @@ -235,8 +251,7 @@ export function objToBase64URI(obj: any): string { } export function base64toObj(b64Encoded: string): any { - const json = decodeURIComponent(atob(b64Encoded).split('').map((c) => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)).join('')); - return JSON.parse(json); + return JSON.parse(base64toString(b64Encoded)); } export function stringToBase64(value: string): string { diff --git a/ui-ngx/src/app/shared/components/file-input.component.ts b/ui-ngx/src/app/shared/components/file-input.component.ts index 727b1628dc..d9f891c7f4 100644 --- a/ui-ngx/src/app/shared/components/file-input.component.ts +++ b/ui-ngx/src/app/shared/components/file-input.component.ts @@ -38,6 +38,7 @@ import { UtilsService } from '@core/services/utils.service'; import { DialogService } from '@core/services/dialog.service'; import { FileSizePipe } from '@shared/pipe/file-size.pipe'; import { coerceBoolean } from '@shared/decorators/coercion'; +import { bytesToString } from '@core/utils'; @Component({ selector: 'tb-file-input', @@ -216,34 +217,39 @@ export class FileInputComponent extends PageComponent implements AfterViewInit, return; } - const reader = new FileReader(); - reader.onload = () => { - let fileName = null; - let fileContent = null; - let mediaType = null; - if (reader.readyState === reader.DONE) { - fileContent = reader.result; - if (fileContent && fileContent.length > 0) { - if (this.contentConvertFunction) { - fileContent = this.contentConvertFunction(fileContent); - } - fileName = fileContent ? file.name : null; - mediaType = file?.file?.type || null; - } - } - resolve({fileContent, fileName, files: null, mediaType}); - }; - reader.onerror = () => { - resolve({fileContent: null, fileName: null, files: null, mediaType: null}); - }; + const onReadError = () => resolve({fileContent: null, fileName: null, files: null, mediaType: null}); + if (this.readAsBinary) { + const reader = new FileReader(); + reader.onload = () => { + const content = reader.readyState === reader.DONE ? reader.result : null; + resolve(this.buildResult(file, content)); + }; + reader.onerror = onReadError; reader.readAsBinaryString(file.file); } else { - reader.readAsText(file.file); + file.file.arrayBuffer().then( + buf => resolve(this.buildResult(file, bytesToString(new Uint8Array(buf)))), + onReadError + ); } }); } + private buildResult(file: flowjs.FlowFile, content: string | ArrayBuffer): any { + let fileContent: any = content; + let fileName = null; + let mediaType = null; + if (fileContent && fileContent.length > 0) { + if (this.contentConvertFunction) { + fileContent = this.contentConvertFunction(fileContent); + } + fileName = fileContent ? file.name : null; + mediaType = file?.file?.type || null; + } + return {fileContent, fileName, files: null, mediaType}; + } + private checkMaxSize(file: flowjs.FlowFile): boolean { return !this.maxSizeByte || file.size <= this.maxSizeByte; }