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