1/* exif-mnote-data-fuji.c 2 * 3 * Copyright (c) 2002 Lutz Mueller <lutz@users.sourceforge.net> 4 * 5 * This library is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Lesser General Public 7 * License as published by the Free Software Foundation; either 8 * version 2 of the License, or (at your option) any later version. 9 * 10 * This library is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * Lesser General Public License for more details. 14 * 15 * You should have received a copy of the GNU Lesser General Public 16 * License along with this library; if not, write to the 17 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 18 * Boston, MA 02110-1301 USA. 19 */ 20 21#include <stdlib.h> 22#include <string.h> 23 24 25#include <config.h> 26#include <libexif/exif-byte-order.h> 27#include <libexif/exif-utils.h> 28 29#include "exif-mnote-data-fuji.h" 30 31struct _MNoteFujiDataPrivate { 32 ExifByteOrder order; 33}; 34 35static void 36exif_mnote_data_fuji_clear (ExifMnoteDataFuji *n) 37{ 38 ExifMnoteData *d = (ExifMnoteData *) n; 39 unsigned int i; 40 41 if (!n) return; 42 43 if (n->entries) { 44 for (i = 0; i < n->count; i++) 45 if (n->entries[i].data) { 46 exif_mem_free (d->mem, n->entries[i].data); 47 n->entries[i].data = NULL; 48 } 49 exif_mem_free (d->mem, n->entries); 50 n->entries = NULL; 51 n->count = 0; 52 } 53} 54 55static void 56exif_mnote_data_fuji_free (ExifMnoteData *n) 57{ 58 if (!n) return; 59 60 exif_mnote_data_fuji_clear ((ExifMnoteDataFuji *) n); 61} 62 63static char * 64exif_mnote_data_fuji_get_value (ExifMnoteData *d, unsigned int i, char *val, unsigned int maxlen) 65{ 66 ExifMnoteDataFuji *n = (ExifMnoteDataFuji *) d; 67 68 if (!d || !val) return NULL; 69 if (i > n->count -1) return NULL; 70 exif_log (d->log, EXIF_LOG_CODE_DEBUG, "ExifMnoteDataFuji", 71 "Querying value for tag '%s'...", 72 mnote_fuji_tag_get_name (n->entries[i].tag)); 73 return mnote_fuji_entry_get_value (&n->entries[i], val, maxlen); 74} 75 76static void 77exif_mnote_data_fuji_save (ExifMnoteData *ne, unsigned char **buf, 78 unsigned int *buf_size) 79{ 80 ExifMnoteDataFuji *n = (ExifMnoteDataFuji *) ne; 81 size_t i, o, s, doff; 82 unsigned char *t; 83 size_t ts; 84 85 if (!n || !buf || !buf_size) return; 86 87 /* 88 * Allocate enough memory for all entries and the number 89 * of entries. 90 */ 91 *buf_size = 8 + 4 + 2 + n->count * 12 + 4; 92 *buf = exif_mem_alloc (ne->mem, *buf_size); 93 if (!*buf) { 94 *buf_size = 0; 95 return; 96 } 97 98 /* 99 * Header: "FUJIFILM" and 4 bytes offset to the first entry. 100 * As the first entry will start right thereafter, the offset is 12. 101 */ 102 memcpy (*buf, "FUJIFILM", 8); 103 exif_set_long (*buf + 8, n->order, 12); 104 105 /* Save the number of entries */ 106 exif_set_short (*buf + 8 + 4, n->order, (ExifShort) n->count); 107 108 /* Save each entry */ 109 for (i = 0; i < n->count; i++) { 110 o = 8 + 4 + 2 + i * 12; 111 exif_set_short (*buf + o + 0, n->order, (ExifShort) n->entries[i].tag); 112 exif_set_short (*buf + o + 2, n->order, (ExifShort) n->entries[i].format); 113 exif_set_long (*buf + o + 4, n->order, n->entries[i].components); 114 o += 8; 115 s = exif_format_get_size (n->entries[i].format) * 116 n->entries[i].components; 117 if (s > 65536) { 118 /* Corrupt data: EXIF data size is limited to the 119 * maximum size of a JPEG segment (64 kb). 120 */ 121 continue; 122 } 123 if (s > 4) { 124 ts = *buf_size + s; 125 126 /* Ensure even offsets. Set padding bytes to 0. */ 127 if (s & 1) ts += 1; 128 t = exif_mem_realloc (ne->mem, *buf, ts); 129 if (!t) { 130 return; 131 } 132 *buf = t; 133 *buf_size = ts; 134 doff = *buf_size - s; 135 if (s & 1) { doff--; *(*buf + *buf_size - 1) = '\0'; } 136 exif_set_long (*buf + o, n->order, doff); 137 } else 138 doff = o; 139 140 /* 141 * Write the data. Fill unneeded bytes with 0. Do not 142 * crash if data is NULL. 143 */ 144 if (!n->entries[i].data) memset (*buf + doff, 0, s); 145 else memcpy (*buf + doff, n->entries[i].data, s); 146 } 147} 148 149static void 150exif_mnote_data_fuji_load (ExifMnoteData *en, 151 const unsigned char *buf, unsigned int buf_size) 152{ 153 ExifMnoteDataFuji *n = (ExifMnoteDataFuji*) en; 154 ExifLong c; 155 size_t i, tcount, o, datao; 156 157 if (!n || !buf || !buf_size) { 158 exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA, 159 "ExifMnoteDataFuji", "Short MakerNote"); 160 return; 161 } 162 datao = 6 + n->offset; 163 if ((datao + 12 < datao) || (datao + 12 < 12) || (datao + 12 > buf_size)) { 164 exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA, 165 "ExifMnoteDataFuji", "Short MakerNote"); 166 return; 167 } 168 169 n->order = EXIF_BYTE_ORDER_INTEL; 170 datao += exif_get_long (buf + datao + 8, EXIF_BYTE_ORDER_INTEL); 171 if ((datao + 2 < datao) || (datao + 2 < 2) || 172 (datao + 2 > buf_size)) { 173 exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA, 174 "ExifMnoteDataFuji", "Short MakerNote"); 175 return; 176 } 177 178 /* Read the number of tags */ 179 c = exif_get_short (buf + datao, EXIF_BYTE_ORDER_INTEL); 180 datao += 2; 181 182 /* Remove any old entries */ 183 exif_mnote_data_fuji_clear (n); 184 185 /* Reserve enough space for all the possible MakerNote tags */ 186 n->entries = exif_mem_alloc (en->mem, sizeof (MnoteFujiEntry) * c); 187 if (!n->entries) { 188 EXIF_LOG_NO_MEMORY(en->log, "ExifMnoteDataFuji", sizeof (MnoteFujiEntry) * c); 189 return; 190 } 191 192 /* Parse all c entries, storing ones that are successfully parsed */ 193 tcount = 0; 194 for (i = c, o = datao; i; --i, o += 12) { 195 size_t s; 196 if ((o + 12 < o) || (o + 12 < 12) || (o + 12 > buf_size)) { 197 exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA, 198 "ExifMnoteDataFuji", "Short MakerNote"); 199 break; 200 } 201 202 n->entries[tcount].tag = exif_get_short (buf + o, n->order); 203 n->entries[tcount].format = exif_get_short (buf + o + 2, n->order); 204 n->entries[tcount].components = exif_get_long (buf + o + 4, n->order); 205 n->entries[tcount].order = n->order; 206 207 exif_log (en->log, EXIF_LOG_CODE_DEBUG, "ExifMnoteDataFuji", 208 "Loading entry 0x%x ('%s')...", n->entries[tcount].tag, 209 mnote_fuji_tag_get_name (n->entries[tcount].tag)); 210 211 /* 212 * Size? If bigger than 4 bytes, the actual data is not 213 * in the entry but somewhere else (offset). 214 */ 215 s = exif_format_get_size (n->entries[tcount].format) * n->entries[tcount].components; 216 n->entries[tcount].size = s; 217 if (s) { 218 size_t dataofs = o + 8; 219 if (s > 4) 220 /* The data in this case is merely a pointer */ 221 dataofs = exif_get_long (buf + dataofs, n->order) + 6 + n->offset; 222 if ((dataofs + s < dataofs) || (dataofs + s < s) || 223 (dataofs + s >= buf_size)) { 224 exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA, 225 "ExifMnoteDataFuji", "Tag data past end of " 226 "buffer (%u >= %u)", dataofs + s, buf_size); 227 continue; 228 } 229 230 n->entries[tcount].data = exif_mem_alloc (en->mem, s); 231 if (!n->entries[tcount].data) { 232 EXIF_LOG_NO_MEMORY(en->log, "ExifMnoteDataFuji", s); 233 continue; 234 } 235 memcpy (n->entries[tcount].data, buf + dataofs, s); 236 } 237 238 /* Tag was successfully parsed */ 239 ++tcount; 240 } 241 /* Store the count of successfully parsed tags */ 242 n->count = tcount; 243} 244 245static unsigned int 246exif_mnote_data_fuji_count (ExifMnoteData *n) 247{ 248 return n ? ((ExifMnoteDataFuji *) n)->count : 0; 249} 250 251static unsigned int 252exif_mnote_data_fuji_get_id (ExifMnoteData *d, unsigned int n) 253{ 254 ExifMnoteDataFuji *note = (ExifMnoteDataFuji *) d; 255 256 if (!note) return 0; 257 if (note->count <= n) return 0; 258 return note->entries[n].tag; 259} 260 261static const char * 262exif_mnote_data_fuji_get_name (ExifMnoteData *d, unsigned int i) 263{ 264 ExifMnoteDataFuji *n = (ExifMnoteDataFuji *) d; 265 266 if (!n) return NULL; 267 if (i >= n->count) return NULL; 268 return mnote_fuji_tag_get_name (n->entries[i].tag); 269} 270 271static const char * 272exif_mnote_data_fuji_get_title (ExifMnoteData *d, unsigned int i) 273{ 274 ExifMnoteDataFuji *n = (ExifMnoteDataFuji *) d; 275 276 if (!n) return NULL; 277 if (i >= n->count) return NULL; 278 return mnote_fuji_tag_get_title (n->entries[i].tag); 279} 280 281static const char * 282exif_mnote_data_fuji_get_description (ExifMnoteData *d, unsigned int i) 283{ 284 ExifMnoteDataFuji *n = (ExifMnoteDataFuji *) d; 285 286 if (!n) return NULL; 287 if (i >= n->count) return NULL; 288 return mnote_fuji_tag_get_description (n->entries[i].tag); 289} 290 291static void 292exif_mnote_data_fuji_set_byte_order (ExifMnoteData *d, ExifByteOrder o) 293{ 294 ExifByteOrder o_orig; 295 ExifMnoteDataFuji *n = (ExifMnoteDataFuji *) d; 296 unsigned int i; 297 298 if (!n) return; 299 300 o_orig = n->order; 301 n->order = o; 302 for (i = 0; i < n->count; i++) { 303 n->entries[i].order = o; 304 exif_array_set_byte_order (n->entries[i].format, n->entries[i].data, 305 n->entries[i].components, o_orig, o); 306 } 307} 308 309static void 310exif_mnote_data_fuji_set_offset (ExifMnoteData *n, unsigned int o) 311{ 312 if (n) ((ExifMnoteDataFuji *) n)->offset = o; 313} 314 315ExifMnoteData * 316exif_mnote_data_fuji_new (ExifMem *mem) 317{ 318 ExifMnoteData *d; 319 320 if (!mem) return NULL; 321 322 d = exif_mem_alloc (mem, sizeof (ExifMnoteDataFuji)); 323 if (!d) return NULL; 324 325 exif_mnote_data_construct (d, mem); 326 327 /* Set up function pointers */ 328 d->methods.free = exif_mnote_data_fuji_free; 329 d->methods.set_byte_order = exif_mnote_data_fuji_set_byte_order; 330 d->methods.set_offset = exif_mnote_data_fuji_set_offset; 331 d->methods.load = exif_mnote_data_fuji_load; 332 d->methods.save = exif_mnote_data_fuji_save; 333 d->methods.count = exif_mnote_data_fuji_count; 334 d->methods.get_id = exif_mnote_data_fuji_get_id; 335 d->methods.get_name = exif_mnote_data_fuji_get_name; 336 d->methods.get_title = exif_mnote_data_fuji_get_title; 337 d->methods.get_description = exif_mnote_data_fuji_get_description; 338 d->methods.get_value = exif_mnote_data_fuji_get_value; 339 340 return d; 341} 342