Automated import from //branches/master/...@141567,141567
diff --git a/exif.c b/exif.c
index b273c45..1efe3d9 100644
--- a/exif.c
+++ b/exif.c
@@ -81,143 +81,219 @@
 //--------------------------------------------------------------------------
 // Describes tag values
 
-#define TAG_MAKE               0x010F
-#define TAG_MODEL              0x0110
-#define TAG_ORIENTATION        0x0112
-#define TAG_DATETIME           0x0132
-#define TAG_THUMBNAIL_OFFSET   0x0201
-#define TAG_THUMBNAIL_LENGTH   0x0202
-#define TAG_EXPOSURETIME       0x829A
-#define TAG_FNUMBER            0x829D
-#define TAG_EXIF_OFFSET        0x8769
-#define TAG_EXPOSURE_PROGRAM   0x8822
-#define TAG_GPSINFO            0x8825
-#define TAG_ISO_EQUIVALENT     0x8827
-#define TAG_DATETIME_ORIGINAL  0x9003
-#define TAG_DATETIME_DIGITIZED 0x9004
-#define TAG_SHUTTERSPEED       0x9201
-#define TAG_APERTURE           0x9202
-#define TAG_EXPOSURE_BIAS      0x9204
-#define TAG_MAXAPERTURE        0x9205
-#define TAG_SUBJECT_DISTANCE   0x9206
-#define TAG_METERING_MODE      0x9207
-#define TAG_LIGHT_SOURCE       0x9208
-#define TAG_FLASH              0x9209
-#define TAG_FOCALLENGTH        0x920A
-#define TAG_MAKER_NOTE         0x927C
-#define TAG_USERCOMMENT        0x9286
-#define TAG_EXIF_IMAGEWIDTH    0xa002
-#define TAG_EXIF_IMAGELENGTH   0xa003
-#define TAG_INTEROP_OFFSET     0xa005
-#define TAG_FOCALPLANEXRES     0xa20E
-#define TAG_FOCALPLANEUNITS    0xa210
-#define TAG_EXPOSURE_INDEX     0xa215
-#define TAG_EXPOSURE_MODE      0xa402
-#define TAG_WHITEBALANCE       0xa403
-#define TAG_DIGITALZOOMRATIO   0xA404
-#define TAG_FOCALLENGTH_35MM   0xa405
+#define TAG_INTEROP_INDEX          0x0001
+#define TAG_INTEROP_VERSION        0x0002
+#define TAG_IMAGE_WIDTH            0x0100
+#define TAG_IMAGE_LENGTH           0x0101
+#define TAG_BITS_PER_SAMPLE        0x0102
+#define TAG_COMPRESSION            0x0103
+#define TAG_PHOTOMETRIC_INTERP     0x0106
+#define TAG_FILL_ORDER             0x010A
+#define TAG_DOCUMENT_NAME          0x010D
+#define TAG_IMAGE_DESCRIPTION      0x010E
+#define TAG_MAKE                   0x010F
+#define TAG_MODEL                  0x0110
+#define TAG_SRIP_OFFSET            0x0111
+#define TAG_ORIENTATION            0x0112
+#define TAG_SAMPLES_PER_PIXEL      0x0115
+#define TAG_ROWS_PER_STRIP         0x0116
+#define TAG_STRIP_BYTE_COUNTS      0x0117
+#define TAG_X_RESOLUTION           0x011A
+#define TAG_Y_RESOLUTION           0x011B
+#define TAG_PLANAR_CONFIGURATION   0x011C
+#define TAG_RESOLUTION_UNIT        0x0128
+#define TAG_TRANSFER_FUNCTION      0x012D
+#define TAG_SOFTWARE               0x0131
+#define TAG_DATETIME               0x0132
+#define TAG_ARTIST                 0x013B
+#define TAG_WHITE_POINT            0x013E
+#define TAG_PRIMARY_CHROMATICITIES 0x013F
+#define TAG_TRANSFER_RANGE         0x0156
+#define TAG_JPEG_PROC              0x0200
+#define TAG_THUMBNAIL_OFFSET       0x0201
+#define TAG_THUMBNAIL_LENGTH       0x0202
+#define TAG_Y_CB_CR_COEFFICIENTS   0x0211
+#define TAG_Y_CB_CR_SUB_SAMPLING   0x0212
+#define TAG_Y_CB_CR_POSITIONING    0x0213
+#define TAG_REFERENCE_BLACK_WHITE  0x0214
+#define TAG_RELATED_IMAGE_WIDTH    0x1001
+#define TAG_RELATED_IMAGE_LENGTH   0x1002
+#define TAG_CFA_REPEAT_PATTERN_DIM 0x828D
+#define TAG_CFA_PATTERN1           0x828E
+#define TAG_BATTERY_LEVEL          0x828F
+#define TAG_COPYRIGHT              0x8298
+#define TAG_EXPOSURETIME           0x829A
+#define TAG_FNUMBER                0x829D
+#define TAG_IPTC_NAA               0x83BB
+#define TAG_EXIF_OFFSET            0x8769
+#define TAG_INTER_COLOR_PROFILE    0x8773
+#define TAG_EXPOSURE_PROGRAM       0x8822
+#define TAG_SPECTRAL_SENSITIVITY   0x8824
+#define TAG_GPSINFO                0x8825
+#define TAG_ISO_EQUIVALENT         0x8827
+#define TAG_OECF                   0x8828
+#define TAG_EXIF_VERSION           0x9000
+#define TAG_DATETIME_ORIGINAL      0x9003
+#define TAG_DATETIME_DIGITIZED     0x9004
+#define TAG_COMPONENTS_CONFIG      0x9101
+#define TAG_CPRS_BITS_PER_PIXEL    0x9102
+#define TAG_SHUTTERSPEED           0x9201
+#define TAG_APERTURE               0x9202
+#define TAG_BRIGHTNESS_VALUE       0x9203
+#define TAG_EXPOSURE_BIAS          0x9204
+#define TAG_MAXAPERTURE            0x9205
+#define TAG_SUBJECT_DISTANCE       0x9206
+#define TAG_METERING_MODE          0x9207
+#define TAG_LIGHT_SOURCE           0x9208
+#define TAG_FLASH                  0x9209
+#define TAG_FOCALLENGTH            0x920A
+#define TAG_MAKER_NOTE             0x927C
+#define TAG_USERCOMMENT            0x9286
+#define TAG_SUBSEC_TIME            0x9290
+#define TAG_SUBSEC_TIME_ORIG       0x9291
+#define TAG_SUBSEC_TIME_DIG        0x9292
+
+#define TAG_WINXP_TITLE            0x9c9b // Windows XP - not part of exif standard.
+#define TAG_WINXP_COMMENT          0x9c9c // Windows XP - not part of exif standard.
+#define TAG_WINXP_AUTHOR           0x9c9d // Windows XP - not part of exif standard.
+#define TAG_WINXP_KEYWORDS         0x9c9e // Windows XP - not part of exif standard.
+#define TAG_WINXP_SUBJECT          0x9c9f // Windows XP - not part of exif standard.
+
+#define TAG_FLASH_PIX_VERSION      0xA000
+#define TAG_COLOR_SPACE            0xA001
+#define TAG_EXIF_IMAGEWIDTH        0xA002
+#define TAG_EXIF_IMAGELENGTH       0xA003
+#define TAG_RELATED_AUDIO_FILE     0xA004
+#define TAG_INTEROP_OFFSET         0xA005
+#define TAG_FLASH_ENERGY           0xA20B
+#define TAG_SPATIAL_FREQ_RESP      0xA20C
+#define TAG_FOCAL_PLANE_XRES       0xA20E
+#define TAG_FOCAL_PLANE_YRES       0xA20F
+#define TAG_FOCAL_PLANE_UNITS      0xA210
+#define TAG_SUBJECT_LOCATION       0xA214
+#define TAG_EXPOSURE_INDEX         0xA215
+#define TAG_SENSING_METHOD         0xA217
+#define TAG_FILE_SOURCE            0xA300
+#define TAG_SCENE_TYPE             0xA301
+#define TAG_CFA_PATTERN            0xA302
+#define TAG_CUSTOM_RENDERED        0xA401
+#define TAG_EXPOSURE_MODE          0xA402
+#define TAG_WHITEBALANCE           0xA403
+#define TAG_DIGITALZOOMRATIO       0xA404
+#define TAG_FOCALLENGTH_35MM       0xA405
+#define TAG_SCENE_CAPTURE_TYPE     0xA406
+#define TAG_GAIN_CONTROL           0xA407
+#define TAG_CONTRAST               0xA408
+#define TAG_SATURATION             0xA409
+#define TAG_SHARPNESS              0xA40A
+#define TAG_DISTANCE_RANGE         0xA40C
 
 // TODO: replace the ", 0" values in this table with the correct format, e.g. ", FMT_USHORT"
 static const TagTable_t TagTable[] = {
-  { 0x001,   "InteropIndex", 0, 0},
-  { 0x002,   "InteropVersion", 0, 0},
-  { 0x100,   "ImageWidth", FMT_USHORT, 1},
-  { 0x101,   "ImageLength", FMT_USHORT, 1},
-  { 0x102,   "BitsPerSample", FMT_USHORT, 3},
-  { 0x103,   "Compression", FMT_USHORT, 1},
-  { 0x106,   "PhotometricInterpretation", FMT_USHORT, 1},
-  { 0x10A,   "FillOrder", 0, 0},
-  { 0x10D,   "DocumentName", 0, 0},
-  { 0x10E,   "ImageDescription", 0, 0 },
-  { 0x10F,   "Make", FMT_STRING, -1},
-  { 0x110,   "Model", FMT_STRING, -1},
-  { 0x111,   "StripOffsets", FMT_USHORT, 1},
-  { 0x112,   "Orientation", FMT_USHORT, 1},
-  { 0x115,   "SamplesPerPixel", FMT_USHORT, 3},
-  { 0x116,   "RowsPerStrip", FMT_USHORT, 1},
-  { 0x117,   "StripByteCounts", FMT_USHORT, 1},
-  { 0x11A,   "XResolution", FMT_URATIONAL, 1},
-  { 0x11B,   "YResolution", FMT_URATIONAL, 1},
-  { 0x11C,   "PlanarConfiguration", FMT_USHORT, 1},
-  { 0x128,   "ResolutionUnit", FMT_USHORT, 1},
-  { 0x12D,   "TransferFunction", FMT_USHORT, 768},
-  { 0x131,   "Software", FMT_STRING, -1},
-  { 0x132,   "DateTime", FMT_STRING, 20},
-  { 0x13B,   "Artist", FMT_STRING, -1},
-  { 0x13E,   "WhitePoint", FMT_SRATIONAL, 2},
-  { 0x13F,   "PrimaryChromaticities", FMT_SRATIONAL, 6},
-  { 0x156,   "TransferRange", 0, 0},
-  { 0x200,   "JPEGProc", 0, 0},
-  { 0x201,   "ThumbnailOffset", 0, 0},
-  { 0x202,   "ThumbnailLength", 0, 0},
-  { 0x211,   "YCbCrCoefficients", FMT_SRATIONAL, 3},
-  { 0x212,   "YCbCrSubSampling", FMT_USHORT, 2},
-  { 0x213,   "YCbCrPositioning", FMT_USHORT, 1},
-  { 0x214,   "ReferenceBlackWhite", FMT_SRATIONAL, 6},
-  { 0x1001,  "RelatedImageWidth", 0, 0},
-  { 0x1002,  "RelatedImageLength", 0, 0},
-  { 0x828D,  "CFARepeatPatternDim", 0, 0},
-  { 0x828E,  "CFAPattern", 0, 0},
-  { 0x828F,  "BatteryLevel", 0, 0},
-  { 0x8298,  "Copyright", FMT_STRING, -1},
-  { 0x829A,  "ExposureTime", FMT_USHORT, 1},
-  { 0x829D,  "FNumber", FMT_SRATIONAL, 1},
-  { 0x83BB,  "IPTC/NAA", 0, 0},
-  { 0x8769,  "ExifOffset", 0, 0},
-  { 0x8773,  "InterColorProfile", 0, 0},
-  { 0x8822,  "ExposureProgram", FMT_SSHORT, 1},
-  { 0x8824,  "SpectralSensitivity", FMT_STRING, -1},
-  { 0x8825,  "GPS Dir offset", 0, 0},
-  { 0x8827,  "ISOSpeedRatings", FMT_SSHORT, -1},
-  { 0x8828,  "OECF", 0, 0},
-  { 0x9000,  "ExifVersion", FMT_BYTE, 4},
-  { 0x9003,  "DateTimeOriginal", FMT_STRING, 20},
-  { 0x9004,  "DateTimeDigitized", FMT_STRING, 20},
-  { 0x9101,  "ComponentsConfiguration", FMT_BYTE, 4},
-  { 0x9102,  "CompressedBitsPerPixel", FMT_SRATIONAL, 1},
-  { 0x9201,  "ShutterSpeedValue", FMT_SRATIONAL, 1},
-  { 0x9202,  "ApertureValue", FMT_URATIONAL, 1},
-  { 0x9203,  "BrightnessValue", FMT_SRATIONAL, 1},
-  { 0x9204,  "ExposureBiasValue", FMT_SRATIONAL, 1},
-  { 0x9205,  "MaxApertureValue", FMT_URATIONAL, 1},
-  { 0x9206,  "SubjectDistance", FMT_URATIONAL, 1},
-  { 0x9207,  "MeteringMode", FMT_USHORT, 1},
-  { 0x9208,  "LightSource", FMT_USHORT, 1},
-  { 0x9209,  "Flash", FMT_USHORT, 1},
-  { 0x920A,  "FocalLength", FMT_URATIONAL, 1},
-  { 0x927C,  "MakerNote", FMT_STRING, -1},
-  { 0x9286,  "UserComment", FMT_STRING, -1},
-  { 0x9290,  "SubSecTime", FMT_STRING, -1},
-  { 0x9291,  "SubSecTimeOriginal", FMT_STRING, -1},
-  { 0x9292,  "SubSecTimeDigitized", FMT_STRING, -1},
-  { 0xA000,  "FlashPixVersion", FMT_BYTE, 4},
-  { 0xA001,  "ColorSpace", FMT_USHORT, 1},
-  { 0xA002,  "ExifImageWidth", 0, 0},
-  { 0xA003,  "ExifImageLength", 0, 0},
-  { 0xA004,  "RelatedAudioFile", 0, 0},
-  { 0xA005,  "InteroperabilityOffset", 0, 0},
-  { 0xA20B,  "FlashEnergy", FMT_URATIONAL, 1},
-  { 0xA20C,  "SpatialFrequencyResponse", FMT_STRING, -1},
-  { 0xA20E,  "FocalPlaneXResolution", FMT_URATIONAL, 1},
-  { 0xA20F,  "FocalPlaneYResolution", FMT_URATIONAL, 1},
-  { 0xA210,  "FocalPlaneResolutionUnit", FMT_USHORT, 1},
-  { 0xA214,  "SubjectLocation", FMT_USHORT, 2},
-  { 0xA215,  "ExposureIndex", FMT_URATIONAL, 1},
-  { 0xA217,  "SensingMethod", FMT_USHORT, 1},
-  { 0xA300,  "FileSource", 0, 1},
-  { 0xA301,  "SceneType", 0, 1},
-  { 0xA301,  "CFA Pattern", 0, -1},
-  { 0xA401,  "CustomRendered", FMT_USHORT, 1},
-  { 0xA402,  "ExposureMode", FMT_USHORT, 1},
-  { 0xA403,  "WhiteBalance", FMT_USHORT, 1},
-  { 0xA404,  "DigitalZoomRatio", FMT_URATIONAL, 1},
-  { 0xA405,  "FocalLengthIn35mmFilm", FMT_USHORT, 1},
-  { 0xA406,  "SceneCaptureType", FMT_USHORT, 1},
-  { 0xA407,  "GainControl", FMT_URATIONAL, 1},
-  { 0xA408,  "Contrast", FMT_USHORT, 1},
-  { 0xA409,  "Saturation", FMT_USHORT, 1},
-  { 0xA40a,  "Sharpness", FMT_USHORT, 1},
-  { 0xA40c,  "SubjectDistanceRange", FMT_USHORT, 1},
+  { TAG_INTEROP_INDEX,          "InteropIndex", 0, 0},
+  { TAG_INTEROP_VERSION,        "InteropVersion", 0, 0},
+  { TAG_IMAGE_WIDTH,            "ImageWidth", FMT_USHORT, 1},
+  { TAG_IMAGE_LENGTH,           "ImageLength", FMT_USHORT, 1},
+  { TAG_BITS_PER_SAMPLE,        "BitsPerSample", FMT_USHORT, 3},
+  { TAG_COMPRESSION,            "Compression", FMT_USHORT, 1},
+  { TAG_PHOTOMETRIC_INTERP,     "PhotometricInterpretation", FMT_USHORT, 1},
+  { TAG_FILL_ORDER,             "FillOrder", 0, 0},
+  { TAG_DOCUMENT_NAME,          "DocumentName", 0, 0},
+  { TAG_IMAGE_DESCRIPTION,      "ImageDescription", 0, 0 },
+  { TAG_MAKE,                   "Make", FMT_STRING, -1},
+  { TAG_MODEL,                  "Model", FMT_STRING, -1},
+  { TAG_SRIP_OFFSET,            "StripOffsets", FMT_USHORT, 1},
+  { TAG_ORIENTATION,            "Orientation", FMT_USHORT, 1},
+  { TAG_SAMPLES_PER_PIXEL,      "SamplesPerPixel", FMT_USHORT, 3},
+  { TAG_ROWS_PER_STRIP,         "RowsPerStrip", FMT_USHORT, 1},
+  { TAG_STRIP_BYTE_COUNTS,      "StripByteCounts", FMT_USHORT, 1},
+  { TAG_X_RESOLUTION,           "XResolution", FMT_URATIONAL, 1},
+  { TAG_Y_RESOLUTION,           "YResolution", FMT_URATIONAL, 1},
+  { TAG_PLANAR_CONFIGURATION,   "PlanarConfiguration", FMT_USHORT, 1},
+  { TAG_RESOLUTION_UNIT,        "ResolutionUnit", FMT_USHORT, 1},
+  { TAG_TRANSFER_FUNCTION,      "TransferFunction", FMT_USHORT, 768},
+  { TAG_SOFTWARE,               "Software", FMT_STRING, -1},
+  { TAG_DATETIME,               "DateTime", FMT_STRING, 20},
+  { TAG_ARTIST,                 "Artist", FMT_STRING, -1},
+  { TAG_WHITE_POINT,            "WhitePoint", FMT_SRATIONAL, 2},
+  { TAG_PRIMARY_CHROMATICITIES, "PrimaryChromaticities", FMT_SRATIONAL, 6},
+  { TAG_TRANSFER_RANGE,         "TransferRange", 0, 0},
+  { TAG_JPEG_PROC,              "JPEGProc", 0, 0},
+  { TAG_THUMBNAIL_OFFSET,       "ThumbnailOffset", 0, 0},
+  { TAG_THUMBNAIL_LENGTH,       "ThumbnailLength", 0, 0},
+  { TAG_Y_CB_CR_COEFFICIENTS,   "YCbCrCoefficients", FMT_SRATIONAL, 3},
+  { TAG_Y_CB_CR_SUB_SAMPLING,   "YCbCrSubSampling", FMT_USHORT, 2},
+  { TAG_Y_CB_CR_POSITIONING,    "YCbCrPositioning", FMT_USHORT, 1},
+  { TAG_REFERENCE_BLACK_WHITE,  "ReferenceBlackWhite", FMT_SRATIONAL, 6},
+  { TAG_RELATED_IMAGE_WIDTH,    "RelatedImageWidth", 0, 0},
+  { TAG_RELATED_IMAGE_LENGTH,   "RelatedImageLength", 0, 0},
+  { TAG_CFA_REPEAT_PATTERN_DIM, "CFARepeatPatternDim", 0, 0},
+  { TAG_CFA_PATTERN1,           "CFAPattern", 0, 0},
+  { TAG_BATTERY_LEVEL,          "BatteryLevel", 0, 0},
+  { TAG_COPYRIGHT,              "Copyright", FMT_STRING, -1},
+  { TAG_EXPOSURETIME,           "ExposureTime", FMT_USHORT, 1},
+  { TAG_FNUMBER,                "FNumber", FMT_SRATIONAL, 1},
+  { TAG_IPTC_NAA,               "IPTC/NAA", 0, 0},
+  { TAG_EXIF_OFFSET,            "ExifOffset", 0, 0},
+  { TAG_INTER_COLOR_PROFILE,    "InterColorProfile", 0, 0},
+  { TAG_EXPOSURE_PROGRAM,       "ExposureProgram", FMT_SSHORT, 1},
+  { TAG_SPECTRAL_SENSITIVITY,   "SpectralSensitivity", FMT_STRING, -1},
+  { TAG_GPSINFO,                "GPS Dir offset", 0, 0},
+  { TAG_ISO_EQUIVALENT,         "ISOSpeedRatings", FMT_SSHORT, -1},
+  { TAG_OECF,                   "OECF", 0, 0},
+  { TAG_EXIF_VERSION,           "ExifVersion", FMT_BYTE, 4},
+  { TAG_DATETIME_ORIGINAL,      "DateTimeOriginal", FMT_STRING, 20},
+  { TAG_DATETIME_DIGITIZED,     "DateTimeDigitized", FMT_STRING, 20},
+  { TAG_COMPONENTS_CONFIG,      "ComponentsConfiguration", FMT_BYTE, 4},
+  { TAG_CPRS_BITS_PER_PIXEL,    "CompressedBitsPerPixel", FMT_SRATIONAL, 1},
+  { TAG_SHUTTERSPEED,           "ShutterSpeedValue", FMT_SRATIONAL, 1},
+  { TAG_APERTURE,               "ApertureValue", FMT_URATIONAL, 1},
+  { TAG_BRIGHTNESS_VALUE,       "BrightnessValue", FMT_SRATIONAL, 1},
+  { TAG_EXPOSURE_BIAS,          "ExposureBiasValue", FMT_SRATIONAL, 1},
+  { TAG_MAXAPERTURE,            "MaxApertureValue", FMT_URATIONAL, 1},
+  { TAG_SUBJECT_DISTANCE,       "SubjectDistance", FMT_URATIONAL, 1},
+  { TAG_METERING_MODE,          "MeteringMode", FMT_USHORT, 1},
+  { TAG_LIGHT_SOURCE,           "LightSource", FMT_USHORT, 1},
+  { TAG_FLASH,                  "Flash", FMT_USHORT, 1},
+  { TAG_FOCALLENGTH,            "FocalLength", FMT_URATIONAL, 1},
+  { TAG_MAKER_NOTE,             "MakerNote", FMT_STRING, -1},
+  { TAG_USERCOMMENT,            "UserComment", FMT_STRING, -1},
+  { TAG_SUBSEC_TIME,            "SubSecTime", FMT_STRING, -1},
+  { TAG_SUBSEC_TIME_ORIG,       "SubSecTimeOriginal", FMT_STRING, -1},
+  { TAG_SUBSEC_TIME_DIG,        "SubSecTimeDigitized", FMT_STRING, -1},
+  { TAG_WINXP_TITLE,            "Windows-XP Title", 0, 0},
+  { TAG_WINXP_COMMENT,          "Windows-XP comment", 0, 0},
+  { TAG_WINXP_AUTHOR,           "Windows-XP author", 0, 0},
+  { TAG_WINXP_KEYWORDS,         "Windows-XP keywords", 0, 0},
+  { TAG_WINXP_SUBJECT,          "Windows-XP subject", 0, 0},
+  { TAG_FLASH_PIX_VERSION,      "FlashPixVersion", FMT_BYTE, 4},
+  { TAG_COLOR_SPACE,            "ColorSpace", FMT_USHORT, 1},
+  { TAG_EXIF_IMAGEWIDTH,        "ExifImageWidth", 0, 0},
+  { TAG_EXIF_IMAGELENGTH,       "ExifImageLength", 0, 0},
+  { TAG_RELATED_AUDIO_FILE,     "RelatedAudioFile", 0, 0},
+  { TAG_INTEROP_OFFSET,         "InteroperabilityOffset", 0, 0},
+  { TAG_FLASH_ENERGY,           "FlashEnergy", FMT_URATIONAL, 1},
+  { TAG_SPATIAL_FREQ_RESP,      "SpatialFrequencyResponse", FMT_STRING, -1},
+  { TAG_FOCAL_PLANE_XRES,       "FocalPlaneXResolution", FMT_URATIONAL, 1},
+  { TAG_FOCAL_PLANE_YRES,       "FocalPlaneYResolution", FMT_URATIONAL, 1},
+  { TAG_FOCAL_PLANE_UNITS,      "FocalPlaneResolutionUnit", FMT_USHORT, 1},
+  { TAG_SUBJECT_LOCATION,       "SubjectLocation", FMT_USHORT, 2},
+  { TAG_EXPOSURE_INDEX,         "ExposureIndex", FMT_URATIONAL, 1},
+  { TAG_SENSING_METHOD,         "SensingMethod", FMT_USHORT, 1},
+  { TAG_FILE_SOURCE,            "FileSource", 0, 1},
+  { TAG_SCENE_TYPE,             "SceneType", 0, 1},
+  { TAG_CFA_PATTERN,            "CFA Pattern", 0, -1},
+  { TAG_CUSTOM_RENDERED,        "CustomRendered", FMT_USHORT, 1},
+  { TAG_EXPOSURE_MODE,          "ExposureMode", FMT_USHORT, 1},
+  { TAG_WHITEBALANCE,           "WhiteBalance", FMT_USHORT, 1},
+  { TAG_DIGITALZOOMRATIO,       "DigitalZoomRatio", FMT_URATIONAL, 1},
+  { TAG_FOCALLENGTH_35MM,       "FocalLengthIn35mmFilm", FMT_USHORT, 1},
+  { TAG_SCENE_CAPTURE_TYPE,     "SceneCaptureType", FMT_USHORT, 1},
+  { TAG_GAIN_CONTROL,           "GainControl", FMT_URATIONAL, 1},
+  { TAG_CONTRAST,               "Contrast", FMT_USHORT, 1},
+  { TAG_SATURATION,             "Saturation", FMT_USHORT, 1},
+  { TAG_SHARPNESS,              "Sharpness", FMT_USHORT, 1},
+  { TAG_DISTANCE_RANGE,         "SubjectDistanceRange", FMT_USHORT, 1},
 } ;
 
 #define TAG_TABLE_SIZE  (sizeof(TagTable) / sizeof(TagTable_t))
