2014-12-21 20:28:13 +01:00
|
|
|
"use strict";
|
|
|
|
|
2021-01-01 02:14:29 +01:00
|
|
|
var goog = goog || {};
|
|
|
|
goog.exportSymbol = function() {};
|
|
|
|
goog.exportProperty = function() {};
|
|
|
|
|
2015-01-12 18:50:15 +01:00
|
|
|
var v86util = v86util || {};
|
|
|
|
|
2014-12-21 20:28:13 +01:00
|
|
|
// pad string with spaces on the right
|
2015-01-12 18:50:15 +01:00
|
|
|
v86util.pads = function(str, len)
|
2014-12-21 20:28:13 +01:00
|
|
|
{
|
2018-04-22 02:00:55 +02:00
|
|
|
str = (str || str === 0) ? str + "" : "";
|
2018-04-23 16:21:57 +02:00
|
|
|
return str.padEnd(len, " ");
|
2017-06-07 16:46:50 +02:00
|
|
|
};
|
2014-12-21 20:28:13 +01:00
|
|
|
|
|
|
|
// pad string with zeros on the left
|
2015-01-12 18:50:15 +01:00
|
|
|
v86util.pad0 = function(str, len)
|
2014-12-21 20:28:13 +01:00
|
|
|
{
|
2018-04-22 02:00:55 +02:00
|
|
|
str = (str || str === 0) ? str + "" : "";
|
2018-04-23 16:21:57 +02:00
|
|
|
return str.padStart(len, "0");
|
2017-06-07 16:46:50 +02:00
|
|
|
};
|
2014-12-21 20:28:13 +01:00
|
|
|
|
2018-06-03 07:14:47 +02:00
|
|
|
// generates array given size with zeros
|
|
|
|
v86util.zeros = function(size)
|
|
|
|
{
|
|
|
|
return Array(size).fill(0);
|
|
|
|
};
|
|
|
|
|
2018-06-03 07:00:55 +02:00
|
|
|
// generates [0, 1, 2, ..., size-1]
|
|
|
|
v86util.range = function(size)
|
|
|
|
{
|
|
|
|
return Array.from(Array(size).keys());
|
|
|
|
};
|
2015-09-12 01:10:38 +02:00
|
|
|
|
2018-08-09 23:06:51 +02:00
|
|
|
v86util.view = function(constructor, memory, offset, length)
|
|
|
|
{
|
|
|
|
return new Proxy({},
|
|
|
|
{
|
|
|
|
get: function(target, property, receiver)
|
|
|
|
{
|
|
|
|
const b = new constructor(memory.buffer, offset, length);
|
|
|
|
const x = b[property];
|
|
|
|
if(typeof x === "function")
|
|
|
|
{
|
|
|
|
return x.bind(b);
|
|
|
|
}
|
2018-08-10 02:37:55 +02:00
|
|
|
dbg_assert(/^\d+$/.test(property) || property === "buffer" || property === "length" ||
|
|
|
|
property === "BYTES_PER_ELEMENT" || property === "byteOffset");
|
2018-08-09 23:06:51 +02:00
|
|
|
return x;
|
|
|
|
},
|
|
|
|
set: function(target, property, value, receiver)
|
|
|
|
{
|
|
|
|
dbg_assert(/^\d+$/.test(property));
|
|
|
|
new constructor(memory.buffer, offset, length)[property] = value;
|
|
|
|
return true;
|
|
|
|
},
|
|
|
|
});
|
2017-06-07 16:46:50 +02:00
|
|
|
};
|
2014-12-21 20:28:13 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* number to hex
|
|
|
|
* @param {number} n
|
|
|
|
* @param {number=} len
|
|
|
|
* @return {string}
|
|
|
|
*/
|
|
|
|
function h(n, len)
|
|
|
|
{
|
2015-09-12 01:10:38 +02:00
|
|
|
if(!n)
|
2014-12-21 20:28:13 +01:00
|
|
|
{
|
2015-03-06 20:20:37 +01:00
|
|
|
var str = "";
|
2014-12-21 20:28:13 +01:00
|
|
|
}
|
2015-09-12 01:10:38 +02:00
|
|
|
else
|
2014-12-21 20:28:13 +01:00
|
|
|
{
|
2015-03-06 20:20:37 +01:00
|
|
|
var str = n.toString(16);
|
2014-12-21 20:28:13 +01:00
|
|
|
}
|
2015-03-06 20:20:37 +01:00
|
|
|
|
|
|
|
return "0x" + v86util.pad0(str.toUpperCase(), len || 1);
|
2014-12-21 20:28:13 +01:00
|
|
|
}
|
|
|
|
|
2017-03-17 20:48:24 +01:00
|
|
|
|
2021-01-04 00:18:46 +01:00
|
|
|
if(typeof crypto !== "undefined" && crypto.getRandomValues)
|
2017-03-17 20:48:24 +01:00
|
|
|
{
|
|
|
|
let rand_data = new Int32Array(1);
|
|
|
|
|
|
|
|
v86util.get_rand_int = function()
|
|
|
|
{
|
2021-01-04 00:18:46 +01:00
|
|
|
crypto.getRandomValues(rand_data);
|
2017-03-17 20:48:24 +01:00
|
|
|
return rand_data[0];
|
|
|
|
};
|
|
|
|
}
|
2018-11-24 22:24:56 +01:00
|
|
|
else if(typeof require !== "undefined")
|
2017-03-17 20:48:24 +01:00
|
|
|
{
|
2018-11-28 22:18:12 +01:00
|
|
|
/** @type {{ randomBytes: Function }} */
|
2018-11-24 22:24:56 +01:00
|
|
|
const crypto = require("crypto");
|
2017-03-17 20:48:24 +01:00
|
|
|
|
|
|
|
v86util.get_rand_int = function()
|
|
|
|
{
|
2021-01-01 02:14:31 +01:00
|
|
|
return crypto.randomBytes(4)["readInt32LE"](0);
|
2017-03-17 20:48:24 +01:00
|
|
|
};
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-11-24 22:29:42 +01:00
|
|
|
dbg_assert(false, "Unsupported platform: No cryptographic random values");
|
2017-03-17 20:48:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-09-12 01:10:38 +02:00
|
|
|
/**
|
2014-12-21 20:28:13 +01:00
|
|
|
* Synchronous access to ArrayBuffer
|
|
|
|
* @constructor
|
|
|
|
*/
|
|
|
|
function SyncBuffer(buffer)
|
|
|
|
{
|
2018-10-08 03:42:01 +02:00
|
|
|
dbg_assert(buffer instanceof ArrayBuffer);
|
|
|
|
|
2014-12-21 20:28:13 +01:00
|
|
|
this.buffer = buffer;
|
|
|
|
this.byteLength = buffer.byteLength;
|
2015-01-21 04:14:31 +01:00
|
|
|
this.onload = undefined;
|
|
|
|
this.onprogress = undefined;
|
2014-12-21 20:28:13 +01:00
|
|
|
}
|
|
|
|
|
2015-01-21 04:14:31 +01:00
|
|
|
SyncBuffer.prototype.load = function()
|
|
|
|
{
|
|
|
|
this.onload && this.onload({ buffer: this.buffer });
|
|
|
|
};
|
|
|
|
|
2015-09-12 01:10:38 +02:00
|
|
|
/**
|
2014-12-21 20:28:13 +01:00
|
|
|
* @param {number} start
|
|
|
|
* @param {number} len
|
|
|
|
* @param {function(!Uint8Array)} fn
|
|
|
|
*/
|
|
|
|
SyncBuffer.prototype.get = function(start, len, fn)
|
|
|
|
{
|
2015-01-21 04:14:31 +01:00
|
|
|
dbg_assert(start + len <= this.byteLength);
|
2014-12-21 20:28:13 +01:00
|
|
|
fn(new Uint8Array(this.buffer, start, len));
|
|
|
|
};
|
|
|
|
|
2015-09-12 01:10:38 +02:00
|
|
|
/**
|
2014-12-21 20:28:13 +01:00
|
|
|
* @param {number} start
|
|
|
|
* @param {!Uint8Array} slice
|
|
|
|
* @param {function()} fn
|
|
|
|
*/
|
|
|
|
SyncBuffer.prototype.set = function(start, slice, fn)
|
|
|
|
{
|
2015-01-21 04:14:31 +01:00
|
|
|
dbg_assert(start + slice.byteLength <= this.byteLength);
|
2014-12-21 20:28:13 +01:00
|
|
|
|
|
|
|
new Uint8Array(this.buffer, start, slice.byteLength).set(slice);
|
|
|
|
fn();
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param {function(!ArrayBuffer)} fn
|
|
|
|
*/
|
|
|
|
SyncBuffer.prototype.get_buffer = function(fn)
|
|
|
|
{
|
|
|
|
fn(this.buffer);
|
|
|
|
};
|
|
|
|
|
2021-01-01 02:14:31 +01:00
|
|
|
SyncBuffer.prototype.get_state = function()
|
|
|
|
{
|
|
|
|
const state = [];
|
|
|
|
state[0] = this.byteLength;
|
|
|
|
state[1] = new Uint8Array(this.buffer);
|
|
|
|
return state;
|
|
|
|
};
|
2014-12-21 20:28:13 +01:00
|
|
|
|
2021-01-01 02:14:31 +01:00
|
|
|
SyncBuffer.prototype.set_state = function(state)
|
|
|
|
{
|
|
|
|
this.byteLength = state[0];
|
|
|
|
this.buffer = state[1].slice().buffer;
|
|
|
|
};
|
2014-12-21 20:28:13 +01:00
|
|
|
|
2015-01-12 18:50:15 +01:00
|
|
|
(function()
|
2014-12-21 20:28:13 +01:00
|
|
|
{
|
2019-05-18 21:15:54 +02:00
|
|
|
if(typeof Math.clz32 === "function" && Math.clz32(0) === 32 &&
|
|
|
|
Math.clz32(0x12345) === 15 && Math.clz32(-1) === 0)
|
2019-05-13 07:42:28 +02:00
|
|
|
{
|
|
|
|
/**
|
|
|
|
* calculate the integer logarithm base 2 of a byte
|
|
|
|
* @param {number} x
|
|
|
|
* @return {number}
|
|
|
|
*/
|
|
|
|
v86util.int_log2_byte = function(x)
|
|
|
|
{
|
|
|
|
dbg_assert(x > 0);
|
|
|
|
dbg_assert(x < 0x100);
|
|
|
|
|
2019-05-18 21:15:54 +02:00
|
|
|
return 31 - Math.clz32(x);
|
|
|
|
};
|
2019-05-13 07:42:28 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* calculate the integer logarithm base 2
|
|
|
|
* @param {number} x
|
|
|
|
* @return {number}
|
|
|
|
*/
|
|
|
|
v86util.int_log2 = function(x)
|
|
|
|
{
|
|
|
|
dbg_assert(x > 0);
|
|
|
|
|
2019-05-18 21:15:54 +02:00
|
|
|
return 31 - Math.clz32(x);
|
|
|
|
};
|
2019-05-13 07:42:28 +02:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-01-12 18:50:15 +01:00
|
|
|
var int_log2_table = new Int8Array(256);
|
2014-12-21 20:28:13 +01:00
|
|
|
|
2015-01-12 18:50:15 +01:00
|
|
|
for(var i = 0, b = -2; i < 256; i++)
|
|
|
|
{
|
|
|
|
if(!(i & i - 1))
|
|
|
|
b++;
|
2014-12-21 20:28:13 +01:00
|
|
|
|
2015-01-12 18:50:15 +01:00
|
|
|
int_log2_table[i] = b;
|
|
|
|
}
|
2014-12-21 20:28:13 +01:00
|
|
|
|
2015-01-12 18:50:15 +01:00
|
|
|
/**
|
|
|
|
* calculate the integer logarithm base 2 of a byte
|
|
|
|
* @param {number} x
|
|
|
|
* @return {number}
|
|
|
|
*/
|
|
|
|
v86util.int_log2_byte = function(x)
|
|
|
|
{
|
|
|
|
dbg_assert(x > 0);
|
|
|
|
dbg_assert(x < 0x100);
|
2014-12-21 20:28:13 +01:00
|
|
|
|
2015-01-12 18:50:15 +01:00
|
|
|
return int_log2_table[x];
|
|
|
|
};
|
2014-12-21 20:28:13 +01:00
|
|
|
|
2015-01-12 18:50:15 +01:00
|
|
|
/**
|
|
|
|
* calculate the integer logarithm base 2
|
|
|
|
* @param {number} x
|
|
|
|
* @return {number}
|
|
|
|
*/
|
|
|
|
v86util.int_log2 = function(x)
|
|
|
|
{
|
2017-07-26 11:51:49 +02:00
|
|
|
x >>>= 0;
|
2015-01-12 18:50:15 +01:00
|
|
|
dbg_assert(x > 0);
|
2014-12-21 20:28:13 +01:00
|
|
|
|
2015-01-12 18:50:15 +01:00
|
|
|
// http://jsperf.com/integer-log2/6
|
|
|
|
var tt = x >>> 16;
|
2014-12-21 20:28:13 +01:00
|
|
|
|
2015-01-12 18:50:15 +01:00
|
|
|
if(tt)
|
2014-12-21 20:28:13 +01:00
|
|
|
{
|
2015-01-12 18:50:15 +01:00
|
|
|
var t = tt >>> 8;
|
|
|
|
if(t)
|
|
|
|
{
|
|
|
|
return 24 + int_log2_table[t];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return 16 + int_log2_table[tt];
|
|
|
|
}
|
2014-12-21 20:28:13 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-01-12 18:50:15 +01:00
|
|
|
var t = x >>> 8;
|
|
|
|
if(t)
|
|
|
|
{
|
|
|
|
return 8 + int_log2_table[t];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return int_log2_table[x];
|
|
|
|
}
|
2014-12-21 20:28:13 +01:00
|
|
|
}
|
2017-06-07 16:46:50 +02:00
|
|
|
};
|
2015-01-12 18:50:15 +01:00
|
|
|
})();
|
2014-12-21 20:28:13 +01:00
|
|
|
|
|
|
|
|
2015-09-12 01:10:38 +02:00
|
|
|
/**
|
|
|
|
* @constructor
|
2014-12-21 20:28:13 +01:00
|
|
|
*
|
|
|
|
* Queue wrapper around Uint8Array
|
|
|
|
* Used by devices such as the PS2 controller
|
|
|
|
*/
|
|
|
|
function ByteQueue(size)
|
|
|
|
{
|
|
|
|
var data = new Uint8Array(size),
|
|
|
|
start,
|
|
|
|
end;
|
|
|
|
|
|
|
|
dbg_assert((size & size - 1) === 0);
|
|
|
|
|
|
|
|
this.length = 0;
|
|
|
|
|
|
|
|
this.push = function(item)
|
|
|
|
{
|
|
|
|
if(this.length === size)
|
|
|
|
{
|
|
|
|
// intentional overwrite
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
this.length++;
|
|
|
|
}
|
|
|
|
|
|
|
|
data[end] = item;
|
|
|
|
end = end + 1 & size - 1;
|
|
|
|
};
|
|
|
|
|
|
|
|
this.shift = function()
|
|
|
|
{
|
|
|
|
if(!this.length)
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
var item = data[start];
|
|
|
|
|
|
|
|
start = start + 1 & size - 1;
|
|
|
|
this.length--;
|
|
|
|
|
|
|
|
return item;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
this.peek = function()
|
|
|
|
{
|
|
|
|
if(!this.length)
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return data[start];
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
this.clear = function()
|
|
|
|
{
|
|
|
|
start = 0;
|
|
|
|
end = 0;
|
|
|
|
this.length = 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
this.clear();
|
|
|
|
}
|
|
|
|
|
2015-01-12 18:50:15 +01:00
|
|
|
|
2017-11-17 23:52:10 +01:00
|
|
|
/**
|
|
|
|
* @constructor
|
|
|
|
*
|
2017-12-14 08:17:18 +01:00
|
|
|
* Queue wrapper around Float32Array
|
2017-11-17 23:52:10 +01:00
|
|
|
* Used by devices such as the sound blaster sound card
|
|
|
|
*/
|
2017-12-14 08:17:18 +01:00
|
|
|
function FloatQueue(size)
|
2017-11-17 23:52:10 +01:00
|
|
|
{
|
2017-12-16 11:12:53 +01:00
|
|
|
this.size = size;
|
|
|
|
this.data = new Float32Array(size);
|
|
|
|
this.start = 0;
|
|
|
|
this.end = 0;
|
|
|
|
this.length = 0;
|
2017-11-17 23:52:10 +01:00
|
|
|
|
|
|
|
dbg_assert((size & size - 1) === 0);
|
2017-12-16 11:12:53 +01:00
|
|
|
}
|
2017-11-17 23:52:10 +01:00
|
|
|
|
2017-12-16 11:12:53 +01:00
|
|
|
FloatQueue.prototype.push = function(item)
|
|
|
|
{
|
|
|
|
if(this.length === this.size)
|
2017-11-17 23:52:10 +01:00
|
|
|
{
|
2017-12-16 11:12:53 +01:00
|
|
|
// intentional overwrite
|
|
|
|
this.start = this.start + 1 & this.size - 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
this.length++;
|
|
|
|
}
|
2017-11-17 23:52:10 +01:00
|
|
|
|
2017-12-16 11:12:53 +01:00
|
|
|
this.data[this.end] = item;
|
|
|
|
this.end = this.end + 1 & this.size - 1;
|
|
|
|
};
|
2017-11-17 23:52:10 +01:00
|
|
|
|
2017-12-16 11:12:53 +01:00
|
|
|
FloatQueue.prototype.shift = function()
|
|
|
|
{
|
|
|
|
if(!this.length)
|
2017-11-17 23:52:10 +01:00
|
|
|
{
|
2017-12-16 11:12:53 +01:00
|
|
|
return undefined;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
var item = this.data[this.start];
|
2017-11-17 23:52:10 +01:00
|
|
|
|
2017-12-16 11:12:53 +01:00
|
|
|
this.start = this.start + 1 & this.size - 1;
|
|
|
|
this.length--;
|
2017-11-17 23:52:10 +01:00
|
|
|
|
2017-12-16 11:12:53 +01:00
|
|
|
return item;
|
|
|
|
}
|
|
|
|
};
|
2017-11-17 23:52:10 +01:00
|
|
|
|
2017-12-16 11:12:53 +01:00
|
|
|
FloatQueue.prototype.shift_block = function(count)
|
|
|
|
{
|
|
|
|
var slice = new Float32Array(count);
|
2017-12-14 08:17:18 +01:00
|
|
|
|
2017-12-16 11:12:53 +01:00
|
|
|
if(count > this.length)
|
|
|
|
{
|
|
|
|
count = this.length;
|
|
|
|
}
|
|
|
|
var slice_end = this.start + count;
|
2017-12-14 08:17:18 +01:00
|
|
|
|
2017-12-16 11:12:53 +01:00
|
|
|
var partial = this.data.subarray(this.start, slice_end);
|
2017-12-14 08:17:18 +01:00
|
|
|
|
2017-12-16 11:12:53 +01:00
|
|
|
slice.set(partial);
|
|
|
|
if(slice_end >= this.size)
|
|
|
|
{
|
|
|
|
slice_end -= this.size;
|
|
|
|
slice.set(this.data.subarray(0, slice_end), partial.length);
|
|
|
|
}
|
|
|
|
this.start = slice_end;
|
2017-12-14 08:17:18 +01:00
|
|
|
|
2017-12-16 11:12:53 +01:00
|
|
|
this.length -= count;
|
2017-12-14 08:17:18 +01:00
|
|
|
|
2017-12-16 11:12:53 +01:00
|
|
|
return slice;
|
|
|
|
};
|
2017-12-14 08:17:18 +01:00
|
|
|
|
2017-12-16 11:12:53 +01:00
|
|
|
FloatQueue.prototype.peek = function()
|
|
|
|
{
|
|
|
|
if(!this.length)
|
2017-11-17 23:52:10 +01:00
|
|
|
{
|
2017-12-16 11:12:53 +01:00
|
|
|
return undefined;
|
|
|
|
}
|
|
|
|
else
|
2017-11-17 23:52:10 +01:00
|
|
|
{
|
2017-12-16 11:12:53 +01:00
|
|
|
return this.data[this.start];
|
|
|
|
}
|
|
|
|
};
|
2017-11-17 23:52:10 +01:00
|
|
|
|
2017-12-16 11:12:53 +01:00
|
|
|
FloatQueue.prototype.clear = function()
|
|
|
|
{
|
|
|
|
this.start = 0;
|
|
|
|
this.end = 0;
|
|
|
|
this.length = 0;
|
|
|
|
};
|
2017-11-17 23:52:10 +01:00
|
|
|
|
|
|
|
|
2015-01-12 18:50:15 +01:00
|
|
|
/**
|
|
|
|
* Simple circular queue for logs
|
|
|
|
*
|
|
|
|
* @param {number} size
|
|
|
|
* @constructor
|
|
|
|
*/
|
|
|
|
function CircularQueue(size)
|
|
|
|
{
|
|
|
|
this.data = [];
|
|
|
|
this.index = 0;
|
|
|
|
this.size = size;
|
|
|
|
}
|
|
|
|
|
|
|
|
CircularQueue.prototype.add = function(item)
|
|
|
|
{
|
|
|
|
this.data[this.index] = item;
|
|
|
|
this.index = (this.index + 1) % this.size;
|
|
|
|
};
|
|
|
|
|
|
|
|
CircularQueue.prototype.toArray = function()
|
|
|
|
{
|
|
|
|
return [].slice.call(this.data, this.index).concat([].slice.call(this.data, 0, this.index));
|
|
|
|
};
|
|
|
|
|
|
|
|
CircularQueue.prototype.clear = function()
|
|
|
|
{
|
|
|
|
this.data = [];
|
|
|
|
this.index = 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param {Array} new_data
|
|
|
|
*/
|
|
|
|
CircularQueue.prototype.set = function(new_data)
|
|
|
|
{
|
|
|
|
this.data = new_data;
|
|
|
|
this.index = 0;
|
|
|
|
};
|
2018-03-17 09:41:25 +01:00
|
|
|
|
|
|
|
function dump_file(ab, name)
|
|
|
|
{
|
|
|
|
if(!(ab instanceof Array))
|
|
|
|
{
|
|
|
|
ab = [ab];
|
|
|
|
}
|
|
|
|
|
|
|
|
var blob = new Blob(ab);
|
|
|
|
download(blob, name);
|
|
|
|
}
|
|
|
|
|
|
|
|
function download(file_or_blob, name)
|
|
|
|
{
|
|
|
|
var a = document.createElement("a");
|
|
|
|
a["download"] = name;
|
|
|
|
a.href = window.URL.createObjectURL(file_or_blob);
|
|
|
|
a.dataset["downloadurl"] = ["application/octet-stream", a["download"], a.href].join(":");
|
|
|
|
|
|
|
|
if(document.createEvent)
|
|
|
|
{
|
|
|
|
var ev = document.createEvent("MouseEvent");
|
|
|
|
ev.initMouseEvent("click", true, true, window,
|
|
|
|
0, 0, 0, 0, 0, false, false, false, false, 0, null);
|
|
|
|
a.dispatchEvent(ev);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
a.click();
|
|
|
|
}
|
|
|
|
|
|
|
|
window.URL.revokeObjectURL(a.href);
|
|
|
|
}
|
2021-01-03 07:51:29 +01:00
|
|
|
|
2018-10-31 18:50:33 +01:00
|
|
|
/**
|
|
|
|
* A simple 1d bitmap
|
2018-11-05 00:30:50 +01:00
|
|
|
* @constructor
|
2018-10-31 18:50:33 +01:00
|
|
|
*/
|
|
|
|
v86util.Bitmap = function(length_or_buffer)
|
|
|
|
{
|
|
|
|
if(typeof length_or_buffer === "number")
|
|
|
|
{
|
|
|
|
this.view = new Uint8Array(length_or_buffer + 7 >> 3);
|
|
|
|
}
|
|
|
|
else if(length_or_buffer instanceof ArrayBuffer)
|
|
|
|
{
|
|
|
|
this.view = new Uint8Array(length_or_buffer);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
console.assert(false);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
v86util.Bitmap.prototype.set = function(index, value)
|
|
|
|
{
|
|
|
|
const bit_index = index & 7;
|
|
|
|
const byte_index = index >> 3;
|
|
|
|
const bit_mask = 1 << bit_index;
|
|
|
|
|
|
|
|
this.view[byte_index] =
|
|
|
|
value ? this.view[byte_index] | bit_mask : this.view[byte_index] & ~bit_mask;
|
|
|
|
};
|
|
|
|
|
|
|
|
v86util.Bitmap.prototype.get = function(index)
|
|
|
|
{
|
|
|
|
const bit_index = index & 7;
|
|
|
|
const byte_index = index >> 3;
|
|
|
|
|
|
|
|
return this.view[byte_index] >> bit_index & 1;
|
|
|
|
};
|
|
|
|
|
|
|
|
v86util.Bitmap.prototype.get_buffer = function()
|
|
|
|
{
|
|
|
|
return this.view.buffer;
|
|
|
|
};
|