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 gboolean parse_exif_gps_coordinate (ExifEntry *entry, gdouble *co, ExifByteOrder byte_order) { gsize val_size; ExifRational val; gdouble hour = 0, min = 0, sec = 0; if (G_UNLIKELY (!MAP_EXIF_ENTRY_IS_GPS_RATIONAL (entry))) return FALSE; val_size = exif_format_get_size (EXIF_FORMAT_RATIONAL); val = exif_get_rational (entry->data, byte_order); if (val.denominator != 0) hour = (gdouble) val.numerator / (gdouble) val.denominator; val = exif_get_rational (entry->data + val_size, byte_order); if (val.denominator != 0) min = (gdouble) val.numerator / (gdouble) val.denominator; val = exif_get_rational (entry->data + (2 * val_size), byte_order); if (val.denominator != 0) sec = (gdouble) val.numerator / (gdouble) val.denominator; if (G_LIKELY (co != NULL)) { *co = hour + (min / 60.0) + (sec / 3600.0); } return TRUE; }
static struct LatLon get_latlon ( ExifData *ed ) { struct LatLon ll = { 0.0, 0.0 }; const struct LatLon ll0 = { 0.0, 0.0 }; gchar str[128]; ExifEntry *ee; // // Lat & Long is necessary to form a waypoint. // ee = exif_content_get_entry (ed->ifd[EXIF_IFD_GPS], EXIF_TAG_GPS_LATITUDE); if ( ! ( ee && ee->components == 3 && ee->format == EXIF_FORMAT_RATIONAL ) ) return ll0; ll.lat = Rational2Double ( ee->data, exif_format_get_size(ee->format), exif_data_get_byte_order(ed) ); ee = exif_content_get_entry (ed->ifd[EXIF_IFD_GPS], EXIF_TAG_GPS_LATITUDE_REF); if ( ee ) { exif_entry_get_value ( ee, str, 128 ); if ( str[0] == 'S' ) ll.lat = -ll.lat; } ee = exif_content_get_entry (ed->ifd[EXIF_IFD_GPS], EXIF_TAG_GPS_LONGITUDE); if ( ! ( ee && ee->components == 3 && ee->format == EXIF_FORMAT_RATIONAL ) ) return ll0; ll.lon = Rational2Double ( ee->data, exif_format_get_size(ee->format), exif_data_get_byte_order(ed) ); ee = exif_content_get_entry (ed->ifd[EXIF_IFD_GPS], EXIF_TAG_GPS_LONGITUDE_REF); if ( ee ) { exif_entry_get_value ( ee, str, 128 ); if ( str[0] == 'W' ) ll.lon = -ll.lon; } return ll; }
static void exif_mnote_data_canon_save (ExifMnoteData *ne, unsigned char **buf, unsigned int *buf_size) { ExifMnoteDataCanon *n = (ExifMnoteDataCanon *) ne; unsigned int i, o, s, doff; if (!n || !buf || !buf_size) return; /* * Allocate enough memory for all entries and the number * of entries. */ *buf_size = 2 + n->count * 12 + 4; *buf = exif_mem_alloc (ne->mem, sizeof (char) * *buf_size); if (!*buf) return; /* Save the number of entries */ exif_set_short (*buf, n->order, (ExifShort) n->count); /* Save each entry */ for (i = 0; i < n->count; i++) { o = 2 + i * 12; exif_set_short (*buf + o + 0, n->order, (ExifShort) n->entries[i].tag); exif_set_short (*buf + o + 2, n->order, (ExifShort) n->entries[i].format); exif_set_long (*buf + o + 4, n->order, n->entries[i].components); o += 8; s = exif_format_get_size (n->entries[i].format) * n->entries[i].components; if (s > 4) { *buf_size += s; /* Ensure even offsets. Set padding bytes to 0. */ if (s & 1) *buf_size += 1; *buf = exif_mem_realloc (ne->mem, *buf, sizeof (char) * *buf_size); if (!*buf) return; doff = *buf_size - s; if (s & 1) { doff--; *(*buf + *buf_size - 1) = '\0'; } exif_set_long (*buf + o, n->order, n->offset + doff); } else doff = o; /* * Write the data. Fill unneeded bytes with 0. Do not * crash if data is NULL. */ if (!n->entries[i].data) memset (*buf + doff, 0, s); else memcpy (*buf + doff, n->entries[i].data, s); if (s < 4) memset (*buf + doff + s, 0, (4 - s)); } }
void exif_entry_set_gps_coord(ExifData * pEdata, ExifIfd eEifd, ExifTag eEtag, ExifRational r1, ExifRational r2, ExifRational r3) { ExifEntry *pE; ExifByteOrder eO; pE = exif_entry_new (); exif_content_add_entry (pEdata->ifd[eEifd], pE); exif_entry_gps_initialize(pE, eEtag); eO = exif_data_get_byte_order (pE->parent->parent); if (pE->data) { exif_set_rational (pE->data, eO, r1); exif_set_rational (pE->data + exif_format_get_size (pE->format), eO, r2); exif_set_rational (pE->data + 2 * exif_format_get_size (pE->format), eO, r3); } else { printf ("ERROR: unallocated e->data Tag %d\n", eEtag); } exif_entry_fix (pE); exif_entry_unref (pE); }
static ExifEntry* allocateEntry(int tag, ExifFormat format, unsigned int numComponents) { ExifMem* mem = exif_mem_new_default(); ExifEntry* entry = exif_entry_new_mem(mem); unsigned int size = numComponents * exif_format_get_size(format); entry->data = reinterpret_cast<unsigned char*>(exif_mem_alloc(mem, size)); entry->size = size; entry->tag = static_cast<ExifTag>(tag); entry->components = numComponents; entry->format = format; exif_mem_unref(mem); return entry; }
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); } }
void write_sgeo_app2(JPEGSection *section, ExifData *exif) { int size_sgeo_bytes = 10; unsigned int i = 0; unsigned int s = 0; unsigned int next_data = 0; ExifEntry *entry = NULL; ExifContent *sgeo_content = NULL; unsigned char *d = NULL; sgeo_content = exif->ifd[EXIF_IFD_SGEO]; size_sgeo_bytes += sgeo_content->count * 12; for (i = 0; i < sgeo_content->count; i++) { entry = sgeo_content->entries[i]; if (entry != NULL) { s = exif_format_get_size(entry->format) * entry->components; if (s > 4) size_sgeo_bytes += s; //s += 12;// +tag size //else // s = 12; } } section->content._generic.data = (unsigned char* )calloc((size_t)size_sgeo_bytes, 1); if (section->content._generic.data == NULL) return; section->marker = JPEG_MARKER_APP2; section->content._generic.size = size_sgeo_bytes; d = section->content._generic.data; memcpy(d, "FPXR\0\0\0\0", 8); d = d + 8; write_content_binary(d, sgeo_content, exif->priv->order, 8 + // "FPXR\0\0\0\0" 2); // size APP2 }
ExifEntry *create_tag_in_content(ExifContent *content, ExifTag tag, size_t len, ExifFormat exifFormat) { void *buf; ExifEntry *entry; size_t size; /* Create a memory allocator to manage this ExifEntry */ ExifMem *mem = exif_mem_new_default(); if (!mem) return NULL; /* Create a new ExifEntry using our allocator */ entry = exif_entry_new_mem (mem); if (entry) { /* Allocate memory to use for holding the tag data */ size = len * exif_format_get_size(exifFormat); buf = exif_mem_alloc(mem, size); if (buf) { /* Fill in the entry */ entry->data = (unsigned char*)buf; entry->size = size; entry->tag = tag; entry->components = len; entry->format = exifFormat; /* Attach the ExifEntry to an IFD */ exif_content_add_entry (content, entry); } exif_entry_unref(entry); } exif_mem_unref(mem); return entry; }
static bool createEntry(ExifData* exifData, ExifIfd ifd, int tag, const float (&values)[N], float denominator = 1000.0) { removeExistingEntry(exifData, ifd, tag); ExifByteOrder byteOrder = exif_data_get_byte_order(exifData); ExifEntry* entry = allocateEntry(tag, EXIF_FORMAT_RATIONAL, N); exif_content_add_entry(exifData->ifd[ifd], entry); unsigned int rationalSize = exif_format_get_size(EXIF_FORMAT_RATIONAL); for (size_t i = 0; i < N; ++i) { ExifRational rational = { static_cast<uint32_t>(values[i] * denominator), static_cast<uint32_t>(denominator) }; exif_set_rational(&entry->data[i * rationalSize], byteOrder, rational); } // Unref entry after changing owner to the ExifData struct exif_entry_unref(entry); return true; }
void write_content_binary(unsigned char *data, ExifContent *content, ExifByteOrder order, unsigned int offset) { unsigned int i = 0; unsigned int next_data = 0; ExifEntry *entry = NULL; unsigned int s = 0; unsigned char *d = data; exif_set_short(d, order, content->count); d += 2; next_data = 2 + offset + content->count * 12;// + 2; for (i = 0; i < content->count; i++) { entry = content->entries[i]; if (entry != NULL) { exif_set_short(d + 0x00, order, entry->tag); exif_set_short(d + 0x02, order, entry->format); exif_set_long (d + 0x04, order, entry->components); s = exif_format_get_size(entry->format) * entry->components; if (s > 4) { exif_set_long (d + 0x08, order, next_data + 2*0);// начало смещения данных после APP2 (2 байта) memcpy(data + next_data - offset, entry->data, s); next_data += s; } else { if (entry->tag == SGEO_TAG_VERSIONID) write_sgeo_version(d + 0x08, order); else memcpy(d + 0x08, entry->data, s); } d = d + 0x0c; } } }
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 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); } }
/** * @brief save the MnoteData from ne to buf * * @param ne extract the data from this structure * @param *buf write the mnoteData to this buffer (buffer will be allocated) * @param buf_size the final size of the buffer */ static void exif_mnote_data_pentax_save (ExifMnoteData *ne, unsigned char **buf, unsigned int *buf_size) { ExifMnoteDataPentax *n = (ExifMnoteDataPentax *) ne; size_t i, base = 0, /* internal MakerNote tag number offset */ o2 = 4 + 2; /* offset to first tag entry, past header */ size_t datao = n->offset; /* this MakerNote style uses offsets based on main IFD, not makernote IFD */ if (!n || !buf || !buf_size) return; /* * Allocate enough memory for header, the number of entries, entries, * and next IFD pointer */ *buf_size = o2 + 2 + n->count * 12 + 4; switch (n->version) { case casioV2: base = MNOTE_PENTAX2_TAG_BASE; *buf = exif_mem_alloc (ne->mem, *buf_size); if (!*buf) { EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteDataPentax", *buf_size); return; } /* Write the magic header */ strcpy ((char *)*buf, "QVC"); exif_set_short (*buf + 4, n->order, (ExifShort) 0); break; case pentaxV3: base = MNOTE_PENTAX2_TAG_BASE; *buf = exif_mem_alloc (ne->mem, *buf_size); if (!*buf) { EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteDataPentax", *buf_size); return; } /* Write the magic header */ strcpy ((char *)*buf, "AOC"); exif_set_short (*buf + 4, n->order, (ExifShort) ( (n->order == EXIF_BYTE_ORDER_INTEL) ? ('I' << 8) | 'I' : ('M' << 8) | 'M')); break; case pentaxV2: base = MNOTE_PENTAX2_TAG_BASE; *buf = exif_mem_alloc (ne->mem, *buf_size); if (!*buf) { EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteDataPentax", *buf_size); return; } /* Write the magic header */ strcpy ((char *)*buf, "AOC"); exif_set_short (*buf + 4, n->order, (ExifShort) 0); break; case pentaxV1: /* It looks like this format doesn't have a magic header as * such, just has a fixed number of entries equal to 0x001b */ *buf_size -= 6; o2 -= 6; *buf = exif_mem_alloc (ne->mem, *buf_size); if (!*buf) { EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteDataPentax", *buf_size); return; } break; default: /* internal error */ return; } /* Write the number of entries. */ exif_set_short (*buf + o2, n->order, (ExifShort) n->count); o2 += 2; /* Save each entry */ for (i = 0; i < n->count; i++) { size_t doff; /* offset to current data portion of tag */ size_t s; unsigned char *t; size_t o = o2 + i * 12; /* current offset into output buffer */ exif_set_short (*buf + o + 0, n->order, (ExifShort) (n->entries[i].tag - base)); exif_set_short (*buf + o + 2, n->order, (ExifShort) n->entries[i].format); exif_set_long (*buf + o + 4, n->order, n->entries[i].components); o += 8; s = exif_format_get_size (n->entries[i].format) * n->entries[i].components; if (s > 65536) { /* Corrupt data: EXIF data size is limited to the * maximum size of a JPEG segment (64 kb). */ continue; } if (s > 4) { size_t ts = *buf_size + s; doff = *buf_size; t = exif_mem_realloc (ne->mem, *buf, sizeof (char) * ts); if (!t) { EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteDataPentax", ts); return; } *buf = t; *buf_size = ts; exif_set_long (*buf + o, n->order, datao + doff); } else doff = o; /* Write the data. */ if (n->entries[i].data) { memcpy (*buf + doff, n->entries[i].data, s); } else { /* Most certainly damaged input file */ memset (*buf + doff, 0, s); } } /* Sanity check the buffer size */ if (*buf_size < (o2 + n->count * 12 + 4)) { exif_log (ne->log, EXIF_LOG_CODE_CORRUPT_DATA, "ExifMnoteDataPentax", "Buffer overflow"); } /* Reset next IFD pointer */ exif_set_long (*buf + o2 + n->count * 12, n->order, 0); }
static void exif_mnote_data_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 generateEncryptData(unsigned char **data, unsigned int *size, SGeoTagsEncrypt *collection, ExifByteOrder order) { unsigned int i = 0; unsigned int s = 0; unsigned int next_data = 0; ExifEntry *entry = NULL; ExifContent *content = NULL; unsigned char *d = NULL, n; ExifData *exif = NULL; int size_sgeo_bytes = 0; ExifIfd ifd = EXIF_IFD_ENCRYPT; srand((unsigned int)time(NULL)); *data = NULL; *size = 0; exif = exif_data_new_mem (exif_mem_new_default()); exif->priv->order = order; content = exif->ifd[EXIF_IFD_ENCRYPT]; // VersionID exif_mem_write(content, SGEO_TAG_ENCRYPT_VERSION, EXIF_FORMAT_BYTE, collection->VersionID, sizeof(collection->VersionID), NULL); // FileName write_unicode_string_to_exif(content, SGEO_TAG_ENCRYPT_FILE_NAME, collection->FileName); // FileSize exif_long_write(content, SGEO_TAG_ENCRYPT_FILE_SIZE, &collection->FileSize, order, NULL); // DateTimeOriginal exif_mem_write(content, EXIF_TAG_DATE_TIME_ORIGINAL, EXIF_FORMAT_ASCII, collection->DateTimeOriginal, sizeof(collection->DateTimeOriginal), &collection->ExistDateTimeOriginal); // Longitude exif_srational_write(content, SGEO_TAG_LONGITUDE, &collection->Longitude, order, &collection->ExistLongitude); // LongAccuracy exif_rational_write(content, SGEO_TAG_LONGACCURACY, &collection->LongitudeAccuracy, order, &collection->ExistLongitudeAccuracy); // Latitude exif_srational_write(content, SGEO_TAG_LATITUDE, &collection->Latitude, order, &collection->ExistLatitude); // LatAccuracy exif_rational_write(content, SGEO_TAG_LATACCURACY, &collection->LatitudeAccuracy, order, &collection->ExistLatitudeAccuracy); // Altitude exif_srational_write(content, SGEO_TAG_ALTITUDE, &collection->Altitude, order, &collection->ExistAltitude); // AltAccuracy exif_rational_write(content, SGEO_TAG_ALTACCURACY, &collection->AltitudeAccuracy, order, &collection->ExistAltitudeAccuracy); // Azimuth exif_srational_write(content, SGEO_TAG_AZIMUTH, &collection->Azimuth, order, &collection->ExistAzimuth); // AzimuthAccuracy exif_rational_write(content, SGEO_TAG_AZIMUTHACCURACY, &collection->AzimuthAccuracy, order, &collection->ExistAzimuthAccuracy); // Pitch exif_srational_write(content, SGEO_TAG_PITCH, &collection->Pitch, order, &collection->ExistPitch); // PitchAccuracy exif_rational_write(content, SGEO_TAG_PITCHACCURACY, &collection->PitchAccuracy, order, &collection->ExistPitchAccuracy); // Roll exif_srational_write(content, SGEO_TAG_ROLL, &collection->Roll, order, &collection->ExistRoll); // RollAccuracy exif_rational_write(content, SGEO_TAG_ROLLACCURACY, &collection->RollAccuracy, order, &collection->ExistRollAccuracy); // HViewAngle exif_rational_write(content, SGEO_TAG_HVIEWANGLE, &collection->HViewAngle, order, &collection->ExistHViewAngle); // HViewAngleAccuracy exif_rational_write(content, SGEO_TAG_HVIEWANGLEACCURACY, &collection->HViewAngleAccuracy, order, &collection->ExistHViewAngleAccuracy); // VViewAngle exif_rational_write(content, SGEO_TAG_VVIEWANGLE, &collection->VViewAngle, order, &collection->ExistVViewAngle); // VViewAngleAccuracy exif_rational_write(content, SGEO_TAG_VVIEWANGLEACCURACY, &collection->VViewAngleAccuracy, order, &collection->ExistVViewAngleAccuracy); // SatCount exif_mem_write(content, SGEO_TAG_SATCOUNT, EXIF_FORMAT_BYTE, &collection->SatCount, sizeof(collection->SatCount), NULL); // global time exif_mem_write(content, SGEO_TAG_GLOBAL_TIME, EXIF_FORMAT_BYTE, collection->GlobalTime, sizeof(collection->GlobalTime), NULL); // GNSSType exif_long_write(content, SGEO_TAG_GNSS_TYPE, &collection->GNSSType, order, NULL); // DeviceName write_unicode_string_to_exif(content, SGEO_TAG_DEVICE_NAME, collection->DeviceName); // DeviceIMEI write_unicode_string_to_exif(content, SGEO_TAG_DEVICE_IMEI, collection->DeviceIMEI); // DeviceNumber write_unicode_string_to_exif(content, SGEO_TAG_DEVICE_NUMBER, collection->DeviceNumber); // DeviceOS write_unicode_string_to_exif(content, SGEO_TAG_DEVICE_OS, collection->DeviceOS); // DeviceOSVersion write_unicode_string_to_exif(content, SGEO_TAG_DEVICE_OS_VERSION, collection->DeviceOSVersion); // DeviceVersion write_unicode_string_to_exif(content, SGEO_TAG_DEVICE_VERSION, collection->DeviceVersion); // DeviceDateTimeMeasure exif_mem_write(content, SGEO_TAG_DEVICE_DATE_TIME_MEASURE, EXIF_FORMAT_BYTE, collection->DeviceDateTimeMeasure, sizeof(collection->DeviceDateTimeMeasure), NULL); // ProgramVersion write_unicode_string_to_exif(content, SGEO_TAG_PROGRAM_VERSION, collection->ProgramVersion); // ProgramName write_unicode_string_to_exif(content, SGEO_TAG_PROGRAM_NAME, collection->ProgramName); // ProgramUserName write_unicode_string_to_exif(content, SGEO_TAG_PROGRAM_USER_NAME, collection->ProgramUserName); size_sgeo_bytes = 2 + content->count * 12; for (i = 0; i < content->count; i++) { entry = content->entries[i]; if (entry != NULL) { s = exif_format_get_size(entry->format) * entry->components; if (s > 4) size_sgeo_bytes += s; // s += 12;// +tag size //else // s = 12; } } if (size_sgeo_bytes > 0) { *data = (unsigned char* )calloc((size_t)size_sgeo_bytes, 1); if (*data != NULL) { write_content_binary(*data, content, order, 0); s = 0; if (size_sgeo_bytes < 1024) s = 1024 - size_sgeo_bytes; s += 2390;// white noice *size = size_sgeo_bytes + s; *data = (unsigned char* )realloc(*data, (size_t)(size_sgeo_bytes + s)); n = rand() % 255; for (i = 0; i < s; i++) { n = GaloisLfsr(n); (*data)[size_sgeo_bytes + i] = n; } } } exif_data_unref(exif); }
static void exif_mnote_data_canon_save (ExifMnoteData *ne, unsigned char **buf, unsigned int *buf_size) { ExifMnoteDataCanon *n = (ExifMnoteDataCanon *) ne; size_t i, o, s, doff; unsigned char *t; size_t ts; if (!n || !buf || !buf_size) return; /* * Allocate enough memory for all entries and the number * of entries. */ *buf_size = 2 + n->count * 12 + 4; *buf = exif_mem_alloc (ne->mem, sizeof (char) * *buf_size); if (!*buf) { EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteCanon", *buf_size); return; } /* Save the number of entries */ exif_set_short (*buf, n->order, (ExifShort) n->count); /* Save each entry */ for (i = 0; i < n->count; i++) { o = 2 + i * 12; exif_set_short (*buf + o + 0, n->order, (ExifShort) n->entries[i].tag); exif_set_short (*buf + o + 2, n->order, (ExifShort) n->entries[i].format); exif_set_long (*buf + o + 4, n->order, n->entries[i].components); o += 8; s = exif_format_get_size (n->entries[i].format) * n->entries[i].components; if (s > 65536) { /* Corrupt data: EXIF data size is limited to the * maximum size of a JPEG segment (64 kb). */ continue; } if (s > 4) { ts = *buf_size + s; /* Ensure even offsets. Set padding bytes to 0. */ if (s & 1) ts += 1; t = exif_mem_realloc (ne->mem, *buf, sizeof (char) * ts); if (!t) { EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteCanon", ts); return; } *buf = t; *buf_size = ts; doff = *buf_size - s; if (s & 1) { doff--; *(*buf + *buf_size - 1) = '\0'; } exif_set_long (*buf + o, n->order, n->offset + doff); } else doff = o; /* * Write the data. Fill unneeded bytes with 0. Do not * crash if data is NULL. */ if (!n->entries[i].data) memset (*buf + doff, 0, s); else memcpy (*buf + doff, n->entries[i].data, s); if (s < 4) memset (*buf + doff + s, 0, (4 - s)); } }
static void exif_mnote_data_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_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; }
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); }
LocImageContainer ImageProcessor::process (QString filename) { QImage image (m_data); if (!image.isNull()) { image = image.scaled(720, 500, Qt::KeepAspectRatioByExpanding); } LocImageContainer locImageContainer(image); locImageContainer.setAltitude(3000.00); //get exif data ExifData *ed = exif_data_new_from_file (filename.toLocal8Bit().constData()); if (!ed) { locImageContainer.setLocationAvailable(false); locImageContainer.setExifDataAvailable(false); return locImageContainer; } locImageContainer.setExifDataAvailable(true); //save temp char value[256]={0,}; // Retrieve make QString make; ExifEntry *ee = exif_content_get_entry(ed->ifd[EXIF_IFD_0], EXIF_TAG_MAKE); if (!ee) { make = ""; } else { exif_entry_get_value(ee, value, sizeof(value)); locImageContainer.setMake (QString(value)); } // Retrieve model ee = exif_content_get_entry(ed->ifd[EXIF_IFD_0], EXIF_TAG_MODEL); if (!ee) { locImageContainer.setCameraModel (""); } else { exif_entry_get_value(ee, value, sizeof(value)); locImageContainer.setCameraModel ("Taken with the "+QString(value)); } // Retrieve time ee = exif_content_get_entry(ed->ifd[EXIF_IFD_EXIF], EXIF_TAG_DATE_TIME_ORIGINAL); if (!ee) { locImageContainer.setDateTaken (""); } else { exif_entry_get_value(ee, value, sizeof(value)); QString dateTime(value); QDateTime dateTaken = QDateTime::fromString (dateTime, "yyyy:MM:dd HH:mm:ss"); locImageContainer.setDateTaken (dateTaken.toString("'on 'dddd d, MMMM yyyy 'at' HH:mm")); } // Retrieve LATITUDE ee = exif_content_get_entry (ed->ifd[EXIF_IFD_GPS], (ExifTag)EXIF_TAG_GPS_LATITUDE); if (!ee) { locImageContainer.setLocationAvailable(false); locImageContainer.setLatitude(-9999.99); } else { if ( ( ee && ee->components == 3 && ee->format == EXIF_FORMAT_RATIONAL ) ) { double lat = Rational2Double ( ee->data, exif_format_get_size(ee->format), exif_data_get_byte_order(ed) ); ee = exif_content_get_entry (ed->ifd[EXIF_IFD_GPS], (ExifTag)EXIF_TAG_GPS_LATITUDE_REF); if ( ee ) { exif_entry_get_value ( ee, value, 128 ); if ( value[0] == 'S' ) lat = -lat; } locImageContainer.setLocationAvailable(true); locImageContainer.setLatitude (lat); } } ee = exif_content_get_entry (ed->ifd[EXIF_IFD_GPS], (ExifTag)EXIF_TAG_GPS_LONGITUDE); if (!ee) { locImageContainer.setLocationAvailable(false); locImageContainer.setLongitude(-9999.99); } else { if ( ( ee && ee->components == 3 && ee->format == EXIF_FORMAT_RATIONAL ) ) { double lon = Rational2Double ( ee->data, exif_format_get_size(ee->format), exif_data_get_byte_order(ed) ); ee = exif_content_get_entry (ed->ifd[EXIF_IFD_GPS], (ExifTag)EXIF_TAG_GPS_LONGITUDE_REF); if ( ee ) { exif_entry_get_value ( ee, value, 128 ); if ( value[0] == 'W' ) lon = -lon; } locImageContainer.setLocationAvailable(true); locImageContainer.setLongitude (lon); } } exif_data_free(ed); return locImageContainer; }
static const char * eog_exif_entry_get_value (ExifEntry *e, char *buf, guint n_buf) { ExifByteOrder bo; /* For now we only want to reformat some GPS values */ if (G_LIKELY (exif_entry_get_ifd (e) != EXIF_IFD_GPS)) return exif_entry_get_value (e, buf, n_buf); bo = exif_data_get_byte_order (e->parent->parent); /* Cast to number to avoid warnings about values not in enumeration */ switch ((guint16) e->tag) { case EXIF_TAG_GPS_LATITUDE: case EXIF_TAG_GPS_LONGITUDE: { gsize rational_size; ExifRational r; gfloat h = 0., m = 0.; rational_size = exif_format_get_size (EXIF_FORMAT_RATIONAL); if (G_UNLIKELY (e->components != 3 || e->format != EXIF_FORMAT_RATIONAL)) return exif_entry_get_value (e, buf, n_buf); r = exif_get_rational (e->data, bo); if (r.denominator != 0) h = (gfloat)r.numerator / r.denominator; r = exif_get_rational (e->data + rational_size, bo); if (r.denominator != 0) m = (gfloat)r.numerator / (gfloat)r.denominator; r = exif_get_rational (e->data + (2 * rational_size), bo); if (r.numerator != 0 && r.denominator != 0) { gfloat s; s = (gfloat)r.numerator / (gfloat)r.denominator; g_snprintf (buf, n_buf, "%.0f° %.0f' %.2f\"", h, m, s); } else { g_snprintf (buf, n_buf, "%.0f° %.2f'", h, m); } break; } case EXIF_TAG_GPS_LATITUDE_REF: case EXIF_TAG_GPS_LONGITUDE_REF: { if (G_UNLIKELY (e->components != 2 || e->format != EXIF_FORMAT_ASCII)) return exif_entry_get_value (e, buf, n_buf); switch (e->data[0]) { case 'N': g_snprintf (buf, n_buf, "%s", _("North")); break; case 'E': g_snprintf (buf, n_buf, "%s", _("East")); break; case 'W': g_snprintf (buf, n_buf, "%s", _("West")); break; case 'S': g_snprintf (buf, n_buf, "%s", _("South")); break; default: return exif_entry_get_value (e, buf, n_buf); break; } break; } default: return exif_entry_get_value (e, buf, n_buf); break; } return buf; }
static void metadatamux_exif_for_each_tag_in_list (const GstTagList * list, const gchar * tag, gpointer user_data) { ExifData *ed = (ExifData *) user_data; ExifTag exif_tag; GType type = G_TYPE_INVALID; ExifEntry *entry = NULL; ExifIfd ifd = EXIF_IFD_COUNT; const ExifByteOrder byte_order = exif_data_get_byte_order (ed); exif_tag = metadatamux_exif_get_exif_from_tag (tag, &type, &ifd); if (!exif_tag) goto done; entry = exif_data_get_entry (ed, exif_tag); if (entry) exif_entry_ref (entry); else { entry = exif_entry_new (); exif_content_add_entry (ed->ifd[ifd], entry); exif_entry_initialize (entry, exif_tag); } if (entry->data == NULL) { if (entry->tag == EXIF_TAG_GPS_ALTITUDE) { entry->format = EXIF_FORMAT_RATIONAL; entry->components = 1; entry->size = exif_format_get_size (entry->format) * entry->components; entry->data = g_malloc (entry->size); } else if (entry->tag == EXIF_TAG_GPS_LATITUDE || entry->tag == EXIF_TAG_GPS_LONGITUDE) { entry->format = EXIF_FORMAT_RATIONAL; entry->components = 3; entry->size = exif_format_get_size (entry->format) * entry->components; entry->data = g_malloc (entry->size); } } if (type == GST_TYPE_FRACTION) { const GValue *gvalue = gst_tag_list_get_value_index (list, tag, 0); gint numerator = gst_value_get_fraction_numerator (gvalue); gint denominator = gst_value_get_fraction_denominator (gvalue); switch (entry->format) { case EXIF_FORMAT_SRATIONAL: { ExifSRational sr = { numerator, denominator }; exif_set_srational (entry->data, byte_order, sr); } break; case EXIF_FORMAT_RATIONAL: { ExifRational r; if (entry->tag == EXIF_TAG_X_RESOLUTION || entry->tag == EXIF_TAG_Y_RESOLUTION) { ExifEntry *unit_entry = NULL; unit_entry = exif_data_get_entry (ed, EXIF_TAG_RESOLUTION_UNIT); if (unit_entry) { ExifShort vsh = exif_get_short (unit_entry->data, byte_order); if (vsh != 2) /* inches */ exif_set_short (unit_entry->data, byte_order, 2); } } r.numerator = numerator; r.denominator = denominator; if (numerator < 0) r.numerator = -numerator; if (denominator < 0) r.denominator = -denominator; exif_set_rational (entry->data, byte_order, r); } break; default: break; } } else if (type == GST_TYPE_BUFFER) { const GValue *val = NULL; GstBuffer *buf; val = gst_tag_list_get_value_index (list, tag, 0); buf = gst_value_get_buffer (val); entry->components = GST_BUFFER_SIZE (buf); entry->size = GST_BUFFER_SIZE (buf); entry->data = g_malloc (entry->size); memcpy (entry->data, GST_BUFFER_DATA (buf), entry->size); } else { switch (type) { case G_TYPE_STRING: { gchar *value = NULL; if (gst_tag_list_get_string (list, tag, &value)) { if (entry->tag == EXIF_TAG_DATE_TIME_DIGITIZED || entry->tag == EXIF_TAG_DATE_TIME || entry->tag == EXIF_TAG_DATE_TIME_ORIGINAL) { GString *datetime = g_string_new_len (value, 20); /* enough memory to hold "YYYY:MM:DD HH:MM:SS" */ if (metadatamux_exif_convert_from_datetime (datetime)) { } else { GST_ERROR ("Unexpected date & time format for %s", tag); } g_free (value); value = datetime->str; g_string_free (datetime, FALSE); } else if (value) { entry->components = strlen (value) + 1; entry->size = exif_format_get_size (entry->format) * entry->components; entry->data = (guint8 *) value; value = NULL; } } } break; case G_TYPE_UINT: case G_TYPE_INT: { gint value; ExifShort v_short; if (G_TYPE_UINT == type) { gst_tag_list_get_uint (list, tag, (guint *) & value); } else { gst_tag_list_get_int (list, tag, &value); } switch (entry->format) { case EXIF_FORMAT_SHORT: if (entry->tag == EXIF_TAG_CONTRAST || entry->tag == EXIF_TAG_SATURATION) { if (value < -33) value = 1; /* low */ else if (value < 34) value = 0; /* normal */ else value = 2; /* high */ } v_short = value; exif_set_short (entry->data, byte_order, v_short); break; case EXIF_FORMAT_LONG: exif_set_long (entry->data, byte_order, value); break; default: break; } } break; case G_TYPE_DOUBLE: { gdouble value; gst_tag_list_get_double (list, tag, &value); if (entry->tag == EXIF_TAG_GPS_LATITUDE || entry->tag == EXIF_TAG_GPS_LONGITUDE) { ExifRational *rt = (ExifRational *) entry->data; gdouble v = fabs (value); ExifEntry *ref_entry = NULL; char ref; const ExifTag ref_tag = entry->tag == EXIF_TAG_GPS_LATITUDE ? EXIF_TAG_GPS_LATITUDE_REF : EXIF_TAG_GPS_LONGITUDE_REF; /* DDD - degrees */ rt->numerator = (gulong) v; rt->denominator = 1; GST_DEBUG ("deg: %lf : %lu / %lu", v, (gulong) rt->numerator, (gulong) rt->denominator); v -= rt->numerator; rt++; /* MM - minutes */ rt->numerator = (gulong) (v * 60.0); rt->denominator = 1; GST_DEBUG ("min: %lf : %lu / %lu", v, (gulong) rt->numerator, (gulong) rt->denominator); v -= ((gdouble) rt->numerator / 60.0); rt++; /* SS - seconds */ rt->numerator = (gulong) (0.5 + v * 3600.0); rt->denominator = 1; GST_DEBUG ("sec: %lf : %lu / %lu", v, (gulong) rt->numerator, (gulong) rt->denominator); if (entry->tag == EXIF_TAG_GPS_LONGITUDE) { GST_DEBUG ("longitude : %lf", value); ref = (value < 0.0) ? 'W' : 'E'; } else { GST_DEBUG ("latitude : %lf", value); ref = (value < 0.0) ? 'S' : 'N'; } ref_entry = exif_data_get_entry (ed, ref_tag); if (ref_entry) { exif_entry_ref (ref_entry); } else { ref_entry = exif_entry_new (); exif_content_add_entry (ed->ifd[EXIF_IFD_GPS], ref_entry); exif_entry_initialize (ref_entry, ref_tag); } if (ref_entry->data == NULL) { ref_entry->format = EXIF_FORMAT_ASCII; ref_entry->components = 2; ref_entry->size = 2; ref_entry->data = g_malloc (2); } ref_entry->data[0] = ref; ref_entry->data[1] = 0; exif_entry_unref (ref_entry); } else if (entry->tag == EXIF_TAG_GPS_ALTITUDE) { ExifEntry *ref_entry = NULL; ExifRational *rt = (ExifRational *) entry->data; rt->numerator = (gulong) fabs (10.0 * value); rt->denominator = 10; GST_DEBUG ("altitude : %lf", value); ref_entry = exif_data_get_entry (ed, EXIF_TAG_GPS_ALTITUDE_REF); if (ref_entry) { exif_entry_ref (ref_entry); } else { ref_entry = exif_entry_new (); exif_content_add_entry (ed->ifd[EXIF_IFD_GPS], ref_entry); exif_entry_initialize (ref_entry, EXIF_TAG_GPS_ALTITUDE_REF); } if (ref_entry->data == NULL) { ref_entry->format = EXIF_FORMAT_BYTE; ref_entry->components = 1; ref_entry->size = 1; ref_entry->data = g_malloc (1); } if (value > 0.0) { ref_entry->data[0] = 0; } else { ref_entry->data[0] = 1; } exif_entry_unref (ref_entry); } } break; default: break; } } done: if (entry) exif_entry_unref (entry); }
/** * a_geotag_create_waypoint_from_file: * @filename: The image file to process * @vcmode: The current location mode to use in the positioning of Waypoint * @name: Returns a name for the Waypoint (can be NULL) * * Returns: An allocated Waypoint or NULL if Waypoint could not be generated (e.g. no EXIF info) * */ VikWaypoint* a_geotag_create_waypoint_from_file ( const gchar *filename, VikCoordMode vcmode, gchar **name ) { // Default return values (for failures) *name = NULL; VikWaypoint *wp = NULL; // TODO use log? //ExifLog *log = NULL; // open image with libexif ExifData *ed = exif_data_new_from_file ( filename ); // Detect EXIF load failure if ( !ed ) // return with no Waypoint return wp; struct LatLon ll; gchar str[128]; ExifEntry *ee; ee = exif_content_get_entry (ed->ifd[EXIF_IFD_GPS], EXIF_TAG_GPS_VERSION_ID); // Confirm this has a GPS Id - normally "2.0.0.0" or "2.2.0.0" if ( ! ( ee && ee->components == 4 ) ) goto MyReturn; // Could test for these versions explicitly but may have byte order issues... //if ( ! ( ee->data[0] == 2 && ee->data[2] == 0 && ee->data[3] == 0 ) ) // goto MyReturn; ee = exif_content_get_entry (ed->ifd[EXIF_IFD_GPS], EXIF_TAG_GPS_MAP_DATUM); if ( ! ( ee && ee->components > 0 && ee->format == EXIF_FORMAT_ASCII ) ) goto MyReturn; // If map datum specified - only deal in WGS-84 - the defacto standard if ( ee && ee->components > 0 ) { exif_entry_get_value ( ee, str, 128 ); if ( strncmp (str, "WGS-84", 6) ) goto MyReturn; } // // Lat & Long is necessary to form a waypoint. // ee = exif_content_get_entry (ed->ifd[EXIF_IFD_GPS], EXIF_TAG_GPS_LATITUDE); if ( ! ( ee && ee->components == 3 && ee->format == EXIF_FORMAT_RATIONAL ) ) goto MyReturn; ll.lat = Rational2Double ( ee->data, exif_format_get_size(ee->format), exif_data_get_byte_order(ed) ); ee = exif_content_get_entry (ed->ifd[EXIF_IFD_GPS], EXIF_TAG_GPS_LATITUDE_REF); if ( ee ) { exif_entry_get_value ( ee, str, 128 ); if ( str[0] == 'S' ) ll.lat = -ll.lat; } ee = exif_content_get_entry (ed->ifd[EXIF_IFD_GPS], EXIF_TAG_GPS_LONGITUDE); if ( ! ( ee && ee->components == 3 && ee->format == EXIF_FORMAT_RATIONAL ) ) goto MyReturn; ll.lon = Rational2Double ( ee->data, exif_format_get_size(ee->format), exif_data_get_byte_order(ed) ); ee = exif_content_get_entry (ed->ifd[EXIF_IFD_GPS], EXIF_TAG_GPS_LONGITUDE_REF); if ( ee ) { exif_entry_get_value ( ee, str, 128 ); if ( str[0] == 'W' ) ll.lon = -ll.lon; } // // Not worried if none of the other fields exist, as can default the values to something // gdouble alt = VIK_DEFAULT_ALTITUDE; ee = exif_content_get_entry (ed->ifd[EXIF_IFD_GPS], EXIF_TAG_GPS_ALTITUDE); if ( ee && ee->components == 1 && ee->format == EXIF_FORMAT_RATIONAL ) { alt = Rational2Double ( ee->data, 0, exif_data_get_byte_order(ed) ); ee = exif_content_get_entry (ed->ifd[EXIF_IFD_GPS], EXIF_TAG_GPS_ALTITUDE_REF); if ( ee && ee->components == 1 && ee->format == EXIF_FORMAT_BYTE && ee->data[0] == 1 ) alt = -alt; } // Name ee = exif_content_get_entry (ed->ifd[EXIF_IFD_0], EXIF_TAG_XP_TITLE); if ( ee ) { exif_entry_get_value ( ee, str, 128 ); *name = g_strdup ( str ); } // // Now create Waypoint with acquired information // wp = vik_waypoint_new(); wp->visible = TRUE; // Set info from exif values // Location vik_coord_load_from_latlon ( &(wp->coord), vcmode, &ll ); // Altitude wp->altitude = alt; wp->comment = geotag_get_exif_comment ( ed ); vik_waypoint_set_image ( wp, filename ); MyReturn: // Finished with EXIF exif_data_free ( ed ); return wp; }
static int iExifWriteTag(ExifData* exif, int index, const char* name, int data_type, int attrib_count, const void* attrib_data) { int c; ExifTag tag = exif_tag_from_name(name); if (tag == 0) { if (!imStrEqual(name, "GPSVersionID")) // EXIF_TAG_GPS_VERSION_ID==0 return 1; } ExifEntry *entry = exif_entry_new(); ExifByteOrder byte_order = exif_data_get_byte_order(exif); ExifContent *content; if (name[0] == 'G' && name[1] == 'P' && name[2] == 'S') { content = exif->ifd[EXIF_IFD_GPS]; // GPS tags if (!iExifGetGPSTagInfo((int)tag, &(entry->format), &(entry->components))) { exif_entry_free(entry); return 1; } } else { if (tag > EXIF_TAG_COPYRIGHT) content = exif->ifd[EXIF_IFD_EXIF]; // EXIF tags else content = exif->ifd[EXIF_IFD_0]; // TIFF tags if (!iExifGetTagInfo(tag, &(entry->format), &(entry->components))) { exif_entry_free(entry); return 1; } } int format_size = exif_format_get_size(entry->format); if (entry->components == 0) entry->components = attrib_count; entry->tag = tag; entry->size = format_size * entry->components; entry->data = (imbyte*)malloc(entry->size); if (tag == EXIF_TAG_RESOLUTION_UNIT) { int res_unit; if (imStrEqual((char*)attrib_data, "DPI")) res_unit = 2; else res_unit = 3; exif_content_add_entry(content, entry); exif_set_short(entry->data, byte_order, (imushort)res_unit); return 1; } /* test if tag type is the same as the attribute type */ if (iExifGetDataType(entry->format) != data_type) { exif_entry_free(entry); return 1; } exif_content_add_entry(content, entry); switch (entry->format) { case EXIF_FORMAT_UNDEFINED: case EXIF_FORMAT_ASCII: case EXIF_FORMAT_SBYTE: case EXIF_FORMAT_BYTE: { imbyte *bvalue = (imbyte*)attrib_data; for (c = 0; c < (int)entry->components; c++) entry->data[c] = bvalue[c]; } break; case EXIF_FORMAT_SHORT: { imushort *usvalue = (imushort*)attrib_data; for (c = 0; c < (int)entry->components; c++) exif_set_short(entry->data + format_size * c, byte_order, usvalue[c]); } break; case EXIF_FORMAT_SSHORT: { short *svalue = (short*)attrib_data; for (c = 0; c < (int)entry->components; c++) exif_set_sshort(entry->data + format_size * c, byte_order, svalue[c]); } break; case EXIF_FORMAT_LONG: { int *ivalue = (int*)attrib_data; for (c = 0; c < (int)entry->components; c++) exif_set_long(entry->data + format_size * c, byte_order, (unsigned int)ivalue[c]); } break; case EXIF_FORMAT_SLONG: { int *ivalue = (int*)attrib_data; for (c = 0; c < (int)entry->components; c++) exif_set_slong(entry->data + format_size * c, byte_order, (int)ivalue[c]); } break; case EXIF_FORMAT_RATIONAL: { ExifRational v_rat; int num, den; float *fvalue = (float*)attrib_data; for (c = 0; c < (int)entry->components; c++) { iGetRational(fvalue[c], &num, &den, 1); v_rat.numerator = num; v_rat.denominator = den; exif_set_rational(entry->data + format_size * c, byte_order, v_rat); } } break; case EXIF_FORMAT_SRATIONAL: { ExifSRational v_srat; int num, den; float *fvalue = (float*)attrib_data; for (c = 0; c < (int)entry->components; c++) { iGetRational(fvalue[c], &num, &den, 1); v_srat.numerator = num; v_srat.denominator = den; exif_set_srational(entry->data + format_size * c, byte_order, v_srat); } } break; case EXIF_FORMAT_FLOAT: // defined but unsupported in libEXIF case EXIF_FORMAT_DOUBLE: // defined but unsupported in libEXIF break; } /* no need to release the entry here, it will be handled internally because we added the entry to the ExifContent */ (void)index; return 1; }
/** Heavily based on convert_arg_to_entry from exif command line tool. * But without ExifLog, exitting, use of g_* io functions * and can take a gdouble value instead of a string */ static void convert_to_entry (const char *set_value, gdouble gdvalue, ExifEntry *e, ExifByteOrder o) { unsigned int i, numcomponents; char *value_p = NULL; char *buf = NULL; /* * ASCII strings are handled separately, * since they don't require any conversion. */ if (e->format == EXIF_FORMAT_ASCII || e->tag == EXIF_TAG_USER_COMMENT) { if (e->data) g_free (e->data); e->components = strlen (set_value) + 1; if (e->tag == EXIF_TAG_USER_COMMENT) e->components += 8 - 1; e->size = sizeof (char) * e->components; e->data = g_malloc (e->size); if (!e->data) { g_warning (_("Not enough memory.")); return; } if (e->tag == EXIF_TAG_USER_COMMENT) { /* assume ASCII charset */ /* TODO: get this from the current locale */ memcpy ((char *) e->data, "ASCII\0\0\0", 8); memcpy ((char *) e->data + 8, set_value, strlen (set_value)); } else strcpy ((char *) e->data, set_value); return; } /* * Make sure we can handle this entry */ if ((e->components == 0) && *set_value) { g_warning (_("Setting a value for this tag is unsupported!")); return; } gboolean use_string = (set_value != NULL); if ( use_string ) { /* Copy the string so we can modify it */ buf = g_strdup (set_value); if (!buf) return; value_p = strtok (buf, " "); } numcomponents = e->components; for (i = 0; i < numcomponents; ++i) { unsigned char s; if ( use_string ) { if (!value_p) { g_warning (_("Too few components specified (need %d, found %d)\n"), numcomponents, i); return; } if (!isdigit(*value_p) && (*value_p != '+') && (*value_p != '-')) { g_warning (_("Numeric value expected\n")); return; } } s = exif_format_get_size (e->format); switch (e->format) { case EXIF_FORMAT_ASCII: g_warning (_("This shouldn't happen!")); return; break; case EXIF_FORMAT_SHORT: exif_set_short (e->data + (s * i), o, atoi (value_p)); break; case EXIF_FORMAT_SSHORT: exif_set_sshort (e->data + (s * i), o, atoi (value_p)); break; case EXIF_FORMAT_RATIONAL: { ExifRational er; double val = 0.0 ; if ( use_string && value_p ) val = fabs (atol (value_p)); else val = fabs (gdvalue); if ( i == 0 ) { // One (or first) part rational // Sneak peek into tag as location tags need rounding down to give just the degrees part if ( e->tag == EXIF_TAG_GPS_LATITUDE || e->tag == EXIF_TAG_GPS_LONGITUDE ) { er.numerator = (ExifLong) floor ( val ); er.denominator = 1.0; } else { // I don't see any point in doing anything too complicated here, // such as trying to work out the 'best' denominator // For the moment use KISS principle. // Fix a precision of 1/100 metre as that's more than enough for GPS accuracy especially altitudes! er.denominator = 100.0; er.numerator = (ExifLong) (val * er.denominator); } } // Now for Location 3 part rationals do Mins and Seconds format // Rounded down minutes if ( i == 1 ) { er.denominator = 1.0; er.numerator = (ExifLong) ( (int) floor ( ( val - floor (val) ) * 60.0 ) ); } // Finally seconds if ( i == 2 ) { er.denominator = 100.0; // Fractional minute. double FracPart = ((val - floor(val)) * 60) - (double)(int) floor ( ( val - floor (val) ) * 60.0 ); er.numerator = (ExifLong) ( (int)floor(FracPart * 6000) ); // Convert to seconds. } exif_set_rational (e->data + (s * i), o, er ); break; } case EXIF_FORMAT_LONG: exif_set_long (e->data + (s * i), o, atol (value_p)); break; case EXIF_FORMAT_SLONG: exif_set_slong (e->data + (s * i), o, atol (value_p)); break; case EXIF_FORMAT_BYTE: case EXIF_FORMAT_SBYTE: case EXIF_FORMAT_UNDEFINED: /* treat as byte array */ e->data[s * i] = atoi (value_p); break; case EXIF_FORMAT_FLOAT: case EXIF_FORMAT_DOUBLE: case EXIF_FORMAT_SRATIONAL: default: g_warning (_("Not yet implemented!")); return; } if ( use_string ) value_p = strtok (NULL, " "); } g_free (buf); if ( use_string ) if ( value_p ) g_warning (_("Warning; Too many components specified!")); }
static int exif_data_load_data_entry (ExifData *data, ExifEntry *entry, const unsigned char *d, unsigned int size, unsigned int offset) { unsigned int s, doff; entry->tag = exif_get_short (d + offset + 0, data->priv->order); entry->format = exif_get_short (d + offset + 2, data->priv->order); entry->components = exif_get_long (d + offset + 4, data->priv->order); /* FIXME: should use exif_tag_get_name_in_ifd here but entry->parent * has not been set yet */ exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData", "Loading entry 0x%x ('%s')...", entry->tag, exif_tag_get_name (entry->tag)); /* {0,1,2,4,8} x { 0x00000000 .. 0xffffffff } * -> { 0x000000000 .. 0x7fffffff8 } */ s = exif_format_get_size(entry->format) * entry->components; if ((s < entry->components) || (s == 0)){ return 0; } /* * Size? If bigger than 4 bytes, the actual data is not * in the entry but somewhere else (offset). */ if (s > 4) doff = exif_get_long (d + offset + 8, data->priv->order); else doff = offset + 8; /* Sanity checks */ if ((doff + s < doff) || (doff + s < s) || (doff + s > size)) { exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData", "Tag data past end of buffer (%u > %u)", doff+s, size); return 0; } entry->data = exif_data_alloc (data, s); if (entry->data) { entry->size = s; memcpy (entry->data, d + doff, s); } else { /* FIXME: What do our callers do if (entry->data == NULL)? */ EXIF_LOG_NO_MEMORY(data->priv->log, "ExifData", s); } /* If this is the MakerNote, remember the offset */ if (entry->tag == EXIF_TAG_MAKER_NOTE) { if (!entry->data) { exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData", "MakerNote found with empty data"); } else if (entry->size > 6) { exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData", "MakerNote found (%02x %02x %02x %02x " "%02x %02x %02x...).", entry->data[0], entry->data[1], entry->data[2], entry->data[3], entry->data[4], entry->data[5], entry->data[6]); } data->priv->offset_mnote = doff; } return 1; }
static void exif_data_save_data_entry (ExifData *data, ExifEntry *e, unsigned char **d, unsigned int *ds, unsigned int offset) { unsigned int doff, s; unsigned int ts; if (!data || !data->priv) return; /* * Each entry is 12 bytes long. The memory for the entry has * already been allocated. */ exif_set_short (*d + 6 + offset + 0, data->priv->order, (ExifShort) e->tag); exif_set_short (*d + 6 + offset + 2, data->priv->order, (ExifShort) e->format); if (!(data->priv->options & EXIF_DATA_OPTION_DONT_CHANGE_MAKER_NOTE)) { /* If this is the maker note tag, update it. */ if ((e->tag == EXIF_TAG_MAKER_NOTE) && data->priv->md) { /* TODO: this is using the wrong ExifMem to free e->data */ exif_mem_free (data->priv->mem, e->data); e->data = NULL; e->size = 0; exif_mnote_data_set_offset (data->priv->md, *ds - 6); exif_mnote_data_save (data->priv->md, &e->data, &e->size); e->components = e->size; } } exif_set_long (*d + 6 + offset + 4, data->priv->order, e->components); /* * Size? If bigger than 4 bytes, the actual data is not in * the entry but somewhere else. */ s = exif_format_get_size (e->format) * e->components; if (s > 4) { unsigned char *t; doff = *ds - 6; ts = *ds + s; /* * According to the TIFF specification, * the offset must be an even number. If we need to introduce * a padding byte, we set it to 0. */ if (s & 1) ts++; t = exif_mem_realloc (data->priv->mem, *d, ts); if (!t) { EXIF_LOG_NO_MEMORY (data->priv->log, "ExifData", ts); return; } *d = t; *ds = ts; exif_set_long (*d + 6 + offset + 8, data->priv->order, doff); if (s & 1) *(*d + *ds - 1) = '\0'; } else doff = offset + 8; /* Write the data. Fill unneeded bytes with 0. Do not crash with * e->data is NULL */ if (e->data) { memcpy (*d + 6 + doff, e->data, s); } else { memset (*d + 6 + doff, 0, s); } if (s < 4) memset (*d + 6 + doff + s, 0, (4 - s)); }
/** * @brief save the MnoteData from ne to buf * * @param ne extract the data from this structure * @param *buf write the mnoteData to this buffer (buffer will be allocated) * @param buf_size the size of the buffer */ static void exif_mnote_data_olympus_save (ExifMnoteData *ne, unsigned char **buf, unsigned int *buf_size) { ExifMnoteDataOlympus *n = (ExifMnoteDataOlympus *) ne; size_t i, o, s, doff, base = 0, o2 = 6 + 2; size_t datao = 0; unsigned char *t; size_t ts; if (!n || !buf || !buf_size) return; /* * Allocate enough memory for all entries and the number of entries. */ *buf_size = 6 + 2 + 2 + n->count * 12; switch (n->version) { case olympusV1: case sanyoV1: case epsonV1: *buf = exif_mem_alloc (ne->mem, *buf_size); if (!*buf) { EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteDataOlympus", *buf_size); return; } /* Write the header and the number of entries. */ strcpy ((char *)*buf, n->version==sanyoV1?"SANYO": (n->version==epsonV1?"EPSON":"OLYMP")); exif_set_short (*buf + 6, n->order, (ExifShort) 1); datao = n->offset; break; case olympusV2: *buf_size += 8-6 + 4; *buf = exif_mem_alloc (ne->mem, *buf_size); if (!*buf) { EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteDataOlympus", *buf_size); return; } /* Write the header and the number of entries. */ strcpy ((char *)*buf, "OLYMPUS"); exif_set_short (*buf + 8, n->order, (ExifShort) ( (n->order == EXIF_BYTE_ORDER_INTEL) ? ('I' << 8) | 'I' : ('M' << 8) | 'M')); exif_set_short (*buf + 10, n->order, (ExifShort) 3); o2 += 4; break; case nikonV1: base = MNOTE_NIKON1_TAG_BASE; /* v1 has offsets based to main IFD, not makernote IFD */ datao += n->offset + 10; /* subtract the size here, so the increment in the next case will not harm us */ *buf_size -= 8 + 2; /* Fall through */ case nikonV2: *buf_size += 8 + 2; *buf_size += 4; /* Next IFD pointer */ *buf = exif_mem_alloc (ne->mem, *buf_size); if (!*buf) { EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteDataOlympus", *buf_size); return; } /* Write the header and the number of entries. */ strcpy ((char *)*buf, "Nikon"); (*buf)[6] = n->version; if (n->version == nikonV2) { exif_set_short (*buf + 10, n->order, (ExifShort) ( (n->order == EXIF_BYTE_ORDER_INTEL) ? ('I' << 8) | 'I' : ('M' << 8) | 'M')); exif_set_short (*buf + 12, n->order, (ExifShort) 0x2A); exif_set_long (*buf + 14, n->order, (ExifShort) 8); o2 += 2 + 8; } datao -= 10; /* Reset next IFD pointer */ exif_set_long (*buf + o2 + 2 + n->count * 12, n->order, 0); break; default: return; } exif_set_short (*buf + o2, n->order, (ExifShort) n->count); o2 += 2; /* Save each entry */ for (i = 0; i < n->count; i++) { o = o2 + i * 12; exif_set_short (*buf + o + 0, n->order, (ExifShort) (n->entries[i].tag - base)); exif_set_short (*buf + o + 2, n->order, (ExifShort) n->entries[i].format); exif_set_long (*buf + o + 4, n->order, n->entries[i].components); o += 8; s = exif_format_get_size (n->entries[i].format) * n->entries[i].components; if (s > 65536) { /* Corrupt data: EXIF data size is limited to the * maximum size of a JPEG segment (64 kb). */ continue; } if (s > 4) { doff = *buf_size; ts = *buf_size + s; t = exif_mem_realloc (ne->mem, *buf, sizeof (char) * ts); if (!t) { EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteDataOlympus", ts); return; } *buf = t; *buf_size = ts; exif_set_long (*buf + o, n->order, datao + doff); } else doff = o; /* Write the data. */ if (n->entries[i].data) { memcpy (*buf + doff, n->entries[i].data, s); } else { /* Most certainly damaged input file */ memset (*buf + doff, 0, s); } } }
static void exif_mnote_data_fuji_save (ExifMnoteData *ne, unsigned char **buf, unsigned int *buf_size) { ExifMnoteDataFuji *n = (ExifMnoteDataFuji *) ne; size_t i, o, s, doff; unsigned char *t; size_t ts; if (!n || !buf || !buf_size) return; /* * Allocate enough memory for all entries and the number * of entries. */ *buf_size = 8 + 4 + 2 + n->count * 12 + 4; *buf = exif_mem_alloc (ne->mem, *buf_size); if (!*buf) { *buf_size = 0; return; } /* * Header: "FUJIFILM" and 4 bytes offset to the first entry. * As the first entry will start right thereafter, the offset is 12. */ memcpy (*buf, "FUJIFILM", 8); exif_set_long (*buf + 8, n->order, 12); /* Save the number of entries */ exif_set_short (*buf + 8 + 4, n->order, (ExifShort) n->count); /* Save each entry */ for (i = 0; i < n->count; i++) { o = 8 + 4 + 2 + i * 12; exif_set_short (*buf + o + 0, n->order, (ExifShort) n->entries[i].tag); exif_set_short (*buf + o + 2, n->order, (ExifShort) n->entries[i].format); exif_set_long (*buf + o + 4, n->order, n->entries[i].components); o += 8; s = exif_format_get_size (n->entries[i].format) * n->entries[i].components; if (s > 65536) { /* Corrupt data: EXIF data size is limited to the * maximum size of a JPEG segment (64 kb). */ continue; } if (s > 4) { ts = *buf_size + s; /* Ensure even offsets. Set padding bytes to 0. */ if (s & 1) ts += 1; t = exif_mem_realloc (ne->mem, *buf, ts); if (!t) { return; } *buf = t; *buf_size = ts; doff = *buf_size - s; if (s & 1) { doff--; *(*buf + *buf_size - 1) = '\0'; } exif_set_long (*buf + o, n->order, doff); } else doff = o; /* * Write the data. Fill unneeded bytes with 0. Do not * crash if data is NULL. */ if (!n->entries[i].data) memset (*buf + doff, 0, s); else memcpy (*buf + doff, n->entries[i].data, s); } }