static void
exif_mnote_data_canon_save (ExifMnoteData *ne, 
	unsigned char **buf, unsigned int *buf_size)
{
	ExifMnoteDataCanon *n = (ExifMnoteDataCanon *) ne;
	unsigned int i, o, s, doff;

	if (!n || !buf || !buf_size) return;

	/*
	 * Allocate enough memory for all entries and the number
	 * of entries.
	 */
	*buf_size = 2 + n->count * 12 + 4;
	*buf = exif_mem_alloc (ne->mem, sizeof (char) * *buf_size);
	if (!*buf) return;

	/* Save the number of entries */
	exif_set_short (*buf, n->order, (ExifShort) n->count);
	
	/* Save each entry */
	for (i = 0; i < n->count; i++) {
		o = 2 + i * 12;
		exif_set_short (*buf + o + 0, n->order, (ExifShort) n->entries[i].tag);
		exif_set_short (*buf + o + 2, n->order, (ExifShort) n->entries[i].format);
		exif_set_long  (*buf + o + 4, n->order,
				n->entries[i].components);
		o += 8;
		s = exif_format_get_size (n->entries[i].format) *
						n->entries[i].components;
		if (s > 4) {
			*buf_size += s;

			/* Ensure even offsets. Set padding bytes to 0. */
			if (s & 1) *buf_size += 1;
			*buf = exif_mem_realloc (ne->mem, *buf,
						 sizeof (char) * *buf_size);
			if (!*buf) return;
			doff = *buf_size - s;
			if (s & 1) { doff--; *(*buf + *buf_size - 1) = '\0'; }
			exif_set_long (*buf + o, n->order, n->offset + doff);
		} else
			doff = o;

		/*
		 * Write the data. Fill unneeded bytes with 0. Do not
		 * crash if data is NULL.
		 */
		if (!n->entries[i].data) memset (*buf + doff, 0, s);
		else memcpy (*buf + doff, n->entries[i].data, s);
		if (s < 4) memset (*buf + doff + s, 0, (4 - s));
	}
}
static void
exif_mnote_data_canon_load (ExifMnoteData *ne,
	const unsigned char *buf, unsigned int buf_size)
{
	ExifMnoteDataCanon *n = (ExifMnoteDataCanon *) ne;
	ExifShort c;
	unsigned int i, o, s;

	if (!n || !buf || !buf_size || (buf_size < 6 + n->offset + 2)) return;

	/* Read the number of entries and remove old ones. */
	c = exif_get_short (buf + 6 + n->offset, n->order);
	exif_mnote_data_canon_clear (n);

	/* Parse the entries */
	for (i = 0; i < c; i++) {
		o = 6 + 2 + n->offset + 12 * i;
	  if (o + 8 > buf_size) return;

		n->count = i + 1;
		n->entries = exif_mem_realloc (ne->mem, n->entries,
				sizeof (MnoteCanonEntry) * (i+1));
		memset (&n->entries[i], 0, sizeof (MnoteCanonEntry));
	  n->entries[i].tag        = exif_get_short (buf + o, n->order);
	  n->entries[i].format     = exif_get_short (buf + o + 2, n->order);
	  n->entries[i].components = exif_get_long (buf + o + 4, n->order);
	  n->entries[i].order      = n->order;

	  /*
	   * Size? If bigger than 4 bytes, the actual data is not
	   * in the entry but somewhere else (offset).
	   */
	  s = exif_format_get_size (n->entries[i].format) * n->entries[i].components;
		if (!s) return;
		o += 8;
		if (s > 4) o = exif_get_long (buf + o, n->order) + 6;
		if (o + s > buf_size) return;

		/* Sanity check */
		n->entries[i].data = exif_mem_alloc (ne->mem, sizeof (char) * s);
		if (!n->entries[i].data) return;
		n->entries[i].size = s;
		memcpy (n->entries[i].data, buf + o, s);
	}
}
Exemple #3
0
void
exif_content_remove_entry (ExifContent *c, ExifEntry *e)
{
	unsigned int i;

	if (!c || !c->priv || !e || (e->parent != c)) return;

	/* Search the entry */
	for (i = 0; i < c->count; i++) if (c->entries[i] == e) break;
	if (i == c->count) return;

	/* Remove the entry */
	memmove (&c->entries[i], &c->entries[i + 1],
		 sizeof (ExifEntry*) * (c->count - i - 1));
	c->count--;
	e->parent = NULL;
	exif_entry_unref (e);
	c->entries = exif_mem_realloc (c->priv->mem, c->entries,
					sizeof(ExifEntry*) * c->count);
}
void
exif_content_remove_entry (ExifContent *c, ExifEntry *e)
{
	unsigned int i;
	ExifEntry **t, *temp;

	if (!c || !c->priv || !e || (e->parent != c)) return;

	
	for (i = 0; i < c->count; i++)
			if (c->entries[i] == e)
					break;

	if (i == c->count)
			return;

	
	temp = c->entries[c->count-1];
	if (c->count > 1) {
		t = exif_mem_realloc (c->priv->mem, c->entries,
					sizeof(ExifEntry*) * (c->count - 1));
		if (!t) {
			return;
		}
		c->entries = t;
		c->count--;
		if (i != c->count) {  
			memmove (&t[i], &t[i + 1], sizeof (ExifEntry*) * (c->count - i - 1));
			t[c->count-1] = temp;
		} 
	} else {
		exif_mem_free (c->priv->mem, c->entries);
		c->entries = NULL;
		c->count = 0;
	}
	e->parent = NULL;
	exif_entry_unref (e);
}
void
exif_content_add_entry (ExifContent *c, ExifEntry *entry)
{
	ExifEntry **entries;
	if (!c || !c->priv || !entry || entry->parent) return;

	
	if (exif_content_get_entry (c, entry->tag)) {
		exif_log (c->priv->log, EXIF_LOG_CODE_DEBUG, "ExifContent",
			"An attempt has been made to add "
			"the tag '%s' twice to an IFD. This is against "
			"specification.", exif_tag_get_name (entry->tag));
		return;
	}

	entries = exif_mem_realloc (c->priv->mem,
		c->entries, sizeof (ExifEntry*) * (c->count + 1));
	if (!entries) return;
	entry->parent = c;
	entries[c->count++] = entry;
	c->entries = entries;
	exif_entry_ref (entry);
}
/** 
 * @brief save the MnoteData from ne to buf
 * 
 * @param ne extract the data from this structure 
 * @param *buf write the mnoteData to this buffer (buffer will be allocated)
 * @param buf_size the size of the buffer
 */
