static void *
exif_data_alloc (ExifData *data, unsigned int i)
{
	void *d;

	if (!data || !i) 
		return NULL;

	d = exif_mem_alloc (data->priv->mem, i);
	if (d) 
		return d;

	EXIF_LOG_NO_MEMORY (data->priv->log, "ExifData", i);
	return NULL;
}
Example #2
0
static void *
exif_loader_alloc (ExifLoader *l, unsigned int i)
{
	void *d;

	if (!l || !i) 
		return NULL;

	d = exif_mem_alloc (l->mem, i);
	if (d) 
		return d;

	EXIF_LOG_NO_MEMORY (l->log, "ExifLog", i);
	return NULL;
}
void
jpeg_data_load_file (JPEGData *data, const char *path)
{
	FILE *f;
	unsigned char *d;
	//For Fix Prevent Issue CID :13211
	int size;

	if (!data) return;
	if (!path) return;

	f = fopen (path, "rb");
	if (!f) {
		exif_log (data->priv->log, EXIF_LOG_CODE_CORRUPT_DATA, "jpeg-data",
				_("Path '%s' invalid."), path);
		return;
	}

	/* For now, we read the data into memory. Patches welcome... */
	fseek (f, 0, SEEK_END);
	size = ftell (f);

	if(size <0){
		fclose (f);
		return;
	}
	
	fseek (f, 0, SEEK_SET);
	d = malloc (size);
	if (!d) {
		EXIF_LOG_NO_MEMORY (data->priv->log, "jpeg-data", size);
		fclose (f);
		return;
	}
	if (fread (d, 1, size, f) != size) {
		free (d);
		fclose (f);
		exif_log (data->priv->log, EXIF_LOG_CODE_CORRUPT_DATA, "jpeg-data",
				_("Could not read '%s'."), path);
		return;
	}
	fclose (f);

	jpeg_data_load_data (data, d, size);
	free (d);
}
Example #4
0
void jpeg_data_exclude_section (JPEGData *data, JPEGSection *exclude)
{
	unsigned int i;
	//JPEGSection *s;

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

	for (i = 0; i < data->count; i++)
		if (&data->sections[i] == exclude)
		{
			data->count--;

			switch (exclude->marker)
			{
			case JPEG_MARKER_SOI:
			case JPEG_MARKER_EOI:
				break;
			case JPEG_MARKER_APP1:
				exif_data_unref (exclude->content.app1);
				break;
			default:
				free (exclude->content._generic.data);
				break;
			}

			for (; i < data->count; i++)
				data->sections[i] = data->sections[i + 1];
			if (data->count > 0)
			{
				data->sections = (JPEGSection *)realloc (data->sections,
					 sizeof (JPEGSection) * (data->count));
				if (!data->sections)
				{
					EXIF_LOG_NO_MEMORY (data->priv->log, "jpeg-data", 
						sizeof (JPEGSection) * (data->count));
				}
			}
			else
			{
				free(data->sections);
				data->sections = NULL;
			}
			break;
		}
}
void
jpeg_data_append_section (JPEGData *data)
{
	JPEGSection *s;

	if (!data) return;

	if (!data->count)
		s = malloc (sizeof (JPEGSection));
	else
		s = realloc (data->sections,
			     sizeof (JPEGSection) * (data->count + 1));
	if (!s) {
		EXIF_LOG_NO_MEMORY (data->priv->log, "jpeg-data", 
				sizeof (JPEGSection) * (data->count + 1));
		return;
	}
	memset(s + data->count, 0, sizeof (JPEGSection));
	data->sections = s;
	data->count++;
}
static void
exif_data_load_data_thumbnail (ExifData *data, const unsigned char *d,
			       unsigned int ds, ExifLong o, ExifLong s)
{
	/* Sanity checks */
	if ((o + s < o) || (o + s < s) || (o + s > ds) || (o > ds)) {
		exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData",
			  "Bogus thumbnail offset (%u) or size (%u).",
			  o, s);
		return;
	}

	if (data->data) 
		exif_mem_free (data->priv->mem, data->data);
	if (!(data->data = exif_data_alloc (data, s))) {
		EXIF_LOG_NO_MEMORY (data->priv->log, "ExifData", s);
		data->size = 0;
		return;
	}
	data->size = s;
	memcpy (data->data, d + o, s);
}
void
jpeg_data_load_data (JPEGData *data, const unsigned char *d,
		     unsigned int size)
{
	unsigned int i, o, len;
	JPEGSection *s;
	JPEGMarker marker;

	if (!data) return;
	if (!d) return;

	for (o = 0; o < size;) {

		/*
		 * JPEG sections start with 0xff. The first byte that is
		 * not 0xff is a marker (hopefully).
		 */
		for (i = 0; i < MIN(7, size - o); i++)
			if (d[o + i] != 0xff)
				break;
		if ((i >= size - o) || !JPEG_IS_MARKER (d[o + i])) {
			exif_log (data->priv->log, EXIF_LOG_CODE_CORRUPT_DATA, "jpeg-data",
					_("Data does not follow JPEG specification."));
			return;
		}
		marker = d[o + i];

		/* Append this section */
		jpeg_data_append_section (data);
		if (!data->count) return;
		s = &data->sections[data->count - 1];
		s->marker = marker;
		o += i + 1;

		switch (s->marker) {
		case JPEG_MARKER_SOI:
		case JPEG_MARKER_EOI:
			break;
		default:

			/* Read the length of the section */
			if (2 > size - o) { o = size; break; }
			len = ((d[o] << 8) | d[o + 1]) - 2;
			if (len > size) { o = size; break; }
			o += 2;
			if (len > size - o) { o = size; break; }

			switch (s->marker) {
			case JPEG_MARKER_APP1:
            /* Changed to add the EXIF_LOG feature.
               2012.04.05 - Samsung Electronics */
				/*s->content.app1 = exif_data_new_from_data (
							d + o - 4, len + 4); */
				s->content.app1 = exif_data_new();
                exif_data_log(s->content.app1, data->priv->log);
            	exif_data_load_data (s->content.app1, d + o - 4, len + 4);
				break;
			default:
				s->content.generic.data =
						malloc (sizeof (char) * len);
				if (!s->content.generic.data) {
					EXIF_LOG_NO_MEMORY (data->priv->log, "jpeg-data", sizeof (char) * len);
					return;
				}
				s->content.generic.size = len;
				memcpy (s->content.generic.data, &d[o], len);

				/* In case of SOS, image data will follow. */
				if (s->marker == JPEG_MARKER_SOS) {
					data->size = size - o - len;
					if (data->size >= 2) {
						/* -2 means 'take all but the last 2 bytes which are
						   hoped to be JPEG_MARKER_EOI */
						data->size -= 2;
						if (d[o + len + data->size] != 0xFF) {
							/* A truncated file (i.e. w/o JPEG_MARKER_EOI at the end).
							   Instead of trying to use the last two bytes as marker,
							   touching memory beyond allocated memory and posssibly saving
							   back screwed file, we rather take the rest of the file. */
							data->size += 2;
						}
					}
					data->data = malloc (
						sizeof (char) * data->size);
					if (!data->data) {
						EXIF_LOG_NO_MEMORY (data->priv->log, "jpeg-data", sizeof (char) * data->size);
						data->size = 0;
						return;
					}
					memcpy (data->data, d + o + len,
						data->size);
					o += data->size;
				}
				break;
			}
			o += len;
			break;
		}
	}
}
/** 
 * @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_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_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 int
exif_data_load_data_entry (ExifData *data, ExifEntry *entry,
			   const unsigned char *d,
			   unsigned int size, unsigned int offset)
{
	unsigned int s, doff;

	entry->tag        = exif_get_short (d + offset + 0, data->priv->order);
	entry->format     = exif_get_short (d + offset + 2, data->priv->order);
	entry->components = exif_get_long  (d + offset + 4, data->priv->order);

	/* FIXME: should use exif_tag_get_name_in_ifd here but entry->parent 
	 * has not been set yet
	 */
	exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData",
		  "Loading entry 0x%x ('%s')...", entry->tag,
		  exif_tag_get_name (entry->tag));

	/* {0,1,2,4,8} x { 0x00000000 .. 0xffffffff } 
	 *   -> { 0x000000000 .. 0x7fffffff8 } */
	s = exif_format_get_size(entry->format) * entry->components;
	if ((s < entry->components) || (s == 0)){
		return 0;
	}

	/*
	 * Size? If bigger than 4 bytes, the actual data is not
	 * in the entry but somewhere else (offset).
	 */
	if (s > 4)
		doff = exif_get_long (d + offset + 8, data->priv->order);
	else
		doff = offset + 8;

	/* Sanity checks */
	if ((doff + s < doff) || (doff + s < s) || (doff + s > size)) {
		exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData",
				  "Tag data past end of buffer (%u > %u)", doff+s, size);	
		return 0;
	}

	entry->data = exif_data_alloc (data, s);
	if (entry->data) {
		entry->size = s;
		memcpy (entry->data, d + doff, s);
	} else {
		/* FIXME: What do our callers do if (entry->data == NULL)? */
		EXIF_LOG_NO_MEMORY(data->priv->log, "ExifData", s);
	}

	/* If this is the MakerNote, remember the offset */
	if (entry->tag == EXIF_TAG_MAKER_NOTE) {
		if (!entry->data) {
			exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData",
					  "MakerNote found with empty data");	
		} else if (entry->size > 6) {
			exif_log (data->priv->log,
					       EXIF_LOG_CODE_DEBUG, "ExifData",
					       "MakerNote found (%02x %02x %02x %02x "
					       "%02x %02x %02x...).",
					       entry->data[0], entry->data[1], entry->data[2],
					       entry->data[3], entry->data[4], entry->data[5],
					       entry->data[6]);
		}
		data->priv->offset_mnote = doff;
	}
	return 1;
}
static void
exif_mnote_data_canon_load (ExifMnoteData *ne,
                            const unsigned char *buf, unsigned int buf_size)
{
    ExifMnoteDataCanon *n = (ExifMnoteDataCanon *) ne;
    ExifShort c;
    size_t i, tcount, o, datao;

    if (!n || !buf || !buf_size) {
        exif_log (ne->log, EXIF_LOG_CODE_CORRUPT_DATA,
                  "ExifMnoteCanon", "Short MakerNote");
        return;
    }
    datao = 6 + n->offset;
    if ((datao + 2 < datao) || (datao + 2 < 2) || (datao + 2 > buf_size)) {
        exif_log (ne->log, EXIF_LOG_CODE_CORRUPT_DATA,
                  "ExifMnoteCanon", "Short MakerNote");
        return;
    }

    /* Read the number of tags */
    c = exif_get_short (buf + datao, n->order);
    datao += 2;

    /* Remove any old entries */
    exif_mnote_data_canon_clear (n);

    /* Reserve enough space for all the possible MakerNote tags */
    n->entries = exif_mem_alloc (ne->mem, sizeof (MnoteCanonEntry) * c);
    if (!n->entries) {
        EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteCanon", sizeof (MnoteCanonEntry) * c);
        return;
    }

    /* Parse the entries */
    tcount = 0;
    for (i = c, o = datao; i; --i, o += 12) {
        size_t s;
        if ((o + 12 < o) || (o + 12 < 12) || (o + 12 > buf_size)) {
            exif_log (ne->log, EXIF_LOG_CODE_CORRUPT_DATA,
                      "ExifMnoteCanon", "Short MakerNote");
            break;
        }

        n->entries[tcount].tag        = exif_get_short (buf + o, n->order);
        n->entries[tcount].format     = exif_get_short (buf + o + 2, n->order);
        n->entries[tcount].components = exif_get_long (buf + o + 4, n->order);
        n->entries[tcount].order      = n->order;

        exif_log (ne->log, EXIF_LOG_CODE_DEBUG, "ExifMnoteCanon",
                  "Loading entry 0x%x ('%s')...", n->entries[tcount].tag,
                  mnote_canon_tag_get_name (n->entries[tcount].tag));

        /*
         * 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[tcount].format) *
            n->entries[tcount].components;
        n->entries[tcount].size = s;
        if (!s) {
            exif_log (ne->log, EXIF_LOG_CODE_CORRUPT_DATA,
                      "ExifMnoteCanon",
                      "Invalid zero-length tag size");
            continue;

        } else {
            size_t dataofs = o + 8;
            if (s > 4) dataofs = exif_get_long (buf + dataofs, n->order) + 6;
            if ((dataofs + s < s) || (dataofs + s < dataofs) || (dataofs + s > buf_size)) {
                exif_log (ne->log, EXIF_LOG_CODE_DEBUG,
                          "ExifMnoteCanon",
                          "Tag data past end of buffer (%u > %u)",
                          dataofs + s, buf_size);
                continue;
            }

            n->entries[tcount].data = exif_mem_alloc (ne->mem, s);
            if (!n->entries[tcount].data) {
                EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteCanon", s);
                continue;
            }
            memcpy (n->entries[tcount].data, buf + dataofs, s);
        }

        /* Tag was successfully parsed */
        ++tcount;
    }
    /* Store the count of successfully parsed tags */
    n->count = tcount;
}
Example #14
0
static void
exif_mnote_data_olympus_load (ExifMnoteData *en,
			      const unsigned char *buf, unsigned int buf_size)
{
	ExifMnoteDataOlympus *n = (ExifMnoteDataOlympus *) en;
	ExifShort c;
	size_t i, tcount, o, o2, datao = 6, base = 0;

	if (!n || !buf || !buf_size) {
		exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA,
			  "ExifMnoteDataOlympus", "Short MakerNote");
		return;
	}
	o2 = 6 + n->offset; /* Start of interesting data */
	if ((o2 + 10 < o2) || (o2 + 10 < 10) || (o2 + 10 > buf_size)) {
		exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA,
			  "ExifMnoteDataOlympus", "Short MakerNote");
		return;
	}

	/*
	 * Olympus headers start with "OLYMP" and need to have at least
	 * a size of 22 bytes (6 for 'OLYMP', 2 other bytes, 2 for the
	 * number of entries, and 12 for one entry.
	 *
	 * Sanyo format is identical and uses identical tags except that
	 * header starts with "SANYO".
	 *
	 * Epson format is identical and uses identical tags except that
	 * header starts with "EPSON".
	 *
	 * Nikon headers start with "Nikon" (6 bytes including '\0'), 
	 * version number (1 or 2).
	 * 
	 * Version 1 continues with 0, 1, 0, number_of_tags,
	 * or just with number_of_tags (models D1H, D1X...).
	 * 
	 * Version 2 continues with an unknown byte (0 or 10),
	 * two unknown bytes (0), "MM" or "II", another byte 0 and 
	 * lastly 0x2A.
	 */
	if (!memcmp (buf + o2, "OLYMP", 6) || !memcmp (buf + o2, "SANYO", 6) ||
	    !memcmp (buf + o2, "EPSON", 6)) {
		exif_log (en->log, EXIF_LOG_CODE_DEBUG, "ExifMnoteDataOlympus",
			"Parsing Olympus/Sanyo/Epson maker note v1...");

		/* The number of entries is at position 8. */
		if (!memcmp (buf + o2, "SANYO", 6))
			n->version = sanyoV1;
		else if (!memcmp (buf + o2, "EPSON", 6))
			n->version = epsonV1;
		else
			n->version = olympusV1;
		if (buf[o2 + 6] == 1)
			n->order = EXIF_BYTE_ORDER_INTEL;
		else if (buf[o2 + 6 + 1] == 1)
			n->order = EXIF_BYTE_ORDER_MOTOROLA;
		o2 += 8;
		if (o2 + 2 > buf_size) return;
		c = exif_get_short (buf + o2, n->order);
		if ((!(c & 0xFF)) && (c > 0x500)) {
			if (n->order == EXIF_BYTE_ORDER_INTEL) {
				n->order = EXIF_BYTE_ORDER_MOTOROLA;
			} else {
				n->order = EXIF_BYTE_ORDER_INTEL;
			}
		}

	} else if (!memcmp (buf + o2, "OLYMPUS", 8)) {
		/* Olympus S760, S770 */
		datao = o2;
		o2 += 8;
		exif_log (en->log, EXIF_LOG_CODE_DEBUG, "ExifMnoteDataOlympus",
			"Parsing Olympus maker note v2 (0x%02x, %02x, %02x, %02x)...",
			buf[o2], buf[o2 + 1], buf[o2 + 2], buf[o2 + 3]);

		if ((buf[o2] == 'I') && (buf[o2 + 1] == 'I'))
			n->order = EXIF_BYTE_ORDER_INTEL;
		else if ((buf[o2] == 'M') && (buf[o2 + 1] == 'M'))
			n->order = EXIF_BYTE_ORDER_MOTOROLA;

		/* The number of entries is at position 8+4. */
		n->version = olympusV2;
		o2 += 4;

	} else if (!memcmp (buf + o2, "Nikon", 6)) {
		o2 += 6;
		exif_log (en->log, EXIF_LOG_CODE_DEBUG, "ExifMnoteDataOlympus",
			"Parsing Nikon maker note (0x%02x, %02x, %02x, "
			"%02x, %02x, %02x, %02x, %02x)...",
			buf[o2 + 0], buf[o2 + 1], buf[o2 + 2], buf[o2 + 3], 
			buf[o2 + 4], buf[o2 + 5], buf[o2 + 6], buf[o2 + 7]);
		/* The first byte is the version. */
		if (o2 >= buf_size) return;
		n->version = buf[o2];
		o2 += 1;

		/* Skip an unknown byte (00 or 0A). */
		o2 += 1;

		switch (n->version) {
		case nikonV1:

			base = MNOTE_NIKON1_TAG_BASE;
			/* Fix endianness, if needed */
			if (o2 + 2 > buf_size) return;
			c = exif_get_short (buf + o2, n->order);
			if ((!(c & 0xFF)) && (c > 0x500)) {
				if (n->order == EXIF_BYTE_ORDER_INTEL) {
					n->order = EXIF_BYTE_ORDER_MOTOROLA;
				} else {
					n->order = EXIF_BYTE_ORDER_INTEL;
				}
			}
			break;

		case nikonV2:

			/* Skip 2 unknown bytes (00 00). */
			o2 += 2;

			/*
			 * Byte order. From here the data offset
			 * gets calculated.
			 */
			datao = o2;
			if (o2 >= buf_size) return;
			if (!strncmp ((char *)&buf[o2], "II", 2))
				n->order = EXIF_BYTE_ORDER_INTEL;
			else if (!strncmp ((char *)&buf[o2], "MM", 2))
				n->order = EXIF_BYTE_ORDER_MOTOROLA;
			else {
				exif_log (en->log, EXIF_LOG_CODE_DEBUG,
					"ExifMnoteDatalympus", "Unknown "
					"byte order '%c%c'", buf[o2],
					buf[o2 + 1]);
				return;
			}
			o2 += 2;

			/* Skip 2 unknown bytes (00 2A). */
			o2 += 2;

			/* Go to where the number of entries is. */
			if (o2 + 4 > buf_size) return;
			o2 = datao + exif_get_long (buf + o2, n->order);
			break;

		default:
			exif_log (en->log, EXIF_LOG_CODE_DEBUG,
				"ExifMnoteDataOlympus", "Unknown version "
				"number %i.", n->version);
			return;
		}
	} else if (!memcmp (buf + o2, "\0\x1b", 2)) {
		n->version = nikonV2;
		/* 00 1b is # of entries in Motorola order - the rest should also be in MM order */
		n->order = EXIF_BYTE_ORDER_MOTOROLA;
	} else {
		return;
	}

	/* Sanity check the offset */
	if ((o2 + 2 < o2) || (o2 + 2 < 2) || (o2 + 2 > buf_size)) {
		exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA,
			  "ExifMnoteOlympus", "Short MakerNote");
		return;
	}

	/* Read the number of tags */
	c = exif_get_short (buf + o2, n->order);
	o2 += 2;

	/* Remove any old entries */
	exif_mnote_data_olympus_clear (n);

	/* Reserve enough space for all the possible MakerNote tags */
	n->entries = exif_mem_alloc (en->mem, sizeof (MnoteOlympusEntry) * c);
	if (!n->entries) {
		EXIF_LOG_NO_MEMORY(en->log, "ExifMnoteOlympus", sizeof (MnoteOlympusEntry) * c);
		return;
	}

	/* Parse all c entries, storing ones that are successfully parsed */
	tcount = 0;
	for (i = c, o = o2; i; --i, o += 12) {
		size_t s;
		if ((o + 12 < o) || (o + 12 < 12) || (o + 12 > buf_size)) {
			exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA,
				  "ExifMnoteOlympus", "Short MakerNote");
			break;
		}

	    n->entries[tcount].tag        = exif_get_short (buf + o, n->order) + base;
	    n->entries[tcount].format     = exif_get_short (buf + o + 2, n->order);
	    n->entries[tcount].components = exif_get_long (buf + o + 4, n->order);
	    n->entries[tcount].order      = n->order;

	    exif_log (en->log, EXIF_LOG_CODE_DEBUG, "ExifMnoteOlympus",
		      "Loading entry 0x%x ('%s')...", n->entries[tcount].tag,
		      mnote_olympus_tag_get_name (n->entries[tcount].tag));
