22 using std::ostringstream;
57 if (!dirname.empty() && dirname[dirname.size() - 1] ==
'/') {
60 dirname.resize(dirname.size() - 1);
115 hash =
int_hash::add_hash(hash, _flags & (F_has_scheme | F_has_username | F_has_server));
137 return _url.substr(0, _scheme_end);
173 if (scheme ==
"http" || scheme.empty()) {
176 }
else if (scheme ==
"https") {
179 }
else if (scheme ==
"socks") {
193 get_server_and_port()
const {
195 string server = get_server();
196 if (server.find(
':') != string::npos) {
198 strm <<
'[' << server <<
']';
218 return _url.substr(_path_start, _path_end - _path_start);
230 return _url.substr(_path_start);
247 lc_scheme.reserve(scheme.length());
248 for (string::const_iterator si = scheme.begin(); si != scheme.end(); ++si) {
249 lc_scheme += tolower(*si);
252 if (lc_scheme.empty()) {
259 length_adjust = -(int)_scheme_end;
260 _url = _url.substr(_scheme_end);
261 _flags &= ~F_has_scheme;
266 if (lc_scheme[lc_scheme.length() - 1] ==
':') {
267 length_adjust = lc_scheme.length();
268 _url = lc_scheme + _url;
271 length_adjust = lc_scheme.length() + 1;
272 _url = lc_scheme +
":" + _url;
278 _flags |= F_has_scheme;
284 if (lc_scheme[lc_scheme.length() - 1] ==
':') {
285 lc_scheme = lc_scheme.substr(0, lc_scheme.length() - 1);
288 int old_length = (int)_scheme_end;
289 length_adjust = scheme.length() - old_length;
290 _url = lc_scheme + _url.substr(_scheme_end);
293 _scheme_end += length_adjust;
294 _username_start += length_adjust;
295 _username_end += length_adjust;
296 _server_start += length_adjust;
297 _server_end += length_adjust;
298 _port_start += length_adjust;
299 _port_end += length_adjust;
300 _path_start += length_adjust;
301 _path_end += length_adjust;
302 _query_start += length_adjust;
312 int extra_slash_adjust = 0;
314 if (authority.empty()) {
319 _username_start -= 2;
320 length_adjust = -((int)_port_end - (
int)_username_start);
321 _url = _url.substr(0, _username_start) + _url.substr(_port_end);
322 _flags &= ~(F_has_authority | F_has_username | F_has_server | F_has_port);
324 _username_end = _username_start;
325 _server_start = _username_start;
326 _server_end = _username_start;
327 _port_start = _username_start;
331 length_adjust = authority.length() + 2;
334 if (
has_path() && _url[_path_start] !=
'/') {
337 extra_slash_adjust = 1;
339 _url = _url.substr(0, _username_start) +
"//" + authority + extra_slash + _url.substr(_port_end);
340 _flags |= F_has_authority;
341 _username_start += 2;
345 int old_length = (int)_port_end - (
int)_username_start;
346 length_adjust = authority.length() - old_length;
347 _url = _url.substr(0, _username_start) + authority + _url.substr(_port_end);
350 _port_end += length_adjust;
351 _path_start += length_adjust;
352 _path_end += length_adjust + extra_slash_adjust;
353 _query_start += length_adjust + extra_slash_adjust;
368 if (!username.empty()) {
369 authority = username +
"@";
373 if (server.find(
':') != string::npos) {
375 authority +=
"[" + server +
"]";
404 if (server.find(
':') != string::npos) {
406 authority +=
"[" + server +
"]";
434 if (server.find(
':') != string::npos) {
436 authority +=
"[" + server +
"]";
474 authority += server_and_port;
490 length_adjust = -((int)_path_end - (
int)_path_start);
491 _url = _url.substr(0, _path_start) + _url.substr(_path_end);
492 _flags &= ~F_has_path;
497 if (cpath[0] !=
'/') {
501 length_adjust = cpath.length();
503 _url = _url.substr(0, _path_start) + cpath + _url.substr(_path_end);
504 _flags |= F_has_path;
509 if (cpath[0] !=
'/') {
513 int old_length = (int)_path_end - (
int)_path_start;
514 length_adjust = cpath.length() - old_length;
515 _url = _url.substr(0, _path_start) + cpath + _url.substr(_path_end);
518 _path_end += length_adjust;
519 _query_start += length_adjust;
533 _url = _url.substr(0, _query_start);
534 _flags &= ~F_has_query;
538 _url = _url.substr(0, _query_start) +
"?" + query;
539 _flags |= F_has_query;
544 _url = _url.substr(0, _query_start) + query;
554 set_url(
const string &url,
bool server_name_expected) {
559 while (p < url.length() && isspace(url[p])) {
563 while (q > p && isspace(url[q - 1])) {
567 _url = url.substr(p, q - p);
572 server_name_expected =
false;
579 for (p = 0; p < _url.length() && _url[p] !=
'?'; p++) {
580 if (_url[p] ==
'\\') {
586 for (p = 0; p + 2 < _url.length();) {
587 if (_url[p++] ==
'%') {
588 if (_url[p] !=
'%') {
589 _url[p] = toupper(_url[p]);
591 _url[p] = toupper(_url[p]);
605 size_t next = _url.find_first_of(
":/", start);
606 if (next < _url.length() - 1 && _url.substr(next, 2) ==
":/") {
608 _flags |= F_has_scheme;
612 for (
size_t p = 0; p < _scheme_end; ++p) {
613 _url[p] = tolower(_url[p]);
621 _username_start = start;
622 _username_end = start;
623 _server_start = start;
636 bool leading_slashes =
637 (start < _url.length() - 1 && _url.substr(start, 2) ==
"//");
638 if (leading_slashes) {
645 if (!leading_slashes) {
646 if (start < _url.length() && _url[start] ==
'/') {
648 _url = _url.substr(0, start + 1) + _url.substr(start);
651 _url = _url.substr(0, start) +
"//" + _url.substr(start);
657 _flags |= F_has_authority;
658 _username_start = start;
659 _port_end = _url.find_first_of(
"/?", start);
660 if (_port_end == string::npos) {
661 _port_end = _url.length();
670 if (start < _url.length() && url[start] !=
'?') {
672 _flags |= F_has_path;
674 _path_end = _url.find(
"?", _path_start);
675 if (_path_end == string::npos) {
676 _path_end = _url.length();
682 _query_start = start;
683 if (start < _url.length()) {
684 nassertv(_url[start] ==
'?');
685 _flags |= F_has_query;
708 output(ostream &out)
const {
719 quote(
const string &source,
const string &safe) {
720 ostringstream result;
721 result << std::hex << setfill(
'0');
723 for (string::const_iterator si = source.begin(); si != source.end(); ++si) {
739 }
else if (safe.find(ch) != string::npos) {
745 result <<
'%' << setw(2) << (int)ch;
759 ostringstream result;
760 result << std::hex << setfill(
'0');
762 for (string::const_iterator si = source.begin(); si != source.end(); ++si) {
782 }
else if (safe.find(ch) != string::npos) {
788 result <<
'%' << setw(2) << (int)ch;
805 while (p < source.length()) {
806 if (source[p] ==
'%' && p + 2 < source.length()) {
809 for (
int i = 0; i < 2; i++) {
811 char ch = source[p + i];
815 value = tolower(ch) -
'a' + 10;
817 hex = (hex << 4) | value;
841 while (p < source.length()) {
842 if (source[p] ==
'%' && p + 2 < source.length()) {
845 for (
int i = 0; i < 2; i++) {
847 char ch = source[p + i];
851 value = tolower(ch) -
'a' + 10;
853 hex = (hex << 4) | value;
858 }
else if (source[p] ==
'+') {
878 _flags &= ~(F_has_username | F_has_server | F_has_port);
885 _username_end = _username_start;
886 _port_start = _port_end;
889 _flags |= F_has_server;
890 _server_start = _username_start;
891 _server_end = _port_end;
894 size_t at_sign = _url.find(
'@', _username_start);
895 if (at_sign < _port_end) {
897 _flags |= F_has_username;
898 _username_end = at_sign;
899 _server_start = at_sign + 1;
903 size_t bracket = _url.find(
'[', _server_start);
904 if (bracket < _port_end) {
908 bracket = _url.find(
']');
909 if (bracket < _server_end) {
910 _server_end = bracket;
913 size_t colon = _url.find(
':', _server_end);
914 if (colon < _port_end) {
915 _port_start = colon + 1;
920 size_t colon = _url.find(
':', _server_start);
921 if (colon < _port_end) {
924 _port_start = colon + 1;
928 if (_port_start < _port_end) {
929 _flags |= F_has_port;
933 string port_str = _url.substr(_port_start, _port_end - _port_start);
934 _port = (uint16_t)atoi(port_str.c_str());
938 for (
size_t si = _server_start; si != _server_end; ++si) {
939 _url[si] = tolower(_url[si]);
944 if (_server_end > _server_start && _url[_server_end - 1] ==
'.') {
945 _url = _url.substr(0, _server_end - 1) + _url.substr(_server_end);
A container for a URL, e.g.
set_query
Replaces the query part of the URL specification.
bool has_username() const
Returns true if the URL specifies a username (and/or password), false otherwise.
bool has_authority() const
Returns true if the URL specifies an authority (this includes username, server, and/or port),...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool has_path() const
Returns true if the URL includes a path specification (that is, the particular filename on the server...
string downcase(const string &s)
Returns the input string with all uppercase letters converted to lowercase.
std::string get_port_str() const
Returns the port specified by the URL as a string, or the empty string if no port is specified.
bool is_default_port() const
Returns true if the port number encoded in this URL is the default port number for the scheme (or if ...
static std::string unquote(const std::string &source)
Reverses the operation of quote(): converts escaped characters of the form "%xx" to their ascii equiv...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
set_server_and_port
Replaces the server and port parts of the URL specification simultaneously.
static size_t add_hash(size_t start, const Key &key)
Adds the indicated key into a running hash.
std::string get_path_and_query() const
Returns the path (or "/" if no path is specified), followed by the query if it is specified.
get_scheme
Returns the scheme specified by the URL, or empty string if no scheme is specified.
set_server
Replaces the server part of the URL specification.
bool has_scheme() const
Returns true if the URL specifies a scheme (e.g.
The name of a file, such as a texture file or an Egg file.
set_path
Replaces the path part of the URL specification.
static int get_default_port_for_scheme(const std::string &scheme)
Returns the default port number for the indicated scheme, or 0 if there is no known default.
std::string get_fullpath() const
Returns the entire filename: directory, basename, extension.
bool has_port() const
Returns true if the URL specifies a port number, false otherwise.
get_path
Returns the path specified by the URL, or "/" if no path is specified.
set_authority
Replaces the authority part of the URL specification.
bool has_server() const
Returns true if the URL specifies a server name, false otherwise.
set_username
Replaces the username part of the URL specification.
get_port
Returns the port number specified by the URL, or the default port if not specified.
bool has_query() const
Returns true if the URL includes a query specification, false otherwise.
int compare_to(const URLSpec &other) const
Returns a number less than zero if this URLSpec sorts before the other one, greater than zero if it s...
void set_url(const std::string &url, bool server_name_expected=false)
Completely replaces the URL with the indicated string.
const std::string & get_url() const
Returns the complete URL specification.
set_scheme
Replaces the scheme part of the URL specification.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_server
Returns the server name specified by the URL, if any.
get_username
Returns the username specified by the URL, if any.
static std::string quote_plus(const std::string &source, const std::string &safe="/")
Behaves like quote() with the additional behavior of replacing spaces with plus signs.
static std::string quote(const std::string &source, const std::string &safe="/")
Returns the source string with all "unsafe" characters quoted, making a string suitable for placing i...
set_port
Replaces the port part of the URL specification.
static size_t add_hash(size_t start, const Key &key)
Adds the elements of the indicated key into a running hash.
static std::string unquote_plus(const std::string &source)
Reverses the operation of quote_plus(): converts escaped characters of the form "%xx" to their ascii ...
get_query
Returns the query specified by the URL, or empty string if no query is specified.