• Skip to content
  • Skip to link menu
KDE 3.5 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

kviewshell

GURL.cpp

Go to the documentation of this file.
00001 //C-  -*- C++ -*-
00002 //C- -------------------------------------------------------------------
00003 //C- DjVuLibre-3.5
00004 //C- Copyright (c) 2002  Leon Bottou and Yann Le Cun.
00005 //C- Copyright (c) 2001  AT&T
00006 //C-
00007 //C- This software is subject to, and may be distributed under, the
00008 //C- GNU General Public License, Version 2. The license should have
00009 //C- accompanied the software or you may obtain a copy of the license
00010 //C- from the Free Software Foundation at http://www.fsf.org .
00011 //C-
00012 //C- This program is distributed in the hope that it will be useful,
00013 //C- but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 //C- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 //C- GNU General Public License for more details.
00016 //C- 
00017 //C- DjVuLibre-3.5 is derived from the DjVu(r) Reference Library
00018 //C- distributed by Lizardtech Software.  On July 19th 2002, Lizardtech 
00019 //C- Software authorized us to replace the original DjVu(r) Reference 
00020 //C- Library notice by the following text (see doc/lizard2002.djvu):
00021 //C-
00022 //C-  ------------------------------------------------------------------
00023 //C- | DjVu (r) Reference Library (v. 3.5)
00024 //C- | Copyright (c) 1999-2001 LizardTech, Inc. All Rights Reserved.
00025 //C- | The DjVu Reference Library is protected by U.S. Pat. No.
00026 //C- | 6,058,214 and patents pending.
00027 //C- |
00028 //C- | This software is subject to, and may be distributed under, the
00029 //C- | GNU General Public License, Version 2. The license should have
00030 //C- | accompanied the software or you may obtain a copy of the license
00031 //C- | from the Free Software Foundation at http://www.fsf.org .
00032 //C- |
00033 //C- | The computer code originally released by LizardTech under this
00034 //C- | license and unmodified by other parties is deemed "the LIZARDTECH
00035 //C- | ORIGINAL CODE."  Subject to any third party intellectual property
00036 //C- | claims, LizardTech grants recipient a worldwide, royalty-free, 
00037 //C- | non-exclusive license to make, use, sell, or otherwise dispose of 
00038 //C- | the LIZARDTECH ORIGINAL CODE or of programs derived from the 
00039 //C- | LIZARDTECH ORIGINAL CODE in compliance with the terms of the GNU 
00040 //C- | General Public License.   This grant only confers the right to 
00041 //C- | infringe patent claims underlying the LIZARDTECH ORIGINAL CODE to 
00042 //C- | the extent such infringement is reasonably necessary to enable 
00043 //C- | recipient to make, have made, practice, sell, or otherwise dispose 
00044 //C- | of the LIZARDTECH ORIGINAL CODE (or portions thereof) and not to 
00045 //C- | any greater extent that may be necessary to utilize further 
00046 //C- | modifications or combinations.
00047 //C- |
00048 //C- | The LIZARDTECH ORIGINAL CODE is provided "AS IS" WITHOUT WARRANTY
00049 //C- | OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
00050 //C- | TO ANY WARRANTY OF NON-INFRINGEMENT, OR ANY IMPLIED WARRANTY OF
00051 //C- | MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
00052 //C- +------------------------------------------------------------------
00053 // 
00054 // $Id: GURL.cpp,v 1.19 2005/04/27 16:34:13 leonb Exp $
00055 // $Name: release_3_5_15 $
00056 
00057 #ifdef HAVE_CONFIG_H
00058 # include "config.h"
00059 #endif
00060 #if NEED_GNUG_PRAGMAS
00061 # pragma implementation
00062 #endif
00063 
00064 // From: Leon Bottou, 1/31/2002
00065 // This has been heavily changed by Lizardtech.
00066 // They decided to use URLs for everyting, including
00067 // the most basic file access.  The URL class now is a unholy 
00068 // mixture of code for syntactically parsing the urls (which it was)
00069 // and file status code (only for local file: urls).
00070 
00071 #include "GException.h"
00072 #include "GOS.h"
00073 #include "GURL.h"
00074 #include "debug.h"
00075 
00076 #include <stdlib.h>
00077 #include <stdio.h>
00078 #include <ctype.h>
00079 #include <math.h>
00080 #include <string.h>
00081 
00082 #ifdef WIN32
00083 # include <atlbase.h>
00084 # include <windows.h>
00085 # include <direct.h>
00086 #endif /* WIN32 */
00087 
00088 // -- MAXPATHLEN
00089 #ifndef MAXPATHLEN
00090 # ifdef _MAX_PATH
00091 #  define MAXPATHLEN _MAX_PATH
00092 # else
00093 #  define MAXPATHLEN 1024
00094 # endif
00095 #else
00096 # if ( MAXPATHLEN < 1024 )
00097 #  undef MAXPATHLEN
00098 #  define MAXPATHLEN 1024
00099 # endif
00100 #endif
00101 
00102 #if defined(UNIX) || defined(OS2)
00103 # include <unistd.h>
00104 # include <sys/types.h>
00105 # include <sys/stat.h>
00106 # include <errno.h>
00107 # include <fcntl.h>
00108 # include <pwd.h>
00109 # include <stdio.h>
00110 # ifdef AUTOCONF
00111 #  ifdef TIME_WITH_SYS_TIME
00112 #   include <sys/time.h>
00113 #   include <time.h>
00114 #  else
00115 #   ifdef HAVE_SYS_TIME_H
00116 #    include <sys/time.h>
00117 #   else
00118 #    include <time.h>
00119 #   endif
00120 #  endif
00121 #  ifdef HAVE_DIRENT_H
00122 #   include <dirent.h>
00123 #   define NAMLEN(dirent) strlen((dirent)->d_name)
00124 #  else
00125 #   define dirent direct
00126 #   define NAMLEN(dirent) (dirent)->d_namlen
00127 #   ifdef HAVE_SYS_NDIR_H
00128 #    include <sys/ndir.h>
00129 #   endif
00130 #   ifdef HAVE_SYS_DIR_H
00131 #    include <sys/dir.h>
00132 #   endif
00133 #   ifdef HAVE_NDIR_H
00134 #    include <ndir.h>
00135 #   endif
00136 #  endif
00137 # else /* !AUTOCONF */ 
00138 #  include <sys/time.h>
00139 #  if defined(XENIX)
00140 #   define USE_DIRECT
00141 #   include <sys/ndir.h>
00142 #  elif defined(OLDBSD)
00143 #   define USE_DIRECT
00144 #   include <sys/dir.h>
00145 #  endif
00146 #  ifdef USE_DIRECT
00147 #   define dirent direct
00148 #   define NAMLEN(dirent) (dirent)->d_namlen
00149 #  else
00150 #   include <dirent.h>
00151 #   define NAMLEN(dirent) strlen((dirent)->d_name)
00152 #  endif 
00153 # endif /* !AUTOCONF */
00154 #endif /* UNIX */
00155 
00156 #ifdef macintosh
00157 #include <unix.h>
00158 #include <errno.h>
00159 #include <unistd.h>
00160 #endif
00161 
00162 
00163 #ifdef HAVE_NAMESPACES
00164 namespace DJVU {
00165 # ifdef NOT_DEFINED // Just to fool emacs c++ mode
00166 }
00167 #endif
00168 #endif
00169 
00170 
00171 static const char djvuopts[]="DJVUOPTS";
00172 static const char localhost[]="file://localhost/";
00173 static const char backslash='\\';  
00174 static const char colon=':';
00175 static const char dot='.';
00176 static const char filespecslashes[] = "file://";
00177 static const char filespec[] = "file:";
00178 static const char slash='/';
00179 static const char percent='%';
00180 static const char localhostspec1[] = "//localhost/";
00181 static const char localhostspec2[] = "///";
00182 static const char nillchar=0;
00183 #if defined(UNIX)
00184   static const char tilde='~';
00185   static const char root[] = "/";
00186 #elif defined(WIN32) || defined(OS2)
00187   static const char root[] = "\\";
00188 #elif defined(macintosh)
00189   static char const * const root = &nillchar; 
00190 #else
00191 #error "Define something here for your operating system"
00192 #endif
00193 
00194 
00195 static const int
00196 pathname_start(const GUTF8String &url, const int protolength);
00197 
00198 // hexval --
00199 // -- Returns the hexvalue of a character.
00200 //    Returns -1 if illegal;
00201 
00202 static int 
00203 hexval(char c)
00204 {
00205   return ((c>='0' && c<='9')
00206     ?(c-'0')
00207     :((c>='A' && c<='F')
00208       ?(c-'A'+10)
00209       :((c>='a' && c<='f')
00210         ?(c-'a'+10):(-1))));
00211 }
00212 
00213 
00214 static bool
00215 is_argument(const char * start)
00216       // Returns TRUE if 'start' points to the beginning of an argument
00217       // (either hash or CGI)
00218 {
00219    // return (*start=='#' || *start=='?' || *start=='&' || *start==';');
00220    return (*start=='#' || *start=='?' );
00221 }
00222 
00223 static bool
00224 is_argument_sep(const char * start)
00225       // Returns TRUE if 'start' points to the beginning of an argument
00226       // (either hash or CGI)
00227 {
00228    return (*start=='&')||(*start == ';');
00229 }
00230 
00231 void
00232 GURL::convert_slashes(void)
00233 {
00234    GUTF8String xurl(get_string());
00235 #if defined(WIN32)
00236    const int protocol_length=protocol(xurl).length();
00237    for(char *ptr=(xurl.getbuf()+protocol_length);*ptr;ptr++)
00238      if(*ptr == backslash)
00239        *ptr=slash;
00240    url=xurl;
00241 #endif
00242 }
00243 
00244 static void
00245 collapse(char * ptr, const int chars)
00246       // Will remove the first 'chars' chars from the string and
00247       // move the rest toward the beginning. Will take into account
00248       // string length
00249 {
00250    const int length=strlen(ptr);
00251    const char *srcptr=ptr+((chars>length)?length:chars);
00252    while((*(ptr++) = *(srcptr++)))
00253      EMPTY_LOOP;
00254 }
00255 
00256 GUTF8String
00257 GURL::beautify_path(GUTF8String xurl)
00258 {
00259 
00260   const int protocol_length=GURL::protocol(xurl).length();
00261    
00262   // Eats parts like ./ or ../ or ///
00263   char * buffer;
00264   GPBuffer<char> gbuffer(buffer,xurl.length()+1);
00265   strcpy(buffer, (const char *)xurl);
00266    
00267   // Find start point
00268   char * start=buffer+pathname_start(xurl,protocol_length);
00269 
00270   // Find end of the url (don't touch arguments)
00271   char * ptr;
00272   GUTF8String args;
00273   for(ptr=start;*ptr;ptr++)
00274   {
00275     if (is_argument(ptr))
00276     {
00277       args=ptr;
00278       *ptr=0;
00279       break;
00280     }
00281   }
00282 
00283   // Eat multiple slashes
00284   for(;(ptr=strstr(start, "////"));collapse(ptr, 3))
00285     EMPTY_LOOP;
00286   for(;(ptr=strstr(start, "//"));collapse(ptr, 1))
00287     EMPTY_LOOP;
00288   // Convert /./ stuff into plain /
00289   for(;(ptr=strstr(start, "/./"));collapse(ptr, 2))
00290     EMPTY_LOOP;
00291 #if defined(WIN32) || defined(OS2)
00292   if(!xurl.cmp(filespec,sizeof(filespec)-1))
00293   {
00294     int offset=1;
00295     if(start&&(start[0] == '/')&& 
00296            !xurl.cmp("file:////",sizeof("file:////")-1))
00297     {
00298       collapse(start, 1);
00299       offset=0;
00300     }
00301     for(ptr=start+offset;(ptr=strchr(ptr, '/'));)
00302     {
00303       if(isalpha((++ptr)[0]))
00304       {
00305         if((ptr[1] == ':')&&(ptr[2]=='/'))
00306         {
00307           char *buffer2;
00308                   GPBuffer<char> gbuffer2(buffer2,strlen(ptr)+1);
00309           strcpy(buffer2,ptr);
00310           gbuffer.resize(strlen(ptr)+sizeof(localhost));
00311           strcpy(buffer,localhost);
00312           strcat(buffer,buffer2);
00313           ptr=(start=buffer+sizeof(localhost))+1;
00314         }
00315       }
00316     }
00317   }
00318 #endif
00319   // Process /../
00320   while((ptr=strstr(start, "/../")))
00321   {
00322     for(char * ptr1=ptr-1;(ptr1>=start);ptr1--)
00323     {
00324       if (*ptr1==slash)
00325       {
00326         collapse(ptr1, ptr-ptr1+3);
00327         break;
00328       }
00329     }
00330   }
00331 
00332   // Remove trailing /.
00333   ptr=start+strlen(start)-2;
00334   if((ptr>=start)&& (ptr == GUTF8String("/.")))
00335   {
00336     ptr[1]=0;
00337   }
00338   // Eat trailing /..
00339   ptr=start+strlen(start)-3;
00340   if((ptr >= start) && (ptr == GUTF8String("/..")))
00341   {
00342     for(char * ptr1=ptr-1;(ptr1>=start);ptr1--)
00343     {
00344       if (*ptr1==slash)
00345       {
00346         ptr1[1]=0;
00347         break;
00348       }
00349     }
00350   }
00351 
00352   // Done. Copy the buffer back into the URL and add arguments.
00353   xurl=buffer;
00354   return (xurl+args);
00355 }
00356 
00357 
00358 void
00359 GURL::beautify_path(void)
00360 {
00361   url=beautify_path(get_string());
00362 }
00363 
00364 void
00365 GURL::init(const bool nothrow)
00366 {
00367    GCriticalSectionLock lock(&class_lock);
00368    validurl=true;
00369    
00370    if (url.length())
00371    {
00372       GUTF8String proto=protocol();
00373       if (proto.length()<2)
00374       {
00375         validurl=false;
00376         if(!nothrow)
00377           G_THROW( ERR_MSG("GURL.no_protocol") "\t"+url);
00378         return;
00379       }
00380 
00381          // Below we have to make this complex test to detect URLs really
00382          // referring to *local* files. Surprisingly, file://hostname/dir/file
00383          // is also valid, but shouldn't be treated thru local FS.
00384       if (proto=="file" && url[5]==slash &&
00385           (url[6]!=slash || !url.cmp(localhost, sizeof(localhost))))
00386       {
00387             // Separate the arguments
00388          GUTF8String arg;
00389          {
00390            const char * const url_ptr=url;
00391            const char * ptr;
00392            for(ptr=url_ptr;*ptr&&!is_argument(ptr);ptr++)
00393                 EMPTY_LOOP;
00394            arg=ptr;
00395            url=url.substr(0,(size_t)ptr-(size_t)url_ptr);
00396          }
00397 
00398             // Do double conversion
00399          GUTF8String tmp=UTF8Filename();
00400          if (!tmp.length())
00401          {
00402            validurl=false;
00403            if(!nothrow)
00404              G_THROW( ERR_MSG("GURL.fail_to_file") );
00405            return;
00406          }
00407          url=GURL::Filename::UTF8(tmp).get_string();
00408          if (!url.length())
00409          {
00410            validurl=false;
00411            if(!nothrow)
00412              G_THROW( ERR_MSG("GURL.fail_to_URL") );
00413            return;
00414          }
00415             // Return the argument back
00416          url+=arg;
00417       }
00418       convert_slashes();
00419       beautify_path();
00420       parse_cgi_args();
00421    }
00422 }
00423 
00424 GURL::GURL(void) 
00425   : validurl(false) 
00426 {
00427 }
00428 
00429 GURL::GURL(const char * url_in) 
00430   : url(url_in ? url_in : ""), validurl(false)
00431 {
00432 }
00433 
00434 GURL::GURL(const GUTF8String & url_in)
00435   : url(url_in), validurl(false)
00436 {
00437 }
00438 
00439 GURL::GURL(const GNativeString & url_in)
00440   : url(url_in.getNative2UTF8()), validurl(false)
00441 {
00442 #if defined(WIN32) || defined(OS2)
00443   if(is_valid() && is_local_file_url())
00444   {
00445     GURL::Filename::UTF8 xurl(UTF8Filename());
00446     url=xurl.get_string(true);
00447     validurl=false;
00448   }
00449 #endif
00450 }
00451 
00452 GURL::GURL(const GURL & url_in)
00453   : validurl(false)
00454 {
00455   if(url_in.is_valid())
00456   {
00457     url=url_in.get_string();
00458     init();
00459   }else
00460   {
00461     url=url_in.url;
00462   }
00463 }
00464 
00465 GURL &
00466 GURL::operator=(const GURL & url_in)
00467 {
00468    GCriticalSectionLock lock(&class_lock);
00469    if(url_in.is_valid())
00470    {
00471      url=url_in.get_string();
00472      init(true);
00473    }else
00474    {
00475      url=url_in.url;
00476      validurl=false;
00477    }
00478    return *this;
00479 }
00480 
00481 GUTF8String
00482 GURL::protocol(const GUTF8String& url)
00483 {
00484    const char * const url_ptr=url;
00485    const char * ptr=url_ptr;
00486    for(char c=*ptr;
00487      c && (isalnum(c) || c == '+' || c == '-' || c == '.');
00488      c=*(++ptr)) EMPTY_LOOP;
00489    return(*ptr==colon)?GUTF8String(url_ptr, ptr-url_ptr):GUTF8String();
00490 }
00491 
00492 GUTF8String
00493 GURL::hash_argument(void) const
00494       // Returns the HASH argument (anything after '#' and before '?')
00495 {
00496    const GUTF8String xurl(get_string());
00497 
00498    bool found=false;
00499    GUTF8String arg;
00500 
00501          // Break if CGI argument is found
00502    for(const char * start=xurl;*start&&(*start!='?');start++)
00503    {
00504       if (found)
00505       {
00506          arg+=*start;
00507       }else
00508       {
00509          found=(*start=='#');
00510       }
00511    }
00512    return decode_reserved(arg);
00513 }
00514 
00515 void
00516 GURL::set_hash_argument(const GUTF8String &arg)
00517 {
00518    const GUTF8String xurl(get_string());
00519 
00520    GUTF8String new_url;
00521    bool found=false;
00522    const char * ptr;
00523    for(ptr=xurl;*ptr;ptr++)
00524    {
00525       if (is_argument(ptr))
00526       {
00527          if (*ptr!='#')
00528          {
00529            break;
00530          }
00531          found=true;
00532       } else if (!found)
00533       {
00534          new_url+=*ptr;
00535       }
00536    }
00537 
00538    url=new_url+"#"+GURL::encode_reserved(arg)+ptr;
00539 }
00540 
00541 void
00542 GURL::parse_cgi_args(void)
00543       // Will read CGI arguments from the URL into
00544       // cgi_name_arr and cgi_value_arr
00545 {
00546    if(!validurl)
00547      init();
00548    GCriticalSectionLock lock1(&class_lock);
00549    cgi_name_arr.empty();
00550    cgi_value_arr.empty();
00551 
00552       // Search for the beginning of CGI arguments
00553    const char * start=url;
00554    while(*start)
00555    {
00556      if(*(start++)=='?')
00557      {
00558        break;
00559      }
00560    }
00561 
00562       // Now loop until we see all of them
00563    while(*start)
00564    {
00565       GUTF8String arg;        // Storage for another argument
00566       while(*start)        // Seek for the end of it
00567       {
00568          if (is_argument_sep(start))
00569          {
00570             start++;
00571             break;
00572          } else
00573          {
00574            arg+=*start++;
00575          }
00576       }
00577       if (arg.length())
00578       {
00579             // Got argument in 'arg'. Split it into 'name' and 'value'
00580          const char * ptr;
00581          const char * const arg_ptr=arg;
00582      for(ptr=arg_ptr;*ptr&&(*ptr != '=');ptr++)
00583        EMPTY_LOOP;
00584 
00585          GUTF8String name, value;
00586          if (*ptr)
00587          {
00588             name=GUTF8String(arg_ptr, (int)((ptr++)-arg_ptr));
00589             value=GUTF8String(ptr, arg.length()-name.length()-1);
00590          } else
00591          {
00592            name=arg;
00593          }
00594             
00595          int args=cgi_name_arr.size();
00596          cgi_name_arr.resize(args);
00597          cgi_value_arr.resize(args);
00598          cgi_name_arr[args]=decode_reserved(name);
00599          cgi_value_arr[args]=decode_reserved(value);
00600       }
00601    }
00602 }
00603 
00604 void
00605 GURL::store_cgi_args(void)
00606       // Will store CGI arguments from the cgi_name_arr and cgi_value_arr
00607       // back into the URL
00608 {
00609    if(!validurl)
00610      init();
00611    GCriticalSectionLock lock1(&class_lock);
00612 
00613    const char * const url_ptr=url;
00614    const char * ptr;
00615    for(ptr=url_ptr;*ptr&&(*ptr!='?');ptr++)
00616         EMPTY_LOOP;
00617    
00618    GUTF8String new_url(url_ptr, ptr-url_ptr);
00619    
00620    for(int i=0;i<cgi_name_arr.size();i++)
00621    {
00622       GUTF8String name=GURL::encode_reserved(cgi_name_arr[i]);
00623       GUTF8String value=GURL::encode_reserved(cgi_value_arr[i]);
00624       new_url+=(i?"&":"?")+name;
00625       if (value.length())
00626          new_url+="="+value;
00627    }
00628 
00629    url=new_url;
00630 }
00631 
00632 int
00633 GURL::cgi_arguments(void) const
00634 {
00635    if(!validurl)
00636       const_cast<GURL *>(this)->init();
00637    return cgi_name_arr.size();
00638 }
00639 
00640 int
00641 GURL::djvu_cgi_arguments(void) const
00642 {
00643    if(!validurl)
00644      const_cast<GURL *>(this)->init();
00645    GCriticalSectionLock lock((GCriticalSection *) &class_lock);
00646 
00647    int args=0;
00648    for(int i=0;i<cgi_name_arr.size();i++)
00649    {
00650       if (cgi_name_arr[i].upcase()==djvuopts)
00651       {
00652          args=cgi_name_arr.size()-(i+1);
00653          break;
00654       }
00655    } 
00656    return args;
00657 }
00658 
00659 GUTF8String
00660 GURL::cgi_name(int num) const
00661 {
00662    if(!validurl) const_cast<GURL *>(this)->init();
00663    GCriticalSectionLock lock((GCriticalSection *) &class_lock);
00664    return (num<cgi_name_arr.size())?cgi_name_arr[num]:GUTF8String();
00665 }
00666 
00667 GUTF8String
00668 GURL::djvu_cgi_name(int num) const
00669 {
00670    if(!validurl) const_cast<GURL *>(this)->init();
00671    GCriticalSectionLock lock((GCriticalSection *) &class_lock);
00672 
00673    GUTF8String arg;
00674    for(int i=0;i<cgi_name_arr.size();i++)
00675       if (cgi_name_arr[i].upcase()==djvuopts)
00676       {
00677          for(i++;i<cgi_name_arr.size();i++)
00678             if (! num--)
00679             {
00680                arg=cgi_name_arr[i];
00681                break;
00682             }
00683          break;
00684       }
00685    return arg;
00686 }
00687 
00688 GUTF8String
00689 GURL::cgi_value(int num) const
00690 {
00691    if(!validurl) const_cast<GURL *>(this)->init();
00692    GCriticalSectionLock lock((GCriticalSection *) &class_lock);
00693    return (num<cgi_value_arr.size())?cgi_value_arr[num]:GUTF8String();
00694 }
00695 
00696 GUTF8String
00697 GURL::djvu_cgi_value(int num) const
00698 {
00699    if(!validurl) const_cast<GURL *>(this)->init();
00700    GCriticalSectionLock lock((GCriticalSection *) &class_lock);
00701 
00702    GUTF8String arg;
00703    for(int i=0;i<cgi_name_arr.size();i++)
00704    {
00705       if (cgi_name_arr[i].upcase()==djvuopts)
00706       {
00707          for(i++;i<cgi_name_arr.size();i++)
00708          {
00709             if (! num--)
00710             {
00711                arg=cgi_value_arr[i];
00712                break;
00713             }
00714          }
00715          break;
00716       }
00717    }
00718    return arg;
00719 }
00720 
00721 DArray<GUTF8String>
00722 GURL::cgi_names(void) const
00723 {
00724    if(!validurl) const_cast<GURL *>(this)->init();
00725    GCriticalSectionLock lock((GCriticalSection *) &class_lock);
00726    return cgi_name_arr;
00727 }
00728 
00729 DArray<GUTF8String>
00730 GURL::cgi_values(void) const
00731 {
00732    if(!validurl) const_cast<GURL *>(this)->init();
00733    GCriticalSectionLock lock((GCriticalSection *) &class_lock);
00734    return cgi_value_arr;
00735 }
00736 
00737 DArray<GUTF8String>
00738 GURL::djvu_cgi_names(void) const
00739 {
00740    if(!validurl) const_cast<GURL *>(this)->init();
00741    GCriticalSectionLock lock((GCriticalSection *) &class_lock);
00742 
00743    int i;
00744    DArray<GUTF8String> arr;
00745    for(i=0;(i<cgi_name_arr.size())&&
00746      (cgi_name_arr[i].upcase()!=djvuopts)
00747      ;i++)
00748         EMPTY_LOOP;
00749 
00750    int size=cgi_name_arr.size()-(i+1);
00751    if (size>0)
00752    {
00753       arr.resize(size-1);
00754       for(i=0;i<arr.size();i++)
00755          arr[i]=cgi_name_arr[cgi_name_arr.size()-arr.size()+i];
00756    }
00757 
00758    return arr;
00759 }
00760 
00761 DArray<GUTF8String>
00762 GURL::djvu_cgi_values(void) const
00763 {
00764    if(!validurl) const_cast<GURL *>(this)->init();
00765    GCriticalSectionLock lock((GCriticalSection *) &class_lock);
00766 
00767    int i;
00768    DArray<GUTF8String> arr;
00769    for(i=0;i<cgi_name_arr.size()&&(cgi_name_arr[i].upcase()!=djvuopts);i++)
00770         EMPTY_LOOP;
00771 
00772    int size=cgi_name_arr.size()-(i+1);
00773    if (size>0)
00774    {
00775       arr.resize(size-1);
00776       for(i=0;i<arr.size();i++)
00777          arr[i]=cgi_value_arr[cgi_value_arr.size()-arr.size()+i];
00778    }
00779 
00780    return arr;
00781 }
00782 
00783 void
00784 GURL::clear_all_arguments(void)
00785 {
00786    clear_hash_argument();
00787    clear_cgi_arguments();
00788 }
00789 
00790 void
00791 GURL::clear_hash_argument(void)
00792       // Clear anything after first '#' and before the following '?'
00793 {
00794    if(!validurl) init();
00795    GCriticalSectionLock lock(&class_lock);
00796    bool found=false;
00797    GUTF8String new_url;
00798    for(const char * start=url;*start;start++)
00799    {
00800          // Break on first CGI arg.
00801       if (*start=='?')
00802       {
00803          new_url+=start;
00804          break;
00805       }
00806 
00807       if (!found)
00808       { 
00809         if (*start=='#')
00810           found=true;
00811         else
00812           new_url+=*start;
00813       }
00814    }
00815    url=new_url;
00816 }
00817 
00818 void
00819 GURL::clear_cgi_arguments(void)
00820 {
00821    if(!validurl)
00822      init();
00823    GCriticalSectionLock lock1(&class_lock);
00824 
00825       // Clear the arrays
00826    cgi_name_arr.empty();
00827    cgi_value_arr.empty();
00828 
00829       // And clear everything past the '?' sign in the URL
00830    for(const char * ptr=url;*ptr;ptr++)
00831       if (*ptr=='?')
00832       {
00833          url.setat(ptr-url, 0);
00834          break;
00835       }
00836 }
00837 
00838 void
00839 GURL::clear_djvu_cgi_arguments(void)
00840 {
00841    if(!validurl) init();
00842       // First - modify the arrays
00843    GCriticalSectionLock lock(&class_lock);
00844    for(int i=0;i<cgi_name_arr.size();i++)
00845    {
00846       if (cgi_name_arr[i].upcase()==djvuopts)
00847       {
00848          cgi_name_arr.resize(i-1);
00849          cgi_value_arr.resize(i-1);
00850          break;
00851       }
00852    }
00853 
00854       // And store them back into the URL
00855    store_cgi_args();
00856 }
00857 
00858 void
00859 GURL::add_djvu_cgi_argument(const GUTF8String &name, const char * value)
00860 {
00861    if(!validurl)
00862      init();
00863    GCriticalSectionLock lock1(&class_lock);
00864 
00865       // Check if we already have the "DJVUOPTS" argument
00866    bool have_djvuopts=false;
00867    for(int i=0;i<cgi_name_arr.size();i++)
00868    {
00869       if (cgi_name_arr[i].upcase()==djvuopts)
00870       {
00871          have_djvuopts=true;
00872          break;
00873       }
00874    }
00875 
00876       // If there is no DJVUOPTS, insert it
00877    if (!have_djvuopts)
00878    {
00879       int pos=cgi_name_arr.size();
00880       cgi_name_arr.resize(pos);
00881       cgi_value_arr.resize(pos);
00882       cgi_name_arr[pos]=djvuopts;
00883    }
00884 
00885       // Add new argument to the array
00886    int pos=cgi_name_arr.size();
00887    cgi_name_arr.resize(pos);
00888    cgi_value_arr.resize(pos);
00889    cgi_name_arr[pos]=name;
00890    cgi_value_arr[pos]=value;
00891 
00892       // And update the URL
00893    store_cgi_args();
00894 }
00895 
00896 bool
00897 GURL::is_local_file_url(void) const
00898 {
00899    if(!validurl) const_cast<GURL *>(this)->init();
00900    GCriticalSectionLock lock((GCriticalSection *) &class_lock);
00901    return (protocol()=="file" && url[5]==slash);
00902 }
00903 
00904 static const int
00905 pathname_start(const GUTF8String &url, const int protolength)
00906 {
00907   const int length=url.length();
00908   int retval=0;
00909   if(protolength+1<length)
00910   {
00911     retval=url.search(slash,((url[protolength+1] == '/')
00912       ?((url[protolength+2] == '/')?(protolength+3):(protolength+2))
00913       :(protolength+1)));
00914   }
00915   return (retval>0)?retval:length;
00916 }
00917 
00918 GUTF8String
00919 GURL::pathname(void) const
00920 {
00921   return (is_local_file_url())
00922     ?GURL::encode_reserved(UTF8Filename()) 
00923     :url.substr(pathname_start(url,protocol().length()),(unsigned int)(-1));
00924 }
00925 
00926 GURL
00927 GURL::base(void) const
00928 {
00929    const GUTF8String xurl(get_string());
00930    const int protocol_length=protocol(xurl).length();
00931    const int xurl_length=xurl.length();
00932    const char * const url_ptr=xurl;
00933    const char * ptr, * xslash;
00934    ptr=xslash=url_ptr+protocol_length+1;
00935    if(xslash[0] == '/')
00936    {
00937      xslash++;
00938      if(xslash[0] == '/')
00939        xslash++;
00940      for(ptr=xslash;ptr[0] && !is_argument(ptr);ptr++)
00941      {
00942        if ((ptr[0]==slash)&&ptr[1]&&!is_argument(ptr+1))
00943         xslash=ptr;
00944      }
00945      if(xslash[0] != '/')
00946      {
00947        xslash=url_ptr+xurl_length;
00948      }
00949    }
00950    return GURL::UTF8(
00951 // ifdef WIN32
00952 // (*(xslash-1) == colon)?
00953 //   (GUTF8String(xurl,(int)(xslash-url_ptr))+"/" ):
00954 // endif
00955      (GUTF8String(xurl,(int)(xslash-url_ptr))+"/"));
00956 }
00957 
00958 bool
00959 GURL::operator==(const GURL & gurl2) const
00960 {
00961   bool retval=false;
00962   const GUTF8String g1(get_string());
00963   const int g1_length=g1.length();
00964   const GUTF8String g2(gurl2.get_string());
00965   const int g2_length=g2.length();
00966   if(g1_length == g2_length) // exactly equal
00967   {
00968     retval=(g1==g2);
00969   }else if(g1_length+1 == g2_length) // g1 is g2 with a slash at the end
00970   {
00971     retval=(g2[g1_length] == '/')&&!g1.cmp(g2,g1_length);
00972   }else if(g2_length+1 == g1_length)  // g2 is g1 with a slash at the end
00973   {
00974     retval=(g1[g2_length] == '/')&&!g1.cmp(g2,g2_length);
00975   }
00976   return retval;
00977 }
00978 
00979 GUTF8String
00980 GURL::name(void) const
00981 {
00982    if(!validurl)
00983      const_cast<GURL *>(this)->init();
00984    GUTF8String retval;
00985    if(!is_empty())
00986    {
00987      const GUTF8String xurl(url);
00988      const int protocol_length=protocol(xurl).length();
00989      const char * ptr, * xslash=(const char *)xurl+protocol_length-1;
00990      for(ptr=(const char *)xurl+protocol_length;
00991        *ptr && !is_argument(ptr);ptr++)
00992      {
00993        if (*ptr==slash)
00994           xslash=ptr;
00995      }
00996      retval=GUTF8String(xslash+1, ptr-xslash-1);
00997    }
00998    return retval;
00999 }
01000 
01001 GUTF8String
01002 GURL::fname(void) const
01003 {
01004    if(!validurl)
01005      const_cast<GURL *>(this)->init();
01006    return decode_reserved(name());
01007 }
01008 
01009 GUTF8String
01010 GURL::extension(void) const
01011 {
01012    if(!validurl)
01013      const_cast<GURL *>(this)->init();
01014    GUTF8String xfilename=name();
01015    GUTF8String retval;
01016 
01017    for(int i=xfilename.length()-1;i>=0;i--)
01018    {
01019       if (xfilename[i]=='.')
01020       {
01021          retval=(const char*)xfilename+i+1;
01022          break;
01023       }
01024    } 
01025    return retval;
01026 }
01027 
01028 GUTF8String
01029 GURL::decode_reserved(const GUTF8String &gurl)
01030 {
01031   const char *url=gurl;
01032   char *res;
01033   GPBuffer<char> gres(res,gurl.length()+1);
01034   char *r=res;
01035   for(const char * ptr=url;*ptr;++ptr,++r)
01036   {
01037     if (*ptr!=percent)
01038     {
01039       r[0]=*ptr;
01040     }else
01041     {
01042       int c1,c2;
01043       if ( ((c1=hexval(ptr[1]))>=0)
01044         && ((c2=hexval(ptr[2]))>=0) )
01045       {
01046         r[0]=(c1<<4)|c2;
01047         ptr+=2;
01048       } else
01049       {
01050         r[0]=*ptr;
01051       }
01052     }
01053   }
01054   r[0]=0;
01055   GUTF8String retval(res);
01056   if(!retval.is_valid())
01057   {
01058     retval=GNativeString(res);
01059   }
01060   return retval;
01061 }
01062 
01063 GUTF8String
01064 GURL::encode_reserved(const GUTF8String &gs)
01065 {
01066   const char *s=(const char *)gs;
01067   // Potentially unsafe characters (cf. RFC1738 and RFC1808)
01068   static const char hex[] = "0123456789ABCDEF";
01069   
01070   unsigned char *retval;
01071   GPBuffer<unsigned char> gd(retval,strlen(s)*3+1);
01072   unsigned char *d=retval;
01073   for (; *s; s++,d++)
01074   {
01075     // Convert directory separator to slashes
01076 #if defined(WIN32) || defined(OS2)
01077     if (*s == backslash || *s== slash)
01078 #else
01079 #ifdef macintosh
01080     if (*s == colon )
01081 #else
01082 #ifdef UNIX
01083     if (*s == slash )
01084 #else
01085 #error "Define something here for your operating system"
01086 #endif  
01087 #endif
01088 #endif
01089     {
01090       *d = slash; 
01091       continue;
01092     }
01093     unsigned char const ss=(unsigned char const)(*s);
01094     // WARNING: Whenever you modify this conversion code,
01095     // make sure, that the following functions are in sync:
01096     //   encode_reserved()
01097     //   decode_reserved()
01098     //   url_to_filename()
01099     //   filename_to_url()
01100     // unreserved characters
01101     if ( (ss>='a' && ss<='z') ||
01102          (ss>='A' && ss<='Z') ||
01103          (ss>='0' && ss<='9') ||
01104          (strchr("$-_.+!*'(),:~=", ss)) ) 
01105     {
01106       *d = ss;
01107       continue;
01108     }
01109     // escape sequence
01110     d[0] = percent;
01111     d[1] = hex[ (ss >> 4) & 0xf ];
01112     d[2] = hex[ (ss) & 0xf ];
01113     d+=2;
01114   }
01115   *d = 0;
01116   return retval;
01117 }
01118 
01119 // -------------------------------------------
01120 // Functions for converting filenames and urls
01121 // -------------------------------------------
01122 
01123 static GUTF8String
01124 url_from_UTF8filename(const GUTF8String &gfilename)
01125 {
01126   if(GURL::UTF8(gfilename).is_valid())
01127   {
01128     DEBUG_MSG("Debug: URL as Filename: " << gfilename << "\n");
01129   } 
01130   const char *filename=gfilename;
01131   if(filename && (unsigned char)filename[0] == (unsigned char)0xEF
01132      && (unsigned char)filename[1] == (unsigned char)0xBB 
01133      && (unsigned char)filename[2] == (unsigned char)0xBF)
01134   {
01135     filename+=3;
01136   }
01137 
01138   // Special case for blank pages
01139   if(!filename || !filename[0])
01140   {
01141     return GUTF8String();
01142   } 
01143 
01144   // Normalize file name to url slash-and-escape syntax
01145   GUTF8String oname=GURL::expand_name(filename);
01146   GUTF8String nname=GURL::encode_reserved(oname);
01147 
01148   // Preprend "file://" to file name. If file is on the local
01149   // machine, include "localhost".
01150   GUTF8String url=filespecslashes;
01151   const char *cnname=nname;
01152   if (cnname[0] == slash)
01153   {
01154     if (cnname[1] == slash)
01155     {
01156       url += cnname+2;
01157     }else
01158     {
01159       url = localhost + nname;
01160     }
01161   }else
01162   {
01163     url += (localhostspec1+2) + nname;
01164   }
01165   return url;
01166 }
01167 
01168 GUTF8String 
01169 GURL::get_string(const bool nothrow) const
01170 {
01171   if(!validurl)
01172     const_cast<GURL *>(this)->init(nothrow);
01173   return url;
01174 }
01175 
01176 // -- Returns a url for accessing a given file.
01177 //    If useragent is not provided, standard url will be created,
01178 //    but will not be understood by some versions if IE.
01179 GUTF8String 
01180 GURL::get_string(const GUTF8String &useragent) const
01181 {
01182   if(!validurl)
01183     const_cast<GURL *>(this)->init();
01184   GUTF8String retval(url);
01185   if(is_local_file_url()&&useragent.length())
01186   {
01187     if(useragent.search("MSIE") >= 0 || useragent.search("Microsoft")>=0)
01188     {
01189       retval=filespecslashes + expand_name(UTF8Filename());
01190     }
01191   }
01192   return retval;
01193 }
01194 
01195 GURL::UTF8::UTF8(const GUTF8String &xurl)
01196 : GURL(xurl) {}
01197 
01198 GURL::UTF8::UTF8(const GUTF8String &xurl,const GURL &codebase)
01199 : GURL(xurl,codebase) {}
01200 
01201 GURL::GURL(const GUTF8String &xurl,const GURL &codebase)
01202   : validurl(false)
01203 {
01204   if(GURL::UTF8(xurl).is_valid())
01205   {
01206     url=xurl;
01207   }else
01208   {
01209     const char *c=xurl;
01210     if(c[0] == slash)
01211     {
01212       GURL base(codebase);
01213       for(GURL newbase=base.base();newbase!=base;newbase=base.base())
01214       {
01215         base=newbase;
01216       }
01217       url=base.get_string(true)+GURL::encode_reserved(xurl);
01218     }else
01219     {
01220       url=beautify_path(codebase.get_string(true)+GUTF8String(slash)+GURL::encode_reserved(xurl));
01221     }
01222   }
01223 }
01224 
01225 GURL::Native::Native(const GNativeString &xurl)
01226 : GURL(xurl) {}
01227 
01228 GURL::Native::Native(const GNativeString &xurl,const GURL &codebase)
01229 : GURL(xurl,codebase) {}
01230 
01231 GURL::GURL(const GNativeString &xurl,const GURL &codebase)
01232   : validurl(false)
01233 {
01234   GURL retval(xurl.getNative2UTF8(),codebase);
01235   if(retval.is_valid())
01236   {
01237 #if defined(WIN32)
01238     // Hack for IE to change \\ to /
01239     if(retval.is_local_file_url())
01240     {
01241       GURL::Filename::UTF8 retval2(retval.UTF8Filename());
01242       url=retval2.get_string(true);
01243       validurl=false;
01244     }else
01245 #endif // WIN32
01246     {
01247       url=retval.get_string(true);
01248       validurl=false;
01249     }
01250   }
01251 }
01252 
01253 GURL::Filename::Filename(const GNativeString &gfilename)
01254 {
01255   url=url_from_UTF8filename(gfilename.getNative2UTF8());
01256 }
01257 
01258 GURL::Filename::Native::Native(const GNativeString &gfilename)
01259 : GURL::Filename(gfilename) {}
01260 
01261 GURL::Filename::Filename(const GUTF8String &gfilename)
01262 {
01263   url=url_from_UTF8filename(gfilename);
01264 }
01265 
01266 GURL::Filename::UTF8::UTF8(const GUTF8String &gfilename)
01267 : GURL::Filename(gfilename) {}
01268 
01269 // filename --
01270 // -- Applies heuristic rules to convert a url into a valid file name.  
01271 //    Returns a simple basename in case of failure.
01272 GUTF8String 
01273 GURL::UTF8Filename(void) const
01274 {
01275   GUTF8String retval;
01276   if(! is_empty())
01277   {
01278     const char *url_ptr=url;
01279   
01280     // WARNING: Whenever you modify this conversion code,
01281     // make sure, that the following functions are in sync:
01282     //   encode_reserved()
01283     //   decode_reserved()
01284     //   url_to_filename()
01285     //   filename_to_url()
01286 
01287     GUTF8String urlcopy=decode_reserved(url);
01288     url_ptr = urlcopy;
01289 
01290     // All file urls are expected to start with filespec which is "file:"
01291     if (GStringRep::cmp(filespec, url_ptr, sizeof(filespec)-1))  //if not
01292       return GOS::basename(url_ptr);
01293     url_ptr += sizeof(filespec)-1;
01294   
01295 #if defined(macintosh)
01296     //remove all leading slashes
01297     for(;*url_ptr==slash;url_ptr++)
01298       EMPTY_LOOP;
01299     // Remove possible localhost spec
01300     if ( !GStringRep::cmp(localhost, url_ptr, sizeof(localhost)-1) )
01301       url_ptr += sizeof(localhost)-1;
01302     //remove all leading slashes
01303     while(*url_ptr==slash)
01304       url_ptr++;
01305 #else
01306     // Remove possible localhost spec
01307     if ( !GStringRep::cmp(localhostspec1, url_ptr, sizeof(localhostspec1)-1) )
01308       // RFC 1738 local host form
01309       url_ptr += sizeof(localhostspec1)-1;
01310     else if ( !GStringRep::cmp(localhostspec2, url_ptr, sizeof(localhostspec2)-1 ) )
01311       // RFC 1738 local host form
01312       url_ptr += sizeof(localhostspec2)-1;
01313     else if ( (strlen(url_ptr) > 4)   // "file://<letter>:/<path>"
01314         && (url_ptr[0] == slash)      // "file://<letter>|/<path>"
01315         && (url_ptr[1] == slash)
01316         && isalpha(url_ptr[2])
01317         && ( url_ptr[3] == colon || url_ptr[3] == '|' )
01318         && (url_ptr[4] == slash) )
01319       url_ptr += 2;
01320     else if ( (strlen(url_ptr)) > 2 // "file:/<path>"
01321         && (url_ptr[0] == slash)
01322         && (url_ptr[1] != slash) )
01323       url_ptr++;
01324 #endif
01325 
01326     // Check if we are finished
01327 #if defined(macintosh)
01328     {
01329       char *l_url;
01330       GPBuffer<char> gl_url(l_url,strlen(url_ptr)+1);
01331       const char *s;
01332       char *r;
01333       for ( s=url_ptr,r=l_url; *s; s++,r++)
01334       {
01335         *r=(*s == slash)?colon:*s;
01336       }
01337       *r=0;
01338       retval = expand_name(l_url,root);
01339     }
01340 #else  
01341     retval = expand_name(url_ptr,root);
01342 #endif
01343     
01344 #if defined(WIN32) || defined(OS2)
01345     if (url_ptr[0] && url_ptr[1]=='|' && url_ptr[2]== slash)
01346     {
01347       if ((url_ptr[0]>='a' && url_ptr[0]<='z') 
01348           || (url_ptr[0]>='A' && url_ptr[0]<='Z'))
01349       {
01350     GUTF8String drive;
01351     drive.format("%c%c%c", url_ptr[0],colon,backslash);
01352     retval = expand_name(url_ptr+3, drive);
01353       }
01354     }
01355 #endif
01356   }
01357   // Return what we have
01358   return retval;
01359 }
01360 
01361 GNativeString 
01362 GURL::NativeFilename(void) const
01363 {
01364   return UTF8Filename().getUTF82Native();
01365 }
01366 
01367 #if defined(UNIX) || defined(macintosh) || defined(OS2)
01368 static int
01369 urlstat(const GURL &url,struct stat &buf)
01370 {
01371   return ::stat(url.NativeFilename(),&buf);
01372 }
01373 #endif
01374 
01375 // is_file(url) --
01376 // -- returns true if filename denotes a regular file.
01377 bool
01378 GURL::is_file(void) const
01379 {
01380   bool retval=false;
01381   if(is_local_file_url())
01382   {
01383 #if defined(UNIX) || defined(macintosh) || defined(OS2)
01384     struct stat buf;
01385     if (!urlstat(*this,buf))
01386     {
01387       retval=!(buf.st_mode & S_IFDIR);
01388     }
01389 #elif defined(WIN32)
01390     GUTF8String filename(UTF8Filename());
01391     if(filename.length() >= MAX_PATH)
01392       {
01393         if(!filename.cmp("\\\\",2))
01394           filename="\\\\?\\UNC"+filename.substr(1,-1);
01395         else
01396           filename="\\\\?\\"+filename;
01397       }
01398     wchar_t *wfilename;
01399     const size_t wfilename_size=filename.length()+1;
01400     GPBuffer<wchar_t> gwfilename(wfilename,wfilename_size);
01401     filename.ncopy(wfilename,wfilename_size);
01402     DWORD dwAttrib;
01403     dwAttrib = GetFileAttributesW(wfilename);
01404     if((dwAttrib|1) == 0xFFFFFFFF)
01405       {
01406         USES_CONVERSION ;
01407         dwAttrib = GetFileAttributes(A2CT(NativeFilename())) ;//MBCS cvt
01408       }
01409     retval=!( dwAttrib & FILE_ATTRIBUTE_DIRECTORY );
01410 #else
01411 # error "Define something here for your operating system"
01412 #endif
01413   }
01414   return retval;
01415 }
01416 
01417 bool
01418 GURL::is_local_path(void) const
01419 {
01420   bool retval=false;
01421   if(is_local_file_url())
01422   {
01423 #if defined(UNIX) || defined(macintosh) || defined(OS2)
01424     struct stat buf;
01425     retval=!urlstat(*this,buf);
01426 #else
01427     GUTF8String filename(UTF8Filename());
01428     if(filename.length() >= MAX_PATH)
01429       {
01430         if(!filename.cmp("\\\\",2))
01431           filename="\\\\?\\UNC"+filename.substr(1,-1);
01432         else
01433           filename="\\\\?\\"+filename;
01434       }
01435     wchar_t *wfilename;
01436     const size_t wfilename_size=filename.length()+1;
01437     GPBuffer<wchar_t> gwfilename(wfilename,wfilename_size);
01438     filename.ncopy(wfilename,wfilename_size);
01439     DWORD dwAttrib;
01440     dwAttrib = GetFileAttributesW(wfilename);
01441     if((dwAttrib|1) == 0xFFFFFFFF)
01442       {
01443         USES_CONVERSION ;
01444         dwAttrib = GetFileAttributes(A2CT(NativeFilename())) ;//MBCS cvt
01445       }
01446     retval=( (dwAttrib|1) != 0xFFFFFFFF);
01447 #endif
01448   }
01449   return retval;
01450 }
01451 
01452 // is_dir(url) --
01453 // -- returns true if url denotes a directory.
01454 bool 
01455 GURL::is_dir(void) const
01456 {
01457   bool retval=false;
01458   if(is_local_file_url())
01459   {
01460     // UNIX implementation
01461 #if defined(UNIX) || defined(macintosh) || defined(OS2)
01462     struct stat buf;
01463     if (!urlstat(*this,buf))
01464     {
01465       retval=(buf.st_mode & S_IFDIR);
01466     }
01467 #elif defined(WIN32)   // (either Windows or WCE)
01468     GUTF8String filename(UTF8Filename());
01469     if(filename.length() >= MAX_PATH)
01470       {
01471         if(!filename.cmp("\\\\",2))
01472           filename="\\\\?\\UNC"+filename.substr(1,-1);
01473         else
01474           filename="\\\\?\\"+filename;
01475       }
01476     wchar_t *wfilename;
01477     const size_t wfilename_size=filename.length()+1;
01478     GPBuffer<wchar_t> gwfilename(wfilename,wfilename_size);
01479     filename.ncopy(wfilename,wfilename_size);
01480     DWORD dwAttrib;
01481     dwAttrib = GetFileAttributesW(wfilename);
01482     if((dwAttrib|1) == 0xFFFFFFFF)
01483       {
01484         USES_CONVERSION ;
01485         dwAttrib = GetFileAttributes(A2CT(NativeFilename())) ;//MBCS cvt
01486       }
01487     retval=((dwAttrib != 0xFFFFFFFF)&&( dwAttrib & FILE_ATTRIBUTE_DIRECTORY ));
01488 #else
01489 # error "Define something here for your operating system"
01490 #endif
01491   }
01492   return retval;
01493 }
01494 
01495 // Follows symbolic links.
01496 GURL 
01497 GURL::follow_symlinks(void) const
01498 {
01499   GURL ret = *this;
01500 #if defined(S_IFLNK)
01501 #if defined(UNIX) || defined(macintosh)
01502   int lnklen;
01503   char lnkbuf[MAXPATHLEN+1];
01504   struct stat buf;
01505   while ( (urlstat(ret, buf) >= 0) &&
01506           (buf.st_mode & S_IFLNK) &&
01507           ((lnklen = readlink(ret.NativeFilename(),lnkbuf,sizeof(lnkbuf))) > 0) )
01508     {
01509       lnkbuf[lnklen] = 0;
01510       GNativeString lnk(lnkbuf);
01511       ret = GURL(lnk, ret.base());
01512     }
01513 #endif
01514 #endif
01515   return ret;
01516 }
01517 
01518 int
01519 GURL::mkdir() const
01520 {
01521   if(! is_local_file_url())
01522     return -1;
01523   int retval=0;
01524   const GURL baseURL=base();
01525   if (baseURL.get_string() != url && !baseURL.is_dir())
01526     retval = baseURL.mkdir();
01527   if(!retval)
01528     {
01529 #if defined(UNIX)
01530       if (is_dir())
01531         retval = 0;
01532       else 
01533         retval = ::mkdir(NativeFilename(), 0755);
01534 #elif defined(WIN32)
01535       USES_CONVERSION;
01536       if (is_dir())
01537         retval = 0;
01538       else 
01539         retval = CreateDirectory(A2CT(NativeFilename()), NULL);
01540 #else
01541 # error "Define something here for your operating system"
01542 #endif
01543     }
01544   return retval;
01545 }
01546 
01547 // deletefile
01548 // -- deletes a file or directory
01549   
01550 int
01551 GURL::deletefile(void) const
01552 {
01553   int retval = -1;
01554   if(is_local_file_url())
01555     {
01556 #if defined(UNIX)
01557       if (is_dir())
01558         retval = ::rmdir(NativeFilename());
01559       else
01560         retval = ::unlink(NativeFilename());
01561 #elif defined(WIN32)
01562       USES_CONVERSION;
01563       if (is_dir())
01564         retval = ::RemoveDirectory(A2CT(NativeFilename()));
01565       else
01566         retval = ::DeleteFile(A2CT(NativeFilename()));
01567 #else
01568 # error "Define something here for your operating system"
01569 #endif
01570   }
01571   return retval;
01572 }
01573 
01574 GList<GURL>
01575 GURL::listdir(void) const
01576 {
01577   GList<GURL> retval;
01578   if(is_dir())
01579   {
01580 #if defined(UNIX) || defined(OS2)
01581     DIR * dir=opendir(NativeFilename());//MBCS cvt
01582     for(dirent *de=readdir(dir);de;de=readdir(dir))
01583     {
01584       const int len = NAMLEN(de);
01585       if (de->d_name[0]== dot  && len==1)
01586         continue;
01587       if (de->d_name[0]== dot  && de->d_name[1]== dot  && len==2)
01588         continue;
01589       retval.append(GURL::Native(de->d_name,*this));
01590     }
01591     closedir(dir);
01592 #elif defined (WIN32)
01593     GURL::UTF8 wildcard("*.*",*this);
01594     WIN32_FIND_DATA finddata;
01595     HANDLE handle = FindFirstFile(wildcard.NativeFilename(), &finddata);//MBCS cvt
01596     const GUTF8String gpathname=pathname();
01597     const GUTF8String gbase=base().pathname();
01598     if( handle != INVALID_HANDLE_VALUE)
01599     {
01600       do
01601       {
01602         GURL::UTF8 Entry(finddata.cFileName,*this);
01603         const GUTF8String gentry=Entry.pathname();
01604         if((gentry != gpathname) && (gentry != gbase))
01605           retval.append(Entry);
01606       } while( FindNextFile(handle, &finddata) );
01607 
01608       FindClose(handle);
01609     }
01610 #else
01611 # error "Define something here for your operating system"
01612 #endif
01613   }
01614   return retval;
01615 }
01616 
01617 int
01618 GURL::cleardir(const int timeout) const
01619 {
01620   int retval=(-1);
01621   if(is_dir())
01622   {
01623     GList<GURL> dirlist=listdir();
01624     retval=0;
01625     for(GPosition pos=dirlist;pos&&!retval;++pos)
01626     {
01627       const GURL &Entry=dirlist[pos];
01628       if(Entry.is_dir())
01629       {
01630         if((retval=Entry.cleardir(timeout)) < 0)
01631         {
01632           break;
01633         }
01634       }
01635       if(((retval=Entry.deletefile())<0) && (timeout>0))
01636       {
01637         GOS::sleep(timeout);
01638         retval=Entry.deletefile();
01639       }
01640     }
01641   }
01642   return retval;
01643 }
01644 
01645 int
01646 GURL::renameto(const GURL &newurl) const
01647 {
01648   if (is_local_file_url() && newurl.is_local_file_url())
01649     return rename(NativeFilename(),newurl.NativeFilename());
01650   return -1;
01651 }
01652 
01653 // expand_name(filename[, fromdirname])
01654 // -- returns the full path name of filename interpreted
01655 //    relative to fromdirname.  Use current working dir when
01656 //    fromdirname is null.
01657 GUTF8String 
01658 GURL::expand_name(const GUTF8String &xfname, const char *from)
01659 {
01660   const char *fname=xfname;
01661   GUTF8String retval;
01662   const size_t maxlen=xfname.length()*9+MAXPATHLEN+10;
01663   char * const string_buffer = retval.getbuf(maxlen);
01664   // UNIX implementation
01665 #if defined(UNIX)
01666   // Perform tilde expansion
01667   GUTF8String senv;
01668   if (fname && fname[0]==tilde)
01669   {
01670     int n;
01671     for(n=1;fname[n] && fname[n]!= slash;n++) 
01672       EMPTY_LOOP;
01673     struct passwd *pw=0;
01674     if (n!=1)
01675     {
01676       GUTF8String user(fname+1, n-1);
01677       pw=getpwnam(user);
01678     }else if ((senv=GOS::getenv("HOME")).length())
01679     {
01680       from=(const char *)senv;
01681       fname = fname + n;
01682     }else if ((senv=GOS::getenv("LOGNAME")).length())
01683     {
01684       pw = getpwnam((const char *)senv.getUTF82Native());
01685     }else
01686     {
01687       pw=getpwuid(getuid());
01688     }
01689     if (pw)
01690     {
01691       senv=GNativeString(pw->pw_dir).getNative2UTF8();
01692       from = (const char *)senv;
01693       fname = fname + n;
01694     }
01695     for(;fname[0] == slash; fname++)
01696       EMPTY_LOOP;
01697   }
01698   // Process absolute vs. relative path
01699   if (fname && fname[0]== slash)
01700   {
01701     string_buffer[0]=slash;
01702     string_buffer[1]=0;
01703   }else if (from)
01704   {
01705     strcpy(string_buffer, expand_name(from));
01706   }else
01707   {
01708     strcpy(string_buffer, GOS::cwd());
01709   }
01710   char *s = string_buffer + strlen(string_buffer);
01711   if(fname)
01712   {
01713     for(;fname[0]== slash;fname++)
01714       EMPTY_LOOP;
01715     // Process path components
01716     while(fname[0])
01717     {
01718       if (fname[0] == dot )
01719       {
01720         if (!fname[1] || fname[1]== slash)
01721         {
01722           fname++;
01723           continue;
01724         }else if (fname[1]== dot && (fname[2]== slash || !fname[2]))
01725         {
01726           fname +=2;
01727           for(;s>string_buffer+1 && *(s-1)== slash; s--)
01728             EMPTY_LOOP;
01729           for(;s>string_buffer+1 && *(s-1)!= slash; s--)
01730             EMPTY_LOOP;
01731           continue;
01732         }
01733       }
01734       if ((s==string_buffer)||(*(s-1)!= slash))
01735       {
01736         *s = slash;
01737         s++;
01738       }
01739       while (*fname &&(*fname!= slash))
01740       {
01741         *s = *fname++;
01742         if ((size_t)((++s)-string_buffer) > maxlen)
01743         {
01744           G_THROW( ERR_MSG("GURL.big_name") );
01745         }
01746       }
01747       *s = 0;
01748       for(;fname[0]== slash;fname++)
01749         EMPTY_LOOP;
01750     }
01751   }
01752   if (!fname || !fname[0])
01753   {
01754     for(;s>string_buffer+1 && *(s-1) == slash; s--)
01755       EMPTY_LOOP;
01756     *s = 0;
01757   }
01758 #elif defined (WIN32) // WIN32 implementation
01759   // Handle base
01760   strcpy(string_buffer, (char const *)(from ? expand_name(from) : GOS::cwd()));
01761   //  GNativeString native;
01762   if (fname)
01763   {
01764     char *s = string_buffer;
01765     char  drv[4];
01766     // Handle absolute part of fname
01767     //      Put absolute part of the file name in string_buffer, and
01768     //      the relative part pointed to by fname.
01769     if (fname[0]== slash || fname[0]== backslash)
01770     {
01771       if (fname[1]== slash || fname[1]== backslash)
01772       {       // Case "//abcd"
01773         s[0]=s[1]= backslash; s[2]=0;
01774       }
01775       else
01776       {       // Case "/abcd" or "/"
01777               //    File is at the root of the current drive. Delete the
01778               //    slash at the beginning of the filename and leave
01779               //    an explicit identification of the root of the drive in
01780               //    string_buffer.
01781         fname++;
01782         s[3] = '\0';
01783       }
01784     }
01785     else if (fname[0] && fname[1]==colon)
01786     {
01787       if (fname[2]!= slash && fname[2]!= backslash)
01788       {       // Case "x:abcd"
01789         if ( toupper((unsigned char)s[0]) != toupper((unsigned char)fname[0])
01790           || s[1]!=colon)
01791         {
01792           drv[0]=fname[0];
01793           drv[1]=colon;
01794           drv[2]= dot ;
01795           drv[3]=0;
01796           GetFullPathName(drv, maxlen, string_buffer, &s);
01797           strcpy(string_buffer,(const char *)GUTF8String(string_buffer).getNative2UTF8());
01798           s = string_buffer;
01799         }
01800         fname += 2;
01801       }
01802       else if (fname[3]!= slash && fname[3]!= backslash)
01803       {       // Case "x:/abcd"
01804         s[0]=toupper((unsigned char)fname[0]);
01805         s[1]=colon;
01806         s[2]=backslash;
01807         s[3]=0;
01808         fname += 3;
01809       }
01810       else
01811       {       // Case "x://abcd"
01812         s[0]=s[1]=backslash;
01813         s[2]=0;
01814         fname += 4;
01815       }
01816     }
01817     // Process path components
01818     for(;*fname== slash || *fname==backslash;fname++)
01819       EMPTY_LOOP;
01820     while(*fname)
01821     {
01822       if (fname[0]== dot )
01823       {
01824         if (fname[1]== slash || fname[1]==backslash || !fname[1])
01825         {
01826           fname++;
01827           continue;
01828         }else if ((fname[1] == dot)
01829           && (fname[2]== slash || fname[2]==backslash || !fname[2]))
01830         {
01831           fname += 2;
01832           char *back=_tcsrchr(string_buffer,backslash);
01833           char *forward=_tcsrchr(string_buffer,slash);
01834           if(back>forward)
01835           {
01836             *back=0;
01837           }else if(forward)
01838           {
01839             *forward=0;
01840           }
01841           s = string_buffer;
01842           continue;
01843         }
01844         char* s2=s;//MBCS DBCS
01845         for(;*s;s++) 
01846           EMPTY_LOOP;
01847         char* back = _tcsrchr(s2,backslash);//MBCS DBCS
01848         if ((s>string_buffer)&&(*(s-1)!= slash)&&
01849             (back == NULL || (back!=NULL && s-1 != back) ))//MBCS DBCS
01850         {
01851           *s = backslash;
01852           s++;
01853         }
01854         while (*fname && *fname!= slash && *fname!=backslash)
01855         {
01856           *s = *fname++;
01857           if ((size_t)((++s)-string_buffer) > maxlen)
01858             G_THROW( ERR_MSG("GURL.big_name") );
01859         }
01860         *s = 0;
01861       }
01862       char* s2=s;//MBCS DBCS
01863       for(;*s;s++) 
01864         EMPTY_LOOP;
01865       char* back = _tcsrchr(s2,backslash);//MBCS DBCS
01866       if ((s>string_buffer)&&(*(s-1)!= slash)
01867           &&(back == NULL || (back!=NULL && s-1 != back) ))//MBCS DBCS
01868       {
01869         *s = backslash;
01870         s++;
01871       }
01872       while (*fname && (*fname!= slash) && (*fname!=backslash))
01873       {
01874         *s = *fname++;
01875         if ((size_t)((++s)-string_buffer) > maxlen)
01876           G_THROW( ERR_MSG("GURL.big_name") );
01877       }
01878       *s = 0;
01879       for(;(*fname== slash)||(*fname==backslash);fname++)
01880         EMPTY_LOOP;
01881     }
01882   }
01883 #elif defined(macintosh) // MACINTOSH implementation
01884   strcpy(string_buffer, (const char *)(from?from:GOS::cwd()));
01885   
01886   if (!GStringRep::cmp(fname, string_buffer,strlen(string_buffer)) || is_file(fname))
01887   {
01888     strcpy(string_buffer, "");//please don't expand, the logic of filename is chaos.
01889   }
01890   
01891   // Process path components
01892   char *s = string_buffer + strlen(string_buffer);
01893   if(fname)
01894   {
01895     for(;fname[0]==colon;fname++)
01896       EMPTY_LOOP;
01897     while(fname[0])
01898     {
01899       if (fname[0]== dot )
01900       {
01901         if (fname[1]==colon || !fname[1])
01902         {
01903           fname++;
01904           continue;
01905         }
01906         if ((fname[1]== dot )
01907           &&(fname[2]==colon || fname[2]==0))
01908         {
01909           fname +=2;
01910           for(;(s>string_buffer+1)&&(*(s-1)==colon);s--)
01911             EMPTY_LOOP;
01912           for(;(s>string_buffer+1)&&(*(s-1)!=colon);s--)
01913             EMPTY_LOOP;
01914           continue;
01915         }
01916       }
01917       if ((s==string_buffer)||(*(s-1)!=colon))
01918       {
01919         *s = colon;
01920         s++;
01921       }
01922       while (*fname!=0 && *fname!=colon)
01923       {
01924         *s = *fname++;
01925         if ((++s)-string_buffer > maxlen)
01926           G_THROW( ERR_MSG("GURL.big_name") );
01927       }
01928       *s = 0;
01929       for(;fname[0]==colon;fname++)
01930         EMPTY_LOOP;
01931     }
01932   }
01933   for(;(s>string_buffer+1) && (*(s-1)==colon);s--)
01934     EMPTY_LOOP;
01935   *s = 0;
01936   return ((string_buffer[0]==colon)?(string_buffer+1):string_buffer);
01937 #else
01938 # error "Define something here for your operating system"
01939 #endif  
01940   return retval;
01941 }
01942 
01943 unsigned int
01944 hash(const GURL & gurl)
01945 {
01946   unsigned int retval;
01947   const GUTF8String s(gurl.get_string());
01948   const int len=s.length();
01949   if(len && (s[len-1] == '/')) // Don't include the trailing slash as part of the hash.
01950   {
01951     retval=hash(s.substr(0,len-1));
01952   }else
01953   {
01954     retval=hash(s);
01955   }
01956   return retval;
01957 }
01958 
01959 
01960 #ifdef HAVE_NAMESPACES
01961 }
01962 # ifndef NOT_USING_DJVU_NAMESPACE
01963 using namespace DJVU;
01964 # endif
01965 #endif

kviewshell

Skip menu "kviewshell"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members

API Reference

Skip menu "API Reference"
  • kviewshell
Generated for API Reference by doxygen 1.5.9
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal