]> git.saurik.com Git - wxWidgets.git/blob - src/tiff/tif_vms.c
More details about the internal module name changes
[wxWidgets.git] / src / tiff / tif_vms.c
1 /* $Header$ */
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 */
46 void TIFFModeCCITTFax3(void){}
47 #endif
48
49 static tsize_t
50 _tiffReadProc(thandle_t fd, tdata_t buf, tsize_t size)
51 {
52 return (read((int) fd, buf, size));
53 }
54
55 static tsize_t
56 _tiffWriteProc(thandle_t fd, tdata_t buf, tsize_t size)
57 {
58 return (write((int) fd, buf, size));
59 }
60
61 static 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
67 static int
68 _tiffCloseProc(thandle_t fd)
69 {
70 return (close((int) fd));
71 }
72
73 #include <sys/stat.h>
74
75 static 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
92 static int no_mapped = 0;
93 static 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 */
112 static 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 */
173 static 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 */
196 static int
197 _tiffMapProc(thandle_t fd, tdata_t* pbase, toff_t* psize)
198 {
199 return (0);
200 }
201
202 static 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 */
211 TIFF*
212 TIFFFdOpen(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 */
228 TIFF*
229 TIFFOpen(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
259 tdata_t
260 _TIFFmalloc(tsize_t s)
261 {
262 return (malloc((size_t) s));
263 }
264
265 void
266 _TIFFfree(tdata_t p)
267 {
268 free(p);
269 }
270
271 tdata_t
272 _TIFFrealloc(tdata_t p, tsize_t s)
273 {
274 return (realloc(p, (size_t) s));
275 }
276
277 void
278 _TIFFmemset(tdata_t p, int v, tsize_t c)
279 {
280 memset(p, v, (size_t) c);
281 }
282
283 void
284 _TIFFmemcpy(tdata_t d, const tdata_t s, tsize_t c)
285 {
286 memcpy(d, s, (size_t) c);
287 }
288
289 int
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
306 static void
307 vmsWarningHandler(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
316 NOSHARE TIFFErrorHandler _TIFFwarningHandler = vmsWarningHandler
317 #if defined(VAX) && defined(__GNUC__)
318 asm("_$$PsectAttributes_NOSHR$$_TIFFwarningHandler")
319 #endif
320 ;
321
322 static void
323 vmsErrorHandler(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
331 NOSHARE TIFFErrorHandler _TIFFerrorHandler = vmsErrorHandler
332 #if defined(VAX) && defined(__GNUC__)
333 asm("_$$PsectAttributes_NOSHR$$_TIFFerrorHandler")
334 #endif
335 ;
336
337
338 #if !HAVE_IEEEFP
339 /* IEEE floting point handling */
340
341 typedef 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;
347 typedef 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
358 typedef struct {
359 u_long mant1 : 7,
360 exp : 8,
361 sign : 1,
362 mant2 : 16,
363 mant3 : 16,
364 mant4 : 16;
365 } nativedouble;
366 typedef struct {
367 u_long mant1 : 7,
368 exp : 8,
369 sign : 1,
370 mant2 : 16;
371 } nativefloat;
372
373 typedef union {
374 ieeedouble ieee;
375 nativedouble native;
376 char b[8];
377 uint32 l[2];
378 double d;
379 } double_t;
380
381 typedef 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 */
419 INLINE static void
420 ieeetod(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
459 INLINE static void
460 dtoieee(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 */
546 void
547 TIFFCvtIEEEFloatToNative(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
557 void
558 TIFFCvtNativeToIEEEFloat(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 }
567 void
568 TIFFCvtIEEEDoubleToNative(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
578 void
579 TIFFCvtNativeToIEEEDouble(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