summaryrefslogtreecommitdiffstats
path: root/kviewshell/plugins/djvu/libdjvu/GURL.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kviewshell/plugins/djvu/libdjvu/GURL.cpp')
-rw-r--r--kviewshell/plugins/djvu/libdjvu/GURL.cpp1965
1 files changed, 1965 insertions, 0 deletions
diff --git a/kviewshell/plugins/djvu/libdjvu/GURL.cpp b/kviewshell/plugins/djvu/libdjvu/GURL.cpp
new file mode 100644
index 00000000..54b082ff
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/GURL.cpp
@@ -0,0 +1,1965 @@
+//C- -*- C++ -*-
+//C- -------------------------------------------------------------------
+//C- DjVuLibre-3.5
+//C- Copyright (c) 2002 Leon Bottou and Yann Le Cun.
+//C- Copyright (c) 2001 AT&T
+//C-
+//C- This software is subject to, and may be distributed under, the
+//C- GNU General Public License, Version 2. The license should have
+//C- accompanied the software or you may obtain a copy of the license
+//C- from the Free Software Foundation at http://www.fsf.org .
+//C-
+//C- This program is distributed in the hope that it will be useful,
+//C- but WITHOUT ANY WARRANTY; without even the implied warranty of
+//C- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+//C- GNU General Public License for more details.
+//C-
+//C- DjVuLibre-3.5 is derived from the DjVu(r) Reference Library
+//C- distributed by Lizardtech Software. On July 19th 2002, Lizardtech
+//C- Software authorized us to replace the original DjVu(r) Reference
+//C- Library notice by the following text (see doc/lizard2002.djvu):
+//C-
+//C- ------------------------------------------------------------------
+//C- | DjVu (r) Reference Library (v. 3.5)
+//C- | Copyright (c) 1999-2001 LizardTech, Inc. All Rights Reserved.
+//C- | The DjVu Reference Library is protected by U.S. Pat. No.
+//C- | 6,058,214 and patents pending.
+//C- |
+//C- | This software is subject to, and may be distributed under, the
+//C- | GNU General Public License, Version 2. The license should have
+//C- | accompanied the software or you may obtain a copy of the license
+//C- | from the Free Software Foundation at http://www.fsf.org .
+//C- |
+//C- | The computer code originally released by LizardTech under this
+//C- | license and unmodified by other parties is deemed "the LIZARDTECH
+//C- | ORIGINAL CODE." Subject to any third party intellectual property
+//C- | claims, LizardTech grants recipient a worldwide, royalty-free,
+//C- | non-exclusive license to make, use, sell, or otherwise dispose of
+//C- | the LIZARDTECH ORIGINAL CODE or of programs derived from the
+//C- | LIZARDTECH ORIGINAL CODE in compliance with the terms of the GNU
+//C- | General Public License. This grant only confers the right to
+//C- | infringe patent claims underlying the LIZARDTECH ORIGINAL CODE to
+//C- | the extent such infringement is reasonably necessary to enable
+//C- | recipient to make, have made, practice, sell, or otherwise dispose
+//C- | of the LIZARDTECH ORIGINAL CODE (or portions thereof) and not to
+//C- | any greater extent that may be necessary to utilize further
+//C- | modifications or combinations.
+//C- |
+//C- | The LIZARDTECH ORIGINAL CODE is provided "AS IS" WITHOUT WARRANTY
+//C- | OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+//C- | TO ANY WARRANTY OF NON-INFRINGEMENT, OR ANY IMPLIED WARRANTY OF
+//C- | MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+//C- +------------------------------------------------------------------
+//
+// $Id: GURL.cpp,v 1.19 2005/04/27 16:34:13 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma implementation
+#endif
+
+// From: Leon Bottou, 1/31/2002
+// This has been heavily changed by Lizardtech.
+// They decided to use URLs for everyting, including
+// the most basic file access. The URL class now is a unholy
+// mixture of code for syntactically parsing the urls (which it was)
+// and file status code (only for local file: urls).
+
+#include "GException.h"
+#include "GOS.h"
+#include "GURL.h"
+#include "debug.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <math.h>
+#include <string.h>
+
+#ifdef WIN32
+# include <atlbase.h>
+# include <windows.h>
+# include <direct.h>
+#endif /* WIN32 */
+
+// -- MAXPATHLEN
+#ifndef MAXPATHLEN
+# ifdef _MAX_PATH
+# define MAXPATHLEN _MAX_PATH
+# else
+# define MAXPATHLEN 1024
+# endif
+#else
+# if ( MAXPATHLEN < 1024 )
+# undef MAXPATHLEN
+# define MAXPATHLEN 1024
+# endif
+#endif
+
+#if defined(UNIX) || defined(OS2)
+# include <unistd.h>
+# include <sys/types.h>
+# include <sys/stat.h>
+# include <errno.h>
+# include <fcntl.h>
+# include <pwd.h>
+# include <stdio.h>
+# ifdef AUTOCONF
+# ifdef TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+# else
+# ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+# endif
+# ifdef HAVE_DIRENT_H
+# include <dirent.h>
+# define NAMLEN(dirent) strlen((dirent)->d_name)
+# else
+# define dirent direct
+# define NAMLEN(dirent) (dirent)->d_namlen
+# ifdef HAVE_SYS_NDIR_H
+# include <sys/ndir.h>
+# endif
+# ifdef HAVE_SYS_DIR_H
+# include <sys/dir.h>
+# endif
+# ifdef HAVE_NDIR_H
+# include <ndir.h>
+# endif
+# endif
+# else /* !AUTOCONF */
+# include <sys/time.h>
+# if defined(XENIX)
+# define USE_DIRECT
+# include <sys/ndir.h>
+# elif defined(OLDBSD)
+# define USE_DIRECT
+# include <sys/dir.h>
+# endif
+# ifdef USE_DIRECT
+# define dirent direct
+# define NAMLEN(dirent) (dirent)->d_namlen
+# else
+# include <dirent.h>
+# define NAMLEN(dirent) strlen((dirent)->d_name)
+# endif
+# endif /* !AUTOCONF */
+#endif /* UNIX */
+
+#ifdef macintosh
+#include <unix.h>
+#include <errno.h>
+#include <unistd.h>
+#endif
+
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+
+static const char djvuopts[]="DJVUOPTS";
+static const char localhost[]="file://localhost/";
+static const char backslash='\\';
+static const char colon=':';
+static const char dot='.';
+static const char filespecslashes[] = "file://";
+static const char filespec[] = "file:";
+static const char slash='/';
+static const char percent='%';
+static const char localhostspec1[] = "//localhost/";
+static const char localhostspec2[] = "///";
+static const char nillchar=0;
+#if defined(UNIX)
+ static const char tilde='~';
+ static const char root[] = "/";
+#elif defined(WIN32) || defined(OS2)
+ static const char root[] = "\\";
+#elif defined(macintosh)
+ static char const * const root = &nillchar;
+#else
+#error "Define something here for your operating system"
+#endif
+
+
+static const int
+pathname_start(const GUTF8String &url, const int protolength);
+
+// hexval --
+// -- Returns the hexvalue of a character.
+// Returns -1 if illegal;
+
+static int
+hexval(char c)
+{
+ return ((c>='0' && c<='9')
+ ?(c-'0')
+ :((c>='A' && c<='F')
+ ?(c-'A'+10)
+ :((c>='a' && c<='f')
+ ?(c-'a'+10):(-1))));
+}
+
+
+static bool
+is_argument(const char * start)
+ // Returns TRUE if 'start' points to the beginning of an argument
+ // (either hash or CGI)
+{
+ // return (*start=='#' || *start=='?' || *start=='&' || *start==';');
+ return (*start=='#' || *start=='?' );
+}
+
+static bool
+is_argument_sep(const char * start)
+ // Returns TRUE if 'start' points to the beginning of an argument
+ // (either hash or CGI)
+{
+ return (*start=='&')||(*start == ';');
+}
+
+void
+GURL::convert_slashes(void)
+{
+ GUTF8String xurl(get_string());
+#if defined(WIN32)
+ const int protocol_length=protocol(xurl).length();
+ for(char *ptr=(xurl.getbuf()+protocol_length);*ptr;ptr++)
+ if(*ptr == backslash)
+ *ptr=slash;
+ url=xurl;
+#endif
+}
+
+static void
+collapse(char * ptr, const int chars)
+ // Will remove the first 'chars' chars from the string and
+ // move the rest toward the beginning. Will take into account
+ // string length
+{
+ const int length=strlen(ptr);
+ const char *srcptr=ptr+((chars>length)?length:chars);
+ while((*(ptr++) = *(srcptr++)))
+ EMPTY_LOOP;
+}
+
+GUTF8String
+GURL::beautify_path(GUTF8String xurl)
+{
+
+ const int protocol_length=GURL::protocol(xurl).length();
+
+ // Eats parts like ./ or ../ or ///
+ char * buffer;
+ GPBuffer<char> gbuffer(buffer,xurl.length()+1);
+ strcpy(buffer, (const char *)xurl);
+
+ // Find start point
+ char * start=buffer+pathname_start(xurl,protocol_length);
+
+ // Find end of the url (don't touch arguments)
+ char * ptr;
+ GUTF8String args;
+ for(ptr=start;*ptr;ptr++)
+ {
+ if (is_argument(ptr))
+ {
+ args=ptr;
+ *ptr=0;
+ break;
+ }
+ }
+
+ // Eat multiple slashes
+ for(;(ptr=strstr(start, "////"));collapse(ptr, 3))
+ EMPTY_LOOP;
+ for(;(ptr=strstr(start, "//"));collapse(ptr, 1))
+ EMPTY_LOOP;
+ // Convert /./ stuff into plain /
+ for(;(ptr=strstr(start, "/./"));collapse(ptr, 2))
+ EMPTY_LOOP;
+#if defined(WIN32) || defined(OS2)
+ if(!xurl.cmp(filespec,sizeof(filespec)-1))
+ {
+ int offset=1;
+ if(start&&(start[0] == '/')&&
+ !xurl.cmp("file:////",sizeof("file:////")-1))
+ {
+ collapse(start, 1);
+ offset=0;
+ }
+ for(ptr=start+offset;(ptr=strchr(ptr, '/'));)
+ {
+ if(isalpha((++ptr)[0]))
+ {
+ if((ptr[1] == ':')&&(ptr[2]=='/'))
+ {
+ char *buffer2;
+ GPBuffer<char> gbuffer2(buffer2,strlen(ptr)+1);
+ strcpy(buffer2,ptr);
+ gbuffer.resize(strlen(ptr)+sizeof(localhost));
+ strcpy(buffer,localhost);
+ strcat(buffer,buffer2);
+ ptr=(start=buffer+sizeof(localhost))+1;
+ }
+ }
+ }
+ }
+#endif
+ // Process /../
+ while((ptr=strstr(start, "/../")))
+ {
+ for(char * ptr1=ptr-1;(ptr1>=start);ptr1--)
+ {
+ if (*ptr1==slash)
+ {
+ collapse(ptr1, ptr-ptr1+3);
+ break;
+ }
+ }
+ }
+
+ // Remove trailing /.
+ ptr=start+strlen(start)-2;
+ if((ptr>=start)&& (ptr == GUTF8String("/.")))
+ {
+ ptr[1]=0;
+ }
+ // Eat trailing /..
+ ptr=start+strlen(start)-3;
+ if((ptr >= start) && (ptr == GUTF8String("/..")))
+ {
+ for(char * ptr1=ptr-1;(ptr1>=start);ptr1--)
+ {
+ if (*ptr1==slash)
+ {
+ ptr1[1]=0;
+ break;
+ }
+ }
+ }
+
+ // Done. Copy the buffer back into the URL and add arguments.
+ xurl=buffer;
+ return (xurl+args);
+}
+
+
+void
+GURL::beautify_path(void)
+{
+ url=beautify_path(get_string());
+}
+
+void
+GURL::init(const bool nothrow)
+{
+ GCriticalSectionLock lock(&class_lock);
+ validurl=true;
+
+ if (url.length())
+ {
+ GUTF8String proto=protocol();
+ if (proto.length()<2)
+ {
+ validurl=false;
+ if(!nothrow)
+ G_THROW( ERR_MSG("GURL.no_protocol") "\t"+url);
+ return;
+ }
+
+ // Below we have to make this complex test to detect URLs really
+ // referring to *local* files. Surprisingly, file://hostname/dir/file
+ // is also valid, but shouldn't be treated thru local FS.
+ if (proto=="file" && url[5]==slash &&
+ (url[6]!=slash || !url.cmp(localhost, sizeof(localhost))))
+ {
+ // Separate the arguments
+ GUTF8String arg;
+ {
+ const char * const url_ptr=url;
+ const char * ptr;
+ for(ptr=url_ptr;*ptr&&!is_argument(ptr);ptr++)
+ EMPTY_LOOP;
+ arg=ptr;
+ url=url.substr(0,(size_t)ptr-(size_t)url_ptr);
+ }
+
+ // Do double conversion
+ GUTF8String tmp=UTF8Filename();
+ if (!tmp.length())
+ {
+ validurl=false;
+ if(!nothrow)
+ G_THROW( ERR_MSG("GURL.fail_to_file") );
+ return;
+ }
+ url=GURL::Filename::UTF8(tmp).get_string();
+ if (!url.length())
+ {
+ validurl=false;
+ if(!nothrow)
+ G_THROW( ERR_MSG("GURL.fail_to_URL") );
+ return;
+ }
+ // Return the argument back
+ url+=arg;
+ }
+ convert_slashes();
+ beautify_path();
+ parse_cgi_args();
+ }
+}
+
+GURL::GURL(void)
+ : validurl(false)
+{
+}
+
+GURL::GURL(const char * url_in)
+ : url(url_in ? url_in : ""), validurl(false)
+{
+}
+
+GURL::GURL(const GUTF8String & url_in)
+ : url(url_in), validurl(false)
+{
+}
+
+GURL::GURL(const GNativeString & url_in)
+ : url(url_in.getNative2UTF8()), validurl(false)
+{
+#if defined(WIN32) || defined(OS2)
+ if(is_valid() && is_local_file_url())
+ {
+ GURL::Filename::UTF8 xurl(UTF8Filename());
+ url=xurl.get_string(true);
+ validurl=false;
+ }
+#endif
+}
+
+GURL::GURL(const GURL & url_in)
+ : validurl(false)
+{
+ if(url_in.is_valid())
+ {
+ url=url_in.get_string();
+ init();
+ }else
+ {
+ url=url_in.url;
+ }
+}
+
+GURL &
+GURL::operator=(const GURL & url_in)
+{
+ GCriticalSectionLock lock(&class_lock);
+ if(url_in.is_valid())
+ {
+ url=url_in.get_string();
+ init(true);
+ }else
+ {
+ url=url_in.url;
+ validurl=false;
+ }
+ return *this;
+}
+
+GUTF8String
+GURL::protocol(const GUTF8String& url)
+{
+ const char * const url_ptr=url;
+ const char * ptr=url_ptr;
+ for(char c=*ptr;
+ c && (isalnum(c) || c == '+' || c == '-' || c == '.');
+ c=*(++ptr)) EMPTY_LOOP;
+ return(*ptr==colon)?GUTF8String(url_ptr, ptr-url_ptr):GUTF8String();
+}
+
+GUTF8String
+GURL::hash_argument(void) const
+ // Returns the HASH argument (anything after '#' and before '?')
+{
+ const GUTF8String xurl(get_string());
+
+ bool found=false;
+ GUTF8String arg;
+
+ // Break if CGI argument is found
+ for(const char * start=xurl;*start&&(*start!='?');start++)
+ {
+ if (found)
+ {
+ arg+=*start;
+ }else
+ {
+ found=(*start=='#');
+ }
+ }
+ return decode_reserved(arg);
+}
+
+void
+GURL::set_hash_argument(const GUTF8String &arg)
+{
+ const GUTF8String xurl(get_string());
+
+ GUTF8String new_url;
+ bool found=false;
+ const char * ptr;
+ for(ptr=xurl;*ptr;ptr++)
+ {
+ if (is_argument(ptr))
+ {
+ if (*ptr!='#')
+ {
+ break;
+ }
+ found=true;
+ } else if (!found)
+ {
+ new_url+=*ptr;
+ }
+ }
+
+ url=new_url+"#"+GURL::encode_reserved(arg)+ptr;
+}
+
+void
+GURL::parse_cgi_args(void)
+ // Will read CGI arguments from the URL into
+ // cgi_name_arr and cgi_value_arr
+{
+ if(!validurl)
+ init();
+ GCriticalSectionLock lock1(&class_lock);
+ cgi_name_arr.empty();
+ cgi_value_arr.empty();
+
+ // Search for the beginning of CGI arguments
+ const char * start=url;
+ while(*start)
+ {
+ if(*(start++)=='?')
+ {
+ break;
+ }
+ }
+
+ // Now loop until we see all of them
+ while(*start)
+ {
+ GUTF8String arg; // Storage for another argument
+ while(*start) // Seek for the end of it
+ {
+ if (is_argument_sep(start))
+ {
+ start++;
+ break;
+ } else
+ {
+ arg+=*start++;
+ }
+ }
+ if (arg.length())
+ {
+ // Got argument in 'arg'. Split it into 'name' and 'value'
+ const char * ptr;
+ const char * const arg_ptr=arg;
+ for(ptr=arg_ptr;*ptr&&(*ptr != '=');ptr++)
+ EMPTY_LOOP;
+
+ GUTF8String name, value;
+ if (*ptr)
+ {
+ name=GUTF8String(arg_ptr, (int)((ptr++)-arg_ptr));
+ value=GUTF8String(ptr, arg.length()-name.length()-1);
+ } else
+ {
+ name=arg;
+ }
+
+ int args=cgi_name_arr.size();
+ cgi_name_arr.resize(args);
+ cgi_value_arr.resize(args);
+ cgi_name_arr[args]=decode_reserved(name);
+ cgi_value_arr[args]=decode_reserved(value);
+ }
+ }
+}
+
+void
+GURL::store_cgi_args(void)
+ // Will store CGI arguments from the cgi_name_arr and cgi_value_arr
+ // back into the URL
+{
+ if(!validurl)
+ init();
+ GCriticalSectionLock lock1(&class_lock);
+
+ const char * const url_ptr=url;
+ const char * ptr;
+ for(ptr=url_ptr;*ptr&&(*ptr!='?');ptr++)
+ EMPTY_LOOP;
+
+ GUTF8String new_url(url_ptr, ptr-url_ptr);
+
+ for(int i=0;i<cgi_name_arr.size();i++)
+ {
+ GUTF8String name=GURL::encode_reserved(cgi_name_arr[i]);
+ GUTF8String value=GURL::encode_reserved(cgi_value_arr[i]);
+ new_url+=(i?"&":"?")+name;
+ if (value.length())
+ new_url+="="+value;
+ }
+
+ url=new_url;
+}
+
+int
+GURL::cgi_arguments(void) const
+{
+ if(!validurl)
+ const_cast<GURL *>(this)->init();
+ return cgi_name_arr.size();
+}
+
+int
+GURL::djvu_cgi_arguments(void) const
+{
+ if(!validurl)
+ const_cast<GURL *>(this)->init();
+ GCriticalSectionLock lock((GCriticalSection *) &class_lock);
+
+ int args=0;
+ for(int i=0;i<cgi_name_arr.size();i++)
+ {
+ if (cgi_name_arr[i].upcase()==djvuopts)
+ {
+ args=cgi_name_arr.size()-(i+1);
+ break;
+ }
+ }
+ return args;
+}
+
+GUTF8String
+GURL::cgi_name(int num) const
+{
+ if(!validurl) const_cast<GURL *>(this)->init();
+ GCriticalSectionLock lock((GCriticalSection *) &class_lock);
+ return (num<cgi_name_arr.size())?cgi_name_arr[num]:GUTF8String();
+}
+
+GUTF8String
+GURL::djvu_cgi_name(int num) const
+{
+ if(!validurl) const_cast<GURL *>(this)->init();
+ GCriticalSectionLock lock((GCriticalSection *) &class_lock);
+
+ GUTF8String arg;
+ for(int i=0;i<cgi_name_arr.size();i++)
+ if (cgi_name_arr[i].upcase()==djvuopts)
+ {
+ for(i++;i<cgi_name_arr.size();i++)
+ if (! num--)
+ {
+ arg=cgi_name_arr[i];
+ break;
+ }
+ break;
+ }
+ return arg;
+}
+
+GUTF8String
+GURL::cgi_value(int num) const
+{
+ if(!validurl) const_cast<GURL *>(this)->init();
+ GCriticalSectionLock lock((GCriticalSection *) &class_lock);
+ return (num<cgi_value_arr.size())?cgi_value_arr[num]:GUTF8String();
+}
+
+GUTF8String
+GURL::djvu_cgi_value(int num) const
+{
+ if(!validurl) const_cast<GURL *>(this)->init();
+ GCriticalSectionLock lock((GCriticalSection *) &class_lock);
+
+ GUTF8String arg;
+ for(int i=0;i<cgi_name_arr.size();i++)
+ {
+ if (cgi_name_arr[i].upcase()==djvuopts)
+ {
+ for(i++;i<cgi_name_arr.size();i++)
+ {
+ if (! num--)
+ {
+ arg=cgi_value_arr[i];
+ break;
+ }
+ }
+ break;
+ }
+ }
+ return arg;
+}
+
+DArray<GUTF8String>
+GURL::cgi_names(void) const
+{
+ if(!validurl) const_cast<GURL *>(this)->init();
+ GCriticalSectionLock lock((GCriticalSection *) &class_lock);
+ return cgi_name_arr;
+}
+
+DArray<GUTF8String>
+GURL::cgi_values(void) const
+{
+ if(!validurl) const_cast<GURL *>(this)->init();
+ GCriticalSectionLock lock((GCriticalSection *) &class_lock);
+ return cgi_value_arr;
+}
+
+DArray<GUTF8String>
+GURL::djvu_cgi_names(void) const
+{
+ if(!validurl) const_cast<GURL *>(this)->init();
+ GCriticalSectionLock lock((GCriticalSection *) &class_lock);
+
+ int i;
+ DArray<GUTF8String> arr;
+ for(i=0;(i<cgi_name_arr.size())&&
+ (cgi_name_arr[i].upcase()!=djvuopts)
+ ;i++)
+ EMPTY_LOOP;
+
+ int size=cgi_name_arr.size()-(i+1);
+ if (size>0)
+ {
+ arr.resize(size-1);
+ for(i=0;i<arr.size();i++)
+ arr[i]=cgi_name_arr[cgi_name_arr.size()-arr.size()+i];
+ }
+
+ return arr;
+}
+
+DArray<GUTF8String>
+GURL::djvu_cgi_values(void) const
+{
+ if(!validurl) const_cast<GURL *>(this)->init();
+ GCriticalSectionLock lock((GCriticalSection *) &class_lock);
+
+ int i;
+ DArray<GUTF8String> arr;
+ for(i=0;i<cgi_name_arr.size()&&(cgi_name_arr[i].upcase()!=djvuopts);i++)
+ EMPTY_LOOP;
+
+ int size=cgi_name_arr.size()-(i+1);
+ if (size>0)
+ {
+ arr.resize(size-1);
+ for(i=0;i<arr.size();i++)
+ arr[i]=cgi_value_arr[cgi_value_arr.size()-arr.size()+i];
+ }
+
+ return arr;
+}
+
+void
+GURL::clear_all_arguments(void)
+{
+ clear_hash_argument();
+ clear_cgi_arguments();
+}
+
+void
+GURL::clear_hash_argument(void)
+ // Clear anything after first '#' and before the following '?'
+{
+ if(!validurl) init();
+ GCriticalSectionLock lock(&class_lock);
+ bool found=false;
+ GUTF8String new_url;
+ for(const char * start=url;*start;start++)
+ {
+ // Break on first CGI arg.
+ if (*start=='?')
+ {
+ new_url+=start;
+ break;
+ }
+
+ if (!found)
+ {
+ if (*start=='#')
+ found=true;
+ else
+ new_url+=*start;
+ }
+ }
+ url=new_url;
+}
+
+void
+GURL::clear_cgi_arguments(void)
+{
+ if(!validurl)
+ init();
+ GCriticalSectionLock lock1(&class_lock);
+
+ // Clear the arrays
+ cgi_name_arr.empty();
+ cgi_value_arr.empty();
+
+ // And clear everything past the '?' sign in the URL
+ for(const char * ptr=url;*ptr;ptr++)
+ if (*ptr=='?')
+ {
+ url.setat(ptr-url, 0);
+ break;
+ }
+}
+
+void
+GURL::clear_djvu_cgi_arguments(void)
+{
+ if(!validurl) init();
+ // First - modify the arrays
+ GCriticalSectionLock lock(&class_lock);
+ for(int i=0;i<cgi_name_arr.size();i++)
+ {
+ if (cgi_name_arr[i].upcase()==djvuopts)
+ {
+ cgi_name_arr.resize(i-1);
+ cgi_value_arr.resize(i-1);
+ break;
+ }
+ }
+
+ // And store them back into the URL
+ store_cgi_args();
+}
+
+void
+GURL::add_djvu_cgi_argument(const GUTF8String &name, const char * value)
+{
+ if(!validurl)
+ init();
+ GCriticalSectionLock lock1(&class_lock);
+
+ // Check if we already have the "DJVUOPTS" argument
+ bool have_djvuopts=false;
+ for(int i=0;i<cgi_name_arr.size();i++)
+ {
+ if (cgi_name_arr[i].upcase()==djvuopts)
+ {
+ have_djvuopts=true;
+ break;
+ }
+ }
+
+ // If there is no DJVUOPTS, insert it
+ if (!have_djvuopts)
+ {
+ int pos=cgi_name_arr.size();
+ cgi_name_arr.resize(pos);
+ cgi_value_arr.resize(pos);
+ cgi_name_arr[pos]=djvuopts;
+ }
+
+ // Add new argument to the array
+ int pos=cgi_name_arr.size();
+ cgi_name_arr.resize(pos);
+ cgi_value_arr.resize(pos);
+ cgi_name_arr[pos]=name;
+ cgi_value_arr[pos]=value;
+
+ // And update the URL
+ store_cgi_args();
+}
+
+bool
+GURL::is_local_file_url(void) const
+{
+ if(!validurl) const_cast<GURL *>(this)->init();
+ GCriticalSectionLock lock((GCriticalSection *) &class_lock);
+ return (protocol()=="file" && url[5]==slash);
+}
+
+static const int
+pathname_start(const GUTF8String &url, const int protolength)
+{
+ const int length=url.length();
+ int retval=0;
+ if(protolength+1<length)
+ {
+ retval=url.search(slash,((url[protolength+1] == '/')
+ ?((url[protolength+2] == '/')?(protolength+3):(protolength+2))
+ :(protolength+1)));
+ }
+ return (retval>0)?retval:length;
+}
+
+GUTF8String
+GURL::pathname(void) const
+{
+ return (is_local_file_url())
+ ?GURL::encode_reserved(UTF8Filename())
+ :url.substr(pathname_start(url,protocol().length()),(unsigned int)(-1));
+}
+
+GURL
+GURL::base(void) const
+{
+ const GUTF8String xurl(get_string());
+ const int protocol_length=protocol(xurl).length();
+ const int xurl_length=xurl.length();
+ const char * const url_ptr=xurl;
+ const char * ptr, * xslash;
+ ptr=xslash=url_ptr+protocol_length+1;
+ if(xslash[0] == '/')
+ {
+ xslash++;
+ if(xslash[0] == '/')
+ xslash++;
+ for(ptr=xslash;ptr[0] && !is_argument(ptr);ptr++)
+ {
+ if ((ptr[0]==slash)&&ptr[1]&&!is_argument(ptr+1))
+ xslash=ptr;
+ }
+ if(xslash[0] != '/')
+ {
+ xslash=url_ptr+xurl_length;
+ }
+ }
+ return GURL::UTF8(
+// ifdef WIN32
+// (*(xslash-1) == colon)?
+// (GUTF8String(xurl,(int)(xslash-url_ptr))+"/" ):
+// endif
+ (GUTF8String(xurl,(int)(xslash-url_ptr))+"/"));
+}
+
+bool
+GURL::operator==(const GURL & gurl2) const
+{
+ bool retval=false;
+ const GUTF8String g1(get_string());
+ const int g1_length=g1.length();
+ const GUTF8String g2(gurl2.get_string());
+ const int g2_length=g2.length();
+ if(g1_length == g2_length) // exactly equal
+ {
+ retval=(g1==g2);
+ }else if(g1_length+1 == g2_length) // g1 is g2 with a slash at the end
+ {
+ retval=(g2[g1_length] == '/')&&!g1.cmp(g2,g1_length);
+ }else if(g2_length+1 == g1_length) // g2 is g1 with a slash at the end
+ {
+ retval=(g1[g2_length] == '/')&&!g1.cmp(g2,g2_length);
+ }
+ return retval;
+}
+
+GUTF8String
+GURL::name(void) const
+{
+ if(!validurl)
+ const_cast<GURL *>(this)->init();
+ GUTF8String retval;
+ if(!is_empty())
+ {
+ const GUTF8String xurl(url);
+ const int protocol_length=protocol(xurl).length();
+ const char * ptr, * xslash=(const char *)xurl+protocol_length-1;
+ for(ptr=(const char *)xurl+protocol_length;
+ *ptr && !is_argument(ptr);ptr++)
+ {
+ if (*ptr==slash)
+ xslash=ptr;
+ }
+ retval=GUTF8String(xslash+1, ptr-xslash-1);
+ }
+ return retval;
+}
+
+GUTF8String
+GURL::fname(void) const
+{
+ if(!validurl)
+ const_cast<GURL *>(this)->init();
+ return decode_reserved(name());
+}
+
+GUTF8String
+GURL::extension(void) const
+{
+ if(!validurl)
+ const_cast<GURL *>(this)->init();
+ GUTF8String xfilename=name();
+ GUTF8String retval;
+
+ for(int i=xfilename.length()-1;i>=0;i--)
+ {
+ if (xfilename[i]=='.')
+ {
+ retval=(const char*)xfilename+i+1;
+ break;
+ }
+ }
+ return retval;
+}
+
+GUTF8String
+GURL::decode_reserved(const GUTF8String &gurl)
+{
+ const char *url=gurl;
+ char *res;
+ GPBuffer<char> gres(res,gurl.length()+1);
+ char *r=res;
+ for(const char * ptr=url;*ptr;++ptr,++r)
+ {
+ if (*ptr!=percent)
+ {
+ r[0]=*ptr;
+ }else
+ {
+ int c1,c2;
+ if ( ((c1=hexval(ptr[1]))>=0)
+ && ((c2=hexval(ptr[2]))>=0) )
+ {
+ r[0]=(c1<<4)|c2;
+ ptr+=2;
+ } else
+ {
+ r[0]=*ptr;
+ }
+ }
+ }
+ r[0]=0;
+ GUTF8String retval(res);
+ if(!retval.is_valid())
+ {
+ retval=GNativeString(res);
+ }
+ return retval;
+}
+
+GUTF8String
+GURL::encode_reserved(const GUTF8String &gs)
+{
+ const char *s=(const char *)gs;
+ // Potentially unsafe characters (cf. RFC1738 and RFC1808)
+ static const char hex[] = "0123456789ABCDEF";
+
+ unsigned char *retval;
+ GPBuffer<unsigned char> gd(retval,strlen(s)*3+1);
+ unsigned char *d=retval;
+ for (; *s; s++,d++)
+ {
+ // Convert directory separator to slashes
+#if defined(WIN32) || defined(OS2)
+ if (*s == backslash || *s== slash)
+#else
+#ifdef macintosh
+ if (*s == colon )
+#else
+#ifdef UNIX
+ if (*s == slash )
+#else
+#error "Define something here for your operating system"
+#endif
+#endif
+#endif
+ {
+ *d = slash;
+ continue;
+ }
+ unsigned char const ss=(unsigned char const)(*s);
+ // WARNING: Whenever you modify this conversion code,
+ // make sure, that the following functions are in sync:
+ // encode_reserved()
+ // decode_reserved()
+ // url_to_filename()
+ // filename_to_url()
+ // unreserved characters
+ if ( (ss>='a' && ss<='z') ||
+ (ss>='A' && ss<='Z') ||
+ (ss>='0' && ss<='9') ||
+ (strchr("$-_.+!*'(),:~=", ss)) )
+ {
+ *d = ss;
+ continue;
+ }
+ // escape sequence
+ d[0] = percent;
+ d[1] = hex[ (ss >> 4) & 0xf ];
+ d[2] = hex[ (ss) & 0xf ];
+ d+=2;
+ }
+ *d = 0;
+ return retval;
+}
+
+// -------------------------------------------
+// Functions for converting filenames and urls
+// -------------------------------------------
+
+static GUTF8String
+url_from_UTF8filename(const GUTF8String &gfilename)
+{
+ if(GURL::UTF8(gfilename).is_valid())
+ {
+ DEBUG_MSG("Debug: URL as Filename: " << gfilename << "\n");
+ }
+ const char *filename=gfilename;
+ if(filename && (unsigned char)filename[0] == (unsigned char)0xEF
+ && (unsigned char)filename[1] == (unsigned char)0xBB
+ && (unsigned char)filename[2] == (unsigned char)0xBF)
+ {
+ filename+=3;
+ }
+
+ // Special case for blank pages
+ if(!filename || !filename[0])
+ {
+ return GUTF8String();
+ }
+
+ // Normalize file name to url slash-and-escape syntax
+ GUTF8String oname=GURL::expand_name(filename);
+ GUTF8String nname=GURL::encode_reserved(oname);
+
+ // Preprend "file://" to file name. If file is on the local
+ // machine, include "localhost".
+ GUTF8String url=filespecslashes;
+ const char *cnname=nname;
+ if (cnname[0] == slash)
+ {
+ if (cnname[1] == slash)
+ {
+ url += cnname+2;
+ }else
+ {
+ url = localhost + nname;
+ }
+ }else
+ {
+ url += (localhostspec1+2) + nname;
+ }
+ return url;
+}
+
+GUTF8String
+GURL::get_string(const bool nothrow) const
+{
+ if(!validurl)
+ const_cast<GURL *>(this)->init(nothrow);
+ return url;
+}
+
+// -- Returns a url for accessing a given file.
+// If useragent is not provided, standard url will be created,
+// but will not be understood by some versions if IE.
+GUTF8String
+GURL::get_string(const GUTF8String &useragent) const
+{
+ if(!validurl)
+ const_cast<GURL *>(this)->init();
+ GUTF8String retval(url);
+ if(is_local_file_url()&&useragent.length())
+ {
+ if(useragent.search("MSIE") >= 0 || useragent.search("Microsoft")>=0)
+ {
+ retval=filespecslashes + expand_name(UTF8Filename());
+ }
+ }
+ return retval;
+}
+
+GURL::UTF8::UTF8(const GUTF8String &xurl)
+: GURL(xurl) {}
+
+GURL::UTF8::UTF8(const GUTF8String &xurl,const GURL &codebase)
+: GURL(xurl,codebase) {}
+
+GURL::GURL(const GUTF8String &xurl,const GURL &codebase)
+ : validurl(false)
+{
+ if(GURL::UTF8(xurl).is_valid())
+ {
+ url=xurl;
+ }else
+ {
+ const char *c=xurl;
+ if(c[0] == slash)
+ {
+ GURL base(codebase);
+ for(GURL newbase=base.base();newbase!=base;newbase=base.base())
+ {
+ base=newbase;
+ }
+ url=base.get_string(true)+GURL::encode_reserved(xurl);
+ }else
+ {
+ url=beautify_path(codebase.get_string(true)+GUTF8String(slash)+GURL::encode_reserved(xurl));
+ }
+ }
+}
+
+GURL::Native::Native(const GNativeString &xurl)
+: GURL(xurl) {}
+
+GURL::Native::Native(const GNativeString &xurl,const GURL &codebase)
+: GURL(xurl,codebase) {}
+
+GURL::GURL(const GNativeString &xurl,const GURL &codebase)
+ : validurl(false)
+{
+ GURL retval(xurl.getNative2UTF8(),codebase);
+ if(retval.is_valid())
+ {
+#if defined(WIN32)
+ // Hack for IE to change \\ to /
+ if(retval.is_local_file_url())
+ {
+ GURL::Filename::UTF8 retval2(retval.UTF8Filename());
+ url=retval2.get_string(true);
+ validurl=false;
+ }else
+#endif // WIN32
+ {
+ url=retval.get_string(true);
+ validurl=false;
+ }
+ }
+}
+
+GURL::Filename::Filename(const GNativeString &gfilename)
+{
+ url=url_from_UTF8filename(gfilename.getNative2UTF8());
+}
+
+GURL::Filename::Native::Native(const GNativeString &gfilename)
+: GURL::Filename(gfilename) {}
+
+GURL::Filename::Filename(const GUTF8String &gfilename)
+{
+ url=url_from_UTF8filename(gfilename);
+}
+
+GURL::Filename::UTF8::UTF8(const GUTF8String &gfilename)
+: GURL::Filename(gfilename) {}
+
+// filename --
+// -- Applies heuristic rules to convert a url into a valid file name.
+// Returns a simple basename in case of failure.
+GUTF8String
+GURL::UTF8Filename(void) const
+{
+ GUTF8String retval;
+ if(! is_empty())
+ {
+ const char *url_ptr=url;
+
+ // WARNING: Whenever you modify this conversion code,
+ // make sure, that the following functions are in sync:
+ // encode_reserved()
+ // decode_reserved()
+ // url_to_filename()
+ // filename_to_url()
+
+ GUTF8String urlcopy=decode_reserved(url);
+ url_ptr = urlcopy;
+
+ // All file urls are expected to start with filespec which is "file:"
+ if (GStringRep::cmp(filespec, url_ptr, sizeof(filespec)-1)) //if not
+ return GOS::basename(url_ptr);
+ url_ptr += sizeof(filespec)-1;
+
+#if defined(macintosh)
+ //remove all leading slashes
+ for(;*url_ptr==slash;url_ptr++)
+ EMPTY_LOOP;
+ // Remove possible localhost spec
+ if ( !GStringRep::cmp(localhost, url_ptr, sizeof(localhost)-1) )
+ url_ptr += sizeof(localhost)-1;
+ //remove all leading slashes
+ while(*url_ptr==slash)
+ url_ptr++;
+#else
+ // Remove possible localhost spec
+ if ( !GStringRep::cmp(localhostspec1, url_ptr, sizeof(localhostspec1)-1) )
+ // RFC 1738 local host form
+ url_ptr += sizeof(localhostspec1)-1;
+ else if ( !GStringRep::cmp(localhostspec2, url_ptr, sizeof(localhostspec2)-1 ) )
+ // RFC 1738 local host form
+ url_ptr += sizeof(localhostspec2)-1;
+ else if ( (strlen(url_ptr) > 4) // "file://<letter>:/<path>"
+ && (url_ptr[0] == slash) // "file://<letter>|/<path>"
+ && (url_ptr[1] == slash)
+ && isalpha(url_ptr[2])
+ && ( url_ptr[3] == colon || url_ptr[3] == '|' )
+ && (url_ptr[4] == slash) )
+ url_ptr += 2;
+ else if ( (strlen(url_ptr)) > 2 // "file:/<path>"
+ && (url_ptr[0] == slash)
+ && (url_ptr[1] != slash) )
+ url_ptr++;
+#endif
+
+ // Check if we are finished
+#if defined(macintosh)
+ {
+ char *l_url;
+ GPBuffer<char> gl_url(l_url,strlen(url_ptr)+1);
+ const char *s;
+ char *r;
+ for ( s=url_ptr,r=l_url; *s; s++,r++)
+ {
+ *r=(*s == slash)?colon:*s;
+ }
+ *r=0;
+ retval = expand_name(l_url,root);
+ }
+#else
+ retval = expand_name(url_ptr,root);
+#endif
+
+#if defined(WIN32) || defined(OS2)
+ if (url_ptr[0] && url_ptr[1]=='|' && url_ptr[2]== slash)
+ {
+ if ((url_ptr[0]>='a' && url_ptr[0]<='z')
+ || (url_ptr[0]>='A' && url_ptr[0]<='Z'))
+ {
+ GUTF8String drive;
+ drive.format("%c%c%c", url_ptr[0],colon,backslash);
+ retval = expand_name(url_ptr+3, drive);
+ }
+ }
+#endif
+ }
+ // Return what we have
+ return retval;
+}
+
+GNativeString
+GURL::NativeFilename(void) const
+{
+ return UTF8Filename().getUTF82Native();
+}
+
+#if defined(UNIX) || defined(macintosh) || defined(OS2)
+static int
+urlstat(const GURL &url,struct stat &buf)
+{
+ return ::stat(url.NativeFilename(),&buf);
+}
+#endif
+
+// is_file(url) --
+// -- returns true if filename denotes a regular file.
+bool
+GURL::is_file(void) const
+{
+ bool retval=false;
+ if(is_local_file_url())
+ {
+#if defined(UNIX) || defined(macintosh) || defined(OS2)
+ struct stat buf;
+ if (!urlstat(*this,buf))
+ {
+ retval=!(buf.st_mode & S_IFDIR);
+ }
+#elif defined(WIN32)
+ GUTF8String filename(UTF8Filename());
+ if(filename.length() >= MAX_PATH)
+ {
+ if(!filename.cmp("\\\\",2))
+ filename="\\\\?\\UNC"+filename.substr(1,-1);
+ else
+ filename="\\\\?\\"+filename;
+ }
+ wchar_t *wfilename;
+ const size_t wfilename_size=filename.length()+1;
+ GPBuffer<wchar_t> gwfilename(wfilename,wfilename_size);
+ filename.ncopy(wfilename,wfilename_size);
+ DWORD dwAttrib;
+ dwAttrib = GetFileAttributesW(wfilename);
+ if((dwAttrib|1) == 0xFFFFFFFF)
+ {
+ USES_CONVERSION ;
+ dwAttrib = GetFileAttributes(A2CT(NativeFilename())) ;//MBCS cvt
+ }
+ retval=!( dwAttrib & FILE_ATTRIBUTE_DIRECTORY );
+#else
+# error "Define something here for your operating system"
+#endif
+ }
+ return retval;
+}
+
+bool
+GURL::is_local_path(void) const
+{
+ bool retval=false;
+ if(is_local_file_url())
+ {
+#if defined(UNIX) || defined(macintosh) || defined(OS2)
+ struct stat buf;
+ retval=!urlstat(*this,buf);
+#else
+ GUTF8String filename(UTF8Filename());
+ if(filename.length() >= MAX_PATH)
+ {
+ if(!filename.cmp("\\\\",2))
+ filename="\\\\?\\UNC"+filename.substr(1,-1);
+ else
+ filename="\\\\?\\"+filename;
+ }
+ wchar_t *wfilename;
+ const size_t wfilename_size=filename.length()+1;
+ GPBuffer<wchar_t> gwfilename(wfilename,wfilename_size);
+ filename.ncopy(wfilename,wfilename_size);
+ DWORD dwAttrib;
+ dwAttrib = GetFileAttributesW(wfilename);
+ if((dwAttrib|1) == 0xFFFFFFFF)
+ {
+ USES_CONVERSION ;
+ dwAttrib = GetFileAttributes(A2CT(NativeFilename())) ;//MBCS cvt
+ }
+ retval=( (dwAttrib|1) != 0xFFFFFFFF);
+#endif
+ }
+ return retval;
+}
+
+// is_dir(url) --
+// -- returns true if url denotes a directory.
+bool
+GURL::is_dir(void) const
+{
+ bool retval=false;
+ if(is_local_file_url())
+ {
+ // UNIX implementation
+#if defined(UNIX) || defined(macintosh) || defined(OS2)
+ struct stat buf;
+ if (!urlstat(*this,buf))
+ {
+ retval=(buf.st_mode & S_IFDIR);
+ }
+#elif defined(WIN32) // (either Windows or WCE)
+ GUTF8String filename(UTF8Filename());
+ if(filename.length() >= MAX_PATH)
+ {
+ if(!filename.cmp("\\\\",2))
+ filename="\\\\?\\UNC"+filename.substr(1,-1);
+ else
+ filename="\\\\?\\"+filename;
+ }
+ wchar_t *wfilename;
+ const size_t wfilename_size=filename.length()+1;
+ GPBuffer<wchar_t> gwfilename(wfilename,wfilename_size);
+ filename.ncopy(wfilename,wfilename_size);
+ DWORD dwAttrib;
+ dwAttrib = GetFileAttributesW(wfilename);
+ if((dwAttrib|1) == 0xFFFFFFFF)
+ {
+ USES_CONVERSION ;
+ dwAttrib = GetFileAttributes(A2CT(NativeFilename())) ;//MBCS cvt
+ }
+ retval=((dwAttrib != 0xFFFFFFFF)&&( dwAttrib & FILE_ATTRIBUTE_DIRECTORY ));
+#else
+# error "Define something here for your operating system"
+#endif
+ }
+ return retval;
+}
+
+// Follows symbolic links.
+GURL
+GURL::follow_symlinks(void) const
+{
+ GURL ret = *this;
+#if defined(S_IFLNK)
+#if defined(UNIX) || defined(macintosh)
+ int lnklen;
+ char lnkbuf[MAXPATHLEN+1];
+ struct stat buf;
+ while ( (urlstat(ret, buf) >= 0) &&
+ (buf.st_mode & S_IFLNK) &&
+ ((lnklen = readlink(ret.NativeFilename(),lnkbuf,sizeof(lnkbuf))) > 0) )
+ {
+ lnkbuf[lnklen] = 0;
+ GNativeString lnk(lnkbuf);
+ ret = GURL(lnk, ret.base());
+ }
+#endif
+#endif
+ return ret;
+}
+
+int
+GURL::mkdir() const
+{
+ if(! is_local_file_url())
+ return -1;
+ int retval=0;
+ const GURL baseURL=base();
+ if (baseURL.get_string() != url && !baseURL.is_dir())
+ retval = baseURL.mkdir();
+ if(!retval)
+ {
+#if defined(UNIX)
+ if (is_dir())
+ retval = 0;
+ else
+ retval = ::mkdir(NativeFilename(), 0755);
+#elif defined(WIN32)
+ USES_CONVERSION;
+ if (is_dir())
+ retval = 0;
+ else
+ retval = CreateDirectory(A2CT(NativeFilename()), NULL);
+#else
+# error "Define something here for your operating system"
+#endif
+ }
+ return retval;
+}
+
+// deletefile
+// -- deletes a file or directory
+
+int
+GURL::deletefile(void) const
+{
+ int retval = -1;
+ if(is_local_file_url())
+ {
+#if defined(UNIX)
+ if (is_dir())
+ retval = ::rmdir(NativeFilename());
+ else
+ retval = ::unlink(NativeFilename());
+#elif defined(WIN32)
+ USES_CONVERSION;
+ if (is_dir())
+ retval = ::RemoveDirectory(A2CT(NativeFilename()));
+ else
+ retval = ::DeleteFile(A2CT(NativeFilename()));
+#else
+# error "Define something here for your operating system"
+#endif
+ }
+ return retval;
+}
+
+GList<GURL>
+GURL::listdir(void) const
+{
+ GList<GURL> retval;
+ if(is_dir())
+ {
+#if defined(UNIX) || defined(OS2)
+ DIR * dir=opendir(NativeFilename());//MBCS cvt
+ for(dirent *de=readdir(dir);de;de=readdir(dir))
+ {
+ const int len = NAMLEN(de);
+ if (de->d_name[0]== dot && len==1)
+ continue;
+ if (de->d_name[0]== dot && de->d_name[1]== dot && len==2)
+ continue;
+ retval.append(GURL::Native(de->d_name,*this));
+ }
+ closedir(dir);
+#elif defined (WIN32)
+ GURL::UTF8 wildcard("*.*",*this);
+ WIN32_FIND_DATA finddata;
+ HANDLE handle = FindFirstFile(wildcard.NativeFilename(), &finddata);//MBCS cvt
+ const GUTF8String gpathname=pathname();
+ const GUTF8String gbase=base().pathname();
+ if( handle != INVALID_HANDLE_VALUE)
+ {
+ do
+ {
+ GURL::UTF8 Entry(finddata.cFileName,*this);
+ const GUTF8String gentry=Entry.pathname();
+ if((gentry != gpathname) && (gentry != gbase))
+ retval.append(Entry);
+ } while( FindNextFile(handle, &finddata) );
+
+ FindClose(handle);
+ }
+#else
+# error "Define something here for your operating system"
+#endif
+ }
+ return retval;
+}
+
+int
+GURL::cleardir(const int timeout) const
+{
+ int retval=(-1);
+ if(is_dir())
+ {
+ GList<GURL> dirlist=listdir();
+ retval=0;
+ for(GPosition pos=dirlist;pos&&!retval;++pos)
+ {
+ const GURL &Entry=dirlist[pos];
+ if(Entry.is_dir())
+ {
+ if((retval=Entry.cleardir(timeout)) < 0)
+ {
+ break;
+ }
+ }
+ if(((retval=Entry.deletefile())<0) && (timeout>0))
+ {
+ GOS::sleep(timeout);
+ retval=Entry.deletefile();
+ }
+ }
+ }
+ return retval;
+}
+
+int
+GURL::renameto(const GURL &newurl) const
+{
+ if (is_local_file_url() && newurl.is_local_file_url())
+ return rename(NativeFilename(),newurl.NativeFilename());
+ return -1;
+}
+
+// expand_name(filename[, fromdirname])
+// -- returns the full path name of filename interpreted
+// relative to fromdirname. Use current working dir when
+// fromdirname is null.
+GUTF8String
+GURL::expand_name(const GUTF8String &xfname, const char *from)
+{
+ const char *fname=xfname;
+ GUTF8String retval;
+ const size_t maxlen=xfname.length()*9+MAXPATHLEN+10;
+ char * const string_buffer = retval.getbuf(maxlen);
+ // UNIX implementation
+#if defined(UNIX)
+ // Perform tilde expansion
+ GUTF8String senv;
+ if (fname && fname[0]==tilde)
+ {
+ int n;
+ for(n=1;fname[n] && fname[n]!= slash;n++)
+ EMPTY_LOOP;
+ struct passwd *pw=0;
+ if (n!=1)
+ {
+ GUTF8String user(fname+1, n-1);
+ pw=getpwnam(user);
+ }else if ((senv=GOS::getenv("HOME")).length())
+ {
+ from=(const char *)senv;
+ fname = fname + n;
+ }else if ((senv=GOS::getenv("LOGNAME")).length())
+ {
+ pw = getpwnam((const char *)senv.getUTF82Native());
+ }else
+ {
+ pw=getpwuid(getuid());
+ }
+ if (pw)
+ {
+ senv=GNativeString(pw->pw_dir).getNative2UTF8();
+ from = (const char *)senv;
+ fname = fname + n;
+ }
+ for(;fname[0] == slash; fname++)
+ EMPTY_LOOP;
+ }
+ // Process absolute vs. relative path
+ if (fname && fname[0]== slash)
+ {
+ string_buffer[0]=slash;
+ string_buffer[1]=0;
+ }else if (from)
+ {
+ strcpy(string_buffer, expand_name(from));
+ }else
+ {
+ strcpy(string_buffer, GOS::cwd());
+ }
+ char *s = string_buffer + strlen(string_buffer);
+ if(fname)
+ {
+ for(;fname[0]== slash;fname++)
+ EMPTY_LOOP;
+ // Process path components
+ while(fname[0])
+ {
+ if (fname[0] == dot )
+ {
+ if (!fname[1] || fname[1]== slash)
+ {
+ fname++;
+ continue;
+ }else if (fname[1]== dot && (fname[2]== slash || !fname[2]))
+ {
+ fname +=2;
+ for(;s>string_buffer+1 && *(s-1)== slash; s--)
+ EMPTY_LOOP;
+ for(;s>string_buffer+1 && *(s-1)!= slash; s--)
+ EMPTY_LOOP;
+ continue;
+ }
+ }
+ if ((s==string_buffer)||(*(s-1)!= slash))
+ {
+ *s = slash;
+ s++;
+ }
+ while (*fname &&(*fname!= slash))
+ {
+ *s = *fname++;
+ if ((size_t)((++s)-string_buffer) > maxlen)
+ {
+ G_THROW( ERR_MSG("GURL.big_name") );
+ }
+ }
+ *s = 0;
+ for(;fname[0]== slash;fname++)
+ EMPTY_LOOP;
+ }
+ }
+ if (!fname || !fname[0])
+ {
+ for(;s>string_buffer+1 && *(s-1) == slash; s--)
+ EMPTY_LOOP;
+ *s = 0;
+ }
+#elif defined (WIN32) // WIN32 implementation
+ // Handle base
+ strcpy(string_buffer, (char const *)(from ? expand_name(from) : GOS::cwd()));
+ // GNativeString native;
+ if (fname)
+ {
+ char *s = string_buffer;
+ char drv[4];
+ // Handle absolute part of fname
+ // Put absolute part of the file name in string_buffer, and
+ // the relative part pointed to by fname.
+ if (fname[0]== slash || fname[0]== backslash)
+ {
+ if (fname[1]== slash || fname[1]== backslash)
+ { // Case "//abcd"
+ s[0]=s[1]= backslash; s[2]=0;
+ }
+ else
+ { // Case "/abcd" or "/"
+ // File is at the root of the current drive. Delete the
+ // slash at the beginning of the filename and leave
+ // an explicit identification of the root of the drive in
+ // string_buffer.
+ fname++;
+ s[3] = '\0';
+ }
+ }
+ else if (fname[0] && fname[1]==colon)
+ {
+ if (fname[2]!= slash && fname[2]!= backslash)
+ { // Case "x:abcd"
+ if ( toupper((unsigned char)s[0]) != toupper((unsigned char)fname[0])
+ || s[1]!=colon)
+ {
+ drv[0]=fname[0];
+ drv[1]=colon;
+ drv[2]= dot ;
+ drv[3]=0;
+ GetFullPathName(drv, maxlen, string_buffer, &s);
+ strcpy(string_buffer,(const char *)GUTF8String(string_buffer).getNative2UTF8());
+ s = string_buffer;
+ }
+ fname += 2;
+ }
+ else if (fname[3]!= slash && fname[3]!= backslash)
+ { // Case "x:/abcd"
+ s[0]=toupper((unsigned char)fname[0]);
+ s[1]=colon;
+ s[2]=backslash;
+ s[3]=0;
+ fname += 3;
+ }
+ else
+ { // Case "x://abcd"
+ s[0]=s[1]=backslash;
+ s[2]=0;
+ fname += 4;
+ }
+ }
+ // Process path components
+ for(;*fname== slash || *fname==backslash;fname++)
+ EMPTY_LOOP;
+ while(*fname)
+ {
+ if (fname[0]== dot )
+ {
+ if (fname[1]== slash || fname[1]==backslash || !fname[1])
+ {
+ fname++;
+ continue;
+ }else if ((fname[1] == dot)
+ && (fname[2]== slash || fname[2]==backslash || !fname[2]))
+ {
+ fname += 2;
+ char *back=_tcsrchr(string_buffer,backslash);
+ char *forward=_tcsrchr(string_buffer,slash);
+ if(back>forward)
+ {
+ *back=0;
+ }else if(forward)
+ {
+ *forward=0;
+ }
+ s = string_buffer;
+ continue;
+ }
+ char* s2=s;//MBCS DBCS
+ for(;*s;s++)
+ EMPTY_LOOP;
+ char* back = _tcsrchr(s2,backslash);//MBCS DBCS
+ if ((s>string_buffer)&&(*(s-1)!= slash)&&
+ (back == NULL || (back!=NULL && s-1 != back) ))//MBCS DBCS
+ {
+ *s = backslash;
+ s++;
+ }
+ while (*fname && *fname!= slash && *fname!=backslash)
+ {
+ *s = *fname++;
+ if ((size_t)((++s)-string_buffer) > maxlen)
+ G_THROW( ERR_MSG("GURL.big_name") );
+ }
+ *s = 0;
+ }
+ char* s2=s;//MBCS DBCS
+ for(;*s;s++)
+ EMPTY_LOOP;
+ char* back = _tcsrchr(s2,backslash);//MBCS DBCS
+ if ((s>string_buffer)&&(*(s-1)!= slash)
+ &&(back == NULL || (back!=NULL && s-1 != back) ))//MBCS DBCS
+ {
+ *s = backslash;
+ s++;
+ }
+ while (*fname && (*fname!= slash) && (*fname!=backslash))
+ {
+ *s = *fname++;
+ if ((size_t)((++s)-string_buffer) > maxlen)
+ G_THROW( ERR_MSG("GURL.big_name") );
+ }
+ *s = 0;
+ for(;(*fname== slash)||(*fname==backslash);fname++)
+ EMPTY_LOOP;
+ }
+ }
+#elif defined(macintosh) // MACINTOSH implementation
+ strcpy(string_buffer, (const char *)(from?from:GOS::cwd()));
+
+ if (!GStringRep::cmp(fname, string_buffer,strlen(string_buffer)) || is_file(fname))
+ {
+ strcpy(string_buffer, "");//please don't expand, the logic of filename is chaos.
+ }
+
+ // Process path components
+ char *s = string_buffer + strlen(string_buffer);
+ if(fname)
+ {
+ for(;fname[0]==colon;fname++)
+ EMPTY_LOOP;
+ while(fname[0])
+ {
+ if (fname[0]== dot )
+ {
+ if (fname[1]==colon || !fname[1])
+ {
+ fname++;
+ continue;
+ }
+ if ((fname[1]== dot )
+ &&(fname[2]==colon || fname[2]==0))
+ {
+ fname +=2;
+ for(;(s>string_buffer+1)&&(*(s-1)==colon);s--)
+ EMPTY_LOOP;
+ for(;(s>string_buffer+1)&&(*(s-1)!=colon);s--)
+ EMPTY_LOOP;
+ continue;
+ }
+ }
+ if ((s==string_buffer)||(*(s-1)!=colon))
+ {
+ *s = colon;
+ s++;
+ }
+ while (*fname!=0 && *fname!=colon)
+ {
+ *s = *fname++;
+ if ((++s)-string_buffer > maxlen)
+ G_THROW( ERR_MSG("GURL.big_name") );
+ }
+ *s = 0;
+ for(;fname[0]==colon;fname++)
+ EMPTY_LOOP;
+ }
+ }
+ for(;(s>string_buffer+1) && (*(s-1)==colon);s--)
+ EMPTY_LOOP;
+ *s = 0;
+ return ((string_buffer[0]==colon)?(string_buffer+1):string_buffer);
+#else
+# error "Define something here for your operating system"
+#endif
+ return retval;
+}
+
+unsigned int
+hash(const GURL & gurl)
+{
+ unsigned int retval;
+ const GUTF8String s(gurl.get_string());
+ const int len=s.length();
+ if(len && (s[len-1] == '/')) // Don't include the trailing slash as part of the hash.
+ {
+ retval=hash(s.substr(0,len-1));
+ }else
+ {
+ retval=hash(s);
+ }
+ return retval;
+}
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif