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