1 /*
2   SDL_image:  An example image loading library for use with SDL
3   Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
4 
5   This software is provided 'as-is', without any express or implied
6   warranty.  In no event will the authors be held liable for any damages
7   arising from the use of this software.
8 
9   Permission is granted to anyone to use this software for any purpose,
10   including commercial applications, and to alter it and redistribute it
11   freely, subject to the following restrictions:
12 
13   1. The origin of this software must not be misrepresented; you must not
14      claim that you wrote the original software. If you use this software
15      in a product, an acknowledgment in the product documentation would be
16      appreciated but is not required.
17   2. Altered source versions must be plainly marked as such, and must not be
18      misrepresented as being the original software.
19   3. This notice may not be removed or altered from any source distribution.
20 */
21 
22 #if !(defined(__APPLE__) || defined(SDL_IMAGE_USE_WIC_BACKEND)) || defined(SDL_IMAGE_USE_COMMON_BACKEND)
23 
24 /* This is a TIFF image file loading framework */
25 
26 #include "SDL_image.h"
27 
28 #ifdef LOAD_TIF
29 
30 #include <tiffio.h>
31 
32 static struct {
33     int loaded;
34     void *handle;
35     TIFF* (*TIFFClientOpen)(const char*, const char*, thandle_t, TIFFReadWriteProc, TIFFReadWriteProc, TIFFSeekProc, TIFFCloseProc, TIFFSizeProc, TIFFMapFileProc, TIFFUnmapFileProc);
36     void (*TIFFClose)(TIFF*);
37     int (*TIFFGetField)(TIFF*, ttag_t, ...);
38     int (*TIFFReadRGBAImageOriented)(TIFF*, uint32, uint32, uint32*, int, int);
39     TIFFErrorHandler (*TIFFSetErrorHandler)(TIFFErrorHandler);
40 } lib;
41 
42 #ifdef LOAD_TIF_DYNAMIC
43 #define FUNCTION_LOADER(FUNC, SIG) \
44     lib.FUNC = (SIG) SDL_LoadFunction(lib.handle, #FUNC); \
45     if (lib.FUNC == NULL) { SDL_UnloadObject(lib.handle); return -1; }
46 #else
47 #define FUNCTION_LOADER(FUNC, SIG) \
48     lib.FUNC = FUNC;
49 #endif
50 
IMG_InitTIF()51 int IMG_InitTIF()
52 {
53     if ( lib.loaded == 0 ) {
54 #ifdef LOAD_TIF_DYNAMIC
55         lib.handle = SDL_LoadObject(LOAD_TIF_DYNAMIC);
56         if ( lib.handle == NULL ) {
57             return -1;
58         }
59 #endif
60         FUNCTION_LOADER(TIFFClientOpen, TIFF * (*)(const char*, const char*, thandle_t, TIFFReadWriteProc, TIFFReadWriteProc, TIFFSeekProc, TIFFCloseProc, TIFFSizeProc, TIFFMapFileProc, TIFFUnmapFileProc))
61         FUNCTION_LOADER(TIFFClose, void (*)(TIFF*))
62         FUNCTION_LOADER(TIFFGetField, int (*)(TIFF*, ttag_t, ...))
63         FUNCTION_LOADER(TIFFReadRGBAImageOriented, int (*)(TIFF*, uint32, uint32, uint32*, int, int))
64         FUNCTION_LOADER(TIFFSetErrorHandler, TIFFErrorHandler (*)(TIFFErrorHandler))
65     }
66     ++lib.loaded;
67 
68     return 0;
69 }
IMG_QuitTIF()70 void IMG_QuitTIF()
71 {
72     if ( lib.loaded == 0 ) {
73         return;
74     }
75     if ( lib.loaded == 1 ) {
76 #ifdef LOAD_TIF_DYNAMIC
77         SDL_UnloadObject(lib.handle);
78 #endif
79     }
80     --lib.loaded;
81 }
82 
83 /*
84  * These are the thunking routine to use the SDL_RWops* routines from
85  * libtiff's internals.
86 */
87 
tiff_read(thandle_t fd,tdata_t buf,tsize_t size)88 static tsize_t tiff_read(thandle_t fd, tdata_t buf, tsize_t size)
89 {
90     return (tsize_t)SDL_RWread((SDL_RWops*)fd, buf, 1, size);
91 }
92 
tiff_seek(thandle_t fd,toff_t offset,int origin)93 static toff_t tiff_seek(thandle_t fd, toff_t offset, int origin)
94 {
95     return SDL_RWseek((SDL_RWops*)fd, offset, origin);
96 }
97 
tiff_write(thandle_t fd,tdata_t buf,tsize_t size)98 static tsize_t tiff_write(thandle_t fd, tdata_t buf, tsize_t size)
99 {
100     return (tsize_t)SDL_RWwrite((SDL_RWops*)fd, buf, 1, size);
101 }
102 
tiff_close(thandle_t fd)103 static int tiff_close(thandle_t fd)
104 {
105     /*
106      * We don't want libtiff closing our SDL_RWops*, but if it's not given
107          * a routine to try, and if the image isn't a TIFF, it'll segfault.
108      */
109     return 0;
110 }
111 
tiff_map(thandle_t fd,tdata_t * pbase,toff_t * psize)112 static int tiff_map(thandle_t fd, tdata_t* pbase, toff_t* psize)
113 {
114     return (0);
115 }
116 
tiff_unmap(thandle_t fd,tdata_t base,toff_t size)117 static void tiff_unmap(thandle_t fd, tdata_t base, toff_t size)
118 {
119     return;
120 }
121 
tiff_size(thandle_t fd)122 static toff_t tiff_size(thandle_t fd)
123 {
124     Sint64 save_pos;
125     toff_t size;
126 
127     save_pos = SDL_RWtell((SDL_RWops*)fd);
128     SDL_RWseek((SDL_RWops*)fd, 0, RW_SEEK_END);
129     size = SDL_RWtell((SDL_RWops*)fd);
130     SDL_RWseek((SDL_RWops*)fd, save_pos, RW_SEEK_SET);
131     return size;
132 }
133 
IMG_isTIF(SDL_RWops * src)134 int IMG_isTIF(SDL_RWops* src)
135 {
136     Sint64 start;
137     int is_TIF;
138     Uint8 magic[4];
139 
140     if ( !src )
141         return 0;
142     start = SDL_RWtell(src);
143     is_TIF = 0;
144     if ( SDL_RWread(src, magic, 1, sizeof(magic)) == sizeof(magic) ) {
145         if ( (magic[0] == 'I' &&
146                       magic[1] == 'I' &&
147               magic[2] == 0x2a &&
148                       magic[3] == 0x00) ||
149              (magic[0] == 'M' &&
150                       magic[1] == 'M' &&
151               magic[2] == 0x00 &&
152                       magic[3] == 0x2a) ) {
153             is_TIF = 1;
154         }
155     }
156     SDL_RWseek(src, start, RW_SEEK_SET);
157     return(is_TIF);
158 }
159 
IMG_LoadTIF_RW(SDL_RWops * src)160 SDL_Surface* IMG_LoadTIF_RW(SDL_RWops* src)
161 {
162     Sint64 start;
163     TIFF* tiff = NULL;
164     SDL_Surface* surface = NULL;
165     Uint32 img_width, img_height;
166     Uint32 Rmask, Gmask, Bmask, Amask;
167 
168     if ( !src ) {
169         /* The error message has been set in SDL_RWFromFile */
170         return NULL;
171     }
172     start = SDL_RWtell(src);
173 
174     if ( (IMG_Init(IMG_INIT_TIF) & IMG_INIT_TIF) == 0 ) {
175         return NULL;
176     }
177 
178     /* turn off memory mapped access with the m flag */
179     tiff = lib.TIFFClientOpen("SDL_image", "rm", (thandle_t)src,
180         tiff_read, tiff_write, tiff_seek, tiff_close, tiff_size, tiff_map, tiff_unmap);
181     if(!tiff)
182         goto error;
183 
184     /* Retrieve the dimensions of the image from the TIFF tags */
185     lib.TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &img_width);
186     lib.TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &img_height);
187 
188     Rmask = 0x000000FF;
189     Gmask = 0x0000FF00;
190     Bmask = 0x00FF0000;
191     Amask = 0xFF000000;
192     surface = SDL_CreateRGBSurface(SDL_SWSURFACE, img_width, img_height, 32,
193         Rmask, Gmask, Bmask, Amask);
194     if(!surface)
195         goto error;
196 
197     if(!lib.TIFFReadRGBAImageOriented(tiff, img_width, img_height, (uint32 *)surface->pixels, ORIENTATION_TOPLEFT, 0))
198         goto error;
199 
200     lib.TIFFClose(tiff);
201 
202     return surface;
203 
204 error:
205     SDL_RWseek(src, start, RW_SEEK_SET);
206     if (surface) {
207         SDL_FreeSurface(surface);
208     }
209     if (tiff) {
210         lib.TIFFClose(tiff);
211     }
212     return NULL;
213 }
214 
215 #else
216 
IMG_InitTIF()217 int IMG_InitTIF()
218 {
219     IMG_SetError("TIFF images are not supported");
220     return(-1);
221 }
222 
IMG_QuitTIF()223 void IMG_QuitTIF()
224 {
225 }
226 
227 /* See if an image is contained in a data source */
IMG_isTIF(SDL_RWops * src)228 int IMG_isTIF(SDL_RWops *src)
229 {
230     return(0);
231 }
232 
233 /* Load a TIFF type image from an SDL datasource */
IMG_LoadTIF_RW(SDL_RWops * src)234 SDL_Surface *IMG_LoadTIF_RW(SDL_RWops *src)
235 {
236     return(NULL);
237 }
238 
239 #endif /* LOAD_TIF */
240 
241 #endif /* !defined(__APPLE__) || defined(SDL_IMAGE_USE_COMMON_BACKEND) */
242