source: trunk/third/tiff/libtiff/tif_vms.c @ 18174

Revision 18174, 13.5 KB checked in by ghudson, 22 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r18173, which included commits to RCS files with non-trunk default branches.
Line 
1/* $Header: /afs/dev.mit.edu/source/repository/third/tiff/libtiff/tif_vms.c,v 1.1.1.1 2002-12-26 02:37:36 ghudson Exp $ */
2
3/*
4 * Copyright (c) 1988-1997 Sam Leffler
5 * Copyright (c) 1991-1997 Silicon Graphics, Inc.
6 *
7 * Permission to use, copy, modify, distribute, and sell this software and
8 * its documentation for any purpose is hereby granted without fee, provided
9 * that (i) the above copyright notices and this permission notice appear in
10 * all copies of the software and related documentation, and (ii) the names of
11 * Sam Leffler and Silicon Graphics may not be used in any advertising or
12 * publicity relating to the software without the specific, prior written
13 * permission of Sam Leffler and Silicon Graphics.
14 *
15 * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
17 * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. 
18 *
19 * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
20 * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
21 * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
22 * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
23 * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
24 * OF THIS SOFTWARE.
25 */
26
27/*
28 * TIFF Library VMS-specific Routines.
29 */
30
31#include <stdlib.h>
32#include <unixio.h>
33#include "tiffiop.h"
34#if !HAVE_IEEEFP
35#include <math.h>
36#endif
37
38#ifdef VAXC
39#define NOSHARE noshare
40#else
41#define NOSHARE
42#endif
43
44#ifdef __alpha
45/* Dummy entry point for backwards compatibility */
46void TIFFModeCCITTFax3(void){}
47#endif
48
49static tsize_t
50_tiffReadProc(thandle_t fd, tdata_t buf, tsize_t size)
51{
52        return (read((int) fd, buf, size));
53}
54
55static tsize_t
56_tiffWriteProc(thandle_t fd, tdata_t buf, tsize_t size)
57{
58        return (write((int) fd, buf, size));
59}
60
61static toff_t
62_tiffSeekProc(thandle_t fd, toff_t off, int whence)
63{
64        return ((toff_t) lseek((int) fd, (off_t) off, whence));
65}
66
67static int
68_tiffCloseProc(thandle_t fd)
69{
70        return (close((int) fd));
71}
72
73#include <sys/stat.h>
74
75static toff_t
76_tiffSizeProc(thandle_t fd)
77{
78        struct stat sb;
79        return (toff_t) (fstat((int) fd, &sb) < 0 ? 0 : sb.st_size);
80}
81
82#ifdef HAVE_MMAP
83#include <starlet.h>
84#include <fab.h>
85#include <secdef.h>
86
87/*
88 * Table for storing information on current open sections.
89 * (Should really be a linked list)
90 */
91#define MAX_MAPPED 100
92static int no_mapped = 0;
93static struct {
94        char *base;
95        char *top;
96        unsigned short channel;
97} map_table[MAX_MAPPED];
98
99/*
100 * This routine maps a file into a private section. Note that this
101 * method of accessing a file is by far the fastest under VMS.
102 * The routine may fail (i.e. return 0) for several reasons, for
103 * example:
104 * - There is no more room for storing the info on sections.
105 * - The process is out of open file quota, channels, ...
106 * - fd does not describe an opened file.
107 * - The file is already opened for write access by this process
108 *   or another process
109 * - There is no free "hole" in virtual memory that fits the
110 *   size of the file
111 */
112static int
113_tiffMapProc(thandle_t fd, tdata_t* pbase, toff_t* psize)
114{
115        char name[256];
116        struct FAB fab;
117        unsigned short channel;
118        char *inadr[2], *retadr[2];
119        unsigned long status;
120        long size;
121       
122        if (no_mapped >= MAX_MAPPED)
123                return(0);
124        /*
125         * We cannot use a file descriptor, we
126         * must open the file once more.
127         */
128        if (getname((int)fd, name, 1) == NULL)
129                return(0);
130        /* prepare the FAB for a user file open */
131        fab = cc$rms_fab;
132        fab.fab$l_fop |= FAB$V_UFO;
133        fab.fab$b_fac = FAB$M_GET;
134        fab.fab$b_shr = FAB$M_SHRGET;
135        fab.fab$l_fna = name;
136        fab.fab$b_fns = strlen(name);
137        status = sys$open(&fab);        /* open file & get channel number */
138        if ((status&1) == 0)
139                return(0);
140        channel = (unsigned short)fab.fab$l_stv;
141        inadr[0] = inadr[1] = (char *)0; /* just an address in P0 space */
142        /*
143         * Map the blocks of the file up to
144         * the EOF block into virtual memory.
145         */
146        size = _tiffSizeProc(fd);
147        status = sys$crmpsc(inadr, retadr, 0, SEC$M_EXPREG, 0,0,0, channel,
148                TIFFhowmany(size,512), 0,0,0);
149        if ((status&1) == 0){
150                sys$dassgn(channel);
151                return(0);
152        }
153        *pbase = (tdata_t) retadr[0];   /* starting virtual address */
154        /*
155         * Use the size of the file up to the
156         * EOF mark for UNIX compatibility.
157         */
158        *psize = (toff_t) size;
159        /* Record the section in the table */
160        map_table[no_mapped].base = retadr[0];
161        map_table[no_mapped].top = retadr[1];
162        map_table[no_mapped].channel = channel;
163        no_mapped++;
164
165        return(1);
166}
167
168/*
169 * This routine unmaps a section from the virtual address space of
170 * the process, but only if the base was the one returned from a
171 * call to TIFFMapFileContents.
172 */
173static void
174_tiffUnmapProc(thandle_t fd, tdata_t base, toff_t size)
175{
176        char *inadr[2];
177        int i, j;
178       
179        /* Find the section in the table */
180        for (i = 0;i < no_mapped; i++) {
181                if (map_table[i].base == (char *) base) {
182                        /* Unmap the section */
183                        inadr[0] = (char *) base;
184                        inadr[1] = map_table[i].top;
185                        sys$deltva(inadr, 0, 0);
186                        sys$dassgn(map_table[i].channel);
187                        /* Remove this section from the list */
188                        for (j = i+1; j < no_mapped; j++)
189                                map_table[j-1] = map_table[j];
190                        no_mapped--;
191                        return;
192                }
193        }
194}
195#else /* !HAVE_MMAP */
196static int
197_tiffMapProc(thandle_t fd, tdata_t* pbase, toff_t* psize)
198{
199        return (0);
200}
201
202static void
203_tiffUnmapProc(thandle_t fd, tdata_t base, toff_t size)
204{
205}
206#endif /* !HAVE_MMAP */
207
208/*
209 * Open a TIFF file descriptor for read/writing.
210 */
211TIFF*
212TIFFFdOpen(int fd, const char* name, const char* mode)
213{
214        TIFF* tif;
215
216        tif = TIFFClientOpen(name, mode,
217            (thandle_t) fd,
218            _tiffReadProc, _tiffWriteProc, _tiffSeekProc, _tiffCloseProc,
219            _tiffSizeProc, _tiffMapProc, _tiffUnmapProc);
220        if (tif)
221                tif->tif_fd = fd;
222        return (tif);
223}
224
225/*
226 * Open a TIFF file for read/writing.
227 */
228TIFF*
229TIFFOpen(const char* name, const char* mode)
230{
231        static const char module[] = "TIFFOpen";
232        int m, fd;
233
234        m = _TIFFgetMode(mode, module);
235        if (m == -1)
236                return ((TIFF*)0);
237        if (m&O_TRUNC){
238                /*
239                 * There is a bug in open in VAXC. If you use
240                 * open w/ m=O_RDWR|O_CREAT|O_TRUNC the
241                 * wrong thing happens.  On the other hand
242                 * creat does the right thing.
243                 */
244                fd = creat((char *) /* bug in stdio.h */ name, 0666,
245                    "alq = 128", "deq = 64", "mbc = 32",
246                    "fop = tef");
247        } else if (m&O_RDWR) {
248                fd = open(name, m, 0666,
249                    "deq = 64", "mbc = 32", "fop = tef", "ctx = stm");
250        } else
251                fd = open(name, m, 0666, "mbc = 32", "ctx = stm");
252        if (fd < 0) {
253                TIFFError(module, "%s: Cannot open", name);
254                return ((TIFF*)0);
255        }
256        return (TIFFFdOpen(fd, name, mode));
257}
258
259tdata_t
260_TIFFmalloc(tsize_t s)
261{
262        return (malloc((size_t) s));
263}
264
265void
266_TIFFfree(tdata_t p)
267{
268        free(p);
269}
270
271tdata_t
272_TIFFrealloc(tdata_t p, tsize_t s)
273{
274        return (realloc(p, (size_t) s));
275}
276
277void
278_TIFFmemset(tdata_t p, int v, tsize_t c)
279{
280        memset(p, v, (size_t) c);
281}
282
283void
284_TIFFmemcpy(tdata_t d, const tdata_t s, tsize_t c)
285{
286        memcpy(d, s, (size_t) c);
287}
288
289int
290_TIFFmemcmp(const tdata_t p1, const tdata_t p2, tsize_t c)
291{
292        return (memcmp(p1, p2, (size_t) c));
293}
294
295/*
296 * On the VAX, we need to make those global, writable pointers
297 * non-shareable, otherwise they would be made shareable by default.
298 * On the AXP, this brain damage has been corrected.
299 *
300 * I (Karsten Spang, krs@kampsax.dk) have dug around in the GCC
301 * manual and the GAS code and have come up with the following
302 * construct, but I don't have GCC on my VAX, so it is untested.
303 * Please tell me if it does not work.
304 */
305
306static void
307vmsWarningHandler(const char* module, const char* fmt, va_list ap)
308{
309        if (module != NULL)
310                fprintf(stderr, "%s: ", module);
311        fprintf(stderr, "Warning, ");
312        vfprintf(stderr, fmt, ap);
313        fprintf(stderr, ".\n");
314}
315
316NOSHARE TIFFErrorHandler _TIFFwarningHandler = vmsWarningHandler
317#if defined(VAX) && defined(__GNUC__)
318asm("_$$PsectAttributes_NOSHR$$_TIFFwarningHandler")
319#endif
320;
321
322static void
323vmsErrorHandler(const char* module, const char* fmt, va_list ap)
324{
325        if (module != NULL)
326                fprintf(stderr, "%s: ", module);
327        vfprintf(stderr, fmt, ap);
328        fprintf(stderr, ".\n");
329}
330
331NOSHARE TIFFErrorHandler _TIFFerrorHandler = vmsErrorHandler
332#if defined(VAX) && defined(__GNUC__)
333asm("_$$PsectAttributes_NOSHR$$_TIFFerrorHandler")
334#endif
335;
336
337
338#if !HAVE_IEEEFP
339/* IEEE floting point handling */
340
341typedef struct ieeedouble {
342        u_long  mant2;                  /* fix NDR: full 8-byte swap */
343        u_long  mant    : 20,
344                exp     : 11,
345                sign    : 1;
346} ieeedouble;
347typedef struct ieeefloat {
348        u_long  mant    : 23,
349                exp     : 8,
350                sign    : 1;
351} ieeefloat;
352
353/*
354 * NB: These are D_FLOAT's, not G_FLOAT's. A G_FLOAT is
355 *  simply a reverse-IEEE float/double.
356 */
357
358typedef struct {
359        u_long  mant1   : 7,
360                exp     : 8,
361                sign    : 1,
362                mant2   : 16,
363                mant3   : 16,
364                mant4   : 16;
365} nativedouble;
366typedef struct {
367        u_long  mant1   : 7,
368                exp     : 8,
369                sign    : 1,
370                mant2   : 16;
371} nativefloat;
372
373typedef union {
374        ieeedouble      ieee;
375        nativedouble    native;
376        char            b[8];
377        uint32          l[2];
378        double          d;
379} double_t;
380
381typedef union {
382        ieeefloat       ieee;
383        nativefloat     native;
384        char            b[4];
385        uint32          l;
386        float           f;
387} float_t;
388
389#if defined(VAXC) || defined(DECC)
390#pragma inline(ieeetod,dtoieee)
391#endif
392
393/*
394 * Convert an IEEE double precision number to native double precision.
395 * The source is contained in two longwords, the second holding the sign,
396 * exponent and the higher order bits of the mantissa, and the first
397 * holding the rest of the mantissa as follows:
398 * (Note: It is assumed that the number has been eight-byte swapped to
399 * LSB first.)
400 *
401 * First longword:
402 *      32 least significant bits of mantissa
403 * Second longword:
404 *      0-19:   20 most significant bits of mantissa
405 *      20-30:  exponent
406 *      31:     sign
407 * The exponent is stored as excess 1023.
408 * The most significant bit of the mantissa is implied 1, and not stored.
409 * If the exponent and mantissa are zero, the number is zero.
410 * If the exponent is 0 (i.e. -1023) and the mantissa is non-zero, it is an
411 * unnormalized number with the most significant bit NOT implied.
412 * If the exponent is 2047, the number is invalid, in case the mantissa is zero,
413 * this means overflow (+/- depending of the sign bit), otherwise
414 * it simply means invalid number.
415 *
416 * If the number is too large for the machine or was specified as overflow,
417 * +/-HUGE_VAL is returned.
418 */
419INLINE static void
420ieeetod(double *dp)
421{
422        double_t source;
423        long sign,exp,mant;
424        double dmant;
425
426        source.ieee = ((double_t*)dp)->ieee;
427        sign = source.ieee.sign;
428        exp = source.ieee.exp;
429        mant = source.ieee.mant;
430
431        if (exp == 2047) {
432                if (mant)                       /* Not a Number (NAN) */
433                        *dp = HUGE_VAL;
434                else                            /* +/- infinity */
435                        *dp = (sign ? -HUGE_VAL : HUGE_VAL);
436                return;
437        }
438        if (!exp) {
439                if (!(mant || source.ieee.mant2)) {     /* zero */
440                        *dp=0;
441                        return;
442                } else {                        /* Unnormalized number */
443                        /* NB: not -1023, the 1 bit is not implied */
444                        exp= -1022;
445                }
446        } else {
447                mant |= 1<<20;
448                exp -= 1023;
449        }
450        dmant = (((double) mant) +
451                ((double) source.ieee.mant2) / (((double) (1<<16)) *
452                ((double) (1<<16)))) / (double) (1<<20);
453        dmant = ldexp(dmant, exp);
454        if (sign)
455                dmant= -dmant;
456        *dp = dmant;
457}
458
459INLINE static void
460dtoieee(double *dp)
461{
462        double_t num;
463        double x;
464        int exp;
465
466        num.d = *dp;
467        if (!num.d) {                   /* Zero is just binary all zeros */
468                num.l[0] = num.l[1] = 0;
469                return;
470        }
471
472        if (num.d < 0) {                /* Sign is encoded separately */
473                num.d = -num.d;
474                num.ieee.sign = 1;
475        } else {
476                num.ieee.sign = 0;
477        }
478
479        /* Now separate the absolute value into mantissa and exponent */
480        x = frexp(num.d, &exp);
481
482        /*
483         * Handle cases where the value is outside the
484         * range for IEEE floating point numbers.
485         * (Overflow cannot happen on a VAX, but underflow
486         * can happen for G float.)
487         */
488        if (exp < -1022) {              /* Unnormalized number */
489                x = ldexp(x, -1023-exp);
490                exp = 0;
491        } else if (exp > 1023) {        /* +/- infinity */
492                x = 0;
493                exp = 2047;
494        } else {                        /* Get rid of most significant bit */
495                x *= 2;
496                x -= 1;
497                exp += 1022; /* fix NDR: 1.0 -> x=0.5, exp=1 -> ieee.exp = 1023 */
498        }
499        num.ieee.exp = exp;
500
501        x *= (double) (1<<20);
502        num.ieee.mant = (long) x;
503        x -= (double) num.ieee.mant;
504        num.ieee.mant2 = (long) (x*((double) (1<<16)*(double) (1<<16)));
505
506        if (!(num.ieee.mant || num.ieee.exp || num.ieee.mant2)) {
507                /* Avoid negative zero */
508                num.ieee.sign = 0;
509        }
510        ((double_t*)dp)->ieee = num.ieee;
511}
512
513/*
514 * Beware, these do not handle over/under-flow
515 * during conversion from ieee to native format.
516 */
517#define NATIVE2IEEEFLOAT(fp) { \
518    float_t t; \
519    if (t.ieee.exp = (fp)->native.exp) \
520        t.ieee.exp += -129 + 127; \
521    t.ieee.sign = (fp)->native.sign; \
522    t.ieee.mant = ((fp)->native.mant1<<16)|(fp)->native.mant2; \
523    *(fp) = t; \
524}
525#define IEEEFLOAT2NATIVE(fp) { \
526    float_t t; int v = (fp)->ieee.exp; \
527    if (v) v += -127 + 129;             /* alter bias of exponent */\
528    t.native.exp = v;                   /* implicit truncation of exponent */\
529    t.native.sign = (fp)->ieee.sign; \
530    v = (fp)->ieee.mant; \
531    t.native.mant1 = v >> 16; \
532    t.native.mant2 = v;\
533    *(fp) = t; \
534}
535
536#define IEEEDOUBLE2NATIVE(dp) ieeetod(dp)
537
538#define NATIVE2IEEEDOUBLE(dp) dtoieee(dp)
539
540
541/*
542 * These unions are used during floating point
543 * conversions.  The above macros define the
544 * conversion operations.
545 */
546void
547TIFFCvtIEEEFloatToNative(TIFF* tif, u_int n, float* f)
548{
549        float_t* fp = (float_t*) f;
550
551        while (n-- > 0) {
552                IEEEFLOAT2NATIVE(fp);
553                fp++;
554        }
555}
556
557void
558TIFFCvtNativeToIEEEFloat(TIFF* tif, u_int n, float* f)
559{
560        float_t* fp = (float_t*) f;
561
562        while (n-- > 0) {
563                NATIVE2IEEEFLOAT(fp);
564                fp++;
565        }
566}
567void
568TIFFCvtIEEEDoubleToNative(TIFF* tif, u_int n, double* f)
569{
570        double_t* fp = (double_t*) f;
571
572        while (n-- > 0) {
573                IEEEDOUBLE2NATIVE(fp);
574                fp++;
575        }
576}
577
578void
579TIFFCvtNativeToIEEEDouble(TIFF* tif, u_int n, double* f)
580{
581        double_t* fp = (double_t*) f;
582
583        while (n-- > 0) {
584                NATIVE2IEEEDOUBLE(fp);
585                fp++;
586        }
587}
588#endif
Note: See TracBrowser for help on using the repository browser.