1 /* exif-mnote-data-canon.c 2 * 3 * Copyright (c) 2002, 2003 Lutz Mueller <lutz (at) users.sourceforge.net> 4 * Copyright (c) 2003 Matthieu Castet <mat-c (at) users.sourceforge.net> 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the 18 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 * Boston, MA 02110-1301 USA. 20 */ 21 22 #include <config.h> 23 #include "exif-mnote-data-canon.h" 24 25 #include <stdlib.h> 26 #include <stdio.h> 27 #include <string.h> 28 29 #include <libexif/exif-byte-order.h> 30 #include <libexif/exif-utils.h> 31 #include <libexif/exif-data.h> 32 33 #define DEBUG 34 35 static void 36 exif_mnote_data_canon_clear (ExifMnoteDataCanon *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 55 static void 56 exif_mnote_data_canon_free (ExifMnoteData *n) 57 { 58 if (!n) return; 59 60 exif_mnote_data_canon_clear ((ExifMnoteDataCanon *) n); 61 } 62 63 static void 64 exif_mnote_data_canon_get_tags (ExifMnoteDataCanon *dc, unsigned int n, 65 unsigned int *m, unsigned int *s) 66 { 67 unsigned int from = 0, to; 68 69 if (!dc || !m) return; 70 for (*m = 0; *m < dc->count; (*m)++) { 71 to = from + mnote_canon_entry_count_values (&dc->entries[*m]); 72 if (to > n) { 73 if (s) *s = n - from; 74 break; 75 } 76 from = to; 77 } 78 } 79 80 static char * 81 exif_mnote_data_canon_get_value (ExifMnoteData *note, unsigned int n, char *val, unsigned int maxlen) 82 { 83 ExifMnoteDataCanon *dc = (ExifMnoteDataCanon *) note; 84 unsigned int m, s; 85 86 if (!dc) return NULL; 87 exif_mnote_data_canon_get_tags (dc, n, &m, &s); 88 if (m >= dc->count) return NULL; 89 return mnote_canon_entry_get_value (&dc->entries[m], s, val, maxlen); 90 } 91 92 static void 93 exif_mnote_data_canon_set_byte_order (ExifMnoteData *d, ExifByteOrder o) 94 { 95 ExifByteOrder o_orig; 96 ExifMnoteDataCanon *n = (ExifMnoteDataCanon *) d; 97 unsigned int i; 98 99 if (!n) return; 100 101 o_orig = n->order; 102 n->order = o; 103 for (i = 0; i < n->count; i++) { 104 n->entries[i].order = o; 105 exif_array_set_byte_order (n->entries[i].format, n->entries[i].data, 106 n->entries[i].components, o_orig, o); 107 } 108 } 109 110 static void 111 exif_mnote_data_canon_set_offset (ExifMnoteData *n, unsigned int o) 112 { 113 if (n) ((ExifMnoteDataCanon *) n)->offset = o; 114 } 115 116 static void 117 exif_mnote_data_canon_save (ExifMnoteData *ne, 118 unsigned char **buf, unsigned int *buf_size) 119 { 120 ExifMnoteDataCanon *n = (ExifMnoteDataCanon *) ne; 121 size_t i, o, s, doff; 122 unsigned char *t; 123 size_t ts; 124 125 if (!n || !buf || !buf_size) return; 126 127 /* 128 * Allocate enough memory for all entries and the number 129 * of entries. 130 */ 131 *buf_size = 2 + n->count * 12 + 4; 132 *buf = exif_mem_alloc (ne->mem, sizeof (char) * *buf_size); 133 if (!*buf) { 134 EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteCanon", *buf_size); 135 return; 136 } 137 138 /* Save the number of entries */ 139 exif_set_short (*buf, n->order, (ExifShort) n->count); 140 141 /* Save each entry */ 142 for (i = 0; i < n->count; i++) { 143 o = 2 + i * 12; 144 exif_set_short (*buf + o + 0, n->order, (ExifShort) n->entries[i].tag); 145 exif_set_short (*buf + o + 2, n->order, (ExifShort) n->entries[i].format); 146 exif_set_long (*buf + o + 4, n->order, 147 n->entries[i].components); 148 o += 8; 149 s = exif_format_get_size (n->entries[i].format) * 150 n->entries[i].components; 151 if (s > 65536) { 152 /* Corrupt data: EXIF data size is limited to the 153 * maximum size of a JPEG segment (64 kb). 154 */ 155 continue; 156 } 157 if (s > 4) { 158 ts = *buf_size + s; 159 160 /* Ensure even offsets. Set padding bytes to 0. */ 161 if (s & 1) ts += 1; 162 t = exif_mem_realloc (ne->mem, *buf, 163 sizeof (char) * ts); 164 if (!t) { 165 EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteCanon", ts); 166 return; 167 } 168 *buf = t; 169 *buf_size = ts; 170 doff = *buf_size - s; 171 if (s & 1) { doff--; *(*buf + *buf_size - 1) = '\0'; } 172 exif_set_long (*buf + o, n->order, n->offset + doff); 173 } else 174 doff = o; 175 176 /* 177 * Write the data. Fill unneeded bytes with 0. Do not 178 * crash if data is NULL. 179 */ 180 if (!n->entries[i].data) memset (*buf + doff, 0, s); 181 else memcpy (*buf + doff, n->entries[i].data, s); 182 if (s < 4) memset (*buf + doff + s, 0, (4 - s)); 183 } 184 } 185 186 /* XXX 187 * FIXME: exif_mnote_data_canon_load() may fail and there is no 188 * semantics to express that. 189 * See bug #1054323 for details, especially the comment by liblit 190 * after it has supposedly been fixed: 191 * 192 * https://sourceforge.net/tracker/?func=detail&aid=1054323&group_id=12272&atid=112272 193 * Unfortunately, the "return" statements aren't commented at 194 * all, so it isn't trivial to find out what is a normal 195 * return, and what is a reaction to an error condition. 196 */ 197 198 static void 199 exif_mnote_data_canon_load (ExifMnoteData *ne, 200 const unsigned char *buf, unsigned int buf_size) 201 { 202 ExifMnoteDataCanon *n = (ExifMnoteDataCanon *) ne; 203 ExifShort c; 204 size_t i, tcount, o, datao; 205 206 if (!n || !buf || !buf_size) { 207 exif_log (ne->log, EXIF_LOG_CODE_CORRUPT_DATA, 208 "ExifMnoteCanon", "Short MakerNote"); 209 return; 210 } 211 datao = 6 + n->offset; 212 if ((datao + 2 < datao) || (datao + 2 < 2) || (datao + 2 > buf_size)) { 213 exif_log (ne->log, EXIF_LOG_CODE_CORRUPT_DATA, 214 "ExifMnoteCanon", "Short MakerNote"); 215 return; 216 } 217 218 /* Read the number of tags */ 219 c = exif_get_short (buf + datao, n->order); 220 datao += 2; 221 222 /* Remove any old entries */ 223 exif_mnote_data_canon_clear (n); 224 225 /* Reserve enough space for all the possible MakerNote tags */ 226 n->entries = exif_mem_alloc (ne->mem, sizeof (MnoteCanonEntry) * c); 227 if (!n->entries) { 228 EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteCanon", sizeof (MnoteCanonEntry) * c); 229 return; 230 } 231 232 /* Parse the entries */ 233 tcount = 0; 234 for (i = c, o = datao; i; --i, o += 12) { 235 size_t s; 236 if ((o + 12 < o) || (o + 12 < 12) || (o + 12 > buf_size)) { 237 exif_log (ne->log, EXIF_LOG_CODE_CORRUPT_DATA, 238 "ExifMnoteCanon", "Short MakerNote"); 239 break; 240 } 241 242 n->entries[tcount].tag = exif_get_short (buf + o, n->order); 243 n->entries[tcount].format = exif_get_short (buf + o + 2, n->order); 244 n->entries[tcount].components = exif_get_long (buf + o + 4, n->order); 245 n->entries[tcount].order = n->order; 246 247 exif_log (ne->log, EXIF_LOG_CODE_DEBUG, "ExifMnoteCanon", 248 "Loading entry 0x%x ('%s')...", n->entries[tcount].tag, 249 mnote_canon_tag_get_name (n->entries[tcount].tag)); 250 251 /* 252 * Size? If bigger than 4 bytes, the actual data is not 253 * in the entry but somewhere else (offset). 254 */ 255 s = exif_format_get_size (n->entries[tcount].format) * 256 n->entries[tcount].components; 257 n->entries[tcount].size = s; 258 if (!s) { 259 exif_log (ne->log, EXIF_LOG_CODE_CORRUPT_DATA, 260 "ExifMnoteCanon", 261 "Invalid zero-length tag size"); 262 continue; 263 264 } else { 265 size_t dataofs = o + 8; 266 if (s > 4) dataofs = exif_get_long (buf + dataofs, n->order) + 6; 267 if ((dataofs + s < s) || (dataofs + s < dataofs) || (dataofs + s > buf_size)) { 268 exif_log (ne->log, EXIF_LOG_CODE_DEBUG, 269 "ExifMnoteCanon", 270 "Tag data past end of buffer (%zu > %u)", 271 dataofs + s, buf_size); 272 continue; 273 } 274 275 n->entries[tcount].data = exif_mem_alloc (ne->mem, s); 276 if (!n->entries[tcount].data) { 277 EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteCanon", s); 278 continue; 279 } 280 memcpy (n->entries[tcount].data, buf + dataofs, s); 281 } 282 283 /* Tag was successfully parsed */ 284 ++tcount; 285 } 286 /* Store the count of successfully parsed tags */ 287 n->count = tcount; 288 } 289 290 static unsigned int 291 exif_mnote_data_canon_count (ExifMnoteData *n) 292 { 293 ExifMnoteDataCanon *dc = (ExifMnoteDataCanon *) n; 294 unsigned int i, c; 295 296 for (i = c = 0; dc && (i < dc->count); i++) 297 c += mnote_canon_entry_count_values (&dc->entries[i]); 298 return c; 299 } 300 301 static unsigned int 302 exif_mnote_data_canon_get_id (ExifMnoteData *d, unsigned int i) 303 { 304 ExifMnoteDataCanon *dc = (ExifMnoteDataCanon *) d; 305 unsigned int m; 306 307 if (!dc) return 0; 308 exif_mnote_data_canon_get_tags (dc, i, &m, NULL); 309 if (m >= dc->count) return 0; 310 return dc->entries[m].tag; 311 } 312 313 static const char * 314 exif_mnote_data_canon_get_name (ExifMnoteData *note, unsigned int i) 315 { 316 ExifMnoteDataCanon *dc = (ExifMnoteDataCanon *) note; 317 unsigned int m, s; 318 319 if (!dc) return NULL; 320 exif_mnote_data_canon_get_tags (dc, i, &m, &s); 321 if (m >= dc->count) return NULL; 322 return mnote_canon_tag_get_name_sub (dc->entries[m].tag, s, dc->options); 323 } 324 325 static const char * 326 exif_mnote_data_canon_get_title (ExifMnoteData *note, unsigned int i) 327 { 328 ExifMnoteDataCanon *dc = (ExifMnoteDataCanon *) note; 329 unsigned int m, s; 330 331 if (!dc) return NULL; 332 exif_mnote_data_canon_get_tags (dc, i, &m, &s); 333 if (m >= dc->count) return NULL; 334 return mnote_canon_tag_get_title_sub (dc->entries[m].tag, s, dc->options); 335 } 336 337 static const char * 338 exif_mnote_data_canon_get_description (ExifMnoteData *note, unsigned int i) 339 { 340 ExifMnoteDataCanon *dc = (ExifMnoteDataCanon *) note; 341 unsigned int m; 342 343 if (!dc) return NULL; 344 exif_mnote_data_canon_get_tags (dc, i, &m, NULL); 345 if (m >= dc->count) return NULL; 346 return mnote_canon_tag_get_description (dc->entries[m].tag); 347 } 348 349 int 350 exif_mnote_data_canon_identify (const ExifData *ed, const ExifEntry *e) 351 { 352 char value[8]; 353 ExifEntry *em = exif_data_get_entry (ed, EXIF_TAG_MAKE); 354 if (!em) 355 return 0; 356 return !strcmp (exif_entry_get_value (em, value, sizeof (value)), "Canon"); 357 } 358 359 ExifMnoteData * 360 exif_mnote_data_canon_new (ExifMem *mem, ExifDataOption o) 361 { 362 ExifMnoteData *d; 363 ExifMnoteDataCanon *dc; 364 365 if (!mem) return NULL; 366 367 d = exif_mem_alloc (mem, sizeof (ExifMnoteDataCanon)); 368 if (!d) 369 return NULL; 370 371 exif_mnote_data_construct (d, mem); 372 373 /* Set up function pointers */ 374 d->methods.free = exif_mnote_data_canon_free; 375 d->methods.set_byte_order = exif_mnote_data_canon_set_byte_order; 376 d->methods.set_offset = exif_mnote_data_canon_set_offset; 377 d->methods.load = exif_mnote_data_canon_load; 378 d->methods.save = exif_mnote_data_canon_save; 379 d->methods.count = exif_mnote_data_canon_count; 380 d->methods.get_id = exif_mnote_data_canon_get_id; 381 d->methods.get_name = exif_mnote_data_canon_get_name; 382 d->methods.get_title = exif_mnote_data_canon_get_title; 383 d->methods.get_description = exif_mnote_data_canon_get_description; 384 d->methods.get_value = exif_mnote_data_canon_get_value; 385 386 dc = (ExifMnoteDataCanon*)d; 387 dc->options = o; 388 return d; 389 } 390