/*	    exif_log (en->log, EXIF_LOG_CODE_DEBUG, "ExifMnoteOlympus",
			    "0x%x %d %ld*(%d)",
		    n->entries[tcount].tag,
		    n->entries[tcount].format,
		    n->entries[tcount].components,
		    (int)exif_format_get_size(n->entries[tcount].format)); */

	    /*
	     * 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[tcount].format) *
		   			 n->entries[tcount].components;
		n->entries[tcount].size = s;
		if (s) {
			size_t dataofs = o + 8;
			if (s > 4) {
				/* The data in this case is merely a pointer */
				dataofs = exif_get_long (buf + dataofs, n->order) + datao;
#ifdef EXIF_OVERCOME_SANYO_OFFSET_BUG
				/* Some Sanyo models (e.g. VPC-C5, C40) suffer from a bug when
				 * writing the offset for the MNOTE_OLYMPUS_TAG_THUMBNAILIMAGE
				 * tag in its MakerNote. The offset is actually the absolute
				 * position in the file instead of the position within the IFD.
				 */
			    if (dataofs + s > buf_size && n->version == sanyoV1) {
					/* fix pointer */
					dataofs -= datao + 6;
					exif_log (en->log, EXIF_LOG_CODE_DEBUG,
						  "ExifMnoteOlympus",
						  "Inconsistent thumbnail tag offset; attempting to recover");
			    }
