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