Home | History | Annotate | Download | only in canon
      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