* Copyright (C) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { BaseElement, element } from '../../base-ui/BaseElement.js';
@element('tab-native-data-modal')
export class DisassemblingWindow extends BaseElement {
private canvas: HTMLCanvasElement | undefined | null;
private window: HTMLElement | undefined | null;
private loading: HTMLElement | undefined | null;
private ctx: CanvasRenderingContext2D | null | undefined;
private hintLine = 0;
private addrArray = new Array<string>();
private maxBinSize = 0;
private close: Function | undefined | null;
setCloseListener(callback: Function) {
this.close = callback;
}
removeCloseListener() {
this.close = null;
}
private getMap(content: string, hintAttr: string) {
let lines = content.split('\n');
this.addrArray = new Array<string>();
let lineMap = new Map<string, Disassembling>();
let effectLint = 0;
this.maxBinSize = 0;
for (let line of lines) {
let lineContents = line.split(':');
if (lineContents.length === 2) {
let addrHex = lineContents[0].trim();
let addr = '0x' + addrHex;
let value = lineContents[1].split('\t');
try {
let binary = value[0];
let lineStruct = new Disassembling();
if (binary === '') {
if (line.includes('Disassembly') || line.includes('file format')) {
continue;
} else {
if (addr.includes(' ')) {
let funcs = addr.split(' ');
lineStruct.addr = funcs[0];
lineStruct.binary = funcs[1];
}
}
} else {
lineStruct.addr = addr;
lineStruct.binary = value[0].trim();
lineStruct.type = value.length > 1 ? value[1] : '';
lineStruct.code = value.length > 2 ? value[2] : '';
}
lineMap.set(addrHex, lineStruct);
this.maxBinSize = Math.max(this.ctx!.measureText(lineStruct.addr + lineStruct.binary).width, this.maxBinSize);
this.addrArray.push(addrHex);
if (addrHex === hintAttr) this.hintLine = effectLint;
effectLint++;
} catch (e) {
console.log(e);
}
}
}
return lineMap;
}
public showContent(content: string, hintAddr: string): void {
this.loading!.style.display = 'none';
this.window!.style.display = 'block';
if (content.startsWith('error')) {
this.window!.innerHTML = `<span class="column1" style="width:100%;text-align: center;">${content}</span>`;
return;
}
let lineMap = this.getMap(content, hintAddr);
this.maxBinSize = this.maxBinSize * 1.7;
this.window!.innerHTML = '';
for (let addr of this.addrArray) {
if (!lineMap.has(addr)) continue;
let struct = lineMap.get(addr);
if (this.addrArray[this.hintLine] == addr) {
this.window!.innerHTML += `<div class="line" id="emphasis" style = background:red">
<span class="column0" style="width:${this.maxBinSize}px;">${struct!.addr} : ${struct!.binary}</span>
<span class="column1" style="width:100px;">${struct!.type}</span>
<span class="column2" style="width:300px;">${struct!.code}</span></div>`;
(this.window!.querySelector('#emphasis') as HTMLElement)!.style.width = this.window!.scrollWidth + 'px';
(this.window!.querySelector('#emphasis') as HTMLElement)!.style.background = '#0A59F7';
} else {
this.window!.innerHTML += `<div class="line">
<span class="column0" style="width:${this.maxBinSize}px;">${struct!.addr} : ${struct!.binary}</span>
<span class="column1" style="width:100px;">${struct!.type}</span>
<span class="column2" style="width:300px;">${struct!.code}</span></div>`;
}
}
this.window!.scrollTo(
0,
(this.hintLine - 1) * this.shadowRoot!.querySelector('#window>.line')!.clientHeight -
this.window!.clientHeight / 2
);
}
private resetCanvas(styleWidth: number, styleHeight: number, width: number, height: number): void {
this.canvas!.style.width = styleWidth + 'px';
this.canvas!.style.height = styleHeight + 'px';
this.canvas!.width = width;
this.canvas!.height = height;
}
public showLoading(): void {
this.loading!.style.display = 'block';
this.window!.style.display = 'none';
this.style.display = 'block';
this.style.position = 'absolute';
this.style.left = '0px';
this.style.border = '1px solid #d8d8d8';
}
initElements(): void {
this.canvas = this.shadowRoot?.querySelector<HTMLCanvasElement>('#canvas');
let close = this.shadowRoot?.querySelector('#close');
this.window = this.shadowRoot?.querySelector('#window');
this.loading = this.shadowRoot?.querySelector('#loading');
this.ctx = this.canvas!.getContext('2d');
this.resetCanvas(0, 0, 0, 0);
close!.addEventListener('click', () => {
if (this.close) {
this.close();
}
return true;
});
}
initHtml(): string {
return `
<style>
#close{
position:absolute;
top:0px;
right: 0px;
color: #D6D6D6;
}
#modal-wrap{
position: absolute;
top: 0;
left: 0;
width:100%;
height:100%;
background: var(--dark-background,#ffffff);
z-index: 2000;
}
#window{
overflow: auto;
position: absolute;
top: 21px;
left: 0;
width: calc(100% - 10px);
height: calc(100% - 21px);
padding-left: 10px;
}
#loading{
position: absolute;
left: calc(50% - 20px);
top: calc(50% - 20px);
width:40px;
height:40px;
transform: rotate(360deg);
animation: rotation 2s linear infinite;
-webkit-animation: rotation 2s linear infinite;
}
@keyframes rotation{
from {
-webkit-transform: rotate(0deg);
}
to {
-webkit-transform: rotate(360deg);
}
}
.line{
line-height:27px;
white-space: nowrap;
}
span{
display: inline-block;
}
</style>
<div id="modal-wrap">
<canvas id="canvas" style="display: none"> </canvas>
<lit-icon id="close" name="close" size="20"> </lit-icon>
<div id="window"> </div>
<lit-icon id="loading" name="loading" size="40"> </lit-icon>
</div>
`;
}
}
class Disassembling {
addr = '';
binary = '';
type = '';
code = '';
}