| OLD | NEW | 
|---|
| 1 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file | 
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a | 
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. | 
| 4 | 4 | 
| 5 class _FileInputStream extends _BaseDataInputStream implements InputStream { | 5 class _FileInputStream extends _BaseDataInputStream implements InputStream { | 
| 6   _FileInputStream(String name) { | 6   _FileInputStream(String name) { | 
| 7     _file = new File(name); | 7     _file = new File(name); | 
| 8     _data = []; | 8     _data = []; | 
| 9     _position = 0; | 9     _position = 0; | 
| 10     _file.errorHandler = (String s) { | 10     _file.onError = (String s) { | 
| 11       if (_clientErrorHandler != null) { | 11       if (_clientErrorHandler != null) { | 
| 12         _clientErrorHandler(); | 12         _clientErrorHandler(); | 
| 13       } | 13       } | 
| 14     }; | 14     }; | 
| 15     _file.open(); | 15     _file.open(FileMode.READ, (openedFile) { | 
| 16     _file.openHandler = (openedFile) { |  | 
| 17       _readDataFromFile(openedFile); | 16       _readDataFromFile(openedFile); | 
| 18     }; | 17     }); | 
| 19   } | 18   } | 
| 20 | 19 | 
| 21   _FileInputStream.fromStdio(int fd) { | 20   _FileInputStream.fromStdio(int fd) { | 
| 22     assert(fd == 0); | 21     assert(fd == 0); | 
| 23     _file = _File._openStdioSync(fd); | 22     _file = _File._openStdioSync(fd); | 
| 24     _data = []; | 23     _data = []; | 
| 25     _position = 0; | 24     _position = 0; | 
| 26     _readDataFromFile(_file); | 25     _readDataFromFile(_file); | 
| 27   } | 26   } | 
| 28 | 27 | 
| 29   void _readDataFromFile(RandomAccessFile openedFile) { | 28   void _readDataFromFile(RandomAccessFile openedFile) { | 
| 30     openedFile.errorHandler = (String s) { | 29     openedFile.onError = (String s) { | 
| 31       if (_clientErrorHandler != null) { | 30       if (_clientErrorHandler != null) { | 
| 32         _clientErrorHandler(); | 31         _clientErrorHandler(); | 
| 33       } | 32       } | 
| 34     }; | 33     }; | 
| 35     openedFile.length(); | 34     openedFile.length((length) { | 
| 36     openedFile.lengthHandler = (length) { |  | 
| 37       var contents = new ByteArray(length); | 35       var contents = new ByteArray(length); | 
| 38       if (length != 0) { | 36       if (length != 0) { | 
| 39         openedFile.readList(contents, 0, length); | 37         openedFile.readList(contents, 0, length, (read) { | 
| 40         openedFile.readListHandler = (read) { |  | 
| 41           if (read != length) { | 38           if (read != length) { | 
| 42             if (_clientErrorHandler != null) { | 39             if (_clientErrorHandler != null) { | 
| 43               _clientErrorHandler(); | 40               _clientErrorHandler(); | 
| 44             } | 41             } | 
| 45             _streamMarkedClosed = true; | 42             _streamMarkedClosed = true; | 
| 46             _checkScheduleCallbacks(); | 43             _checkScheduleCallbacks(); | 
| 47           } else { | 44           } else { | 
| 48             _data = contents; | 45             _data = contents; | 
| 49             _streamMarkedClosed = true; | 46             _streamMarkedClosed = true; | 
| 50             _checkScheduleCallbacks(); | 47             _checkScheduleCallbacks(); | 
| 51           } | 48           } | 
| 52           openedFile.close(); | 49           openedFile.close(() => null); | 
| 53         }; | 50         }); | 
| 54       } else { | 51       } else { | 
| 55         _streamMarkedClosed = true; | 52         _streamMarkedClosed = true; | 
| 56         _checkScheduleCallbacks(); | 53         _checkScheduleCallbacks(); | 
| 57         openedFile.close(); | 54         openedFile.close(() => null); | 
| 58       } | 55       } | 
| 59     }; | 56     }); | 
| 60   } | 57   } | 
| 61 | 58 | 
| 62   int available() { | 59   int available() { | 
| 63     return _closed ? 0 : _data.length - _position; | 60     return _closed ? 0 : _data.length - _position; | 
| 64   } | 61   } | 
| 65 | 62 | 
| 66   void pipe(OutputStream output, [bool close = true]) { | 63   void pipe(OutputStream output, [bool close = true]) { | 
| 67     _pipe(this, output, close: close); | 64     _pipe(this, output, close: close); | 
| 68   } | 65   } | 
| 69 | 66 | 
| (...skipping 21 matching lines...) Expand all  Loading... | 
| 91   List<int> _data; | 88   List<int> _data; | 
| 92   int _position; | 89   int _position; | 
| 93   bool _closed = false; | 90   bool _closed = false; | 
| 94 } | 91 } | 
| 95 | 92 | 
| 96 | 93 | 
| 97 class _FileOutputStream implements OutputStream { | 94 class _FileOutputStream implements OutputStream { | 
| 98   _FileOutputStream(String name, FileMode mode) { | 95   _FileOutputStream(String name, FileMode mode) { | 
| 99     _pendingOperations = new List<List<int>>(); | 96     _pendingOperations = new List<List<int>>(); | 
| 100     var f = new File(name); | 97     var f = new File(name); | 
| 101     f.open(mode); | 98     f.open(mode, (openedFile) { | 
| 102     f.openHandler = (openedFile) { |  | 
| 103       _file = openedFile; | 99       _file = openedFile; | 
| 104       _setupFileHandlers(); | 100       _setupFileHandlers(); | 
| 105       _processPendingOperations(); | 101       _processPendingOperations(); | 
| 106     }; | 102     }); | 
| 107     f.errorHandler = (e) { | 103     f.onError = (e) { | 
| 108       if (_errorHandler != null) _errorHandler(); | 104       if (_onError != null) _onError(); | 
| 109     }; | 105     }; | 
| 110   } | 106   } | 
| 111 | 107 | 
| 112   _FileOutputStream.fromStdio(int fd) { | 108   _FileOutputStream.fromStdio(int fd) { | 
| 113     assert(1 <= fd && fd <= 2); | 109     assert(1 <= fd && fd <= 2); | 
| 114     _file = _File._openStdioSync(fd); | 110     _file = _File._openStdioSync(fd); | 
| 115     _setupFileHandlers(); | 111     _setupFileHandlers(); | 
| 116   } | 112   } | 
| 117 | 113 | 
| 118 | 114 | 
| 119   void _setupFileHandlers() { | 115   void _setupFileHandlers() { | 
| 120     _file.errorHandler = (e) { | 116     _file.onError = (e) { | 
| 121       if (_errorHandler != null) _errorHandler(); | 117       if (_onError != null) _onError(); | 
| 122     }; | 118     }; | 
| 123     _file.noPendingWriteHandler = () { | 119     _file.onNoPendingWrites = () { | 
| 124       if (!_streamMarkedClosed && _noPendingWriteHandler != null) { | 120       if (!_streamMarkedClosed && _onNoPendingWrites != null) { | 
| 125         _noPendingWriteHandler(); | 121         _onNoPendingWrites(); | 
| 126       } | 122       } | 
| 127     }; | 123     }; | 
| 128     _file.closeHandler = () { |  | 
| 129       if (_closeHandler != null) _closeHandler(); |  | 
| 130     }; |  | 
| 131   } | 124   } | 
| 132 | 125 | 
| 133   bool write(List<int> buffer, [bool copyBuffer = false]) { | 126   bool write(List<int> buffer, [bool copyBuffer = false]) { | 
| 134     var data = buffer; | 127     var data = buffer; | 
| 135     if (copyBuffer) { | 128     if (copyBuffer) { | 
| 136       var length = buffer.length; | 129       var length = buffer.length; | 
| 137       data = new ByteArray(length); | 130       data = new ByteArray(length); | 
| 138       data.setRange(0, length, buffer, 0); | 131       data.setRange(0, length, buffer, 0); | 
| 139     } | 132     } | 
| 140     if (_file == null) { | 133     if (_file == null) { | 
| (...skipping 13 matching lines...) Expand all  Loading... | 
| 154     } | 147     } | 
| 155     var copy = new ByteArray(length); | 148     var copy = new ByteArray(length); | 
| 156     copy.setRange(0, length, buffer, offset); | 149     copy.setRange(0, length, buffer, offset); | 
| 157     return write(copy); | 150     return write(copy); | 
| 158   } | 151   } | 
| 159 | 152 | 
| 160   void close() { | 153   void close() { | 
| 161     if (_file == null) { | 154     if (_file == null) { | 
| 162       _pendingOperations.add(null); | 155       _pendingOperations.add(null); | 
| 163     } else if (!_streamMarkedClosed) { | 156     } else if (!_streamMarkedClosed) { | 
| 164       _file.close(); | 157       _file.close(() { | 
|  | 158         if (_onClosed != null) _onClosed(); | 
|  | 159       }); | 
| 165       _streamMarkedClosed = true; | 160       _streamMarkedClosed = true; | 
| 166     } | 161     } | 
| 167   } | 162   } | 
| 168 | 163 | 
| 169   void set noPendingWriteHandler(void callback()) { | 164   void set onNoPendingWrites(void callback()) { | 
| 170     _noPendingWriteHandler = callback; | 165     _onNoPendingWrites = callback; | 
| 171   } | 166   } | 
| 172 | 167 | 
| 173   void set closeHandler(void callback()) { | 168   void set onClosed(void callback()) { | 
| 174     _closeHandler = callback; | 169     _onClosed = callback; | 
| 175   } | 170   } | 
| 176 | 171 | 
| 177   void set errorHandler(void callback()) { | 172   void set onError(void callback()) { | 
| 178     _errorHandler = callback; | 173     _onError = callback; | 
| 179   } | 174   } | 
| 180 | 175 | 
| 181   void _processPendingOperations() { | 176   void _processPendingOperations() { | 
| 182     _pendingOperations.forEach((buffer) { | 177     _pendingOperations.forEach((buffer) { | 
| 183       (buffer != null) ? write(buffer) : close(); | 178       (buffer != null) ? write(buffer) : close(); | 
| 184     }); | 179     }); | 
| 185     _pendingOperations = null; | 180     _pendingOperations = null; | 
| 186   } | 181   } | 
| 187 | 182 | 
| 188   void _write(List<int> buffer, int offset, int len) { | 183   void _write(List<int> buffer, int offset, int len) { | 
| 189     _file.writeList(buffer, offset, len); | 184     _file.writeList(buffer, offset, len); | 
| 190   } | 185   } | 
| 191 | 186 | 
| 192   RandomAccessFile _file; | 187   RandomAccessFile _file; | 
| 193 | 188 | 
| 194   // When this is set to true the stream is marked closed. When a | 189   // When this is set to true the stream is marked closed. When a | 
| 195   // stream is marked closed no more data can be written. | 190   // stream is marked closed no more data can be written. | 
| 196   bool _streamMarkedClosed = false; | 191   bool _streamMarkedClosed = false; | 
| 197 | 192 | 
| 198   // When this is set to true the close callback has been called and | 193   // When this is set to true the close callback has been called and | 
| 199   // the stream is fully closed. | 194   // the stream is fully closed. | 
| 200   bool _closeCallbackCalled = false; | 195   bool _closeCallbackCalled = false; | 
| 201 | 196 | 
| 202   // List of pending writes that were issued before the underlying | 197   // List of pending writes that were issued before the underlying | 
| 203   // file was successfully opened. | 198   // file was successfully opened. | 
| 204   List<List<int>> _pendingOperations; | 199   List<List<int>> _pendingOperations; | 
| 205 | 200 | 
| 206   Function _noPendingWriteHandler; | 201   Function _onNoPendingWrites; | 
| 207   Function _closeHandler; | 202   Function _onClosed; | 
| 208   Function _errorHandler; | 203   Function _onError; | 
| 209 } | 204 } | 
| 210 | 205 | 
| 211 | 206 | 
| 212 // Helper class containing static file helper methods. | 207 // Helper class containing static file helper methods. | 
| 213 class _FileUtils { | 208 class _FileUtils { | 
| 214   static final kExistsRequest = 0; | 209   static final kExistsRequest = 0; | 
| 215   static final kCreateRequest = 1; | 210   static final kCreateRequest = 1; | 
| 216   static final kDeleteRequest = 2; | 211   static final kDeleteRequest = 2; | 
| 217   static final kOpenRequest = 3; | 212   static final kOpenRequest = 3; | 
| 218   static final kFullPathRequest = 4; | 213   static final kFullPathRequest = 4; | 
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 316     return writeString(id, string); | 311     return writeString(id, string); | 
| 317   } | 312   } | 
| 318 } | 313 } | 
| 319 | 314 | 
| 320 | 315 | 
| 321 // Class for encapsulating the native implementation of files. | 316 // Class for encapsulating the native implementation of files. | 
| 322 class _File implements File { | 317 class _File implements File { | 
| 323   // Constructor for file. | 318   // Constructor for file. | 
| 324   _File(String this._name) : _asyncUsed = false; | 319   _File(String this._name) : _asyncUsed = false; | 
| 325 | 320 | 
| 326   void exists() { | 321   void exists(void callback(bool exists)) { | 
| 327     _ensureFileService(); | 322     _ensureFileService(); | 
| 328     _asyncUsed = true; | 323     _asyncUsed = true; | 
| 329     if (_name is !String) { | 324     if (_name is !String) { | 
| 330       if (_errorHandler != null) { | 325       if (_onError != null) { | 
| 331         _errorHandler('File name is not a string: $_name'); | 326         _onError('File name is not a string: $_name'); | 
| 332       } | 327       } | 
| 333       return; | 328       return; | 
| 334     } | 329     } | 
| 335     List request = new List(2); | 330     List request = new List(2); | 
| 336     request[0] = _FileUtils.kExistsRequest; | 331     request[0] = _FileUtils.kExistsRequest; | 
| 337     request[1] = _name; | 332     request[1] = _name; | 
| 338     _fileService.call(request).receive((exists, replyTo) { | 333     _fileService.call(request).receive((exists, replyTo) { | 
| 339       if (_existsHandler != null) _existsHandler(exists); | 334       callback(exists); | 
| 340     }); | 335     }); | 
| 341   } | 336   } | 
| 342 | 337 | 
| 343   bool existsSync() { | 338   bool existsSync() { | 
| 344     if (_asyncUsed) { | 339     if (_asyncUsed) { | 
| 345       throw new FileIOException( | 340       throw new FileIOException( | 
| 346           "Mixed use of synchronous and asynchronous API"); | 341           "Mixed use of synchronous and asynchronous API"); | 
| 347     } | 342     } | 
| 348     if (_name is !String) { | 343     if (_name is !String) { | 
| 349       throw new FileIOException('File name is not a string: $_name'); | 344       throw new FileIOException('File name is not a string: $_name'); | 
| 350     } | 345     } | 
| 351     return _FileUtils.exists(_name); | 346     return _FileUtils.exists(_name); | 
| 352   } | 347   } | 
| 353 | 348 | 
| 354   void create() { | 349   void create(void callback()) { | 
| 355     _ensureFileService(); | 350     _ensureFileService(); | 
| 356     _asyncUsed = true; | 351     _asyncUsed = true; | 
| 357     List request = new List(2); | 352     List request = new List(2); | 
| 358     request[0] = _FileUtils.kCreateRequest; | 353     request[0] = _FileUtils.kCreateRequest; | 
| 359     request[1] = _name; | 354     request[1] = _name; | 
| 360     _fileService.call(request).receive((created, replyTo) { | 355     _fileService.call(request).receive((created, replyTo) { | 
| 361       if (created) { | 356       if (created) { | 
| 362         if (_createHandler != null) _createHandler(); | 357         callback(); | 
| 363       } else if (_errorHandler != null) { | 358       } else if (_onError != null) { | 
| 364         _errorHandler("Cannot create file: $_name"); | 359         _onError("Cannot create file: $_name"); | 
| 365       } | 360       } | 
| 366     }); | 361     }); | 
| 367   } | 362   } | 
| 368 | 363 | 
| 369   void createSync() { | 364   void createSync() { | 
| 370     if (_asyncUsed) { | 365     if (_asyncUsed) { | 
| 371       throw new FileIOException( | 366       throw new FileIOException( | 
| 372           "Mixed use of synchronous and asynchronous API"); | 367           "Mixed use of synchronous and asynchronous API"); | 
| 373     } | 368     } | 
| 374     bool created = _FileUtils.checkedCreate(_name); | 369     bool created = _FileUtils.checkedCreate(_name); | 
| 375     if (!created) { | 370     if (!created) { | 
| 376       throw new FileIOException("Cannot create file: $_name"); | 371       throw new FileIOException("Cannot create file: $_name"); | 
| 377     } | 372     } | 
| 378   } | 373   } | 
| 379 | 374 | 
| 380   void delete() { | 375   void delete(void callback()) { | 
| 381     _ensureFileService(); | 376     _ensureFileService(); | 
| 382     _asyncUsed = true; | 377     _asyncUsed = true; | 
| 383     List request = new List(2); | 378     List request = new List(2); | 
| 384     request[0] = _FileUtils.kDeleteRequest; | 379     request[0] = _FileUtils.kDeleteRequest; | 
| 385     request[1] = _name; | 380     request[1] = _name; | 
| 386     _fileService.call(request).receive((deleted, replyTo) { | 381     _fileService.call(request).receive((deleted, replyTo) { | 
| 387       if (deleted) { | 382       if (deleted) { | 
| 388         if (_deleteHandler != null) _deleteHandler(); | 383         callback(); | 
| 389       } else if (_errorHandler != null) { | 384       } else if (_onError != null) { | 
| 390         _errorHandler("Cannot delete file: $_name"); | 385         _onError("Cannot delete file: $_name"); | 
| 391       } | 386       } | 
| 392     }); | 387     }); | 
| 393   } | 388   } | 
| 394 | 389 | 
| 395   void deleteSync() { | 390   void deleteSync() { | 
| 396     if (_asyncUsed) { | 391     if (_asyncUsed) { | 
| 397       throw new FileIOException( | 392       throw new FileIOException( | 
| 398           "Mixed use of synchronous and asynchronous API"); | 393           "Mixed use of synchronous and asynchronous API"); | 
| 399     } | 394     } | 
| 400     bool deleted = _FileUtils.checkedDelete(_name); | 395     bool deleted = _FileUtils.checkedDelete(_name); | 
| 401     if (!deleted) { | 396     if (!deleted) { | 
| 402       throw new FileIOException("Cannot delete file: $_name"); | 397       throw new FileIOException("Cannot delete file: $_name"); | 
| 403     } | 398     } | 
| 404   } | 399   } | 
| 405 | 400 | 
| 406   void directory() { | 401   void directory(void callback(Directory dir)) { | 
| 407     _ensureFileService(); | 402     _ensureFileService(); | 
| 408     _asyncUsed = true; | 403     _asyncUsed = true; | 
| 409     List request = new List(2); | 404     List request = new List(2); | 
| 410     request[0] = _FileUtils.kDirectoryRequest; | 405     request[0] = _FileUtils.kDirectoryRequest; | 
| 411     request[1] = _name; | 406     request[1] = _name; | 
| 412     _fileService.call(request).receive((path, replyTo) { | 407     _fileService.call(request).receive((path, replyTo) { | 
| 413       if (path != null) { | 408       if (path != null) { | 
| 414         if (_directoryHandler != null) _directoryHandler(new Directory(path)); | 409         callback(new Directory(path)); | 
| 415       } else if (_errorHandler != null) { | 410       } else if (_onError != null) { | 
| 416         _errorHandler("Cannot get directory for: ${_name}"); | 411         _onError("Cannot get directory for: ${_name}"); | 
| 417       } | 412       } | 
| 418     }); | 413     }); | 
| 419   } | 414   } | 
| 420 | 415 | 
| 421   Directory directorySync() { | 416   Directory directorySync() { | 
| 422     if (_asyncUsed) { | 417     if (_asyncUsed) { | 
| 423       throw new FileIOException( | 418       throw new FileIOException( | 
| 424           "Mixed use of synchronous and asynchronous API"); | 419           "Mixed use of synchronous and asynchronous API"); | 
| 425     } | 420     } | 
| 426     if (!existsSync()) { | 421     if (!existsSync()) { | 
| 427       throw new FileIOException("Cannot get directory for: $_name"); | 422       throw new FileIOException("Cannot get directory for: $_name"); | 
| 428     } | 423     } | 
| 429     return new Directory(_FileUtils.directory(_name)); | 424     return new Directory(_FileUtils.directory(_name)); | 
| 430   } | 425   } | 
| 431 | 426 | 
| 432   void open([FileMode mode = FileMode.READ]) { | 427   void open(FileMode mode, void callback(RandomAccessFile file)) { | 
| 433     _ensureFileService(); | 428     _ensureFileService(); | 
| 434     _asyncUsed = true; | 429     _asyncUsed = true; | 
| 435     if (mode != FileMode.READ && | 430     if (mode != FileMode.READ && | 
| 436         mode != FileMode.WRITE && | 431         mode != FileMode.WRITE && | 
| 437         mode != FileMode.APPEND) { | 432         mode != FileMode.APPEND) { | 
| 438       if (_errorHandler != null) { | 433       if (_onError != null) { | 
| 439         _errorHandler("Unknown file mode. Use FileMode.READ, FileMode.WRITE " + | 434         _onError("Unknown file mode. Use FileMode.READ, FileMode.WRITE " + | 
| 440                       "or FileMode.APPEND."); | 435                  "or FileMode.APPEND."); | 
| 441         return; | 436         return; | 
| 442       } | 437       } | 
| 443     } | 438     } | 
| 444     List request = new List(3); | 439     List request = new List(3); | 
| 445     request[0] = _FileUtils.kOpenRequest; | 440     request[0] = _FileUtils.kOpenRequest; | 
| 446     request[1] = _name; | 441     request[1] = _name; | 
| 447     request[2] = mode._mode;  // Direct int value for serialization. | 442     request[2] = mode._mode;  // Direct int value for serialization. | 
| 448     _fileService.call(request).receive((id, replyTo) { | 443     _fileService.call(request).receive((id, replyTo) { | 
| 449       var handler = _openHandler; |  | 
| 450       if (handler === null) { |  | 
| 451         // If no open handler is present, close the file immediately to |  | 
| 452         // avoid leaking an open file descriptor. |  | 
| 453         handler = (file) => file.close(); |  | 
| 454       } |  | 
| 455       if (id != 0) { | 444       if (id != 0) { | 
| 456         var randomAccessFile = new _RandomAccessFile(id, _name); | 445         callback(new _RandomAccessFile(id, _name)); | 
| 457         handler(randomAccessFile); | 446       } else if (_onError != null) { | 
| 458       } else if (_errorHandler != null) { | 447         _onError("Cannot open file: $_name"); | 
| 459         _errorHandler("Cannot open file: $_name"); |  | 
| 460       } | 448       } | 
| 461     }); | 449     }); | 
| 462   } | 450   } | 
| 463 | 451 | 
| 464   RandomAccessFile openSync([FileMode mode = FileMode.READ]) { | 452   RandomAccessFile openSync([FileMode mode = FileMode.READ]) { | 
| 465     if (_asyncUsed) { | 453     if (_asyncUsed) { | 
| 466       throw new FileIOException( | 454       throw new FileIOException( | 
| 467           "Mixed use of synchronous and asynchronous API"); | 455           "Mixed use of synchronous and asynchronous API"); | 
| 468     } | 456     } | 
| 469     if (mode != FileMode.READ && | 457     if (mode != FileMode.READ && | 
| (...skipping 10 matching lines...) Expand all  Loading... | 
| 480   } | 468   } | 
| 481 | 469 | 
| 482   static RandomAccessFile _openStdioSync(int fd) { | 470   static RandomAccessFile _openStdioSync(int fd) { | 
| 483     var id = _FileUtils.openStdio(fd); | 471     var id = _FileUtils.openStdio(fd); | 
| 484     if (id == 0) { | 472     if (id == 0) { | 
| 485       throw new FileIOException("Cannot open stdio file for: $fd"); | 473       throw new FileIOException("Cannot open stdio file for: $fd"); | 
| 486     } | 474     } | 
| 487     return new _RandomAccessFile(id, ""); | 475     return new _RandomAccessFile(id, ""); | 
| 488   } | 476   } | 
| 489 | 477 | 
| 490   void fullPath() { | 478   void fullPath(void callback(String result)) { | 
| 491     _ensureFileService(); | 479     _ensureFileService(); | 
| 492     _asyncUsed = true; | 480     _asyncUsed = true; | 
| 493     List request = new List(2); | 481     List request = new List(2); | 
| 494     request[0] = _FileUtils.kFullPathRequest; | 482     request[0] = _FileUtils.kFullPathRequest; | 
| 495     request[1] = _name; | 483     request[1] = _name; | 
| 496     _fileService.call(request).receive((result, replyTo) { | 484     _fileService.call(request).receive((result, replyTo) { | 
| 497       if (result != null) { | 485       if (result != null) { | 
| 498         if (_fullPathHandler != null) _fullPathHandler(result); | 486         callback(result); | 
| 499       } else if (_errorHandler != null) { | 487       } else if (_onError != null) { | 
| 500         _errorHandler("fullPath failed"); | 488         _onError("fullPath failed"); | 
| 501       } | 489       } | 
| 502     }); | 490     }); | 
| 503   } | 491   } | 
| 504 | 492 | 
| 505   String fullPathSync() { | 493   String fullPathSync() { | 
| 506     if (_asyncUsed) { | 494     if (_asyncUsed) { | 
| 507       throw new FileIOException( | 495       throw new FileIOException( | 
| 508           "Mixed use of synchronous and asynchronous API"); | 496           "Mixed use of synchronous and asynchronous API"); | 
| 509     } | 497     } | 
| 510     String result = _FileUtils.checkedFullPath(_name); | 498     String result = _FileUtils.checkedFullPath(_name); | 
| 511     if (result == null) { | 499     if (result == null) { | 
| 512       throw new FileIOException("fullPath failed"); | 500       throw new FileIOException("fullPath failed"); | 
| 513     } | 501     } | 
| 514     return result; | 502     return result; | 
| 515   } | 503   } | 
| 516 | 504 | 
| 517   InputStream openInputStream() { | 505   InputStream openInputStream() { | 
| 518     return new _FileInputStream(_name); | 506     return new _FileInputStream(_name); | 
| 519   } | 507   } | 
| 520 | 508 | 
| 521   OutputStream openOutputStream([FileMode mode = FileMode.WRITE]) { | 509   OutputStream openOutputStream([FileMode mode = FileMode.WRITE]) { | 
| 522     if (mode != FileMode.WRITE && | 510     if (mode != FileMode.WRITE && | 
| 523         mode != FileMode.APPEND) { | 511         mode != FileMode.APPEND) { | 
| 524       throw new FileIOException( | 512       throw new FileIOException( | 
| 525           "Wrong FileMode. Use FileMode.WRITE or FileMode.APPEND"); | 513           "Wrong FileMode. Use FileMode.WRITE or FileMode.APPEND"); | 
| 526     } | 514     } | 
| 527     return new _FileOutputStream(_name, mode); | 515     return new _FileOutputStream(_name, mode); | 
| 528   } | 516   } | 
| 529 | 517 | 
| 530   void readAsBytes() { | 518   void readAsBytes(void callback(List<int> bytes)) { | 
| 531     _asyncUsed = true; | 519     _asyncUsed = true; | 
| 532     var chunks = new _BufferList(); | 520     var chunks = new _BufferList(); | 
| 533     var stream = openInputStream(); | 521     var stream = openInputStream(); | 
| 534     stream.closeHandler = () { | 522     stream.onClosed = () { | 
| 535       if (_readAsBytesHandler != null) { | 523       callback(chunks.readBytes(chunks.length)); | 
| 536         _readAsBytesHandler(chunks.readBytes(chunks.length)); |  | 
| 537       } |  | 
| 538     }; | 524     }; | 
| 539     stream.dataHandler = () { | 525     stream.onData = () { | 
| 540       var chunk = stream.read(); | 526       var chunk = stream.read(); | 
| 541       chunks.add(chunk); | 527       chunks.add(chunk); | 
| 542     }; | 528     }; | 
| 543     stream.errorHandler = () { | 529     stream.onError = () { | 
| 544       if (_errorHandler != null) { | 530       if (_onError != null) { | 
| 545         _errorHandler("Failed to read file as bytes: $_name"); | 531         _onError("Failed to read file as bytes: $_name"); | 
| 546       } | 532       } | 
| 547     }; | 533     }; | 
| 548   } | 534   } | 
| 549 | 535 | 
| 550   List<int> readAsBytesSync() { | 536   List<int> readAsBytesSync() { | 
| 551     if (_asyncUsed) { | 537     if (_asyncUsed) { | 
| 552       throw new FileIOException( | 538       throw new FileIOException( | 
| 553           "Mixed use of synchronous and asynchronous API"); | 539           "Mixed use of synchronous and asynchronous API"); | 
| 554     } | 540     } | 
| 555     var opened = openSync(); | 541     var opened = openSync(); | 
| 556     var length = opened.lengthSync(); | 542     var length = opened.lengthSync(); | 
| 557     var result = new ByteArray(length); | 543     var result = new ByteArray(length); | 
| 558     var read = opened.readListSync(result, 0, length); | 544     var read = opened.readListSync(result, 0, length); | 
| 559     if (read != length) { | 545     if (read != length) { | 
| 560       throw new FileIOException("Failed reading file as bytes: $_name"); | 546       throw new FileIOException("Failed reading file as bytes: $_name"); | 
| 561     } | 547     } | 
| 562     opened.close(); | 548     opened.closeSync(); | 
| 563     return result; | 549     return result; | 
| 564   } | 550   } | 
| 565 | 551 | 
| 566   _StringDecoder _getDecoder(encoding) { | 552   _StringDecoder _getDecoder(encoding) { | 
| 567     if (encoding == "UTF-8") { | 553     if (encoding == "UTF-8") { | 
| 568       return new _UTF8Decoder(); | 554       return new _UTF8Decoder(); | 
| 569     } else if (encoding == "ISO-8859-1") { | 555     } else if (encoding == "ISO-8859-1") { | 
| 570       return new _Latin1Decoder(); | 556       return new _Latin1Decoder(); | 
| 571     } else if (encoding == "ASCII") { | 557     } else if (encoding == "ASCII") { | 
| 572       return new _AsciiDecoder(); | 558       return new _AsciiDecoder(); | 
| 573     } | 559     } | 
| 574     throw new FileIOException("Unsupported encoding $_encoding"); | 560     throw new FileIOException("Unsupported encoding $_encoding"); | 
| 575   } | 561   } | 
| 576 | 562 | 
| 577   void readAsText([String encoding = "UTF-8"]) { | 563   void readAsText(String encoding, void callback(String text)) { | 
| 578     _asyncUsed = true; | 564     _asyncUsed = true; | 
| 579     var decoder = _getDecoder(encoding); | 565     var decoder = _getDecoder(encoding); | 
| 580     readAsBytes(); | 566     readAsBytes((bytes) { | 
| 581     readAsBytesHandler = (bytes) { | 567       try { | 
| 582       if (_readAsTextHandler != null) { | 568         decoder.write(bytes); | 
| 583         try { | 569       } catch (var e) { | 
| 584           decoder.write(bytes); | 570         if (_onError != null) { | 
| 585         } catch (var e) { | 571           _onError(e.toString()); | 
| 586           if (_errorHandler != null) { | 572           return; | 
| 587             _errorHandler(e.toString()); |  | 
| 588             return; |  | 
| 589           } |  | 
| 590         } | 573         } | 
| 591         _readAsTextHandler(decoder.decoded); |  | 
| 592       } | 574       } | 
| 593     }; | 575       callback(decoder.decoded); | 
|  | 576     }); | 
| 594   } | 577   } | 
| 595 | 578 | 
| 596   String readAsTextSync([String encoding = "UTF-8"]) { | 579   String readAsTextSync([String encoding = 'UTF-8']) { | 
| 597     if (_asyncUsed) { | 580     if (_asyncUsed) { | 
| 598       throw new FileIOException( | 581       throw new FileIOException( | 
| 599           "Mixed use of synchronous and asynchronous API"); | 582           "Mixed use of synchronous and asynchronous API"); | 
| 600     } | 583     } | 
| 601     var decoder = _getDecoder(encoding); | 584     var decoder = _getDecoder(encoding); | 
| 602     List<int> bytes = readAsBytesSync(); | 585     List<int> bytes = readAsBytesSync(); | 
| 603     decoder.write(bytes); | 586     decoder.write(bytes); | 
| 604     return decoder.decoded; | 587     return decoder.decoded; | 
| 605   } | 588   } | 
| 606 | 589 | 
| 607   List<String> _getDecodedLines(_StringDecoder decoder) { | 590   List<String> _getDecodedLines(_StringDecoder decoder) { | 
| 608     List<String> result = []; | 591     List<String> result = []; | 
| 609     var line = decoder.decodedLine; | 592     var line = decoder.decodedLine; | 
| 610     while (line != null) { | 593     while (line != null) { | 
| 611       result.add(line); | 594       result.add(line); | 
| 612       line = decoder.decodedLine; | 595       line = decoder.decodedLine; | 
| 613     } | 596     } | 
| 614     // If there is more data with no terminating line break we treat | 597     // If there is more data with no terminating line break we treat | 
| 615     // it as the last line. | 598     // it as the last line. | 
| 616     var data = decoder.decoded; | 599     var data = decoder.decoded; | 
| 617     if (data != null) { | 600     if (data != null) { | 
| 618       result.add(data); | 601       result.add(data); | 
| 619     } | 602     } | 
| 620     return result; | 603     return result; | 
| 621   } | 604   } | 
| 622 | 605 | 
| 623   void readAsLines([String encoding = "UTF-8"]) { | 606   void readAsLines(String encoding, void callback(List<String> lines)) { | 
| 624     _asyncUsed = true; | 607     _asyncUsed = true; | 
| 625     var decoder = _getDecoder(encoding); | 608     var decoder = _getDecoder(encoding); | 
| 626     readAsBytes(); | 609     readAsBytes((bytes) { | 
| 627     readAsBytesHandler = (bytes) { | 610       try { | 
| 628       if (_readAsLinesHandler != null) { | 611         decoder.write(bytes); | 
| 629         try { | 612       } catch (var e) { | 
| 630           decoder.write(bytes); | 613         if (_onError != null) { | 
| 631         } catch (var e) { | 614           _onError(e.toString()); | 
| 632           if (_errorHandler != null) { | 615           return; | 
| 633             _errorHandler(e.toString()); |  | 
| 634             return; |  | 
| 635           } |  | 
| 636         } | 616         } | 
| 637         _readAsLinesHandler(_getDecodedLines(decoder)); |  | 
| 638       } | 617       } | 
| 639     }; | 618       callback(_getDecodedLines(decoder)); | 
|  | 619     }); | 
| 640   } | 620   } | 
| 641 | 621 | 
| 642   List<String> readAsLinesSync([String encoding = "UTF-8"]) { | 622   List<String> readAsLinesSync([String encoding = "UTF-8"]) { | 
| 643     if (_asyncUsed) { | 623     if (_asyncUsed) { | 
| 644       throw new FileIOException( | 624       throw new FileIOException( | 
| 645           "Mixed use of synchronous and asynchronous API"); | 625           "Mixed use of synchronous and asynchronous API"); | 
| 646     } | 626     } | 
| 647     var decoder = _getDecoder(encoding); | 627     var decoder = _getDecoder(encoding); | 
| 648     List<int> bytes = readAsBytesSync(); | 628     List<int> bytes = readAsBytesSync(); | 
| 649     decoder.write(bytes); | 629     decoder.write(bytes); | 
| 650     return _getDecodedLines(decoder); | 630     return _getDecodedLines(decoder); | 
| 651   } | 631   } | 
| 652 | 632 | 
| 653   String get name() => _name; | 633   String get name() => _name; | 
| 654 | 634 | 
| 655   void set existsHandler(void handler(bool exists)) { | 635   void set onError(void handler(String error)) { | 
| 656     _existsHandler = handler; | 636     _onError = handler; | 
| 657   } |  | 
| 658 |  | 
| 659   void set createHandler(void handler()) { |  | 
| 660     _createHandler = handler; |  | 
| 661   } |  | 
| 662 |  | 
| 663   void set deleteHandler(void handler()) { |  | 
| 664     _deleteHandler = handler; |  | 
| 665   } |  | 
| 666 |  | 
| 667   void set directoryHandler(void handler(Directory directory)) { |  | 
| 668     _directoryHandler = handler; |  | 
| 669   } |  | 
| 670 |  | 
| 671   void set openHandler(void handler(RandomAccessFile file)) { |  | 
| 672     _openHandler = handler; |  | 
| 673   } |  | 
| 674 |  | 
| 675   void set readAsBytesHandler(void handler(List<int> bytes)) { |  | 
| 676     _readAsBytesHandler = handler; |  | 
| 677   } |  | 
| 678 |  | 
| 679   void set readAsTextHandler(void handler(String text)) { |  | 
| 680     _readAsTextHandler = handler; |  | 
| 681   } |  | 
| 682 |  | 
| 683   void set readAsLinesHandler(void handler(List<String> lines)) { |  | 
| 684     _readAsLinesHandler = handler; |  | 
| 685   } |  | 
| 686 |  | 
| 687   void set fullPathHandler(void handler(String)) { |  | 
| 688     _fullPathHandler = handler; |  | 
| 689   } |  | 
| 690 |  | 
| 691   void set errorHandler(void handler(String error)) { |  | 
| 692     _errorHandler = handler; |  | 
| 693   } | 637   } | 
| 694 | 638 | 
| 695   void _ensureFileService() { | 639   void _ensureFileService() { | 
| 696     if (_fileService == null) { | 640     if (_fileService == null) { | 
| 697       _fileService = _FileUtils.newServicePort(); | 641       _fileService = _FileUtils.newServicePort(); | 
| 698     } | 642     } | 
| 699   } | 643   } | 
| 700 | 644 | 
| 701   String _name; | 645   String _name; | 
| 702   bool _asyncUsed; | 646   bool _asyncUsed; | 
| 703 | 647 | 
| 704   SendPort _fileService; | 648   SendPort _fileService; | 
| 705 | 649 | 
| 706   Function _existsHandler; | 650   Function _onError; | 
| 707   Function _createHandler; |  | 
| 708   Function _deleteHandler; |  | 
| 709   Function _directoryHandler; |  | 
| 710   Function _openHandler; |  | 
| 711   Function _readAsBytesHandler; |  | 
| 712   Function _readAsTextHandler; |  | 
| 713   Function _readAsLinesHandler; |  | 
| 714   Function _fullPathHandler; |  | 
| 715   Function _errorHandler; |  | 
| 716 } | 651 } | 
| 717 | 652 | 
| 718 | 653 | 
| 719 class _RandomAccessFile implements RandomAccessFile { | 654 class _RandomAccessFile implements RandomAccessFile { | 
| 720   _RandomAccessFile(int this._id, String this._name) : _asyncUsed = false; | 655   _RandomAccessFile(int this._id, String this._name) : _asyncUsed = false; | 
| 721 | 656 | 
| 722   void close() { | 657   void close(void callback()) { | 
| 723     if (_id == 0) return; | 658     if (_id == 0) return; | 
| 724     _ensureFileService(); | 659     _ensureFileService(); | 
| 725     _asyncUsed = true; | 660     _asyncUsed = true; | 
| 726     List request = new List(2); | 661     List request = new List(2); | 
| 727     request[0] = _FileUtils.kCloseRequest; | 662     request[0] = _FileUtils.kCloseRequest; | 
| 728     request[1] = _id; | 663     request[1] = _id; | 
| 729     // Set the id_ to 0 (NULL) to ensure the no more async requests | 664     // Set the id_ to 0 (NULL) to ensure the no more async requests | 
| 730     // can be issues for this file. | 665     // can be issues for this file. | 
| 731     _id = 0; | 666     _id = 0; | 
| 732     _fileService.call(request).receive((result, replyTo) { | 667     _fileService.call(request).receive((result, replyTo) { | 
| 733       if (result != -1) { | 668       if (result != -1) { | 
| 734         _id = result; | 669         _id = result; | 
| 735         if (_closeHandler != null) _closeHandler(); | 670         callback(); | 
| 736       } else if (_errorHandler != null) { | 671       } else if (_onError != null) { | 
| 737         _errorHandler("Cannot close file: $_name"); | 672         _onError("Cannot close file: $_name"); | 
| 738       } | 673       } | 
| 739     }); | 674     }); | 
| 740   } | 675   } | 
| 741 | 676 | 
| 742   void closeSync() { | 677   void closeSync() { | 
| 743     if (_asyncUsed) { | 678     if (_asyncUsed) { | 
| 744       throw new FileIOException( | 679       throw new FileIOException( | 
| 745           "Mixed use of synchronous and asynchronous API"); | 680           "Mixed use of synchronous and asynchronous API"); | 
| 746     } | 681     } | 
| 747     var id = _FileUtils.close(_id); | 682     var id = _FileUtils.close(_id); | 
| 748     if (id == -1) { | 683     if (id == -1) { | 
| 749       throw new FileIOException("Cannot close file: $_name"); | 684       throw new FileIOException("Cannot close file: $_name"); | 
| 750     } | 685     } | 
| 751     _id = id; | 686     _id = id; | 
| 752   } | 687   } | 
| 753 | 688 | 
| 754   void readByte() { | 689   void readByte(void callback(int byte)) { | 
| 755     _ensureFileService(); | 690     _ensureFileService(); | 
| 756     _asyncUsed = true; | 691     _asyncUsed = true; | 
| 757     List request = new List(2); | 692     List request = new List(2); | 
| 758     request[0] = _FileUtils.kReadByteRequest; | 693     request[0] = _FileUtils.kReadByteRequest; | 
| 759     request[1] = _id; | 694     request[1] = _id; | 
| 760     _fileService.call(request).receive((result, replyTo) { | 695     _fileService.call(request).receive((result, replyTo) { | 
| 761       if (result != -1) { | 696       if (result != -1) { | 
| 762         if (_readByteHandler != null) _readByteHandler(result); | 697         callback(result); | 
| 763       } else if (_errorHandler != null) { | 698       } else if (_onError != null) { | 
| 764         _errorHandler("readByte failed"); | 699         _onError("readByte failed"); | 
| 765       } | 700       } | 
| 766     }); | 701     }); | 
| 767   } | 702   } | 
| 768 | 703 | 
| 769   int readByteSync() { | 704   int readByteSync() { | 
| 770     if (_asyncUsed) { | 705     if (_asyncUsed) { | 
| 771       throw new FileIOException( | 706       throw new FileIOException( | 
| 772           "Mixed use of synchronous and asynchronous API"); | 707           "Mixed use of synchronous and asynchronous API"); | 
| 773     } | 708     } | 
| 774     int result = _FileUtils.readByte(_id); | 709     int result = _FileUtils.readByte(_id); | 
| 775     if (result == -1) { | 710     if (result == -1) { | 
| 776       throw new FileIOException("readByte failed"); | 711       throw new FileIOException("readByte failed"); | 
| 777     } | 712     } | 
| 778     return result; | 713     return result; | 
| 779   } | 714   } | 
| 780 | 715 | 
| 781   void readList(List<int> buffer, int offset, int bytes) { | 716   void readList(List<int> buffer, int offset, int bytes, | 
|  | 717                 void callback(int read)) { | 
| 782     _ensureFileService(); | 718     _ensureFileService(); | 
| 783     _asyncUsed = true; | 719     _asyncUsed = true; | 
| 784     if (buffer is !List || offset is !int || bytes is !int) { | 720     if (buffer is !List || offset is !int || bytes is !int) { | 
| 785       if (_errorHandler != null) { | 721       if (_onError != null) { | 
| 786         _errorHandler("Invalid arguments to readList"); | 722         _onError("Invalid arguments to readList"); | 
| 787       } | 723       } | 
| 788       return; | 724       return; | 
| 789     }; | 725     }; | 
| 790     List request = new List(3); | 726     List request = new List(3); | 
| 791     request[0] = _FileUtils.kReadListRequest; | 727     request[0] = _FileUtils.kReadListRequest; | 
| 792     request[1] = _id; | 728     request[1] = _id; | 
| 793     request[2] = bytes; | 729     request[2] = bytes; | 
| 794     _fileService.call(request).receive((result, replyTo) { | 730     _fileService.call(request).receive((result, replyTo) { | 
| 795       if (result is List && result.length == 2 && result[0] != -1) { | 731       if (result is List && result.length == 2 && result[0] != -1) { | 
| 796         var read = result[0]; | 732         var read = result[0]; | 
| 797         var data = result[1]; | 733         var data = result[1]; | 
| 798         buffer.setRange(offset, read, data); | 734         buffer.setRange(offset, read, data); | 
| 799         if (_readListHandler != null) _readListHandler(read); | 735         callback(read); | 
| 800         return; | 736         return; | 
| 801       } else if (_errorHandler != null) { | 737       } else if (_onError != null) { | 
| 802         _errorHandler(result is String ? result : "readList failed"); | 738         _onError(result is String ? result : "readList failed"); | 
| 803       } | 739       } | 
| 804     }); | 740     }); | 
| 805   } | 741   } | 
| 806 | 742 | 
| 807   int readListSync(List<int> buffer, int offset, int bytes) { | 743   int readListSync(List<int> buffer, int offset, int bytes) { | 
| 808     if (_asyncUsed) { | 744     if (_asyncUsed) { | 
| 809       throw new FileIOException( | 745       throw new FileIOException( | 
| 810           "Mixed use of synchronous and asynchronous API"); | 746           "Mixed use of synchronous and asynchronous API"); | 
| 811     } | 747     } | 
| 812     if (buffer is !List || offset is !int || bytes is !int) { | 748     if (buffer is !List || offset is !int || bytes is !int) { | 
| 813       throw new FileIOException("Invalid arguments to readList"); | 749       throw new FileIOException("Invalid arguments to readList"); | 
| 814     } | 750     } | 
| 815     if (bytes == 0) return 0; | 751     if (bytes == 0) return 0; | 
| 816     int index = | 752     int index = | 
| 817         _FileUtils.checkReadWriteListArguments(buffer.length, offset, bytes); | 753         _FileUtils.checkReadWriteListArguments(buffer.length, offset, bytes); | 
| 818     if (index != 0) { | 754     if (index != 0) { | 
| 819       throw new IndexOutOfRangeException(index); | 755       throw new IndexOutOfRangeException(index); | 
| 820     } | 756     } | 
| 821     int result = _FileUtils.readList(_id, buffer, offset, bytes); | 757     int result = _FileUtils.readList(_id, buffer, offset, bytes); | 
| 822     if (result == -1) { | 758     if (result == -1) { | 
| 823       throw new FileIOException("readList failed"); | 759       throw new FileIOException("readList failed"); | 
| 824     } | 760     } | 
| 825     return result; | 761     return result; | 
| 826   } | 762   } | 
| 827 | 763 | 
| 828   void writeByte(int value) { | 764   void writeByte(int value) { | 
| 829     _ensureFileService(); | 765     _ensureFileService(); | 
| 830     _asyncUsed = true; | 766     _asyncUsed = true; | 
| 831     if (value is !int) { | 767     if (value is !int) { | 
| 832       if (_errorHandler != null) { | 768       if (_onError != null) { | 
| 833         _errorHandler("Invalid argument to writeByte"); | 769         _onError("Invalid argument to writeByte"); | 
| 834       } | 770       } | 
| 835       return; | 771       return; | 
| 836     } | 772     } | 
| 837     List request = new List(3); | 773     List request = new List(3); | 
| 838     request[0] = _FileUtils.kWriteByteRequest; | 774     request[0] = _FileUtils.kWriteByteRequest; | 
| 839     request[1] = _id; | 775     request[1] = _id; | 
| 840     request[2] = value; | 776     request[2] = value; | 
| 841     _writeEnqueued(); | 777     _writeEnqueued(); | 
| 842     _fileService.call(request).receive((result, replyTo) { | 778     _fileService.call(request).receive((result, replyTo) { | 
| 843       _writeCompleted(); | 779       _writeCompleted(); | 
| 844       if (result == -1 && _errorHandler !== null) { | 780       if (result == -1 && _onError !== null) { | 
| 845         _errorHandler("writeByte failed"); | 781         _onError("writeByte failed"); | 
| 846       } | 782       } | 
| 847     }); | 783     }); | 
| 848   } | 784   } | 
| 849 | 785 | 
| 850   int writeByteSync(int value) { | 786   int writeByteSync(int value) { | 
| 851     if (_asyncUsed) { | 787     if (_asyncUsed) { | 
| 852       throw new FileIOException( | 788       throw new FileIOException( | 
| 853           "Mixed use of synchronous and asynchronous API"); | 789           "Mixed use of synchronous and asynchronous API"); | 
| 854     } | 790     } | 
| 855     if (value is !int) { | 791     if (value is !int) { | 
| 856       throw new FileIOException("Invalid argument to writeByte"); | 792       throw new FileIOException("Invalid argument to writeByte"); | 
| 857     } | 793     } | 
| 858     int result = _FileUtils.writeByte(_id, value); | 794     int result = _FileUtils.writeByte(_id, value); | 
| 859     if (result == -1) { | 795     if (result == -1) { | 
| 860       throw new FileIOException("writeByte failed"); | 796       throw new FileIOException("writeByte failed"); | 
| 861     } | 797     } | 
| 862     return result; | 798     return result; | 
| 863   } | 799   } | 
| 864 | 800 | 
| 865   void writeList(List<int> buffer, int offset, int bytes) { | 801   void writeList(List<int> buffer, int offset, int bytes) { | 
| 866     _ensureFileService(); | 802     _ensureFileService(); | 
| 867     _asyncUsed = true; | 803     _asyncUsed = true; | 
| 868     if (buffer is !List || offset is !int || bytes is !int) { | 804     if (buffer is !List || offset is !int || bytes is !int) { | 
| 869       if (_errorHandler != null) { | 805       if (_onError != null) { | 
| 870         _errorHandler("Invalid arguments to writeList"); | 806         _onError("Invalid arguments to writeList"); | 
| 871       } | 807       } | 
| 872       return; | 808       return; | 
| 873     } | 809     } | 
| 874 | 810 | 
| 875     List result = | 811     List result = | 
| 876         _FileUtils.ensureFastAndSerializableBuffer(buffer, offset, bytes); | 812         _FileUtils.ensureFastAndSerializableBuffer(buffer, offset, bytes); | 
| 877     List outBuffer = result[0]; | 813     List outBuffer = result[0]; | 
| 878     int outOffset = result[1]; | 814     int outOffset = result[1]; | 
| 879 | 815 | 
| 880     List request = new List(5); | 816     List request = new List(5); | 
| 881     request[0] = _FileUtils.kWriteListRequest; | 817     request[0] = _FileUtils.kWriteListRequest; | 
| 882     request[1] = _id; | 818     request[1] = _id; | 
| 883     request[2] = outBuffer; | 819     request[2] = outBuffer; | 
| 884     request[3] = outOffset; | 820     request[3] = outOffset; | 
| 885     request[4] = bytes; | 821     request[4] = bytes; | 
| 886     _writeEnqueued(); | 822     _writeEnqueued(); | 
| 887     _fileService.call(request).receive((result, replyTo) { | 823     _fileService.call(request).receive((result, replyTo) { | 
| 888       _writeCompleted(); | 824       _writeCompleted(); | 
| 889       if (result == -1 && _errorHandler !== null) { | 825       if (result == -1 && _onError !== null) { | 
| 890         _errorHandler("writeList failed"); | 826         _onError("writeList failed"); | 
| 891       } | 827       } | 
| 892     }); | 828     }); | 
| 893   } | 829   } | 
| 894 | 830 | 
| 895   int writeListSync(List<int> buffer, int offset, int bytes) { | 831   int writeListSync(List<int> buffer, int offset, int bytes) { | 
| 896     if (_asyncUsed) { | 832     if (_asyncUsed) { | 
| 897       throw new FileIOException( | 833       throw new FileIOException( | 
| 898           "Mixed use of synchronous and asynchronous API"); | 834           "Mixed use of synchronous and asynchronous API"); | 
| 899     } | 835     } | 
| 900     if (buffer is !List || offset is !int || bytes is !int) { | 836     if (buffer is !List || offset is !int || bytes is !int) { | 
| (...skipping 15 matching lines...) Expand all  Loading... | 
| 916   void writeString(String string) { | 852   void writeString(String string) { | 
| 917     _ensureFileService(); | 853     _ensureFileService(); | 
| 918     _asyncUsed = true; | 854     _asyncUsed = true; | 
| 919     List request = new List(3); | 855     List request = new List(3); | 
| 920     request[0] = _FileUtils.kWriteStringRequest; | 856     request[0] = _FileUtils.kWriteStringRequest; | 
| 921     request[1] = _id; | 857     request[1] = _id; | 
| 922     request[2] = string; | 858     request[2] = string; | 
| 923     _writeEnqueued(); | 859     _writeEnqueued(); | 
| 924     _fileService.call(request).receive((result, replyTo) { | 860     _fileService.call(request).receive((result, replyTo) { | 
| 925       _writeCompleted(); | 861       _writeCompleted(); | 
| 926       if (result == -1 && _errorHandler !== null) { | 862       if (result == -1 && _onError !== null) { | 
| 927         _errorHandler("writeString failed"); | 863         _onError("writeString failed"); | 
| 928       } | 864       } | 
| 929     }); | 865     }); | 
| 930   } | 866   } | 
| 931 | 867 | 
| 932   int writeStringSync(String string) { | 868   int writeStringSync(String string) { | 
| 933     if (_asyncUsed) { | 869     if (_asyncUsed) { | 
| 934       throw new FileIOException( | 870       throw new FileIOException( | 
| 935           "Mixed use of synchronous and asynchronous API"); | 871           "Mixed use of synchronous and asynchronous API"); | 
| 936     } | 872     } | 
| 937     int result = _FileUtils.checkedWriteString(_id, string); | 873     int result = _FileUtils.checkedWriteString(_id, string); | 
| 938     if (result == -1) { | 874     if (result == -1) { | 
| 939       throw new FileIOException("writeString failed"); | 875       throw new FileIOException("writeString failed"); | 
| 940     } | 876     } | 
| 941     return result; | 877     return result; | 
| 942   } | 878   } | 
| 943 | 879 | 
| 944   void position() { | 880   void position(void callback(int position)) { | 
| 945     _ensureFileService(); | 881     _ensureFileService(); | 
| 946     _asyncUsed = true; | 882     _asyncUsed = true; | 
| 947     List request = new List(2); | 883     List request = new List(2); | 
| 948     request[0] = _FileUtils.kPositionRequest; | 884     request[0] = _FileUtils.kPositionRequest; | 
| 949     request[1] = _id; | 885     request[1] = _id; | 
| 950     _fileService.call(request).receive((result, replyTo) { | 886     _fileService.call(request).receive((result, replyTo) { | 
| 951       if (result != -1) { | 887       if (result != -1) { | 
| 952         if (_positionHandler != null) _positionHandler(result); | 888         callback(result); | 
| 953       } else if (_errorHandler != null) { | 889       } else if (_onError != null) { | 
| 954         _errorHandler("position failed"); | 890         _onError("position failed"); | 
| 955       } | 891       } | 
| 956     }); | 892     }); | 
| 957   } | 893   } | 
| 958 | 894 | 
| 959   int positionSync() { | 895   int positionSync() { | 
| 960     if (_asyncUsed) { | 896     if (_asyncUsed) { | 
| 961       throw new FileIOException( | 897       throw new FileIOException( | 
| 962           "Mixed use of synchronous and asynchronous API"); | 898           "Mixed use of synchronous and asynchronous API"); | 
| 963     } | 899     } | 
| 964     int result = _FileUtils.position(_id); | 900     int result = _FileUtils.position(_id); | 
| 965     if (result == -1) { | 901     if (result == -1) { | 
| 966       throw new FileIOException("position failed"); | 902       throw new FileIOException("position failed"); | 
| 967     } | 903     } | 
| 968     return result; | 904     return result; | 
| 969   } | 905   } | 
| 970 | 906 | 
| 971   void setPosition(int position) { | 907   void setPosition(int position, void callback()) { | 
| 972     _ensureFileService(); | 908     _ensureFileService(); | 
| 973     _asyncUsed = true; | 909     _asyncUsed = true; | 
| 974     List request = new List(3); | 910     List request = new List(3); | 
| 975     request[0] = _FileUtils.kSetPositionRequest; | 911     request[0] = _FileUtils.kSetPositionRequest; | 
| 976     request[1] = _id; | 912     request[1] = _id; | 
| 977     request[2] = position; | 913     request[2] = position; | 
| 978     _fileService.call(request).receive((result, replyTo) { | 914     _fileService.call(request).receive((result, replyTo) { | 
| 979       if (result) { | 915       if (result) { | 
| 980         if (_setPositionHandler != null) _setPositionHandler(); | 916         callback(); | 
| 981       } else if (_errorHandler != null) { | 917       } else if (_onError != null) { | 
| 982         _errorHandler("setPosition failed"); | 918         _onError("setPosition failed"); | 
| 983       } | 919       } | 
| 984     }); | 920     }); | 
| 985   } | 921   } | 
| 986 | 922 | 
| 987   void setPositionSync(int position) { | 923   void setPositionSync(int position) { | 
| 988     _ensureFileService(); | 924     _ensureFileService(); | 
| 989     if (_asyncUsed) { | 925     if (_asyncUsed) { | 
| 990       throw new FileIOException( | 926       throw new FileIOException( | 
| 991           "Mixed use of synchronous and asynchronous API"); | 927           "Mixed use of synchronous and asynchronous API"); | 
| 992     } | 928     } | 
| 993     bool result = _FileUtils.setPosition(_id, position); | 929     bool result = _FileUtils.setPosition(_id, position); | 
| 994     if (result == false) { | 930     if (result == false) { | 
| 995       throw new FileIOException("setPosition failed"); | 931       throw new FileIOException("setPosition failed"); | 
| 996     } | 932     } | 
| 997   } | 933   } | 
| 998 | 934 | 
| 999   void truncate(int length) { | 935   void truncate(int length, void callback()) { | 
| 1000     _ensureFileService(); | 936     _ensureFileService(); | 
| 1001     _asyncUsed = true; | 937     _asyncUsed = true; | 
| 1002     List request = new List(3); | 938     List request = new List(3); | 
| 1003     request[0] = _FileUtils.kTruncateRequest; | 939     request[0] = _FileUtils.kTruncateRequest; | 
| 1004     request[1] = _id; | 940     request[1] = _id; | 
| 1005     request[2] = length; | 941     request[2] = length; | 
| 1006     _fileService.call(request).receive((result, replyTo) { | 942     _fileService.call(request).receive((result, replyTo) { | 
| 1007       if (result) { | 943       if (result) { | 
| 1008         if (_truncateHandler != null) _truncateHandler(); | 944         callback(); | 
| 1009       } else if (_errorHandler != null) { | 945       } else if (_onError != null) { | 
| 1010         _errorHandler("truncate failed"); | 946         _onError("truncate failed"); | 
| 1011       } | 947       } | 
| 1012     }); | 948     }); | 
| 1013   } | 949   } | 
| 1014 | 950 | 
| 1015   void truncateSync(int length) { | 951   void truncateSync(int length) { | 
| 1016     if (_asyncUsed) { | 952     if (_asyncUsed) { | 
| 1017       throw new FileIOException( | 953       throw new FileIOException( | 
| 1018           "Mixed use of synchronous and asynchronous API"); | 954           "Mixed use of synchronous and asynchronous API"); | 
| 1019     } | 955     } | 
| 1020     bool result = _FileUtils.truncate(_id, length); | 956     bool result = _FileUtils.truncate(_id, length); | 
| 1021     if (result == false) { | 957     if (result == false) { | 
| 1022       throw new FileIOException("truncate failed"); | 958       throw new FileIOException("truncate failed"); | 
| 1023     } | 959     } | 
| 1024   } | 960   } | 
| 1025 | 961 | 
| 1026   void length() { | 962   void length(void callback(int length)) { | 
| 1027     _ensureFileService(); | 963     _ensureFileService(); | 
| 1028     _asyncUsed = true; | 964     _asyncUsed = true; | 
| 1029     List request = new List(2); | 965     List request = new List(2); | 
| 1030     request[0] = _FileUtils.kLengthRequest; | 966     request[0] = _FileUtils.kLengthRequest; | 
| 1031     request[1] = _id; | 967     request[1] = _id; | 
| 1032     _fileService.call(request).receive((result, replyTo) { | 968     _fileService.call(request).receive((result, replyTo) { | 
| 1033       if (result != -1) { | 969       if (result != -1) { | 
| 1034         if (_lengthHandler != null) _lengthHandler(result); | 970         callback(result); | 
| 1035       } else if (_errorHandler != null) { | 971       } else if (_onError != null) { | 
| 1036         _errorHandler("length failed"); | 972         _onError("length failed"); | 
| 1037       } | 973       } | 
| 1038     }); | 974     }); | 
| 1039   } | 975   } | 
| 1040 | 976 | 
| 1041   int lengthSync() { | 977   int lengthSync() { | 
| 1042     if (_asyncUsed) { | 978     if (_asyncUsed) { | 
| 1043       throw new FileIOException( | 979       throw new FileIOException( | 
| 1044           "Mixed use of synchronous and asynchronous API"); | 980           "Mixed use of synchronous and asynchronous API"); | 
| 1045     } | 981     } | 
| 1046     int result = _FileUtils.length(_id); | 982     int result = _FileUtils.length(_id); | 
| 1047     if (result == -1) { | 983     if (result == -1) { | 
| 1048       throw new FileIOException("length failed"); | 984       throw new FileIOException("length failed"); | 
| 1049     } | 985     } | 
| 1050     return result; | 986     return result; | 
| 1051   } | 987   } | 
| 1052 | 988 | 
| 1053   void flush() { | 989   void flush(void callback()) { | 
| 1054     _ensureFileService(); | 990     _ensureFileService(); | 
| 1055     _asyncUsed = true; | 991     _asyncUsed = true; | 
| 1056     List request = new List(2); | 992     List request = new List(2); | 
| 1057     request[0] = _FileUtils.kFlushRequest; | 993     request[0] = _FileUtils.kFlushRequest; | 
| 1058     request[1] = _id; | 994     request[1] = _id; | 
| 1059     _fileService.call(request).receive((result, replyTo) { | 995     _fileService.call(request).receive((result, replyTo) { | 
| 1060       if (result != -1) { | 996       if (result != -1) { | 
| 1061         if (_flushHandler != null) _flushHandler(); | 997         callback(); | 
| 1062       } else if (_errorHandler != null) { | 998       } else if (_onError != null) { | 
| 1063         _errorHandler("flush failed"); | 999         _onError("flush failed"); | 
| 1064       } | 1000       } | 
| 1065     }); | 1001     }); | 
| 1066   } | 1002   } | 
| 1067 | 1003 | 
| 1068   void flushSync() { | 1004   void flushSync() { | 
| 1069     if (_asyncUsed) { | 1005     if (_asyncUsed) { | 
| 1070       throw new FileIOException( | 1006       throw new FileIOException( | 
| 1071           "Mixed use of synchronous and asynchronous API"); | 1007           "Mixed use of synchronous and asynchronous API"); | 
| 1072     } | 1008     } | 
| 1073     int result = _FileUtils.flush(_id); | 1009     int result = _FileUtils.flush(_id); | 
| 1074     if (result == -1) { | 1010     if (result == -1) { | 
| 1075       throw new FileIOException("flush failed"); | 1011       throw new FileIOException("flush failed"); | 
| 1076     } | 1012     } | 
| 1077   } | 1013   } | 
| 1078 | 1014 | 
| 1079   String get name() => _name; | 1015   String get name() => _name; | 
| 1080 | 1016 | 
| 1081   void set errorHandler(void handler(String error)) { | 1017   void set onError(void handler(String error)) { | 
| 1082     _errorHandler = handler; | 1018     _onError = handler; | 
| 1083   } | 1019   } | 
| 1084 | 1020 | 
| 1085   void set closeHandler(void handler()) { | 1021   void set onNoPendingWrites(void handler()) { | 
| 1086     _closeHandler = handler; | 1022     _onNoPendingWrites = handler; | 
| 1087   } |  | 
| 1088 |  | 
| 1089   void set readByteHandler(void handler(int byte)) { |  | 
| 1090     _readByteHandler = handler; |  | 
| 1091   } |  | 
| 1092 |  | 
| 1093   void set readListHandler(void handler(int read)) { |  | 
| 1094     _readListHandler = handler; |  | 
| 1095   } |  | 
| 1096 |  | 
| 1097   void set noPendingWriteHandler(void handler()) { |  | 
| 1098     _noPendingWriteHandler = handler; |  | 
| 1099     if (_pendingWrites == 0) { | 1023     if (_pendingWrites == 0) { | 
| 1100       _noPendingWriteTimer = new Timer((t) { | 1024       _noPendingWriteTimer = new Timer((t) { | 
| 1101         if (_noPendingWriteHandler != null) _noPendingWriteHandler(); | 1025         if (_onNoPendingWrites != null) _onNoPendingWrites(); | 
| 1102       }, 0); | 1026       }, 0); | 
| 1103     } | 1027     } | 
| 1104   } | 1028   } | 
| 1105 | 1029 | 
| 1106   void set positionHandler(void handler(int pos)) { |  | 
| 1107     _positionHandler = handler; |  | 
| 1108   } |  | 
| 1109 |  | 
| 1110   void set setPositionHandler(void handler()) { |  | 
| 1111     _setPositionHandler = handler; |  | 
| 1112   } |  | 
| 1113 |  | 
| 1114   void set truncateHandler(void handler()) { |  | 
| 1115     _truncateHandler = handler; |  | 
| 1116   } |  | 
| 1117 |  | 
| 1118   void set lengthHandler(void handler(int length)) { |  | 
| 1119     _lengthHandler = handler; |  | 
| 1120   } |  | 
| 1121 |  | 
| 1122   void set flushHandler(void handler()) { |  | 
| 1123     _flushHandler = handler; |  | 
| 1124   } |  | 
| 1125 |  | 
| 1126   void _ensureFileService() { | 1030   void _ensureFileService() { | 
| 1127     if (_fileService == null) { | 1031     if (_fileService == null) { | 
| 1128       _fileService = _FileUtils.newServicePort(); | 1032       _fileService = _FileUtils.newServicePort(); | 
| 1129     } | 1033     } | 
| 1130   } | 1034   } | 
| 1131 | 1035 | 
| 1132   void _writeEnqueued() { | 1036   void _writeEnqueued() { | 
| 1133     _pendingWrites++; | 1037     _pendingWrites++; | 
| 1134     if (_noPendingWriteTimer != null) { | 1038     if (_noPendingWriteTimer != null) { | 
| 1135       _noPendingWriteTimer.cancel(); | 1039       _noPendingWriteTimer.cancel(); | 
| 1136       _noPendingWriteTimer = null; | 1040       _noPendingWriteTimer = null; | 
| 1137     } | 1041     } | 
| 1138   } | 1042   } | 
| 1139 | 1043 | 
| 1140   void  _writeCompleted() { | 1044   void  _writeCompleted() { | 
| 1141     _pendingWrites--; | 1045     _pendingWrites--; | 
| 1142     if (_pendingWrites == 0 && _noPendingWriteHandler != null) { | 1046     if (_pendingWrites == 0 && _onNoPendingWrites != null) { | 
| 1143       _noPendingWriteHandler(); | 1047       _onNoPendingWrites(); | 
| 1144     } | 1048     } | 
| 1145   } | 1049   } | 
| 1146 | 1050 | 
| 1147 | 1051 | 
| 1148   String _name; | 1052   String _name; | 
| 1149   int _id; | 1053   int _id; | 
| 1150   bool _asyncUsed; | 1054   bool _asyncUsed; | 
| 1151   int _pendingWrites = 0; | 1055   int _pendingWrites = 0; | 
| 1152 | 1056 | 
| 1153   SendPort _fileService; | 1057   SendPort _fileService; | 
| 1154 | 1058 | 
| 1155   Timer _noPendingWriteTimer; | 1059   Timer _noPendingWriteTimer; | 
| 1156 | 1060 | 
| 1157   Function _closeHandler; | 1061   Function _onNoPendingWrites; | 
| 1158   Function _readByteHandler; | 1062   Function _onError; | 
| 1159   Function _readListHandler; |  | 
| 1160   Function _noPendingWriteHandler; |  | 
| 1161   Function _positionHandler; |  | 
| 1162   Function _setPositionHandler; |  | 
| 1163   Function _truncateHandler; |  | 
| 1164   Function _lengthHandler; |  | 
| 1165   Function _flushHandler; |  | 
| 1166   Function _errorHandler; |  | 
| 1167 } | 1063 } | 
| OLD | NEW | 
|---|