From 835e373b3eeaabcd0621ed6798ab500f37982fae Mon Sep 17 00:00:00 2001 From: Calvin Morrison Date: Wed, 5 Apr 2023 14:13:39 -0400 Subject: xpdf-no-select-disable --- goo/gfile.cc | 779 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 779 insertions(+) create mode 100644 goo/gfile.cc (limited to 'goo/gfile.cc') diff --git a/goo/gfile.cc b/goo/gfile.cc new file mode 100644 index 0000000..9ec8bae --- /dev/null +++ b/goo/gfile.cc @@ -0,0 +1,779 @@ +//======================================================================== +// +// gfile.cc +// +// Miscellaneous file and directory name manipulation. +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef _WIN32 +# undef WIN32_LEAN_AND_MEAN +# include +# include +# include +# include +# include +#else +# if !defined(ACORN) +# include +# include +# include +# endif +# include +# include +# include +# if !defined(VMS) && !defined(ACORN) +# include +# endif +# if defined(VMS) && (__DECCXX_VER < 50200000) +# include +# endif +#endif // _WIN32 +#include "gmem.h" +#include "gmempp.h" +#include "GString.h" +#include "gfile.h" + +// Some systems don't define this, so just make it something reasonably +// large. +#ifndef PATH_MAX +#define PATH_MAX 1024 +#endif + +//------------------------------------------------------------------------ + +GString *getHomeDir() { +#ifdef VMS + //---------- VMS ---------- + return new GString("SYS$LOGIN:"); + +#elif defined(_WIN32) + //---------- Win32 ---------- + char *s; + GString *ret; + + if ((s = getenv("USERPROFILE"))) + ret = new GString(s); + else + ret = new GString("."); + return ret; + +#elif defined(__EMX__) + //---------- OS/2+EMX ---------- + char *s; + GString *ret; + + if ((s = getenv("HOME"))) + ret = new GString(s); + else + ret = new GString("."); + return ret; + +#elif defined(ACORN) + //---------- RISCOS ---------- + return new GString("@"); + +#else + //---------- Unix ---------- + char *s; + struct passwd *pw; + GString *ret; + + if ((s = getenv("HOME"))) { + ret = new GString(s); + } else { + if ((s = getenv("USER"))) + pw = getpwnam(s); + else + pw = getpwuid(getuid()); + if (pw) + ret = new GString(pw->pw_dir); + else + ret = new GString("."); + } + return ret; +#endif +} + +GString *getCurrentDir() { + char buf[PATH_MAX+1]; + +#if defined(__EMX__) + if (_getcwd2(buf, sizeof(buf))) +#elif defined(_WIN32) + if (GetCurrentDirectoryA(sizeof(buf), buf)) +#elif defined(ACORN) + if (strcpy(buf, "@")) +#else + if (getcwd(buf, sizeof(buf))) +#endif + return new GString(buf); + return new GString(); +} + +GString *appendToPath(GString *path, const char *fileName) { +#if defined(VMS) + //---------- VMS ---------- + //~ this should handle everything necessary for file + //~ requesters, but it's certainly not complete + char *p0, *p1, *p2; + char *q1; + + p0 = path->getCString(); + p1 = p0 + path->getLength() - 1; + if (!strcmp(fileName, "-")) { + if (*p1 == ']') { + for (p2 = p1; p2 > p0 && *p2 != '.' && *p2 != '['; --p2) ; + if (*p2 == '[') + ++p2; + path->del(p2 - p0, p1 - p2); + } else if (*p1 == ':') { + path->append("[-]"); + } else { + path->clear(); + path->append("[-]"); + } + } else if ((q1 = strrchr(fileName, '.')) && !strncmp(q1, ".DIR;", 5)) { + if (*p1 == ']') { + path->insert(p1 - p0, '.'); + path->insert(p1 - p0 + 1, fileName, q1 - fileName); + } else if (*p1 == ':') { + path->append('['); + path->append(']'); + path->append(fileName, q1 - fileName); + } else { + path->clear(); + path->append(fileName, q1 - fileName); + } + } else { + if (*p1 != ']' && *p1 != ':') + path->clear(); + path->append(fileName); + } + return path; + +#elif defined(_WIN32) + //---------- Win32 ---------- + GString *tmp; + char buf[256]; + char *fp; + + tmp = new GString(path); + tmp->append('/'); + tmp->append(fileName); + GetFullPathNameA(tmp->getCString(), sizeof(buf), buf, &fp); + delete tmp; + path->clear(); + path->append(buf); + return path; + +#elif defined(ACORN) + //---------- RISCOS ---------- + char *p; + int i; + + path->append("."); + i = path->getLength(); + path->append(fileName); + for (p = path->getCString() + i; *p; ++p) { + if (*p == '/') { + *p = '.'; + } else if (*p == '.') { + *p = '/'; + } + } + return path; + +#elif defined(__EMX__) + //---------- OS/2+EMX ---------- + int i; + + // appending "." does nothing + if (!strcmp(fileName, ".")) + return path; + + // appending ".." goes up one directory + if (!strcmp(fileName, "..")) { + for (i = path->getLength() - 2; i >= 0; --i) { + if (path->getChar(i) == '/' || path->getChar(i) == '\\' || + path->getChar(i) == ':') + break; + } + if (i <= 0) { + if (path->getChar(0) == '/' || path->getChar(0) == '\\') { + path->del(1, path->getLength() - 1); + } else if (path->getLength() >= 2 && path->getChar(1) == ':') { + path->del(2, path->getLength() - 2); + } else { + path->clear(); + path->append(".."); + } + } else { + if (path->getChar(i-1) == ':') + ++i; + path->del(i, path->getLength() - i); + } + return path; + } + + // otherwise, append "/" and new path component + if (path->getLength() > 0 && + path->getChar(path->getLength() - 1) != '/' && + path->getChar(path->getLength() - 1) != '\\') + path->append('/'); + path->append(fileName); + return path; + +#else + //---------- Unix ---------- + int i; + + // appending "." does nothing + if (!strcmp(fileName, ".")) + return path; + + // appending ".." goes up one directory + if (!strcmp(fileName, "..")) { + for (i = path->getLength() - 2; i >= 0; --i) { + if (path->getChar(i) == '/') + break; + } + if (i <= 0) { + if (path->getChar(0) == '/') { + path->del(1, path->getLength() - 1); + } else { + path->clear(); + path->append(".."); + } + } else { + path->del(i, path->getLength() - i); + } + return path; + } + + // otherwise, append "/" and new path component + if (path->getLength() > 0 && + path->getChar(path->getLength() - 1) != '/') + path->append('/'); + path->append(fileName); + return path; +#endif +} + +GString *grabPath(char *fileName) { +#ifdef VMS + //---------- VMS ---------- + char *p; + + if ((p = strrchr(fileName, ']'))) + return new GString(fileName, p + 1 - fileName); + if ((p = strrchr(fileName, ':'))) + return new GString(fileName, p + 1 - fileName); + return new GString(); + +#elif defined(__EMX__) || defined(_WIN32) + //---------- OS/2+EMX and Win32 ---------- + char *p; + + if ((p = strrchr(fileName, '/'))) + return new GString(fileName, (int)(p - fileName)); + if ((p = strrchr(fileName, '\\'))) + return new GString(fileName, (int)(p - fileName)); + if ((p = strrchr(fileName, ':'))) + return new GString(fileName, (int)(p + 1 - fileName)); + return new GString(); + +#elif defined(ACORN) + //---------- RISCOS ---------- + char *p; + + if ((p = strrchr(fileName, '.'))) + return new GString(fileName, p - fileName); + return new GString(); + +#else + //---------- Unix ---------- + char *p; + + if ((p = strrchr(fileName, '/'))) + return new GString(fileName, (int)(p - fileName)); + return new GString(); +#endif +} + +GBool isAbsolutePath(char *path) { +#ifdef VMS + //---------- VMS ---------- + return strchr(path, ':') || + (path[0] == '[' && path[1] != '.' && path[1] != '-'); + +#elif defined(__EMX__) || defined(_WIN32) + //---------- OS/2+EMX and Win32 ---------- + return path[0] == '/' || path[0] == '\\' || path[1] == ':'; + +#elif defined(ACORN) + //---------- RISCOS ---------- + return path[0] == '$'; + +#else + //---------- Unix ---------- + return path[0] == '/'; +#endif +} + +GString *makePathAbsolute(GString *path) { +#ifdef VMS + //---------- VMS ---------- + char buf[PATH_MAX+1]; + + if (!isAbsolutePath(path->getCString())) { + if (getcwd(buf, sizeof(buf))) { + path->insert(0, buf); + } + } + return path; + +#elif defined(_WIN32) + //---------- Win32 ---------- + char buf[MAX_PATH]; + char *fp; + + buf[0] = '\0'; + if (!GetFullPathNameA(path->getCString(), MAX_PATH, buf, &fp)) { + path->clear(); + return path; + } + path->clear(); + path->append(buf); + return path; + +#elif defined(ACORN) + //---------- RISCOS ---------- + path->insert(0, '@'); + return path; + +#else + //---------- Unix and OS/2+EMX ---------- + struct passwd *pw; + char buf[PATH_MAX+1]; + GString *s; + char *p1, *p2; + int n; + + if (path->getChar(0) == '~') { + if (path->getChar(1) == '/' || +#ifdef __EMX__ + path->getChar(1) == '\\' || +#endif + path->getLength() == 1) { + path->del(0, 1); + s = getHomeDir(); + path->insert(0, s); + delete s; + } else { + p1 = path->getCString() + 1; +#ifdef __EMX__ + for (p2 = p1; *p2 && *p2 != '/' && *p2 != '\\'; ++p2) ; +#else + for (p2 = p1; *p2 && *p2 != '/'; ++p2) ; +#endif + if ((n = (int)(p2 - p1)) > PATH_MAX) + n = PATH_MAX; + strncpy(buf, p1, n); + buf[n] = '\0'; + if ((pw = getpwnam(buf))) { + path->del(0, (int)(p2 - p1 + 1)); + path->insert(0, pw->pw_dir); + } + } + } else if (!isAbsolutePath(path->getCString())) { + if (getcwd(buf, sizeof(buf))) { +#ifndef __EMX__ + path->insert(0, '/'); +#endif + path->insert(0, buf); + } + } + return path; +#endif +} + +GBool pathIsFile(const char *path) { +#ifdef _WIN32 + wchar_t wPath[winMaxLongPath + 1]; + fileNameToUCS2(path, wPath, winMaxLongPath + 1); + DWORD attr = GetFileAttributesW(wPath); + return attr != INVALID_FILE_ATTRIBUTES && + !(attr & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_DEVICE)); +#else + struct stat statBuf; + return stat(path, &statBuf) == 0 && S_ISREG(statBuf.st_mode); +#endif +} + +time_t getModTime(char *fileName) { +#ifdef _WIN32 + //~ should implement this, but it's (currently) only used in xpdf + return 0; +#else + struct stat statBuf; + + if (stat(fileName, &statBuf)) { + return 0; + } + return statBuf.st_mtime; +#endif +} + +GBool openTempFile(GString **name, FILE **f, + const char *mode, const char *ext) { +#if defined(_WIN32) + //---------- Win32 ---------- + char tempPath[MAX_PATH + 1]; + GString *s, *s2; + FILE *f2; + DWORD n; + int t, i; + + // this has the standard race condition problem, but I haven't found + // a better way to generate temp file names with extensions on + // Windows + n = GetTempPathA(sizeof(tempPath), tempPath); + if (n > 0 && n <= sizeof(tempPath)) { + s = new GString(tempPath); + if (tempPath[n-1] != '\\') { + s->append('\\'); + } + } else { + s = new GString(".\\"); + } + s->appendf("xpdf_{0:d}_{1:d}_", + (int)GetCurrentProcessId(), (int)GetCurrentThreadId()); + t = (int)time(NULL); + for (i = 0; i < 1000; ++i) { + s2 = GString::format("{0:t}{1:d}", s, t + i); + if (ext) { + s2->append(ext); + } + if (!(f2 = fopen(s2->getCString(), "r"))) { + if (!(f2 = fopen(s2->getCString(), mode))) { + delete s2; + delete s; + return gFalse; + } + *name = s2; + *f = f2; + delete s; + return gTrue; + } + fclose(f2); + delete s2; + } + delete s; + return gFalse; +#elif defined(VMS) || defined(__EMX__) || defined(ACORN) + //---------- non-Unix ---------- + char *s; + + // There is a security hole here: an attacker can create a symlink + // with this file name after the tmpnam call and before the fopen + // call. I will happily accept fixes to this function for non-Unix + // OSs. + if (!(s = tmpnam(NULL))) { + return gFalse; + } + *name = new GString(s); + if (ext) { + (*name)->append(ext); + } + if (!(*f = fopen((*name)->getCString(), mode))) { + delete (*name); + *name = NULL; + return gFalse; + } + return gTrue; +#else + //---------- Unix ---------- + char *s; + int fd; + + if (ext) { +#if HAVE_MKSTEMPS + if ((s = getenv("TMPDIR"))) { + *name = new GString(s); + } else { + *name = new GString("/tmp"); + } + (*name)->append("/XXXXXX")->append(ext); + fd = mkstemps((*name)->getCString(), (int)strlen(ext)); +#else + if (!(s = tmpnam(NULL))) { + return gFalse; + } + *name = new GString(s); + (*name)->append(ext); + fd = open((*name)->getCString(), O_WRONLY | O_CREAT | O_EXCL, 0600); +#endif + } else { +#if HAVE_MKSTEMP + if ((s = getenv("TMPDIR"))) { + *name = new GString(s); + } else { + *name = new GString("/tmp"); + } + (*name)->append("/XXXXXX"); + fd = mkstemp((*name)->getCString()); +#else // HAVE_MKSTEMP + if (!(s = tmpnam(NULL))) { + return gFalse; + } + *name = new GString(s); + fd = open((*name)->getCString(), O_WRONLY | O_CREAT | O_EXCL, 0600); +#endif // HAVE_MKSTEMP + } + if (fd < 0 || !(*f = fdopen(fd, mode))) { + delete *name; + *name = NULL; + return gFalse; + } + return gTrue; +#endif +} + +GBool createDir(char *path, int mode) { +#ifdef _WIN32 + return !_mkdir(path); +#else + return !mkdir(path, mode); +#endif +} + +GBool executeCommand(char *cmd) { +#ifdef VMS + return system(cmd) ? gTrue : gFalse; +#else + return system(cmd) ? gFalse : gTrue; +#endif +} + +#ifdef _WIN32 +GString *fileNameToUTF8(char *path) { + GString *s; + char *p; + + s = new GString(); + for (p = path; *p; ++p) { + if (*p & 0x80) { + s->append((char)(0xc0 | ((*p >> 6) & 0x03))); + s->append((char)(0x80 | (*p & 0x3f))); + } else { + s->append(*p); + } + } + return s; +} + +GString *fileNameToUTF8(wchar_t *path) { + GString *s; + wchar_t *p; + + s = new GString(); + for (p = path; *p; ++p) { + if (*p < 0x80) { + s->append((char)*p); + } else if (*p < 0x800) { + s->append((char)(0xc0 | ((*p >> 6) & 0x1f))); + s->append((char)(0x80 | (*p & 0x3f))); + } else { + s->append((char)(0xe0 | ((*p >> 12) & 0x0f))); + s->append((char)(0x80 | ((*p >> 6) & 0x3f))); + s->append((char)(0x80 | (*p & 0x3f))); + } + } + return s; +} + +wchar_t *fileNameToUCS2(const char *path, wchar_t *out, size_t outSize) { + const char *p; + size_t i; + + for (p = path, i = 0; *p && i < outSize - 1; ++i) { + if ((p[0] & 0xe0) == 0xc0 && + p[1] && (p[1] & 0xc0) == 0x80) { + out[i] = (wchar_t)(((p[0] & 0x1f) << 6) | + (p[1] & 0x3f)); + p += 2; + } else if ((p[0] & 0xf0) == 0xe0 && + (p[1] & 0xc0) == 0x80 && + (p[2] & 0xc0) == 0x80) { + out[i] = (wchar_t)(((p[0] & 0x0f) << 12) | + ((p[1] & 0x3f) << 6) | + (p[2] & 0x3f)); + p += 3; + } else { + out[i] = (wchar_t)(p[0] & 0xff); + p += 1; + } + } + out[i] = (wchar_t)0; + return out; +} +#endif + +FILE *openFile(const char *path, const char *mode) { +#if defined(_WIN32) + wchar_t wPath[winMaxLongPath + 1]; + wchar_t wMode[8]; + int i; + + fileNameToUCS2(path, wPath, winMaxLongPath + 1); + for (i = 0; mode[i] && i < sizeof(wMode)/sizeof(wchar_t) - 1; ++i) { + wMode[i] = (wchar_t)(mode[i] & 0xff); + } + wMode[i] = (wchar_t)0; + readWindowsShortcut(wPath, winMaxLongPath + 1); + return _wfopen(wPath, wMode); +#elif defined(VMS) + return fopen(path, mode, "ctx=stm"); +#else + return fopen(path, mode); +#endif +} + +#ifdef _WIN32 +void readWindowsShortcut(wchar_t *wPath, size_t wPathSize) { + size_t n = wcslen(wPath); + if (n < 4 || wcscmp(wPath + n - 4, L".lnk")) { + return; + } + IShellLinkW *shellLink; + HRESULT hres; + hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, + IID_IShellLinkW, (LPVOID *)&shellLink); + bool needCoUninit = false; + if (hres == CO_E_NOTINITIALIZED) { + CoInitialize(NULL); + needCoUninit = true; + hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, + IID_IShellLinkW, (LPVOID *)&shellLink); + } + if (FAILED(hres)) { + return; + } + IPersistFile *persistFile; + hres = shellLink->QueryInterface(IID_IPersistFile, (LPVOID *)&persistFile); + if (FAILED(hres)) { + return; + } + hres = persistFile->Load(wPath, STGM_READ); + if (FAILED(hres)) { + fprintf(stderr, "IPersistFile.Load failed: 0x%08x\n", hres); + exit(1); + } + wchar_t target[winMaxLongPath + 1]; + hres = shellLink->GetPath(target, winMaxLongPath + 1, NULL, 0); + if (FAILED(hres)) { + return; + } + shellLink->Release(); + if (needCoUninit) { + CoUninitialize(); + } + if (wcslen(target) > wPathSize - 1) { + return; + } + wcscpy(wPath, target); +} +#endif + +int makeDir(const char *path, int mode) { +#ifdef _WIN32 + wchar_t wPath[winMaxLongPath + 1]; + return _wmkdir(fileNameToUCS2(path, wPath, winMaxLongPath + 1)); +#else + return mkdir(path, (mode_t)mode); +#endif +} + +char *getLine(char *buf, int size, FILE *f) { + int c, i; + + i = 0; + while (i < size - 1) { + if ((c = fgetc(f)) == EOF) { + break; + } + buf[i++] = (char)c; + if (c == '\x0a') { + break; + } + if (c == '\x0d') { + c = fgetc(f); + if (c == '\x0a' && i < size - 1) { + buf[i++] = (char)c; + } else if (c != EOF) { + ungetc(c, f); + } + break; + } + } + buf[i] = '\0'; + if (i == 0) { + return NULL; + } + return buf; +} + +int gfseek(FILE *f, GFileOffset offset, int whence) { +#if HAVE_FSEEKO + return fseeko(f, offset, whence); +#elif HAVE_FSEEK64 + return fseek64(f, offset, whence); +#elif HAVE_FSEEKI64 + return _fseeki64(f, offset, whence); +#else + return fseek(f, offset, whence); +#endif +} + +GFileOffset gftell(FILE *f) { +#if HAVE_FSEEKO + return ftello(f); +#elif HAVE_FSEEK64 + return ftell64(f); +#elif HAVE_FSEEKI64 + return _ftelli64(f); +#else + return ftell(f); +#endif +} + +void fixCommandLine(int *argc, char **argv[]) { +#ifdef _WIN32 + int argcw; + wchar_t **argvw; + GString *arg; + int i; + + argvw = CommandLineToArgvW(GetCommandLineW(), &argcw); + if (!argvw || argcw < 0) { + return; + } + + *argc = argcw; + + *argv = (char **)gmallocn(argcw + 1, sizeof(char *)); + for (i = 0; i < argcw; ++i) { + arg = fileNameToUTF8(argvw[i]); + (*argv)[i] = copyString(arg->getCString()); + delete arg; + } + (*argv)[argcw] = NULL; + + LocalFree(argvw); +#endif +} -- cgit v1.2.3