| 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(RandomAccessFile this._file, int this._length) { | 6 _FileInputStream(RandomAccessFile this._file, int this._length) { |
| 7 _streamMarkedClosed = true; | 7 _streamMarkedClosed = true; |
| 8 _checkScheduleCallbacks(); | 8 _checkScheduleCallbacks(); |
| 9 } | 9 } |
| 10 | 10 |
| (...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 149 // the stream is fully closed. | 149 // the stream is fully closed. |
| 150 bool _closeCallbackCalled = false; | 150 bool _closeCallbackCalled = false; |
| 151 | 151 |
| 152 Timer _scheduledNoPendingWriteCallback; | 152 Timer _scheduledNoPendingWriteCallback; |
| 153 Timer _scheduledCloseCallback; | 153 Timer _scheduledCloseCallback; |
| 154 Function _noPendingWriteHandler; | 154 Function _noPendingWriteHandler; |
| 155 Function _closeHandler; | 155 Function _closeHandler; |
| 156 } | 156 } |
| 157 | 157 |
| 158 | 158 |
| 159 class _FileOperation { | |
| 160 abstract void execute(ReceivePort port); | |
| 161 | |
| 162 void set replyPort(SendPort port) { | |
| 163 _replyPort = port; | |
| 164 } | |
| 165 | |
| 166 bool isWrite() => false; | |
| 167 | |
| 168 SendPort _replyPort; | |
| 169 } | |
| 170 | |
| 171 | |
| 172 class _ExistsOperation extends _FileOperation { | |
| 173 _ExistsOperation(String this._name); | |
| 174 | |
| 175 void execute(ReceivePort port) { | |
| 176 _replyPort.send(_FileUtils.exists(_name), port.toSendPort()); | |
| 177 } | |
| 178 | |
| 179 String _name; | |
| 180 } | |
| 181 | |
| 182 | |
| 183 class _OpenOperation extends _FileOperation { | |
| 184 _OpenOperation(String this._name, int this._mode); | |
| 185 | |
| 186 void execute(ReceivePort port) { | |
| 187 _replyPort.send(_FileUtils.checkedOpen(_name, _mode), | |
| 188 port.toSendPort()); | |
| 189 } | |
| 190 | |
| 191 String _name; | |
| 192 int _mode; | |
| 193 } | |
| 194 | |
| 195 | |
| 196 class _CloseOperation extends _FileOperation { | |
| 197 _CloseOperation(int this._id); | |
| 198 | |
| 199 void execute(ReceivePort port) { | |
| 200 _replyPort.send(_FileUtils.close(_id), port.toSendPort()); | |
| 201 } | |
| 202 | |
| 203 int _id; | |
| 204 } | |
| 205 | |
| 206 | |
| 207 class _ReadByteOperation extends _FileOperation { | |
| 208 _ReadByteOperation(int this._id); | |
| 209 | |
| 210 void execute(ReceivePort port) { | |
| 211 _replyPort.send(_FileUtils.readByte(_id), port.toSendPort()); | |
| 212 } | |
| 213 | |
| 214 int _id; | |
| 215 } | |
| 216 | |
| 217 | |
| 218 class _ReadListResult { | |
| 219 _ReadListResult(this.read, this.buffer); | |
| 220 int read; | |
| 221 List buffer; | |
| 222 } | |
| 223 | |
| 224 | |
| 225 class _ReadListOperation extends _FileOperation { | |
| 226 _ReadListOperation(int this._id, | |
| 227 int this._length, | |
| 228 int this._offset, | |
| 229 int this._bytes); | |
| 230 | |
| 231 void execute(ReceivePort port) { | |
| 232 if (_bytes == 0) { | |
| 233 _replyPort.send(0, port.toSendPort()); | |
| 234 return; | |
| 235 } | |
| 236 int index = | |
| 237 _FileUtils.checkReadWriteListArguments(_length, _offset, _bytes); | |
| 238 if (index != 0) { | |
| 239 _replyPort.send("index out of range in readList: $index", | |
| 240 port.toSendPort()); | |
| 241 return; | |
| 242 } | |
| 243 ByteArray buffer = new ByteArray(_bytes); | |
| 244 var result = | |
| 245 new _ReadListResult(_FileUtils.readList(_id, buffer, 0, _bytes), | |
| 246 buffer); | |
| 247 _replyPort.send(result, port.toSendPort()); | |
| 248 } | |
| 249 | |
| 250 int _id; | |
| 251 int _length; | |
| 252 int _offset; | |
| 253 int _bytes; | |
| 254 } | |
| 255 | |
| 256 | |
| 257 class _WriteByteOperation extends _FileOperation { | |
| 258 _WriteByteOperation(int this._id, int this._value); | |
| 259 | |
| 260 void execute(ReceivePort port) { | |
| 261 _replyPort.send(_FileUtils.writeByte(_id, _value), port.toSendPort()); | |
| 262 } | |
| 263 | |
| 264 bool isWrite() => true; | |
| 265 | |
| 266 int _id; | |
| 267 int _value; | |
| 268 } | |
| 269 | |
| 270 | |
| 271 class _WriteListOperation extends _FileOperation { | |
| 272 _WriteListOperation(int this._id, | |
| 273 List this._buffer, | |
| 274 int this._offset, | |
| 275 int this._bytes); | |
| 276 | |
| 277 void execute(ReceivePort port) { | |
| 278 if (_bytes == 0) { | |
| 279 _replyPort.send(0, port.toSendPort()); | |
| 280 return; | |
| 281 } | |
| 282 int index = | |
| 283 _FileUtils.checkReadWriteListArguments(_buffer.length, _offset, _bytes); | |
| 284 if (index != 0) { | |
| 285 _replyPort.send("index out of range in writeList: $index", | |
| 286 port.toSendPort()); | |
| 287 return; | |
| 288 } | |
| 289 var result = _FileUtils.writeList(_id, _buffer, _offset, _bytes); | |
| 290 _replyPort.send(result, port.toSendPort()); | |
| 291 } | |
| 292 | |
| 293 bool isWrite() => true; | |
| 294 | |
| 295 int _id; | |
| 296 List _buffer; | |
| 297 int _offset; | |
| 298 int _bytes; | |
| 299 } | |
| 300 | |
| 301 | |
| 302 class _WriteStringOperation extends _FileOperation { | |
| 303 _WriteStringOperation(int this._id, String this._string); | |
| 304 | |
| 305 void execute(ReceivePort port) { | |
| 306 _replyPort.send(_FileUtils.checkedWriteString(_id, _string), | |
| 307 port.toSendPort()); | |
| 308 } | |
| 309 | |
| 310 bool isWrite() => true; | |
| 311 | |
| 312 int _id; | |
| 313 String _string; | |
| 314 } | |
| 315 | |
| 316 | |
| 317 class _PositionOperation extends _FileOperation { | |
| 318 _PositionOperation(int this._id); | |
| 319 | |
| 320 void execute(ReceivePort port) { | |
| 321 _replyPort.send(_FileUtils.position(_id), port.toSendPort()); | |
| 322 } | |
| 323 | |
| 324 int _id; | |
| 325 } | |
| 326 | |
| 327 | |
| 328 class _SetPositionOperation extends _FileOperation { | |
| 329 _SetPositionOperation(int this._id, int this._position); | |
| 330 | |
| 331 void execute(ReceivePort port) { | |
| 332 _replyPort.send(_FileUtils.setPosition(_id, _position), port.toSendPort()); | |
| 333 } | |
| 334 | |
| 335 int _id; | |
| 336 int _position; | |
| 337 } | |
| 338 | |
| 339 | |
| 340 class _TruncateOperation extends _FileOperation { | |
| 341 _TruncateOperation(int this._id, int this._length); | |
| 342 | |
| 343 void execute(ReceivePort port) { | |
| 344 _replyPort.send(_FileUtils.truncate(_id, _length), port.toSendPort()); | |
| 345 } | |
| 346 | |
| 347 int _id; | |
| 348 int _length; | |
| 349 } | |
| 350 | |
| 351 | |
| 352 class _LengthOperation extends _FileOperation { | |
| 353 _LengthOperation(int this._id); | |
| 354 | |
| 355 void execute(ReceivePort port) { | |
| 356 _replyPort.send(_FileUtils.length(_id), port.toSendPort()); | |
| 357 } | |
| 358 | |
| 359 int _id; | |
| 360 } | |
| 361 | |
| 362 | |
| 363 class _FlushOperation extends _FileOperation { | |
| 364 _FlushOperation(int this._id); | |
| 365 | |
| 366 void execute(ReceivePort port) { | |
| 367 _replyPort.send(_FileUtils.flush(_id), port.toSendPort()); | |
| 368 } | |
| 369 | |
| 370 int _id; | |
| 371 } | |
| 372 | |
| 373 | |
| 374 class _FullPathOperation extends _FileOperation { | |
| 375 _FullPathOperation(String this._name); | |
| 376 | |
| 377 void execute(ReceivePort port) { | |
| 378 _replyPort.send(_FileUtils.checkedFullPath(_name), port.toSendPort()); | |
| 379 } | |
| 380 | |
| 381 String _name; | |
| 382 } | |
| 383 | |
| 384 | |
| 385 class _CreateOperation extends _FileOperation { | |
| 386 _CreateOperation(String this._name); | |
| 387 | |
| 388 void execute(ReceivePort port) { | |
| 389 _replyPort.send(_FileUtils.checkedCreate(_name), port.toSendPort()); | |
| 390 } | |
| 391 | |
| 392 String _name; | |
| 393 } | |
| 394 | |
| 395 | |
| 396 class _DeleteOperation extends _FileOperation { | |
| 397 _DeleteOperation(String this._name); | |
| 398 | |
| 399 void execute(ReceivePort port) { | |
| 400 _replyPort.send(_FileUtils.checkedDelete(_name), port.toSendPort()); | |
| 401 } | |
| 402 | |
| 403 String _name; | |
| 404 } | |
| 405 | |
| 406 | |
| 407 class _DirectoryOperation extends _FileOperation { | |
| 408 _DirectoryOperation(String this._name); | |
| 409 | |
| 410 void execute(ReceivePort port) { | |
| 411 if (_name is String) { | |
| 412 if (_FileUtils.exists(_name)) { | |
| 413 _replyPort.send(_FileUtils.directory(_name), port.toSendPort()); | |
| 414 return; | |
| 415 } | |
| 416 } | |
| 417 // Either _name is not a string or the file does not exist. | |
| 418 _replyPort.send(null, port.toSendPort()); | |
| 419 } | |
| 420 | |
| 421 String _name; | |
| 422 } | |
| 423 | |
| 424 | |
| 425 class _ExitOperation extends _FileOperation { | |
| 426 void execute(ReceivePort port) { | |
| 427 port.close(); | |
| 428 } | |
| 429 } | |
| 430 | |
| 431 | |
| 432 class _FileOperationIsolate extends Isolate { | |
| 433 _FileOperationIsolate() : super.heavy(); | |
| 434 | |
| 435 void handleOperation(_FileOperation message, SendPort ignored) { | |
| 436 message.execute(port); | |
| 437 port.receive(handleOperation); | |
| 438 } | |
| 439 | |
| 440 void main() { | |
| 441 port.receive(handleOperation); | |
| 442 } | |
| 443 } | |
| 444 | |
| 445 | |
| 446 class _FileOperationScheduler { | |
| 447 _FileOperationScheduler() : _queue = new Queue(); | |
| 448 | |
| 449 void schedule(SendPort port) { | |
| 450 assert(_isolate != null); | |
| 451 if (_queue.isEmpty()) { | |
| 452 port.send(new _ExitOperation()); | |
| 453 _isolate = null; | |
| 454 } else { | |
| 455 port.send(_queue.removeFirst()); | |
| 456 } | |
| 457 } | |
| 458 | |
| 459 void scheduleWrap(void callback(result, ignored)) { | |
| 460 return (result, replyTo) { | |
| 461 callback(result, replyTo); | |
| 462 schedule(replyTo); | |
| 463 }; | |
| 464 } | |
| 465 | |
| 466 void enqueue(_FileOperation operation, void callback(result, ignored)) { | |
| 467 ReceivePort replyPort = new ReceivePort.singleShot(); | |
| 468 replyPort.receive(scheduleWrap(callback)); | |
| 469 operation.replyPort = replyPort.toSendPort(); | |
| 470 _queue.addLast(operation); | |
| 471 if (_isolate == null) { | |
| 472 _isolate = new _FileOperationIsolate(); | |
| 473 _isolate.spawn().then((port) { | |
| 474 schedule(port); | |
| 475 }); | |
| 476 } | |
| 477 } | |
| 478 | |
| 479 bool noPendingWrite() { | |
| 480 int queuedWrites = 0; | |
| 481 _queue.forEach((operation) { | |
| 482 if (operation.isWrite()) { | |
| 483 queuedWrites++; | |
| 484 } | |
| 485 }); | |
| 486 return queuedWrites == 0; | |
| 487 } | |
| 488 | |
| 489 Queue<_FileOperation> _queue; | |
| 490 _FileOperationIsolate _isolate; | |
| 491 } | |
| 492 | |
| 493 | |
| 494 // Helper class containing static file helper methods. | 159 // Helper class containing static file helper methods. |
| 495 class _FileUtils { | 160 class _FileUtils { |
| 496 static bool exists(String name) native "File_Exists"; | 161 static final kExistsRequest = 0; |
| 497 static int open(String name, int mode) native "File_Open"; | 162 static final kCreateRequest = 1; |
| 498 static bool create(String name) native "File_Create"; | 163 static final kDeleteRequest = 2; |
| 499 static bool delete(String name) native "File_Delete"; | 164 static final kOpenRequest = 3; |
| 500 static String directory(String name) native "File_Directory"; | 165 static final kFullPathRequest = 4; |
| 501 static String fullPath(String name) native "File_FullPath"; | 166 static final kDirectoryRequest = 5; |
| 502 static int close(int id) native "File_Close"; | 167 static final kCloseRequest = 6; |
| 503 static int readByte(int id) native "File_ReadByte"; | 168 static final kPositionRequest = 7; |
| 504 static int readList(int id, List<int> buffer, int offset, int bytes) | 169 static final kSetPositionRequest = 8; |
| 505 native "File_ReadList"; | 170 static final kTruncateRequest = 9; |
| 506 static int writeByte(int id, int value) native "File_WriteByte"; | 171 static final kLengthRequest = 10; |
| 507 static int writeList(int id, List<int> buffer, int offset, int bytes) { | 172 static final kFlushRequest = 11; |
| 173 static final kReadByteRequest = 12; |
| 174 static final kWriteByteRequest = 13; |
| 175 static final kReadListRequest = 14; |
| 176 static final kWriteListRequest = 15; |
| 177 static final kWriteStringRequest = 16; |
| 178 |
| 179 static List ensureFastAndSerializableBuffer( |
| 180 List buffer, int offset, int bytes) { |
| 508 // When using the Dart C API to access raw data, using a ByteArray is | 181 // When using the Dart C API to access raw data, using a ByteArray is |
| 509 // currently much faster. This function will make a copy of the | 182 // currently much faster. This function will make a copy of the |
| 510 // supplied List to a ByteArray if it isn't already. | 183 // supplied List to a ByteArray if it isn't already. |
| 511 List outBuffer; | 184 List outBuffer; |
| 512 int outOffset = offset; | 185 int outOffset = offset; |
| 513 if (buffer is ByteArray || buffer is ObjectArray) { | 186 if (buffer is ByteArray || buffer is ObjectArray) { |
| 514 outBuffer = buffer; | 187 outBuffer = buffer; |
| 515 } else { | 188 } else { |
| 516 outBuffer = new ByteArray(bytes); | 189 outBuffer = new ByteArray(bytes); |
| 517 outOffset = 0; | 190 outOffset = 0; |
| 518 int j = offset; | 191 int j = offset; |
| 519 for (int i = 0; i < bytes; i++) { | 192 for (int i = 0; i < bytes; i++) { |
| 520 int value = buffer[j]; | 193 int value = buffer[j]; |
| 521 if (value is! int) { | 194 if (value is! int) { |
| 522 throw new FileIOException( | 195 throw new FileIOException( |
| 523 "List element is not an integer at index $j"); | 196 "List element is not an integer at index $j"); |
| 524 } | 197 } |
| 525 outBuffer[i] = value; | 198 outBuffer[i] = value; |
| 526 j++; | 199 j++; |
| 527 } | 200 } |
| 528 } | 201 } |
| 202 return [outBuffer, outOffset]; |
| 203 } |
| 204 |
| 205 static bool exists(String name) native "File_Exists"; |
| 206 static int open(String name, int mode) native "File_Open"; |
| 207 static bool create(String name) native "File_Create"; |
| 208 static bool delete(String name) native "File_Delete"; |
| 209 static String fullPath(String name) native "File_FullPath"; |
| 210 static String directory(String name) native "File_Directory"; |
| 211 static int close(int id) native "File_Close"; |
| 212 static int readByte(int id) native "File_ReadByte"; |
| 213 static int readList(int id, List<int> buffer, int offset, int bytes) |
| 214 native "File_ReadList"; |
| 215 static int writeByte(int id, int value) native "File_WriteByte"; |
| 216 static int writeList(int id, List<int> buffer, int offset, int bytes) { |
| 217 List result = |
| 218 _FileUtils.ensureFastAndSerializableBuffer(buffer, offset, bytes); |
| 219 List outBuffer = result[0]; |
| 220 int outOffset = result[1]; |
| 529 return writeListNative(id, outBuffer, outOffset, bytes); | 221 return writeListNative(id, outBuffer, outOffset, bytes); |
| 530 } | 222 } |
| 531 static int writeListNative(int id, List<int> buffer, int offset, int bytes) | 223 static int writeListNative(int id, List<int> buffer, int offset, int bytes) |
| 532 native "File_WriteList"; | 224 native "File_WriteList"; |
| 533 static int writeString(int id, String string) native "File_WriteString"; | 225 static int writeString(int id, String string) native "File_WriteString"; |
| 534 static int position(int id) native "File_Position"; | 226 static int position(int id) native "File_Position"; |
| 535 static bool setPosition(int id, int position) native "File_SetPosition"; | 227 static bool setPosition(int id, int position) native "File_SetPosition"; |
| 536 static bool truncate(int id, int length) native "File_Truncate"; | 228 static bool truncate(int id, int length) native "File_Truncate"; |
| 537 static int length(int id) native "File_Length"; | 229 static int length(int id) native "File_Length"; |
| 538 static int flush(int id) native "File_Flush"; | 230 static int flush(int id) native "File_Flush"; |
| 539 static int openStdio(int fd) native "File_OpenStdio"; | 231 static int openStdio(int fd) native "File_OpenStdio"; |
| 232 static SendPort newServicePort() native "File_NewServicePort"; |
| 540 | 233 |
| 541 static int checkedOpen(String name, int mode) { | 234 static int checkedOpen(String name, int mode) { |
| 542 if (name is !String || mode is !int) return 0; | 235 if (name is !String || mode is !int) return 0; |
| 543 return open(name, mode); | 236 return open(name, mode); |
| 544 } | 237 } |
| 545 | 238 |
| 546 static bool checkedCreate(String name) { | 239 static bool checkedCreate(String name) { |
| 547 if (name is !String) return false; | 240 if (name is !String) return false; |
| 548 return create(name); | 241 return create(name); |
| 549 } | 242 } |
| (...skipping 18 matching lines...) Expand all Loading... |
| 568 static int checkedWriteString(int id, String string) { | 261 static int checkedWriteString(int id, String string) { |
| 569 if (string is !String) return -1; | 262 if (string is !String) return -1; |
| 570 return writeString(id, string); | 263 return writeString(id, string); |
| 571 } | 264 } |
| 572 } | 265 } |
| 573 | 266 |
| 574 | 267 |
| 575 // Class for encapsulating the native implementation of files. | 268 // Class for encapsulating the native implementation of files. |
| 576 class _File implements File { | 269 class _File implements File { |
| 577 // Constructor for file. | 270 // Constructor for file. |
| 578 _File(String this._name) | 271 _File(String this._name) : _asyncUsed = false; |
| 579 : _scheduler = new _FileOperationScheduler(), | |
| 580 _asyncUsed = false; | |
| 581 | 272 |
| 582 void exists() { | 273 void exists() { |
| 274 _ensureFileService(); |
| 583 _asyncUsed = true; | 275 _asyncUsed = true; |
| 584 if (_name is !String) { | 276 if (_name is !String) { |
| 585 if (_errorHandler != null) { | 277 if (_errorHandler != null) { |
| 586 _errorHandler('File name is not a string: $_name'); | 278 _errorHandler('File name is not a string: $_name'); |
| 587 } | 279 } |
| 588 return; | 280 return; |
| 589 } | 281 } |
| 590 var operation = new _ExistsOperation(_name); | 282 List request = new List(2); |
| 591 _scheduler.enqueue(operation, (result, ignored) { | 283 request[0] = _FileUtils.kExistsRequest; |
| 592 var handler = | 284 request[1] = _name; |
| 593 (_existsHandler != null) ? _existsHandler : (result) => null; | 285 _fileService.call(request).receive((exists, replyTo) { |
| 594 handler(result); | 286 if (_existsHandler != null) _existsHandler(exists); |
| 595 }); | 287 }); |
| 596 } | 288 } |
| 597 | 289 |
| 598 bool existsSync() { | 290 bool existsSync() { |
| 599 if (_asyncUsed) { | 291 if (_asyncUsed) { |
| 600 throw new FileIOException( | 292 throw new FileIOException( |
| 601 "Mixed use of synchronous and asynchronous API"); | 293 "Mixed use of synchronous and asynchronous API"); |
| 602 } | 294 } |
| 603 if (_name is !String) { | 295 if (_name is !String) { |
| 604 throw new FileIOException('File name is not a string: $_name'); | 296 throw new FileIOException('File name is not a string: $_name'); |
| 605 } | 297 } |
| 606 return _FileUtils.exists(_name); | 298 return _FileUtils.exists(_name); |
| 607 } | 299 } |
| 608 | 300 |
| 609 void create() { | 301 void create() { |
| 302 _ensureFileService(); |
| 610 _asyncUsed = true; | 303 _asyncUsed = true; |
| 611 var handleCreateResult = (created, ignored) { | 304 List request = new List(2); |
| 612 var handler = (_createHandler != null) ? _createHandler : () => null; | 305 request[0] = _FileUtils.kCreateRequest; |
| 306 request[1] = _name; |
| 307 _fileService.call(request).receive((created, replyTo) { |
| 613 if (created) { | 308 if (created) { |
| 614 handler(); | 309 if (_createHandler != null) _createHandler(); |
| 615 } else if (_errorHandler != null) { | 310 } else if (_errorHandler != null) { |
| 616 _errorHandler("Cannot create file: $_name"); | 311 _errorHandler("Cannot create file: $_name"); |
| 617 } | 312 } |
| 618 }; | 313 }); |
| 619 var operation = new _CreateOperation(_name); | |
| 620 _scheduler.enqueue(operation, handleCreateResult); | |
| 621 } | 314 } |
| 622 | 315 |
| 623 void createSync() { | 316 void createSync() { |
| 624 if (_asyncUsed) { | 317 if (_asyncUsed) { |
| 625 throw new FileIOException( | 318 throw new FileIOException( |
| 626 "Mixed use of synchronous and asynchronous API"); | 319 "Mixed use of synchronous and asynchronous API"); |
| 627 } | 320 } |
| 628 bool created = _FileUtils.checkedCreate(_name); | 321 bool created = _FileUtils.checkedCreate(_name); |
| 629 if (!created) { | 322 if (!created) { |
| 630 throw new FileIOException("Cannot create file: $_name"); | 323 throw new FileIOException("Cannot create file: $_name"); |
| 631 } | 324 } |
| 632 } | 325 } |
| 633 | 326 |
| 634 void delete() { | 327 void delete() { |
| 328 _ensureFileService(); |
| 635 _asyncUsed = true; | 329 _asyncUsed = true; |
| 636 var handleDeleteResult = (created, ignored) { | 330 List request = new List(2); |
| 637 var handler = (_deleteHandler != null) ? _deleteHandler : () => null; | 331 request[0] = _FileUtils.kDeleteRequest; |
| 638 if (created) { | 332 request[1] = _name; |
| 639 handler(); | 333 _fileService.call(request).receive((deleted, replyTo) { |
| 334 if (deleted) { |
| 335 if (_deleteHandler != null) _deleteHandler(); |
| 640 } else if (_errorHandler != null) { | 336 } else if (_errorHandler != null) { |
| 641 _errorHandler("Cannot delete file: $_name"); | 337 _errorHandler("Cannot delete file: $_name"); |
| 642 } | 338 } |
| 643 }; | 339 }); |
| 644 var operation = new _DeleteOperation(_name); | |
| 645 _scheduler.enqueue(operation, handleDeleteResult); | |
| 646 } | 340 } |
| 647 | 341 |
| 648 void deleteSync() { | 342 void deleteSync() { |
| 649 if (_asyncUsed) { | 343 if (_asyncUsed) { |
| 650 throw new FileIOException( | 344 throw new FileIOException( |
| 651 "Mixed use of synchronous and asynchronous API"); | 345 "Mixed use of synchronous and asynchronous API"); |
| 652 } | 346 } |
| 653 bool deleted = _FileUtils.checkedDelete(_name); | 347 bool deleted = _FileUtils.checkedDelete(_name); |
| 654 if (!deleted) { | 348 if (!deleted) { |
| 655 throw new FileIOException("Cannot delete file: $_name"); | 349 throw new FileIOException("Cannot delete file: $_name"); |
| 656 } | 350 } |
| 657 } | 351 } |
| 658 | 352 |
| 659 void directory() { | 353 void directory() { |
| 354 _ensureFileService(); |
| 660 _asyncUsed = true; | 355 _asyncUsed = true; |
| 661 var handleDirectoryResult = (path, ignored) { | 356 List request = new List(2); |
| 662 var handler = | 357 request[0] = _FileUtils.kDirectoryRequest; |
| 663 (_directoryHandler != null) ? _directoryHandler : (s) => null; | 358 request[1] = _name; |
| 359 _fileService.call(request).receive((path, replyTo) { |
| 664 if (path != null) { | 360 if (path != null) { |
| 665 handler(new Directory(path)); | 361 if (_directoryHandler != null) _directoryHandler(new Directory(path)); |
| 666 } else if (_errorHandler != null) { | 362 } else if (_errorHandler != null) { |
| 667 _errorHandler("Cannot get containing directory for: ${_name}"); | 363 _errorHandler("Cannot get directory for: ${_name}"); |
| 668 } | 364 } |
| 669 }; | 365 }); |
| 670 var operation = new _DirectoryOperation(_name); | |
| 671 _scheduler.enqueue(operation, handleDirectoryResult); | |
| 672 } | 366 } |
| 673 | 367 |
| 674 void directorySync() { | 368 void directorySync() { |
| 675 if (_asyncUsed) { | 369 if (_asyncUsed) { |
| 676 throw new FileIOException( | 370 throw new FileIOException( |
| 677 "Mixed use of synchronous and asynchronous API"); | 371 "Mixed use of synchronous and asynchronous API"); |
| 678 } | 372 } |
| 679 if (!existsSync()) { | 373 if (!existsSync()) { |
| 680 throw new FileIOException("Cannot get directory for: $_name"); | 374 throw new FileIOException("Cannot get directory for: $_name"); |
| 681 } | 375 } |
| 682 return new Directory(_FileUtils.directory(_name)); | 376 return new Directory(_FileUtils.directory(_name)); |
| 683 } | 377 } |
| 684 | 378 |
| 685 void open([FileMode mode = FileMode.READ]) { | 379 void open([FileMode mode = FileMode.READ]) { |
| 380 _ensureFileService(); |
| 686 _asyncUsed = true; | 381 _asyncUsed = true; |
| 687 if (mode != FileMode.READ && | 382 if (mode != FileMode.READ && |
| 688 mode != FileMode.WRITE && | 383 mode != FileMode.WRITE && |
| 689 mode != FileMode.APPEND) { | 384 mode != FileMode.APPEND) { |
| 690 if (_errorHandler != null) { | 385 if (_errorHandler != null) { |
| 691 _errorHandler("Unknown file mode. Use FileMode.READ, FileMode.WRITE " + | 386 _errorHandler("Unknown file mode. Use FileMode.READ, FileMode.WRITE " + |
| 692 "or FileMode.APPEND."); | 387 "or FileMode.APPEND."); |
| 693 return; | 388 return; |
| 694 } | 389 } |
| 695 } | 390 } |
| 696 var handleOpenResult = (id, ignored) { | 391 List request = new List(3); |
| 697 // If no open handler is present, close the file immediately to | 392 request[0] = _FileUtils.kOpenRequest; |
| 698 // avoid leaking an open file descriptor. | 393 request[1] = _name; |
| 394 request[2] = mode._mode; // Direct int value for serialization. |
| 395 _fileService.call(request).receive((id, replyTo) { |
| 699 var handler = _openHandler; | 396 var handler = _openHandler; |
| 700 if (handler === null) { | 397 if (handler === null) { |
| 398 // If no open handler is present, close the file immediately to |
| 399 // avoid leaking an open file descriptor. |
| 701 handler = (file) => file.close(); | 400 handler = (file) => file.close(); |
| 702 } | 401 } |
| 703 if (id != 0) { | 402 if (id != 0) { |
| 704 var randomAccessFile = new _RandomAccessFile(id, _name); | 403 var randomAccessFile = new _RandomAccessFile(id, _name); |
| 705 handler(randomAccessFile); | 404 handler(randomAccessFile); |
| 706 } else if (_errorHandler != null) { | 405 } else if (_errorHandler != null) { |
| 707 _errorHandler("Cannot open file: $_name"); | 406 _errorHandler("Cannot open file: $_name"); |
| 708 } | 407 } |
| 709 }; | 408 }); |
| 710 var operation = new _OpenOperation(_name, mode._mode); | |
| 711 _scheduler.enqueue(operation, handleOpenResult); | |
| 712 } | 409 } |
| 713 | 410 |
| 714 RandomAccessFile openSync([FileMode mode = FileMode.READ]) { | 411 RandomAccessFile openSync([FileMode mode = FileMode.READ]) { |
| 715 if (_asyncUsed) { | 412 if (_asyncUsed) { |
| 716 throw new FileIOException( | 413 throw new FileIOException( |
| 717 "Mixed use of synchronous and asynchronous API"); | 414 "Mixed use of synchronous and asynchronous API"); |
| 718 } | 415 } |
| 719 if (mode != FileMode.READ && | 416 if (mode != FileMode.READ && |
| 720 mode != FileMode.WRITE && | 417 mode != FileMode.WRITE && |
| 721 mode != FileMode.APPEND) { | 418 mode != FileMode.APPEND) { |
| 722 throw new FileIOException("Unknown file mode. Use FileMode.READ, " + | 419 throw new FileIOException("Unknown file mode. Use FileMode.READ, " + |
| 723 "FileMode.WRITE or FileMode.APPEND."); | 420 "FileMode.WRITE or FileMode.APPEND."); |
| 724 } | 421 } |
| 725 var id = _FileUtils.checkedOpen(_name, mode._mode); | 422 var id = _FileUtils.checkedOpen(_name, mode._mode); |
| 726 if (id == 0) { | 423 if (id == 0) { |
| 727 throw new FileIOException("Cannot open file: $_name"); | 424 throw new FileIOException("Cannot open file: $_name"); |
| 728 } | 425 } |
| 729 return new _RandomAccessFile(id, _name); | 426 return new _RandomAccessFile(id, _name); |
| 730 } | 427 } |
| 731 | 428 |
| 732 static RandomAccessFile _openStdioSync(int fd) { | 429 static RandomAccessFile _openStdioSync(int fd) { |
| 733 var id = _FileUtils.openStdio(fd); | 430 var id = _FileUtils.openStdio(fd); |
| 734 if (id == 0) { | 431 if (id == 0) { |
| 735 throw new FileIOException("Cannot open stdio file for: $fd"); | 432 throw new FileIOException("Cannot open stdio file for: $fd"); |
| 736 } | 433 } |
| 737 return new _RandomAccessFile(id, ""); | 434 return new _RandomAccessFile(id, ""); |
| 738 } | 435 } |
| 739 | 436 |
| 740 void fullPath() { | 437 void fullPath() { |
| 438 _ensureFileService(); |
| 741 _asyncUsed = true; | 439 _asyncUsed = true; |
| 742 var handleFullPathResult = (result, ignored) { | 440 List request = new List(2); |
| 743 var handler = _fullPathHandler; | 441 request[0] = _FileUtils.kFullPathRequest; |
| 744 if (handler == null) handler = (path) => null; | 442 request[1] = _name; |
| 443 _fileService.call(request).receive((result, replyTo) { |
| 745 if (result != null) { | 444 if (result != null) { |
| 746 handler(result); | 445 if (_fullPathHandler != null) _fullPathHandler(result); |
| 747 } else if (_errorHandler != null) { | 446 } else if (_errorHandler != null) { |
| 748 _errorHandler("fullPath failed"); | 447 _errorHandler("fullPath failed"); |
| 749 } | 448 } |
| 750 }; | 449 }); |
| 751 var operation = new _FullPathOperation(_name); | |
| 752 _scheduler.enqueue(operation, handleFullPathResult); | |
| 753 } | 450 } |
| 754 | 451 |
| 755 String fullPathSync() { | 452 String fullPathSync() { |
| 756 if (_asyncUsed) { | 453 if (_asyncUsed) { |
| 757 throw new FileIOException( | 454 throw new FileIOException( |
| 758 "Mixed use of synchronous and asynchronous API"); | 455 "Mixed use of synchronous and asynchronous API"); |
| 759 } | 456 } |
| 760 String result = _FileUtils.checkedFullPath(_name); | 457 String result = _FileUtils.checkedFullPath(_name); |
| 761 if (result == null) { | 458 if (result == null) { |
| 762 throw new FileIOException("fullPath failed"); | 459 throw new FileIOException("fullPath failed"); |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 858 } | 555 } |
| 859 | 556 |
| 860 void set fullPathHandler(void handler(String)) { | 557 void set fullPathHandler(void handler(String)) { |
| 861 _fullPathHandler = handler; | 558 _fullPathHandler = handler; |
| 862 } | 559 } |
| 863 | 560 |
| 864 void set errorHandler(void handler(String error)) { | 561 void set errorHandler(void handler(String error)) { |
| 865 _errorHandler = handler; | 562 _errorHandler = handler; |
| 866 } | 563 } |
| 867 | 564 |
| 565 void _ensureFileService() { |
| 566 if (_fileService == null) { |
| 567 _fileService = _FileUtils.newServicePort(); |
| 568 } |
| 569 } |
| 570 |
| 868 String _name; | 571 String _name; |
| 869 bool _asyncUsed; | 572 bool _asyncUsed; |
| 870 | 573 |
| 871 _FileOperationScheduler _scheduler; | 574 SendPort _fileService; |
| 872 | 575 |
| 873 Function _existsHandler; | 576 Function _existsHandler; |
| 874 Function _createHandler; | 577 Function _createHandler; |
| 875 Function _deleteHandler; | 578 Function _deleteHandler; |
| 876 Function _directoryHandler; | 579 Function _directoryHandler; |
| 877 Function _openHandler; | 580 Function _openHandler; |
| 878 Function _inputStreamHandler; | 581 Function _inputStreamHandler; |
| 879 Function _outputStreamHandler; | 582 Function _outputStreamHandler; |
| 880 Function _fullPathHandler; | 583 Function _fullPathHandler; |
| 881 Function _errorHandler; | 584 Function _errorHandler; |
| 882 } | 585 } |
| 883 | 586 |
| 884 | 587 |
| 885 class _RandomAccessFile implements RandomAccessFile { | 588 class _RandomAccessFile implements RandomAccessFile { |
| 886 _RandomAccessFile(int this._id, String this._name) | 589 _RandomAccessFile(int this._id, String this._name) : _asyncUsed = false; |
| 887 : _scheduler = new _FileOperationScheduler(), | |
| 888 _asyncUsed = false; | |
| 889 | 590 |
| 890 void close() { | 591 void close() { |
| 592 if (_id == 0) return; |
| 593 _ensureFileService(); |
| 891 _asyncUsed = true; | 594 _asyncUsed = true; |
| 892 var handleCloseResult = (result, ignored) { | 595 List request = new List(2); |
| 893 var handler = (_closeHandler != null) ? _closeHandler : () => null; | 596 request[0] = _FileUtils.kCloseRequest; |
| 597 request[1] = _id; |
| 598 // Set the id_ to 0 (NULL) to ensure the no more async requests |
| 599 // can be issues for this file. |
| 600 _id = 0; |
| 601 _fileService.call(request).receive((result, replyTo) { |
| 894 if (result != -1) { | 602 if (result != -1) { |
| 895 _id = result; | 603 _id = result; |
| 896 handler(); | 604 if (_closeHandler != null) _closeHandler(); |
| 897 } else if (_errorHandler != null) { | 605 } else if (_errorHandler != null) { |
| 898 _errorHandler("Cannot close file: $_name"); | 606 _errorHandler("Cannot close file: $_name"); |
| 899 } | 607 } |
| 900 }; | 608 }); |
| 901 var operation = new _CloseOperation(_id); | |
| 902 _scheduler.enqueue(operation, handleCloseResult); | |
| 903 } | 609 } |
| 904 | 610 |
| 905 void closeSync() { | 611 void closeSync() { |
| 906 if (_asyncUsed) { | 612 if (_asyncUsed) { |
| 907 throw new FileIOException( | 613 throw new FileIOException( |
| 908 "Mixed use of synchronous and asynchronous API"); | 614 "Mixed use of synchronous and asynchronous API"); |
| 909 } | 615 } |
| 910 var id = _FileUtils.close(_id); | 616 var id = _FileUtils.close(_id); |
| 911 if (id == -1) { | 617 if (id == -1) { |
| 912 throw new FileIOException("Cannot close file: $_name"); | 618 throw new FileIOException("Cannot close file: $_name"); |
| 913 } | 619 } |
| 914 _id = id; | 620 _id = id; |
| 915 } | 621 } |
| 916 | 622 |
| 917 void readByte() { | 623 void readByte() { |
| 624 _ensureFileService(); |
| 918 _asyncUsed = true; | 625 _asyncUsed = true; |
| 919 var handleReadByteResult = (result, ignored) { | 626 List request = new List(2); |
| 920 var handler = | 627 request[0] = _FileUtils.kReadByteRequest; |
| 921 (_readByteHandler != null) ? _readByteHandler : (byte) => null; | 628 request[1] = _id; |
| 629 _fileService.call(request).receive((result, replyTo) { |
| 922 if (result != -1) { | 630 if (result != -1) { |
| 923 handler(result); | 631 if (_readByteHandler != null) _readByteHandler(result); |
| 924 } else if (_errorHandler != null) { | 632 } else if (_errorHandler != null) { |
| 925 _errorHandler("readByte failed"); | 633 _errorHandler("readByte failed"); |
| 926 } | 634 } |
| 927 }; | 635 }); |
| 928 var operation = new _ReadByteOperation(_id); | |
| 929 _scheduler.enqueue(operation, handleReadByteResult); | |
| 930 } | 636 } |
| 931 | 637 |
| 932 int readByteSync() { | 638 int readByteSync() { |
| 933 if (_asyncUsed) { | 639 if (_asyncUsed) { |
| 934 throw new FileIOException( | 640 throw new FileIOException( |
| 935 "Mixed use of synchronous and asynchronous API"); | 641 "Mixed use of synchronous and asynchronous API"); |
| 936 } | 642 } |
| 937 int result = _FileUtils.readByte(_id); | 643 int result = _FileUtils.readByte(_id); |
| 938 if (result == -1) { | 644 if (result == -1) { |
| 939 throw new FileIOException("readByte failed"); | 645 throw new FileIOException("readByte failed"); |
| 940 } | 646 } |
| 941 return result; | 647 return result; |
| 942 } | 648 } |
| 943 | 649 |
| 944 void readList(List<int> buffer, int offset, int bytes) { | 650 void readList(List<int> buffer, int offset, int bytes) { |
| 651 _ensureFileService(); |
| 945 _asyncUsed = true; | 652 _asyncUsed = true; |
| 946 if (buffer is !List || offset is !int || bytes is !int) { | 653 if (buffer is !List || offset is !int || bytes is !int) { |
| 947 if (_errorHandler != null) { | 654 if (_errorHandler != null) { |
| 948 _errorHandler("Invalid arguments to readList"); | 655 _errorHandler("Invalid arguments to readList"); |
| 949 } | 656 } |
| 950 return; | 657 return; |
| 951 }; | 658 }; |
| 952 var handleReadListResult = (result, ignored) { | 659 List request = new List(3); |
| 953 var handler = | 660 request[0] = _FileUtils.kReadListRequest; |
| 954 (_readListHandler != null) ? _readListHandler : (result) => null; | 661 request[1] = _id; |
| 955 if (result is _ReadListResult && result.read != -1) { | 662 request[2] = bytes; |
| 956 var read = result.read; | 663 _fileService.call(request).receive((result, replyTo) { |
| 957 buffer.setRange(offset, read, result.buffer); | 664 if (result is List && result.length == 2 && result[0] != -1) { |
| 958 handler(read); | 665 var read = result[0]; |
| 666 var data = result[1]; |
| 667 buffer.setRange(offset, read, data); |
| 668 if (_readListHandler != null) _readListHandler(read); |
| 959 return; | 669 return; |
| 960 } | 670 } else if (_errorHandler != null) { |
| 961 if (_errorHandler != null) { | |
| 962 _errorHandler(result is String ? result : "readList failed"); | 671 _errorHandler(result is String ? result : "readList failed"); |
| 963 } | 672 } |
| 964 }; | 673 }); |
| 965 var operation = new _ReadListOperation(_id, buffer.length, offset, bytes); | |
| 966 _scheduler.enqueue(operation, handleReadListResult); | |
| 967 } | 674 } |
| 968 | 675 |
| 969 int readListSync(List<int> buffer, int offset, int bytes) { | 676 int readListSync(List<int> buffer, int offset, int bytes) { |
| 970 if (_asyncUsed) { | 677 if (_asyncUsed) { |
| 971 throw new FileIOException( | 678 throw new FileIOException( |
| 972 "Mixed use of synchronous and asynchronous API"); | 679 "Mixed use of synchronous and asynchronous API"); |
| 973 } | 680 } |
| 974 if (buffer is !List || offset is !int || bytes is !int) { | 681 if (buffer is !List || offset is !int || bytes is !int) { |
| 975 throw new FileIOException("Invalid arguments to readList"); | 682 throw new FileIOException("Invalid arguments to readList"); |
| 976 } | 683 } |
| 977 if (bytes == 0) return 0; | 684 if (bytes == 0) return 0; |
| 978 int index = | 685 int index = |
| 979 _FileUtils.checkReadWriteListArguments(buffer.length, offset, bytes); | 686 _FileUtils.checkReadWriteListArguments(buffer.length, offset, bytes); |
| 980 if (index != 0) { | 687 if (index != 0) { |
| 981 throw new IndexOutOfRangeException(index); | 688 throw new IndexOutOfRangeException(index); |
| 982 } | 689 } |
| 983 int result = _FileUtils.readList(_id, buffer, offset, bytes); | 690 int result = _FileUtils.readList(_id, buffer, offset, bytes); |
| 984 if (result == -1) { | 691 if (result == -1) { |
| 985 throw new FileIOException("readList failed"); | 692 throw new FileIOException("readList failed"); |
| 986 } | 693 } |
| 987 return result; | 694 return result; |
| 988 } | 695 } |
| 989 | 696 |
| 990 void _checkPendingWrites() { | |
| 991 if (_scheduler.noPendingWrite() && _noPendingWriteHandler != null) { | |
| 992 _noPendingWriteHandler(); | |
| 993 } | |
| 994 } | |
| 995 | |
| 996 void writeByte(int value) { | 697 void writeByte(int value) { |
| 698 _ensureFileService(); |
| 997 _asyncUsed = true; | 699 _asyncUsed = true; |
| 998 if (value is !int) { | 700 if (value is !int) { |
| 999 if (_errorHandler != null) { | 701 if (_errorHandler != null) { |
| 1000 _errorHandler("Invalid argument to writeByte"); | 702 _errorHandler("Invalid argument to writeByte"); |
| 1001 } | 703 } |
| 1002 return; | 704 return; |
| 1003 } | 705 } |
| 1004 var handleReadByteResult = (result, ignored) { | 706 List request = new List(3); |
| 1005 if (result == -1 &&_errorHandler != null) { | 707 request[0] = _FileUtils.kWriteByteRequest; |
| 708 request[1] = _id; |
| 709 request[2] = value; |
| 710 _writeEnqueued(); |
| 711 _fileService.call(request).receive((result, replyTo) { |
| 712 _writeCompleted(); |
| 713 if (result == -1 && _errorHandler !== null) { |
| 1006 _errorHandler("writeByte failed"); | 714 _errorHandler("writeByte failed"); |
| 1007 return; | |
| 1008 } | 715 } |
| 1009 _checkPendingWrites(); | 716 }); |
| 1010 }; | |
| 1011 var operation = new _WriteByteOperation(_id, value); | |
| 1012 _scheduler.enqueue(operation, handleReadByteResult); | |
| 1013 } | 717 } |
| 1014 | 718 |
| 1015 int writeByteSync(int value) { | 719 int writeByteSync(int value) { |
| 1016 if (_asyncUsed) { | 720 if (_asyncUsed) { |
| 1017 throw new FileIOException( | 721 throw new FileIOException( |
| 1018 "Mixed use of synchronous and asynchronous API"); | 722 "Mixed use of synchronous and asynchronous API"); |
| 1019 } | 723 } |
| 1020 if (value is !int) { | 724 if (value is !int) { |
| 1021 throw new FileIOException("Invalid argument to writeByte"); | 725 throw new FileIOException("Invalid argument to writeByte"); |
| 1022 } | 726 } |
| 1023 int result = _FileUtils.writeByte(_id, value); | 727 int result = _FileUtils.writeByte(_id, value); |
| 1024 if (result == -1) { | 728 if (result == -1) { |
| 1025 throw new FileIOException("writeByte failed"); | 729 throw new FileIOException("writeByte failed"); |
| 1026 } | 730 } |
| 1027 return result; | 731 return result; |
| 1028 } | 732 } |
| 1029 | 733 |
| 1030 void writeList(List<int> buffer, int offset, int bytes) { | 734 void writeList(List<int> buffer, int offset, int bytes) { |
| 735 _ensureFileService(); |
| 1031 _asyncUsed = true; | 736 _asyncUsed = true; |
| 1032 if (buffer is !List || offset is !int || bytes is !int) { | 737 if (buffer is !List || offset is !int || bytes is !int) { |
| 1033 if (_errorHandler != null) { | 738 if (_errorHandler != null) { |
| 1034 _errorHandler("Invalid arguments to writeList"); | 739 _errorHandler("Invalid arguments to writeList"); |
| 1035 } | 740 } |
| 1036 return; | 741 return; |
| 1037 } | 742 } |
| 1038 var handleWriteListResult = (result, ignored) { | 743 |
| 1039 if (result is !String && result != -1) { | 744 List result = |
| 1040 if (result < bytes) { | 745 _FileUtils.ensureFastAndSerializableBuffer(buffer, offset, bytes); |
| 1041 writeList(buffer, offset + result, bytes - result); | 746 List outBuffer = result[0]; |
| 1042 } else { | 747 int outOffset = result[1]; |
| 1043 _checkPendingWrites(); | 748 |
| 1044 } | 749 List request = new List(5); |
| 1045 return; | 750 request[0] = _FileUtils.kWriteListRequest; |
| 751 request[1] = _id; |
| 752 request[2] = outBuffer; |
| 753 request[3] = outOffset; |
| 754 request[4] = bytes; |
| 755 _writeEnqueued(); |
| 756 _fileService.call(request).receive((result, replyTo) { |
| 757 _writeCompleted(); |
| 758 if (result == -1 && _errorHandler !== null) { |
| 759 _errorHandler("writeList failed"); |
| 1046 } | 760 } |
| 1047 if (_errorHandler != null) { | 761 }); |
| 1048 _errorHandler(result is String ? result : "writeList failed"); | |
| 1049 } | |
| 1050 }; | |
| 1051 var operation = new _WriteListOperation(_id, buffer, offset, bytes); | |
| 1052 _scheduler.enqueue(operation, handleWriteListResult); | |
| 1053 } | 762 } |
| 1054 | 763 |
| 1055 int writeListSync(List<int> buffer, int offset, int bytes) { | 764 int writeListSync(List<int> buffer, int offset, int bytes) { |
| 1056 if (_asyncUsed) { | 765 if (_asyncUsed) { |
| 1057 throw new FileIOException( | 766 throw new FileIOException( |
| 1058 "Mixed use of synchronous and asynchronous API"); | 767 "Mixed use of synchronous and asynchronous API"); |
| 1059 } | 768 } |
| 1060 if (buffer is !List || offset is !int || bytes is !int) { | 769 if (buffer is !List || offset is !int || bytes is !int) { |
| 1061 throw new FileIOException("Invalid arguments to writeList"); | 770 throw new FileIOException("Invalid arguments to writeList"); |
| 1062 } | 771 } |
| 1063 if (bytes == 0) return 0; | 772 if (bytes == 0) return 0; |
| 1064 int index = | 773 int index = |
| 1065 _FileUtils.checkReadWriteListArguments(buffer.length, offset, bytes); | 774 _FileUtils.checkReadWriteListArguments(buffer.length, offset, bytes); |
| 1066 if (index != 0) { | 775 if (index != 0) { |
| 1067 throw new IndexOutOfRangeException(index); | 776 throw new IndexOutOfRangeException(index); |
| 1068 } | 777 } |
| 1069 int result = _FileUtils.writeList(_id, buffer, offset, bytes); | 778 int result = _FileUtils.writeList(_id, buffer, offset, bytes); |
| 1070 if (result == -1) { | 779 if (result == -1) { |
| 1071 throw new FileIOException("writeList failed"); | 780 throw new FileIOException("writeList failed"); |
| 1072 } | 781 } |
| 1073 return result; | 782 return result; |
| 1074 } | 783 } |
| 1075 | 784 |
| 1076 void writeString(String string) { | 785 void writeString(String string) { |
| 786 _ensureFileService(); |
| 1077 _asyncUsed = true; | 787 _asyncUsed = true; |
| 1078 var handleWriteStringResult = (result, ignored) { | 788 List request = new List(3); |
| 1079 if (result == -1 &&_errorHandler != null) { | 789 request[0] = _FileUtils.kWriteStringRequest; |
| 790 request[1] = _id; |
| 791 request[2] = string; |
| 792 _writeEnqueued(); |
| 793 _fileService.call(request).receive((result, replyTo) { |
| 794 _writeCompleted(); |
| 795 if (result == -1 && _errorHandler !== null) { |
| 1080 _errorHandler("writeString failed"); | 796 _errorHandler("writeString failed"); |
| 1081 return; | |
| 1082 } | 797 } |
| 1083 if (result < string.length) { | 798 }); |
| 1084 writeString(string.substring(result)); | |
| 1085 } else { | |
| 1086 _checkPendingWrites(); | |
| 1087 } | |
| 1088 }; | |
| 1089 var operation = new _WriteStringOperation(_id, string); | |
| 1090 _scheduler.enqueue(operation, handleWriteStringResult); | |
| 1091 } | 799 } |
| 1092 | 800 |
| 1093 int writeStringSync(String string) { | 801 int writeStringSync(String string) { |
| 1094 if (_asyncUsed) { | 802 if (_asyncUsed) { |
| 1095 throw new FileIOException( | 803 throw new FileIOException( |
| 1096 "Mixed use of synchronous and asynchronous API"); | 804 "Mixed use of synchronous and asynchronous API"); |
| 1097 } | 805 } |
| 1098 int result = _FileUtils.checkedWriteString(_id, string); | 806 int result = _FileUtils.checkedWriteString(_id, string); |
| 1099 if (result == -1) { | 807 if (result == -1) { |
| 1100 throw new FileIOException("writeString failed"); | 808 throw new FileIOException("writeString failed"); |
| 1101 } | 809 } |
| 1102 return result; | 810 return result; |
| 1103 } | 811 } |
| 1104 | 812 |
| 1105 void position() { | 813 void position() { |
| 814 _ensureFileService(); |
| 1106 _asyncUsed = true; | 815 _asyncUsed = true; |
| 1107 var handlePositionResult = (result, ignored) { | 816 List request = new List(2); |
| 1108 var handler = | 817 request[0] = _FileUtils.kPositionRequest; |
| 1109 (_positionHandler != null) ? _positionHandler : (pos) => null; | 818 request[1] = _id; |
| 1110 if (result == -1 && _errorHandler != null) { | 819 _fileService.call(request).receive((result, replyTo) { |
| 820 if (result != -1) { |
| 821 if (_positionHandler != null) _positionHandler(result); |
| 822 } else if (_errorHandler != null) { |
| 1111 _errorHandler("position failed"); | 823 _errorHandler("position failed"); |
| 1112 return; | |
| 1113 } | 824 } |
| 1114 handler(result); | 825 }); |
| 1115 }; | |
| 1116 var operation = new _PositionOperation(_id); | |
| 1117 _scheduler.enqueue(operation, handlePositionResult); | |
| 1118 } | 826 } |
| 1119 | 827 |
| 1120 int positionSync() { | 828 int positionSync() { |
| 1121 if (_asyncUsed) { | 829 if (_asyncUsed) { |
| 1122 throw new FileIOException( | 830 throw new FileIOException( |
| 1123 "Mixed use of synchronous and asynchronous API"); | 831 "Mixed use of synchronous and asynchronous API"); |
| 1124 } | 832 } |
| 1125 int result = _FileUtils.position(_id); | 833 int result = _FileUtils.position(_id); |
| 1126 if (result == -1) { | 834 if (result == -1) { |
| 1127 throw new FileIOException("position failed"); | 835 throw new FileIOException("position failed"); |
| 1128 } | 836 } |
| 1129 return result; | 837 return result; |
| 1130 } | 838 } |
| 1131 | 839 |
| 1132 void setPosition(int position) { | 840 void setPosition(int position) { |
| 841 _ensureFileService(); |
| 1133 _asyncUsed = true; | 842 _asyncUsed = true; |
| 1134 var handleSetPositionResult = (result, ignored) { | 843 List request = new List(3); |
| 1135 var handler = | 844 request[0] = _FileUtils.kSetPositionRequest; |
| 1136 (_setPositionHandler != null) ? _setPositionHandler : () => null; | 845 request[1] = _id; |
| 1137 if (result == false && _errorHandler != null) { | 846 request[2] = position; |
| 847 _fileService.call(request).receive((result, replyTo) { |
| 848 if (result) { |
| 849 if (_setPositionHandler != null) _setPositionHandler(); |
| 850 } else if (_errorHandler != null) { |
| 1138 _errorHandler("setPosition failed"); | 851 _errorHandler("setPosition failed"); |
| 1139 return; | |
| 1140 } | 852 } |
| 1141 handler(); | 853 }); |
| 1142 }; | |
| 1143 var operation = new _SetPositionOperation(_id, position); | |
| 1144 _scheduler.enqueue(operation, handleSetPositionResult); | |
| 1145 } | 854 } |
| 1146 | 855 |
| 1147 void setPositionSync(int position) { | 856 void setPositionSync(int position) { |
| 857 _ensureFileService(); |
| 1148 if (_asyncUsed) { | 858 if (_asyncUsed) { |
| 1149 throw new FileIOException( | 859 throw new FileIOException( |
| 1150 "Mixed use of synchronous and asynchronous API"); | 860 "Mixed use of synchronous and asynchronous API"); |
| 1151 } | 861 } |
| 1152 bool result = _FileUtils.setPosition(_id, position); | 862 bool result = _FileUtils.setPosition(_id, position); |
| 1153 if (result == false) { | 863 if (result == false) { |
| 1154 throw new FileIOException("setPosition failed"); | 864 throw new FileIOException("setPosition failed"); |
| 1155 } | 865 } |
| 1156 } | 866 } |
| 1157 | 867 |
| 1158 void truncate(int length) { | 868 void truncate(int length) { |
| 869 _ensureFileService(); |
| 1159 _asyncUsed = true; | 870 _asyncUsed = true; |
| 1160 var handleTruncateResult = (result, ignored) { | 871 List request = new List(3); |
| 1161 var handler = (_truncateHandler != null) ? _truncateHandler : () => null; | 872 request[0] = _FileUtils.kTruncateRequest; |
| 1162 if (result == false && _errorHandler != null) { | 873 request[1] = _id; |
| 874 request[2] = length; |
| 875 _fileService.call(request).receive((result, replyTo) { |
| 876 if (result) { |
| 877 if (_truncateHandler != null) _truncateHandler(); |
| 878 } else if (_errorHandler != null) { |
| 1163 _errorHandler("truncate failed"); | 879 _errorHandler("truncate failed"); |
| 1164 return; | |
| 1165 } | 880 } |
| 1166 handler(); | 881 }); |
| 1167 }; | |
| 1168 var operation = new _TruncateOperation(_id, length); | |
| 1169 _scheduler.enqueue(operation, handleTruncateResult); | |
| 1170 } | 882 } |
| 1171 | 883 |
| 1172 void truncateSync(int length) { | 884 void truncateSync(int length) { |
| 1173 if (_asyncUsed) { | 885 if (_asyncUsed) { |
| 1174 throw new FileIOException( | 886 throw new FileIOException( |
| 1175 "Mixed use of synchronous and asynchronous API"); | 887 "Mixed use of synchronous and asynchronous API"); |
| 1176 } | 888 } |
| 1177 bool result = _FileUtils.truncate(_id, length); | 889 bool result = _FileUtils.truncate(_id, length); |
| 1178 if (result == false) { | 890 if (result == false) { |
| 1179 throw new FileIOException("truncate failed"); | 891 throw new FileIOException("truncate failed"); |
| 1180 } | 892 } |
| 1181 } | 893 } |
| 1182 | 894 |
| 1183 void length() { | 895 void length() { |
| 896 _ensureFileService(); |
| 1184 _asyncUsed = true; | 897 _asyncUsed = true; |
| 1185 var handleLengthResult = (result, ignored) { | 898 List request = new List(2); |
| 1186 var handler = (_lengthHandler != null) ? _lengthHandler : (pos) => null; | 899 request[0] = _FileUtils.kLengthRequest; |
| 1187 if (result == -1 && _errorHandler != null) { | 900 request[1] = _id; |
| 901 _fileService.call(request).receive((result, replyTo) { |
| 902 if (result != -1) { |
| 903 if (_lengthHandler != null) _lengthHandler(result); |
| 904 } else if (_errorHandler != null) { |
| 1188 _errorHandler("length failed"); | 905 _errorHandler("length failed"); |
| 1189 return; | |
| 1190 } | 906 } |
| 1191 handler(result); | 907 }); |
| 1192 }; | |
| 1193 var operation = new _LengthOperation(_id); | |
| 1194 _scheduler.enqueue(operation, handleLengthResult); | |
| 1195 } | 908 } |
| 1196 | 909 |
| 1197 int lengthSync() { | 910 int lengthSync() { |
| 1198 if (_asyncUsed) { | 911 if (_asyncUsed) { |
| 1199 throw new FileIOException( | 912 throw new FileIOException( |
| 1200 "Mixed use of synchronous and asynchronous API"); | 913 "Mixed use of synchronous and asynchronous API"); |
| 1201 } | 914 } |
| 1202 int result = _FileUtils.length(_id); | 915 int result = _FileUtils.length(_id); |
| 1203 if (result == -1) { | 916 if (result == -1) { |
| 1204 throw new FileIOException("length failed"); | 917 throw new FileIOException("length failed"); |
| 1205 } | 918 } |
| 1206 return result; | 919 return result; |
| 1207 } | 920 } |
| 1208 | 921 |
| 1209 void flush() { | 922 void flush() { |
| 923 _ensureFileService(); |
| 1210 _asyncUsed = true; | 924 _asyncUsed = true; |
| 1211 var handleFlushResult = (result, ignored) { | 925 List request = new List(2); |
| 1212 var handler = (_flushHandler != null) ? _flushHandler : (pos) => null; | 926 request[0] = _FileUtils.kFlushRequest; |
| 1213 if (result == -1 && _errorHandler != null) { | 927 request[1] = _id; |
| 928 _fileService.call(request).receive((result, replyTo) { |
| 929 if (result != -1) { |
| 930 if (_flushHandler != null) _flushHandler(); |
| 931 } else if (_errorHandler != null) { |
| 1214 _errorHandler("flush failed"); | 932 _errorHandler("flush failed"); |
| 1215 return; | |
| 1216 } | 933 } |
| 1217 handler(); | 934 }); |
| 1218 }; | |
| 1219 var operation = new _FlushOperation(_id); | |
| 1220 _scheduler.enqueue(operation, handleFlushResult); | |
| 1221 } | 935 } |
| 1222 | 936 |
| 1223 void flushSync() { | 937 void flushSync() { |
| 1224 if (_asyncUsed) { | 938 if (_asyncUsed) { |
| 1225 throw new FileIOException( | 939 throw new FileIOException( |
| 1226 "Mixed use of synchronous and asynchronous API"); | 940 "Mixed use of synchronous and asynchronous API"); |
| 1227 } | 941 } |
| 1228 int result = _FileUtils.flush(_id); | 942 int result = _FileUtils.flush(_id); |
| 1229 if (result == -1) { | 943 if (result == -1) { |
| 1230 throw new FileIOException("flush failed"); | 944 throw new FileIOException("flush failed"); |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1266 } | 980 } |
| 1267 | 981 |
| 1268 void set lengthHandler(void handler(int length)) { | 982 void set lengthHandler(void handler(int length)) { |
| 1269 _lengthHandler = handler; | 983 _lengthHandler = handler; |
| 1270 } | 984 } |
| 1271 | 985 |
| 1272 void set flushHandler(void handler()) { | 986 void set flushHandler(void handler()) { |
| 1273 _flushHandler = handler; | 987 _flushHandler = handler; |
| 1274 } | 988 } |
| 1275 | 989 |
| 990 void _ensureFileService() { |
| 991 if (_fileService == null) { |
| 992 _fileService = _FileUtils.newServicePort(); |
| 993 } |
| 994 } |
| 995 |
| 996 void _writeEnqueued() => _pendingWrites++; |
| 997 |
| 998 void _writeCompleted() { |
| 999 _pendingWrites--; |
| 1000 if (_pendingWrites == 0 && _noPendingWriteHandler != null) { |
| 1001 _noPendingWriteHandler(); |
| 1002 } |
| 1003 } |
| 1004 |
| 1005 |
| 1276 String _name; | 1006 String _name; |
| 1277 int _id; | 1007 int _id; |
| 1278 bool _asyncUsed; | 1008 bool _asyncUsed; |
| 1009 int _pendingWrites = 0; |
| 1279 | 1010 |
| 1280 _FileOperationScheduler _scheduler; | 1011 SendPort _fileService; |
| 1281 | 1012 |
| 1282 Function _closeHandler; | 1013 Function _closeHandler; |
| 1283 Function _readByteHandler; | 1014 Function _readByteHandler; |
| 1284 Function _readListHandler; | 1015 Function _readListHandler; |
| 1285 Function _noPendingWriteHandler; | 1016 Function _noPendingWriteHandler; |
| 1286 Function _positionHandler; | 1017 Function _positionHandler; |
| 1287 Function _setPositionHandler; | 1018 Function _setPositionHandler; |
| 1288 Function _truncateHandler; | 1019 Function _truncateHandler; |
| 1289 Function _lengthHandler; | 1020 Function _lengthHandler; |
| 1290 Function _flushHandler; | 1021 Function _flushHandler; |
| 1291 Function _errorHandler; | 1022 Function _errorHandler; |
| 1292 } | 1023 } |
| OLD | NEW |