upgrade to xpdf 3.00.
[swftools.git] / pdf2swf / xpdf / gfile.cc
blob11f5cf69e200715f1ff3252c950213743288d89c
1 //========================================================================
2 //
3 // gfile.cc
4 //
5 // Miscellaneous file and directory name manipulation.
6 //
7 // Copyright 1996-2003 Glyph & Cog, LLC
8 //
9 //========================================================================
11 #include <aconf.h>
13 #ifndef WIN32
14 # if defined(MACOS)
15 # include <sys/stat.h>
16 # elif !defined(ACORN)
17 # include <sys/types.h>
18 # include <sys/stat.h>
19 # include <fcntl.h>
20 # endif
21 # include <limits.h>
22 # include <string.h>
23 # if !defined(VMS) && !defined(ACORN) && !defined(MACOS)
24 # include <pwd.h>
25 # endif
26 # if defined(VMS) && (__DECCXX_VER < 50200000)
27 # include <unixlib.h>
28 # endif
29 #endif // WIN32
30 #include "GString.h"
31 #include "gfile.h"
33 // Some systems don't define this, so just make it something reasonably
34 // large.
35 #ifndef PATH_MAX
36 #define PATH_MAX 1024
37 #endif
39 //------------------------------------------------------------------------
41 GString *getHomeDir() {
42 #ifdef VMS
43 //---------- VMS ----------
44 return new GString("SYS$LOGIN:");
46 #elif defined(__EMX__) || defined(WIN32)
47 //---------- OS/2+EMX and Win32 ----------
48 char *s;
49 GString *ret;
51 if ((s = getenv("HOME")))
52 ret = new GString(s);
53 else
54 ret = new GString(".");
55 return ret;
57 #elif defined(ACORN)
58 //---------- RISCOS ----------
59 return new GString("@");
61 #elif defined(MACOS)
62 //---------- MacOS ----------
63 return new GString(":");
65 #else
66 //---------- Unix ----------
67 char *s;
68 struct passwd *pw;
69 GString *ret;
71 if ((s = getenv("HOME"))) {
72 ret = new GString(s);
73 } else {
74 if ((s = getenv("USER")))
75 pw = getpwnam(s);
76 else
77 pw = getpwuid(getuid());
78 if (pw)
79 ret = new GString(pw->pw_dir);
80 else
81 ret = new GString(".");
83 return ret;
84 #endif
87 GString *getCurrentDir() {
88 char buf[PATH_MAX+1];
90 #if defined(__EMX__)
91 if (_getcwd2(buf, sizeof(buf)))
92 #elif defined(WIN32)
93 if (GetCurrentDirectory(sizeof(buf), buf))
94 #elif defined(ACORN)
95 if (strcpy(buf, "@"))
96 #elif defined(MACOS)
97 if (strcpy(buf, ":"))
98 #else
99 if (getcwd(buf, sizeof(buf)))
100 #endif
101 return new GString(buf);
102 return new GString();
105 GString *appendToPath(GString *path, char *fileName) {
106 #if defined(VMS)
107 //---------- VMS ----------
108 //~ this should handle everything necessary for file
109 //~ requesters, but it's certainly not complete
110 char *p0, *p1, *p2;
111 char *q1;
113 p0 = path->getCString();
114 p1 = p0 + path->getLength() - 1;
115 if (!strcmp(fileName, "-")) {
116 if (*p1 == ']') {
117 for (p2 = p1; p2 > p0 && *p2 != '.' && *p2 != '['; --p2) ;
118 if (*p2 == '[')
119 ++p2;
120 path->del(p2 - p0, p1 - p2);
121 } else if (*p1 == ':') {
122 path->append("[-]");
123 } else {
124 path->clear();
125 path->append("[-]");
127 } else if ((q1 = strrchr(fileName, '.')) && !strncmp(q1, ".DIR;", 5)) {
128 if (*p1 == ']') {
129 path->insert(p1 - p0, '.');
130 path->insert(p1 - p0 + 1, fileName, q1 - fileName);
131 } else if (*p1 == ':') {
132 path->append('[');
133 path->append(']');
134 path->append(fileName, q1 - fileName);
135 } else {
136 path->clear();
137 path->append(fileName, q1 - fileName);
139 } else {
140 if (*p1 != ']' && *p1 != ':')
141 path->clear();
142 path->append(fileName);
144 return path;
146 #elif defined(WIN32)
147 //---------- Win32 ----------
148 GString *tmp;
149 char buf[256];
150 char *fp;
152 tmp = new GString(path);
153 tmp->append('/');
154 tmp->append(fileName);
155 GetFullPathName(tmp->getCString(), sizeof(buf), buf, &fp);
156 delete tmp;
157 path->clear();
158 path->append(buf);
159 return path;
161 #elif defined(ACORN)
162 //---------- RISCOS ----------
163 char *p;
164 int i;
166 path->append(".");
167 i = path->getLength();
168 path->append(fileName);
169 for (p = path->getCString() + i; *p; ++p) {
170 if (*p == '/') {
171 *p = '.';
172 } else if (*p == '.') {
173 *p = '/';
176 return path;
178 #elif defined(MACOS)
179 //---------- MacOS ----------
180 char *p;
181 int i;
183 path->append(":");
184 i = path->getLength();
185 path->append(fileName);
186 for (p = path->getCString() + i; *p; ++p) {
187 if (*p == '/') {
188 *p = ':';
189 } else if (*p == '.') {
190 *p = ':';
193 return path;
195 #elif defined(__EMX__)
196 //---------- OS/2+EMX ----------
197 int i;
199 // appending "." does nothing
200 if (!strcmp(fileName, "."))
201 return path;
203 // appending ".." goes up one directory
204 if (!strcmp(fileName, "..")) {
205 for (i = path->getLength() - 2; i >= 0; --i) {
206 if (path->getChar(i) == '/' || path->getChar(i) == '\\' ||
207 path->getChar(i) == ':')
208 break;
210 if (i <= 0) {
211 if (path->getChar(0) == '/' || path->getChar(0) == '\\') {
212 path->del(1, path->getLength() - 1);
213 } else if (path->getLength() >= 2 && path->getChar(1) == ':') {
214 path->del(2, path->getLength() - 2);
215 } else {
216 path->clear();
217 path->append("..");
219 } else {
220 if (path->getChar(i-1) == ':')
221 ++i;
222 path->del(i, path->getLength() - i);
224 return path;
227 // otherwise, append "/" and new path component
228 if (path->getLength() > 0 &&
229 path->getChar(path->getLength() - 1) != '/' &&
230 path->getChar(path->getLength() - 1) != '\\')
231 path->append('/');
232 path->append(fileName);
233 return path;
235 #else
236 //---------- Unix ----------
237 int i;
239 // appending "." does nothing
240 if (!strcmp(fileName, "."))
241 return path;
243 // appending ".." goes up one directory
244 if (!strcmp(fileName, "..")) {
245 for (i = path->getLength() - 2; i >= 0; --i) {
246 if (path->getChar(i) == '/')
247 break;
249 if (i <= 0) {
250 if (path->getChar(0) == '/') {
251 path->del(1, path->getLength() - 1);
252 } else {
253 path->clear();
254 path->append("..");
256 } else {
257 path->del(i, path->getLength() - i);
259 return path;
262 // otherwise, append "/" and new path component
263 if (path->getLength() > 0 &&
264 path->getChar(path->getLength() - 1) != '/')
265 path->append('/');
266 path->append(fileName);
267 return path;
268 #endif
271 GString *grabPath(char *fileName) {
272 #ifdef VMS
273 //---------- VMS ----------
274 char *p;
276 if ((p = strrchr(fileName, ']')))
277 return new GString(fileName, p + 1 - fileName);
278 if ((p = strrchr(fileName, ':')))
279 return new GString(fileName, p + 1 - fileName);
280 return new GString();
282 #elif defined(__EMX__) || defined(WIN32)
283 //---------- OS/2+EMX and Win32 ----------
284 char *p;
286 if ((p = strrchr(fileName, '/')))
287 return new GString(fileName, p - fileName);
288 if ((p = strrchr(fileName, '\\')))
289 return new GString(fileName, p - fileName);
290 if ((p = strrchr(fileName, ':')))
291 return new GString(fileName, p + 1 - fileName);
292 return new GString();
294 #elif defined(ACORN)
295 //---------- RISCOS ----------
296 char *p;
298 if ((p = strrchr(fileName, '.')))
299 return new GString(fileName, p - fileName);
300 return new GString();
302 #elif defined(MACOS)
303 //---------- MacOS ----------
304 char *p;
306 if ((p = strrchr(fileName, ':')))
307 return new GString(fileName, p - fileName);
308 return new GString();
310 #else
311 //---------- Unix ----------
312 char *p;
314 if ((p = strrchr(fileName, '/')))
315 return new GString(fileName, p - fileName);
316 return new GString();
317 #endif
320 GBool isAbsolutePath(char *path) {
321 #ifdef VMS
322 //---------- VMS ----------
323 return strchr(path, ':') ||
324 (path[0] == '[' && path[1] != '.' && path[1] != '-');
326 #elif defined(__EMX__) || defined(WIN32)
327 //---------- OS/2+EMX and Win32 ----------
328 return path[0] == '/' || path[0] == '\\' || path[1] == ':';
330 #elif defined(ACORN)
331 //---------- RISCOS ----------
332 return path[0] == '$';
334 #elif defined(MACOS)
335 //---------- MacOS ----------
336 return path[0] != ':';
338 #else
339 //---------- Unix ----------
340 return path[0] == '/';
341 #endif
344 GString *makePathAbsolute(GString *path) {
345 #ifdef VMS
346 //---------- VMS ----------
347 char buf[PATH_MAX+1];
349 if (!isAbsolutePath(path->getCString())) {
350 if (getcwd(buf, sizeof(buf))) {
351 path->insert(0, buf);
354 return path;
356 #elif defined(WIN32)
357 //---------- Win32 ----------
358 char buf[_MAX_PATH];
359 char *fp;
361 buf[0] = '\0';
362 if (!GetFullPathName(path->getCString(), _MAX_PATH, buf, &fp)) {
363 path->clear();
364 return path;
366 path->clear();
367 path->append(buf);
368 return path;
370 #elif defined(ACORN)
371 //---------- RISCOS ----------
372 path->insert(0, '@');
373 return path;
375 #elif defined(MACOS)
376 //---------- MacOS ----------
377 path->del(0, 1);
378 return path;
380 #else
381 //---------- Unix and OS/2+EMX ----------
382 struct passwd *pw;
383 char buf[PATH_MAX+1];
384 GString *s;
385 char *p1, *p2;
386 int n;
388 if (path->getChar(0) == '~') {
389 if (path->getChar(1) == '/' ||
390 #ifdef __EMX__
391 path->getChar(1) == '\\' ||
392 #endif
393 path->getLength() == 1) {
394 path->del(0, 1);
395 s = getHomeDir();
396 path->insert(0, s);
397 delete s;
398 } else {
399 p1 = path->getCString() + 1;
400 #ifdef __EMX__
401 for (p2 = p1; *p2 && *p2 != '/' && *p2 != '\\'; ++p2) ;
402 #else
403 for (p2 = p1; *p2 && *p2 != '/'; ++p2) ;
404 #endif
405 if ((n = p2 - p1) > PATH_MAX)
406 n = PATH_MAX;
407 strncpy(buf, p1, n);
408 buf[n] = '\0';
409 if ((pw = getpwnam(buf))) {
410 path->del(0, p2 - p1 + 1);
411 path->insert(0, pw->pw_dir);
414 } else if (!isAbsolutePath(path->getCString())) {
415 if (getcwd(buf, sizeof(buf))) {
416 #ifndef __EMX__
417 path->insert(0, '/');
418 #endif
419 path->insert(0, buf);
422 return path;
423 #endif
426 time_t getModTime(char *fileName) {
427 #ifdef WIN32
428 //~ should implement this, but it's (currently) only used in xpdf
429 return 0;
430 #else
431 struct stat statBuf;
433 if (stat(fileName, &statBuf)) {
434 return 0;
436 return statBuf.st_mtime;
437 #endif
440 GBool openTempFile(GString **name, FILE **f, char *mode, char *ext) {
441 #if defined(WIN32)
442 //---------- Win32 ----------
443 char *s;
445 if (!(s = _tempnam(getenv("TEMP"), NULL))) {
446 return gFalse;
448 *name = new GString(s);
449 free(s);
450 if (ext) {
451 (*name)->append(ext);
453 if (!(*f = fopen((*name)->getCString(), mode))) {
454 delete (*name);
455 return gFalse;
457 return gTrue;
458 #elif defined(VMS) || defined(__EMX__) || defined(ACORN) || defined(MACOS)
459 //---------- non-Unix ----------
460 char *s;
462 // There is a security hole here: an attacker can create a symlink
463 // with this file name after the tmpnam call and before the fopen
464 // call. I will happily accept fixes to this function for non-Unix
465 // OSs.
466 if (!(s = tmpnam(NULL))) {
467 return gFalse;
469 *name = new GString(s);
470 if (ext) {
471 (*name)->append(ext);
473 if (!(*f = fopen((*name)->getCString(), mode))) {
474 delete (*name);
475 return gFalse;
477 return gTrue;
478 #else
479 //---------- Unix ----------
480 char *s;
481 int fd;
483 if (ext) {
484 #if HAVE_MKSTEMPS
485 if ((s = getenv("TMPDIR"))) {
486 *name = new GString(s);
487 } else {
488 *name = new GString("/tmp");
490 (*name)->append("/XXXXXX")->append(ext);
491 fd = mkstemps((*name)->getCString(), strlen(ext));
492 #else
493 if (!(s = tmpnam(NULL))) {
494 return gFalse;
496 *name = new GString(s);
497 (*name)->append(ext);
498 fd = open((*name)->getCString(), O_WRONLY | O_CREAT | O_EXCL, 0600);
499 #endif
500 } else {
501 #if HAVE_MKSTEMP
502 if ((s = getenv("TMPDIR"))) {
503 *name = new GString(s);
504 } else {
505 *name = new GString("/tmp");
507 (*name)->append("/XXXXXX");
508 fd = mkstemp((*name)->getCString());
509 #else // HAVE_MKSTEMP
510 if (!(s = tmpnam(NULL))) {
511 return gFalse;
513 *name = new GString(s);
514 fd = open((*name)->getCString(), O_WRONLY | O_CREAT | O_EXCL, 0600);
515 #endif // HAVE_MKSTEMP
517 if (fd < 0 || !(*f = fdopen(fd, mode))) {
518 delete *name;
519 return gFalse;
521 return gTrue;
522 #endif
525 GBool executeCommand(char *cmd) {
526 #ifdef VMS
527 return system(cmd) ? gTrue : gFalse;
528 #else
529 return system(cmd) ? gFalse : gTrue;
530 #endif
533 char *getLine(char *buf, int size, FILE *f) {
534 int c, i;
536 i = 0;
537 while (i < size - 1) {
538 if ((c = fgetc(f)) == EOF) {
539 break;
541 buf[i++] = (char)c;
542 if (c == '\x0a') {
543 break;
545 if (c == '\x0d') {
546 c = fgetc(f);
547 if (c == '\x0a' && i < size - 1) {
548 buf[i++] = (char)c;
549 } else if (c != EOF) {
550 ungetc(c, f);
552 break;
555 buf[i] = '\0';
556 if (i == 0) {
557 return NULL;
559 return buf;
562 //------------------------------------------------------------------------
563 // GDir and GDirEntry
564 //------------------------------------------------------------------------
566 GDirEntry::GDirEntry(char *dirPath, char *nameA, GBool doStat) {
567 #ifdef VMS
568 char *p;
569 #elif defined(WIN32)
570 int fa;
571 GString *s;
572 #elif defined(ACORN)
573 #else
574 struct stat st;
575 GString *s;
576 #endif
578 name = new GString(nameA);
579 dir = gFalse;
580 if (doStat) {
581 #ifdef VMS
582 if (!strcmp(nameA, "-") ||
583 ((p = strrchr(nameA, '.')) && !strncmp(p, ".DIR;", 5)))
584 dir = gTrue;
585 #elif defined(ACORN)
586 #else
587 s = new GString(dirPath);
588 appendToPath(s, nameA);
589 #ifdef WIN32
590 fa = GetFileAttributes(s->getCString());
591 dir = (fa != 0xFFFFFFFF && (fa & FILE_ATTRIBUTE_DIRECTORY));
592 #else
593 if (stat(s->getCString(), &st) == 0)
594 dir = S_ISDIR(st.st_mode);
595 #endif
596 delete s;
597 #endif
601 GDirEntry::~GDirEntry() {
602 delete name;
605 GDir::GDir(char *name, GBool doStatA) {
606 path = new GString(name);
607 doStat = doStatA;
608 #if defined(WIN32)
609 GString *tmp;
611 tmp = path->copy();
612 tmp->append("/*.*");
613 hnd = FindFirstFile(tmp->getCString(), &ffd);
614 delete tmp;
615 #elif defined(ACORN)
616 #elif defined(MACOS)
617 #else
618 dir = opendir(name);
619 #ifdef VMS
620 needParent = strchr(name, '[') != NULL;
621 #endif
622 #endif
625 GDir::~GDir() {
626 delete path;
627 #if defined(WIN32)
628 if (hnd) {
629 FindClose(hnd);
630 hnd = NULL;
632 #elif defined(ACORN)
633 #elif defined(MACOS)
634 #else
635 if (dir)
636 closedir(dir);
637 #endif
640 GDirEntry *GDir::getNextEntry() {
641 GDirEntry *e;
643 #if defined(WIN32)
644 if (hnd) {
645 e = new GDirEntry(path->getCString(), ffd.cFileName, doStat);
646 if (hnd && !FindNextFile(hnd, &ffd)) {
647 FindClose(hnd);
648 hnd = NULL;
650 } else {
651 e = NULL;
653 #elif defined(ACORN)
654 #elif defined(MACOS)
655 #elif defined(VMS)
656 struct dirent *ent;
657 e = NULL;
658 if (dir) {
659 if (needParent) {
660 e = new GDirEntry(path->getCString(), "-", doStat);
661 needParent = gFalse;
662 return e;
664 ent = readdir(dir);
665 if (ent) {
666 e = new GDirEntry(path->getCString(), ent->d_name, doStat);
669 #else
670 struct dirent *ent;
671 e = NULL;
672 if (dir) {
673 ent = readdir(dir);
674 if (ent && !strcmp(ent->d_name, ".")) {
675 ent = readdir(dir);
677 if (ent) {
678 e = new GDirEntry(path->getCString(), ent->d_name, doStat);
681 #endif
683 return e;
686 void GDir::rewind() {
687 #ifdef WIN32
688 GString *tmp;
690 if (hnd)
691 FindClose(hnd);
692 tmp = path->copy();
693 tmp->append("/*.*");
694 hnd = FindFirstFile(tmp->getCString(), &ffd);
695 delete tmp;
696 #elif defined(ACORN)
697 #elif defined(MACOS)
698 #else
699 if (dir)
700 rewinddir(dir);
701 #ifdef VMS
702 needParent = strchr(path->getCString(), '[') != NULL;
703 #endif
704 #endif