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