@@ -308,7 +384,7 @@
 {
     int s,n;
 
-    for(n=0;n<20;n++){
+    for(n=0;n<16;n++){
         switch(Format){
             case FMT_SBYTE:
             case FMT_BYTE:      printf("%02x",*(uchar *)ValuePtr); s=1;  break;
@@ -334,7 +410,7 @@
         ValuePtr = (void *)((char *)ValuePtr + s);
 
     }
-    if (n >= 20) printf("...");
+    if (n >= 16) printf("...");
 }
 
 
@@ -414,12 +490,12 @@
                 // Version 1.3 of jhead would truncate a bit too much.
                 // This also caught later on as well.
             }else{
-                ErrNonfatal("Illegally sized directory",0,0);
+                ErrNonfatal("Illegally sized exif subdirectory (%d entries)",NumDirEntries,0);
                 return;
             }
         }
         if (DumpExifMap){
-            printf("Map: %05d-%05d: Directory\n",DirStart-OffsetBase, DirEnd+4-OffsetBase);
+            printf("Map: %05d-%05d: Directory\n",(int)(DirStart-OffsetBase), (int)(DirEnd+4-OffsetBase));
         }
 
 
@@ -575,9 +651,28 @@
                     (char *)ValuePtr - (char *)OffsetBase;
                 break;
 
