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; }
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; }
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; } }
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); } }
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; } }
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; }
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; }
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; }
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); } }
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); } }
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); }
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); }
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; }
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; } } }