示例#1
0
文件: sgeo-tag.c 项目: SITIS/libsgeo
MapTags *read_sgeo_tags_map(ExifData **exif_array, ExifIfd ifd, ExifShort map_count)
{
	int i;
	MapTags *map_data = NULL;
	ExifData *exif = NULL;
	ExifEntry *entry;
	ExifByteOrder order;
	SGeoTag stag;
	ExifSRational *srational = NULL;
	ExifLong *elong = NULL;
	
	order = exif_data_get_byte_order(exif);
	map_data = (MapTags* )calloc(map_count, sizeof(*map_data));
	for (i = 0; i < map_count; i++)
	{
		exif = exif_array[i];

		entry = exif_content_get_entry (exif->ifd[ifd], (ExifTag)(SGEO_TAG_MAP_VERSION));
		if (entry)
			memcpy(map_data[i].VersionID, entry->data, sizeof(map_data[i].VersionID));

		entry = exif_content_get_entry (exif->ifd[ifd], (ExifTag)(SGEO_TAG_MAP_ID));
		if (entry)
			map_data[i].ID = exif_get_long(entry->data, order);

		srational = &map_data[i].TopLeftLongitude;
		for (stag = SGEO_TAG_MAP_TOP_LEFT_LONGITUDE; stag <= SGEO_TAG_MAP_BOTTOM_RIGHT_LATITUDE; stag++)
		{
			entry = exif_content_get_entry (exif->ifd[ifd], (ExifTag)(stag));
			if (entry)
				*srational = exif_get_srational(entry->data, order);
			srational++;
		}
		elong = &map_data[i].CoordinateSystem;
		for (stag = SGEO_TAG_MAP_COORDINATE_SYSTEM; stag <= SGEO_TAG_MAP_THUMBNAIL_FORMAT; stag++)
		{
			entry = exif_content_get_entry (exif->ifd[ifd], (ExifTag)(stag));
			if (entry)
				*elong = exif_get_long(entry->data, order);
			elong++;
		}
		entry = exif_content_get_entry (exif->ifd[ifd], (ExifTag)(SGEO_TAG_MAP_THUMBNAIL));
		if (entry)
		{
			map_data[i].Data = (void *)malloc(entry->size);
			map_data[i].DataSize = entry->size;
			memcpy(map_data[i].Data, entry->data, entry->size);
		}
	}
	return map_data;
}
示例#2
0
quint64 ImageSlideInfo::readExifUIntValue(ExifData* pExifData, ExifTag exifTag)
{
    quint64 exifValue = 0;

    if (!pExifData)
        return exifValue;

    ExifByteOrder exifByteOrder = exif_data_get_byte_order(pExifData);

    ExifEntry* pExifEntry = exif_data_get_entry(pExifData, exifTag);
    if (pExifEntry) {
        // paranoic a bit
        if (pExifEntry->size <= sizeof(quint64)) {
            if (pExifEntry->format == EXIF_FORMAT_BYTE)
                exifValue = static_cast<quint64>(*pExifEntry->data);

            if (pExifEntry->format == EXIF_FORMAT_SHORT)
                exifValue = static_cast<quint64>(exif_get_short(pExifEntry->data, exifByteOrder));

            if (pExifEntry->format == EXIF_FORMAT_LONG)
                exifValue = static_cast<quint64>(exif_get_long(pExifEntry->data, exifByteOrder));
        }
    }

    return exifValue;
}
示例#3
0
static void entry_getdata_aux (lua_State *L, ExifEntry *entry, unsigned int n) {
  ExifFormat format = entry->format;
  size_t formatsize = (size_t)exif_format_get_size(format);
  const unsigned char *ptr = entry->data+formatsize*n;
  ExifByteOrder order = exif_data_get_byte_order(entry->parent->parent);

  switch (format) {
  case EXIF_FORMAT_BYTE: lua_pushinteger(L, (ExifByte)*ptr); break;
  case EXIF_FORMAT_SBYTE: lua_pushinteger(L, (ExifSByte)*ptr); break;
  case EXIF_FORMAT_SHORT: lua_pushinteger(L, exif_get_short(ptr, order)); break;
  case EXIF_FORMAT_SSHORT: lua_pushinteger(L, exif_get_sshort(ptr, order)); break;
  case EXIF_FORMAT_LONG: lua_pushnumber(L, exif_get_long(ptr, order)); break;
  case EXIF_FORMAT_SLONG: lua_pushinteger(L, exif_get_slong(ptr, order)); break;
  case EXIF_FORMAT_RATIONAL: {
      ExifRational rat = exif_get_rational(ptr, order);
      pushrational(L, rat.numerator, rat.denominator);
      break;
    }
  case EXIF_FORMAT_SRATIONAL: {
      ExifSRational rat = exif_get_srational(ptr, order);
      pushrational(L, rat.numerator, rat.denominator);
      break;
    }
  case EXIF_FORMAT_ASCII: lua_pushinteger(L, *ptr); break;
  default:
    lua_pushnil(L);
    break;
  }
}
示例#4
0
static double exifDouble(ExifEntry *entry, ExifByteOrder byte_order) {
  switch (entry->format) {
  case EXIF_FORMAT_BYTE:
    return double(entry->data[0]);
  case EXIF_FORMAT_SHORT:
    return double(exif_get_short(entry->data, byte_order));
  case EXIF_FORMAT_LONG:
    return double(exif_get_long(entry->data, byte_order));
  case EXIF_FORMAT_RATIONAL: {
    ExifRational r = exif_get_rational(entry->data, byte_order);
    return double(r.numerator)/double(r.denominator);
  }
  case EXIF_FORMAT_SBYTE:
    return double(*(signed char *)entry->data);
  case EXIF_FORMAT_SSHORT:
    return double(exif_get_sshort(entry->data, byte_order));
  case EXIF_FORMAT_SLONG:
    return double(exif_get_slong(entry->data, byte_order));
  case EXIF_FORMAT_SRATIONAL: {
    ExifSRational r = exif_get_srational(entry->data, byte_order);
    return double(r.numerator)/double(r.denominator);
  }
  case EXIF_FORMAT_FLOAT:
    return double(((float *)entry->data)[0]);
  case EXIF_FORMAT_DOUBLE:
    return ((double *)entry->data)[0];
  default:
    return nan(0);
  }
}
示例#5
0
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);
	}
}
static int getDouble(ExifData *ed, ExifByteOrder bo, ExifTag t, double *d) {
    ExifEntry * e = exif_data_get_entry(ed, t);
    if (!e)
        return 0;

    char *b = e->data;

    switch (e->format) {
        case EXIF_FORMAT_SHORT:
            *d = (double) exif_get_short(b, bo);
            return 1;

        case EXIF_FORMAT_SSHORT:
            *d = (double) exif_get_sshort(b, bo);
            return 1;

        case EXIF_FORMAT_LONG:
            *d = (double) exif_get_long(b, bo);
            return 1;

        case EXIF_FORMAT_SLONG:
            *d = (double) exif_get_slong(b, bo);
            return 1;

        case EXIF_FORMAT_RATIONAL:
        {
            ExifRational r = exif_get_rational(b, bo);
            *d = (double) r.numerator / (double) r.denominator;
            return 1;
        }

        case EXIF_FORMAT_SRATIONAL:
        {
            ExifSRational r = exif_get_srational(b, bo);
            *d = (double) r.numerator / (double) r.denominator;
            return 1;
        }

        default:
            return 0;
    }
}
示例#7
0
static long get_int(ExifData *ed, ExifEntry *ee)
{
    ExifByteOrder o = exif_data_get_byte_order(ed);
    long value;
    
    switch (ee->format) {
    case EXIF_FORMAT_SHORT:
	value = exif_get_short (ee->data, o);
	break;
    case EXIF_FORMAT_LONG:
	value = exif_get_long (ee->data, o);
	break;
    case EXIF_FORMAT_SLONG:
	value = exif_get_slong (ee->data, o);
	break;
    default:
	fprintf(stderr,"get_int oops\n");
	exit(1);
    }
    return value;
}
示例#8
0
文件: exif.c 项目: jcupitt/libvips
static int
vips_exif_get_int( ExifData *ed, 
	ExifEntry *entry, unsigned long component, int *out )
{
	ExifByteOrder bo = exif_data_get_byte_order( ed );
	size_t sizeof_component = entry->size / entry->components;
	size_t offset = component * sizeof_component;

	if( entry->format == EXIF_FORMAT_SHORT ) 
		*out = exif_get_short( entry->data + offset, bo );
	else if( entry->format == EXIF_FORMAT_SSHORT ) 
		*out = exif_get_sshort( entry->data + offset, bo );
	else if( entry->format == EXIF_FORMAT_LONG ) 
		/* This won't work for huge values, but who cares.
		 */
		*out = (int) exif_get_long( entry->data + offset, bo );
	else if( entry->format == EXIF_FORMAT_SLONG ) 
		*out = exif_get_slong( entry->data + offset, bo );
	else
		return( -1 );

	return( 0 );
}
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;
}
示例#10
0
static void
metadataparse_exif_content_foreach_entry_func (ExifEntry * entry,
    void *user_data)
{
  MEUserData *meudata = (MEUserData *) user_data;
  GType type = G_TYPE_NONE;
  ExifByteOrder byte_order;
  const gchar *tag;

  /* We need the byte order */
  if (!entry || !entry->parent || !entry->parent->parent)
    return;

  tag = metadataparse_exif_get_tag_from_exif (entry->tag, &type);
  byte_order = exif_data_get_byte_order (entry->parent->parent);

  if (metadataparse_handle_unit_tags (entry, meudata, byte_order))
    goto done;

  if (!tag)
    goto done;

  if (type == GST_TYPE_FRACTION) {
    gint numerator = 0;
    gint denominator = 1;

    switch (entry->format) {
      case EXIF_FORMAT_SRATIONAL:
      {
        ExifSRational v_srat;

        v_srat = exif_get_srational (entry->data, byte_order);
        if (v_srat.denominator) {
          numerator = (gint) v_srat.numerator;
          denominator = (gint) v_srat.denominator;
        }
      }
        break;
      case EXIF_FORMAT_RATIONAL:
      {
        ExifRational v_rat;

        v_rat = exif_get_rational (entry->data, byte_order);
        if (v_rat.denominator) {
          numerator = (gint) v_rat.numerator;
          denominator = (gint) v_rat.denominator;
        }
        if (meudata->resolution_unit == 3) {
          /* converts from cm to inches */
          if (entry->tag == EXIF_TAG_X_RESOLUTION
              || entry->tag == EXIF_TAG_Y_RESOLUTION) {
            numerator *= 2;
            denominator *= 5;
          }
        }
      }
        break;
      default:
        GST_ERROR ("Unexpected Tag Type");
        goto done;
        break;
    }
    gst_tag_list_add (meudata->taglist, meudata->mode, tag, numerator,
        denominator, NULL);

  } else if (type == GST_TYPE_BUFFER) {
    GstBuffer *buf = gst_buffer_new_and_alloc (entry->components);

    memcpy (GST_BUFFER_DATA (buf), entry->data, entry->components);
    gst_tag_list_add (meudata->taglist, meudata->mode, tag, buf, NULL);
    gst_buffer_unref (buf);
  } else {
    switch (type) {
      case G_TYPE_STRING:
      {
        char buf[2048];
        const gchar *str = exif_entry_get_value (entry, buf, sizeof (buf));
        GString *value = NULL;

        if (entry->tag == EXIF_TAG_DATE_TIME_DIGITIZED
            || entry->tag == EXIF_TAG_DATE_TIME
            || entry->tag == EXIF_TAG_DATE_TIME_ORIGINAL) {
          value = g_string_new_len (str, 20);
          /* 20 is enough memory to hold "YYYY-MM-DDTHH:MM:SS" */

          if (metadataparse_exif_convert_to_datetime (value)) {
            str = value->str;
          } else {
            GST_ERROR ("Unexpected date & time format for %s", tag);
            str = NULL;
          }

        }
        if (str)
          gst_tag_list_add (meudata->taglist, meudata->mode, tag, str, NULL);
        if (value)
          g_string_free (value, TRUE);
      }
        break;
      case G_TYPE_INT:
        /* fall through */
      case G_TYPE_UINT:
      {
        gint value;

        switch (entry->format) {
          case EXIF_FORMAT_SHORT:
            value = exif_get_short (entry->data, byte_order);
            break;
          case EXIF_FORMAT_LONG:
            value = exif_get_long (entry->data, byte_order);
            break;
          default:
            GST_ERROR ("Unexpected Exif Tag Type (%s - %s)",
                tag, exif_format_get_name (entry->format));
            goto done;
            break;
        }
        if (entry->tag == EXIF_TAG_CONTRAST ||
            entry->tag == EXIF_TAG_SATURATION) {
          switch (value) {
            case 0:
              break;
            case 1:
              value = -67;      /* -100-34 /2 */
              break;
            case 2:
              value = 67;       /* 100+34 /2 */
              break;
            default:
              GST_ERROR ("Unexpected value");
              break;
          }
        }
        gst_tag_list_add (meudata->taglist, meudata->mode, tag, value, NULL);
      }
        break;
      case G_TYPE_DOUBLE:
      {
        gdouble value = 0.0;

        if (entry->tag == EXIF_TAG_GPS_LATITUDE
            || entry->tag == EXIF_TAG_GPS_LONGITUDE) {
          ExifRational *rt = (ExifRational *) entry->data;

          /* DDD - degrees */
          value = (gdouble) rt->numerator / (gdouble) rt->denominator;
          GST_DEBUG ("deg: %lu / %lu", (gulong) rt->numerator,
              (gulong) rt->denominator);
          rt++;

          /* MM - minutes and SS - seconds */
          GST_DEBUG ("min: %lu / %lu", (gulong) rt->numerator,
              (gulong) rt->denominator);
          value += (gdouble) rt->numerator / ((gdouble) rt->denominator * 60.0);
          rt++;
          GST_DEBUG ("sec: %lu / %lu", (gulong) rt->numerator,
              (gulong) rt->denominator);
          value +=
              (gdouble) rt->numerator / ((gdouble) rt->denominator * 3600.0);

          /* apply sign */
          if (entry->tag == EXIF_TAG_GPS_LATITUDE) {
            if (((meudata->latitude_ref == 'S') && (value > 0.0)) ||
                ((meudata->latitude_ref == 'N') && (value < 0.0))) {
              value = -value;
            }
          } else {
            if (((meudata->longitude_ref == 'W') && (value > 0.0)) ||
                ((meudata->longitude_ref == 'E') && (value < 0.0))) {
              value = -value;
            }
          }
          GST_DEBUG ("long/lat : %lf", value);
        }
        if (entry->tag == EXIF_TAG_GPS_ALTITUDE) {
          ExifRational v_rat = exif_get_rational (entry->data, byte_order);
          value = (gdouble) v_rat.numerator / (gdouble) v_rat.denominator;
          if (((meudata->altitude_ref == 1) && (value > 0.0)) ||
              ((meudata->altitude_ref == 0) && (value < 0.0))) {
            value = -value;
          }
          GST_DEBUG ("altitude = %lf", value);
        }
        gst_tag_list_add (meudata->taglist, meudata->mode, tag, value, NULL);
      }
        break;
      default:
        break;
    }
  }


done:
  {
#ifndef GST_DISABLE_GST_DEBUG
    char buf[2048];
    GST_LOG ("\n    Entry %p: %s (%s)\n"
        "      Size, Comps: %d, %d\n"
        "      Value: %s\n"
        "      Title: %s\n"
        "      Description: %s\n",
        entry,
        exif_tag_get_name (entry->tag),
        exif_format_get_name (entry->format),
        entry->size,
        (int) (entry->components),
        exif_entry_get_value (entry, buf, sizeof (buf)),
        exif_tag_get_title (entry->tag), exif_tag_get_description (entry->tag));
#endif
  }
  return;

}
示例#11
0
void imFileFormatJPEG::iReadExifAttrib(unsigned char* data, int data_length, imAttribTable* attrib_table)
{
  ExifData* exif = exif_data_new_from_data(data, data_length);
  if (!exif)
    return;

  void* value = NULL;
  int c, value_size = 0;

  ExifByteOrder byte_order = exif_data_get_byte_order(exif);

  for (int ifd = 0; ifd < EXIF_IFD_COUNT; ifd++)
  {
    if (ifd == EXIF_IFD_1 || ifd == EXIF_IFD_INTEROPERABILITY) // Skip thumbnail and interoperability
      continue;

    ExifContent *content = exif->ifd[ifd];

    if (content && content->count) 
    {
      for (int j = 0; j < (int)content->count; j++) 
      {
        ExifEntry *entry = content->entries[j];
        int type = 0;

        const char* name = exif_tag_get_name_in_ifd(entry->tag, (ExifIfd)ifd);
        if (!name)
          continue;

        if (value_size < (int)entry->size)
        {
          value = realloc(value, entry->size);
          value_size = entry->size;
        }

        int format_size = exif_format_get_size(entry->format);

        if (entry->tag == EXIF_TAG_RESOLUTION_UNIT)
        {
          int res_unit = (int)exif_get_short (entry->data, byte_order);

          if (res_unit == 2)
            attrib_table->Set("ResolutionUnit", IM_BYTE, -1, "DPI");
          else if (res_unit == 3)
            attrib_table->Set("ResolutionUnit", IM_BYTE, -1, "DPC");

          continue;
        }

        switch (entry->format) 
        {
        case EXIF_FORMAT_UNDEFINED:
        case EXIF_FORMAT_ASCII:
        case EXIF_FORMAT_SBYTE:
        case EXIF_FORMAT_BYTE:
          {
            type = IM_BYTE;
            imbyte *bvalue = (imbyte*)value;
            for (c = 0; c < (int)entry->components; c++) 
              bvalue[c] = entry->data[c];
          }
          break;
        case EXIF_FORMAT_SSHORT:
          {
            type = IM_SHORT;
            short *svalue = (short*)value;
            for (c = 0; c < (int)entry->components; c++) 
              svalue[c] = exif_get_short(entry->data + format_size * c, byte_order);
          }
          break;
        case EXIF_FORMAT_SHORT:
          {
            type = IM_USHORT;
            imushort *usvalue = (imushort*)value;
            for (c = 0; c < (int)entry->components; c++) 
              usvalue[c] = exif_get_short(entry->data + format_size * c, byte_order);
          }
          break;
        case EXIF_FORMAT_LONG:
          {
            type = IM_INT;
            int *ivalue = (int*)value;
            for (c = 0; c < (int)entry->components; c++) 
              ivalue[c] = (int)exif_get_long(entry->data + format_size * c, byte_order);
          }
          break;
        case EXIF_FORMAT_SLONG:
          {
            type = IM_INT;
            int *ivalue = (int*)value;
            for (c = 0; c < (int)entry->components; c++) 
              ivalue[c] = (int)exif_get_slong(entry->data + format_size * c, byte_order);
          }
          break;
        case EXIF_FORMAT_RATIONAL:
          {
            ExifRational v_rat;
            type = IM_FLOAT;
            float *fvalue = (float*)value;
            for (c = 0; c < (int)entry->components; c++) 
            {
              v_rat = exif_get_rational(entry->data + format_size * c, byte_order);
              fvalue[c] = (float)v_rat.numerator / (float)v_rat.denominator;
            }
          }
          break;
        case EXIF_FORMAT_SRATIONAL:
          {
            ExifSRational v_srat;
            type = IM_FLOAT;
            float *fvalue = (float*)value;
            for (c = 0; c < (int)entry->components; c++) 
            {
              v_srat = exif_get_srational(entry->data + format_size * c, byte_order);
              fvalue[c] = (float)v_srat.numerator / (float)v_srat.denominator;
            }
          }
          break;
        case EXIF_FORMAT_FLOAT:  // defined but unsupported in libEXIF
        case EXIF_FORMAT_DOUBLE: // defined but unsupported in libEXIF
          break;
        }

        attrib_table->Set(name, type, entry->components, value);
      }
    }
  }

  if (value) free(value);

  exif_data_free(exif);
}
static void
exif_mnote_data_pentax_load (ExifMnoteData *en,
		const unsigned char *buf, unsigned int buf_size)
{
	ExifMnoteDataPentax *n = (ExifMnoteDataPentax *) en;
	unsigned int i, o, s, datao = 6 + n->offset, base = 0;
	ExifShort c;

	/* Number of entries */
	if (buf_size < datao + (4 + 2) + 2) return;
	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;
		}
		datao += 4 + 2;
		base = MNOTE_PENTAX2_TAG_BASE;
	} if (!memcmp(buf + datao, "QVC", 4)) {
		n->version = casioV2;
		base = MNOTE_CASIO2_TAG_BASE;
		datao += 4 + 2;
	} else {
		n->version = pentaxV1;
	}
	c = exif_get_short (buf + datao, n->order);
	n->entries = (MnotePentaxEntry *)exif_mem_alloc (en->mem, sizeof (MnotePentaxEntry) * c);
	if (!n->entries) return;

	for (i = 0; i < c; i++) {
		o = datao + 2 + 12 * i;
		if (o + 8 > buf_size) return;

		n->count = i + 1;
		n->entries[i].tag        = exif_get_short (buf + o + 0, n->order) + base;
		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 = (unsigned char *)exif_mem_alloc (en->mem, s);
		if (!n->entries[i].data) return;
		n->entries[i].size = s;
		memcpy (n->entries[i].data, buf + o, s);
        }
}
示例#13
0
static void
exif_mnote_data_olympus_load (ExifMnoteData *en,
			      const unsigned char *buf, unsigned int buf_size)
{
	ExifMnoteDataOlympus *n = (ExifMnoteDataOlympus *) en;
	ExifShort c;
	unsigned int i, s, o, o2 = 0, datao = 6, base = 0;

	if (!n || !buf) return;

	/* Start of interesting data */
	o2 = 6 + n->offset;

	/*
	 * 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.
	 *
	 * 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 (buf_size - n->offset < 22) return;
	if (!memcmp (buf + o2, "OLYMP", 6)) {
		exif_log (en->log, EXIF_LOG_CODE_DEBUG, "ExifMnoteDataOlympus",
			"Parsing Olympus maker note v1...");

		/* The number of entries is at position 8. */
		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;

	} 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;
			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 >= 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;
	} else {
		return;
	}

	/* Number of entries */
	if (o2 >= buf_size) return;
	c = exif_get_short (buf + o2, n->order);
	o2 += 2;

	/* Read the number of entries and remove old ones. */
	exif_mnote_data_olympus_clear (n);

	n->entries = exif_mem_alloc (en->mem, sizeof (MnoteOlympusEntry) * c);
	if (!n->entries) return;

	/* Parse the entries */
	for (i = 0; i < c; i++) {
	    o = o2 + 12 * i;
	    if (o + 12 > buf_size) return;

	    n->count = i + 1;
	    n->entries[i].tag        = exif_get_short (buf + o, n->order) + base;
	    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;

	    exif_log (en->log, EXIF_LOG_CODE_DEBUG, "ExifMnoteOlympus",
		      "Loading entry 0x%x ('%s')...", n->entries[i].tag,
		      mnote_olympus_tag_get_name (n->entries[i].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[i].format) *
		   			 n->entries[i].components;
	    if (!s) continue;
	    o += 8;
	    if (s > 4) o = exif_get_long (buf + o, n->order) + datao;
	    if (o + s > buf_size) continue;

	    /* Sanity check */
	    n->entries[i].data = exif_mem_alloc (en->mem, s);
	    if (!n->entries[i].data) continue;
	    n->entries[i].size = s;
	    memcpy (n->entries[i].data, buf + o, s);
	}
}
示例#14
0
static void foreach_exif_entry( ExifEntry * entry , void * _closure )
{
	if ( ! entry )
	{
		return;
	}

	//.........................................................................
	// Bail out of types we don't handle

	switch( entry->format )
	{
	case EXIF_FORMAT_UNDEFINED:
	case EXIF_FORMAT_FLOAT:
	case EXIF_FORMAT_DOUBLE:
		return;
	default:
		break;
	}

	//.........................................................................

	unsigned char component_size = exif_format_get_size( entry->format );

	ExifIfd ifd = exif_content_get_ifd( entry->parent );

	const char * tag_name = exif_tag_get_name_in_ifd( entry->tag , ifd );

	if ( ! tag_name || ! entry->data || ! entry->size || ! component_size || ! entry->components )
	{
		return;
	}

	//.........................................................................
	// Add a prefix based on the IFD

	String name( tag_name );

	switch( ifd )
	{
	case EXIF_IFD_0:
		name = "IMAGE/" + name;
		break;
	case EXIF_IFD_1:
		name = "THUMBNAIL/" + name;
		break;
	case EXIF_IFD_EXIF:
		name = "EXIF/" + name;
		break;
	case EXIF_IFD_GPS:
		name = "GPS/" + name;
		break;
	case EXIF_IFD_INTEROPERABILITY:
		name = "INTEROP/" + name;
		break;
	default:
		return;
	}

	ExifClosure * closure = ( ExifClosure * ) _closure;

	JSON::Object * tags = closure->tags;

	//.........................................................................
	// ASCII ones are easy

	if ( entry->format == EXIF_FORMAT_ASCII )
	{
		(*tags)[ name ] = String( ( const char * ) entry->data , entry->size );
		return;
	}

	//.........................................................................

	if ( ( entry->components * component_size ) != entry->size )
	{
		return;
	}

	ExifByteOrder byte_order = exif_data_get_byte_order( closure->exif_data );

	const unsigned char * data = entry->data;

	JSON::Array array;

	for ( unsigned long i = 0; i < entry->components; ++i )
	{
		switch( entry->format )
		{
		case EXIF_FORMAT_BYTE:
			array.append( JSON::Value( int( * data ) ) );
			break;

		case EXIF_FORMAT_SHORT:
			array.append( JSON::Value( int( exif_get_short( data , byte_order ) ) ) );
			break;

		case EXIF_FORMAT_LONG:
			array.append( JSON::Value( int( exif_get_long( data , byte_order ) ) ) );
			break;

		case EXIF_FORMAT_SBYTE:
			array.append( JSON::Value( int( * ( ( const char * ) data ) ) ) );
			break;

		case EXIF_FORMAT_SSHORT:
			array.append( JSON::Value( exif_get_sshort( data , byte_order ) ) );
			break;

		case EXIF_FORMAT_SLONG:
			array.append( JSON::Value( exif_get_slong( data , byte_order ) ) );
			break;

		// TODO: I don't like representing a rational number as a string with a slash,

		case EXIF_FORMAT_SRATIONAL:
		{
			ExifSRational r = exif_get_srational( data , byte_order );
			array.append( Util::format("%ld/%ld" , r.numerator , r.denominator ) );
			break;
		}

		case EXIF_FORMAT_RATIONAL:
		{
			ExifRational r = exif_get_rational( data , byte_order );
			array.append( Util::format("%lu/%lu" , r.numerator , r.denominator ) );
			break;
		}
		default:
			break;
		}

		data += component_size;
	}

	if ( array.size() == 1 )
	{
		(*tags)[ name ] = array[ 0 ];
	}
	else if ( array.size() > 1 )
	{
		(*tags)[ name ] = array;
	}
}
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;
}
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.
	 */
	interpret_maker_note(data, d, ds);

	/* Fixup tags if requested */
	if (data->priv->options & EXIF_DATA_OPTION_FOLLOW_SPECIFICATION)
		exif_data_fix (data);
}
示例#17
0
static void analyzer_jpeg_exif_entry_analyze(ExifEntry *entry, void *pload) {

	ExifIfd ifd = exif_content_get_ifd(entry->parent);

	const char *tag_name = exif_tag_get_name_in_ifd(entry->tag, ifd);
	if (!tag_name) // Unknown tag
		return;

	struct ptype *value = NULL;
	// First parse ascii values
	if (entry->format == EXIF_FORMAT_ASCII) {
		char *str = malloc(entry->size);
		if (!str) {
			pom_oom(entry->size);
			return;
		}
		memcpy(str, entry->data, entry->size);
		// Make sure it's NULL terminated
		str[entry->size - 1] = 0;

		value = ptype_alloc("string");
		if (!value) {
			free(str);
			return;
		}
		PTYPE_STRING_SETVAL_P(value, str);
	} else if (entry->components == 1) {
		
		ExifByteOrder byte_order = exif_data_get_byte_order(entry->parent->parent);
		if (entry->format == EXIF_FORMAT_BYTE) {
			value = ptype_alloc("uint8");
			if (!value)
				return;
			PTYPE_UINT8_SETVAL(value, *entry->data);
		} else if (entry->format == EXIF_FORMAT_SHORT)	{
			value = ptype_alloc("uint16");
			if (!value)
				return;
			PTYPE_UINT16_SETVAL(value, exif_get_short(entry->data, byte_order));
		} else if (entry->format == EXIF_FORMAT_LONG) {
			value = ptype_alloc("uint32");
			if (!value)
				return;
			PTYPE_UINT32_SETVAL(value, exif_get_long(entry->data, byte_order));
		}

	}

	if (!value) {
		// Fallback for types not parsed by us yet
		// FIXME this is subject to the locale

		char buff[256];
		buff[sizeof(buff) - 1] = 0;
		exif_entry_get_value(entry, buff, sizeof(buff) - 1);

		value = ptype_alloc("string");
		if (!value)
			return;
		PTYPE_STRING_SETVAL(value, buff);

	}

	char *key = strdup(tag_name);
	if (!key) {
		pom_oom(strlen(tag_name) + 1);
		return;
	}

	struct data *data = analyzer_pload_buffer_get_data(pload);
	data_item_add_ptype(data, analyzer_jpeg_pload_exif, key, value);

}
示例#18
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_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;
}
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;
}
示例#21
0
char *
mnote_pentax_entry_get_value (MnotePentaxEntry *entry,
			      char *val, unsigned int maxlen)
{
	ExifLong vl;
	ExifShort vs, vs2;
	int i = 0, j = 0;

	if (!entry) return (NULL);

	memset (val, 0, maxlen);
	maxlen--;

	switch (entry->tag) {
	  case MNOTE_PENTAX_TAG_MODE:
	  case MNOTE_PENTAX_TAG_QUALITY:
	  case MNOTE_PENTAX_TAG_FOCUS:
	  case MNOTE_PENTAX_TAG_FLASH:
	  case MNOTE_PENTAX_TAG_WHITE_BALANCE:
	  case MNOTE_PENTAX_TAG_SHARPNESS:
	  case MNOTE_PENTAX_TAG_CONTRAST:
	  case MNOTE_PENTAX_TAG_SATURATION:
	  case MNOTE_PENTAX_TAG_ISO_SPEED:
	  case MNOTE_PENTAX_TAG_COLOR:
	  case MNOTE_PENTAX2_TAG_MODE:
	  case MNOTE_PENTAX2_TAG_QUALITY:
	  case MNOTE_PENTAX2_TAG_FLASH_MODE:
	  case MNOTE_PENTAX2_TAG_FOCUS_MODE:
	  case MNOTE_PENTAX2_TAG_AFPOINT_SELECTED:
	  case MNOTE_PENTAX2_TAG_AUTO_AFPOINT:
	  case MNOTE_PENTAX2_TAG_WHITE_BALANCE:
	  case MNOTE_PENTAX2_TAG_PICTURE_MODE:
	  case MNOTE_PENTAX2_TAG_IMAGE_SIZE:
	  case MNOTE_CASIO2_TAG_BESTSHOT_MODE:
		CF (entry->format, EXIF_FORMAT_SHORT, val, maxlen);
		CC2 (entry->components, 1, 2, val, maxlen);
		if (entry->components == 1) {
			vs = exif_get_short (entry->data, entry->order);

			/* search the tag */
			for (i = 0; (items[i].tag && items[i].tag != entry->tag); i++);
			if (!items[i].tag) {
				snprintf (val, maxlen,
					  _("Internal error (unknown value %i)"), vs);
			  	break;
			}

			/* find the value */
			for (j = 0; items[i].elem[j].string &&
			    (items[i].elem[j].index < vs); j++);
			if (items[i].elem[j].index != vs) {
				snprintf (val, maxlen,
					  _("Internal error (unknown value %i)"), vs);
				break;
			}
			strncpy (val, _(items[i].elem[j].string), maxlen);
		} else {
			/* Two-component values */
			CF (entry->format, EXIF_FORMAT_SHORT, val, maxlen);
			CC2 (entry->components, 1, 2, val, maxlen);
			vs = exif_get_short (entry->data, entry->order);
			vs2 = exif_get_short (entry->data+2, entry->order) << 16;

			/* search the tag */
			for (i = 0; (items2[i].tag && items2[i].tag != entry->tag); i++);
			if (!items2[i].tag) {
				snprintf (val, maxlen,
					  _("Internal error (unknown value %i %i)"), vs, vs2);
			  	break;
			}

			/* find the value */
			for (j = 0; items2[i].elem[j].string && ((items2[i].elem[j].index2 < vs2)
				|| ((items2[i].elem[j].index2 == vs2) && (items2[i].elem[j].index1 < vs))); j++);
			if ((items2[i].elem[j].index1 != vs) || (items2[i].elem[j].index2 != vs2)) {
				snprintf (val, maxlen,
					  _("Internal error (unknown value %i %i)"), vs, vs2);
				break;
			}
			strncpy (val, _(items2[i].elem[j].string), maxlen);
		}
		break;

	case MNOTE_PENTAX_TAG_ZOOM:
		CF (entry->format, EXIF_FORMAT_LONG, val, maxlen);
		CC (entry->components, 1, val, maxlen);
		vl = exif_get_long (entry->data, entry->order);
		snprintf (val, maxlen, "%li", (long int) vl);
		break;
	case MNOTE_PENTAX_TAG_PRINTIM:
		CF (entry->format, EXIF_FORMAT_UNDEFINED, val, maxlen);
		CC (entry->components, 124, val, maxlen);
		snprintf (val, maxlen, _("%i bytes unknown data"),
			entry->size);
		break;
	case MNOTE_PENTAX_TAG_TZ_CITY:
	case MNOTE_PENTAX_TAG_TZ_DST:
		CF (entry->format, EXIF_FORMAT_UNDEFINED, val, maxlen);
		CC (entry->components, 4, val, maxlen);
		strncpy (val, (char*)entry->data, MIN(maxlen, entry->size));
		break;
	case MNOTE_PENTAX2_TAG_DATE:
		CF (entry->format, EXIF_FORMAT_UNDEFINED, val, maxlen);
		CC (entry->components, 4, val, maxlen);
		/* Note: format is UNDEFINED, not SHORT -> order is fixed: MOTOROLA */
		vs = exif_get_short (entry->data, EXIF_BYTE_ORDER_MOTOROLA);
		snprintf (val, maxlen, "%i:%02i:%02i", vs, entry->data[2], entry->data[3]);
		break;
	case MNOTE_PENTAX2_TAG_TIME:
		CF (entry->format, EXIF_FORMAT_UNDEFINED, val, maxlen);
		CC2 (entry->components, 3, 4, val, maxlen);
		snprintf (val, maxlen, "%02i:%02i:%02i", entry->data[0], entry->data[1], entry->data[2]);
		break;
	default:
		switch (entry->format) {
		case EXIF_FORMAT_ASCII:
		  strncpy (val, (char *)entry->data, MIN(maxlen, entry->size));
		  break;
		case EXIF_FORMAT_SHORT:
		  {
			const unsigned char *data = entry->data;
		  	size_t k, len = strlen(val);
		  	for(k=0; k<entry->components; k++) {
				vs = exif_get_short (data, entry->order);
				snprintf (val+len, maxlen-len, "%i ", vs);
				len = strlen(val);
				data += 2;
			}
		  }
		  break;
		case EXIF_FORMAT_LONG:
		  {
			const unsigned char *data = entry->data;
		  	size_t k, len = strlen(val);
		  	for(k=0; k<entry->components; k++) {
				vl = exif_get_long (data, entry->order);
				snprintf (val+len, maxlen-len, "%li", (long int) vl);
				len = strlen(val);
				data += 4;
			}
		  }
		  break;
		case EXIF_FORMAT_UNDEFINED:
		default:
		  snprintf (val, maxlen, _("%i bytes unknown data"),
			  entry->size);
		  break;
		}
		break;
	}

	return (val);
}
/*! Load data for an IFD.
 *
 * \param[in,out] data #ExifData
 * \param[in] ifd IFD to load
 * \param[in] d pointer to buffer containing raw IFD data
 * \param[in] ds size of raw data in buffer at \c d
 * \param[in] offset offset into buffer at \c d at which IFD starts
 * \param[in] recursion_depth number of times this function has been
 * recursively called without returning
 */
