OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2013, 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 library barback.asset.internal_asset; |
| 6 |
| 7 import 'dart:async'; |
| 8 import 'dart:convert'; |
| 9 import 'dart:typed_data'; |
| 10 |
| 11 import '../serialize.dart'; |
| 12 import '../utils.dart'; |
| 13 import '../utils/file_pool.dart'; |
| 14 import '../utils/stream_replayer.dart'; |
| 15 import 'asset.dart'; |
| 16 import 'asset_id.dart'; |
| 17 |
| 18 /// Serialize an asset to a form that's safe to send across isolates. |
| 19 Map serializeAsset(Asset asset) { |
| 20 var id = serializeId(asset.id); |
| 21 if (asset is BinaryAsset) { |
| 22 return { |
| 23 'type': 'binary', |
| 24 'id': id, |
| 25 'contents': asset._contents |
| 26 }; |
| 27 } else if (asset is FileAsset) { |
| 28 return { |
| 29 'type': 'file', |
| 30 'id': id, |
| 31 'path': asset._path |
| 32 }; |
| 33 } else if (asset is StringAsset) { |
| 34 return { |
| 35 'type': 'string', |
| 36 'id': id, |
| 37 'contents': asset._contents |
| 38 }; |
| 39 } else { |
| 40 // [asset] is probably a [StreamAsset], but it's possible that the user has |
| 41 // created a custom subclass, in which case we just serialize the stream |
| 42 // anyway. |
| 43 return { |
| 44 'type': 'stream', |
| 45 'id': id, |
| 46 'stream': serializeStream(asset.read()) |
| 47 }; |
| 48 } |
| 49 } |
| 50 |
| 51 /// Deserialize an asset from the form returned by [serialize]. |
| 52 Asset deserializeAsset(Map asset) { |
| 53 var id = deserializeId(asset['id']); |
| 54 switch (asset['type']) { |
| 55 case 'binary': return new BinaryAsset(id, asset['contents']); |
| 56 case 'file': return new FileAsset(id, asset['path']); |
| 57 case 'string': return new StringAsset(id, asset['contents']); |
| 58 case 'stream': |
| 59 return new StreamAsset(id, deserializeStream(asset['stream'])); |
| 60 default: |
| 61 throw new FormatException('Unknown asset type "${asset['type']}".'); |
| 62 } |
| 63 } |
| 64 |
| 65 /// An asset whose data is stored in a list of bytes. |
| 66 class BinaryAsset implements Asset { |
| 67 final AssetId id; |
| 68 |
| 69 final Uint8List _contents; |
| 70 |
| 71 BinaryAsset(this.id, List<int> contents) |
| 72 : _contents = toUint8List(contents); |
| 73 |
| 74 Future<String> readAsString({Encoding encoding}) { |
| 75 if (encoding == null) encoding = UTF8; |
| 76 |
| 77 return new Future.value(encoding.decode(_contents)); |
| 78 } |
| 79 |
| 80 Stream<List<int>> read() => new Future<List<int>>.value(_contents).asStream(); |
| 81 |
| 82 String toString() { |
| 83 var buffer = new StringBuffer(); |
| 84 buffer.write("Bytes ["); |
| 85 |
| 86 // Don't show the whole list if it's long. |
| 87 if (_contents.length > 11) { |
| 88 for (var i = 0; i < 5; i++) { |
| 89 buffer.write(byteToHex(_contents[i])); |
| 90 buffer.write(" "); |
| 91 } |
| 92 |
| 93 buffer.write("..."); |
| 94 |
| 95 for (var i = _contents.length - 5; i < _contents.length; i++) { |
| 96 buffer.write(" "); |
| 97 buffer.write(byteToHex(_contents[i])); |
| 98 } |
| 99 } else { |
| 100 for (var i = 0; i < _contents.length; i++) { |
| 101 if (i > 0) buffer.write(" "); |
| 102 buffer.write(byteToHex(_contents[i])); |
| 103 } |
| 104 } |
| 105 |
| 106 buffer.write("]"); |
| 107 return buffer.toString(); |
| 108 } |
| 109 } |
| 110 |
| 111 /// An asset backed by a file on the local file system. |
| 112 class FileAsset implements Asset { |
| 113 final AssetId id; |
| 114 |
| 115 /// Use a [FilePool] to handle reads so we can try to cope with running out |
| 116 /// of file descriptors more gracefully. |
| 117 static final _pool = new FilePool(); |
| 118 |
| 119 final String _path; |
| 120 FileAsset(this.id, this._path); |
| 121 |
| 122 Future<String> readAsString({Encoding encoding}) { |
| 123 if (encoding == null) encoding = UTF8; |
| 124 return _pool.readAsString(_path, encoding); |
| 125 } |
| 126 |
| 127 Stream<List<int>> read() => _pool.openRead(_path); |
| 128 |
| 129 String toString() => 'File "${_path}"'; |
| 130 } |
| 131 |
| 132 /// An asset whose data is stored in a string. |
| 133 class StringAsset implements Asset { |
| 134 final AssetId id; |
| 135 |
| 136 final String _contents; |
| 137 |
| 138 StringAsset(this.id, this._contents); |
| 139 |
| 140 Future<String> readAsString({Encoding encoding}) => |
| 141 new Future.value(_contents); |
| 142 |
| 143 Stream<List<int>> read() => |
| 144 new Future<List<int>>.value(UTF8.encode(_contents)).asStream(); |
| 145 |
| 146 String toString() { |
| 147 // Don't show the whole string if it's long. |
| 148 var contents = _contents; |
| 149 if (contents.length > 40) { |
| 150 contents = contents.substring(0, 20) + " ... " + |
| 151 contents.substring(contents.length - 20); |
| 152 } |
| 153 |
| 154 contents = _escape(contents); |
| 155 return 'String "$contents"'; |
| 156 } |
| 157 |
| 158 String _escape(String string) { |
| 159 return string |
| 160 .replaceAll("\"", r'\"') |
| 161 .replaceAll("\n", r"\n") |
| 162 .replaceAll("\r", r"\r") |
| 163 .replaceAll("\t", r"\t"); |
| 164 } |
| 165 } |
| 166 |
| 167 /// An asset whose data is available from a stream. |
| 168 class StreamAsset implements Asset { |
| 169 final AssetId id; |
| 170 |
| 171 /// A stream replayer that records and replays the contents of the input |
| 172 /// stream. |
| 173 final StreamReplayer<List<int>> _replayer; |
| 174 |
| 175 StreamAsset(this.id, Stream<List<int>> stream) |
| 176 : _replayer = new StreamReplayer(stream); |
| 177 |
| 178 Future<String> readAsString({Encoding encoding}) { |
| 179 if (encoding == null) encoding = UTF8; |
| 180 return _replayer.getReplay().toList() |
| 181 .then((chunks) => encoding.decode(flatten(chunks))); |
| 182 } |
| 183 |
| 184 Stream<List<int>> read() => _replayer.getReplay(); |
| 185 |
| 186 String toString() => "Stream"; |
| 187 } |
OLD | NEW |