OLD | NEW |
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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 #include "vm/bootstrap_natives.h" | 5 #include "vm/bootstrap_natives.h" |
6 | |
7 #include "vm/dart_api_impl.h" | 6 #include "vm/dart_api_impl.h" |
| 7 #include "vm/datastream.h" |
8 #include "vm/exceptions.h" | 8 #include "vm/exceptions.h" |
| 9 #include "vm/growable_array.h" |
9 #include "vm/message.h" | 10 #include "vm/message.h" |
10 #include "vm/native_entry.h" | 11 #include "vm/native_entry.h" |
11 #include "vm/object.h" | 12 #include "vm/object.h" |
12 #include "vm/port.h" | 13 #include "vm/port.h" |
13 #include "vm/service_isolate.h" | 14 #include "vm/service_isolate.h" |
14 #include "vm/symbols.h" | 15 #include "vm/symbols.h" |
15 | 16 |
16 namespace dart { | 17 namespace dart { |
17 | 18 |
18 DECLARE_FLAG(bool, trace_service); | 19 DECLARE_FLAG(bool, trace_service); |
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
144 GET_NON_NULL_NATIVE_ARGUMENT(String, stream_id, arguments->NativeArgAt(0)); | 145 GET_NON_NULL_NATIVE_ARGUMENT(String, stream_id, arguments->NativeArgAt(0)); |
145 Service::CancelStream(stream_id.ToCString()); | 146 Service::CancelStream(stream_id.ToCString()); |
146 return Object::null(); | 147 return Object::null(); |
147 } | 148 } |
148 | 149 |
149 | 150 |
150 DEFINE_NATIVE_ENTRY(VMService_RequestAssets, 0) { | 151 DEFINE_NATIVE_ENTRY(VMService_RequestAssets, 0) { |
151 return Service::RequestAssets(); | 152 return Service::RequestAssets(); |
152 } | 153 } |
153 | 154 |
| 155 |
| 156 // TODO(25041): When reading, this class copies out the filenames and contents |
| 157 // into new buffers. It does this because the lifetime of |bytes| is uncertain. |
| 158 // If |bytes| is pinned in memory, then we could instead load up |
| 159 // |filenames_| and |contents_| with pointers into |bytes| without making |
| 160 // copies. |
| 161 class TarArchive { |
| 162 public: |
| 163 TarArchive(uint8_t* bytes, intptr_t bytes_length) |
| 164 : rs_(bytes, bytes_length) {} |
| 165 |
| 166 void Read() { |
| 167 while (HasNext()) { |
| 168 char* filename; |
| 169 uint8_t* data; |
| 170 intptr_t data_length; |
| 171 if (Next(&filename, &data, &data_length)) { |
| 172 filenames_.Add(filename); |
| 173 contents_.Add(data); |
| 174 content_lengths_.Add(data_length); |
| 175 } |
| 176 } |
| 177 } |
| 178 |
| 179 char* NextFilename() { |
| 180 return filenames_.RemoveLast(); |
| 181 } |
| 182 |
| 183 uint8_t* NextContent() { |
| 184 return contents_.RemoveLast(); |
| 185 } |
| 186 |
| 187 intptr_t NextContentLength() { |
| 188 return content_lengths_.RemoveLast(); |
| 189 } |
| 190 |
| 191 bool HasMore() const { |
| 192 return filenames_.length() > 0; |
| 193 } |
| 194 |
| 195 intptr_t Length() const { return filenames_.length(); } |
| 196 |
| 197 private: |
| 198 enum TarHeaderFields { |
| 199 kTarHeaderFilenameOffset = 0, |
| 200 kTarHeaderFilenameSize = 100, |
| 201 kTarHeaderSizeOffset = 124, |
| 202 kTarHeaderSizeSize = 12, |
| 203 kTarHeaderTypeOffset = 156, |
| 204 kTarHeaderTypeSize = 1, |
| 205 kTarHeaderSize = 512, |
| 206 }; |
| 207 |
| 208 enum TarType { |
| 209 kTarAregType = '\0', |
| 210 kTarRegType = '0', |
| 211 kTarLnkType = '1', |
| 212 kTarSymType = '2', |
| 213 kTarChrType = '3', |
| 214 kTarBlkType = '4', |
| 215 kTarDirType = '5', |
| 216 kTarFifoType = '6', |
| 217 kTarContType = '7', |
| 218 kTarXhdType = 'x', |
| 219 kTarXglType = 'g', |
| 220 }; |
| 221 |
| 222 bool HasNext() const { |
| 223 return !EndOfArchive(); |
| 224 } |
| 225 |
| 226 bool Next(char** filename, uint8_t** data, intptr_t* data_length) { |
| 227 intptr_t startOfBlock = rs_.Position(); |
| 228 *filename = ReadFilename(); |
| 229 rs_.SetPosition(startOfBlock + kTarHeaderSizeOffset); |
| 230 intptr_t size = ReadSize(); |
| 231 rs_.SetPosition(startOfBlock + kTarHeaderTypeOffset); |
| 232 TarType type = ReadType(); |
| 233 SeekToNextBlock(kTarHeaderSize); |
| 234 if ((type != kTarRegType) && (type != kTarAregType)) { |
| 235 SkipContents(size); |
| 236 return false; |
| 237 } |
| 238 ReadContents(data, size); |
| 239 *data_length = size; |
| 240 return true; |
| 241 } |
| 242 |
| 243 void SeekToNextBlock(intptr_t blockSize) { |
| 244 intptr_t remainder = blockSize - (rs_.Position() % blockSize); |
| 245 rs_.Advance(remainder); |
| 246 } |
| 247 |
| 248 uint8_t PeekByte(intptr_t i) const { |
| 249 return *(rs_.AddressOfCurrentPosition() + i); |
| 250 } |
| 251 |
| 252 bool EndOfArchive() const { |
| 253 if (rs_.PendingBytes() < (kTarHeaderSize * 2)) { |
| 254 return true; |
| 255 } |
| 256 for (intptr_t i = 0; i < (kTarHeaderSize * 2); i++) { |
| 257 if (PeekByte(i) != 0) { |
| 258 return false; |
| 259 } |
| 260 } |
| 261 return true; |
| 262 } |
| 263 |
| 264 TarType ReadType() { |
| 265 return static_cast<TarType>(ReadStream::Raw<1, uint8_t>::Read(&rs_)); |
| 266 } |
| 267 |
| 268 void SkipContents(intptr_t size) { |
| 269 rs_.Advance(size); |
| 270 SeekToNextBlock(kTarHeaderSize); |
| 271 } |
| 272 |
| 273 intptr_t ReadCString(char** s, intptr_t length) { |
| 274 intptr_t to_read = Utils::Minimum(length, rs_.PendingBytes()); |
| 275 char* result = new char[to_read + 1]; |
| 276 strncpy(result, |
| 277 reinterpret_cast<const char*>(rs_.AddressOfCurrentPosition()), |
| 278 to_read); |
| 279 result[to_read] = '\0'; |
| 280 rs_.SetPosition(rs_.Position() + to_read); |
| 281 *s = result; |
| 282 return to_read; |
| 283 } |
| 284 |
| 285 intptr_t ReadSize() { |
| 286 char* octalSize; |
| 287 unsigned int size; |
| 288 |
| 289 ReadCString(&octalSize, kTarHeaderSizeSize); |
| 290 int result = sscanf(octalSize, "%o", &size); |
| 291 delete[] octalSize; |
| 292 |
| 293 if (result != 1) { |
| 294 return 0; |
| 295 } |
| 296 return size; |
| 297 } |
| 298 |
| 299 char* ReadFilename() { |
| 300 char* result; |
| 301 intptr_t result_length = ReadCString(&result, kTarHeaderFilenameSize); |
| 302 if (result[0] == '/') { |
| 303 return result; |
| 304 } |
| 305 char* fixed_result = new char[result_length + 2]; // '/' + '\0'. |
| 306 fixed_result[0] = '/'; |
| 307 strncpy(&fixed_result[1], result, result_length); |
| 308 fixed_result[result_length + 1] = '\0'; |
| 309 delete[] result; |
| 310 return fixed_result; |
| 311 } |
| 312 |
| 313 void ReadContents(uint8_t** data, intptr_t size) { |
| 314 uint8_t* result = new uint8_t[size]; |
| 315 rs_.ReadBytes(result, size); |
| 316 SeekToNextBlock(kTarHeaderSize); |
| 317 *data = result; |
| 318 } |
| 319 |
| 320 ReadStream rs_; |
| 321 GrowableArray<char*> filenames_; |
| 322 GrowableArray<uint8_t*> contents_; |
| 323 GrowableArray<intptr_t> content_lengths_; |
| 324 |
| 325 DISALLOW_COPY_AND_ASSIGN(TarArchive); |
| 326 }; |
| 327 |
| 328 |
| 329 static void ContentsFinalizer(void* isolate_callback_data, |
| 330 Dart_WeakPersistentHandle handle, |
| 331 void* peer) { |
| 332 uint8_t* data = reinterpret_cast<uint8_t*>(peer); |
| 333 delete[] data; |
| 334 } |
| 335 |
| 336 |
| 337 static void FilenameFinalizer(void* peer) { |
| 338 char* filename = reinterpret_cast<char*>(peer); |
| 339 delete[] filename; |
| 340 } |
| 341 |
| 342 |
| 343 DEFINE_NATIVE_ENTRY(VMService_DecodeAssets, 1) { |
| 344 GET_NON_NULL_NATIVE_ARGUMENT(TypedData, data, arguments->NativeArgAt(0)); |
| 345 Api::Scope scope(thread); |
| 346 |
| 347 Dart_Handle data_handle = Api::NewHandle(thread->isolate(), data.raw()); |
| 348 |
| 349 Dart_TypedData_Type typ; |
| 350 void* bytes; |
| 351 intptr_t length; |
| 352 Dart_Handle err = Dart_TypedDataAcquireData( |
| 353 data_handle, &typ, &bytes, &length); |
| 354 ASSERT(!Dart_IsError(err)); |
| 355 |
| 356 TarArchive archive(reinterpret_cast<uint8_t*>(bytes), length); |
| 357 archive.Read(); |
| 358 |
| 359 err = Dart_TypedDataReleaseData(data_handle); |
| 360 ASSERT(!Dart_IsError(err)); |
| 361 |
| 362 intptr_t archive_size = archive.Length(); |
| 363 |
| 364 const Array& result_list = Array::Handle(thread->zone(), |
| 365 Array::New(2 * archive_size)); |
| 366 |
| 367 intptr_t idx = 0; |
| 368 while (archive.HasMore()) { |
| 369 char* filename = archive.NextFilename(); |
| 370 uint8_t* contents = archive.NextContent(); |
| 371 intptr_t contents_length = archive.NextContentLength(); |
| 372 |
| 373 Dart_Handle dart_filename = Dart_NewExternalLatin1String( |
| 374 reinterpret_cast<uint8_t*>(filename), |
| 375 strlen(filename), |
| 376 filename, |
| 377 FilenameFinalizer); |
| 378 ASSERT(!Dart_IsError(dart_filename)); |
| 379 |
| 380 Dart_Handle dart_contents = Dart_NewExternalTypedData( |
| 381 Dart_TypedData_kUint8, contents, contents_length); |
| 382 ASSERT(!Dart_IsError(dart_contents)); |
| 383 Dart_NewWeakPersistentHandle( |
| 384 dart_contents, contents, contents_length, ContentsFinalizer); |
| 385 |
| 386 result_list.SetAt(idx, Api::UnwrapStringHandle( |
| 387 thread->zone(), dart_filename)); |
| 388 result_list.SetAt(idx + 1, Api::UnwrapExternalTypedDataHandle( |
| 389 thread->zone(), dart_contents)); |
| 390 idx += 2; |
| 391 } |
| 392 |
| 393 return result_list.raw(); |
| 394 } |
| 395 |
154 } // namespace dart | 396 } // namespace dart |
OLD | NEW |