diff options
Diffstat (limited to 'StoneIsland/plugins/cordova-plugin-file/www/FileReader.js')
| -rw-r--r-- | StoneIsland/plugins/cordova-plugin-file/www/FileReader.js | 298 |
1 files changed, 298 insertions, 0 deletions
diff --git a/StoneIsland/plugins/cordova-plugin-file/www/FileReader.js b/StoneIsland/plugins/cordova-plugin-file/www/FileReader.js new file mode 100644 index 00000000..9115f5f5 --- /dev/null +++ b/StoneIsland/plugins/cordova-plugin-file/www/FileReader.js @@ -0,0 +1,298 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * +*/ + +var exec = require('cordova/exec'); +var modulemapper = require('cordova/modulemapper'); +var utils = require('cordova/utils'); +var FileError = require('./FileError'); +var ProgressEvent = require('./ProgressEvent'); +var origFileReader = modulemapper.getOriginalSymbol(window, 'FileReader'); + +/** + * This class reads the mobile device file system. + * + * For Android: + * The root directory is the root of the file system. + * To read from the SD card, the file name is "sdcard/my_file.txt" + * @constructor + */ +var FileReader = function () { + this._readyState = 0; + this._error = null; + this._result = null; + this._progress = null; + this._localURL = ''; + this._realReader = origFileReader ? new origFileReader() : {}; // eslint-disable-line new-cap +}; + +/** + * Defines the maximum size to read at a time via the native API. The default value is a compromise between + * minimizing the overhead of many exec() calls while still reporting progress frequently enough for large files. + * (Note attempts to allocate more than a few MB of contiguous memory on the native side are likely to cause + * OOM exceptions, while the JS engine seems to have fewer problems managing large strings or ArrayBuffers.) + */ +FileReader.READ_CHUNK_SIZE = 256 * 1024; + +// States +FileReader.EMPTY = 0; +FileReader.LOADING = 1; +FileReader.DONE = 2; + +utils.defineGetter(FileReader.prototype, 'readyState', function () { + return this._localURL ? this._readyState : this._realReader.readyState; +}); + +utils.defineGetter(FileReader.prototype, 'error', function () { + return this._localURL ? this._error : this._realReader.error; +}); + +utils.defineGetter(FileReader.prototype, 'result', function () { + return this._localURL ? this._result : this._realReader.result; +}); + +function defineEvent (eventName) { + utils.defineGetterSetter(FileReader.prototype, eventName, function () { + return this._realReader[eventName] || null; + }, function (value) { + this._realReader[eventName] = value; + }); +} +defineEvent('onloadstart'); // When the read starts. +defineEvent('onprogress'); // While reading (and decoding) file or fileBlob data, and reporting partial file data (progress.loaded/progress.total) +defineEvent('onload'); // When the read has successfully completed. +defineEvent('onerror'); // When the read has failed (see errors). +defineEvent('onloadend'); // When the request has completed (either in success or failure). +defineEvent('onabort'); // When the read has been aborted. For instance, by invoking the abort() method. + +function initRead (reader, file) { + // Already loading something + if (reader.readyState === FileReader.LOADING) { + throw new FileError(FileError.INVALID_STATE_ERR); + } + + reader._result = null; + reader._error = null; + reader._progress = 0; + reader._readyState = FileReader.LOADING; + + if (typeof file.localURL === 'string') { + reader._localURL = file.localURL; + } else { + reader._localURL = ''; + return true; + } + + if (reader.onloadstart) { + reader.onloadstart(new ProgressEvent('loadstart', {target: reader})); + } +} + +/** + * Callback used by the following read* functions to handle incremental or final success. + * Must be bound to the FileReader's this along with all but the last parameter, + * e.g. readSuccessCallback.bind(this, "readAsText", "UTF-8", offset, totalSize, accumulate) + * @param readType The name of the read function to call. + * @param encoding Text encoding, or null if this is not a text type read. + * @param offset Starting offset of the read. + * @param totalSize Total number of bytes or chars to read. + * @param accumulate A function that takes the callback result and accumulates it in this._result. + * @param r Callback result returned by the last read exec() call, or null to begin reading. + */ +function readSuccessCallback (readType, encoding, offset, totalSize, accumulate, r) { + if (this._readyState === FileReader.DONE) { + return; + } + + var CHUNK_SIZE = FileReader.READ_CHUNK_SIZE; + if (readType === 'readAsDataURL') { + // Windows proxy does not support reading file slices as Data URLs + // so read the whole file at once. + CHUNK_SIZE = cordova.platformId === 'windows' ? totalSize : // eslint-disable-line no-undef + // Calculate new chunk size for data URLs to be multiply of 3 + // Otherwise concatenated base64 chunks won't be valid base64 data + FileReader.READ_CHUNK_SIZE - (FileReader.READ_CHUNK_SIZE % 3) + 3; + } + + if (typeof r !== 'undefined') { + accumulate(r); + this._progress = Math.min(this._progress + CHUNK_SIZE, totalSize); + + if (typeof this.onprogress === 'function') { + this.onprogress(new ProgressEvent('progress', {loaded: this._progress, total: totalSize})); + } + } + + if (typeof r === 'undefined' || this._progress < totalSize) { + var execArgs = [ + this._localURL, + offset + this._progress, + offset + this._progress + Math.min(totalSize - this._progress, CHUNK_SIZE)]; + if (encoding) { + execArgs.splice(1, 0, encoding); + } + exec( + readSuccessCallback.bind(this, readType, encoding, offset, totalSize, accumulate), + readFailureCallback.bind(this), + 'File', readType, execArgs); + } else { + this._readyState = FileReader.DONE; + + if (typeof this.onload === 'function') { + this.onload(new ProgressEvent('load', {target: this})); + } + + if (typeof this.onloadend === 'function') { + this.onloadend(new ProgressEvent('loadend', {target: this})); + } + } +} + +/** + * Callback used by the following read* functions to handle errors. + * Must be bound to the FileReader's this, e.g. readFailureCallback.bind(this) + */ +function readFailureCallback (e) { + if (this._readyState === FileReader.DONE) { + return; + } + + this._readyState = FileReader.DONE; + this._result = null; + this._error = new FileError(e); + + if (typeof this.onerror === 'function') { + this.onerror(new ProgressEvent('error', {target: this})); + } + + if (typeof this.onloadend === 'function') { + this.onloadend(new ProgressEvent('loadend', {target: this})); + } +} + +/** + * Abort reading file. + */ +FileReader.prototype.abort = function () { + if (origFileReader && !this._localURL) { + return this._realReader.abort(); + } + this._result = null; + + if (this._readyState === FileReader.DONE || this._readyState === FileReader.EMPTY) { + return; + } + + this._readyState = FileReader.DONE; + + // If abort callback + if (typeof this.onabort === 'function') { + this.onabort(new ProgressEvent('abort', {target: this})); + } + // If load end callback + if (typeof this.onloadend === 'function') { + this.onloadend(new ProgressEvent('loadend', {target: this})); + } +}; + +/** + * Read text file. + * + * @param file {File} File object containing file properties + * @param encoding [Optional] (see http://www.iana.org/assignments/character-sets) + */ +FileReader.prototype.readAsText = function (file, encoding) { + if (initRead(this, file)) { + return this._realReader.readAsText(file, encoding); + } + + // Default encoding is UTF-8 + var enc = encoding || 'UTF-8'; + + var totalSize = file.end - file.start; + readSuccessCallback.bind(this)('readAsText', enc, file.start, totalSize, function (r) { + if (this._progress === 0) { + this._result = ''; + } + this._result += r; + }.bind(this)); +}; + +/** + * Read file and return data as a base64 encoded data url. + * A data url is of the form: + * data:[<mediatype>][;base64],<data> + * + * @param file {File} File object containing file properties + */ +FileReader.prototype.readAsDataURL = function (file) { + if (initRead(this, file)) { + return this._realReader.readAsDataURL(file); + } + + var totalSize = file.end - file.start; + readSuccessCallback.bind(this)('readAsDataURL', null, file.start, totalSize, function (r) { + var commaIndex = r.indexOf(','); + if (this._progress === 0) { + this._result = r; + } else { + this._result += r.substring(commaIndex + 1); + } + }.bind(this)); +}; + +/** + * Read file and return data as a binary data. + * + * @param file {File} File object containing file properties + */ +FileReader.prototype.readAsBinaryString = function (file) { + if (initRead(this, file)) { + return this._realReader.readAsBinaryString(file); + } + + var totalSize = file.end - file.start; + readSuccessCallback.bind(this)('readAsBinaryString', null, file.start, totalSize, function (r) { + if (this._progress === 0) { + this._result = ''; + } + this._result += r; + }.bind(this)); +}; + +/** + * Read file and return data as a binary data. + * + * @param file {File} File object containing file properties + */ +FileReader.prototype.readAsArrayBuffer = function (file) { + if (initRead(this, file)) { + return this._realReader.readAsArrayBuffer(file); + } + + var totalSize = file.end - file.start; + readSuccessCallback.bind(this)('readAsArrayBuffer', null, file.start, totalSize, function (r) { + var resultArray = (this._progress === 0 ? new Uint8Array(totalSize) : new Uint8Array(this._result)); + resultArray.set(new Uint8Array(r), this._progress); + this._result = resultArray.buffer; + }.bind(this)); +}; + +module.exports = FileReader; |
