xref: /libtiff-4.0.7/libtiff/tif_vms.c (revision 8ba4a1c8)
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