blob: e6ae314036d7ca9f39cb2ba47a58e1831c812b64 [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
export class BinaryResourceViewFactory {
/**
* @param {string} base64content
* @param {string} contentUrl
* @param {!Common.ResourceType} resourceType
*/
constructor(base64content, contentUrl, resourceType) {
this._base64content = base64content;
this._contentUrl = contentUrl;
this._resourceType = resourceType;
/** @type {?Promise<!Uint8Array>} */
this._arrayPromise = null;
/** @type {?Promise<string>} */
this._hexPromise = null;
/** @type {?Promise<!Common.DeferredContent>} */
this._utf8Promise = null;
}
async _fetchContentAsArray() {
if (!this._arrayPromise) {
this._arrayPromise = new Promise(async resolve => {
const fetchResponse = await fetch('data:;base64,' + this._base64content);
resolve(new Uint8Array(await fetchResponse.arrayBuffer()));
});
}
return await this._arrayPromise;
}
/**
* @return {!Promise<!Common.DeferredContent>}
*/
async hex() {
if (!this._hexPromise) {
this._hexPromise = new Promise(async resolve => {
const content = await this._fetchContentAsArray();
const hexString = BinaryResourceViewFactory.uint8ArrayToHexString(content);
resolve({content: hexString, isEncoded: false});
});
}
return this._hexPromise;
}
/**
* @return {!Promise<!Common.DeferredContent>}
*/
async base64() {
return {content: this._base64content, isEncoded: true};
}
/**
* @return {!Promise<!Common.DeferredContent>}
*/
async utf8() {
if (!this._utf8Promise) {
this._utf8Promise = new Promise(async resolve => {
const content = await this._fetchContentAsArray();
const utf8String = new TextDecoder('utf8').decode(content);
resolve({content: utf8String, isEncoded: false});
});
}
return this._utf8Promise;
}
/**
* @return {!SourceFrame.ResourceSourceFrame}
*/
createBase64View() {
return new SourceFrame.ResourceSourceFrame(
Common.StaticContentProvider.fromString(this._contentUrl, this._resourceType, this._base64content),
/* autoPrettyPrint */ false, {lineNumbers: false, lineWrapping: true});
}
/**
* @return {!SourceFrame.ResourceSourceFrame}
*/
createHexView() {
const hexViewerContentProvider =
new Common.StaticContentProvider(this._contentUrl, this._resourceType, async () => {
const contentAsArray = await this._fetchContentAsArray();
const content = BinaryResourceViewFactory.uint8ArrayToHexViewer(contentAsArray);
return {content, isEncoded: false};
});
return new SourceFrame.ResourceSourceFrame(
hexViewerContentProvider,
/* autoPrettyPrint */ false, {lineNumbers: false, lineWrapping: false});
}
/**
* @return {!SourceFrame.ResourceSourceFrame}
*/
createUtf8View() {
const utf8fn = this.utf8.bind(this);
const utf8ContentProvider = new Common.StaticContentProvider(this._contentUrl, this._resourceType, utf8fn);
return new SourceFrame.ResourceSourceFrame(
utf8ContentProvider,
/* autoPrettyPrint */ false, {lineNumbers: true, lineWrapping: true});
}
/**
* @param {!Uint8Array} uint8Array
* @return {string}
*/
static uint8ArrayToHexString(uint8Array) {
let output = '';
for (let i = 0; i < uint8Array.length; i++) {
output += BinaryResourceViewFactory.numberToHex(uint8Array[i], 2);
}
return output;
}
/**
* @param {number} number
* @param {number} padding
* @return {string}
*/
static numberToHex(number, padding) {
let hex = number.toString(16);
while (hex.length < padding) {
hex = '0' + hex;
}
return hex;
}
/**
* @param {!Uint8Array} array
* @return {string}
*/
static uint8ArrayToHexViewer(array) {
let output = '';
let line = 0;
while ((line * 16) < array.length) {
const lineArray = array.slice(line * 16, (line + 1) * 16);
// line number
output += BinaryResourceViewFactory.numberToHex(line, 8) + ':';
// hex
let hexColsPrinted = 0;
for (let i = 0; i < lineArray.length; i++) {
if (i % 2 === 0) {
output += ' ';
hexColsPrinted++;
}
output += BinaryResourceViewFactory.numberToHex(lineArray[i], 2);
hexColsPrinted += 2;
}
// hex-ascii padding
while (hexColsPrinted < 42) {
output += ' ';
hexColsPrinted++;
}
// ascii
for (let i = 0; i < lineArray.length; i++) {
const code = lineArray[i];
if (code >= 32 && code <= 126) {
// printable ascii character
output += String.fromCharCode(code);
} else {
// non-printable
output += '.';
}
}
output += '\n';
line++;
}
return output;
}
}
/* Legacy exported object */
self.SourceFrame = self.SourceFrame || {};
/* Legacy exported object */
SourceFrame = SourceFrame || {};
/** @constructor */
SourceFrame.BinaryResourceViewFactory = BinaryResourceViewFactory;