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

Last change on this file since 461 was 461, checked in by Silvan Scherrer, 11 years ago

poppler update to 0.14.2

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