+            case TAG_WINXP_COMMENT:
+                if (ImageInfo.Comments[0]){ // We already have a jpeg comment.
+                    // Already have a comment (probably windows comment), skip this one.
+                    if (ShowTags) printf("Windows XP commend and other comment in header\n");
+                    break; // Already have a windows comment, skip this one.
+                }
+
+                if (ByteCount > 1){
+                    if (ByteCount > MAX_COMMENT_SIZE) ByteCount = MAX_COMMENT_SIZE;
+                    memcpy(ImageInfo.Comments, ValuePtr, ByteCount);
+                    ImageInfo.CommentWidchars = ByteCount/2;
+                }
+                break;
 
             case TAG_USERCOMMENT:
-                // Olympus has this padded with trailing spaces.  Remove these first.
+                if (ImageInfo.Comments[0]){ // We already have a jpeg comment.
+                    // Already have a comment (probably windows comment), skip this one.
+                    if (ShowTags) printf("Multiple comments in exif header\n");
+                    break; // Already have a windows comment, skip this one.
+                }
+
+                // Comment is often padded with trailing spaces.  Remove these first.
                 for (a=ByteCount;;){
                     a--;
                     if ((ValuePtr)[a] == ' '){
@@ -598,9 +693,8 @@
                             break;
                         }
                     }
