1145 lines
28 KiB
JavaScript
1145 lines
28 KiB
JavaScript
/*-------------------------------------------------------------------------
|
|
| SAE - Scripted Amiga Emulator
|
|
| https://github.com/naTmeg/ScriptedAmigaEmulator
|
|
|
|
|
| Copyright (C) 2012-2016 Rupert Hausberger
|
|
|
|
|
| This program is free software; you can redistribute it and/or
|
|
| modify it under the terms of the GNU General Public License
|
|
| as published by the Free Software Foundation; either version 2
|
|
| of the License, or (at your option) any later version.
|
|
|
|
|
| This program 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 General Public License for more details.
|
|
-------------------------------------------------------------------------*/
|
|
/* global constants */
|
|
|
|
const SAEC_LITTLE_ENDIAN = (function() {
|
|
var buffer = new ArrayBuffer(2);
|
|
new DataView(buffer).setInt16(0, 256, true);
|
|
return new Int16Array(buffer)[0] === 256; /* read is LE */
|
|
})();
|
|
//console.log("Little endian system: "+(SAEC_LITTLE_ENDIAN ? "Yes" : "No"));
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
/* byte-swapping */
|
|
|
|
function SAEF_bswap16(v) {
|
|
return ((v & 0x00ff) << 8) | ((v & 0xff00) >> 8);
|
|
}
|
|
function SAEF_bswap32(v) {
|
|
return (((v & 0x000000ff) << 24) | ((v & 0x0000ff00) << 8) | ((v & 0x00ff0000) >>> 8) | ((v & 0xff000000) >>> 24)) >>> 0;
|
|
}
|
|
|
|
function SAEF_be16toh(v) {
|
|
if (SAEC_LITTLE_ENDIAN)
|
|
return ((v & 0x00ff) << 8) | ((v & 0xff00) >> 8);
|
|
else
|
|
return v;
|
|
}
|
|
function SAEF_be32toh(v) {
|
|
if (SAEC_LITTLE_ENDIAN)
|
|
return (((v & 0x000000ff) << 24) | ((v & 0x0000ff00) << 8) | ((v & 0x00ff0000) >>> 8) | ((v & 0xff000000) >>> 24)) >>> 0;
|
|
else
|
|
return v;
|
|
}
|
|
|
|
function SAEF_le32toh(v) {
|
|
if (SAEC_LITTLE_ENDIAN)
|
|
return v;
|
|
else
|
|
return (((v & 0x000000ff) << 24) | ((v & 0x0000ff00) << 8) | ((v & 0x00ff0000) >>> 8) | ((v & 0xff000000) >>> 24)) >>> 0;
|
|
}
|
|
function SAEF_le16toh(v) {
|
|
if (SAEC_LITTLE_ENDIAN)
|
|
return v;
|
|
else
|
|
return ((v & 0x00ff) << 8) | ((v & 0xff00) >> 8);
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
/* moving average */
|
|
|
|
function SAEO_MAvg(size) {
|
|
var values = new Array(size);
|
|
var size = size;
|
|
var usage = 0;
|
|
var offset = 0;
|
|
var average = 0;
|
|
|
|
this.clr = function () {
|
|
usage = 0;
|
|
offset = 0;
|
|
average = 0;
|
|
};
|
|
|
|
this.get = function() {
|
|
return average / usage; /* return as float */
|
|
}
|
|
|
|
this.set = function(newval) {
|
|
if (usage < size) {
|
|
values[usage++] = newval;
|
|
average += newval;
|
|
} else {
|
|
average -= values[offset];
|
|
values[offset] = newval;
|
|
average += newval;
|
|
if (++offset >= size)
|
|
offset -= size;
|
|
}
|
|
return average / usage; /* return as float */
|
|
}
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
/* CRC checksumming */
|
|
|
|
var SAEV_crc32Table = new Uint32Array(256);
|
|
var SAEV_crc16Table = new Uint16Array(256);
|
|
{
|
|
var c, w;
|
|
var n, k;
|
|
for (n = 0; n < 256; n++) {
|
|
c = n;
|
|
w = n << 8;
|
|
for (k = 0; k < 8; k++) {
|
|
c = ((c >>> 1) ^ (c & 1 ? 0xedb88320 : 0)) >>> 0;
|
|
w = ((w << 1) & 0xffff) ^ ((w & 0x8000) ? 0x1021 : 0);
|
|
}
|
|
SAEV_crc32Table[n] = c;
|
|
SAEV_crc16Table[n] = w;
|
|
}
|
|
}
|
|
|
|
function SAEF_crc32(buf,bufo, len) {
|
|
var crc = 0xffffffff;
|
|
if (typeof buf === "string") {
|
|
while (len-- > 0)
|
|
crc = SAEV_crc32Table[(crc ^ buf.charCodeAt(bufo++)) & 0xff] ^ (crc >>> 8);
|
|
} else {
|
|
while (len-- > 0)
|
|
crc = SAEV_crc32Table[(crc ^ buf[bufo++]) & 0xff] ^ (crc >>> 8);
|
|
}
|
|
return (crc ^ 0xffffffff) >>> 0;
|
|
}
|
|
|
|
function SAEF_crc16(buf,bufo, len) {
|
|
var crc = 0xffff;
|
|
while (len-- > 0)
|
|
crc = ((crc << 8) & 0xffff) ^ SAEV_crc16Table[((crc >> 8) ^ buf[bufo++]) & 0xff];
|
|
return crc;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
/* Date/Time conversion */
|
|
|
|
function SAEF_gettimeofday(tv, tz) {
|
|
var now = performance.now();
|
|
now += performance.timing.navigationStart;
|
|
now = Math.floor(now * 1000);
|
|
tv.tv_sec = Math.floor(now / 1000000);
|
|
tv.tv_usec = now % 1000000;
|
|
}
|
|
|
|
function SAEF_timeval_to_amiga(tv, amiga, tickcount) {
|
|
/* tv.tv_sec is secs since 1-1-1970 */
|
|
/* days since 1-1-1978 */
|
|
/* mins since midnight */
|
|
/* ticks past minute @ 50Hz */
|
|
const msecs_per_day = 24 * 60 * 60 * 1000;
|
|
|
|
var t = tv.tv_sec * 1000 + Math.floor(tv.tv_usec / 1000);
|
|
t -= (8 * 365 + 2) * 24 * 60 * 60 * 1000;
|
|
|
|
if (t < 0)
|
|
t = 0;
|
|
amiga.days = Math.floor(t / msecs_per_day);
|
|
t -= amiga.days * msecs_per_day;
|
|
amiga.mins = Math.floor(t / (60 * 1000));
|
|
t -= amiga.mins * (60 * 1000);
|
|
amiga.ticks = Math.floor(t / (1000 / tickcount));
|
|
}
|
|
|
|
/*function SAEF_amiga_to_timeval(tv, days, mins, ticks, tickcount) {
|
|
if (days < 0)
|
|
days = 0;
|
|
if (days > 9900 * 365)
|
|
days = 9900 * 365; // in future far enough?
|
|
if (mins < 0 || mins >= 24 * 60)
|
|
mins = 0;
|
|
if (ticks < 0 || ticks >= 60 * tickcount)
|
|
ticks = 0;
|
|
|
|
var t = ticks * 20;
|
|
t += mins * 60 * 1000;
|
|
t += days * 24 * 60 * 60 * 1000;
|
|
t += (8 * 365 + 2) * 24 * 60 * 60 * 1000;
|
|
|
|
tv.tv_sec = Math.floor(t / 1000);
|
|
tv.tv_usec = (t % 1000) * 1000;
|
|
}*/
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
|
|
function SAEF_memset(dst,dsto, value, length) {
|
|
for (var i = dsto, j = dsto + length; i < j; i++)
|
|
dst[i] = value;
|
|
}
|
|
|
|
function SAEF_memcpy(dst,dsto, src,srco, length) {
|
|
for (var i = 0; i < length; i++)
|
|
dst[dsto + i] = src[srco + i];
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
|
|
function SAEF_Array2String(array, start, end) {
|
|
if (typeof end == "undefined") end = array.length;
|
|
if (typeof start == "undefined") start = 0;
|
|
var string = "";
|
|
for (var i = start; i < end; i++)
|
|
string += String.fromCharCode(array[i]);
|
|
return string;
|
|
}
|
|
|
|
function SAEF_String2Array(string, start, end) {
|
|
if (typeof end == "undefined") end = string.length;
|
|
if (typeof start == "undefined") start = 0;
|
|
var array = new Uint8Array(end - start);
|
|
for (var i = start; i < end; i++)
|
|
array[i - start] = string.charCodeAt(i);
|
|
return array;
|
|
}
|
|
|
|
/*function SAEF_CopyArray(dst_array, src_array, src_end) {
|
|
if (typeof src_end == "undefined") src_end = src_array.length;
|
|
for (var i = 0; i < src_end; i++) {
|
|
if (typeof dst_array[i] === 'undefined' || typeof src_array[i] === 'undefined')
|
|
return 1;
|
|
dst_array[i] = src_array[i];
|
|
}
|
|
return 0;
|
|
}*/
|
|
|
|
function SAEF_CompareArray(array1, array2, end2) {
|
|
if (typeof end2 == "undefined") end2 = array2.length;
|
|
for (var i = 0; i < end2; i++) {
|
|
if (typeof array1[i] === 'undefined' || typeof array2[i] === 'undefined')
|
|
return 1;
|
|
if (array1[i] != array2[i])
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
function SAEF_CompareArrayAfter(array1, start1, array2, end2) {
|
|
if (typeof end2 == "undefined") end2 = array2.length;
|
|
for (var i = 0; i < end2; i++) {
|
|
if (typeof array1[start1 + i] === 'undefined' || typeof array2[i] === 'undefined')
|
|
return 1;
|
|
if (array1[start1 + i] != array2[i])
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
/* Javascript sprintf - http://www.webtoolkit.info
|
|
This is the only function that does not correspond to the global name space
|
|
*/
|
|
var sprintfWrapper = {
|
|
init: function () {
|
|
if (typeof arguments == "undefined") {
|
|
return null;
|
|
}
|
|
if (arguments.length < 1) {
|
|
return null;
|
|
}
|
|
if (typeof arguments[0] != "string") {
|
|
return null;
|
|
}
|
|
if (typeof RegExp == "undefined") {
|
|
return null;
|
|
}
|
|
|
|
var string = arguments[0];
|
|
var exp = new RegExp(/(%([%]|(\-)?(\+|\x20)?(0)?(\d+)?(\.(\d)?)?([bcdfosxX])))/g);
|
|
var matches = [];
|
|
var strings = [];
|
|
var convCount = 0;
|
|
var stringPosStart = 0;
|
|
var stringPosEnd = 0;
|
|
var matchPosEnd = 0;
|
|
var newString = "";
|
|
var match;
|
|
|
|
while (match = exp.exec(string)) {
|
|
if (match[9]) {
|
|
convCount += 1;
|
|
}
|
|
|
|
stringPosStart = matchPosEnd;
|
|
stringPosEnd = exp.lastIndex - match[0].length;
|
|
strings[strings.length] = string.substring(stringPosStart, stringPosEnd);
|
|
|
|
matchPosEnd = exp.lastIndex;
|
|
matches[matches.length] = {
|
|
match: match[0],
|
|
left: match[3] ? true : false,
|
|
sign: match[4] || "",
|
|
pad: match[5] || " ",
|
|
min: match[6] || 0,
|
|
precision: match[8],
|
|
code: match[9] || "%",
|
|
negative: !!(parseInt(arguments[convCount]) < 0),
|
|
argument: String(arguments[convCount])
|
|
};
|
|
}
|
|
strings[strings.length] = string.substring(matchPosEnd);
|
|
|
|
if (matches.length == 0) {
|
|
return string;
|
|
}
|
|
if ((arguments.length - 1) < convCount) {
|
|
return null;
|
|
}
|
|
|
|
for (var i = 0; i < matches.length; i++) {
|
|
var substitution;
|
|
|
|
if (matches[i].code == "%") {
|
|
substitution = "%"
|
|
} else if (matches[i].code == "b") {
|
|
matches[i].argument = String(Math.abs(parseInt(matches[i].argument)).toString(2));
|
|
substitution = sprintfWrapper.convert(matches[i], true);
|
|
} else if (matches[i].code == "c") {
|
|
matches[i].argument = String(String.fromCharCode(parseInt(Math.abs(parseInt(matches[i].argument)))));
|
|
substitution = sprintfWrapper.convert(matches[i], true);
|
|
} else if (matches[i].code == "d") {
|
|
matches[i].argument = String(Math.abs(parseInt(matches[i].argument)));
|
|
substitution = sprintfWrapper.convert(matches[i]);
|
|
} else if (matches[i].code == "f") {
|
|
matches[i].argument = String(Math.abs(parseFloat(matches[i].argument)).toFixed(matches[i].precision ? matches[i].precision : 6));
|
|
substitution = sprintfWrapper.convert(matches[i]);
|
|
} else if (matches[i].code == "o") {
|
|
matches[i].argument = String(Math.abs(parseInt(matches[i].argument)).toString(8));
|
|
substitution = sprintfWrapper.convert(matches[i]);
|
|
} else if (matches[i].code == "s") {
|
|
matches[i].argument = matches[i].argument.substring(0, matches[i].precision ? matches[i].precision : matches[i].argument.length);
|
|
substitution = sprintfWrapper.convert(matches[i], true);
|
|
} else if (matches[i].code == "x") {
|
|
matches[i].argument = String(Math.abs(parseInt(matches[i].argument)).toString(16));
|
|
substitution = sprintfWrapper.convert(matches[i]);
|
|
} else if (matches[i].code == "X") {
|
|
matches[i].argument = String(Math.abs(parseInt(matches[i].argument)).toString(16));
|
|
substitution = sprintfWrapper.convert(matches[i]).toUpperCase();
|
|
} else {
|
|
substitution = matches[i].match;
|
|
}
|
|
newString += strings[i];
|
|
newString += substitution;
|
|
|
|
}
|
|
newString += strings[i];
|
|
|
|
return newString;
|
|
},
|
|
convert: function (match, nosign) {
|
|
if (nosign) {
|
|
match.sign = "";
|
|
} else {
|
|
match.sign = match.negative ? "-" : match.sign;
|
|
}
|
|
var l = match.min - match.argument.length + 1 - match.sign.length;
|
|
var pad = new Array(l < 0 ? 0 : l).join(match.pad);
|
|
if (!match.left) {
|
|
if (match.pad == "0" || nosign) {
|
|
return match.sign + pad + match.argument;
|
|
} else {
|
|
return pad + match.sign + match.argument;
|
|
}
|
|
} else {
|
|
if (match.pad == "0" || nosign) {
|
|
return match.sign + match.argument + pad.replace(/0/g, " ");
|
|
} else {
|
|
return match.sign + match.argument + pad;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
var sprintf = sprintfWrapper.init;
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
/* Z wrapper */
|
|
|
|
const SEEK_SET = 0; /* set file offset to offset */
|
|
const SEEK_CUR = 1; /* set file offset to current plus offset */
|
|
const SEEK_END = 2; /* set file offset to EOF plus offset */
|
|
|
|
/*struct zfile {
|
|
TCHAR *name;
|
|
TCHAR *originalname;
|
|
uae_u8 *data; // unpacked data
|
|
int dataseek; // use seek position even if real file
|
|
|
|
uae_s64 size; // real size
|
|
uae_s64 datasize; // available size (not yet unpacked completely?)
|
|
uae_s64 allocsize; // memory allocated before realloc() needed again
|
|
uae_s64 seek; // seek position
|
|
|
|
int opencnt;
|
|
};*/
|
|
function SAEO_ZFile() {
|
|
this.name = "";
|
|
this.originalname = "";
|
|
this.data = null; // unpacked data
|
|
this.dataseek = 0; // use seek position even if real file
|
|
|
|
this.size = 0; // real size
|
|
this.datasize = 0; // available size (not yet unpacked completely?)
|
|
this.allocsize = 0; // memory allocated before realloc() needed again
|
|
this.seek = 0; // seek position
|
|
|
|
this.opencnt = 0;
|
|
}
|
|
|
|
/*---------------------------------*/
|
|
|
|
function SAEF_ZFile_create(prev, originalname) {
|
|
var z = new SAEO_ZFile();
|
|
z.opencnt = 1;
|
|
|
|
if (prev !== null && prev.originalname)
|
|
z.originalname = prev.originalname;
|
|
else if (originalname.length)
|
|
z.originalname = originalname;
|
|
|
|
return z;
|
|
}
|
|
|
|
function SAEF_ZFile_free(f) {
|
|
f.name = "";
|
|
f.originalname = "";
|
|
f.data = null;
|
|
}
|
|
|
|
/*---------------------------------*/
|
|
|
|
function SAEF_ZFile_fopen_empty(prev, name, size) {
|
|
var l = SAEF_ZFile_create(prev, "");
|
|
l.name = name.length ? name : "";
|
|
if (size) {
|
|
l.data = new Uint8Array(size);
|
|
/*if (!l.data) {
|
|
xfree(l);
|
|
return null;
|
|
}*/
|
|
l.size = size;
|
|
l.datasize = size;
|
|
l.allocsize = size;
|
|
} else {
|
|
l.data = new Uint8Array(1000);
|
|
l.size = 0;
|
|
l.allocsize = 1000;
|
|
}
|
|
return l;
|
|
}
|
|
|
|
function SAEF_ZFile_fopen_load_zfile(f) {
|
|
var l = SAEF_ZFile_fopen_empty(f, f.name, f.size);
|
|
if (l === null)
|
|
return null;
|
|
SAEF_ZFile_fseek(f, 0, SEEK_SET);
|
|
SAEF_ZFile_fread(l.data,0, f.size, 1, f);
|
|
return l;
|
|
}
|
|
|
|
/*function SAEF_ZFile_fopen_data(name, size, data) {
|
|
if (size) {
|
|
var l = SAEF_ZFile_create(null, name);
|
|
l.name = name.length ? name : "";
|
|
if (1) { // ptr
|
|
l.data = data;
|
|
} else {
|
|
l.data = new Uint8Array(size);
|
|
l.data.set(data); //memcpy(l.data, data, size);
|
|
}
|
|
l.size = size;
|
|
l.datasize = size;
|
|
l.allocsize = size; //OWN
|
|
return l;
|
|
}
|
|
return null;
|
|
}*/
|
|
|
|
function SAEF_ZFile_fopen_file(file) {
|
|
if (file.size) {
|
|
var l = SAEF_ZFile_create(null, file.name);
|
|
l.name = file.name.length ? file.name : "";
|
|
|
|
if (0) { /* ptr-mode. do not enable */
|
|
l.data = file.data;
|
|
} else {
|
|
l.data = new Uint8Array(file.size);
|
|
//memcpy(l.data, data, size);
|
|
if (typeof file.data === "string")
|
|
l.data.set(SAEF_String2Array(file.data, 0, file.size));
|
|
else
|
|
l.data.set(file.data);
|
|
}
|
|
l.size = file.size;
|
|
l.datasize = file.size;
|
|
l.allocsize = file.size; //OWN
|
|
|
|
//if (l.data[0] == 68 && l.data[1] == 77 && l.data[2] == 83 && l.data[3] == 33) { /* DMS! */
|
|
if (SAEF_CompareArray(l.data, SAEF_String2Array("DMS!"), 4) == 0) {
|
|
var dms = new SAEO_DMS();
|
|
var f = dms.DMS2ADF(l);
|
|
if (f !== null) {
|
|
var data = SAEF_ZFile_getdata(f, 0, -1);
|
|
file.name = SAEF_ZFile_getname(f);
|
|
file.data = SAEF_Array2String(data);
|
|
file.size = SAEF_ZFile_size(f);
|
|
file.prot = false;
|
|
return f;
|
|
}
|
|
}
|
|
else if (SAEF_CompareArray(l.data, [0x00,0x00,0x03,0xf3,0x00,0x00,0x00,0x00], 8) == 0) {
|
|
var f = SAER.disk.EXE2ADF(l);
|
|
if (f !== null) {
|
|
var data = SAEF_ZFile_getdata(f, 0, -1);
|
|
file.name = SAEF_ZFile_getname(f);
|
|
file.data = SAEF_Array2String(data);
|
|
file.size = SAEF_ZFile_size(f);
|
|
file.prot = false;
|
|
return f;
|
|
}
|
|
}
|
|
return l;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
function SAEF_ZFile_fclose(f) {
|
|
if (!f)
|
|
return;
|
|
if (f.opencnt < 0) {
|
|
SAEF_warn("SAEF_ZFile_fclose() tried to free already closed filehandle!");
|
|
return;
|
|
}
|
|
f.opencnt--;
|
|
if (f.opencnt > 0)
|
|
return;
|
|
f.opencnt = -100;
|
|
|
|
SAEF_ZFile_free(f);
|
|
}
|
|
|
|
/*---------------------------------*/
|
|
|
|
function SAEF_ZFile_iscompressed(z) {
|
|
return false; //z.data !== null ? 1 : 0; //ATT
|
|
}
|
|
|
|
/*---------------------------------*/
|
|
|
|
/*function SAEF_ZFile_truncate(z, size) {
|
|
if (size < z.size) {
|
|
z.size = size;
|
|
if (z.size < z.datasize)
|
|
z.datasize = z.size;
|
|
if (z.size < z.seek)
|
|
z.seek = z.size;
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}*/
|
|
|
|
function SAEF_ZFile_resize(z, newsize) { //OWN
|
|
if (newsize > z.allocsize) {
|
|
z.allocsize = newsize;
|
|
|
|
SAEF_log("SAEF_ZFile_resize() increase %d -> %d bytes", z.size, z.allocsize);
|
|
|
|
var tmp = new Uint8Array(z.allocsize);
|
|
tmp.set(z.data);
|
|
z.data = tmp;
|
|
z.datasize = z.size = newsize;
|
|
return 1;
|
|
}
|
|
if (newsize < z.allocsize) {
|
|
z.allocsize = newsize;
|
|
|
|
SAEF_log("SAEF_ZFile_resize() decrease %d -> %d bytes", z.size, z.allocsize);
|
|
|
|
var tmp = new Uint8Array(z.allocsize);
|
|
tmp.set(z.data.subarray(0, z.allocsize));
|
|
z.data = tmp;
|
|
z.datasize = z.size = newsize;
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
function SAEF_ZFile_size(z) {
|
|
return z.size;
|
|
}
|
|
|
|
/*---------------------------------*/
|
|
|
|
function SAEF_ZFile_ftell(z) {
|
|
return z.seek;
|
|
}
|
|
|
|
function SAEF_ZFile_fseek(z, offset, mode) {
|
|
var ret = 0;
|
|
switch (mode) {
|
|
case SEEK_SET:
|
|
z.seek = offset;
|
|
break;
|
|
case SEEK_CUR:
|
|
z.seek += offset;
|
|
break;
|
|
case SEEK_END:
|
|
z.seek = z.size + offset;
|
|
break;
|
|
}
|
|
if (z.seek < 0) {
|
|
z.seek = 0;
|
|
ret = 1;
|
|
}
|
|
if (z.seek > z.size) {
|
|
z.seek = z.size;
|
|
ret = 1;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/*---------------------------------*/
|
|
|
|
/*function SAEF_ZFile_fread(b,bo, l1, l2, z) {
|
|
var l = l1 * l2;
|
|
if (z.datasize < z.size && z.seek + l > z.datasize) {
|
|
SAEF_warn("SAEF_ZFile_fread() read beyond size");
|
|
return 0;
|
|
}
|
|
if (z.seek + l > z.size) {
|
|
l2 = l1 ? Math.truncate((z.size - z.seek) / l1) : 0;
|
|
if (l2 < 0) l2 = 0;
|
|
l = l1 * l2;
|
|
}
|
|
//memcpy(b, z.data + z.seek, l1 * l2);
|
|
if (typeof b === "string") {
|
|
SAEF_warn("SAEF_ZFile_fread() string");
|
|
return 0;
|
|
} else {
|
|
var o = z.seek;
|
|
if (typeof z.data === "string") {
|
|
while (l-- > 0)
|
|
b[bo++] = z.data.charCodeAt(o++);
|
|
} else {
|
|
while (l-- > 0)
|
|
b[bo++] = z.data[o++];
|
|
}
|
|
}
|
|
z.seek += l1 * l2;
|
|
return l2;
|
|
}
|
|
|
|
function SAEF_ZFile_fwrite(b,bo, l1, l2, z) {
|
|
var off = z.seek + l1 * l2;
|
|
if (z.allocsize == 0) {
|
|
SAEF_warn("SAEF_ZFile_fwrite() allocsize == 0, aborting...");
|
|
return 0;
|
|
}
|
|
if (off > z.allocsize) {
|
|
//if (z.allocsize < off)
|
|
z.allocsize = off;
|
|
z.allocsize += Math.floor(z.size / 2);
|
|
if (z.allocsize < 10000)
|
|
z.allocsize = 10000;
|
|
|
|
SAEF_log("SAEF_ZFile_fwrite() relocate %d -> %d bytes", z.size, z.allocsize);
|
|
var tmp = new Uint8Array(z.allocsize);
|
|
tmp.cpy(z.data, z.size);
|
|
z.data = tmp;
|
|
z.datasize = z.size = off;
|
|
}
|
|
//memcpy(z.data + z.seek, b, l1 * l2);
|
|
if (typeof b === "string") {
|
|
SAEF_warn("SAEF_ZFile_fwrite() string");
|
|
return 0;
|
|
} else {
|
|
var l = l1 * l2;
|
|
if (typeof z.data === "string") {
|
|
var txt = "", len = l;
|
|
while (l-- > 0) txt += String.fromCharCode(b[bo++]);
|
|
var tmp = z.data.substr(0, z.seek) + txt + z.data.substr(z.seek + len);
|
|
z.data = tmp;
|
|
} else {
|
|
var o = z.seek;
|
|
while (l-- > 0)
|
|
z.data[o++] = b[bo++];
|
|
}
|
|
}
|
|
z.seek += l1 * l2;
|
|
if (z.seek > z.size)
|
|
z.size = z.seek;
|
|
if (z.size > z.datasize)
|
|
z.datasize = z.size;
|
|
return l2;
|
|
}*/
|
|
|
|
function SAEF_ZFile_fread(b,bo, l1, l2, z) {
|
|
if (z.datasize < z.size && z.seek + l1 * l2 > z.datasize) {
|
|
SAEF_warn("SAEF_ZFile_fread() read beyond size");
|
|
return 0;
|
|
}
|
|
if (z.seek + l1 * l2 > z.size) {
|
|
l2 = l1 ? Math.truncate((z.size - z.seek) / l1) : 0;
|
|
if (l2 < 0) l2 = 0;
|
|
}
|
|
b.set(z.data.subarray(z.seek, z.seek + l1 * l2), bo); //memcpy (b, z.data + z.offset + z.seek, l1 * l2);
|
|
z.seek += l1 * l2;
|
|
return l2;
|
|
}
|
|
|
|
function SAEF_ZFile_fwrite(b,bo, l1, l2, z) {
|
|
var off = z.seek + l1 * l2; //s64
|
|
if (z.allocsize == 0) {
|
|
SAEF_warn("SAEF_ZFile_fwrite() allocsize == 0, aborting...");
|
|
return 0;
|
|
}
|
|
if (off > z.allocsize) {
|
|
if (z.allocsize < off)
|
|
z.allocsize = off;
|
|
z.allocsize += (z.size >> 1);
|
|
if (z.allocsize < 10000)
|
|
z.allocsize = 10000;
|
|
|
|
//z.data = xrealloc (uae_u8, z.data, z.allocsize);
|
|
|
|
SAEF_log("SAEF_ZFile_fwrite() relocate %d -> %d bytes", z.size, z.allocsize);
|
|
var tmp = new Uint8Array(z.allocsize);
|
|
tmp.set(z.data);
|
|
z.data = tmp;
|
|
|
|
z.datasize = z.size = off;
|
|
}
|
|
|
|
z.data.set(b.subarray(bo, bo + l1 * l2), z.seek); //memcpy (z.data + z.seek, b, l1 * l2);
|
|
|
|
z.seek += l1 * l2;
|
|
if (z.seek > z.size)
|
|
z.size = z.seek;
|
|
if (z.size > z.datasize)
|
|
z.datasize = z.size;
|
|
return l2;
|
|
}
|
|
|
|
/*---------------------------------*/
|
|
|
|
/*function SAEF_ZFile_ferror(z) {
|
|
return 0;
|
|
}*/
|
|
|
|
function SAEF_ZFile_getdata(z, offset, len) {
|
|
var pos = SAEF_ZFile_ftell(z);
|
|
if (len < 0) {
|
|
SAEF_ZFile_fseek(z, 0, SEEK_END);
|
|
len = SAEF_ZFile_ftell(z);
|
|
SAEF_ZFile_fseek(z, 0, SEEK_SET);
|
|
}
|
|
var b = new Uint8Array(len);
|
|
SAEF_ZFile_fseek(z, offset, SEEK_SET);
|
|
SAEF_ZFile_fread(b,0, len, 1, z);
|
|
SAEF_ZFile_fseek(z, pos, SEEK_SET);
|
|
return b;
|
|
}
|
|
|
|
function SAEF_ZFile_getname(f) {
|
|
return f ? f.name : null;
|
|
}
|
|
|
|
function SAEF_ZFile_getoriginalname(f) {
|
|
return f ? f.originalname : null;
|
|
}
|
|
|
|
function SAEF_ZFile_getfilename(f) {
|
|
/*if (!f.name.length)
|
|
return null;
|
|
for (var i = f.name.length - 1; i >= 0; i--) {
|
|
if (f.name[i] == '\\' || f.name[i] == '/' || f.name[i] == ':') {
|
|
i++;
|
|
return &f.name[i];
|
|
}
|
|
}*/
|
|
return f.name;
|
|
}
|
|
|
|
/*---------------------------------*/
|
|
|
|
function SAEF_ZFile_crc32(f) {
|
|
if (f === null)
|
|
return 0;
|
|
//if (f.dataBuffer)
|
|
return SAEF_crc32(f.data,0, f.size);
|
|
|
|
/*var pos = SAEF_ZFile_ftell (f);
|
|
SAEF_ZFile_fseek (f, 0, SEEK_END);
|
|
var size = SAEF_ZFile_ftell (f);
|
|
var p = xmalloc (uae_u8, size);
|
|
if (!p)
|
|
return 0;
|
|
memset (p, 0, size);
|
|
SAEF_ZFile_fseek (f, 0, SEEK_SET);
|
|
SAEF_ZFile_fread (p, 1, size, f);
|
|
SAEF_ZFile_fseek (f, pos, SEEK_SET);
|
|
var crc = p.crc32(size);
|
|
xfree (p);
|
|
return crc;*/
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
/*-----------------------------------------------------------------------*/
|
|
/*-----------------------------------------------------------------------*/
|
|
/* some testing stuff */
|
|
|
|
function CreateEvent(lpEventAttributes, bManualReset, bInitialState, lpName) {
|
|
var hEvent = new uae_sem_t();
|
|
hEvent.manual = bManualReset != 0;
|
|
hEvent.signaled = bInitialState != 0;
|
|
return hEvent;
|
|
}
|
|
|
|
function SetEvent(hEvent) {
|
|
hEvent.signaled = true;
|
|
return true;
|
|
}
|
|
|
|
function ResetEvent(hEvent) {
|
|
hEvent.signaled = false;
|
|
return true;
|
|
}
|
|
|
|
const INFINITE = 0xFFFFFFFF;
|
|
const WAIT_ABANDONED = 0x00000080;
|
|
const WAIT_OBJECT_0 = 0x00000000;
|
|
const WAIT_TIMEOUT = 0x00000102;
|
|
const WAIT_FAILED = 0xFFFFFFFF;
|
|
|
|
function WaitForSingleObject(hEvent, dwMilliseconds) {
|
|
if (!hEvent.signaled) {
|
|
if (dwMilliseconds == INFINITE) {
|
|
var cnt = 0;
|
|
while (!hEvent.signaled && cnt++ < 200)
|
|
SAEF_sleep(5);
|
|
}
|
|
else if (dwMilliseconds > 0)
|
|
SAEF_sleep(dwMilliseconds);
|
|
}
|
|
if (hEvent.signaled) {
|
|
if (!hEvent.manual) //&& waiting > 0
|
|
ResetEvent(hEvent);
|
|
|
|
return WAIT_OBJECT_0;
|
|
}
|
|
return WAIT_TIMEOUT;
|
|
}
|
|
|
|
/*---------------------------------*/
|
|
|
|
function uae_sem_init(event, manual_reset, initial_state) {
|
|
if (event.handle) {
|
|
if (initial_state)
|
|
SetEvent(event.handle);
|
|
else
|
|
ResetEvent(event.handle);
|
|
} else
|
|
event.handle = CreateEvent(null, manual_reset, initial_state, null);
|
|
}
|
|
|
|
function uae_sem_wait(event) {
|
|
WaitForSingleObject(event.handle, INFINITE);
|
|
}
|
|
|
|
function uae_sem_post(event) {
|
|
SetEvent(event.handle);
|
|
}
|
|
|
|
/*function uae_sem_trywait(event) {
|
|
return WaitForSingleObject(event.handle, 0) == WAIT_OBJECT_0 ? 0 : -1;
|
|
}*/
|
|
|
|
/*function uae_sem_destroy(event) {
|
|
if (event.handle) {
|
|
//CloseHandle(event);
|
|
event.handle = null;
|
|
}
|
|
}*/
|
|
|
|
/*---------------------------------*/
|
|
|
|
//typedef HANDLE uae_sem_t;
|
|
//typedef HANDLE uae_thread_id;
|
|
function uae_sem_t() {
|
|
this.value = null;
|
|
this.manual = false;
|
|
this.signaled = false;
|
|
}
|
|
|
|
/*typedef union {
|
|
int i;
|
|
uae_u32 u32;
|
|
void *pv;
|
|
} uae_pt;*/
|
|
|
|
function smp_comm_pipe() {
|
|
//this.lock = new uae_sem_t();
|
|
//this.reader_wait = new uae_sem_t();
|
|
//this.writer_wait = new uae_sem_t();
|
|
this.lock = { handle:null };
|
|
this.reader_wait = { handle:null };
|
|
this.writer_wait = { handle:null };
|
|
this.data = null; //uae_pt *
|
|
this.dataView = null; //OWN
|
|
this.size = 0;
|
|
this.chunks = 0;
|
|
this.rdp = 0; //volatile
|
|
this.wrp = 0; //volatile
|
|
this.reader_waiting = 0; //volatile
|
|
this.writer_waiting = 0; //volatile
|
|
}
|
|
|
|
function init_comm_pipe(p, size, chunks) {
|
|
//p.data = (uae_pt *)malloc (size*sizeof (uae_pt));
|
|
p.lock = { handle:null };
|
|
p.reader_wait = { handle:null };
|
|
p.writer_wait = { handle:null };
|
|
p.data = new ArrayBuffer(size * 4);
|
|
p.dataView = new DataView(p.data);
|
|
p.size = size;
|
|
p.chunks = chunks;
|
|
p.rdp = p.wrp = 0;
|
|
p.reader_waiting = 0;
|
|
p.writer_waiting = 0;
|
|
uae_sem_init(p.lock, 0, 1);
|
|
uae_sem_init(p.reader_wait, 0, 0);
|
|
uae_sem_init(p.writer_wait, 0, 0);
|
|
}
|
|
|
|
/*function destroy_comm_pipe(p) {
|
|
uae_sem_destroy(p.lock);
|
|
uae_sem_destroy(p.reader_wait);
|
|
uae_sem_destroy(p.writer_wait);
|
|
}*/
|
|
|
|
/*function comm_pipe_has_data(p) {
|
|
return p.rdp != p.wrp;
|
|
}*/
|
|
|
|
function read_comm_pipe_pt_blocking(p, type) {
|
|
var data;
|
|
|
|
uae_sem_wait(p.lock);
|
|
if (p.rdp == p.wrp) {
|
|
/* Pipe empty */
|
|
p.reader_waiting = 1;
|
|
uae_sem_post(p.lock);
|
|
uae_sem_wait(p.reader_wait);
|
|
uae_sem_wait(p.lock);
|
|
}
|
|
switch (type) {
|
|
case 1: data = p.dataView.getInt32(p.rdp << 2, false); break;
|
|
case 2:
|
|
case 3: data = p.dataView.getUint32(p.rdp << 2, false); break;
|
|
}
|
|
p.rdp = (p.rdp + 1) % p.size;
|
|
|
|
/* We ignore chunks here. If this is a problem, make the size bigger in the init call. */
|
|
if (p.writer_waiting) {
|
|
p.writer_waiting = 0;
|
|
uae_sem_post(p.writer_wait);
|
|
}
|
|
uae_sem_post(p.lock);
|
|
return data;
|
|
}
|
|
function read_comm_pipe_int_blocking(p) {
|
|
//var foo = read_comm_pipe_pt_blocking(p); return foo.i;
|
|
return read_comm_pipe_pt_blocking(p, 1);
|
|
}
|
|
function read_comm_pipe_u32_blocking(p) {
|
|
//var foo = read_comm_pipe_pt_blocking(p); return foo.u32;
|
|
return read_comm_pipe_pt_blocking(p, 2);
|
|
}
|
|
function read_comm_pipe_pvoid_blocking(p) {
|
|
//var foo = read_comm_pipe_pt_blocking(p); return foo.pv;
|
|
return read_comm_pipe_pt_blocking(p, 3);
|
|
}
|
|
|
|
function maybe_wake_reader(p, no_buffer) {
|
|
if (p.reader_waiting && (no_buffer || ((p.wrp - p.rdp + p.size) % p.size) >= p.chunks)) {
|
|
p.reader_waiting = 0;
|
|
uae_sem_post(p.reader_wait);
|
|
}
|
|
}
|
|
function write_comm_pipe_pt(p, type, data, no_buffer) {
|
|
var nxwrp = (p.wrp + 1) % p.size;
|
|
|
|
if (p.reader_waiting) {
|
|
/* No need to do all the locking */
|
|
switch (type) {
|
|
case 1: p.dataView.setInt32(p.wrp << 2, data, SAEC_LITTLE_ENDIAN); break;
|
|
case 2:
|
|
case 3: p.dataView.setUint32(p.wrp << 2, data, SAEC_LITTLE_ENDIAN); break;
|
|
}
|
|
p.wrp = nxwrp;
|
|
maybe_wake_reader(p, no_buffer);
|
|
return;
|
|
}
|
|
uae_sem_wait(p.lock);
|
|
if (nxwrp == p.rdp) {
|
|
/* Pipe full */
|
|
p.writer_waiting = 1;
|
|
uae_sem_post(p.lock);
|
|
uae_sem_wait(p.writer_wait);
|
|
uae_sem_wait(p.lock);
|
|
}
|
|
switch (type) {
|
|
case 1: p.dataView.setInt32(p.wrp << 2, data, SAEC_LITTLE_ENDIAN); break;
|
|
case 2:
|
|
case 3: p.dataView.setUint32(p.wrp << 2, data, SAEC_LITTLE_ENDIAN); break;
|
|
}
|
|
p.wrp = nxwrp;
|
|
maybe_wake_reader(p, no_buffer);
|
|
uae_sem_post(p.lock);
|
|
}
|
|
function write_comm_pipe_int(p, data, no_buffer) {
|
|
//var foo; foo.i = data; write_comm_pipe_pt(p, foo, no_buffer);
|
|
write_comm_pipe_pt(p, 1, data, no_buffer);
|
|
}
|
|
function write_comm_pipe_u32(p, data, no_buffer) {
|
|
//var foo; foo.u32 = data; write_comm_pipe_pt(p, foo, no_buffer);
|
|
write_comm_pipe_pt(p, 2, data, no_buffer);
|
|
}
|
|
function write_comm_pipe_pvoid (p, data, no_buffer) {
|
|
//var foo; foo.pv = data; write_comm_pipe_pt(p, foo, no_buffer);
|
|
write_comm_pipe_pt(p, 3, data, no_buffer);
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
|
|
//extern HANDLE AVTask;
|
|
|
|
//typedef unsigned (__stdcall *BEGINTHREADEX_FUNCPTR)(void *);
|
|
|
|
/*struct thparms {
|
|
void *(*f)(void*);
|
|
void *arg;
|
|
};
|
|
|
|
static unsigned __stdcall thread_init (void *f) {
|
|
struct thparms *thp = (struct thparms*)f;
|
|
void *(*fp)(void*) = thp->f;
|
|
void *arg = thp->arg;
|
|
|
|
xfree (f);
|
|
|
|
__try {
|
|
fp (arg);
|
|
} __except (WIN32_ExceptionFilter (GetExceptionInformation (), GetExceptionCode ())) {}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void uae_end_thread (uae_thread_id *tid) {
|
|
if (tid) {
|
|
CloseHandle (*tid);
|
|
*tid = NULL;
|
|
}
|
|
}
|
|
|
|
STATIC_INLINE void uae_wait_thread (uae_thread_id tid)
|
|
{
|
|
WaitForSingleObject (tid, INFINITE);
|
|
CloseHandle (tid);
|
|
}
|
|
|
|
int uae_start_thread (const TCHAR *name, void *(*f)(void *), void *arg, uae_thread_id *tid) {
|
|
HANDLE hThread;
|
|
int result = 1;
|
|
unsigned foo;
|
|
struct thparms *thp;
|
|
|
|
thp = xmalloc (struct thparms, 1);
|
|
thp->f = f;
|
|
thp->arg = arg;
|
|
hThread = (HANDLE)_beginthreadex (NULL, 0, thread_init, thp, 0, &foo);
|
|
if (hThread) {
|
|
if (name) {
|
|
//write_log (_T("Thread '%s' started (%d)\n"), name, hThread);
|
|
if (!AVTask) {
|
|
SetThreadPriority (hThread, THREAD_PRIORITY_HIGHEST);
|
|
} else {
|
|
AvSetMmThreadPriority(AVTask, AVRT_PRIORITY_HIGH);
|
|
}
|
|
}
|
|
} else {
|
|
result = 0;
|
|
write_log (_T("Thread '%s' failed to start!?\n"), name ? name : _T("<unknown>"));
|
|
}
|
|
if (tid)
|
|
*tid = hThread;
|
|
else
|
|
CloseHandle (hThread);
|
|
return result;
|
|
}*/
|
|
|
|
/*int uae_start_thread_fast (void *(*f)(void *), void *arg, uae_thread_id *tid) {
|
|
int v = uae_start_thread (NULL, f, arg, tid);
|
|
if (*tid) {
|
|
if (!AVTask) {
|
|
SetThreadPriority (*tid, THREAD_PRIORITY_HIGHEST);
|
|
} else {
|
|
AvSetMmThreadPriority(AVTask, AVRT_PRIORITY_HIGH);
|
|
}
|
|
}
|
|
return v;
|
|
}*/
|
|
|
|
/*DWORD_PTR cpu_affinity = 1, cpu_paffinity = 1;
|
|
void uae_set_thread_priority (uae_thread_id *tid, int pri) {
|
|
#if 0
|
|
int pri2;
|
|
HANDLE th;
|
|
|
|
if (tid)
|
|
th = *tid;
|
|
else
|
|
th = GetCurrentThread ();
|
|
pri2 = GetThreadPriority (th);
|
|
if (pri2 == THREAD_PRIORITY_ERROR_RETURN)
|
|
pri2 = 0;
|
|
if (pri > 0)
|
|
pri2 = THREAD_PRIORITY_HIGHEST;
|
|
else
|
|
pri2 = THREAD_PRIORITY_ABOVE_NORMAL;
|
|
pri2 += pri;
|
|
if (pri2 > 1)
|
|
pri2 = 1;
|
|
if (pri2 < -1)
|
|
pri2 = -1;
|
|
SetThreadPriority (th, pri2);
|
|
#endif
|
|
if (!AVTask) {
|
|
if (!SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_HIGHEST))
|
|
SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
|
|
} else {
|
|
AvSetMmThreadPriority(AVTask, AVRT_PRIORITY_HIGH);
|
|
}
|
|
}*/
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
|