173 lines
4.4 KiB
JavaScript
173 lines
4.4 KiB
JavaScript
/* Copyright (C) 2023-2025 anonymous
|
|
|
|
This file is part of PSFree.
|
|
|
|
PSFree is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU Affero General Public License as
|
|
published by the Free Software Foundation, either version 3 of the
|
|
License, or (at your option) any later version.
|
|
|
|
PSFree is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU Affero General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Affero General Public License
|
|
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
|
|
|
import { Int } from './int64.mjs';
|
|
|
|
export class DieError extends Error {
|
|
constructor(...args) {
|
|
super(...args);
|
|
this.name = this.constructor.name;
|
|
}
|
|
}
|
|
|
|
export function die(msg='') {
|
|
throw new DieError(msg);
|
|
}
|
|
|
|
const console = document.getElementById('console');
|
|
export function log(msg='') {
|
|
console.append(msg + '\n');
|
|
}
|
|
|
|
export function clear_log() {
|
|
console.innerHTML = null;
|
|
}
|
|
|
|
// alignment must be 32 bits and is a power of 2
|
|
export function align(a, alignment) {
|
|
if (!(a instanceof Int)) {
|
|
a = new Int(a);
|
|
}
|
|
const mask = -alignment & 0xffffffff;
|
|
let type = a.constructor;
|
|
let low = a.lo & mask;
|
|
return new type(low, a.hi);
|
|
}
|
|
|
|
export async function send(url, buffer, file_name, onload=() => {}) {
|
|
const file = new File(
|
|
[buffer],
|
|
file_name,
|
|
{type:'application/octet-stream'}
|
|
);
|
|
const form = new FormData();
|
|
form.append('upload', file);
|
|
|
|
log('send');
|
|
const response = await fetch(url, {method: 'POST', body: form});
|
|
|
|
if (!response.ok) {
|
|
throw Error(`Network response was not OK, status: ${response.status}`);
|
|
}
|
|
onload();
|
|
}
|
|
|
|
// mostly used to yield to the GC. marking is concurrent but collection isn't
|
|
//
|
|
// yielding also lets the DOM update. which is useful since we use the DOM for
|
|
// logging and we loop when waiting for a collection to occur
|
|
export function sleep(ms=0) {
|
|
return new Promise(resolve => setTimeout(resolve, ms));
|
|
}
|
|
|
|
export function hex(number) {
|
|
return '0x' + number.toString(16);
|
|
}
|
|
|
|
// no "0x" prefix
|
|
export function hex_np(number) {
|
|
return number.toString(16);
|
|
}
|
|
|
|
// expects a byte array
|
|
export function hexdump(view) {
|
|
const num_16 = view.length & ~15;
|
|
const residue = view.length - num_16;
|
|
const max_off_len = hex_np(((view.length + 7) & ~7) - 1).length;
|
|
|
|
function chr(i) {
|
|
if (0x20 <= i && i <= 0x7e) {
|
|
return String.fromCodePoint(i);
|
|
}
|
|
return '.';
|
|
}
|
|
|
|
function to_hex(view, offset, length) {
|
|
return (
|
|
[...view.slice(offset, offset + length)]
|
|
.map(e => hex_np(e).padStart(2, '0'))
|
|
.join(' ')
|
|
);
|
|
}
|
|
|
|
let bytes = [];
|
|
for (let i = 0; i < num_16; i += 16) {
|
|
const long1 = to_hex(view, i, 8);
|
|
const long2 = to_hex(view, i + 8, 8);
|
|
|
|
let print = '';
|
|
for (let j = 0; j < 16; j++) {
|
|
print += chr(view[j]);
|
|
}
|
|
|
|
bytes.push([`${long1} ${long2}`, print]);
|
|
}
|
|
|
|
if (residue) {
|
|
const small = residue <= 8;
|
|
const long1_len = small ? residue : 8;
|
|
|
|
let long1 = to_hex(view, num_16, long1_len);
|
|
if (small) {
|
|
for (let i = 0; i < 8 - residue; i++) {
|
|
long1 += ' xx';
|
|
}
|
|
}
|
|
|
|
const long2 = (() => {
|
|
if (small) {
|
|
return Array(8).fill('xx').join(' ');
|
|
}
|
|
|
|
let res = to_hex(view, num_16 + 8, residue - 8);
|
|
for (let i = 0; i < 16 - residue; i++) {
|
|
res += ' xx';
|
|
}
|
|
|
|
return res;
|
|
})();
|
|
|
|
let print = '';
|
|
for (let i = 0; i < residue; i++) {
|
|
print += chr(view[num_16 + i]);
|
|
}
|
|
for (let i = 0; i < 16 - residue; i++) {
|
|
print += ' ';
|
|
}
|
|
|
|
bytes.push([`${long1} ${long2}`, print]);
|
|
}
|
|
|
|
for (const [pos, [val, print]] of bytes.entries()) {
|
|
const off = hex_np(pos * 16).padStart(max_off_len, '0');
|
|
log(`${off} | ${val} |${print}|`);
|
|
}
|
|
}
|
|
|
|
// make a JavaScript string
|
|
export function jstr(buffer) {
|
|
let res = '';
|
|
for (const item of buffer) {
|
|
if (item === 0) {
|
|
break;
|
|
}
|
|
res += String.fromCodePoint(item);
|
|
}
|
|
// convert to primitive string
|
|
return String(res);
|
|
}
|