494 lines
18 KiB
C
494 lines
18 KiB
C
|
/*
|
||
|
* 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 <string>
|
||
|
#include <dae/daeTypes.h>
|
||
|
#include <dae/daeElement.h>
|
||
|
#include <dae/daeUtils.h>
|
||
|
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 <instance> element has the url= attribute of type @c anyURL, and the
|
||
|
* <controller> 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
|
||
|
* <tt>daeElement::getBaseURI().</tt>
|
||
|
* 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.
|
||
|
*
|
||
|
* <b>Definition of Absolute URI:</b>
|
||
|
* 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 <tt><i>fragment</i></tt> 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 <tt><i>baseURI</i></tt> and a <tt><i>uriString.</i></tt>
|
||
|
* 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 <tt><i>from</i></tt> 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 <tt><i>state</i></tt> 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<daeURIResolver*> 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<daeURIResolver*>& list();
|
||
|
daeElement* resolveElement(const daeURI& uri);
|
||
|
|
||
|
private:
|
||
|
// Disabled copy constructor/assignment operator
|
||
|
daeURIResolverList(const daeURIResolverList& resolverList) { };
|
||
|
daeURIResolverList& operator=(const daeURIResolverList& resolverList) { return *this; };
|
||
|
|
||
|
daeTArray<daeURIResolver*> 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__
|