1 //
2 // Copyright 2016 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 #ifndef PXR_USD_SDF_FILE_FORMAT_H
25 #define PXR_USD_SDF_FILE_FORMAT_H
26 
27 /// \file sdf/fileFormat.h
28 
29 #include "pxr/pxr.h"
30 #include "pxr/usd/ar/ar.h"
31 #include "pxr/usd/sdf/api.h"
32 #include "pxr/usd/sdf/declareHandles.h"
33 #include "pxr/base/tf/declarePtrs.h"
34 #include "pxr/base/tf/refBase.h"
35 #include "pxr/base/tf/staticTokens.h"
36 #include "pxr/base/tf/token.h"
37 #include "pxr/base/tf/type.h"
38 #include "pxr/base/tf/weakBase.h"
39 
40 #include <map>
41 #include <string>
42 #include <vector>
43 
44 PXR_NAMESPACE_OPEN_SCOPE
45 
46 class ArAssetInfo;
47 class SdfSchemaBase;
48 class SdfLayerHints;
49 
50 SDF_DECLARE_HANDLES(SdfLayer);
51 SDF_DECLARE_HANDLES(SdfSpec);
52 TF_DECLARE_WEAK_AND_REF_PTRS(SdfAbstractData);
53 TF_DECLARE_WEAK_AND_REF_PTRS(SdfFileFormat);
54 
55 #define SDF_FILE_FORMAT_TOKENS   \
56     ((TargetArg, "target"))
57 
58 TF_DECLARE_PUBLIC_TOKENS(SdfFileFormatTokens, SDF_API, SDF_FILE_FORMAT_TOKENS);
59 
60 /// \class SdfFileFormat
61 ///
62 /// Base class for file format implementations.
63 ///
64 class SdfFileFormat
65     : public TfRefBase
66     , public TfWeakBase
67 {
68 public:
69     SdfFileFormat(const SdfFileFormat&) = delete;
70     SdfFileFormat& operator=(const SdfFileFormat&) = delete;
71 
72     /// Returns the schema for this format.
73     SDF_API const SdfSchemaBase& GetSchema() const;
74 
75     /// Returns the format identifier.
76     SDF_API const TfToken& GetFormatId() const;
77 
78     /// Returns the target for this file format.
79     SDF_API const TfToken& GetTarget() const;
80 
81     /// Returns the cookie to be used when writing files with this format.
82     SDF_API const std::string& GetFileCookie() const;
83 
84     /// Returns the current version of this file format.
85     SDF_API const TfToken& GetVersionString() const;
86 
87     /// Returns true if this file format is the primary format for the
88     /// extensions it handles.
89     SDF_API bool IsPrimaryFormatForExtensions() const;
90 
91     /// Returns a list of extensions that this format supports.
92     SDF_API const std::vector<std::string>& GetFileExtensions() const;
93 
94     /// Returns the primary file extension for this format. This is the
95     /// extension that is reported for layers using this file format.
96     SDF_API const std::string& GetPrimaryFileExtension() const;
97 
98     /// Returns true if \p extension matches one of the extensions returned by
99     /// GetFileExtensions.
100     SDF_API bool IsSupportedExtension(const std::string& extension) const;
101 
102     /// Returns true if this file format is a package containing other
103     /// assets.
104     SDF_API
105     virtual bool IsPackage() const;
106 
107     /// Returns the path of the "root" layer contained in the package
108     /// layer at \p resolvedPath produced by this file format. If this
109     /// file format is not a package, returns the empty string.
110     ///
111     /// The package root layer is the layer in the package layer that
112     /// is used when that package is opened via SdfLayer.
113     SDF_API
114     virtual std::string GetPackageRootLayerPath(
115         const std::string& resolvedPath) const;
116 
117     /// Type for specifying additional file format-specific arguments
118     /// to the various API below.
119     typedef std::map<std::string, std::string> FileFormatArguments;
120 
121     /// Returns the FileFormatArguments that correspond to the default behavior
122     /// of this file format when no FileFormatArguments are passed to NewLayer
123     /// or InitData.
124     SDF_API
125     virtual FileFormatArguments GetDefaultFileFormatArguments() const;
126 
127     /// This method allows the file format to bind to whatever data container is
128     /// appropriate.
129     ///
130     /// Returns a shared pointer to an SdfAbstractData implementation.
131     SDF_API
132     virtual SdfAbstractDataRefPtr
133     InitData(const FileFormatArguments& args) const;
134 
135     /// Instantiate a layer.
136     SDF_API
137     SdfLayerRefPtr NewLayer(const SdfFileFormatConstPtr &fileFormat,
138                             const std::string &identifier,
139                             const std::string &realPath,
140                             const ArAssetInfo& assetInfo,
141                             const FileFormatArguments &args) const;
142 
143     /// Return true if this file format prefers to skip reloading anonymous
144     /// layers.
145     SDF_API bool ShouldSkipAnonymousReload() const;
146 
147 #if AR_VERSION == 1
148     /// Return true if layers produced by this file format are based
149     /// on physical files on disk. If so, this file format requires
150     /// layers to be serialized to and read from files on disk.
151     ///
152     /// For file formats where this function returns true, when
153     /// opening a layer Sdf will fetch layers to the filesystem
154     /// via calls to ArResolver::FetchToLocalResolvedPath prior
155     /// to calling ReadFromFile.
156     ///
157     /// This allows asset systems that do not store layers as individual
158     /// files to operate with file formats that require these files.
159     ///
160     /// \sa ArResolver::Resolve
161     /// \sa ArResolver::FetchToLocalResolvedPath
162     SDF_API bool LayersAreFileBased() const;
163 #endif
164 
165     /// Returns true if anonymous layer identifiers should be passed to Read
166     /// when a layer is opened or reloaded.
167     ///
168     /// Anonymous layers will not have an asset backing and thus for most
169     /// file formats there is nothing that can be read for an anonymous layer.
170     /// However, there are file formats that use Read to generate dynamic layer
171     /// content without reading any data from the resolved asset associated with
172     /// the layer's identifier.
173     ///
174     /// For these types of file formats it is useful to be able to open
175     /// anonymous layers and allow Read to populate them to avoid requiring a
176     /// placeholder asset to exist just so Read can populate the layer.
177     SDF_API bool ShouldReadAnonymousLayers() const;
178 
179     /// Returns true if \p file can be read by this format.
180     SDF_API
181     virtual bool CanRead(
182         const std::string& file) const = 0;
183 
184     /// Reads scene description from the asset specified by \p resolvedPath
185     /// into the layer \p layer.
186     ///
187     /// \p metadataOnly is a flag that asks for only the layer metadata
188     /// to be read in, which can be much faster if that is all that is
189     /// required.  Note that this is just a hint: some FileFormat readers
190     /// may disregard this flag and still fully populate the layer contents.
191     ///
192     /// Returns true if the asset is successfully read into \p layer,
193     /// false otherwise.
194     SDF_API
195     virtual bool Read(
196         SdfLayer* layer,
197         const std::string& resolvedPath,
198         bool metadataOnly) const = 0;
199 
200     /// Writes the content in \p layer into the file at \p filePath. If the
201     /// content is successfully written, this method returns true. Otherwise,
202     /// false is returned and errors are posted. The default implementation
203     /// returns false.
204     SDF_API
205     virtual bool WriteToFile(
206         const SdfLayer& layer,
207         const std::string& filePath,
208         const std::string& comment = std::string(),
209         const FileFormatArguments& args = FileFormatArguments()) const;
210 
211     /// Reads data in the string \p str into the layer \p layer. If
212     /// the file is successfully read, this method returns true. Otherwise,
213     /// false is returned and errors are posted.
214     SDF_API
215     virtual bool ReadFromString(
216         SdfLayer* layer,
217         const std::string& str) const;
218 
219     /// Write the provided \p spec to \p out indented \p indent levels.
220     SDF_API
221     virtual bool WriteToStream(
222         const SdfSpecHandle &spec,
223         std::ostream& out,
224         size_t indent) const;
225 
226     /// Writes the content in \p layer to the string \p str. This function
227     /// should write a textual representation of \p layer to the stream
228     /// that can be read back in via ReadFromString.
229     SDF_API
230     virtual bool WriteToString(
231         const SdfLayer& layer,
232         std::string* str,
233         const std::string& comment = std::string()) const;
234 
235     /// Returns the set of resolved paths to external asset file dependencies
236     /// for the given \p layer. These are additional dependencies, specific to
237     /// the file format, that are needed when generating the layer's contents
238     /// and would not otherwise be discoverable through composition dependencies
239     /// (i.e. sublayers, references, and payloads).
240     ///
241     /// The default implementation returns an empty set. Derived file formats
242     /// that depend on external assets to read and generate layer content
243     /// should implement this function to return the external asset paths.
244     ///
245     /// \sa SdfLayer::GetExternalAssetDependencies
246     /// \sa SdfLayer::Reload
247     SDF_API
248     virtual std::set<std::string> GetExternalAssetDependencies(
249         const SdfLayer& layer) const;
250 
251     /// Returns the file extension for path or file name \p s, without the
252     /// leading dot character.
253     SDF_API static std::string GetFileExtension(const std::string& s);
254 
255     /// Returns a set containing the extension(s) corresponding to
256     /// all registered file formats.
257     SDF_API static std::set<std::string> FindAllFileFormatExtensions();
258 
259     /// Returns the file format instance with the specified \p formatId
260     /// identifier. If a format with a matching identifier is not found, this
261     /// returns a null file format pointer.
262     SDF_API
263     static SdfFileFormatConstPtr FindById(
264         const TfToken& formatId);
265 
266     /// Returns the file format instance that supports the extension for
267     /// \p path.  If a format with a matching extension is not found, this
268     /// returns a null file format pointer.
269     ///
270     /// An extension may be handled by multiple file formats, but each
271     /// with a different target. In such cases, if no \p target is specified,
272     /// the file format that is registered as the primary plugin will be
273     /// returned. Otherwise, the file format whose target matches \p target
274     /// will be returned.
275     SDF_API
276     static SdfFileFormatConstPtr FindByExtension(
277         const std::string& path,
278         const std::string& target = std::string());
279 
280     /// Returns a file format instance that supports the extension for \p
281     /// path and whose target matches one of those specified by the given
282     /// \p args. If the \p args specify no target, then the file format that is
283     /// registered as the primary plugin will be returned. If a format with a
284     /// matching extension is not found, this returns a null file format
285     /// pointer.
286     SDF_API
287     static SdfFileFormatConstPtr FindByExtension(
288         const std::string& path,
289         const FileFormatArguments& args);
290 
291 protected:
292     /// Constructor.
293     SDF_API SdfFileFormat(
294         const TfToken& formatId,
295         const TfToken& versionString,
296         const TfToken& target,
297         const std::string& extension);
298 
299     /// Constructor.
300     /// \p schema must remain valid for the lifetime of this file format.
301     SDF_API SdfFileFormat(
302         const TfToken& formatId,
303         const TfToken& versionString,
304         const TfToken& target,
305         const std::string& extension,
306         const SdfSchemaBase& schema);
307 
308     /// Disallow temporary SdfSchemaBase objects being passed to the c'tor.
309     SdfFileFormat(
310         const TfToken& formatId,
311         const TfToken& versionString,
312         const TfToken& target,
313         const std::string& extension,
314         const SdfSchemaBase&& schema) = delete;
315 
316     /// Constructor.
317     SDF_API SdfFileFormat(
318         const TfToken& formatId,
319         const TfToken& versionString,
320         const TfToken& target,
321         const std::vector<std::string> &extensions);
322 
323     /// Constructor.
324     /// \p schema must remain valid for the lifetime of this file format.
325     SDF_API SdfFileFormat(
326         const TfToken& formatId,
327         const TfToken& versionString,
328         const TfToken& target,
329         const std::vector<std::string> &extensions,
330         const SdfSchemaBase& schema);
331 
332     /// Disallow temporary SdfSchemaBase objects being passed to the c'tor.
333     SdfFileFormat(
334         const TfToken& formatId,
335         const TfToken& versionString,
336         const TfToken& target,
337         const std::vector<std::string> &extensions,
338         const SdfSchemaBase&& schema) = delete;
339 
340     /// Destructor.
341     SDF_API virtual ~SdfFileFormat();
342 
343     //
344     // Minimally break layer encapsulation with the following methods.  These
345     // methods are also intended to limit the need for SdfLayer friendship with
346     // SdfFileFormat child classes.
347     //
348 
349     /// Set the internal data for \p layer to \p data, possibly transferring
350     /// ownership of \p data.
351     ///
352     /// Existing layer hints are reset to the default hints.
353     SDF_API
354     static void _SetLayerData(
355         SdfLayer* layer, SdfAbstractDataRefPtr& data);
356 
357     /// Set the internal data for \p layer to \p data, possibly transferring
358     /// ownership of \p data.
359     ///
360     /// Existing layer hints are replaced with \p hints.
361     SDF_API
362     static void _SetLayerData(
363         SdfLayer* layer, SdfAbstractDataRefPtr& data,
364         SdfLayerHints hints);
365 
366     /// Get the internal data for \p layer.
367     SDF_API
368     static SdfAbstractDataConstPtr _GetLayerData(const SdfLayer& layer);
369 
370 protected:
371     SDF_API
372     virtual SdfLayer *_InstantiateNewLayer(
373         const SdfFileFormatConstPtr &fileFormat,
374         const std::string &identifier,
375         const std::string &realPath,
376         const ArAssetInfo& assetInfo,
377         const FileFormatArguments &args) const;
378 
379     // File format subclasses may override this if they prefer not to skip
380     // reloading anonymous layers.  Default implementation returns true.
381     SDF_API
382     virtual bool _ShouldSkipAnonymousReload() const;
383 
384 #if AR_VERSION == 1
385     /// File format subclasses may override this to specify whether
386     /// their layers are backed by physical files on disk.
387     /// Default implementation returns true.
388     SDF_API
389     virtual bool _LayersAreFileBased() const;
390 #endif
391 
392     /// File format subclasses may override this to specify whether
393     /// Read should be called when creating, opening, or reloading an anonymous
394     /// layer of this format.
395     /// Default implementation returns false.
396     SDF_API
397     virtual bool _ShouldReadAnonymousLayers() const;
398 
399 private:
400     const SdfSchemaBase& _schema;
401     const TfToken _formatId;
402     const TfToken _target;
403     const std::string _cookie;
404     const TfToken _versionString;
405     const std::vector<std::string> _extensions;
406     const bool _isPrimaryFormat;
407 };
408 
409 // Base file format factory.
410 class Sdf_FileFormatFactoryBase : public TfType::FactoryBase {
411 public:
412     virtual SdfFileFormatRefPtr New() const = 0;
413 };
414 
415 // Default file format factory.
416 template <typename T>
417 class Sdf_FileFormatFactory : public Sdf_FileFormatFactoryBase {
418 public:
New()419     virtual SdfFileFormatRefPtr New() const
420     {
421         return TfCreateRefPtr(new T);
422     }
423 };
424 
425 /// \def SDF_DEFINE_FILE_FORMAT
426 ///
427 /// Performs registrations needed for the specified file format class to be
428 /// discovered by Sdf. This typically would be invoked in a TF_REGISTRY_FUNCTION
429 /// in the source file defining the file format.
430 ///
431 /// The first argument is the name of the file format class being registered.
432 /// Subsequent arguments list the base classes of the file format. Since all
433 /// file formats must ultimately derive from SdfFileFormat, there should be
434 /// at least one base class specified.
435 ///
436 /// For example:
437 ///
438 /// \code
439 /// // in MyFileFormat.cpp
440 /// TF_REGISTRY_FUNCTION(TfType)
441 /// {
442 ///     SDF_DEFINE_FILE_FORMAT(MyFileFormat, SdfFileFormat);
443 /// }
444 /// \endcode
445 ///
446 #ifdef doxygen
447 #define SDF_DEFINE_FILE_FORMAT(FileFormatClass, BaseClass1, ...)
448 #else
449 #define SDF_DEFINE_FILE_FORMAT(...) SdfDefineFileFormat<__VA_ARGS__>()
450 
451 template <class FileFormat, class ...BaseFormats>
SdfDefineFileFormat()452 void SdfDefineFileFormat()
453 {
454     TfType::Define<FileFormat, TfType::Bases<BaseFormats...>>()
455         .template SetFactory<Sdf_FileFormatFactory<FileFormat>>();
456 }
457 #endif // doxygen
458 
459 /// \def SDF_DEFINE_ABSTRACT_FILE_FORMAT
460 ///
461 /// Performs registrations needed for the specified abstract file format
462 /// class. This is used to register types that serve as base classes
463 /// for other concrete file format classes used by Sdf.
464 ///
465 /// The first argument is the name of the file format class being registered.
466 /// Subsequent arguments list the base classes of the file format. Since all
467 /// file formats must ultimately derive from SdfFileFormat, there should be
468 /// at least one base class specified.
469 ///
470 /// For example:
471 ///
472 /// \code
473 /// // in MyFileFormat.cpp
474 /// TF_REGISTRY_FUNCTION(TfType)
475 /// {
476 ///     SDF_DEFINE_ABSTRACT_FILE_FORMAT(MyFileFormat, SdfFileFormat);
477 /// }
478 /// \endcode
479 ///
480 #ifdef doxygen
481 #define SDF_DEFINE_ABSTRACT_FILE_FORMAT(FileFormatClass, BaseClass1, ...)
482 #else
483 #define SDF_DEFINE_ABSTRACT_FILE_FORMAT(...) \
484     SdfDefineAbstractFileFormat<__VA_ARGS__>()
485 
486 template <class FileFormat, class ...BaseFormats>
SdfDefineAbstractFileFormat()487 void SdfDefineAbstractFileFormat()
488 {
489     TfType::Define<FileFormat, TfType::Bases<BaseFormats...>>();
490 }
491 #endif //doxygen
492 
493 /// \def SDF_FILE_FORMAT_FACTORY_ACCESS
494 ///
495 /// Provides access to allow file format classes to be instantiated
496 /// from Sdf. This should be specified in the class definition for
497 /// concrete file format classes.
498 ///
499 /// For example:
500 ///
501 /// \code
502 /// // in MyFileFormat.h
503 /// class MyFileFormat : public SdfFileFormat
504 /// {
505 ///     SDF_FILE_FORMAT_FACTORY_ACCESS;
506 ///     // ...
507 /// };
508 /// \endcode
509 ///
510 #ifdef doxygen
511 #define SDF_FILE_FORMAT_FACTORY_ACCESS
512 #else
513 #define SDF_FILE_FORMAT_FACTORY_ACCESS \
514     template<typename T> friend class Sdf_FileFormatFactory
515 #endif //doxygen
516 
517 PXR_NAMESPACE_CLOSE_SCOPE
518 
519 #endif
520