blob: cc12a5d16b91ee4bef06ef4afdfefe7c2dbcb3b7 [file] [log] [blame]
// ==========================================================
// Tag manipulation functions
//
// Design and implementation by
// - Hervé Drolon <drolon@infonie.fr>
//
// This file is part of FreeImage 3
//
// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
// THIS DISCLAIMER.
//
// Use at your own risk!
// ==========================================================
#ifdef _MSC_VER
#pragma warning (disable : 4786) // identifier was truncated to 'number' characters
#endif
#include "FreeImage.h"
#include "Utilities.h"
#include "FreeImageTag.h"
// --------------------------------------------------------------------------
// FITAG header definition
// --------------------------------------------------------------------------
FI_STRUCT (FITAGHEADER) {
char *key; // tag field name
char *description; // tag description
WORD id; // tag ID
WORD type; // tag data type (see FREE_IMAGE_MDTYPE)
DWORD count; // number of components (in 'tag data types' units)
DWORD length; // value length in bytes
void *value; // tag value
};
// --------------------------------------------------------------------------
// FITAG creation / destruction
// --------------------------------------------------------------------------
FITAG * DLL_CALLCONV
FreeImage_CreateTag() {
FITAG *tag = (FITAG *)malloc(sizeof(FITAG));
if (tag != NULL) {
unsigned tag_size = sizeof(FITAGHEADER);
tag->data = (BYTE *)malloc(tag_size * sizeof(BYTE));
if (tag->data != NULL) {
memset(tag->data, 0, tag_size);
return tag;
}
free(tag);
}
return NULL;
}
void DLL_CALLCONV
FreeImage_DeleteTag(FITAG *tag) {
if (NULL != tag) {
if (NULL != tag->data) {
FITAGHEADER *tag_header = (FITAGHEADER *)tag->data;
// delete tag members
free(tag_header->key);
free(tag_header->description);
free(tag_header->value);
// delete the tag
free(tag->data);
}
// and the wrapper
free(tag);
}
}
FITAG * DLL_CALLCONV
FreeImage_CloneTag(FITAG *tag) {
if(!tag) return NULL;
// allocate a new tag
FITAG *clone = FreeImage_CreateTag();
if(!clone) return NULL;
try {
// copy the tag
FITAGHEADER *src_tag = (FITAGHEADER *)tag->data;
FITAGHEADER *dst_tag = (FITAGHEADER *)clone->data;
// tag ID
dst_tag->id = src_tag->id;
// tag key
if(src_tag->key) {
dst_tag->key = (char*)malloc((strlen(src_tag->key) + 1) * sizeof(char));
if(!dst_tag->key) {
throw FI_MSG_ERROR_MEMORY;
}
strcpy(dst_tag->key, src_tag->key);
}
// tag description
if(src_tag->description) {
dst_tag->description = (char*)malloc((strlen(src_tag->description) + 1) * sizeof(char));
if(!dst_tag->description) {
throw FI_MSG_ERROR_MEMORY;
}
strcpy(dst_tag->description, src_tag->description);
}
// tag data type
dst_tag->type = src_tag->type;
// tag count
dst_tag->count = src_tag->count;
// tag length
dst_tag->length = src_tag->length;
// tag value
switch(dst_tag->type) {
case FIDT_ASCII:
dst_tag->value = (BYTE*)malloc((src_tag->length + 1) * sizeof(BYTE));
if(!dst_tag->value) {
throw FI_MSG_ERROR_MEMORY;
}
memcpy(dst_tag->value, src_tag->value, src_tag->length);
((BYTE*)dst_tag->value)[src_tag->length] = 0;
break;
default:
dst_tag->value = (BYTE*)malloc(src_tag->length * sizeof(BYTE));
if(!dst_tag->value) {
throw FI_MSG_ERROR_MEMORY;
}
memcpy(dst_tag->value, src_tag->value, src_tag->length);
break;
}
return clone;
} catch(const char *message) {
FreeImage_DeleteTag(clone);
FreeImage_OutputMessageProc(FIF_UNKNOWN, message);
return NULL;
}
}
// --------------------------------------------------------------------------
// FITAG getters / setters
// --------------------------------------------------------------------------
const char * DLL_CALLCONV
FreeImage_GetTagKey(FITAG *tag) {
return tag ? ((FITAGHEADER *)tag->data)->key : 0;
}
const char * DLL_CALLCONV
FreeImage_GetTagDescription(FITAG *tag) {
return tag ? ((FITAGHEADER *)tag->data)->description : 0;
}
WORD DLL_CALLCONV
FreeImage_GetTagID(FITAG *tag) {
return tag ? ((FITAGHEADER *)tag->data)->id : 0;
}
FREE_IMAGE_MDTYPE DLL_CALLCONV
FreeImage_GetTagType(FITAG *tag) {
return tag ? (FREE_IMAGE_MDTYPE)(((FITAGHEADER *)tag->data)->type) : FIDT_NOTYPE;
}
DWORD DLL_CALLCONV
FreeImage_GetTagCount(FITAG *tag) {
return tag ? ((FITAGHEADER *)tag->data)->count : 0;
}
DWORD DLL_CALLCONV
FreeImage_GetTagLength(FITAG *tag) {
return tag ? ((FITAGHEADER *)tag->data)->length : 0;
}
const void *DLL_CALLCONV
FreeImage_GetTagValue(FITAG *tag) {
return tag ? ((FITAGHEADER *)tag->data)->value : 0;
}
BOOL DLL_CALLCONV
FreeImage_SetTagKey(FITAG *tag, const char *key) {
if(tag && key) {
FITAGHEADER *tag_header = (FITAGHEADER *)tag->data;
if(tag_header->key) free(tag_header->key);
tag_header->key = (char*)malloc(strlen(key) + 1);
strcpy(tag_header->key, key);
return TRUE;
}
return FALSE;
}
BOOL DLL_CALLCONV
FreeImage_SetTagDescription(FITAG *tag, const char *description) {
if(tag && description) {
FITAGHEADER *tag_header = (FITAGHEADER *)tag->data;
if(tag_header->description) free(tag_header->description);
tag_header->description = (char*)malloc(strlen(description) + 1);
strcpy(tag_header->description, description);
return TRUE;
}
return FALSE;
}
BOOL DLL_CALLCONV
FreeImage_SetTagID(FITAG *tag, WORD id) {
if(tag) {
FITAGHEADER *tag_header = (FITAGHEADER *)tag->data;
tag_header->id = id;
return TRUE;
}
return FALSE;
}
BOOL DLL_CALLCONV
FreeImage_SetTagType(FITAG *tag, FREE_IMAGE_MDTYPE type) {
if(tag) {
FITAGHEADER *tag_header = (FITAGHEADER *)tag->data;
tag_header->type = (WORD)type;
return TRUE;
}
return FALSE;
}
BOOL DLL_CALLCONV
FreeImage_SetTagCount(FITAG *tag, DWORD count) {
if(tag) {
FITAGHEADER *tag_header = (FITAGHEADER *)tag->data;
tag_header->count = count;
return TRUE;
}
return FALSE;
}
BOOL DLL_CALLCONV
FreeImage_SetTagLength(FITAG *tag, DWORD length) {
if(tag) {
FITAGHEADER *tag_header = (FITAGHEADER *)tag->data;
tag_header->length = length;
return TRUE;
}
return FALSE;
}
BOOL DLL_CALLCONV
FreeImage_SetTagValue(FITAG *tag, const void *value) {
if(tag && value) {
FITAGHEADER *tag_header = (FITAGHEADER *)tag->data;
// first, check the tag
if(tag_header->count * FreeImage_TagDataWidth((FREE_IMAGE_MDTYPE)tag_header->type) != tag_header->length) {
// invalid data count ?
return FALSE;
}
if(tag_header->value) {
free(tag_header->value);
}
switch(tag_header->type) {
case FIDT_ASCII:
{
tag_header->value = (char*)malloc((tag_header->length + 1) * sizeof(char));
if(!tag_header->value) {
return FALSE;
}
char *src_data = (char*)value;
char *dst_data = (char*)tag_header->value;
for(DWORD i = 0; i < tag_header->length; i++) {
dst_data[i] = src_data[i];
}
dst_data[tag_header->length] = '\0';
}
break;
default:
tag_header->value = malloc(tag_header->length * sizeof(BYTE));
if(!tag_header->value) {
return FALSE;
}
memcpy(tag_header->value, value, tag_header->length);
break;
}
return TRUE;
}
return FALSE;
}
// --------------------------------------------------------------------------
// FITAG internal helper functions
// --------------------------------------------------------------------------
unsigned
FreeImage_TagDataWidth(FREE_IMAGE_MDTYPE type) {
static const unsigned format_bytes[] = {
0, // FIDT_NOTYPE = 0, // placeholder
1, // FIDT_BYTE = 1, // 8-bit unsigned integer
1, // FIDT_ASCII = 2, // 8-bit bytes w/ last byte null
2, // FIDT_SHORT = 3, // 16-bit unsigned integer
4, // FIDT_LONG = 4, // 32-bit unsigned integer
8, // FIDT_RATIONAL = 5, // 64-bit unsigned fraction
1, // FIDT_SBYTE = 6, // 8-bit signed integer
1, // FIDT_UNDEFINED= 7, // 8-bit untyped data
2, // FIDT_SSHORT = 8, // 16-bit signed integer
4, // FIDT_SLONG = 9, // 32-bit signed integer
8, // FIDT_SRATIONAL= 10, // 64-bit signed fraction
4, // FIDT_FLOAT = 11, // 32-bit IEEE floating point
8, // FIDT_DOUBLE = 12, // 64-bit IEEE floating point
4, // FIDT_IFD = 13, // 32-bit unsigned integer (offset)
4, // FIDT_PALETTE = 14 // 32-bit RGBQUAD
0, // placeholder (15)
8, // FIDT_LONG8 = 16, // 64-bit unsigned integer
8, // FIDT_SLONG8 = 17, // 64-bit signed integer
8 // FIDT_IFD8 = 18 // 64-bit unsigned integer (offset)
};
return (type < (sizeof(format_bytes)/sizeof(format_bytes[0]))) ?
format_bytes[type] : 0;
}
size_t
FreeImage_GetTagMemorySize(FITAG *tag) {
size_t size = 0;
if (tag) {
FITAGHEADER *tag_header = (FITAGHEADER *)tag->data;
size += sizeof(FITAG);
size += sizeof(FITAGHEADER);
if (tag_header->key) {
size += strlen(tag_header->key) + 1;
}
if (tag_header->description) {
size += strlen(tag_header->description) + 1;
}
if (tag_header->value) {
switch (tag_header->type) {
case FIDT_ASCII:
// for ASCII strings, the value of the count part of an ASCII tag entry includes the NULL.
// however, FreeImage adds another '\0' to be sure that this last character is present.
size += tag_header->length + 1;
break;
default:
size += tag_header->length;
break;
}
}
}
return size;
}