fixed windows access violation which occurs if one tries to retrieve
[swftools.git] / pdf2swf / xpdf / gfile.cc
blobb4d88cd1027c53bfe76b2efe10be3f92bc6b5be6
1 //========================================================================
2 //
3 // gfile.cc
4 //
5 // Miscellaneous file and directory name manipulation.
6 //
7 // Copyright 1996-2002 Glyph & Cog, LLC
8 //
9 //========================================================================
11 #include <aconf.h>
12 #include "../../config.h"
14 #ifdef WIN32
15 extern "C" {
16 //# ifndef _MSC_VER
17 //# include <kpathsea/win32lib.h>
18 //# endif
20 #else // !WIN32
21 # if defined(MACOS)
22 # include <sys/stat.h>
23 # elif !defined(ACORN)
24 # include <sys/types.h>
25 # include <sys/stat.h>
26 # include <fcntl.h>
27 # endif
28 # include <limits.h>
29 # include <string.h>
30 # if !defined(VMS) && !defined(ACORN) && !defined(MACOS)
31 # include <pwd.h>
32 # endif
33 # if defined(VMS) && (__DECCXX_VER < 50200000)
34 # include <unixlib.h>
35 # endif
36 #endif // WIN32
37 #include "GString.h"
38 #include "gfile.h"
40 // Some systems don't define this, so just make it something reasonably
41 // large.
42 #ifndef PATH_MAX
43 #define PATH_MAX 1024
44 #endif
46 //------------------------------------------------------------------------
48 GString *getHomeDir() {
49 #ifdef VMS
50 //---------- VMS ----------
51 return new GString("SYS$LOGIN:");
53 #elif defined(__EMX__) || defined(WIN32)
54 //---------- OS/2+EMX and Win32 ----------
55 char *s;
56 GString *ret;
58 if ((s = getenv("HOME")))
59 ret = new GString(s);
60 else
61 ret = new GString(".");
62 return ret;
64 #elif defined(ACORN)
65 //---------- RISCOS ----------
66 return new GString("@");
68 #elif defined(MACOS)
69 //---------- MacOS ----------
70 return new GString(":");
72 #else
73 //---------- Unix ----------
74 char *s;
75 struct passwd *pw;
76 GString *ret;
78 if ((s = getenv("HOME"))) {
79 ret = new GString(s);
80 } else {
81 if ((s = getenv("USER")))
82 pw = getpwnam(s);
83 else
84 pw = getpwuid(getuid());
85 if (pw)
86 ret = new GString(pw->pw_dir);
87 else
88 ret = new GString(".");
90 return ret;
91 #endif
94 GString *getCurrentDir() {
95 char buf[PATH_MAX+1];
97 #if defined(__EMX__)
98 if (_getcwd2(buf, sizeof(buf)))
99 #elif defined(WIN32)
100 if (GetCurrentDirectory(sizeof(buf), buf))
101 #elif defined(ACORN)
102 if (strcpy(buf, "@"))
103 #elif defined(MACOS)
104 if (strcpy(buf, ":"))
105 #else
106 if (getcwd(buf, sizeof(buf)))
107 #endif
108 return new GString(buf);
109 return new GString();
112 GString *appendToPath(GString *path, char *fileName) {
113 #if defined(VMS)
114 //---------- VMS ----------
115 //~ this should handle everything necessary for file
116 //~ requesters, but it's certainly not complete
117 char *p0, *p1, *p2;
118 char *q1;
120 p0 = path->getCString();
121 p1 = p0 + path->getLength() - 1;
122 if (!strcmp(fileName, "-")) {
123 if (*p1 == ']') {
124 for (p2 = p1; p2 > p0 && *p2 != '.' && *p2 != '['; --p2) ;
125 if (*p2 == '[')
126 ++p2;
127 path->del(p2 - p0, p1 - p2);
128 } else if (*p1 == ':') {
129 path->append("[-]");
130 } else {
131 path->clear();
132 path->append("[-]");
134 } else if ((q1 = strrchr(fileName, '.')) && !strncmp(q1, ".DIR;", 5)) {
135 if (*p1 == ']') {
136 path->insert(p1 - p0, '.');
137 path->insert(p1 - p0 + 1, fileName, q1 - fileName);
138 } else if (*p1 == ':') {
139 path->append('[');
140 path->append(']');
141 path->append(fileName, q1 - fileName);
142 } else {
143 path->clear();
144 path->append(fileName, q1 - fileName);
146 } else {
147 if (*p1 != ']' && *p1 != ':')
148 path->clear();
149 path->append(fileName);
151 return path;
153 #elif defined(WIN32)
154 //---------- Win32 ----------
155 GString *tmp;
156 char buf[256];
157 char *fp;
159 tmp = new GString(path);
160 tmp->append('/');
161 tmp->append(fileName);
162 GetFullPathName(tmp->getCString(), sizeof(buf), buf, &fp);
163 delete tmp;
164 path->clear();
165 path->append(buf);
166 return path;
168 #elif defined(ACORN)
169 //---------- RISCOS ----------
170 char *p;
171 int i;
173 path->append(".");
174 i = path->getLength();
175 path->append(fileName);
176 for (p = path->getCString() + i; *p; ++p) {
177 if (*p == '/') {
178 *p = '.';
179 } else if (*p == '.') {
180 *p = '/';
183 return path;
185 #elif defined(MACOS)
186 //---------- MacOS ----------
187 char *p;
188 int i;
190 path->append(":");
191 i = path->getLength();
192 path->append(fileName);
193 for (p = path->getCString() + i; *p; ++p) {
194 if (*p == '/') {
195 *p = ':';
196 } else if (*p == '.') {
197 *p = ':';
200 return path;
202 #elif defined(__EMX__)
203 //---------- OS/2+EMX ----------
204 int i;
206 // appending "." does nothing
207 if (!strcmp(fileName, "."))
208 return path;
210 // appending ".." goes up one directory
211 if (!strcmp(fileName, "..")) {
212 for (i = path->getLength() - 2; i >= 0; --i) {
213 if (path->getChar(i) == '/' || path->getChar(i) == '\\' ||
214 path->getChar(i) == ':')
215 break;
217 if (i <= 0) {
218 if (path->getChar(0) == '/' || path->getChar(0) == '\\') {
219 path->del(1, path->getLength() - 1);
220 } else if (path->getLength() >= 2 && path->getChar(1) == ':') {
221 path->del(2, path->getLength() - 2);
222 } else {
223 path->clear();
224 path->append("..");
226 } else {
227 if (path->getChar(i-1) == ':')
228 ++i;
229 path->del(i, path->getLength() - i);
231 return path;
234 // otherwise, append "/" and new path component
235 if (path->getLength() > 0 &&
236 path->getChar(path->getLength() - 1) != '/' &&
237 path->getChar(path->getLength() - 1) != '\\')
238 path->append('/');
239 path->append(fileName);
240 return path;
242 #else
243 //---------- Unix ----------
244 int i;
246 // appending "." does nothing
247 if (!strcmp(fileName, "."))
248 return path;
250 // appending ".." goes up one directory
251 if (!strcmp(fileName, "..")) {
252 for (i = path->getLength() - 2; i >= 0; --i) {
253 if (path->getChar(i) == '/')
254 break;
256 if (i <= 0) {
257 if (path->getChar(0) == '/') {
258 path->del(1, path->getLength() - 1);
259 } else {
260 path->clear();
261 path->append("..");
263 } else {
264 path->del(i, path->getLength() - i);
266 return path;
269 // otherwise, append "/" and new path component
270 if (path->getLength() > 0 &&
271 path->getChar(path->getLength() - 1) != '/')
272 path->append('/');
273 path->append(fileName);
274 return path;
275 #endif
278 GString *grabPath(char *fileName) {
279 #ifdef VMS
280 //---------- VMS ----------
281 char *p;
283 if ((p = strrchr(fileName, ']')))
284 return new GString(fileName, p + 1 - fileName);
285 if ((p = strrchr(fileName, ':')))
286 return new GString(fileName, p + 1 - fileName);
287 return new GString();
289 #elif defined(__EMX__) || defined(WIN32)
290 //---------- OS/2+EMX and Win32 ----------
291 char *p;
293 if ((p = strrchr(fileName, '/')))
294 return new GString(fileName, p - fileName);
295 if ((p = strrchr(fileName, '\\')))
296 return new GString(fileName, p - fileName);
297 if ((p = strrchr(fileName, ':')))
298 return new GString(fileName, p + 1 - fileName);
299 return new GString();
301 #elif defined(ACORN)
302 //---------- RISCOS ----------
303 char *p;
305 if ((p = strrchr(fileName, '.')))
306 return new GString(fileName, p - fileName);
307 return new GString();
309 #elif defined(MACOS)
310 //---------- MacOS ----------
311 char *p;
313 if ((p = strrchr(fileName, ':')))
314 return new GString(fileName, p - fileName);
315 return new GString();
317 #else
318 //---------- Unix ----------
319 char *p;
321 if ((p = strrchr(fileName, '/')))
322 return new GString(fileName, p - fileName);
323 return new GString();
324 #endif
327 GBool isAbsolutePath(char *path) {
328 #ifdef VMS
329 //---------- VMS ----------
330 return strchr(path, ':') ||
331 (path[0] == '[' && path[1] != '.' && path[1] != '-');
333 #elif defined(__EMX__) || defined(WIN32)
334 //---------- OS/2+EMX and Win32 ----------
335 return path[0] == '/' || path[0] == '\\' || path[1] == ':';
337 #elif defined(ACORN)
338 //---------- RISCOS ----------
339 return path[0] == '$';
341 #elif defined(MACOS)
342 //---------- MacOS ----------
343 return path[0] != ':';
345 #else
346 //---------- Unix ----------
347 return path[0] == '/';
348 #endif
351 GString *makePathAbsolute(GString *path) {
352 #ifdef VMS
353 //---------- VMS ----------
354 char buf[PATH_MAX+1];
356 if (!isAbsolutePath(path->getCString())) {
357 if (getcwd(buf, sizeof(buf))) {
358 path->insert(0, buf);
361 return path;
363 #elif defined(WIN32)
364 //---------- Win32 ----------
365 char buf[_MAX_PATH];
366 char *fp;
368 buf[0] = '\0';
369 if (!GetFullPathName(path->getCString(), _MAX_PATH, buf, &fp)) {
370 path->clear();
371 return path;
373 path->clear();
374 path->append(buf);
375 return path;
377 #elif defined(ACORN)
378 //---------- RISCOS ----------
379 path->insert(0, '@');
380 return path;
382 #elif defined(MACOS)
383 //---------- MacOS ----------
384 path->del(0, 1);
385 return path;
387 #else
388 //---------- Unix and OS/2+EMX ----------
389 struct passwd *pw;
390 char buf[PATH_MAX+1];
391 GString *s;
392 char *p1, *p2;
393 int n;
395 if (path->getChar(0) == '~') {
396 if (path->getChar(1) == '/' ||
397 #ifdef __EMX__
398 path->getChar(1) == '\\' ||
399 #endif
400 path->getLength() == 1) {
401 path->del(0, 1);
402 s = getHomeDir();
403 path->insert(0, s);
404 delete s;
405 } else {
406 p1 = path->getCString() + 1;
407 #ifdef __EMX__
408 for (p2 = p1; *p2 && *p2 != '/' && *p2 != '\\'; ++p2) ;
409 #else
410 for (p2 = p1; *p2 && *p2 != '/'; ++p2) ;
411 #endif
412 if ((n = p2 - p1) > PATH_MAX)
413 n = PATH_MAX;
414 strncpy(buf, p1, n);
415 buf[n] = '\0';
416 if ((pw = getpwnam(buf))) {
417 path->del(0, p2 - p1 + 1);
418 path->insert(0, pw->pw_dir);
421 } else if (!isAbsolutePath(path->getCString())) {
422 if (getcwd(buf, sizeof(buf))) {
423 #ifndef __EMX__
424 path->insert(0, '/');
425 #endif
426 path->insert(0, buf);
429 return path;
430 #endif
433 time_t getModTime(char *fileName) {
434 #ifdef WIN32
435 //~ should implement this, but it's (currently) only used in xpdf
436 return 0;
437 #else
438 struct stat statBuf;
440 if (stat(fileName, &statBuf)) {
441 return 0;
443 return statBuf.st_mtime;
444 #endif
447 static char* getTempDir()
449 #ifdef WIN32
450 char*dir = getenv("TMP");
451 if(!dir) dir = getenv("TEMP");
452 if(!dir) dir = getenv("tmp");
453 if(!dir) dir = getenv("temp");
454 if(!dir) dir = "C:\\";
455 #else
456 char* dir = "/tmp/";
457 #endif
458 return dir;
461 char* mktmpname(char*ptr) {
462 static char tmpbuf[128];
463 char*dir = getTempDir();
464 int l = strlen(dir);
465 char*sep = "";
466 if(!ptr)
467 ptr = tmpbuf;
468 if(l && dir[l-1]!='/' && dir[l-1]!='\\') {
469 #ifdef WIN32
470 sep = "\\";
471 #else
472 sep = "/";
473 #endif
476 // used to be mktemp. This does remove the warnings, but
477 // It's not exactly an improvement.
478 #ifdef HAVE_LRAND48
479 sprintf(ptr, "%s%s%08x%08x",dir,sep,lrand48(),lrand48());
480 #else
481 # ifdef HAVE_RAND
482 sprintf(ptr, "%s%s%08x%08x",dir,sep,rand(),rand());
483 # else
484 static int count = 1;
485 sprintf(ptr, "%s%s%08x%04x%04x",dir,sep,time(0),(unsigned int)tmpbuf^((unsigned int)tmpbuf)>>16,count);
486 count ++;
487 # endif
488 #endif
489 return ptr;
492 GBool openTempFile(GString **name, FILE **f, char *mode, char *ext) {
493 #if defined(WIN32)
494 //---------- Win32 ----------
495 char *s;
496 char buf[_MAX_PATH];
497 char *fp;
499 if (!(s = _tempnam(getenv("TEMP"), NULL))) {
500 return gFalse;
502 *name = new GString(s);
503 free(s);
504 if (ext) {
505 (*name)->append(ext);
507 if (!(*f = fopen((*name)->getCString(), mode))) {
508 delete (*name);
509 return gFalse;
511 return gTrue;
512 #elif defined(VMS) || defined(__EMX__) || defined(ACORN) || defined(MACOS)
513 //---------- non-Unix ----------
514 char *s;
516 // There is a security hole here: an attacker can create a symlink
517 // with this file name after the tmpnam call and before the fopen
518 // call. I will happily accept fixes to this function for non-Unix
519 // OSs.
520 if (!(s = mktmpname(NULL))) { //was: tmpnam
521 return gFalse;
523 *name = new GString(s);
524 if (ext) {
525 (*name)->append(ext);
527 if (!(*f = fopen((*name)->getCString(), mode))) {
528 delete (*name);
529 return gFalse;
531 return gTrue;
532 #else
533 //---------- Unix ----------
534 char *s;
535 int fd;
537 if (ext) {
538 #if HAVE_MKSTEMPS
539 if ((s = getenv("TMPDIR"))) {
540 *name = new GString(s);
541 } else {
542 *name = new GString("/tmp");
544 (*name)->append("/XXXXXX")->append(ext);
545 fd = mkstemps((*name)->getCString(), strlen(ext));
546 #else
547 if (!(s = mktmpname(NULL))) { //was: tmpnam
548 return gFalse;
550 *name = new GString(s);
551 (*name)->append(ext);
552 fd = open((*name)->getCString(), O_WRONLY | O_CREAT | O_EXCL, 0600);
553 #endif
554 } else {
555 #if HAVE_MKSTEMP
556 if ((s = getenv("TMPDIR"))) {
557 *name = new GString(s);
558 } else {
559 *name = new GString("/tmp");
561 (*name)->append("/XXXXXX");
562 fd = mkstemp((*name)->getCString());
563 #else // HAVE_MKSTEMP
564 if (!(s = mktmpname(NULL))) { //was: tmpnam
565 return gFalse;
567 *name = new GString(s);
568 fd = open((*name)->getCString(), O_WRONLY | O_CREAT | O_EXCL, 0600);
569 #endif // HAVE_MKSTEMP
571 if (fd < 0 || !(*f = fdopen(fd, mode))) {
572 delete *name;
573 return gFalse;
575 return gTrue;
576 #endif
579 GBool executeCommand(char *cmd) {
580 #ifdef VMS
581 return system(cmd) ? gTrue : gFalse;
582 #else
583 return system(cmd) ? gFalse : gTrue;
584 #endif
587 char *getLine(char *buf, int size, FILE *f) {
588 int c, i;
590 i = 0;
591 while (i < size - 1) {
592 if ((c = fgetc(f)) == EOF) {
593 break;
595 buf[i++] = (char)c;
596 if (c == '\x0a') {
597 break;
599 if (c == '\x0d') {
600 c = fgetc(f);
601 if (c == '\x0a' && i < size - 1) {
602 buf[i++] = (char)c;
603 } else if (c != EOF) {
604 ungetc(c, f);
606 break;
609 buf[i] = '\0';
610 if (i == 0) {
611 return NULL;
613 return buf;
616 //------------------------------------------------------------------------
617 // GDir and GDirEntry
618 //------------------------------------------------------------------------
620 GDirEntry::GDirEntry(char *dirPath, char *nameA, GBool doStat) {
621 #ifdef VMS
622 char *p;
623 #elif defined(WIN32)
624 int fa;
625 GString *s;
626 #elif defined(ACORN)
627 #else
628 struct stat st;
629 GString *s;
630 #endif
632 name = new GString(nameA);
633 dir = gFalse;
634 if (doStat) {
635 #ifdef VMS
636 if (!strcmp(nameA, "-") ||
637 ((p = strrchr(nameA, '.')) && !strncmp(p, ".DIR;", 5)))
638 dir = gTrue;
639 #elif defined(ACORN)
640 #else
641 s = new GString(dirPath);
642 appendToPath(s, nameA);
643 #ifdef WIN32
644 fa = GetFileAttributes(s->getCString());
645 dir = (fa != 0xFFFFFFFF && (fa & FILE_ATTRIBUTE_DIRECTORY));
646 #else
647 if (stat(s->getCString(), &st) == 0)
648 dir = S_ISDIR(st.st_mode);
649 #endif
650 delete s;
651 #endif
655 GDirEntry::~GDirEntry() {
656 delete name;
659 GDir::GDir(char *name, GBool doStatA) {
660 path = new GString(name);
661 doStat = doStatA;
662 #if defined(WIN32)
663 GString *tmp;
665 tmp = path->copy();
666 tmp->append("/*.*");
667 hnd = FindFirstFile(tmp->getCString(), &ffd);
668 delete tmp;
669 #elif defined(ACORN)
670 #elif defined(MACOS)
671 #else
672 dir = opendir(name);
673 #ifdef VMS
674 needParent = strchr(name, '[') != NULL;
675 #endif
676 #endif
679 GDir::~GDir() {
680 delete path;
681 #if defined(WIN32)
682 if (hnd) {
683 FindClose(hnd);
684 hnd = NULL;
686 #elif defined(ACORN)
687 #elif defined(MACOS)
688 #else
689 if (dir)
690 closedir(dir);
691 #endif
694 GDirEntry *GDir::getNextEntry() {
695 struct dirent *ent;
696 GDirEntry *e;
698 e = NULL;
699 #if defined(WIN32)
700 e = new GDirEntry(path->getCString(), ffd.cFileName, doStat);
701 if (hnd && !FindNextFile(hnd, &ffd)) {
702 FindClose(hnd);
703 hnd = NULL;
705 #elif defined(ACORN)
706 #elif defined(MACOS)
707 #else
708 if (dir) {
709 #ifdef VMS
710 if (needParent) {
711 e = new GDirEntry(path->getCString(), "-", doStat);
712 needParent = gFalse;
713 return e;
715 #endif
716 ent = readdir(dir);
717 #ifndef VMS
718 if (ent && !strcmp(ent->d_name, "."))
719 ent = readdir(dir);
720 #endif
721 if (ent)
722 e = new GDirEntry(path->getCString(), ent->d_name, doStat);
724 #endif
725 return e;
728 void GDir::rewind() {
729 #ifdef WIN32
730 GString *tmp;
732 if (hnd)
733 FindClose(hnd);
734 tmp = path->copy();
735 tmp->append("/*.*");
736 hnd = FindFirstFile(tmp->getCString(), &ffd);
737 #elif defined(ACORN)
738 #elif defined(MACOS)
739 #else
740 if (dir)
741 rewinddir(dir);
742 #ifdef VMS
743 needParent = strchr(path->getCString(), '[') != NULL;
744 #endif
745 #endif