Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(833)

Side by Side Diff: runtime/bin/file_impl.dart

Issue 11337019: Use patching for dart:io. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Address comments Created 8 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 class _FileInputStream extends _BaseDataInputStream implements InputStream {
6 _FileInputStream(String name)
7 : _data = const [],
8 _position = 0,
9 _filePosition = 0 {
10 var file = new File(name);
11 var future = file.open(FileMode.READ);
12 future.handleException((e) {
13 _reportError(e);
14 return true;
15 });
16 future.then(_setupOpenedFile);
17 }
18
19 _FileInputStream.fromStdio(int fd)
20 : _data = const [],
21 _position = 0,
22 _filePosition = 0 {
23 assert(fd == 0);
24 _setupOpenedFile(_File._openStdioSync(fd));
25 }
26
27 void _setupOpenedFile(RandomAccessFile openedFile) {
28 _openedFile = openedFile;
29 if (_streamMarkedClosed) {
30 // This input stream has already been closed.
31 _fileLength = 0;
32 _closeFile();
33 return;
34 }
35 var futureOpen = _openedFile.length();
36 futureOpen.then((len) {
37 _fileLength = len;
38 _fillBuffer();
39 });
40 futureOpen.handleException((e) {
41 _reportError(e);
42 return true;
43 });
44 }
45
46 void _closeFile() {
47 if (_openedFile == null) {
48 _streamMarkedClosed = true;
49 return;
50 }
51 if (available() == 0) _cancelScheduledDataCallback();
52 if (!_openedFile.closed) {
53 _openedFile.close().then((ignore) {
54 _streamMarkedClosed = true;
55 _checkScheduleCallbacks();
56 });
57 }
58 }
59
60 void _fillBuffer() {
61 Expect.equals(_position, _data.length);
62 if (_openedFile == null) return; // Called before the file is opened.
63 int size = min(_bufferLength, _fileLength - _filePosition);
64 if (size == 0) {
65 _closeFile();
66 return;
67 }
68 // If there is currently a _fillBuffer call waiting on readList,
69 // let it fill the buffer instead of us.
70 if (_activeFillBufferCall) return;
71 _activeFillBufferCall = true;
72 if (_data.length != size) {
73 _data = new Uint8List(size);
74 // Maintain the invariant signalling that the buffer is empty.
75 _position = _data.length;
76 }
77 var future = _openedFile.readList(_data, 0, _data.length);
78 future.then((read) {
79 _filePosition += read;
80 if (read != _data.length) {
81 _data = _data.getRange(0, read);
82 }
83 _position = 0;
84 _activeFillBufferCall = false;
85
86 if (_fileLength == _filePosition) {
87 _closeFile();
88 }
89 _checkScheduleCallbacks();
90 });
91 future.handleException((e) {
92 _activeFillBufferCall = false;
93 _reportError(e);
94 return true;
95 });
96 }
97
98 int available() {
99 return closed ? 0 : _data.length - _position;
100 }
101
102 void pipe(OutputStream output, {bool close: true}) {
103 _pipe(this, output, close: close);
104 }
105
106 void _finishRead() {
107 if (_position == _data.length && !_streamMarkedClosed) {
108 _fillBuffer();
109 } else {
110 _checkScheduleCallbacks();
111 }
112 }
113
114 List<int> _read(int bytesToRead) {
115 List<int> result;
116 if (_position == 0 && bytesToRead == _data.length) {
117 result = _data;
118 _data = const [];
119 } else {
120 result = new Uint8List(bytesToRead);
121 result.setRange(0, bytesToRead, _data, _position);
122 _position += bytesToRead;
123 }
124 _finishRead();
125 return result;
126 }
127
128 int _readInto(List<int> buffer, int offset, int len) {
129 buffer.setRange(offset, len, _data, _position);
130 _position += len;
131 _finishRead();
132 return len;
133 }
134
135 void _close() {
136 _data = const [];
137 _position = 0;
138 _filePosition = 0;
139 _fileLength = 0;
140 _closeFile();
141 }
142
143 static const int _bufferLength = 64 * 1024;
144
145 RandomAccessFile _openedFile;
146 List<int> _data;
147 int _position;
148 int _filePosition;
149 int _fileLength;
150 bool _activeFillBufferCall = false;
151 }
152
153
154 class _PendingOperation {
155 const _PendingOperation(this._id);
156 static const _PendingOperation CLOSE = const _PendingOperation(0);
157 static const _PendingOperation FLUSH = const _PendingOperation(1);
158 final int _id;
159 }
160
161
162 class _FileOutputStream extends _BaseOutputStream implements OutputStream {
163 _FileOutputStream(String name, FileMode mode) {
164 _pendingOperations = new List();
165 var f = new File(name);
166 var openFuture = f.open(mode);
167 openFuture.then((openedFile) {
168 _file = openedFile;
169 _processPendingOperations();
170 });
171 openFuture.handleException((e) {
172 _reportError(e);
173 return true;
174 });
175 }
176
177 _FileOutputStream.fromStdio(int fd) {
178 assert(1 <= fd && fd <= 2);
179 _file = _File._openStdioSync(fd);
180 }
181
182 bool write(List<int> buffer, [bool copyBuffer = false]) {
183 var data = buffer;
184 if (copyBuffer) {
185 var length = buffer.length;
186 data = new Uint8List(length);
187 data.setRange(0, length, buffer, 0);
188 }
189 if (_file == null) {
190 _pendingOperations.add(data);
191 } else {
192 _write(data, 0, data.length);
193 }
194 return false;
195 }
196
197 bool writeFrom(List<int> buffer, [int offset = 0, int len]) {
198 // A copy is required by the interface.
199 var length = buffer.length - offset;
200 if (len != null) {
201 if (len > length) throw new IndexOutOfRangeException(len);
202 length = len;
203 }
204 var copy = new Uint8List(length);
205 copy.setRange(0, length, buffer, offset);
206 return write(copy);
207 }
208
209
210 void flush() {
211 if (_file == null) {
212 _pendingOperations.add(_PendingOperation.FLUSH);
213 } else {
214 _file.flush().then((ignored) => null);
215 }
216 }
217
218
219 void close() {
220 _streamMarkedClosed = true;
221 if (_file == null) {
222 _pendingOperations.add(_PendingOperation.CLOSE);
223 } else if (!_closeCallbackScheduled) {
224 _file.close().then((ignore) {
225 if (_onClosed != null) _onClosed();
226 });
227 _closeCallbackScheduled = true;
228 }
229 }
230
231 void set onNoPendingWrites(void callback()) {
232 _onNoPendingWrites = callback;
233 if ((_pendingOperations == null || _pendingOperations.length == 0) &&
234 outstandingWrites == 0 &&
235 !_streamMarkedClosed &&
236 _onNoPendingWrites != null) {
237 new Timer(0, (t) {
238 if (_onNoPendingWrites != null) {
239 _onNoPendingWrites();
240 }
241 });
242 }
243 }
244
245 void set onClosed(void callback()) {
246 _onClosed = callback;
247 }
248
249 void _processPendingOperations() {
250 _pendingOperations.forEach((buffer) {
251 if (buffer is _PendingOperation) {
252 if (buffer === _PendingOperation.CLOSE) {
253 close();
254 } else {
255 assert(buffer === _PendingOperation.FLUSH);
256 flush();
257 }
258 } else {
259 write(buffer);
260 }
261 });
262 _pendingOperations = null;
263 }
264
265 void _write(List<int> buffer, int offset, int len) {
266 outstandingWrites++;
267 var writeListFuture = _file.writeList(buffer, offset, len);
268 writeListFuture.then((ignore) {
269 outstandingWrites--;
270 if (outstandingWrites == 0 &&
271 !_streamMarkedClosed &&
272 _onNoPendingWrites != null) {
273 _onNoPendingWrites();
274 }
275 });
276 writeListFuture.handleException((e) {
277 outstandingWrites--;
278 _reportError(e);
279 return true;
280 });
281 }
282
283 bool get closed => _streamMarkedClosed;
284
285 RandomAccessFile _file;
286
287 // When this is set to true the stream is marked closed. When a
288 // stream is marked closed no more data can be written.
289 bool _streamMarkedClosed = false;
290
291 // When this is set to true, the close callback has been scheduled and the
292 // stream will be fully closed once it's called.
293 bool _closeCallbackScheduled = false;
294
295 // Number of writes that have not yet completed.
296 int outstandingWrites = 0;
297
298 // List of pending writes that were issued before the underlying
299 // file was successfully opened.
300 List _pendingOperations;
301
302 Function _onNoPendingWrites;
303 Function _onClosed;
304 }
305
306 const int _EXISTS_REQUEST = 0;
307 const int _CREATE_REQUEST = 1;
308 const int _DELETE_REQUEST = 2;
309 const int _OPEN_REQUEST = 3;
310 const int _FULL_PATH_REQUEST = 4;
311 const int _DIRECTORY_REQUEST = 5;
312 const int _CLOSE_REQUEST = 6;
313 const int _POSITION_REQUEST = 7;
314 const int _SET_POSITION_REQUEST = 8;
315 const int _TRUNCATE_REQUEST = 9;
316 const int _LENGTH_REQUEST = 10;
317 const int _LENGTH_FROM_NAME_REQUEST = 11;
318 const int _LAST_MODIFIED_REQUEST = 12;
319 const int _FLUSH_REQUEST = 13;
320 const int _READ_BYTE_REQUEST = 14;
321 const int _WRITE_BYTE_REQUEST = 15;
322 const int _READ_LIST_REQUEST = 16;
323 const int _WRITE_LIST_REQUEST = 17;
324 const int _WRITE_STRING_REQUEST = 18;
325
326 // Base class for _File and _RandomAccessFile with shared functions.
327 class _FileBase {
328 bool _isErrorResponse(response) {
329 return response is List && response[0] != _SUCCESS_RESPONSE;
330 }
331
332 Exception _exceptionFromResponse(response, String message) {
333 assert(_isErrorResponse(response));
334 switch (response[_ERROR_RESPONSE_ERROR_TYPE]) {
335 case _ILLEGAL_ARGUMENT_RESPONSE:
336 return new ArgumentError();
337 case _OSERROR_RESPONSE:
338 var err = new OSError(response[_OSERROR_RESPONSE_MESSAGE],
339 response[_OSERROR_RESPONSE_ERROR_CODE]);
340 return new FileIOException(message, err);
341 case _FILE_CLOSED_RESPONSE:
342 return new FileIOException("File closed");
343 default:
344 return new Exception("Unknown error");
345 }
346 }
347 }
348
349 SendPort _newServicePort() native "File_NewServicePort";
350
351 // Class for encapsulating the native implementation of files.
352 class _File extends _FileBase implements File {
353 // Constructor for file.
354 _File(String this._name) {
355 if (_name is! String) {
356 throw new ArgumentError('${NoSuchMethodError.safeToString(_name)} '
357 'is not a String');
358 }
359 }
360
361 // Constructor from Path for file.
362 _File.fromPath(Path path) : this(path.toNativePath());
363
364 Future<bool> exists() {
365 _ensureFileService();
366 List request = new List(2);
367 request[0] = _EXISTS_REQUEST;
368 request[1] = _name;
369 return _fileService.call(request).transform((response) {
370 if (_isErrorResponse(response)) {
371 throw _exceptionFromResponse(response, "Cannot open file '$_name'");
372 }
373 return response;
374 });
375 }
376
377
378 static _exists(String name) native "File_Exists";
379
380 bool existsSync() {
381 var result = _exists(_name);
382 throwIfError(result, "Cannot check existence of file '$_name'");
383 return result;
384 }
385
386 Future<File> create() {
387 _ensureFileService();
388 List request = new List(2);
389 request[0] = _CREATE_REQUEST;
390 request[1] = _name;
391 return _fileService.call(request).transform((response) {
392 if (_isErrorResponse(response)) {
393 throw _exceptionFromResponse(response, "Cannot create file '$_name'");
394 }
395 return this;
396 });
397 }
398
399 static _create(String name) native "File_Create";
400
401 void createSync() {
402 var result = _create(_name);
403 throwIfError(result, "Cannot create file '$_name'");
404 }
405
406 Future<File> delete() {
407 _ensureFileService();
408 List request = new List(2);
409 request[0] = _DELETE_REQUEST;
410 request[1] = _name;
411 return _fileService.call(request).transform((response) {
412 if (_isErrorResponse(response)) {
413 throw _exceptionFromResponse(response, "Cannot delete file '$_name'");
414 }
415 return this;
416 });
417 }
418
419 static _delete(String name) native "File_Delete";
420
421 void deleteSync() {
422 var result = _delete(_name);
423 throwIfError(result, "Cannot delete file '$_name'");
424 }
425
426 Future<Directory> directory() {
427 _ensureFileService();
428 List request = new List(2);
429 request[0] = _DIRECTORY_REQUEST;
430 request[1] = _name;
431 return _fileService.call(request).transform((response) {
432 if (_isErrorResponse(response)) {
433 throw _exceptionFromResponse(response,
434 "Cannot retrieve directory for "
435 "file '$_name'");
436 }
437 return new Directory(response);
438 });
439 }
440
441 static _directory(String name) native "File_Directory";
442
443 Directory directorySync() {
444 var result = _directory(name);
445 throwIfError(result, "Cannot retrieve directory for file '$_name'");
446 return new Directory(result);
447 }
448
449 Future<RandomAccessFile> open([FileMode mode = FileMode.READ]) {
450 _ensureFileService();
451 Completer<RandomAccessFile> completer = new Completer<RandomAccessFile>();
452 if (mode != FileMode.READ &&
453 mode != FileMode.WRITE &&
454 mode != FileMode.APPEND) {
455 new Timer(0, (t) {
456 completer.completeException(new ArgumentError());
457 });
458 return completer.future;
459 }
460 List request = new List(3);
461 request[0] = _OPEN_REQUEST;
462 request[1] = _name;
463 request[2] = mode._mode; // Direct int value for serialization.
464 return _fileService.call(request).transform((response) {
465 if (_isErrorResponse(response)) {
466 throw _exceptionFromResponse(response, "Cannot open file '$_name'");
467 }
468 return new _RandomAccessFile(response, _name);
469 });
470 }
471
472 Future<int> length() {
473 _ensureFileService();
474 List request = new List(2);
475 request[0] = _LENGTH_FROM_NAME_REQUEST;
476 request[1] = _name;
477 return _fileService.call(request).transform((response) {
478 if (_isErrorResponse(response)) {
479 throw _exceptionFromResponse(response,
480 "Cannot retrieve length of "
481 "file '$_name'");
482 }
483 return response;
484 });
485 }
486
487
488 static _lengthFromName(String name) native "File_LengthFromName";
489
490 int lengthSync() {
491 var result = _lengthFromName(_name);
492 throwIfError(result, "Cannot retrieve length of file '$_name'");
493 return result;
494 }
495
496 Future<Date> lastModified() {
497 _ensureFileService();
498 List request = new List(2);
499 request[0] = _LAST_MODIFIED_REQUEST;
500 request[1] = _name;
501 return _fileService.call(request).transform((response) {
502 if (_isErrorResponse(response)) {
503 throw _exceptionFromResponse(response,
504 "Cannot retrieve modification time "
505 "for file '$_name'");
506 }
507 return new Date.fromMillisecondsSinceEpoch(response);
508 });
509 }
510
511 static _lastModified(String name) native "File_LastModified";
512
513 Date lastModifiedSync() {
514 var ms = _lastModified(name);
515 throwIfError(ms, "Cannot retrieve modification time for file '$_name'");
516 return new Date.fromMillisecondsSinceEpoch(ms);
517 }
518
519 static _open(String name, int mode) native "File_Open";
520
521 RandomAccessFile openSync([FileMode mode = FileMode.READ]) {
522 if (mode != FileMode.READ &&
523 mode != FileMode.WRITE &&
524 mode != FileMode.APPEND) {
525 throw new FileIOException("Unknown file mode. Use FileMode.READ, "
526 "FileMode.WRITE or FileMode.APPEND.");
527 }
528 var id = _open(_name, mode._mode);
529 throwIfError(id, "Cannot open file '$_name'");
530 return new _RandomAccessFile(id, _name);
531 }
532
533 static int _openStdio(int fd) native "File_OpenStdio";
534
535 static RandomAccessFile _openStdioSync(int fd) {
536 var id = _openStdio(fd);
537 if (id == 0) {
538 throw new FileIOException("Cannot open stdio file for: $fd");
539 }
540 return new _RandomAccessFile(id, "");
541 }
542
543 Future<String> fullPath() {
544 _ensureFileService();
545 List request = new List(2);
546 request[0] = _FULL_PATH_REQUEST;
547 request[1] = _name;
548 return _fileService.call(request).transform((response) {
549 if (_isErrorResponse(response)) {
550 throw _exceptionFromResponse(response,
551 "Cannot retrieve full path"
552 " for '$_name'");
553 }
554 return response;
555 });
556 }
557
558 static _fullPath(String name) native "File_FullPath";
559
560 String fullPathSync() {
561 var result = _fullPath(_name);
562 throwIfError(result, "Cannot retrieve full path for file '$_name'");
563 return result;
564 }
565
566 InputStream openInputStream() {
567 return new _FileInputStream(_name);
568 }
569
570 OutputStream openOutputStream([FileMode mode = FileMode.WRITE]) {
571 if (mode != FileMode.WRITE &&
572 mode != FileMode.APPEND) {
573 throw new FileIOException(
574 "Wrong FileMode. Use FileMode.WRITE or FileMode.APPEND");
575 }
576 return new _FileOutputStream(_name, mode);
577 }
578
579 Future<List<int>> readAsBytes() {
580 _ensureFileService();
581 Completer<List<int>> completer = new Completer<List<int>>();
582 var chunks = new _BufferList();
583 var stream = openInputStream();
584 stream.onClosed = () {
585 var result = chunks.readBytes(chunks.length);
586 if (result == null) result = <int>[];
587 completer.complete(result);
588 };
589 stream.onData = () {
590 var chunk = stream.read();
591 chunks.add(chunk);
592 };
593 stream.onError = completer.completeException;
594 return completer.future;
595 }
596
597 List<int> readAsBytesSync() {
598 var opened = openSync();
599 var length = opened.lengthSync();
600 var result = new Uint8List(length);
601 var read = opened.readListSync(result, 0, length);
602 if (read != length) {
603 throw new FileIOException("Failed to read file");
604 }
605 opened.closeSync();
606 return result;
607 }
608
609 Future<String> readAsText([Encoding encoding = Encoding.UTF_8]) {
610 _ensureFileService();
611 return readAsBytes().transform((bytes) {
612 if (bytes.length == 0) return "";
613 var decoder = _StringDecoders.decoder(encoding);
614 decoder.write(bytes);
615 return decoder.decoded();
616 });
617 }
618
619 String readAsTextSync([Encoding encoding = Encoding.UTF_8]) {
620 var decoder = _StringDecoders.decoder(encoding);
621 List<int> bytes = readAsBytesSync();
622 if (bytes.length == 0) return "";
623 decoder.write(bytes);
624 return decoder.decoded();
625 }
626
627 List<String> _getDecodedLines(_StringDecoder decoder) {
628 List<String> result = [];
629 var line = decoder.decodedLine;
630 while (line != null) {
631 result.add(line);
632 line = decoder.decodedLine;
633 }
634 // If there is more data with no terminating line break we treat
635 // it as the last line.
636 var data = decoder.decoded();
637 if (data != null) {
638 result.add(data);
639 }
640 return result;
641 }
642
643 Future<List<String>> readAsLines([Encoding encoding = Encoding.UTF_8]) {
644 _ensureFileService();
645 Completer<List<String>> completer = new Completer<List<String>>();
646 return readAsBytes().transform((bytes) {
647 var decoder = _StringDecoders.decoder(encoding);
648 decoder.write(bytes);
649 return _getDecodedLines(decoder);
650 });
651 }
652
653 List<String> readAsLinesSync([Encoding encoding = Encoding.UTF_8]) {
654 var decoder = _StringDecoders.decoder(encoding);
655 List<int> bytes = readAsBytesSync();
656 decoder.write(bytes);
657 return _getDecodedLines(decoder);
658 }
659
660 String get name => _name;
661
662 void _ensureFileService() {
663 if (_fileService == null) {
664 _fileService = _newServicePort();
665 }
666 }
667
668 static throwIfError(Object result, String msg) {
669 if (result is OSError) {
670 throw new FileIOException(msg, result);
671 }
672 }
673
674 final String _name;
675
676 SendPort _fileService;
677 }
678
679
680 class _RandomAccessFile extends _FileBase implements RandomAccessFile {
681 _RandomAccessFile(int this._id, String this._name);
682
683 Future<RandomAccessFile> close() {
684 Completer<RandomAccessFile> completer = new Completer<RandomAccessFile>();
685 if (closed) return _completeWithClosedException(completer);
686 _ensureFileService();
687 List request = new List(2);
688 request[0] = _CLOSE_REQUEST;
689 request[1] = _id;
690 // Set the id_ to 0 (NULL) to ensure the no more async requests
691 // can be issued for this file.
692 _id = 0;
693 return _fileService.call(request).transform((result) {
694 if (result != -1) {
695 _id = result;
696 return this;
697 } else {
698 throw new FileIOException("Cannot close file '$_name'");
699 }
700 });
701 }
702
703 static int _close(int id) native "File_Close";
704
705 void closeSync() {
706 _checkNotClosed();
707 var id = _close(_id);
708 if (id == -1) {
709 throw new FileIOException("Cannot close file '$_name'");
710 }
711 _id = id;
712 }
713
714 Future<int> readByte() {
715 _ensureFileService();
716 Completer<int> completer = new Completer<int>();
717 if (closed) return _completeWithClosedException(completer);
718 List request = new List(2);
719 request[0] = _READ_BYTE_REQUEST;
720 request[1] = _id;
721 return _fileService.call(request).transform((response) {
722 if (_isErrorResponse(response)) {
723 throw _exceptionFromResponse(response,
724 "readByte failed for file '$_name'");
725 }
726 return response;
727 });
728 }
729
730 static _readByte(int id) native "File_ReadByte";
731
732 int readByteSync() {
733 _checkNotClosed();
734 var result = _readByte(_id);
735 if (result is OSError) {
736 throw new FileIOException("readByte failed for file '$_name'", result);
737 }
738 return result;
739 }
740
741 Future<int> readList(List<int> buffer, int offset, int bytes) {
742 _ensureFileService();
743 Completer<int> completer = new Completer<int>();
744 if (buffer is !List || offset is !int || bytes is !int) {
745 // Complete asynchronously so the user has a chance to setup
746 // handlers without getting exceptions when registering the
747 // then handler.
748 new Timer(0, (t) {
749 completer.completeException(new FileIOException(
750 "Invalid arguments to readList for file '$_name'"));
751 });
752 return completer.future;
753 };
754 if (closed) return _completeWithClosedException(completer);
755 List request = new List(3);
756 request[0] = _READ_LIST_REQUEST;
757 request[1] = _id;
758 request[2] = bytes;
759 return _fileService.call(request).transform((response) {
760 if (_isErrorResponse(response)) {
761 throw _exceptionFromResponse(response,
762 "readList failed for file '$_name'");
763 }
764 var read = response[1];
765 var data = response[2];
766 buffer.setRange(offset, read, data);
767 return read;
768 });
769 }
770
771 static void _checkReadWriteListArguments(int length, int offset, int bytes) {
772 if (offset < 0) throw new IndexOutOfRangeException(offset);
773 if (bytes < 0) throw new IndexOutOfRangeException(bytes);
774 if ((offset + bytes) > length) {
775 throw new IndexOutOfRangeException(offset + bytes);
776 }
777 }
778
779 static _readList(int id, List<int> buffer, int offset, int bytes)
780 native "File_ReadList";
781
782 int readListSync(List<int> buffer, int offset, int bytes) {
783 _checkNotClosed();
784 if (buffer is !List || offset is !int || bytes is !int) {
785 throw new FileIOException(
786 "Invalid arguments to readList for file '$_name'");
787 }
788 if (bytes == 0) return 0;
789 _checkReadWriteListArguments(buffer.length, offset, bytes);
790 var result = _readList(_id, buffer, offset, bytes);
791 if (result is OSError) {
792 throw new FileIOException("readList failed for file '$_name'",
793 result);
794 }
795 return result;
796 }
797
798 Future<RandomAccessFile> writeByte(int value) {
799 _ensureFileService();
800 Completer<RandomAccessFile> completer = new Completer<RandomAccessFile>();
801 if (value is !int) {
802 // Complete asynchronously so the user has a chance to setup
803 // handlers without getting exceptions when registering the
804 // then handler.
805 new Timer(0, (t) {
806 completer.completeException(new FileIOException(
807 "Invalid argument to writeByte for file '$_name'"));
808 });
809 return completer.future;
810 }
811 if (closed) return _completeWithClosedException(completer);
812 List request = new List(3);
813 request[0] = _WRITE_BYTE_REQUEST;
814 request[1] = _id;
815 request[2] = value;
816 return _fileService.call(request).transform((response) {
817 if (_isErrorResponse(response)) {
818 throw _exceptionFromResponse(response,
819 "writeByte failed for file '$_name'");
820 }
821 return this;
822 });
823 }
824
825 static _writeByte(int id, int value) native "File_WriteByte";
826
827 int writeByteSync(int value) {
828 _checkNotClosed();
829 if (value is !int) {
830 throw new FileIOException(
831 "Invalid argument to writeByte for file '$_name'");
832 }
833 var result = _writeByte(_id, value);
834 if (result is OSError) {
835 throw new FileIOException("writeByte failed for file '$_name'",
836 result);
837 }
838 return result;
839 }
840
841 Future<RandomAccessFile> writeList(List<int> buffer, int offset, int bytes) {
842 _ensureFileService();
843 Completer<RandomAccessFile> completer = new Completer<RandomAccessFile>();
844 if (buffer is !List || offset is !int || bytes is !int) {
845 // Complete asynchronously so the user has a chance to setup
846 // handlers without getting exceptions when registering the
847 // then handler.
848 new Timer(0, (t) {
849 completer.completeException(new FileIOException(
850 "Invalid arguments to writeList for file '$_name'"));
851 });
852 return completer.future;
853 }
854 if (closed) return _completeWithClosedException(completer);
855
856 _BufferAndOffset result;
857 try {
858 result = _ensureFastAndSerializableBuffer(buffer, offset, bytes);
859 } catch (e) {
860 // Complete asynchronously so the user has a chance to setup
861 // handlers without getting exceptions when registering the
862 // then handler.
863 new Timer(0, (t) => completer.completeException(e));
864 return completer.future;
865 }
866
867 List request = new List(5);
868 request[0] = _WRITE_LIST_REQUEST;
869 request[1] = _id;
870 request[2] = result.buffer;
871 request[3] = result.offset;
872 request[4] = bytes;
873 return _fileService.call(request).transform((response) {
874 if (_isErrorResponse(response)) {
875 throw _exceptionFromResponse(response,
876 "writeList failed for file '$_name'");
877 }
878 return this;
879 });
880 }
881
882 static _writeList(int id, List<int> buffer, int offset, int bytes)
883 native "File_WriteList";
884
885 int writeListSync(List<int> buffer, int offset, int bytes) {
886 _checkNotClosed();
887 if (buffer is !List || offset is !int || bytes is !int) {
888 throw new FileIOException(
889 "Invalid arguments to writeList for file '$_name'");
890 }
891 if (bytes == 0) return 0;
892 _checkReadWriteListArguments(buffer.length, offset, bytes);
893 _BufferAndOffset bufferAndOffset =
894 _ensureFastAndSerializableBuffer(buffer, offset, bytes);
895 var result =
896 _writeList(_id, bufferAndOffset.buffer, bufferAndOffset.offset, bytes);
897 if (result is OSError) {
898 throw new FileIOException("writeList failed for file '$_name'", result);
899 }
900 return result;
901 }
902
903 Future<RandomAccessFile> writeString(String string,
904 [Encoding encoding = Encoding.UTF_8]) {
905 _ensureFileService();
906 Completer<RandomAccessFile> completer = new Completer<RandomAccessFile>();
907 if (closed) return _completeWithClosedException(completer);
908 List request = new List(3);
909 request[0] = _WRITE_STRING_REQUEST;
910 request[1] = _id;
911 request[2] = string;
912 return _fileService.call(request).transform((response) {
913 if (_isErrorResponse(response)) {
914 throw _exceptionFromResponse(response,
915 "writeString failed for file '$_name'");
916 }
917 return this;
918 });
919 }
920
921 static _writeString(int id, String string) native "File_WriteString";
922
923 int writeStringSync(String string, [Encoding encoding = Encoding.UTF_8]) {
924 _checkNotClosed();
925 if (string is !String) throw new ArgumentError();
926 var result = _writeString(_id, string);
927 if (result is OSError) {
928 throw new FileIOException("writeString failed for file '$_name'");
929 }
930 return result;
931 }
932
933 Future<int> position() {
934 _ensureFileService();
935 Completer<int> completer = new Completer<int>();
936 if (closed) return _completeWithClosedException(completer);
937 List request = new List(2);
938 request[0] = _POSITION_REQUEST;
939 request[1] = _id;
940 return _fileService.call(request).transform((response) {
941 if (_isErrorResponse(response)) {
942 throw _exceptionFromResponse(response,
943 "position failed for file '$_name'");
944 }
945 return response;
946 });
947 }
948
949 static _position(int id) native "File_Position";
950
951 int positionSync() {
952 _checkNotClosed();
953 var result = _position(_id);
954 if (result is OSError) {
955 throw new FileIOException("position failed for file '$_name'", result);
956 }
957 return result;
958 }
959
960 Future<RandomAccessFile> setPosition(int position) {
961 _ensureFileService();
962 Completer<RandomAccessFile> completer = new Completer<RandomAccessFile>();
963 if (closed) return _completeWithClosedException(completer);
964 List request = new List(3);
965 request[0] = _SET_POSITION_REQUEST;
966 request[1] = _id;
967 request[2] = position;
968 return _fileService.call(request).transform((response) {
969 if (_isErrorResponse(response)) {
970 throw _exceptionFromResponse(response,
971 "setPosition failed for file '$_name'");
972 }
973 return this;
974 });
975 }
976
977 static _setPosition(int id, int position) native "File_SetPosition";
978
979 void setPositionSync(int position) {
980 _checkNotClosed();
981 var result = _setPosition(_id, position);
982 if (result is OSError) {
983 throw new FileIOException("setPosition failed for file '$_name'", result);
984 }
985 }
986
987 Future<RandomAccessFile> truncate(int length) {
988 _ensureFileService();
989 Completer<RandomAccessFile> completer = new Completer<RandomAccessFile>();
990 if (closed) return _completeWithClosedException(completer);
991 List request = new List(3);
992 request[0] = _TRUNCATE_REQUEST;
993 request[1] = _id;
994 request[2] = length;
995 return _fileService.call(request).transform((response) {
996 if (_isErrorResponse(response)) {
997 throw _exceptionFromResponse(response,
998 "truncate failed for file '$_name'");
999 }
1000 return this;
1001 });
1002 }
1003
1004 static _truncate(int id, int length) native "File_Truncate";
1005
1006 void truncateSync(int length) {
1007 _checkNotClosed();
1008 var result = _truncate(_id, length);
1009 if (result is OSError) {
1010 throw new FileIOException("truncate failed for file '$_name'", result);
1011 }
1012 }
1013
1014 Future<int> length() {
1015 _ensureFileService();
1016 Completer<int> completer = new Completer<int>();
1017 if (closed) return _completeWithClosedException(completer);
1018 List request = new List(2);
1019 request[0] = _LENGTH_REQUEST;
1020 request[1] = _id;
1021 return _fileService.call(request).transform((response) {
1022 if (_isErrorResponse(response)) {
1023 throw _exceptionFromResponse(response,
1024 "length failed for file '$_name'");
1025 }
1026 return response;
1027 });
1028 }
1029
1030 static _length(int id) native "File_Length";
1031
1032 int lengthSync() {
1033 _checkNotClosed();
1034 var result = _length(_id);
1035 if (result is OSError) {
1036 throw new FileIOException("length failed for file '$_name'", result);
1037 }
1038 return result;
1039 }
1040
1041 Future<RandomAccessFile> flush() {
1042 _ensureFileService();
1043 Completer<RandomAccessFile> completer = new Completer<RandomAccessFile>();
1044 if (closed) return _completeWithClosedException(completer);
1045 List request = new List(2);
1046 request[0] = _FLUSH_REQUEST;
1047 request[1] = _id;
1048 return _fileService.call(request).transform((response) {
1049 if (_isErrorResponse(response)) {
1050 throw _exceptionFromResponse(response,
1051 "flush failed for file '$_name'");
1052 }
1053 return this;
1054 });
1055 }
1056
1057 static _flush(int id) native "File_Flush";
1058
1059 void flushSync() {
1060 _checkNotClosed();
1061 var result = _flush(_id);
1062 if (result is OSError) {
1063 throw new FileIOException("flush failed for file '$_name'", result);
1064 }
1065 }
1066
1067 String get name => _name;
1068
1069 void _ensureFileService() {
1070 if (_fileService == null) {
1071 _fileService = _newServicePort();
1072 }
1073 }
1074
1075 bool get closed => _id == 0;
1076
1077 void _checkNotClosed() {
1078 if (closed) {
1079 throw new FileIOException("File closed '$_name'");
1080 }
1081 }
1082
1083 Future _completeWithClosedException(Completer completer) {
1084 new Timer(0, (t) {
1085 completer.completeException(
1086 new FileIOException("File closed '$_name'"));
1087 });
1088 return completer.future;
1089 }
1090
1091 final String _name;
1092 int _id;
1093
1094 SendPort _fileService;
1095 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698