#endif
			}
			if ((dataofs + s < dataofs) || (dataofs + s < s) || 
			    (dataofs + s > buf_size)) {
				exif_log (en->log, EXIF_LOG_CODE_DEBUG,
					  "ExifMnoteOlympus",
					  "Tag data past end of buffer (%u > %u)",
					  dataofs + s, buf_size);
				continue;
			}

			n->entries[tcount].data = exif_mem_alloc (en->mem, s);
			if (!n->entries[tcount].data) {
				EXIF_LOG_NO_MEMORY(en->log, "ExifMnoteOlympus", s);
				continue;
			}
			memcpy (n->entries[tcount].data, buf + dataofs, s);
		}

		/* Tag was successfully parsed */
		++tcount;
	}
	/* Store the count of successfully parsed tags */
	n->count = tcount;
}
static void
exif_mnote_data_pentax_load (ExifMnoteData *en,
		const unsigned char *buf, unsigned int buf_size)
{
	ExifMnoteDataPentax *n = (ExifMnoteDataPentax *) en;
	size_t i, tcount, o, datao, base = 0;
	ExifShort c;

	if (!n || !buf || !buf_size) {
		exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA,
			  "ExifMnoteDataPentax", "Short MakerNote");
		return;
	}
	datao = 6 + n->offset;
	if ((datao + 8 < datao) || (datao + 8 < 8) || (datao + 8 > buf_size)) {
		exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA,
			  "ExifMnoteDataPentax", "Short MakerNote");
		return;
	}

	/* Detect variant of Pentax/Casio MakerNote found */
	if (!memcmp(buf + datao, "AOC", 4)) {
		if ((buf[datao + 4] == 'I') && (buf[datao + 5] == 'I')) {
			n->version = pentaxV3;
			n->order = EXIF_BYTE_ORDER_INTEL;
		} else if ((buf[datao + 4] == 'M') && (buf[datao + 5] == 'M')) {
			n->version = pentaxV3;
			n->order = EXIF_BYTE_ORDER_MOTOROLA;
		} else {
			/* Uses Casio v2 tags */
			n->version = pentaxV2;
		}
		exif_log (en->log, EXIF_LOG_CODE_DEBUG, "ExifMnoteDataPentax",
			"Parsing Pentax maker note v%d...", (int)n->version);
		datao += 4 + 2;
		base = MNOTE_PENTAX2_TAG_BASE;
	} else if (!memcmp(buf + datao, "QVC", 4)) {
		exif_log (en->log, EXIF_LOG_CODE_DEBUG, "ExifMnoteDataPentax",
			"Parsing Casio maker note v2...");
		n->version = casioV2;
		base = MNOTE_CASIO2_TAG_BASE;
		datao += 4 + 2;
	} else {
		/* probably assert(!memcmp(buf + datao, "\x00\x1b", 2)) */
		exif_log (en->log, EXIF_LOG_CODE_DEBUG, "ExifMnoteDataPentax",
			"Parsing Pentax maker note v1...");
		n->version = pentaxV1;
	}

	/* Read the number of tags */
	c = exif_get_short (buf + datao, n->order);
	datao += 2;

	/* Remove any old entries */
	exif_mnote_data_pentax_clear (n);

	/* Reserve enough space for all the possible MakerNote tags */
	n->entries = exif_mem_alloc (en->mem, sizeof (MnotePentaxEntry) * c);
	if (!n->entries) {
		EXIF_LOG_NO_MEMORY(en->log, "ExifMnoteDataPentax", sizeof (MnotePentaxEntry) * c);
		return;
	}

	/* Parse all c entries, storing ones that are successfully parsed */
	tcount = 0;
	for (i = c, o = datao; i; --i, o += 12) {
		size_t s;
		if ((o + 12 < o) || (o + 12 < 12) || (o + 12 > buf_size)) {
			exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA,
				  "ExifMnoteDataPentax", "Short MakerNote");
			break;
		}

		n->entries[tcount].tag        = exif_get_short (buf + o + 0, n->order) + base;
		n->entries[tcount].format     = exif_get_short (buf + o + 2, n->order);
		n->entries[tcount].components = exif_get_long  (buf + o + 4, n->order);
		n->entries[tcount].order      = n->order;

		exif_log (en->log, EXIF_LOG_CODE_DEBUG, "ExifMnotePentax",
			  "Loading entry 0x%x ('%s')...", n->entries[tcount].tag,
			  mnote_pentax_tag_get_name (n->entries[tcount].tag));

		/*
		 * 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[tcount].format) *
                                      n->entries[tcount].components;
		n->entries[tcount].size = s;
		if (s) {
			size_t dataofs = o + 8;
			if (s > 4)
				/* The data in this case is merely a pointer */
			   	dataofs = exif_get_long (buf + dataofs, n->order) + 6;
			if ((dataofs + s < dataofs) || (dataofs + s < s) ||
				(dataofs + s > buf_size)) {
				exif_log (en->log, EXIF_LOG_CODE_DEBUG,
						  "ExifMnoteDataPentax", "Tag data past end "
					  "of buffer (%u > %u)", dataofs + s, buf_size);
				continue;
			}

			n->entries[tcount].data = exif_mem_alloc (en->mem, s);
			if (!n->entries[tcount].data) {
				EXIF_LOG_NO_MEMORY(en->log, "ExifMnoteDataPentax", s);
				continue;
			}
			memcpy (n->entries[tcount].data, buf + dataofs, s);
		}

		/* Tag was successfully parsed */
		++tcount;
	}
	/* Store the count of successfully parsed tags */
	n->count = tcount;
}
Example #16
0
/** 
 * @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);
		}
	}
}
static void
exif_mnote_data_fuji_load (ExifMnoteData *en,
	const unsigned char *buf, unsigned int buf_size)
{
	ExifMnoteDataFuji *n = (ExifMnoteDataFuji*) en;
	ExifLong c;
	size_t i, tcount, o, datao;

	if (!n || !buf || !buf_size) {
		exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA,
			  "ExifMnoteDataFuji", "Short MakerNote");
		return;
	}
	datao = 6 + n->offset;
	if ((datao + 12 < datao) || (datao + 12 < 12) || (datao + 12 > buf_size)) {
		exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA,
			  "ExifMnoteDataFuji", "Short MakerNote");
		return;
	}

	n->order = EXIF_BYTE_ORDER_INTEL;
	datao += exif_get_long (buf + datao + 8, EXIF_BYTE_ORDER_INTEL);
	if ((datao + 2 < datao) || (datao + 2 < 2) ||
	    (datao + 2 > buf_size)) {
		exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA,
			  "ExifMnoteDataFuji", "Short MakerNote");
		return;
	}

	/* Read the number of tags */
	c = exif_get_short (buf + datao, EXIF_BYTE_ORDER_INTEL);
	datao += 2;

	/* Remove any old entries */
	exif_mnote_data_fuji_clear (n);

	/* Reserve enough space for all the possible MakerNote tags */
	n->entries = exif_mem_alloc (en->mem, sizeof (MnoteFujiEntry) * c);
	if (!n->entries) {
		EXIF_LOG_NO_MEMORY(en->log, "ExifMnoteDataFuji", sizeof (MnoteFujiEntry) * c);
		return;
	}

	/* Parse all c entries, storing ones that are successfully parsed */
	tcount = 0;
	for (i = c, o = datao; i; --i, o += 12) {
		size_t s;
		if ((o + 12 < o) || (o + 12 < 12) || (o + 12 > buf_size)) {
			exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA,
				  "ExifMnoteDataFuji", "Short MakerNote");
			break;
		}

		n->entries[tcount].tag        = exif_get_short (buf + o, n->order);
		n->entries[tcount].format     = exif_get_short (buf + o + 2, n->order);
		n->entries[tcount].components = exif_get_long (buf + o + 4, n->order);
		n->entries[tcount].order      = n->order;

		exif_log (en->log, EXIF_LOG_CODE_DEBUG, "ExifMnoteDataFuji",
			  "Loading entry 0x%x ('%s')...", n->entries[tcount].tag,
			  mnote_fuji_tag_get_name (n->entries[tcount].tag));

		/*
		 * 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[tcount].format) * n->entries[tcount].components;
		n->entries[tcount].size = s;
		if (s) {
			size_t dataofs = o + 8;
			if (s > 4)
				/* The data in this case is merely a pointer */
				dataofs = exif_get_long (buf + dataofs, n->order) + 6 + n->offset;
			if ((dataofs + s < dataofs) || (dataofs + s < s) ||
				(dataofs + s >= buf_size)) {
				exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA,
						  "ExifMnoteDataFuji", "Tag data past end of "
					  "buffer (%zu >= %u)", dataofs + s, buf_size);
				continue;
			}

			n->entries[tcount].data = exif_mem_alloc (en->mem, s);
			if (!n->entries[tcount].data) {
				EXIF_LOG_NO_MEMORY(en->log, "ExifMnoteDataFuji", s);
				continue;
			}
			memcpy (n->entries[tcount].data, buf + dataofs, s);
		}

		/* Tag was successfully parsed */
		++tcount;
	}
	/* Store the count of successfully parsed tags */
	n->count = tcount;
}