1cordova.define("cordova-plugin-file.FileReader", function(require, exports, module) { /* 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20*/ 21 22const exec = require('cordova/exec'); 23const modulemapper = require('cordova/modulemapper'); 24const utils = require('cordova/utils'); 25const FileError = require('./FileError'); 26const ProgressEvent = require('./ProgressEvent'); 27const origFileReader = modulemapper.getOriginalSymbol(window, 'FileReader'); 28 29/** 30 * This class reads the mobile device file system. 31 * 32 * For Android: 33 * The root directory is the root of the file system. 34 * To read from the SD card, the file name is "sdcard/my_file.txt" 35 * @constructor 36 */ 37const FileReader = function () { 38 this._readyState = 0; 39 this._error = null; 40 this._result = null; 41 this._progress = null; 42 this._localURL = ''; 43 this._realReader = origFileReader ? new origFileReader() : {}; // eslint-disable-line new-cap 44}; 45 46/** 47 * Defines the maximum size to read at a time via the native API. The default value is a compromise between 48 * minimizing the overhead of many exec() calls while still reporting progress frequently enough for large files. 49 * (Note attempts to allocate more than a few MB of contiguous memory on the native side are likely to cause 50 * OOM exceptions, while the JS engine seems to have fewer problems managing large strings or ArrayBuffers.) 51 */ 52FileReader.READ_CHUNK_SIZE = 256 * 1024; 53 54// States 55FileReader.EMPTY = 0; 56FileReader.LOADING = 1; 57FileReader.DONE = 2; 58 59utils.defineGetter(FileReader.prototype, 'readyState', function () { 60 return this._localURL ? this._readyState : this._realReader.readyState; 61}); 62 63utils.defineGetter(FileReader.prototype, 'error', function () { 64 return this._localURL ? this._error : this._realReader.error; 65}); 66 67utils.defineGetter(FileReader.prototype, 'result', function () { 68 return this._localURL ? this._result : this._realReader.result; 69}); 70 71function defineEvent (eventName) { 72 utils.defineGetterSetter(FileReader.prototype, eventName, function () { 73 return this._realReader[eventName] || null; 74 }, function (value) { 75 this._realReader[eventName] = value; 76 }); 77} 78 79// When the read starts. 80defineEvent('onloadstart'); 81 82// While reading (and decoding) file or fileBlob data, and reporting partial file data (progress.loaded/progress.total) 83defineEvent('onprogress'); 84 85// When the read has successfully completed. 86defineEvent('onload'); 87 88// When the read has failed (see errors). 89defineEvent('onerror'); 90 91// When the request has completed (either in success or failure). 92defineEvent('onloadend'); 93 94// When the read has been aborted. For instance, by invoking the abort() method. 95defineEvent('onabort'); 96 97function initRead (reader, file) { 98 // Already loading something 99 if (reader.readyState === FileReader.LOADING) { 100 throw new FileError(FileError.INVALID_STATE_ERR); 101 } 102 103 reader._result = null; 104 reader._error = null; 105 reader._progress = 0; 106 reader._readyState = FileReader.LOADING; 107 108 if (typeof file.localURL === 'string') { 109 reader._localURL = file.localURL; 110 } else { 111 reader._localURL = ''; 112 return true; 113 } 114 115 if (reader.onloadstart) { 116 reader.onloadstart(new ProgressEvent('loadstart', { target: reader })); 117 } 118} 119 120/** 121 * Callback used by the following read* functions to handle incremental or final success. 122 * Must be bound to the FileReader's this along with all but the last parameter, 123 * e.g. readSuccessCallback.bind(this, "readAsText", "UTF-8", offset, totalSize, accumulate) 124 * @param readType The name of the read function to call. 125 * @param encoding Text encoding, or null if this is not a text type read. 126 * @param offset Starting offset of the read. 127 * @param totalSize Total number of bytes or chars to read. 128 * @param accumulate A function that takes the callback result and accumulates it in this._result. 129 * @param r Callback result returned by the last read exec() call, or null to begin reading. 130 */ 131function readSuccessCallback (readType, encoding, offset, totalSize, accumulate, r) { 132 if (this._readyState === FileReader.DONE) { 133 return; 134 } 135 136 let CHUNK_SIZE = FileReader.READ_CHUNK_SIZE;
137 if (readType === 'readAsDataURL') { 138 // Windows proxy does not support reading file slices as Data URLs 139 // so read the whole file at once. 140 CHUNK_SIZE = cordova.platformId === 'windows' 141 ? totalSize 142 : ( 143 // Calculate new chunk size for data URLs to be multiply of 3 144 // Otherwise concatenated base64 chunks won't be valid base64 data 145 FileReader.READ_CHUNK_SIZE - (FileReader.READ_CHUNK_SIZE % 3) + 3 146 ); 147 } 148 149 if (typeof r !== 'undefined') { 150 accumulate(r); 151 this._progress = Math.min(this._progress + CHUNK_SIZE, totalSize); 152 153 if (typeof this.onprogress === 'function') { 154 this.onprogress(new ProgressEvent('progress', { loaded: this._progress, total: totalSize })); 155 } 156 } 157 158 if (typeof r === 'undefined' || this._progress < totalSize) { 159 const execArgs = [ 160 this._localURL, 161 offset + this._progress, 162 offset + this._progress + Math.min(totalSize - this._progress, CHUNK_SIZE)]; 163 if (encoding) { 164 execArgs.splice(1, 0, encoding); 165 } 166 exec( 167 readSuccessCallback.bind(this, readType, encoding, offset, totalSize, accumulate), 168 readFailureCallback.bind(this), 169 'File', readType, execArgs); 170 } else { 171 this._readyState = FileReader.DONE; 172 173 if (typeof this.onload === 'function') { 174 this.onload(new ProgressEvent('load', { target: this })); 175 } 176 177 if (typeof this.onloadend === 'function') { 178 this.onloadend(new ProgressEvent('loadend', { target: this })); 179 } 180 } 181} 182 183/** 184 * Callback used by the following read* functions to handle errors. 185 * Must be bound to the FileReader's this, e.g. readFailureCallback.bind(this) 186 */ 187function readFailureCallback (e) { 188 if (this._readyState === FileReader.DONE) { 189 return; 190 } 191 192 this._readyState = FileReader.DONE; 193 this._result = null; 194 this._error = new FileError(e); 195 196 if (typeof this.onerror === 'function') { 197 this.onerror(new ProgressEvent('error', { target: this })); 198 } 199 200 if (typeof this.onloadend === 'function') { 201 this.onloadend(new ProgressEvent('loadend', { target: this })); 202 } 203} 204 205/** 206 * Abort reading file. 207 */ 208FileReader.prototype.abort = function () { 209 if (origFileReader && !this._localURL) { 210 return this._realReader.abort(); 211 } 212 this._result = null; 213 214 if (this._readyState === FileReader.DONE || this._readyState === FileReader.EMPTY) { 215 return; 216 } 217 218 this._readyState = FileReader.DONE; 219 220 // If abort callback 221 if (typeof this.onabort === 'function') { 222 this.onabort(new ProgressEvent('abort', { target: this })); 223 } 224 // If load end callback 225 if (typeof this.onloadend === 'function') { 226 this.onloadend(new ProgressEvent('loadend', { target: this })); 227 } 228}; 229 230/** 231 * Read text file. 232 * 233 * @param file {File} File object containing file properties 234 * @param encoding [Optional] (see http://www.iana.org/assignments/character-sets) 235 */ 236FileReader.prototype.readAsText = function (file, encoding) { 237 if (initRead(this, file)) { 238 return this._realReader.readAsText(file, encoding); 239 } 240 241 // Default encoding is UTF-8 242 const enc = encoding || 'UTF-8'; 243 244 const totalSize = file.end - file.start; 245 readSuccessCallback.bind(this)('readAsText', enc, file.start, totalSize, function (r) { 246 if (this._progress === 0) { 247 this._result = ''; 248 } 249 this._result += r; 250 }.bind(this)); 251}; 252 253/** 254 * Read file and return data as a base64 encoded data url. 255 * A data url is of the form: 256 * data:[<mediatype>][;base64],<data> 257 * 258 * @param file {File} File object containing file properties 259 */ 260FileReader.prototype.readAsDataURL = function (file) { 261 if (initRead(this, file)) { 262 return this._realReader.readAsDataURL(file); 263 } 264 265 const totalSize = file.end - file.start; 266 readSuccessCallback.bind(this)('readAsDataURL', null, file.start, totalSize, function (r) { 267 const commaIndex = r.indexOf(','); 268 if (this._progress === 0) { 269 this._result = r; 270 } else { 271 this._result += r.substring(commaIndex + 1); 272 } 273 }.bind(this)); 274}; 275 276/** 277 * Read file and return data as a binary data. 278 * 279 * @param file {File}
279 File object containing file properties 280 */ 281FileReader.prototype.readAsBinaryString = function (file) { 282 if (initRead(this, file)) { 283 return this._realReader.readAsBinaryString(file); 284 } 285 286 const totalSize = file.end - file.start; 287 readSuccessCallback.bind(this)('readAsBinaryString', null, file.start, totalSize, function (r) { 288 if (this._progress === 0) { 289 this._result = ''; 290 } 291 this._result += r; 292 }.bind(this)); 293}; 294 295/** 296 * Read file and return data as a binary data. 297 * 298 * @param file {File} File object containing file properties 299 */ 300FileReader.prototype.readAsArrayBuffer = function (file) { 301 if (initRead(this, file)) { 302 return this._realReader.readAsArrayBuffer(file); 303 } 304 305 const totalSize = file.end - file.start; 306 readSuccessCallback.bind(this)('readAsArrayBuffer', null, file.start, totalSize, function (r) { 307 const resultArray = (this._progress === 0 ? new Uint8Array(totalSize) : new Uint8Array(this._result)); 308 resultArray.set(new Uint8Array(r), this._progress); 309 this._result = resultArray.buffer; 310 }.bind(this)); 311}; 312 313module.exports = FileReader; 314 315});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.