Changed save.js, fdc.js, and diskdump.js to use a shared download function

This commit is contained in:
Jeff Parsons 2016-02-23 00:06:38 -08:00
commit 255700f88a
7 changed files with 1332 additions and 1337 deletions

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -87,7 +87,7 @@ var fNormalize = true;
* BufferPF(init, start, end)
*
* BufferPF is our browser polyfill (hence the PF) for Node's Buffer class. It's basically a wrapper object
* containing a real Buffer in Node and a simulated buffer in a browser.
* containing a real Buffer in Node and a simulated buffer in the browser.
*
* This is NOT a general-purpose polyfill. It supports only those Buffer constructor calls and methods that the
* DiskDump module actually requires.
@ -311,10 +311,10 @@ BufferPF.prototype.slice = function(start, end)
/**
* DiskDump()
*
* TODO: Honor the caller's mbHD size. At the moment, any hard disk build request translates to 10Mb,
* TODO: Honor the caller's mbHD size. At the moment, any hard disk request translates to 10Mb,
* since we rely on a "canned" BPB in aDefaultBPBs.
*
* TODO: If sServerRoot is set, make sure the final sDiskPath refers to something in either /apps/ or /disks/,
* TODO: If sServerRoot is set, make sure sDiskPath refers to something in either /apps/ or /disks/,
* to prevent random enumeration of other server resources.
*
* @constructor
@ -336,7 +336,10 @@ function DiskDump(sDiskPath, asExclude, sFormat, fComments, mbHD, sServerRoot, s
* with a slash, and process.cwd() otherwise.
*/
this.sServerRoot = sServerRoot;
this.sDiskPath = (net.isRemote(sDiskPath)? sDiskPath : path.join(this.sServerRoot, sDiskPath));
this.sDiskPath = sDiskPath;
if (this.sServerRoot && !net.isRemote(sDiskPath)) {
this.sDiskPath = path.join(this.sServerRoot, sDiskPath);
}
this.asExclude = asExclude || DiskDump.asExclusions;
this.mbHD = mbHD? parseInt(mbHD, 10) : 0;
this.sFormat = (sFormat || DumpAPI.FORMAT.JSON);
@ -402,7 +405,7 @@ DiskDump.setLogFile = function(file) {
* Class constants
*/
DiskDump.sAPIURL = "http://www.pcjs.org" + DumpAPI.ENDPOINT;
DiskDump.sCopyright = "© 2012-2015 by Jeff Parsons (@jeffpar)";
DiskDump.sCopyright = "© 2012-2016 by Jeff Parsons (@jeffpar)";
DiskDump.sNotice = DiskDump.sAPIURL + " " + DiskDump.sCopyright;
DiskDump.sUsage = "Usage: " + DiskDump.sAPIURL + "?" + DumpAPI.QUERY.PATH + "={url}&" + DumpAPI.QUERY.FORMAT + "=json|data|hex|bytes|img";
@ -669,8 +672,22 @@ DiskDump.API = function(aParms)
disk.loadFile(function(err) {
if (!err) {
var sResponse = disk.convertToJSON();
if (sResponse) web.downloadJSON(sResponse);
var sData, sType, fBase64;
if (sFormat == DumpAPI.FORMAT.IMG) {
sType = "octet-stream";
var buf = disk.convertToIMG();
if (buf) {
sData = disk.encodeAsBase64(buf);
fBase64 = true;
}
} else {
sType = "json";
sData = disk.convertToJSON();
}
if (sData) {
var sAlert = web.downloadFile(sData, sType, fBase64);
web.alertUser(sAlert);
}
}
});
};
@ -1041,7 +1058,7 @@ DiskDump.readFile = function(sPath, sEncoding, done)
web.getResource(sPath, "bytes", true, function doneReadFileBrowser(sURL, sResource, nErrorCode) {
var buf = sResource;
if (!nErrorCode) {
if (str.endsWith(sURL, ".img")) {
if (!str.endsWith(sURL, ".json")) {
buf = new BufferPF(sResource);
}
}
@ -3050,6 +3067,25 @@ DiskDump.prototype.convertToIMG = function()
return this.bufDisk;
};
/**
* encodeAsBase64(buf)
*
* Converts the buffer contents to base64. TODO: Consider implementing BufferPF.toString('ascii').
*
* @this {DiskDump}
* @param {Buffer} buf
* @return {string}
*/
DiskDump.prototype.encodeAsBase64 = function(buf)
{
var s = "";
for (var off = 0; off < buf.length; off++) {
s += String.fromCharCode(buf.readUInt8(off));
}
return btoa(s);
};
if (NODE) {
module.exports = DiskDump;
} else {

View file

@ -82,7 +82,7 @@ function FileDump(sFormat, fComments, fDecimal, offDump, nWidthDump, sServerRoot
* Class constants
*/
FileDump.sAPIURL = "http://www.pcjs.org" + DumpAPI.ENDPOINT;
FileDump.sCopyright = "© 2012-2015 by Jeff Parsons (@jeffpar)";
FileDump.sCopyright = "© 2012-2016 by Jeff Parsons (@jeffpar)";
FileDump.sNotice = FileDump.sAPIURL + " " + FileDump.sCopyright;
FileDump.sUsage = "Usage: " + FileDump.sAPIURL + "?" + DumpAPI.QUERY.FILE + "=({path}|{URL})&" + DumpAPI.QUERY.FORMAT + "=(json|data|hex|bytes|rom)";

View file

@ -477,19 +477,8 @@ FDC.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
if (drive) {
if (drive.disk) {
if (DEBUG) fdc.println("saving disk " + drive.disk.sDiskPath + "...");
var sURI = "data:application/octet-stream;base64," + drive.disk.encodeAsBase64();
var link = document.createElement('a');
var sFileName = drive.disk.sDiskFile.replace(".json", ".img");
if (typeof link.download == 'string') {
link.href = sURI;
link.download = sFileName;
document.body.appendChild(link); // Firefox requires the link to be in the body
link.click();
document.body.removeChild(link);
} else {
window.open(sURI);
web.alertUser('The disk is being downloaded, but you will need to manually rename it to "' + sFileName + '".');
}
var sAlert = web.downloadFile(drive.disk.encodeAsBase64(), "octet-stream", true, drive.disk.sDiskFile.replace(".json", ".img"));
web.alertUser(sAlert);
} else {
fdc.notice("No disk loaded in drive");
}

View file

@ -198,45 +198,18 @@ function downloadPC(sURL, sCSS, nErrorCode, aMachineInfo)
if (sXMLFile && sXSLFile) {
var sResources = JSON.stringify(resNew);
sScript += ".js";
sPCJS = matchScript[1] + "var resources=" + sResources + ";" + matchScript[2] + matchScript[3];
Component.log("saving machine: '" + idMachine + "' (" + sPCJS.length + " bytes)");
var sURI, sAlert;
var link = document.createElement('a');
var fDownload = (!DEBUG && typeof link.download == 'string');
sPCJS = sPCJS.replace(/\u00A9/g, "&#xA9;");
if (MAXDEBUG) {
sPCJS = sPCJS.replace(/[\u00A0-\u2666]/g, function(c) {
return '&#' + c.charCodeAt(0) + ';';
});
sURI = "data:application/javascript;base64," + btoa(encodeURI(sPCJS));
} else {
sPCJS = sPCJS.replace(/\u00A9/g, "&#xA9;");
sURI = "data:application/javascript,";
if (!web.isUserAgent("Firefox")) {
fDownload = false;
sURI += encodeURI(sPCJS);
} else {
sURI += encodeURIComponent(sPCJS);
}
}
var sAlert = web.downloadFile(sPCJS, "javascript", false, sScript);
if (fDownload) {
link.href = sURI;
link.download = sScript + ".js";
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
sAlert = 'Check your Downloads folder for "' + link.download + '", ';
} else {
window.open(sURI);
sAlert = 'Check your browser for a new window/tab containing the PCjs script, ';
}
sAlert += 'copy it to your web server as "' + sScript + '.js", and then add the following to your web page:\n\n';
sAlert += ', copy it to your web server as "' + sScript + '", and then add the following to your web page:\n\n';
sAlert += '<div id="' + idMachine + '"></div>\n';
sAlert += '...\n';
sAlert += '<script type="text/javascript" src="' + sScript + '.js"></script>\n';
sAlert += '<script type="text/javascript" src="' + sScript + '"></script>\n';
sAlert += '<script type="text/javascript">embedPC("' + idMachine + '","' + sXMLFile + '","' + sXSLFile + '");</script>\n\n';
sAlert += 'The machine should appear where the <div> is located.';
web.alertUser(sAlert);

View file

@ -239,7 +239,7 @@ web.getResource = function(sURL, dataPost, fAsync, done)
};
}
if (typeof dataPost == "object") {
if (dataPost && typeof dataPost == "object") {
var sDataPost = "";
for (var p in dataPost) {
if (!dataPost.hasOwnProperty(p)) continue;
@ -601,44 +601,41 @@ web.getURLParameters = function(sParms)
};
/**
* downloadJSON()
* downloadFile(sData, sType, fBase64, sFileName)
*
* @param {string} sJSON
* @param {string} sData
* @param {string} sType
* @param {boolean} [fBase64]
* @param {string} [sFileName]
*/
web.downloadJSON = function(sJSON, sFileName)
web.downloadFile = function(sData, sType, fBase64, sFileName)
{
var link, sAlert;
var fDownload = !!sFileName;
var sURI = "data:application/json,";
var link = null, sAlert;
var sURI = "data:application/" + sType + (fBase64? ";base64" : "") + ",";
if (!web.isUserAgent("Firefox")) {
fDownload = false;
sURI += encodeURI(sJSON);
sURI += (fBase64? sData : encodeURI(sData));
} else {
sURI += encodeURIComponent(sJSON);
if (fDownload) {
sURI += (fBase64? sData : encodeURIComponent(sData));
if (sFileName) {
link = document.createElement('a');
if (typeof link.download != 'string') fDownload = false;
if (typeof link.download != 'string') link = null;
}
}
if (fDownload) {
if (link) {
link.href = sURI;
link.download = sFileName;
document.body.appendChild(link);
document.body.appendChild(link); // Firefox requires the link to be in the body
link.click();
document.body.removeChild(link);
sAlert = 'Check your Downloads folder for "' + sFileName + '".';
sAlert = 'Check your Downloads folder for "' + sFileName + '"';
} else {
window.open(sURI);
sAlert = 'Check your browser for a new window/tab containing the requested data.';
sAlert = 'Check your browser for a new window/tab containing the requested data';
}
web.alertUser(sAlert);
return sAlert;
};
/**
* onCountRepeat(n, fnRepeat, fnComplete, msDelay)
*