static void exif_mnote_data_canon_save (ExifMnoteData *ne, unsigned char **buf, unsigned int *buf_size) { ExifMnoteDataCanon *n = (ExifMnoteDataCanon *) ne; unsigned int i, o, s, doff; if (!n || !buf || !buf_size) return; /* * Allocate enough memory for all entries and the number * of entries. */ *buf_size = 2 + n->count * 12 + 4; *buf = exif_mem_alloc (ne->mem, sizeof (char) * *buf_size); if (!*buf) return; /* Save the number of entries */ exif_set_short (*buf, n->order, (ExifShort) n->count); /* Save each entry */ for (i = 0; i < n->count; i++) { o = 2 + i * 12; exif_set_short (*buf + o + 0, n->order, (ExifShort) n->entries[i].tag); exif_set_short (*buf + o + 2, n->order, (ExifShort) n->entries[i].format); exif_set_long (*buf + o + 4, n->order, n->entries[i].components); o += 8; s = exif_format_get_size (n->entries[i].format) * n->entries[i].components; if (s > 4) { *buf_size += s; /* Ensure even offsets. Set padding bytes to 0. */ if (s & 1) *buf_size += 1; *buf = exif_mem_realloc (ne->mem, *buf, sizeof (char) * *buf_size); if (!*buf) return; doff = *buf_size - s; if (s & 1) { doff--; *(*buf + *buf_size - 1) = '\0'; } exif_set_long (*buf + o, n->order, n->offset + doff); } else doff = o; /* * Write the data. Fill unneeded bytes with 0. Do not * crash if data is NULL. */ if (!n->entries[i].data) memset (*buf + doff, 0, s); else memcpy (*buf + doff, n->entries[i].data, s); if (s < 4) memset (*buf + doff + s, 0, (4 - s)); } }
static void write_short( ExifEntry *entry, ExifByteOrder bo, void *data ) { ExifShort *v = (ExifShort *) data; exif_set_short( entry->data, bo, *v ); }
static void vips_exif_set_int( ExifData *ed, ExifEntry *entry, unsigned long component, void *data ) { int value = *((int *) data); ExifByteOrder bo; size_t sizeof_component; size_t offset = component; if( entry->components <= component ) { VIPS_DEBUG_MSG( "vips_exif_set_int: too few components\n" ); return; } /* Wait until after the component check to make sure we cant get /0. */ bo = exif_data_get_byte_order( ed ); sizeof_component = entry->size / entry->components; offset = component * sizeof_component; VIPS_DEBUG_MSG( "vips_exif_set_int: %s = %d\n", vips_exif_entry_get_name( entry ), value ); if( entry->format == EXIF_FORMAT_SHORT ) exif_set_short( entry->data + offset, bo, value ); else if( entry->format == EXIF_FORMAT_SSHORT ) exif_set_sshort( entry->data + offset, bo, value ); else if( entry->format == EXIF_FORMAT_LONG ) exif_set_long( entry->data + offset, bo, value ); else if( entry->format == EXIF_FORMAT_SLONG ) exif_set_slong( entry->data + offset, bo, value ); }
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; } } }
void exif_data_save_data (ExifData *data, unsigned char **d, unsigned int *ds) { if (ds) *ds = 0; /* This means something went wrong */ if (!data || !d || !ds) return; /* Header */ *ds = 14; *d = exif_data_alloc (data, *ds); if (!*d) { *ds = 0; return; } memcpy (*d, ExifHeader, 6); /* Order (offset 6) */ if (data->priv->order == EXIF_BYTE_ORDER_INTEL) { memcpy (*d + 6, "II", 2); } else { memcpy (*d + 6, "MM", 2); } /* Fixed value (2 bytes, offset 8) */ exif_set_short (*d + 8, data->priv->order, 0x002a); /* * IFD 0 offset (4 bytes, offset 10). * We will start 8 bytes after the * EXIF header (2 bytes for order, another 2 for the test, and * 4 bytes for the IFD 0 offset make 8 bytes together). */ exif_set_long (*d + 10, data->priv->order, 8); /* Now save IFD 0. IFD 1 will be saved automatically. */ exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData", "Saving IFDs..."); exif_data_save_data_content (data, data->ifd[EXIF_IFD_0], d, ds, *ds - 6); exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData", "Saved %i byte(s) EXIF data.", *ds); }
void exif_entry_set_short (ExifData * pEdata, ExifIfd eEifd, ExifTag eEtag, ExifShort n) { ExifEntry *pE; ExifByteOrder eO; pE = exif_entry_new (); exif_content_add_entry (pEdata->ifd[eEifd], pE); exif_entry_initialize (pE, eEtag); eO = exif_data_get_byte_order (pE->parent->parent); if (pE->data) { exif_set_short (pE->data, eO, n); } else { printf ("ERROR: unallocated e->data Tag %d\n", eEtag); } exif_entry_fix (pE); exif_entry_unref (pE); }
static void set_int(ExifData *ed, ExifEntry *ee, long value) { ExifByteOrder o = exif_data_get_byte_order(ed); switch (ee->format) { case EXIF_FORMAT_SHORT: exif_set_short (ee->data, o, value); break; case EXIF_FORMAT_LONG: exif_set_long (ee->data, o, value); break; case EXIF_FORMAT_SLONG: exif_set_slong (ee->data, o, value); break; default: fprintf(stderr,"set_int oops\n"); exit(1); } }
void jpeg_setup_exif_for_save (ExifData *exif_data, const gint32 image_ID) { ExifRational r; gdouble xres, yres; ExifEntry *entry; gint byte_order = exif_data_get_byte_order (exif_data); /* set orientation to top - left */ if ((entry = exif_content_get_entry (exif_data->ifd[EXIF_IFD_0], EXIF_TAG_ORIENTATION))) { exif_set_short (entry->data, byte_order, (ExifShort) 1); } /* set x and y resolution */ gimp_image_get_resolution (image_ID, &xres, &yres); r.numerator = xres; r.denominator = 1; if ((entry = exif_content_get_entry (exif_data->ifd[EXIF_IFD_0], EXIF_TAG_X_RESOLUTION))) { exif_set_rational (entry->data, byte_order, r); } r.numerator = yres; if ((entry = exif_content_get_entry (exif_data->ifd[EXIF_IFD_0], EXIF_TAG_Y_RESOLUTION))) { exif_set_rational (entry->data, byte_order, r); } /* set resolution unit, always inches */ if ((entry = exif_content_get_entry (exif_data->ifd[EXIF_IFD_0], EXIF_TAG_RESOLUTION_UNIT))) { exif_set_short (entry->data, byte_order, (ExifShort) 2); } /* set software to "GIMP" and include the version number */ if ((entry = exif_content_get_entry (exif_data->ifd[EXIF_IFD_0], EXIF_TAG_SOFTWARE))) { const gchar *name = "GIMP " GIMP_VERSION; entry->data = (guchar *) g_strdup (name); entry->size = strlen (name) + 1; entry->components = entry->size; } /* set the width and height */ if ((entry = exif_content_get_entry (exif_data->ifd[EXIF_IFD_EXIF], EXIF_TAG_PIXEL_X_DIMENSION))) { exif_set_long (entry->data, byte_order, (ExifLong) gimp_image_width (image_ID)); } if ((entry = exif_content_get_entry (exif_data->ifd[EXIF_IFD_EXIF], EXIF_TAG_PIXEL_Y_DIMENSION))) { exif_set_long (entry->data, byte_order, (ExifLong) gimp_image_height (image_ID)); } /* * set the date & time image was saved * note, date & time of original photo is stored elsewwhere, we * aren't losing it. */ if ((entry = exif_content_get_entry (exif_data->ifd[EXIF_IFD_0], EXIF_TAG_DATE_TIME))) { /* small memory leak here */ entry->data = NULL; exif_entry_initialize (entry, EXIF_TAG_DATE_TIME); } /* should set components configuration, don't know how */ /* * remove entries that don't apply to jpeg * (may have come from tiff or raw) */ gimp_exif_data_remove_entry (exif_data, EXIF_IFD_0, EXIF_TAG_COMPRESSION); gimp_exif_data_remove_entry (exif_data, EXIF_IFD_0, EXIF_TAG_IMAGE_WIDTH); gimp_exif_data_remove_entry (exif_data, EXIF_IFD_0, EXIF_TAG_IMAGE_LENGTH); gimp_exif_data_remove_entry (exif_data, EXIF_IFD_0, EXIF_TAG_BITS_PER_SAMPLE); gimp_exif_data_remove_entry (exif_data, EXIF_IFD_0, EXIF_TAG_SAMPLES_PER_PIXEL); gimp_exif_data_remove_entry (exif_data, EXIF_IFD_0, EXIF_TAG_PHOTOMETRIC_INTERPRETATION); gimp_exif_data_remove_entry (exif_data, EXIF_IFD_0, EXIF_TAG_STRIP_OFFSETS); gimp_exif_data_remove_entry (exif_data, EXIF_IFD_0, EXIF_TAG_PLANAR_CONFIGURATION); gimp_exif_data_remove_entry (exif_data, EXIF_IFD_0, EXIF_TAG_YCBCR_SUB_SAMPLING); /* should set thumbnail attributes */ }
int createEXIF(dc1394featureset_t *xFeatures, ExifData ** pParentEd) { ExifEntry *pE; ExifData * pEd; int i = !xFeatures->feature[DC1394_FEATURE_WHITE_BALANCE - DC1394_FEATURE_MIN].auto_active; ExifSRational xR = {xFeatures->feature[DC1394_FEATURE_BRIGHTNESS - DC1394_FEATURE_MIN].value, xFeatures->feature[DC1394_FEATURE_BRIGHTNESS - DC1394_FEATURE_MIN].max};; printf ("Creating EXIF data...\n"); pEd = exif_data_new (); printf ("Adding a Make reference\n"); pE = exif_entry_new (); exif_content_add_entry (pEd->ifd[EXIF_IFD_0], pE); exif_entry_initialize (pE, EXIF_TAG_MAKE); pE->data="AVT"; exif_entry_unref (pE); printf ("Adding a Model reference\n"); pE = exif_entry_new (); exif_content_add_entry (pEd->ifd[EXIF_IFD_0], pE); exif_entry_initialize (pE, EXIF_TAG_MODEL); pE->data="510c"; exif_entry_unref (pE); printf ("Adding a Tag to reference # samples per pixel\n"); pE = exif_entry_new (); exif_content_add_entry (pEd->ifd[EXIF_IFD_0], pE); exif_entry_initialize (pE, EXIF_TAG_SAMPLES_PER_PIXEL); exif_entry_unref (pE); printf ("Adding a White Balance Reference\n"); pE = exif_entry_new (); exif_content_add_entry (pEd->ifd[EXIF_IFD_0], pE); exif_entry_initialize (pE, EXIF_TAG_WHITE_BALANCE); exif_set_short(pE->data, exif_data_get_byte_order (pEd), i); exif_entry_unref (pE); printf ("Adding a Sharpness Reference\n"); pE = exif_entry_new (); exif_content_add_entry (pEd->ifd[EXIF_IFD_0], pE); exif_entry_initialize (pE, EXIF_TAG_SHARPNESS); exif_set_short(pE->data, exif_data_get_byte_order (pEd), 0); exif_entry_unref (pE); printf ("Adding a Brightness reference\n"); pE = exif_entry_new (); exif_content_add_entry (pEd->ifd[EXIF_IFD_0], pE); exif_entry_initialize (pE, EXIF_TAG_BRIGHTNESS_VALUE); exif_set_srational (pE->data, exif_data_get_byte_order (pEd), xR); *pParentEd = pEd; printf("Done!\n"); return 0; }
/** * @brief save the MnoteData from ne to buf * * @param ne extract the data from this structure * @param *buf write the mnoteData to this buffer (buffer will be allocated) * @param buf_size the 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); }
/** 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 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)); } }
void write_sgeo_version(unsigned char *data, ExifByteOrder order) { memcpy(data + 0x00, "SG", 2); exif_set_short(data + 0x02, order, SGEO_VERSION); }
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); }
static void exif_data_save_data_entry (ExifData *data, ExifEntry *e, unsigned char **d, unsigned int *ds, unsigned int offset) { unsigned int doff, s; unsigned int ts; if (!data || !data->priv) return; /* * Each entry is 12 bytes long. The memory for the entry has * already been allocated. */ exif_set_short (*d + 6 + offset + 0, data->priv->order, (ExifShort) e->tag); exif_set_short (*d + 6 + offset + 2, data->priv->order, (ExifShort) e->format); if (!(data->priv->options & EXIF_DATA_OPTION_DONT_CHANGE_MAKER_NOTE)) { /* If this is the maker note tag, update it. */ if ((e->tag == EXIF_TAG_MAKER_NOTE) && data->priv->md) { /* TODO: this is using the wrong ExifMem to free e->data */ exif_mem_free (data->priv->mem, e->data); e->data = NULL; e->size = 0; exif_mnote_data_set_offset (data->priv->md, *ds - 6); exif_mnote_data_save (data->priv->md, &e->data, &e->size); e->components = e->size; } } exif_set_long (*d + 6 + offset + 4, data->priv->order, e->components); /* * Size? If bigger than 4 bytes, the actual data is not in * the entry but somewhere else. */ s = exif_format_get_size (e->format) * e->components; if (s > 4) { unsigned char *t; doff = *ds - 6; ts = *ds + s; /* * According to the TIFF specification, * the offset must be an even number. If we need to introduce * a padding byte, we set it to 0. */ if (s & 1) ts++; t = exif_mem_realloc (data->priv->mem, *d, ts); if (!t) { EXIF_LOG_NO_MEMORY (data->priv->log, "ExifData", ts); return; } *d = t; *ds = ts; exif_set_long (*d + 6 + offset + 8, data->priv->order, doff); if (s & 1) *(*d + *ds - 1) = '\0'; } else doff = offset + 8; /* Write the data. Fill unneeded bytes with 0. Do not crash with * e->data is NULL */ if (e->data) { memcpy (*d + 6 + doff, e->data, s); } else { memset (*d + 6 + doff, 0, s); } if (s < 4) memset (*d + 6 + doff + s, 0, (4 - s)); }
static int 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; }
static void exif_data_save_data_content (ExifData *data, ExifContent *ifd, unsigned char **d, unsigned int *ds, unsigned int offset) { unsigned int j, n_ptr = 0, n_thumb = 0; ExifIfd i; unsigned char *t; unsigned int ts; if (!data || !data->priv || !ifd || !d || !ds) return; for (i = 0; i < EXIF_IFD_COUNT; i++) if (ifd == data->ifd[i]) break; if (i == EXIF_IFD_COUNT) return; /* error */ /* * Check if we need some extra entries for pointers or the thumbnail. */ switch (i) { case EXIF_IFD_0: /* * The pointer to IFD_EXIF is in IFD_0. The pointer to * IFD_INTEROPERABILITY is in IFD_EXIF. */ if (data->ifd[EXIF_IFD_EXIF]->count || data->ifd[EXIF_IFD_INTEROPERABILITY]->count) n_ptr++; /* The pointer to IFD_GPS is in IFD_0. */ if (data->ifd[EXIF_IFD_GPS]->count) n_ptr++; break; case EXIF_IFD_1: if (data->size) n_thumb = 2; break; case EXIF_IFD_EXIF: if (data->ifd[EXIF_IFD_INTEROPERABILITY]->count) n_ptr++; default: break; } /* * Allocate enough memory for all entries * and the number of entries. */ ts = *ds + (2 + (ifd->count + n_ptr + n_thumb) * 12 + 4); t = exif_mem_realloc (data->priv->mem, *d, ts); if (!t) { EXIF_LOG_NO_MEMORY (data->priv->log, "ExifData", ts); return; } *d = t; *ds = ts; /* Save the number of entries */ exif_set_short (*d + 6 + offset, data->priv->order, (ExifShort) (ifd->count + n_ptr + n_thumb)); offset += 2; /* * Save each entry. Make sure that no memcpys from NULL pointers are * performed */ exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData", "Saving %i entries (IFD '%s', offset: %i)...", ifd->count, exif_ifd_get_name (i), offset); for (j = 0; j < ifd->count; j++) { if (ifd->entries[j]) { exif_data_save_data_entry (data, ifd->entries[j], d, ds, offset + 12 * j); } } offset += 12 * ifd->count; /* Now save special entries. */ switch (i) { case EXIF_IFD_0: /* * The pointer to IFD_EXIF is in IFD_0. * However, the pointer to IFD_INTEROPERABILITY is in IFD_EXIF, * therefore, if IFD_INTEROPERABILITY is not empty, we need * IFD_EXIF even if latter is empty. */ if (data->ifd[EXIF_IFD_EXIF]->count || data->ifd[EXIF_IFD_INTEROPERABILITY]->count) { exif_set_short (*d + 6 + offset + 0, data->priv->order, EXIF_TAG_EXIF_IFD_POINTER); exif_set_short (*d + 6 + offset + 2, data->priv->order, EXIF_FORMAT_LONG); exif_set_long (*d + 6 + offset + 4, data->priv->order, 1); exif_set_long (*d + 6 + offset + 8, data->priv->order, *ds - 6); exif_data_save_data_content (data, data->ifd[EXIF_IFD_EXIF], d, ds, *ds - 6); offset += 12; } /* The pointer to IFD_GPS is in IFD_0, too. */ if (data->ifd[EXIF_IFD_GPS]->count) { exif_set_short (*d + 6 + offset + 0, data->priv->order, EXIF_TAG_GPS_INFO_IFD_POINTER); exif_set_short (*d + 6 + offset + 2, data->priv->order, EXIF_FORMAT_LONG); exif_set_long (*d + 6 + offset + 4, data->priv->order, 1); exif_set_long (*d + 6 + offset + 8, data->priv->order, *ds - 6); exif_data_save_data_content (data, data->ifd[EXIF_IFD_GPS], d, ds, *ds - 6); offset += 12; } break; case EXIF_IFD_EXIF: /* * The pointer to IFD_INTEROPERABILITY is in IFD_EXIF. * See note above. */ if (data->ifd[EXIF_IFD_INTEROPERABILITY]->count) { exif_set_short (*d + 6 + offset + 0, data->priv->order, EXIF_TAG_INTEROPERABILITY_IFD_POINTER); exif_set_short (*d + 6 + offset + 2, data->priv->order, EXIF_FORMAT_LONG); exif_set_long (*d + 6 + offset + 4, data->priv->order, 1); exif_set_long (*d + 6 + offset + 8, data->priv->order, *ds - 6); exif_data_save_data_content (data, data->ifd[EXIF_IFD_INTEROPERABILITY], d, ds, *ds - 6); offset += 12; } break; case EXIF_IFD_1: /* * Information about the thumbnail (if any) is saved in * IFD_1. */ if (data->size) { /* EXIF_TAG_JPEG_INTERCHANGE_FORMAT */ exif_set_short (*d + 6 + offset + 0, data->priv->order, EXIF_TAG_JPEG_INTERCHANGE_FORMAT); exif_set_short (*d + 6 + offset + 2, data->priv->order, EXIF_FORMAT_LONG); exif_set_long (*d + 6 + offset + 4, data->priv->order, 1); exif_set_long (*d + 6 + offset + 8, data->priv->order, *ds - 6); ts = *ds + data->size; t = exif_mem_realloc (data->priv->mem, *d, ts); if (!t) { EXIF_LOG_NO_MEMORY (data->priv->log, "ExifData", ts); return; } *d = t; *ds = ts; memcpy (*d + *ds - data->size, data->data, data->size); offset += 12; /* EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH */ exif_set_short (*d + 6 + offset + 0, data->priv->order, EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH); exif_set_short (*d + 6 + offset + 2, data->priv->order, EXIF_FORMAT_LONG); exif_set_long (*d + 6 + offset + 4, data->priv->order, 1); exif_set_long (*d + 6 + offset + 8, data->priv->order, data->size); offset += 12; } break; default: break; } /* Sort the directory according to TIFF specification */ qsort (*d + 6 + offset - (ifd->count + n_ptr + n_thumb) * 12, (ifd->count + n_ptr + n_thumb), 12, (data->priv->order == EXIF_BYTE_ORDER_INTEL) ? cmp_func_intel : cmp_func_motorola); /* Correctly terminate the directory */ if (i == EXIF_IFD_0 && (data->ifd[EXIF_IFD_1]->count || data->size)) { /* * We are saving IFD 0. Tell where IFD 1 starts and save * IFD 1. */ exif_set_long (*d + 6 + offset, data->priv->order, *ds - 6); exif_data_save_data_content (data, data->ifd[EXIF_IFD_1], d, ds, *ds - 6); } else exif_set_long (*d + 6 + offset, data->priv->order, 0); }
/** * @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); } }