static void
exif_mnote_data_olympus_save (ExifMnoteData *ne,
		unsigned char **buf, unsigned int *buf_size)
{
	ExifMnoteDataOlympus *n = (ExifMnoteDataOlympus *) ne;
	size_t i, o, s, doff, base = 0, o2 = 6 + 2;
	size_t datao = 0;
	unsigned char *t;
	size_t ts;

	if (!n || !buf || !buf_size) return;

	/*
	 * Allocate enough memory for all entries and the number of entries.
	 */
	*buf_size = 6 + 2 + 2 + n->count * 12;
	switch (n->version) {
	case olympusV1:
	case sanyoV1:
	case epsonV1:
		*buf = exif_mem_alloc (ne->mem, *buf_size);
		if (!*buf) {
			EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteDataOlympus", *buf_size);
			return;
		}

		/* Write the header and the number of entries. */
		strcpy ((char *)*buf, n->version==sanyoV1?"SANYO":
					(n->version==epsonV1?"EPSON":"OLYMP"));
		exif_set_short (*buf + 6, n->order, (ExifShort) 1);
		datao = n->offset;
		break;
	case olympusV2:
		*buf_size += 8-6 + 4;
		*buf = exif_mem_alloc (ne->mem, *buf_size);
		if (!*buf) {
			EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteDataOlympus", *buf_size);
			return;
		}

		/* Write the header and the number of entries. */
		strcpy ((char *)*buf, "OLYMPUS");
		exif_set_short (*buf + 8, n->order, (ExifShort) (
			(n->order == EXIF_BYTE_ORDER_INTEL) ?
			('I' << 8) | 'I' :
			('M' << 8) | 'M'));
		exif_set_short (*buf + 10, n->order, (ExifShort) 3);
		o2 += 4;
		break;
	case nikonV1: 
		base = MNOTE_NIKON1_TAG_BASE;

		/* v1 has offsets based to main IFD, not makernote IFD */
		datao += n->offset + 10;
		/* subtract the size here, so the increment in the next case will not harm us */
		*buf_size -= 8 + 2;
		/* Fall through */
	case nikonV2: 
		*buf_size += 8 + 2;
		*buf_size += 4; /* Next IFD pointer */
		*buf = exif_mem_alloc (ne->mem, *buf_size);
		if (!*buf) {
			EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteDataOlympus", *buf_size);
			return;
		}

		/* Write the header and the number of entries. */
		strcpy ((char *)*buf, "Nikon");
		(*buf)[6] = n->version;

		if (n->version == nikonV2) {
			exif_set_short (*buf + 10, n->order, (ExifShort) (
				(n->order == EXIF_BYTE_ORDER_INTEL) ?
				('I' << 8) | 'I' :
				('M' << 8) | 'M'));
			exif_set_short (*buf + 12, n->order, (ExifShort) 0x2A);
			exif_set_long (*buf + 14, n->order, (ExifShort) 8);
			o2 += 2 + 8;
		}
		datao -= 10;
		/* Reset next IFD pointer */
		exif_set_long (*buf + o2 + 2 + n->count * 12, n->order, 0);
		break;

	default:
		return;
	}

	exif_set_short (*buf + o2, n->order, (ExifShort) n->count);
	o2 += 2;

	/* Save each entry */
	for (i = 0; i < n->count; i++) {
		o = o2 + i * 12;
		exif_set_short (*buf + o + 0, n->order,
				(ExifShort) (n->entries[i].tag - base));
		exif_set_short (*buf + o + 2, n->order,
				(ExifShort) n->entries[i].format);
		exif_set_long  (*buf + o + 4, n->order,
				n->entries[i].components);
		o += 8;
		s = exif_format_get_size (n->entries[i].format) *
						n->entries[i].components;
		if (s > 65536) {
			/* Corrupt data: EXIF data size is limited to the
			 * maximum size of a JPEG segment (64 kb).
			 */
			continue;
		}
		if (s > 4) {
			doff = *buf_size;
			ts = *buf_size + s;
			t = exif_mem_realloc (ne->mem, *buf,
						 sizeof (char) * ts);
			if (!t) {
				EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteDataOlympus", ts);
				return;
			}
			*buf = t;
			*buf_size = ts;
			exif_set_long (*buf + o, n->order, datao + doff);
		} else
			doff = o;

		/* Write the data. */
		if (n->entries[i].data) {
			memcpy (*buf + doff, n->entries[i].data, s);
		} else {
			/* Most certainly damaged input file */
			memset (*buf + doff, 0, s);
		}
	}
}
/** 
 * @brief save the MnoteData from ne to buf
 * 
 * @param ne extract the data from this structure 
 * @param *buf write the mnoteData to this buffer (buffer will be allocated)
 * @param buf_size the final size of the buffer
 */
