// ========================================================== // Tag manipulation functions // // Design and implementation by // - Hervé Drolon // // 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; }