1 // ==========================================================
2 // Tag manipulation functions
3 //
4 // Design and implementation by
5 // - Herv� Drolon <drolon@infonie.fr>
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 #ifdef _MSC_VER
23 #pragma warning (disable : 4786) // identifier was truncated to 'number' characters
24 #endif
25 
26 #include "FreeImage.h"
27 #include "Utilities.h"
28 #include "FreeImageTag.h"
29 
30 // --------------------------------------------------------------------------
31 // FITAG header definition
32 // --------------------------------------------------------------------------
33 
FI_STRUCT(FITAGHEADER)34 FI_STRUCT (FITAGHEADER) {
35 	char *key;			// tag field name
36 	char *description;	// tag description
37 	WORD id;			// tag ID
38 	WORD type;			// tag data type (see FREE_IMAGE_MDTYPE)
39 	DWORD count;		// number of components (in 'tag data types' units)
40 	DWORD length;		// value length in bytes
41 	void *value;		// tag value
42 };
43 
44 // --------------------------------------------------------------------------
45 // FITAG creation / destruction
46 // --------------------------------------------------------------------------
47 
48 FITAG * DLL_CALLCONV
FreeImage_CreateTag()49 FreeImage_CreateTag() {
50 	FITAG *tag = (FITAG *)malloc(sizeof(FITAG));
51 
52 	if (tag != NULL) {
53 		unsigned tag_size = sizeof(FITAGHEADER);
54 		tag->data = (BYTE *)malloc(tag_size * sizeof(BYTE));
55 		if (tag->data != NULL) {
56 			memset(tag->data, 0, tag_size);
57 			return tag;
58 		}
59 		free(tag);
60 	}
61 
62 	return NULL;
63 }
64 
65 void DLL_CALLCONV
FreeImage_DeleteTag(FITAG * tag)66 FreeImage_DeleteTag(FITAG *tag) {
67 	if (NULL != tag) {
68 		if (NULL != tag->data) {
69 			FITAGHEADER *tag_header = (FITAGHEADER *)tag->data;
70 			// delete tag members
71 			free(tag_header->key);
72 			free(tag_header->description);
73 			free(tag_header->value);
74 			// delete the tag
75 			free(tag->data);
76 		}
77 		// and the wrapper
78 		free(tag);
79 	}
80 }
81 
82 FITAG * DLL_CALLCONV
FreeImage_CloneTag(FITAG * tag)83 FreeImage_CloneTag(FITAG *tag) {
84 	if(!tag) return NULL;
85 
86 	// allocate a new tag
87 	FITAG *clone = FreeImage_CreateTag();
88 	if(!clone) return NULL;
89 
90 	try {
91 		// copy the tag
92 		FITAGHEADER *src_tag = (FITAGHEADER *)tag->data;
93 		FITAGHEADER *dst_tag = (FITAGHEADER *)clone->data;
94 
95 		// tag ID
96 		dst_tag->id = src_tag->id;
97 		// tag key
98 		if(src_tag->key) {
99 			dst_tag->key = (char*)malloc((strlen(src_tag->key) + 1) * sizeof(char));
100 			if(!dst_tag->key) {
101 				throw FI_MSG_ERROR_MEMORY;
102 			}
103 			strcpy(dst_tag->key, src_tag->key);
104 		}
105 		// tag description
106 		if(src_tag->description) {
107 			dst_tag->description = (char*)malloc((strlen(src_tag->description) + 1) * sizeof(char));
108 			if(!dst_tag->description) {
109 				throw FI_MSG_ERROR_MEMORY;
110 			}
111 			strcpy(dst_tag->description, src_tag->description);
112 		}
113 		// tag data type
114 		dst_tag->type = src_tag->type;
115 		// tag count
116 		dst_tag->count = src_tag->count;
117 		// tag length
118 		dst_tag->length = src_tag->length;
119 		// tag value
120 		switch(dst_tag->type) {
121 			case FIDT_ASCII:
122 				dst_tag->value = (BYTE*)malloc((src_tag->length + 1) * sizeof(BYTE));
123 				if(!dst_tag->value) {
124 					throw FI_MSG_ERROR_MEMORY;
125 				}
126 				memcpy(dst_tag->value, src_tag->value, src_tag->length);
127 				((BYTE*)dst_tag->value)[src_tag->length] = 0;
128 				break;
129 			default:
130 				dst_tag->value = (BYTE*)malloc(src_tag->length * sizeof(BYTE));
131 				if(!dst_tag->value) {
132 					throw FI_MSG_ERROR_MEMORY;
133 				}
134 				memcpy(dst_tag->value, src_tag->value, src_tag->length);
135 				break;
136 		}
137 
138 		return clone;
139 
140 	} catch(const char *message) {
141 		FreeImage_DeleteTag(clone);
142 		FreeImage_OutputMessageProc(FIF_UNKNOWN, message);
143 		return NULL;
144 	}
145 }
146 
147 // --------------------------------------------------------------------------
148 // FITAG getters / setters
149 // --------------------------------------------------------------------------
150 
151 const char * DLL_CALLCONV
FreeImage_GetTagKey(FITAG * tag)152 FreeImage_GetTagKey(FITAG *tag) {
153 	return tag ? ((FITAGHEADER *)tag->data)->key : 0;
154 }
155 
156 const char * DLL_CALLCONV
FreeImage_GetTagDescription(FITAG * tag)157 FreeImage_GetTagDescription(FITAG *tag) {
158 	return tag ? ((FITAGHEADER *)tag->data)->description : 0;
159 }
160 
161 WORD DLL_CALLCONV
FreeImage_GetTagID(FITAG * tag)162 FreeImage_GetTagID(FITAG *tag) {
163 	return tag ? ((FITAGHEADER *)tag->data)->id : 0;
164 }
165 
166 FREE_IMAGE_MDTYPE DLL_CALLCONV
FreeImage_GetTagType(FITAG * tag)167 FreeImage_GetTagType(FITAG *tag) {
168 	return tag ? (FREE_IMAGE_MDTYPE)(((FITAGHEADER *)tag->data)->type) : FIDT_NOTYPE;
169 }
170 
171 DWORD DLL_CALLCONV
FreeImage_GetTagCount(FITAG * tag)172 FreeImage_GetTagCount(FITAG *tag) {
173 	return tag ? ((FITAGHEADER *)tag->data)->count : 0;
174 }
175 
176 DWORD DLL_CALLCONV
FreeImage_GetTagLength(FITAG * tag)177 FreeImage_GetTagLength(FITAG *tag) {
178 	return tag ? ((FITAGHEADER *)tag->data)->length : 0;
179 }
180 
181 const void *DLL_CALLCONV
FreeImage_GetTagValue(FITAG * tag)182 FreeImage_GetTagValue(FITAG *tag) {
183 	return tag ? ((FITAGHEADER *)tag->data)->value : 0;
184 }
185 
186 BOOL DLL_CALLCONV
FreeImage_SetTagKey(FITAG * tag,const char * key)187 FreeImage_SetTagKey(FITAG *tag, const char *key) {
188 	if(tag && key) {
189 		FITAGHEADER *tag_header = (FITAGHEADER *)tag->data;
190 		if(tag_header->key) free(tag_header->key);
191 		tag_header->key = (char*)malloc(strlen(key) + 1);
192 		strcpy(tag_header->key, key);
193 		return TRUE;
194 	}
195 	return FALSE;
196 }
197 
198 BOOL DLL_CALLCONV
FreeImage_SetTagDescription(FITAG * tag,const char * description)199 FreeImage_SetTagDescription(FITAG *tag, const char *description) {
200 	if(tag && description) {
201 		FITAGHEADER *tag_header = (FITAGHEADER *)tag->data;
202 		if(tag_header->description) free(tag_header->description);
203 		tag_header->description = (char*)malloc(strlen(description) + 1);
204 		strcpy(tag_header->description, description);
205 		return TRUE;
206 	}
207 	return FALSE;
208 }
209 
210 BOOL DLL_CALLCONV
FreeImage_SetTagID(FITAG * tag,WORD id)211 FreeImage_SetTagID(FITAG *tag, WORD id) {
212 	if(tag) {
213 		FITAGHEADER *tag_header = (FITAGHEADER *)tag->data;
214 		tag_header->id = id;
215 		return TRUE;
216 	}
217 	return FALSE;
218 }
219 
220 BOOL DLL_CALLCONV
FreeImage_SetTagType(FITAG * tag,FREE_IMAGE_MDTYPE type)221 FreeImage_SetTagType(FITAG *tag, FREE_IMAGE_MDTYPE type) {
222 	if(tag) {
223 		FITAGHEADER *tag_header = (FITAGHEADER *)tag->data;
224 		tag_header->type = (WORD)type;
225 		return TRUE;
226 	}
227 	return FALSE;
228 }
229 
230 BOOL DLL_CALLCONV
FreeImage_SetTagCount(FITAG * tag,DWORD count)231 FreeImage_SetTagCount(FITAG *tag, DWORD count) {
232 	if(tag) {
233 		FITAGHEADER *tag_header = (FITAGHEADER *)tag->data;
234 		tag_header->count = count;
235 		return TRUE;
236 	}
237 	return FALSE;
238 }
239 
240 BOOL DLL_CALLCONV
FreeImage_SetTagLength(FITAG * tag,DWORD length)241 FreeImage_SetTagLength(FITAG *tag, DWORD length) {
242 	if(tag) {
243 		FITAGHEADER *tag_header = (FITAGHEADER *)tag->data;
244 		tag_header->length = length;
245 		return TRUE;
246 	}
247 	return FALSE;
248 }
249 
250 BOOL DLL_CALLCONV
FreeImage_SetTagValue(FITAG * tag,const void * value)251 FreeImage_SetTagValue(FITAG *tag, const void *value) {
252 	if(tag && value) {
253 		FITAGHEADER *tag_header = (FITAGHEADER *)tag->data;
254 		// first, check the tag
255 		if(tag_header->count * FreeImage_TagDataWidth((FREE_IMAGE_MDTYPE)tag_header->type) != tag_header->length) {
256 			// invalid data count ?
257 			return FALSE;
258 		}
259 
260 		if(tag_header->value) {
261 			free(tag_header->value);
262 		}
263 
264 		switch(tag_header->type) {
265 			case FIDT_ASCII:
266 			{
267 				tag_header->value = (char*)malloc((tag_header->length + 1) * sizeof(char));
268 				if(!tag_header->value) {
269 					return FALSE;
270 				}
271 				char *src_data = (char*)value;
272 				char *dst_data = (char*)tag_header->value;
273 				for(DWORD i = 0; i < tag_header->length; i++) {
274 					dst_data[i] = src_data[i];
275 				}
276 				dst_data[tag_header->length] = '\0';
277 			}
278 			break;
279 
280 			default:
281 				tag_header->value = malloc(tag_header->length * sizeof(BYTE));
282 				if(!tag_header->value) {
283 					return FALSE;
284 				}
285 				memcpy(tag_header->value, value, tag_header->length);
286 				break;
287 		}
288 		return TRUE;
289 	}
290 	return FALSE;
291 }
292 
293 
294 // --------------------------------------------------------------------------
295 // FITAG internal helper functions
296 // --------------------------------------------------------------------------
297 
298 unsigned
FreeImage_TagDataWidth(FREE_IMAGE_MDTYPE type)299 FreeImage_TagDataWidth(FREE_IMAGE_MDTYPE type) {
300 	static const unsigned format_bytes[] = {
301 		0, // FIDT_NOTYPE	= 0,	// placeholder
302 		1, // FIDT_BYTE		= 1,	// 8-bit unsigned integer
303 		1, // FIDT_ASCII	= 2,	// 8-bit bytes w/ last byte null
304 		2, // FIDT_SHORT	= 3,	// 16-bit unsigned integer
305 		4, // FIDT_LONG		= 4,	// 32-bit unsigned integer
306 		8, // FIDT_RATIONAL	= 5,	// 64-bit unsigned fraction
307 		1, // FIDT_SBYTE	= 6,	// 8-bit signed integer
308 		1, // FIDT_UNDEFINED= 7,	// 8-bit untyped data
309 		2, // FIDT_SSHORT	= 8,	// 16-bit signed integer
310 		4, // FIDT_SLONG	= 9,	// 32-bit signed integer
311 		8, // FIDT_SRATIONAL= 10,	// 64-bit signed fraction
312 		4, // FIDT_FLOAT	= 11,	// 32-bit IEEE floating point
313 		8, // FIDT_DOUBLE	= 12,	// 64-bit IEEE floating point
314 		4, // FIDT_IFD		= 13,	// 32-bit unsigned integer (offset)
315 		4, // FIDT_PALETTE	= 14	// 32-bit RGBQUAD
316 		0, // placeholder (15)
317 		8, // FIDT_LONG8	= 16,	// 64-bit unsigned integer
318 		8, // FIDT_SLONG8	= 17,	// 64-bit signed integer
319 		8  // FIDT_IFD8		= 18	// 64-bit unsigned integer (offset)
320 	};
321 
322 	  return (type < (sizeof(format_bytes)/sizeof(format_bytes[0]))) ?
323 		  format_bytes[type] : 0;
324 }
325 
326 size_t
FreeImage_GetTagMemorySize(FITAG * tag)327 FreeImage_GetTagMemorySize(FITAG *tag) {
328 	size_t size = 0;
329 	if (tag) {
330 		FITAGHEADER *tag_header = (FITAGHEADER *)tag->data;
331 		size += sizeof(FITAG);
332 		size += sizeof(FITAGHEADER);
333 		if (tag_header->key) {
334 			size += strlen(tag_header->key) + 1;
335 		}
336 		if (tag_header->description) {
337 			size += strlen(tag_header->description) + 1;
338 		}
339 		if (tag_header->value) {
340 			switch (tag_header->type) {
341 				case FIDT_ASCII:
342 					// for ASCII strings, the value of the count part of an ASCII tag entry includes the NULL.
343 					// however, FreeImage adds another '\0' to be sure that this last character is present.
344 					size += tag_header->length + 1;
345 					break;
346 				default:
347 					size += tag_header->length;
348 					break;
349 			}
350 		}
351 	}
352 	return size;
353 }
354