/* * Copyright 2006 Sony Computer Entertainment Inc. * * Licensed under the MIT Open Source License, for details please see license.txt or the website * http://www.opensource.org/licenses/mit-license.php * */ #ifndef __DAE_URI_H__ #define __DAE_URI_H__ #include #include #include #include class DAE; /** * The @c daeURI is a simple class designed to aid in the parsing and resolution * of URI references inside COLLADA elements. * A @c daeURI is created for every @c anyURL and @c IDREF in the COLLADA schema. * For example, the element has the url= attribute of type @c anyURL, and the * element has the target= attribute of type @c IDREF. * The @c daeURI class contains a URI string; the @c set() method breaks the string into * its components including scheme, authority, path (directory), and fragment. * It also has the capability to attempt to resolve this reference * into a @c daeElement, through the method @c resolveElement(). * If a @c daeURI is stored within a @c daeElement, it fills * its container field to point to the containing element. * * The main API on the @c daeURI, @c resolveElement(), uses a @c daeURIResolver * to search for the @c daeElement inside a @c daeDatabase. * * URIs are resolved hierarchically, where each URI is resolved based on * the following criteria via itself and its element's base URI, which represents the * URI of the document that contains the element, retrieved by * daeElement::getBaseURI(). * If no base URI is provided, then the application URI * is used as a base. * * The URI resolution order for the COLLADA DOM is as follows: * - Absolute URI is specified (see definition below): * The URI ignores its parent/base URI when validating. * - Relative URI is specified: * The URI uses the base URI to provide the scheme, authority, and base path. * This URI's path is appended to the path given the the base URI. * This URI's file and ID are used. * - Each level of URI is resolved in this way against the base URI of the * containing file until the top level is reached. Then the application URI * is used as the default. * * Definition of Absolute URI: * For the purposes of the COLLADA DOM, a URI is considered absolute * if it starts by specifying a scheme. * For example, * - file:///c:/data/foo.dae#myScene is an absolute URI. * - foo.dae#myScene is relative. * - foo.dae is a top-level file reference and is relative. * If the URI does not include a pound sign (#), the fragment is empty. */ class DLLSPEC daeURI { private: daeElement* internalResolveElement() const; public: /** * An enum describing the status of the URI resolution process. * This is pretty much entirely useless now. Just use the various accessors * to query the state of the uri. */ enum ResolveState{ /** No URI specified */ uri_empty, /** URI specified but unresolved */ uri_loaded, /** Resolution pending */ uri_pending, /** Resolution successful */ uri_success, /** Failure due to unsupported URI scheme */ uri_failed_unsupported_protocol, /** Failure because the file was not found */ uri_failed_file_not_found, /** Failure because the fragment was not found */ uri_failed_id_not_found, /** Failure due to an invalid fragment */ uri_failed_invalid_id, /** A flag specifying that the URI should be resolved locally to its own document */ uri_resolve_local, /** A flag specifying that the URI should be resolved using this relative URI */ uri_resolve_relative, /** A flag specifying that the URI should be resolved using this absolute URI */ uri_resolve_absolute, /** Failure due to an invalid reference */ uri_failed_invalid_reference, /** Failure due to an external error */ uri_failed_externalization, /** Failure due to missing document */ uri_failed_missing_container, /** Failure because automatic loading of a document is turned off */ uri_failed_external_document }; private: // All daeURIs have a pointer to a master DAE that they use to access global information. mutable DAE* dae; /** Resolved version of the URI */ std::string uriString; /** Original URI before resolution */ std::string originalURIString; /** scheme component */ std::string _scheme; /** authority component */ std::string _authority; /** path component */ std::string _path; /** query component */ std::string _query; /** fragment component */ std::string _fragment; /** Pointer to the element that owns this URI */ daeElement* container; public: /** * Constructs a daeURI object that contains no URI reference. * @param dae The DAE associated with this daeURI. * current working directory. */ daeURI(DAE& dae); /** * Destructor */ ~daeURI(); /** * Constructs a daeURI object from a URI passed in as a string. * @param dae The DAE associated with this daeURI. * @param URIString Passed to set() automatically. * @param nofrag If true, the fragment part of the URI is stripped off before construction. */ daeURI(DAE& dae, const std::string& URIString, daeBool nofrag = false); /** * Constructs a daeURI object using a baseURI and a uriString. * Calls set(URIString), and @c validate(baseURI). * @param baseURI Base URI to resolve against. * @param URIString String designating this URI. */ daeURI(const daeURI& baseURI, const std::string& URIString); /** * Constructs a daeURI object based on a simple copy from an existing @c daeURI. * @param constructFromURI URI to copy into this one. */ daeURI(const daeURI& constructFromURI); /** * Constructs a daeURI given a container element and a URI string. * @param container The container element. * @param uriString the URI string. */ daeURI(daeElement& container, const std::string& uriString = ""); // This constructor is for internal DOM purposes only. For client code, use the constructor // that takes only a daeElement instead of this one. daeURI(DAE& dae, daeElement& container, const std::string& uriString = ""); /** * Gets the DAE objects associated with this daeURI. * @return Returns a pointer to the associated DAE. This will never return null. */ DAE* getDAE() const; // Returns the fully resolved URI as a string const std::string& str() const; // Returns the URI as originally set (i.e. not resolved against the base URI) const std::string& originalStr() const; // Old C string versions of the previous functions daeString getURI() const; // Alias for str() daeString getOriginalURI() const; // Alias for originalStr(); // Setter function for setting the full uri. void set(const std::string& uriStr, const daeURI* baseURI = NULL); // Setter function for setting the individual uri components. void set(const std::string& scheme, const std::string& authority, const std::string& path, const std::string& query, const std::string& fragment, const daeURI* baseURI = NULL); // Old C string function. Alias for set(). void setURI(daeString uriStr, const daeURI* baseURI = NULL); // std::string based component accessors. const std::string& scheme() const; const std::string& authority() const; const std::string& path() const; const std::string& query() const; const std::string& fragment() const; const std::string& id() const; // Alias for fragment() // Component setter functions. If you're going to be calling multiple setters, as in // uri.path(path); // uri.fragment(frag); // it'd be more efficient to call uri.set once instead. void scheme(const std::string& scheme); void authority(const std::string& authority); void path(const std::string& path); void query(const std::string& query); void fragment(const std::string& fragment); void id(const std::string& id); // Alias for uri.fragment(frag) // Retrieves the individual path components. For example, in a uri of the form // file:/folder/file.dae, dir = /folder/, baseName = file, ext = .dae void pathComponents(std::string& dir, std::string& baseName, std::string& ext) const; // Individual path component accessors. If you need access to multiple path // components, calling pathComponents() will be faster. std::string pathDir() const; // daeURI("/folder/file.dae").pathDir() == "/folder/" std::string pathFileBase() const; // daeURI("/folder/file.dae").pathFileBase() == "file" std::string pathExt() const; // daeURI("/folder/file.dae").pathExt() == ".dae" std::string pathFile() const; // daeURI("/folder/file.dae").pathFile() == "file.dae" // Path component setter. void path(const std::string& dir, const std::string& baseName, const std::string& ext); // Individual path component setters. If you're going to be calling multiple setters, // it'd be more efficient to call set() instead. void pathDir(const std::string& dir); void pathFileBase(const std::string& baseName); void pathExt(const std::string& ext); void pathFile(const std::string& file); // The older C string accessors. Aliases for the std::string based component accessors. daeString getScheme() const; daeString getProtocol() const; // Alias for getScheme() daeString getAuthority() const; daeString getPath() const; daeString getQuery() const; daeString getFragment() const; daeString getID() const; // Alias for getFragment() // Same as getPath(), but puts the result in the destination buffer. This is only here // for backward compatibility. Use getPath() instead. daeBool getPath(daeChar* dest, daeInt size) const; /** * Gets the element that this URI resolves to in memory. * @return Returns a ref to the element. */ daeElementRef getElement() const; // Returns the document that this URI references, or null if the document // hasn't been loaded yet. daeDocument* getReferencedDocument() const; /** * Gets a pointer to the @c daeElement that contains this URI. * @return Returns the pointer to the containing daeElmement. */ inline daeElement* getContainer() const {return(container);}; /** * Sets the pointer to the @c daeElement that contains this URI. * @param cont Pointer to the containing @c daeElmement. */ void setContainer(daeElement* container); /** * Gets if this URI resolves to an element that is not contained in the same document as the URI. * @return Returns true if the URI references an external element. False otherwise. */ daeBool isExternalReference() const; /** * Copies the URI specified in from into @c this. * Performs a simple copy without validating the URI. * @param from URI to copy from. */ void copyFrom(const daeURI& from); /** * Outputs all components of this URI to stderr. * Useful for debugging URIs, this outputs each part of the URI separately. */ void print(); /** * Makes the "originalURI" in this URI relative to some other uri * @param uri the URI to make "this" relative to. * @note this is experimental and not fully tested, please don't use in critical code yet. */ int makeRelativeTo(const daeURI* uri); /** * Comparison operator. * @return Returns true if URI's are equal. */ inline bool operator==(const daeURI& other) const { return uriString == other.uriString; } daeURI& operator=(const daeURI& other); daeURI& operator=(const std::string& uri); // These methods are deprecated. void resolveElement(); // Call getElement directly. void validate(const daeURI* baseURI = NULL); // Shouldn't ever need to call this. ResolveState getState() const; // Call getElement to see if resolving succeeded. void setState(ResolveState newState); // Don't call this. private: /** * Resets this URI; frees all string references * and returns state to @c empty. */ void reset(); /** * Provides a shared initialization for all constructors */ void initialize(); public: /** * Performs RFC2396 path normalization. * @param path Path to be normalized. */ static void normalizeURIPath(char* path); }; class daeURIResolver; typedef daeTArray daeURIResolverPtrArray; /** * The @c daeURIResolver class is the plugin point for URI resolution. * This class is an abstract base class that defines an interface for * resolving URIs. * Every URI is passed through this list of @c daeURIResolvers for resolution. * The list is ordered on a first come, first serve basis, and resolution * terminates after any resolver instance resolves the URI. */ class DLLSPEC daeURIResolver { public: /** * Constructor * @param dae The associated dae object. */ daeURIResolver(DAE& dae); /** * Destructor */ virtual ~daeURIResolver(); /** * Sets a flag that tells the URI resolver whether or not to load a separate document if a URI * being resolved points to one. * @param load Set to true if you want the URI Resolver to automatically load other documents to * resolve URIs. */ static void setAutoLoadExternalDocuments( daeBool load ); /** * Gets a flag that tells if the URI resolver is set to load an external document if a URI * being resolved points to one. * @return Returns true if the resolver will automatically load documents to resolve a URI. * False otherwise. */ static daeBool getAutoLoadExternalDocuments(); /** * Provides an abstract interface for converting a @c daeURI into a @c daeElement * @param uri @c daeURI to resolve. * @return Returns the resolved element, or null if resolving failed. * returns false otherwise. */ virtual daeElement* resolveElement(const daeURI& uri) = 0; /** * Gets the name of this resolver. * @return Returns the resolver name as a string. */ virtual daeString getName() = 0; protected: static daeBool _loadExternalDocuments; DAE* dae; }; // This is a container class for storing a modifiable list of daeURIResolver objects. class DLLSPEC daeURIResolverList { public: daeURIResolverList(); ~daeURIResolverList(); daeTArray& list(); daeElement* resolveElement(const daeURI& uri); private: // Disabled copy constructor/assignment operator daeURIResolverList(const daeURIResolverList& resolverList) { }; daeURIResolverList& operator=(const daeURIResolverList& resolverList) { return *this; }; daeTArray resolvers; }; // Helper functions for file path <--> URI conversion namespace cdom { // Takes a uri reference and parses it into its components. DLLSPEC bool parseUriRef(const std::string& uriRef, std::string& scheme, std::string& authority, std::string& path, std::string& query, std::string& fragment); // Takes the uri components of a uri ref and combines them. // // The 'forceLibxmlCompatible' param is meant to work around bugs in the file // scheme uri handling of libxml. It causes the function to output a uri // that's fully compatible with libxml. It only modifies file scheme uris, // since uris with other schemes seem to work fine. // // The known libxml uri bugs are as follows: // 1) libxml won't write files when given file scheme URIs with an empty // authority, as in "file:/home". // 2) libxml won't read or write Windows UNC paths represented with the // machine name in the authority, as in "file://otherMachine/folder/file.dae" // 3) On Windows, libxml won't read or write paths that don't have a drive // letter, as in "/folder/file.dae". DLLSPEC std::string assembleUri(const std::string& scheme, const std::string& authority, const std::string& path, const std::string& query, const std::string& fragment, bool forceLibxmlCompatible = false); // A wrapper function for calling assembleUri to create a URI that's compatible // with libxml. DLLSPEC std::string fixUriForLibxml(const std::string& uriRef); // This function takes a file path in the OS's native format and converts it to // a URI reference. If a relative path is given, a relative URI reference is // returned. If an absolute path is given, a relative URI reference containing // a fully specified path is returned. Spaces are encoded as %20. The 'type' // parameter indicates the format of the nativePath. // // Examples - Windows // nativePathToUri("C:\myFolder\myFile.dae") --> "/C:/myFolder/myFile.dae" // nativePathToUri("\myFolder\myFile.dae") --> "/myFolder/myFile.dae" // nativePathToUri("..\myFolder\myFile.dae") --> "../myFolder/myFile.dae" // nativePathToUri("\\otherComputer\myFile.dae") --> "//otherComputer/myFile.dae" // // Examples - Linux/Mac // nativePathToUri("/myFolder/myFile.dae") --> "/myFolder/myFile.dae" // nativePathToUri("../myFolder/myFile.dae") --> "../myFolder/myFile.dae" // nativePathToUri("/my folder/my file.dae") --> "/my%20folder/my%20file.dae" DLLSPEC std::string nativePathToUri(const std::string& nativePath, systemType type = getSystemType()); // This function takes a URI reference and converts it to an OS file path. Conversion // can fail if the URI reference is ill-formed, or if the URI contains a scheme other // than "file", in which case an empty string is returned. The 'type' parameter // indicates the format of the returned native path. // // Examples - Windows // uriToNativePath("../folder/file.dae") --> "..\folder\file.dae" // uriToNativePath("/folder/file.dae") --> "\folder\file.dae" // uriToNativePath("file:/C:/folder/file.dae") --> "C:\folder\file.dae" // uriToNativePath("file://otherComputer/file.dae") --> "\\otherComputer\file.dae" // uriToNativePath("http://www.slashdot.org") --> "" (it's not a file scheme URI!) // // Examples - Linux/Mac // uriToNativePath("../folder/file.dae") --> "../folder/file.dae" // uriToNativePath("file:/folder/file.dae") --> "/folder/file.dae" // uriToNativePath("http://www.slashdot.org") --> "" (it's not a file scheme URI!) DLLSPEC std::string uriToNativePath(const std::string& uriRef, systemType type = getSystemType()); DLLSPEC std::string filePathToUri(const std::string& filePath); // Alias for nativePathToUri DLLSPEC std::string uriToFilePath(const std::string& uriRef); // Alias for uriToNativePath } #endif //__DAE_URI_H__