ScriptedAmigaEmulator/sae/hardfile.js
Rupert Hausberger fbf36a4fa5 update 0.9.0
2016-07-15 19:44:16 +02:00

1339 lines
39 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.
|
| Note: ported from WinUAE 3.2.x
-------------------------------------------------------------------------*/
function SAEO_Hardfile_Data() { //hardfiledata
this.virtsize = 0; //u64, virtual size
this.physsize = 0; //u64, physical size (dynamic disk)
this.offset = 0; //u64
this.ci = new SAEO_Config_Mount_Info();
this.handle = null; //struct hardfilehandle *
this.handle_valid = 0;
//this.dangerous = 0;
//this.flags = 0;
this.cache = null; //u8 *
this.cache_valid = 0;
this.cache_offset = 0; //u64
this.vendor_id = ""; //[8 + 1]
this.product_id = ""; //[16 + 1]
this.product_rev = ""; //[4 + 1]
// geometry from possible RDSK block
//int rdbcylinders;
//int rdbsectors;
//int rdbheads;
this.virtual_rdb = null;
this.virtual_size = 0; //u64
//int unitnum; //FS
this.byteswap = false;
this.adide = false;
this.hfd_type = 0;
//virtual hard disk
this.vhd_header = null;
this.vhd_bamoffset = 0; //u32
this.vhd_bamsize = 0; //u32
this.vhd_blocksize = 0; //u32
this.vhd_sectormap = null;
this.vhd_sectormapblock = 0; //u64
this.vhd_bitmapsize = 0; //u32
this.vhd_footerblock = 0; //u64
//void *chd_handle;
this.drive_empty = false;
//TCHAR *emptyname;
};
function SAEO_Hardfile_Data_HD() { //hd_hardfiledata
this.hfd = new SAEO_Hardfile_Data();
this.size = 0; //u64
this.cyls = 0;
this.heads = 0;
this.secspertrack = 0;
this.cyls_def = 0;
this.secspertrack_def = 0;
this.heads_def = 0;
this.ansi_version = 0;
};
/*---------------------------------*/
function SAEO_Hardfile() {
const HFD_VHD_FIXED = 2;
const HFD_VHD_DYNAMIC = 3;
//const WITH_CHD = 1;
//const HFD_CHD_HD = 4;
//const HFD_CHD_OTHER = 5;
/*---------------------------------*/
function getchsgeometry(size, ptr, mode) { //int *pcyl, int *phead, int *psectorspertrack, int mode) {
var spt, head, cyl;
var total = Math.floor(size / 512);
if (typeof mode == "undefined") mode = 0;
if (mode == 1) {
// old-style head=1, spt=32 always mode
head = 1;
spt = 32;
cyl = Math.floor(total / (head * spt));
} else {
var sptt = new Array(4);
sptt[0] = 63;
sptt[1] = 127;
sptt[2] = 255;
sptt[3] = -1;
for (var i = 0; sptt[i] >= 0; i++) {
var maxhead = sptt[i] < 255 ? 16 : 255;
spt = sptt[i];
for (head = 4; head <= maxhead; head++) {
cyl = Math.floor(total / (head * spt));
if (size <= 512 * 1024 * 1024) {
if (cyl <= 1023)
break;
} else {
if (cyl < 16383)
break;
if (cyl < 32767 && head >= 5)
break;
if (cyl <= 65535)
break;
}
if (maxhead > 16) {
head *= 2;
head--;
}
}
if (head <= 16)
break;
}
}
if (head > 16)
head--;
ptr.cyl = cyl;
ptr.head = head;
ptr.sectorspertrack = spt;
}
/*void getchsgeometry_hdf(struct hardfiledata *hfd, uae_u64 size, int *pcyl, int *phead, int *psectorspertrack) {
uae_u8 block[512];
int i;
uae_u64 minsize = 512 * 1024 * 1024;
if (size <= minsize) {
*phead = 1;
*psectorspertrack = 32;
}
memset (block, 0, sizeof block);
if (hfd) {
hdf_read(hfd, block, 0, 512);
if (block[0] == 'D' && block[1] == 'O' && block[2] == 'S') {
int mode;
for (mode = 0; mode < 2; mode++) {
uae_u32 rootblock;
uae_u32 chk = 0;
getchsgeometry(size, pcyl, phead, psectorspertrack, mode);
rootblock = (2 + ((*pcyl) * (*phead) * (*psectorspertrack) - 1)) / 2;
memset (block, 0, sizeof block);
hdf_read(hfd, block, (uae_u64)rootblock * 512, 512);
for (i = 0; i < 512; i += 4)
chk += (block[i] << 24) | (block[i + 1] << 16) | (block[i + 2] << 8) | (block[i + 3] << 0);
if (!chk && block[0] == 0 && block[1] == 0 && block[2] == 0 && block[3] == 2 &&
block[4] == 0 && block[5] == 0 && block[6] == 0 && block[7] == 0 &&
block[8] == 0 && block[9] == 0 && block[10] == 0 && block[11] == 0 &&
block[508] == 0 && block[509] == 0 && block[510] == 0 && block[511] == 1) {
return;
}
}
}
}
getchsgeometry(size, pcyl, phead, psectorspertrack, size <= minsize ? 1 : 2);
}*/
function getchspgeometry(total, ptr, idegeometry) { //, int *pcyl, int *phead, int *psectorspertrack, bool idegeometry)
blocks = Math.floor(total / 512);
if (blocks > 16515072) {
/* >8G, CHS=16383/16/63 */
ptr.cyl = 16383;
ptr.head = 16;
ptr.sectorspertrack = 63;
return;
}
if (idegeometry) {
ptr.head = 16;
ptr.sectorspertrack = 63;
ptr.cyl = Math.floor(blocks / (ptr.sectorspertrack * ptr.head));
return;
}
//getchsgeometry(total, pcyl, phead, psectorspertrack);
getchsgeometry(total, ptr);
}
function getchshd(hfd, ptr) { //int *pcyl, int *phead, int *psectorspertrack) {
//getchspgeometry(hfd.virtsize, pcyl, phead, psectorspertrack, false);
getchspgeometry(hfd.virtsize, ptr, false);
}
/*---------------------------------*/
function gl(p, po) { //OPT
return ((p[po] << 24) | (p[po+1] << 16) | (p[po+2] << 8) | p[po+3]) >>> 0;
}
/*-----------------------------------------------------------------------*/
function rl(p, po) {
po <<= 2;
return ((p[po] << 24) | (p[po+1] << 16) | (p[po+2] << 8) | p[po+3]) >>> 0;
}
function pl(p, po, v) {
po <<= 2;
p[po ] = v >>> 24;
p[po+1] = (v >>> 16) & 0xff;
p[po+2] = (v >>> 8) & 0xff;
p[po+3] = v & 0xff;
}
function ps(p, po, max, src) { //OWN
const space = ' '.charCodeAt(0);
var len = src.length;
po <<= 2;
p[po++] = Math.min(len, max);
for (var i = 0; i < max; i++)
p[po++] = i < len ? src.charCodeAt(i) : space;
}
function rdb_crc(p,po) {
var sum = 0; //u32
var blocksize = rl(p, po + 1);
for (var i = 0; i < blocksize; i++) {
sum += rl(p, po + i);
if (sum > 0xffffffff) sum -= 0x100000000;
}
sum = -sum; if (sum < 0) sum += 0x100000000;
pl(p, po + 2, sum);
}
function create_virtual_rdb(hfd) {
var cyl = hfd.ci.surfaces * hfd.ci.sectors;
var cyls = 262144 / (cyl * 512);
var size = cyl * cyls * 512;
SAEF_log("hardfile.create_virtual_rdb() cyl %d, cyls %d, size %d", cyl, cyls, size);
var rdb = new Uint8Array(size);
SAEF_memset(rdb,0, 0, size); //OWN
hfd.virtual_rdb = rdb;
hfd.virtual_size = size;
pl(rdb, 0, 0x5244534b);
pl(rdb, 1, 64);
pl(rdb, 2, 0); // chksum
pl(rdb, 3, 7); // hostid
pl(rdb, 4, 512); // blockbytes
pl(rdb, 5, 0); // flags
pl(rdb, 6, -1); // badblock
pl(rdb, 7, 1); // part
pl(rdb, 8, -1); // fs
pl(rdb, 9, -1); // driveinit
pl(rdb, 10, -1); // reserved
pl(rdb, 11, -1); // reserved
pl(rdb, 12, -1); // reserved
pl(rdb, 13, -1); // reserved
pl(rdb, 14, -1); // reserved
pl(rdb, 15, -1); // reserved
pl(rdb, 16, hfd.ci.highcyl);
pl(rdb, 17, hfd.ci.sectors);
pl(rdb, 18, hfd.ci.surfaces);
pl(rdb, 19, hfd.ci.interleave ? 1 : 0); // interleave
pl(rdb, 20, 0); // park
pl(rdb, 21, -1); // res
pl(rdb, 22, -1); // res
pl(rdb, 23, -1); // res
pl(rdb, 24, 0); // writeprecomp
pl(rdb, 25, 0); // reducedwrite
pl(rdb, 26, 0); // steprate
pl(rdb, 27, -1); // res
pl(rdb, 28, -1); // res
pl(rdb, 29, -1); // res
pl(rdb, 30, -1); // res
pl(rdb, 31, -1); // res
pl(rdb, 32, 0); // rdbblockslo
pl(rdb, 33, cyl * cyls); // rdbblockshi
pl(rdb, 34, cyls); // locyl
pl(rdb, 35, hfd.ci.highcyl + cyls); // hicyl
pl(rdb, 36, cyl); // cylblocks
pl(rdb, 37, 0); // autopark
pl(rdb, 38, 2); // highrdskblock
pl(rdb, 39, -1); // res
ps(rdb, 40, 8, hfd.vendor_id);
ps(rdb, 42, 16, hfd.product_id);
ps(rdb, 46, 4, hfd.product_rev);
rdb_crc(rdb, 0);
//var part = rdb + 512;
var part = 512 >> 2;
pl(rdb, part+0, 0x50415254);
pl(rdb, part+1, 64);
pl(rdb, part+2, 0);
pl(rdb, part+3, 0);
pl(rdb, part+4, -1);
pl(rdb, part+5, 1); // 1 = bootable, 3 = bootable + noautomount
pl(rdb, part+6, -1);
pl(rdb, part+7, -1);
pl(rdb, part+8, 0); // devflags
ps(rdb, part+9, 30, hfd.ci.devname);
//denv = part + 128;
var denv = part + (128 >> 2);
pl(rdb, denv+0, 80);
pl(rdb, denv+1, 512 >> 2);
pl(rdb, denv+2, 0); // secorg
pl(rdb, denv+3, hfd.ci.surfaces);
pl(rdb, denv+4, hfd.ci.blocksize >> 9); // / 512);
pl(rdb, denv+5, hfd.ci.sectors);
pl(rdb, denv+6, hfd.ci.reserved);
pl(rdb, denv+7, 0); // prealloc
pl(rdb, denv+8, hfd.ci.interleave ? 1 : 0); // interleave
pl(rdb, denv+9, cyls); // lowcyl
pl(rdb, denv+10, hfd.ci.highcyl + cyls - 1);
pl(rdb, denv+11, hfd.ci.buffers);
pl(rdb, denv+12, hfd.ci.bufmemtype);
pl(rdb, denv+13, hfd.ci.maxtransfer);
pl(rdb, denv+14, hfd.ci.mask);
pl(rdb, denv+15, hfd.ci.bootpri);
pl(rdb, denv+16, hfd.ci.dostype);
rdb_crc(rdb, part);
hfd.virtsize += size;
}
/*-----------------------------------------------------------------------*/
this.hdf_hd_open = function(hfd) {
if (hdf_open(hfd.hfd) <= 0)
return 0;
var ci = hfd.hfd.ci;
if (ci.physical_geometry) {
hfd.cyls = ci.pcyls;
hfd.heads = ci.pheads;
hfd.secspertrack = ci.psecs;
} else if (ci.highcyl && ci.surfaces && ci.sectors) {
hfd.cyls = ci.highcyl;
hfd.heads = ci.surfaces;
hfd.secspertrack = ci.sectors;
} else {
var ptr = {};
getchshd(hfd.hfd, ptr); //&hfd.cyls, &hfd.heads, &hfd.secspertrack);
hfd.cyls = ptr.cyl;
hfd.heads = ptr.head;
hfd.secspertrack = ptr.sectorspertrack;
}
hfd.cyls_def = hfd.cyls;
hfd.secspertrack_def = hfd.secspertrack;
hfd.heads_def = hfd.heads;
if (ci.surfaces && ci.sectors) {
var buf = new Uint8Array(512); buf[0] = 0;
this.hdf_read(hfd.hfd, buf, 0, 512);
if (buf[0] != 0 && SAEF_CompareArray(buf, SAEF_String2Array("RDSK"), 4) != 0) {
ci.highcyl = Math.floor(Math.floor(hfd.hfd.virtsize / ci.blocksize) / (ci.sectors * ci.surfaces));
ci.dostype = rl(buf,0);
SAEF_warn("hardfile.hdf_hd_open() no RDSK, dostype 0x%08x, highcyl %d", ci.dostype, ci.highcyl);
create_virtual_rdb(hfd.hfd);
while (ci.highcyl * ci.surfaces * ci.sectors > hfd.cyls_def * hfd.secspertrack_def * hfd.heads_def)
hfd.cyls_def++;
}
}
hfd.size = hfd.hfd.virtsize;
return 1;
}
this.hdf_hd_close = function(hfd) {
if (hfd !== null)
hdf_close(hfd.hfd);
}
/*-----------------------------------------------------------------------*/
//function hdf_open(hfd, pname) {
function hdf_open(hfd, file) {
if (typeof file == "undefined") file = null;
//if ((!pname || pname[0] == 0) && hfd.ci.rootdir[0] == 0)
//if (!pname) pname = hfd.ci.rootdir;
if (file === null) { //OWN
if (hfd.ci.file.size == 0)
return 0;
file = hfd.ci.file.clone();
}
hfd.byteswap = false;
hfd.adide = false;
hfd.hfd_type = 0;
/*#ifdef WITH_CHD
TCHAR nametmp[MAX_DPATH];
_tcscpy (nametmp, pname);
TCHAR *ext = _tcsrchr (nametmp, '.');
if (ext && !_tcsicmp (ext, _T(".chd"))) {
bool chd_readonly = false;
struct zfile *zf = null;
if (!hfd.ci.readonly)
zf = SAEF_ZFile_fopen(nametmp, "rb+");
if (!zf) {
chd_readonly = true;
zf = SAEF_ZFile_fopen(nametmp, "rb");
}
if (zf) {
int err = CHDERR_FILE_NOT_WRITEABLE;
hard_disk_file *chdf;
chd_file *cf = new chd_file();
if (!chd_readonly)
err = cf.open(*zf, true, null);
if (err == CHDERR_FILE_NOT_WRITEABLE) {
chd_readonly = true;
err = cf.open(*zf, false, null);
}
if (err != CHDERR_NONE) {
SAEF_ZFile_fclose(zf);
delete cf;
goto end;
}
chdf = hard_disk_open(cf);
if (!chdf) {
hfd.ci.readonly = true;
hfd.hfd_type = HFD_CHD_OTHER;
hfd.chd_handle = cf;
} else {
hfd.hfd_type = HFD_CHD_HD;
hfd.chd_handle = chdf;
}
if (chd_readonly)
hfd.ci.readonly = true;
hfd.virtsize = cf.logical_bytes();
hfd.handle_valid = -1;
write_log(_T("CHD '%s' mounted as %s, %s.\n"), pname, chdf ? _T("HD") : _T("OTHER"), hfd.ci.readonly ? _T("read only") : _T("read/write"));
return 1;
}
}
#endif*/
var ret = hdf_open_target(hfd, file);
if (ret <= 0)
return ret;
var tmp = new Uint8Array(512);
if (hdf_read_target(hfd, tmp,0, 0, 512) != 512) {
//goto nonvhd;
SAEF_log("hardfile.hdf_open() no VHD-image, file samller than 512 bytes");
hfd.hfd_type = 0;
return 1;
}
var v = gl(tmp, 8); // features
if ((v & 3) != 2) {
SAEF_log("hardfile.hdf_open() no VHD-image, wrong file features %d != 2", v & 3);
//goto nonvhd;
hfd.hfd_type = 0;
return 1;
}
v = gl(tmp, 8 + 4); // version
if ((v >>> 16) != 1) {
SAEF_log("hardfile.hdf_open() no VHD-image, wrong file version %d != 1", v >>> 16);
//goto nonvhd;
hfd.hfd_type = 0;
return 1;
}
hfd.hfd_type = gl(tmp, 8 + 4 + 4 + 8 + 4 + 4 + 4 + 4 + 8 + 8 + 4);
if (hfd.hfd_type != HFD_VHD_FIXED && hfd.hfd_type != HFD_VHD_DYNAMIC) {
SAEF_log("hardfile.hdf_open() no VHD-image, wrong file type %d", hfd.hfd_type);
//goto nonvhd;
hfd.hfd_type = 0;
return 1;
}
v = gl(tmp, 8 + 4 + 4 + 8 + 4 + 4 + 4 + 4 + 8 + 8 + 4 + 4);
if (v == 0) {
SAEF_log("hardfile.hdf_open() no VHD-image, error 1");
//goto nonvhd;
hfd.hfd_type = 0;
return 1;
}
var cs = vhd_checksum(tmp, 8 + 4 + 4 + 8 + 4 + 4 + 4 + 4 + 8 + 8 + 4 + 4);
if (cs != v) {
SAEF_log("hardfile.hdf_open() no VHD-image, wrong file checksum 0x%08x != 0x%08x", cs, v);
//goto nonvhd;
hfd.hfd_type = 0;
return 1;
}
var tmp2 = new Uint8Array(512);
if (hdf_read_target(hfd, tmp2,0, hfd.physsize - tmp2.length, 512) != 512) {
SAEF_warn("hardfile.hdf_open() file read error");
hdf_close_target(hfd); return 0;
//goto end;
}
if (SAEF_CompareArray(tmp, tmp2) != 0) {
SAEF_log("hardfile.hdf_open() no VHD-image, error 2");
//goto nonvhd;
hfd.hfd_type = 0;
return 1;
}
hfd.vhd_footerblock = hfd.physsize - 512;
//hfd.virtsize = gl(tmp, 8 + 4 + 4 + 8 + 4 + 4 + 4 + 4 + 8) << 32; //ATT
//hfd.virtsize |= gl(tmp, 8 + 4 + 4 + 8 + 4 + 4 + 4 + 4 + 8 + 4);
hfd.virtsize = gl(tmp, 8 + 4 + 4 + 8 + 4 + 4 + 4 + 4 + 8) * 0x100000000;
hfd.virtsize += gl(tmp, 8 + 4 + 4 + 8 + 4 + 4 + 4 + 4 + 8 + 4);
if (hfd.hfd_type == HFD_VHD_DYNAMIC) {
var fail = true;
hfd.vhd_bamoffset = gl(tmp, 8 + 4 + 4 + 4);
if (hfd.vhd_bamoffset > 0 && hfd.vhd_bamoffset < hfd.physsize) {
if (hdf_read_target(hfd, tmp,0, hfd.vhd_bamoffset, 512) == 512) {
v = gl(tmp, 8 + 8 + 8 + 4 + 4 + 4);
if (vhd_checksum(tmp, 8 + 8 + 8 + 4 + 4 + 4) == v) {
v = gl(tmp, 8 + 8 + 8);
if ((v >>> 16) == 1) { //version
hfd.vhd_blocksize = gl(tmp, 8 + 8 + 8 + 4 + 4);
hfd.vhd_bamoffset = gl(tmp, 8 + 8 + 4);
hfd.vhd_bamsize = (Math.floor((hfd.virtsize + hfd.vhd_blocksize - 1) / hfd.vhd_blocksize) * 4 + 511) & ~511;
var size = hfd.vhd_bamoffset + hfd.vhd_bamsize;
hfd.vhd_header = new Uint8Array(size);
if (hdf_read_target(hfd, hfd.vhd_header,0, 0, size) == size) {
hfd.vhd_sectormap = new Uint8Array(512);
hfd.vhd_sectormapblock = -1;
hfd.vhd_bitmapsize = (Math.floor(hfd.vhd_blocksize / (8 * 512)) + 511) & ~511;
fail = false;
}
}
}
}
}
if (fail) {
hdf_close_target(hfd);
return 0;
}
}
SAEF_log("hardfile.hdf_open() HDF is VHD %s image, virtual size=%dK (%x %d)", hfd.hfd_type == HFD_VHD_FIXED ? "fixed" : "dynamic", Math.floor(hfd.virtsize / 1024), hfd.virtsize, hfd.virtsize);
hdf_init_cache(hfd);
return 1;
/*nonvhd:
hfd.hfd_type = 0;
return 1;
end:
hdf_close_target (hfd);
return 0;*/
}
function hdf_close(hfd) {
hdf_flush_cache(hfd);
hdf_close_target(hfd);
/*
#ifdef WITH_CHD
if (hfd.hfd_type == HFD_CHD_OTHER) {
chd_file *cf = (chd_file*)hfd.chd_handle;
cf.close();
delete cf;
} else if (hfd.hfd_type == HFD_CHD_HD) {
hard_disk_file *chdf = (hard_disk_file*)hfd.chd_handle;
chd_file *cf = hard_disk_get_chd(chdf);
hard_disk_close(chdf);
cf.close();
delete cf;
}
hfd.chd_handle = null;
#endif*/
hfd.hfd_type = 0;
//xfree(hfd.vhd_header);
hfd.vhd_header = null;
//xfree(hfd.vhd_sectormap);
hfd.vhd_sectormap = null;
}
/*int hdf_dup(struct hardfiledata *dhfd, const struct hardfiledata *shfd) {
return hdf_dup_target(dhfd, shfd);
}*/
/*-----------------------------------------------------------------------*/
function vhd_checksum(p, offset) {
var sum = 0; //u32
for (var i = 0; i < 512; i++) {
if (offset >= 0 && i >= offset && i < offset + 4)
continue;
sum += p[i];
if (sum > 0xffffffff) sum -= 0x100000000;
}
return ~sum >>> 0;
}
function vhd_read(hfd, data, offset, len) {
//uae_u8 *dataptr = (uae_u8*)data;
var dataptr = 0;
//SAEF_log("hardfile.vhd_read() %08x %08x", offset, len);
//SAEF_log("hardfile.vhd_read() %d %d", offset, len);
var read = 0; //u64
if (offset & 511)
return read;
if (len & 511)
return read;
while (len > 0) {
var bamoffset = Math.floor(offset / hfd.vhd_blocksize) * 4 + hfd.vhd_bamoffset; //u32
var sectoroffset = gl(hfd.vhd_header, bamoffset); //u32
if (sectoroffset == 0xffffffff) {
//memset(dataptr, 0, 512);
SAEF_memset(data,dataptr, 0, 512);
read += 512;
} else {
var bitmapoffsetbits = Math.floor(offset / 512) % (hfd.vhd_blocksize >> 9); //int
var bitmapoffsetbytes = Math.floor(bitmapoffsetbits / 8); //int
var sectormapblock = sectoroffset * 512 + (bitmapoffsetbytes & ~511); //u64
if (hfd.vhd_sectormapblock != sectormapblock) {
// read sector bitmap
//SAEF_log("hardfile.vhd_read() BM %08x", sectormapblock);
if (hdf_read_target(hfd, hfd.vhd_sectormap,0, sectormapblock, 512) != 512) {
SAEF_warn("hardfile.vhd_read() bitmap read error");
return read;
}
hfd.vhd_sectormapblock = sectormapblock;
}
// block allocated in bitmap?
if (hfd.vhd_sectormap[bitmapoffsetbytes & 511] & (1 << (7 - (bitmapoffsetbits & 7)))) {
// read data block
var block = sectoroffset * 512 + hfd.vhd_bitmapsize + bitmapoffsetbits * 512; //u64
//SAEF_log("hardfile.vhd_read() DB %08x", block);
if (hdf_read_target(hfd, data,dataptr, block, 512) != 512) {
SAEF_warn("hardfile.vhd_read() data read error");
return read;
}
} else {
//memset(dataptr, 0, 512);
SAEF_memset(data,dataptr, 0, 512);
}
read += 512;
}
len -= 512;
dataptr += 512;
offset += 512;
}
return read;
}
function vhd_write_enlarge(hfd, bamoffset) {
var len = hfd.vhd_blocksize + hfd.vhd_bitmapsize + 512;
if (!hdf_resize_target(hfd, hfd.physsize + len - 512)) {
SAEF_warn("hardfile.vhd_write_enlarge() failure");
return false;
}
// add footer (same as 512 byte header)
var buf = new Uint8Array(len);
SAEF_memset(buf,0, 0, len - 512); //OWN
buf.set(hfd.vhd_header.subarray(0, 512), len - 512); //memcpy (buf + len - 512, hfd->vhd_header, 512);
var v = hdf_write_target(hfd, buf,0, hfd.vhd_footerblock, len);
delete buf;
if (v != len) {
SAEF_warn("hardfile.vhd_write_enlarge() footer write error");
return false;
}
// write new offset to BAM
var block = Math.floor(hfd.vhd_footerblock / 512);
hfd.vhd_header[bamoffset + 0] = block >>> 24;
hfd.vhd_header[bamoffset + 1] = (block >>> 16) & 0xff;
hfd.vhd_header[bamoffset + 2] = (block >>> 8) & 0xff;
hfd.vhd_header[bamoffset + 3] = block & 0xff;
// write to disk
if (hdf_write_target(hfd, hfd.vhd_header,hfd.vhd_bamoffset, hfd.vhd_bamoffset, hfd.vhd_bamsize) != hfd.vhd_bamsize) {
SAEF_warn("hardfile.vhd_write_enlarge() bam write error");
return false;
}
hfd.vhd_footerblock += len - 512;
return true;
}
function vhd_write(hfd, data, offset, len) {
//uae_u8 *dataptr = (uae_u8*)v;
var dataptr = 0;
//SAEF_log("hardfile.vhd_read() %08x %08x", offset, len);
//SAEF_log("hardfile.vhd_write() %d %d", offset, len);
var written = 0; //u64
if (offset & 511)
return written;
if (len & 511)
return written;
while (len > 0) {
var bamoffset = Math.floor(offset / hfd.vhd_blocksize) * 4 + hfd.vhd_bamoffset; //u32
var sectoroffset = gl(hfd.vhd_header, bamoffset); //u32
if (sectoroffset == 0xffffffff) {
if (!vhd_write_enlarge(hfd, bamoffset))
return written;
continue;
} else {
var bitmapoffsetbits = Math.floor(offset / 512) % (hfd.vhd_blocksize >> 9); //int
var bitmapoffsetbytes = Math.floor(bitmapoffsetbits / 8); //int
var sectormapblock = sectoroffset * 512 + (bitmapoffsetbytes & ~511); //u64
if (hfd.vhd_sectormapblock != sectormapblock) {
// read sector bitmap
//SAEF_log("hardfile.vhd_write() BM %08x", sectormapblock);
if (hdf_read_target(hfd, hfd.vhd_sectormap,0, sectormapblock, 512) != 512) {
SAEF_warn("hardfile.vhd_write() bitmap read error");
return written;
}
hfd.vhd_sectormapblock = sectormapblock;
}
// write data
var block = sectoroffset * 512 + hfd.vhd_bitmapsize + bitmapoffsetbits * 512; //u64
//SAEF_log("hardfile.vhd_write() DB %08x", block);
if (hdf_write_target(hfd, data,dataptr, block, 512) != 512) {
SAEF_warn("hardfile.vhd_write() data write error");
return written;
}
// block already allocated in bitmap?
if (!(hfd.vhd_sectormap[bitmapoffsetbytes & 511] & (1 << (7 - (bitmapoffsetbits & 7))))) {
// no, we need to mark it allocated and write the modified bitmap back to the disk
hfd.vhd_sectormap[bitmapoffsetbytes & 511] |= (1 << (7 - (bitmapoffsetbits & 7)));
if (hdf_write_target(hfd, hfd.vhd_sectormap,0, sectormapblock, 512) != 512) {
SAEF_warn("hardfile.vhd_write() bam write error");
return written;
}
}
written += 512;
}
len -= 512;
dataptr += 512;
offset += 512;
}
return written;
}
/*int vhd_create (const TCHAR *name, uae_u64 size, uae_u32 dostype) {
struct hardfiledata hfd;
struct zfile *zf;
uae_u8 *b;
int cyl, cylsec, head, tracksec;
uae_u32 crc, blocksize, batsize, batentrysize;
int ret, i;
time_t tm;
if (size >= (uae_u64)10 * 1024 * 1024 * 1024)
blocksize = 2 * 1024 * 1024;
else
blocksize = 512 * 1024;
batsize = (size + blocksize - 1) / blocksize;
batentrysize = batsize;
batsize *= 4;
batsize += 511;
batsize &= ~511;
ret = 0;
b = NULL;
zf = SAEF_ZFile_fopen(name, "wb", 0);
if (!zf)
goto end;
b = xcalloc (uae_u8, 512 + 1024 + batsize + 512);
if (SAEF_ZFile_fwrite(b,0, 512 + 1024 + batsize + 512, 1, zf) != 1)
goto end;
memset (&hfd, 0, sizeof hfd);
hfd.virtsize = hfd.physsize = size;
hfd.ci.blocksize = 512;
strcpy ((char*)b, "conectix"); // cookie
b[0x0b] = 2; // features
b[0x0d] = 1; // version
b[0x10 + 6] = 2; // data offset
// time stamp
tm = time (NULL) - 946684800;
b[0x18] = tm >> 24;
b[0x19] = tm >> 16;
b[0x1a] = tm >> 8;
b[0x1b] = tm >> 0;
strcpy ((char*)b + 0x1c, "vpc "); // creator application
b[0x21] = 5; // creator version
strcpy ((char*)b + 0x24, "Wi2k"); // creator host os
// original and current size
b[0x28] = b[0x30] = size >> 56;
b[0x29] = b[0x31] = size >> 48;
b[0x2a] = b[0x32] = size >> 40;
b[0x2b] = b[0x33] = size >> 32;
b[0x2c] = b[0x34] = size >> 24;
b[0x2d] = b[0x35] = size >> 16;
b[0x2e] = b[0x36] = size >> 8;
b[0x2f] = b[0x37] = size >> 0;
getchs2 (&hfd, &cyl, &cylsec, &head, &tracksec);
// cylinders
b[0x38] = cyl >> 8;
b[0x39] = cyl;
// heads
b[0x3a] = head;
// sectors per track
b[0x3b] = tracksec;
// disk type
b[0x3c + 3] = HFD_VHD_DYNAMIC;
get_guid_target (b + 0x44);
crc = vhd_checksum (b, -1);
b[0x40] = crc >> 24;
b[0x41] = crc >> 16;
b[0x42] = crc >> 8;
b[0x43] = crc >> 0;
// write header
SAEF_ZFile_fseek(zf, 0, SEEK_SET);
SAEF_ZFile_fwrite(b,0, 512, 1, zf);
// write footer
SAEF_ZFile_fseek(zf, 512 + 1024 + batsize, SEEK_SET);
SAEF_ZFile_fwrite(b,0, 512, 1, zf);
// dynamic disk header
memset (b, 0, 1024);
// cookie
strcpy ((char*)b, "cxsparse");
// data offset
for (i = 0; i < 8; i++)
b[0x08 + i] = 0xff;
// table offset (bat)
b[0x10 + 6] = 0x06;
// version
b[0x19] = 1;
// max table entries
b[0x1c] = batentrysize >> 24;
b[0x1d] = batentrysize >> 16;
b[0x1e] = batentrysize >> 8;
b[0x1f] = batentrysize >> 0;
b[0x20] = blocksize >> 24;
b[0x21] = blocksize >> 16;
b[0x22] = blocksize >> 8;
b[0x23] = blocksize >> 0;
crc = vhd_checksum (b, -1);
b[0x24] = crc >> 24;
b[0x25] = crc >> 16;
b[0x26] = crc >> 8;
b[0x27] = crc >> 0;
// write dynamic header
SAEF_ZFile_fseek(zf, 512, SEEK_SET);
SAEF_ZFile_fwrite(b,0, 1024, 1, zf);
// bat
memset (b, 0, batsize);
memset (b, 0xff, batentrysize * 4);
SAEF_ZFile_fwrite(b,0, batsize, 1, zf);
SAEF_ZFile_fclose(zf);
zf = NULL;
if (dostype) {
uae_u8 bootblock[512] = { 0 };
bootblock[0] = dostype >> 24;
bootblock[1] = dostype >> 16;
bootblock[2] = dostype >> 8;
bootblock[3] = dostype >> 0;
if (hdf_open(&hfd, file) > 0) {
vhd_write(&hfd, bootblock, 0, 512);
hdf_close(&hfd);
}
}
ret = 1;
end:
xfree (b);
SAEF_ZFile_fclose(zf);
return ret;
}*/
/*-----------------------------------------------------------------------*/
function hdf_read2(hfd, buffer, offset, len) {
if (hfd.hfd_type == HFD_VHD_DYNAMIC)
return vhd_read(hfd, buffer, offset, len);
else if (hfd.hfd_type == HFD_VHD_FIXED)
return hdf_read_target(hfd, buffer,0, offset + 512, len);
/*
#ifdef WITH_CHD
else if (hfd.hfd_type == HFD_CHD_OTHER) {
chd_file *cf = (chd_file*)hfd.chd_handle;
if (cf.read_bytes(offset, buffer, len) == CHDERR_NONE)
return len;
return 0;
} else if (hfd.hfd_type == HFD_CHD_HD) {
hard_disk_file *chdf = (hard_disk_file*)hfd.chd_handle;
hard_disk_info *chdi = hard_disk_get_info(chdf);
chd_file *cf = hard_disk_get_chd(chdf);
uae_u8 *buf = (uae_u8*)buffer;
int got = 0;
offset /= chdi.sectorbytes;
while (len > 0) {
if (cf.read_units(offset, buf) != CHDERR_NONE)
return got;
got += chdi.sectorbytes;
buf += chdi.sectorbytes;
len -= chdi.sectorbytes;
offset++;
}
return got;
}
#endif*/
else
return hdf_read_target(hfd, buffer,0, offset, len);
}
function hdf_write2(hfd, buffer, offset, len) {
if (hfd.hfd_type == HFD_VHD_DYNAMIC)
return vhd_write(hfd, buffer, offset, len);
else if (hfd.hfd_type == HFD_VHD_FIXED)
return hdf_write_target(hfd, buffer,0, offset + 512, len);
/*
#ifdef WITH_CHD
else if (hfd.hfd_type == HFD_CHD_OTHER)
return 0;
else if (hfd.hfd_type == HFD_CHD_HD) {
if (hfd.ci.readonly)
return 0;
hard_disk_file *chdf = (hard_disk_file*)hfd.chd_handle;
hard_disk_info *chdi = hard_disk_get_info(chdf);
chd_file *cf = hard_disk_get_chd(chdf);
uae_u8 *buf = (uae_u8*)buffer;
int got = 0;
offset /= chdi.sectorbytes;
while (len > 0) {
if (cf.write_units(offset, buf) != CHDERR_NONE)
return got;
got += chdi.sectorbytes;
buf += chdi.sectorbytes;
len -= chdi.sectorbytes;
offset++;
}
return got;
}
#endif*/
else
return hdf_write_target(hfd, buffer,0, offset, len);
}
function hdf_cache_read(hfd, buffer, offset, len) {
return hdf_read2(hfd, buffer, offset, len);
}
function hdf_cache_write(hfd, buffer, offset, len) {
return hdf_write2(hfd, buffer, offset, len);
}
function hdf_init_cache(hfd) {}
function hdf_flush_cache(hdf) {}
/*-----------------------------------------------------------------------*/
function adide_decode(v, len) {
SAEF_warn("hardfile.adide_decode() 0x%04x %d", v, len);
/*int i;
uae_u8 *buffer = (uae_u8*)v;
for (i = 0; i < len; i += 2) {
uae_u8 *b = buffer + i;
uae_u16 w = (b[0] << 8) | (b[1] << 0);
uae_u16 o = SAER.ide.adide_decode_word(w);
b[0] = o >> 8;
b[1] = o >> 0;
}*/
}
function adide_encode(v, len) {
SAEF_warn("hardfile.adide_encode() 0x%04x %d", v, len);
/*int i;
uae_u8 *buffer = (uae_u8*)v;
for (i = 0; i < len; i += 2) {
uae_u8 *b = buffer + i;
uae_u16 w = (b[0] << 8) | (b[1] << 0);
uae_u16 o = SAER.ide.adide_encode_word(w);
b[0] = o >> 8;
b[1] = o >> 0;
}*/
}
function hdf_byteswap(v, len) {
SAEF_warn("hardfile.hdf_byteswap() 0x%04x %d", v, len);
/*int i;
uae_u8 *b = (uae_u8*)v;
for (i = 0; i < len; i += 2) {
uae_u8 tmp = b[i];
b[i] = b[i + 1];
b[i + 1] = tmp;
}*/
}
/*int hdf_read_rdb (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len) {
int v;
v = hdf_read (hfd, buffer, offset, len);
if (v > 0 && offset < 16 * 512 && !hfd.byteswap && !hfd.adide) {
uae_u8 *buf = (uae_u8*)buffer;
bool changed = false;
if (buf[0] == 0x39 && buf[1] == 0x10 && buf[2] == 0xd3 && buf[3] == 0x12) { // AdIDE encoded "CPRM"
hfd.adide = true;
changed = true;
write_log (_T("HDF: adide scrambling detected\n"));
} else if (!memcmp (buf, "DRKS", 4)) {
hfd.byteswap = true;
changed = true;
write_log (_T("HDF: byteswapped RDB detected\n"));
}
if (changed)
v = hdf_read (hfd, buffer, offset, len);
}
return v;
}*/
this.hdf_read = function(hfd, buffer, offset, len) {
var v;
//SAEF_log("hardfile.hdf_read() %04x-%08x (%d) %08x (%d)", Math.floor(offset / 0x100000000), Math.floor(offset % 0x100000000), Math.floor(offset / hfd.ci.blocksize), len >>> 0, Math.floor(len / hfd.ci.blocksize));
if (!hfd.adide) {
v = hdf_cache_read(hfd, buffer, offset, len);
} else {
offset += 512;
v = hdf_cache_read(hfd, buffer, offset, len);
adide_decode(buffer, len);
}
if (hfd.byteswap)
hdf_byteswap(buffer, len);
return v;
}
this.hdf_write = function(hfd, buffer, offset, len) {
var v;
//SAEF_log("hardfile.hdf_write() %04x-%08x (%d) %08x (%d)", Math.floor(offset / 0x100000000), Math.floor(offset % 0x100000000), Math.floor(offset / hfd.ci.blocksize), len >>> 0, Math.floor(len / hfd.ci.blocksize));
if (hfd.byteswap)
hdf_byteswap(buffer, len);
if (!hfd.adide)
v = hdf_cache_write(hfd, buffer, offset, len);
else {
offset += 512;
adide_encode(buffer, len);
v = hdf_cache_write(hfd, buffer, offset, len);
adide_decode(buffer, len);
}
if (hfd.byteswap)
hdf_byteswap(buffer, len);
return v;
}
/*-----------------------------------------------------------------------*/
/* target */
const CACHE_SIZE = 16384;
function hardfilehandle() {
this.zf = null;
this.firstwrite = false;
};
//function hdf_open_target(hfd, pname) {
function hdf_open_target(hfd, file) {
//hfd.flags = 0;
hfd.drive_empty = false;
hdf_close(hfd);
hfd.cache = new Uint8Array(CACHE_SIZE); //(uae_u8*)VirtualAlloc (null, CACHE_SIZE, MEM_COMMIT, PAGE_READWRITE);
/*if (!hfd.cache) {
SAEF_warn("VirtualAlloc(%d) failed, error %d", CACHE_SIZE, GetLastError());
hdf_close(hfd);
return -1;
}*/
hfd.cache_valid = 0;
hfd.virtual_size = 0;
hfd.virtual_rdb = null;
hfd.vendor_id = "UAE";
hfd.product_id = file.name.substr(0, Math.min(file.name.length, 16-1));
hfd.product_rev = "0.1";
SAEF_log("hardfile.hdf_open_target() attempting to open HDF '%s'... (%d bytes)", file.name, file.size);
hfd.handle = new hardfilehandle();
//hfd.handle.zf = SAEF_ZFile_fopen(pname, "rb", ZFD_NORMAL);
hfd.handle.zf = SAEF_ZFile_fopen_file(file);
if (hfd.handle.zf === null) {
hdf_close(hfd);
return -1;
}
SAEF_ZFile_fseek(hfd.handle.zf, 0, SEEK_END);
hfd.physsize = hfd.virtsize = SAEF_ZFile_ftell(hfd.handle.zf);
SAEF_ZFile_fseek(hfd.handle.zf, 0, SEEK_SET);
hfd.handle_valid = 1;
SAEF_log("hardfile.hdf_open_target() HDF '%s' opened (size %dK, empty %d)", file.name, Math.floor(hfd.physsize / 1024), hfd.drive_empty ? 1:0);
return 1;
/*if (hfd.handle_valid || hfd.drive_empty) {
SAEF_log("hardfile.hdf_open_target() HDF '%s' opened (size %dK, mode %d, empty %d)", file.name, Math.floor(hfd.physsize / 1024), hfd.handle_valid, hfd.drive_empty);
return 1;
}
hdf_close(hfd);
return -1;*/
}
function freehandle(h) {
if (h !== null) {
if (h.zf !== null) {
SAEF_ZFile_fclose(h.zf);
h.zf = null;
}
}
}
function hdf_close_target(hfd) {
freehandle(hfd.handle);
//xfree(hfd.handle);
//xfree(hfd.emptyname);
//hfd.emptyname = null;
hfd.handle = null;
hfd.handle_valid = 0;
//if (hfd.cache) VirtualFree(hfd.cache, 0, MEM_RELEASE);
hfd.cache = null;
hfd.cache_valid = 0;
//xfree(hfd.virtual_rdb);
hfd.virtual_rdb = null;
hfd.virtual_size = 0;
hfd.drive_empty = false;
//hfd.dangerous = 0;
}
/*---------------------------------*/
/*int hdf_dup_target(struct hardfiledata *dhfd, const struct hardfiledata *shfd) {
if (!shfd.handle_valid)
return 0;
freehandle (dhfd.handle);
struct zfile *zf = SAEF_ZFile_dup(shfd.handle.zf);
if (!zf)
return 0;
dhfd.handle.zf = zf;
dhfd.handle_valid = 1;
dhfd.cache = (uae_u8*)VirtualAlloc (null, CACHE_SIZE, MEM_COMMIT, PAGE_READWRITE);
dhfd.cache_valid = 0;
if (!dhfd.cache) {
hdf_close(dhfd);
return 0;
}
return 1;
}*/
function hdf_resize_target(hfd, newsize) {
/*DWORD ret, err;
if (newsize >= 0x80000000) {
LONG highword = (DWORD)(newsize >> 32);
ret = SetFilePointer (hfd.handle.h, (DWORD)newsize, &highword, FILE_BEGIN);
} else {
ret = SetFilePointer (hfd.handle.h, (DWORD)newsize, null, FILE_BEGIN);
}
err = GetLastError ();
if (ret == INVALID_SET_FILE_POINTER && err != NO_ERROR) {
write_log (_T("hdf_resize_target: SetFilePointer() %d\n"), err);
return 0;
}
if (SetEndOfFile (hfd.handle.h)) {
hfd.physsize = newsize;
return 1;
}
err = GetLastError ();
write_log (_T("hdf_resize_target: SetEndOfFile() %d\n"), err);
return 0;*/
SAEF_ZFile_resize(hfd.handle.zf, newsize);
hfd.physsize = newsize;
return true;
}
/*---------------------------------*/
function hdf_seek(hfd, offset) {
if (hfd.handle_valid == 0) {
SAEF_warn("hardfile.hdf_seek() hdf handle is not valid. bug.");
//abort();
return -1;
}
if (offset >= hfd.physsize - hfd.virtual_size) {
SAEF_warn("hardfile.hdf_seek() tried to seek out of bounds! (%X >= %X - %X)", offset, hfd.physsize, hfd.virtual_size);
//abort();
return -1;
}
offset += hfd.offset;
if (offset & (hfd.ci.blocksize - 1)) {
SAEF_warn("hardfile.hdf_seek() fail, offset = %X not aligned to blocksize %d! (%X & %04X = %04X)", offset, hfd.ci.blocksize, offset, hfd.ci.blocksize, offset & (hfd.ci.blocksize - 1));
//abort();
return -1;
}
if (SAEF_ZFile_fseek(hfd.handle.zf, offset, SEEK_SET) != 0) {
SAEF_warn("hardfile.hdf_seek() common seek error");
return -1;
}
return 0;
}
/*---------------------------------*/
function poscheck(hfd, len) {
var pos = SAEF_ZFile_ftell(hfd.handle.zf);
if (len < 0) {
SAEF_warn("hardfile.poscheck() fail, negative length! (%d)", len);
//abort();
return -1;
}
if (pos < hfd.offset) {
SAEF_warn("hardfile.poscheck() fail, offset out of bounds! (%d < %d)", pos, hfd.offset);
//abort();
return -1;
}
if (pos >= hfd.offset + hfd.physsize - hfd.virtual_size || pos >= hfd.offset + hfd.physsize + len - hfd.virtual_size) {
SAEF_warn("hardfile.poscheck() fail, offset out of bounds! (%d >= %d, LEN=%d)", pos, hfd.offset + hfd.physsize, len);
//abort();
return -1;
}
if (pos & (hfd.ci.blocksize - 1)) {
SAEF_warn("hardfile.poscheck() fail, offset not aligned to blocksize! (%X & %X = %04X)", pos, hfd.ci.blocksize, pos & hfd.ci.blocksize);
//abort();
return -1;
}
return 0;
}
/*---------------------------------*/
function isincache(hfd, offset, len) {
if (!hfd.cache_valid)
return -1;
if (offset >= hfd.cache_offset && offset + len <= hfd.cache_offset + CACHE_SIZE)
return offset - hfd.cache_offset;
return -1;
}
function hdf_read_target_2(hfd, buffer,buffero, offset, len) { //hdf_read_2()
if (offset == 0)
hfd.cache_valid = 0;
var coffset = isincache(hfd, offset, len);
if (coffset >= 0) {
buffer.set(hfd.cache.subarray(coffset, coffset + len), buffero); //memcpy (buffer, hfd->cache + coffset, len);
return len;
}
hfd.cache_offset = offset;
if (offset + CACHE_SIZE > hfd.offset + (hfd.physsize - hfd.virtual_size))
hfd.cache_offset = hfd.offset + (hfd.physsize - hfd.virtual_size) - CACHE_SIZE;
if (hdf_seek(hfd, hfd.cache_offset) == -1)
return -1;
if (poscheck(hfd, CACHE_SIZE) == -1)
return -1;
var outlen = SAEF_ZFile_fread(hfd.cache,0, 1, CACHE_SIZE, hfd.handle.zf);
hfd.cache_valid = 0;
if (outlen != CACHE_SIZE)
return 0;
hfd.cache_valid = 1;
coffset = isincache(hfd, offset, len);
if (coffset >= 0) {
buffer.set(hfd.cache.subarray(coffset, coffset + len), buffero); //memcpy (buffer, hfd->cache + coffset, len);
return len;
}
SAEF_error("hardfile.hdf_read_target_2() cache bug! offset %d, len %d", offset, len);
hfd.cache_valid = 0;
return 0;
}
function hdf_read_target(hfd, buffer,buffero, offset, len) {
var got = 0;
//var p = buffer;
var p = buffero;
if (hfd.drive_empty)
return 0;
if (offset < hfd.virtual_size) {
var len2 = offset + len <= hfd.virtual_size ? len : hfd.virtual_size - offset;
if (!hfd.virtual_rdb)
return 0;
buffer.set(hfd.virtual_rdb.subarray(offset, offset + len2), p); //memcpy(buffer, hfd.virtual_rdb + offset, len2);
return len2;
}
offset -= hfd.virtual_size;
while (len > 0) {
var maxlen;
var ret;
if (hfd.physsize < CACHE_SIZE) {
hfd.cache_valid = 0;
if (hdf_seek(hfd, offset) == -1)
return -1;
if (poscheck(hfd, len) == -1)
return -1;
ret = SAEF_ZFile_fread(buffer,p, 1, len, hfd.handle.zf);
maxlen = len;
} else {
maxlen = len > CACHE_SIZE ? CACHE_SIZE : len;
ret = hdf_read_target_2(hfd, buffer,p, offset, maxlen);
}
if (ret < 0)
return ret;
got += ret;
if (ret != maxlen)
return got;
offset += maxlen;
p += maxlen;
len -= maxlen;
}
return got;
}
/*---------------------------------*/
function hdf_write_target_2(hfd, buffer,buffero, offset, len) { //hdf_write_2()
if (hfd.ci.readonly)
return 0;
//if (hfd.dangerous)
//return 0;
hfd.cache_valid = 0;
if (hdf_seek(hfd, offset) == -1)
return -1;
if (poscheck(hfd, len) == -1)
return -1;
hfd.cache.set(buffer.subarray(buffero, buffero + len)); //memcpy(hfd.cache, buffer, len);
return SAEF_ZFile_fwrite(hfd.cache,0, 1, len, hfd.handle.zf);
}
function hdf_write_target(hfd, buffer,buffero, offset, len) {
var got = 0;
//var p = buffer;
var p = buffero;
if (hfd.drive_empty)
return 0;
if (offset < hfd.virtual_size)
return len;
offset -= hfd.virtual_size;
while (len > 0) {
var maxlen = len > CACHE_SIZE ? CACHE_SIZE : len;
var ret = hdf_write_target_2(hfd, buffer,p, offset, maxlen);
if (ret < 0)
return ret;
got += ret;
if (ret != maxlen)
return got;
offset += maxlen;
p += maxlen;
len -= maxlen;
}
return got;
}
/*-----------------------------------------------------------------------*/
this.reset = function() {} //hardfile_reset()
}