/*! If MakerNote is recognized, load it.
 *
 * \param[in,out] data #ExifData
 * \param[in] d pointer to raw EXIF data
 * \param[in] ds length of data at d
 */
static void
interpret_maker_note(ExifData *data, const unsigned char *d, unsigned int ds)
{
	int mnoteid;
	ExifEntry* e = exif_data_get_entry (data, EXIF_TAG_MAKER_NOTE);
	if (!e)
		return;
	
	if ((mnoteid = exif_mnote_data_olympus_identify (data, e)) != 0) {
		exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG,
			"ExifData", "Olympus MakerNote variant type %d", mnoteid);
		data->priv->md = exif_mnote_data_olympus_new (data->priv->mem);

	} else if ((mnoteid = exif_mnote_data_canon_identify (data, e)) != 0) {
		exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG,
			"ExifData", "Canon MakerNote variant type %d", mnoteid);
		data->priv->md = exif_mnote_data_canon_new (data->priv->mem, data->priv->options);

	} else if ((mnoteid = exif_mnote_data_fuji_identify (data, e)) != 0) {
		exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG,
			"ExifData", "Fuji MakerNote variant type %d", mnoteid);
		data->priv->md = exif_mnote_data_fuji_new (data->priv->mem);

	/* NOTE: Must do Pentax detection last because some of the
	 * heuristics are pretty general. */
	} else if ((mnoteid = exif_mnote_data_pentax_identify (data, e)) != 0) {
		exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG,
			"ExifData", "Pentax MakerNote variant type %d", mnoteid);
		data->priv->md = exif_mnote_data_pentax_new (data->priv->mem);
	}

	/* 
	 * If we are able to interpret the maker note, do so.
	 */
	if (data->priv->md) {
		exif_mnote_data_log (data->priv->md, data->priv->log);
		exif_mnote_data_set_byte_order (data->priv->md,
						data->priv->order);
		exif_mnote_data_set_offset (data->priv->md,
					    data->priv->offset_mnote);
		exif_mnote_data_load (data->priv->md, d, ds);
	}
}
static void
exif_data_save_data_entry (ExifData *data, ExifEntry *e,
			   unsigned char **d, unsigned int *ds,
			   unsigned int offset)
{
	unsigned int doff, s;
	unsigned int ts;

	if (!data || !data->priv) 
		return;

	/*
	 * Each entry is 12 bytes long. The memory for the entry has
	 * already been allocated.
	 */
	exif_set_short (*d + 6 + offset + 0,
			data->priv->order, (ExifShort) e->tag);
	exif_set_short (*d + 6 + offset + 2,
			data->priv->order, (ExifShort) e->format);

	if (!(data->priv->options & EXIF_DATA_OPTION_DONT_CHANGE_MAKER_NOTE)) {
		/* If this is the maker note tag, update it. */
		if ((e->tag == EXIF_TAG_MAKER_NOTE) && data->priv->md) {
			/* TODO: this is using the wrong ExifMem to free e->data */
			exif_mem_free (data->priv->mem, e->data);
			e->data = NULL;
			e->size = 0;
			exif_mnote_data_set_offset (data->priv->md, *ds - 6);
			exif_mnote_data_save (data->priv->md, &e->data, &e->size);
			e->components = e->size;
		}
	}

	exif_set_long  (*d + 6 + offset + 4,
			data->priv->order, e->components);

	/*
	 * Size? If bigger than 4 bytes, the actual data is not in
	 * the entry but somewhere else.
	 */
	s = exif_format_get_size (e->format) * e->components;
	if (s > 4) {
		unsigned char *t;
		doff = *ds - 6;
		ts = *ds + s;

		/*
		 * According to the TIFF specification,
		 * the offset must be an even number. If we need to introduce
		 * a padding byte, we set it to 0.
		 */
		if (s & 1)
			ts++;
		t = exif_mem_realloc (data->priv->mem, *d, ts);
		if (!t) {
			EXIF_LOG_NO_MEMORY (data->priv->log, "ExifData", ts);
		  	return;
		}
		*d = t;
		*ds = ts;
		exif_set_long (*d + 6 + offset + 8, data->priv->order, doff);
		if (s & 1) 
			*(*d + *ds - 1) = '\0';

	} else
		doff = offset + 8;

	/* Write the data. Fill unneeded bytes with 0. Do not crash with
	 * e->data is NULL */
	if (e->data) {
		memcpy (*d + 6 + doff, e->data, s);
	} else {
		memset (*d + 6 + doff, 0, s);
	}
	if (s < 4) 
		memset (*d + 6 + doff + s, 0, (4 - s));
}
Ejemplo n.º 3
0
void
exif_data_load_data (ExifData *data, const unsigned char *d_orig,
		     unsigned int ds_orig)
{
	unsigned int l;
	ExifLong offset;
	ExifShort n;
	const unsigned char *d = d_orig;
	unsigned int ds = ds_orig, len;

	if (!data || !data->priv || !d || !ds) 
		return;

	exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData",
		  "Parsing %i byte(s) EXIF data...\n", ds);

	/*
	 * It can be that the data starts with the EXIF header. If it does
	 * not, search the EXIF marker.
	 */
	if (ds < 6) {
		LOG_TOO_SMALL;
		return;
	}
	if (!memcmp (d, ExifHeader, 6)) {
		exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData",
			  "Found EXIF header.");
	} else {
		while (1) {
			while ((d[0] == 0xff) && ds) {
				d++;
				ds--;
			}

			/* JPEG_MARKER_SOI */
			if (d[0] == JPEG_MARKER_SOI) {
				d++;
				ds--;
				continue;
			}

			/* JPEG_MARKER_APP0 */
			if (d[0] == JPEG_MARKER_APP0) {
				d++;
				ds--;
				l = (d[0] << 8) | d[1];
				if (l > ds)
					return;
				d += l;
				ds -= l;
				continue;
			}

			/* JPEG_MARKER_APP1 */
			if (d[0] == JPEG_MARKER_APP1)
				break;

			/* Unknown marker or data. Give up. */
			exif_log (data->priv->log, EXIF_LOG_CODE_CORRUPT_DATA,
				  "ExifData", _("EXIF marker not found."));
			return;
		}
		d++;
		ds--;
		if (ds < 2) {
			LOG_TOO_SMALL;
			return;
		}
		len = (d[0] << 8) | d[1];
		exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData",
			  "We have to deal with %i byte(s) of EXIF data.",
			  len);
		d += 2;
		ds -= 2;
	}

	/*
	 * Verify the exif header
	 * (offset 2, length 6).
	 */
	if (ds < 6) {
		LOG_TOO_SMALL;
		return;
	}
	if (memcmp (d, ExifHeader, 6)) {
		exif_log (data->priv->log, EXIF_LOG_CODE_CORRUPT_DATA,
			  "ExifData", _("EXIF header not found."));
		return;
	}

	exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData",
		  "Found EXIF header.");

	/* Byte order (offset 6, length 2) */
	if (ds < 14)
		return;
	if (!memcmp (d + 6, "II", 2))
		data->priv->order = EXIF_BYTE_ORDER_INTEL;
	else if (!memcmp (d + 6, "MM", 2))
		data->priv->order = EXIF_BYTE_ORDER_MOTOROLA;
	else {
		exif_log (data->priv->log, EXIF_LOG_CODE_CORRUPT_DATA,
			  "ExifData", _("Unknown encoding."));
		return;
	}

	/* Fixed value */
	if (exif_get_short (d + 8, data->priv->order) != 0x002a)
		return;

	/* IFD 0 offset */
	offset = exif_get_long (d + 10, data->priv->order);
	exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData", 
		  "IFD 0 at %i.", (int) offset);

	/* Parse the actual exif data (usually offset 14 from start) */
	exif_data_load_data_content (data, EXIF_IFD_0, d + 6, ds - 6, offset, 0);

	/* IFD 1 offset */
	if (offset + 6 + 2 > ds) {
		return;
	}
	n = exif_get_short (d + 6 + offset, data->priv->order);
	if (offset + 6 + 2 + 12 * n + 4 > ds) {
		return;
	}
	offset = exif_get_long (d + 6 + offset + 2 + 12 * n, data->priv->order);
	if (offset) {
		exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData",
			  "IFD 1 at %i.", (int) offset);

		/* Sanity check. */
		if (offset > ds - 6) {
			exif_log (data->priv->log, EXIF_LOG_CODE_CORRUPT_DATA,
				  "ExifData", "Bogus offset of IFD1.");
		} else {
		   exif_data_load_data_content (data, EXIF_IFD_1, d + 6, ds - 6, offset, 0);
		}
	}

	/*
	 * If we got an EXIF_TAG_MAKER_NOTE, try to interpret it. Some
	 * cameras use pointers in the maker note tag that point to the
	 * space between IFDs. Here is the only place where we have access
	 * to that data.
	 */
	switch (exif_data_get_type_maker_note (data)) {
	case EXIF_DATA_TYPE_MAKER_NOTE_OLYMPUS:
	case EXIF_DATA_TYPE_MAKER_NOTE_NIKON:
		data->priv->md = exif_mnote_data_olympus_new (data->priv->mem);
		break;
	case EXIF_DATA_TYPE_MAKER_NOTE_PENTAX:
	case EXIF_DATA_TYPE_MAKER_NOTE_CASIO:
		data->priv->md = exif_mnote_data_pentax_new (data->priv->mem);
		break;
	case EXIF_DATA_TYPE_MAKER_NOTE_CANON:
		data->priv->md = exif_mnote_data_canon_new (data->priv->mem, data->priv->options);
		break;
	case EXIF_DATA_TYPE_MAKER_NOTE_FUJI:
		data->priv->md = exif_mnote_data_fuji_new (data->priv->mem);
		break;
	default:
		break;
	}

	/* 
	 * If we are able to interpret the maker note, do so.
	 */
	if (data->priv->md) {
		exif_mnote_data_log (data->priv->md, data->priv->log);
		exif_mnote_data_set_byte_order (data->priv->md,
						data->priv->order);
		exif_mnote_data_set_offset (data->priv->md,
					    data->priv->offset_mnote);
		exif_mnote_data_load (data->priv->md, d, ds);
	}

	if (data->priv->options & EXIF_DATA_OPTION_FOLLOW_SPECIFICATION)
		exif_data_fix (data);
}