Home | History | Annotate | Download | only in pentax
      1 /* exif-mnote-data-pentax.c
      2  *
      3  * Copyright (c) 2002, 2003 Lutz Mueller <lutz (at) 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 "config.h"
     22 #include "exif-mnote-data-pentax.h"
     23 
     24 #include <stdlib.h>
     25 #include <string.h>
     26 #include <stdio.h>
     27 
     28 #include <libexif/exif-byte-order.h>
     29 #include <libexif/exif-utils.h>
     30 
     31 static void
     32 exif_mnote_data_pentax_clear (ExifMnoteDataPentax *n)
     33 {
     34 	ExifMnoteData *d = (ExifMnoteData *) n;
     35 	unsigned int i;
     36 
     37 	if (!n) return;
     38 
     39 	if (n->entries) {
     40 		for (i = 0; i < n->count; i++)
     41 			if (n->entries[i].data) {
     42 				exif_mem_free (d->mem, n->entries[i].data);
     43 				n->entries[i].data = NULL;
     44 			}
     45 		exif_mem_free (d->mem, n->entries);
     46 		n->entries = NULL;
     47 		n->count = 0;
     48 	}
     49 }
     50 
     51 static void
     52 exif_mnote_data_pentax_free (ExifMnoteData *n)
     53 {
     54 	if (!n) return;
     55 
     56 	exif_mnote_data_pentax_clear ((ExifMnoteDataPentax *) n);
     57 }
     58 
     59 static char *
     60 exif_mnote_data_pentax_get_value (ExifMnoteData *d, unsigned int i, char *val, unsigned int maxlen)
     61 {
     62 	ExifMnoteDataPentax *n = (ExifMnoteDataPentax *) d;
     63 
     64 	if (!n) return NULL;
     65 	if (n->count <= i) return NULL;
     66 	return mnote_pentax_entry_get_value (&n->entries[i], val, maxlen);
     67 }
     68 
     69 /**
     70  * @brief save the MnoteData from ne to buf
     71  *
     72  * @param ne extract the data from this structure
     73  * @param *buf write the mnoteData to this buffer (buffer will be allocated)
     74  * @param buf_size the final size of the buffer
     75  */
     76 static void
     77 exif_mnote_data_pentax_save (ExifMnoteData *ne,
     78 		unsigned char **buf, unsigned int *buf_size)
     79 {
     80 	ExifMnoteDataPentax *n = (ExifMnoteDataPentax *) ne;
     81 	size_t i,
     82 	   base = 0,		/* internal MakerNote tag number offset */
     83 	   o2 = 4 + 2;  	/* offset to first tag entry, past header */
     84         size_t datao = n->offset; /* this MakerNote style uses offsets
     85         			  based on main IFD, not makernote IFD */
     86 
     87 	if (!n || !buf || !buf_size) return;
     88 
     89 	/*
     90 	 * Allocate enough memory for header, the number of entries, entries,
     91 	 * and next IFD pointer
     92 	 */
     93 	*buf_size = o2 + 2 + n->count * 12 + 4;
     94 	switch (n->version) {
     95 	case casioV2:
     96 		base = MNOTE_PENTAX2_TAG_BASE;
     97 		*buf = exif_mem_alloc (ne->mem, *buf_size);
     98 		if (!*buf) {
     99 			EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteDataPentax", *buf_size);
    100 			return;
    101 		}
    102 		/* Write the magic header */
    103 		strcpy ((char *)*buf, "QVC");
    104 		exif_set_short (*buf + 4, n->order, (ExifShort) 0);
    105 
    106 		break;
    107 
    108 	case pentaxV3:
    109 		base = MNOTE_PENTAX2_TAG_BASE;
    110 		*buf = exif_mem_alloc (ne->mem, *buf_size);
    111 		if (!*buf) {
    112 			EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteDataPentax", *buf_size);
    113 			return;
    114 		}
    115 
    116 		/* Write the magic header */
    117 		strcpy ((char *)*buf, "AOC");
    118 		exif_set_short (*buf + 4, n->order, (ExifShort) (
    119 			(n->order == EXIF_BYTE_ORDER_INTEL) ?
    120 			('I' << 8) | 'I' :
    121 			('M' << 8) | 'M'));
    122 		break;
    123 
    124 	case pentaxV2:
    125 		base = MNOTE_PENTAX2_TAG_BASE;
    126 		*buf = exif_mem_alloc (ne->mem, *buf_size);
    127 		if (!*buf) {
    128 			EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteDataPentax", *buf_size);
    129 			return;
    130 		}
    131 
    132 		/* Write the magic header */
    133 		strcpy ((char *)*buf, "AOC");
    134 		exif_set_short (*buf + 4, n->order, (ExifShort) 0);
    135 		break;
    136 
    137 	case pentaxV1:
    138 		/* It looks like this format doesn't have a magic header as
    139 		 * such, just has a fixed number of entries equal to 0x001b */
    140 		*buf_size -= 6;
    141 		o2 -= 6;
    142 		*buf = exif_mem_alloc (ne->mem, *buf_size);
    143 		if (!*buf) {
    144 			EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteDataPentax", *buf_size);
    145 			return;
    146 		}
    147 		break;
    148 
    149 	default:
    150 		/* internal error */
    151 		return;
    152 	}
    153 
    154 	/* Write the number of entries. */
    155 	exif_set_short (*buf + o2, n->order, (ExifShort) n->count);
    156 	o2 += 2;
    157 
    158 	/* Save each entry */
    159 	for (i = 0; i < n->count; i++) {
    160 		size_t doff;	/* offset to current data portion of tag */
    161 		size_t s;
    162 		unsigned char *t;
    163 		size_t o = o2 + i * 12;   /* current offset into output buffer */
    164 		exif_set_short (*buf + o + 0, n->order,
    165 				(ExifShort) (n->entries[i].tag - base));
    166 		exif_set_short (*buf + o + 2, n->order,
    167 				(ExifShort) n->entries[i].format);
    168 		exif_set_long  (*buf + o + 4, n->order,
    169 				n->entries[i].components);
    170 		o += 8;
    171 		s = exif_format_get_size (n->entries[i].format) *
    172 						n->entries[i].components;
    173 		if (s > 65536) {
    174 			/* Corrupt data: EXIF data size is limited to the
    175 			 * maximum size of a JPEG segment (64 kb).
    176 			 */
    177 			continue;
    178 		}
    179 		if (s > 4) {
    180 			size_t ts = *buf_size + s;
    181 			doff = *buf_size;
    182 			t = exif_mem_realloc (ne->mem, *buf,
    183 						 sizeof (char) * ts);
    184 			if (!t) {
    185 				EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteDataPentax", ts);
    186 				return;
    187 			}
    188 			*buf = t;
    189 			*buf_size = ts;
    190 			exif_set_long (*buf + o, n->order, datao + doff);
    191 		} else
    192 			doff = o;
    193 
    194 		/* Write the data. */
    195 		if (n->entries[i].data) {
    196 			memcpy (*buf + doff, n->entries[i].data, s);
    197 		} else {
    198 			/* Most certainly damaged input file */
    199 			memset (*buf + doff, 0, s);
    200 		}
    201 	}
    202 
    203 	/* Sanity check the buffer size */
    204 	if (*buf_size < (o2 + n->count * 12 + 4)) {
    205 		exif_log (ne->log, EXIF_LOG_CODE_CORRUPT_DATA, "ExifMnoteDataPentax",
    206 			"Buffer overflow");
    207 	}
    208 
    209 	/* Reset next IFD pointer */
    210 	exif_set_long (*buf + o2 + n->count * 12, n->order, 0);
    211 }
    212 
    213 static void
    214 exif_mnote_data_pentax_load (ExifMnoteData *en,
    215 		const unsigned char *buf, unsigned int buf_size)
    216 {
    217 	ExifMnoteDataPentax *n = (ExifMnoteDataPentax *) en;
    218 	size_t i, tcount, o, datao, base = 0;
    219 	ExifShort c;
    220 
    221 	if (!n || !buf || !buf_size) {
    222 		exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA,
    223 			  "ExifMnoteDataPentax", "Short MakerNote");
    224 		return;
    225 	}
    226 	datao = 6 + n->offset;
    227 	if ((datao + 8 < datao) || (datao + 8 < 8) || (datao + 8 > buf_size)) {
    228 		exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA,
    229 			  "ExifMnoteDataPentax", "Short MakerNote");
    230 		return;
    231 	}
    232 
    233 	/* Detect variant of Pentax/Casio MakerNote found */
    234 	if (!memcmp(buf + datao, "AOC", 4)) {
    235 		if ((buf[datao + 4] == 'I') && (buf[datao + 5] == 'I')) {
    236 			n->version = pentaxV3;
    237 			n->order = EXIF_BYTE_ORDER_INTEL;
    238 		} else if ((buf[datao + 4] == 'M') && (buf[datao + 5] == 'M')) {
    239 			n->version = pentaxV3;
    240 			n->order = EXIF_BYTE_ORDER_MOTOROLA;
    241 		} else {
    242 			/* Uses Casio v2 tags */
    243 			n->version = pentaxV2;
    244 		}
    245 		exif_log (en->log, EXIF_LOG_CODE_DEBUG, "ExifMnoteDataPentax",
    246 			"Parsing Pentax maker note v%d...", (int)n->version);
    247 		datao += 4 + 2;
    248 		base = MNOTE_PENTAX2_TAG_BASE;
    249 	} else if (!memcmp(buf + datao, "QVC", 4)) {
    250 		exif_log (en->log, EXIF_LOG_CODE_DEBUG, "ExifMnoteDataPentax",
    251 			"Parsing Casio maker note v2...");
    252 		n->version = casioV2;
    253 		base = MNOTE_CASIO2_TAG_BASE;
    254 		datao += 4 + 2;
    255 	} else {
    256 		/* probably assert(!memcmp(buf + datao, "\x00\x1b", 2)) */
    257 		exif_log (en->log, EXIF_LOG_CODE_DEBUG, "ExifMnoteDataPentax",
    258 			"Parsing Pentax maker note v1...");
    259 		n->version = pentaxV1;
    260 	}
    261 
    262 	/* Read the number of tags */
    263 	c = exif_get_short (buf + datao, n->order);
    264 	datao += 2;
    265 
    266 	/* Remove any old entries */
    267 	exif_mnote_data_pentax_clear (n);
    268 
    269 	/* Reserve enough space for all the possible MakerNote tags */
    270 	n->entries = exif_mem_alloc (en->mem, sizeof (MnotePentaxEntry) * c);
    271 	if (!n->entries) {
    272 		EXIF_LOG_NO_MEMORY(en->log, "ExifMnoteDataPentax", sizeof (MnotePentaxEntry) * c);
    273 		return;
    274 	}
    275 
    276 	/* Parse all c entries, storing ones that are successfully parsed */
    277 	tcount = 0;
    278 	for (i = c, o = datao; i; --i, o += 12) {
    279 		size_t s;
    280 		if ((o + 12 < o) || (o + 12 < 12) || (o + 12 > buf_size)) {
    281 			exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA,
    282 				  "ExifMnoteDataPentax", "Short MakerNote");
    283 			break;
    284 		}
    285 
    286 		n->entries[tcount].tag        = exif_get_short (buf + o + 0, n->order) + base;
    287 		n->entries[tcount].format     = exif_get_short (buf + o + 2, n->order);
    288 		n->entries[tcount].components = exif_get_long  (buf + o + 4, n->order);
    289 		n->entries[tcount].order      = n->order;
    290 
    291 		exif_log (en->log, EXIF_LOG_CODE_DEBUG, "ExifMnotePentax",
    292 			  "Loading entry 0x%x ('%s')...", n->entries[tcount].tag,
    293 			  mnote_pentax_tag_get_name (n->entries[tcount].tag));
    294 
    295 		/*
    296 		 * Size? If bigger than 4 bytes, the actual data is not
    297 		 * in the entry but somewhere else (offset).
    298 		 */
    299 		s = exif_format_get_size (n->entries[tcount].format) *
    300                                       n->entries[tcount].components;
    301 		n->entries[tcount].size = s;
    302 		if (s) {
    303 			size_t dataofs = o + 8;
    304 			if (s > 4)
    305 				/* The data in this case is merely a pointer */
    306 			   	dataofs = exif_get_long (buf + dataofs, n->order) + 6;
    307 			if ((dataofs + s < dataofs) || (dataofs + s < s) ||
    308 				(dataofs + s > buf_size)) {
    309 				exif_log (en->log, EXIF_LOG_CODE_DEBUG,
    310 						  "ExifMnoteDataPentax", "Tag data past end "
    311 					  "of buffer (%zu > %u)", dataofs + s, buf_size);
    312 				continue;
    313 			}
    314 
    315 			n->entries[tcount].data = exif_mem_alloc (en->mem, s);
    316 			if (!n->entries[tcount].data) {
    317 				EXIF_LOG_NO_MEMORY(en->log, "ExifMnoteDataPentax", s);
    318 				continue;
    319 			}
    320 			memcpy (n->entries[tcount].data, buf + dataofs, s);
    321 		}
    322 
    323 		/* Tag was successfully parsed */
    324 		++tcount;
    325 	}
    326 	/* Store the count of successfully parsed tags */
    327 	n->count = tcount;
    328 }
    329 
    330 static unsigned int
    331 exif_mnote_data_pentax_count (ExifMnoteData *n)
    332 {
    333 	return n ? ((ExifMnoteDataPentax *) n)->count : 0;
    334 }
    335 
    336 static unsigned int
    337 exif_mnote_data_pentax_get_id (ExifMnoteData *d, unsigned int n)
    338 {
    339 	ExifMnoteDataPentax *note = (ExifMnoteDataPentax *) d;
    340 
    341 	if (!note) return 0;
    342 	if (note->count <= n) return 0;
    343 	return note->entries[n].tag;
    344 }
    345 
    346 static const char *
    347 exif_mnote_data_pentax_get_name (ExifMnoteData *d, unsigned int n)
    348 {
    349 	ExifMnoteDataPentax *note = (ExifMnoteDataPentax *) d;
    350 
    351 	if (!note) return NULL;
    352 	if (note->count <= n) return NULL;
    353 	return mnote_pentax_tag_get_name (note->entries[n].tag);
    354 }
    355 
    356 static const char *
    357 exif_mnote_data_pentax_get_title (ExifMnoteData *d, unsigned int n)
    358 {
    359 	ExifMnoteDataPentax *note = (ExifMnoteDataPentax *) d;
    360 
    361 	if (!note) return NULL;
    362 	if (note->count <= n) return NULL;
    363 	return mnote_pentax_tag_get_title (note->entries[n].tag);
    364 }
    365 
    366 static const char *
    367 exif_mnote_data_pentax_get_description (ExifMnoteData *d, unsigned int n)
    368 {
    369 	ExifMnoteDataPentax *note = (ExifMnoteDataPentax *) d;
    370 
    371 	if (!note) return NULL;
    372 	if (note->count <= n) return NULL;
    373 	return mnote_pentax_tag_get_description (note->entries[n].tag);
    374 }
    375 
    376 static void
    377 exif_mnote_data_pentax_set_offset (ExifMnoteData *d, unsigned int o)
    378 {
    379 	if (d) ((ExifMnoteDataPentax *) d)->offset = o;
    380 }
    381 
    382 static void
    383 exif_mnote_data_pentax_set_byte_order (ExifMnoteData *d, ExifByteOrder o)
    384 {
    385 	ExifByteOrder o_orig;
    386 	ExifMnoteDataPentax *n = (ExifMnoteDataPentax *) d;
    387 	unsigned int i;
    388 
    389 	if (!n) return;
    390 
    391 	o_orig = n->order;
    392 	n->order = o;
    393 	for (i = 0; i < n->count; i++) {
    394 		n->entries[i].order = o;
    395 		exif_array_set_byte_order (n->entries[i].format, n->entries[i].data,
    396 				n->entries[i].components, o_orig, o);
    397 	}
    398 }
    399 
    400 int
    401 exif_mnote_data_pentax_identify (const ExifData *ed, const ExifEntry *e)
    402 {
    403 	if ((e->size >= 8) && !memcmp (e->data, "AOC", 4)) {
    404 		if (((e->data[4] == 'I') && (e->data[5] == 'I')) ||
    405 		    ((e->data[4] == 'M') && (e->data[5] == 'M')))
    406 			return pentaxV3;
    407 		else
    408 			/* Uses Casio v2 tags */
    409 			return pentaxV2;
    410 	}
    411 
    412 	if ((e->size >= 8) && !memcmp (e->data, "QVC", 4))
    413 		return casioV2;
    414 
    415 	/* This isn't a very robust test, so make sure it's done last */
    416 	/* Maybe we should additionally check for a make of Asahi or Pentax */
    417 	if ((e->size >= 2) && (e->data[0] == 0x00) && (e->data[1] == 0x1b))
    418 		return pentaxV1;
    419 
    420 	return 0;
    421 }
    422 
    423 ExifMnoteData *
    424 exif_mnote_data_pentax_new (ExifMem *mem)
    425 {
    426 	ExifMnoteData *d;
    427 
    428 	if (!mem) return NULL;
    429 
    430 	d = exif_mem_alloc (mem, sizeof (ExifMnoteDataPentax));
    431 	if (!d) return NULL;
    432 
    433 	exif_mnote_data_construct (d, mem);
    434 
    435 	/* Set up function pointers */
    436 	d->methods.free            = exif_mnote_data_pentax_free;
    437 	d->methods.set_byte_order  = exif_mnote_data_pentax_set_byte_order;
    438 	d->methods.set_offset      = exif_mnote_data_pentax_set_offset;
    439 	d->methods.load            = exif_mnote_data_pentax_load;
    440 	d->methods.save            = exif_mnote_data_pentax_save;
    441 	d->methods.count           = exif_mnote_data_pentax_count;
    442 	d->methods.get_id          = exif_mnote_data_pentax_get_id;
    443 	d->methods.get_name        = exif_mnote_data_pentax_get_name;
    444 	d->methods.get_title       = exif_mnote_data_pentax_get_title;
    445 	d->methods.get_description = exif_mnote_data_pentax_get_description;
    446 	d->methods.get_value       = exif_mnote_data_pentax_get_value;
    447 
    448 	return d;
    449 }
    450