@@ -279,7 +279,7 @@ ResourceLoader::LoadToken::~LoadToken() {
279
279
clear ();
280
280
}
281
281
282
- Ref<Resource> ResourceLoader::_load (const String &p_path, const String &p_original_path, const String &p_type_hint, ResourceFormatLoader::CacheMode p_cache_mode, Error *r_error, bool p_use_sub_threads, float *r_progress) {
282
+ Ref<Resource> ResourceLoader::_load (const String &p_path, const String &p_original_path, const String &p_type_hint, ResourceFormatLoader::CacheMode p_cache_mode, bool p_using_whitelist, Dictionary p_external_path_whitelist, Dictionary p_type_whitelist, Error *r_error, bool p_use_sub_threads, float *r_progress) {
283
283
const String &original_path = p_original_path.is_empty () ? p_path : p_original_path;
284
284
load_nesting++;
285
285
if (load_paths_stack.size ()) {
@@ -304,7 +304,11 @@ Ref<Resource> ResourceLoader::_load(const String &p_path, const String &p_origin
304
304
continue ;
305
305
}
306
306
found = true ;
307
- res = loader[i]->load (p_path, original_path, r_error, p_use_sub_threads, r_progress, p_cache_mode);
307
+ if (p_using_whitelist) {
308
+ res = loader[i]->load_whitelisted (p_path, p_external_path_whitelist, p_type_whitelist, p_original_path.is_valid_filename () ? p_path : p_original_path, r_error, p_use_sub_threads, r_progress, p_cache_mode);
309
+ } else {
310
+ res = loader[i]->load (p_path, p_original_path.is_valid_filename () ? p_path : p_original_path, r_error, p_use_sub_threads, r_progress, p_cache_mode);
311
+ }
308
312
if (res.is_valid ()) {
309
313
break ;
310
314
}
@@ -386,7 +390,17 @@ void ResourceLoader::_run_load_task(void *p_userdata) {
386
390
const String &remapped_path = _path_remap (load_task.local_path , &xl_remapped);
387
391
388
392
Error load_err = OK;
389
- Ref<Resource> res = _load (remapped_path, remapped_path != load_task.local_path ? load_task.local_path : String (), load_task.type_hint , load_task.cache_mode , &load_err, load_task.use_sub_threads , &load_task.progress );
393
+ Ref<Resource> res = _load (remapped_path,
394
+ remapped_path != load_task.local_path ? load_task.local_path : String (),
395
+ load_task.type_hint ,
396
+ load_task.cache_mode ,
397
+ load_task.using_whitelist ,
398
+ load_task.external_path_whitelist ,
399
+ load_task.type_whitelist ,
400
+ &load_err,
401
+ load_task.use_sub_threads ,
402
+ &load_task.progress );
403
+
390
404
if (MessageQueue::get_singleton () != MessageQueue::get_main_singleton ()) {
391
405
MessageQueue::get_singleton ()->flush ();
392
406
}
@@ -507,7 +521,12 @@ String ResourceLoader::_validate_local_path(const String &p_path) {
507
521
}
508
522
509
523
Error ResourceLoader::load_threaded_request (const String &p_path, const String &p_type_hint, bool p_use_sub_threads, ResourceFormatLoader::CacheMode p_cache_mode) {
510
- Ref<ResourceLoader::LoadToken> token = _load_start (p_path, p_type_hint, p_use_sub_threads ? LOAD_THREAD_DISTRIBUTE : LOAD_THREAD_SPAWN_SINGLE, p_cache_mode, true );
524
+ Ref<ResourceLoader::LoadToken> token = _load_start (p_path, p_type_hint, p_use_sub_threads ? LOAD_THREAD_DISTRIBUTE : LOAD_THREAD_SPAWN_SINGLE, p_cache_mode, true , false , Dictionary (), Dictionary ());
525
+ return token.is_valid () ? OK : FAILED;
526
+ }
527
+
528
+ Error ResourceLoader::load_threaded_request_whitelisted (const String &p_path, Dictionary p_external_path_whitelist, Dictionary p_type_whitelist, const String &p_type_hint, bool p_use_sub_threads, ResourceFormatLoader::CacheMode p_cache_mode) {
529
+ Ref<ResourceLoader::LoadToken> token = _load_start (p_path, p_type_hint, p_use_sub_threads ? LOAD_THREAD_DISTRIBUTE : LOAD_THREAD_SPAWN_SINGLE, p_cache_mode, true , true , p_external_path_whitelist, p_type_whitelist);
511
530
return token.is_valid () ? OK : FAILED;
512
531
}
513
532
@@ -544,8 +563,33 @@ Ref<Resource> ResourceLoader::load(const String &p_path, const String &p_type_hi
544
563
// cyclic load detection and awaiting.
545
564
thread_mode = LOAD_THREAD_SPAWN_SINGLE;
546
565
}
547
- Ref<LoadToken> load_token = _load_start (p_path, p_type_hint, thread_mode, p_cache_mode);
548
- if (load_token.is_null ()) {
566
+ Ref<LoadToken> load_token = _load_start (p_path, p_type_hint, thread_mode, p_cache_mode, false , false , Dictionary (), Dictionary ());
567
+ if (!load_token.is_valid ()) {
568
+ if (r_error) {
569
+ *r_error = FAILED;
570
+ }
571
+ return Ref<Resource>();
572
+ }
573
+
574
+ Ref<Resource> res = _load_complete (*load_token.ptr (), r_error);
575
+ return res;
576
+ }
577
+
578
+ Ref<Resource> ResourceLoader::load_whitelisted (const String &p_path, Dictionary p_external_path_whitelist, Dictionary p_type_whitelist, const String &p_type_hint, ResourceFormatLoader::CacheMode p_cache_mode, Error *r_error) {
579
+ if (r_error) {
580
+ *r_error = OK;
581
+ }
582
+
583
+ LoadThreadMode thread_mode = LOAD_THREAD_FROM_CURRENT;
584
+ if (WorkerThreadPool::get_singleton ()->get_caller_task_id () != WorkerThreadPool::INVALID_TASK_ID) {
585
+ // If user is initiating a single-threaded load from a WorkerThreadPool task,
586
+ // we instead spawn a new task so there's a precondition that a load in a pool task
587
+ // is always initiated by the engine. That makes certain aspects simpler, such as
588
+ // cyclic load detection and awaiting.
589
+ thread_mode = LOAD_THREAD_SPAWN_SINGLE;
590
+ }
591
+ Ref<LoadToken> load_token = _load_start (p_path, p_type_hint, thread_mode, p_cache_mode, false , true , p_external_path_whitelist, p_type_whitelist);
592
+ if (!load_token.is_valid ()) {
549
593
if (r_error) {
550
594
*r_error = FAILED;
551
595
}
@@ -556,9 +600,14 @@ Ref<Resource> ResourceLoader::load(const String &p_path, const String &p_type_hi
556
600
return res;
557
601
}
558
602
559
- Ref<ResourceLoader::LoadToken> ResourceLoader::_load_start (const String &p_path, const String &p_type_hint, LoadThreadMode p_thread_mode, ResourceFormatLoader::CacheMode p_cache_mode, bool p_for_user) {
603
+ Ref<ResourceLoader::LoadToken> ResourceLoader::_load_start (const String &p_path, const String &p_type_hint, LoadThreadMode p_thread_mode, ResourceFormatLoader::CacheMode p_cache_mode, bool p_for_user, bool p_use_whitelist, Dictionary p_external_path_whitelist, Dictionary p_type_whitelist ) {
560
604
String local_path = _validate_local_path (p_path);
561
605
606
+ if (p_use_whitelist && !p_external_path_whitelist.has (local_path)) {
607
+ WARN_PRINT (vformat (" Blocked path not on whitelist: %s." , local_path));
608
+ return Ref<ResourceLoader::LoadToken>();
609
+ }
610
+
562
611
bool ignoring_cache = p_cache_mode == ResourceFormatLoader::CACHE_MODE_IGNORE || p_cache_mode == ResourceFormatLoader::CACHE_MODE_IGNORE_DEEP;
563
612
564
613
Ref<LoadToken> load_token;
@@ -605,6 +654,9 @@ Ref<ResourceLoader::LoadToken> ResourceLoader::_load_start(const String &p_path,
605
654
load_task.type_hint = p_type_hint;
606
655
load_task.cache_mode = p_cache_mode;
607
656
load_task.use_sub_threads = p_thread_mode == LOAD_THREAD_DISTRIBUTE;
657
+ load_task.using_whitelist = p_use_whitelist;
658
+ load_task.external_path_whitelist = p_external_path_whitelist;
659
+ load_task.type_whitelist = p_type_whitelist;
608
660
if (p_cache_mode == ResourceFormatLoader::CACHE_MODE_REUSE) {
609
661
Ref<Resource> existing = ResourceCache::get_ref (local_path);
610
662
if (existing.is_valid ()) {
@@ -1573,3 +1625,7 @@ HashMap<String, Vector<String>> ResourceLoader::translation_remaps;
1573
1625
HashMap<String, String> ResourceLoader::path_remaps;
1574
1626
1575
1627
ResourceLoaderImport ResourceLoader::import = nullptr ;
1628
+
1629
+ Ref<Resource> ResourceFormatLoader::load_whitelisted (const String &p_path, Dictionary p_external_path_whitelist, Dictionary p_type_whitelist, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
1630
+ return Ref<Resource>();
1631
+ }
0 commit comments