static void
exif_data_load_data_content (ExifData *data, ExifIfd ifd,
			     const unsigned char *d,
			     unsigned int ds, unsigned int offset, unsigned int recursion_depth)
{
	ExifLong o, thumbnail_offset = 0, thumbnail_length = 0;
	ExifShort n;
	ExifEntry *entry;
	unsigned int i;
	ExifTag tag;

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

	/* check for valid ExifIfd enum range */
	if ((((int)ifd) < 0) || ( ((int)ifd) >= EXIF_IFD_COUNT))
	  return;

	if (recursion_depth > 30) {
		exif_log (data->priv->log, EXIF_LOG_CODE_CORRUPT_DATA, "ExifData",
			  "Deep recursion detected!");
		return;
	}

	/* Read the number of entries */
	if ((offset + 2 < offset) || (offset + 2 < 2) || (offset + 2 > ds)) {
		exif_log (data->priv->log, EXIF_LOG_CODE_CORRUPT_DATA, "ExifData",
			  "Tag data past end of buffer (%u > %u)", offset+2, ds);
		return;
	}
	n = exif_get_short (d + offset, data->priv->order);
	exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData",
	          "Loading %hu entries...", n);
	offset += 2;

	/* Check if we have enough data. */
	if (offset + 12 * n > ds) {
		n = (ds - offset) / 12;
		exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData",
				  "Short data; only loading %hu entries...", n);
	}

	for (i = 0; i < n; i++) {

		tag = exif_get_short (d + offset + 12 * i, data->priv->order);
		switch (tag) {
		case EXIF_TAG_EXIF_IFD_POINTER:
		case EXIF_TAG_GPS_INFO_IFD_POINTER:
		case EXIF_TAG_INTEROPERABILITY_IFD_POINTER:
		case EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH:
		case EXIF_TAG_JPEG_INTERCHANGE_FORMAT:
			o = exif_get_long (d + offset + 12 * i + 8,
					   data->priv->order);
			/* FIXME: IFD_POINTER tags aren't marked as being in a
			 * specific IFD, so exif_tag_get_name_in_ifd won't work
			 */
			exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData",
				  "Sub-IFD entry 0x%x ('%s') at %u.", tag,
				  exif_tag_get_name(tag), o);
			switch (tag) {
			case EXIF_TAG_EXIF_IFD_POINTER:
				CHECK_REC (EXIF_IFD_EXIF);
				exif_data_load_data_content (data, EXIF_IFD_EXIF, d, ds, o, recursion_depth + 1);
				break;
			case EXIF_TAG_GPS_INFO_IFD_POINTER:
				CHECK_REC (EXIF_IFD_GPS);
				exif_data_load_data_content (data, EXIF_IFD_GPS, d, ds, o, recursion_depth + 1);
				break;
			case EXIF_TAG_INTEROPERABILITY_IFD_POINTER:
				CHECK_REC (EXIF_IFD_INTEROPERABILITY);
				exif_data_load_data_content (data, EXIF_IFD_INTEROPERABILITY, d, ds, o, recursion_depth + 1);
				break;
			case EXIF_TAG_JPEG_INTERCHANGE_FORMAT:
				thumbnail_offset = o;
				if (thumbnail_offset && thumbnail_length)
					exif_data_load_data_thumbnail (data, d,
								       ds, thumbnail_offset,
								       thumbnail_length);
				break;
			case EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH:
				thumbnail_length = o;
				if (thumbnail_offset && thumbnail_length)
					exif_data_load_data_thumbnail (data, d,
								       ds, thumbnail_offset,
								       thumbnail_length);
				break;
			default:
				return;
			}
			break;
		default:

			/*
			 * If we don't know the tag, don't fail. It could be that new 
			 * versions of the standard have defined additional tags. Note that
			 * 0 is a valid tag in the GPS IFD.
			 */
			if (!exif_tag_get_name_in_ifd (tag, ifd)) {

				/*
				 * Special case: Tag and format 0. That's against specification
				 * (at least up to 2.2). But Photoshop writes it anyways.
				 */
				if (!memcmp (d + offset + 12 * i, "\0\0\0\0", 4)) {
					exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData",
						  "Skipping empty entry at position %u in '%s'.", i, 
						  exif_ifd_get_name (ifd));
					break;
				}
				exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData",
					  "Unknown tag 0x%04x (entry %u in '%s'). Please report this tag "
					  "to <*****@*****.**>.", tag, i,
					  exif_ifd_get_name (ifd));
				if (data->priv->options & EXIF_DATA_OPTION_IGNORE_UNKNOWN_TAGS)
					break;
			}
			entry = exif_entry_new_mem (data->priv->mem);
			if (exif_data_load_data_entry (data, entry, d, ds,
						   offset + 12 * i))
				exif_content_add_entry (data->ifd[ifd], entry);
			exif_entry_unref (entry);
			break;
		}
	}
}