-
                 }else{
-                    strncpy(ImageInfo.Comments, (char *)ValuePtr, 199);
+                    strncpy(ImageInfo.Comments, (char *)ValuePtr, MAX_COMMENT_SIZE-1);
                 }
                 break;
 
@@ -679,11 +773,11 @@
                 if (ExifImageWidth < a) ExifImageWidth = a;
                 break;
 
-            case TAG_FOCALPLANEXRES:
+            case TAG_FOCAL_PLANE_XRES:
                 FocalplaneXRes = ConvertAnyFormat(ValuePtr, Format);
                 break;
 
-            case TAG_FOCALPLANEUNITS:
+            case TAG_FOCAL_PLANE_UNITS:
                 switch((int)ConvertAnyFormat(ValuePtr, Format)){
                     case 1: FocalplaneUnits = 25.4; break; // inch
                     case 2:
@@ -791,6 +885,12 @@
                 // computing it from sensor geometry and actual focal length.
                 ImageInfo.FocalLength35mmEquiv = (unsigned)ConvertAnyFormat(ValuePtr, Format);
                 break;
+
+            case TAG_DISTANCE_RANGE:
+                // Three possible standard values:
+                //   1 = macro, 2 = close, 3 = distant
+                ImageInfo.DistanceRange = (int)ConvertAnyFormat(ValuePtr, Format);
+                break;
         }
     }
 
@@ -1073,12 +1173,12 @@
     unsigned short NumEntries;
     int DataWriteIndex;
     int DirIndex;
-    int ThumbnailOffsetDirIndex = 0;
+    int DirContinuation = 0;
 
 #ifdef SUPERDEBUG
     LOGE("create_EXIF %d exif elements, %d gps elements", exifTagCount, gpsTagCount);
 #endif
-
+    
     MotorolaOrder = 0;
 
     memcpy(Buffer+2, "Exif\0\0II",8);
@@ -1097,7 +1197,8 @@
 
         Put16u(Buffer+DirIndex, NumEntries); // Number of entries
         DirIndex += 2;
-        // Entries go here....
+  
+        // Entries go here...
         {
             // Date/time entry
             char* dateTime = NULL;
@@ -1142,8 +1243,7 @@
                                     &DirIndex,
                                     &DataWriteIndex);
             }
