- Joined
- Feb 16, 2016
- Messages
- 10
- Reaction score
- 5
- First Language
- Italian
- Primarily Uses
I'm happy to show you my first plugin!
NFileOps.js
DESCRIPTION
The title says it all: this plugin allows you to work with files, using the web API, Managed Storage and native modules *** to work synch- and asynchronously!
This plugin supports UNIX systems*** and download of files, it can also execute an external application***!
The weight of this library is around 50Kb.
*** = Locally deployed games only. I didn't check for mobile versions. If you try to run methods that rely on Node.JS with a non-NW platform, an Exception is thrown.
Use Utils.isNwjs() to check
DOCUMENTATION is found as attachment in PDF with chapters or in HTML format and in the js header (it is detailed, warnings are present).
Italian version can be found here with examples: http://www.rpg2s.net/forum/index.php/topic/20455-nfileopsjs-opera-con-il-file-system/
NEWS: added FileOps.VirtualGetStorageSpaceLeft() and fixed some bugs; added PDF version of the documentation organized in chapters.
View attachment NFileOps.html
View attachment NFileOps.pdf
NFileOps.js
DESCRIPTION
The title says it all: this plugin allows you to work with files, using the web API, Managed Storage and native modules *** to work synch- and asynchronously!
This plugin supports UNIX systems*** and download of files, it can also execute an external application***!
The weight of this library is around 50Kb.
*** = Locally deployed games only. I didn't check for mobile versions. If you try to run methods that rely on Node.JS with a non-NW platform, an Exception is thrown.
Use Utils.isNwjs() to check
//=============================================================================
// NFileOps.js
//=============================================================================
/*:
* @plugindesc File operations utility.
* @author Nomid
*
* @help
*
* This library contains methods to operate with File System (only NW.js platform),
* Virtual Storage and Managed Storage (RPGMAKER default).
*
* WARNING: Before trying to save data in the Virtual Storage, please set Nomid.VirtualGrantedMaxQuota,
* either editing plugin file or calling Nomid.FileOps.VirtualRequestMaxQuota( quota ),
* with quota expressed in bytes (1 * 1024 * 1024 = 1M
.
* You can also update the quota recalling function, but please, take care of
* the size!
* WARNING: Please consider using FileOps.VirtualFileExists() to check file existence
* without errors being thrown!
* WARNING: All file operations within the Virtual Storage are ASYNCHRONOUS!!!
* A callback HAS to be defined WHERE SPECIFIED.
* WARNING: All file operations without user prompt are done in the SANDBOXED
* Virtual Storage!!!
* WARNING: Use Nomid.FileOps.StringToBytes() to calculate sizes of strings!!!
*
* PROPERTIES:
* MIME
* This is an object with predefined MIME types:
*
* FileOps.MIME.AVI - MSVIDEO AVI movie file
* FileOps.MIME.CSS - Cascading Style Sheet CSS file
* FileOps.MIME.CSV - Comma Separated Values CSV file
* FileOps.MIME.GeneralBinaryData - General binary data
* FileOps.MIME.GIF - GIF image
* FileOps.MIME.GZIP - GZIP archive
* FileOps.MIME.HTML - Ordinary HTML file
* FileOps.MIME.JavaScript - Ordinary javascript file
* FileOps.MIME.JPEG - JPG image
* FileOps.MIME.MP4 - MP4 video
* FileOps.MIME.MPEGAUDIO - MP3 audio file
* FileOps.MIME.MSWORD - Microsoft(c) Word(r) file
* FileOps.MIME.PDF - Adobe(c) PDF (r) file
* FileOps.MIME.PLAINTEXT - Any unformatted text file (txt, cpp, h, etc...)
* FileOps.MIME.PNG - PNG image
* FileOps.MIME.RAR - RAR archive
* FileOps.MIME.RTF - Rich Text Format RTF file
* FileOps.MIME.TAR - TAR archive
* FileOps.MIME.WAVE - Raw wave WAV audio file
* FileOps.MIME.XML - Ordinary XML file
* FileOps.MIME.ZIP - ZIP archive
*
* ENCODINGS
* This is an object with predefined file encodings for WEB requests:
*
* FileOps.ENCODINGS.ISO_8859_1
* FileOps.ENCODINGS.US_ASCII
* FileOps.ENCODINGS.UTF_8
* FileOps.ENCODINGS.UTF_16
* FileOps.ENCODINGS.WINDOWS_1252
*
* NODEJS_ENCODINGS
* This is an object with predefined file encodings for NodeJS streams:
*
* FileOps.NODEJS_ENCODINGS.ASCII
* FileOps.NODEJS_ENCODINGS.BASE_64
* FileOps.NODEJS_ENCODINGS.BINARY
* FileOps.NODEJS_ENCODINGS.HEX
* FileOps.NODEJS_ENCODINGS.UCS2
* FileOps.NODEJS_ENCODINGS.UTF_8
* FileOps.NODEJS_ENCODINGS.UTF_16_LE
*
* METHODS:
* WARNING: All prefixed methods work in the Virtual or Managed area.
*
* Note that "userprompt" (where specified) shows a window that allows
* the user to save a file wherever he'd like to.
*
* WARNING: All Virtual- methods are asynchronous!!!
*
* BOOL FileOps.FileExists( filepath )
* Checks the existence of the specified file.
*
* STRING filepath: Full path to file, e.g.: "C:\\file.txt"
*
* STRING FileOps.BufferToString( buffer, encoding, start, length )
* Turns a Buffer object returned by NodeJS into a string.
* Alias of NodeJS's Buffer.toString().
* https://nodejs.org/api/buffer.html#buffer_buf_tostring_encoding_start_end
*
* WARNING: NodeJS methohds don't work in non-NW.js platforms and if you try
* to execute them in that case, an Exception is thrown.
*
* FileOps.ReadFile
* Alias for NodeJS's readFileSync().
* https://nodejs.org/api/fs.html#fs_fs_readfilesync_file_options
*
* FileOps.ReadFileAsync
* Alias for NodeJS's readFile().
* https://nodejs.org/api/fs.html#fs_fs_readfile_file_options_callback
*
* FileOps.WriteFile
* Alias for NodeJS's writeFileSync().
* https://nodejs.org/api/fs.html#fs_fs_writefilesync_file_data_options
*
* FileOps.WriteFileAsync
* Alias for NodeJS's writeFile().
* https://nodejs.org/api/fs.html#fs_fs_writefile_file_data_options_callback
*
* ASYNC FileOps.URIExists( uri, callback )
* Checks the existence of a remote file.
* WARNING: This method is asynchronous!
* WARNING: ONLY HTTP 200 will return true!!!
*
* STRING uri: URI of the file to test.
* FUNCTION( BOOL ) callback: To be called when the response is ready.
* The response is BOOLEAN.
*
* INT FileOps.StringToBytes( str )
* Gets length of given string in bytes.
* WARNING: UTF8 encoding is assumed!!!
*
* STRING str: The string to be elaborated.
*
* VOID FileOps.VirtualGetStorageInfo( callback )
* Gets storage information.
* FUNCTION( OBJECT ) callback: To be called when the response is ready.
* An object containing members "used" and "MaxQuota" is returned,
* their values are expressed in bytes (1 * 1024 * 1024 = 1M
.
*
* INT FileOps.VirtualGetStorageSpaceLeft ( )
* Gets storage's space left.
* WARNING: Please use it.
*
* ASYNC FileOps.VirtualDeleteFile( filepath, callback )
* Deletes the specified virtual file.
* WARNING: May end in unexpected results.
*
* STRING filepath: Path to file, can be virtual only.
* FUNCTION( VOID ) callback: To be called when the response is ready.
* No message is returned.
*
* ASYNC FileOps.VirtualFileExists( filepath, callback )
* Checks the existence of a virtual file.
* WARNING: This method is asynchronous!!!
* WARNING: Use FileOps.URIExists() to test a remote file!!!
*
* STRING filepath: Path to file, can be virtual or absolute. To specify
* an absolute path, use file:///C:/... protocol.
* FUNCTION( BOOL/FILEERROR ) callback: To be called when the response is ready.
* The response is BOOLEAN when the file exists or not, FILEERROR if an
* error has occurred.
*
* VOID FileOps.VirtualRequestMaxQuota( quota )
* Sets the maximum storage size of written files.
* WARNING: The specified quota considers the SUM of the sizes of the
* files, so be careful when saving data with User Prompt disabled!!!
*
* INT quota: the amount of MAX storage IN BYTES (1 * 1024 * 1024 = 1M
* that the application may use.
*
* ASYNC FileOps.VirtualSaveFile( filepath, txt, userprompt, size, callback )
* Saves a text file in the sandboxed virtual storage.
* WARNING: This method is asynchronous!!!
* WARNING: This function IS NOT binary safe! Use FileOps.VirtualSaveJSON() to save
* javascript data and FileOps.VirtualSaveBinary() for binary data!!!
*
* STRING filepath: Path to file, can be virtual only.
* STRING txt: The text to be written.
* BOOL userprompt: Whether to prompt user to save file to a custom location
* (in this case, size is not needed and can be set to 0).
* INT size: In bytes (1 * 1024 * 1024 = 1M
, the size of the text to be written.
* N.B.: Consider using FileOps.StringToBytes().
* FUNCTION( VOID ) callback: To be called when the response is ready.
* No message is returned.
*
* ASYNC FileOps.VirtualSaveJSON( filepath, json, userprompt, size, callback )
* Same thing as FileOps.VirtualSaveFile(), requires data in JSON format.
* N.B.: Any javascript object data is considered JSON data.
* WARNING: This method is asynchronous!!!
*
* STRING filepath: Path to file, can be virtual only.
* OBJECT json: The JSON object to be saved.
* BOOL userprompt: Whether to prompt user to save file to a custom location
* (in this case, size is not needed and can be set to 0).
* INT size: In bytes (1 * 1024 * 1024 = 1M
, the size of the text to be written.
* N.B.: Consider using FileOps.StringToBytes().
* FUNCTION( VOID ) callback: To be called when the response is ready.
* No message is returned.
*
* ASYNC FileOps.VirtualSaveBinary( filepath, arrBuffer, mime, userprompt, size, callback )
* Writes binary data to a file in the sandboxed virtual storage.
* WARNING: arrBuffer IS NOT an ordinary Array!!!
* WARNING: This method is asynchronous!!!
*
* STRING filepath: Path to file, can be virtual only.
* ARRAYBUFFER arrBuffer: The binary data to be written.
* WARNING: This is not an ordinary Array!!!
* BOOL userprompt: Whether to prompt user to save file to a custom location
* (in this case, size is not needed and can be set to 0).
* INT size: In bytes (1 * 1024 * 1024 = 1M
, the size of the text to be written.
* N.B.: Consider using FileOps.StringToBytes().
* STRING mime: MIME type of the data. Take a look to the predefined ones,
* above mentioned.
* WARNING: An invalid MIME format likely causes the procedure to fail!!!
* FUNCTION( VOID ) callback: To be called when the response is ready.
* No message is returned.
*
* ASYNC FileOps.VirtualReadFile( filepath, callback )
* Reads text data from a file or web stream.
* WARNING: This method IS NOT binary safe! Use FileOps.VirtualReadJSON() to read
* javascript data and FileOps.VirtualReadBinary() for binary data!!!
* WARNING: This method is asynchronous!!!
*
* STRING filepath: Path to file, can be virtual or absolute. To specify
* an absolute path, use file:///C:/... protocol.
* N.B.: Can be a web URI.
* WARNING: In order to deploy / read data from the URI without errors,
* Access-Control-Allow-Origin header must be set to "*".
* Please, take a look at
* https://en.wikipedia.org/wiki/Same-origin_policy
* FUNCTION( STRING ) callback: To be called when the response is ready.
* The content of the file is returned.
*
* ASYNC FileOps.VirtualReadJSON( filepath, callback )
* Reads JSON data from a file or web stream.
* WARNING: This method IS NOT binary safe! Use FileOps.VirtualReadBinary() for binary data!!!
* WARNING: This method is asynchronous!!!
*
* STRING filepath: Path to file, can be virtual or absolute. To specify
* an absolute path, use file:///C:/... protocol.
* N.B.: Can be a web URI.
* WARNING: In order to deploy / read data from the URI without errors,
* Access-Control-Allow-Origin header must be set to "*".
* Please, take a look at
* https://en.wikipedia.org/wiki/Same-origin_policy
* FUNCTION( OBJECT ) callback: To be called when the response is ready.
* JSON object is returned.
*
* ASYNC FileOps.VirtualReadBinary( filepath, mime, callback )
* Reads binary data from a file or web stream.
* WARNING: This method returns an ArrayBuffer, please check out documentation
* at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer
*
* STRING filepath: Path to file, can be virtual or absolute. To specify
* an absolute path, use file:///C:/... protocol.
* N.B.: Can be a web URI.
* WARNING: In order to deploy / read data from the URI without errors,
* Access-Control-Allow-Origin header must be set to "*".
* Please, take a look at
* https://en.wikipedia.org/wiki/Same-origin_policy
* STRING mime: MIME type of the data. Take a look to the predefined ones,
* above mentioned.
* WARNING: An invalid MIME format likely causes the procedure to fail!!!
* FUNCTION( ARRAYBUFFER ) callback: To be called when the response is ready.
* ArrayBuffer object is returned.
* WARNING: This is not an ordinary Array!!!
*
* VOID FileOps.ManagedSaveJSON( fileid, json )
* Saves JSON data using the predefined manager.
* WARNING: This data is managed by RPGMAKER!!!
*
* STRING fileid: ID of the file.
* WARNING: This is not a path!!!
* OBJECT json: The JSON object to be saved.
*
* OBJECT FileOps.ManagedReadJSON( fileid )
* Reads JSON data using the predefined manager.
* WARNING: This data is managed by RPGMAKER!!!
*
* STRING fileid: ID of the file.
* WARNING: This is not a path!!!
*
* BOOL FileOps.ManagedFileExists( fileid )
* Checks the existence of the specified file using the predefined manager.
* WARNING: This tests inside the managed area!!!
*
* STRING fileid: ID of the file.
* WARNING: This is not a path!!!
*
* VOID FileOps.ManagedDeleteFile( fileid )
* Deletes a file using the predefined manager.
* WARNING: This data is managed by RPGMAKER!!!
*
* STRING fileid: ID of the file.
* WARNING: This is not a path!!!
*
* WARNING: NodeJS methohds don't work in non-NW.js platforms and if you try
* to execute them in that case, an Exception is thrown.
*
* FileOps.ExecuteCommand
* Alias for NodeJS's execSync().
* https://nodejs.org/api/child_process.html#child_process_child_process_execsync_command_options
*
* ASYNC FileOps.ExecuteCommandAsync
* Alias for NodeJS's exec().
* https://nodejs.org/api/child_process.html#child_process_child_process_exec_command_options_callback
*
* FileOps.SpawnCommand
* Alias for NodeJS's spawnSync().
* https://nodejs.org/api/child_process.html#child_process_child_process_spawnsync_command_args_options
*
* ASYNC FileOps.SpawnCommandAsync
* Alias for NodeJS's spawn().
* https://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options
*
* FileOps.ExecuteFile
* Alias for NodeJS's execFileSync().
* https://nodejs.org/api/child_process.html#child_process_child_process_execfilesync_file_args_options
*
* ASYNC FileOps.ExecuteFileAsync
* Alias for NodeJS's execFile().
* https://nodejs.org/api/child_process.html#child_process_child_process_execfile_file_args_options_callback
*
* ******************** Nomid ********************
*/
!function(window)
{
"use strict";
if(window.Nomid === undefined)
window.Nomid = {};
window.Nomid.FileOps = {};
/* CONFIGURATION */
/// Max storage allocation (all created files must TOTALIZE lower than this quota)
window.Nomid.VirtualGrantedMaxQuota = 5 * 1024 * 1024; // 5 MB
window.Nomid.ShowDebugInfo = false;
/* END CONFIGURATION */
// Try-Catch works
function NomidFileOpsException(message)
{
SceneManager._scene.stop();
AudioManager.stopAll();
Graphics.printError('Nomid.FileOps Exception', message);
return new Error("Nomid.FileOps Exception: " + message);
}
/**
* Checks whether the platform is NW.js.
*
* @author Iavra
*
* @static
* @method isNwjs
* @return {Boolean} True if the platform is NW.js
*/
Utils.isNwjs = function()
{ return typeof require === 'function' && typeof process === 'object'; };
window.requestFileSystem = window.requestFileSystem || window.webkitRequestFileSystem;
/// Helper
function onInitFs(fs)
{
if(Nomid.ShowDebugInfo) console.info('Nomid.FileOps: Access granted for Virtual File Path: %s', fs.name);
if(Nomid.ShowDebugInfo) console.log('Nomid.FileOps: File System properties: %o', fs);
}
function errorHandler(e)
{
throw NomidFileOpsException('errorHandler(): Error saving file: ' + e.message);
}
function saveWithoutPrompt(fpath, fs, blob, callback)
{
onInitFs(fs);
fs.root.getFile(fpath, {create: true, exclusive: false}, function(fileEntry)
{
if(Nomid.ShowDebugInfo) console.info('Nomid.FileOps::saveWithoutPrompt(): Initializing buffer...');
fileEntry.createWriter(function(fileWriter)
{
fileWriter.onwriteend = function(e)
{
if(Nomid.ShowDebugInfo) console.info('Nomid.FileOps::saveWithoutPrompt(): Writing of ' + fpath + ' succeded.');
callback();
};
fileWriter.onerror = function(e)
{
throw NomidFileOpsException('saveWithoutPrompt(): Writing of ' + fpath + ' failed: ' + e.toString());
};
fileWriter.write(blob);
}, errorHandler);
}, errorHandler);
}
function loadNWmodule(what)
{
if(!Utils.isNwjs())
throw NomidFileOpsException("Can't load a NW.js module in a non NW.js environment.");
else
return fs[what];
}
var fs = require("fs") || "unavailable";
var exec = require('child_process').exec || "unavailable";
var spawn = require('child_process').spawn || "unavailable";
var execFile = require('child_process').execFile || "unavailable";
var execSync = require('child_process').execSync || "unavailable";
var spawnSync = require('child_process').spawnSync || "unavailable";
var execFileSync = require('child_process').execFileSync || "unavailable";
if(!Utils.isNwjs()) console.warn("Nomid.FileOps: Not in a NW.js environment: File System methods won't work.");
window.Nomid.FileOps = {
/// Predefined MIME types
MIME: {
JavaScript: "application/javascript",
MP4: "application/mp4",
GeneralBinaryData: "application/octet-stream",
MSWORD: "application/msword",
PDF: "application/pdf",
RTF: "text/rtf",
XML: "text/xml",
TAR: "application/x-tar",
ZIP: "multipart/x-zip",
MPEGAUDIO: "audio/mpeg",
WAVE: "audio/x-wav",
GIF: "image/gif",
JPEG: "image/jpeg",
PNG: "image/png",
GZIP: "multipart/x-gzip",
CSS: "text/css",
CSV: "text/csv",
HTML: "text/html",
PLAINTEXT: "text/plain",
AVI: "video/msvideo",
RAR: "application/x-rar-compressed"
},
/// Predefined file encodings for requests
ENCODINGS: {
UTF_8: 'utf8',
US_ASCII: 'us-ascii',
UTF_16: 'utf16',
ISO_8859_1: 'iso-8859-1',
WINDOWS_1252: 'windows-1252'
},
/// Supported file encodings by NodeJS
NODEJS_ENCODINGS: {
UTF_8: 'utf8',
ASCII: 'ascii',
BASE_64: 'base64',
BINARY: 'binary',
HEX: 'hex',
UCS2: 'ucs2',
UTF_16_LE: 'utf16le'
},
/// Predefined system shells
SHELLS: {
WINDOWS: 'cmd.exe',
UNIX: '/bin/sh'
},
/**
* @param {String} filepath
* @param {Function} callback
* @returns {String}
*/
URIExists: function(filepath, callback)
{
if(typeof filepath !== "string" || filepath === undefined || filepath == '')
throw NomidFileOpsException('URIExists(): URI path is null.');
if(typeof callback !== "function")
throw NomidFileOpsException('URIExists(): Callback is not set. Filename: ' + filepath);
if(Nomid.ShowDebugInfo) console.info("Nomid.FileOps: URIExists(): Checking for existence of %s...", filepath);
var rawFile = new XMLHttpRequest(), allText = '';
rawFile.open("HEAD", filepath, false);
rawFile.onreadystatechange = function ()
{
if(rawFile.readyState === 4)
allText = rawFile.responseText, !function()
{
if(Nomid.ShowDebugInfo) console.info("Nomid.FileOps: URIExists(): Status: %s.", rawFile.status.toString());
callback(!!(rawFile.status === 200));
}();
};
try
{
rawFile.send(null);
} catch(E)
{
throw NomidFileOpsException('URIExists(): Unknown DOMError: ' + E.message);
}
},
/**
* @param {String} str
* @returns {Number}
*/
StringToBytes: function(str)
{
return Buffer.byteLength(str, 'utf8');
},
/**
* @param {Buffer} buff
* @param {String} enc
* @param {Number} s
* @param {Number} l
* @returns {string}
*/
BufferToString: function(buff, enc, s, l)
{
return buff.toString(enc, s, l);
},
/**
* @param {String} quota
* @returns {void}
*/
VirtualRequestMaxQuota: function(quota)
{
if(quota === || quota === undefined)
throw NomidFileOpsException("VirtualRequestMaxQuota(): Can't set a null quota.");
navigator.webkitPersistentStorage.requestQuota(quota, function(grantedBytes)
{
window.requestFileSystem(PERSISTENT, grantedBytes, onInitFs, errorHandler);
}, function(e) {
throw NomidFileOpsException('VirtualRequestMaxQuota(): Access Denied using quota ' + quota + ': ' + e);
});
if(Nomid.ShowDebugInfo) console.info("Nomid.FileOps: Set max quota: " + quota);
Nomid.VirtualGrantedMaxQuota = quota;
},
/**
* @param {Function} callback( { usage, MaxQuota } )
* @returns {Object}
*/
VirtualGetStorageInfo: function(callback)
{
if(typeof callback !== "function")
throw NomidFileOpsException('VirtualGetStorageInfo(): Callback is not set. Filename: ' + filepath);
navigator.webkitPersistentStorage.queryUsageAndQuota(function(used, max)
{
callback({ 'usage': used, 'MaxQuota': max });
}, function(E)
{
throw NomidFileOpsException('VirtualGetStorageInfo(): Error: ' + E.message);
});
},
VirtualGetStorageSpaceLeft: function()
{
var cb;
FileOps.VirtualGetStorageInfo(function(i){ cb = i; });
return (cb.MaxQuota - cb.used);
},
/**
* @param {String} filepath
* @param {Function} callback( void )
* @returns {void}
*/
VirtualDeleteFile: function(filepath, callback)
{
if(typeof filepath !== "string" || filepath === undefined || filepath == '')
throw NomidFileOpsException('VirtualDeleteFile(): File path is null.');
if(typeof callback !== "function")
throw NomidFileOpsException('VirtualDeleteFile(): Callback is not set. Filename: ' + filepath);
Nomid.FileOps.VirtualFileExists(filepath, function(E)
{
if(E)
navigator.webkitPersistentStorage.requestQuota(, function(grantedBytes)
{
window.requestFileSystem(PERSISTENT, grantedBytes, function(fs)
{
onInitFs();
fs.root.getFile(filepath, {create: false}, function(fe)
{
if(Nomid.ShowDebugInfo) console.info("Nomid.FileOps: VirtualDeleteFile(): Trying to delete file %s...", filepath);
fe.remove(function()
{
if(Nomid.ShowDebugInfo) console.info("Nomid.FileOps: VirtualDeleteFile(): File %s has been deleted.", filepath)
callback();
}, errorHandler);
}, errorHandler);
}, errorHandler);
}, function(e)
{
throw NomidFileOpsException("VirtualDeleteFile(): Unexpected error: " + e.message);
});
else
throw NomidFileOpsException("VirtualDeleteFile(): File " + filepath + " does not exist.");
});
},
/**
* @param {String} filepath
* @param {Function} callback( boolean )
* @returns {void}
*/
VirtualFileExists: function(filepath, callback)
{
if(typeof filepath !== "string" || filepath === undefined || filepath == '')
throw NomidFileOpsException('VirtualFileExists(): File path is null.');
if(typeof callback !== "function")
throw NomidFileOpsException('VirtualFileExists(): Callback is not set. Filename: ' + filepath);
if(filepath.indexOf("http://") == -1 && filepath.indexOf("file:///") == -1)
return window.requestFileSystem(PERSISTENT, , function(fs)
{
if(Nomid.ShowDebugInfo) console.info("Nomid.FileOps: VirtualFileExists(): Checking for existence of %s...", filepath);
fs.root.getFile(filepath, {create: false}, function(f)
{
onInitFs(f);
callback(true);
}, function(E)
{
if(E.name === "NotFoundError")
if(Nomid.ShowDebugInfo) console.warn("Nomid.FileOps: VirtualFileExists(): File not found."), callback(false);
else
if(Nomid.ShowDebugInfo) console.warn("Nomid.FileOps: VirtualFileExists(): FileError: " + E.message), callback(E);
});
}, errorHandler);
if(Nomid.ShowDebugInfo) console.info("Nomid.FileOps: VirtualFileExists(): Checking for existence of %s...", filepath);
var rawFile = new XMLHttpRequest(), allText = '';
rawFile.open("HEAD", filepath, false);
rawFile.onreadystatechange = function ()
{
if(rawFile.readyState === 4)
allText = rawFile.responseText, !function()
{
var res = (rawFile.responseURL !== "");
if(Nomid.ShowDebugInfo) console.info("Nomid.FileOps: VirtualFileExists(): Status: %s; exists: %s.", rawFile.status.toString(), res.toString());
callback(res);
}();
};
try
{
rawFile.send(null);
} catch(E)
{
throw NomidFileOpsException('VirtualFileExists(): Unknown DOMError: ' + E.message);
}
},
/**
* @param {String} filepath
* @param {String} txt
* @param {Boolean} userprompt
* @param {Number} size
* @param {Function} callback( void )
* @returns {void}
*/
VirtualSaveFile: function(filepath, txt, userprompt, size, callback)
{
if(typeof filepath !== "string" || filepath === undefined || filepath == '')
throw NomidFileOpsException('VirtualSaveFile(): File path is null.');
if(typeof txt !== "string")
throw NomidFileOpsException('VirtualSaveFile(): Input data must be a string. Filename: ' + filepath);
if(!userprompt && (typeof size !== "number" || size < FileOps.VirtualGetStorageSpaceLeft())
throw NomidFileOpsException('VirtualSaveFile(): Invalid file size. Filename: ' + filepath);
if(userprompt !== true)
userprompt = false;
if(filepath.indexOf("file:///") > -1 && !userprompt)
throw NomidFileOpsException('VirtualSaveFile(): Can\'t save a file outside the Virtual Storage area without prompt.');
if(typeof callback !== "function" && !userprompt)
throw NomidFileOpsException('VirtualSaveFile(): Callback is not set. Filename: ' + filepath);
Nomid.FileOps.VirtualFileExists(filepath, function(E)
{
if(E)
if(Nomid.ShowDebugInfo) console.warn("Nomid.FileOps: VirtualSaveFile(): File exists, will overwrite. Filename: " + filepath);
});
var myBlob = new Blob([txt], {type: 'text/plain'});
if(userprompt)
saveAs(myBlob, filepath, true);
else
{
var doTheSave = function(fs)
{
saveWithoutPrompt(filepath, fs, myBlob, callback);
};
window.requestFileSystem(window.PERSISTENT, size, doTheSave, errorHandler);
}
},
/**
* @param {String} filepath
* @param {Object} json
* @param {Boolean} userprompt
* @param {Number} size
* @param {Function} callback( void )
* @returns {void}
*/
VirtualSaveJSON: function(filepath, json, userprompt, size, callback)
{
if(typeof filepath !== "string" || filepath === undefined || filepath == '')
throw NomidFileOpsException('VirtualSaveJSON(): File path is null.');
if(typeof json !== "object")
throw NomidFileOpsException('VirtualSaveJSON(): Input data must be a JSON object. Filename: ' + filepath);
if(!userprompt && (typeof size !== "number" || size < FileOps.VirtualGetStorageSpaceLeft()))
throw NomidFileOpsException('VirtualSaveJSON(): Invalid file size. Filename: ' + filepath);
if(userprompt !== true)
userprompt = false;
if(filepath.indexOf("file:///") > -1 && !userprompt)
throw NomidFileOpsException('VirtualSaveFile(): Can\'t save a file outside the Virtual Storage area without prompt.');
if(typeof callback !== "function" && !userprompt)
throw NomidFileOpsException('VirtualSaveJSON(): Callback is not set. Filename: ' + filepath);
Nomid.FileOps.VirtualFileExists(filepath, function(E)
{
if(E)
if(Nomid.ShowDebugInfo) console.warn("Nomid.FileOps: VirtualSaveJSON(): File exists, will overwrite. Filename: " + filepath);
});
var myBlob = new Blob([JSON.stringify(json)], {type: 'text/json'});
if(userprompt)
saveAs(myBlob, filepath, true);
else
{
var doTheSave = function(fs)
{
saveWithoutPrompt(filepath, fs, myBlob, callback);
};
window.requestFileSystem(window.PERSISTENT, size, doTheSave, errorHandler);
}
},
/**
* @param {String} filepath
* @param {ArrayBuffer} arrBuffer
* @param {String} mime
* @param {Boolean} userprompt
* @param {Number} size
* @param {Function} callback( void )
* @returns {void}
*/
VirtualSaveBinary: function(filepath, arrBuffer, mime, userprompt, size, callback)
{
if(typeof filepath !== "string" || filepath === undefined || filepath == '')
throw NomidFileOpsException('VirtualSaveBinary(): File path is null.');
if(!(arrBuffer instanceof ArrayBuffer))
throw NomidFileOpsException('VirtualSaveBinary(): Input data must be an instance of ArrayBuffer. Filename: ' + filepath);
if(typeof mime !== "string" || mime === undefined || mime == '')
throw NomidFileOpsException('VirtualSaveBinary(): File MIME can\'t be null. Filename: ' + filepath);
if(!userprompt && (typeof size !== "number" || size < FileOps.VirtualGetStorageSpaceLeft()))
throw NomidFileOpsException('VirtualSaveBinary(): Invalid file size. Filename: ' + filepath);
if(userprompt !== true)
userprompt = false;
if(filepath.indexOf("file:///") > -1 && !userprompt)
throw NomidFileOpsException('VirtualSaveFile(): Can\'t save a file outside the Virtual Storage area without prompt.');
if(typeof callback !== "function" && !userprompt)
throw NomidFileOpsException('VirtualSaveBinary(): Callback is not set. Filename: ' + filepath);
if(Nomid.ShowDebugInfo) console.warn("Nomid.FileOps: VirtualSaveBinary(): Using MIME %s for file %s", mime, filepath);
Nomid.FileOps.VirtualFileExists(filepath, function(E)
{
if(E)
if(Nomid.ShowDebugInfo) console.warn("Nomid.FileOps: VirtualSaveBinary(): File exists, will overwrite. Filename: %s", filepath);
});
if(Nomid.ShowDebugInfo) console.info("Nomid.FileOps: VirtualSaveBinary(): Recieved buffer: %o", arrBuffer);
var myBlob = new Blob([arrBuffer], {type: mime});
if(userprompt)
saveAs(myBlob, filepath, true);
else
{
var doTheSave = function(fs)
{
saveWithoutPrompt(filepath, fs, myBlob, callback);
};
window.requestFileSystem(window.PERSISTENT, size, doTheSave, errorHandler);
}
},
/**
* @param {String} filepath
* @param {Function} callback( string )
* @returns {void}
*/
VirtualReadFile: function(filepath, callback)
{
if(typeof filepath !== "string" || filepath === undefined || filepath == '')
throw NomidFileOpsException('VirtualReadFile(): File path is null.');
if(typeof callback !== "function")
throw NomidFileOpsException('VirtualReadFile(): Callback is not set. Filename: ' + filepath);
Nomid.FileOps.VirtualFileExists(filepath, function(R)
{
if(R)
{
if(filepath.indexOf("file:///") > -1)
window.requestFileSystem(PERSISTENT, , function(fs)
{
onInitFs();
fs.root.getFile(filepath, {}, function(fs)
{
fs.file(function(file) {
var reader = new FileReader();
reader.onloadend = function(e)
{
callback(this.result);
};
reader.readAsText(file);
}, errorHandler);
}, errorHandler);
}, errorHandler);
else
{
var rawFile = new XMLHttpRequest(), allText = '';
rawFile.open("HEAD", filepath, false);
rawFile.onreadystatechange = function ()
{
if(rawFile.readyState === 4)
if(rawFile.status === 200 || rawFile.status == )
allText = rawFile.responseText, !function()
{
if(Nomid.ShowDebugInfo) console.info("Nomid.FileOps: VirtualReadFile(): Read " + filepath);
callback(allText);
}();
};
try
{
rawFile.send(null);
} catch(E)
{
throw NomidFileOpsException("VirtualReadFile(): Unexpected error: " + E.message);
}
}
}
else
throw NomidFileOpsException('VirtualReadFile(): File does not exist. Filename: ' + filepath);
});
},
/**
* @param {String} filepath
* @param {Function} callback( object )
* @returns {void}
*/
VirtualReadJSON: function(filepath, callback)
{
if(typeof filepath !== "string" || filepath === undefined || filepath == '')
throw NomidFileOpsException('VirtualReadJSON(): File path is null.');
if(typeof callback !== "function")
throw NomidFileOpsException('VirtualReadJSON(): Callback is not set. Filename: ' + filepath);
Nomid.FileOps.VirtualReadFile(filepath, function(E)
{
var json;
try
{
json = JSON.parse(E);
}
catch(E)
{
throw NomidFileOpsException('VirtualReadJSON(): Malformed JSON. Filename: ' + filepath);
}
callback(json);
});
},
/**
* @param {String} filepath
* @param {String} mime
* @param {Function} callback( ArrayBuffer )
* @returns {void}
*/
VirtualReadBinary: function(filepath, mime, callback)
{
if(typeof filepath !== "string" || filepath === undefined || filepath == '')
throw NomidFileOpsException('VirtualReadJSON(): File path is null.');
if(typeof callback !== "function")
throw NomidFileOpsException('VirtualReadBinary(): Callback is not set. Filename: ' + filepath);
if(filepath === undefined)
throw NomidFileOpsException("Nomid.FileOps: ");
if(mime === undefined || mime == "")
throw NomidFileOpsException("VirtualReadBinary(): MIME type not defined. Filename: " + filepath);
if(Nomid.ShowDebugInfo) console.warn("Nomid.FileOps: VirtualReadBinary(): Reading " + filepath + " with mime " + mime);
Nomid.FileOps.VirtualFileExists(filepath, function(R)
{
if(R)
{
if(filepath.indexOf("file:///") == -1 && filepath.indexOf("http://") == -1)
window.requestFileSystem(PERSISTENT, , function(fs)
{
onInitFs(fs);
fs.root.getFile(filepath, {}, function(fs)
{
if(Nomid.ShowDebugInfo) console.log("Nomid.FileOps: VirtualReadBinary: Accessing %o", fs);
fs.file(function(file) {
var reader = new FileReader();
reader.onloadend = function(e)
{
if(Nomid.ShowDebugInfo) console.log("Nomid.FileOps: VirtualReadBinary: Read end: %o with %o", this.result, e);
callback(this.result);
};
reader.readAsArrayBuffer(file);
if(Nomid.ShowDebugInfo) console.log("Nomid.FileOps: VirtualReadBinary: Read stream %o from %o", reader, file);
}, errorHandler);
}, errorHandler);
}, errorHandler);
else
{
var oReq = new XMLHttpRequest();
oReq.open("GET", filepath, true);
oReq.responseType = "arraybuffer";
var blob = undefined;
oReq.onload = function(oEvent)
{
blob = new Blob([oReq.response], {type: mime});
if(Nomid.ShowDebugInfo) console.info("Nomid.FileOps: VirtualReadBinary(): Read %s.", filepath);
var arrayBuffer;
var fileReader = new FileReader();
fileReader.onload = function()
{
arrayBuffer = this.result;
callback(arrayBuffer);
};
fileReader.readAsArrayBuffer(blob);
};
try
{
oReq.send();
} catch(E)
{
throw NomidFileOpsException("VirtualReadBinary(): Unexpected error: " + E.message);
}
}
}
});
},
/**
* @param {String} fileid
* @param {Object} json
* @returns {void}
*/
ManagedSaveJSON: function(fileid, json)
{
if(typeof fileid !== "string" || fileid === undefined || fileid == '')
throw NomidFileOpsException('ManagedSaveJSON(): File ID is null.');
if(typeof json !== "object" || json === undefined)
throw NomidFileOpsException('ManagedSaveJSON(): Invalid object.');
StorageManager.save(fileid, JSON.stringify(json));
},
/**
* @param {String} fileid
* @returns {Object}
*/
ManagedReadJSON: function(fileid)
{
if(typeof fileid !== "string" || fileid === undefined || fileid == '')
throw NomidFileOpsException('ManagedReadJSON(): File ID is null.');
return StorageManager.load(fileid);
},
/**
* @param {String} fileid
* @returns {Boolean}
*/
ManagedFileExists: function(fileid)
{
if(typeof fileid !== "string" || fileid === undefined || fileid == '')
throw NomidFileOpsException('ManagedReadJSON(): File ID is null.');
return StorageManager.exists(fileid);
},
/**
* @param {String} fileid
* @returns {void}
*/
ManagedDeleteFile: function(fileid)
{
if(typeof fileid !== "string" || fileid === undefined || fileid == '')
throw NomidFileOpsException('ManagedReadJSON(): File ID is null.');
if(!Nomid.FileOps.ManagedFileExists(fileid))
throw NomidFileOpsException('ManagedReadJSON(): File with ID "' + fileid + '" does not exist.');
StorageManager.remove(fileid);
},
/**
* @param {String} fpath
* @returns {Boolean}
*/
FileExists: function(fpath)
{
if(!Utils.isNwjs())
throw NomidFileOpsException("Can't load a NW.js module in a non NW.js environment.");
if(typeof filepath !== "string" || filepath === undefined || filepath == '')
throw NomidFileOpsException('FileExists(): File path is null.');
var f = fs.statSync(fpath);
return !!(f.isFile());
},
ReadFile: function()
{
if(!Utils.isNwjs())
throw NomidFileOpsException("Can't load a NW.js module in a non NW.js environment.");
else
return fs.readFileSync.apply(this, arguments);
},
ReadFileAsync: function()
{
if(!Utils.isNwjs())
throw NomidFileOpsException("Can't load a NW.js module in a non NW.js environment.");
else
return fs.readFile.apply(this, arguments);
},
WriteFileAsync: function()
{
if(!Utils.isNwjs())
throw NomidFileOpsException("Can't load a NW.js module in a non NW.js environment.");
else
return fs.writeFile.apply(this, arguments);
},
WriteFile: function()
{
if(!Utils.isNwjs())
throw NomidFileOpsException("Can't load a NW.js module in a non NW.js environment.");
else
return fs.writeFileSync.apply(this, arguments);
},
ExecuteCommand: function()
{
if(!Utils.isNwjs())
throw NomidFileOpsException("Can't load a NW.js module in a non NW.js environment.");
else
return execSync.apply(this, arguments);
},
SpawnCommand: function()
{
if(!Utils.isNwjs())
throw NomidFileOpsException("Can't load a NW.js module in a non NW.js environment.");
else
return spawnSync.apply(this, arguments);
},
ExecuteFile: function()
{
if(!Utils.isNwjs())
throw NomidFileOpsException("Can't load a NW.js module in a non NW.js environment.");
else
return execFileSync.apply(this, arguments);
},
ExecuteCommandAsync: function()
{
if(!Utils.isNwjs())
throw NomidFileOpsException("Can't load a NW.js module in a non NW.js environment.");
else
return exec.apply(this, arguments);
},
SpawnCommandAsync: function()
{
if(!Utils.isNwjs())
throw NomidFileOpsException("Can't load a NW.js module in a non NW.js environment.");
else
return spawn.apply(this, arguments);
},
ExecuteFileAsync: function()
{
if(!Utils.isNwjs())
throw NomidFileOpsException("Can't load a NW.js module in a non NW.js environment.");
else
return execFile.apply(this, arguments);
}
};
/// It's better to check from the beginning
Nomid.FileOps.VirtualRequestMaxQuota(Nomid.VirtualGrantedMaxQuota);
// EDITED BY NOMID
/* saveAs() FileSaver implementation.
* 1.1.20151003
*
* By Eli Grey, http://eligrey.com
* License: MIT
* See https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md
*/
/*global self */
/*jslint bitwise: true, indent: 4, laxbreak: true, laxcomma: true, smarttabs: true, plusplus: true */
/*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */
var saveAs = saveAs || (function(view)
{
"use strict";
// IE <10 is explicitly unsupported
if (typeof navigator !== "undefined" && /MSIE [1-9]\./.test(navigator.userAgent)) {
return;
}
var
doc = view.document
// only get URL when necessary in case Blob.js hasn't overridden it yet
, get_URL = function() {
return view.URL || view.webkitURL || view;
}
, save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a")
, can_use_save_link = "download" in save_link
, click = function(node) {
var event = new MouseEvent("click");
node.dispatchEvent(event);
}
, is_safari = /Version\/[\d\.]+.*Safari/.test(navigator.userAgent)
, webkit_req_fs = view.webkitRequestFileSystem
, req_fs = view.requestFileSystem || webkit_req_fs || view.mozRequestFileSystem
, throw_outside = function(ex) {
(view.setImmediate || view.setTimeout)(function() {
throw ex;
}, );
}
, force_saveable_type = "application/octet-stream"
, fs_min_size =
// See https://code.google.com/p/chromium/issues/detail?id=375297#c7 and
// https://github.com/eligrey/FileSaver.js/commit/485930a#commitcomment-8768047
// for the reasoning behind the timeout and revocation flow
, arbitrary_revoke_timeout = 500 // in ms
, revoke = function(file) {
var revoker = function() {
if (typeof file === "string") { // file is an object URL
get_URL().revokeObjectURL(file);
} else { // file is a File
file.remove();
}
};
if (view.chrome) {
revoker();
} else {
setTimeout(revoker, arbitrary_revoke_timeout);
}
}
, dispatch = function(filesaver, event_types, event) {
event_types = [].concat(event_types);
var i = event_types.length;
while (i--) {
var listener = filesaver["on" + event_types];
if (typeof listener === "function") {
try {
listener.call(filesaver, event || filesaver);
} catch (ex) {
throw_outside(ex);
}
}
}
}
, auto_bom = function(blob) {
// prepend BOM for UTF-8 XML and text/* types (including HTML)
if (/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) {
return new Blob(["\ufeff", blob], {type: blob.type});
}
return blob;
}
, FileSaver = function(blob, name, no_auto_bom) {
if (!no_auto_bom) {
blob = auto_bom(blob);
}
// First try a.download, then web filesystem, then object URLs
var
filesaver = this
, type = blob.type
, blob_changed = false
, object_url
, target_view
, dispatch_all = function() {
dispatch(filesaver, "writestart progress write writeend".split(" "));
}
// on any filesys errors revert to saving with object URLs
, fs_error = function() {
if (target_view && is_safari && typeof FileReader !== "undefined") {
// Safari doesn't allow downloading of blob urls
var reader = new FileReader();
reader.onloadend = function() {
var base64Data = reader.result;
target_view.location.href = "data:attachment/file" + base64Data.slice(base64Data.search(/[,;]/));
filesaver.readyState = filesaver.DONE;
dispatch_all();
};
reader.readAsDataURL(blob);
filesaver.readyState = filesaver.INIT;
return;
}
// don't create more object URLs than needed
if (blob_changed || !object_url) {
object_url = get_URL().createObjectURL(blob);
}
if (target_view) {
target_view.location.href = object_url;
} else {
var new_tab = view.open(object_url, "_blank");
if (new_tab == undefined && is_safari) {
//Apple do not allow window.open, see http://bit.ly/1kZffRI
view.location.href = object_url
}
}
filesaver.readyState = filesaver.DONE;
dispatch_all();
revoke(object_url);
}
, abortable = function(func) {
return function() {
if (filesaver.readyState !== filesaver.DONE) {
return func.apply(this, arguments);
}
};
}
, create_if_not_found = {create: true, exclusive: false}
, slice
;
filesaver.readyState = filesaver.INIT;
if (!name) {
name = "download";
}
if (can_use_save_link) {
object_url = get_URL().createObjectURL(blob);
setTimeout(function() {
save_link.href = object_url;
save_link.download = name;
click(save_link);
dispatch_all();
revoke(object_url);
filesaver.readyState = filesaver.DONE;
});
return;
}
// Object and web filesystem URLs have a problem saving in Google Chrome when
// viewed in a tab, so I force save with application/octet-stream
// http://code.google.com/p/chromium/issues/detail?id=91158
// Update: Google errantly closed 91158, I submitted it again:
// https://code.google.com/p/chromium/issues/detail?id=389642
if (view.chrome && type && type !== force_saveable_type) {
slice = blob.slice || blob.webkitSlice;
blob = slice.call(blob, , blob.size, force_saveable_type);
blob_changed = true;
}
// Since I can't be sure that the guessed media type will trigger a download
// in WebKit, I append .download to the filename.
// https://bugs.webkit.org/show_bug.cgi?id=65440
if (webkit_req_fs && name !== "download") {
name += ".download";
}
if (type === force_saveable_type || webkit_req_fs) {
target_view = view;
}
if (!req_fs) {
fs_error();
return;
}
fs_min_size += blob.size;
req_fs(view.TEMPORARY, fs_min_size, abortable(function(fs) {
fs.root.getDirectory("saved", create_if_not_found, abortable(function(dir) {
var save = function() {
dir.getFile(name, create_if_not_found, abortable(function(file) {
file.createWriter(abortable(function(writer) {
writer.onwriteend = function(event) {
target_view.location.href = file.toURL();
filesaver.readyState = filesaver.DONE;
dispatch(filesaver, "writeend", event);
revoke(file);
};
writer.onerror = function() {
var error = writer.error;
if (error.code !== error.ABORT_ERR) {
fs_error();
}
};
"writestart progress write abort".split(" ").forEach(function(event) {
writer["on" + event] = filesaver["on" + event];
});
writer.write(blob);
filesaver.abort = function() {
writer.abort();
filesaver.readyState = filesaver.DONE;
};
filesaver.readyState = filesaver.WRITING;
}), fs_error);
}), fs_error);
};
dir.getFile(name, {create: false}, abortable(function(file) {
// delete file if it already exists
file.remove();
save();
}), abortable(function(ex) {
if (ex.code === ex.NOT_FOUND_ERR) {
save();
} else {
fs_error();
}
}));
}), fs_error);
}), fs_error);
}
, FS_proto = FileSaver.prototype
, saveAs = function(blob, name, no_auto_bom) {
return new FileSaver(blob, name, no_auto_bom);
}
;
// IE 10+ (native saveAs)
if (typeof navigator !== "undefined" && navigator.msSaveOrOpenBlob) {
return function(blob, name, no_auto_bom) {
if (!no_auto_bom) {
blob = auto_bom(blob);
}
return navigator.msSaveOrOpenBlob(blob, name || "download");
};
}
FS_proto.abort = function() {
var filesaver = this;
filesaver.readyState = filesaver.DONE;
dispatch(filesaver, "abort");
};
FS_proto.readyState = FS_proto.INIT = ;
FS_proto.WRITING = 1;
FS_proto.DONE = 2;
FS_proto.error =
FS_proto.onwritestart =
FS_proto.onprogress =
FS_proto.onwrite =
FS_proto.onabort =
FS_proto.onerror = null;
FS_proto.onwriteend =
null;
return saveAs;
}(
typeof self !== "undefined" && self
|| typeof window !== "undefined" && window
|| this.content
));
// `self` is undefined in Firefox for Android content script context
// while `this` is nsIContentFrameMessageManager
// with an attribute `content` that corresponds to the window
if (typeof module !== "undefined" && module.exports) {
module.exports.saveAs = saveAs;
} else if ((typeof define !== "undefined" && define !== null) && (define.amd != null)) {
define([], function() {
return saveAs;
});
}
}(window);
This plugin is free to use for all --- please give credit!
Thank you for using my plugin, report me any bug / features! Please, let me know if you use it!
Thanks to lavra for Utils.isNwjs() utility.
TODO list in next updates:
// NFileOps.js
//=============================================================================
/*:
* @plugindesc File operations utility.
* @author Nomid
*
* @help
*
* This library contains methods to operate with File System (only NW.js platform),
* Virtual Storage and Managed Storage (RPGMAKER default).
*
* WARNING: Before trying to save data in the Virtual Storage, please set Nomid.VirtualGrantedMaxQuota,
* either editing plugin file or calling Nomid.FileOps.VirtualRequestMaxQuota( quota ),
* with quota expressed in bytes (1 * 1024 * 1024 = 1M
* You can also update the quota recalling function, but please, take care of
* the size!
* WARNING: Please consider using FileOps.VirtualFileExists() to check file existence
* without errors being thrown!
* WARNING: All file operations within the Virtual Storage are ASYNCHRONOUS!!!
* A callback HAS to be defined WHERE SPECIFIED.
* WARNING: All file operations without user prompt are done in the SANDBOXED
* Virtual Storage!!!
* WARNING: Use Nomid.FileOps.StringToBytes() to calculate sizes of strings!!!
*
* PROPERTIES:
* MIME
* This is an object with predefined MIME types:
*
* FileOps.MIME.AVI - MSVIDEO AVI movie file
* FileOps.MIME.CSS - Cascading Style Sheet CSS file
* FileOps.MIME.CSV - Comma Separated Values CSV file
* FileOps.MIME.GeneralBinaryData - General binary data
* FileOps.MIME.GIF - GIF image
* FileOps.MIME.GZIP - GZIP archive
* FileOps.MIME.HTML - Ordinary HTML file
* FileOps.MIME.JavaScript - Ordinary javascript file
* FileOps.MIME.JPEG - JPG image
* FileOps.MIME.MP4 - MP4 video
* FileOps.MIME.MPEGAUDIO - MP3 audio file
* FileOps.MIME.MSWORD - Microsoft(c) Word(r) file
* FileOps.MIME.PDF - Adobe(c) PDF (r) file
* FileOps.MIME.PLAINTEXT - Any unformatted text file (txt, cpp, h, etc...)
* FileOps.MIME.PNG - PNG image
* FileOps.MIME.RAR - RAR archive
* FileOps.MIME.RTF - Rich Text Format RTF file
* FileOps.MIME.TAR - TAR archive
* FileOps.MIME.WAVE - Raw wave WAV audio file
* FileOps.MIME.XML - Ordinary XML file
* FileOps.MIME.ZIP - ZIP archive
*
* ENCODINGS
* This is an object with predefined file encodings for WEB requests:
*
* FileOps.ENCODINGS.ISO_8859_1
* FileOps.ENCODINGS.US_ASCII
* FileOps.ENCODINGS.UTF_8
* FileOps.ENCODINGS.UTF_16
* FileOps.ENCODINGS.WINDOWS_1252
*
* NODEJS_ENCODINGS
* This is an object with predefined file encodings for NodeJS streams:
*
* FileOps.NODEJS_ENCODINGS.ASCII
* FileOps.NODEJS_ENCODINGS.BASE_64
* FileOps.NODEJS_ENCODINGS.BINARY
* FileOps.NODEJS_ENCODINGS.HEX
* FileOps.NODEJS_ENCODINGS.UCS2
* FileOps.NODEJS_ENCODINGS.UTF_8
* FileOps.NODEJS_ENCODINGS.UTF_16_LE
*
* METHODS:
* WARNING: All prefixed methods work in the Virtual or Managed area.
*
* Note that "userprompt" (where specified) shows a window that allows
* the user to save a file wherever he'd like to.
*
* WARNING: All Virtual- methods are asynchronous!!!
*
* BOOL FileOps.FileExists( filepath )
* Checks the existence of the specified file.
*
* STRING filepath: Full path to file, e.g.: "C:\\file.txt"
*
* STRING FileOps.BufferToString( buffer, encoding, start, length )
* Turns a Buffer object returned by NodeJS into a string.
* Alias of NodeJS's Buffer.toString().
* https://nodejs.org/api/buffer.html#buffer_buf_tostring_encoding_start_end
*
* WARNING: NodeJS methohds don't work in non-NW.js platforms and if you try
* to execute them in that case, an Exception is thrown.
*
* FileOps.ReadFile
* Alias for NodeJS's readFileSync().
* https://nodejs.org/api/fs.html#fs_fs_readfilesync_file_options
*
* FileOps.ReadFileAsync
* Alias for NodeJS's readFile().
* https://nodejs.org/api/fs.html#fs_fs_readfile_file_options_callback
*
* FileOps.WriteFile
* Alias for NodeJS's writeFileSync().
* https://nodejs.org/api/fs.html#fs_fs_writefilesync_file_data_options
*
* FileOps.WriteFileAsync
* Alias for NodeJS's writeFile().
* https://nodejs.org/api/fs.html#fs_fs_writefile_file_data_options_callback
*
* ASYNC FileOps.URIExists( uri, callback )
* Checks the existence of a remote file.
* WARNING: This method is asynchronous!
* WARNING: ONLY HTTP 200 will return true!!!
*
* STRING uri: URI of the file to test.
* FUNCTION( BOOL ) callback: To be called when the response is ready.
* The response is BOOLEAN.
*
* INT FileOps.StringToBytes( str )
* Gets length of given string in bytes.
* WARNING: UTF8 encoding is assumed!!!
*
* STRING str: The string to be elaborated.
*
* VOID FileOps.VirtualGetStorageInfo( callback )
* Gets storage information.
* FUNCTION( OBJECT ) callback: To be called when the response is ready.
* An object containing members "used" and "MaxQuota" is returned,
* their values are expressed in bytes (1 * 1024 * 1024 = 1M
*
* INT FileOps.VirtualGetStorageSpaceLeft ( )
* Gets storage's space left.
* WARNING: Please use it.
*
* ASYNC FileOps.VirtualDeleteFile( filepath, callback )
* Deletes the specified virtual file.
* WARNING: May end in unexpected results.
*
* STRING filepath: Path to file, can be virtual only.
* FUNCTION( VOID ) callback: To be called when the response is ready.
* No message is returned.
*
* ASYNC FileOps.VirtualFileExists( filepath, callback )
* Checks the existence of a virtual file.
* WARNING: This method is asynchronous!!!
* WARNING: Use FileOps.URIExists() to test a remote file!!!
*
* STRING filepath: Path to file, can be virtual or absolute. To specify
* an absolute path, use file:///C:/... protocol.
* FUNCTION( BOOL/FILEERROR ) callback: To be called when the response is ready.
* The response is BOOLEAN when the file exists or not, FILEERROR if an
* error has occurred.
*
* VOID FileOps.VirtualRequestMaxQuota( quota )
* Sets the maximum storage size of written files.
* WARNING: The specified quota considers the SUM of the sizes of the
* files, so be careful when saving data with User Prompt disabled!!!
*
* INT quota: the amount of MAX storage IN BYTES (1 * 1024 * 1024 = 1M
* that the application may use.
*
* ASYNC FileOps.VirtualSaveFile( filepath, txt, userprompt, size, callback )
* Saves a text file in the sandboxed virtual storage.
* WARNING: This method is asynchronous!!!
* WARNING: This function IS NOT binary safe! Use FileOps.VirtualSaveJSON() to save
* javascript data and FileOps.VirtualSaveBinary() for binary data!!!
*
* STRING filepath: Path to file, can be virtual only.
* STRING txt: The text to be written.
* BOOL userprompt: Whether to prompt user to save file to a custom location
* (in this case, size is not needed and can be set to 0).
* INT size: In bytes (1 * 1024 * 1024 = 1M
* N.B.: Consider using FileOps.StringToBytes().
* FUNCTION( VOID ) callback: To be called when the response is ready.
* No message is returned.
*
* ASYNC FileOps.VirtualSaveJSON( filepath, json, userprompt, size, callback )
* Same thing as FileOps.VirtualSaveFile(), requires data in JSON format.
* N.B.: Any javascript object data is considered JSON data.
* WARNING: This method is asynchronous!!!
*
* STRING filepath: Path to file, can be virtual only.
* OBJECT json: The JSON object to be saved.
* BOOL userprompt: Whether to prompt user to save file to a custom location
* (in this case, size is not needed and can be set to 0).
* INT size: In bytes (1 * 1024 * 1024 = 1M
* N.B.: Consider using FileOps.StringToBytes().
* FUNCTION( VOID ) callback: To be called when the response is ready.
* No message is returned.
*
* ASYNC FileOps.VirtualSaveBinary( filepath, arrBuffer, mime, userprompt, size, callback )
* Writes binary data to a file in the sandboxed virtual storage.
* WARNING: arrBuffer IS NOT an ordinary Array!!!
* WARNING: This method is asynchronous!!!
*
* STRING filepath: Path to file, can be virtual only.
* ARRAYBUFFER arrBuffer: The binary data to be written.
* WARNING: This is not an ordinary Array!!!
* BOOL userprompt: Whether to prompt user to save file to a custom location
* (in this case, size is not needed and can be set to 0).
* INT size: In bytes (1 * 1024 * 1024 = 1M
* N.B.: Consider using FileOps.StringToBytes().
* STRING mime: MIME type of the data. Take a look to the predefined ones,
* above mentioned.
* WARNING: An invalid MIME format likely causes the procedure to fail!!!
* FUNCTION( VOID ) callback: To be called when the response is ready.
* No message is returned.
*
* ASYNC FileOps.VirtualReadFile( filepath, callback )
* Reads text data from a file or web stream.
* WARNING: This method IS NOT binary safe! Use FileOps.VirtualReadJSON() to read
* javascript data and FileOps.VirtualReadBinary() for binary data!!!
* WARNING: This method is asynchronous!!!
*
* STRING filepath: Path to file, can be virtual or absolute. To specify
* an absolute path, use file:///C:/... protocol.
* N.B.: Can be a web URI.
* WARNING: In order to deploy / read data from the URI without errors,
* Access-Control-Allow-Origin header must be set to "*".
* Please, take a look at
* https://en.wikipedia.org/wiki/Same-origin_policy
* FUNCTION( STRING ) callback: To be called when the response is ready.
* The content of the file is returned.
*
* ASYNC FileOps.VirtualReadJSON( filepath, callback )
* Reads JSON data from a file or web stream.
* WARNING: This method IS NOT binary safe! Use FileOps.VirtualReadBinary() for binary data!!!
* WARNING: This method is asynchronous!!!
*
* STRING filepath: Path to file, can be virtual or absolute. To specify
* an absolute path, use file:///C:/... protocol.
* N.B.: Can be a web URI.
* WARNING: In order to deploy / read data from the URI without errors,
* Access-Control-Allow-Origin header must be set to "*".
* Please, take a look at
* https://en.wikipedia.org/wiki/Same-origin_policy
* FUNCTION( OBJECT ) callback: To be called when the response is ready.
* JSON object is returned.
*
* ASYNC FileOps.VirtualReadBinary( filepath, mime, callback )
* Reads binary data from a file or web stream.
* WARNING: This method returns an ArrayBuffer, please check out documentation
* at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer
*
* STRING filepath: Path to file, can be virtual or absolute. To specify
* an absolute path, use file:///C:/... protocol.
* N.B.: Can be a web URI.
* WARNING: In order to deploy / read data from the URI without errors,
* Access-Control-Allow-Origin header must be set to "*".
* Please, take a look at
* https://en.wikipedia.org/wiki/Same-origin_policy
* STRING mime: MIME type of the data. Take a look to the predefined ones,
* above mentioned.
* WARNING: An invalid MIME format likely causes the procedure to fail!!!
* FUNCTION( ARRAYBUFFER ) callback: To be called when the response is ready.
* ArrayBuffer object is returned.
* WARNING: This is not an ordinary Array!!!
*
* VOID FileOps.ManagedSaveJSON( fileid, json )
* Saves JSON data using the predefined manager.
* WARNING: This data is managed by RPGMAKER!!!
*
* STRING fileid: ID of the file.
* WARNING: This is not a path!!!
* OBJECT json: The JSON object to be saved.
*
* OBJECT FileOps.ManagedReadJSON( fileid )
* Reads JSON data using the predefined manager.
* WARNING: This data is managed by RPGMAKER!!!
*
* STRING fileid: ID of the file.
* WARNING: This is not a path!!!
*
* BOOL FileOps.ManagedFileExists( fileid )
* Checks the existence of the specified file using the predefined manager.
* WARNING: This tests inside the managed area!!!
*
* STRING fileid: ID of the file.
* WARNING: This is not a path!!!
*
* VOID FileOps.ManagedDeleteFile( fileid )
* Deletes a file using the predefined manager.
* WARNING: This data is managed by RPGMAKER!!!
*
* STRING fileid: ID of the file.
* WARNING: This is not a path!!!
*
* WARNING: NodeJS methohds don't work in non-NW.js platforms and if you try
* to execute them in that case, an Exception is thrown.
*
* FileOps.ExecuteCommand
* Alias for NodeJS's execSync().
* https://nodejs.org/api/child_process.html#child_process_child_process_execsync_command_options
*
* ASYNC FileOps.ExecuteCommandAsync
* Alias for NodeJS's exec().
* https://nodejs.org/api/child_process.html#child_process_child_process_exec_command_options_callback
*
* FileOps.SpawnCommand
* Alias for NodeJS's spawnSync().
* https://nodejs.org/api/child_process.html#child_process_child_process_spawnsync_command_args_options
*
* ASYNC FileOps.SpawnCommandAsync
* Alias for NodeJS's spawn().
* https://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options
*
* FileOps.ExecuteFile
* Alias for NodeJS's execFileSync().
* https://nodejs.org/api/child_process.html#child_process_child_process_execfilesync_file_args_options
*
* ASYNC FileOps.ExecuteFileAsync
* Alias for NodeJS's execFile().
* https://nodejs.org/api/child_process.html#child_process_child_process_execfile_file_args_options_callback
*
* ******************** Nomid ********************
*/
!function(window)
{
"use strict";
if(window.Nomid === undefined)
window.Nomid = {};
window.Nomid.FileOps = {};
/* CONFIGURATION */
/// Max storage allocation (all created files must TOTALIZE lower than this quota)
window.Nomid.VirtualGrantedMaxQuota = 5 * 1024 * 1024; // 5 MB
window.Nomid.ShowDebugInfo = false;
/* END CONFIGURATION */
// Try-Catch works
function NomidFileOpsException(message)
{
SceneManager._scene.stop();
AudioManager.stopAll();
Graphics.printError('Nomid.FileOps Exception', message);
return new Error("Nomid.FileOps Exception: " + message);
}
/**
* Checks whether the platform is NW.js.
*
* @author Iavra
*
* @static
* @method isNwjs
* @return {Boolean} True if the platform is NW.js
*/
Utils.isNwjs = function()
{ return typeof require === 'function' && typeof process === 'object'; };
window.requestFileSystem = window.requestFileSystem || window.webkitRequestFileSystem;
/// Helper
function onInitFs(fs)
{
if(Nomid.ShowDebugInfo) console.info('Nomid.FileOps: Access granted for Virtual File Path: %s', fs.name);
if(Nomid.ShowDebugInfo) console.log('Nomid.FileOps: File System properties: %o', fs);
}
function errorHandler(e)
{
throw NomidFileOpsException('errorHandler(): Error saving file: ' + e.message);
}
function saveWithoutPrompt(fpath, fs, blob, callback)
{
onInitFs(fs);
fs.root.getFile(fpath, {create: true, exclusive: false}, function(fileEntry)
{
if(Nomid.ShowDebugInfo) console.info('Nomid.FileOps::saveWithoutPrompt(): Initializing buffer...');
fileEntry.createWriter(function(fileWriter)
{
fileWriter.onwriteend = function(e)
{
if(Nomid.ShowDebugInfo) console.info('Nomid.FileOps::saveWithoutPrompt(): Writing of ' + fpath + ' succeded.');
callback();
};
fileWriter.onerror = function(e)
{
throw NomidFileOpsException('saveWithoutPrompt(): Writing of ' + fpath + ' failed: ' + e.toString());
};
fileWriter.write(blob);
}, errorHandler);
}, errorHandler);
}
function loadNWmodule(what)
{
if(!Utils.isNwjs())
throw NomidFileOpsException("Can't load a NW.js module in a non NW.js environment.");
else
return fs[what];
}
var fs = require("fs") || "unavailable";
var exec = require('child_process').exec || "unavailable";
var spawn = require('child_process').spawn || "unavailable";
var execFile = require('child_process').execFile || "unavailable";
var execSync = require('child_process').execSync || "unavailable";
var spawnSync = require('child_process').spawnSync || "unavailable";
var execFileSync = require('child_process').execFileSync || "unavailable";
if(!Utils.isNwjs()) console.warn("Nomid.FileOps: Not in a NW.js environment: File System methods won't work.");
window.Nomid.FileOps = {
/// Predefined MIME types
MIME: {
JavaScript: "application/javascript",
MP4: "application/mp4",
GeneralBinaryData: "application/octet-stream",
MSWORD: "application/msword",
PDF: "application/pdf",
RTF: "text/rtf",
XML: "text/xml",
TAR: "application/x-tar",
ZIP: "multipart/x-zip",
MPEGAUDIO: "audio/mpeg",
WAVE: "audio/x-wav",
GIF: "image/gif",
JPEG: "image/jpeg",
PNG: "image/png",
GZIP: "multipart/x-gzip",
CSS: "text/css",
CSV: "text/csv",
HTML: "text/html",
PLAINTEXT: "text/plain",
AVI: "video/msvideo",
RAR: "application/x-rar-compressed"
},
/// Predefined file encodings for requests
ENCODINGS: {
UTF_8: 'utf8',
US_ASCII: 'us-ascii',
UTF_16: 'utf16',
ISO_8859_1: 'iso-8859-1',
WINDOWS_1252: 'windows-1252'
},
/// Supported file encodings by NodeJS
NODEJS_ENCODINGS: {
UTF_8: 'utf8',
ASCII: 'ascii',
BASE_64: 'base64',
BINARY: 'binary',
HEX: 'hex',
UCS2: 'ucs2',
UTF_16_LE: 'utf16le'
},
/// Predefined system shells
SHELLS: {
WINDOWS: 'cmd.exe',
UNIX: '/bin/sh'
},
/**
* @param {String} filepath
* @param {Function} callback
* @returns {String}
*/
URIExists: function(filepath, callback)
{
if(typeof filepath !== "string" || filepath === undefined || filepath == '')
throw NomidFileOpsException('URIExists(): URI path is null.');
if(typeof callback !== "function")
throw NomidFileOpsException('URIExists(): Callback is not set. Filename: ' + filepath);
if(Nomid.ShowDebugInfo) console.info("Nomid.FileOps: URIExists(): Checking for existence of %s...", filepath);
var rawFile = new XMLHttpRequest(), allText = '';
rawFile.open("HEAD", filepath, false);
rawFile.onreadystatechange = function ()
{
if(rawFile.readyState === 4)
allText = rawFile.responseText, !function()
{
if(Nomid.ShowDebugInfo) console.info("Nomid.FileOps: URIExists(): Status: %s.", rawFile.status.toString());
callback(!!(rawFile.status === 200));
}();
};
try
{
rawFile.send(null);
} catch(E)
{
throw NomidFileOpsException('URIExists(): Unknown DOMError: ' + E.message);
}
},
/**
* @param {String} str
* @returns {Number}
*/
StringToBytes: function(str)
{
return Buffer.byteLength(str, 'utf8');
},
/**
* @param {Buffer} buff
* @param {String} enc
* @param {Number} s
* @param {Number} l
* @returns {string}
*/
BufferToString: function(buff, enc, s, l)
{
return buff.toString(enc, s, l);
},
/**
* @param {String} quota
* @returns {void}
*/
VirtualRequestMaxQuota: function(quota)
{
if(quota === || quota === undefined)
throw NomidFileOpsException("VirtualRequestMaxQuota(): Can't set a null quota.");
navigator.webkitPersistentStorage.requestQuota(quota, function(grantedBytes)
{
window.requestFileSystem(PERSISTENT, grantedBytes, onInitFs, errorHandler);
}, function(e) {
throw NomidFileOpsException('VirtualRequestMaxQuota(): Access Denied using quota ' + quota + ': ' + e);
});
if(Nomid.ShowDebugInfo) console.info("Nomid.FileOps: Set max quota: " + quota);
Nomid.VirtualGrantedMaxQuota = quota;
},
/**
* @param {Function} callback( { usage, MaxQuota } )
* @returns {Object}
*/
VirtualGetStorageInfo: function(callback)
{
if(typeof callback !== "function")
throw NomidFileOpsException('VirtualGetStorageInfo(): Callback is not set. Filename: ' + filepath);
navigator.webkitPersistentStorage.queryUsageAndQuota(function(used, max)
{
callback({ 'usage': used, 'MaxQuota': max });
}, function(E)
{
throw NomidFileOpsException('VirtualGetStorageInfo(): Error: ' + E.message);
});
},
VirtualGetStorageSpaceLeft: function()
{
var cb;
FileOps.VirtualGetStorageInfo(function(i){ cb = i; });
return (cb.MaxQuota - cb.used);
},
/**
* @param {String} filepath
* @param {Function} callback( void )
* @returns {void}
*/
VirtualDeleteFile: function(filepath, callback)
{
if(typeof filepath !== "string" || filepath === undefined || filepath == '')
throw NomidFileOpsException('VirtualDeleteFile(): File path is null.');
if(typeof callback !== "function")
throw NomidFileOpsException('VirtualDeleteFile(): Callback is not set. Filename: ' + filepath);
Nomid.FileOps.VirtualFileExists(filepath, function(E)
{
if(E)
navigator.webkitPersistentStorage.requestQuota(, function(grantedBytes)
{
window.requestFileSystem(PERSISTENT, grantedBytes, function(fs)
{
onInitFs();
fs.root.getFile(filepath, {create: false}, function(fe)
{
if(Nomid.ShowDebugInfo) console.info("Nomid.FileOps: VirtualDeleteFile(): Trying to delete file %s...", filepath);
fe.remove(function()
{
if(Nomid.ShowDebugInfo) console.info("Nomid.FileOps: VirtualDeleteFile(): File %s has been deleted.", filepath)
callback();
}, errorHandler);
}, errorHandler);
}, errorHandler);
}, function(e)
{
throw NomidFileOpsException("VirtualDeleteFile(): Unexpected error: " + e.message);
});
else
throw NomidFileOpsException("VirtualDeleteFile(): File " + filepath + " does not exist.");
});
},
/**
* @param {String} filepath
* @param {Function} callback( boolean )
* @returns {void}
*/
VirtualFileExists: function(filepath, callback)
{
if(typeof filepath !== "string" || filepath === undefined || filepath == '')
throw NomidFileOpsException('VirtualFileExists(): File path is null.');
if(typeof callback !== "function")
throw NomidFileOpsException('VirtualFileExists(): Callback is not set. Filename: ' + filepath);
if(filepath.indexOf("http://") == -1 && filepath.indexOf("file:///") == -1)
return window.requestFileSystem(PERSISTENT, , function(fs)
{
if(Nomid.ShowDebugInfo) console.info("Nomid.FileOps: VirtualFileExists(): Checking for existence of %s...", filepath);
fs.root.getFile(filepath, {create: false}, function(f)
{
onInitFs(f);
callback(true);
}, function(E)
{
if(E.name === "NotFoundError")
if(Nomid.ShowDebugInfo) console.warn("Nomid.FileOps: VirtualFileExists(): File not found."), callback(false);
else
if(Nomid.ShowDebugInfo) console.warn("Nomid.FileOps: VirtualFileExists(): FileError: " + E.message), callback(E);
});
}, errorHandler);
if(Nomid.ShowDebugInfo) console.info("Nomid.FileOps: VirtualFileExists(): Checking for existence of %s...", filepath);
var rawFile = new XMLHttpRequest(), allText = '';
rawFile.open("HEAD", filepath, false);
rawFile.onreadystatechange = function ()
{
if(rawFile.readyState === 4)
allText = rawFile.responseText, !function()
{
var res = (rawFile.responseURL !== "");
if(Nomid.ShowDebugInfo) console.info("Nomid.FileOps: VirtualFileExists(): Status: %s; exists: %s.", rawFile.status.toString(), res.toString());
callback(res);
}();
};
try
{
rawFile.send(null);
} catch(E)
{
throw NomidFileOpsException('VirtualFileExists(): Unknown DOMError: ' + E.message);
}
},
/**
* @param {String} filepath
* @param {String} txt
* @param {Boolean} userprompt
* @param {Number} size
* @param {Function} callback( void )
* @returns {void}
*/
VirtualSaveFile: function(filepath, txt, userprompt, size, callback)
{
if(typeof filepath !== "string" || filepath === undefined || filepath == '')
throw NomidFileOpsException('VirtualSaveFile(): File path is null.');
if(typeof txt !== "string")
throw NomidFileOpsException('VirtualSaveFile(): Input data must be a string. Filename: ' + filepath);
if(!userprompt && (typeof size !== "number" || size < FileOps.VirtualGetStorageSpaceLeft())
throw NomidFileOpsException('VirtualSaveFile(): Invalid file size. Filename: ' + filepath);
if(userprompt !== true)
userprompt = false;
if(filepath.indexOf("file:///") > -1 && !userprompt)
throw NomidFileOpsException('VirtualSaveFile(): Can\'t save a file outside the Virtual Storage area without prompt.');
if(typeof callback !== "function" && !userprompt)
throw NomidFileOpsException('VirtualSaveFile(): Callback is not set. Filename: ' + filepath);
Nomid.FileOps.VirtualFileExists(filepath, function(E)
{
if(E)
if(Nomid.ShowDebugInfo) console.warn("Nomid.FileOps: VirtualSaveFile(): File exists, will overwrite. Filename: " + filepath);
});
var myBlob = new Blob([txt], {type: 'text/plain'});
if(userprompt)
saveAs(myBlob, filepath, true);
else
{
var doTheSave = function(fs)
{
saveWithoutPrompt(filepath, fs, myBlob, callback);
};
window.requestFileSystem(window.PERSISTENT, size, doTheSave, errorHandler);
}
},
/**
* @param {String} filepath
* @param {Object} json
* @param {Boolean} userprompt
* @param {Number} size
* @param {Function} callback( void )
* @returns {void}
*/
VirtualSaveJSON: function(filepath, json, userprompt, size, callback)
{
if(typeof filepath !== "string" || filepath === undefined || filepath == '')
throw NomidFileOpsException('VirtualSaveJSON(): File path is null.');
if(typeof json !== "object")
throw NomidFileOpsException('VirtualSaveJSON(): Input data must be a JSON object. Filename: ' + filepath);
if(!userprompt && (typeof size !== "number" || size < FileOps.VirtualGetStorageSpaceLeft()))
throw NomidFileOpsException('VirtualSaveJSON(): Invalid file size. Filename: ' + filepath);
if(userprompt !== true)
userprompt = false;
if(filepath.indexOf("file:///") > -1 && !userprompt)
throw NomidFileOpsException('VirtualSaveFile(): Can\'t save a file outside the Virtual Storage area without prompt.');
if(typeof callback !== "function" && !userprompt)
throw NomidFileOpsException('VirtualSaveJSON(): Callback is not set. Filename: ' + filepath);
Nomid.FileOps.VirtualFileExists(filepath, function(E)
{
if(E)
if(Nomid.ShowDebugInfo) console.warn("Nomid.FileOps: VirtualSaveJSON(): File exists, will overwrite. Filename: " + filepath);
});
var myBlob = new Blob([JSON.stringify(json)], {type: 'text/json'});
if(userprompt)
saveAs(myBlob, filepath, true);
else
{
var doTheSave = function(fs)
{
saveWithoutPrompt(filepath, fs, myBlob, callback);
};
window.requestFileSystem(window.PERSISTENT, size, doTheSave, errorHandler);
}
},
/**
* @param {String} filepath
* @param {ArrayBuffer} arrBuffer
* @param {String} mime
* @param {Boolean} userprompt
* @param {Number} size
* @param {Function} callback( void )
* @returns {void}
*/
VirtualSaveBinary: function(filepath, arrBuffer, mime, userprompt, size, callback)
{
if(typeof filepath !== "string" || filepath === undefined || filepath == '')
throw NomidFileOpsException('VirtualSaveBinary(): File path is null.');
if(!(arrBuffer instanceof ArrayBuffer))
throw NomidFileOpsException('VirtualSaveBinary(): Input data must be an instance of ArrayBuffer. Filename: ' + filepath);
if(typeof mime !== "string" || mime === undefined || mime == '')
throw NomidFileOpsException('VirtualSaveBinary(): File MIME can\'t be null. Filename: ' + filepath);
if(!userprompt && (typeof size !== "number" || size < FileOps.VirtualGetStorageSpaceLeft()))
throw NomidFileOpsException('VirtualSaveBinary(): Invalid file size. Filename: ' + filepath);
if(userprompt !== true)
userprompt = false;
if(filepath.indexOf("file:///") > -1 && !userprompt)
throw NomidFileOpsException('VirtualSaveFile(): Can\'t save a file outside the Virtual Storage area without prompt.');
if(typeof callback !== "function" && !userprompt)
throw NomidFileOpsException('VirtualSaveBinary(): Callback is not set. Filename: ' + filepath);
if(Nomid.ShowDebugInfo) console.warn("Nomid.FileOps: VirtualSaveBinary(): Using MIME %s for file %s", mime, filepath);
Nomid.FileOps.VirtualFileExists(filepath, function(E)
{
if(E)
if(Nomid.ShowDebugInfo) console.warn("Nomid.FileOps: VirtualSaveBinary(): File exists, will overwrite. Filename: %s", filepath);
});
if(Nomid.ShowDebugInfo) console.info("Nomid.FileOps: VirtualSaveBinary(): Recieved buffer: %o", arrBuffer);
var myBlob = new Blob([arrBuffer], {type: mime});
if(userprompt)
saveAs(myBlob, filepath, true);
else
{
var doTheSave = function(fs)
{
saveWithoutPrompt(filepath, fs, myBlob, callback);
};
window.requestFileSystem(window.PERSISTENT, size, doTheSave, errorHandler);
}
},
/**
* @param {String} filepath
* @param {Function} callback( string )
* @returns {void}
*/
VirtualReadFile: function(filepath, callback)
{
if(typeof filepath !== "string" || filepath === undefined || filepath == '')
throw NomidFileOpsException('VirtualReadFile(): File path is null.');
if(typeof callback !== "function")
throw NomidFileOpsException('VirtualReadFile(): Callback is not set. Filename: ' + filepath);
Nomid.FileOps.VirtualFileExists(filepath, function(R)
{
if(R)
{
if(filepath.indexOf("file:///") > -1)
window.requestFileSystem(PERSISTENT, , function(fs)
{
onInitFs();
fs.root.getFile(filepath, {}, function(fs)
{
fs.file(function(file) {
var reader = new FileReader();
reader.onloadend = function(e)
{
callback(this.result);
};
reader.readAsText(file);
}, errorHandler);
}, errorHandler);
}, errorHandler);
else
{
var rawFile = new XMLHttpRequest(), allText = '';
rawFile.open("HEAD", filepath, false);
rawFile.onreadystatechange = function ()
{
if(rawFile.readyState === 4)
if(rawFile.status === 200 || rawFile.status == )
allText = rawFile.responseText, !function()
{
if(Nomid.ShowDebugInfo) console.info("Nomid.FileOps: VirtualReadFile(): Read " + filepath);
callback(allText);
}();
};
try
{
rawFile.send(null);
} catch(E)
{
throw NomidFileOpsException("VirtualReadFile(): Unexpected error: " + E.message);
}
}
}
else
throw NomidFileOpsException('VirtualReadFile(): File does not exist. Filename: ' + filepath);
});
},
/**
* @param {String} filepath
* @param {Function} callback( object )
* @returns {void}
*/
VirtualReadJSON: function(filepath, callback)
{
if(typeof filepath !== "string" || filepath === undefined || filepath == '')
throw NomidFileOpsException('VirtualReadJSON(): File path is null.');
if(typeof callback !== "function")
throw NomidFileOpsException('VirtualReadJSON(): Callback is not set. Filename: ' + filepath);
Nomid.FileOps.VirtualReadFile(filepath, function(E)
{
var json;
try
{
json = JSON.parse(E);
}
catch(E)
{
throw NomidFileOpsException('VirtualReadJSON(): Malformed JSON. Filename: ' + filepath);
}
callback(json);
});
},
/**
* @param {String} filepath
* @param {String} mime
* @param {Function} callback( ArrayBuffer )
* @returns {void}
*/
VirtualReadBinary: function(filepath, mime, callback)
{
if(typeof filepath !== "string" || filepath === undefined || filepath == '')
throw NomidFileOpsException('VirtualReadJSON(): File path is null.');
if(typeof callback !== "function")
throw NomidFileOpsException('VirtualReadBinary(): Callback is not set. Filename: ' + filepath);
if(filepath === undefined)
throw NomidFileOpsException("Nomid.FileOps: ");
if(mime === undefined || mime == "")
throw NomidFileOpsException("VirtualReadBinary(): MIME type not defined. Filename: " + filepath);
if(Nomid.ShowDebugInfo) console.warn("Nomid.FileOps: VirtualReadBinary(): Reading " + filepath + " with mime " + mime);
Nomid.FileOps.VirtualFileExists(filepath, function(R)
{
if(R)
{
if(filepath.indexOf("file:///") == -1 && filepath.indexOf("http://") == -1)
window.requestFileSystem(PERSISTENT, , function(fs)
{
onInitFs(fs);
fs.root.getFile(filepath, {}, function(fs)
{
if(Nomid.ShowDebugInfo) console.log("Nomid.FileOps: VirtualReadBinary: Accessing %o", fs);
fs.file(function(file) {
var reader = new FileReader();
reader.onloadend = function(e)
{
if(Nomid.ShowDebugInfo) console.log("Nomid.FileOps: VirtualReadBinary: Read end: %o with %o", this.result, e);
callback(this.result);
};
reader.readAsArrayBuffer(file);
if(Nomid.ShowDebugInfo) console.log("Nomid.FileOps: VirtualReadBinary: Read stream %o from %o", reader, file);
}, errorHandler);
}, errorHandler);
}, errorHandler);
else
{
var oReq = new XMLHttpRequest();
oReq.open("GET", filepath, true);
oReq.responseType = "arraybuffer";
var blob = undefined;
oReq.onload = function(oEvent)
{
blob = new Blob([oReq.response], {type: mime});
if(Nomid.ShowDebugInfo) console.info("Nomid.FileOps: VirtualReadBinary(): Read %s.", filepath);
var arrayBuffer;
var fileReader = new FileReader();
fileReader.onload = function()
{
arrayBuffer = this.result;
callback(arrayBuffer);
};
fileReader.readAsArrayBuffer(blob);
};
try
{
oReq.send();
} catch(E)
{
throw NomidFileOpsException("VirtualReadBinary(): Unexpected error: " + E.message);
}
}
}
});
},
/**
* @param {String} fileid
* @param {Object} json
* @returns {void}
*/
ManagedSaveJSON: function(fileid, json)
{
if(typeof fileid !== "string" || fileid === undefined || fileid == '')
throw NomidFileOpsException('ManagedSaveJSON(): File ID is null.');
if(typeof json !== "object" || json === undefined)
throw NomidFileOpsException('ManagedSaveJSON(): Invalid object.');
StorageManager.save(fileid, JSON.stringify(json));
},
/**
* @param {String} fileid
* @returns {Object}
*/
ManagedReadJSON: function(fileid)
{
if(typeof fileid !== "string" || fileid === undefined || fileid == '')
throw NomidFileOpsException('ManagedReadJSON(): File ID is null.');
return StorageManager.load(fileid);
},
/**
* @param {String} fileid
* @returns {Boolean}
*/
ManagedFileExists: function(fileid)
{
if(typeof fileid !== "string" || fileid === undefined || fileid == '')
throw NomidFileOpsException('ManagedReadJSON(): File ID is null.');
return StorageManager.exists(fileid);
},
/**
* @param {String} fileid
* @returns {void}
*/
ManagedDeleteFile: function(fileid)
{
if(typeof fileid !== "string" || fileid === undefined || fileid == '')
throw NomidFileOpsException('ManagedReadJSON(): File ID is null.');
if(!Nomid.FileOps.ManagedFileExists(fileid))
throw NomidFileOpsException('ManagedReadJSON(): File with ID "' + fileid + '" does not exist.');
StorageManager.remove(fileid);
},
/**
* @param {String} fpath
* @returns {Boolean}
*/
FileExists: function(fpath)
{
if(!Utils.isNwjs())
throw NomidFileOpsException("Can't load a NW.js module in a non NW.js environment.");
if(typeof filepath !== "string" || filepath === undefined || filepath == '')
throw NomidFileOpsException('FileExists(): File path is null.');
var f = fs.statSync(fpath);
return !!(f.isFile());
},
ReadFile: function()
{
if(!Utils.isNwjs())
throw NomidFileOpsException("Can't load a NW.js module in a non NW.js environment.");
else
return fs.readFileSync.apply(this, arguments);
},
ReadFileAsync: function()
{
if(!Utils.isNwjs())
throw NomidFileOpsException("Can't load a NW.js module in a non NW.js environment.");
else
return fs.readFile.apply(this, arguments);
},
WriteFileAsync: function()
{
if(!Utils.isNwjs())
throw NomidFileOpsException("Can't load a NW.js module in a non NW.js environment.");
else
return fs.writeFile.apply(this, arguments);
},
WriteFile: function()
{
if(!Utils.isNwjs())
throw NomidFileOpsException("Can't load a NW.js module in a non NW.js environment.");
else
return fs.writeFileSync.apply(this, arguments);
},
ExecuteCommand: function()
{
if(!Utils.isNwjs())
throw NomidFileOpsException("Can't load a NW.js module in a non NW.js environment.");
else
return execSync.apply(this, arguments);
},
SpawnCommand: function()
{
if(!Utils.isNwjs())
throw NomidFileOpsException("Can't load a NW.js module in a non NW.js environment.");
else
return spawnSync.apply(this, arguments);
},
ExecuteFile: function()
{
if(!Utils.isNwjs())
throw NomidFileOpsException("Can't load a NW.js module in a non NW.js environment.");
else
return execFileSync.apply(this, arguments);
},
ExecuteCommandAsync: function()
{
if(!Utils.isNwjs())
throw NomidFileOpsException("Can't load a NW.js module in a non NW.js environment.");
else
return exec.apply(this, arguments);
},
SpawnCommandAsync: function()
{
if(!Utils.isNwjs())
throw NomidFileOpsException("Can't load a NW.js module in a non NW.js environment.");
else
return spawn.apply(this, arguments);
},
ExecuteFileAsync: function()
{
if(!Utils.isNwjs())
throw NomidFileOpsException("Can't load a NW.js module in a non NW.js environment.");
else
return execFile.apply(this, arguments);
}
};
/// It's better to check from the beginning
Nomid.FileOps.VirtualRequestMaxQuota(Nomid.VirtualGrantedMaxQuota);
// EDITED BY NOMID
/* saveAs() FileSaver implementation.
* 1.1.20151003
*
* By Eli Grey, http://eligrey.com
* License: MIT
* See https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md
*/
/*global self */
/*jslint bitwise: true, indent: 4, laxbreak: true, laxcomma: true, smarttabs: true, plusplus: true */
/*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */
var saveAs = saveAs || (function(view)
{
"use strict";
// IE <10 is explicitly unsupported
if (typeof navigator !== "undefined" && /MSIE [1-9]\./.test(navigator.userAgent)) {
return;
}
var
doc = view.document
// only get URL when necessary in case Blob.js hasn't overridden it yet
, get_URL = function() {
return view.URL || view.webkitURL || view;
}
, save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a")
, can_use_save_link = "download" in save_link
, click = function(node) {
var event = new MouseEvent("click");
node.dispatchEvent(event);
}
, is_safari = /Version\/[\d\.]+.*Safari/.test(navigator.userAgent)
, webkit_req_fs = view.webkitRequestFileSystem
, req_fs = view.requestFileSystem || webkit_req_fs || view.mozRequestFileSystem
, throw_outside = function(ex) {
(view.setImmediate || view.setTimeout)(function() {
throw ex;
}, );
}
, force_saveable_type = "application/octet-stream"
, fs_min_size =
// See https://code.google.com/p/chromium/issues/detail?id=375297#c7 and
// https://github.com/eligrey/FileSaver.js/commit/485930a#commitcomment-8768047
// for the reasoning behind the timeout and revocation flow
, arbitrary_revoke_timeout = 500 // in ms
, revoke = function(file) {
var revoker = function() {
if (typeof file === "string") { // file is an object URL
get_URL().revokeObjectURL(file);
} else { // file is a File
file.remove();
}
};
if (view.chrome) {
revoker();
} else {
setTimeout(revoker, arbitrary_revoke_timeout);
}
}
, dispatch = function(filesaver, event_types, event) {
event_types = [].concat(event_types);
var i = event_types.length;
while (i--) {
var listener = filesaver["on" + event_types];
if (typeof listener === "function") {
try {
listener.call(filesaver, event || filesaver);
} catch (ex) {
throw_outside(ex);
}
}
}
}
, auto_bom = function(blob) {
// prepend BOM for UTF-8 XML and text/* types (including HTML)
if (/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) {
return new Blob(["\ufeff", blob], {type: blob.type});
}
return blob;
}
, FileSaver = function(blob, name, no_auto_bom) {
if (!no_auto_bom) {
blob = auto_bom(blob);
}
// First try a.download, then web filesystem, then object URLs
var
filesaver = this
, type = blob.type
, blob_changed = false
, object_url
, target_view
, dispatch_all = function() {
dispatch(filesaver, "writestart progress write writeend".split(" "));
}
// on any filesys errors revert to saving with object URLs
, fs_error = function() {
if (target_view && is_safari && typeof FileReader !== "undefined") {
// Safari doesn't allow downloading of blob urls
var reader = new FileReader();
reader.onloadend = function() {
var base64Data = reader.result;
target_view.location.href = "data:attachment/file" + base64Data.slice(base64Data.search(/[,;]/));
filesaver.readyState = filesaver.DONE;
dispatch_all();
};
reader.readAsDataURL(blob);
filesaver.readyState = filesaver.INIT;
return;
}
// don't create more object URLs than needed
if (blob_changed || !object_url) {
object_url = get_URL().createObjectURL(blob);
}
if (target_view) {
target_view.location.href = object_url;
} else {
var new_tab = view.open(object_url, "_blank");
if (new_tab == undefined && is_safari) {
//Apple do not allow window.open, see http://bit.ly/1kZffRI
view.location.href = object_url
}
}
filesaver.readyState = filesaver.DONE;
dispatch_all();
revoke(object_url);
}
, abortable = function(func) {
return function() {
if (filesaver.readyState !== filesaver.DONE) {
return func.apply(this, arguments);
}
};
}
, create_if_not_found = {create: true, exclusive: false}
, slice
;
filesaver.readyState = filesaver.INIT;
if (!name) {
name = "download";
}
if (can_use_save_link) {
object_url = get_URL().createObjectURL(blob);
setTimeout(function() {
save_link.href = object_url;
save_link.download = name;
click(save_link);
dispatch_all();
revoke(object_url);
filesaver.readyState = filesaver.DONE;
});
return;
}
// Object and web filesystem URLs have a problem saving in Google Chrome when
// viewed in a tab, so I force save with application/octet-stream
// http://code.google.com/p/chromium/issues/detail?id=91158
// Update: Google errantly closed 91158, I submitted it again:
// https://code.google.com/p/chromium/issues/detail?id=389642
if (view.chrome && type && type !== force_saveable_type) {
slice = blob.slice || blob.webkitSlice;
blob = slice.call(blob, , blob.size, force_saveable_type);
blob_changed = true;
}
// Since I can't be sure that the guessed media type will trigger a download
// in WebKit, I append .download to the filename.
// https://bugs.webkit.org/show_bug.cgi?id=65440
if (webkit_req_fs && name !== "download") {
name += ".download";
}
if (type === force_saveable_type || webkit_req_fs) {
target_view = view;
}
if (!req_fs) {
fs_error();
return;
}
fs_min_size += blob.size;
req_fs(view.TEMPORARY, fs_min_size, abortable(function(fs) {
fs.root.getDirectory("saved", create_if_not_found, abortable(function(dir) {
var save = function() {
dir.getFile(name, create_if_not_found, abortable(function(file) {
file.createWriter(abortable(function(writer) {
writer.onwriteend = function(event) {
target_view.location.href = file.toURL();
filesaver.readyState = filesaver.DONE;
dispatch(filesaver, "writeend", event);
revoke(file);
};
writer.onerror = function() {
var error = writer.error;
if (error.code !== error.ABORT_ERR) {
fs_error();
}
};
"writestart progress write abort".split(" ").forEach(function(event) {
writer["on" + event] = filesaver["on" + event];
});
writer.write(blob);
filesaver.abort = function() {
writer.abort();
filesaver.readyState = filesaver.DONE;
};
filesaver.readyState = filesaver.WRITING;
}), fs_error);
}), fs_error);
};
dir.getFile(name, {create: false}, abortable(function(file) {
// delete file if it already exists
file.remove();
save();
}), abortable(function(ex) {
if (ex.code === ex.NOT_FOUND_ERR) {
save();
} else {
fs_error();
}
}));
}), fs_error);
}), fs_error);
}
, FS_proto = FileSaver.prototype
, saveAs = function(blob, name, no_auto_bom) {
return new FileSaver(blob, name, no_auto_bom);
}
;
// IE 10+ (native saveAs)
if (typeof navigator !== "undefined" && navigator.msSaveOrOpenBlob) {
return function(blob, name, no_auto_bom) {
if (!no_auto_bom) {
blob = auto_bom(blob);
}
return navigator.msSaveOrOpenBlob(blob, name || "download");
};
}
FS_proto.abort = function() {
var filesaver = this;
filesaver.readyState = filesaver.DONE;
dispatch(filesaver, "abort");
};
FS_proto.readyState = FS_proto.INIT = ;
FS_proto.WRITING = 1;
FS_proto.DONE = 2;
FS_proto.error =
FS_proto.onwritestart =
FS_proto.onprogress =
FS_proto.onwrite =
FS_proto.onabort =
FS_proto.onerror = null;
FS_proto.onwriteend =
null;
return saveAs;
}(
typeof self !== "undefined" && self
|| typeof window !== "undefined" && window
|| this.content
));
// `self` is undefined in Firefox for Android content script context
// while `this` is nsIContentFrameMessageManager
// with an attribute `content` that corresponds to the window
if (typeof module !== "undefined" && module.exports) {
module.exports.saveAs = saveAs;
} else if ((typeof define !== "undefined" && define !== null) && (define.amd != null)) {
define([], function() {
return saveAs;
});
}
}(window);
This plugin is free to use for all --- please give credit!
Thank you for using my plugin, report me any bug / features! Please, let me know if you use it!
Thanks to lavra for Utils.isNwjs() utility.
TODO list in next updates:
- Add in the asynchronous callbacks a status to inform about the operations.
- Local Storage access on mobile
DOCUMENTATION is found as attachment in PDF with chapters or in HTML format and in the js header (it is detailed, warnings are present).
Italian version can be found here with examples: http://www.rpg2s.net/forum/index.php/topic/20455-nfileopsjs-opera-con-il-file-system/
NEWS: added FileOps.VirtualGetStorageSpaceLeft() and fixed some bugs; added PDF version of the documentation organized in chapters.
View attachment NFileOps.html
View attachment NFileOps.pdf
Last edited by a moderator:

