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