-        }
-        {
+        
             if (gpsTagCount) {
                 // Link to gps dir entry
                 writeExifTagAndData(TAG_GPSINFO,
@@ -1161,7 +1261,7 @@
             if (gpsTagCount) {
                 exifDirPtr += 2 + gpsTagCount*12 + 4;
             }
-            ThumbnailOffsetDirIndex = DirIndex;
+            DirContinuation = DirIndex;
             writeExifTagAndData(TAG_EXIF_OFFSET,
                                 FMT_ULONG,
                                 1,
@@ -1173,10 +1273,11 @@
         }
 
         // End of directory - contains optional link to continued directory.
-        Put32u(Buffer+DirIndex, 0);
+        DirContinuation = DirIndex;
         printf("Ending Exif section DirIndex = %d DataWriteIndex %d", DirIndex, DataWriteIndex);
     }
 
+
     // GPS Section
     if (gpsTagCount) {
         DirIndex = DataWriteIndex;
@@ -1216,9 +1317,8 @@
     }
 
     {
-        // Now that we know where the Thumbnail section is written, we have to go
-        // back and "poke" the address to point here.
-        Put32u(Buffer+ThumbnailOffsetDirIndex + 8, DataWriteIndex-8); // Pointer or value.
+        //Continuation which links to this directory;
+        Put32u(Buffer+DirContinuation, DataWriteIndex-8);
 
         printf("Starting Thumbnail section DirIndex = %d", DirIndex);
         DirIndex = DataWriteIndex;
@@ -1256,6 +1356,7 @@
         printf("Ending Thumbnail section DirIndex = %d DataWriteIndex %d", DirIndex, DataWriteIndex);
     }
 
+    
     Buffer[0] = (unsigned char)(DataWriteIndex >> 8);
     Buffer[1] = (unsigned char)DataWriteIndex;
 
@@ -1594,6 +1695,23 @@
             break;
     }
 
+    if (ImageInfo.DistanceRange) {
+        printf("Focus range  : ");
+        switch(ImageInfo.DistanceRange) {
+            case 1:
+                printf("macro");
+                break;
+            case 2:
+                printf("close");
+                break;
+            case 3:
+                printf("distant");
+                break;
+        }
+        printf("\n");
+    }
+
+
 
     if (ImageInfo.Process != M_SOF0){
         // don't show it if its the plain old boring 'baseline' process, but do
@@ -1622,21 +1740,25 @@
     if (ImageInfo.Comments[0]){
         int a,c;
         printf("Comment      : ");
-        for (a=0;a<MAX_COMMENT;a++){
-            c = ImageInfo.Comments[a];
-            if (c == '\0') break;
-            if (c == '\n'){
-                // Do not start a new line if the string ends with a carriage return.
-                if (ImageInfo.Comments[a+1] != '\0'){
-                    printf("\nComment      : ");
+        if (!ImageInfo.CommentWidchars){
+            for (a=0;a<MAX_COMMENT_SIZE;a++){
+                c = ImageInfo.Comments[a];
+                if (c == '\0') break;
+                if (c == '\n'){
+                    // Do not start a new line if the string ends with a carriage return.
+                    if (ImageInfo.Comments[a+1] != '\0'){
+                        printf("\nComment      : ");
+                    }else{
+                        printf("\n");
+                    }
                 }else{
-                    printf("\n");
+                    putchar(c);
                 }
-            }else{
-                putchar(c);
             }
+            printf("\n");
+        }else{
+            printf("%.*ls\n", ImageInfo.CommentWidchars, (wchar_t *)ImageInfo.Comments);
         }
-        printf("\n");
     }
     if (ImageInfo.ThumbnailOffset){
         printf("Map: %05d-%05d: Thumbnail\n",ImageInfo.ThumbnailOffset, ImageInfo.ThumbnailOffset+ImageInfo.ThumbnailSize);
diff --git a/gpsinfo.c b/gpsinfo.c
index 2a25368..18b9d07 100644
--- a/gpsinfo.c
+++ b/gpsinfo.c
@@ -205,21 +205,22 @@
                     ErrNonfatal("Inappropriate format (%d) for GPS coordinates!", Format, 0);
                 }
                 strcpy(FmtString, "%0.0fd %0.0fm %0.0fs");
-
                 for (a=0;a<3;a++){
                     int den, digits;
 
                     den = Get32s(ValuePtr+4+a*ComponentSize);
                     digits = 0;
-                    while (den > 1){
+                    while (den > 1 && digits <= 6){
                         den = den / 10;
                         digits += 1;
                     }
+                    if (digits > 6) digits = 6;
                     FmtString[1+a*7] = (char)('2'+digits+(digits ? 1 : 0));
                     FmtString[3+a*7] = (char)('0'+digits);
 
                     Values[a] = ConvertAnyFormat(ValuePtr+a*ComponentSize, Format);
                 }
+
                 sprintf(TempString, FmtString, Values[0], Values[1], Values[2]);
 
                 if (Tag == TAG_GPS_LAT){
@@ -244,7 +245,8 @@
                 break;
 
             case TAG_GPS_ALT:
-                sprintf(ImageInfo.GpsAlt + 1, "%dm", Get32s(ValuePtr));
+                sprintf(ImageInfo.GpsAlt + 1, "%.2fm", 
+                    ConvertAnyFormat(ValuePtr, Format));
                 break;
         }
 
@@ -256,7 +258,7 @@
                 // Show unknown tag
                 printf("        Illegal GPS tag %04x=", Tag);
             }
-    
+
             switch(Format){
                 case FMT_UNDEFINED:
                     // Undefined is typically an ascii string.
diff --git a/iptc.c b/iptc.c
index 37f7127..93d6f34 100644
--- a/iptc.c
+++ b/iptc.c
@@ -1,9 +1,10 @@
 //--------------------------------------------------------------------------
-//  Process IPTC data.
+//  Process IPTC data and XMP data.
 //--------------------------------------------------------------------------
 #include "jhead.h"
 
-// Supported IPTC entry types
+// IPTC entry types known to Jhead (there's many more defined)
+#define IPTC_RECORD_VERSION         0x00
 #define IPTC_SUPLEMENTAL_CATEGORIES 0x14
 #define IPTC_KEYWORDS               0x19
 #define IPTC_CAPTION                0x78
@@ -25,6 +26,9 @@
 #define IPTC_COPYRIGHT              0x0A
 #define IPTC_COUNTRY_CODE           0x64
 #define IPTC_REFERENCE_SERVICE      0x2D
+#define IPTC_TIME_CREATED           0x3C
+#define IPTC_SUB_LOCATION           0x5C
+#define IPTC_IMAGE_TYPE             0x82
 
 //--------------------------------------------------------------------------
 //  Process and display IPTC marker.
@@ -86,21 +90,21 @@
     // Get length (from motorola format)
     //length = (*pos << 24) | (*(pos+1) << 16) | (*(pos+2) << 8) | *(pos+3);
 
-    pos += sizeof(long);                    // move data pointer to the next field
+    pos += 4;                    // move data pointer to the next field
 
     printf("======= IPTC data: =======\n");
 
     // Now read IPTC data
     while (pos < (Data + itemlen-5)) {
         short  signature;
-        char   type = 0;
+        unsigned char   type = 0;
         short  length = 0;
         char * description = NULL;
 
         if (pos+5 > maxpos) goto corrupt;
 
         signature = (*pos << 8) + (*(pos+1));
-        pos += sizeof(short);
+        pos += 2;
 
         if (signature != 0x1C02){
             break;
@@ -108,42 +112,50 @@
 
         type    = *pos++;
         length  = (*pos << 8) + (*(pos+1));
-        pos    += sizeof(short);                // Skip tag length
+        pos    += 2;                          // Skip tag length
 
         if (pos+length > maxpos) goto corrupt;
         // Process tag here
         switch (type) {
+            case IPTC_RECORD_VERSION:
+                printf("Record vers.  : %d\n", (*pos << 8) + (*(pos+1)));
+                break;
+
             case IPTC_SUPLEMENTAL_CATEGORIES:  description = "SuplementalCategories"; break;
             case IPTC_KEYWORDS:                description = "Keywords"; break;
             case IPTC_CAPTION:                 description = "Caption"; break;
             case IPTC_AUTHOR:                  description = "Author"; break;
             case IPTC_HEADLINE:                description = "Headline"; break;
-            case IPTC_SPECIAL_INSTRUCTIONS:    description = "Spec.Instr."; break;
+            case IPTC_SPECIAL_INSTRUCTIONS:    description = "Spec. Instr."; break;
             case IPTC_CATEGORY:                description = "Category"; break;
             case IPTC_BYLINE:                  description = "Byline"; break;
-            case IPTC_BYLINE_TITLE:            description = "BylineTitle"; break;
+            case IPTC_BYLINE_TITLE:            description = "Byline Title"; break;
             case IPTC_CREDIT:                  description = "Credit"; break;
             case IPTC_SOURCE:                  description = "Source"; break;
             case IPTC_COPYRIGHT_NOTICE:        description = "(C)Notice"; break;
-            case IPTC_OBJECT_NAME:             description = "ObjectName"; break;
+            case IPTC_OBJECT_NAME:             description = "Object Name"; break;
             case IPTC_CITY:                    description = "City"; break;
             case IPTC_STATE:                   description = "State"; break;
             case IPTC_COUNTRY:                 description = "Country"; break;
             case IPTC_TRANSMISSION_REFERENCE:  description = "OriginalTransmissionReference"; break;
             case IPTC_DATE:                    description = "DateCreated"; break;
             case IPTC_COPYRIGHT:               description = "(C)Flag"; break;
-            case IPTC_REFERENCE_SERVICE:       description = "CountryCode"; break;
-            case IPTC_COUNTRY_CODE:            description = "Ref.Service"; break;
+            case IPTC_REFERENCE_SERVICE:       description = "Country Code"; break;
+            case IPTC_COUNTRY_CODE:            description = "Ref. Service"; break;
+            case IPTC_TIME_CREATED:            description = "Time Created"; break;
+            case IPTC_SUB_LOCATION:            description = "Sub Location"; break;
+            case IPTC_IMAGE_TYPE:              description = "Image type"; break;
+
             default:
                 if (ShowTags){
-                    printf("Unrecognised IPTC tag: 0x%02x \n", type);
+                    printf("Unrecognised IPTC tag: %d\n", type );
                 }
             break;
         }
         if (description != NULL) {
             char TempBuf[32];
             memset(TempBuf, 0, sizeof(TempBuf));
-            memset(TempBuf, ' ', 13);
+            memset(TempBuf, ' ', 14);
             memcpy(TempBuf, description, strlen(description));
             strcat(TempBuf, ":"); 
             printf("%s %*.*s\n", TempBuf, length, length, pos);
@@ -154,3 +166,40 @@
 corrupt:
     ErrNonfatal("Pointer corruption in IPTC\n",0,0);
 }
+
+
+
+//--------------------------------------------------------------------------
+// Dump contents of XMP section
+//--------------------------------------------------------------------------
+void ShowXmp(Section_t XmpSection)
+{
+    unsigned char * Data;
+    char OutLine[101];
+    int OutLineChars;
+    int NonBlank;
+    unsigned a;
+    NonBlank = 0;
+    Data = XmpSection.Data;
+    OutLineChars = 0;
+
+
+    for (a=0;a<XmpSection.Size;a++){
+        if (Data[a] >= 32 && Data[a] < 128){
+            OutLine[OutLineChars++] = Data[a];
+            if (Data[a] != ' ') NonBlank |= 1;
+        }else{
+            if (Data[a] != '\n'){
+                OutLine[OutLineChars++] = '?';
+            }
+        }
+        if (Data[a] == '\n' || OutLineChars >= 100){
+            OutLine[OutLineChars] = 0;
+            if (NonBlank){
+                puts(OutLine);
+            }
+            NonBlank = (NonBlank & 1) << 1;
+            OutLineChars = 0;
+        }
+    }
+}
diff --git a/jhead.c b/jhead.c
index 036eb69..88bd527 100644
--- a/jhead.c
+++ b/jhead.c
@@ -2,12 +2,12 @@
 // Program to pull the information out of various types of EXIF digital 
 // camera files and show it in a reasonably consistent way
 //
-// Version 2.71
+// Version 2.86
 //
 // Compiling under Windows:  
 //   Make sure you have Microsoft's compiler on the path, then run make.bat
 //
-// Dec 1999 - Feb 2007
+// Dec 1999 - Mar 2009
 //
 // by Matthias Wandel   www.sentex.net/~mwandel
 //--------------------------------------------------------------------------
@@ -16,11 +16,11 @@
 #include <sys/stat.h>
 #include <utils/Log.h>
 
-#define JHEAD_VERSION "2.71"
+#define JHEAD_VERSION "2.87"
 
 // This #define turns on features that are too very specific to 
 // how I organize my photos.  Best to ignore everything inside #ifdef MATTHIAS
-#define MATTHIAS
+//#define MATTHIAS
 
 #ifdef _WIN32
     #include <io.h>
@@ -36,8 +36,10 @@
 //--------------------------------------------------------------------------
 // Command line options flags
 static int TrimExif = FALSE;        // Cut off exif beyond interesting data.
-static int RenameToDate = FALSE;
+static int RenameToDate = 0;        // 1=rename, 2=rename all.
+#ifdef _WIN32
 static int RenameAssociatedFiles = FALSE;
+#endif
 static char * strftime_args = NULL; // Format for new file name.
 static int Exif2FileTime  = FALSE;
 static int DoModify     = FALSE;
@@ -60,6 +62,7 @@
 static int DeleteComments = FALSE;
 static int DeleteExif = FALSE;
 static int DeleteIptc = FALSE;
+static int DeleteXmp = FALSE;
 static int DeleteUnknown = FALSE;
 static char * ThumbSaveName = NULL; // If not NULL, use this string to make up
                                     // the filename to store the thumbnail to.
@@ -86,7 +89,6 @@
                                     // (file name, file size, file date)
 
 
-
 #ifdef MATTHIAS
     // This #ifdef to take out less than elegant stuff for editing
     // the comments in a JPEG.  The programs rdjpgcom and wrjpgcom
@@ -103,7 +105,6 @@
 void ErrFatal(char * msg)
 {
     LOGE("Error : %s\n", msg);
-    fprintf(stderr,"Error : %s\n", msg);
     if (CurrentFile) fprintf(stderr,"in file '%s'\n",CurrentFile);
     exit(EXIT_FAILURE);
 } 
@@ -118,7 +119,7 @@
     LOGE(msg, a1, a2);
     if (SupressNonFatalErrors) return;
 
-    fprintf(stderr,"Nonfatal Error : ");
+    fprintf(stderr,"\nNonfatal Error : ");
     if (CurrentFile) fprintf(stderr,"'%s' ",CurrentFile);
     fprintf(stderr, msg, a1, a2);
     fprintf(stderr, "\n");
@@ -142,7 +143,7 @@
 {
     FILE * file;
     int a;
-    char QuotedPath[PATH_MAX];
+    char QuotedPath[PATH_MAX+10];
 
     file = fopen(TempFileName, "w");
     if (file == NULL){
@@ -156,8 +157,8 @@
     fflush(stdout); // So logs are contiguous.
 
     {
-    char * Editor;
-    Editor = getenv("EDITOR");
+        char * Editor;
+        Editor = getenv("EDITOR");
         if (Editor == NULL){
 #ifdef _WIN32
             Editor = "notepad";
@@ -165,11 +166,12 @@
             Editor = "vi";
 #endif
         }
+        if (strlen(Editor) > PATH_MAX) ErrFatal("env too long");
 
         sprintf(QuotedPath, "%s \"%s\"",Editor, TempFileName);
         a = system(QuotedPath);
     }
-    
+
     if (a != 0){
         perror("Editor failed to launch");
         exit(-1);
@@ -245,11 +247,11 @@
                                 // Overwrite old comment of same tag with new one.
                                 if (!memcmp(Line, AddComment, l+1)){
                                     TagExists = TRUE;
-                                    strcpy(Line, AddComment);
+                                    strncpy(Line, AddComment, sizeof(Line));
                                     Modified = TRUE;
                                 }
                             }
-                            strcat(OutComment, Line);
+                            strncat(OutComment, Line, MAX_COMMENT_SIZE-5-strlen(OutComment));
                             strcat(OutComment, "\n");
                             break;
                         }
@@ -264,7 +266,7 @@
     }
 
     if (AddComment && TagExists == FALSE){
-        strcat(OutComment, AddComment);
+        strncat(OutComment, AddComment, MAX_COMMENT_SIZE-5-strlen(OutComment));
         strcat(OutComment, "\n");
         Modified = TRUE;
     }
@@ -273,7 +275,7 @@
         // Scan date is not in the file yet, and it doesn't have one built in.  Add it.
         char Temp[30];
         sprintf(Temp, "scan_date=%s", ctime(&ImageInfo.FileDateTime));
-        strcat(OutComment, Temp);
+        strncat(OutComment, Temp, MAX_COMMENT_SIZE-5-strlen(OutComment));
         Modified = TRUE;
     }
     return Modified;
@@ -283,7 +285,7 @@
 //--------------------------------------------------------------------------
 static int AutoResizeCmdStuff(void)
 {
-    static char CommandString[500];
+    static char CommandString[PATH_MAX+1];
     double scale;
 
     ApplyCommand = CommandString;
@@ -307,37 +309,82 @@
 
 
 //--------------------------------------------------------------------------
+// Escape an argument such that it is interpreted literally by the shell
+// (returns the number of written characters)
+//--------------------------------------------------------------------------
+static int shellescape(char* to, const char* from)
+{
+    int i, j;
+    i = j = 0;
+
+    // Enclosing characters in double quotes preserves the literal value of
+    // all characters within the quotes, with the exception of $, `, and \.
+    to[j++] = '"';
+    while(from[i])
+    {
+#ifdef _WIN32
+        // Under WIN32, there isn't really anything dangerous you can do with 
+        // escape characters, plus windows users aren't as sercurity paranoid.
+        // Hence, no need to do fancy escaping.
+        to[j++] = from[i++];
+#else
+        switch(from[i]) {
+            case '"':
+            case '$':
+            case '`':
+            case '\\':
+                to[j++] = '\\';
+                // Fallthru...
+            default:
+                to[j++] = from[i++];
+        }
+#endif 
+        if (j >= PATH_MAX) ErrFatal("max path exceeded");
+    }
+    to[j++] = '"';
+    return j;
+}
+
+
+//--------------------------------------------------------------------------
 // Apply the specified command to the JPEG file.
 //--------------------------------------------------------------------------
 static void DoCommand(const char * FileName, int ShowIt)
 {
     int a,e;
-    char ExecString[400];
-    char TempName[200];
+    char ExecString[PATH_MAX*3];
+    char TempName[PATH_MAX+10];
     int TempUsed = FALSE;
 
     e = 0;
 
-    // Make a temporary file in the destination directory by changing last char.
-    strcpy(TempName, FileName);
-    a = strlen(TempName)-1;
-    TempName[a] = (char)(TempName[a] == 't' ? 'z' : 't');
+    // Generate an unused temporary file name in the destination directory
+    // (a is the number of characters to copy from FileName)
+    a = strlen(FileName)-1;
+    while(a > 0 && FileName[a-1] != SLASH) a--;
+    memcpy(TempName, FileName, a);
+    strcpy(TempName+a, "XXXXXX");
+    mktemp(TempName);
+    if(!TempName[0]) {
+        ErrFatal("Cannot find available temporary file name");
+    }
+
+
 
     // Build the exec string.  &i and &o in the exec string get replaced by input and output files.
     for (a=0;;a++){
         if (ApplyCommand[a] == '&'){
             if (ApplyCommand[a+1] == 'i'){
                 // Input file.
-                e += sprintf(ExecString+e, "\"%s\"",FileName);
+                e += shellescape(ExecString+e, FileName);
                 a += 1;
                 continue;
             }
             if (ApplyCommand[a+1] == 'o'){
                 // Needs an output file distinct from the input file.
-                e += sprintf(ExecString+e, "\"%s\"",TempName);
+                e += shellescape(ExecString+e, TempName);
                 a += 1;
                 TempUsed = TRUE;
-                unlink(TempName);// Remove any pre-existing temp file
                 continue;
             }
         }
@@ -421,7 +468,7 @@
         strncat(OutFileName, OrigName, PATH_MAX);
         strncat(OutFileName, Subst+2, PATH_MAX);
     }else{
-        strcpy(OutFileName, NamePattern); 
+        strncpy(OutFileName, NamePattern, PATH_MAX); 
     }
 }
 
@@ -435,8 +482,8 @@
     int a;
     int PathLen;
     int ExtPos;
-    char FilePattern[_MAX_PATH];
-    char NewName[_MAX_PATH];
+    char FilePattern[_MAX_PATH+1];
+    char NewName[_MAX_PATH+1];
     struct _finddata_t finddata;
     long find_handle;
 
@@ -448,7 +495,7 @@
     FilePattern[ExtPos] = '*';
     FilePattern[ExtPos+1] = '\0';
 
-    for(PathLen = strlen(FileName);FileName[PathLen-1] != '\\';){
+    for(PathLen = strlen(FileName);FileName[PathLen-1] != SLASH;){
         if (--PathLen == 0) break;
     }
 
@@ -462,13 +509,13 @@
         if (!memcmp(finddata.name, "..",3)) goto next_file;
         if (finddata.attrib & _A_SUBDIR) goto next_file;
 
-        strcpy(FilePattern+PathLen, finddata.name); // full name with path
+        strncpy(FilePattern+PathLen, finddata.name, PATH_MAX-PathLen); // full name with path
 
         strcpy(NewName, NewBaseName);
         for(a = strlen(finddata.name);finddata.name[a] != '.';){
             if (--a == 0) goto next_file;
         }
-        strcat(NewName, finddata.name+a); // add extension to new name
+        strncat(NewName, finddata.name+a, _MAX_PATH-strlen(NewName)); // add extension to new name
 
         if (rename(FilePattern, NewName) == 0){
             if (!Quiet){
@@ -490,14 +537,17 @@
 {
     int NumAlpha = 0;
     int NumDigit = 0;
-    int PrefixPart = 0;
-    int ExtensionPart = strlen(FileName);
+    int PrefixPart = 0; // Where the actual filename starts.
+    int ExtensionPart;  // Where the file extension starts.
     int a;
     struct tm tm;
     char NewBaseName[PATH_MAX*2];
+    int AddLetter = 0;
+    char NewName[PATH_MAX+2];
 
+    ExtensionPart = strlen(FileName);
     for (a=0;FileName[a];a++){
-        if (FileName[a] == '/' || FileName[a] == '\\'){
+        if (FileName[a] == SLASH){
             // Don't count path component.
             NumAlpha = 0;
             NumDigit = 0;
@@ -524,7 +574,7 @@
     }
     
 
-    strcpy(NewBaseName, FileName); // Get path component of name.
+    strncpy(NewBaseName, FileName, PATH_MAX); // Get path component of name.
 
     if (strftime_args){
         // Complicated scheme for flexibility.  Just pass the args to strftime.
@@ -559,14 +609,17 @@
                 }else if (pattern[a] == 'i'){
                     if (ppos >= 0 && a<ppos+4){
                         // Replace this part with a number.
-                        char pat[8];
-                        char num[16];
+                        char pat[8], num[16];
+                        int l,nl;
                         memcpy(pat, pattern+ppos, 4);
                         pat[a-ppos] = 'd'; // Replace 'i' with 'd' for '%d'
                         pat[a-ppos+1] = '\0';
                         sprintf(num, pat, FileSequence); // let printf do the number formatting.
-                        memmove(pattern+ppos+strlen(num), pattern+a+1, strlen(pattern+a+1)+1);
-                        memcpy(pattern+ppos, num, strlen(num));
+                        nl = strlen(num);
+                        l = strlen(pattern+a+1);
+                        if (ppos+nl+l+1 >= PATH_MAX) ErrFatal("str overflow");
+                        memmove(pattern+ppos+nl, pattern+a+1, l+1);
+                        memcpy(pattern+ppos, num, nl);
                         break;
                     }
                 }else if (!isdigit(pattern[a])){
@@ -574,16 +627,19 @@
                 }
             }
         }
-
-        strftime(NewBaseName+PrefixPart, PATH_MAX, pattern, &tm);
+        strftime(NewName, PATH_MAX, pattern, &tm);
     }else{
         // My favourite scheme.
-        sprintf(NewBaseName+PrefixPart, "%02d%02d-%02d%02d%02d",
+        sprintf(NewName, "%02d%02d-%02d%02d%02d",
              tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
     }
 
+    NewBaseName[PrefixPart] = 0;
+    CatPath(NewBaseName, NewName);
+
+    AddLetter = isdigit(NewBaseName[strlen(NewBaseName)-1]);
     for (a=0;;a++){
-        char NewName[PATH_MAX];
+        char NewName[PATH_MAX+10];
         char NameExtra[3];
         struct stat dummy;
 
@@ -593,10 +649,10 @@
             // it.  This to avoid using a separator character - this because any good separator
             // is before the '.' in ascii, and so sorting the names would put the later name before
             // the name without suffix, causing the pictures to more likely be out of order.
-            if (isdigit(NewBaseName[strlen(NewBaseName)-1])){
-                NameExtra[0] = (char)('a'-1+a); // Try a,b,c,d... for suffix if it ends in a letter.
+            if (AddLetter){
+                NameExtra[0] = (char)('a'-1+a); // Try a,b,c,d... for suffix if it ends in a number.
             }else{
-                NameExtra[0] = (char)('0'-1+a); // Try 1,2,3,4... for suffix if it ends in a char.
+                NameExtra[0] = (char)('0'-1+a); // Try 0,1,2,3... for suffix if it ends in a latter.
             }
             NameExtra[1] = 0;
         }else{
@@ -607,6 +663,11 @@
 
         if (!strcmp(FileName, NewName)) break; // Skip if its already this name.
 
+        if (!EnsurePathExists(NewBaseName)){
+            break;
+        }
+
+
         if (stat(NewName, &dummy)){
             // This name does not pre-exist.
             if (rename(FileName, NewName) == 0){
@@ -621,9 +682,10 @@
                 printf("Error: Couldn't rename '%s' to '%s'\n",FileName, NewName);
             }
             break;
+
         }
 
-        if (a >= 9){
+        if (a > 25 || (!AddLetter && a > 9)){
             printf("Possible new names for for '%s' already exist\n",FileName);
             break;
         }
@@ -645,7 +707,7 @@
                 ErrFatal("Orientation screwup");
             }
 
-            sprintf(RotateCommand, "jpegtran -%s -outfile &o &i", Argument);
+            sprintf(RotateCommand, "jpegtran -trim -%s -outfile &o &i", Argument);
             ApplyCommand = RotateCommand;
             DoCommand(FileName, FALSE);
             ApplyCommand = NULL;
@@ -656,15 +718,15 @@
                 ImageInfo.ThumbnailAtEnd){
                 // Must have a thumbnail that exists and is modifieable.
 
-                char ThumbTempName_in[PATH_MAX+4];
-                char ThumbTempName_out[PATH_MAX+4];
+                char ThumbTempName_in[PATH_MAX+5];
+                char ThumbTempName_out[PATH_MAX+5];
 
                 strcpy(ThumbTempName_in, FileName);
                 strcat(ThumbTempName_in, ".thi");
                 strcpy(ThumbTempName_out, FileName);
                 strcat(ThumbTempName_out, ".tho");
                 SaveThumbnail(ThumbTempName_in);
-                sprintf(RotateCommand,"jpegtran -%s -outfile \"%s\" \"%s\"",
+                sprintf(RotateCommand,"jpegtran -trim -%s -outfile \"%s\" \"%s\"",
                     Argument, ThumbTempName_out, ThumbTempName_in);
 
                 if (system(RotateCommand) == 0){
@@ -710,7 +772,14 @@
 void ProcessFile(const char * FileName)
 {
     int Modified = FALSE;
-    ReadMode_t ReadMode = READ_METADATA;
+    ReadMode_t ReadMode;
+
+    if (strlen(FileName) >= PATH_MAX-1){
+        // Protect against buffer overruns in strcpy / strcat's on filename
+        ErrFatal("filename too long");
+    }
+
+    ReadMode = READ_METADATA;
     CurrentFile = FileName;
     FilesMatched = 1; 
 
@@ -874,7 +943,7 @@
                    EditComment || CommentInsertfileName || CommentInsertLiteral){
 
         Section_t * CommentSec;
-        char Comment[1001];
+        char Comment[MAX_COMMENT_SIZE+1];
         int CommentSize;
 
         CommentSec = FindSection(M_COM);
@@ -890,9 +959,9 @@
         }
 
         CommentSize = CommentSec->Size-2;
-        if (CommentSize > 1000){
-            fprintf(stderr, "Truncating comment at 1000 chars\n");
-            CommentSize = 1000;
+        if (CommentSize > MAX_COMMENT_SIZE){
+            fprintf(stderr, "Truncating comment at %d chars\n",MAX_COMMENT_SIZE);
+            CommentSize = MAX_COMMENT_SIZE;
         }
 
         if (CommentInsertfileName){
@@ -914,11 +983,11 @@
                 if (CommentSize < 0) CommentSize = 0;
             }
         }else if (CommentInsertLiteral){
-            strncpy(Comment, CommentInsertLiteral, 1000);
+            strncpy(Comment, CommentInsertLiteral, MAX_COMMENT_SIZE);
             CommentSize = strlen(Comment);
         }else{
 #ifdef MATTHIAS
-            char CommentZt[1001];
+            char CommentZt[MAX_COMMENT_SIZE+1];
             memcpy(CommentZt, (char *)CommentSec->Data+2, CommentSize);
             CommentZt[CommentSize] = '\0';
             if (ModifyDescriptComment(Comment, CommentZt)){
@@ -930,7 +999,7 @@
             memcpy(Comment, (char *)CommentSec->Data+2, CommentSize);
 #endif
             {
-                char EditFileName[PATH_MAX+4];
+                char EditFileName[PATH_MAX+5];
                 strcpy(EditFileName, FileName);
                 strcat(EditFileName, ".txt");
 
@@ -1027,6 +1096,7 @@
                 Pointer = ExifSection->Data+ImageInfo.DateTimeOffsets[a]+8;
                 memcpy(Pointer, TempBuf, 19);
             }
+            memcpy(ImageInfo.DateTime, TempBuf, 19);
 
             Modified = TRUE;
         }else{
@@ -1043,13 +1113,16 @@
     if (DeleteIptc){
         if (RemoveSectionType(M_IPTC)) Modified = TRUE;
     }
+    if (DeleteXmp){
+        if (RemoveSectionType(M_XMP)) Modified = TRUE;
+    }
     if (DeleteUnknown){
         if (RemoveUnknownSections()) Modified = TRUE;
     }
 
 
     if (Modified){
-        char BackupName[400];
+        char BackupName[PATH_MAX+5];
         struct stat buf;
 
         if (!Quiet) printf("Modified: %s\n",FileName);
@@ -1133,7 +1206,7 @@
 static void Usage (void)
 {
     printf("Jhead is a program for manipulating settings and thumnails in Exif jpeg headers\n"
-           "used by most Digital Cameras.  v"JHEAD_VERSION" Matthias Wandel, April 29 2006.\n"
+           "used by most Digital Cameras.  v"JHEAD_VERSION" Matthias Wandel, Mar 02 2009.\n"
            "http://www.sentex.net/~mwandel/jhead\n"
            "\n");
 
@@ -1148,6 +1221,7 @@
            "  -dc        Delete comment field (as left by progs like Photoshop & Compupic)\n"
            "  -de        Strip Exif section (smaller JPEG file, but lose digicam info)\n"
            "  -di        Delete IPTC section (from Photoshop, or Picasa)\n"
+           "  -dx        Deletex XMP section\n"
            "  -du        Delete non image sections except for Exif and comment sections\n"
            "  -purejpg   Strip all unnecessary data from jpeg (combines -dc -de and -du)\n"
            "  -mkexif    Create new minimal exif section (overwrites pre-existing exif)\n"
@@ -1177,6 +1251,8 @@
            "             The '.jpg' is automatically added to the end of the name.  If the\n"
            "             destination name already exists, a letter or digit is added to \n"
            "             the end of the name to make it unique.\n"
+           "             The new name may include a path as part of the name.  If this path\n"
+           "             does not exist, it will be created\n"
            "  -nf[format-string]\n"
            "             Same as -n, but rename regardless of original name\n"
            "  -a         (Windows only) Rename files with same name but different extension\n"
@@ -1195,8 +1271,8 @@
            "             To deal with different months and years having different numbers of\n"
            "             days, a simple date-month-year offset would result in unexpected\n"
            "             results.  Instead, the difference is specified as desired date\n"
-           "             minus original date.  Date is specified as yyyy:mmm:dd or as date\n"
-           "             and time in the format yyyy:mmm:dd/hh:mm:ss\n"
+           "             minus original date.  Date is specified as yyyy:mm:dd or as date\n"
+           "             and time in the format yyyy:mm:dd/hh:mm:ss\n"
            "  -ts<time>  Set the Exif internal time to <time>.  <time> is in the format\n"
            "             yyyy:mm:dd-hh:mm:ss\n"
            "  -ds<date>  Set the Exif internal date.  <date> is in the format YYYY:MM:DD\n"
@@ -1340,6 +1416,9 @@
         }else if (!strcmp(arg,"-di")){
             DeleteIptc = TRUE;
             DoModify = TRUE;
+        }else if (!strcmp(arg,"-dx")){
+            DeleteXmp = TRUE;
+            DoModify = TRUE;
         }else if (!strcmp(arg, "-du")){
             DeleteUnknown = TRUE;
             DoModify = TRUE;
@@ -1348,6 +1427,7 @@
             DeleteComments = TRUE;
             DeleteIptc = TRUE;
             DeleteUnknown = TRUE;
+            DeleteXmp = TRUE;
             DoModify = TRUE;
         }else if (!strcmp(arg,"-ce")){
             EditComment = TRUE;
@@ -1422,13 +1502,17 @@
             if (*arg){
                 // A strftime format string is supplied.
                 strftime_args = arg;
+                #ifdef _WIN32
+                    SlashToNative(strftime_args);
+                #endif
                 //printf("strftime_args = %s\n",arg);
             }
         }else if (!strcmp(arg,"-a")){
-            RenameAssociatedFiles = TRUE;
             #ifndef _WIN32
                 ErrFatal("Error: -a only supported in Windows version");
-            #endif 
+            #else
+                RenameAssociatedFiles = TRUE;
+            #endif
         }else if (!strcmp(arg,"-ft")){
             Exif2FileTime = TRUE;
             DoReadAction = TRUE;
@@ -1588,13 +1672,7 @@
         FilesMatched = FALSE;
 
         #ifdef _WIN32
-            {
-                int a;
-                for (a=0;;a++){
-                    if (argv[argn][a] == '\0') break;
-                    if (argv[argn][a] == '/') argv[argn][a] = '\\';
-                }
-            }
+            SlashToNative(argv[argn]);
             // Use my globbing module to do fancier wildcard expansion with recursive
             // subdirectories under Windows.
             MyGlob(argv[argn], ProcessFile);
diff --git a/jhead.h b/jhead.h
index 2eca8b8..1540d94 100644
--- a/jhead.h
+++ b/jhead.h
@@ -35,12 +35,16 @@
     #define FALSE 0
 #endif
 
-#define MAX_COMMENT 2000
+#define MAX_COMMENT_SIZE 2000
 
 #ifdef _WIN32
     #define PATH_MAX _MAX_PATH
+    #define SLASH '\\'
+#else
+    #define SLASH '/'
 #endif
 
+
 //--------------------------------------------------------------------------
 // This structure is used to store jpeg file sections in memory.
 typedef struct {
@@ -85,7 +89,10 @@
     int   ExposureMode;
     int   ISOequivalent;
     int   LightSource;
-    char  Comments[MAX_COMMENT];
+    int   DistanceRange;
+
+    char  Comments[MAX_COMMENT_SIZE];
+    int   CommentWidchars; // If nonzer, widechar comment, indicates number of chars.
 
     unsigned ThumbnailOffset;          // Exif offset to thumbnail
     unsigned ThumbnailSize;            // Size of thumbnail.
@@ -191,10 +198,18 @@
 TagTable_t* GpsTagToTagTableEntry(unsigned short tag);
 
 // iptc.c prototpyes
-void    show_IPTC (unsigned char * CharBuf, unsigned int length);
+void show_IPTC (unsigned char * CharBuf, unsigned int length);
+void ShowXmp(Section_t XmpSection);
 
 // Prototypes for myglob.c module
-extern void MyGlob(const char * Pattern , void (*FileFuncParm)(const char * FileName));
+#ifdef _WIN32
+void MyGlob(const char * Pattern , void (*FileFuncParm)(const char * FileName));
+void SlashToNative(char * Path);
+#endif
+
+// Prototypes for paths.c module
+int EnsurePathExists(const char * FileName);
+void CatPath(char * BasePath, const char * FilePath);
 
 // Prototypes from jpgfile.c
 int ReadJpegSections (FILE * infile, ReadMode_t ReadMode);
@@ -221,11 +236,11 @@
 // in this program.  (See jdmarker.c for a more complete list.)
 //--------------------------------------------------------------------------
 
-#define M_SOF0  0xC0            // Start Of Frame N
-#define M_SOF1  0xC1            // N indicates which compression process
-#define M_SOF2  0xC2            // Only SOF0-SOF2 are now in common use
+#define M_SOF0  0xC0          // Start Of Frame N
+#define M_SOF1  0xC1          // N indicates which compression process
+#define M_SOF2  0xC2          // Only SOF0-SOF2 are now in common use
 #define M_SOF3  0xC3
-#define M_SOF5  0xC5            // NB: codes C4 and CC are NOT SOF markers
+#define M_SOF5  0xC5          // NB: codes C4 and CC are NOT SOF markers
 #define M_SOF6  0xC6
 #define M_SOF7  0xC7
 #define M_SOF9  0xC9
@@ -234,15 +249,16 @@
 #define M_SOF13 0xCD
 #define M_SOF14 0xCE
 #define M_SOF15 0xCF
-#define M_SOI   0xD8            // Start Of Image (beginning of datastream)
-#define M_EOI   0xD9            // End Of Image (end of datastream)
-#define M_SOS   0xDA            // Start Of Scan (begins compressed data)
-#define M_JFIF  0xE0            // Jfif marker
-#define M_EXIF  0xE1            // Exif marker
-#define M_COM   0xFE            // COMment 
+#define M_SOI   0xD8          // Start Of Image (beginning of datastream)
+#define M_EOI   0xD9          // End Of Image (end of datastream)
+#define M_SOS   0xDA          // Start Of Scan (begins compressed data)
+#define M_JFIF  0xE0          // Jfif marker
+#define M_EXIF  0xE1          // Exif marker.  Also used for XMP data!
+#define M_XMP   0x10E1        // Not a real tag (same value in file as Exif!)
+#define M_COM   0xFE          // COMment 
 #define M_DQT   0xDB
 #define M_DHT   0xC4
 #define M_DRI   0xDD
-#define M_IPTC  0xED            // IPTC marker
+#define M_IPTC  0xED          // IPTC marker
 
 
diff --git a/jpgfile.c b/jpgfile.c
index 6f5cf72..cf81039 100644
--- a/jpgfile.c
+++ b/jpgfile.c
@@ -45,13 +45,13 @@
 static void process_COM (const uchar * Data, int length)
 {
     int ch;
-    char Comment[MAX_COMMENT+1];
+    char Comment[MAX_COMMENT_SIZE+1];
     int nch;
     int a;
 
     nch = 0;
 
-    if (length > MAX_COMMENT) length = MAX_COMMENT; // Truncate if it won't fit in our structure.
+    if (length > MAX_COMMENT_SIZE) length = MAX_COMMENT_SIZE; // Truncate if it won't fit in our structure.
 
     for (a=2;a<length;a++){
         ch = Data[a];
@@ -72,6 +72,7 @@
     }
 
     strcpy(ImageInfo.Comments,Comment);
+    ImageInfo.CommentWidchars = 0;
 }
 
  
@@ -141,22 +142,16 @@
 
         CheckSectionsAllocated();
 
-        for (a=0;a<7;a++){
+        for (a=0;a<=16;a++){
             marker = fgetc(infile);
             if (marker != 0xff) break;
 
-            if (a >= 6){
+            if (a >= 16){
                 fprintf(stderr,"too many padding bytes\n");
                 return FALSE;
             }
         }
 
-        if (marker == 0xff){
-            // 0xff is legal padding, but if we get that many, something's wrong.
-            //ErrFatal("too many padding bytes!");
-            LOGE("too many padding bytes!");
-		    return FALSE;
-        }
 
         Sections[SectionsRead].Type = marker;
   
@@ -254,15 +249,24 @@
                 break;
 
             case M_EXIF:
-                // Seen files from some 'U-lead' software with Vivitar scanner
-                // that uses marker 31 for non exif stuff.  Thus make sure 
-                // it says 'Exif' in the section before treating it as exif.
-                if ((ReadMode & READ_METADATA) && memcmp(Data+2, "Exif", 4) == 0){
-                    process_EXIF(Data, itemlen);
-                }else{
-                    // Discard this section.
-                    free(Sections[--SectionsRead].Data);
+                // There can be different section using the same marker.
+                if (ReadMode & READ_METADATA){
+                    if (memcmp(Data+2, "Exif", 4) == 0){
+                        process_EXIF(Data, itemlen);
+                        break;
+                    }else if (memcmp(Data+2, "http:", 5) == 0){
+                        Sections[SectionsRead-1].Type = M_XMP; // Change tag for internal purposes.
+                        if (ShowTags){
+                            printf("Image cotains XMP section, %d bytes long\n", itemlen);
+                            if (ShowTags){
+                                ShowXmp(Sections[SectionsRead-1]);
+                            }
+                        }
+                        break;
+                    }
                 }
+                // Oterwise, discard this section.
+                free(Sections[--SectionsRead].Data);
                 break;
 
             case M_IPTC:
@@ -399,9 +403,14 @@
     uchar * ThumbnailPointer;
 
     if (ImageInfo.ThumbnailOffset == 0 || ImageInfo.ThumbnailAtEnd == FALSE){
+        if (ThumbFileName == NULL){
+            // Delete of nonexistent thumbnail (not even pointers present)
+            // No action, no error.
+            return FALSE;
+        }
+
         // Adding or removing of thumbnail is not possible - that would require rearranging
         // of the exif header, which is risky, and jhad doesn't know how to do.
-
         fprintf(stderr,"Image contains no thumbnail to replace - add is not possible\n");
 #ifdef SUPERDEBUG
         LOGE("Image contains no thumbnail to replace - add is not possible\n");
@@ -430,6 +439,10 @@
 	        return FALSE;
         }
     }else{
+        if (ImageInfo.ThumbnailSize == 0){
+             return FALSE;
+        }
+
         ThumbLen = 0;
         ThumbnailFile = NULL;
     }
@@ -469,15 +482,19 @@
     Section_t ExifKeeper;
     Section_t CommentKeeper;
     Section_t IptcKeeper;
+    Section_t XmpKeeper;
     int a;
 
     memset(&ExifKeeper, 0, sizeof(ExifKeeper));
     memset(&CommentKeeper, 0, sizeof(CommentKeeper));
     memset(&IptcKeeper, 0, sizeof(IptcKeeper));
+    memset(&XmpKeeper, 0, sizeof(IptcKeeper));
 
     for (a=0;a<SectionsRead;a++){
         if (Sections[a].Type == M_EXIF && ExifKeeper.Type == 0){
-            ExifKeeper = Sections[a];
+           ExifKeeper = Sections[a];
+        }else if (Sections[a].Type == M_XMP && XmpKeeper.Type == 0){
+           XmpKeeper = Sections[a];
         }else if (Sections[a].Type == M_COM && CommentKeeper.Type == 0){
             CommentKeeper = Sections[a];
         }else if (Sections[a].Type == M_IPTC && IptcKeeper.Type == 0){
@@ -499,6 +516,11 @@
         CheckSectionsAllocated();
         Sections[SectionsRead++] = IptcKeeper;
     }
+
+    if (XmpKeeper.Type){
+        CheckSectionsAllocated();
+        Sections[SectionsRead++] = XmpKeeper;
+    }
 }    
 
 //--------------------------------------------------------------------------
@@ -537,7 +559,7 @@
     // Write all the misc sections
     for (a=0;a<SectionsRead-1;a++){
         fputc(0xff,outfile);
-        fputc(Sections[a].Type, outfile);
+        fputc((unsigned char)Sections[a].Type, outfile);
         fwrite(Sections[a].Data, Sections[a].Size, 1, outfile);
     }
 
@@ -611,6 +633,7 @@
             case  M_SOS:
             case  M_JFIF:
             case  M_EXIF:
+            case  M_XMP:
             case  M_COM:
             case  M_DQT:
             case  M_DHT: