]> git.saurik.com Git - wxWidgets.git/blob - src/tiff/libtiff/tif_open.c
Added ability to switch off more components of the size page UI
[wxWidgets.git] / src / tiff / libtiff / tif_open.c
1 /* $Id$ */
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.
29 */
30 #include "tiffiop.h"
31
32 /*
33 * Dummy functions to fill the omitted client procedures.
34 */
35 static int
36 _tiffDummyMapProc(thandle_t fd, void** pbase, toff_t* psize)
37 {
38 (void) fd; (void) pbase; (void) psize;
39 return (0);
40 }
41
42 static void
43 _tiffDummyUnmapProc(thandle_t fd, void* base, toff_t size)
44 {
45 (void) fd; (void) base; (void) size;
46 }
47
48 int
49 _TIFFgetMode(const char* mode, const char* module)
50 {
51 int m = -1;
52
53 switch (mode[0]) {
54 case 'r':
55 m = O_RDONLY;
56 if (mode[1] == '+')
57 m = O_RDWR;
58 break;
59 case 'w':
60 case 'a':
61 m = O_RDWR|O_CREAT;
62 if (mode[0] == 'w')
63 m |= O_TRUNC;
64 break;
65 default:
66 TIFFErrorExt(0, module, "\"%s\": Bad mode", mode);
67 break;
68 }
69 return (m);
70 }
71
72 TIFF*
73 TIFFClientOpen(
74 const char* name, const char* mode,
75 thandle_t clientdata,
76 TIFFReadWriteProc readproc,
77 TIFFReadWriteProc writeproc,
78 TIFFSeekProc seekproc,
79 TIFFCloseProc closeproc,
80 TIFFSizeProc sizeproc,
81 TIFFMapFileProc mapproc,
82 TIFFUnmapFileProc unmapproc
83 )
84 {
85 static const char module[] = "TIFFClientOpen";
86 TIFF *tif;
87 int m;
88 const char* cp;
89
90 /* The following are configuration checks. They should be redundant, but should not
91 * compile to any actual code in an optimised release build anyway. If any of them
92 * fail, (makefile-based or other) configuration is not correct */
93 assert(sizeof(uint8)==1);
94 assert(sizeof(int8)==1);
95 assert(sizeof(uint16)==2);
96 assert(sizeof(int16)==2);
97 assert(sizeof(uint32)==4);
98 assert(sizeof(int32)==4);
99 assert(sizeof(uint64)==8);
100 assert(sizeof(int64)==8);
101 assert(sizeof(tmsize_t)==sizeof(void*));
102 {
103 union{
104 uint8 a8[2];
105 uint16 a16;
106 } n;
107 n.a8[0]=1;
108 n.a8[1]=0;
109 #ifdef WORDS_BIGENDIAN
110 assert(n.a16==256);
111 #else
112 assert(n.a16==1);
113 #endif
114 }
115
116 m = _TIFFgetMode(mode, module);
117 if (m == -1)
118 goto bad2;
119 tif = (TIFF *)_TIFFmalloc((tmsize_t)(sizeof (TIFF) + strlen(name) + 1));
120 if (tif == NULL) {
121 TIFFErrorExt(clientdata, module, "%s: Out of memory (TIFF structure)", name);
122 goto bad2;
123 }
124 _TIFFmemset(tif, 0, sizeof (*tif));
125 tif->tif_name = (char *)tif + sizeof (TIFF);
126 strcpy(tif->tif_name, name);
127 tif->tif_mode = m &~ (O_CREAT|O_TRUNC);
128 tif->tif_curdir = (uint16) -1; /* non-existent directory */
129 tif->tif_curoff = 0;
130 tif->tif_curstrip = (uint32) -1; /* invalid strip */
131 tif->tif_row = (uint32) -1; /* read/write pre-increment */
132 tif->tif_clientdata = clientdata;
133 if (!readproc || !writeproc || !seekproc || !closeproc || !sizeproc) {
134 TIFFErrorExt(clientdata, module,
135 "One of the client procedures is NULL pointer.");
136 goto bad2;
137 }
138 tif->tif_readproc = readproc;
139 tif->tif_writeproc = writeproc;
140 tif->tif_seekproc = seekproc;
141 tif->tif_closeproc = closeproc;
142 tif->tif_sizeproc = sizeproc;
143 if (mapproc)
144 tif->tif_mapproc = mapproc;
145 else
146 tif->tif_mapproc = _tiffDummyMapProc;
147 if (unmapproc)
148 tif->tif_unmapproc = unmapproc;
149 else
150 tif->tif_unmapproc = _tiffDummyUnmapProc;
151 _TIFFSetDefaultCompressionState(tif); /* setup default state */
152 /*
153 * Default is to return data MSB2LSB and enable the
154 * use of memory-mapped files and strip chopping when
155 * a file is opened read-only.
156 */
157 tif->tif_flags = FILLORDER_MSB2LSB;
158 if (m == O_RDONLY )
159 tif->tif_flags |= TIFF_MAPPED;
160
161 #ifdef STRIPCHOP_DEFAULT
162 if (m == O_RDONLY || m == O_RDWR)
163 tif->tif_flags |= STRIPCHOP_DEFAULT;
164 #endif
165
166 /*
167 * Process library-specific flags in the open mode string.
168 * The following flags may be used to control intrinsic library
169 * behaviour that may or may not be desirable (usually for
170 * compatibility with some application that claims to support
171 * TIFF but only supports some braindead idea of what the
172 * vendor thinks TIFF is):
173 *
174 * 'l' use little-endian byte order for creating a file
175 * 'b' use big-endian byte order for creating a file
176 * 'L' read/write information using LSB2MSB bit order
177 * 'B' read/write information using MSB2LSB bit order
178 * 'H' read/write information using host bit order
179 * 'M' enable use of memory-mapped files when supported
180 * 'm' disable use of memory-mapped files
181 * 'C' enable strip chopping support when reading
182 * 'c' disable strip chopping support
183 * 'h' read TIFF header only, do not load the first IFD
184 * '4' ClassicTIFF for creating a file (default)
185 * '8' BigTIFF for creating a file
186 *
187 * The use of the 'l' and 'b' flags is strongly discouraged.
188 * These flags are provided solely because numerous vendors,
189 * typically on the PC, do not correctly support TIFF; they
190 * only support the Intel little-endian byte order. This
191 * support is not configured by default because it supports
192 * the violation of the TIFF spec that says that readers *MUST*
193 * support both byte orders. It is strongly recommended that
194 * you not use this feature except to deal with busted apps
195 * that write invalid TIFF. And even in those cases you should
196 * bang on the vendors to fix their software.
197 *
198 * The 'L', 'B', and 'H' flags are intended for applications
199 * that can optimize operations on data by using a particular
200 * bit order. By default the library returns data in MSB2LSB
201 * bit order for compatibiltiy with older versions of this
202 * library. Returning data in the bit order of the native cpu
203 * makes the most sense but also requires applications to check
204 * the value of the FillOrder tag; something they probably do
205 * not do right now.
206 *
207 * The 'M' and 'm' flags are provided because some virtual memory
208 * systems exhibit poor behaviour when large images are mapped.
209 * These options permit clients to control the use of memory-mapped
210 * files on a per-file basis.
211 *
212 * The 'C' and 'c' flags are provided because the library support
213 * for chopping up large strips into multiple smaller strips is not
214 * application-transparent and as such can cause problems. The 'c'
215 * option permits applications that only want to look at the tags,
216 * for example, to get the unadulterated TIFF tag information.
217 */
218 for (cp = mode; *cp; cp++)
219 switch (*cp) {
220 case 'b':
221 #ifndef WORDS_BIGENDIAN
222 if (m&O_CREAT)
223 tif->tif_flags |= TIFF_SWAB;
224 #endif
225 break;
226 case 'l':
227 #ifdef WORDS_BIGENDIAN
228 if ((m&O_CREAT))
229 tif->tif_flags |= TIFF_SWAB;
230 #endif
231 break;
232 case 'B':
233 tif->tif_flags = (tif->tif_flags &~ TIFF_FILLORDER) |
234 FILLORDER_MSB2LSB;
235 break;
236 case 'L':
237 tif->tif_flags = (tif->tif_flags &~ TIFF_FILLORDER) |
238 FILLORDER_LSB2MSB;
239 break;
240 case 'H':
241 tif->tif_flags = (tif->tif_flags &~ TIFF_FILLORDER) |
242 HOST_FILLORDER;
243 break;
244 case 'M':
245 if (m == O_RDONLY)
246 tif->tif_flags |= TIFF_MAPPED;
247 break;
248 case 'm':
249 if (m == O_RDONLY)
250 tif->tif_flags &= ~TIFF_MAPPED;
251 break;
252 case 'C':
253 if (m == O_RDONLY)
254 tif->tif_flags |= TIFF_STRIPCHOP;
255 break;
256 case 'c':
257 if (m == O_RDONLY)
258 tif->tif_flags &= ~TIFF_STRIPCHOP;
259 break;
260 case 'h':
261 tif->tif_flags |= TIFF_HEADERONLY;
262 break;
263 case '8':
264 if (m&O_CREAT)
265 tif->tif_flags |= TIFF_BIGTIFF;
266 break;
267 }
268 /*
269 * Read in TIFF header.
270 */
271 if ((m & O_TRUNC) ||
272 !ReadOK(tif, &tif->tif_header, sizeof (TIFFHeaderClassic))) {
273 if (tif->tif_mode == O_RDONLY) {
274 TIFFErrorExt(tif->tif_clientdata, name,
275 "Cannot read TIFF header");
276 goto bad;
277 }
278 /*
279 * Setup header and write.
280 */
281 #ifdef WORDS_BIGENDIAN
282 tif->tif_header.common.tiff_magic = tif->tif_flags & TIFF_SWAB
283 ? TIFF_LITTLEENDIAN : TIFF_BIGENDIAN;
284 #else
285 tif->tif_header.common.tiff_magic = tif->tif_flags & TIFF_SWAB
286 ? TIFF_BIGENDIAN : TIFF_LITTLEENDIAN;
287 #endif
288 if (!(tif->tif_flags&TIFF_BIGTIFF))
289 {
290 tif->tif_header.common.tiff_version = TIFF_VERSION_CLASSIC;
291 tif->tif_header.classic.tiff_diroff = 0;
292 if (tif->tif_flags & TIFF_SWAB)
293 TIFFSwabShort(&tif->tif_header.common.tiff_version);
294 tif->tif_header_size = sizeof(TIFFHeaderClassic);
295 }
296 else
297 {
298 tif->tif_header.common.tiff_version = TIFF_VERSION_BIG;
299 tif->tif_header.big.tiff_offsetsize = 8;
300 tif->tif_header.big.tiff_unused = 0;
301 tif->tif_header.big.tiff_diroff = 0;
302 if (tif->tif_flags & TIFF_SWAB)
303 {
304 TIFFSwabShort(&tif->tif_header.common.tiff_version);
305 TIFFSwabShort(&tif->tif_header.big.tiff_offsetsize);
306 }
307 tif->tif_header_size = sizeof (TIFFHeaderBig);
308 }
309 /*
310 * The doc for "fopen" for some STD_C_LIBs says that if you
311 * open a file for modify ("+"), then you must fseek (or
312 * fflush?) between any freads and fwrites. This is not
313 * necessary on most systems, but has been shown to be needed
314 * on Solaris.
315 */
316 TIFFSeekFile( tif, 0, SEEK_SET );
317 if (!WriteOK(tif, &tif->tif_header, (tmsize_t)(tif->tif_header_size))) {
318 TIFFErrorExt(tif->tif_clientdata, name,
319 "Error writing TIFF header");
320 goto bad;
321 }
322 /*
323 * Setup the byte order handling.
324 */
325 if (tif->tif_header.common.tiff_magic == TIFF_BIGENDIAN) {
326 #ifndef WORDS_BIGENDIAN
327 tif->tif_flags |= TIFF_SWAB;
328 #endif
329 } else {
330 #ifdef WORDS_BIGENDIAN
331 tif->tif_flags |= TIFF_SWAB;
332 #endif
333 }
334 /*
335 * Setup default directory.
336 */
337 if (!TIFFDefaultDirectory(tif))
338 goto bad;
339 tif->tif_diroff = 0;
340 tif->tif_dirlist = NULL;
341 tif->tif_dirlistsize = 0;
342 tif->tif_dirnumber = 0;
343 return (tif);
344 }
345 /*
346 * Setup the byte order handling.
347 */
348 if (tif->tif_header.common.tiff_magic != TIFF_BIGENDIAN &&
349 tif->tif_header.common.tiff_magic != TIFF_LITTLEENDIAN
350 #if MDI_SUPPORT
351 &&
352 #if HOST_BIGENDIAN
353 tif->tif_header.common.tiff_magic != MDI_BIGENDIAN
354 #else
355 tif->tif_header.common.tiff_magic != MDI_LITTLEENDIAN
356 #endif
357 ) {
358 TIFFErrorExt(tif->tif_clientdata, name,
359 "Not a TIFF or MDI file, bad magic number %d (0x%x)",
360 #else
361 ) {
362 TIFFErrorExt(tif->tif_clientdata, name,
363 "Not a TIFF file, bad magic number %d (0x%x)",
364 #endif
365 tif->tif_header.common.tiff_magic,
366 tif->tif_header.common.tiff_magic);
367 goto bad;
368 }
369 if (tif->tif_header.common.tiff_magic == TIFF_BIGENDIAN) {
370 #ifndef WORDS_BIGENDIAN
371 tif->tif_flags |= TIFF_SWAB;
372 #endif
373 } else {
374 #ifdef WORDS_BIGENDIAN
375 tif->tif_flags |= TIFF_SWAB;
376 #endif
377 }
378 if (tif->tif_flags & TIFF_SWAB)
379 TIFFSwabShort(&tif->tif_header.common.tiff_version);
380 if ((tif->tif_header.common.tiff_version != TIFF_VERSION_CLASSIC)&&
381 (tif->tif_header.common.tiff_version != TIFF_VERSION_BIG)) {
382 TIFFErrorExt(tif->tif_clientdata, name,
383 "Not a TIFF file, bad version number %d (0x%x)",
384 tif->tif_header.common.tiff_version,
385 tif->tif_header.common.tiff_version);
386 goto bad;
387 }
388 if (tif->tif_header.common.tiff_version == TIFF_VERSION_CLASSIC)
389 {
390 if (tif->tif_flags & TIFF_SWAB)
391 TIFFSwabLong(&tif->tif_header.classic.tiff_diroff);
392 tif->tif_header_size = sizeof(TIFFHeaderClassic);
393 }
394 else
395 {
396 if (!ReadOK(tif, ((uint8*)(&tif->tif_header) + sizeof(TIFFHeaderClassic)), (sizeof(TIFFHeaderBig)-sizeof(TIFFHeaderClassic))))
397 {
398 TIFFErrorExt(tif->tif_clientdata, name,
399 "Cannot read TIFF header");
400 goto bad;
401 }
402 if (tif->tif_flags & TIFF_SWAB)
403 {
404 TIFFSwabShort(&tif->tif_header.big.tiff_offsetsize);
405 TIFFSwabLong8(&tif->tif_header.big.tiff_diroff);
406 }
407 if (tif->tif_header.big.tiff_offsetsize != 8)
408 {
409 TIFFErrorExt(tif->tif_clientdata, name,
410 "Not a TIFF file, bad BigTIFF offsetsize %d (0x%x)",
411 tif->tif_header.big.tiff_offsetsize,
412 tif->tif_header.big.tiff_offsetsize);
413 goto bad;
414 }
415 if (tif->tif_header.big.tiff_unused != 0)
416 {
417 TIFFErrorExt(tif->tif_clientdata, name,
418 "Not a TIFF file, bad BigTIFF unused %d (0x%x)",
419 tif->tif_header.big.tiff_unused,
420 tif->tif_header.big.tiff_unused);
421 goto bad;
422 }
423 tif->tif_header_size = sizeof(TIFFHeaderBig);
424 tif->tif_flags |= TIFF_BIGTIFF;
425 }
426 tif->tif_flags |= TIFF_MYBUFFER;
427 tif->tif_rawcp = tif->tif_rawdata = 0;
428 tif->tif_rawdatasize = 0;
429 tif->tif_rawdataoff = 0;
430 tif->tif_rawdataloaded = 0;
431
432 switch (mode[0]) {
433 case 'r':
434 if (!(tif->tif_flags&TIFF_BIGTIFF))
435 tif->tif_nextdiroff = tif->tif_header.classic.tiff_diroff;
436 else
437 tif->tif_nextdiroff = tif->tif_header.big.tiff_diroff;
438 /*
439 * Try to use a memory-mapped file if the client
440 * has not explicitly suppressed usage with the
441 * 'm' flag in the open mode (see above).
442 */
443 if (tif->tif_flags & TIFF_MAPPED)
444 {
445 toff_t n;
446 if (TIFFMapFileContents(tif,(void**)(&tif->tif_base),&n))
447 {
448 tif->tif_size=(tmsize_t)n;
449 assert((toff_t)tif->tif_size==n);
450 }
451 else
452 tif->tif_flags &= ~TIFF_MAPPED;
453 }
454 /*
455 * Sometimes we do not want to read the first directory (for example,
456 * it may be broken) and want to proceed to other directories. I this
457 * case we use the TIFF_HEADERONLY flag to open file and return
458 * immediately after reading TIFF header.
459 */
460 if (tif->tif_flags & TIFF_HEADERONLY)
461 return (tif);
462
463 /*
464 * Setup initial directory.
465 */
466 if (TIFFReadDirectory(tif)) {
467 tif->tif_rawcc = (tmsize_t)-1;
468 tif->tif_flags |= TIFF_BUFFERSETUP;
469 return (tif);
470 }
471 break;
472 case 'a':
473 /*
474 * New directories are automatically append
475 * to the end of the directory chain when they
476 * are written out (see TIFFWriteDirectory).
477 */
478 if (!TIFFDefaultDirectory(tif))
479 goto bad;
480 return (tif);
481 }
482 bad:
483 tif->tif_mode = O_RDONLY; /* XXX avoid flush */
484 TIFFCleanup(tif);
485 bad2:
486 return ((TIFF*)0);
487 }
488
489 /*
490 * Query functions to access private data.
491 */
492
493 /*
494 * Return open file's name.
495 */
496 const char *
497 TIFFFileName(TIFF* tif)
498 {
499 return (tif->tif_name);
500 }
501
502 /*
503 * Set the file name.
504 */
505 const char *
506 TIFFSetFileName(TIFF* tif, const char *name)
507 {
508 const char* old_name = tif->tif_name;
509 tif->tif_name = (char *)name;
510 return (old_name);
511 }
512
513 /*
514 * Return open file's I/O descriptor.
515 */
516 int
517 TIFFFileno(TIFF* tif)
518 {
519 return (tif->tif_fd);
520 }
521
522 /*
523 * Set open file's I/O descriptor, and return previous value.
524 */
525 int
526 TIFFSetFileno(TIFF* tif, int fd)
527 {
528 int old_fd = tif->tif_fd;
529 tif->tif_fd = fd;
530 return old_fd;
531 }
532
533 /*
534 * Return open file's clientdata.
535 */
536 thandle_t
537 TIFFClientdata(TIFF* tif)
538 {
539 return (tif->tif_clientdata);
540 }
541
542 /*
543 * Set open file's clientdata, and return previous value.
544 */
545 thandle_t
546 TIFFSetClientdata(TIFF* tif, thandle_t newvalue)
547 {
548 thandle_t m = tif->tif_clientdata;
549 tif->tif_clientdata = newvalue;
550 return m;
551 }
552
553 /*
554 * Return read/write mode.
555 */
556 int
557 TIFFGetMode(TIFF* tif)
558 {
559 return (tif->tif_mode);
560 }
561
562 /*
563 * Return read/write mode.
564 */
565 int
566 TIFFSetMode(TIFF* tif, int mode)
567 {
568 int old_mode = tif->tif_mode;
569 tif->tif_mode = mode;
570 return (old_mode);
571 }
572
573 /*
574 * Return nonzero if file is organized in
575 * tiles; zero if organized as strips.
576 */
577 int
578 TIFFIsTiled(TIFF* tif)
579 {
580 return (isTiled(tif));
581 }
582
583 /*
584 * Return current row being read/written.
585 */
586 uint32
587 TIFFCurrentRow(TIFF* tif)
588 {
589 return (tif->tif_row);
590 }
591
592 /*
593 * Return index of the current directory.
594 */
595 uint16
596 TIFFCurrentDirectory(TIFF* tif)
597 {
598 return (tif->tif_curdir);
599 }
600
601 /*
602 * Return current strip.
603 */
604 uint32
605 TIFFCurrentStrip(TIFF* tif)
606 {
607 return (tif->tif_curstrip);
608 }
609
610 /*
611 * Return current tile.
612 */
613 uint32
614 TIFFCurrentTile(TIFF* tif)
615 {
616 return (tif->tif_curtile);
617 }
618
619 /*
620 * Return nonzero if the file has byte-swapped data.
621 */
622 int
623 TIFFIsByteSwapped(TIFF* tif)
624 {
625 return ((tif->tif_flags & TIFF_SWAB) != 0);
626 }
627
628 /*
629 * Return nonzero if the data is returned up-sampled.
630 */
631 int
632 TIFFIsUpSampled(TIFF* tif)
633 {
634 return (isUpSampled(tif));
635 }
636
637 /*
638 * Return nonzero if the data is returned in MSB-to-LSB bit order.
639 */
640 int
641 TIFFIsMSB2LSB(TIFF* tif)
642 {
643 return (isFillOrder(tif, FILLORDER_MSB2LSB));
644 }
645
646 /*
647 * Return nonzero if given file was written in big-endian order.
648 */
649 int
650 TIFFIsBigEndian(TIFF* tif)
651 {
652 return (tif->tif_header.common.tiff_magic == TIFF_BIGENDIAN);
653 }
654
655 /*
656 * Return pointer to file read method.
657 */
658 TIFFReadWriteProc
659 TIFFGetReadProc(TIFF* tif)
660 {
661 return (tif->tif_readproc);
662 }
663
664 /*
665 * Return pointer to file write method.
666 */
667 TIFFReadWriteProc
668 TIFFGetWriteProc(TIFF* tif)
669 {
670 return (tif->tif_writeproc);
671 }
672
673 /*
674 * Return pointer to file seek method.
675 */
676 TIFFSeekProc
677 TIFFGetSeekProc(TIFF* tif)
678 {
679 return (tif->tif_seekproc);
680 }
681
682 /*
683 * Return pointer to file close method.
684 */
685 TIFFCloseProc
686 TIFFGetCloseProc(TIFF* tif)
687 {
688 return (tif->tif_closeproc);
689 }
690
691 /*
692 * Return pointer to file size requesting method.
693 */
694 TIFFSizeProc
695 TIFFGetSizeProc(TIFF* tif)
696 {
697 return (tif->tif_sizeproc);
698 }
699
700 /*
701 * Return pointer to memory mapping method.
702 */
703 TIFFMapFileProc
704 TIFFGetMapFileProc(TIFF* tif)
705 {
706 return (tif->tif_mapproc);
707 }
708
709 /*
710 * Return pointer to memory unmapping method.
711 */
712 TIFFUnmapFileProc
713 TIFFGetUnmapFileProc(TIFF* tif)
714 {
715 return (tif->tif_unmapproc);
716 }
717
718 /* vim: set ts=8 sts=8 sw=8 noet: */
719 /*
720 * Local Variables:
721 * mode: c
722 * c-basic-offset: 8
723 * fill-column: 78
724 * End:
725 */