1 //
2 // Copyright 2020 Pixar
3 //
4 // Licensed under the Apache License, Version 2.0 (the "Apache License")
5 // with the following modification; you may not use this file except in
6 // compliance with the Apache License and the following modification to it:
7 // Section 6. Trademarks. is deleted and replaced with:
8 //
9 // 6. Trademarks. This License does not grant permission to use the trade
10 // names, trademarks, service marks, or product names of the Licensor
11 // and its affiliates, except as required to comply with Section 4(c) of
12 // the License and to reproduce the content of the NOTICE file.
13 //
14 // You may obtain a copy of the Apache License at
15 //
16 // http://www.apache.org/licenses/LICENSE-2.0
17 //
18 // Unless required by applicable law or agreed to in writing, software
19 // distributed under the Apache License with the above modification is
20 // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21 // KIND, either express or implied. See the Apache License for the specific
22 // language governing permissions and limitations under the Apache License.
23
24 #include "pxr/pxr.h"
25 #include "pxr/usd/ar/asset.h"
26 #include "pxr/usd/ar/assetInfo.h"
27 #include "pxr/usd/ar/debugCodes.h"
28 #include "pxr/usd/ar/defaultResolver.h"
29 #include "pxr/usd/ar/definePackageResolver.h"
30 #include "pxr/usd/ar/defineResolver.h"
31 #include "pxr/usd/ar/packageResolver.h"
32 #include "pxr/usd/ar/packageUtils.h"
33 #include "pxr/usd/ar/resolvedPath.h"
34 #include "pxr/usd/ar/resolver.h"
35 #include "pxr/usd/ar/threadLocalScopedCache.h"
36
37 #include "pxr/base/vt/value.h"
38 #include "pxr/base/plug/plugin.h"
39 #include "pxr/base/plug/registry.h"
40 #include "pxr/base/js/utils.h"
41 #include "pxr/base/js/value.h"
42 #include "pxr/base/tf/envSetting.h"
43 #include "pxr/base/tf/errorMark.h"
44 #include "pxr/base/tf/pathUtils.h"
45 #include "pxr/base/tf/registryManager.h"
46 #include "pxr/base/tf/scoped.h"
47 #include "pxr/base/tf/staticData.h"
48 #include "pxr/base/tf/staticTokens.h"
49 #include "pxr/base/tf/stl.h"
50 #include "pxr/base/tf/stringUtils.h"
51 #include "pxr/base/tf/type.h"
52
53 #include <tbb/concurrent_hash_map.h>
54
55 #include <memory>
56 #include <mutex>
57 #include <set>
58 #include <string>
59 #include <unordered_map>
60 #include <vector>
61
62 PXR_NAMESPACE_OPEN_SCOPE
63
TF_REGISTRY_FUNCTION(TfType)64 TF_REGISTRY_FUNCTION(TfType)
65 {
66 TfType::Define<ArResolver>();
67 }
68
69 TF_DEFINE_PRIVATE_TOKENS(_tokens,
70 // Plugin metadata key for package resolver extensions.
71 (extensions)
72
73 // Plugin metadata key for resolver URI schemes.
74 (uriSchemes)
75
76 // Plugin metadata keys for specifying resolver functionality.
77 (implementsContexts)
78 (implementsScopedCaches)
79 );
80
81 TF_DEFINE_ENV_SETTING(
82 PXR_AR_DISABLE_PLUGIN_RESOLVER, false,
83 "Disables plugin resolver implementation, falling back to default "
84 "supplied by Ar.");
85
86 TF_DEFINE_ENV_SETTING(
87 PXR_AR_DISABLE_PLUGIN_URI_RESOLVERS, false,
88 "Disables plugin URI resolver implementations.");
89
90 static TfStaticData<std::string> _preferredResolver;
91
92 void
ArSetPreferredResolver(const std::string & resolverTypeName)93 ArSetPreferredResolver(const std::string& resolverTypeName)
94 {
95 *_preferredResolver = resolverTypeName;
96 }
97
98 // ------------------------------------------------------------
99
100 namespace
101 {
102
103 // Global stack of resolvers being constructed used by
104 // _CreateResolver / ArCreateResolver and ArGetAvailableResolvers.
105 // These functions are documented to be non-thread-safe.
106 static TfStaticData<std::vector<TfType>> _resolverStack;
107
108 class _ResolverInfo
109 {
110 public:
111 // Plugin for the resolver implementation.
112 PlugPluginPtr plugin;
113
114 // TfType for the resolver implementation.
115 TfType type;
116
117 // URI schemes associated with the resolver implementation.
118 std::vector<std::string> uriSchemes;
119
120 // Whether this resolver can be used as a primary resolver.
121 bool canBePrimaryResolver = false;
122
123 // Whether this resolver implements any context-related operations.
124 bool implementsContexts = false;
125
126 // Whether this resolver implements any scoped cache-related opereations.
127 bool implementsScopedCaches = false;
128 };
129
130 std::string
_GetTypeNames(const std::vector<_ResolverInfo> & resolvers)131 _GetTypeNames(const std::vector<_ResolverInfo>& resolvers)
132 {
133 std::vector<std::string> typeNames;
134 typeNames.reserve(resolvers.size());
135 for (const auto& resolver : resolvers) {
136 typeNames.push_back(resolver.type.GetTypeName());
137 }
138 return TfStringJoin(typeNames, ", ");
139 }
140
141 PlugPluginPtr
_GetPluginForType(const TfType & t)142 _GetPluginForType(const TfType& t)
143 {
144 const PlugPluginPtr p = PlugRegistry::GetInstance().GetPluginForType(t);
145 if (!p) {
146 TF_CODING_ERROR(
147 "Failed to find plugin for %s", t.GetTypeName().c_str());
148 }
149 return p;
150 }
151
152 template <class T>
153 JsOptionalValue
_FindMetadataValueOnTypeOrBase(const TfToken & metadata,const TfType & t)154 _FindMetadataValueOnTypeOrBase(const TfToken& metadata, const TfType& t)
155 {
156 if (t.IsRoot()) {
157 return JsOptionalValue();
158 }
159
160 const PlugPluginPtr plugin = _GetPluginForType(t);
161 if (!plugin) {
162 return JsOptionalValue();
163 }
164
165 JsOptionalValue value = JsFindValue(
166 plugin->GetMetadataForType(t), metadata);
167
168 if (value) {
169 if (value->Is<T>()) {
170 return value;
171 }
172 else {
173 TF_CODING_ERROR(
174 "'%s' metadata for %s must be a %s.",
175 metadata.GetText(), t.GetTypeName().c_str(),
176 JsValue(T()).GetTypeName().c_str());
177 }
178 }
179
180 for (const TfType& base : t.GetBaseTypes()) {
181 value = _FindMetadataValueOnTypeOrBase<T>(metadata, base);
182 if (value) {
183 return value;
184 }
185 }
186
187 return JsOptionalValue();
188 }
189
190 std::vector<_ResolverInfo>
_GetAvailableResolvers()191 _GetAvailableResolvers()
192 {
193 std::vector<TfType> sortedResolverTypes;
194 {
195 std::set<TfType> resolverTypes;
196 PlugRegistry::GetAllDerivedTypes(
197 TfType::Find<ArResolver>(), &resolverTypes);
198
199 // Ensure this list is in a consistent order to ensure stable behavior.
200 // TfType's operator< is not stable across runs, so we sort based on
201 // typename instead.
202 sortedResolverTypes.assign(resolverTypes.begin(), resolverTypes.end());
203 std::sort(
204 sortedResolverTypes.begin(), sortedResolverTypes.end(),
205 [](const TfType& x, const TfType& y) {
206 return x.GetTypeName() < y.GetTypeName();
207 });
208 }
209
210 std::vector<_ResolverInfo> resolvers;
211 resolvers.reserve(sortedResolverTypes.size());
212
213 // Fill in the URI schemes associated with each available resolver.
214 for (const TfType& resolverType : sortedResolverTypes) {
215 const PlugPluginPtr plugin = _GetPluginForType(resolverType);
216 if (!plugin) {
217 continue;
218 }
219
220 std::vector<std::string> uriSchemes;
221 if (const JsOptionalValue uriSchemesVal = JsFindValue(
222 plugin->GetMetadataForType(resolverType),
223 _tokens->uriSchemes.GetString())) {
224
225 if (uriSchemesVal->IsArrayOf<std::string>()) {
226 uriSchemes = uriSchemesVal->GetArrayOf<std::string>();
227 }
228 else {
229 TF_CODING_ERROR(
230 "'%s' metadata for %s must be a list of strings.",
231 _tokens->uriSchemes.GetText(),
232 resolverType.GetTypeName().c_str());
233 continue;
234 }
235 }
236
237 const JsOptionalValue implementsContextsVal =
238 _FindMetadataValueOnTypeOrBase<bool>(
239 _tokens->implementsContexts, resolverType);
240
241 const JsOptionalValue implementsScopedCachesVal =
242 _FindMetadataValueOnTypeOrBase<bool>(
243 _tokens->implementsScopedCaches, resolverType);
244
245 _ResolverInfo info;
246 info.plugin = plugin;
247 info.type = resolverType;
248 info.uriSchemes = std::move(uriSchemes);
249 info.canBePrimaryResolver = info.uriSchemes.empty();
250 if (implementsContextsVal) {
251 info.implementsContexts = implementsContextsVal->GetBool();
252 }
253 if (implementsScopedCachesVal) {
254 info.implementsScopedCaches = implementsScopedCachesVal->GetBool();
255 }
256
257 resolvers.push_back(std::move(info));
258 }
259
260 return resolvers;
261 }
262
263 std::vector<_ResolverInfo>
_GetAvailablePrimaryResolvers(const std::vector<_ResolverInfo> & availableResolvers)264 _GetAvailablePrimaryResolvers(
265 const std::vector<_ResolverInfo>& availableResolvers)
266 {
267 const TfType defaultResolverType = TfType::Find<ArDefaultResolver>();
268
269 std::vector<_ResolverInfo> availablePrimaryResolvers;
270
271 const std::vector<_ResolverInfo> emptyResolverList;
272 const std::vector<_ResolverInfo>* allAvailableResolvers =
273 TfGetEnvSetting(PXR_AR_DISABLE_PLUGIN_RESOLVER) ?
274 &emptyResolverList : &availableResolvers;
275
276 for (const _ResolverInfo& resolver : *allAvailableResolvers) {
277 // Skip resolvers that are not marked as a potential primary resolver.
278 if (!resolver.canBePrimaryResolver) {
279 continue;
280 }
281
282 // Skip the default resolver so that we only process plugin types.
283 // We'll add the default resolver back later.
284 if (resolver.type == defaultResolverType) {
285 continue;
286 }
287
288 // Skip all resolvers that are currently under construction.
289 if (std::find(
290 _resolverStack->begin(), _resolverStack->end(), resolver.type)
291 != _resolverStack->end()) {
292 continue;
293 }
294
295 availablePrimaryResolvers.push_back(resolver);
296 }
297
298 // The default resolver is always the last resolver to be considered.
299 // This function is always called with the result of _GetAvailableResolvers,
300 // so we should always find the default resolver below.
301 for (const _ResolverInfo& resolver : availableResolvers) {
302 if (resolver.type == defaultResolverType) {
303 availablePrimaryResolvers.push_back(resolver);
304 break;
305 }
306 }
307 TF_VERIFY(availablePrimaryResolvers.back().type == defaultResolverType);
308
309 return availablePrimaryResolvers;
310 }
311
312 // Helper class to manage plugin resolvers that are loaded on-demand.
313 template <class ResolverType, class ResolverTypeFactory>
314 class _PluginResolver
315 {
316 public:
_PluginResolver(const PlugPluginPtr & plugin,const TfType & resolverType,const std::shared_ptr<ResolverType> & resolver=nullptr)317 _PluginResolver(
318 const PlugPluginPtr& plugin,
319 const TfType& resolverType,
320 const std::shared_ptr<ResolverType>& resolver = nullptr)
321 : _plugin(plugin)
322 , _resolverType(resolverType)
323 , _hasResolver(static_cast<bool>(resolver))
324 , _resolver(resolver)
325 {
326 }
327
GetType() const328 const TfType& GetType() const { return _resolverType; }
329
Create()330 std::unique_ptr<ResolverType> Create()
331 {
332 std::unique_ptr<ResolverType> resolver;
333
334 if (!_plugin->Load()) {
335 TF_CODING_ERROR("Failed to load plugin %s for %s",
336 _plugin->GetName().c_str(),
337 _resolverType.GetTypeName().c_str());
338 return nullptr;
339 }
340
341 ResolverTypeFactory* factory =
342 _resolverType.GetFactory<ResolverTypeFactory>();
343 if (factory) {
344 resolver.reset(factory->New());
345 }
346
347 if (!resolver) {
348 TF_CODING_ERROR(
349 "Failed to manufacture asset resolver %s from plugin %s",
350 _resolverType.GetTypeName().c_str(),
351 _plugin->GetName().c_str());
352 }
353
354 return resolver;
355 }
356
Get()357 ResolverType* Get()
358 {
359 if (!_hasResolver) {
360 std::unique_ptr<ResolverType> newResolver = Create();
361
362 std::lock_guard<std::mutex> g(_mutex);
363 if (!_hasResolver) {
364 _resolver.reset(newResolver.release());
365 _hasResolver = true;
366 }
367 }
368 return _resolver.get();
369 };
370
371 private:
372 PlugPluginPtr _plugin;
373 TfType _resolverType;
374
375 std::atomic<bool> _hasResolver;
376 std::mutex _mutex;
377 std::shared_ptr<ResolverType> _resolver;
378 };
379
380 std::unique_ptr<ArResolver>
_CreateResolver(const TfType & resolverType,std::string * debugMsg=nullptr)381 _CreateResolver(const TfType& resolverType, std::string* debugMsg = nullptr)
382 {
383 _resolverStack->push_back(resolverType);
384 TfScoped<> popResolverStack([]() { _resolverStack->pop_back(); });
385
386 const TfType defaultResolverType = TfType::Find<ArDefaultResolver>();
387 std::unique_ptr<ArResolver> tmpResolver;
388 if (!resolverType) {
389 TF_CODING_ERROR("Invalid resolver type");
390 }
391 else if (!resolverType.IsA<ArResolver>()) {
392 TF_CODING_ERROR(
393 "Given type %s does not derive from ArResolver",
394 resolverType.GetTypeName().c_str());
395 }
396 else if (resolverType != defaultResolverType) {
397 const PlugPluginPtr plugin = _GetPluginForType(resolverType);
398 if (plugin) {
399 tmpResolver = _PluginResolver<ArResolver, Ar_ResolverFactoryBase>(
400 plugin, resolverType).Create();
401
402 if (tmpResolver && debugMsg) {
403 *debugMsg = TfStringPrintf(
404 "Using asset resolver %s from plugin %s",
405 resolverType.GetTypeName().c_str(),
406 plugin->GetPath().c_str());
407 }
408 }
409 }
410
411 if (!tmpResolver) {
412 if (debugMsg) {
413 *debugMsg = TfStringPrintf("Using default asset resolver %s",
414 defaultResolverType.GetTypeName().c_str());
415 }
416 tmpResolver.reset(new ArDefaultResolver);
417 }
418
419 return tmpResolver;
420 }
421
422 // Private ArResolver implementation that owns and forwards calls to the
423 // plugin asset resolver implementation. This is used to overlay additional
424 // behaviors on top of the plugin resolver.
425 class _DispatchingResolver final
426 : public ArResolver
427 {
428 public:
_DispatchingResolver()429 _DispatchingResolver()
430 : _maxURISchemeLength(0)
431 {
432 const std::vector<_ResolverInfo> availableResolvers =
433 _GetAvailableResolvers();
434
435 _InitializePrimaryResolver(availableResolvers);
436 _InitializeURIResolvers(availableResolvers);
437 _InitializePackageResolvers();
438 }
439
GetPrimaryResolver()440 ArResolver& GetPrimaryResolver()
441 {
442 return *_resolver->Get();
443 }
444
GetInternallyManagedCurrentContext() const445 const ArResolverContext* GetInternallyManagedCurrentContext() const
446 {
447 _ContextStack& contextStack = _threadContextStack.local();
448 return contextStack.empty() ? nullptr : contextStack.back();
449 }
450
CreateContextFromString(const std::string & uriScheme,const std::string & contextStr) const451 ArResolverContext CreateContextFromString(
452 const std::string& uriScheme, const std::string& contextStr) const
453 {
454 ArResolver* resolver =
455 uriScheme.empty() ?
456 _resolver->Get() : _GetURIResolverForScheme(uriScheme);
457 return resolver ?
458 resolver->CreateContextFromString(contextStr) : ArResolverContext();
459 }
460
CreateContextFromStrings(const std::vector<std::pair<std::string,std::string>> & strs) const461 ArResolverContext CreateContextFromStrings(
462 const std::vector<std::pair<std::string, std::string>>& strs) const
463 {
464 std::vector<ArResolverContext> contexts;
465 contexts.reserve(strs.size());
466
467 for (const auto& entry : strs) {
468 ArResolverContext ctx =
469 CreateContextFromString(entry.first, entry.second);
470 if (!ctx.IsEmpty()) {
471 contexts.push_back(std::move(ctx));
472 }
473 };
474
475 return ArResolverContext(contexts);
476 }
477
_CreateIdentifier(const std::string & assetPath,const ArResolvedPath & anchorAssetPath) const478 std::string _CreateIdentifier(
479 const std::string& assetPath,
480 const ArResolvedPath& anchorAssetPath) const final
481 {
482 return _CreateIdentifierHelper(
483 assetPath, anchorAssetPath,
484 [](ArResolver& resolver, const std::string& assetPath,
485 const ArResolvedPath& anchorAssetPath) {
486 return resolver.CreateIdentifier(assetPath, anchorAssetPath);
487 });
488 }
489
_CreateIdentifierForNewAsset(const std::string & assetPath,const ArResolvedPath & anchorAssetPath) const490 std::string _CreateIdentifierForNewAsset(
491 const std::string& assetPath,
492 const ArResolvedPath& anchorAssetPath) const final
493 {
494 return _CreateIdentifierHelper(
495 assetPath, anchorAssetPath,
496 [](ArResolver& resolver, const std::string& assetPath,
497 const ArResolvedPath& anchorAssetPath) {
498 return resolver.CreateIdentifierForNewAsset(
499 assetPath, anchorAssetPath);
500 });
501 }
502
503 template <class CreateIdentifierFn>
_CreateIdentifierHelper(const std::string & assetPath,const ArResolvedPath & anchorAssetPath,const CreateIdentifierFn & createIdentifierFn) const504 std::string _CreateIdentifierHelper(
505 const std::string& assetPath,
506 const ArResolvedPath& anchorAssetPath,
507 const CreateIdentifierFn& createIdentifierFn) const
508 {
509 // If assetPath has a recognized URI scheme, we assume it's an absolute
510 // URI per RFC 3986 sec 4.3 and delegate to the associated URI resolver
511 // to handle this query.
512 //
513 // If path does not have a recognized URI scheme, we delegate to the
514 // resolver for the anchorAssetPath. Although we could implement URI
515 // anchoring per RFC 3986 sec 5 here, we want to give implementations
516 // the chance to do additional manipulations.
517 ArResolver* resolver = _GetURIResolver(assetPath);
518 if (!resolver) {
519 resolver = &_GetResolver(anchorAssetPath);
520 }
521
522 // XXX:
523 // If the anchorAssetPath is a package-relative path like
524 // /foo/bar.package[baz.file], we curently just use the outer package
525 // path as the anchoring asset. It might be more consistent if we
526 // used the inner *packaged* path as the anchor instead. Since the
527 // packaged path syntax is fully under Ar's control, we might not
528 // dispatch to any other resolver in this case and just anchor
529 // the packaged path and given assetPath ourselves.
530 const ArResolvedPath anchorResolvedPath(
531 ArSplitPackageRelativePathOuter(anchorAssetPath).first);
532
533 if (ArIsPackageRelativePath(assetPath)) {
534 std::pair<std::string, std::string> packageAssetPath =
535 ArSplitPackageRelativePathOuter(assetPath);
536 packageAssetPath.first = createIdentifierFn(
537 *resolver, packageAssetPath.first, anchorResolvedPath);
538
539 return ArJoinPackageRelativePath(packageAssetPath);
540 }
541
542 return createIdentifierFn(*resolver, assetPath, anchorResolvedPath);
543 }
544
_IsContextDependentPath(const std::string & assetPath) const545 bool _IsContextDependentPath(
546 const std::string& assetPath) const final
547 {
548 const _ResolverInfo* info = nullptr;
549 ArResolver& resolver = _GetResolver(assetPath, &info);
550
551 if (!info->implementsContexts) {
552 return false;
553 }
554
555 if (ArIsPackageRelativePath(assetPath)) {
556 return resolver.IsContextDependentPath(
557 ArSplitPackageRelativePathOuter(assetPath).first);
558 }
559 return resolver.IsContextDependentPath(assetPath);
560 }
561
_IsRepositoryPath(const std::string & path) const562 bool _IsRepositoryPath(const std::string& path) const final
563 {
564 ArResolver& resolver = _GetResolver(path);
565 if (ArIsPackageRelativePath(path)) {
566 return resolver.IsRepositoryPath(
567 ArSplitPackageRelativePathOuter(path).first);
568 }
569 return resolver.IsRepositoryPath(path);
570 }
571
_GetExtension(const std::string & path) const572 std::string _GetExtension(const std::string& path) const final
573 {
574 ArResolver& resolver = _GetResolver(path);
575 if (ArIsPackageRelativePath(path)) {
576 // We expect clients of this API will primarily care about the
577 // *packaged* asset, so we return the extension of the inner-most
578 // packaged path. Clients that care about the outer package's
579 // extension can split the package-relative path and call this
580 // function on the package path.
581 //
582 // XXX: This doesn't seem right. If Ar is defining the packaged
583 // path syntax, then Ar should be responsible for getting the
584 // extension for packaged paths instead of delegating.
585 const std::pair<std::string, std::string> packagePath =
586 ArSplitPackageRelativePathInner(path);
587 return resolver.GetExtension(packagePath.second);
588 }
589 return resolver.GetExtension(path);
590 }
591
592 // The primary resolver and the URI resolvers all participate
593 // in context binding and may have context-related data to store
594 // away. To accommodate this, _Resolve stores away a vector of
595 // VtValues where each element corresponds to the primary resolver
596 // or a URI resolver.
597 using _ResolverContextData = std::vector<VtValue>;
598
_BindContext(const ArResolverContext & context,VtValue * bindingData)599 void _BindContext(
600 const ArResolverContext& context,
601 VtValue* bindingData) final
602 {
603 _ResolverContextData contextData(1 + _uriResolvers.size());
604
605 size_t dataIndex = 0;
606
607 if (_resolver->info.implementsContexts) {
608 _resolver->Get()->BindContext(context, &contextData[dataIndex]);
609 ++dataIndex;
610 }
611
612 for (const auto& entry : _uriResolvers) {
613 if (!entry.second->info.implementsContexts) {
614 continue;
615 }
616
617 if (ArResolver* uriResolver = entry.second->Get()) {
618 uriResolver->BindContext(context, &contextData[dataIndex]);
619 }
620 ++dataIndex;
621 }
622
623 bindingData->Swap(contextData);
624
625 _ContextStack& contextStack = _threadContextStack.local();
626 contextStack.push_back(&context);
627 }
628
_UnbindContext(const ArResolverContext & context,VtValue * bindingData)629 void _UnbindContext(
630 const ArResolverContext& context,
631 VtValue* bindingData) final
632 {
633 if (!TF_VERIFY(bindingData->IsHolding<_ResolverContextData>())) {
634 return;
635 }
636
637 _ResolverContextData contextData;
638 bindingData->UncheckedSwap(contextData);
639
640 size_t dataIndex = 0;
641
642 if (_resolver->info.implementsContexts) {
643 _resolver->Get()->UnbindContext(context, &contextData[dataIndex]);
644 ++dataIndex;
645 }
646
647 for (const auto& entry : _uriResolvers) {
648 if (!entry.second->info.implementsContexts) {
649 continue;
650 }
651
652 if (ArResolver* uriResolver = entry.second->Get()) {
653 uriResolver->UnbindContext(context, &contextData[dataIndex]);
654 }
655 ++dataIndex;
656 }
657
658 bindingData->Swap(contextData);
659
660 _ContextStack& contextStack = _threadContextStack.local();
661 if (contextStack.empty()) {
662 TF_CODING_ERROR(
663 "No context was bound, cannot unbind context: %s",
664 context.GetDebugString().c_str());
665 }
666 else {
667 contextStack.pop_back();
668 }
669 }
670
_CreateDefaultContext() const671 ArResolverContext _CreateDefaultContext() const final
672 {
673 std::vector<ArResolverContext> contexts;
674
675 if (_resolver->info.implementsContexts) {
676 contexts.push_back(_resolver->Get()->CreateDefaultContext());
677 }
678
679 for (const auto& entry : _uriResolvers) {
680 if (!entry.second->info.implementsContexts) {
681 continue;
682 }
683
684 if (ArResolver* uriResolver = entry.second->Get()) {
685 contexts.push_back(uriResolver->CreateDefaultContext());
686 }
687 }
688
689 return ArResolverContext(contexts);
690 }
691
_CreateContextFromString(const std::string & str) const692 ArResolverContext _CreateContextFromString(
693 const std::string& str) const final
694 {
695 if (!_resolver->info.implementsContexts) {
696 return ArResolverContext();
697 }
698
699 return _resolver->Get()->CreateContextFromString(str);
700 }
701
_CreateDefaultContextForAsset(const std::string & assetPath) const702 ArResolverContext _CreateDefaultContextForAsset(
703 const std::string& assetPath) const final
704 {
705 if (ArIsPackageRelativePath(assetPath)) {
706 return _CreateDefaultContextForAsset(
707 ArSplitPackageRelativePathOuter(assetPath).first);
708 }
709
710 std::vector<ArResolverContext> contexts;
711
712 if (_resolver->info.implementsContexts) {
713 contexts.push_back(
714 _resolver->Get()->CreateDefaultContextForAsset(assetPath));
715 }
716
717 for (const auto& entry : _uriResolvers) {
718 if (!entry.second->info.implementsContexts) {
719 continue;
720 }
721
722 if (ArResolver* uriResolver = entry.second->Get()) {
723 contexts.push_back(
724 uriResolver->CreateDefaultContextForAsset(assetPath));
725 }
726 }
727
728 return ArResolverContext(contexts);
729 }
730
_RefreshContext(const ArResolverContext & context)731 void _RefreshContext(const ArResolverContext& context) final
732 {
733 if (_resolver->info.implementsContexts) {
734 _resolver->Get()->RefreshContext(context);
735 }
736
737 for (const auto& entry : _uriResolvers) {
738 if (!entry.second->info.implementsContexts) {
739 continue;
740 }
741
742 if (ArResolver* uriResolver = entry.second->Get()) {
743 uriResolver->RefreshContext(context);
744 }
745 }
746 }
747
_GetCurrentContext() const748 ArResolverContext _GetCurrentContext() const final
749 {
750 // Although we manage the stack of contexts bound via calls
751 // to BindContext, some resolver implementations may also be
752 // managing these bindings themselves and have a different
753 // idea of what the currently bound context is. So, we collect
754 // the results of calling GetCurrentContext on each resolver
755 // implementation and merge that over the contexts we're
756 // managing internally.
757 std::vector<ArResolverContext> contexts;
758
759 if (_resolver->info.implementsContexts) {
760 contexts.push_back(_resolver->Get()->GetCurrentContext());
761 }
762
763 for (const auto& entry : _uriResolvers) {
764 if (!entry.second->info.implementsContexts) {
765 continue;
766 }
767
768 if (ArResolver* uriResolver = entry.second->Get()) {
769 contexts.push_back(uriResolver->GetCurrentContext());
770 }
771 }
772
773 if (const ArResolverContext* ctx =
774 GetInternallyManagedCurrentContext()) {
775 contexts.push_back(*ctx);
776 }
777
778 return ArResolverContext(contexts);
779 }
780
_Resolve(const std::string & assetPath) const781 ArResolvedPath _Resolve(
782 const std::string& assetPath) const final
783 {
784 auto resolveFn = [this](const std::string& path) {
785 const _ResolverInfo* info = nullptr;
786 ArResolver& resolver = _GetResolver(path, &info);
787
788 if (!info->implementsScopedCaches) {
789 if (_CachePtr currentCache = _threadCache.GetCurrentCache()) {
790 _Cache::_PathToResolvedPathMap::accessor accessor;
791 if (currentCache->_pathToResolvedPathMap.insert(
792 accessor, std::make_pair(path, ArResolvedPath()))) {
793 accessor->second = resolver.Resolve(path);
794 }
795 return accessor->second;
796 }
797 }
798
799 return resolver.Resolve(path);
800 };
801
802 return _ResolveHelper(assetPath, resolveFn);
803 }
804
_ResolveForNewAsset(const std::string & assetPath) const805 ArResolvedPath _ResolveForNewAsset(
806 const std::string& assetPath) const final
807 {
808 ArResolver& resolver = _GetResolver(assetPath);
809 if (ArIsPackageRelativePath(assetPath)) {
810 std::pair<std::string, std::string> packagePath =
811 ArSplitPackageRelativePathOuter(assetPath);
812 packagePath.first = resolver.ResolveForNewAsset(packagePath.first);
813 return ArResolvedPath(ArJoinPackageRelativePath(packagePath));
814 }
815 return resolver.ResolveForNewAsset(assetPath);
816 };
817
_GetAssetInfo(const std::string & assetPath,const ArResolvedPath & resolvedPath) const818 ArAssetInfo _GetAssetInfo(
819 const std::string& assetPath,
820 const ArResolvedPath& resolvedPath) const final
821 {
822 ArAssetInfo assetInfo;
823
824 ArResolver& resolver = _GetResolver(assetPath);
825 if (ArIsPackageRelativePath(assetPath)) {
826 std::pair<std::string, std::string> packageAssetPath =
827 ArSplitPackageRelativePathOuter(assetPath);
828 std::pair<std::string, std::string> packageResolvedPath =
829 ArSplitPackageRelativePathOuter(resolvedPath);
830
831 assetInfo = resolver.GetAssetInfo(
832 packageAssetPath.first,
833 ArResolvedPath(packageResolvedPath.first));
834
835 // If resolvedPath was a package-relative path, make sure the
836 // repoPath field is also a package-relative path, since the primary
837 // resolver would only have been given the outer package path.
838 if (!assetInfo.repoPath.empty()) {
839 assetInfo.repoPath = ArJoinPackageRelativePath(
840 assetInfo.repoPath, packageResolvedPath.second);
841 }
842
843 return assetInfo;
844 }
845 return resolver.GetAssetInfo(assetPath, resolvedPath);
846 }
847
_GetModificationTimestamp(const std::string & path,const ArResolvedPath & resolvedPath) const848 ArTimestamp _GetModificationTimestamp(
849 const std::string& path,
850 const ArResolvedPath& resolvedPath) const final
851 {
852 ArResolver& resolver = _GetResolver(path);
853 if (ArIsPackageRelativePath(path)) {
854 return resolver.GetModificationTimestamp(
855 ArSplitPackageRelativePathOuter(path).first,
856 ArResolvedPath(
857 ArSplitPackageRelativePathOuter(resolvedPath).first));
858 }
859 return resolver.GetModificationTimestamp(path, resolvedPath);
860 }
861
_OpenAsset(const ArResolvedPath & resolvedPath) const862 std::shared_ptr<ArAsset> _OpenAsset(
863 const ArResolvedPath& resolvedPath) const final
864 {
865 ArResolver& resolver = _GetResolver(resolvedPath);
866 if (ArIsPackageRelativePath(resolvedPath)) {
867 const std::pair<std::string, std::string> resolvedPackagePath =
868 ArSplitPackageRelativePathInner(resolvedPath);
869
870 ArPackageResolver* packageResolver =
871 _GetPackageResolver(resolvedPackagePath.first);
872 if (packageResolver) {
873 return packageResolver->OpenAsset(
874 resolvedPackagePath.first, resolvedPackagePath.second);
875 }
876 return nullptr;
877 }
878 return resolver.OpenAsset(resolvedPath);
879 }
880
_OpenAssetForWrite(const ArResolvedPath & resolvedPath,WriteMode mode) const881 std::shared_ptr<ArWritableAsset> _OpenAssetForWrite(
882 const ArResolvedPath& resolvedPath,
883 WriteMode mode) const final
884 {
885 ArResolver& resolver = _GetResolver(resolvedPath);
886 if (ArIsPackageRelativePath(resolvedPath)) {
887 TF_CODING_ERROR("Cannot open package-relative paths for write");
888 return nullptr;
889 };
890 return resolver.OpenAssetForWrite(resolvedPath, mode);
891 }
892
_CanWriteAssetToPath(const ArResolvedPath & resolvedPath,std::string * whyNot) const893 bool _CanWriteAssetToPath(
894 const ArResolvedPath& resolvedPath,
895 std::string* whyNot) const final
896 {
897 ArResolver& resolver = _GetResolver(resolvedPath);
898 if (ArIsPackageRelativePath(resolvedPath)) {
899 if (whyNot) {
900 *whyNot = "Cannot open package-relative paths for write";
901 }
902 return false;
903 }
904 return resolver.CanWriteAssetToPath(resolvedPath, whyNot);
905 }
906
907 // The primary resolver and the package resolvers all participate in
908 // scoped caching and may have caching-related data to store away. To
909 // accommodate this, _Resolver stores away a vector of VtValues where
910 // each element corresponds to either the primary resolver or a
911 // package resolver.
912 using _ResolverCacheData = std::vector<VtValue>;
913
_BeginCacheScope(VtValue * cacheScopeData)914 void _BeginCacheScope(
915 VtValue* cacheScopeData) final
916 {
917 // If we've filled in cacheScopeData from a previous call to
918 // BeginCacheScope, extract the _ResolverCacheData so we can pass
919 // each of the VtValues to the corresponding resolver.
920 _ResolverCacheData cacheData;
921 if (cacheScopeData->IsHolding<_ResolverCacheData>()) {
922 cacheScopeData->UncheckedSwap(cacheData);
923 }
924 else {
925 cacheData.resize(
926 2 + _packageResolvers.size() + _uriResolvers.size());
927 }
928
929 TF_VERIFY(cacheData.size() ==
930 2 + _packageResolvers.size() + _uriResolvers.size());
931
932 size_t cacheDataIndex = 0;
933
934 if (_resolver->info.implementsScopedCaches) {
935 _resolver->Get()->BeginCacheScope(&cacheData[cacheDataIndex]);
936 ++cacheDataIndex;
937 }
938
939 for (const auto& entry : _uriResolvers) {
940 if (!entry.second->info.implementsScopedCaches) {
941 continue;
942 }
943
944 if (ArResolver* uriResolver = entry.second->Get()) {
945 uriResolver->BeginCacheScope(&cacheData[cacheDataIndex]);
946 }
947 ++cacheDataIndex;
948 }
949
950 for (size_t i = 0, e = _packageResolvers.size(); i != e;
951 ++i, ++cacheDataIndex) {
952 ArPackageResolver* packageResolver = _packageResolvers[i]->Get();
953 if (packageResolver) {
954 packageResolver->BeginCacheScope(&cacheData[cacheDataIndex]);
955 }
956 }
957
958 _threadCache.BeginCacheScope(&cacheData[cacheDataIndex]);
959 ++cacheDataIndex;
960
961 cacheScopeData->Swap(cacheData);
962 }
963
_EndCacheScope(VtValue * cacheScopeData)964 void _EndCacheScope(
965 VtValue* cacheScopeData) final
966 {
967 if (!TF_VERIFY(cacheScopeData->IsHolding<_ResolverCacheData>())) {
968 return;
969 }
970
971 _ResolverCacheData cacheData;
972 cacheScopeData->UncheckedSwap(cacheData);
973
974 size_t cacheDataIndex = 0;
975
976 if (_resolver->info.implementsScopedCaches) {
977 _resolver->Get()->EndCacheScope(&cacheData[cacheDataIndex]);
978 ++cacheDataIndex;
979 }
980
981 for (const auto& entry : _uriResolvers) {
982 if (!entry.second->info.implementsScopedCaches) {
983 continue;
984 }
985
986 if (ArResolver* uriResolver = entry.second->Get()) {
987 uriResolver->EndCacheScope(&cacheData[cacheDataIndex]);
988 }
989 ++cacheDataIndex;
990 }
991
992 for (size_t i = 0, e = _packageResolvers.size(); i != e;
993 ++i, ++cacheDataIndex) {
994 ArPackageResolver* packageResolver = _packageResolvers[i]->Get();
995 if (packageResolver) {
996 packageResolver->EndCacheScope(&cacheData[cacheDataIndex]);
997 }
998 }
999
1000 _threadCache.EndCacheScope(&cacheData[cacheDataIndex]);
1001 ++cacheDataIndex;
1002
1003 cacheScopeData->Swap(cacheData);
1004 }
1005
1006 private:
_InitializePrimaryResolver(const std::vector<_ResolverInfo> & availableResolvers)1007 void _InitializePrimaryResolver(
1008 const std::vector<_ResolverInfo>& availableResolvers)
1009 {
1010 const TfType defaultResolverType = TfType::Find<ArDefaultResolver>();
1011 TfType resolverType = defaultResolverType;
1012
1013 const std::vector<_ResolverInfo> primaryResolvers =
1014 _GetAvailablePrimaryResolvers(availableResolvers);
1015
1016 TF_DEBUG(AR_RESOLVER_INIT).Msg(
1017 "ArGetResolver(): Found primary asset resolver types: [%s]\n",
1018 _GetTypeNames(primaryResolvers).c_str());
1019
1020 if (TfGetEnvSetting(PXR_AR_DISABLE_PLUGIN_RESOLVER)) {
1021 TF_DEBUG(AR_RESOLVER_INIT).Msg(
1022 "ArGetResolver(): Plugin asset resolver disabled via "
1023 "PXR_AR_DISABLE_PLUGIN_RESOLVER.\n");
1024 }
1025 else if (!_preferredResolver->empty()) {
1026 const TfType preferredResolverType =
1027 PlugRegistry::FindTypeByName(*_preferredResolver);
1028 if (!preferredResolverType) {
1029 TF_WARN(
1030 "ArGetResolver(): Preferred resolver %s not found. "
1031 "Using default resolver.",
1032 _preferredResolver->c_str());
1033 }
1034 else if (!preferredResolverType.IsA<ArResolver>()) {
1035 TF_WARN(
1036 "ArGetResolver(): Preferred resolver %s does not derive "
1037 "from ArResolver. Using default resolver.\n",
1038 _preferredResolver->c_str());
1039 }
1040 else {
1041 TF_DEBUG(AR_RESOLVER_INIT).Msg(
1042 "ArGetResolver(): Using preferred resolver %s\n",
1043 _preferredResolver->c_str());
1044 resolverType = preferredResolverType;
1045 }
1046 }
1047 else if (TF_VERIFY(!primaryResolvers.empty())) {
1048 // primaryResolvers should never be empty, at minimum the default
1049 // resolver should be returned by _GetAvailablePrimaryResolvers.
1050 // Because of this, if there's more than 2 elements in
1051 // primaryResolvers, there must have been more than one resolver
1052 // from an external plugin.
1053 resolverType = primaryResolvers.front().type;
1054 if (primaryResolvers.size() > 2) {
1055 TF_DEBUG(AR_RESOLVER_INIT).Msg(
1056 "ArGetResolver(): Found multiple primary asset "
1057 "resolvers, using %s\n",
1058 resolverType.GetTypeName().c_str());
1059 }
1060 }
1061
1062 std::string debugMsg;
1063
1064 auto createResolver = [&, this](const TfType& resolverType) {
1065 for (const _ResolverInfo& info : primaryResolvers) {
1066 if (info.type != resolverType) {
1067 continue;
1068 }
1069
1070 std::unique_ptr<ArResolver> resolver =
1071 _CreateResolver(resolverType, &debugMsg);
1072 if (resolver) {
1073 _resolver = std::make_shared<_Resolver>(
1074 info, std::shared_ptr<ArResolver>(resolver.release()));
1075 return true;
1076 }
1077 }
1078 return false;
1079 };
1080
1081 if (!createResolver(resolverType)) {
1082 createResolver(defaultResolverType);
1083 }
1084
1085 TF_DEBUG(AR_RESOLVER_INIT).Msg(
1086 "ArGetResolver(): %s for primary resolver\n",
1087 debugMsg.c_str());
1088 }
1089
_InitializeURIResolvers(const std::vector<_ResolverInfo> & availableResolvers)1090 void _InitializeURIResolvers(
1091 const std::vector<_ResolverInfo>& availableResolvers)
1092 {
1093 if (TfGetEnvSetting(PXR_AR_DISABLE_PLUGIN_URI_RESOLVERS)) {
1094 TF_DEBUG(AR_RESOLVER_INIT).Msg(
1095 "ArGetResolver(): Plugin URI asset resolvers disabled via "
1096 "PXR_AR_DISABLE_PLUGIN_URI_RESOLVERS.\n");
1097 return;
1098 }
1099
1100 size_t maxSchemeLength = 0;
1101 std::unordered_map<std::string, _ResolverSharedPtr> uriResolvers;
1102
1103 for (const _ResolverInfo& resolverInfo : availableResolvers) {
1104 TF_DEBUG(AR_RESOLVER_INIT).Msg(
1105 "ArGetResolver(): Found URI resolver %s\n",
1106 resolverInfo.type.GetTypeName().c_str());
1107
1108 std::vector<std::string> uriSchemes;
1109 uriSchemes.reserve(resolverInfo.uriSchemes.size());
1110
1111 for (std::string uriScheme : resolverInfo.uriSchemes) {
1112 // Per RFC 3986 sec 3.1 schemes are case-insensitive.
1113 // Force all schemes to lower-case to support this.
1114 uriScheme = TfStringToLower(uriScheme);
1115
1116 if (const _ResolverSharedPtr* existingResolver =
1117 TfMapLookupPtr(uriResolvers, uriScheme)) {
1118 TF_WARN(
1119 "ArGetResolver(): %s registered to handle scheme '%s' "
1120 "which is already handled by %s. Ignoring.\n",
1121 resolverInfo.type.GetTypeName().c_str(),
1122 uriScheme.c_str(),
1123 (*existingResolver)->GetType().GetTypeName().c_str());
1124 }
1125 else {
1126 uriSchemes.push_back(uriScheme);
1127 }
1128 }
1129
1130 if (uriSchemes.empty()) {
1131 continue;
1132 }
1133
1134 TF_DEBUG(AR_RESOLVER_INIT).Msg(
1135 "ArGetResolver(): Using %s for URI scheme(s) [\"%s\"]\n",
1136 resolverInfo.type.GetTypeName().c_str(),
1137 TfStringJoin(uriSchemes, "\", \"").c_str());
1138
1139 // Create resolver. We only want one instance of each resolver
1140 // type, so make sure we reuse the primary resolver if it has
1141 // also been registered as handling additional URI schemes.
1142 _ResolverSharedPtr uriResolver =
1143 resolverInfo.type == _resolver->GetType() ?
1144 _resolver : std::make_shared<_Resolver>(resolverInfo);
1145
1146 for (std::string& uriScheme : uriSchemes) {
1147 maxSchemeLength = std::max(uriScheme.length(), maxSchemeLength);
1148 uriResolvers.emplace(std::move(uriScheme), uriResolver);
1149 };
1150 }
1151
1152 _uriResolvers = std::move(uriResolvers);
1153 _maxURISchemeLength = maxSchemeLength;
1154 }
1155
_InitializePackageResolvers()1156 void _InitializePackageResolvers()
1157 {
1158 std::set<TfType> packageResolverTypes;
1159 PlugRegistry::GetAllDerivedTypes<ArPackageResolver>(
1160 &packageResolverTypes);
1161
1162 _packageResolvers.reserve(packageResolverTypes.size());
1163
1164 PlugRegistry& plugReg = PlugRegistry::GetInstance();
1165 for (const TfType& packageResolverType : packageResolverTypes) {
1166 TF_DEBUG(AR_RESOLVER_INIT).Msg(
1167 "ArGetResolver(): Found package resolver %s\n",
1168 packageResolverType.GetTypeName().c_str());
1169
1170 const PlugPluginPtr plugin =
1171 plugReg.GetPluginForType(packageResolverType);
1172 if (!plugin) {
1173 TF_CODING_ERROR(
1174 "Could not find plugin for package resolver %s",
1175 packageResolverType.GetTypeName().c_str());
1176 continue;
1177 }
1178
1179 const JsOptionalValue extensionsVal = JsFindValue(
1180 plugin->GetMetadataForType(packageResolverType),
1181 _tokens->extensions.GetString());
1182 if (!extensionsVal) {
1183 TF_CODING_ERROR(
1184 "No package formats specified in '%s' metadata for '%s'",
1185 _tokens->extensions.GetText(),
1186 packageResolverType.GetTypeName().c_str());
1187 continue;
1188 }
1189
1190 std::vector<std::string> extensions;
1191 if (extensionsVal->IsArrayOf<std::string>()) {
1192 extensions = extensionsVal->GetArrayOf<std::string>();
1193 }
1194 else {
1195 TF_CODING_ERROR(
1196 "'%s' metadata for %s must be a list of strings.",
1197 _tokens->extensions.GetText(),
1198 packageResolverType.GetTypeName().c_str());
1199 continue;
1200 }
1201
1202 for (const std::string& extension : extensions) {
1203 if (extension.empty()) {
1204 continue;
1205 }
1206
1207 _packageResolvers.push_back(std::make_shared<_PackageResolver>(
1208 extension, plugin, packageResolverType));
1209
1210 TF_DEBUG(AR_RESOLVER_INIT).Msg(
1211 "ArGetResolver(): Using package resolver %s for %s "
1212 "from plugin %s\n",
1213 packageResolverType.GetTypeName().c_str(),
1214 extension.c_str(), plugin->GetName().c_str());
1215 }
1216 }
1217 }
1218
1219 ArResolver&
_GetResolver(const std::string & assetPath,const _ResolverInfo ** info=nullptr) const1220 _GetResolver(
1221 const std::string& assetPath,
1222 const _ResolverInfo** info = nullptr) const
1223 {
1224 ArResolver* uriResolver = _GetURIResolver(assetPath, info);
1225 if (uriResolver) {
1226 return *uriResolver;
1227 }
1228
1229 if (info) {
1230 *info = &_resolver->info;
1231 }
1232 return *(_resolver->Get());
1233 }
1234
1235 ArResolver*
_GetURIResolver(const std::string & assetPath,const _ResolverInfo ** info=nullptr) const1236 _GetURIResolver(
1237 const std::string& assetPath,
1238 const _ResolverInfo** info = nullptr) const
1239 {
1240 if (_uriResolvers.empty()) {
1241 return nullptr;
1242 }
1243
1244 // Search for the first ":" character delimiting a URI scheme in
1245 // the given asset path. As an optimization, we only search the
1246 // first _maxURISchemeLength + 1 (to accommodate the ":") characters.
1247 const size_t numSearchChars =
1248 std::min(assetPath.length(), _maxURISchemeLength + 1);
1249
1250 auto endIt = assetPath.begin() + numSearchChars;
1251 auto delimIt = std::find(assetPath.begin(), endIt, ':');
1252 if (delimIt == endIt) {
1253 return nullptr;
1254 }
1255
1256 return _GetURIResolverForScheme(
1257 std::string(assetPath.begin(), delimIt), info);
1258 }
1259
1260 ArResolver*
_GetURIResolverForScheme(const std::string & scheme,const _ResolverInfo ** info=nullptr) const1261 _GetURIResolverForScheme(
1262 const std::string& scheme,
1263 const _ResolverInfo** info = nullptr) const
1264 {
1265 // Per RFC 3986 sec 3.1 schemes are case-insensitive. The schemes
1266 // stored in _uriResolvers are always stored in lower-case, so
1267 // convert our candidate scheme to lower case as well.
1268 const _ResolverSharedPtr* uriResolver =
1269 TfMapLookupPtr(_uriResolvers, TfStringToLower(scheme));
1270 if (uriResolver) {
1271 if (info) {
1272 *info = &((*uriResolver)->info);
1273 }
1274 return (*uriResolver)->Get();
1275 }
1276
1277 return nullptr;
1278 }
1279
1280 ArPackageResolver*
_GetPackageResolver(const std::string & packageRelativePath) const1281 _GetPackageResolver(const std::string& packageRelativePath) const
1282 {
1283 const std::string innermostPackage =
1284 ArSplitPackageRelativePathInner(packageRelativePath).first;
1285 const std::string format = GetExtension(innermostPackage);
1286
1287 for (size_t i = 0, e = _packageResolvers.size(); i != e; ++i) {
1288 if (_packageResolvers[i]->HandlesFormat(format)) {
1289 return _packageResolvers[i]->Get();
1290 }
1291 }
1292
1293 return nullptr;
1294 }
1295
1296 template <class ResolveFn>
1297 ArResolvedPath
_ResolveHelper(const std::string & path,ResolveFn resolveFn) const1298 _ResolveHelper(const std::string& path, ResolveFn resolveFn) const
1299 {
1300 if (ArIsPackageRelativePath(path)) {
1301 // Resolve the outer-most package path first. For example, given a
1302 // path like "/path/to/p.package_a[sub.package_b[asset.file]]", the
1303 // underlying resolver needs to resolve "/path/to/p.package_a"
1304 // since this is a 'real' asset in the client's asset system.
1305 std::string packagePath, packagedPath;
1306 std::tie(packagePath, packagedPath) =
1307 ArSplitPackageRelativePathOuter(path);
1308
1309 std::string resolvedPackagePath = resolveFn(packagePath);
1310 if (resolvedPackagePath.empty()) {
1311 return ArResolvedPath();
1312 }
1313
1314 // Loop through the remaining packaged paths and resolve each
1315 // of them using the appropriate package resolver. In the above
1316 // example, this loop would:
1317 //
1318 // - Resolve "sub.package_b" in package "/path/to/p.package_a"
1319 // - Resolve "asset.file" in "/path/to/p.package_a[sub.package_b]"
1320 //
1321 while (!packagedPath.empty()) {
1322 std::tie(packagePath, packagedPath) =
1323 ArSplitPackageRelativePathOuter(packagedPath);
1324
1325 ArPackageResolver* packageResolver =
1326 _GetPackageResolver(resolvedPackagePath);
1327 if (!packageResolver) {
1328 return ArResolvedPath();
1329 }
1330
1331 packagePath = packageResolver->Resolve(
1332 resolvedPackagePath, packagePath);
1333 if (packagePath.empty()) {
1334 return ArResolvedPath();
1335 }
1336
1337 resolvedPackagePath = ArJoinPackageRelativePath(
1338 resolvedPackagePath, packagePath);
1339 }
1340
1341 return ArResolvedPath(std::move(resolvedPackagePath));
1342 }
1343
1344 return resolveFn(path);
1345 }
1346
1347 // Primary and URI Resolvers --------------------
1348
1349 class _Resolver
1350 : public _PluginResolver<ArResolver, Ar_ResolverFactoryBase>
1351 {
1352 using Base = _PluginResolver<ArResolver, Ar_ResolverFactoryBase>;
1353
1354 public:
_Resolver(const _ResolverInfo & info_,const std::shared_ptr<ArResolver> & resolver=nullptr)1355 _Resolver(
1356 const _ResolverInfo& info_,
1357 const std::shared_ptr<ArResolver>& resolver = nullptr)
1358 : Base(info_.plugin, info_.type, resolver)
1359 , info(info_)
1360 {
1361 }
1362
1363 _ResolverInfo info;
1364 };
1365
1366 using _ResolverSharedPtr = std::shared_ptr<_Resolver>;
1367
1368 // Primary Resolver
1369 _ResolverSharedPtr _resolver;
1370
1371 // URI Resolvers
1372 std::unordered_map<std::string, _ResolverSharedPtr> _uriResolvers;
1373 size_t _maxURISchemeLength;
1374
1375 // Package Resolvers --------------------
1376
1377 class _PackageResolver
1378 : public _PluginResolver<
1379 ArPackageResolver, Ar_PackageResolverFactoryBase>
1380 {
1381 using Base = _PluginResolver<
1382 ArPackageResolver, Ar_PackageResolverFactoryBase>;
1383
1384 public:
_PackageResolver(const std::string & packageFormat,const PlugPluginPtr & plugin,const TfType & resolverType)1385 _PackageResolver(
1386 const std::string& packageFormat,
1387 const PlugPluginPtr& plugin,
1388 const TfType& resolverType)
1389 : Base(plugin, resolverType)
1390 , _packageFormat(packageFormat)
1391 { }
1392
HandlesFormat(const std::string & extension) const1393 bool HandlesFormat(const std::string& extension) const
1394 {
1395 return _packageFormat == extension;
1396 }
1397
1398 private:
1399 std::string _packageFormat;
1400 };
1401
1402 using _PackageResolverSharedPtr = std::shared_ptr<_PackageResolver>;
1403 std::vector<_PackageResolverSharedPtr> _packageResolvers;
1404
1405 // Context Management --------------------
1406
1407 using _ContextStack = std::vector<const ArResolverContext*>;
1408 using _PerThreadContextStack =
1409 tbb::enumerable_thread_specific<_ContextStack>;
1410 mutable _PerThreadContextStack _threadContextStack;
1411
1412 // Scoped Cache --------------------
1413
1414 struct _Cache
1415 {
1416 using _PathToResolvedPathMap =
1417 tbb::concurrent_hash_map<std::string, ArResolvedPath>;
1418 _PathToResolvedPathMap _pathToResolvedPathMap;
1419 };
1420
1421 using _PerThreadCache = ArThreadLocalScopedCache<_Cache>;
1422 using _CachePtr = _PerThreadCache::CachePtr;
1423 mutable _PerThreadCache _threadCache;
1424
1425 };
1426
1427 _DispatchingResolver&
_GetResolver()1428 _GetResolver()
1429 {
1430 // If other threads enter this function while another thread is
1431 // constructing the resolver, it's guaranteed that those threads
1432 // will wait until the resolver is constructed.
1433 static _DispatchingResolver resolver;
1434 return resolver;
1435 }
1436
1437 } // end anonymous namespace
1438
1439
1440 // ------------------------------------------------------------
1441
ArResolver()1442 ArResolver::ArResolver()
1443 {
1444 }
1445
~ArResolver()1446 ArResolver::~ArResolver()
1447 {
1448 }
1449
1450 std::string
CreateIdentifier(const std::string & assetPath,const ArResolvedPath & anchorAssetPath) const1451 ArResolver::CreateIdentifier(
1452 const std::string& assetPath,
1453 const ArResolvedPath& anchorAssetPath) const
1454 {
1455 return _CreateIdentifier(assetPath, anchorAssetPath);
1456 }
1457
1458 std::string
CreateIdentifierForNewAsset(const std::string & assetPath,const ArResolvedPath & anchorAssetPath) const1459 ArResolver::CreateIdentifierForNewAsset(
1460 const std::string& assetPath,
1461 const ArResolvedPath& anchorAssetPath) const
1462 {
1463 return _CreateIdentifierForNewAsset(assetPath, anchorAssetPath);
1464 }
1465
1466 ArResolvedPath
Resolve(const std::string & assetPath) const1467 ArResolver::Resolve(
1468 const std::string& assetPath) const
1469 {
1470 return _Resolve(assetPath);
1471 }
1472
1473 ArResolvedPath
ResolveForNewAsset(const std::string & assetPath) const1474 ArResolver::ResolveForNewAsset(
1475 const std::string& assetPath) const
1476 {
1477 return _ResolveForNewAsset(assetPath);
1478 }
1479
1480 void
BindContext(const ArResolverContext & context,VtValue * bindingData)1481 ArResolver::BindContext(
1482 const ArResolverContext& context,
1483 VtValue* bindingData)
1484 {
1485 _BindContext(context, bindingData);
1486 }
1487
1488 void
UnbindContext(const ArResolverContext & context,VtValue * bindingData)1489 ArResolver::UnbindContext(
1490 const ArResolverContext& context,
1491 VtValue* bindingData)
1492 {
1493 _UnbindContext(context, bindingData);
1494 }
1495
1496 ArResolverContext
CreateDefaultContext() const1497 ArResolver::CreateDefaultContext() const
1498 {
1499 return _CreateDefaultContext();
1500 }
1501
1502 ArResolverContext
CreateDefaultContextForAsset(const std::string & assetPath) const1503 ArResolver::CreateDefaultContextForAsset(
1504 const std::string& assetPath) const
1505 {
1506 return _CreateDefaultContextForAsset(assetPath);
1507 }
1508
1509 ArResolverContext
CreateContextFromString(const std::string & contextStr) const1510 ArResolver::CreateContextFromString(
1511 const std::string& contextStr) const
1512 {
1513 return _CreateContextFromString(contextStr);
1514 }
1515
1516 ArResolverContext
CreateContextFromString(const std::string & uriScheme,const std::string & contextStr) const1517 ArResolver::CreateContextFromString(
1518 const std::string& uriScheme, const std::string& contextStr) const
1519 {
1520 return _GetResolver().CreateContextFromString(uriScheme, contextStr);
1521 }
1522
1523 ArResolverContext
CreateContextFromStrings(const std::vector<std::pair<std::string,std::string>> & contextStrs) const1524 ArResolver::CreateContextFromStrings(
1525 const std::vector<std::pair<std::string, std::string>>& contextStrs) const
1526 {
1527 return _GetResolver().CreateContextFromStrings(contextStrs);
1528 }
1529
1530 void
RefreshContext(const ArResolverContext & context)1531 ArResolver::RefreshContext(
1532 const ArResolverContext& context)
1533 {
1534 _RefreshContext(context);
1535 }
1536
1537 ArResolverContext
GetCurrentContext() const1538 ArResolver::GetCurrentContext() const
1539 {
1540 return _GetCurrentContext();
1541 }
1542
1543 std::string
GetExtension(const std::string & assetPath) const1544 ArResolver::GetExtension(
1545 const std::string& assetPath) const
1546 {
1547 return _GetExtension(assetPath);
1548 }
1549
1550 ArAssetInfo
GetAssetInfo(const std::string & assetPath,const ArResolvedPath & resolvedPath) const1551 ArResolver::GetAssetInfo(
1552 const std::string& assetPath,
1553 const ArResolvedPath& resolvedPath) const
1554 {
1555 return _GetAssetInfo(assetPath, resolvedPath);
1556 }
1557
1558 ArTimestamp
GetModificationTimestamp(const std::string & assetPath,const ArResolvedPath & resolvedPath) const1559 ArResolver::GetModificationTimestamp(
1560 const std::string& assetPath,
1561 const ArResolvedPath& resolvedPath) const
1562 {
1563 return _GetModificationTimestamp(assetPath, resolvedPath);
1564 }
1565
1566 std::shared_ptr<ArAsset>
OpenAsset(const ArResolvedPath & resolvedPath) const1567 ArResolver::OpenAsset(
1568 const ArResolvedPath& resolvedPath) const
1569 {
1570 return _OpenAsset(resolvedPath);
1571 }
1572
1573 std::shared_ptr<ArWritableAsset>
OpenAssetForWrite(const ArResolvedPath & resolvedPath,WriteMode mode) const1574 ArResolver::OpenAssetForWrite(
1575 const ArResolvedPath& resolvedPath,
1576 WriteMode mode) const
1577 {
1578 return _OpenAssetForWrite(resolvedPath, mode);
1579 }
1580
1581 bool
CanWriteAssetToPath(const ArResolvedPath & resolvedPath,std::string * whyNot) const1582 ArResolver::CanWriteAssetToPath(
1583 const ArResolvedPath& resolvedPath,
1584 std::string* whyNot) const
1585 {
1586 return _CanWriteAssetToPath(resolvedPath, whyNot);
1587 }
1588
1589 bool
IsContextDependentPath(const std::string & assetPath) const1590 ArResolver::IsContextDependentPath(
1591 const std::string& assetPath) const
1592 {
1593 return _IsContextDependentPath(assetPath);
1594 }
1595
1596 void
BeginCacheScope(VtValue * cacheScopeData)1597 ArResolver::BeginCacheScope(
1598 VtValue* cacheScopeData)
1599 {
1600 _BeginCacheScope(cacheScopeData);
1601 }
1602
1603 void
EndCacheScope(VtValue * cacheScopeData)1604 ArResolver::EndCacheScope(
1605 VtValue* cacheScopeData)
1606 {
1607 _EndCacheScope(cacheScopeData);
1608 }
1609
1610 bool
IsRepositoryPath(const std::string & path) const1611 ArResolver::IsRepositoryPath(
1612 const std::string& path) const
1613 {
1614 return _IsRepositoryPath(path);
1615 }
1616
1617 void
_BindContext(const ArResolverContext & context,VtValue * bindingData)1618 ArResolver::_BindContext(
1619 const ArResolverContext& context,
1620 VtValue* bindingData)
1621 {
1622 }
1623
1624 void
_UnbindContext(const ArResolverContext & context,VtValue * bindingData)1625 ArResolver::_UnbindContext(
1626 const ArResolverContext& context,
1627 VtValue* bindingData)
1628 {
1629 }
1630
1631 void
_BeginCacheScope(VtValue * cacheScopeData)1632 ArResolver::_BeginCacheScope(
1633 VtValue* cacheScopeData)
1634 {
1635 }
1636
1637 void
_EndCacheScope(VtValue * cacheScopeData)1638 ArResolver::_EndCacheScope(
1639 VtValue* cacheScopeData)
1640 {
1641 }
1642
1643 ArResolverContext
_CreateDefaultContext() const1644 ArResolver::_CreateDefaultContext() const
1645 {
1646 return ArResolverContext();
1647 }
1648
1649 ArResolverContext
_CreateDefaultContextForAsset(const std::string & assetPath) const1650 ArResolver::_CreateDefaultContextForAsset(
1651 const std::string& assetPath) const
1652 {
1653 return ArResolverContext();
1654 }
1655
1656 ArResolverContext
_CreateContextFromString(const std::string & contextStr) const1657 ArResolver::_CreateContextFromString(
1658 const std::string& contextStr) const
1659 {
1660 return ArResolverContext();
1661 }
1662
1663 void
_RefreshContext(const ArResolverContext & context)1664 ArResolver::_RefreshContext(
1665 const ArResolverContext& context)
1666 {
1667 }
1668
1669 ArResolverContext
_GetCurrentContext() const1670 ArResolver::_GetCurrentContext() const
1671 {
1672 return ArResolverContext();
1673 }
1674
1675 std::string
_GetExtension(const std::string & assetPath) const1676 ArResolver::_GetExtension(
1677 const std::string& assetPath) const
1678 {
1679 return TfGetExtension(assetPath);
1680 }
1681
1682 ArAssetInfo
_GetAssetInfo(const std::string & assetPath,const ArResolvedPath & resolvedPath) const1683 ArResolver::_GetAssetInfo(
1684 const std::string& assetPath,
1685 const ArResolvedPath& resolvedPath) const
1686 {
1687 return ArAssetInfo();
1688 }
1689
1690 ArTimestamp
_GetModificationTimestamp(const std::string & assetPath,const ArResolvedPath & resolvedPath) const1691 ArResolver::_GetModificationTimestamp(
1692 const std::string& assetPath,
1693 const ArResolvedPath& resolvedPath) const
1694 {
1695 return ArTimestamp();
1696 }
1697
1698 bool
_CanWriteAssetToPath(const ArResolvedPath & resolvedPath,std::string * whyNot) const1699 ArResolver::_CanWriteAssetToPath(
1700 const ArResolvedPath& resolvedPath,
1701 std::string* whyNot) const
1702 {
1703 return true;
1704 }
1705
1706 bool
_IsContextDependentPath(const std::string & assetPath) const1707 ArResolver::_IsContextDependentPath(
1708 const std::string& assetPath) const
1709 {
1710 return false;
1711 }
1712
1713 bool
_IsRepositoryPath(const std::string & path) const1714 ArResolver::_IsRepositoryPath(
1715 const std::string& path) const
1716 {
1717 return false;
1718 }
1719
1720 const ArResolverContext*
_GetInternallyManagedCurrentContext() const1721 ArResolver::_GetInternallyManagedCurrentContext() const
1722 {
1723 return _GetResolver().GetInternallyManagedCurrentContext();
1724 }
1725
1726 // ------------------------------------------------------------
1727
1728 ArResolver&
ArGetResolver()1729 ArGetResolver()
1730 {
1731 return _GetResolver();
1732 }
1733
1734 ArResolver&
ArGetUnderlyingResolver()1735 ArGetUnderlyingResolver()
1736 {
1737 return _GetResolver().GetPrimaryResolver();
1738 }
1739
1740 std::vector<TfType>
ArGetAvailableResolvers()1741 ArGetAvailableResolvers()
1742 {
1743 std::vector<TfType> resolverTypes;
1744 for (const _ResolverInfo& info :
1745 _GetAvailablePrimaryResolvers(_GetAvailableResolvers())) {
1746 resolverTypes.push_back(info.type);
1747 }
1748 return resolverTypes;
1749 }
1750
1751 std::unique_ptr<ArResolver>
ArCreateResolver(const TfType & resolverType)1752 ArCreateResolver(const TfType& resolverType)
1753 {
1754 return _CreateResolver(resolverType);
1755 }
1756
1757 PXR_NAMESPACE_CLOSE_SCOPE
1758