source: trunk/poppler/mypoppler/goo/gfile.cc @ 257

Last change on this file since 257 was 257, checked in by Eugene Romanenko, 13 years ago

PDF plugin: Poppler library updated to version 0.10.0

File size: 16.6 KB
Line 
1//========================================================================
2//
3// gfile.cc
4//
5// Miscellaneous file and directory name manipulation.
6//
7// Copyright 1996-2003 Glyph & Cog, LLC
8//
9//========================================================================
10
11//========================================================================
12//
13// Modified under the Poppler project - http://poppler.freedesktop.org
14//
15// All changes made under the Poppler project to this file are licensed
16// under GPL version 2 or later
17//
18// Copyright (C) 2006 Takashi Iwai <tiwai@suse.de>
19// Copyright (C) 2006 Kristian HÞgsberg <krh@redhat.com>
20// Copyright (C) 2008 Adam Batkin <adam@batkin.net>
21//
22// To see a description of the changes please see the Changelog file that
23// came with your tarball or type make ChangeLog if you are building from git
24//
25//========================================================================
26
27#include <config.h>
28
29#ifdef WIN32
30#  include <time.h>
31#else
32#  if defined(MACOS)
33#    include <sys/stat.h>
34#  elif !defined(ACORN)
35#    include <sys/types.h>
36#    include <sys/stat.h>
37#    include <fcntl.h>
38#  endif
39#  include <limits.h>
40#  include <string.h>
41#  if !defined(VMS) && !defined(ACORN) && !defined(MACOS) && !defined(OS2)
42#    include <pwd.h>
43#  endif
44#  if defined(VMS) && (__DECCXX_VER < 50200000)
45#    include <unixlib.h>
46#  endif
47#endif // WIN32
48#include "GooString.h"
49#include "gfile.h"
50
51// Some systems don't define this, so just make it something reasonably
52// large.
53#ifndef PATH_MAX
54#define PATH_MAX 1024
55#endif
56
57//------------------------------------------------------------------------
58
59GooString *getHomeDir() {
60#ifdef VMS
61  //---------- VMS ----------
62  return new GooString("SYS$LOGIN:");
63
64#elif defined(__EMX__) || defined(WIN32) || defined(OS2)
65  //---------- OS/2+EMX and Win32 ----------
66  char *s;
67  GooString *ret;
68
69  if ((s = getenv("HOME")))
70    ret = new GooString(s);
71  else
72    ret = new GooString(".");
73  return ret;
74
75#elif defined(ACORN)
76  //---------- RISCOS ----------
77  return new GooString("@");
78
79#elif defined(MACOS)
80  //---------- MacOS ----------
81  return new GooString(":");
82
83#else
84  //---------- Unix ----------
85  char *s;
86  struct passwd *pw;
87  GooString *ret;
88
89  if ((s = getenv("HOME"))) {
90    ret = new GooString(s);
91  } else {
92    if ((s = getenv("USER")))
93      pw = getpwnam(s);
94    else
95      pw = getpwuid(getuid());
96    if (pw)
97      ret = new GooString(pw->pw_dir);
98    else
99      ret = new GooString(".");
100  }
101  return ret;
102#endif
103}
104
105GooString *getCurrentDir() {
106  char buf[PATH_MAX+1];
107
108#if defined(__EMX__)
109  if (_getcwd2(buf, sizeof(buf)))
110#elif defined(WIN32)
111  if (GetCurrentDirectory(sizeof(buf), buf))
112#elif defined(ACORN)
113  if (strcpy(buf, "@"))
114#elif defined(MACOS)
115  if (strcpy(buf, ":"))
116#else
117  if (getcwd(buf, sizeof(buf)))
118#endif
119    return new GooString(buf);
120  return new GooString();
121}
122
123GooString *appendToPath(GooString *path, char *fileName) {
124#if defined(VMS)
125  //---------- VMS ----------
126  //~ this should handle everything necessary for file
127  //~ requesters, but it's certainly not complete
128  char *p0, *p1, *p2;
129  char *q1;
130
131  p0 = path->getCString();
132  p1 = p0 + path->getLength() - 1;
133  if (!strcmp(fileName, "-")) {
134    if (*p1 == ']') {
135      for (p2 = p1; p2 > p0 && *p2 != '.' && *p2 != '['; --p2) ;
136      if (*p2 == '[')
137        ++p2;
138      path->del(p2 - p0, p1 - p2);
139    } else if (*p1 == ':') {
140      path->append("[-]");
141    } else {
142      path->clear();
143      path->append("[-]");
144    }
145  } else if ((q1 = strrchr(fileName, '.')) && !strncmp(q1, ".DIR;", 5)) {
146    if (*p1 == ']') {
147      path->insert(p1 - p0, '.');
148      path->insert(p1 - p0 + 1, fileName, q1 - fileName);
149    } else if (*p1 == ':') {
150      path->append('[');
151      path->append(']');
152      path->append(fileName, q1 - fileName);
153    } else {
154      path->clear();
155      path->append(fileName, q1 - fileName);
156    }
157  } else {
158    if (*p1 != ']' && *p1 != ':')
159      path->clear();
160    path->append(fileName);
161  }
162  return path;
163
164#elif defined(WIN32)
165  //---------- Win32 ----------
166  GooString *tmp;
167  char buf[256];
168  char *fp;
169
170  tmp = new GooString(path);
171  tmp->append('/');
172  tmp->append(fileName);
173  GetFullPathName(tmp->getCString(), sizeof(buf), buf, &fp);
174  delete tmp;
175  path->clear();
176  path->append(buf);
177  return path;
178
179#elif defined(ACORN)
180  //---------- RISCOS ----------
181  char *p;
182  int i;
183
184  path->append(".");
185  i = path->getLength();
186  path->append(fileName);
187  for (p = path->getCString() + i; *p; ++p) {
188    if (*p == '/') {
189      *p = '.';
190    } else if (*p == '.') {
191      *p = '/';
192    }
193  }
194  return path;
195
196#elif defined(MACOS)
197  //---------- MacOS ----------
198  char *p;
199  int i;
200
201  path->append(":");
202  i = path->getLength();
203  path->append(fileName);
204  for (p = path->getCString() + i; *p; ++p) {
205    if (*p == '/') {
206      *p = ':';
207    } else if (*p == '.') {
208      *p = ':';
209    }
210  }
211  return path;
212
213#elif defined(__EMX__) || defined(OS2)
214  //---------- OS/2+EMX ----------
215  int i;
216
217  // appending "." does nothing
218  if (!strcmp(fileName, "."))
219    return path;
220
221  // appending ".." goes up one directory
222  if (!strcmp(fileName, "..")) {
223    for (i = path->getLength() - 2; i >= 0; --i) {
224      if (path->getChar(i) == '/' || path->getChar(i) == '\\' ||
225          path->getChar(i) == ':')
226        break;
227    }
228    if (i <= 0) {
229      if (path->getChar(0) == '/' || path->getChar(0) == '\\') {
230        path->del(1, path->getLength() - 1);
231      } else if (path->getLength() >= 2 && path->getChar(1) == ':') {
232        path->del(2, path->getLength() - 2);
233      } else {
234        path->clear();
235        path->append("..");
236      }
237    } else {
238      if (path->getChar(i-1) == ':')
239        ++i;
240      path->del(i, path->getLength() - i);
241    }
242    return path;
243  }
244
245  // otherwise, append "/" and new path component
246  if (path->getLength() > 0 &&
247      path->getChar(path->getLength() - 1) != '/' &&
248      path->getChar(path->getLength() - 1) != '\\')
249    path->append('/');
250  path->append(fileName);
251  return path;
252
253#else
254  //---------- Unix ----------
255  int i;
256
257  // appending "." does nothing
258  if (!strcmp(fileName, "."))
259    return path;
260
261  // appending ".." goes up one directory
262  if (!strcmp(fileName, "..")) {
263    for (i = path->getLength() - 2; i >= 0; --i) {
264      if (path->getChar(i) == '/')
265        break;
266    }
267    if (i <= 0) {
268      if (path->getChar(0) == '/') {
269        path->del(1, path->getLength() - 1);
270      } else {
271        path->clear();
272        path->append("..");
273      }
274    } else {
275      path->del(i, path->getLength() - i);
276    }
277    return path;
278  }
279
280  // otherwise, append "/" and new path component
281  if (path->getLength() > 0 &&
282      path->getChar(path->getLength() - 1) != '/')
283    path->append('/');
284  path->append(fileName);
285  return path;
286#endif
287}
288
289GooString *grabPath(char *fileName) {
290#ifdef VMS
291  //---------- VMS ----------
292  char *p;
293
294  if ((p = strrchr(fileName, ']')))
295    return new GooString(fileName, p + 1 - fileName);
296  if ((p = strrchr(fileName, ':')))
297    return new GooString(fileName, p + 1 - fileName);
298  return new GooString();
299
300#elif defined(__EMX__) || defined(WIN32) || defined(OS2)
301  //---------- OS/2+EMX and Win32 ----------
302  char *p;
303
304  if ((p = strrchr(fileName, '/')))
305    return new GooString(fileName, p - fileName);
306  if ((p = strrchr(fileName, '\\')))
307    return new GooString(fileName, p - fileName);
308  if ((p = strrchr(fileName, ':')))
309    return new GooString(fileName, p + 1 - fileName);
310  return new GooString();
311
312#elif defined(ACORN)
313  //---------- RISCOS ----------
314  char *p;
315
316  if ((p = strrchr(fileName, '.')))
317    return new GooString(fileName, p - fileName);
318  return new GooString();
319
320#elif defined(MACOS)
321  //---------- MacOS ----------
322  char *p;
323
324  if ((p = strrchr(fileName, ':')))
325    return new GooString(fileName, p - fileName);
326  return new GooString();
327
328#else
329  //---------- Unix ----------
330  char *p;
331
332  if ((p = strrchr(fileName, '/')))
333    return new GooString(fileName, p - fileName);
334  return new GooString();
335#endif
336}
337
338GBool isAbsolutePath(char *path) {
339#ifdef VMS
340  //---------- VMS ----------
341  return strchr(path, ':') ||
342         (path[0] == '[' && path[1] != '.' && path[1] != '-');
343
344#elif defined(__EMX__) || defined(WIN32) || defined(OS2)
345  //---------- OS/2+EMX and Win32 ----------
346  return path[0] == '/' || path[0] == '\\' || path[1] == ':';
347
348#elif defined(ACORN)
349  //---------- RISCOS ----------
350  return path[0] == '$';
351
352#elif defined(MACOS)
353  //---------- MacOS ----------
354  return path[0] != ':';
355
356#else
357  //---------- Unix ----------
358  return path[0] == '/';
359#endif
360}
361
362GooString *makePathAbsolute(GooString *path) {
363#ifdef VMS
364  //---------- VMS ----------
365  char buf[PATH_MAX+1];
366
367  if (!isAbsolutePath(path->getCString())) {
368    if (getcwd(buf, sizeof(buf))) {
369      path->insert(0, buf);
370    }
371  }
372  return path;
373
374#elif defined(WIN32)
375  //---------- Win32 ----------
376  char buf[_MAX_PATH];
377  char *fp;
378
379  buf[0] = '\0';
380  if (!GetFullPathName(path->getCString(), _MAX_PATH, buf, &fp)) {
381    path->clear();
382    return path;
383  }
384  path->clear();
385  path->append(buf);
386  return path;
387
388#elif defined(ACORN)
389  //---------- RISCOS ----------
390  path->insert(0, '@');
391  return path;
392
393#elif defined(MACOS)
394  //---------- MacOS ----------
395  path->del(0, 1);
396  return path;
397
398#elif defined(OS2)
399  //---------- OS/2 -----------
400  char buf[_MAX_PATH];
401  buf[0] = '\0';
402  if (!_fullpath( buf, path->getCString(), _MAX_PATH ) ) {
403    path->clear();
404    return path;
405  }
406  path->clear();
407  path->append(buf);
408  return path;
409 
410#else
411  //---------- Unix and OS/2+EMX ----------
412  struct passwd *pw;
413  char buf[PATH_MAX+1];
414  GooString *s;
415  char *p1, *p2;
416  int n;
417
418  if (path->getChar(0) == '~') {
419    if (path->getChar(1) == '/' ||
420#ifdef __EMX__
421        path->getChar(1) == '\\' ||
422#endif
423        path->getLength() == 1) {
424      path->del(0, 1);
425      s = getHomeDir();
426      path->insert(0, s);
427      delete s;
428    } else {
429      p1 = path->getCString() + 1;
430#ifdef __EMX__
431      for (p2 = p1; *p2 && *p2 != '/' && *p2 != '\\'; ++p2) ;
432#else
433      for (p2 = p1; *p2 && *p2 != '/'; ++p2) ;
434#endif
435      if ((n = p2 - p1) > PATH_MAX)
436        n = PATH_MAX;
437      strncpy(buf, p1, n);
438      buf[n] = '\0';
439      if ((pw = getpwnam(buf))) {
440        path->del(0, p2 - p1 + 1);
441        path->insert(0, pw->pw_dir);
442      }
443    }
444  } else if (!isAbsolutePath(path->getCString())) {
445    if (getcwd(buf, sizeof(buf))) {
446#ifndef __EMX__
447      path->insert(0, '/');
448#endif
449      path->insert(0, buf);
450    }
451  }
452  return path;
453#endif
454}
455
456time_t getModTime(char *fileName) {
457#ifdef WIN32
458  //~ should implement this, but it's (currently) only used in xpdf
459  return 0;
460#else
461  struct stat statBuf;
462
463  if (stat(fileName, &statBuf)) {
464    return 0;
465  }
466  return statBuf.st_mtime;
467#endif
468}
469
470GBool openTempFile(GooString **name, FILE **f, char *mode, char *ext) {
471#if defined(WIN32)
472  //---------- Win32 ----------
473  char *tempDir;
474  GooString *s, *s2;
475  char buf[32];
476  FILE *f2;
477  int t, i;
478
479  // this has the standard race condition problem, but I haven't found
480  // a better way to generate temp file names with extensions on
481  // Windows
482  if ((tempDir = getenv("TEMP"))) {
483    s = new GooString(tempDir);
484    s->append('\\');
485  } else {
486    s = new GooString();
487  }
488  s->append("x");
489  t = (int)time(NULL);
490  for (i = 0; i < 1000; ++i) {
491    sprintf(buf, "%d", t + i);
492    s2 = s->copy()->append(buf);
493    if (ext) {
494      s2->append(ext);
495    }
496    if (!(f2 = fopen(s2->getCString(), "r"))) {
497      if (!(f2 = fopen(s2->getCString(), mode))) {
498        delete s2;
499        delete s;
500        return gFalse;
501      }
502      *name = s2;
503      *f = f2;
504      delete s;
505      return gTrue;
506    }
507    fclose(f2);
508    delete s2;
509  }
510  delete s;
511  return gFalse;
512#elif defined(VMS) || defined(__EMX__) || defined(ACORN) || defined(MACOS) || defined(OS2)
513  //---------- non-Unix ----------
514  char *s;
515
516  // There is a security hole here: an attacker can create a symlink
517  // with this file name after the tmpnam call and before the fopen
518  // call.  I will happily accept fixes to this function for non-Unix
519  // OSs.
520  if (!(s = tmpnam(NULL))) {
521    return gFalse;
522  }
523  *name = new GooString(s);
524  if (ext) {
525    (*name)->append(ext);
526  }
527  if (!(*f = fopen((*name)->getCString(), mode))) {
528    delete (*name);
529    return gFalse;
530  }
531  return gTrue;
532#else
533  //---------- Unix ----------
534  char *s;
535  int fd;
536
537  if (ext) {
538#if HAVE_MKSTEMPS
539    if ((s = getenv("TMPDIR"))) {
540      *name = new GooString(s);
541    } else {
542      *name = new GooString("/tmp");
543    }
544    (*name)->append("/XXXXXX")->append(ext);
545    fd = mkstemps((*name)->getCString(), strlen(ext));
546#elif defined(HAVE_MKSTEMP)
547    if ((s = getenv("TMPDIR"))) {
548      *name = new GooString(s);
549    } else {
550      *name = new GooString("/tmp");
551    }
552    (*name)->append("/XXXXXX")->append(ext);
553    fd = mkstemp((*name)->getCString());
554#else
555    if (!(s = tmpnam(NULL))) {
556      return gFalse;
557    }
558    *name = new GooString(s);
559    (*name)->append(ext);
560    fd = open((*name)->getCString(), O_WRONLY | O_CREAT | O_EXCL, 0600);
561#endif
562  } else {
563#if HAVE_MKSTEMP
564    if ((s = getenv("TMPDIR"))) {
565      *name = new GooString(s);
566    } else {
567      *name = new GooString("/tmp");
568    }
569    (*name)->append("/XXXXXX");
570    fd = mkstemp((*name)->getCString());
571#else // HAVE_MKSTEMP
572    if (!(s = tmpnam(NULL))) {
573      return gFalse;
574    }
575    *name = new GooString(s);
576    fd = open((*name)->getCString(), O_WRONLY | O_CREAT | O_EXCL, 0600);
577#endif // HAVE_MKSTEMP
578  }
579  if (fd < 0 || !(*f = fdopen(fd, mode))) {
580    delete *name;
581    return gFalse;
582  }
583  return gTrue;
584#endif
585}
586
587GBool executeCommand(char *cmd) {
588#ifdef VMS
589  return system(cmd) ? gTrue : gFalse;
590#else
591  return system(cmd) ? gFalse : gTrue;
592#endif
593}
594
595char *getLine(char *buf, int size, FILE *f) {
596  int c, i;
597
598  i = 0;
599  while (i < size - 1) {
600    if ((c = fgetc(f)) == EOF) {
601      break;
602    }
603    buf[i++] = (char)c;
604    if (c == '\x0a') {
605      break;
606    }
607    if (c == '\x0d') {
608      c = fgetc(f);
609      if (c == '\x0a' && i < size - 1) {
610        buf[i++] = (char)c;
611      } else if (c != EOF) {
612        ungetc(c, f);
613      }
614      break;
615    }
616  }
617  buf[i] = '\0';
618  if (i == 0) {
619    return NULL;
620  }
621  return buf;
622}
623
624//------------------------------------------------------------------------
625// GDir and GDirEntry
626//------------------------------------------------------------------------
627
628GDirEntry::GDirEntry(char *dirPath, char *nameA, GBool doStat) {
629#ifdef VMS
630  char *p;
631#elif defined(WIN32)
632  int fa;
633#elif defined(ACORN)
634#else
635  struct stat st;
636#endif
637
638  name = new GooString(nameA);
639  dir = gFalse;
640  fullPath = new GooString(dirPath);
641  appendToPath(fullPath, nameA);
642  if (doStat) {
643#ifdef VMS
644    if (!strcmp(nameA, "-") ||
645        ((p = strrchr(nameA, '.')) && !strncmp(p, ".DIR;", 5)))
646      dir = gTrue;
647#elif defined(ACORN)
648#else
649#ifdef WIN32
650    fa = GetFileAttributes(fullPath->getCString());
651    dir = (fa != 0xFFFFFFFF && (fa & FILE_ATTRIBUTE_DIRECTORY));
652#else
653    if (stat(fullPath->getCString(), &st) == 0)
654      dir = S_ISDIR(st.st_mode);
655#endif
656#endif
657  }
658}
659
660GDirEntry::~GDirEntry() {
661  delete fullPath;
662  delete name;
663}
664
665GDir::GDir(char *name, GBool doStatA) {
666  path = new GooString(name);
667  doStat = doStatA;
668#if defined(WIN32)
669  GooString *tmp;
670
671  tmp = path->copy();
672  tmp->append("/*.*");
673  hnd = FindFirstFile(tmp->getCString(), &ffd);
674  delete tmp;
675#elif defined(ACORN)
676#elif defined(MACOS)
677#else
678  dir = opendir(name);
679#ifdef VMS
680  needParent = strchr(name, '[') != NULL;
681#endif
682#endif
683}
684
685GDir::~GDir() {
686  delete path;
687#if defined(WIN32)
688  if (hnd != INVALID_HANDLE_VALUE) {
689    FindClose(hnd);
690    hnd = INVALID_HANDLE_VALUE;
691  }
692#elif defined(ACORN)
693#elif defined(MACOS)
694#else
695  if (dir)
696    closedir(dir);
697#endif
698}
699
700GDirEntry *GDir::getNextEntry() {
701  GDirEntry *e;
702
703#if defined(WIN32)
704  if (hnd != INVALID_HANDLE_VALUE) {
705    e = new GDirEntry(path->getCString(), ffd.cFileName, doStat);
706    if (!FindNextFile(hnd, &ffd)) {
707      FindClose(hnd);
708      hnd = INVALID_HANDLE_VALUE;
709    }
710  } else {
711    e = NULL;
712  }
713#elif defined(ACORN)
714#elif defined(MACOS)
715#elif defined(VMS)
716  struct dirent *ent;
717  e = NULL;
718  if (dir) {
719    if (needParent) {
720      e = new GDirEntry(path->getCString(), "-", doStat);
721      needParent = gFalse;
722      return e;
723    }
724    ent = readdir(dir);
725    if (ent) {
726      e = new GDirEntry(path->getCString(), ent->d_name, doStat);
727    }
728  }
729#else
730  struct dirent *ent;
731  e = NULL;
732  if (dir) {
733    do {
734      ent = readdir(dir);
735    }
736    while (ent && (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")));
737    if (ent) {
738      e = new GDirEntry(path->getCString(), ent->d_name, doStat);
739    }
740  }
741#endif
742
743  return e;
744}
745
746void GDir::rewind() {
747#ifdef WIN32
748  GooString *tmp;
749
750  if (hnd != INVALID_HANDLE_VALUE)
751    FindClose(hnd);
752  tmp = path->copy();
753  tmp->append("/*.*");
754  hnd = FindFirstFile(tmp->getCString(), &ffd);
755  delete tmp;
756#elif defined(ACORN)
757#elif defined(MACOS)
758#else
759  if (dir)
760    rewinddir(dir);
761#ifdef VMS
762  needParent = strchr(path->getCString(), '[') != NULL;
763#endif
764#endif
765}
Note: See TracBrowser for help on using the repository browser.