Initial revision
[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 static char* mktmpname(char*ptr) {
446 //   used to be mktemp. This does remove the warnings, but
447 //   It's not exactly an improvement.
448     sprintf(tmpbuf, "%08x%08x",lrand48(),lrand48());
449     return tmpbuf;
450 }
451 GBool openTempFile(GString **name, FILE **f, char *mode, char *ext) {
452 #if defined(VMS) || defined(__EMX__) || defined(WIN32) || defined(ACORN) || defined(MACOS)
453   //---------- non-Unix ----------
454   char *s;
455
456   // There is a security hole here: an attacker can create a symlink
457   // with this file name after the tmpnam call and before the fopen
458   // call.  I will happily accept fixes to this function for non-Unix
459   // OSs.
460   if (!(s = mktmpname(NULL))) {
461     return gFalse;
462   }
463   *name = new GString(s);
464   if (ext) {
465     (*name)->append(ext);
466   }
467   if (!(*f = fopen((*name)->getCString(), mode))) {
468     delete (*name);
469     return gFalse;
470   }
471   return gTrue;
472 #else
473   //---------- Unix ----------
474   char *s, *p;
475   int fd;
476
477   if (ext) {
478     if (!(s = mktmpname(NULL))) {
479       return gFalse;
480     }
481     *name = new GString(s);
482     s = (*name)->getCString();
483     if ((p = strrchr(s, '.'))) {
484       (*name)->del(p - s, (*name)->getLength() - (p - s));
485     }
486     (*name)->append(ext);
487     fd = open((*name)->getCString(), O_WRONLY | O_CREAT | O_EXCL, 0600);
488   } else {
489 #if HAVE_MKSTEMP
490     if ((s = getenv("TMPDIR"))) {
491       *name = new GString(s);
492     } else {
493       *name = new GString("/tmp");
494     }
495     (*name)->append("/XXXXXX");
496     fd = mkstemp((*name)->getCString());
497 #else // HAVE_MKSTEMP
498     if (!(s = mktmpname(NULL))) {
499       return gFalse;
500     }
501     *name = new GString(s);
502     fd = open((*name)->getCString(), O_WRONLY | O_CREAT | O_EXCL, 0600);
503 #endif // HAVE_MKSTEMP
504   }
505   if (fd < 0 || !(*f = fdopen(fd, mode))) {
506     delete *name;
507     return gFalse;
508   }
509   return gTrue;
510 #endif
511 }
512
513 //------------------------------------------------------------------------
514 // GDir and GDirEntry
515 //------------------------------------------------------------------------
516
517 GDirEntry::GDirEntry(char *dirPath, char *name1, GBool doStat) {
518 #ifdef VMS
519   char *p;
520 #elif defined(WIN32)
521   int fa;
522   GString *s;
523 #elif defined(ACORN)
524 #else
525   struct stat st;
526   GString *s;
527 #endif
528
529   name = new GString(name1);
530   dir = gFalse;
531   if (doStat) {
532 #ifdef VMS
533     if (!strcmp(name1, "-") ||
534         ((p = strrchr(name1, '.')) && !strncmp(p, ".DIR;", 5)))
535       dir = gTrue;
536 #elif defined(ACORN)
537 #else
538     s = new GString(dirPath);
539     appendToPath(s, name1);
540 #ifdef WIN32
541     fa = GetFileAttributes(s->getCString());
542     dir = (fa != 0xFFFFFFFF && (fa & FILE_ATTRIBUTE_DIRECTORY));
543 #else
544     if (stat(s->getCString(), &st) == 0)
545       dir = S_ISDIR(st.st_mode);
546 #endif
547     delete s;
548 #endif
549   }
550 }
551
552 GDirEntry::~GDirEntry() {
553   delete name;
554 }
555
556 GDir::GDir(char *name, GBool doStat1) {
557   path = new GString(name);
558   doStat = doStat1;
559 #if defined(WIN32)
560   GString *tmp;
561
562   tmp = path->copy();
563   tmp->append("/*.*");
564   hnd = FindFirstFile(tmp->getCString(), &ffd);
565   delete tmp;
566 #elif defined(ACORN)
567 #elif defined(MACOS)
568 #else
569   dir = opendir(name);
570 #ifdef VMS
571   needParent = strchr(name, '[') != NULL;
572 #endif
573 #endif
574 }
575
576 GDir::~GDir() {
577   delete path;
578 #if defined(WIN32)
579   if (hnd) {
580     FindClose(hnd);
581     hnd = NULL;
582   }
583 #elif defined(ACORN)
584 #elif defined(MACOS)
585 #else
586   if (dir)
587     closedir(dir);
588 #endif
589 }
590
591 GDirEntry *GDir::getNextEntry() {
592   struct dirent *ent;
593   GDirEntry *e;
594
595   e = NULL;
596 #if defined(WIN32)
597   e = new GDirEntry(path->getCString(), ffd.cFileName, doStat);
598   if (hnd  && !FindNextFile(hnd, &ffd)) {
599     FindClose(hnd);
600     hnd = NULL;
601   }
602 #elif defined(ACORN)
603 #elif defined(MACOS)
604 #else
605   if (dir) {
606 #ifdef VMS
607     if (needParent) {
608       e = new GDirEntry(path->getCString(), "-", doStat);
609       needParent = gFalse;
610       return e;
611     }
612 #endif
613     ent = readdir(dir);
614 #ifndef VMS
615     if (ent && !strcmp(ent->d_name, "."))
616       ent = readdir(dir);
617 #endif
618     if (ent)
619       e = new GDirEntry(path->getCString(), ent->d_name, doStat);
620   }
621 #endif
622   return e;
623 }
624
625 void GDir::rewind() {
626 #ifdef WIN32
627   GString *tmp;
628
629   if (hnd)
630     FindClose(hnd);
631   tmp = path->copy();
632   tmp->append("/*.*");
633   hnd = FindFirstFile(tmp->getCString(), &ffd);
634 #elif defined(ACORN)
635 #elif defined(MACOS)
636 #else
637   if (dir)
638     rewinddir(dir);
639 #ifdef VMS
640   needParent = strchr(path->getCString(), '[') != NULL;
641 #endif
642 #endif
643 }