static void
exif_mnote_data_pentax_save (ExifMnoteData *ne,
		unsigned char **buf, unsigned int *buf_size)
{
	ExifMnoteDataPentax *n = (ExifMnoteDataPentax *) ne;
	size_t i,
	   base = 0,		/* internal MakerNote tag number offset */
	   o2 = 4 + 2;  	/* offset to first tag entry, past header */
        size_t datao = n->offset; /* this MakerNote style uses offsets
        			  based on main IFD, not makernote IFD */

	if (!n || !buf || !buf_size) return;

	/*
	 * Allocate enough memory for header, the number of entries, entries,
	 * and next IFD pointer
	 */
	*buf_size = o2 + 2 + n->count * 12 + 4;
	switch (n->version) {
	case casioV2:
		base = MNOTE_PENTAX2_TAG_BASE;
		*buf = exif_mem_alloc (ne->mem, *buf_size);
		if (!*buf) {
			EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteDataPentax", *buf_size);
			return;
		}
		/* Write the magic header */
		strcpy ((char *)*buf, "QVC");
		exif_set_short (*buf + 4, n->order, (ExifShort) 0);

		break;

	case pentaxV3:
		base = MNOTE_PENTAX2_TAG_BASE;
		*buf = exif_mem_alloc (ne->mem, *buf_size);
		if (!*buf) {
			EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteDataPentax", *buf_size);
			return;
		}

		/* Write the magic header */
		strcpy ((char *)*buf, "AOC");
		exif_set_short (*buf + 4, n->order, (ExifShort) (
			(n->order == EXIF_BYTE_ORDER_INTEL) ?
			('I' << 8) | 'I' :
			('M' << 8) | 'M'));
		break;

	case pentaxV2:
		base = MNOTE_PENTAX2_TAG_BASE;
		*buf = exif_mem_alloc (ne->mem, *buf_size);
		if (!*buf) {
			EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteDataPentax", *buf_size);
			return;
		}

		/* Write the magic header */
		strcpy ((char *)*buf, "AOC");
		exif_set_short (*buf + 4, n->order, (ExifShort) 0);
		break;

	case pentaxV1:
		/* It looks like this format doesn't have a magic header as
		 * such, just has a fixed number of entries equal to 0x001b */
		*buf_size -= 6;
		o2 -= 6;
		*buf = exif_mem_alloc (ne->mem, *buf_size);
		if (!*buf) {
			EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteDataPentax", *buf_size);
			return;
		}
		break;

	default:
		/* internal error */
		return;
	}

	/* Write the number of entries. */
	exif_set_short (*buf + o2, n->order, (ExifShort) n->count);
	o2 += 2;

	/* Save each entry */
	for (i = 0; i < n->count; i++) {
		size_t doff;	/* offset to current data portion of tag */
		size_t s;
		unsigned char *t;
		size_t o = o2 + i * 12;   /* current offset into output buffer */
		exif_set_short (*buf + o + 0, n->order,
				(ExifShort) (n->entries[i].tag - base));
		exif_set_short (*buf + o + 2, n->order,
				(ExifShort) n->entries[i].format);
		exif_set_long  (*buf + o + 4, n->order,
				n->entries[i].components);
		o += 8;
		s = exif_format_get_size (n->entries[i].format) *
						n->entries[i].components;
		if (s > 65536) {
			/* Corrupt data: EXIF data size is limited to the
			 * maximum size of a JPEG segment (64 kb).
			 */
			continue;
		}
		if (s > 4) {
			size_t ts = *buf_size + s;
			doff = *buf_size;
			t = exif_mem_realloc (ne->mem, *buf,
						 sizeof (char) * ts);
			if (!t) {
				EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteDataPentax", ts);
				return;
			}
			*buf = t;
			*buf_size = ts;
			exif_set_long (*buf + o, n->order, datao + doff);
		} else
			doff = o;

		/* Write the data. */
		if (n->entries[i].data) {
			memcpy (*buf + doff, n->entries[i].data, s);
		} else {
			/* Most certainly damaged input file */
			memset (*buf + doff, 0, s);
		}
	}

	/* Sanity check the buffer size */
	if (*buf_size < (o2 + n->count * 12 + 4)) {
		exif_log (ne->log, EXIF_LOG_CODE_CORRUPT_DATA, "ExifMnoteDataPentax",
			"Buffer overflow");
	}

	/* Reset next IFD pointer */
	exif_set_long (*buf + o2 + n->count * 12, n->order, 0);
}
static void
exif_data_save_data_content (ExifData *data, ExifContent *ifd,
			     unsigned char **d, unsigned int *ds,
			     unsigned int offset)
{
	unsigned int j, n_ptr = 0, n_thumb = 0;
	ExifIfd i;
	unsigned char *t;
	unsigned int ts;

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

	for (i = 0; i < EXIF_IFD_COUNT; i++)
		if (ifd == data->ifd[i])
			break;
	if (i == EXIF_IFD_COUNT)
		return;	/* error */

	/*
	 * Check if we need some extra entries for pointers or the thumbnail.
	 */
	switch (i) {
	case EXIF_IFD_0:

		/*
		 * The pointer to IFD_EXIF is in IFD_0. The pointer to
		 * IFD_INTEROPERABILITY is in IFD_EXIF.
		 */
		if (data->ifd[EXIF_IFD_EXIF]->count ||
		    data->ifd[EXIF_IFD_INTEROPERABILITY]->count)
			n_ptr++;

		/* The pointer to IFD_GPS is in IFD_0. */
		if (data->ifd[EXIF_IFD_GPS]->count)
			n_ptr++;

		break;
	case EXIF_IFD_1:
		if (data->size)
			n_thumb = 2;
		break;
	case EXIF_IFD_EXIF:
		if (data->ifd[EXIF_IFD_INTEROPERABILITY]->count)
			n_ptr++;
	default:
		break;
	}

	/*
	 * Allocate enough memory for all entries
	 * and the number of entries.
	 */
	ts = *ds + (2 + (ifd->count + n_ptr + n_thumb) * 12 + 4);
	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;

	/* Save the number of entries */
	exif_set_short (*d + 6 + offset, data->priv->order,
			(ExifShort) (ifd->count + n_ptr + n_thumb));
	offset += 2;

	/*
	 * Save each entry. Make sure that no memcpys from NULL pointers are
	 * performed
	 */
	exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData",
		  "Saving %i entries (IFD '%s', offset: %i)...",
		  ifd->count, exif_ifd_get_name (i), offset);
	for (j = 0; j < ifd->count; j++) {
		if (ifd->entries[j]) {
			exif_data_save_data_entry (data, ifd->entries[j], d, ds,
				offset + 12 * j);
		}
	}

	offset += 12 * ifd->count;

	/* Now save special entries. */
	switch (i) {
	case EXIF_IFD_0:

		/*
		 * The pointer to IFD_EXIF is in IFD_0.
		 * However, the pointer to IFD_INTEROPERABILITY is in IFD_EXIF,
		 * therefore, if IFD_INTEROPERABILITY is not empty, we need
		 * IFD_EXIF even if latter is empty.
		 */
		if (data->ifd[EXIF_IFD_EXIF]->count ||
		    data->ifd[EXIF_IFD_INTEROPERABILITY]->count) {
			exif_set_short (*d + 6 + offset + 0, data->priv->order,
					EXIF_TAG_EXIF_IFD_POINTER);
			exif_set_short (*d + 6 + offset + 2, data->priv->order,
					EXIF_FORMAT_LONG);
			exif_set_long  (*d + 6 + offset + 4, data->priv->order,
					1);
			exif_set_long  (*d + 6 + offset + 8, data->priv->order,
					*ds - 6);
			exif_data_save_data_content (data,
						     data->ifd[EXIF_IFD_EXIF], d, ds, *ds - 6);
			offset += 12;
		}

		/* The pointer to IFD_GPS is in IFD_0, too. */
		if (data->ifd[EXIF_IFD_GPS]->count) {
			exif_set_short (*d + 6 + offset + 0, data->priv->order,
					EXIF_TAG_GPS_INFO_IFD_POINTER);
			exif_set_short (*d + 6 + offset + 2, data->priv->order,
					EXIF_FORMAT_LONG);
			exif_set_long  (*d + 6 + offset + 4, data->priv->order,
					1);
			exif_set_long  (*d + 6 + offset + 8, data->priv->order,
					*ds - 6);
			exif_data_save_data_content (data,
						     data->ifd[EXIF_IFD_GPS], d, ds, *ds - 6);
			offset += 12;
		}

		break;
	case EXIF_IFD_EXIF:

		/*
		 * The pointer to IFD_INTEROPERABILITY is in IFD_EXIF.
		 * See note above.
		 */
		if (data->ifd[EXIF_IFD_INTEROPERABILITY]->count) {
			exif_set_short (*d + 6 + offset + 0, data->priv->order,
					EXIF_TAG_INTEROPERABILITY_IFD_POINTER);
			exif_set_short (*d + 6 + offset + 2, data->priv->order,
					EXIF_FORMAT_LONG);
			exif_set_long  (*d + 6 + offset + 4, data->priv->order,
					1);
			exif_set_long  (*d + 6 + offset + 8, data->priv->order,
					*ds - 6);
			exif_data_save_data_content (data,
						     data->ifd[EXIF_IFD_INTEROPERABILITY], d, ds,
						     *ds - 6);
			offset += 12;
		}

		break;
	case EXIF_IFD_1:

		/*
		 * Information about the thumbnail (if any) is saved in
		 * IFD_1.
		 */
		if (data->size) {

			/* EXIF_TAG_JPEG_INTERCHANGE_FORMAT */
			exif_set_short (*d + 6 + offset + 0, data->priv->order,
					EXIF_TAG_JPEG_INTERCHANGE_FORMAT);
			exif_set_short (*d + 6 + offset + 2, data->priv->order,
					EXIF_FORMAT_LONG);
			exif_set_long  (*d + 6 + offset + 4, data->priv->order,
					1);
			exif_set_long  (*d + 6 + offset + 8, data->priv->order,
					*ds - 6);
			ts = *ds + data->size;
			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;
			memcpy (*d + *ds - data->size, data->data, data->size);
			offset += 12;

			/* EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH */
			exif_set_short (*d + 6 + offset + 0, data->priv->order,
					EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH);
			exif_set_short (*d + 6 + offset + 2, data->priv->order,
					EXIF_FORMAT_LONG);
			exif_set_long  (*d + 6 + offset + 4, data->priv->order,
					1);
			exif_set_long  (*d + 6 + offset + 8, data->priv->order,
					data->size);
			offset += 12;
		}

		break;
	default:
		break;
	}

	/* Sort the directory according to TIFF specification */
	qsort (*d + 6 + offset - (ifd->count + n_ptr + n_thumb) * 12,
	       (ifd->count + n_ptr + n_thumb), 12,
	       (data->priv->order == EXIF_BYTE_ORDER_INTEL) ? cmp_func_intel : cmp_func_motorola);

	/* Correctly terminate the directory */
	if (i == EXIF_IFD_0 && (data->ifd[EXIF_IFD_1]->count ||
				data->size)) {

		/*
		 * We are saving IFD 0. Tell where IFD 1 starts and save
		 * IFD 1.
		 */
		exif_set_long (*d + 6 + offset, data->priv->order, *ds - 6);
		exif_data_save_data_content (data, data->ifd[EXIF_IFD_1], d, ds,
					     *ds - 6);
	} else
		exif_set_long (*d + 6 + offset, data->priv->order, 0);
}
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));
}
static void
exif_mnote_data_canon_save (ExifMnoteData *ne,
                            unsigned char **buf, unsigned int *buf_size)
{
    ExifMnoteDataCanon *n = (ExifMnoteDataCanon *) ne;
    size_t i, o, s, doff;
    unsigned char *t;
    size_t ts;

    if (!n || !buf || !buf_size) return;

    /*
     * Allocate enough memory for all entries and the number
     * of entries.
     */
    *buf_size = 2 + n->count * 12 + 4;
    *buf = exif_mem_alloc (ne->mem, sizeof (char) * *buf_size);
    if (!*buf) {
        EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteCanon", *buf_size);
        return;
    }

    /* Save the number of entries */
    exif_set_short (*buf, n->order, (ExifShort) n->count);

    /* Save each entry */
    for (i = 0; i < n->count; i++) {
        o = 2 + i * 12;
        exif_set_short (*buf + o + 0, n->order, (ExifShort) n->entries[i].tag);
        exif_set_short (*buf + o + 2, n->order, (ExifShort) n->entries[i].format);
        exif_set_long  (*buf + o + 4, n->order,
                        n->entries[i].components);
        o += 8;
        s = exif_format_get_size (n->entries[i].format) *
            n->entries[i].components;
        if (s > 65536) {
            /* Corrupt data: EXIF data size is limited to the
             * maximum size of a JPEG segment (64 kb).
             */
            continue;
        }
        if (s > 4) {
            ts = *buf_size + s;

            /* Ensure even offsets. Set padding bytes to 0. */
            if (s & 1) ts += 1;
            t = exif_mem_realloc (ne->mem, *buf,
                                  sizeof (char) * ts);
            if (!t) {
                EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteCanon", ts);
                return;
            }
            *buf = t;
            *buf_size = ts;
            doff = *buf_size - s;
            if (s & 1) {
                doff--;
                *(*buf + *buf_size - 1) = '\0';
            }
            exif_set_long (*buf + o, n->order, n->offset + doff);
        } else
            doff = o;

        /*
         * Write the data. Fill unneeded bytes with 0. Do not
         * crash if data is NULL.
         */
        if (!n->entries[i].data) memset (*buf + doff, 0, s);
        else memcpy (*buf + doff, n->entries[i].data, s);
        if (s < 4) memset (*buf + doff + s, 0, (4 - s));
    }
}
static void
exif_mnote_data_fuji_save (ExifMnoteData *ne, unsigned char **buf,
			   unsigned int *buf_size)
{
	ExifMnoteDataFuji *n = (ExifMnoteDataFuji *) ne;
	size_t i, o, s, doff;
	unsigned char *t;
	size_t ts;

	if (!n || !buf || !buf_size) return;

	/*
	 * Allocate enough memory for all entries and the number
	 * of entries.
	 */
	*buf_size = 8 + 4 + 2 + n->count * 12 + 4;
	*buf = exif_mem_alloc (ne->mem, *buf_size);
	if (!*buf) {
		*buf_size = 0;
		return;
	}

	/*
	 * Header: "FUJIFILM" and 4 bytes offset to the first entry.
	 * As the first entry will start right thereafter, the offset is 12.
	 */
	memcpy (*buf, "FUJIFILM", 8);
	exif_set_long (*buf + 8, n->order, 12);

	/* Save the number of entries */
	exif_set_short (*buf + 8 + 4, n->order, (ExifShort) n->count);
	
	/* Save each entry */
	for (i = 0; i < n->count; i++) {
		o = 8 + 4 + 2 + i * 12;
		exif_set_short (*buf + o + 0, n->order, (ExifShort) n->entries[i].tag);
		exif_set_short (*buf + o + 2, n->order, (ExifShort) n->entries[i].format);
		exif_set_long  (*buf + o + 4, n->order, n->entries[i].components);
		o += 8;
		s = exif_format_get_size (n->entries[i].format) *
						n->entries[i].components;
		if (s > 65536) {
			/* Corrupt data: EXIF data size is limited to the
			 * maximum size of a JPEG segment (64 kb).
			 */
			continue;
		}
		if (s > 4) {
			ts = *buf_size + s;

			/* Ensure even offsets. Set padding bytes to 0. */
			if (s & 1) ts += 1;
			t = exif_mem_realloc (ne->mem, *buf, ts);
			if (!t) {
				return;
			}
			*buf = t;
			*buf_size = ts;
			doff = *buf_size - s;
			if (s & 1) { doff--; *(*buf + *buf_size - 1) = '\0'; }
			exif_set_long (*buf + o, n->order, doff);
		} else
			doff = o;

		/*
		 * Write the data. Fill unneeded bytes with 0. Do not
		 * crash if data is NULL.
		 */
		if (!n->entries[i].data) memset (*buf + doff, 0, s);
		else memcpy (*buf + doff, n->entries[i].data, s);
	}
}