1 // ==========================================================
2 // CUT Loader
3 //
4 // Design and implementation by
5 // - Floris van den Berg (flvdberg@wxs.nl)
6 //
7 // This file is part of FreeImage 3
8 //
9 // COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
10 // OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
11 // THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
12 // OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
13 // CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
14 // THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
15 // SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
16 // PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
17 // THIS DISCLAIMER.
18 //
19 // Use at your own risk!
20 // ==========================================================
21 
22 #include "FreeImage.h"
23 #include "Utilities.h"
24 
25 // ----------------------------------------------------------
26 //   Constants + headers
27 // ----------------------------------------------------------
28 
29 #ifdef _WIN32
30 #pragma pack(push, 1)
31 #else
32 #pragma pack(1)
33 #endif
34 
35 typedef struct tagCUTHEADER {
36 	WORD width;
37 	WORD height;
38 	LONG dummy;
39 } CUTHEADER;
40 
41 #ifdef _WIN32
42 #pragma pack(pop)
43 #else
44 #pragma pack()
45 #endif
46 
47 // ==========================================================
48 // Plugin Interface
49 // ==========================================================
50 
51 static int s_format_id;
52 
53 // ==========================================================
54 // Plugin Implementation
55 // ==========================================================
56 
57 static const char * DLL_CALLCONV
Format()58 Format() {
59 	return "CUT";
60 }
61 
62 static const char * DLL_CALLCONV
Description()63 Description() {
64 	return "Dr. Halo";
65 }
66 
67 static const char * DLL_CALLCONV
Extension()68 Extension() {
69 	return "cut";
70 }
71 
72 static const char * DLL_CALLCONV
RegExpr()73 RegExpr() {
74 	return NULL;
75 }
76 
77 static const char * DLL_CALLCONV
MimeType()78 MimeType() {
79 	return "image/x-cut";
80 }
81 
82 static BOOL DLL_CALLCONV
Validate(FreeImageIO * io,fi_handle handle)83 Validate(FreeImageIO *io, fi_handle handle) {
84 	return FALSE;
85 }
86 
87 static BOOL DLL_CALLCONV
SupportsExportDepth(int depth)88 SupportsExportDepth(int depth) {
89 	return FALSE;
90 }
91 
92 static BOOL DLL_CALLCONV
SupportsExportType(FREE_IMAGE_TYPE type)93 SupportsExportType(FREE_IMAGE_TYPE type) {
94 	return FALSE;
95 }
96 
97 static BOOL DLL_CALLCONV
SupportsNoPixels()98 SupportsNoPixels() {
99 	return TRUE;
100 }
101 
102 // ----------------------------------------------------------
103 
104 static FIBITMAP * DLL_CALLCONV
Load(FreeImageIO * io,fi_handle handle,int page,int flags,void * data)105 Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
106 	FIBITMAP *dib = NULL;
107 
108 	if(!handle) {
109 		return NULL;
110 	}
111 
112 	try {
113 		CUTHEADER header;
114 
115 		BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS;
116 
117 		// read the cut header
118 
119 		if(io->read_proc(&header, 1, sizeof(CUTHEADER), handle) != sizeof(CUTHEADER)) {
120 			throw FI_MSG_ERROR_PARSING;
121 		}
122 
123 #ifdef FREEIMAGE_BIGENDIAN
124 		SwapShort((WORD *)&header.width);
125 		SwapShort((WORD *)&header.height);
126 #endif
127 
128 		if ((header.width == 0) || (header.height == 0)) {
129 			return NULL;
130 		}
131 
132 		// allocate a new bitmap
133 
134 		dib = FreeImage_AllocateHeader(header_only, header.width, header.height, 8);
135 
136 		if (dib == NULL) {
137 			throw FI_MSG_ERROR_DIB_MEMORY;
138 		}
139 
140 		// stuff it with a palette
141 
142 		RGBQUAD *palette = FreeImage_GetPalette(dib);
143 
144 		for (int j = 0; j < 256; ++j) {
145 			palette[j].rgbBlue = palette[j].rgbGreen = palette[j].rgbRed = (BYTE)j;
146 		}
147 
148 		if(header_only) {
149 			// header only mode
150 			return dib;
151 		}
152 
153 		// unpack the RLE bitmap bits
154 
155 		BYTE *bits = FreeImage_GetScanLine(dib, header.height - 1);
156 
157 		unsigned i = 0, k = 0;
158 		unsigned pitch = FreeImage_GetPitch(dib);
159 		unsigned size = header.width * header.height;
160 		BYTE count = 0, run = 0;
161 
162 		while (i < size) {
163 			if(io->read_proc(&count, 1, sizeof(BYTE), handle) != 1) {
164 				throw FI_MSG_ERROR_PARSING;
165 			}
166 
167 			if (count == 0) {
168 				k = 0;
169 				bits -= pitch;
170 
171 				// paint shop pro adds two useless bytes here...
172 
173 				io->read_proc(&count, 1, sizeof(BYTE), handle);
174 				io->read_proc(&count, 1, sizeof(BYTE), handle);
175 
176 				continue;
177 			}
178 
179 			if (count & 0x80) {
180 				count &= ~(0x80);
181 
182 				if(io->read_proc(&run, 1, sizeof(BYTE), handle) != 1) {
183 					throw FI_MSG_ERROR_PARSING;
184 				}
185 
186 				if(k + count <= header.width) {
187 					memset(bits + k, run, count);
188 				} else {
189 					throw FI_MSG_ERROR_PARSING;
190 				}
191 			} else {
192 				if(k + count <= header.width) {
193 					if(io->read_proc(&bits[k], count, sizeof(BYTE), handle) != 1) {
194 						throw FI_MSG_ERROR_PARSING;
195 					}
196 				} else {
197 					throw FI_MSG_ERROR_PARSING;
198 				}
199 			}
200 
201 			k += count;
202 			i += count;
203 		}
204 
205 		return dib;
206 
207 	} catch(const char* text) {
208 		if(dib) {
209 			FreeImage_Unload(dib);
210 		}
211 		FreeImage_OutputMessageProc(s_format_id, text);
212 		return NULL;
213 	}
214 }
215 
216 // ==========================================================
217 //   Init
218 // ==========================================================
219 
220 void DLL_CALLCONV
InitCUT(Plugin * plugin,int format_id)221 InitCUT(Plugin *plugin, int format_id) {
222 	s_format_id = format_id;
223 
224 	plugin->format_proc = Format;
225 	plugin->description_proc = Description;
226 	plugin->extension_proc = Extension;
227 	plugin->regexpr_proc = RegExpr;
228 	plugin->open_proc = NULL;
229 	plugin->close_proc = NULL;
230 	plugin->pagecount_proc = NULL;
231 	plugin->pagecapability_proc = NULL;
232 	plugin->load_proc = Load;
233 	plugin->save_proc = NULL;
234 	plugin->validate_proc = Validate;
235 	plugin->mime_proc = MimeType;
236 	plugin->supports_export_bpp_proc = SupportsExportDepth;
237 	plugin->supports_export_type_proc = SupportsExportType;
238 	plugin->supports_icc_profiles_proc = NULL;
239 	plugin->supports_no_pixels_proc = SupportsNoPixels;
240 }
241