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

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

PDF plugin: poppler library updated to version 0.8.3

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