| // ========================================================== |
| // 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; |
| } |