/*---------------------------------------------------------------------------* | PDFlib - A library for generating PDF on the fly | +---------------------------------------------------------------------------+ | Copyright (c) 1997-2005 Thomas Merz and PDFlib GmbH. All rights reserved. | +---------------------------------------------------------------------------+ | | | This software is subject to the PDFlib license. It is NOT in the | | public domain. Extended versions and commercial licenses are | | available, please check http://www.pdflib.com. | | | *---------------------------------------------------------------------------*/ /* $Id: pc_file.c,v 1.1 2006-05-04 16:36:51 brugno Exp $ * * Various file routines * */ #include #include "pc_util.h" #include "pc_md5.h" #include "pc_file.h" /* headers for getpid() or _getpid(). */ #if defined(WIN32) #define WIN32_LEAN_AND_MEAN #include #include #include #else #if defined(MAC) #include #else #include #include #endif #endif #ifndef WINCE #include #else #include #endif /* platform independent wrapper functions for 64-bit file handling. */ int pdc__fseek(FILE *fp, pdc_off_t offset, int whence) { #if defined(_LARGEFILE_SOURCE) #if defined(WIN32) switch (whence) { case SEEK_SET: return fsetpos(fp, &offset); case SEEK_CUR: { pdc_off_t pos; fgetpos(fp, &pos); pos += offset; return fsetpos(fp, &pos); } case SEEK_END: { pdc_off_t pos, len; pos = _telli64(fileno(fp)); _lseeki64(fileno(fp), 0, SEEK_END); len = _telli64(fileno(fp)); _lseeki64(fileno(fp), pos, SEEK_SET); len += offset; return fsetpos(fp, &len); } default: return -1; } #else return fseeko(fp, offset, whence); #endif #else return fseek(fp, offset, whence); #endif } pdc_off_t pdc__ftell(FILE *fp) { #if defined(_LARGEFILE_SOURCE) #if defined(WIN32) pdc_off_t pos; fgetpos(fp, &pos); return pos; #else return ftello(fp); #endif #else return ftell(fp); #endif } size_t pdc__fread(void *ptr, size_t size, size_t nmemb, FILE *fp) { return fread(ptr, size, nmemb, fp); } size_t pdc__fwrite(void *ptr, size_t size, size_t nmemb, FILE *fp) { return fwrite(ptr, size, nmemb, fp); } int pdc__fgetc(FILE *fp) { return fgetc(fp); } int pdc__feof(FILE *fp) { return feof(fp); } struct pdc_file_s { pdc_core *pdc; /* pdcore struct */ char *filename; /* file name */ FILE *fp; /* file struct or NULL. Then data != NULL: */ const pdc_byte *data; /* file data or NULL. Then fp != NULL */ const pdc_byte *end; /* first byte above data buffer */ const pdc_byte *pos; /* current file position in data buffer */ }; FILE * pdc_get_fileptr(pdc_file *sfp) { return sfp->fp; } #if defined(_MSC_VER) && defined(_MANAGED) #pragma unmanaged #endif int pdc_get_fopen_errnum(pdc_core *pdc, int errnum) { int outnum = errnum, isread; (void) pdc; isread = (errnum == PDC_E_IO_RDOPEN); #if defined(MVS) switch (errno) { case 49: outnum = isread ? PDC_E_IO_RDOPEN_NF : PDC_E_IO_WROPEN_NF; } return outnum; #elif defined(WIN32) { DWORD lasterror = GetLastError(); switch (lasterror) { case ERROR_FILE_NOT_FOUND: outnum = isread ? PDC_E_IO_RDOPEN_NF : PDC_E_IO_WROPEN_NF; break; case ERROR_ACCESS_DENIED: case ERROR_INVALID_PASSWORD: case ERROR_NETWORK_ACCESS_DENIED: outnum = isread ? PDC_E_IO_RDOPEN_PD : PDC_E_IO_WROPEN_PD; break; case ERROR_INVALID_NAME: outnum = isread ? PDC_E_IO_RDOPEN_NF : PDC_E_IO_WROPEN_IS; break; case ERROR_PATH_NOT_FOUND: case ERROR_INVALID_DRIVE: case ERROR_BAD_NETPATH: case ERROR_BAD_UNIT: outnum = isread ? PDC_E_IO_RDOPEN_NF : PDC_E_IO_WROPEN_NP; break; case ERROR_TOO_MANY_OPEN_FILES: case ERROR_SHARING_BUFFER_EXCEEDED: outnum = isread ? PDC_E_IO_RDOPEN_TM : PDC_E_IO_WROPEN_TM; break; case ERROR_FILE_EXISTS: outnum = PDC_E_IO_WROPEN_AE; break; case ERROR_BUFFER_OVERFLOW: outnum = PDC_E_IO_WROPEN_TL; break; case ERROR_WRITE_FAULT: case ERROR_CANNOT_MAKE: outnum = PDC_E_IO_WROPEN_NC; break; case ERROR_HANDLE_DISK_FULL: case ERROR_DISK_FULL: outnum = PDC_E_IO_WROPEN_NS; break; case ERROR_SHARING_VIOLATION: outnum = isread ? PDC_E_IO_RDOPEN_SV : PDC_E_IO_WROPEN_SV; break; } if (lasterror) { errno = (int) lasterror; return outnum; } /* if lasterror == 0 we must look for errno (see .NET) */ } #endif /* WIN32 */ switch (errno) { #ifdef EACCES case EACCES: outnum = isread ? PDC_E_IO_RDOPEN_PD : PDC_E_IO_WROPEN_PD; break; #endif #ifdef EMACOSERR case EMACOSERR: #if defined(MAC) switch (__MacOSErrNo) { case fnfErr: case dirNFErr: case resFNotFound: case afpDirNotFound: outnum = isread ? PDC_E_IO_RDOPEN_NF : PDC_E_IO_WROPEN_NF; break; case permErr: case wrPermErr: case wPrErr: case afpAccessDenied: case afpVolLocked: outnum = isread ? PDC_E_IO_RDOPEN_PD : PDC_E_IO_WROPEN_PD; break; case nsvErr: case afpObjectTypeErr: outnum = isread ? PDC_E_IO_RDOPEN_NF : PDC_E_IO_WROPEN_IS; break; case tmfoErr: case afpTooManyFilesOpen: outnum = isread ? PDC_E_IO_RDOPEN_TM : PDC_E_IO_WROPEN_TM; break; case opWrErr: outnum = PDC_E_IO_WROPEN_AE; break; case dirFulErr: case dskFulErr: case afpDiskFull: outnum = PDC_E_IO_WROPEN_NS; break; case fLckdErr: case afpLockErr: outnum = isread ? PDC_E_IO_RDOPEN_SV : PDC_E_IO_WROPEN_SV; break; default: break; } if (__MacOSErrNo) { return outnum; } #endif break; #endif #ifdef ENOENT case ENOENT: outnum = isread ? PDC_E_IO_RDOPEN_NF : PDC_E_IO_WROPEN_NF; break; #endif #ifdef EMFILE case EMFILE: outnum = isread ? PDC_E_IO_RDOPEN_TM : PDC_E_IO_WROPEN_TM; break; #endif #ifdef ENFILE case ENFILE: outnum = isread ? PDC_E_IO_RDOPEN_TM : PDC_E_IO_WROPEN_TM; break; #endif #ifdef EISDIR case EISDIR: outnum = isread ? PDC_E_IO_RDOPEN_ID : PDC_E_IO_WROPEN_ID; break; #endif #ifdef EEXIST case EEXIST: outnum = PDC_E_IO_WROPEN_AE; break; #endif #ifdef ENAMETOOLONG case ENAMETOOLONG: outnum = PDC_E_IO_WROPEN_TL; break; #endif #ifdef ENOSPC case ENOSPC: outnum = PDC_E_IO_WROPEN_NS; break; #endif default: /* observed on Solaris */ if (errno == 0) { outnum = isread ? PDC_E_IO_RDOPEN_TM : PDC_E_IO_WROPEN_TM; break; } outnum = errnum; break; } return outnum; } #if defined(_MSC_VER) && defined(_MANAGED) #pragma managed #endif void pdc_set_fopen_errmsg(pdc_core *pdc, int errnum, const char *qualifier, const char *filename) { const char *stemp = NULL; errnum = pdc_get_fopen_errnum(pdc, errnum); if (errnum == PDC_E_IO_RDOPEN) errnum = PDC_E_IO_RDOPEN_CODE; else if (errnum == PDC_E_IO_WROPEN) errnum = PDC_E_IO_WROPEN_CODE; if (errnum == PDC_E_IO_RDOPEN_CODE || errnum == PDC_E_IO_WROPEN_CODE) { #if defined(EMACOSERR) && defined(MAC) errno = (int) __MacOSErrNo; #endif stemp = pdc_errprintf(pdc, "%d", errno); } pdc_set_errmsg(pdc, errnum, qualifier, filename, stemp, 0); } static void pdc_logg_openclose(pdc_core *pdc, FILE *fp, pdc_bool opened) { if (pdc_trace_protocol_is_enabled(pdc, 3, trc_filesearch)) { int errno2 = 0; #if defined(WIN32) errno2 = (int) GetLastError(); #elif defined(MAC) errno2 = __MacOSErrNo; #endif pdc_trace(pdc, "\t%p", fp); if (opened) pdc_trace(pdc, " opened"); else pdc_trace(pdc, " closed"); #if PDC_FILENO_EXISTS if (fp != NULL && opened) pdc_trace(pdc, ", fileno=%d", fileno(fp)); #endif pdc_trace(pdc, ", errno=%d", errno); if (errno2 != 0) pdc_trace(pdc, ", errno2=%d", errno2); pdc_trace(pdc, "\n"); } } void * pdc_read_file(pdc_core *pdc, FILE *fp, pdc_off_t *o_filelen, int incore) { static const char fn[] = "pdc_read_file"; pdc_off_t filelen = 0, len = 0; char *content = NULL; #if !defined(MVS) || !defined(I370) pdc__fseek(fp, 0, SEEK_END); filelen = pdc__ftell(fp); pdc__fseek(fp, 0, SEEK_SET); if (incore && filelen) { content = (char *) pdc_malloc(pdc, (size_t) (filelen + 1), fn); len = (pdc_off_t) pdc__fread(content, 1, (size_t) filelen, fp); if (len != filelen) { pdc_free(pdc, content); filelen = 0; content = NULL; } } #endif if (content) content[filelen] = 0; *o_filelen = filelen; return (void *) content; } FILE * pdc_wfopen(pdc_core *pdc, const char *filename, const char *mode) { FILE *fp = NULL; #if defined(PDC_UNICODE_FILENAME) pdc_byte *outfilename = NULL; pdc_text_format nameformat = pdc_utf8; pdc_text_format targetnameformat = pdc_utf16; int len = (int) strlen(filename); int outlen = 0; /* convert filename from UTF-8 to UTF-16 or Latin-1 */ pdc_convert_string(pdc, nameformat, 0, NULL, (pdc_byte *) filename, len, &targetnameformat, NULL, &outfilename, &outlen, PDC_CONV_TRYBYTES, pdc_true); if (targetnameformat == pdc_bytes) { fp = fopen((const char *) outfilename, mode); } else { wchar_t wmode[8]; int i; len = (int) strlen(mode); for (i = 0; i < len; i++) wmode[i] = (wchar_t) mode[i]; wmode[len] = 0; fp = _wfopen((wchar_t *) outfilename, wmode); } pdc_free(pdc, outfilename); #else (void) pdc; fp = fopen(filename, mode); #endif pdc_logg_openclose(pdc, fp, pdc_true); return fp; } pdc_file * pdc_fopen(pdc_core *pdc, const char *filename, const char *qualifier, const pdc_byte *data, size_t size, int flags) { static const char fn[] = "pdc_fopen"; pdc_file *sfile; sfile = (pdc_file *) pdc_calloc(pdc, sizeof(pdc_file), fn); if (data) { sfile->data = data; sfile->pos = sfile->data; sfile->end = sfile->data + size; } else { sfile->fp = pdc_wfopen(pdc, filename, (flags & PDC_FILE_BINARY) ? READBMODE : READTMODE); if (sfile->fp == NULL) { pdc_free(pdc, sfile); if (qualifier == NULL) qualifier = ""; pdc_set_fopen_errmsg(pdc, PDC_E_IO_RDOPEN, qualifier, filename); return NULL; } } sfile->pdc = pdc; sfile->filename = pdc_strdup(pdc, filename); return sfile; } pdc_bool pdc_file_isvirtual(pdc_file *sfp) { return sfp->fp ? pdc_false : pdc_true; } char * pdc_file_name(pdc_file *sfp) { return sfp->filename; } pdc_core * pdc_file_getpdc(pdc_file *sfp) { return sfp->pdc; } pdc_off_t pdc_file_size(pdc_file *sfp) { pdc_off_t filelen; if (sfp->fp) { pdc_off_t pos = pdc__ftell(sfp->fp); pdc_read_file(sfp->pdc, sfp->fp, &filelen, 0); pdc__fseek(sfp->fp, pos, SEEK_SET); } else filelen = (pdc_off_t) (sfp->end - sfp->data); return filelen; } const void * pdc_freadall(pdc_file *sfp, size_t *filelen, pdc_bool *ismem) { pdc_off_t flen; /* TODO2GB: >2GB on 32-bit platforms? */ if (sfp->fp) { const void *result = pdc_read_file(sfp->pdc, sfp->fp, &flen, 1); if (ismem) *ismem = pdc_false; *filelen = (size_t) flen; return result; } if (ismem) *ismem = pdc_true; *filelen = (size_t) (sfp->end - sfp->data); return sfp->data; } static int pdc_fgetc_e(pdc_file *sfp) { int c = pdc_fgetc(sfp); return c; } char * pdc_fgetline(char *s, int size, pdc_file *sfp) { int i, c; c = pdc_fgetc_e(sfp); if (c == EOF) return NULL; size--; for (i = 0; i < size; i++) { if (c == '\n' || c == '\r' || c == EOF) break; s[i] = (char) c; c = pdc_fgetc_e(sfp); } s[i] = 0; /* Skip windows line end \r\n */ if (c == '\r') { c = pdc_fgetc_e(sfp); if (c != '\n' && c != EOF) { if (sfp->fp) ungetc(c, sfp->fp); else pdc_fseek(sfp, -1, SEEK_CUR); } } return s; } /* * Emulation of C file functions - relevant for PDFlib */ pdc_off_t pdc_ftell(pdc_file *sfp) { if (sfp->fp) return pdc__ftell(sfp->fp); return (pdc_off_t) (sfp->pos - sfp->data); } int pdc_fseek(pdc_file *sfp, pdc_off_t offset, int whence) { if (sfp->fp) return pdc__fseek(sfp->fp, offset, whence); switch (whence) { case SEEK_SET: if (sfp->data + offset > sfp->end) return -1; sfp->pos = sfp->data + offset; break; case SEEK_CUR: if (sfp->pos + offset > sfp->end) return -1; sfp->pos += offset; break; case SEEK_END: if (sfp->end + offset > sfp->end) return -1; sfp->pos = sfp->end + offset; break; } return 0; } size_t pdc_fread(void *ptr, size_t size, size_t nmemb, pdc_file *sfp) { size_t nbytes = 0; if (sfp->fp) return pdc__fread(ptr, size, nmemb, sfp->fp); nbytes = size * nmemb; if (sfp->pos + nbytes > sfp->end) { nbytes = (size_t) (sfp->end - sfp->pos); nmemb = nbytes / size; nbytes = nmemb *size; } memcpy(ptr, sfp->pos, nbytes); sfp->pos += nbytes; return nmemb; } int pdc_fgetc(pdc_file *sfp) { int ch = 0; if (sfp->fp) return pdc__fgetc(sfp->fp); if (sfp->pos < sfp->end) { ch = (int) *sfp->pos; sfp->pos++; } else { ch = EOF; } return ch; } int pdc_feof(pdc_file *sfp) { if (sfp->fp) return pdc__feof(sfp->fp); return (sfp->pos >= sfp->end) ? 1 : 0; } void pdc_wfclose(pdc_core *pdc, FILE *fp) { fclose(fp); pdc_logg_openclose(pdc, fp, pdc_false); } void pdc_fclose(pdc_file *sfp) { if (sfp) { if (sfp->fp) { pdc_wfclose(sfp->pdc, sfp->fp); sfp->fp = NULL; } if (sfp->filename) { pdc_free(sfp->pdc, sfp->filename); sfp->filename = NULL; } pdc_free(sfp->pdc, sfp); } } /* * Concatenating a directory name with a file base name to a full valid * file name. On MVS platforms an extension at the end of basename * will be discarded. */ void pdc_file_fullname(const char *dirname, const char *basename, char *fullname) { const char *pathsep = PDC_PATHSEP; #ifdef MVS pdc_bool lastterm = pdc_false; #endif if (!dirname || !dirname[0]) { strcpy(fullname, basename); } else { fullname[0] = 0; #ifdef MVS if (strncmp(dirname, PDC_FILEQUOT, 1)) strcat(fullname, PDC_FILEQUOT); #endif strcat(fullname, dirname); #ifdef VMS /* look for logical name or whose result */ if(getenv(dirname)) pathsep = PDC_PATHSEP_LOG; else if (fullname[strlen(fullname)-1] == ']') pathsep = ""; #endif strcat(fullname, pathsep); strcat(fullname, basename); #ifdef MVS lastterm = pdc_true; #endif } #ifdef MVS { int ie, len; len = strlen(fullname); for (ie = len - 1; ie >= 0; ie--) { if (fullname[ie] == pathsep[0]) break; if (fullname[ie] == '.') { fullname[ie] = 0; break; } } if (lastterm) { strcat(fullname, PDC_PATHTERM); strcat(fullname, PDC_FILEQUOT); } } #endif } #define EXTRA_SPACE 32 /* extra space for separators, FILEQUOT etc. */ char * pdc_file_fullname_mem(pdc_core *pdc, const char *dirname, const char *basename) { static const char fn[] = "pdc_file_fullname_mem"; char *fullname; size_t len; len = strlen(basename); if (dirname && dirname[0]) len += strlen(dirname); len += EXTRA_SPACE; fullname = (char *) pdc_malloc(pdc, len, fn); pdc_file_fullname(dirname, basename, fullname); return fullname; } /* * Function reads a text file and creates a string list * of all no-empty and no-comment lines. The strings are stripped * by leading and trailing white space characters. * * The caller is responsible for freeing the resultated string list * by calling the function pdc_cleanup_stringlist. * * Not for unicode strings. * * Return value: Number of strings */ #define PDC_BUFSIZE 1024 #define PDC_ARGV_CHUNKSIZE 256 int pdc_read_textfile(pdc_core *pdc, pdc_file *sfp, char ***linelist) { static const char fn[] = "pdc_read_textfile"; char buf[PDC_BUFSIZE]; char *content = NULL; char **argv = NULL; int nlines = 0; pdc_off_t filelen; size_t len, maxl = 0; int tocont, incont = 0; int i, is = 0, isb = 0; /* Get file length */ filelen = pdc_file_size(sfp); if (filelen) { /* Allocate content array */ content = (char *) pdc_malloc(pdc, (size_t) filelen, fn); /* Read loop */ while (pdc_fgetline(buf, PDC_BUFSIZE, sfp) != NULL) { /* Strip blank and comment lines */ pdc_str2trim(buf); if (buf[0] == 0 || buf[0] == '%') continue; /* Strip inline comments */ len = strlen(buf); for (i = 1; i < (int) len; i++) { if (buf[i] == '%') { if (buf[i-1] == '\\') { memmove(&buf[i-1], &buf[i], (size_t) (len - i)); len--; buf[len] = 0; } else { buf[i] = 0; pdc_strtrim(buf); len = strlen(buf); break; } } } /* Continuation line */ tocont = (buf[len-1] == '\\') ? 1:0; if (tocont) { buf[len-1] = '\0'; len--; } if (!incont) isb = is; incont = tocont; /* Copy line */ strcpy(&content[is], buf); /* Save whole line */ if (!incont) { if (nlines >= (int) maxl) { maxl += PDC_ARGV_CHUNKSIZE; argv = (argv == NULL) ? (char **)pdc_malloc(pdc, maxl * sizeof(char *), fn): (char **)pdc_realloc(pdc, argv, maxl * sizeof(char *), fn); } argv[nlines] = &content[isb]; nlines++; pdc_trace_protocol(pdc, 2, trc_filesearch, "\t\tLine %d; \"%s\"\n", nlines, argv[nlines - 1]); } /* Next index */ is += (int) (len + 1 - incont); } if (!argv) pdc_free(pdc, content); } *linelist = argv; return nlines; } /* generate a temporary file name from the current time, pid, 'dirname', ** and the data in 'inbuf' using MD5. prepend 'dirname' to the file name. ** the result is written to 'outbuf'. if 'outbuf' is NULL, memory will be ** allocated and must be freed by the caller. otherwise, 'pdc' can be set ** to NULL. ** ** if 'dirname' isn't specified the function looks for an environment ** variable via the define PDC_TMPDIR_ENV. This define is set in ** pc_config.h. If the environment variable has a value and if the ** directory exists (check with the temporary file together) the ** directory will be used. */ #ifdef MVS #define TMP_NAME_LEN 9 #define TMP_SUFFIX "" #define TMP_SUFF_LEN 0 #else #define TMP_NAME_LEN 14 #define TMP_SUFFIX ".TMP" #define TMP_SUFF_LEN 4 #endif char * pdc_temppath( pdc_core *pdc, char *outbuf, const char *inbuf, size_t inlen, const char *dirname) { char name[TMP_NAME_LEN + TMP_SUFF_LEN + 1]; MD5_CTX md5; time_t timer; unsigned char digest[MD5_DIGEST_LENGTH]; int i; size_t dirlen; #ifdef VMS char *tmpdir = NULL; #endif /* VMS */ #if defined(WIN32) #if defined(__BORLANDC__) int pid = getpid(); #else int pid = _getpid(); #endif #else #if !defined(MAC) pid_t pid = getpid(); #endif #endif #ifdef PDC_TMPDIR_ENV if (!dirname) { dirname = (char *) getenv(PDC_TMPDIR_ENV); } #endif /* !PDC_TMPDIR_ENV */ time(&timer); MD5_Init(&md5); #if !defined(MAC) MD5_Update(&md5, (unsigned char *) &pid, sizeof pid); #endif MD5_Update(&md5, (unsigned char *) &timer, sizeof timer); if (inlen == 0 && inbuf != (const char *) 0) inlen = strlen(inbuf); if (inlen != 0) MD5_Update(&md5, (unsigned char *) inbuf, inlen); dirlen = dirname ? strlen(dirname) : 0; if (dirlen) MD5_Update(&md5, (const unsigned char *) dirname, dirlen); MD5_Final(digest, &md5); for (i = 0; i < TMP_NAME_LEN - 1; ++i) name[i] = (char) (PDF_A + digest[i % MD5_DIGEST_LENGTH] % 26); name[i] = 0; strcat(name, TMP_SUFFIX); if (!outbuf) outbuf = pdc_file_fullname_mem(pdc, dirname, name); else pdc_file_fullname(dirname, name, outbuf); return outbuf; } #if defined(MAC) || defined(MACOSX) #ifdef PDF_TARGET_API_MAC_CARBON /* Construct an FSSpec from a Posix path name. Only required for * Carbon (host font support and file type/creator). */ OSStatus FSPathMakeFSSpec(const UInt8 *path, FSSpec *spec) { OSStatus result; FSRef ref; /* convert the POSIX path to an FSRef */ result = FSPathMakeRef(path, &ref, NULL); if (result != noErr) return result; /* and then convert the FSRef to an FSSpec */ result = FSGetCatalogInfo(&ref, kFSCatInfoNone, NULL, NULL, spec, NULL); return result; } #else #endif /* !PDF_TARGET_API_MAC_CARBON */ #endif /* (defined(MAC) || defined(MACOSX)) */