source: trunk/libdjvu/GURL.cpp @ 17

Last change on this file since 17 was 17, checked in by Eugene Romanenko, 15 years ago

update makefiles, remove absolute paths, update djvulibre to version 3.5.17

File size: 48.6 KB
RevLine 
[17]1//C-  -*- C++ -*-
2//C- -------------------------------------------------------------------
3//C- DjVuLibre-3.5
4//C- Copyright (c) 2002  Leon Bottou and Yann Le Cun.
5//C- Copyright (c) 2001  AT&T
6//C-
7//C- This software is subject to, and may be distributed under, the
8//C- GNU General Public License, Version 2. The license should have
9//C- accompanied the software or you may obtain a copy of the license
10//C- from the Free Software Foundation at http://www.fsf.org .
11//C-
12//C- This program is distributed in the hope that it will be useful,
13//C- but WITHOUT ANY WARRANTY; without even the implied warranty of
14//C- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15//C- GNU General Public License for more details.
16//C-
17//C- DjVuLibre-3.5 is derived from the DjVu(r) Reference Library
18//C- distributed by Lizardtech Software.  On July 19th 2002, Lizardtech
19//C- Software authorized us to replace the original DjVu(r) Reference
20//C- Library notice by the following text (see doc/lizard2002.djvu):
21//C-
22//C-  ------------------------------------------------------------------
23//C- | DjVu (r) Reference Library (v. 3.5)
24//C- | Copyright (c) 1999-2001 LizardTech, Inc. All Rights Reserved.
25//C- | The DjVu Reference Library is protected by U.S. Pat. No.
26//C- | 6,058,214 and patents pending.
27//C- |
28//C- | This software is subject to, and may be distributed under, the
29//C- | GNU General Public License, Version 2. The license should have
30//C- | accompanied the software or you may obtain a copy of the license
31//C- | from the Free Software Foundation at http://www.fsf.org .
32//C- |
33//C- | The computer code originally released by LizardTech under this
34//C- | license and unmodified by other parties is deemed "the LIZARDTECH
35//C- | ORIGINAL CODE."  Subject to any third party intellectual property
36//C- | claims, LizardTech grants recipient a worldwide, royalty-free,
37//C- | non-exclusive license to make, use, sell, or otherwise dispose of
38//C- | the LIZARDTECH ORIGINAL CODE or of programs derived from the
39//C- | LIZARDTECH ORIGINAL CODE in compliance with the terms of the GNU
40//C- | General Public License.   This grant only confers the right to
41//C- | infringe patent claims underlying the LIZARDTECH ORIGINAL CODE to
42//C- | the extent such infringement is reasonably necessary to enable
43//C- | recipient to make, have made, practice, sell, or otherwise dispose
44//C- | of the LIZARDTECH ORIGINAL CODE (or portions thereof) and not to
45//C- | any greater extent that may be necessary to utilize further
46//C- | modifications or combinations.
47//C- |
48//C- | The LIZARDTECH ORIGINAL CODE is provided "AS IS" WITHOUT WARRANTY
49//C- | OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
50//C- | TO ANY WARRANTY OF NON-INFRINGEMENT, OR ANY IMPLIED WARRANTY OF
51//C- | MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
52//C- +------------------------------------------------------------------
53//
54// $Id: GURL.cpp,v 1.21 2005/12/24 12:45:01 leonb Exp $
55// $Name:  $
56
57#ifdef HAVE_CONFIG_H
58# include "config.h"
59#endif
60#if NEED_GNUG_PRAGMAS
61# pragma implementation
62#endif
63
64// From: Leon Bottou, 1/31/2002
65// This has been heavily changed by Lizardtech.
66// They decided to use URLs for everyting, including
67// the most basic file access.  The URL class now is a unholy
68// mixture of code for syntactically parsing the urls (which it was)
69// and file status code (only for local file: urls).
70
71#include "GException.h"
72#include "GOS.h"
73#include "GURL.h"
74#include "debug.h"
75
76#include <stdlib.h>
77#include <stdio.h>
78#include <ctype.h>
79#include <math.h>
80#include <string.h>
81
82#ifdef WIN32
83# include <atlbase.h>
84# include <windows.h>
85# include <direct.h>
86#endif /* WIN32 */
87
88// -- MAXPATHLEN
89#ifndef MAXPATHLEN
90# ifdef _MAX_PATH
91#  define MAXPATHLEN _MAX_PATH
92# else
93#  define MAXPATHLEN 1024
94# endif
95#else
96# if ( MAXPATHLEN < 1024 )
97#  undef MAXPATHLEN
98#  define MAXPATHLEN 1024
99# endif
100#endif
101
102#if defined(UNIX) || defined(OS2)
103# include <unistd.h>
104# include <sys/types.h>
105# include <sys/stat.h>
106# include <errno.h>
107# include <fcntl.h>
108# include <pwd.h>
109# include <stdio.h>
110# ifdef AUTOCONF
111#  ifdef TIME_WITH_SYS_TIME
112#   include <sys/time.h>
113#   include <time.h>
114#  else
115#   ifdef HAVE_SYS_TIME_H
116#    include <sys/time.h>
117#   else
118#    include <time.h>
119#   endif
120#  endif
121#  ifdef HAVE_DIRENT_H
122#   include <dirent.h>
123#   define NAMLEN(dirent) strlen((dirent)->d_name)
124#  else
125#   define dirent direct
126#   define NAMLEN(dirent) (dirent)->d_namlen
127#   ifdef HAVE_SYS_NDIR_H
128#    include <sys/ndir.h>
129#   endif
130#   ifdef HAVE_SYS_DIR_H
131#    include <sys/dir.h>
132#   endif
133#   ifdef HAVE_NDIR_H
134#    include <ndir.h>
135#   endif
136#  endif
137# else /* !AUTOCONF */ 
138#  include <sys/time.h>
139#  if defined(XENIX)
140#   define USE_DIRECT
141#   include <sys/ndir.h>
142#  elif defined(OLDBSD)
143#   define USE_DIRECT
144#   include <sys/dir.h>
145#  endif
146#  ifdef USE_DIRECT
147#   define dirent direct
148#   define NAMLEN(dirent) (dirent)->d_namlen
149#  else
150#   include <dirent.h>
151#   define NAMLEN(dirent) strlen((dirent)->d_name)
152#  endif
153# endif /* !AUTOCONF */
154#endif /* UNIX */
155
156#ifdef macintosh
157#include <unix.h>
158#include <errno.h>
159#include <unistd.h>
160#endif
161
162
163#ifdef HAVE_NAMESPACES
164namespace DJVU {
165# ifdef NOT_DEFINED // Just to fool emacs c++ mode
166}
167#endif
168#endif
169
170
171static const char djvuopts[]="DJVUOPTS";
172static const char localhost[]="file://localhost/";
173static const char backslash='\\'; 
174static const char colon=':';
175static const char dot='.';
176static const char filespecslashes[] = "file://";
177static const char filespec[] = "file:";
178static const char slash='/';
179static const char percent='%';
180static const char localhostspec1[] = "//localhost/";
181static const char localhostspec2[] = "///";
182static const char nillchar=0;
183#if defined(UNIX)
184  static const char tilde='~';
185  static const char root[] = "/";
186#elif defined(WIN32) || defined(OS2)
187  static const char root[] = "\\";
188#elif defined(macintosh)
189  static char const * const root = &nillchar; 
190#else
191#error "Define something here for your operating system"
192#endif
193
194
195static const int
196pathname_start(const GUTF8String &url, const int protolength);
197
198// hexval --
199// -- Returns the hexvalue of a character.
200//    Returns -1 if illegal;
201
202static int 
203hexval(char c)
204{
205  return ((c>='0' && c<='9')
206    ?(c-'0')
207    :((c>='A' && c<='F')
208      ?(c-'A'+10)
209      :((c>='a' && c<='f')
210        ?(c-'a'+10):(-1))));
211}
212
213
214static bool
215is_argument(const char * start)
216      // Returns TRUE if 'start' points to the beginning of an argument
217      // (either hash or CGI)
218{
219   // return (*start=='#' || *start=='?' || *start=='&' || *start==';');
220   return (*start=='#' || *start=='?' );
221}
222
223static bool
224is_argument_sep(const char * start)
225      // Returns TRUE if 'start' points to the beginning of an argument
226      // (either hash or CGI)
227{
228   return (*start=='&')||(*start == ';');
229}
230
231void
232GURL::convert_slashes(void)
233{
234   GUTF8String xurl(get_string());
235#if defined(WIN32)
236   const int protocol_length=protocol(xurl).length();
237   for(char *ptr=(xurl.getbuf()+protocol_length);*ptr;ptr++)
238     if(*ptr == backslash)
239       *ptr=slash;
240   url=xurl;
241#endif
242}
243
244static void
245collapse(char * ptr, const int chars)
246      // Will remove the first 'chars' chars from the string and
247      // move the rest toward the beginning. Will take into account
248      // string length
249{
250   const int length=strlen(ptr);
251   const char *srcptr=ptr+((chars>length)?length:chars);
252   while((*(ptr++) = *(srcptr++)))
253     EMPTY_LOOP;
254}
255
256GUTF8String
257GURL::beautify_path(GUTF8String xurl)
258{
259
260  const int protocol_length=GURL::protocol(xurl).length();
261   
262  // Eats parts like ./ or ../ or ///
263  char * buffer;
264  GPBuffer<char> gbuffer(buffer,xurl.length()+1);
265  strcpy(buffer, (const char *)xurl);
266   
267  // Find start point
268  char * start=buffer+pathname_start(xurl,protocol_length);
269
270  // Find end of the url (don't touch arguments)
271  char * ptr;
272  GUTF8String args;
273  for(ptr=start;*ptr;ptr++)
274  {
275    if (is_argument(ptr))
276    {
277      args=ptr;
278      *ptr=0;
279      break;
280    }
281  }
282
283  // Eat multiple slashes
284  for(;(ptr=strstr(start, "////"));collapse(ptr, 3))
285    EMPTY_LOOP;
286  for(;(ptr=strstr(start, "//"));collapse(ptr, 1))
287    EMPTY_LOOP;
288  // Convert /./ stuff into plain /
289  for(;(ptr=strstr(start, "/./"));collapse(ptr, 2))
290    EMPTY_LOOP;
291#if defined(WIN32) || defined(OS2)
292  if(!xurl.cmp(filespec,sizeof(filespec)-1))
293  {
294        int offset=1;
295        if(start&&(start[0] == '/')&& 
296           !xurl.cmp("file:////",sizeof("file:////")-1))
297        {
298          collapse(start, 1);
299          offset=0;
300        }
301    for(ptr=start+offset;(ptr=strchr(ptr, '/'));)
302        {
303          if(isalpha((++ptr)[0]))
304          {
305            if((ptr[1] == ':')&&(ptr[2]=='/'))
306                {
307                  char *buffer2;
308                  GPBuffer<char> gbuffer2(buffer2,strlen(ptr)+1);
309                  strcpy(buffer2,ptr);
310                  gbuffer.resize(strlen(ptr)+sizeof(localhost));
311                  strcpy(buffer,localhost);
312                  strcat(buffer,buffer2);
313                  ptr=(start=buffer+sizeof(localhost))+1;
314                }
315          }
316        }
317  }
318#endif
319  // Process /../
320  while((ptr=strstr(start, "/../")))
321  {
322    for(char * ptr1=ptr-1;(ptr1>=start);ptr1--)
323    {
324      if (*ptr1==slash)
325      {
326        collapse(ptr1, ptr-ptr1+3);
327        break;
328      }
329    }
330  }
331
332  // Remove trailing /.
333  ptr=start+strlen(start)-2;
334  if((ptr>=start)&& (ptr == GUTF8String("/.")))
335  {
336    ptr[1]=0;
337  }
338  // Eat trailing /..
339  ptr=start+strlen(start)-3;
340  if((ptr >= start) && (ptr == GUTF8String("/..")))
341  {
342    for(char * ptr1=ptr-1;(ptr1>=start);ptr1--)
343    {
344      if (*ptr1==slash)
345      {
346        ptr1[1]=0;
347        break;
348      }
349    }
350  }
351
352  // Done. Copy the buffer back into the URL and add arguments.
353  xurl=buffer;
354  return (xurl+args);
355}
356
357
358void
359GURL::beautify_path(void)
360{
361  url=beautify_path(get_string());
362}
363
364void
365GURL::init(const bool nothrow)
366{
367   GCriticalSectionLock lock(&class_lock);
368   validurl=true;
369   
370   if (url.length())
371   {
372      GUTF8String proto=protocol();
373      if (proto.length()<2)
374      {
375        validurl=false;
376        if(!nothrow)
377          G_THROW( ERR_MSG("GURL.no_protocol") "\t"+url);
378        return;
379      }
380
381         // Below we have to make this complex test to detect URLs really
382         // referring to *local* files. Surprisingly, file://hostname/dir/file
383         // is also valid, but shouldn't be treated thru local FS.
384      if (proto=="file" && url[5]==slash &&
385          (url[6]!=slash || !url.cmp(localhost, sizeof(localhost))))
386      {
387            // Separate the arguments
388         GUTF8String arg;
389         {
390           const char * const url_ptr=url;
391           const char * ptr;
392           for(ptr=url_ptr;*ptr&&!is_argument(ptr);ptr++)
393                        EMPTY_LOOP;
394           arg=ptr;
395           url=url.substr(0,(size_t)(ptr-url_ptr));
396         }
397
398            // Do double conversion
399         GUTF8String tmp=UTF8Filename();
400         if (!tmp.length())
401         {
402           validurl=false;
403           if(!nothrow)
404             G_THROW( ERR_MSG("GURL.fail_to_file") );
405           return;
406         }
407         url=GURL::Filename::UTF8(tmp).get_string();
408         if (!url.length())
409         {
410           validurl=false;
411           if(!nothrow)
412             G_THROW( ERR_MSG("GURL.fail_to_URL") );
413           return;
414         }
415            // Return the argument back
416         url+=arg;
417      }
418      convert_slashes();
419      beautify_path();
420      parse_cgi_args();
421   }
422}
423
424GURL::GURL(void) 
425  : validurl(false) 
426{
427}
428
429GURL::GURL(const char * url_in) 
430  : url(url_in ? url_in : ""), validurl(false)
431{
432}
433
434GURL::GURL(const GUTF8String & url_in)
435  : url(url_in), validurl(false)
436{
437}
438
439GURL::GURL(const GNativeString & url_in)
440  : url(url_in.getNative2UTF8()), validurl(false)
441{
442#if defined(WIN32) || defined(OS2)
443  if(is_valid() && is_local_file_url())
444  {
445    GURL::Filename::UTF8 xurl(UTF8Filename());
446    url=xurl.get_string(true);
447    validurl=false;
448  }
449#endif
450}
451
452GURL::GURL(const GURL & url_in)
453  : validurl(false)
454{
455  if(url_in.is_valid())
456  {
457    url=url_in.get_string();
458    init();
459  }else
460  {
461    url=url_in.url;
462  }
463}
464
465GURL &
466GURL::operator=(const GURL & url_in)
467{
468   GCriticalSectionLock lock(&class_lock);
469   if(url_in.is_valid())
470   {
471     url=url_in.get_string();
472     init(true);
473   }else
474   {
475     url=url_in.url;
476     validurl=false;
477   }
478   return *this;
479}
480
481GUTF8String
482GURL::protocol(const GUTF8String& url)
483{
484   const char * const url_ptr=url;
485   const char * ptr=url_ptr;
486   for(char c=*ptr;
487     c && (isalnum(c) || c == '+' || c == '-' || c == '.');
488     c=*(++ptr)) EMPTY_LOOP;
489   return(*ptr==colon)?GUTF8String(url_ptr, ptr-url_ptr):GUTF8String();
490}
491
492GUTF8String
493GURL::hash_argument(void) const
494      // Returns the HASH argument (anything after '#' and before '?')
495{
496   const GUTF8String xurl(get_string());
497
498   bool found=false;
499   GUTF8String arg;
500
501         // Break if CGI argument is found
502   for(const char * start=xurl;*start&&(*start!='?');start++)
503   {
504      if (found)
505      {
506         arg+=*start;
507      }else
508      {
509         found=(*start=='#');
510      }
511   }
512   return decode_reserved(arg);
513}
514
515void
516GURL::set_hash_argument(const GUTF8String &arg)
517{
518   const GUTF8String xurl(get_string());
519
520   GUTF8String new_url;
521   bool found=false;
522   const char * ptr;
523   for(ptr=xurl;*ptr;ptr++)
524   {
525      if (is_argument(ptr))
526      {
527         if (*ptr!='#')
528         {
529           break;
530         }
531         found=true;
532      } else if (!found)
533      {
534         new_url+=*ptr;
535      }
536   }
537
538   url=new_url+"#"+GURL::encode_reserved(arg)+ptr;
539}
540
541void
542GURL::parse_cgi_args(void)
543      // Will read CGI arguments from the URL into
544      // cgi_name_arr and cgi_value_arr
545{
546   if(!validurl)
547     init();
548   GCriticalSectionLock lock1(&class_lock);
549   cgi_name_arr.empty();
550   cgi_value_arr.empty();
551
552      // Search for the beginning of CGI arguments
553   const char * start=url;
554   while(*start)
555   {
556     if(*(start++)=='?')
557     {
558       break;
559     }
560   }
561
562      // Now loop until we see all of them
563   while(*start)
564   {
565      GUTF8String arg;        // Storage for another argument
566      while(*start)        // Seek for the end of it
567      {
568         if (is_argument_sep(start))
569         {
570            start++;
571            break;
572         } else
573         {
574           arg+=*start++;
575         }
576      }
577      if (arg.length())
578      {
579            // Got argument in 'arg'. Split it into 'name' and 'value'
580         const char * ptr;
581         const char * const arg_ptr=arg;
582         for(ptr=arg_ptr;*ptr&&(*ptr != '=');ptr++)
583           EMPTY_LOOP;
584
585         GUTF8String name, value;
586         if (*ptr)
587         {
588            name=GUTF8String(arg_ptr, (int)((ptr++)-arg_ptr));
589            value=GUTF8String(ptr, arg.length()-name.length()-1);
590         } else
591         {
592           name=arg;
593         }
594           
595         int args=cgi_name_arr.size();
596         cgi_name_arr.resize(args);
597         cgi_value_arr.resize(args);
598         cgi_name_arr[args]=decode_reserved(name);
599         cgi_value_arr[args]=decode_reserved(value);
600      }
601   }
602}
603
604void
605GURL::store_cgi_args(void)
606      // Will store CGI arguments from the cgi_name_arr and cgi_value_arr
607      // back into the URL
608{
609   if(!validurl)
610     init();
611   GCriticalSectionLock lock1(&class_lock);
612
613   const char * const url_ptr=url;
614   const char * ptr;
615   for(ptr=url_ptr;*ptr&&(*ptr!='?');ptr++)
616                EMPTY_LOOP;
617   
618   GUTF8String new_url(url_ptr, ptr-url_ptr);
619   
620   for(int i=0;i<cgi_name_arr.size();i++)
621   {
622      GUTF8String name=GURL::encode_reserved(cgi_name_arr[i]);
623      GUTF8String value=GURL::encode_reserved(cgi_value_arr[i]);
624      new_url+=(i?"&":"?")+name;
625      if (value.length())
626         new_url+="="+value;
627   }
628
629   url=new_url;
630}
631
632int
633GURL::cgi_arguments(void) const
634{
635   if(!validurl)
636      const_cast<GURL *>(this)->init();
637   return cgi_name_arr.size();
638}
639
640int
641GURL::djvu_cgi_arguments(void) const
642{
643   if(!validurl)
644     const_cast<GURL *>(this)->init();
645   GCriticalSectionLock lock((GCriticalSection *) &class_lock);
646
647   int args=0;
648   for(int i=0;i<cgi_name_arr.size();i++)
649   {
650      if (cgi_name_arr[i].upcase()==djvuopts)
651      {
652         args=cgi_name_arr.size()-(i+1);
653         break;
654      }
655   } 
656   return args;
657}
658
659GUTF8String
660GURL::cgi_name(int num) const
661{
662   if(!validurl) const_cast<GURL *>(this)->init();
663   GCriticalSectionLock lock((GCriticalSection *) &class_lock);
664   return (num<cgi_name_arr.size())?cgi_name_arr[num]:GUTF8String();
665}
666
667GUTF8String
668GURL::djvu_cgi_name(int num) const
669{
670   if(!validurl) const_cast<GURL *>(this)->init();
671   GCriticalSectionLock lock((GCriticalSection *) &class_lock);
672
673   GUTF8String arg;
674   for(int i=0;i<cgi_name_arr.size();i++)
675      if (cgi_name_arr[i].upcase()==djvuopts)
676      {
677         for(i++;i<cgi_name_arr.size();i++)
678            if (! num--)
679            {
680               arg=cgi_name_arr[i];
681               break;
682            }
683         break;
684      }
685   return arg;
686}
687
688GUTF8String
689GURL::cgi_value(int num) const
690{
691   if(!validurl) const_cast<GURL *>(this)->init();
692   GCriticalSectionLock lock((GCriticalSection *) &class_lock);
693   return (num<cgi_value_arr.size())?cgi_value_arr[num]:GUTF8String();
694}
695
696GUTF8String
697GURL::djvu_cgi_value(int num) const
698{
699   if(!validurl) const_cast<GURL *>(this)->init();
700   GCriticalSectionLock lock((GCriticalSection *) &class_lock);
701
702   GUTF8String arg;
703   for(int i=0;i<cgi_name_arr.size();i++)
704   {
705      if (cgi_name_arr[i].upcase()==djvuopts)
706      {
707         for(i++;i<cgi_name_arr.size();i++)
708         {
709            if (! num--)
710            {
711               arg=cgi_value_arr[i];
712               break;
713            }
714         }
715         break;
716      }
717   }
718   return arg;
719}
720
721DArray<GUTF8String>
722GURL::cgi_names(void) const
723{
724   if(!validurl) const_cast<GURL *>(this)->init();
725   GCriticalSectionLock lock((GCriticalSection *) &class_lock);
726   return cgi_name_arr;
727}
728
729DArray<GUTF8String>
730GURL::cgi_values(void) const
731{
732   if(!validurl) const_cast<GURL *>(this)->init();
733   GCriticalSectionLock lock((GCriticalSection *) &class_lock);
734   return cgi_value_arr;
735}
736
737DArray<GUTF8String>
738GURL::djvu_cgi_names(void) const
739{
740   if(!validurl) const_cast<GURL *>(this)->init();
741   GCriticalSectionLock lock((GCriticalSection *) &class_lock);
742
743   int i;
744   DArray<GUTF8String> arr;
745   for(i=0;(i<cgi_name_arr.size())&&
746     (cgi_name_arr[i].upcase()!=djvuopts)
747     ;i++)
748        EMPTY_LOOP;
749
750   int size=cgi_name_arr.size()-(i+1);
751   if (size>0)
752   {
753      arr.resize(size-1);
754      for(i=0;i<arr.size();i++)
755         arr[i]=cgi_name_arr[cgi_name_arr.size()-arr.size()+i];
756   }
757
758   return arr;
759}
760
761DArray<GUTF8String>
762GURL::djvu_cgi_values(void) const
763{
764   if(!validurl) const_cast<GURL *>(this)->init();
765   GCriticalSectionLock lock((GCriticalSection *) &class_lock);
766
767   int i;
768   DArray<GUTF8String> arr;
769   for(i=0;i<cgi_name_arr.size()&&(cgi_name_arr[i].upcase()!=djvuopts);i++)
770                EMPTY_LOOP;
771
772   int size=cgi_name_arr.size()-(i+1);
773   if (size>0)
774   {
775      arr.resize(size-1);
776      for(i=0;i<arr.size();i++)
777         arr[i]=cgi_value_arr[cgi_value_arr.size()-arr.size()+i];
778   }
779
780   return arr;
781}
782
783void
784GURL::clear_all_arguments(void)
785{
786   clear_hash_argument();
787   clear_cgi_arguments();
788}
789
790void
791GURL::clear_hash_argument(void)
792      // Clear anything after first '#' and before the following '?'
793{
794   if(!validurl) init();
795   GCriticalSectionLock lock(&class_lock);
796   bool found=false;
797   GUTF8String new_url;
798   for(const char * start=url;*start;start++)
799   {
800         // Break on first CGI arg.
801      if (*start=='?')
802      {
803         new_url+=start;
804         break;
805      }
806
807      if (!found)
808      { 
809        if (*start=='#')
810          found=true;
811        else
812          new_url+=*start;
813      }
814   }
815   url=new_url;
816}
817
818void
819GURL::clear_cgi_arguments(void)
820{
821   if(!validurl)
822     init();
823   GCriticalSectionLock lock1(&class_lock);
824
825      // Clear the arrays
826   cgi_name_arr.empty();
827   cgi_value_arr.empty();
828
829      // And clear everything past the '?' sign in the URL
830   const char * ptrurl = url;
831   for(const char *ptr = ptrurl; *ptr; ptr++)
832      if (*ptr=='?')
833      {
834         url.setat(ptr-ptrurl, 0);
835         break;
836      }
837}
838
839void
840GURL::clear_djvu_cgi_arguments(void)
841{
842   if(!validurl) init();
843      // First - modify the arrays
844   GCriticalSectionLock lock(&class_lock);
845   for(int i=0;i<cgi_name_arr.size();i++)
846   {
847      if (cgi_name_arr[i].upcase()==djvuopts)
848      {
849         cgi_name_arr.resize(i-1);
850         cgi_value_arr.resize(i-1);
851         break;
852      }
853   }
854
855      // And store them back into the URL
856   store_cgi_args();
857}
858
859void
860GURL::add_djvu_cgi_argument(const GUTF8String &name, const char * value)
861{
862   if(!validurl)
863     init();
864   GCriticalSectionLock lock1(&class_lock);
865
866      // Check if we already have the "DJVUOPTS" argument
867   bool have_djvuopts=false;
868   for(int i=0;i<cgi_name_arr.size();i++)
869   {
870      if (cgi_name_arr[i].upcase()==djvuopts)
871      {
872         have_djvuopts=true;
873         break;
874      }
875   }
876
877      // If there is no DJVUOPTS, insert it
878   if (!have_djvuopts)
879   {
880      int pos=cgi_name_arr.size();
881      cgi_name_arr.resize(pos);
882      cgi_value_arr.resize(pos);
883      cgi_name_arr[pos]=djvuopts;
884   }
885
886      // Add new argument to the array
887   int pos=cgi_name_arr.size();
888   cgi_name_arr.resize(pos);
889   cgi_value_arr.resize(pos);
890   cgi_name_arr[pos]=name;
891   cgi_value_arr[pos]=value;
892
893      // And update the URL
894   store_cgi_args();
895}
896
897bool
898GURL::is_local_file_url(void) const
899{
900   if(!validurl) const_cast<GURL *>(this)->init();
901   GCriticalSectionLock lock((GCriticalSection *) &class_lock);
902   return (protocol()=="file" && url[5]==slash);
903}
904
905static const int
906pathname_start(const GUTF8String &url, const int protolength)
907{
908  const int length=url.length();
909  int retval=0;
910  if(protolength+1<length)
911  {
912    retval=url.search(slash,((url[protolength+1] == '/')
913      ?((url[protolength+2] == '/')?(protolength+3):(protolength+2))
914      :(protolength+1)));
915  }
916  return (retval>0)?retval:length;
917}
918
919GUTF8String
920GURL::pathname(void) const
921{
922  return (is_local_file_url())
923    ?GURL::encode_reserved(UTF8Filename()) 
924    :url.substr(pathname_start(url,protocol().length()),(unsigned int)(-1));
925}
926
927GURL
928GURL::base(void) const
929{
930   const GUTF8String xurl(get_string());
931   const int protocol_length=protocol(xurl).length();
932   const int xurl_length=xurl.length();
933   const char * const url_ptr=xurl;
934   const char * ptr, * xslash;
935   ptr=xslash=url_ptr+protocol_length+1;
936   if(xslash[0] == '/')
937   {
938     xslash++;
939     if(xslash[0] == '/')
940       xslash++;
941     for(ptr=xslash;ptr[0] && !is_argument(ptr);ptr++)
942     {
943       if ((ptr[0]==slash)&&ptr[1]&&!is_argument(ptr+1))
944        xslash=ptr;
945     }
946     if(xslash[0] != '/')
947     {
948       xslash=url_ptr+xurl_length;
949     }
950   }
951   return GURL::UTF8(
952// ifdef WIN32
953// (*(xslash-1) == colon)?
954//   (GUTF8String(xurl,(int)(xslash-url_ptr))+"/" ):
955// endif
956     (GUTF8String(xurl,(int)(xslash-url_ptr))+"/"));
957}
958
959bool
960GURL::operator==(const GURL & gurl2) const
961{
962  bool retval=false;
963  const GUTF8String g1(get_string());
964  const int g1_length=g1.length();
965  const GUTF8String g2(gurl2.get_string());
966  const int g2_length=g2.length();
967  if(g1_length == g2_length) // exactly equal
968  {
969        retval=(g1==g2);
970  }else if(g1_length+1 == g2_length) // g1 is g2 with a slash at the end
971  {
972    retval=(g2[g1_length] == '/')&&!g1.cmp(g2,g1_length);
973  }else if(g2_length+1 == g1_length)  // g2 is g1 with a slash at the end
974  {
975    retval=(g1[g2_length] == '/')&&!g1.cmp(g2,g2_length);
976  }
977  return retval;
978}
979
980GUTF8String
981GURL::name(void) const
982{
983   if(!validurl)
984     const_cast<GURL *>(this)->init();
985   GUTF8String retval;
986   if(!is_empty())
987   {
988     const GUTF8String xurl(url);
989     const int protocol_length=protocol(xurl).length();
990     const char * ptr, * xslash=(const char *)xurl+protocol_length-1;
991     for(ptr=(const char *)xurl+protocol_length;
992       *ptr && !is_argument(ptr);ptr++)
993         {
994       if (*ptr==slash)
995          xslash=ptr;
996         }
997     retval=GUTF8String(xslash+1, ptr-xslash-1);
998   }
999   return retval;
1000}
1001
1002GUTF8String
1003GURL::fname(void) const
1004{
1005   if(!validurl)
1006     const_cast<GURL *>(this)->init();
1007   return decode_reserved(name());
1008}
1009
1010GUTF8String
1011GURL::extension(void) const
1012{
1013   if(!validurl)
1014     const_cast<GURL *>(this)->init();
1015   GUTF8String xfilename=name();
1016   GUTF8String retval;
1017
1018   for(int i=xfilename.length()-1;i>=0;i--)
1019   {
1020      if (xfilename[i]=='.')
1021      {
1022         retval=(const char*)xfilename+i+1;
1023         break;
1024      }
1025   } 
1026   return retval;
1027}
1028
1029GUTF8String
1030GURL::decode_reserved(const GUTF8String &gurl)
1031{
1032  const char *url=gurl;
1033  char *res;
1034  GPBuffer<char> gres(res,gurl.length()+1);
1035  char *r=res;
1036  for(const char * ptr=url;*ptr;++ptr,++r)
1037  {
1038    if (*ptr!=percent)
1039    {
1040      r[0]=*ptr;
1041    }else
1042    {
1043      int c1,c2;
1044      if ( ((c1=hexval(ptr[1]))>=0)
1045        && ((c2=hexval(ptr[2]))>=0) )
1046      {
1047        r[0]=(c1<<4)|c2;
1048        ptr+=2;
1049      } else
1050      {
1051        r[0]=*ptr;
1052      }
1053    }
1054  }
1055  r[0]=0;
1056  GUTF8String retval(res);
1057  if(!retval.is_valid())
1058  {
1059    retval=GNativeString(res);
1060  }
1061  return retval;
1062}
1063
1064GUTF8String
1065GURL::encode_reserved(const GUTF8String &gs)
1066{
1067  const char *s=(const char *)gs;
1068  // Potentially unsafe characters (cf. RFC1738 and RFC1808)
1069  static const char hex[] = "0123456789ABCDEF";
1070 
1071  unsigned char *retval;
1072  GPBuffer<unsigned char> gd(retval,strlen(s)*3+1);
1073  unsigned char *d=retval;
1074  for (; *s; s++,d++)
1075  {
1076    // Convert directory separator to slashes
1077#if defined(WIN32) || defined(OS2)
1078    if (*s == backslash || *s== slash)
1079#else
1080#ifdef macintosh
1081    if (*s == colon )
1082#else
1083#ifdef UNIX
1084    if (*s == slash )
1085#else
1086#error "Define something here for your operating system"
1087#endif 
1088#endif
1089#endif
1090    {
1091      *d = slash; 
1092      continue;
1093    }
1094    unsigned char const ss=(unsigned char const)(*s);
1095    // WARNING: Whenever you modify this conversion code,
1096    // make sure, that the following functions are in sync:
1097    //   encode_reserved()
1098    //   decode_reserved()
1099    //   url_to_filename()
1100    //   filename_to_url()
1101    // unreserved characters
1102    if ( (ss>='a' && ss<='z') ||
1103         (ss>='A' && ss<='Z') ||
1104         (ss>='0' && ss<='9') ||
1105         (strchr("$-_.+!*'(),:~=", ss)) ) 
1106    {
1107      *d = ss;
1108      continue;
1109    }
1110    // escape sequence
1111    d[0] = percent;
1112    d[1] = hex[ (ss >> 4) & 0xf ];
1113    d[2] = hex[ (ss) & 0xf ];
1114    d+=2;
1115  }
1116  *d = 0;
1117  return retval;
1118}
1119
1120// -------------------------------------------
1121// Functions for converting filenames and urls
1122// -------------------------------------------
1123
1124static GUTF8String
1125url_from_UTF8filename(const GUTF8String &gfilename)
1126{
1127  if(GURL::UTF8(gfilename).is_valid())
1128  {
1129    DEBUG_MSG("Debug: URL as Filename: " << gfilename << "\n");
1130  } 
1131  const char *filename=gfilename;
1132  if(filename && (unsigned char)filename[0] == (unsigned char)0xEF
1133     && (unsigned char)filename[1] == (unsigned char)0xBB 
1134     && (unsigned char)filename[2] == (unsigned char)0xBF)
1135  {
1136    filename+=3;
1137  }
1138
1139  // Special case for blank pages
1140  if(!filename || !filename[0])
1141  {
1142    return GUTF8String();
1143  } 
1144
1145  // Normalize file name to url slash-and-escape syntax
1146  GUTF8String oname=GURL::expand_name(filename);
1147  GUTF8String nname=GURL::encode_reserved(oname);
1148
1149  // Preprend "file://" to file name. If file is on the local
1150  // machine, include "localhost".
1151  GUTF8String url=filespecslashes;
1152  const char *cnname=nname;
1153  if (cnname[0] == slash)
1154  {
1155    if (cnname[1] == slash)
1156    {
1157      url += cnname+2;
1158    }else
1159    {
1160      url = localhost + nname;
1161    }
1162  }else
1163  {
1164    url += (localhostspec1+2) + nname;
1165  }
1166  return url;
1167}
1168
1169GUTF8String
1170GURL::get_string(const bool nothrow) const
1171{
1172  if(!validurl)
1173    const_cast<GURL *>(this)->init(nothrow);
1174  return url;
1175}
1176
1177// -- Returns a url for accessing a given file.
1178//    If useragent is not provided, standard url will be created,
1179//    but will not be understood by some versions if IE.
1180GUTF8String
1181GURL::get_string(const GUTF8String &useragent) const
1182{
1183  if(!validurl)
1184    const_cast<GURL *>(this)->init();
1185  GUTF8String retval(url);
1186  if(is_local_file_url()&&useragent.length())
1187  {
1188    if(useragent.search("MSIE") >= 0 || useragent.search("Microsoft")>=0)
1189    {
1190      retval=filespecslashes + expand_name(UTF8Filename());
1191    }
1192  }
1193  return retval;
1194}
1195
1196GURL::UTF8::UTF8(const GUTF8String &xurl)
1197: GURL(xurl) {}
1198
1199GURL::UTF8::UTF8(const GUTF8String &xurl,const GURL &codebase)
1200: GURL(xurl,codebase) {}
1201
1202GURL::GURL(const GUTF8String &xurl,const GURL &codebase)
1203  : validurl(false)
1204{
1205  if(GURL::UTF8(xurl).is_valid())
1206  {
1207    url=xurl;
1208  }else
1209  {
1210    const char *c=xurl;
1211    if(c[0] == slash)
1212    {
1213      GURL base(codebase);
1214      for(GURL newbase=base.base();newbase!=base;newbase=base.base())
1215      {
1216        base=newbase;
1217      }
1218      url=base.get_string(true)+GURL::encode_reserved(xurl);
1219    }else
1220    {
1221      url=beautify_path(codebase.get_string(true)+GUTF8String(slash)+GURL::encode_reserved(xurl));
1222    }
1223  }
1224}
1225
1226GURL::Native::Native(const GNativeString &xurl)
1227: GURL(xurl) {}
1228
1229GURL::Native::Native(const GNativeString &xurl,const GURL &codebase)
1230: GURL(xurl,codebase) {}
1231
1232GURL::GURL(const GNativeString &xurl,const GURL &codebase)
1233  : validurl(false)
1234{
1235  GURL retval(xurl.getNative2UTF8(),codebase);
1236  if(retval.is_valid())
1237  {
1238#if defined(WIN32)
1239    // Hack for IE to change \\ to /
1240    if(retval.is_local_file_url())
1241    {
1242      GURL::Filename::UTF8 retval2(retval.UTF8Filename());
1243      url=retval2.get_string(true);
1244      validurl=false;
1245    }else
1246#endif // WIN32
1247    {
1248      url=retval.get_string(true);
1249      validurl=false;
1250    }
1251  }
1252}
1253
1254GURL::Filename::Filename(const GNativeString &gfilename)
1255{
1256  url=url_from_UTF8filename(gfilename.getNative2UTF8());
1257}
1258
1259GURL::Filename::Native::Native(const GNativeString &gfilename)
1260: GURL::Filename(gfilename) {}
1261
1262GURL::Filename::Filename(const GUTF8String &gfilename)
1263{
1264  url=url_from_UTF8filename(gfilename);
1265}
1266
1267GURL::Filename::UTF8::UTF8(const GUTF8String &gfilename)
1268: GURL::Filename(gfilename) {}
1269
1270// filename --
1271// -- Applies heuristic rules to convert a url into a valid file name. 
1272//    Returns a simple basename in case of failure.
1273GUTF8String
1274GURL::UTF8Filename(void) const
1275{
1276  GUTF8String retval;
1277  if(! is_empty())
1278  {
1279    const char *url_ptr=url;
1280 
1281    // WARNING: Whenever you modify this conversion code,
1282    // make sure, that the following functions are in sync:
1283    //   encode_reserved()
1284    //   decode_reserved()
1285    //   url_to_filename()
1286    //   filename_to_url()
1287
1288    GUTF8String urlcopy=decode_reserved(url);
1289    url_ptr = urlcopy;
1290
1291    // All file urls are expected to start with filespec which is "file:"
1292    if (GStringRep::cmp(filespec, url_ptr, sizeof(filespec)-1))  //if not
1293      return GOS::basename(url_ptr);
1294    url_ptr += sizeof(filespec)-1;
1295 
1296#if defined(macintosh)
1297    //remove all leading slashes
1298    for(;*url_ptr==slash;url_ptr++)
1299      EMPTY_LOOP;
1300    // Remove possible localhost spec
1301    if ( !GStringRep::cmp(localhost, url_ptr, sizeof(localhost)-1) )
1302      url_ptr += sizeof(localhost)-1;
1303    //remove all leading slashes
1304    while(*url_ptr==slash)
1305      url_ptr++;
1306#else
1307    // Remove possible localhost spec
1308    if ( !GStringRep::cmp(localhostspec1, url_ptr, sizeof(localhostspec1)-1) )
1309      // RFC 1738 local host form
1310      url_ptr += sizeof(localhostspec1)-1;
1311    else if ( !GStringRep::cmp(localhostspec2, url_ptr, sizeof(localhostspec2)-1 ) )
1312      // RFC 1738 local host form
1313      url_ptr += sizeof(localhostspec2)-1;
1314    else if ( (strlen(url_ptr) > 4)   // "file://<letter>:/<path>"
1315        && (url_ptr[0] == slash)      // "file://<letter>|/<path>"
1316        && (url_ptr[1] == slash)
1317        && isalpha(url_ptr[2])
1318        && ( url_ptr[3] == colon || url_ptr[3] == '|' )
1319        && (url_ptr[4] == slash) )
1320      url_ptr += 2;
1321    else if ( (strlen(url_ptr)) > 2 // "file:/<path>"
1322        && (url_ptr[0] == slash)
1323        && (url_ptr[1] != slash) )
1324      url_ptr++;
1325#endif
1326
1327    // Check if we are finished
1328#if defined(macintosh)
1329    {
1330      char *l_url;
1331      GPBuffer<char> gl_url(l_url,strlen(url_ptr)+1);
1332      const char *s;
1333      char *r;
1334      for ( s=url_ptr,r=l_url; *s; s++,r++)
1335      {
1336        *r=(*s == slash)?colon:*s;
1337      }
1338      *r=0;
1339      retval = expand_name(l_url,root);
1340    }
1341#else 
1342    retval = expand_name(url_ptr,root);
1343#endif
1344   
1345#if defined(WIN32) || defined(OS2)
1346    if (url_ptr[0] && url_ptr[1]=='|' && url_ptr[2]== slash)
1347    {
1348      if ((url_ptr[0]>='a' && url_ptr[0]<='z') 
1349          || (url_ptr[0]>='A' && url_ptr[0]<='Z'))
1350      {
1351        GUTF8String drive;
1352        drive.format("%c%c%c", url_ptr[0],colon,backslash);
1353        retval = expand_name(url_ptr+3, drive);
1354      }
1355    }
1356#endif
1357  }
1358  // Return what we have
1359  return retval;
1360}
1361
1362GNativeString
1363GURL::NativeFilename(void) const
1364{
1365  return UTF8Filename().getUTF82Native();
1366}
1367
1368#if defined(UNIX) || defined(macintosh) || defined(OS2)
1369static int
1370urlstat(const GURL &url,struct stat &buf)
1371{
1372  return ::stat(url.NativeFilename(),&buf);
1373}
1374#endif
1375
1376// is_file(url) --
1377// -- returns true if filename denotes a regular file.
1378bool
1379GURL::is_file(void) const
1380{
1381  bool retval=false;
1382  if(is_local_file_url())
1383  {
1384#if defined(UNIX) || defined(macintosh) || defined(OS2)
1385    struct stat buf;
1386    if (!urlstat(*this,buf))
1387    {
1388      retval=!(buf.st_mode & S_IFDIR);
1389    }
1390#elif defined(WIN32)
1391    GUTF8String filename(UTF8Filename());
1392    if(filename.length() >= MAX_PATH)
1393      {
1394        if(!filename.cmp("\\\\",2))
1395          filename="\\\\?\\UNC"+filename.substr(1,-1);
1396        else
1397          filename="\\\\?\\"+filename;
1398      }
1399    wchar_t *wfilename;
1400    const size_t wfilename_size=filename.length()+1;
1401    GPBuffer<wchar_t> gwfilename(wfilename,wfilename_size);
1402    filename.ncopy(wfilename,wfilename_size);
1403    DWORD dwAttrib;
1404    dwAttrib = GetFileAttributesW(wfilename);
1405    if((dwAttrib|1) == 0xFFFFFFFF)
1406      {
1407        USES_CONVERSION ;
1408        dwAttrib = GetFileAttributes(A2CT(NativeFilename())) ;//MBCS cvt
1409      }
1410    retval=!( dwAttrib & FILE_ATTRIBUTE_DIRECTORY );
1411#else
1412# error "Define something here for your operating system"
1413#endif
1414  }
1415  return retval;
1416}
1417
1418bool
1419GURL::is_local_path(void) const
1420{
1421  bool retval=false;
1422  if(is_local_file_url())
1423  {
1424#if defined(UNIX) || defined(macintosh) || defined(OS2)
1425    struct stat buf;
1426    retval=!urlstat(*this,buf);
1427#else
1428    GUTF8String filename(UTF8Filename());
1429    if(filename.length() >= MAX_PATH)
1430      {
1431        if(!filename.cmp("\\\\",2))
1432          filename="\\\\?\\UNC"+filename.substr(1,-1);
1433        else
1434          filename="\\\\?\\"+filename;
1435      }
1436    wchar_t *wfilename;
1437    const size_t wfilename_size=filename.length()+1;
1438    GPBuffer<wchar_t> gwfilename(wfilename,wfilename_size);
1439    filename.ncopy(wfilename,wfilename_size);
1440    DWORD dwAttrib;
1441    dwAttrib = GetFileAttributesW(wfilename);
1442    if((dwAttrib|1) == 0xFFFFFFFF)
1443      {
1444        USES_CONVERSION ;
1445        dwAttrib = GetFileAttributes(A2CT(NativeFilename())) ;//MBCS cvt
1446      }
1447    retval=( (dwAttrib|1) != 0xFFFFFFFF);
1448#endif
1449  }
1450  return retval;
1451}
1452
1453// is_dir(url) --
1454// -- returns true if url denotes a directory.
1455bool 
1456GURL::is_dir(void) const
1457{
1458  bool retval=false;
1459  if(is_local_file_url())
1460  {
1461    // UNIX implementation
1462#if defined(UNIX) || defined(macintosh) || defined(OS2)
1463    struct stat buf;
1464    if (!urlstat(*this,buf))
1465    {
1466      retval=(buf.st_mode & S_IFDIR);
1467    }
1468#elif defined(WIN32)   // (either Windows or WCE)
1469    GUTF8String filename(UTF8Filename());
1470    if(filename.length() >= MAX_PATH)
1471      {
1472        if(!filename.cmp("\\\\",2))
1473          filename="\\\\?\\UNC"+filename.substr(1,-1);
1474        else
1475          filename="\\\\?\\"+filename;
1476      }
1477    wchar_t *wfilename;
1478    const size_t wfilename_size=filename.length()+1;
1479    GPBuffer<wchar_t> gwfilename(wfilename,wfilename_size);
1480    filename.ncopy(wfilename,wfilename_size);
1481    DWORD dwAttrib;
1482    dwAttrib = GetFileAttributesW(wfilename);
1483    if((dwAttrib|1) == 0xFFFFFFFF)
1484      {
1485        USES_CONVERSION ;
1486        dwAttrib = GetFileAttributes(A2CT(NativeFilename())) ;//MBCS cvt
1487      }
1488    retval=((dwAttrib != 0xFFFFFFFF)&&( dwAttrib & FILE_ATTRIBUTE_DIRECTORY ));
1489#else
1490# error "Define something here for your operating system"
1491#endif
1492  }
1493  return retval;
1494}
1495
1496// Follows symbolic links.
1497GURL
1498GURL::follow_symlinks(void) const
1499{
1500  GURL ret = *this;
1501#if defined(S_IFLNK)
1502#if defined(UNIX) || defined(macintosh)
1503  int lnklen;
1504  char lnkbuf[MAXPATHLEN+1];
1505  struct stat buf;
1506  while ( (urlstat(ret, buf) >= 0) &&
1507          (buf.st_mode & S_IFLNK) &&
1508          ((lnklen = readlink(ret.NativeFilename(),lnkbuf,sizeof(lnkbuf))) > 0) )
1509    {
1510      lnkbuf[lnklen] = 0;
1511      GNativeString lnk(lnkbuf);
1512      ret = GURL(lnk, ret.base());
1513    }
1514#endif
1515#endif
1516  return ret;
1517}
1518
1519int
1520GURL::mkdir() const
1521{
1522  if(! is_local_file_url())
1523    return -1;
1524  int retval=0;
1525  const GURL baseURL=base();
1526  if (baseURL.get_string() != url && !baseURL.is_dir())
1527    retval = baseURL.mkdir();
1528  if(!retval)
1529    {
1530#if defined(UNIX) || defined(OS2)
1531      if (is_dir())
1532        retval = 0;
1533      else 
1534        retval = ::mkdir(NativeFilename(), 0755);
1535#elif defined(WIN32)
1536      USES_CONVERSION;
1537      if (is_dir())
1538        retval = 0;
1539      else 
1540        retval = CreateDirectory(A2CT(NativeFilename()), NULL);
1541#else
1542# error "Define something here for your operating system"
1543#endif
1544    }
1545  return retval;
1546}
1547
1548// deletefile
1549// -- deletes a file or directory
1550 
1551int
1552GURL::deletefile(void) const
1553{
1554  int retval = -1;
1555  if(is_local_file_url())
1556    {
1557#if defined(UNIX) || defined(OS2)
1558      if (is_dir())
1559        retval = ::rmdir(NativeFilename());
1560      else
1561        retval = ::unlink(NativeFilename());
1562#elif defined(WIN32)
1563      USES_CONVERSION;
1564      if (is_dir())
1565        retval = ::RemoveDirectory(A2CT(NativeFilename()));
1566      else
1567        retval = ::DeleteFile(A2CT(NativeFilename()));
1568#else
1569# error "Define something here for your operating system"
1570#endif
1571  }
1572  return retval;
1573}
1574
1575GList<GURL>
1576GURL::listdir(void) const
1577{
1578  GList<GURL> retval;
1579  if(is_dir())
1580  {
1581#if defined(UNIX) || defined(OS2)
1582    DIR * dir=opendir(NativeFilename());//MBCS cvt
1583    for(dirent *de=readdir(dir);de;de=readdir(dir))
1584    {
1585      const int len = NAMLEN(de);
1586      if (de->d_name[0]== dot  && len==1)
1587        continue;
1588      if (de->d_name[0]== dot  && de->d_name[1]== dot  && len==2)
1589        continue;
1590      retval.append(GURL::Native(de->d_name,*this));
1591    }
1592    closedir(dir);
1593#elif defined (WIN32)
1594    GURL::UTF8 wildcard("*.*",*this);
1595    WIN32_FIND_DATA finddata;
1596    HANDLE handle = FindFirstFile(wildcard.NativeFilename(), &finddata);//MBCS cvt
1597    const GUTF8String gpathname=pathname();
1598    const GUTF8String gbase=base().pathname();
1599    if( handle != INVALID_HANDLE_VALUE)
1600    {
1601      do
1602      {
1603        GURL::UTF8 Entry(finddata.cFileName,*this);
1604        const GUTF8String gentry=Entry.pathname();
1605        if((gentry != gpathname) && (gentry != gbase))
1606          retval.append(Entry);
1607      } while( FindNextFile(handle, &finddata) );
1608
1609      FindClose(handle);
1610    }
1611#else
1612# error "Define something here for your operating system"
1613#endif
1614  }
1615  return retval;
1616}
1617
1618int
1619GURL::cleardir(const int timeout) const
1620{
1621  int retval=(-1);
1622  if(is_dir())
1623  {
1624    GList<GURL> dirlist=listdir();
1625    retval=0;
1626    for(GPosition pos=dirlist;pos&&!retval;++pos)
1627    {
1628      const GURL &Entry=dirlist[pos];
1629      if(Entry.is_dir())
1630      {
1631        if((retval=Entry.cleardir(timeout)) < 0)
1632        {
1633          break;
1634        }
1635      }
1636      if(((retval=Entry.deletefile())<0) && (timeout>0))
1637      {
1638        GOS::sleep(timeout);
1639        retval=Entry.deletefile();
1640      }
1641    }
1642  }
1643  return retval;
1644}
1645
1646int
1647GURL::renameto(const GURL &newurl) const
1648{
1649  if (is_local_file_url() && newurl.is_local_file_url())
1650    return rename(NativeFilename(),newurl.NativeFilename());
1651  return -1;
1652}
1653
1654// expand_name(filename[, fromdirname])
1655// -- returns the full path name of filename interpreted
1656//    relative to fromdirname.  Use current working dir when
1657//    fromdirname is null.
1658GUTF8String
1659GURL::expand_name(const GUTF8String &xfname, const char *from)
1660{
1661  const char *fname=xfname;
1662  GUTF8String retval;
1663  const size_t maxlen=xfname.length()*9+MAXPATHLEN+10;
1664  char * const string_buffer = retval.getbuf(maxlen);
1665  // UNIX implementation
1666#if defined(UNIX)
1667  // Perform tilde expansion
1668  GUTF8String senv;
1669  if (fname && fname[0]==tilde)
1670  {
1671    int n;
1672    for(n=1;fname[n] && fname[n]!= slash;n++) 
1673      EMPTY_LOOP;
1674    struct passwd *pw=0;
1675    if (n!=1)
1676    {
1677      GUTF8String user(fname+1, n-1);
1678      pw=getpwnam(user);
1679    }else if ((senv=GOS::getenv("HOME")).length())
1680    {
1681      from=(const char *)senv;
1682      fname = fname + n;
1683    }else if ((senv=GOS::getenv("LOGNAME")).length())
1684    {
1685      pw = getpwnam((const char *)senv.getUTF82Native());
1686    }else
1687    {
1688      pw=getpwuid(getuid());
1689    }
1690    if (pw)
1691    {
1692      senv=GNativeString(pw->pw_dir).getNative2UTF8();
1693      from = (const char *)senv;
1694      fname = fname + n;
1695    }
1696    for(;fname[0] == slash; fname++)
1697      EMPTY_LOOP;
1698  }
1699  // Process absolute vs. relative path
1700  if (fname && fname[0]== slash)
1701  {
1702    string_buffer[0]=slash;
1703    string_buffer[1]=0;
1704  }else if (from)
1705  {
1706    strcpy(string_buffer, expand_name(from));
1707  }else
1708  {
1709    strcpy(string_buffer, GOS::cwd());
1710  }
1711  char *s = string_buffer + strlen(string_buffer);
1712  if(fname)
1713  {
1714    for(;fname[0]== slash;fname++)
1715      EMPTY_LOOP;
1716    // Process path components
1717    while(fname[0])
1718    {
1719      if (fname[0] == dot )
1720      {
1721        if (!fname[1] || fname[1]== slash)
1722        {
1723          fname++;
1724          continue;
1725        }else if (fname[1]== dot && (fname[2]== slash || !fname[2]))
1726        {
1727          fname +=2;
1728          for(;s>string_buffer+1 && *(s-1)== slash; s--)
1729            EMPTY_LOOP;
1730          for(;s>string_buffer+1 && *(s-1)!= slash; s--)
1731            EMPTY_LOOP;
1732          continue;
1733        }
1734      }
1735      if ((s==string_buffer)||(*(s-1)!= slash))
1736      {
1737        *s = slash;
1738        s++;
1739      }
1740      while (*fname &&(*fname!= slash))
1741      {
1742        *s = *fname++;
1743        if ((size_t)((++s)-string_buffer) > maxlen)
1744        {
1745          G_THROW( ERR_MSG("GURL.big_name") );
1746        }
1747      }
1748      *s = 0;
1749      for(;fname[0]== slash;fname++)
1750        EMPTY_LOOP;
1751    }
1752  }
1753  if (!fname || !fname[0])
1754  {
1755    for(;s>string_buffer+1 && *(s-1) == slash; s--)
1756      EMPTY_LOOP;
1757    *s = 0;
1758  }
1759#elif defined(WIN32) || defined(OS2) // WIN32 implementation
1760  // Handle base
1761  strcpy(string_buffer, (char const *)(from ? expand_name(from) : GOS::cwd()));
1762  //  GNativeString native;
1763  if (fname)
1764  {
1765    char *s = string_buffer;
1766    char  drv[4];
1767    // Handle absolute part of fname
1768    //      Put absolute part of the file name in string_buffer, and
1769    //      the relative part pointed to by fname.
1770    if (fname[0]== slash || fname[0]== backslash)
1771    {
1772      if (fname[1]== slash || fname[1]== backslash)
1773      {       // Case "//abcd"
1774        s[0]=s[1]= backslash; s[2]=0;
1775      }
1776      else
1777      {       // Case "/abcd" or "/"
1778              //    File is at the root of the current drive. Delete the
1779              //    slash at the beginning of the filename and leave
1780              //    an explicit identification of the root of the drive in
1781              //    string_buffer.
1782        fname++;
1783        s[3] = '\0';
1784      }
1785    }
1786    else if (fname[0] && fname[1]==colon)
1787    {
1788      if (fname[2]!= slash && fname[2]!= backslash)
1789      {       // Case "x:abcd"
1790        if ( toupper((unsigned char)s[0]) != toupper((unsigned char)fname[0])
1791          || s[1]!=colon)
1792        {
1793          drv[0]=fname[0];
1794          drv[1]=colon;
1795          drv[2]= dot ;
1796          drv[3]=0;
1797          // todo !!!
1798          //GetFullPathName(drv, maxlen, string_buffer, &s);
1799          strcpy(string_buffer,(const char *)GUTF8String(string_buffer).getNative2UTF8());
1800          s = string_buffer;
1801        }
1802        fname += 2;
1803      }
1804      else if (fname[3]!= slash && fname[3]!= backslash)
1805      {       // Case "x:/abcd"
1806        s[0]=toupper((unsigned char)fname[0]);
1807        s[1]=colon;
1808        s[2]=backslash;
1809        s[3]=0;
1810        fname += 3;
1811      }
1812      else
1813      {       // Case "x://abcd"
1814        s[0]=s[1]=backslash;
1815        s[2]=0;
1816        fname += 4;
1817      }
1818    }
1819    // Process path components
1820    for(;*fname== slash || *fname==backslash;fname++)
1821      EMPTY_LOOP;
1822    while(*fname)
1823    {
1824      if (fname[0]== dot )
1825      {
1826        if (fname[1]== slash || fname[1]==backslash || !fname[1])
1827        {
1828          fname++;
1829          continue;
1830        }else if ((fname[1] == dot)
1831          && (fname[2]== slash || fname[2]==backslash || !fname[2]))
1832        {
1833          fname += 2;
1834          char *back=NULL;//_tcsrchr(string_buffer,backslash);
1835          char *forward=NULL;//_tcsrchr(string_buffer,slash);
1836          if(back>forward)
1837          {
1838            *back=0;
1839          }else if(forward)
1840          {
1841            *forward=0;
1842          }
1843          s = string_buffer;
1844          continue;
1845        }
1846        char* s2=s;//MBCS DBCS
1847        for(;*s;s++) 
1848          EMPTY_LOOP;
1849        char* back = NULL;//_tcsrchr(s2,backslash);//MBCS DBCS
1850        if ((s>string_buffer)&&(*(s-1)!= slash)&&
1851            (back == NULL || (back!=NULL && s-1 != back) ))//MBCS DBCS
1852        {
1853          *s = backslash;
1854          s++;
1855        }
1856        while (*fname && *fname!= slash && *fname!=backslash)
1857        {
1858          *s = *fname++;
1859          if ((size_t)((++s)-string_buffer) > maxlen)
1860            G_THROW( ERR_MSG("GURL.big_name") );
1861        }
1862        *s = 0;
1863      }
1864      char* s2=s;//MBCS DBCS
1865      for(;*s;s++) 
1866        EMPTY_LOOP;
1867      char* back = NULL;//_tcsrchr(s2,backslash);//MBCS DBCS
1868      if ((s>string_buffer)&&(*(s-1)!= slash)
1869          &&(back == NULL || (back!=NULL && s-1 != back) ))//MBCS DBCS
1870      {
1871        *s = backslash;
1872        s++;
1873      }
1874      while (*fname && (*fname!= slash) && (*fname!=backslash))
1875      {
1876        *s = *fname++;
1877        if ((size_t)((++s)-string_buffer) > maxlen)
1878          G_THROW( ERR_MSG("GURL.big_name") );
1879      }
1880      *s = 0;
1881      for(;(*fname== slash)||(*fname==backslash);fname++)
1882        EMPTY_LOOP;
1883    }
1884  }
1885#elif defined(macintosh) // MACINTOSH implementation
1886  strcpy(string_buffer, (const char *)(from?from:GOS::cwd()));
1887 
1888  if (!GStringRep::cmp(fname, string_buffer,strlen(string_buffer)) || is_file(fname))
1889  {
1890    strcpy(string_buffer, "");//please don't expand, the logic of filename is chaos.
1891  }
1892 
1893  // Process path components
1894  char *s = string_buffer + strlen(string_buffer);
1895  if(fname)
1896  {
1897    for(;fname[0]==colon;fname++)
1898      EMPTY_LOOP;
1899    while(fname[0])
1900    {
1901      if (fname[0]== dot )
1902      {
1903        if (fname[1]==colon || !fname[1])
1904        {
1905          fname++;
1906          continue;
1907        }
1908        if ((fname[1]== dot )
1909          &&(fname[2]==colon || fname[2]==0))
1910        {
1911          fname +=2;
1912          for(;(s>string_buffer+1)&&(*(s-1)==colon);s--)
1913            EMPTY_LOOP;
1914          for(;(s>string_buffer+1)&&(*(s-1)!=colon);s--)
1915            EMPTY_LOOP;
1916          continue;
1917        }
1918      }
1919      if ((s==string_buffer)||(*(s-1)!=colon))
1920      {
1921        *s = colon;
1922        s++;
1923      }
1924      while (*fname!=0 && *fname!=colon)
1925      {
1926        *s = *fname++;
1927        if ((++s)-string_buffer > maxlen)
1928          G_THROW( ERR_MSG("GURL.big_name") );
1929      }
1930      *s = 0;
1931      for(;fname[0]==colon;fname++)
1932        EMPTY_LOOP;
1933    }
1934  }
1935  for(;(s>string_buffer+1) && (*(s-1)==colon);s--)
1936    EMPTY_LOOP;
1937  *s = 0;
1938  return ((string_buffer[0]==colon)?(string_buffer+1):string_buffer);
1939#else
1940# error "Define something here for your operating system"
1941#endif 
1942  return retval;
1943}
1944
1945unsigned int
1946hash(const GURL & gurl)
1947{
1948  unsigned int retval;
1949  const GUTF8String s(gurl.get_string());
1950  const int len=s.length();
1951  if(len && (s[len-1] == '/')) // Don't include the trailing slash as part of the hash.
1952  {
1953        retval=hash(s.substr(0,len-1));
1954  }else
1955  {
1956    retval=hash(s);
1957  }
1958  return retval;
1959}
1960
1961
1962#ifdef HAVE_NAMESPACES
1963}
1964# ifndef NOT_USING_DJVU_NAMESPACE
1965using namespace DJVU;
1966# endif
1967#endif
Note: See TracBrowser for help on using the repository browser.