1/*---------------------------------------------------------------------------*
2 |              PDFlib - A library for generating PDF on the fly             |
3 +---------------------------------------------------------------------------+
4 | Copyright (c) 1997-2004 Thomas Merz and PDFlib GmbH. All rights reserved. |
5 +---------------------------------------------------------------------------+
6 |                                                                           |
7 |    This software is subject to the PDFlib license. It is NOT in the       |
8 |    public domain. Extended versions and commercial licenses are           |
9 |    available, please check http://www.pdflib.com.                         |
10 |                                                                           |
11 *---------------------------------------------------------------------------*/
12
13/* $Id: pc_file.c 14574 2005-10-29 16:27:43Z bonefish $
14 *
15 * Various file routines
16 *
17 */
18
19#include <errno.h>
20
21#include "pc_config.h"
22#include "pc_util.h"
23#include "pc_md5.h"
24#include "pc_file.h"
25
26/* headers for getpid() or _getpid().
27*/
28#if defined(WIN32)
29#define WIN32_LEAN_AND_MEAN
30#include <windows.h>
31#include <process.h>
32#else
33#if !defined(MAC)
34	#include <sys/types.h>
35	#include <unistd.h>
36#endif
37#endif
38
39#ifndef WINCE
40#include <time.h>
41#else
42#include <winbase.h>
43#endif
44
45struct pdc_file_s
46{
47    pdc_core       *pdc;       /* pdcore struct */
48    char           *filename;  /* file name */
49    FILE           *fp;        /* file struct or NULL. Then data != NULL: */
50    const pdc_byte *data;      /* file data or NULL. Then fp != NULL */
51    const pdc_byte *end;       /* first byte above data buffer */
52    const pdc_byte *pos;       /* current file position in data buffer */
53    pdc_byte       *tdata;     /* temporary buffer filled up by ungetc */
54    int             number;    /* next available entry in tdata buffer */
55    int             capacity;  /* currently allocated size of tdata buffer */
56};
57
58#if defined(_MSC_VER) && defined(_MANAGED)
59#pragma unmanaged
60#endif
61int
62pdc_get_fopen_errnum(pdc_core *pdc, int errnum)
63{
64    int outnum = errnum, isread;
65
66    (void) pdc;
67
68    isread = (errnum == PDC_E_IO_RDOPEN);
69
70#if defined(MVS)
71
72    switch (errno)
73    {
74        case 49:
75        outnum = isread ? PDC_E_IO_RDOPEN_NF : PDC_E_IO_WROPEN_NF;
76    }
77    return outnum;
78
79#elif defined(WIN32)
80    {
81	DWORD lasterror = GetLastError();
82        switch (lasterror)
83        {
84            case ERROR_ACCESS_DENIED:
85            outnum = isread ? PDC_E_IO_RDOPEN_PD : PDC_E_IO_WROPEN_PD;
86            break;
87
88            case ERROR_FILE_NOT_FOUND:
89            case ERROR_INVALID_DRIVE:
90            case ERROR_BAD_UNIT:
91            outnum = isread ? PDC_E_IO_RDOPEN_NF : PDC_E_IO_WROPEN_NF;
92            break;
93
94            case ERROR_INVALID_NAME:
95            outnum = isread ? PDC_E_IO_RDOPEN_NF : PDC_E_IO_WROPEN_IS;
96            break;
97
98            case ERROR_PATH_NOT_FOUND:
99            outnum = isread ? PDC_E_IO_RDOPEN_NF : PDC_E_IO_WROPEN_NP;
100            break;
101
102            case ERROR_TOO_MANY_OPEN_FILES:
103            case ERROR_SHARING_BUFFER_EXCEEDED:
104            outnum = isread ? PDC_E_IO_RDOPEN_TM : PDC_E_IO_WROPEN_TM;
105            break;
106
107            case ERROR_FILE_EXISTS:
108            outnum = PDC_E_IO_WROPEN_AE;
109            break;
110
111            case ERROR_BUFFER_OVERFLOW:
112            outnum = PDC_E_IO_WROPEN_TL;
113            break;
114
115            case ERROR_WRITE_FAULT:
116            case ERROR_CANNOT_MAKE:
117            outnum = PDC_E_IO_WROPEN_NC;
118            break;
119
120            case ERROR_HANDLE_DISK_FULL:
121            outnum = PDC_E_IO_WROPEN_NS;
122            break;
123        }
124
125        if (lasterror)
126            return outnum;
127
128        /* if lasterror == 0 we must look for errno (see .NET) */
129    }
130
131#endif /* WIN32 */
132
133    switch (errno)
134    {
135#ifdef EACCES
136        case EACCES:
137        outnum = isread ? PDC_E_IO_RDOPEN_PD : PDC_E_IO_WROPEN_PD;
138        break;
139#endif
140#ifdef ENOENT
141        case ENOENT:
142        outnum = isread ? PDC_E_IO_RDOPEN_NF : PDC_E_IO_WROPEN_NF;
143        break;
144#endif
145#ifdef EMFILE
146        case EMFILE:
147        outnum = isread ? PDC_E_IO_RDOPEN_TM : PDC_E_IO_WROPEN_TM;
148        break;
149#endif
150#ifdef ENFILE
151        case ENFILE:
152        outnum = isread ? PDC_E_IO_RDOPEN_TM : PDC_E_IO_WROPEN_TM;
153        break;
154#endif
155#ifdef EISDIR
156        case EISDIR:
157        outnum = isread ? PDC_E_IO_RDOPEN_ID : PDC_E_IO_WROPEN_ID;
158        break;
159#endif
160#ifdef EEXIST
161        case EEXIST:
162        outnum = PDC_E_IO_WROPEN_AE;
163        break;
164#endif
165#ifdef ENAMETOOLONG
166        case ENAMETOOLONG:
167        outnum = PDC_E_IO_WROPEN_TL;
168        break;
169#endif
170#ifdef ENOSPC
171        case ENOSPC:
172        outnum = PDC_E_IO_WROPEN_NS;
173        break;
174#endif
175        default:
176        outnum = errnum;
177        break;
178    }
179
180    return outnum;
181}
182#if defined(_MSC_VER) && defined(_MANAGED)
183#pragma managed
184#endif
185
186void *
187pdc_read_file(pdc_core *pdc, FILE *fp, size_t *o_filelen, int incore)
188{
189    static const char *fn = "pdc_read_file";
190    size_t filelen, len;
191    char *content = NULL;
192
193#if defined(MVS) && defined(I370)
194#define PDC_READ_CHUNKSIZE 64000
195
196    while (!feof(fp))
197    {
198        if (!content)
199        {
200            len = 0;
201            filelen = PDC_READ_CHUNKSIZE;
202            content = (char *) pdc_malloc(pdc, filelen + 1, fn);
203        }
204        else if (incore)
205        {
206            len = filelen;
207            filelen += PDC_READ_CHUNKSIZE;
208            content = (char *) pdc_realloc(pdc, content, filelen + 1, fn);
209        }
210        len = fread(&content[len], 1, PDC_READ_CHUNKSIZE, fp);
211    }
212    filelen += len - PDC_READ_CHUNKSIZE;
213    if (incore && filelen)
214    {
215        content = (char *) pdc_realloc(pdc, content, filelen + 1, fn);
216    }
217    else
218    {
219        pdc_free(pdc, content);
220        content = NULL;
221    }
222
223#else
224
225    fseek(fp, 0L, SEEK_END);
226    filelen = (size_t) ftell(fp);
227    fseek(fp, 0L, SEEK_SET);
228    if (incore && filelen)
229    {
230        content = (char *) pdc_malloc(pdc, filelen + 1, fn);
231        len = fread(content, 1, filelen, fp);
232        if (len != filelen)
233        {
234            pdc_free(pdc, content);
235            filelen = 0;
236            content = NULL;
237        }
238    }
239
240#endif
241
242    if (content) content[filelen] = 0;
243    *o_filelen = filelen;
244    return (void *) content;
245}
246
247pdc_file *
248pdc_fopen(pdc_core *pdc, const char *filename, const char *qualifier,
249          const pdc_byte *data, size_t size, int flags)
250{
251    static const char fn[] = "pdc_fopen";
252    pdc_file *sfile;
253
254    sfile = (pdc_file *) pdc_calloc(pdc, sizeof(pdc_file), fn);
255    if (data)
256    {
257        sfile->data = data;
258        sfile->pos = sfile->data;
259        sfile->end = sfile->data + size;
260    }
261    else
262    {
263        sfile->fp = fopen(filename,
264                          (flags & PDC_FILE_BINARY) ? READBMODE : READTMODE);
265        if (sfile->fp == NULL)
266        {
267            pdc_free(pdc, sfile);
268            if (qualifier)
269            {
270                pdc_set_errmsg(pdc, pdc_get_fopen_errnum(pdc, PDC_E_IO_RDOPEN),
271                          qualifier, filename, 0, 0);
272            }
273            return NULL;
274        }
275    }
276
277    sfile->pdc = pdc;
278    sfile->filename = pdc_strdup(pdc, filename);
279
280
281    return sfile;
282}
283
284
285pdc_bool
286pdc_file_isvirtual(pdc_file *sfp)
287{
288    return sfp->fp ? pdc_false : pdc_true;
289}
290
291char *
292pdc_file_name(pdc_file *sfp)
293{
294    return sfp->filename;
295}
296
297pdc_core *
298pdc_file_getpdc(pdc_file *sfp)
299{
300    return sfp->pdc;
301}
302
303size_t
304pdc_file_size(pdc_file *sfp)
305{
306    size_t filelen;
307
308    if (sfp->fp)
309    {
310        long pos = ftell(sfp->fp);
311        pdc_read_file(sfp->pdc, sfp->fp, &filelen, 0);
312        fseek(sfp->fp, pos, SEEK_SET);
313    }
314    else
315        filelen = (size_t) (sfp->end - sfp->data);
316    return filelen;
317}
318
319const void *
320pdc_freadall(pdc_file *sfp, size_t *filelen, pdc_bool *ismem)
321{
322    if (sfp->fp)
323    {
324        if (ismem) *ismem = pdc_false;
325        return (const void *) pdc_read_file(sfp->pdc, sfp->fp, filelen, 1);
326    }
327
328    if (ismem) *ismem = pdc_true;
329    *filelen = (size_t) (sfp->end - sfp->data);
330    return sfp->data;
331}
332
333static int
334pdc_fgetc_e(pdc_file *sfp)
335{
336    int c = pdc_fgetc(sfp);
337    return c;
338}
339
340char *
341pdc_fgets_comp(char *s, int size, pdc_file *sfp)
342{
343    int i, c;
344
345    c = pdc_fgetc_e(sfp);
346    if (c == EOF)
347        return NULL;
348
349    size--;
350    for (i = 0; i < size; i++)
351    {
352        if (c == '\n' || c == '\r' || c == EOF) break;
353        s[i] = (char) c;
354        c = pdc_fgetc_e(sfp);
355    }
356    s[i] = 0;
357
358    /* Skip windows line end \r\n */
359    if (c == '\r')
360    {
361        c = pdc_fgetc_e(sfp);
362        if (c != '\n')
363        {
364            pdc_ungetc(c, sfp);
365        }
366    }
367    return s;
368}
369
370/*
371 * Emulation of C file functions - relevant for PDFlib
372 */
373
374long
375pdc_ftell(pdc_file *sfp)
376{
377    if (sfp->fp)
378        return ftell(sfp->fp);
379
380    return (long) (sfp->pos - sfp->data);
381}
382
383int
384pdc_fseek(pdc_file *sfp, long offset, int whence)
385{
386    if (sfp->fp)
387        return fseek(sfp->fp, offset, whence);
388
389    sfp->number = 0;
390
391    switch (whence)
392    {
393        case SEEK_SET:
394        if (sfp->data + offset > sfp->end)
395            return -1;
396        sfp->pos = sfp->data + offset;
397        break;
398
399        case SEEK_CUR:
400        if (sfp->pos + offset > sfp->end)
401            return -1;
402        sfp->pos += offset;
403        break;
404
405        case SEEK_END:
406        if (sfp->end + offset > sfp->end)
407            return -1;
408        sfp->pos = sfp->end + offset;
409        break;
410    }
411    return 0;
412}
413
414size_t
415pdc_fread(void *ptr, size_t size, size_t nmemb, pdc_file *sfp)
416{
417    size_t nbytes = 0;
418
419    if (sfp->fp)
420        return fread(ptr, size, nmemb, sfp->fp);
421
422    nbytes = size * nmemb;
423    if (sfp->pos + nbytes > sfp->end)
424    {
425        nbytes = (size_t) (sfp->end - sfp->pos);
426        nmemb = nbytes / size;
427        nbytes = nmemb *size;
428    }
429    memcpy(ptr, sfp->pos, nbytes);
430    sfp->pos += nbytes;
431
432    return nmemb;
433}
434
435#define UNGETC_CHUNKSIZE  16
436
437int
438pdc_ungetc(int c, pdc_file *sfp)
439{
440    static const char fn[] = "pdc_ungetc";
441
442    if (sfp->fp)
443        return ungetc(c, sfp->fp);
444
445    if (!sfp->capacity)
446    {
447        sfp->capacity = UNGETC_CHUNKSIZE;
448        sfp->tdata = (pdc_byte *) pdc_malloc(sfp->pdc,
449                         sfp->capacity * sizeof(pdc_byte), fn);
450    }
451    else if (sfp->number == sfp->capacity)
452    {
453        sfp->capacity += UNGETC_CHUNKSIZE;
454        sfp->tdata = (pdc_byte *) pdc_realloc(sfp->pdc, sfp->tdata,
455                         sfp->capacity * sizeof(pdc_byte), fn);
456    }
457
458    sfp->tdata[sfp->number] = (pdc_byte) c;
459    sfp->number++;
460    return c;
461}
462
463int
464pdc_fgetc(pdc_file *sfp)
465{
466    int ch = 0;
467
468    if (sfp->fp)
469        return fgetc(sfp->fp);
470
471    if (sfp->tdata && sfp->number > 0)
472    {
473        sfp->number--;
474        ch = (int) sfp->tdata[sfp->number];
475    }
476    else
477    {
478        if (sfp->pos < sfp->end)
479        {
480            ch = (int) *sfp->pos;
481            sfp->pos++;
482        }
483        else
484        {
485            ch = EOF;
486        }
487    }
488    return ch;
489}
490
491char *
492pdc_fgets(char *s, int size, pdc_file *sfp)
493{
494    int i;
495    int ch, chp;
496
497    if (sfp->fp)
498        return fgets(s, size, sfp->fp);
499
500    chp = 0;
501    for (i = 0; i < size ; i++)
502    {
503        ch = 0;
504        if (i < size - 1 && chp != '\n')
505        {
506            if (sfp->number > 0)
507            {
508                sfp->number--;
509                ch = (int) sfp->tdata[sfp->number];
510            }
511            else if (sfp->pos < sfp->end)
512            {
513                ch = (int) *sfp->pos;
514                sfp->pos++;
515            }
516            if (ch == EOF) ch = 0;
517        }
518        s[i] = (char) ch;
519        if (!ch)
520            break;
521        chp = (int) s[i];
522    }
523
524    return (i > 1) ? s : NULL;
525}
526
527int
528pdc_feof(pdc_file *sfp)
529{
530    if (sfp->fp)
531        return feof(sfp->fp);
532
533    return (sfp->pos >= sfp->end) ? 1 : 0;
534}
535
536void
537pdc_fclose(pdc_file *sfp)
538{
539    if (sfp)
540    {
541        if (sfp->fp)
542        {
543            fclose(sfp->fp);
544            sfp->fp = NULL;
545        }
546        if (sfp->tdata)
547        {
548            pdc_free(sfp->pdc, sfp->tdata);
549            sfp->tdata = NULL;
550        }
551        if (sfp->filename)
552        {
553            pdc_free(sfp->pdc, sfp->filename);
554            sfp->filename = NULL;
555        }
556        pdc_free(sfp->pdc, sfp);
557    }
558}
559
560/*
561 * Concatenating a directory name with a file base name to a full valid
562 * file name. On MVS platforms an extension at the end of basename
563 * will be discarded.
564 */
565void
566pdc_file_fullname(const char *dirname, const char *basename, char *fullname)
567{
568    int ib;
569    size_t len = strlen(basename);
570#ifdef MVS
571    pdc_bool lastterm = pdc_false;
572#endif
573
574    for (ib = 0; ib < (int) len; ib++)
575        if (!isspace(basename[ib]))
576            break;
577
578    if (!dirname || !dirname[0])
579    {
580        strcpy(fullname, &basename[ib]);
581    }
582    else
583    {
584        fullname[0] = 0;
585#ifdef MVS
586        if (strncmp(dirname, PDC_FILEQUOT, 1))
587            strcat(fullname, PDC_FILEQUOT);
588#endif
589        strcat(fullname, dirname);
590        strcat(fullname, PDC_PATHSEP);
591        strcat(fullname, &basename[ib]);
592#ifdef MVS
593        lastterm = pdc_true;
594#endif
595    }
596
597#ifdef MVS
598    {
599        int ie;
600
601        len = strlen(fullname);
602        for (ie = len; ie >= 0; ie--)
603        {
604            if (!strncmp(&fullname[ie], PDC_PATHSEP, 1))
605                break;
606            if (fullname[ie] == '.')
607            {
608                fullname[ie] = 0;
609                break;
610            }
611        }
612        if (lastterm)
613        {
614            strcat(fullname, PDC_PATHTERM);
615            strcat(fullname, PDC_FILEQUOT);
616        }
617    }
618#endif
619}
620
621/*
622 * Function reads a text file and creates a string list
623 * of all no-empty and no-comment lines. The strings are stripped
624 * by leading and trailing white space characters.
625 *
626 * The caller is responsible for freeing the resultated string list
627 * by calling the function pdc_cleanup_stringlist.
628 *
629 * Not for unicode strings.
630 *
631 * Return value: Number of strings
632 */
633
634#define PDC_BUFSIZE 1024
635#define PDC_ARGV_CHUNKSIZE 256
636
637int
638pdc_read_textfile(pdc_core *pdc, pdc_file *sfp, char ***linelist)
639{
640    static const char *fn = "pdc_read_textfile";
641    char   buf[PDC_BUFSIZE];
642    char  *content = NULL;
643    char **argv = NULL;
644    int    nlines = 0;
645    size_t filelen;
646    size_t len, maxl = 0;
647    int    tocont, incont = 0;
648    int    i, is = 0;
649
650    /* Get file length and allocate content array */
651    filelen = pdc_file_size(sfp);
652    content = (char *) pdc_malloc(pdc, filelen, fn);
653
654    /* Read loop */
655    while (pdc_fgets_comp(buf, PDC_BUFSIZE, sfp) != NULL)
656    {
657        /* Strip blank and comment lines */
658        pdc_str2trim(buf);
659        if (buf[0] == 0 || buf[0] == '%')
660            continue;
661
662        /* Strip inline comments */
663        len = strlen(buf);
664        for (i = 1; i < (int) len; i++)
665        {
666            if (buf[i] == '%' && buf[i-1] != '\\')
667            {
668                buf[i] = 0;
669                pdc_strtrim(buf);
670                len = strlen(buf);
671                break;
672            }
673        }
674
675        /* Continuation line */
676        tocont = (buf[len-1] == '\\') ? 1:0;
677        if (tocont)
678        {
679            buf[len-1] = '\0';
680            len--;
681        }
682
683        /* Copy line */
684        strcpy(&content[is], buf);
685
686        /* Save whole line */
687        if (!incont)
688        {
689            if (nlines >= (int) maxl)
690            {
691                maxl += PDC_ARGV_CHUNKSIZE;
692                argv = (argv == NULL) ?
693                        (char **)pdc_malloc(pdc, maxl * sizeof(char *), fn):
694                        (char **)pdc_realloc(pdc, argv, maxl *
695                                             sizeof(char *), fn);
696            }
697            argv[nlines] = &content[is];
698            nlines++;
699        }
700
701        /* Next index */
702        incont = tocont;
703        is += (int) (len + 1 - incont);
704    }
705
706    if (!argv) pdc_free(pdc, content);
707    *linelist = argv;
708    return nlines;
709}
710
711
712/* generate a temporary file name from the current time, pid, and the
713** data in inbuf using MD5.
714*/
715void
716pdc_tempname(char *outbuf, int outlen, const char *inbuf, int inlen)
717{
718    MD5_CTX             md5;
719    time_t              timer;
720    unsigned char       digest[MD5_DIGEST_LENGTH];
721    int                 i;
722
723#if defined(WIN32)
724    int pid = _getpid();
725#else
726#if !defined(MAC)
727    pid_t pid = getpid();
728#endif
729#endif
730
731    time(&timer);
732
733    MD5_Init(&md5);
734#if !defined(MAC)
735    MD5_Update(&md5, (unsigned char *) &pid, sizeof pid);
736#endif
737    MD5_Update(&md5, (unsigned char *) &timer, sizeof timer);
738    MD5_Update(&md5, (unsigned char *) inbuf, (unsigned int) inlen);
739    MD5_Final(digest, &md5);
740
741    for (i = 0; i < outlen - 1; ++i)
742        outbuf[i] = (char) ('A' + digest[i % MD5_DIGEST_LENGTH] % 26);
743
744    outbuf[i] = 0;
745}
746
747#ifdef PDF_TARGET_API_MAC_CARBON
748
749/* Construct an FSSpec from a Posix path name. Only required for
750 * Carbon (host font support and file type/creator).
751 */
752
753OSStatus
754FSPathMakeFSSpec(const UInt8 *path, FSSpec *spec)
755{
756        OSStatus        result;
757        FSRef           ref;
758
759        /* convert the POSIX path to an FSRef */
760        result = FSPathMakeRef(path, &ref, NULL);
761
762        if (result != noErr)
763                return result;
764
765        /* and then convert the FSRef to an FSSpec */
766        result = FSGetCatalogInfo(&ref, kFSCatInfoNone, NULL, NULL, spec, NULL);
767
768        return result;
769}
770
771#endif /* PDF_TARGET_API_MAC_CARBON */
772
773