/**************************************************************************** Copyright (c) 2006, Radon Labs GmbH Copyright (c) 2011-2013,WebJet Business Division,CYOU http://www.genesis-3d.com.cn Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ****************************************************************************/ #pragma once #ifndef IO_URI_H #define IO_URI_H //------------------------------------------------------------------------------ /** @class IO::URI An URI object can split a Uniform Resource Identifier string into its components or build a string from URI components. Please note that the memory footprint of an URI object is always bigger then a pure String object, so if memory usage is of concern, it is advised to keep paths as String objects around, and only use URI objects to encode and decode them. An URI is made of the following components, where most of them are optional: Scheme://UserInfo@Host:Port/LocalPath#Fragment?Query Example URIs: http://user:password@www.myserver.com:8080/index.html#main http://www.myserver.com/query?user=bla ftp://ftp.myserver.com/pub/bla.zip file:///c:/temp/bla.txt file://SambaServer/temp/blub.txt Note that assigns will be resolved before splitting a URI into its components, for instance the assign "textures" could be defined as: Assign("textures", "http://www.dataserv.com/myapp/textures/"); So a path to a texture URI could be defined as: URI("textures:mytex.dds") Which would actually resolve into: http://www.dataserv.com/myapp/textures/mytex.dds Decoding into components happens in the init constructor or the Set() method in the following steps: - resolve any assigns in the original string - split into Scheme, Host and Path blocks - resolve Host and Path blocks further Enconding from components into string happens in the AsString() method in the following steps: - concatenate URI string from components - convert part of the string back into an existing assign */ #include "core/types.h" #include "util/string.h" #include "util/dictionary.h" //------------------------------------------------------------------------------ namespace IO { class URI { public: /// default constructor URI(); /// init constructor URI(const Util::String& s); /// init constructor URI(const char* s); /// copy constructor URI(const URI& rhs); /// assignmnent operator void operator=(const URI& rhs); /// equality operator bool operator==(const URI& rhs) const; /// inequality operator bool operator!=(const URI& rhs) const; /// greater-then operator bool operator>(const URI& rhs) const; /// less-then operator bool operator<(const URI& rhs) const; /// greater-or-equal operator bool operator>=(const URI& rhs) const; /// less-or-equal operator bool operator<=(const URI& rhs) const; /// set complete URI string void Set(const Util::String& s); /// return as concatenated string Util::String AsString() const; /// return true if the URI is empty bool IsEmpty() const; /// return true if the URI is not empty bool IsValid() const; /// clear the URI void Clear(); /// set Scheme component (ftp, http, etc...) void SetScheme(const Util::String& s); /// get Scheme component (default is file) const Util::String& Scheme() const; /// set UserInfo component void SetUserInfo(const Util::String& s); /// get UserInfo component (can be empty) const Util::String& UserInfo() const; /// set Host component void SetHost(const Util::String& s); /// get Host component (can be empty) const Util::String& Host() const; /// set Port component void SetPort(const Util::String& s); /// get Port component (can be empty) const Util::String& Port() const; /// set LocalPath component void SetLocalPath(const Util::String& s); /// get LocalPath component (can be empty) const Util::String& LocalPath() const; /// append an element to the local path component void AppendLocalPath(const Util::String& pathComponent); /// set Fragment component void SetFragment(const Util::String& s); /// get Fragment component (can be empty) const Util::String& Fragment() const; /// set Query component void SetQuery(const Util::String& s); /// get Query component (can be empty) const Util::String& Query() const; /// parse query parameters into a dictionary Util::Dictionary ParseQuery() const; /// get the "tail" (path, query and fragment) Util::String GetTail() const; /// get the host and path without scheme Util::String GetHostAndLocalPath() const; const Util::String& GetOriginalPath() const; static Util::String GetRawPathFromUri( const char* uri ); static Util::String GetUriFromRawPath( const Util::String spath ,const Util::String spre); private: /// split string into components bool Split(const Util::String& s); /// build string from components Util::String Build() const; bool isEmpty; Util::String scheme; Util::String userInfo; Util::String host; Util::String port; Util::String localPath; Util::String fragment; Util::String query; Util::String original; }; //------------------------------------------------------------------------------ /** */ inline URI::URI() : isEmpty(true) { // empty } //------------------------------------------------------------------------------ /** */ inline URI::URI(const Util::String& s) : isEmpty(true), original(s) { bool validUri = this->Split(s); n_assert2(validUri, s.AsCharPtr()); } //------------------------------------------------------------------------------ /** */ inline URI::URI(const char* s) : isEmpty(true), original(s) { bool validUri = this->Split(s); n_assert2(validUri, s); } //------------------------------------------------------------------------------ /** */ inline URI::URI(const URI& rhs) : isEmpty(rhs.isEmpty), scheme(rhs.scheme), userInfo(rhs.userInfo), host(rhs.host), port(rhs.port), localPath(rhs.localPath), fragment(rhs.fragment), query(rhs.query), original(rhs.original) { // empty } //------------------------------------------------------------------------------ /** */ inline void URI::operator=(const URI& rhs) { this->isEmpty = rhs.isEmpty; this->scheme = rhs.scheme; this->userInfo = rhs.userInfo; this->host = rhs.host; this->port = rhs.port; this->localPath = rhs.localPath; this->fragment = rhs.fragment; this->query = rhs.query; this->original = rhs.original; } //------------------------------------------------------------------------------ /** */ inline bool URI::operator==(const URI& rhs) const { if (this->isEmpty && rhs.isEmpty) { return true; } else { return ((this->scheme == rhs.scheme) && (this->userInfo == rhs.userInfo) && (this->host == rhs.host) && (this->port == rhs.port) && (this->localPath == rhs.localPath) && (this->fragment == rhs.fragment) && (this->query == rhs.query)); } } //------------------------------------------------------------------------------ /** */ inline bool URI::operator!=(const URI& rhs) const { return !(*this == rhs); } //------------------------------------------------------------------------------ /** */ inline bool URI::operator>(const URI& rhs) const { if (this->isEmpty) { return false; } else if (rhs.isEmpty) { return true; } return (this->Build() > rhs.Build()); } //------------------------------------------------------------------------------ /** */ inline bool URI::operator<(const URI& rhs) const { if (rhs.isEmpty) { return false; } else if (this->isEmpty) { return true; } return (this->Build() < rhs.Build()); } //------------------------------------------------------------------------------ /** */ inline bool URI::operator>=(const URI& rhs) const { if (rhs.isEmpty) { return true; } else if (this->isEmpty) { return false; } return (this->Build() >= rhs.Build()); } //------------------------------------------------------------------------------ /** */ inline bool URI::operator<=(const URI& rhs) const { if (this->isEmpty) { return true; } else if (rhs.isEmpty) { return false; } return (this->Build() <= rhs.Build()); } //------------------------------------------------------------------------------ /** */ inline bool URI::IsEmpty() const { return this->isEmpty; } //------------------------------------------------------------------------------ /** */ inline bool URI::IsValid() const { return !(this->isEmpty); } //------------------------------------------------------------------------------ /** */ inline void URI::Clear() { this->isEmpty = true; this->scheme.Clear(); this->userInfo.Clear(); this->host.Clear(); this->port.Clear(); this->localPath.Clear(); this->fragment.Clear(); this->query.Clear(); } //------------------------------------------------------------------------------ /** */ inline void URI::Set(const Util::String& s) { this->Split(s); } //------------------------------------------------------------------------------ /** */ inline Util::String URI::AsString() const { return this->Build(); } //------------------------------------------------------------------------------ /** */ inline void URI::SetScheme(const Util::String& s) { this->isEmpty = false; this->scheme = s; } //------------------------------------------------------------------------------ /** */ inline const Util::String& URI::Scheme() const { return this->scheme; } //------------------------------------------------------------------------------ /** */ inline void URI::SetUserInfo(const Util::String& s) { this->isEmpty = false; this->userInfo = s; } //------------------------------------------------------------------------------ /** */ inline const Util::String& URI::UserInfo() const { return this->userInfo; } //------------------------------------------------------------------------------ /** */ inline void URI::SetHost(const Util::String& s) { this->isEmpty = false; this->host = s; } //------------------------------------------------------------------------------ /** */ inline const Util::String& URI::Host() const { return this->host; } //------------------------------------------------------------------------------ /** */ inline void URI::SetPort(const Util::String& s) { this->isEmpty = false; this->port = s; } //------------------------------------------------------------------------------ /** */ inline const Util::String& URI::Port() const { return this->port; } //------------------------------------------------------------------------------ /** */ inline void URI::SetLocalPath(const Util::String& s) { this->isEmpty = false; this->localPath = s; } //------------------------------------------------------------------------------ /** */ inline const Util::String& URI::LocalPath() const { return this->localPath; } //------------------------------------------------------------------------------ /** */ inline void URI::SetFragment(const Util::String& s) { this->isEmpty = false; this->fragment = s; } //------------------------------------------------------------------------------ /** */ inline const Util::String& URI::Fragment() const { return this->fragment; } //------------------------------------------------------------------------------ /** */ inline void URI::SetQuery(const Util::String& s) { this->isEmpty = false; this->query = s; } //------------------------------------------------------------------------------ /** */ inline const Util::String& URI::Query() const { return this->query; } inline const Util::String& URI::GetOriginalPath() const { return this->original; } } // namespace IO //------------------------------------------------------------------------------ #endif