diff --git a/ConfigureChecks.cmake b/ConfigureChecks.cmake index 6e547ed..9f67b43 100644 --- a/ConfigureChecks.cmake +++ b/ConfigureChecks.cmake @@ -27,6 +27,8 @@ check_include_files(unistd.h HAVE_UNISTD_H) check_function_exists(fseek64 HAVE_FSEEK64) check_function_exists(fseeko HAVE_FSEEKO) check_function_exists(ftell64 HAVE_FTELL64) +check_function_exists(pread64 HAVE_PREAD64) +check_function_exists(lseek64 HAVE_LSEEK64) check_function_exists(gmtime_r HAVE_GMTIME_R) check_function_exists(gettimeofday HAVE_GETTIMEOFDAY) check_function_exists(localtime_r HAVE_LOCALTIME_R) diff --git a/config.h.cmake b/config.h.cmake index cde219f..3e74fad 100644 --- a/config.h.cmake +++ b/config.h.cmake @@ -46,6 +46,12 @@ /* Define to 1 if you have the `ftell64' function. */ #cmakedefine HAVE_FTELL64 1 +/* Define to 1 if you have the `pread64' function. */ +#cmakedefine HAVE_PREAD64 + +/* Define to 1 if you have the `lseek64' function. */ +#cmakedefine HAVE_LSEEK64 1 + /* Defines if gettimeofday is available on your system */ #cmakedefine HAVE_GETTIMEOFDAY 1 diff --git a/configure.ac b/configure.ac index fc77b22..cd4645b 100644 --- a/configure.ac +++ b/configure.ac @@ -264,6 +264,7 @@ AC_CHECK_FUNCS(ftell64, xpdf_cv_func_ftell64=yes, xpdf_cv_func_ftell64=no) if test "$xpdf_cv_func_fseek64" = yes -a "$xpdf_cv_func_ftell64" = yes; then AC_DEFINE(HAVE_FSEEK64) fi +AC_CHECK_FUNCS(pread64 lseek64) dnl Test for zlib AC_ARG_ENABLE([zlib], diff --git a/goo/gfile.cc b/goo/gfile.cc index 7630e20..5d60c65 100644 --- a/goo/gfile.cc +++ b/goo/gfile.cc @@ -585,6 +585,85 @@ Goffset GoffsetMax() { } //------------------------------------------------------------------------ +// GooFile +//------------------------------------------------------------------------ + +#ifdef _WIN32 + +int GooFile::read(char *buf, int n, Goffset offset) const { + DWORD m; + + LARGE_INTEGER largeInteger = {0}; + largeInteger.QuadPart = offset; + + OVERLAPPED overlapped = {0}; + overlapped.Offset = largeInteger.LowPart; + overlapped.OffsetHigh = largeInteger.HighPart; + + return FALSE == ReadFile(handle, buf, n, &m, &overlapped) ? -1 : m; +} + +Goffset GooFile::size() const { + LARGE_INTEGER size = {-1,-1}; + + GetFileSizeEx(handle, &size); + + return size.QuadPart; +} + +GooFile* GooFile::open(const GooString *fileName) { + HANDLE handle = CreateFile(fileName->getCString(), + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL); + + return handle == INVALID_HANDLE_VALUE ? NULL : new GooFile(handle); +} + +GooFile* GooFile::open(const wchar_t *fileName) { + HANDLE handle = CreateFileW(fileName, + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL); + + return handle == INVALID_HANDLE_VALUE ? NULL : new GooFile(handle); +} + +#else + +int GooFile::read(char *buf, int n, Goffset offset) const { +#ifdef HAVE_PREAD64 + return pread64(fd, buf, n, offset); +#else + return pread(fd, buf, n, offset); +#endif +} + +Goffset GooFile::size() const { +#ifdef HAVE_LSEEK64 + return lseek64(fd, 0, SEEK_END); +#else + return lseek(fd, 0, SEEK_END); +#endif +} + +GooFile* GooFile::open(const GooString *fileName) { +#ifdef VMS + int fd = ::open(fileName->getCString(), Q_RDONLY, "ctx=stm"); +#else + int fd = ::open(fileName->getCString(), O_RDONLY); +#endif + + return fd < 0 ? NULL : new GooFile(fd); +} + +#endif // _WIN32 + +//------------------------------------------------------------------------ // GDir and GDirEntry //------------------------------------------------------------------------ diff --git a/goo/gfile.h b/goo/gfile.h index 6787a6e..edb2226 100644 --- a/goo/gfile.h +++ b/goo/gfile.h @@ -122,6 +122,35 @@ extern Goffset Gftell(FILE *f); extern Goffset GoffsetMax(); //------------------------------------------------------------------------ +// GooFile +//------------------------------------------------------------------------ + +class GooFile +{ +public: + int read(char *buf, int n, Goffset offset) const; + Goffset size() const; + + static GooFile *open(const GooString *fileName); + +#ifdef _WIN32 + static GooFile *open(const wchar_t *fileName); + + ~GooFile() { CloseHandle(handle); } + +private: + GooFile(HANDLE handleA): handle(handleA) {} + HANDLE handle; +#else + ~GooFile() { close(fd); } + +private: + GooFile(int fdA) : fd(fdA) {} + int fd; +#endif // _WIN32 +}; + +//------------------------------------------------------------------------ // GDir and GDirEntry //------------------------------------------------------------------------ diff --git a/poppler/GlobalParamsWin.cc b/poppler/GlobalParamsWin.cc index e83c079..984c350 100644 --- a/poppler/GlobalParamsWin.cc +++ b/poppler/GlobalParamsWin.cc @@ -408,9 +408,7 @@ void GlobalParams::setupBaseFonts(char * dir) { const char *dataRoot = popplerDataDir ? popplerDataDir : POPPLER_DATADIR; GooString *fileName = NULL; - struct stat buf; - FILE *file; - int size = 0; + GooFile *file; if (baseFontsInitialized) return; @@ -453,15 +451,9 @@ void GlobalParams::setupBaseFonts(char * dir) fileName = new GooString(dataRoot); fileName->append("/cidfmap"); - if (stat(fileName->getCString(), &buf) == 0) { - size = buf.st_size; - } + // try to open file -#ifdef VMS - file = fopen(fileName->getCString(), "rb", "ctx=stm"); -#else - file = fopen(fileName->getCString(), "rb"); -#endif + file = GooFile::open(fileName); if (file != NULL) { Parser *parser; @@ -470,7 +462,7 @@ void GlobalParams::setupBaseFonts(char * dir) obj1.initNull(); parser = new Parser(NULL, new Lexer(NULL, - new FileStream(file, fileName->getCString(), 0, gFalse, size, &obj1)), + new FileStream(file, 0, gFalse, file->size(), &obj1)), gTrue); obj1.free(); parser->getObj(&obj1); @@ -498,7 +490,7 @@ void GlobalParams::setupBaseFonts(char * dir) parser->getObj(&obj1); } } - fclose(file); + delete file; delete parser; } } diff --git a/poppler/PDFDoc.cc b/poppler/PDFDoc.cc index 46ecea5..9075953 100644 --- a/poppler/PDFDoc.cc +++ b/poppler/PDFDoc.cc @@ -55,6 +55,7 @@ #include #include "goo/gstrtod.h" #include "goo/GooString.h" +#include "goo/gfile.h" #include "poppler-config.h" #include "GlobalParams.h" #include "Page.h" @@ -129,7 +130,6 @@ PDFDoc::PDFDoc() PDFDoc::PDFDoc(GooString *fileNameA, GooString *ownerPassword, GooString *userPassword, void *guiDataA) { Object obj; - Goffset size = 0; #ifdef _WIN32 int n, i; #endif @@ -147,17 +147,8 @@ PDFDoc::PDFDoc(GooString *fileNameA, GooString *ownerPassword, fileNameU[n] = L'\0'; #endif - struct stat buf; - if (stat(fileName->getCString(), &buf) == 0) { - size = buf.st_size; - } - // try to open file -#ifdef VMS - file = fopen(fileName->getCString(), "rb", "ctx=stm"); -#else - file = fopen(fileName->getCString(), "rb"); -#endif + file = GooFile::open(fileName); if (file == NULL) { // fopen() has failed. // Keep a copy of the errno returned by fopen so that it can be @@ -170,7 +161,7 @@ PDFDoc::PDFDoc(GooString *fileNameA, GooString *ownerPassword, // create stream obj.initNull(); - str = new FileStream(file, fileName->getCString(), 0, gFalse, size, &obj); + str = new FileStream(file, 0, gFalse, file->size(), &obj); ok = setup(ownerPassword, userPassword); } @@ -194,26 +185,17 @@ PDFDoc::PDFDoc(wchar_t *fileNameA, int fileNameLen, GooString *ownerPassword, fileNameU[i] = fileNameA[i]; } fileNameU[fileNameLen] = L'\0'; - - + // try to open file // NB: _wfopen is only available in NT - struct _stat buf; - int size = 0; version.dwOSVersionInfoSize = sizeof(version); GetVersionEx(&version); if (version.dwPlatformId == VER_PLATFORM_WIN32_NT) { - if (_wstat(fileNameU, &buf) == 0) { - size = buf.st_size; - } - file = _wfopen(fileNameU, L"rb"); + file = GooFile::open(fileNameU); } else { - if (_stat(fileName->getCString(), &buf) == 0) { - size = buf.st_size; - } - file = fopen(fileName->getCString(), "rb"); + file = GooFile::open(fileName); } - if (!size || !file) { + if (!file) { error(errIO, -1, "Couldn't open file '{0:t}'", fileName); errCode = errOpenFile; return; @@ -221,7 +203,7 @@ PDFDoc::PDFDoc(wchar_t *fileNameA, int fileNameLen, GooString *ownerPassword, // create stream obj.initNull(); - str = new FileStream(file, fileName->getCString(), 0, gFalse, size, &obj); + str = new FileStream(file, 0, gFalse, file->size(), &obj); ok = setup(ownerPassword, userPassword); } @@ -343,7 +325,7 @@ PDFDoc::~PDFDoc() { delete str; } if (file) { - fclose(file); + delete file; } if (fileName) { delete fileName; diff --git a/poppler/PDFDoc.h b/poppler/PDFDoc.h index cc9d2db..616e4af 100644 --- a/poppler/PDFDoc.h +++ b/poppler/PDFDoc.h @@ -49,6 +49,7 @@ #include "Stream.h" class GooString; +class GooFile; class BaseStream; class OutputDev; class Links; @@ -307,7 +308,7 @@ private: #ifdef _WIN32 wchar_t *fileNameU; #endif - FILE *file; + GooFile *file; BaseStream *str; void *guiData; int pdfMajorVersion; diff --git a/poppler/Stream.cc b/poppler/Stream.cc index 6ffd5d3..fa53fb7 100644 --- a/poppler/Stream.cc +++ b/poppler/Stream.cc @@ -750,30 +750,14 @@ GBool StreamPredictor::getNextLine() { } //------------------------------------------------------------------------ -// UniqueFileStream -//------------------------------------------------------------------------ - -UniqueFileStream::UniqueFileStream(FILE *fA, char *fileNameA, Goffset startA, GBool limitedA, - Goffset lengthA, Object *dictA): - FileStream(fA, fileNameA, startA, limitedA, lengthA, dictA) { - f = fopen(fileName, "rb"); -} - -UniqueFileStream::~UniqueFileStream() { - close(); - fclose(f); -} - -//------------------------------------------------------------------------ // FileStream //------------------------------------------------------------------------ -FileStream::FileStream(FILE *fA, char *fileNameA, Goffset startA, GBool limitedA, +FileStream::FileStream(GooFile* fileA, Goffset startA, GBool limitedA, Goffset lengthA, Object *dictA): BaseStream(dictA, lengthA) { - f = fA; - fileName = fileNameA; - start = startA; + file = fileA; + offset = start = startA; limited = limitedA; length = lengthA; bufPtr = bufEnd = buf; @@ -787,17 +771,17 @@ FileStream::~FileStream() { } BaseStream *FileStream::copy() { - return new UniqueFileStream(f, fileName, start, limited, length, &dict); + return new FileStream(file, start, limited, length, &dict); } Stream *FileStream::makeSubStream(Goffset startA, GBool limitedA, Goffset lengthA, Object *dictA) { - return new FileStream(f, fileName, startA, limitedA, lengthA, dictA); + return new FileStream(file, startA, limitedA, lengthA, dictA); } void FileStream::reset() { - savePos = Gftell(f); - Gfseek(f, start, SEEK_SET); + savePos = offset; + offset = start; saved = gTrue; bufPtr = bufEnd = buf; bufPos = start; @@ -805,7 +789,7 @@ void FileStream::reset() { void FileStream::close() { if (saved) { - Gfseek(f, savePos, SEEK_SET); + offset = savePos; saved = gFalse; } } @@ -823,7 +807,8 @@ GBool FileStream::fillBuf() { } else { n = fileStreamBufSize; } - n = fread(buf, 1, n, f); + n = file->read(buf, n, offset); + offset += n; bufEnd = buf + n; if (bufPtr >= bufEnd) { return gFalse; @@ -835,15 +820,13 @@ void FileStream::setPos(Goffset pos, int dir) { Goffset size; if (dir >= 0) { - Gfseek(f, pos, SEEK_SET); - bufPos = pos; + offset = bufPos = pos; } else { - Gfseek(f, 0, SEEK_END); - size = Gftell(f); + size = file->size(); if (pos > size) pos = size; - Gfseek(f, -pos, SEEK_END); - bufPos = Gftell(f); + offset = size - pos; + bufPos = offset; } bufPtr = bufEnd = buf; } diff --git a/poppler/Stream.h b/poppler/Stream.h index dfcd530..d3cf051 100644 --- a/poppler/Stream.h +++ b/poppler/Stream.h @@ -43,6 +43,7 @@ #include "Object.h" #include "goo/GooMutex.h" +class GooFile; class BaseStream; class CachedFile; @@ -443,7 +444,7 @@ private: class FileStream: public BaseStream { public: - FileStream(FILE *fA, char *fileName, Goffset startA, GBool limitedA, + FileStream(GooFile* fileA, Goffset startA, GBool limitedA, Goffset lengthA, Object *dictA); virtual ~FileStream(); virtual BaseStream *copy(); @@ -491,10 +492,9 @@ private: return n; } -protected: - FILE *f; - char *fileName; private: + GooFile* file; + Goffset offset; Goffset start; GBool limited; char buf[fileStreamBufSize]; @@ -505,14 +505,6 @@ private: GBool saved; }; -class UniqueFileStream: public FileStream { -public: - - UniqueFileStream(FILE *fA, char *fileNameA, Goffset startA, GBool limitedA, - Goffset lengthA, Object *dictA); - virtual ~UniqueFileStream(); -}; - //------------------------------------------------------------------------ // CachedFileStream //------------------------------------------------------------------------