Ignore:
Timestamp:
2011-06-01T12:33:42+12:00 (13 years ago)
Author:
sjm84
Message:

Updating the ExifTool perl modules

File:
1 edited

Legend:

Unmodified
Added
Removed
  • main/trunk/greenstone2/perllib/cpan/Image/ExifTool/WriteExif.pl

    r16842 r24107  
    1111use strict;
    1212use vars qw($VERSION $AUTOLOAD @formatSize @formatName %formatNumber
    13             %lightSource %compression %photometricInterpretation %orientation);
     13            %compression %photometricInterpretation %orientation);
    1414
    1515use Image::ExifTool::Fixup;
     
    3030        0x011a => 72,       # XResolution
    3131        0x011b => 72,       # YResolution
    32         0x0128 => 2,        # Resolution unit (inches)
     32        0x0128 => 2,        # ResolutionUnit (inches)
    3333        0x0213 => 1,        # YCbCrPositioning (centered)
    3434      # 0x8769 => ????,     # ExifOffset
     
    3838        0x011a => 72,       # XResolution
    3939        0x011b => 72,       # YResolution
    40         0x0128 => 2,        # Resolution unit (inches)
     40        0x0128 => 2,        # ResolutionUnit (inches)
    4141    },
    4242    ExifIFD => {
    43         0x9000 => '0220',   # ExifVersion
    44         0x9101 => "\1\2\3\0", # ComponentsConfiguration
     43        0x9000 => '0230',   # ExifVersion
     44        0x9101 => "1 2 3 0",# ComponentsConfiguration
    4545        0xa000 => '0100',   # FlashpixVersion
    4646        0xa001 => 0xffff,   # ColorSpace (uncalibrated)
    4747      # 0xa002 => ????,     # ExifImageWidth
    48       # 0xa003 => ????,     # ExifImageLength
     48      # 0xa003 => ????,     # ExifImageHeight
    4949    },
    5050    GPS => {
    51         0x0000 => '2 2 0 0',# GPSVersionID
     51        0x0000 => '2 3 0 0',# GPSVersionID
    5252    },
    5353    InteropIFD => {
     
    7272        Protected => 1,
    7373        Writable => 'undef',
     74        Mandatory => 1,
    7475        WriteGroup => 'InteropIFD',
    7576    },
     
    9394        WriteGroup => 'IFD0',
    9495    },
    95     0x0101 => {             # ImageHeigth
     96    0x0101 => {             # ImageHeight
    9697        Protected => 1,
    9798        Writable => 'int32u',
     
    108109        Writable => 'int16u',
    109110        WriteGroup => 'IFD0',
     111        Mandatory => 1,
    110112    },
    111113    0x0106 => {             # PhotometricInterpretation
     
    175177        Writable => 'rational64u',
    176178        WriteGroup => 'IFD0',
     179        Mandatory => 1,
    177180    },
    178181    0x011b => {             # YResolution
    179182        Writable => 'rational64u',
    180183        WriteGroup => 'IFD0',
     184        Mandatory => 1,
    181185    },
    182186    0x011c => {             # PlanarConfiguration
     
    204208        Writable => 'int16u',
    205209        WriteGroup => 'IFD0',
     210        Mandatory => 1,
    206211    },
    207212    0x0129 => {             # PageNumber
     
    210215        Count => 2,
    211216    },
     217    0x012d => {             # TransferFunction
     218        Protected => 1,
     219        Writable => 'int16u',
     220        WriteGroup => 'IFD0',
     221        Count => 768,
     222    },
    212223    0x0131 => {             # Software
    213224        Writable => 'string',
     
    218229        Shift => 'Time',
    219230        WriteGroup => 'IFD0',
    220         PrintConvInv => 'Image::ExifTool::Exif::ExifDateTime($val)',
     231        PrintConvInv => '$self->InverseDateTime($val,0)',
    221232    },
    222233    0x013b => {             # Artist
     
    286297        Writable => 'int16u',
    287298        WriteGroup => 'IFD0',
     299        Mandatory => 1,
    288300    },
    289301    0x0214 => {             # ReferenceBlackWhite
     
    302314        WriteGroup => 'InteropIFD',
    303315    },
    304     0x1002 => {             # RelatedImageLength (is really the height)
     316    0x1002 => {             # RelatedImageHeight (more commonly RelatedImageLength)
    305317        Protected => 1,
    306318        Writable => 'int16u',
     
    320332        Writable => 'string',
    321333        WriteGroup => 'IFD0',
     334        RawConvInv => q{
     335            if ($val =~ /(.*?)\s*[\n\r]+\s*(.*)/s) {
     336                return $1 . "\0" unless length $2;
     337                # photographer copyright set to ' ' if it doesn't exist, according to spec.
     338                return((length($1) ? $1 : ' ') . "\0" . $2 . "\0");
     339            }
     340            return $val . "\0";
     341        },
    322342    },
    323343#
     
    326346    0x829a => {             # ExposureTime
    327347        Writable => 'rational64u',
    328         PrintConvInv => 'eval $val',
     348        PrintConvInv => 'Image::ExifTool::Exif::ConvertFraction($val)',
    329349    },
    330350    0x829d => {             # FNumber
     
    332352        PrintConvInv => '$val',
    333353    },
    334     0x83bb => {             # IPTC-NAA
    335         # this should actually be written as 'undef' (see
    336         # http://www.awaresystems.be/imaging/tiff/tifftags/iptc.html),
    337         # but Photoshop writes it as int32u and Nikon Capture won't read
    338         # anything else, so we do the same thing here...  Doh!
    339         Format => 'undef',      # convert binary values as undef
    340         Writable => 'int32u',   # but write int32u format code in IFD
    341         WriteGroup => 'IFD0',
    342     },
    343354    0x8546 => {             # SEMInfo
    344355        Writable => 'string',
     
    347358    0x8822 => 'int16u',     # ExposureProgram
    348359    0x8824 => 'string',     # SpectralSensitivity
    349     0x8827 => 'int16u',     # ISO
     360    0x8827 => {             # ISO
     361        Writable => 'int16u',
     362        Count => -1,
     363        PrintConvInv => '$val=~tr/,//d; $val',
     364    },
    350365    0x882a => {             # TimeZoneOffset
    351366        Writable => 'int16s',
     
    357372    },
    358373    0x882b => 'int16u',     # SelfTimerMode
    359     0x9000 => 'undef',      # ExifVersion
     374    0x8830 => 'int16u',     # SensitivityType
     375    0x8831 => 'int32u',     # StandardOutputSensitivity
     376    0x8832 => 'int32u',     # RecommendedExposureIndex
     377    0x8833 => 'int32u',     # ISOSpeed
     378    0x8834 => 'int32u',     # ISOSpeedLatitudeyyy
     379    0x8835 => 'int32u',     # ISOSpeedLatitudezzz
     380    0x9000 => {             # ExifVersion
     381        Writable => 'undef',
     382        Mandatory => 1,
     383    },
    360384    0x9003 => {             # DateTimeOriginal
    361385        Writable => 'string',
    362386        Shift => 'Time',
    363         PrintConvInv => 'Image::ExifTool::Exif::ExifDateTime($val)',
     387        PrintConvInv => '$self->InverseDateTime($val,0)',
    364388    },
    365389    0x9004 => {             # CreateDate
    366390        Writable => 'string',
    367391        Shift => 'Time',
    368         PrintConvInv => 'Image::ExifTool::Exif::ExifDateTime($val)',
     392        PrintConvInv => '$self->InverseDateTime($val,0)',
    369393    },
    370394    0x9101 => {             # ComponentsConfiguration
     395        Protected => 1,
    371396        Writable => 'undef',
    372         PrintConv => '$_=$val;s/\0.*//s;tr/\x01-\x06/YXWRGB/;s/X/Cb/g;s/W/Cr/g;$_',
    373         PrintConvInv => q{
    374             $_=uc($val); s/CR/W/g; s/CB/X/g;
    375             return undef if /[^YXWRGB]/;
    376             tr/YXWRGB/\x01-\x06/;
    377             return $_ . "\0";
    378         },
    379     },
    380     0x9102 => 'rational64u',# CompressedBitsPerPixel
     397        Count => 4,
     398        Mandatory => 1,
     399        ValueConvInv => '$val=~tr/,//d; $val',  # (so we can copy from XMP with -n)
     400    },
     401    0x9102 => {             # CompressedBitsPerPixel
     402        Protected => 1,
     403        Writable => 'rational64u',
     404    },
    381405    0x9201 => {             # ShutterSpeedValue
    382406        Writable => 'rational64s',
    383407        ValueConvInv => '$val>0 ? -log($val)/log(2) : -100',
    384408        # do eval to convert things like '1/100'
    385         PrintConvInv => 'eval $val',
     409        PrintConvInv => 'Image::ExifTool::Exif::ConvertFraction($val)',
    386410    },
    387411    0x9202 => {             # ApertureValue
     
    394418        Writable => 'rational64s',
    395419        # do eval to convert things like '+2/3'
    396         PrintConvInv => 'eval $val',
     420        PrintConvInv => 'Image::ExifTool::Exif::ConvertFraction($val)',
    397421    },
    398422    0x9205 => {             # MaxApertureValue
     
    415439    0x9212 => 'string',     # SecurityClassification
    416440    0x9213 => 'string',     # ImageHistory
    417     0x9214 => {             # SubjectLocation
    418         Writable => 'int16u',
    419         Count => 4,  # write this SubjectLocation with 4 and the other with 2 values
     441    0x9214 => {             # SubjectArea
     442        Writable => 'int16u',
     443        Count => -1, # 2, 3 or 4 values
    420444    },
    421445#    0x927c => 'undef',      # MakerNotes
    422     0x9286 => {             # UserComment (string that starts with "ASCII\0\0\0")
     446    0x9286 => {             # UserComment
    423447        Writable => 'undef',
    424         PrintConvInv => 'Image::ExifTool::Exif::EncodeExifText($self,$val)',
    425     },
    426     0x9290 => 'string',     # SubSecTime
    427     0x9291 => 'string',     # SubSecTimeOriginal
    428     0x9292 => 'string',     # SubSecTimeDigitized
     448        #  (starts with "ASCII\0\0\0", "UNICODE\0", "JIS\0\0\0\0\0" or "\0\0\0\0\0\0\0\0")
     449        RawConvInv => 'Image::ExifTool::Exif::EncodeExifText($self,$val)',
     450        # SHOULD ADD SPECIAL LOGIC TO ALLOW CONDITIONAL OVERWRITE OF
     451        # "UNKNOWN" VALUES FILLED WITH SPACES
     452    },
     453    0x9290 => {             # SubSecTime
     454        Writable => 'string',
     455        # extract fractional seconds from a full date/time value
     456        ValueConvInv => '$val=~/^(\d+)\s*$/ ? $1 : ($val=~/\.(\d+)/ ? $1 : undef)',
     457    },
     458    0x9291 => {             # SubSecTimeOriginal
     459        Writable => 'string',
     460        ValueConvInv => '$val=~/^(\d+)\s*$/ ? $1 : ($val=~/\.(\d+)/ ? $1 : undef)',
     461    },
     462    0x9292 => {             # SubSecTimeDigitized
     463        Writable => 'string',
     464        ValueConvInv => '$val=~/^(\d+)\s*$/ ? $1 : ($val=~/\.(\d+)/ ? $1 : undef)',
     465    },
    429466    0x935c => {             # ImageSourceData
    430467        Writable => 'undef',
    431468        WriteGroup => 'IFD0',
     469        Protected => 1,
    432470    },
    433471#    0x9928 => 'undef',      # Opto-ElectricConversionFactor
     
    438476            tags 0x9c9b-0x9c9f are used by Windows Explorer; special characters
    439477            in these values are converted to UTF-8 by default, or Windows Latin1
    440             with the -L option. XPTitle is ignored by Windows Explorer if
     478            with the -L option.  XPTitle is ignored by Windows Explorer if
    441479            ImageDescription exists
    442480        },
    443         ValueConvInv => '$self->Charset2Unicode($val,"II") . "\0\0"',
     481        ValueConvInv => '$self->Encode($val,"UCS2","II") . "\0\0"',
    444482    },
    445483    0x9c9c => {             # XPComment
    446484        Writable => 'int8u',
    447485        WriteGroup => 'IFD0',
    448         ValueConvInv => '$self->Charset2Unicode($val,"II") . "\0\0"',
     486        ValueConvInv => '$self->Encode($val,"UCS2","II") . "\0\0"',
    449487    },
    450488    0x9c9d => {             # XPAuthor
     
    452490        WriteGroup => 'IFD0',
    453491        Notes => 'ignored by Windows Explorer if Artist exists',
    454         ValueConvInv => '$self->Charset2Unicode($val,"II") . "\0\0"',
     492        ValueConvInv => '$self->Encode($val,"UCS2","II") . "\0\0"',
    455493    },
    456494    0x9c9e => {             # XPKeywords
    457495        Writable => 'int8u',
    458496        WriteGroup => 'IFD0',
    459         ValueConvInv => '$self->Charset2Unicode($val,"II") . "\0\0"',
     497        ValueConvInv => '$self->Encode($val,"UCS2","II") . "\0\0"',
    460498    },
    461499    0x9c9f => {             # XPSubject
    462500        Writable => 'int8u',
    463501        WriteGroup => 'IFD0',
    464         ValueConvInv => '$self->Charset2Unicode($val,"II") . "\0\0"',
    465     },
    466     0xa000 => 'undef',      # FlashpixVersion
    467     0xa001 => 'int16u',     # ColorSpace
    468     0xa002 => 'int16u',     # ExifImageWidth (could also be int32u)
    469     0xa003 => 'int16u',     # ExifImageLength (could also be int32u)
     502        ValueConvInv => '$self->Encode($val,"UCS2","II") . "\0\0"',
     503    },
     504    0xa000 => {             # FlashpixVersion
     505        Writable => 'undef',
     506        Mandatory => 1,
     507    },
     508    0xa001 => {             # ColorSpace
     509        Writable => 'int16u',
     510        Mandatory => 1,
     511    },
     512    0xa002 => {             # ExifImageWidth (could also be int32u)
     513        Writable => 'int16u',
     514        Mandatory => 1,
     515    },
     516    0xa003 => {             # ExifImageHeight (could also be int32u)
     517        Writable => 'int16u',
     518        Mandatory => 1,
     519    },
    470520    0xa004 => 'string',     # RelatedSoundFile
    471521    0xa20b => {             # FlashEnergy
     
    485535    0xa300 => {             # FileSource
    486536        Writable => 'undef',
    487         ValueConvInv => 'chr($val)',
    488         PrintConvInv => 3,
     537        ValueConvInv => '($val=~/^\d+$/ and $val < 256) ? chr($val) : $val',
    489538    },
    490539    0xa301 => {             # SceneType
     
    521570    0xa40c => 'int16u',     # SubjectDistanceRange
    522571    0xa420 => 'string',     # ImageUniqueID
     572    0xa430 => 'string',     # OwnerName
     573    0xa431 => 'string',     # SerialNumber
     574    0xa432 => {             # LensInfo
     575        Writable => 'rational64u',
     576        Count => 4,
     577        PrintConvInv => \&ConvertLensInfo,
     578    },
     579    0xa433 => 'string',     # LensMake
     580    0xa434 => 'string',     # LensModel
     581    0xa435 => 'string',     # LensSerialNumber
    523582    0xa500 => 'rational64u',# Gamma
    524     0xc4a5 => {             # PrintIM
    525         Writable => 'undef',
    526         WriteGroup => 'IFD0',
    527     },
    528583#
    529584# DNG stuff (back in IFD0)
     
    533588        WriteGroup => 'IFD0',
    534589        Count => 4,
     590        Protected => 1, # (confuses Apple Preview if written to a TIFF image)
     591        PrintConvInv => '$val =~ tr/./ /; $val',
    535592    },
    536593    0xc613 => {             # DNGBackwardVersion
     
    538595        WriteGroup => 'IFD0',
    539596        Count => 4,
     597        Protected => 1,
    540598    },
    541599    0xc614 => {             # UniqueCameraModel
     
    547605        WriteGroup => 'IFD0',
    548606        PrintConvInv => '$val',
     607    },
     608    0xc619 => {             # BlackLevelRepeatDim
     609        Writable => 'int16u',
     610        WriteGroup => 'SubIFD',
     611        Count => 2,
     612        Protected => 1,
     613    },
     614    0xc61a => {             # BlackLevel
     615        Writable => 'rational64u',
     616        WriteGroup => 'SubIFD',
     617        Count => -1,
     618        Protected => 1,
     619    },
     620    0xc61d => {             # WhiteLevel
     621        Writable => 'int32u',
     622        WriteGroup => 'SubIFD',
     623        Count => -1,
     624        Protected => 1,
    549625    },
    550626    0xc61e => {             # DefaultScale
     
    552628        WriteGroup => 'SubIFD',
    553629        Count => 2,
     630        Protected => 1,
    554631    },
    555632    0xc61f => {             # DefaultCropOrigin
     
    557634        WriteGroup => 'SubIFD',
    558635        Count => 2,
     636        Protected => 1,
    559637    },
    560638    0xc620 => {             # DefaultCropSize
     
    562640        WriteGroup => 'SubIFD',
    563641        Count => 2,
     642        Protected => 1,
     643    },
     644    0xc621 => {             # ColorMatrix1
     645        Writable => 'rational64s',
     646        Count => -1,
     647        WriteGroup => 'IFD0',
     648        Protected => 1,
     649    },
     650    0xc622 => {             # ColorMatrix2
     651        Writable => 'rational64s',
     652        Count => -1,
     653        WriteGroup => 'IFD0',
     654        Protected => 1,
     655    },
     656    0xc623 => {             # CameraCalibration1
     657        Writable => 'rational64s',
     658        Count => -1,
     659        WriteGroup => 'IFD0',
     660        Protected => 1,
     661    },
     662    0xc624 => {             # CameraCalibration2
     663        Writable => 'rational64s',
     664        Count => -1,
     665        WriteGroup => 'IFD0',
     666        Protected => 1,
     667    },
     668    0xc625 => {             # ReductionMatrix1
     669        Writable => 'rational64s',
     670        Count => -1,
     671        WriteGroup => 'IFD0',
     672        Protected => 1,
     673    },
     674    0xc626 => {             # ReductionMatrix2
     675        Writable => 'rational64s',
     676        Count => -1,
     677        WriteGroup => 'IFD0',
     678        Protected => 1,
     679    },
     680    0xc627 => {             # AnalogBalance
     681        Writable => 'rational64u',
     682        Count => -1,
     683        WriteGroup => 'IFD0',
     684        Protected => 1,
     685    },
     686    0xc628 => {             # AsShotNeutral
     687        Writable => 'rational64u',
     688        WriteGroup => 'IFD0',
     689        Count => -1,
     690        Protected => 1,
    564691    },
    565692    0xc629 => {             # AsShotWhiteXY
     
    567694        WriteGroup => 'IFD0',
    568695        Count => 2,
     696        Protected => 1,
    569697    },
    570698    0xc62a => {             # BaselineExposure
    571699        Writable => 'rational64s',
    572700        WriteGroup => 'IFD0',
     701        Protected => 1,
    573702    },
    574703    0xc62b => {             # BaselineNoise
    575704        Writable => 'rational64u',
    576705        WriteGroup => 'IFD0',
     706        Protected => 1,
    577707    },
    578708    0xc62c => {             # BaselineSharpness
    579709        Writable => 'rational64u',
    580710        WriteGroup => 'IFD0',
     711        Protected => 1,
    581712    },
    582713    0xc62d => {             # BayerGreenSplit
    583714        Writable => 'int32u',
    584715        WriteGroup => 'SubIFD',
     716        Protected => 1,
    585717    },
    586718    0xc62e => {             # LinearResponseLimit
    587719        Writable => 'rational64u',
    588720        WriteGroup => 'IFD0',
     721        Protected => 1,
    589722    },
    590723    0xc62f => {             # CameraSerialNumber
     
    596729        WriteGroup => 'IFD0',
    597730        Count => 4,
    598         PrintConvInv => '$_=$val;s/(-|mm f)/ /g;$_',
     731        PrintConvInv => \&ConvertLensInfo,
    599732    },
    600733    0xc631 => {             # ChromaBlurRadius
    601734        Writable => 'rational64u',
    602735        WriteGroup => 'SubIFD',
     736        Protected => 1,
    603737    },
    604738    0xc632 => {             # AntiAliasStrength
    605739        Writable => 'rational64u',
    606740        WriteGroup => 'SubIFD',
     741        Protected => 1,
    607742    },
    608743    0xc633 => {             # ShadowScale
    609744        Writable => 'rational64u',
    610745        WriteGroup => 'IFD0',
     746        Protected => 1,
    611747    },
    612748    0xc635 => {             # MakerNoteSafety
     
    617753        Writable => 'int16u',
    618754        WriteGroup => 'IFD0',
     755        Protected => 1,
    619756    },
    620757    0xc65b => {             # CalibrationIlluminant2
    621758        Writable => 'int16u',
    622759        WriteGroup => 'IFD0',
     760        Protected => 1,
    623761    },
    624762    0xc65c => {             # BestQualityScale
    625763        Writable => 'rational64u',
    626764        WriteGroup => 'SubIFD',
     765        Protected => 1,
    627766    },
    628767    0xc65d => {             # RawDataUniqueID
     
    630769        WriteGroup => 'IFD0',
    631770        Count => 16,
    632         ValueConvInv => 'pack("H*",$val)',
     771        ValueConvInv => 'pack("H*", $val)',
     772        Protected => 1,
    633773    },
    634774    0xc68b => {             # OriginalRawFileName
    635775        Writable => 'string',
    636776        WriteGroup => 'IFD0',
    637     },
    638     0xc68c => {             # OriginalRawFileData (a writable directory)
    639         Writable => 'undef',
    640         WriteGroup => 'IFD0',
     777        Protected => 1,
    641778    },
    642779    0xc68d => {             # ActiveArea
     
    644781        WriteGroup => 'SubIFD',
    645782        Count => 4,
     783        Protected => 1,
    646784    },
    647785    0xc68e => {             # MaskedAreas
     
    649787        WriteGroup => 'SubIFD',
    650788        Count => 4,
    651     },
    652     0xc68f => {             # AsShotICCProfile
    653         Writable => 'undef',
     789        Protected => 1,
     790    },
     791    0xc68f => {             # AsShotICCProfile (writable directory)
    654792        WriteGroup => 'IFD0',
    655793        Protected => 1,
     
    665803        Protected => 1,
    666804    },
    667     0xc691 => {             # CurrentICCProfile
     805    0xc691 => {             # CurrentICCProfile (writable directory)
    668806        Writable => 'undef',
    669807        WriteGroup => 'IFD0',
     
    676814    0xc692 => {             # CurrentPreProfileMatrix
    677815        Writable => 'rational64s',
     816        Count => -1,
     817        WriteGroup => 'IFD0',
     818        Protected => 1,
     819    },
     820    0xc6bf => {             # ColorimetricReference
     821        Writable => 'int16u',
     822        WriteGroup => 'IFD0',
     823        Protected => 1,
     824    },
     825    0xc6d2 => {             # PanasonicTitle (Panasonic DMC-TZ5, not a DNG tag)
     826        Writable => 'undef',
     827        WriteGroup => 'IFD0',
     828        ValueConvInv => '$self->Encode($val,"UTF8")',
     829    },
     830    0xc6d3 => {             # PanasonicTitle2 (Panasonic DMC-FS7, not a DNG tag)
     831        Writable => 'undef',
     832        WriteGroup => 'IFD0',
     833        ValueConvInv => '$self->Encode($val,"UTF8")',
     834    },
     835    0xc6f3 => {             # CameraCalibrationSig
     836        Writable => 'string',
     837        WriteGroup => 'IFD0',
     838        Protected => 1,
     839    },
     840    0xc6f4 => {             # ProfileCalibrationSig
     841        Writable => 'string',
     842        WriteGroup => 'IFD0',
     843        Protected => 1,
     844    },
     845    0xc6f6 => {             # AsShotProfileName
     846        Writable => 'string',
     847        WriteGroup => 'IFD0',
     848        Protected => 1,
     849    },
     850    0xc6f7 => {             # NoiseReductionApplied
     851        Writable => 'rational64u',
     852        WriteGroup => 'SubIFD',
     853        Protected => 1,
     854    },
     855    0xc6f8 => {             # ProfileName
     856        Writable => 'string',
     857        WriteGroup => 'IFD0',
     858        Protected => 1,
     859    },
     860    0xc6f9 => {             # ProfileHueSatMapDims
     861        Writable => 'int32u',
     862        Count => 3,
     863        WriteGroup => 'IFD0',
     864        Protected => 1,
     865    },
     866    0xc6fa => {             # ProfileHueSatMapData1
     867        Writable => 'float',
     868        Count => -1,
     869        WriteGroup => 'IFD0',
     870        Protected => 1,
     871    },
     872    0xc6fb => {             # ProfileHueSatMapData2
     873        Writable => 'float',
     874        Count => -1,
     875        WriteGroup => 'IFD0',
     876        Protected => 1,
     877    },
     878    0xc6fc => {             # ProfileToneCurve
     879        Writable => 'float',
     880        Count => -1,
     881        WriteGroup => 'IFD0',
     882        Protected => 1,
     883    },
     884    0xc6fd => {             # ProfileEmbedPolicy
     885        Writable => 'int32u',
     886        WriteGroup => 'IFD0',
     887        Protected => 1,
     888    },
     889    0xc6fe => {             # ProfileCopyright
     890        Writable => 'string',
     891        WriteGroup => 'IFD0',
     892        Protected => 1,
     893    },
     894    0xc714 => {             # ForwardMatrix1
     895        Writable => 'rational64s',
     896        Count => -1,
     897        WriteGroup => 'IFD0',
     898        Protected => 1,
     899    },
     900    0xc715 => {             # ForwardMatrix2
     901        Writable => 'rational64s',
     902        Count => -1,
     903        WriteGroup => 'IFD0',
     904        Protected => 1,
     905    },
     906    0xc716 => {             # PreviewApplicationName
     907        Writable => 'string',
     908        WriteGroup => 'IFD0',
     909        Protected => 1,
     910    },
     911    0xc717 => {             # PreviewApplicationVersion
     912        Writable => 'string',
     913        WriteGroup => 'IFD0',
     914        Protected => 1,
     915    },
     916    0xc718 => {             # PreviewSettingsName
     917        Writable => 'string',
     918        WriteGroup => 'IFD0',
     919        Protected => 1,
     920    },
     921    0xc719 => {             # PreviewSettingsDigest
     922        Writable => 'int8u',
     923        WriteGroup => 'IFD0',
     924        Protected => 1,
     925        ValueConvInv => 'pack("H*", $val)',
     926    },
     927    0xc71a => {             # PreviewColorSpace
     928        Writable => 'int32u',
     929        WriteGroup => 'IFD0',
     930        Protected => 1,
     931        PrintConv => {
     932            0 => 'Unknown',
     933            1 => 'Gray Gamma 2.2',
     934            2 => 'sRGB',
     935            3 => 'Adobe RGB',
     936            4 => 'ProPhoto RGB',
     937        },
     938    },
     939    0xc71b => {             # PreviewDateTime
     940        Writable => 'string',
     941        WriteGroup => 'IFD0',
     942        Protected => 1,
     943        ValueConvInv => q{
     944            require Image::ExifTool::XMP;
     945            return Image::ExifTool::XMP::FormatXMPDate($val);
     946        },
     947        PrintConvInv => '$self->InverseDateTime($val,1,1)',
     948    },
     949    0xc71c => {             # RawImageDigest
     950        Writable => 'int8u',
     951        WriteGroup => 'IFD0',
     952        Protected => 1,
     953        ValueConvInv => 'pack("H*", $val)',
     954    },
     955    0xc71d => {             # OriginalRawFileDigest
     956        Writable => 'int8u',
     957        WriteGroup => 'IFD0',
     958        Protected => 1,
     959        ValueConvInv => 'pack("H*", $val)',
     960    },
     961    0xc725 => {             # ProfileLookTableDims
     962        Writable => 'int32u',
     963        Count => 3,
     964        WriteGroup => 'IFD0',
     965        Protected => 1,
     966    },
     967    0xc726 => {             # ProfileLookTableData
     968        Writable => 'float',
    678969        Count => -1,
    679970        WriteGroup => 'IFD0',
     
    692983        ValueConvInv => q{"Owner's Name: $val"},
    693984        Notes => q{
    694             tags 0xfde8-0xfe58 are generated by Photoshop Camera RAW -- some
    695             names are the same as other EXIF tags, but ExifTool will avoid
    696             writing these unless they already exist in the file
     985            tags 0xfde8-0xfdea and 0xfe4c-0xfe58 are generated by Photoshop Camera RAW.
     986            Some names are the same as other EXIF tags, but ExifTool will avoid writing
     987            these unless they already exist in the file
    697988        },
    698989    },
     
    7911082
    7921083# insert our writable properties into main EXIF tag table
    793 InsertWritableProperties('Image::ExifTool::Exif::Main', \%writeTable, \&CheckExif);
     1084InsertWritableProperties(\%Image::ExifTool::Exif::Main, \%writeTable, \&CheckExif);
    7941085
    7951086#------------------------------------------------------------------------------
    796 # Change date/time string to standard EXIF formatting
    797 # Inputs: 0) Date/Time string
    798 # Returns: formatted date/time string (or undef and issues warning on error)
    799 sub ExifDateTime($)
     1087# Inverse print conversion for LensInfo
     1088# Inputs: 0) lens info string
     1089# Returns: PrintConvInv of string
     1090sub ConvertLensInfo($)
    8001091{
    8011092    my $val = shift;
    802     my $rtnVal;
    803     if ($val =~ /(\d{4})/g) {           # get YYYY
    804         my $yr = $1;
    805         my @a = ($val =~ /\d{2}/g);     # get MM, DD, and maybe hh, mm, ss
    806         if (@a >= 2) {
    807             push @a, '00' while @a < 5; # add hh, mm, ss if not given
    808             # construct properly formatted date/time string
    809             $rtnVal = "$yr:$a[0]:$a[1] $a[2]:$a[3]:$a[4]";
    810         }
    811     }
    812     $rtnVal or warn "Improperly formatted date/time\n";
    813     return $rtnVal;
     1093    my @a = GetLensInfo($val, 1); # (allow unknown "?" values)
     1094    return @a ? join(' ', @a) : $val;
    8141095}
    8151096
     
    8441125#------------------------------------------------------------------------------
    8451126# validate raw values for writing
    846 # Inputs: 0) ExifTool object reference, 1) tagInfo hash reference,
    847 #         2) raw value reference
     1127# Inputs: 0) ExifTool ref, 1) tagInfo hash ref, 2) raw value ref
    8481128# Returns: error string or undef (and possibly changes value) on success
    8491129sub CheckExif($$$)
    8501130{
    8511131    my ($exifTool, $tagInfo, $valPtr) = @_;
    852     my $format = $$tagInfo{Format} || $$tagInfo{Writable} || $tagInfo->{Table}->{WRITABLE};
     1132    my $format = $$tagInfo{Format} || $$tagInfo{Writable} || $tagInfo->{Table}{WRITABLE};
    8531133    if (not $format or $format eq '1') {
    854         if ($tagInfo->{Groups}->{0} eq 'MakerNotes') {
     1134        if ($tagInfo->{Groups}{0} eq 'MakerNotes') {
    8551135            return undef;   # OK to have no format for makernotes
    8561136        } else {
     
    8651145# Inputs: 0) ExifTool ref, 1) text string
    8661146# Returns: encoded string
     1147# Note: MUST be called Raw conversion time so the EXIF byte order is known!
    8671148sub EncodeExifText($$)
    8681149{
     
    8701151    # does the string contain special characters?
    8711152    if ($val =~ /[\x80-\xff]/) {
    872         return "UNICODE\0" . $exifTool->Charset2Unicode($val);
     1153        my $order = $exifTool->GetNewValues('ExifUnicodeByteOrder');
     1154        return "UNICODE\0" . $exifTool->Encode($val,'UCS2',$order);
    8731155    } else {
    8741156        return "ASCII\0\0\0$val";
     
    8781160#------------------------------------------------------------------------------
    8791161# insert writable properties into main tag table
    880 # Inputs: 0) tag table name, 1) reference to writable properties
     1162# Inputs: 0) tag table ref, 1) reference to writable properties
    8811163#         2) [optional] CHECK_PROC reference
    8821164sub InsertWritableProperties($$;$)
    8831165{
    884     my ($tableName, $writeTablePtr, $checkProc) = @_;
     1166    my ($tagTablePtr, $writeTablePtr, $checkProc) = @_;
    8851167    my $tag;
    886     my $tagTablePtr = GetTagTable($tableName);
    8871168    $checkProc and $tagTablePtr->{CHECK_PROC} = $checkProc;
    8881169    foreach $tag (keys %$writeTablePtr) {
     
    8951176                    my $key;
    8961177                    foreach $key (%$writeInfo) {
    897                         $$tagInfo{$key} = $$writeInfo{$key};
     1178                        $$tagInfo{$key} = $$writeInfo{$key} unless defined $$tagInfo{$key};
    8981179                    }
    8991180                } else {
    900                     $$tagInfo{Writable} = $writeInfo;
     1181                    $$tagInfo{Writable} = $writeInfo unless defined $$tagInfo{Writable};
    9011182                }
    9021183            }
     
    9101191# rebuild maker notes to properly contain all value data
    9111192# (some manufacturers put value data outside maker notes!!)
    912 # Inputs: 0) ExifTool object reference, 1) tag table reference,
    913 #         2) dirInfo reference
     1193# Inputs: 0) ExifTool object ref, 1) tag table ref, 2) dirInfo ref
    9141194# Returns: new maker note data (and creates MAKER_NOTE_FIXUP), or undef on error
    9151195sub RebuildMakerNotes($$$)
     
    9251205    delete $exifTool->{MAKER_NOTE_FIXUP};
    9261206
    927     # don't need to rebuild text or binary-data maker notes
     1207    # don't need to rebuild text, BinaryData or PreviewImage maker notes
    9281208    my $tagInfo = $$dirInfo{TagInfo};
    9291209    my $subdir = $$tagInfo{SubDirectory};
    9301210    my $proc = $$subdir{ProcessProc} || $$tagTablePtr{PROCESS_PROC} || \&ProcessExif;
    9311211    if (($proc ne \&ProcessExif and $$tagInfo{Name} =~ /Text/) or
    932          $proc eq \&Image::ExifTool::ProcessBinaryData)
     1212         $proc eq \&Image::ExifTool::ProcessBinaryData or
     1213        ($$tagInfo{PossiblePreview} and $dirLen > 6 and
     1214         substr($$dataPt, $dirStart, 3) eq "\xff\xd8\xff"))
    9331215    {
    9341216        return substr($$dataPt, $dirStart, $dirLen);
     
    9401222        # create new exiftool object to rewrite the directory without changing it
    9411223        my $newTool = new Image::ExifTool;
     1224        $newTool->Init();   # must do this before calling WriteDirectory()!
    9421225        # don't copy over preview image
    9431226        $newTool->SetNewValue(PreviewImage => '');
    9441227        # copy all transient members over in case they are used for writing
    945         # (CameraMake, CameraModel, etc)
     1228        # (Make, Model, etc)
    9461229        foreach (grep /[a-z]/, keys %$exifTool) {
    9471230            $$newTool{$_} = $$exifTool{$_};
     
    9491232        # fix base offsets if specified
    9501233        $newTool->Options(FixBase => $exifTool->Options('FixBase'));
    951         # set FILE_TYPE to JPEG so PREVIEW_INFO will be generated
    952         $newTool->{FILE_TYPE} = 'JPEG';
     1234        # set GENERATE_PREVIEW_INFO flag so PREVIEW_INFO will be generated
     1235        $newTool->{GENERATE_PREVIEW_INFO} = 1;
    9531236        # drop any large tags
    9541237        $newTool->{DROP_TAGS} = 1;
     1238        # initialize other necessary data members
     1239        $newTool->{FILE_TYPE} = $exifTool->{FILE_TYPE};
     1240        $newTool->{TIFF_TYPE} = $exifTool->{TIFF_TYPE};
    9551241        # rewrite maker notes
    9561242        $rtnValue = $newTool->WriteDirectory(\%subdirInfo, $tagTablePtr);
    9571243        if (defined $rtnValue and length $rtnValue) {
    958             # add the dummy preview image if necessary
     1244            # add the dummy/empty preview image if necessary
    9591245            if ($newTool->{PREVIEW_INFO}) {
    9601246                $makerFixup->SetMarkerPointers(\$rtnValue, 'PreviewImage', length($rtnValue));
    961                 $rtnValue .= $newTool->{PREVIEW_INFO}->{Data};
     1247                $rtnValue .= $newTool->{PREVIEW_INFO}{Data};
    9621248                delete $newTool->{PREVIEW_INFO};
    9631249            }
    9641250            # add makernote header
    965             $loc and $rtnValue = substr($$dataPt, $dirStart, $loc) . $rtnValue;
    966             # adjust fixup for shift in start position
    967             $makerFixup->{Start} += $loc;
     1251            if ($loc) {
     1252                my $hdr = substr($$dataPt, $dirStart, $loc);
     1253                # special case: convert Pentax/Samsung DNG maker notes to JPEG style
     1254                # (in JPEG, Pentax makernotes are absolute and start with "AOC\0")
     1255                if ($hdr =~ s/^(PENTAX |SAMSUNG)\0/AOC\0/) {
     1256                    # save fixup so we will adjust to absolute offsets when writing
     1257                    $exifTool->{MAKER_NOTE_FIXUP} = $makerFixup;
     1258                }
     1259                $rtnValue = $hdr . $rtnValue;
     1260                # adjust fixup for shift in start position
     1261                $makerFixup->{Start} += length $hdr;
     1262            }
    9681263            # shift offsets according to original position of maker notes,
    9691264            # and relative to the makernotes Base
     
    9741269            # fix up pointers to the specified offset
    9751270            $makerFixup->ApplyFixup(\$rtnValue);
    976         }
    977         # save fixup information unless offsets were relative
    978         unless ($subdirInfo{Relative}) {
    979             # set shift so offsets are all relative to start of maker notes
    980             $makerFixup->{Shift} -= $dataPos + $dirStart;
    981             $exifTool->{MAKER_NOTE_FIXUP} = $makerFixup;    # save fixup for later
     1271            # save fixup information unless offsets were relative
     1272            unless ($subdirInfo{Relative}) {
     1273                # set shift so offsets are all relative to start of maker notes
     1274                $makerFixup->{Shift} -= $dataPos + $dirStart;
     1275                $exifTool->{MAKER_NOTE_FIXUP} = $makerFixup;    # save fixup for later
     1276            }
    9821277        }
    9831278    }
     
    9951290    my ($index, %entries);
    9961291    # split the directory into separate entries
    997     my ($padding, $newDir) = ('','');
     1292    my $newDir = '';
    9981293    for ($index=0; $index<$numEntries; ++$index) {
    9991294        my $entry = $dirStart + 2 + 12 * $index;
     
    10031298        $tagID = 0x10000 unless $tagID or $index == 0;
    10041299        # add new entry (allow for duplicate tag ID's, which shouldn't normally happen)
    1005         $entries{$tagID} or $entries{$tagID} = '';
    1006         $entries{$tagID} .= $entryData;
     1300        if ($entries{$tagID}) {
     1301            $entries{$tagID} .= $entryData;
     1302        } else {
     1303            $entries{$tagID} = $entryData;
     1304        }
    10071305    }
    10081306    # sort the directory entries
     
    10121310    }
    10131311    # replace original directory with new, sorted one
    1014     substr($$dataPt, $dirStart + 2, 12 * $numEntries) = $newDir . $padding;
     1312    substr($$dataPt, $dirStart + 2, 12 * $numEntries) = $newDir;
    10151313}
    10161314
     
    10361334        my $entry = 12 * $index;
    10371335        my $tagID = Get16u(\$buff, $entry);
    1038         $tagID > $lastID or return 0;
     1336        $tagID > $lastID or $$dirInfo{AllowOutOfOrderTags} or return 0;
    10391337        my $format = Get16u(\$buff, $entry+2);
    10401338        $format > 0 and $format <= 13 or return 0;
     
    10441342    }
    10451343    return 1;
     1344}
     1345
     1346#------------------------------------------------------------------------------
     1347# Get sorted list of offsets used in IFD
     1348# Inputs: 0) data ref, 1) directory start, 2) dataPos, 3) IFD entries, 4) tag table ref
     1349# Returns: 0) sorted list of offsets (only offsets after the end of the IFD)
     1350#          1) hash of list indices keyed by offset value
     1351# Notes: This is used in a patch to fix the count for tags in Kodak SubIFD3
     1352sub GetOffList($$$$$)
     1353{
     1354    my ($dataPt, $dirStart, $dataPos, $numEntries, $tagTablePtr) = @_;
     1355    my $ifdEnd = $dirStart + 2 + 12 * $numEntries + $dataPos;
     1356    my ($index, $offset, %offHash);
     1357    for ($index=0; $index<$numEntries; ++$index) {
     1358        my $entry = $dirStart + 2 + 12 * $index;
     1359        my $format = Get16u($dataPt, $entry + 2);
     1360        next if $format < 1 or $format > 13;
     1361        my $count = Get16u($dataPt, $entry + 4);
     1362        my $size = $formatSize[$format] * $count;
     1363        if ($size <= 4) {
     1364            my $tagID = Get16u($dataPt, $entry);
     1365            next unless ref $$tagTablePtr{$tagID} eq 'HASH' and $$tagTablePtr{$tagID}{FixCount};
     1366        }
     1367        my $offset = Get16u($dataPt, $entry + 8);
     1368        $offHash{$offset} = 1 if $offset >= $ifdEnd;
     1369    }
     1370    # set offset hash values to indices in list
     1371    my @offList = sort keys %offHash;
     1372    $index = 0;
     1373    foreach $offset (@offList) {
     1374        $offHash{$offset} = $index++;
     1375    }
     1376    return(\@offList, \%offHash);
    10461377}
    10471378
     
    10611392#------------------------------------------------------------------------------
    10621393# Handle error while writing EXIF
    1063 # Inputs: 0) ExifTool ref, 1) error string, 2) flag set for minor error
     1394# Inputs: 0) ExifTool ref, 1) error string, 2) tag table ref
    10641395# Returns: undef on fatal error, or '' if minor error is ignored
    10651396sub ExifErr($$$)
    10661397{
    1067     my ($exifTool, $errStr, $minor) = @_;
     1398    my ($exifTool, $errStr, $tagTablePtr) = @_;
     1399    # MakerNote errors are minor by default
     1400    my $minor = ($tagTablePtr->{GROUPS}{0} eq 'MakerNotes');
     1401    if ($tagTablePtr->{VARS} and $tagTablePtr->{VARS}{MINOR_ERRORS}) {
     1402        $exifTool->Warn("$errStr. IFD dropped.") and return '' if $minor;
     1403        $minor = 1;
     1404    }
    10681405    return undef if $exifTool->Error($errStr, $minor);
    10691406    return '';
     
    10711408
    10721409#------------------------------------------------------------------------------
     1410# Read/Write IFD with TIFF-like header (used by DNG 1.2)
     1411# Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
     1412# Returns: Reading: 1 on success, otherwise returns 0 and sets a Warning
     1413#          Writing: new data block or undef on error
     1414sub ProcessTiffIFD($$$)
     1415{
     1416    my ($exifTool, $dirInfo, $tagTablePtr) = @_;
     1417    $exifTool or return 1;    # allow dummy access
     1418    my $raf = $$dirInfo{RAF};
     1419    my $base = $$dirInfo{Base} || 0;
     1420    my $dirName = $$dirInfo{DirName};
     1421    my $magic = $dirInfo->{Subdir}{Magic} || 0x002a;
     1422    my $buff;
     1423
     1424    # structured with a TIFF-like header and relative offsets
     1425    $raf->Seek($base, 0) and $raf->Read($buff, 8) == 8 or return 0;
     1426    unless (SetByteOrder(substr($buff,0,2)) and Get16u(\$buff, 2) == $magic) {
     1427        my $msg = "Invalid $dirName header";
     1428        if ($$dirInfo{IsWriting}) {
     1429            $exifTool->Error($msg);
     1430            return undef;
     1431        } else {
     1432            $exifTool->Warn($msg);
     1433            return 0;
     1434        }
     1435    }
     1436    my $offset = Get32u(\$buff, 4);
     1437    my %dirInfo = (
     1438        DirName  => $$dirInfo{DirName},
     1439        Parent   => $$dirInfo{Parent},
     1440        Base     => $base,
     1441        DataPt   => \$buff,
     1442        DataLen  => length $buff,
     1443        DataPos  => 0,
     1444        DirStart => $offset,
     1445        DirLen   => length($buff) - $offset,
     1446        RAF      => $raf,
     1447        NewDataPos => 8,
     1448    );
     1449    if ($$dirInfo{IsWriting}) {
     1450        # rewrite the Camera Profile IFD
     1451        my $newDir = WriteExif($exifTool, \%dirInfo, $tagTablePtr);
     1452        # don't add header if error writing directory ($newDir is undef)
     1453        # or if directory is being deleted ($newDir is empty)
     1454        return $newDir unless $newDir;
     1455        # return directory with TIFF-like header
     1456        return GetByteOrder() . Set16u($magic) . Set32u(8) . $newDir;
     1457    }
     1458    if ($exifTool->{HTML_DUMP}) {
     1459        my $tip = sprintf("Byte order: %s endian\nIdentifier: 0x%.4x\n%s offset: 0x%.4x",
     1460                          (GetByteOrder() eq 'II') ? 'Little' : 'Big', $magic, $dirName, $offset);
     1461        $exifTool->HDump($base, 8, "$dirName header", $tip, 0);
     1462    }
     1463    return ProcessExif($exifTool, \%dirInfo, $tagTablePtr);
     1464}
     1465
     1466#------------------------------------------------------------------------------
    10731467# Write EXIF directory
    1074 # Inputs: 0) ExifTool object reference, 1) source dirInfo reference,
    1075 #         2) tag table reference
     1468# Inputs: 0) ExifTool object ref, 1) source dirInfo ref, 2) tag table ref
    10761469# Returns: Exif data block (may be empty if no Exif data) or undef on error
    10771470# Notes: Increments ExifTool CHANGED flag for each tag changed.  Also updates
     
    10861479{
    10871480    my ($exifTool, $dirInfo, $tagTablePtr) = @_;
    1088     $exifTool or return 1;    # allow dummy access to autoload this package
     1481    $exifTool or return 1;      # allow dummy access to autoload this package
     1482    my $origDirInfo = $dirInfo; # save original dirInfo
    10891483    my $dataPt = $$dirInfo{DataPt};
    10901484    unless ($dataPt) {
     
    11011495    my $dirName = $$dirInfo{DirName} || 'unknown';
    11021496    my $fixup = $$dirInfo{Fixup} || new Image::ExifTool::Fixup;
     1497    my $imageDataFlag = $$dirInfo{ImageData} || '';
    11031498    my $verbose = $exifTool->Options('Verbose');
    11041499    my $out = $exifTool->Options('TextOut');
     1500    my ($nextIfdPos, %offsetData, $inMakerNotes);
    11051501    my (@offsetInfo, %xDelete);
     1502    my $deleteAll = 0;
    11061503    my $newData = '';   # initialize buffer to receive new directory data
    1107     my ($nextIfdPos, %offsetData, $inMakerNotes);
    1108     my $deleteAll = 0;
     1504    my @imageData;      # image data blocks to copy later if requested
     1505    my $name = $$dirInfo{Name};
     1506    $name = $dirName unless $name and $dirName eq 'MakerNotes' and $name !~ /^MakerNote/;
    11091507
    11101508    # allow multiple IFD's in IFD0-IFD1-IFD2... chain
    1111     $$dirInfo{Multi} = 1 if $dirName eq 'IFD0' or $dirName eq 'SubIFD';
    1112     $inMakerNotes = 1 if $tagTablePtr->{GROUPS}->{0} eq 'MakerNotes';
     1509    $$dirInfo{Multi} = 1 if $dirName =~ /^(IFD0|SubIFD)$/ and not defined $$dirInfo{Multi};
     1510    $inMakerNotes = 1 if $tagTablePtr->{GROUPS}{0} eq 'MakerNotes';
    11131511    my $ifd;
    11141512#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     
    11171515    for ($ifd=0; ; ++$ifd) {  # loop through multiple IFD's
    11181516
     1517        # save pointer to start of this IFD within the newData
     1518        my $newStart = length($newData);
     1519        my @subdirs;    # list of subdirectory data and tag table pointers
     1520        # determine if directory is contained within our data
     1521        my $mustRead;
     1522        if ($dirStart < 0 or $dirStart > $dataLen-2) {
     1523            $mustRead = 1;
     1524        } elsif ($dirLen > 2) {
     1525            my $len = 2 + 12 * Get16u($dataPt, $dirStart);
     1526            $mustRead = 1 if $dirStart + $len > $dataLen;
     1527        }
     1528        # read IFD from file if necessary
     1529        if ($mustRead) {
     1530            if ($raf) {
     1531                # read the count of entries in this IFD
     1532                my $offset = $dirStart + $dataPos;
     1533                my ($buff, $buf2);
     1534                unless ($raf->Seek($offset + $base, 0) and $raf->Read($buff,2) == 2) {
     1535                    return ExifErr($exifTool, "Bad IFD or truncated file in $name", $tagTablePtr);
     1536                }
     1537                my $len = 12 * Get16u(\$buff,0);
     1538                # (also read next IFD pointer if available)
     1539                unless ($raf->Read($buf2, $len+4) >= $len) {
     1540                    return ExifErr($exifTool, "Error reading $name", $tagTablePtr);
     1541                }
     1542                $buff .= $buf2;
     1543                # make copy of dirInfo since we're going to modify it
     1544                my %newDirInfo = %$dirInfo;
     1545                $dirInfo = \%newDirInfo;
     1546                # update directory parameters for the newly loaded IFD
     1547                $dataPt = $$dirInfo{DataPt} = \$buff;
     1548                $dirStart = $$dirInfo{DirStart} = 0;
     1549                $dataPos = $$dirInfo{DataPos} = $offset;
     1550                $dataLen = $$dirInfo{DataLen} = length $buff;
     1551                $dirLen = $$dirInfo{DirLen} = $dataLen;
     1552                # only account for nextIFD pointer if we are going to use it
     1553                $len += 4 if $dataLen==$len+6 and ($$dirInfo{Multi} or $buff =~ /\0{4}$/);
     1554                UpdateTiffEnd($exifTool, $offset+$base+2+$len);
     1555            } elsif ($dirLen) {
     1556                # error if we can't load IFD (unless we are creating
     1557                # from scratch, in which case dirLen will be zero)
     1558                my $str = $exifTool->Options('IgnoreMinorErrors') ? 'Deleted bad' : 'Bad';
     1559                $exifTool->Error("$str $name directory", 1);
     1560            }
     1561        }
     1562        my ($index, $dirEnd, $numEntries);
     1563        if ($dirStart + 4 < $dataLen) {
     1564            $numEntries = Get16u($dataPt, $dirStart);
     1565            $dirEnd = $dirStart + 2 + 12 * $numEntries;
     1566            if ($dirEnd > $dataLen) {
     1567                return ExifErr($exifTool, "Truncated $name directory", $tagTablePtr);
     1568            }
     1569            # sort entries if necessary (but not in maker notes IFDs)
     1570            unless ($inMakerNotes) {
     1571                my $lastID = -1;
     1572                for ($index=0; $index<$numEntries; ++$index) {
     1573                    my $tagID = Get16u($dataPt, $dirStart + 2 + 12 * $index);
     1574                    # check for proper sequence (but ignore null entries at end)
     1575                    if ($tagID < $lastID and $tagID) {
     1576                        SortIFD($dataPt, $dirStart, $numEntries);
     1577                        $exifTool->Warn("Entries in $name were out of sequence. Fixed.",1);
     1578                        last;
     1579                    }
     1580                    $lastID = $tagID;
     1581                }
     1582            }
     1583        } else {
     1584            $numEntries = 0;
     1585            $dirEnd = $dirStart;
     1586        }
     1587
    11191588        # loop through new values and accumulate all information for this IFD
    11201589        my (%set, $tagInfo);
    1121         my $tableGroup = $tagTablePtr->{GROUPS}->{0};
    11221590        my $wrongDir = $crossDelete{$dirName};
    11231591        foreach $tagInfo ($exifTool->GetNewTagInfoList($tagTablePtr)) {
     
    11341602                    }
    11351603                    if (defined $val) {
    1136                         $curInfo = $exifTool->GetTagInfo($tagTablePtr, $tagID, \$val,
    1137                                         $$tagInfo{Format} || 'undef', $$tagInfo{Count} || 1);
     1604                        my $fmt = $$tagInfo{Writable} || $$tagInfo{Format} || 'undef';
     1605                        my $cnt = $$tagInfo{Count} || 1;
     1606                        # always use old format/count for Condition in maker notes
     1607                        if ($inMakerNotes) {
     1608                            for ($index=0; $index<$numEntries; ++$index) {
     1609                                my $entry = $dirStart + 2 + 12 * $index;
     1610                                my $id = Get16u($dataPt, $entry);
     1611                                if ($id eq $tagID) {
     1612                                    my $f = Get16u($dataPt, $entry + 2);
     1613                                    if ($formatName[$f]) {
     1614                                        $fmt = $formatName[$f];
     1615                                        $cnt = Get32u($dataPt, $entry + 4);
     1616                                    }
     1617                                    last;
     1618                                }
     1619                            }
     1620                        }
     1621                        $curInfo = $exifTool->GetTagInfo($tagTablePtr, $tagID, \$val, $fmt, $cnt);
    11381622                    }
    11391623                }
     
    11491633                }
    11501634            }
    1151             my $newValueHash = $exifTool->GetNewValueHash($tagInfo, $dirName);
    1152             unless ($newValueHash) {
     1635            my $nvHash = $exifTool->GetNewValueHash($tagInfo, $dirName);
     1636            unless ($nvHash) {
    11531637                next unless $wrongDir;
    11541638                # delete stuff from the wrong directory if setting somewhere else
    1155                 $newValueHash = $exifTool->GetNewValueHash($tagInfo, $wrongDir);
    1156                 next unless Image::ExifTool::IsOverwriting($newValueHash);
     1639                $nvHash = $exifTool->GetNewValueHash($tagInfo, $wrongDir);
     1640                next unless Image::ExifTool::IsOverwriting($nvHash);
    11571641                # don't cross delete if specifically deleting from the other directory
    1158                 my $val = Image::ExifTool::GetNewValues($newValueHash);
    1159                 next if not defined $val and $newValueHash->{WantGroup} and
    1160                         lc($newValueHash->{WantGroup}) eq lc($wrongDir);
     1642                my $val = Image::ExifTool::GetNewValues($nvHash);
     1643                next if not defined $val and $nvHash->{WantGroup} and
     1644                        lc($nvHash->{WantGroup}) eq lc($wrongDir);
    11611645                # remove this tag if found in this IFD
    11621646                $xDelete{$tagID} = 1;
    11631647            }
    1164             $set{$tagID} = $tagInfo;
    1165         }
    1166         # save pointer to start of this IFD within the newData
    1167         my $newStart = length($newData);
    1168         my @subdirs;    # list of subdirectory data and tag table pointers
    1169         # determine if directory is contained within our data
    1170         my $mustRead;
    1171         if ($dirStart < 0 or $dirStart > $dataLen-2) {
    1172             $mustRead = 1;
    1173         } elsif ($dirLen > 2) {
    1174             my $len = 2 + 12 * Get16u($dataPt, $dirStart);
    1175             $mustRead = 1 if $dirStart + $len > $dataLen;
    1176         }
    1177         # read IFD from file if necessary
    1178         if ($raf and $mustRead) {
    1179             # read the count of entries in this IFD
    1180             my $offset = $dirStart + $dataPos;
    1181             my ($buff, $buf2);
    1182             unless ($raf->Seek($offset + $base, 0) and $raf->Read($buff,2) == 2) {
    1183                 return ExifErr($exifTool, "Bad IFD or truncated file in $dirName", $inMakerNotes);
    1184             }
    1185             my $len = 12 * Get16u(\$buff,0);
    1186             # (also read next IFD pointer if available)
    1187             unless ($raf->Read($buf2, $len+4) >= $len) {
    1188                 return ExifErr($exifTool, "Error reading $dirName", $inMakerNotes);
    1189             }
    1190             $buff .= $buf2;
    1191             # make copy of dirInfo since we're going to modify it
    1192             my %newDirInfo = %$dirInfo;
    1193             $dirInfo = \%newDirInfo;
    1194             # update directory parameters for the newly loaded IFD
    1195             $dataPt = $$dirInfo{DataPt} = \$buff;
    1196             $dirStart = $$dirInfo{DirStart} = 0;
    1197             $dataPos = $$dirInfo{DataPos} = $offset;
    1198             $dataLen = $$dirInfo{DataLen} = length $buff;
    1199             $dirLen = $$dirInfo{DirLen} = $dataLen;
    1200             # only account for nextIFD pointer if we are going to use it
    1201             $len += 4 if $dataLen==$len+6 and ($$dirInfo{Multi} or $buff =~ /\0{4}$/);
    1202             UpdateTiffEnd($exifTool, $offset+$base+2+$len);
    1203         }
    1204         my ($len, $numEntries);
    1205         if ($dirStart + 4 < $dataLen) {
    1206             $numEntries = Get16u($dataPt, $dirStart);
    1207             $len = 2 + 12 * $numEntries;
    1208             if ($dirStart + $len > $dataLen) {
    1209                 return ExifErr($exifTool, "Truncated $dirName directory", $inMakerNotes);
    1210             }
    1211             # sort entries if necessary (but not in maker notes IFDs)
    1212             unless ($inMakerNotes) {
    1213                 my $index;
    1214                 my $lastID = -1;
    1215                 for ($index=0; $index<$numEntries; ++$index) {
    1216                     my $tagID = Get16u($dataPt, $dirStart + 2 + 12 * $index);
    1217                     # check for proper sequence (but ignore null entries at end)
    1218                     if ($tagID < $lastID and $tagID) {
    1219                         SortIFD($dataPt, $dirStart, $numEntries);
    1220                         $exifTool->Warn("Entries in $dirName were out of sequence. Fixed.");
    1221                         last;
    1222                     }
    1223                     $lastID = $tagID;
     1648            if ($set{$tagID}) {
     1649                # this tag is being set twice, which can happen if two Condition's
     1650                # were true for this tag.  Hopefully the only case where this can
     1651                # happen is the MakerNotes tag since it may store two very different
     1652                # types of information (MakerNotes and PreviewImage), but we want
     1653                # to store the MakerNotes if both are available
     1654                if ($tagID == 0x927c and $dirName =~ /^(ExifIFD|IFD0)$/) {
     1655                    next if $$tagInfo{Name} eq 'PreviewImage';
     1656                } else {
     1657                    $exifTool->Warn(sprintf("Multiple new values for $name tag 0x%.4x",$tagID));
    12241658                }
    12251659            }
    1226         } else {
    1227             $numEntries = $len = 0;
    1228         }
    1229 
    1230         # fix base offsets
    1231         if ($dirName eq 'MakerNotes' and $$dirInfo{Parent} eq 'ExifIFD' and
     1660            $set{$tagID} = $tagInfo;
     1661        }
     1662       
     1663        # fix base offsets (some cameras incorrectly write maker notes in IFD0)
     1664        if ($dirName eq 'MakerNotes' and $$dirInfo{Parent} =~ /^(ExifIFD|IFD0)$/ and
     1665            $$exifTool{TIFF_TYPE} !~ /^(ARW|SR2)$/ and not $$exifTool{LeicaTrailerPos} and
    12321666            Image::ExifTool::MakerNotes::FixBase($exifTool, $dirInfo))
    12331667        {
     
    12391673        # initialize variables to handle mandatory tags
    12401674        my $mandatory = $mandatory{$dirName};
    1241         my $allMandatory;
     1675        my ($allMandatory, $addMandatory);
    12421676        if ($mandatory) {
    12431677            # use X/Y resolution values from JFIF if available
     
    12491683                $mandatory = \%ifd0Vals;
    12501684            }
    1251             $allMandatory = 0; # initialize to zero
     1685            $allMandatory = $addMandatory = 0; # initialize to zero
    12521686            # add mandatory tags if creating a new directory
    12531687            unless ($numEntries) {
     
    12611695        my ($addDirs, @newTags);
    12621696        if ($inMakerNotes) {
    1263             $addDirs = { };
     1697            $addDirs = { };     # can't currently add new directories in MakerNotes
     1698            # allow non-permanent makernotes tags to be added
     1699            # (note: we may get into trouble if there are too many of these
     1700            #  because we allow out-of-order tags in MakerNote IFD's but our
     1701            #  logic to add new tags relies on ordered entries)
     1702            foreach (keys %set) {
     1703                my $perm = $set{$_}{Permanent};
     1704                push @newTags, $_ if defined $perm and not $perm;
     1705            }
     1706            @newTags = sort { $a <=> $b } @newTags if @newTags > 1;
    12641707        } else {
    12651708            # get a hash of directories we will be writing in this one
     
    12791722        my $dirFixup = new Image::ExifTool::Fixup;
    12801723        my $entryBasedFixup;
    1281         my $index = 0;
    12821724        my $lastTagID = -1;
    1283         my ($oldInfo, $oldFormat, $oldFormName, $oldCount, $oldSize, $oldValue);
     1725        my ($oldInfo, $oldFormat, $oldFormName, $oldCount, $oldSize, $oldValue, $oldImageData);
    12841726        my ($readFormat, $readFormName, $readCount); # format for reading old value(s)
    12851727        my ($entry, $valueDataPt, $valueDataPos, $valueDataLen, $valuePtr, $valEnd);
     1728        my ($offList, $offHash, $ignoreCount, $fixCount);
    12861729        my $oldID = -1;
    12871730        my $newID = -1;
     1731
     1732        # patch for Canon EOS 40D firmware 1.0.4 bug (incorrect directory counts)
     1733        if ($inMakerNotes and $$exifTool{Model} eq 'Canon EOS 40D') {
     1734            my $fmt = Get16u($dataPt, $dirStart + 2 + 12 * ($numEntries - 1) + 2);
     1735            if ($fmt < 1 or $fmt > 13) {
     1736                # adjust the number of directory entries
     1737                --$numEntries;
     1738                $dirEnd -= 12;
     1739                $ignoreCount = 1;
     1740            }
     1741        }
    12881742#..............................................................................
    12891743# loop through entries in new directory
    12901744#
     1745        $index = 0;
    12911746Entry:  for (;;) {
    12921747
     
    13001755                    $readFormat = $oldFormat = Get16u($dataPt, $entry+2);
    13011756                    $readCount = $oldCount = Get32u($dataPt, $entry+4);
     1757                    undef $oldImageData;
    13021758                    if ($oldFormat < 1 or $oldFormat > 13) {
     1759                        # patch to preserve invalid directory entries in SubIFD3 of
     1760                        # various Kodak Z-series cameras (Z812, Z1085IS, Z1275)
     1761                        if ($dirName eq 'MakerNotes' and $$exifTool{Make}=~/KODAK/i and
     1762                            $$dirInfo{Name} and $$dirInfo{Name} eq 'SubIFD3')
     1763                        {
     1764                            $dirBuff .= substr($$dataPt, $entry, 12);
     1765                            goto WroteIt;
     1766                        }
    13031767                        # don't write out null directory entry
    1304                         unless ($oldFormat or $oldCount or not $index) {
    1305                             ++$index;
    1306                             $newID = $oldID;    # pretend we wrote this
     1768                        if ($oldFormat==0 and $index and $oldCount==0) {
     1769                            $ignoreCount = ($ignoreCount || 0) + 1;
    13071770                            # must keep same directory size to avoid messing up our fixed offsets
    13081771                            $dirBuff .= ("\0" x 12) if $$dirInfo{FixBase};
     1772WroteIt:                    ++$index;
     1773                            $newID = $oldID;    # pretend we wrote this
    13091774                            next;
    13101775                        }
    1311                         return ExifErr($exifTool, "Bad format ($oldFormat) for $dirName entry $index", $inMakerNotes);
     1776                        my $msg = "Bad format ($oldFormat) for $name entry $index";
     1777                        return ExifErr($exifTool, $msg, $tagTablePtr);
    13121778                    }
    13131779                    $readFormName = $oldFormName = $formatName[$oldFormat];
     
    13161782                    $valueDataLen = $dataLen;
    13171783                    $valuePtr = $entry + 8;
    1318                     $oldSize = $oldCount * $formatSize[$oldFormat];
    1319                     # must try direct method first so we will get unknown tags too
    1320                     # (this is necessary so we don't miss a tag we want to Drop)
     1784                    # try direct method first for speed
    13211785                    $oldInfo = $$tagTablePtr{$oldID};
    13221786                    if (ref $oldInfo ne 'HASH' or $$oldInfo{Condition}) {
     1787                        # must get unknown tags too
     1788                        # (necessary so we don't miss a tag we want to Drop)
     1789                        my $unk = $exifTool->Options(Unknown => 1);
    13231790                        $oldInfo = $exifTool->GetTagInfo($tagTablePtr, $oldID);
    1324                     }
     1791                        $exifTool->Options(Unknown => $unk);
     1792                    }
     1793                    # patch incorrect count in Kodak SubIFD3 tags
     1794                    if ($oldCount < 2 and $oldInfo and $$oldInfo{FixCount}) {
     1795                        $offList or ($offList, $offHash) = GetOffList($dataPt, $dirStart, $dataPos,
     1796                                                                      $numEntries, $tagTablePtr);
     1797                        my $i = $$offHash{Get32u($dataPt, $valuePtr)};
     1798                        if (defined $i and $i < $#$offList) {
     1799                            $oldCount = int(($$offList[$i+1] - $$offList[$i]) / $formatSize[$oldFormat]);
     1800                            $fixCount = ($fixCount || 0) + 1 if $oldCount != $readCount;
     1801                        }
     1802                    }
     1803                    $oldSize = $oldCount * $formatSize[$oldFormat];
    13251804                    my $readFromFile;
    13261805                    if ($oldSize > 4) {
     
    13301809                            $valEnd or $valEnd = $dataPos + $dirStart + 2 + 12 * $numEntries + 4;
    13311810                            my ($tagID, $size, $wFlag) = ($oldID, $oldSize, 1);
    1332                             #### eval FixOffsets($valuePtr, $valEnd, $size, $tagID, $wFlag)
     1811                            #### eval FixOffsets ($valuePtr, $valEnd, $size, $tagID, $wFlag)
    13331812                            eval $$dirInfo{FixOffsets};
    13341813                            unless (defined $valuePtr) {
    13351814                                unless ($$exifTool{DROP_TAGS}) {
    13361815                                    my $tagStr = $oldInfo ? $$oldInfo{Name} : sprintf("tag 0x%x",$oldID);
    1337                                     return undef if $exifTool->Error("Bad $dirName directory pointer for $tagStr", $inMakerNotes);
     1816                                    return undef if $exifTool->Error("Bad $name offset for $tagStr", $inMakerNotes);
    13381817                                }
    13391818                                goto DropTag;
    13401819                            }
    13411820                        }
     1821                        # offset shouldn't point into TIFF or IFD header
     1822                        my $suspect = ($valuePtr < 8);
    13421823                        # convert offset to pointer in $$dataPt
    13431824                        if ($$dirInfo{EntryBased} or (ref $$tagTablePtr{$oldID} eq 'HASH' and
    1344                             $tagTablePtr->{$oldID}->{EntryBased}))
     1825                            $tagTablePtr->{$oldID}{EntryBased}))
    13451826                        {
    13461827                            $valuePtr += $entry;
     
    13481829                            $valuePtr -= $dataPos;
    13491830                        }
     1831                        # value shouldn't overlap our directory
     1832                        $suspect = 1 if $valuePtr < $dirEnd and $valuePtr+$oldSize > $dirStart;
    13501833                        # get value by seeking in file if we are allowed
    13511834                        if ($valuePtr < 0 or $valuePtr+$oldSize > $dataLen) {
    1352                             my ($pos, $tagStr, $invalidPreview);
     1835                            my ($pos, $tagStr, $invalidPreview, $tmpInfo);
    13531836                            if ($oldInfo) {
    13541837                                $tagStr = $$oldInfo{Name};
    13551838                            } elsif (defined $oldInfo) {
    1356                                 my $tmpInfo = $exifTool->GetTagInfo($tagTablePtr, $oldID, \ '', $oldFormName, $oldCount);
     1839                                $tmpInfo = $exifTool->GetTagInfo($tagTablePtr, $oldID, \ '', $oldFormName, $oldCount);
    13571840                                $tagStr = $$tmpInfo{Name} if $tmpInfo;
    13581841                            }
    13591842                            $tagStr or $tagStr = sprintf("tag 0x%x",$oldID);
    1360                             # allow PreviewImage to run outside EXIF segment
    1361                             if (not $raf and $tagStr eq 'PreviewImage') {
    1362                                 $raf = $exifTool->{RAF};
    1363                                 if ($raf) {
    1364                                     $pos = $raf->Tell();
    1365                                 } else {
    1366                                     $invalidPreview = 1;
     1843                            # allow PreviewImage to run outside EXIF segment in JPEG images
     1844                            if (not $raf) {
     1845                                if ($tagStr eq 'PreviewImage') {
     1846                                    $raf = $exifTool->{RAF};
     1847                                    if ($raf) {
     1848                                        $pos = $raf->Tell();
     1849                                        if ($oldInfo and $$oldInfo{ChangeBase}) {
     1850                                            # adjust base offset for this tag only
     1851                                            #### eval ChangeBase ($dirStart,$dataPos)
     1852                                            my $newBase = eval $$oldInfo{ChangeBase};
     1853                                            $valuePtr += $newBase;
     1854                                        }
     1855                                    } else {
     1856                                        $invalidPreview = 1;
     1857                                    }
     1858                                } elsif ($tagStr eq 'MakerNoteLeica6') {
     1859                                    # save information about Leica makernote trailer
     1860                                    $$exifTool{LeicaTrailer} = {
     1861                                        TagInfo => $oldInfo || $tmpInfo,
     1862                                        Offset  => $base + $valuePtr + $dataPos,
     1863                                        Size    => $oldSize,
     1864                                    },
     1865                                    $invalidPreview = 2;
     1866                                    # remove SubDirectory to prevent processing (for now)
     1867                                    my %copy = %{$oldInfo || $tmpInfo};
     1868                                    delete $copy{SubDirectory};
     1869                                    delete $copy{MakerNotes};
     1870                                    $oldInfo = \%copy;
    13671871                                }
    13681872                            }
    1369                             if ($raf) {
    1370                                 my $success = ($raf->Seek($base + $valuePtr + $dataPos, 0) and
     1873                            if ($oldSize > BINARY_DATA_LIMIT and $$origDirInfo{ImageData} and
     1874                                (not defined $oldInfo or ($oldInfo and not $$oldInfo{SubDirectory})))
     1875                            {
     1876                                # copy huge data blocks later instead of loading into memory
     1877                                $oldValue = ''; # dummy empty value
     1878                                # copy this value later unless writing a new value
     1879                                unless ($set{$oldID}) {
     1880                                    my $pad = $oldSize & 0x01 ? 1 : 0;
     1881                                    # save block information to copy later (set directory offset later)
     1882                                    $oldImageData = [$base+$valuePtr+$dataPos, $oldSize, $pad];
     1883                                }
     1884                            } elsif ($raf) {
     1885                                my $success = ($raf->Seek($base+$valuePtr+$dataPos, 0) and
    13711886                                               $raf->Read($oldValue, $oldSize) == $oldSize);
    13721887                                if (defined $pos) {
    13731888                                    $raf->Seek($pos, 0);
    13741889                                    undef $raf;
    1375                                     unless ($success and $oldValue =~ /^(\xff\xd8\xff|.\xd8\xff\xdb)/s) {
    1376                                         $exifTool->Error("Bad PreviewImage pointer in $dirName", 1);
     1890                                    # (sony A700 has 32-byte header on PreviewImage)
     1891                                    unless ($success and $oldValue =~ /^(\xff\xd8\xff|(.|.{33})\xd8\xff\xdb)/s) {
    13771892                                        $invalidPreview = 1;
    1378                                         $success = 1;   # continue writing directory
     1893                                        $success = 1;   # continue writing directory anyway
    13791894                                    }
    13801895                                }
    13811896                                unless ($success) {
    1382                                     return undef if $exifTool->Error("Error reading value for $dirName entry $index", $inMakerNotes);
     1897                                    return undef if $exifTool->Error("Error reading value for $name entry $index", $inMakerNotes);
    13831898                                    goto DropTag;
    13841899                                }
    13851900                            } elsif (not $invalidPreview) {
    1386                                 return undef if $exifTool->Error("Bad $dirName directory pointer for $tagStr", $inMakerNotes);
     1901                                return undef if $exifTool->Error("Bad $name offset for $tagStr", $inMakerNotes);
    13871902                                goto DropTag;
    13881903                            }
    13891904                            if ($invalidPreview) {
    1390                                 $oldValue = 'none';     # flag for missing preview
    1391                                 $oldSize = length $oldValue;
     1905                                # set value for invalid preview
     1906                                if ($exifTool->{FILE_TYPE} eq 'JPEG') {
     1907                                    # define dummy value for preview (or Leica MakerNote) to write later
     1908                                    # (value must be larger than 4 bytes to generate PREVIEW_INFO,
     1909                                    # and an even number of bytes so it won't be padded)
     1910                                    $oldValue = 'LOAD_PREVIEW';
     1911                                } else {
     1912                                    $oldValue = 'none';
     1913                                    $oldSize = length $oldValue;
     1914                                }
    13921915                                $valuePtr = 0;
    13931916                            } else {
     
    14011924                            $readFromFile = 1;
    14021925                        }
     1926                        if ($suspect) {
     1927                            my $tagStr = $oldInfo ? $$oldInfo{Name} : sprintf('tag 0x%.4x', $oldID);
     1928                            my $str = "Suspicious $name offset for $tagStr";
     1929                            if ($inMakerNotes) {
     1930                                $exifTool->Warn($str, 1);
     1931                            } else {
     1932                                return undef if $exifTool->Error($str, 1);
     1933                            }
     1934                        }
    14031935                    }
    14041936                    # read value if we haven't already
     
    14061938                    # get tagInfo using value if necessary
    14071939                    if (defined $oldInfo and not $oldInfo) {
     1940                        my $unk = $exifTool->Options(Unknown => 1);
    14081941                        $oldInfo = $exifTool->GetTagInfo($tagTablePtr, $oldID, \$oldValue, $oldFormName, $oldCount);
     1942                        $exifTool->Options(Unknown => $unk);
     1943                    }
     1944                    # make sure we are handling the 'ifd' format properly
     1945                    if (($oldFormat == 13 or $oldFormat == 18) and
     1946                        (not $oldInfo or not $$oldInfo{SubIFD}))
     1947                    {
     1948                        my $str = sprintf('%s tag 0x%.4x IFD format not handled', $name, $oldID);
     1949                        $exifTool->Error($str, $inMakerNotes);
    14091950                    }
    14101951                    # override format we use to read the value if specified
    14111952                    if ($oldInfo) {
     1953                        # check for tags which must be integers
     1954                        if (($$oldInfo{IsOffset} or $$oldInfo{SubIFD}) and
     1955                            not $intFormat{$oldFormName})
     1956                        {
     1957                            $exifTool->Error("Invalid format ($oldFormName) for $name $$oldInfo{Name}", $inMakerNotes);
     1958                            goto DropTag;
     1959                        }
    14121960                        if ($$oldInfo{Drop} and $$exifTool{DROP_TAGS}) {
    14131961                            # don't rewrite this tag
     
    14311979                        my $str = $oldInfo ? "$$oldInfo{Name} tag" : sprintf('tag 0x%x',$oldID);
    14321980                        if ($oldID == $lastTagID) {
    1433                             $exifTool->Warn("Duplicate $str in $dirName");;
     1981                            $exifTool->Warn("Duplicate $str in $name");;
    14341982                        } else {
    1435                             $exifTool->Warn("\u$str out of sequence in $dirName");
     1983                            $exifTool->Warn("\u$str out of sequence in $name");
    14361984                        }
    14371985                    }
     
    14792027                    $newInfo = $set{$newID};
    14802028                    $newCount = $$newInfo{Count};
    1481                     my ($val, $newVal);
    1482                     my $newValueHash = $exifTool->GetNewValueHash($newInfo, $dirName);
     2029                    my ($val, $newVal, $n);
     2030                    my $nvHash = $exifTool->GetNewValueHash($newInfo, $dirName);
    14832031                    if ($isNew > 0) {
    14842032                        # don't create new entry unless requested
    1485                         if ($newValueHash) {
    1486                             next unless Image::ExifTool::IsCreating($newValueHash);
    1487                             $isOverwriting = Image::ExifTool::IsOverwriting($newValueHash);
     2033                        if ($nvHash) {
     2034                            next unless Image::ExifTool::IsCreating($nvHash);
     2035                            if ($$newInfo{IsOverwriting}) {
     2036                                my $proc = $$newInfo{IsOverwriting};
     2037                                $isOverwriting = &$proc($exifTool, $nvHash, $val, \$newVal);
     2038                            } else {
     2039                                $isOverwriting = Image::ExifTool::IsOverwriting($nvHash);
     2040                            }
    14882041                        } else {
    14892042                            next if $xDelete{$newID};       # don't create if cross deleting
     
    14992052                            $newFormName = $$newInfo{Writable};
    15002053                            unless ($newFormName) {
    1501                                 warn("No format for $dirName $$newInfo{Name}\n");
     2054                                warn("No format for $name $$newInfo{Name}\n");
    15022055                                next;
    15032056                            }
    15042057                        }
    15052058                        $newFormat = $formatNumber{$newFormName};
    1506                     } elsif ($newValueHash or $xDelete{$newID}) {
    1507                         unless ($newValueHash) {
    1508                             $newValueHash = $exifTool->GetNewValueHash($newInfo, $wrongDir);
     2059                    } elsif ($nvHash or $xDelete{$newID}) {
     2060                        unless ($nvHash) {
     2061                            $nvHash = $exifTool->GetNewValueHash($newInfo, $wrongDir);
    15092062                        }
    15102063                        # read value
    15112064                        $val = ReadValue(\$oldValue, 0, $readFormName, $readCount, $oldSize);
    1512                         if ($$newInfo{Format}) {
    1513                             $newFormName = $$newInfo{Format};
    1514                             # override existing format if necessary
    1515                             $ifdFormName = $$newInfo{Writable};
    1516                             $ifdFormName = $oldFormName unless $ifdFormName and $ifdFormName ne '1';
     2065                        # determine write format (by default, use 'Writable' format)
     2066                        my $writable = $$newInfo{Writable};
     2067                        # (or use existing format if 'Writable' not specified)
     2068                        $writable = $oldFormName unless $writable and $writable ne '1';
     2069                        # (and override write format with 'Format' if specified)
     2070                        my $writeForm = $$newInfo{Format} || $writable;
     2071                        if ($writeForm ne $newFormName) {
     2072                            # write in specified format
     2073                            $newFormName = $writeForm;
    15172074                            $newFormat = $formatNumber{$newFormName};
     2075                            # use different IFD format code if necessary
     2076                            if ($inMakerNotes) {
     2077                                # always preserve IFD format in maker notes
     2078                                $ifdFormName = $oldFormName;
     2079                            } elsif ($writable ne $newFormName) {
     2080                                # use specified IFD format
     2081                                $ifdFormName = $writable;
     2082                            }
    15182083                        }
    15192084                        if ($inMakerNotes and $readFormName ne 'string' and $readFormName ne 'undef') {
     
    15212086                            $newCount = $oldCount * $formatSize[$oldFormat] / $formatSize[$newFormat];
    15222087                        }
    1523                         $isOverwriting = Image::ExifTool::IsOverwriting($newValueHash, $val);
     2088                        if ($$newInfo{IsOverwriting}) {
     2089                            my $proc = $$newInfo{IsOverwriting};
     2090                            $isOverwriting = &$proc($exifTool, $nvHash, $val, \$newVal);
     2091                        } else {
     2092                            $isOverwriting = Image::ExifTool::IsOverwriting($nvHash, $val);
     2093                        }
    15242094                    }
    15252095                    if ($isOverwriting) {
    1526                         $newVal = Image::ExifTool::GetNewValues($newValueHash) unless defined $newVal;
     2096                        $newVal = Image::ExifTool::GetNewValues($nvHash) unless defined $newVal;
    15272097                        # value undefined if deleting this tag
    15282098                        # (also delete tag if cross-deleting and this isn't a date/time shift)
    1529                         if (not defined $newVal or ($xDelete{$newID} and not defined $$newValueHash{Shift})) {
    1530                             if ($$newInfo{RawConvInv} and defined $$newValueHash{Value}) {
     2099                        if (not defined $newVal or ($xDelete{$newID} and not defined $$nvHash{Shift})) {
     2100                            if ($$newInfo{RawConvInv} and defined $$nvHash{Value}) {
    15312101                                goto NoOverwrite;   # error in RawConvInv, so rewrite existing tag
    15322102                            }
    15332103                            unless ($isNew) {
    15342104                                ++$exifTool->{CHANGED};
    1535                                 $val = $exifTool->Printable($val);
    1536                                 $verbose > 1 and print $out "    - $dirName:$$newInfo{Name} = '$val'\n";
     2105                                $exifTool->VerboseValue("- $dirName:$$newInfo{Name}", $val);
    15372106                            }
    15382107                            next;
    15392108                        }
    1540                         if (length $newVal) {
    1541                             if ($newCount and $newCount < 0) {
    1542                                 # set count to number of values if variable
    1543                                 my @vals = split ' ',$newVal;
    1544                                 $newCount = @vals;
    1545                             }
    1546                             # convert to binary format
    1547                             $newValue = WriteValue($newVal, $newFormName, $newCount);
    1548                             unless (defined $newValue) {
    1549                                 $exifTool->Warn("Error writing $dirName:$$newInfo{Name}");
     2109                        if ($newCount and $newCount < 0) {
     2110                            # set count to number of values if variable
     2111                            my @vals = split ' ',$newVal;
     2112                            $newCount = @vals;
     2113                        }
     2114                        # convert to binary format
     2115                        $newValue = WriteValue($newVal, $newFormName, $newCount);
     2116                        unless (defined $newValue) {
     2117                            $exifTool->Warn("Error writing $dirName:$$newInfo{Name}");
     2118                            goto NoOverwrite;
     2119                        }
     2120                        if (length $newValue) {
     2121                            # limit maximum value length in JPEG images
     2122                            # (max segment size is 65533 bytes and the min EXIF size is 96 incl an additional IFD entry)
     2123                            if ($$exifTool{FILE_TYPE} eq 'JPEG' and length($newValue) > 65436 and
     2124                                $$newInfo{Name} ne 'PreviewImage')
     2125                            {
     2126                                my $name = $$newInfo{MakerNotes} ? 'MakerNotes' : $$newInfo{Name};
     2127                                $exifTool->Warn("$name too large to write in JPEG segment");
    15502128                                goto NoOverwrite;
    15512129                            }
    15522130                        } else {
    1553                             $exifTool->Warn("Can't write zero length $$newInfo{Name} in $tagTablePtr->{GROUPS}->{1}");
     2131                            $exifTool->Warn("Can't write zero length $$newInfo{Name} in $tagTablePtr->{GROUPS}{1}");
    15542132                            goto NoOverwrite;
    15552133                        }
     
    15572135                            $newCount = length($newValue) / $formatSize[$newFormat];
    15582136                            ++$exifTool->{CHANGED};
     2137                            if (defined $allMandatory) {
     2138                                # not all mandatory if we are writing any tag specifically
     2139                                if ($nvHash) {
     2140                                    undef $allMandatory;
     2141                                    undef $deleteAll;
     2142                                } else {
     2143                                    ++$addMandatory;    # count mandatory tags that we added
     2144                                }
     2145                            }
    15592146                            if ($verbose > 1) {
    1560                                 $val = $exifTool->Printable($val);
    1561                                 $newVal = $exifTool->Printable($newVal);
    1562                                 print $out "    - $dirName:$$newInfo{Name} = '$val'\n" unless $isNew;
    1563                                 my $str = $newValueHash ? '' : ' (mandatory)';
    1564                                 print $out "    + $dirName:$$newInfo{Name} = '$newVal'$str\n";
     2147                                $exifTool->VerboseValue("- $dirName:$$newInfo{Name}", $val) unless $isNew;
     2148                                my $str = $nvHash ? '' : ' (mandatory)';
     2149                                $exifTool->VerboseValue("+ $dirName:$$newInfo{Name}", $newVal, $str);
    15652150                            }
    15662151                        }
     
    15792164# create new subdirectory
    15802165#
    1581                     $newInfo = $$addDirs{$newID} or warn('internal error'), next;
     2166                    # newInfo may not be defined if we try to add a mandatory tag
     2167                    # to a directory that doesn't support it (ie. IFD1 in RW2 images)
     2168                    $newInfo = $$addDirs{$newID} or next;
    15822169                    # make sure we don't try to generate a new MakerNotes directory
    15832170                    # or a SubIFD
    15842171                    next if $$newInfo{MakerNotes} or $$newInfo{Name} eq 'SubIFD';
    15852172                    my $subTable;
    1586                     if ($newInfo->{SubDirectory}->{TagTable}) {
    1587                         $subTable = GetTagTable($newInfo->{SubDirectory}->{TagTable});
     2173                    if ($newInfo->{SubDirectory}{TagTable}) {
     2174                        $subTable = Image::ExifTool::GetTagTable($newInfo->{SubDirectory}{TagTable});
    15882175                    } else {
    15892176                        $subTable = $tagTablePtr;
     
    15942181                        Fixup => new Image::ExifTool::Fixup,
    15952182                    );
    1596                     $sourceDir{DirName} = $newInfo->{Groups}->{1} if $$newInfo{SubIFD};
     2183                    $sourceDir{DirName} = $newInfo->{Groups}{1} if $$newInfo{SubIFD};
    15972184                    $newValue = $exifTool->WriteDirectory(\%sourceDir, $subTable);
    15982185                    # only add new directory if it isn't empty
     
    16142201                    } else {
    16152202                        # subdirectory goes directly into value buffer
    1616                         $sourceDir{Fixup}->{Start} += length($valBuff);
     2203                        $sourceDir{Fixup}{Start} += length($valBuff);
    16172204                        # use Writable to set format, otherwise 'undef'
    16182205                        $newFormName = $$newInfo{Writable};
     
    16352222                $newFormat = $oldFormat; # (just in case it changed)
    16362223                $newFormName = $oldFormName;
     2224                # set offset of this entry in the directory so we can update the pointer
     2225                # and save block information to copy this large block later
     2226                if ($oldImageData) {
     2227                    $$oldImageData[3] = $newStart + length($dirBuff) + 2;
     2228                    push @imageData, $oldImageData;
     2229                    $$origDirInfo{ImageData} = \@imageData;
     2230                }
    16372231            }
    16382232            if ($newInfo) {
     
    16432237                    my $dataTag = $$newInfo{DataTag};
    16442238                    # load data for this tag
    1645                     unless (defined $offsetData{$dataTag}) {
    1646                         $offsetData{$dataTag} = $exifTool->GetNewValues($dataTag);
     2239                    unless (defined $offsetData{$dataTag} or $dataTag eq 'LeicaTrailer') {
     2240                        # prefer tag from Composite table if it exists (otherwise
     2241                        # PreviewImage data would be taken from Extra tag)
     2242                        my $compInfo = $Image::ExifTool::Composite{$dataTag};
     2243                        $offsetData{$dataTag} = $exifTool->GetNewValues($compInfo || $dataTag);
    16472244                        my $err;
    16482245                        if (defined $offsetData{$dataTag}) {
    1649                             if ($exifTool->{FILE_TYPE} eq 'JPEG' and
    1650                                 $dataTag ne 'PreviewImage' and length($offsetData{$dataTag}) > 60000)
    1651                             {
     2246                            my $len = length $offsetData{$dataTag};
     2247                            if ($dataTag eq 'PreviewImage') {
     2248                                # must set DEL_PREVIEW flag now if preview fit into IFD
     2249                                $$exifTool{DEL_PREVIEW} = 1 if $len <= 4;
     2250                            } elsif ($exifTool->{FILE_TYPE} eq 'JPEG' and $len > 60000) {
    16522251                                delete $offsetData{$dataTag};
    16532252                                $err = "$dataTag not written (too large for JPEG segment)";
     
    16682267                if ($$newInfo{MakerNotes}) {
    16692268                    # don't write new makernotes if we are deleting this group
    1670                     if ($exifTool->{DEL_GROUP}->{MakerNotes} and
    1671                         ($exifTool->{DEL_GROUP}->{MakerNotes} != 2 or $isNew <= 0))
     2269                    if ($exifTool->{DEL_GROUP}{MakerNotes} and
     2270                       ($exifTool->{DEL_GROUP}{MakerNotes} != 2 or $isNew <= 0))
    16722271                    {
    16732272                        if ($isNew <= 0) {
     
    16812280                        # we are writing a whole new maker note block
    16822281                        # --> add fixup information if necessary
    1683                         my $newValueHash = $exifTool->GetNewValueHash($newInfo, $dirName);
    1684                         if ($newValueHash and $newValueHash->{MAKER_NOTE_FIXUP}) {
     2282                        my $nvHash = $exifTool->GetNewValueHash($newInfo, $dirName);
     2283                        if ($nvHash and $nvHash->{MAKER_NOTE_FIXUP}) {
    16852284                            # must clone fixup because we will be shifting it
    1686                             my $makerFixup = $newValueHash->{MAKER_NOTE_FIXUP}->Clone();
     2285                            my $makerFixup = $nvHash->{MAKER_NOTE_FIXUP}->Clone();
    16872286                            my $valLen = length($valBuff);
    16882287                            $makerFixup->{Start} += $valLen;
     
    16922291                        # update maker notes if possible
    16932292                        my %subdirInfo = (
    1694                             Base => $base,
    1695                             DataPt => $valueDataPt,
    1696                             DataPos => $valueDataPos,
    1697                             DataLen => $valueDataLen,
     2293                            Base     => $base,
     2294                            DataPt   => $valueDataPt,
     2295                            DataPos  => $valueDataPos,
     2296                            DataLen  => $valueDataLen,
    16982297                            DirStart => $valuePtr,
    1699                             DirLen => $oldSize,
    1700                             DirName => 'MakerNotes',
    1701                             Parent => $dirName,
    1702                             TagInfo => $newInfo,
    1703                             RAF => $raf,
     2298                            DirLen   => $oldSize,
     2299                            DirName  => 'MakerNotes',
     2300                            Name     => $$newInfo{Name},
     2301                            Parent   => $dirName,
     2302                            TagInfo  => $newInfo,
     2303                            RAF      => $raf,
    17042304                        );
     2305                        my ($subTable, $subdir, $loc, $writeProc, $notIFD);
    17052306                        if ($$newInfo{SubDirectory}) {
    17062307                            my $sub = $$newInfo{SubDirectory};
     
    17082309                            $subdirInfo{FixOffsets} = $$sub{FixOffsets};
    17092310                            $subdirInfo{EntryBased} = $$sub{EntryBased};
    1710                             $subdirInfo{NoFixBase} = 1 if $$sub{Base};
     2311                            $subdirInfo{NoFixBase} = 1 if defined $$sub{Base};
     2312                            $subdirInfo{AutoFix} = $$sub{AutoFix};
    17112313                        }
    17122314                        # get the proper tag table for these maker notes
    1713                         my $subTable;
    1714                         if ($oldInfo and $oldInfo->{SubDirectory}) {
    1715                             $subTable = $oldInfo->{SubDirectory}->{TagTable};
     2315                        if ($oldInfo and $$oldInfo{SubDirectory}) {
     2316                            $subTable = $$oldInfo{SubDirectory}{TagTable};
    17162317                            $subTable and $subTable = Image::ExifTool::GetTagTable($subTable);
     2318                            $writeProc = $$oldInfo{SubDirectory}{WriteProc};
     2319                            $notIFD = $$oldInfo{NotIFD};
    17172320                        } else {
    17182321                            $exifTool->Warn('Internal problem getting maker notes tag table');
    17192322                        }
    17202323                        $subTable or $subTable = $tagTablePtr;
    1721                         my $subdir;
    1722                         # look for IFD-style maker notes
    1723                         my $loc = Image::ExifTool::MakerNotes::LocateIFD($exifTool,\%subdirInfo);
     2324                        if ($writeProc and
     2325                            $writeProc eq \&Image::ExifTool::MakerNotes::WriteUnknownOrPreview and
     2326                            $oldValue =~ /^\xff\xd8\xff/)
     2327                        {
     2328                            $loc = 0;
     2329                        } elsif (not $notIFD) {
     2330                            # look for IFD-style maker notes
     2331                            $loc = Image::ExifTool::MakerNotes::LocateIFD($exifTool,\%subdirInfo);
     2332                        }
    17242333                        if (defined $loc) {
    17252334                            # we need fixup data for this subdirectory
    17262335                            $subdirInfo{Fixup} = new Image::ExifTool::Fixup;
    17272336                            # rewrite maker notes
    1728                             $subdir = $exifTool->WriteDirectory(\%subdirInfo, $subTable);
     2337                            $subdir = $exifTool->WriteDirectory(\%subdirInfo, $subTable, $writeProc);
    17292338                        } elsif ($$subTable{PROCESS_PROC} and
    17302339                                 $$subTable{PROCESS_PROC} eq \&Image::ExifTool::ProcessBinaryData)
    17312340                        {
    1732                             my $sub = $oldInfo->{SubDirectory};
     2341                            my $sub = $$oldInfo{SubDirectory};
    17332342                            if (defined $$sub{Start}) {
    17342343                                #### eval Start ($valuePtr)
     
    17422351                            # rewrite maker notes
    17432352                            $subdir = $exifTool->WriteDirectory(\%subdirInfo, $subTable);
    1744                         } else {
    1745                             $exifTool->Warn('Maker notes could not be parsed',1);
     2353                        } elsif (not $notIFD) {
     2354                            my $msg = 'Maker notes could not be parsed';
     2355                            if ($$exifTool{FILE_TYPE} eq 'JPEG') {
     2356                                $exifTool->Warn($msg, 1);
     2357                            } else {
     2358                                $exifTool->Error($msg, 1);
     2359                            }
    17462360                        }
    17472361                        if (defined $subdir) {
     
    17632377                                    # remove all but PreviewImage fixup (since others shouldn't change)
    17642378                                    foreach (keys %{$makerFixup->{Pointers}}) {
    1765                                         /_PreviewImage$/ or delete $makerFixup->{Pointers}->{$_};
     2379                                        /_PreviewImage$/ or delete $makerFixup->{Pointers}{$_};
    17662380                                    }
    17672381                                    # zero pointer so we can see how it gets shifted later
     
    17742388                                    $previewInfo->{Relative} = 1;
    17752389                                }
     2390                            # don't shift anything if relative flag set to zero (Pentax patch)
    17762391                            } elsif (not defined $subdirInfo{Relative}) {
    1777                                 # don't shift anything if relative flag set to zero (Pentax patch)
     2392                                # shift offset base if shifted in the original image or if FixBase
     2393                                # was used, but be careful of automatic FixBase with negative shifts
     2394                                # since they may lead to negative (invalid) offsets (casio_edit_problem.jpg)
    17782395                                my $baseShift = $base - $subdirInfo{Base};
     2396                                if ($subdirInfo{AutoFix}) {
     2397                                    $baseShift = 0;
     2398                                } elsif ($subdirInfo{FixBase} and $baseShift < 0 and
     2399                                    # allow negative base shift if offsets are bigger (PentaxOptioWP.jpg)
     2400                                    (not $subdirInfo{MinOffset} or $subdirInfo{MinOffset} + $baseShift < 0))
     2401                                {
     2402                                    my $fixBase = $exifTool->Options('FixBase');
     2403                                    if (not defined $fixBase) {
     2404                                        my $str = $exifTool->Options('IgnoreMinorErrors') ? 'ignored' : 'fix or ignore?';
     2405                                        $exifTool->Error("MakerNotes offsets may be incorrect ($str)", 1);
     2406                                    } elsif ($fixBase eq '') {
     2407                                        $exifTool->Warn('Fixed incorrect MakerNotes offsets');
     2408                                        $baseShift = 0;
     2409                                    }
     2410                                }
    17792411                                $makerFixup->{Start} += $valLen + $loc;
    17802412                                $makerFixup->{Shift} += $baseShift;
     2413                                # permanently fix makernote offset errors
     2414                                $makerFixup->{Shift} += $subdirInfo{FixedBy} || 0;
    17812415                                push @valFixups, $makerFixup;
    17822416                                if ($previewInfo and not $previewInfo->{NoBaseShift}) {
     
    18002434# rewrite existing sub IFD's
    18012435#
    1802                         my $subdirName = $newInfo->{Groups}->{1} || $$newInfo{Name};
     2436                        my $subTable = $tagTablePtr;
     2437                        if ($$subdir{TagTable}) {
     2438                            $subTable = Image::ExifTool::GetTagTable($$subdir{TagTable});
     2439                        }
     2440                        # determine directory name for this IFD
     2441                        my $subdirName = $newInfo->{Groups}{1} || $$newInfo{Name};
     2442                        # all makernotes directory names must be 'MakerNotes'
     2443                        $subdirName = 'MakerNotes' if $subTable->{GROUPS}{0} eq 'MakerNotes';
    18032444                        # must handle sub-IFD's specially since the values
    18042445                        # are actually offsets to subdirectories
    18052446                        unless ($readCount) {   # can't have zero count
    1806                             return undef if $exifTool->Error("$dirName entry $index has zero count", 1);
     2447                            return undef if $exifTool->Error("$name entry $index has zero count", 1);
    18072448                            next;
    18082449                        }
     
    18172458                            my $subdirBase = $base;
    18182459                            if ($$subdir{Base}) {
    1819                                 my $start = $subdirStart + $valueDataPos;
    1820                                 #### eval Base ($start)
     2460                                my $start = $subdirStart + $dataPos;
     2461                                #### eval Base ($start,$base)
    18212462                                $subdirBase += eval $$subdir{Base};
    18222463                            }
     2464                            # add IFD number if more than one
     2465                            $subdirName =~ s/\d*$/$i/ if $i;
    18232466                            my %subdirInfo = (
    1824                                 Base => $subdirBase,
    1825                                 DataPt => $dataPt,
    1826                                 DataPos => $dataPos - $subdirBase + $base,
    1827                                 DataLen => $dataLen,
     2467                                Base     => $subdirBase,
     2468                                DataPt   => $dataPt,
     2469                                DataPos  => $dataPos - $subdirBase + $base,
     2470                                DataLen  => $dataLen,
    18282471                                DirStart => $subdirStart,
    1829                                 DirName => $subdirName . ($i ? $i : ''),
    1830                                 Parent => $dirName,
    1831                                 Fixup => new Image::ExifTool::Fixup,
    1832                                 RAF => $raf,
     2472                                DirName  => $subdirName,
     2473                                Name     => $$newInfo{Name},
     2474                                TagInfo  => $newInfo,
     2475                                Parent   => $dirName,
     2476                                Fixup    => new Image::ExifTool::Fixup,
     2477                                RAF      => $raf,
     2478                                Subdir   => $subdir,
     2479                                # set ImageData only for 1st level SubIFD's
     2480                                ImageData=> $imageDataFlag eq 'Main' ? 'SubIFD' : undef,
    18332481                            );
    1834                             # read IFD from file if necessary
     2482                            # pass on header pointer only for certain sub IFD's
     2483                            $subdirInfo{HeaderPtr} = $$dirInfo{HeaderPtr} if $$newInfo{SubIFD} == 2;
     2484                            if ($$subdir{RelativeBase}) {
     2485                                # apply one-time fixup if offsets are relative (Sony IDC hack)
     2486                                delete $subdirInfo{Fixup};
     2487                                delete $subdirInfo{ImageData};
     2488                            }
     2489                            # is the subdirectory outside our current data?
    18352490                            if ($subdirStart < 0 or $subdirStart + 2 > $dataLen) {
    1836                                 my ($buff, $buf2, $subSize);
    1837                                 unless ($raf and $raf->Seek($pt + $base, 0) and
    1838                                         $raf->Read($buff,2) == 2 and
    1839                                         $subSize = 12 * Get16u(\$buff, 0) and
    1840                                         $raf->Read($buf2,$subSize+4) >= $subSize)
    1841                                 {
    1842                                     if (defined $subSize and not $subSize) {
    1843                                         return undef if $exifTool->Error("$subdirName IFD has zero entries", 1);
    1844                                         next Entry;
     2491                                if ($raf) {
     2492                                    # reset SubDirectory buffer (we will load it later)
     2493                                    my $buff = '';
     2494                                    $subdirInfo{DataPt} = \$buff;
     2495                                    $subdirInfo{DataLen} = 0;
     2496                                } else {
     2497                                    my @err = ("Can't read $subdirName data", $inMakerNotes);
     2498                                    if ($$subTable{VARS} and $subTable->{VARS}{MINOR_ERRORS}) {
     2499                                        $exifTool->Warn($err[0] . '. Ignored.');
     2500                                    } elsif ($exifTool->Error(@err)) {
     2501                                        return undef;
    18452502                                    }
    1846                                     return undef if $exifTool->Error("Can't read $subdirName data", $inMakerNotes);
    1847                                     next Entry;
     2503                                    next Entry; # don't write this directory
    18482504                                }
    1849                                 $buff .= $buf2;
    1850                                 # change subdirectory information to data we just read
    1851                                 $subdirInfo{DataPt} = \$buff;
    1852                                 $subdirInfo{DirStart} = 0;
    1853                                 $subdirInfo{DataPos} = $pt;
    1854                                 $subdirInfo{DataLen} = length $buff;
    1855                                 # only account for nextIFD pointer if we will use it
    1856                                 $subSize += 4 if length($buff)==$subSize+6 and
    1857                                     ($$newInfo{Name} eq 'SubIFD' or $buff =~ /\0{4}$/);
    1858                                 UpdateTiffEnd($exifTool, $pt+$base+2+$subSize);
    18592505                            }
    1860                             my $subTable = $tagTablePtr;
    1861                             if ($$subdir{TagTable}) {
    1862                                 $subTable = GetTagTable($$subdir{TagTable});
     2506                            my $subdirData = $exifTool->WriteDirectory(\%subdirInfo, $subTable, $$subdir{WriteProc});
     2507                            unless (defined $subdirData) {
     2508                                # WriteDirectory should have issued an error, but check just in case
     2509                                $exifTool->Error("Error writing $subdirName") unless $$exifTool{VALUE}{Error};
     2510                                return undef;
    18632511                            }
    1864                             my $subdirData = $exifTool->WriteDirectory(\%subdirInfo, $subTable);
    1865                             return undef unless defined $subdirData;
    1866                             next unless length($subdirData);
     2512                            unless (length $subdirData) {
     2513                                next unless $inMakerNotes;
     2514                                # don't delete MakerNote Sub-IFD's, write empty IFD instead
     2515                                $subdirData = "\0" x 6;
     2516                                # reset SubIFD ImageData and Fixup just to be safe
     2517                                delete $subdirInfo{ImageData};
     2518                                delete $subdirInfo{Fixup};
     2519                            }
     2520                            # handle data blocks that we will transfer later
     2521                            if (ref $subdirInfo{ImageData}) {
     2522                                push @imageData, @{$subdirInfo{ImageData}};
     2523                                $$origDirInfo{ImageData} = \@imageData;
     2524                            }
    18672525                            # temporarily set value to subdirectory index
    18682526                            # (will set to actual offset later when we know what it is)
     
    18782536                            # add to list of subdirectories we will append later
    18792537                            push @subdirs, {
    1880                                 DataPt => \$subdirData,
    1881                                 Table => $subTable,
    1882                                 Fixup => $subdirInfo{Fixup},
    1883                                 Offset => $offset,
    1884                                 Where => $where,
     2538                                DataPt    => \$subdirData,
     2539                                Table     => $subTable,
     2540                                Fixup     => $subdirInfo{Fixup},
     2541                                Offset    => $offset,
     2542                                Where     => $where,
     2543                                ImageData => $subdirInfo{ImageData},
    18852544                            };
    18862545                            ++$writeCount;  # count number of subdirs written
     
    18902549                        # a directory and only one remains
    18912550                        if ($writeCount < $readCount and $writeCount == 1) {
    1892                             $subdirs[-1]->{Where} = 'dirBuff';
    1893                             $subdirs[-1]->{Offset} = length($dirBuff) + 8;
     2551                            $subdirs[-1]{Where} = 'dirBuff';
     2552                            $subdirs[-1]{Offset} = length($dirBuff) + 8;
    18942553                        }
    18952554                        # set new format to int32u for IFD
     
    19162575                        if ($$subdir{Base}) {
    19172576                            my $start = $subdirStart + $valueDataPos;
    1918                             #### eval Base ($start)
     2577                            #### eval Base ($start,$base)
    19192578                            $subdirBase += eval $$subdir{Base};
    19202579                        }
    19212580                        my $subFixup = new Image::ExifTool::Fixup;
    19222581                        my %subdirInfo = (
    1923                             Base => $subdirBase,
    1924                             DataPt => $valueDataPt,
    1925                             DataPos => $valueDataPos - $subdirBase + $base,
    1926                             DataLen => $valueDataLen,
     2582                            Base     => $subdirBase,
     2583                            DataPt   => $valueDataPt,
     2584                            DataPos  => $valueDataPos - $subdirBase + $base,
     2585                            DataLen  => $valueDataLen,
    19272586                            DirStart => $subdirStart,
    1928                             DirName => $$subdir{DirName},
    1929                             DirLen => $oldSize,
    1930                             Parent => $dirName,
    1931                             Fixup => $subFixup,
    1932                             RAF => $raf,
     2587                            DirName  => $$subdir{DirName},
     2588                            DirLen   => $oldSize,
     2589                            Parent   => $dirName,
     2590                            Fixup    => $subFixup,
     2591                            RAF      => $raf,
     2592                            TagInfo  => $newInfo,
    19332593                        );
    1934                         my $subTable = GetTagTable($$subdir{TagTable});
    1935                         $newValue = $exifTool->WriteDirectory(\%subdirInfo, $subTable);
     2594                        unless ($oldSize) {
     2595                            # replace with dummy data if empty to prevent WriteDirectory
     2596                            # routines from accessing data they shouldn't
     2597                            my $tmp = '';
     2598                            $subdirInfo{DataPt} = \$tmp;
     2599                            $subdirInfo{DataLen} = 0;
     2600                            $subdirInfo{DirStart} = 0;
     2601                            $subdirInfo{DataPos} += $subdirStart;
     2602                        }
     2603                        my $subTable = Image::ExifTool::GetTagTable($$subdir{TagTable});
     2604                        my $oldOrder = GetByteOrder();
     2605                        SetByteOrder($$subdir{ByteOrder}) if $$subdir{ByteOrder};
     2606                        $newValue = $exifTool->WriteDirectory(\%subdirInfo, $subTable, $$subdir{WriteProc});
     2607                        SetByteOrder($oldOrder);
    19362608                        if (defined $newValue) {
    19372609                            my $hdrLen = $subdirStart - $valuePtr;
     
    19462618                            return undef;
    19472619                        }
    1948                         next unless length $$newValuePt;
     2620                        unless (length $$newValuePt) {
     2621                            # don't delete a previously empty makernote directory
     2622                            next if $oldSize or not $inMakerNotes;
     2623                        }
    19492624                        if ($subFixup->{Pointers} and $subdirInfo{Base} == $base) {
    19502625                            $subFixup->{Start} += length $valBuff;
     
    19642639                        # must decide now if we will write CanonVRD information
    19652640                        my $hasVRD;
    1966                         if ($exifTool->{NEW_VALUE}->{$Image::ExifTool::Extra{CanonVRD}}) {
     2641                        if ($exifTool->{NEW_VALUE}{$Image::ExifTool::Extra{CanonVRD}}) {
    19672642                            # adding or deleting as a block
    19682643                            $hasVRD = $exifTool->GetNewValues('CanonVRD') ? 1 : 0;
    1969                         } elsif ($exifTool->{DEL_GROUP}->{CanonVRD} or
    1970                                  $exifTool->{DEL_GROUP}->{Trailer})
     2644                        } elsif ($exifTool->{DEL_GROUP}{CanonVRD} or
     2645                                 $exifTool->{DEL_GROUP}{Trailer})
    19712646                        {
    19722647                            $hasVRD = 0;    # deleting as a group
     
    19822657                            $newValuePt = \$newValue;
    19832658                        }
     2659                    } elsif ($dataTag eq 'OriginalDecisionData') {
     2660                        # handle Canon OriginalDecisionData (no associated length tag)
     2661                        # - I'm going out of my way here to preserve data which is
     2662                        #   invalidated anyway by our edits
     2663                        my $odd;
     2664                        my $oddInfo = $Image::ExifTool::Composite{OriginalDecisionData};
     2665                        if ($oddInfo and $exifTool->{NEW_VALUE}{$oddInfo}) {
     2666                            $odd = $exifTool->GetNewValues($dataTag);
     2667                            if ($verbose > 1) {
     2668                                print $out "    - $dirName:$dataTag\n" if $$newValuePt ne "\0\0\0\0";
     2669                                print $out "    + $dirName:$dataTag\n" if $odd;
     2670                            }
     2671                            ++$exifTool->{CHANGED};
     2672                        } elsif ($$newValuePt ne "\0\0\0\0") {
     2673                            if (length($$newValuePt) == 4) {
     2674                                require Image::ExifTool::Canon;
     2675                                my $offset = Get32u($newValuePt,0);
     2676                                # absolute offset in JPEG images only
     2677                                $offset += $base unless $$exifTool{FILE_TYPE} eq 'JPEG';
     2678                                $odd = Image::ExifTool::Canon::ReadODD($exifTool, $offset);
     2679                                $odd = $$odd if ref $odd;
     2680                            } else {
     2681                                $exifTool->Error("Invalid $$newInfo{Name}",1);
     2682                            }
     2683                        }
     2684                        if ($odd) {
     2685                            my $newOffset = length($valBuff);
     2686                            # (ODD offset is absolute in JPEG, so add base offset!)
     2687                            $newOffset += $base if $$exifTool{FILE_TYPE} eq 'JPEG';
     2688                            $newValue = Set32u($newOffset);
     2689                            $dirFixup->AddFixup(length($dirBuff) + 8, $dataTag);
     2690                            $valBuff .= $odd;   # add original decision data
     2691                        } else {
     2692                            $newValue = "\0\0\0\0";
     2693                        }
     2694                        $newValuePt = \$newValue;
    19842695                    } else {
    19852696                        my $offsetInfo = $offsetInfo[$ifd];
     
    19872698                        my @vals;
    19882699                        if ($isNew <= 0) {
     2700                            my $oldOrder = GetByteOrder();
     2701                            # Minolta A200 stores these in the wrong byte order!
     2702                            SetByteOrder($$newInfo{ByteOrder}) if $$newInfo{ByteOrder};
    19892703                            @vals = ReadValue(\$oldValue, 0, $readFormName, $readCount, $oldSize);
     2704                            SetByteOrder($oldOrder);
    19902705                        }
    19912706                        # only support int32 pointers (for now)
    19922707                        if ($formatSize[$newFormat] != 4 and $$newInfo{IsOffset}) {
    1993                             die "Internal error (Offset not int32)" if $isNew > 0;
    1994                             die "Wrong count!" if $newCount != $readCount;
     2708                            $isNew > 0 and warn("Internal error (Offset not int32)"), return undef;
     2709                            $newCount != $readCount and warn("Wrong count!"), return undef;
    19952710                            # change to int32
    19962711                            $newFormName = 'int32u';
    19972712                            $newFormat = $formatNumber{$newFormName};
    19982713                            $newValue = WriteValue(join(' ',@vals), $newFormName, $newCount);
    1999                             die "Internal error writing offsets\n" unless defined $newValue;
     2714                            unless (defined $newValue) {
     2715                                warn "Internal error writing offsets for $$newInfo{Name}\n";
     2716                                return undef;
     2717                            }
    20002718                        }
    20012719                        $offsetInfo or $offsetInfo = $offsetInfo[$ifd] = { };
     
    20112729                } elsif ($$newInfo{DataMember}) {
    20122730
    2013                     # save any necessary data members (CameraMake, CameraModel)
    2014                     $exifTool->{$$newInfo{DataMember}} = $$newValuePt;
     2731                    # save any necessary data members (Make, Model, etc)
     2732                    my $formatStr = $newFormName;
     2733                    my $count = $newCount;
     2734                    # change to specified format if necessary
     2735                    if ($$newInfo{Format} and $$newInfo{Format} ne $formatStr) {
     2736                        $formatStr = $$newInfo{Format};
     2737                        my $format = $formatNumber{$formatStr};
     2738                        # adjust number of items for new format size
     2739                        $count = int(length($$newValuePt) / $formatSize[$format]) if $format;
     2740                    }
     2741                    my $val = ReadValue($newValuePt,0,$formatStr,$count,length($$newValuePt));
     2742                    my $conv = $$newInfo{RawConv};
     2743                    if ($conv) {
     2744                        # let the RawConv store the (possibly converted) data member
     2745                        if (ref $conv eq 'CODE') {
     2746                            &$conv($val, $exifTool);
     2747                        } else {
     2748                            my ($self, $tag, $taginfo) = ($exifTool, $$newInfo{Name}, $newInfo);
     2749                            #### eval RawConv ($self, $val, $tag, $tagInfo)
     2750                            eval $conv;
     2751                        }
     2752                    } else {
     2753                        $$exifTool{$$newInfo{DataMember}} = $val;
     2754                    }
    20152755                }
    20162756            }
     
    20362776                    $offsetVal = Set32u(length $valBuff);
    20372777                }
    2038                 my $dataTag;
    2039                 if ($newInfo and $$newInfo{DataTag}) {
    2040                     $dataTag = $$newInfo{DataTag};
    2041                     if ($dataTag eq 'PreviewImage' and $exifTool->{FILE_TYPE} eq 'JPEG') {
     2778                my ($dataTag, $putFirst);
     2779                ($dataTag, $putFirst) = @$newInfo{'DataTag','PutFirst'} if $newInfo;
     2780                if ($dataTag) {
     2781                    if ($dataTag eq 'PreviewImage' and ($exifTool->{FILE_TYPE} eq 'JPEG' or
     2782                        $$exifTool{GENERATE_PREVIEW_INFO}))
     2783                    {
    20422784                        # hold onto the PreviewImage until we can determine if it fits
    20432785                        $exifTool->{PREVIEW_INFO} or $exifTool->{PREVIEW_INFO} = { };
    2044                         $exifTool->{PREVIEW_INFO}->{Data} = $$newValuePt;
    2045                         if ($$newInfo{Name} eq 'PreviewImage') {
    2046                             $exifTool->{PREVIEW_INFO}->{IsValue} = 1;
    2047                         }
     2786                        $exifTool->{PREVIEW_INFO}{Data} = $$newValuePt;
     2787                        $exifTool->{PREVIEW_INFO}{ChangeBase} = 1 if $$newInfo{ChangeBase};
    20482788                        if ($$newInfo{IsOffset} and $$newInfo{IsOffset} eq '2') {
    2049                             $exifTool->{PREVIEW_INFO}->{NoBaseShift} = 1;
    2050                         }
     2789                            $exifTool->{PREVIEW_INFO}{NoBaseShift} = 1;
     2790                        }
     2791                        # use original preview size if we will attempt to load it later
     2792                        $newCount = $oldCount if $$newValuePt eq 'LOAD_PREVIEW';
    20512793                        $$newValuePt = '';
     2794                    } elsif ($dataTag eq 'LeicaTrailer' and $$exifTool{LeicaTrailer}) {
     2795                        $$newValuePt = '';
    20522796                    }
    20532797                }
    2054                 $valBuff .= $$newValuePt;       # add value data to buffer
    2055                 # must save a fixup pointer for every pointer in the directory
    2056                 if ($entryBased) {
    2057                     $entryBasedFixup or $entryBasedFixup = new Image::ExifTool::Fixup;
    2058                     $entryBasedFixup->AddFixup(length($dirBuff) + 8, $dataTag);
     2798                if ($putFirst and $$dirInfo{HeaderPtr}) {
     2799                    my $hdrPtr = $$dirInfo{HeaderPtr};
     2800                    # place this value immediately after the TIFF header
     2801                    $offsetVal = Set32u(length $$hdrPtr);
     2802                    $$hdrPtr .= $$newValuePt;
    20592803                } else {
    2060                     $dirFixup->AddFixup(length($dirBuff) + 8, $dataTag);
     2804                    $valBuff .= $$newValuePt;       # add value data to buffer
     2805                    # must save a fixup pointer for every pointer in the directory
     2806                    if ($entryBased) {
     2807                        $entryBasedFixup or $entryBasedFixup = new Image::ExifTool::Fixup;
     2808                        $entryBasedFixup->AddFixup(length($dirBuff) + 8, $dataTag);
     2809                    } else {
     2810                        $dirFixup->AddFixup(length($dirBuff) + 8, $dataTag);
     2811                    }
    20612812                }
    20622813            } else {
     
    20722823                if (defined $$mandatory{$newID}) {
    20732824                    # values must correspond to mandatory values
    2074                     my $mandVal = WriteValue($$mandatory{$newID}, $newFormName, $newCount);
     2825                    my $form = $$newInfo{Format} || $newFormName;
     2826                    my $mandVal = WriteValue($$mandatory{$newID}, $form, $newCount);
    20752827                    if (defined $mandVal and $mandVal eq $$newValuePt) {
    20762828                        ++$allMandatory;        # count mandatory tags
     
    20822834            }
    20832835        }
     2836        if ($ignoreCount) {
     2837            my $y = $ignoreCount > 1 ? 'ies' : 'y';
     2838            $exifTool->Warn("Removed $ignoreCount invalid entr$y from $name", 1);
     2839        }
     2840        if ($fixCount) {
     2841            my $s = $fixCount > 1 ? 's' : '';
     2842            $exifTool->Warn("Fixed invalid count$s for $fixCount $name tag$s", 1);
     2843        }
    20842844#..............................................................................
    20852845# write directory counts and nextIFD pointer and add value data to end of IFD
    20862846#
     2847        # determine now if there is or will be another IFD after this one
     2848        my $nextIfdOffset;
     2849        if ($dirEnd + 4 <= $dataLen) {
     2850            $nextIfdOffset = Get32u($dataPt, $dirEnd);
     2851        } else {
     2852            $nextIfdOffset = 0;
     2853        }
     2854        my $isNextIFD = ($$dirInfo{Multi} and ($nextIfdOffset or
     2855                        # account for the case where we will create the next IFD
     2856                        ($dirName eq 'IFD0' and $exifTool->{ADD_DIRS}{'IFD1'})));
    20872857        # calculate number of entries in new directory
    20882858        my $newEntries = length($dirBuff) / 12;
    2089         # delete entire directory if only mandatory tags remain
    2090         if ($newEntries < $numEntries and $allMandatory) {
     2859        # delete entire directory if we deleted a tag and only mandatory tags remain or we
     2860        # attempted to create a directory with only mandatory tags and there is no nextIFD
     2861        if ($allMandatory and not $isNextIFD and ($newEntries < $numEntries or $numEntries == 0)) {
    20912862            $newEntries = 0;
    20922863            $dirBuff = '';
     
    20952866            ++$deleteAll if defined $deleteAll;
    20962867            $verbose > 1 and print $out "    - $allMandatory mandatory tag(s)\n";
     2868            $exifTool->{CHANGED} -= $addMandatory;    # didn't change these after all
    20972869        }
    20982870        if ($ifd and not $newEntries) {
     
    21272899            my $subdir;
    21282900            foreach $subdir (@subdirs) {
    2129                 my $pos = length($newData);    # position of subdirectory in data
    2130                 my $subdirFixup = $subdir->{Fixup};
    2131                 $subdirFixup->{Start} += $pos;
    2132                 $fixup->AddFixup($subdirFixup);
    2133                 $newData .= ${$subdir->{DataPt}};   # add subdirectory to our data
    2134                 undef ${$subdir->{DataPt}};         # free memory now
     2901                my $len = length($newData);         # position of subdirectory in data
     2902                my $subdirFixup = $$subdir{Fixup};
     2903                if ($subdirFixup) {
     2904                    $$subdirFixup{Start} += $len;
     2905                    $fixup->AddFixup($subdirFixup);
     2906                }
     2907                my $imageData = $$subdir{ImageData};
     2908                my $blockSize = 0;
     2909                # must also update start position for ImageData fixups
     2910                if (ref $imageData) {
     2911                    my $blockInfo;
     2912                    foreach $blockInfo (@$imageData) {
     2913                        my ($pos, $size, $pad, $entry, $subFix) = @$blockInfo;
     2914                        if ($subFix) {
     2915                            $$subFix{Start} += $len;
     2916                            # save expected image data offset for calculating shift later
     2917                            $$subFix{BlockLen} = length(${$$subdir{DataPt}}) + $blockSize;
     2918                        }
     2919                        $blockSize += $size + $pad;
     2920                    }
     2921                }
     2922                $newData .= ${$$subdir{DataPt}};    # add subdirectory to our data
     2923                undef ${$$subdir{DataPt}};          # free memory now
    21352924                # set the pointer
    2136                 my $offset = $subdir->{Offset};
     2925                my $offset = $$subdir{Offset};
    21372926                # if offset is in valBuff, it was added to the end of dirBuff
    21382927                # (plus 4 bytes for nextIFD pointer)
    2139                 $offset += length($dirBuff) + 4 if $subdir->{Where} eq 'valBuff';
     2928                $offset += length($dirBuff) + 4 if $$subdir{Where} eq 'valBuff';
    21402929                $offset += $newStart + 2;           # get offset in newData
    21412930                # check to be sure we got the right offset
    21422931                unless (Get32u(\$newData, $offset) == 0xfeedf00d) {
    2143                     $exifTool->Error("Internal error while rewriting $dirName");
     2932                    $exifTool->Error("Internal error while rewriting $name");
    21442933                    return undef;
    21452934                }
    21462935                # set the offset to the subdirectory data
    2147                 Set32u($pos, \$newData, $offset);
     2936                Set32u($len, \$newData, $offset);
    21482937                $fixup->AddFixup($offset);  # add fixup for this offset in newData
    21492938            }
     
    21632952        }
    21642953        # stop if no next IFD pointer
    2165         last unless $$dirInfo{Multi};  # stop unless scanning for multiple IFD's
    2166         my $offset;
    2167         if ($dirStart + $len + 4 <= $dataLen) {
    2168             $offset = Get32u($dataPt, $dirStart + $len);
    2169         } else {
    2170             $offset = 0;
    2171         }
    2172         if ($offset) {
     2954        last unless $isNextIFD;   # stop unless scanning for multiple IFD's
     2955        if ($nextIfdOffset) {
    21732956            # continue with next IFD
    2174             $dirStart = $offset - $dataPos;
     2957            $dirStart = $nextIfdOffset - $dataPos;
    21752958        } else {
    21762959            # create IFD1 if necessary
    2177             last unless $dirName eq 'IFD0' and $exifTool->{ADD_DIRS}->{'IFD1'};
    21782960            $verbose and print $out "  Creating IFD1\n";
    21792961            my $ifd1 = "\0" x 2;  # empty IFD1 data (zero entry count)
     
    21832965        }
    21842966        # increment IFD name
    2185         $dirName =~ s/(\d+)$//;
    2186         $dirName .= ($1 || 0) + 1;
    2187         $exifTool->{DIR_NAME} = $dirName;
    2188         next unless $offset;
     2967        my $ifdNum = $dirName =~ s/(\d+)$// ? $1 : 0;
     2968        $dirName .= $ifdNum + 1;
     2969        $$exifTool{DIR_NAME} = $$exifTool{PATH}[-1] = $dirName;
     2970        next unless $nextIfdOffset;
    21892971
    21902972        # guard against writing the same directory twice
    2191         my $addr = $offset + $base;
    2192         if ($exifTool->{PROCESSED}->{$addr}) {
    2193             $exifTool->Error("$dirName pointer references previous $exifTool->{PROCESSED}->{$addr} directory", 1);
     2973        my $addr = $nextIfdOffset + $base;
     2974        if ($exifTool->{PROCESSED}{$addr}) {
     2975            $exifTool->Error("$name pointer references previous $exifTool->{PROCESSED}{$addr} directory", 1);
    21942976            last;
    21952977        }
    2196         $exifTool->{PROCESSED}->{$addr} = $dirName;
     2978        $exifTool->{PROCESSED}{$addr} = $name;
    21972979
    21982980        if ($dirName eq 'SubIFD1' and not ValidateIFD($dirInfo, $dirStart)) {
     
    22042986            last;   # don't write bad IFD
    22052987        }
    2206         if ($exifTool->{DEL_GROUP}->{$dirName}) {
     2988        if ($exifTool->{DEL_GROUP}{$dirName}) {
    22072989            $verbose and print $out "  Deleting $dirName\n";
    22082990            $raf and $exifTool->Error("Deleting $dirName also deletes subsequent" .
    22092991                                      " IFD's and possibly image data", 1);
    22102992            ++$exifTool->{CHANGED};
    2211             if ($exifTool->{DEL_GROUP}->{$dirName} == 2 and
    2212                 $exifTool->{ADD_DIRS}->{$dirName})
     2993            if ($exifTool->{DEL_GROUP}{$dirName} == 2 and
     2994                $exifTool->{ADD_DIRS}{$dirName})
    22132995            {
    22142996                my $emptyIFD = "\0" x 2;    # start with empty IFD
     
    22203002            }
    22213003        } else {
    2222             $verbose and print $out "  Rewriting $dirName\n";
     3004            $verbose and print $out "  Rewriting $name\n";
    22233005        }
    22243006    }
     
    22283010    $fixup->ApplyFixup(\$newData);
    22293011#
     3012# determine total block size for deferred data
     3013#
     3014    my $numBlocks = scalar @imageData;  # save this so we scan only existing blocks later
     3015    my $blockSize = 0;  # total size of blocks to copy later
     3016    my $blockInfo;
     3017    foreach $blockInfo (@imageData) {
     3018        my ($pos, $size, $pad) = @$blockInfo;
     3019        $blockSize += $size + $pad;
     3020    }
     3021#
    22303022# copy over image data for IFD's, starting with the last IFD first
    22313023#
    2232     my @imageData; # image data blocks if requested
    2233     my $blockSize = 0;  # total size of blocks to copy later
    22343024    if (@offsetInfo) {
    2235         my @writeLater;  # write image data last
     3025        my $ttwLen;     # length of MRW TTW segment
     3026        my @writeLater; # write image data last
    22363027        for ($ifd=$#offsetInfo; $ifd>=-1; --$ifd) {
    22373028            # build list of offsets to process
     
    22393030            if ($ifd >= 0) {
    22403031                my $offsetInfo = $offsetInfo[$ifd] or next;
     3032                # patch Panasonic RAW/RW2 StripOffsets/StripByteCounts if necessary
     3033                my $stripOffsets = $$offsetInfo{0x111};
     3034                if ($stripOffsets and $$stripOffsets[0]{PanasonicHack}) {
     3035                    require Image::ExifTool::PanasonicRaw;
     3036                    my $err = Image::ExifTool::PanasonicRaw::PatchRawDataOffset($offsetInfo, $raf, $ifd);
     3037                    $err and $exifTool->Error($err);
     3038                }
    22413039                my $tagID;
    22423040                # loop through all tags in reverse order so we save thumbnail
    22433041                # data before main image data if both exist in the same IFD
    22443042                foreach $tagID (reverse sort keys %$offsetInfo) {
    2245                     my $tagInfo = $offsetInfo->{$tagID}->[0];
     3043                    my $tagInfo = $offsetInfo->{$tagID}[0];
    22463044                    next unless $$tagInfo{IsOffset}; # handle byte counts with offsets
    22473045                    my $sizeInfo = $offsetInfo->{$$tagInfo{OffsetPair}};
     
    22493047                    my $dataTag = $$tagInfo{DataTag};
    22503048                    # write TIFF image data (strips or tiles) later if requested
    2251                     if ($raf and defined $_[1]->{ImageData} and
    2252                         ($tagID == 0x111 or $tagID == 0x144) and
     3049                    if ($raf and defined $$origDirInfo{ImageData} and
     3050                        ($tagID == 0x111 or $tagID == 0x144 or
     3051                          # also defer writing of other big data such as JpgFromRaw in NEF
     3052                          ($$sizeInfo[3][0] and
     3053                           # (calculate approximate combined size of all blocks)
     3054                           $$sizeInfo[3][0] * scalar(@{$$sizeInfo[3]}) > 1000000)) and
     3055                        # but don't defer writing if replacing with new value
    22533056                        (not defined $dataTag or not defined $offsetData{$dataTag}))
    22543057                    {
     
    22683071                # must be the same number of offset and byte count values
    22693072                unless ($count == $count2) {
    2270                     $exifTool->Error("Offset/byteCounts disagree on count for $$tagInfo{Name}");
     3073                    $exifTool->Error("Offsets/ByteCounts disagree on count for $$tagInfo{Name}");
    22713074                    return undef;
    22723075                }
     
    22813084                }
    22823085                # get offset base and data pos (abnormal for some preview images)
    2283                 my ($dbase, $dpos);
     3086                my ($dbase, $dpos, $wrongBase, $subIfdDataFixup);
    22843087                if ($$tagInfo{IsOffset} eq '2') {
    22853088                    $dbase = $firstBase;
     
    22893092                    $dpos = $dataPos;
    22903093                }
     3094                # use different base if necessary for some offsets (Minolta A200)
     3095                if ($$tagInfo{WrongBase}) {
     3096                    my $self = $exifTool;
     3097                    #### eval WrongBase ($self)
     3098                    $wrongBase = eval $$tagInfo{WrongBase} || 0;
     3099                    $dbase += $wrongBase;
     3100                    $dpos -= $wrongBase;
     3101                } else {
     3102                    $wrongBase = 0;
     3103                }
     3104                my $oldOrder = GetByteOrder();
     3105                my $dataTag = $$tagInfo{DataTag};
     3106                # use different byte order for values of this offset pair if required (Minolta A200)
     3107                SetByteOrder($$tagInfo{ByteOrder}) if $$tagInfo{ByteOrder};
    22913108                # transfer the data referenced by all offsets of this tag
    22923109                for ($n=0; $n<$count; ++$n) {
    2293                     my $oldEnd;
     3110                    my ($oldEnd, $size);
    22943111                    if (@$oldOffset and @$oldSize) {
    22953112                        # calculate end offset of this block
     
    23003117                    my $offsetPos = $offsets + $n * 4;
    23013118                    my $byteCountPos = $byteCounts + $n * $formatSize[$format];
    2302                     my $size = ReadValue(\$newData, $byteCountPos, $formatStr, 1, 4);
    2303                     my $offset = Get32u(\$newData, $offsetPos) - $dpos;
     3119                    if ($$tagInfo{PanasonicHack}) {
     3120                        # use actual raw data length (may be different than StripByteCounts!)
     3121                        $size = $$oldSize[$n];
     3122                    } else {
     3123                        # use size of new data
     3124                        $size = ReadValue(\$newData, $byteCountPos, $formatStr, 1, 4);
     3125                    }
     3126                    my $offset = $$oldOffset[$n];
     3127                    if (defined $offset) {
     3128                        $offset -= $dpos;
     3129                    } elsif ($size != 0xfeedfeed) {
     3130                        $exifTool->Error('Internal error (no offset)');
     3131                        return undef;
     3132                    }
     3133                    my $newOffset = length($newData) - $wrongBase;
    23043134                    my $buff;
    23053135                    # look for 'feed' code to use our new data
    23063136                    if ($size == 0xfeedfeed) {
    2307                         my $dataTag = $$tagInfo{DataTag};
    23083137                        unless (defined $dataTag) {
    23093138                            $exifTool->Error("No DataTag defined for $$tagInfo{Name}");
     
    23323161                                  $oldEnd != $$oldOffset[$n+1]);
    23333162                        # preserve original image padding if specified
    2334                         if ($_[1]->{PreserveImagePadding} and $n+1 < $count and
     3163                        if ($$origDirInfo{PreserveImagePadding} and $n+1 < $count and
    23353164                            $oldEnd and $$oldOffset[$n+1] > $oldEnd)
    23363165                        {
     
    23393168                        # copy data later
    23403169                        push @imageData, [$offset+$dbase+$dpos, $size, $pad];
     3170                        $newOffset += $blockSize;   # data comes after other deferred data
     3171                        # create fixup for SubIFD ImageData
     3172                        if ($imageDataFlag eq 'SubIFD' and not $subIfdDataFixup) {
     3173                            $subIfdDataFixup = new Image::ExifTool::Fixup;
     3174                            $imageData[-1][4] = $subIfdDataFixup;
     3175                        }
    23413176                        $size += $pad; # account for pad byte if necessary
    23423177                        # return ImageData list
    2343                         $_[1]->{ImageData} = \@imageData;
     3178                        $$origDirInfo{ImageData} = \@imageData;
    23443179                    } elsif ($offset >= 0 and $offset+$size <= $dataLen) {
    23453180                        # take data from old dir data buffer
    23463181                        $buff = substr($$dataPt, $offset, $size);
     3182                    } elsif ($$exifTool{TIFF_TYPE} eq 'MRW') {
     3183                        # TTW segment must be an even 4 bytes long, so pad now if necessary
     3184                        my $n = length $newData;
     3185                        $buff = ($n & 0x03) ? "\0" x (4 - ($n & 0x03)) : '';
     3186                        $size = length($buff);
     3187                        # data exists after MRW TTW segment
     3188                        $ttwLen = length($newData) + $size unless defined $ttwLen;
     3189                        $newOffset = $offset + $dpos + $ttwLen - $dataLen;
    23473190                    } elsif ($raf and $raf->Seek($offset+$dbase+$dpos,0) and
    23483191                             $raf->Read($buff,$size) == $size)
    23493192                    {
    2350                         # data read OK
     3193                        # (data was read OK)
     3194                        # patch incorrect ThumbnailOffset in Sony A100 1.00 ARW images
     3195                        if ($$exifTool{TIFF_TYPE} eq 'ARW' and $$tagInfo{Name} eq 'ThumbnailOffset' and
     3196                            $$exifTool{Model} eq 'DSLR-A100' and $buff !~ /^\xff\xd8\xff/)
     3197                        {
     3198                            my $pos = $offset + $dbase + $dpos;
     3199                            my $try;
     3200                            if ($pos < 0x10000 and $raf->Seek($pos+0x10000,0) and
     3201                                $raf->Read($try,$size) == $size and $try =~ /^\xff\xd8\xff/)
     3202                            {
     3203                                $buff = $try;
     3204                                $exifTool->Warn('Adjusted incorrect A100 ThumbnailOffset', 1);
     3205                            } else {
     3206                                $exifTool->Error('Invalid ThumbnailImage');
     3207                            }
     3208                        }
    23513209                    } elsif ($$tagInfo{Name} eq 'ThumbnailOffset' and $offset>=0 and $offset<$dataLen) {
    23523210                        # Grrr.  The Canon 350D writes the thumbnail with an incorrect byte count
     
    23723230                            $r->Seek($tell, 0) or $exifTool->Error('Seek error'), return undef;
    23733231                        }
    2374                         $buff = 'LOAD' unless defined $buff;    # flag indicating we must load PreviewImage
     3232                        # set flag if we must load PreviewImage
     3233                        $buff = 'LOAD_PREVIEW' unless defined $buff;
    23753234                    } else {
    2376                         my $dataName = $$tagInfo{DataTag} || $$tagInfo{Name};
    2377                         return undef if $exifTool->Error("Error reading $dataName data in $dirName", $inMakerNotes);
     3235                        my $dataName = $dataTag || $$tagInfo{Name};
     3236                        return undef if $exifTool->Error("Error reading $dataName data in $name", $inMakerNotes);
    23783237                        $buff = '';
    23793238                    }
    2380                     if ($$tagInfo{Name} eq 'PreviewImageStart' and $exifTool->{FILE_TYPE} eq 'JPEG') {
    2381                         # hold onto the PreviewImage until we can determine if it fits
    2382                         $exifTool->{PREVIEW_INFO} or $exifTool->{PREVIEW_INFO} = { };
    2383                         $exifTool->{PREVIEW_INFO}->{Data} = $buff;
    2384                         if ($$tagInfo{IsOffset} and $$tagInfo{IsOffset} eq '2') {
    2385                             $exifTool->{PREVIEW_INFO}->{NoBaseShift} = 1;
    2386                         }
    2387                         $buff = '';
     3239                    if ($$tagInfo{Name} eq 'PreviewImageStart') {
     3240                        if ($$exifTool{FILE_TYPE} eq 'JPEG' and not $$tagInfo{MakerPreview}) {
     3241                            # hold onto the PreviewImage until we can determine if it fits
     3242                            $exifTool->{PREVIEW_INFO} or $exifTool->{PREVIEW_INFO} = { };
     3243                            $exifTool->{PREVIEW_INFO}{Data} = $buff;
     3244                            if ($$tagInfo{IsOffset} and $$tagInfo{IsOffset} eq '2') {
     3245                                $exifTool->{PREVIEW_INFO}{NoBaseShift} = 1;
     3246                            }
     3247                            $buff = '';
     3248                        } elsif ($$exifTool{TIFF_TYPE} eq 'ARW' and $$exifTool{Model}  eq 'DSLR-A100') {
     3249                            # the A100 double-references the same preview, so ignore the
     3250                            # second one (the offset and size will be patched later)
     3251                            next if $$exifTool{A100PreviewLength};
     3252                            $$exifTool{A100PreviewLength} = length $buff if defined $buff;
     3253                        }
    23883254                    }
    23893255                    # update offset accordingly and add to end of new data
    2390                     Set32u(length($newData)+$blockSize, \$newData, $offsetPos);
     3256                    Set32u($newOffset, \$newData, $offsetPos);
    23913257                    # add a pointer to fix up this offset value (marked with DataTag name)
    2392                     $fixup->AddFixup($offsetPos, $$tagInfo{DataTag});
     3258                    $fixup->AddFixup($offsetPos, $dataTag);
     3259                    # also add to subIfdDataFixup if necessary
     3260                    $subIfdDataFixup->AddFixup($offsetPos, $dataTag) if $subIfdDataFixup;
     3261                    # must also (sometimes) update StripOffsets in Panasonic RW2 images
     3262                    my $otherPos = $$offsetPair[0][5];
     3263                    if ($otherPos and $$tagInfo{PanasonicHack}) {
     3264                        Set32u($newOffset, \$newData, $otherPos);
     3265                        $fixup->AddFixup($otherPos, $dataTag);
     3266                    }
    23933267                    if ($ifd >= 0) {
    2394                         $buff .= "\0" if $size & 0x01;  # must be even size
     3268                        # buff length must be even (Note: may have changed since $size was set)
     3269                        $buff .= "\0" if length($buff) & 0x01;
    23953270                        $newData .= $buff;      # add this strip to the data
    23963271                    } else {
     
    23983273                    }
    23993274                }
     3275                SetByteOrder($oldOrder);
    24003276            }
    24013277        }
     3278        # verify that nothing else got written after determining TTW length
     3279        if (defined $ttwLen and $ttwLen != length($newData)) {
     3280            $exifTool->Error('Internal error writing MRW TTW');
     3281        }
    24023282    }
    24033283#
     3284# set offsets and generate fixups for tag values which were too large for memory
     3285#
     3286    $blockSize = 0;
     3287    foreach $blockInfo (@imageData) {
     3288        my ($pos, $size, $pad, $entry, $subFix) = @$blockInfo;
     3289        if (defined $entry) {
     3290            my $format = Get16u(\$newData, $entry + 2);
     3291            if ($format < 1 or $format > 13) {
     3292                $exifTool->Error('Internal error copying huge value');
     3293                last;
     3294            } else {
     3295                # set count and offset in directory entry
     3296                Set32u($size / $formatSize[$format], \$newData, $entry + 4);
     3297                Set32u(length($newData)+$blockSize, \$newData, $entry + 8);
     3298                $fixup->AddFixup($entry + 8);
     3299                # create special fixup for SubIFD data
     3300                if ($imageDataFlag eq 'SubIFD') {
     3301                    my $subIfdDataFixup = new Image::ExifTool::Fixup;
     3302                    $subIfdDataFixup->AddFixup($entry + 8);
     3303                    # save fixup in imageData list
     3304                    $$blockInfo[4] = $subIfdDataFixup;
     3305                }
     3306                # must reset entry pointer so we don't use it again in a parent IFD!
     3307                $$blockInfo[3] = undef;
     3308            }
     3309        }
     3310        # apply additional shift required for contained SubIFD image data offsets
     3311        if ($subFix and defined $$subFix{BlockLen} and $numBlocks > 0) {
     3312            # our offset expects the data at the end of the SubIFD block (BlockLen + Start),
     3313            # but it will actually be at length($newData) + $blockSize.  So adjust
     3314            # accordingly (and subtract an extra Start because this shift is applied later)
     3315            $subFix->{Shift} += length($newData) - $$subFix{BlockLen} - 2 * $$subFix{Start} + $blockSize;
     3316            $subFix->ApplyFixup(\$newData);
     3317        }
     3318        $blockSize += $size + $pad;
     3319        --$numBlocks;
     3320    }
     3321#
    24043322# apply final shift to new data position if this is the top level IFD
    24053323#
    24063324    unless ($$dirInfo{Fixup}) {
    2407         my $newDataPos = $$dirInfo{NewDataPos} || 0;
     3325        my $hdrPtr = $$dirInfo{HeaderPtr};
     3326        my $newDataPos = $hdrPtr ? length $$hdrPtr : $$dirInfo{NewDataPos} || 0;
    24083327        # adjust CanonVRD offset to point to end of regular TIFF if necessary
    24093328        # (NOTE: This will be incorrect if multiple trailers exist,
    2410         #  but it is unlikely that it could ever be correct in this case anyway)
     3329        #  but it is unlikely that it could ever be correct in this case anyway.
     3330        #  Also, this doesn't work for JPEG images (but CanonDPP doesn't set
     3331        #  this when editing JPEG images anyway))
    24113332        $fixup->SetMarkerPointers(\$newData, 'CanonVRD', length($newData) + $blockSize);
    24123333        if ($newDataPos) {
     
    24143335            $fixup->ApplyFixup(\$newData);
    24153336        }
     3337        # save fixup for adjusting Leica trailer offset if necessary
     3338        if ($$exifTool{LeicaTrailer}) {
     3339            my $trail = $$exifTool{LeicaTrailer};
     3340            $$trail{Fixup} or $$trail{Fixup} = new Image::ExifTool::Fixup;
     3341            $$trail{Fixup}->AddFixup($fixup);
     3342        }
    24163343        # save fixup for PreviewImage in JPEG file if necessary
    24173344        my $previewInfo = $exifTool->{PREVIEW_INFO};
    24183345        if ($previewInfo) {
    2419             my $pt = \$previewInfo->{Data}; # image data or 'LOAD' flag
     3346            my $pt = \$previewInfo->{Data}; # image data or 'LOAD_PREVIEW' flag
    24203347            # now that we know the size of the EXIF data, first test to see if our new image fits
    24213348            # inside the EXIF segment (remember about the TIFF and EXIF headers: 8+6 bytes)
    2422             if (($$pt ne 'LOAD' and length($$pt) + length($newData) + 14 <= 0xfffd) or
     3349            if (($$pt ne 'LOAD_PREVIEW' and length($$pt) + length($newData) + 14 <= 0xfffd and
     3350                not $previewInfo->{IsTrailer}) or
    24233351                $previewInfo->{IsShort}) # must fit in this segment if using short pointers
    24243352            {
    24253353                # It fits! (or must exist in EXIF segment), so fixup the
    24263354                # PreviewImage pointers and stuff the preview image in here
    2427                 my $newPos = length($newData) + ($newDataPos || 0);
     3355                my $newPos = length($newData) + $newDataPos;
    24283356                $newPos += ($previewInfo->{BaseShift} || 0);
    24293357                if ($previewInfo->{Relative}) {
     
    24413369                $previewInfo->{Fixup}->AddFixup($fixup);
    24423370            }
    2443         } else {
    2444             # delete both IFD0 and IFD1 if only mandatory tags remain
    2445             $newData = '' if defined $newData and $deleteAll;
     3371        } elsif (defined $newData and $deleteAll) {
     3372            $newData = '';  # delete both IFD0 and IFD1 since only mandatory tags remain
     3373        } elsif ($$exifTool{A100PreviewLength}) {
     3374            # save preview image start for patching A100 quirks later
     3375            $$exifTool{A100PreviewStart} = $fixup->GetMarkerPointers(\$newData, 'PreviewImage');
    24463376        }
    24473377        # save location of last IFD for use in Canon RAW header
    24483378        if ($newDataPos == 16) {
    24493379            my @ifdPos = $fixup->GetMarkerPointers(\$newData,'NextIFD');
    2450             $_[1]->{LastIFD} = pop @ifdPos;
     3380            $$origDirInfo{LastIFD} = pop @ifdPos;
     3381        }
     3382        # recrypt SR2 SubIFD data if necessary
     3383        my $key = $$exifTool{SR2SubIFDKey};
     3384        if ($key) {
     3385            my $start = $fixup->GetMarkerPointers(\$newData, 'SR2SubIFDOffset');
     3386            my $len = $$exifTool{SR2SubIFDLength};
     3387            # (must subtract 8 for size of TIFF header)
     3388            if ($start and $start - 8 + $len <= length $newData) {
     3389                require Image::ExifTool::Sony;
     3390                Image::ExifTool::Sony::Decrypt(\$newData, $start - 8, $len, $key);
     3391            }
    24513392        }
    24523393    }
     
    24763417=head1 AUTHOR
    24773418
    2478 Copyright 2003-2007, Phil Harvey (phil at owl.phy.queensu.ca)
     3419Copyright 2003-2011, Phil Harvey (phil at owl.phy.queensu.ca)
    24793420
    24803421This library is free software; you can redistribute it and/or modify it
Note: See TracChangeset for help on using the changeset viewer.