Home | History | Annotate | Download | only in dae
      1 /*
      2 * Copyright 2006 Sony Computer Entertainment Inc.
      3 *
      4 * Licensed under the MIT Open Source License, for details please see license.txt or the website
      5 * http://www.opensource.org/licenses/mit-license.php
      6 *
      7 */
      8 
      9 #ifndef __DAE_URI_H__
     10 #define __DAE_URI_H__
     11 
     12 #include <string>
     13 #include <dae/daeTypes.h>
     14 #include <dae/daeElement.h>
     15 #include <dae/daeUtils.h>
     16 class DAE;
     17 
     18 /**
     19  * The @c daeURI is a simple class designed to aid in the parsing and resolution
     20  * of URI references inside COLLADA elements.
     21  * A @c daeURI is created for every @c anyURL and @c IDREF in the COLLADA schema.
     22  * For example, the <instance> element has the url= attribute of type @c anyURL, and the
     23  * <controller> element has the target= attribute of type @c IDREF.
     24  * The @c daeURI class contains a URI string; the @c set() method breaks the string into
     25  * its components including scheme, authority, path (directory), and fragment.
     26  * It also has the capability to attempt to resolve this reference
     27  * into a @c daeElement, through the method @c resolveElement().
     28  * If a @c daeURI is stored within a @c daeElement, it fills
     29  * its container field to point to the containing element.
     30  *
     31  * The main API on the @c daeURI, @c resolveElement(), uses a @c daeURIResolver
     32  * to search for the @c daeElement inside a @c daeDatabase.
     33  *
     34  * URIs are resolved hierarchically, where each URI is resolved based on
     35  * the following criteria via itself and its element's base URI, which represents the
     36  * URI of the document that contains the element, retrieved by
     37  * <tt>daeElement::getBaseURI().</tt>
     38  * If no base URI is provided, then the application URI
     39  * is used as a base.
     40  *
     41  * The URI resolution order for the COLLADA DOM is as follows:
     42  * - Absolute URI is specified (see definition below):
     43  *   The URI ignores its parent/base URI when validating.
     44  * - Relative URI is specified:
     45  *   The URI uses the base URI to provide the scheme, authority, and base path.
     46  *    This URI's path is appended to the path given the the base URI.
     47  *    This URI's file and ID are used.
     48  * - Each level of URI is resolved in this way against the base URI of the
     49  *    containing file until the top level is reached.  Then the application URI
     50  *    is used as the default.
     51  *
     52  * <b>Definition of Absolute URI:</b>
     53  * For the purposes of the COLLADA DOM, a URI is considered absolute
     54  * if it starts by specifying a scheme.
     55  * For example,
     56  * - file:///c:/data/foo.dae#myScene is an absolute URI.
     57  * - foo.dae#myScene is relative.
     58  * - foo.dae is a top-level file reference and is relative.
     59  * If the URI does not include a pound sign (#), the <tt><i>fragment</i></tt> is empty.
     60  */
     61 class DLLSPEC daeURI
     62 {
     63 private:
     64 	daeElement* internalResolveElement() const;
     65 
     66 public:
     67 	/**
     68 	 * An enum describing the status of the URI resolution process.
     69 	 * This is pretty much entirely useless now. Just use the various accessors
     70 	 * to query the state of the uri.
     71 	 */
     72 	enum ResolveState{
     73 		/** No URI specified */
     74 		uri_empty,
     75 		/** URI specified but unresolved */
     76 		uri_loaded,
     77 		/** Resolution pending */
     78 		uri_pending,
     79 		/** Resolution successful */
     80 		uri_success,
     81 		/** Failure due to unsupported URI scheme */
     82 		uri_failed_unsupported_protocol,
     83 		/** Failure because the file was not found */
     84 		uri_failed_file_not_found,
     85 		/** Failure because the fragment was not found */
     86 		uri_failed_id_not_found,
     87 		/** Failure due to an invalid fragment */
     88 		uri_failed_invalid_id,
     89 		/** A flag specifying that the URI should be resolved locally to its own document */
     90 		uri_resolve_local,
     91 		/** A flag specifying that the URI should be resolved using this relative URI */
     92 		uri_resolve_relative,
     93 		/** A flag specifying that the URI should be resolved using this absolute URI */
     94 		uri_resolve_absolute,
     95 		/** Failure due to an invalid reference */
     96 		uri_failed_invalid_reference,
     97 		/** Failure due to an external error */
     98 		uri_failed_externalization,
     99 		/** Failure due to missing document */
    100 		uri_failed_missing_container,
    101 		/** Failure because automatic loading of a document is turned off */
    102 		uri_failed_external_document
    103 	};
    104 
    105 private:
    106 	// All daeURIs have a pointer to a master DAE that they use to access global information.
    107 	mutable DAE* dae;
    108 
    109 	/** Resolved version of the URI */
    110 	std::string uriString;
    111 
    112 	/** Original URI before resolution */
    113 	std::string originalURIString;
    114 
    115 	/** scheme component */
    116 	std::string _scheme;
    117 	/** authority component */
    118 	std::string _authority;
    119 	/** path component */
    120 	std::string _path;
    121 	/** query component */
    122 	std::string _query;
    123 	/** fragment component */
    124 	std::string _fragment;
    125 	/** Pointer to the element that owns this URI */
    126 	daeElement* container;
    127 
    128 public:
    129 	/**
    130 	 * Constructs a daeURI object that contains no URI reference.
    131 	 * @param dae The DAE associated with this daeURI.
    132 	 * current working directory.
    133 	 */
    134 	daeURI(DAE& dae);
    135 	/**
    136 	 * Destructor
    137 	 */
    138 	~daeURI();
    139 
    140 	/**
    141 	 * Constructs a daeURI object from a URI passed in as a string.
    142 	 * @param dae The DAE associated with this daeURI.
    143 	 * @param URIString Passed to set() automatically.
    144 	 * @param nofrag If true, the fragment part of the URI is stripped off before construction.
    145 	 */
    146 	daeURI(DAE& dae, const std::string& URIString, daeBool nofrag = false);
    147 
    148 	/**
    149 	 * Constructs a daeURI object using a <tt><i>baseURI</i></tt> and a <tt><i>uriString.</i></tt>
    150 	 * Calls set(URIString), and @c validate(baseURI).
    151 	 * @param baseURI Base URI to resolve against.
    152 	 * @param URIString String designating this URI.
    153 	 */
    154 	daeURI(const daeURI& baseURI, const std::string& URIString);
    155 
    156 	/**
    157 	 * Constructs a daeURI object based on a simple copy from an existing @c daeURI.
    158 	 * @param constructFromURI  URI to copy into this one.
    159 	 */
    160 	daeURI(const daeURI& constructFromURI);
    161 
    162 	/**
    163 	 * Constructs a daeURI given a container element and a URI string.
    164 	 * @param container The container element.
    165 	 * @param uriString the URI string.
    166 	 */
    167 	daeURI(daeElement& container, const std::string& uriString = "");
    168 
    169 	// This constructor is for internal DOM purposes only. For client code, use the constructor
    170 	// that takes only a daeElement instead of this one.
    171 	daeURI(DAE& dae, daeElement& container, const std::string& uriString = "");
    172 
    173 	/**
    174 	 * Gets the DAE objects associated with this daeURI.
    175 	 * @return Returns a pointer to the associated DAE. This will never return null.
    176 	 */
    177 	DAE* getDAE() const;
    178 
    179 	// Returns the fully resolved URI as a string
    180 	const std::string& str() const;
    181 	// Returns the URI as originally set (i.e. not resolved against the base URI)
    182 	const std::string& originalStr() const;
    183 
    184 	// Old C string versions of the previous functions
    185 	daeString getURI() const; // Alias for str()
    186 	daeString getOriginalURI() const; // Alias for originalStr();
    187 
    188 	// Setter function for setting the full uri.
    189 	void set(const std::string& uriStr, const daeURI* baseURI = NULL);
    190 	// Setter function for setting the individual uri components.
    191 	void set(const std::string& scheme,
    192 	         const std::string& authority,
    193 	         const std::string& path,
    194 	         const std::string& query,
    195 	         const std::string& fragment,
    196 	         const daeURI* baseURI = NULL);
    197 
    198 	// Old C string function. Alias for set().
    199 	void setURI(daeString uriStr, const daeURI* baseURI = NULL);
    200 
    201 	// std::string based component accessors.
    202 	const std::string& scheme() const;
    203 	const std::string& authority() const;
    204 	const std::string& path() const;
    205 	const std::string& query() const;
    206 	const std::string& fragment() const;
    207 	const std::string& id() const; // Alias for fragment()
    208 
    209 	// Component setter functions. If you're going to be calling multiple setters, as in
    210 	//   uri.path(path);
    211 	//   uri.fragment(frag);
    212 	// it'd be more efficient to call uri.set once instead.
    213 	void scheme(const std::string& scheme);
    214 	void authority(const std::string& authority);
    215 	void path(const std::string& path);
    216 	void query(const std::string& query);
    217 	void fragment(const std::string& fragment);
    218 	void id(const std::string& id); // Alias for uri.fragment(frag)
    219 
    220 	// Retrieves the individual path components. For example, in a uri of the form
    221 	// file:/folder/file.dae, dir = /folder/, baseName = file, ext = .dae
    222 	void pathComponents(std::string& dir, std::string& baseName, std::string& ext) const;
    223 
    224 	// Individual path component accessors. If you need access to multiple path
    225 	// components, calling pathComponents() will be faster.
    226 	std::string pathDir() const;      // daeURI("/folder/file.dae").pathDir() == "/folder/"
    227 	std::string pathFileBase() const; // daeURI("/folder/file.dae").pathFileBase() == "file"
    228 	std::string pathExt() const;      // daeURI("/folder/file.dae").pathExt() == ".dae"
    229 	std::string pathFile() const;     // daeURI("/folder/file.dae").pathFile() == "file.dae"
    230 
    231 	// Path component setter.
    232 	void path(const std::string& dir, const std::string& baseName, const std::string& ext);
    233 
    234 	// Individual path component setters. If you're going to be calling multiple setters,
    235 	// it'd be more efficient to call set() instead.
    236 	void pathDir(const std::string& dir);
    237 	void pathFileBase(const std::string& baseName);
    238 	void pathExt(const std::string& ext);
    239 	void pathFile(const std::string& file);
    240 
    241 	// The older C string accessors. Aliases for the std::string based component accessors.
    242 	daeString getScheme() const;
    243 	daeString getProtocol() const; // Alias for getScheme()
    244 	daeString getAuthority() const;
    245 	daeString getPath() const;
    246 	daeString getQuery() const;
    247 	daeString getFragment() const;
    248 	daeString getID() const; // Alias for getFragment()
    249 	// Same as getPath(), but puts the result in the destination buffer. This is only here
    250 	// for backward compatibility. Use getPath() instead.
    251 	daeBool getPath(daeChar* dest, daeInt size) const;
    252 
    253 	/**
    254 	 * Gets the element that this URI resolves to in memory.
    255 	 * @return Returns a ref to the element.
    256 	 */
    257 	daeElementRef getElement() const;
    258 
    259 	// Returns the document that this URI references, or null if the document
    260 	// hasn't been loaded yet.
    261 	daeDocument* getReferencedDocument() const;
    262 
    263 	/**
    264 	 * Gets a pointer to the @c daeElement that contains this URI.
    265 	 * @return Returns the pointer to the containing daeElmement.
    266 	 */
    267 	inline daeElement* getContainer() const {return(container);};
    268 
    269 	/**
    270 	 * Sets the pointer to the @c daeElement that contains this URI.
    271 	 * @param cont Pointer to the containing @c daeElmement.
    272 	 */
    273 	void setContainer(daeElement* container);
    274 
    275 	/**
    276 	 * Gets if this URI resolves to an element that is not contained in the same document as the URI.
    277 	 * @return Returns true if the URI references an external element. False otherwise.
    278 	 */
    279 	daeBool isExternalReference() const;
    280 
    281 	/**
    282 	 * Copies the URI specified in <tt><i>from</i></tt> into @c this.
    283 	 * Performs a simple copy without validating the URI.
    284 	 * @param from URI to copy from.
    285 	 */
    286 	void copyFrom(const daeURI& from);
    287 
    288 	/**
    289 	 * Outputs all components of this URI to stderr.
    290 	 * Useful for debugging URIs, this outputs each part of the URI separately.
    291 	 */
    292 	void print();
    293 
    294 	/**
    295 	 * Makes the "originalURI" in this URI relative to some other uri
    296 	 * @param uri the URI to make "this" relative to.
    297 	 * @note this is experimental and not fully tested, please don't use in critical code yet.
    298 	 */
    299 	int makeRelativeTo(const daeURI* uri);
    300 
    301 	/**
    302 	 * Comparison operator.
    303 	 * @return Returns true if URI's are equal.
    304 	 */
    305 	inline bool operator==(const daeURI& other) const {
    306 		return uriString == other.uriString;
    307 	}
    308 
    309 	daeURI& operator=(const daeURI& other);
    310 	daeURI& operator=(const std::string& uri);
    311 
    312 	// These methods are deprecated.
    313 	void resolveElement(); // Call getElement directly.
    314 	void validate(const daeURI* baseURI = NULL); // Shouldn't ever need to call this.
    315 	ResolveState getState() const; 	// Call getElement to see if resolving succeeded.
    316 	void setState(ResolveState newState); // Don't call this.
    317 
    318 private:
    319 	/**
    320 	 * Resets this URI; frees all string references
    321 	 * and returns <tt><i>state</i></tt> to @c empty.
    322 	 */
    323 	void reset();
    324 
    325 	/**
    326 	 * Provides a shared initialization for all constructors
    327 	 */
    328 	void initialize();
    329 public:
    330 	/**
    331 	 * Performs RFC2396 path normalization.
    332 	 * @param path Path to be normalized.
    333 	 */
    334 	static void normalizeURIPath(char* path);
    335 };
    336 
    337 class daeURIResolver;
    338 typedef daeTArray<daeURIResolver*> daeURIResolverPtrArray;
    339 
    340 /**
    341  * The @c daeURIResolver class is the plugin point for URI resolution.
    342  * This class is an abstract base class that defines an interface for
    343  * resolving URIs.
    344  * Every URI is passed through this list of @c daeURIResolvers for resolution.
    345  * The list is ordered on a first come, first serve basis, and resolution
    346  * terminates after any resolver instance resolves the URI.
    347  */
    348 class DLLSPEC daeURIResolver
    349 {
    350 public:
    351 	/**
    352 	 * Constructor
    353 	 * @param dae The associated dae object.
    354 	 */
    355 	daeURIResolver(DAE& dae);
    356 
    357 	/**
    358 	 * Destructor
    359 	 */
    360 	virtual ~daeURIResolver();
    361 
    362 	/**
    363 	 * Sets a flag that tells the URI resolver whether or not to load a separate document if a URI
    364 	 * being resolved points to one.
    365 	 * @param load Set to true if you want the URI Resolver to automatically load other documents to
    366 	 * resolve URIs.
    367 	 */
    368 	static void setAutoLoadExternalDocuments( daeBool load );
    369 
    370 	/**
    371 	 * Gets a flag that tells if the URI resolver is set to load an external document if a URI
    372 	 * being resolved points to one.
    373 	 * @return Returns true if the resolver will automatically load documents to resolve a URI.
    374 	 * False otherwise.
    375 	 */
    376 	static daeBool getAutoLoadExternalDocuments();
    377 
    378 	/**
    379 	 * Provides an abstract interface for converting a @c daeURI into a @c daeElement
    380 	 * @param uri @c daeURI to resolve.
    381 	 * @return Returns the resolved element, or null if resolving failed.
    382 	 * returns false otherwise.
    383 	 */
    384 	virtual daeElement* resolveElement(const daeURI& uri) = 0;
    385 
    386 	/**
    387 	 * Gets the name of this resolver.
    388 	 * @return Returns the resolver name as a string.
    389 	 */
    390 	virtual daeString getName() = 0;
    391 
    392 protected:
    393 	static daeBool _loadExternalDocuments;
    394 	DAE* dae;
    395 };
    396 
    397 
    398 // This is a container class for storing a modifiable list of daeURIResolver objects.
    399 class DLLSPEC daeURIResolverList {
    400 public:
    401 	daeURIResolverList();
    402 	~daeURIResolverList();
    403 
    404 	daeTArray<daeURIResolver*>& list();
    405 	daeElement* resolveElement(const daeURI& uri);
    406 
    407 private:
    408 	// Disabled copy constructor/assignment operator
    409 	daeURIResolverList(const daeURIResolverList& resolverList) { };
    410 	daeURIResolverList& operator=(const daeURIResolverList& resolverList) { return *this; };
    411 
    412 	daeTArray<daeURIResolver*> resolvers;
    413 };
    414 
    415 
    416 // Helper functions for file path <--> URI conversion
    417 namespace cdom {
    418 	// Takes a uri reference and parses it into its components.
    419 	DLLSPEC bool parseUriRef(const std::string& uriRef,
    420 	                         std::string& scheme,
    421 	                         std::string& authority,
    422 	                         std::string& path,
    423 	                         std::string& query,
    424 	                         std::string& fragment);
    425 
    426 	// Takes the uri components of a uri ref and combines them.
    427 	//
    428 	// The 'forceLibxmlCompatible' param is meant to work around bugs in the file
    429 	// scheme uri handling of libxml. It causes the function to output a uri
    430 	// that's fully compatible with libxml. It only modifies file scheme uris,
    431 	// since uris with other schemes seem to work fine.
    432 	//
    433 	// The known libxml uri bugs are as follows:
    434 	//   1) libxml won't write files when given file scheme URIs with an empty
    435 	//      authority, as in "file:/home".
    436 	//   2) libxml won't read or write Windows UNC paths represented with the
    437 	//      machine name in the authority, as in "file://otherMachine/folder/file.dae"
    438 	//   3) On Windows, libxml won't read or write paths that don't have a drive
    439 	//      letter, as in "/folder/file.dae".
    440 	DLLSPEC std::string assembleUri(const std::string& scheme,
    441 	                                const std::string& authority,
    442 	                                const std::string& path,
    443 	                                const std::string& query,
    444 	                                const std::string& fragment,
    445 	                                bool forceLibxmlCompatible = false);
    446 
    447 	// A wrapper function for calling assembleUri to create a URI that's compatible
    448 	// with libxml.
    449 	DLLSPEC std::string fixUriForLibxml(const std::string& uriRef);
    450 
    451 	// This function takes a file path in the OS's native format and converts it to
    452 	// a URI reference. If a relative path is given, a relative URI reference is
    453 	// returned. If an absolute path is given, a relative URI reference containing
    454 	// a fully specified path is returned. Spaces are encoded as %20. The 'type'
    455 	// parameter indicates the format of the nativePath.
    456 	//
    457 	// Examples - Windows
    458 	//   nativePathToUri("C:\myFolder\myFile.dae") --> "/C:/myFolder/myFile.dae"
    459 	//   nativePathToUri("\myFolder\myFile.dae") --> "/myFolder/myFile.dae"
    460 	//   nativePathToUri("..\myFolder\myFile.dae") --> "../myFolder/myFile.dae"
    461 	//   nativePathToUri("\\otherComputer\myFile.dae") --> "//otherComputer/myFile.dae"
    462 	//
    463 	// Examples - Linux/Mac
    464 	//   nativePathToUri("/myFolder/myFile.dae") --> "/myFolder/myFile.dae"
    465 	//   nativePathToUri("../myFolder/myFile.dae") --> "../myFolder/myFile.dae"
    466 	//   nativePathToUri("/my folder/my file.dae") --> "/my%20folder/my%20file.dae"
    467 	DLLSPEC std::string nativePathToUri(const std::string& nativePath,
    468 	                                    systemType type = getSystemType());
    469 
    470 	// This function takes a URI reference and converts it to an OS file path. Conversion
    471 	// can fail if the URI reference is ill-formed, or if the URI contains a scheme other
    472 	// than "file", in which case an empty string is returned. The 'type' parameter
    473 	// indicates the format of the returned native path.
    474 	//
    475 	// Examples - Windows
    476 	//   uriToNativePath("../folder/file.dae") --> "..\folder\file.dae"
    477 	//   uriToNativePath("/folder/file.dae") --> "\folder\file.dae"
    478 	//   uriToNativePath("file:/C:/folder/file.dae") --> "C:\folder\file.dae"
    479 	//   uriToNativePath("file://otherComputer/file.dae") --> "\\otherComputer\file.dae"
    480 	//   uriToNativePath("http://www.slashdot.org") --> "" (it's not a file scheme URI!)
    481 	//
    482 	// Examples - Linux/Mac
    483 	//   uriToNativePath("../folder/file.dae") --> "../folder/file.dae"
    484 	//   uriToNativePath("file:/folder/file.dae") --> "/folder/file.dae"
    485 	//   uriToNativePath("http://www.slashdot.org") --> "" (it's not a file scheme URI!)
    486 	DLLSPEC std::string uriToNativePath(const std::string& uriRef,
    487 	                                    systemType type = getSystemType());
    488 
    489 	DLLSPEC std::string filePathToUri(const std::string& filePath); // Alias for nativePathToUri
    490 	DLLSPEC std::string uriToFilePath(const std::string& uriRef); // Alias for uriToNativePath
    491 }
    492 
    493 #endif //__DAE_URI_H__
    494