exiv2-0.23/0000755000175000017500000000000011745263717012324 5ustar andreasandreasexiv2-0.23/msvc64/0000755000175000017500000000000011745263367013447 5ustar andreasandreasexiv2-0.23/msvc64/expat/0000755000175000017500000000000011745263366014567 5ustar andreasandreasexiv2-0.23/msvc64/expat/expat.vcproj0000644000175000017500000004306511510162225017123 0ustar andreasandreas exiv2-0.23/msvc64/include/0000755000175000017500000000000011745263366015071 5ustar andreasandreasexiv2-0.23/msvc64/include/exv_msvc.h0000644000175000017500000000615511733051454017071 0ustar andreasandreas/* ***************************************************************** -*- C -*- */ /*! @file exv_msvc.h @brief Configuration settings for MSVC @version $Rev: 2320 $ @author Andreas Huggel (ahu) ahuggel@gmx.net @date 07-Feb-04, ahu: created 26-Feb-05, ahu: renamed and moved to src directory */ /* Todo: The PACKAGE_* defines should be generated */ #ifdef _MSC_VER #if _MSC_VER >= 1600 // stdint.h was introduced with DevStudio 2010 #define EXV_HAVE_STDINT_H 1 #endif /* Define to 1 if you have the header file. */ #define EXV_HAVE_PROCESS_H 1 /* Define to the address where bug reports for this package should be sent. */ #define EXV_PACKAGE_BUGREPORT "ahuggel@gmx.net" /* Define to the full name of this package. */ #define EXV_PACKAGE_NAME "exiv2" /* Define to the full name and version of this package. */ #define EXV_PACKAGE_STRING "exiv2 0.23" /* Define to the one symbol short name of this package. */ #define EXV_PACKAGE_TARNAME "exiv2" /* Define to the version of this package. */ #define EXV_PACKAGE_VERSION "0.23" /* Define to `int' if does not define pid_t. */ typedef int pid_t; #ifndef EXV_COMMERCIAL_VERSION /* Define to 1 to enable translation of Nikon lens names. */ # define EXV_HAVE_LENSDATA 1 /* Define to 1 if translation of program messages to the user's native language is requested. */ # undef EXV_ENABLE_NLS #endif /* !EXV_COMMERCIAL_VERSION */ /* Define to 1 if you have the `iconv' function. */ # undef EXV_HAVE_ICONV /* Define as 1 if you have the `zlib' library. (0 to omit zlib) [png support] */ #define HAVE_LIBZ 1 #if HAVE_LIBZ #define EXV_HAVE_LIBZ // assist VC7.1 to compile vsnprintf #if (_MSC_VER < 1400) && !defined(vsnprintf) #define vsnprintf _vsnprintf #endif #endif /* Define to 1 if you have the Adobe XMP Toolkit. */ #define EXV_HAVE_XMP_TOOLKIT 1 /* File path seperator */ #define EXV_SEPERATOR_STR "\\" #define EXV_SEPERATOR_CHR '\\' /* Windows unicode path support */ #define EXV_UNICODE_PATH /* Define to 1 if you have the `mmap' function. */ /* #undef EXV_HAVE_MMAP */ /* Define to 1 if you have the `munmap' function. */ /* #undef EXV_HAVE_MUNMAP */ /* Shared library support */ #ifdef EXV_HAVE_DLL #define EXV_IMPORT __declspec(dllimport) #define EXV_EXPORT __declspec(dllexport) #define EXV_DLLLOCAL #define EXV_DLLPUBLIC #else #define EXV_IMPORT #define EXV_EXPORT #define EXV_DLLLOCAL #define EXV_DLLPUBLIC #define EXIV2API #endif /* Define EXIV2API for DLL builds */ #ifdef EXV_HAVE_DLL # ifdef EXV_BUILDING_LIB # define EXIV2API EXV_EXPORT # else # define EXIV2API EXV_IMPORT # endif /* ! EXV_BUILDING_LIB */ #else # define EXIV2API #endif /* ! EXV_HAVE_DLL */ /* Disable warning 4251. This is warning from std templates about exporting interfaces */ #ifdef EXV_HAVE_DLL #pragma warning( disable : 4251 ) #endif /* Visual Studio C++ 2005 (8.0) Disable warnings about 'deprecated' standard functions See, eg. http://www.informit.com/guides/content.asp?g=cplusplus&seqNum=259 */ #if _MSC_VER >= 1400 # pragma warning(disable : 4996) #endif #endif /* _MSC_VER */ exiv2-0.23/msvc64/exiv2lib/0000755000175000017500000000000011745263366015172 5ustar andreasandreasexiv2-0.23/msvc64/exiv2lib/exiv2lib.vcproj0000644000175000017500000006734411602254046020144 0ustar andreasandreas exiv2-0.23/msvc64/zlib123/0000755000175000017500000000000011745263366014634 5ustar andreasandreasexiv2-0.23/msvc64/zlib123/zlib.vcproj0000644000175000017500000004151511510162225017005 0ustar andreasandreas exiv2-0.23/msvc64/src/0000755000175000017500000000000011745263366014235 5ustar andreasandreasexiv2-0.23/msvc64/runner.txt0000644000175000017500000022057011744730536015523 0ustar andreasandreasexiv2 0.23 001700 (32 bit build) Copyright (C) 2004-2012 Andreas Huggel. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Exif.Photo.DateTimeOriginal Ascii 20 2008:09:06 14:34:23 Exif.Photo.DateTimeOriginal Ascii 20 2008:09:06 14:34:23 Exif.Image.Make Ascii 6 Canon Exif.Image.Model Ascii 22 Canon PowerShot S5 IS Exif.Image.Orientation Short 1 top, left Exif.Image.XResolution Rational 1 180 Exif.Image.YResolution Rational 1 180 Exif.Image.ResolutionUnit Short 1 inch Exif.Image.DateTime Ascii 20 2008:09:06 14:34:23 Exif.Image.YCbCrPositioning Short 1 Centered Exif.Image.ExifTag Long 1 186 Exif.Photo.ExposureTime Rational 1 1/500 s Exif.Photo.FNumber Rational 1 F4 Exif.Photo.ISOSpeedRatings Short 1 80 Exif.Photo.ExifVersion Undefined 4 2.20 Exif.Photo.DateTimeOriginal Ascii 20 2008:09:06 14:34:23 Exif.Photo.DateTimeDigitized Ascii 20 2008:09:06 14:34:23 Exif.Photo.ComponentsConfiguration Undefined 4 YCbCr Exif.Photo.CompressedBitsPerPixel Rational 1 3 Exif.Photo.ShutterSpeedValue SRational 1 1/501 s Exif.Photo.ApertureValue Rational 1 F4 Exif.Photo.ExposureBiasValue SRational 1 0 EV Exif.Photo.MaxApertureValue Rational 1 F3.5 Exif.Photo.MeteringMode Short 1 Multi-segment Exif.Photo.Flash Short 1 No, compulsory Exif.Photo.FocalLength Rational 1 21.3 mm Exif.Photo.MakerNote Undefined 2382 (Binary value suppressed) Exif.MakerNote.Offset Long 1 680 Exif.MakerNote.ByteOrder Ascii 3 MM Exif.CanonCs.Macro Short 1 Off Exif.CanonCs.Selftimer Short 1 Off Exif.CanonCs.Quality Short 1 Fine Exif.CanonCs.FlashMode Short 1 Off Exif.CanonCs.DriveMode Short 1 Single / timer Exif.CanonCs.FocusMode Short 1 Single Exif.CanonCs.ImageSize Short 1 Medium 1 Exif.CanonCs.EasyMode Short 1 Manual Exif.CanonCs.DigitalZoom Short 1 None Exif.CanonCs.Contrast Short 1 Normal Exif.CanonCs.Saturation Short 1 Normal Exif.CanonCs.Sharpness Short 1 Normal Exif.CanonCs.ISOSpeed Short 1 Auto Exif.CanonCs.MeteringMode Short 1 Evaluative Exif.CanonCs.FocusType Short 1 Auto Exif.CanonCs.AFPoint Short 1 Manual AF point selection Exif.CanonCs.ExposureProgram Short 1 Program (P) Exif.CanonCs.LensType Short 1 (65535) Exif.CanonCs.Lens Short 3 6.0 - 72.0 mm Exif.CanonCs.MaxAperture Short 1 F3.6 Exif.CanonCs.MinAperture Short 1 F8 Exif.CanonCs.FlashActivity Short 1 Did not fire Exif.CanonCs.FlashDetails Short 1 Exif.CanonCs.FocusContinuous Short 1 Continuous Exif.CanonCs.AESetting Short 1 Normal AE Exif.CanonCs.ImageStabilization Short 1 On Exif.CanonCs.DisplayAperture Short 1 0 Exif.CanonCs.ZoomSourceWidth Short 1 3264 Exif.CanonCs.ZoomTargetWidth Short 1 3264 Exif.CanonCs.SpotMeteringMode Short 1 Center Exif.CanonCs.PhotoEffect Short 1 (65535) Exif.CanonCs.ManualFlashOutput Short 1 n/a Exif.CanonCs.ColorTone Short 1 32767 Exif.Canon.FocalLength Short 4 21.3 mm Exif.CanonSi.ISOSpeed Short 1 100 Exif.CanonSi.MeasuredEV Short 1 14.25 Exif.CanonSi.TargetAperture Short 1 F4 Exif.CanonSi.TargetShutterSpeed Short 1 1/501 s Exif.CanonSi.WhiteBalance Short 1 Sunny Exif.CanonSi.Sequence Short 1 0 Exif.CanonSi.AFPointUsed Short 1 0 focus points; none used Exif.CanonSi.FlashBias Short 1 0 EV Exif.CanonSi.SubjectDistance Short 1 503 Exif.CanonSi.ApertureValue Short 1 F4 Exif.CanonSi.ShutterSpeedValue Short 1 1/546 s Exif.CanonSi.MeasuredEV2 Short 1 -6.00 Exif.Canon.ImageType Ascii 25 IMG:PowerShot S5 IS JPEG Exif.Canon.FirmwareVersion Ascii 22 Firmware Version 1.01 Exif.Canon.FileNumber Long 1 100-1904 Exif.Canon.OwnerName Ascii 32 Robin Mills Exif.Canon.CameraInfo Long 148 370 411 0 0 0 384 874 4294967255 0 0 0 0 577 889 4294967150 0 0 4294967287 0 0 1 0 0 0 9 10 888 888 888 384 1015 4294967148 0 0 888 888 0 0 1 3072 3072 3072 3072 3072 4294964224 4294964224 4294964224 4294964224 4294964224 0 4294964224 4294967287 0 0 0 0 0 0 0 0 0 0 164 1024 1024 40 94 0 0 0 0 0 0 525 0 40 94 0 0 3 1 0 0 921 1027 1024 1280 0 40 97 10 881 1646 1711 881 1 1014 384 888 659 4294967148 2 128 1 0 0 0 0 7532 5 0 0 0 0 0 0 7819 8252 8279 128 1 0 4294961112 3 1 7471 0 0 0 0 0 0 0 0 5345 1088 245 446 100 196 44 4091 4091 1 1 25 8 2400605383 Exif.Canon.ModelID Long 1 PowerShot S5 IS Exif.Canon.ThumbnailImageValidArea Short 4 0 0 0 0 Exif.Canon.SuperMacro Short 1 Off Exif.Canon.AFInfo Short 48 96 2 9 1 2592 1944 1088 245 196 0 0 0 0 0 0 0 0 44 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 Exif.Photo.UserComment Undefined 264 (Binary value suppressed) Exif.Photo.FlashpixVersion Undefined 4 1.00 Exif.Photo.ColorSpace Short 1 sRGB Exif.Photo.PixelXDimension Short 1 2592 Exif.Photo.PixelYDimension Short 1 1944 Exif.Photo.InteroperabilityTag Long 1 3350 Exif.Iop.InteroperabilityIndex Ascii 4 R98 Exif.Iop.InteroperabilityVersion Undefined 4 1.00 Exif.Iop.RelatedImageWidth Short 1 2592 Exif.Iop.RelatedImageLength Short 1 1944 Exif.Photo.FocalPlaneXResolution Rational 1 11520 Exif.Photo.FocalPlaneYResolution Rational 1 11503 Exif.Photo.FocalPlaneResolutionUnit Short 1 inch Exif.Photo.SensingMethod Short 1 One-chip color area Exif.Photo.FileSource Undefined 1 Digital still camera Exif.Photo.CustomRendered Short 1 Normal process Exif.Photo.ExposureMode Short 1 Auto Exif.Photo.WhiteBalance Short 1 Manual Exif.Photo.DigitalZoomRatio Rational 1 1.0 Exif.Photo.SceneCaptureType Short 1 Standard Exif.Thumbnail.Compression Short 1 JPEG (old-style) Exif.Thumbnail.XResolution Rational 1 180 Exif.Thumbnail.YResolution Rational 1 180 Exif.Thumbnail.ResolutionUnit Short 1 inch Exif.Thumbnail.JPEGInterchangeFormat Long 1 3498 Exif.Thumbnail.JPEGInterchangeFormatLength Long 1 6714 exiv2 0.23 001700 (32 bit build) Copyright (C) 2004-2012 Andreas Huggel. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Exif.Photo.DateTimeOriginal Ascii 20 2008:09:06 14:34:23 Exif.Photo.DateTimeOriginal Ascii 20 2008:09:06 14:34:23 Exif.Image.Make Ascii 6 Canon Exif.Image.Model Ascii 22 Canon PowerShot S5 IS Exif.Image.Orientation Short 1 top, left Exif.Image.XResolution Rational 1 180 Exif.Image.YResolution Rational 1 180 Exif.Image.ResolutionUnit Short 1 inch Exif.Image.DateTime Ascii 20 2008:09:06 14:34:23 Exif.Image.YCbCrPositioning Short 1 Centered Exif.Image.ExifTag Long 1 186 Exif.Photo.ExposureTime Rational 1 1/500 s Exif.Photo.FNumber Rational 1 F4 Exif.Photo.ISOSpeedRatings Short 1 80 Exif.Photo.ExifVersion Undefined 4 2.20 Exif.Photo.DateTimeOriginal Ascii 20 2008:09:06 14:34:23 Exif.Photo.DateTimeDigitized Ascii 20 2008:09:06 14:34:23 Exif.Photo.ComponentsConfiguration Undefined 4 YCbCr Exif.Photo.CompressedBitsPerPixel Rational 1 3 Exif.Photo.ShutterSpeedValue SRational 1 1/501 s Exif.Photo.ApertureValue Rational 1 F4 Exif.Photo.ExposureBiasValue SRational 1 0 EV Exif.Photo.MaxApertureValue Rational 1 F3.5 Exif.Photo.MeteringMode Short 1 Multi-segment Exif.Photo.Flash Short 1 No, compulsory Exif.Photo.FocalLength Rational 1 21.3 mm Exif.Photo.MakerNote Undefined 2382 (Binary value suppressed) Exif.MakerNote.Offset Long 1 680 Exif.MakerNote.ByteOrder Ascii 3 MM Exif.CanonCs.Macro Short 1 Off Exif.CanonCs.Selftimer Short 1 Off Exif.CanonCs.Quality Short 1 Fine Exif.CanonCs.FlashMode Short 1 Off Exif.CanonCs.DriveMode Short 1 Single / timer Exif.CanonCs.FocusMode Short 1 Single Exif.CanonCs.ImageSize Short 1 Medium 1 Exif.CanonCs.EasyMode Short 1 Manual Exif.CanonCs.DigitalZoom Short 1 None Exif.CanonCs.Contrast Short 1 Normal Exif.CanonCs.Saturation Short 1 Normal Exif.CanonCs.Sharpness Short 1 Normal Exif.CanonCs.ISOSpeed Short 1 Auto Exif.CanonCs.MeteringMode Short 1 Evaluative Exif.CanonCs.FocusType Short 1 Auto Exif.CanonCs.AFPoint Short 1 Manual AF point selection Exif.CanonCs.ExposureProgram Short 1 Program (P) Exif.CanonCs.LensType Short 1 (65535) Exif.CanonCs.Lens Short 3 6.0 - 72.0 mm Exif.CanonCs.MaxAperture Short 1 F3.6 Exif.CanonCs.MinAperture Short 1 F8 Exif.CanonCs.FlashActivity Short 1 Did not fire Exif.CanonCs.FlashDetails Short 1 Exif.CanonCs.FocusContinuous Short 1 Continuous Exif.CanonCs.AESetting Short 1 Normal AE Exif.CanonCs.ImageStabilization Short 1 On Exif.CanonCs.DisplayAperture Short 1 0 Exif.CanonCs.ZoomSourceWidth Short 1 3264 Exif.CanonCs.ZoomTargetWidth Short 1 3264 Exif.CanonCs.SpotMeteringMode Short 1 Center Exif.CanonCs.PhotoEffect Short 1 (65535) Exif.CanonCs.ManualFlashOutput Short 1 n/a Exif.CanonCs.ColorTone Short 1 32767 Exif.Canon.FocalLength Short 4 21.3 mm Exif.CanonSi.ISOSpeed Short 1 100 Exif.CanonSi.MeasuredEV Short 1 14.25 Exif.CanonSi.TargetAperture Short 1 F4 Exif.CanonSi.TargetShutterSpeed Short 1 1/501 s Exif.CanonSi.WhiteBalance Short 1 Sunny Exif.CanonSi.Sequence Short 1 0 Exif.CanonSi.AFPointUsed Short 1 0 focus points; none used Exif.CanonSi.FlashBias Short 1 0 EV Exif.CanonSi.SubjectDistance Short 1 503 Exif.CanonSi.ApertureValue Short 1 F4 Exif.CanonSi.ShutterSpeedValue Short 1 1/546 s Exif.CanonSi.MeasuredEV2 Short 1 -6.00 Exif.Canon.ImageType Ascii 25 IMG:PowerShot S5 IS JPEG Exif.Canon.FirmwareVersion Ascii 22 Firmware Version 1.01 Exif.Canon.FileNumber Long 1 100-1904 Exif.Canon.OwnerName Ascii 32 Robin Mills Exif.Canon.CameraInfo Long 148 370 411 0 0 0 384 874 4294967255 0 0 0 0 577 889 4294967150 0 0 4294967287 0 0 1 0 0 0 9 10 888 888 888 384 1015 4294967148 0 0 888 888 0 0 1 3072 3072 3072 3072 3072 4294964224 4294964224 4294964224 4294964224 4294964224 0 4294964224 4294967287 0 0 0 0 0 0 0 0 0 0 164 1024 1024 40 94 0 0 0 0 0 0 525 0 40 94 0 0 3 1 0 0 921 1027 1024 1280 0 40 97 10 881 1646 1711 881 1 1014 384 888 659 4294967148 2 128 1 0 0 0 0 7532 5 0 0 0 0 0 0 7819 8252 8279 128 1 0 4294961112 3 1 7471 0 0 0 0 0 0 0 0 5345 1088 245 446 100 196 44 4091 4091 1 1 25 8 2400605383 Exif.Canon.ModelID Long 1 PowerShot S5 IS Exif.Canon.ThumbnailImageValidArea Short 4 0 0 0 0 Exif.Canon.SuperMacro Short 1 Off Exif.Canon.AFInfo Short 48 96 2 9 1 2592 1944 1088 245 196 0 0 0 0 0 0 0 0 44 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 Exif.Photo.UserComment Undefined 264 (Binary value suppressed) Exif.Photo.FlashpixVersion Undefined 4 1.00 Exif.Photo.ColorSpace Short 1 sRGB Exif.Photo.PixelXDimension Short 1 2592 Exif.Photo.PixelYDimension Short 1 1944 Exif.Photo.InteroperabilityTag Long 1 3350 Exif.Iop.InteroperabilityIndex Ascii 4 R98 Exif.Iop.InteroperabilityVersion Undefined 4 1.00 Exif.Iop.RelatedImageWidth Short 1 2592 Exif.Iop.RelatedImageLength Short 1 1944 Exif.Photo.FocalPlaneXResolution Rational 1 11520 Exif.Photo.FocalPlaneYResolution Rational 1 11503 Exif.Photo.FocalPlaneResolutionUnit Short 1 inch Exif.Photo.SensingMethod Short 1 One-chip color area Exif.Photo.FileSource Undefined 1 Digital still camera Exif.Photo.CustomRendered Short 1 Normal process Exif.Photo.ExposureMode Short 1 Auto Exif.Photo.WhiteBalance Short 1 Manual Exif.Photo.DigitalZoomRatio Rational 1 1.0 Exif.Photo.SceneCaptureType Short 1 Standard Exif.Thumbnail.Compression Short 1 JPEG (old-style) Exif.Thumbnail.XResolution Rational 1 180 Exif.Thumbnail.YResolution Rational 1 180 Exif.Thumbnail.ResolutionUnit Short 1 inch Exif.Thumbnail.JPEGInterchangeFormat Long 1 3498 Exif.Thumbnail.JPEGInterchangeFormatLength Long 1 6714 exiv2 0.23 001700 (32 bit build) Copyright (C) 2004-2012 Andreas Huggel. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Exif.Photo.DateTimeOriginal Ascii 20 2008:09:06 14:34:23 Exif.Photo.DateTimeOriginal Ascii 20 2008:09:06 14:34:23 Exif.Image.Make Ascii 6 Canon Exif.Image.Model Ascii 22 Canon PowerShot S5 IS Exif.Image.Orientation Short 1 top, left Exif.Image.XResolution Rational 1 180 Exif.Image.YResolution Rational 1 180 Exif.Image.ResolutionUnit Short 1 inch Exif.Image.DateTime Ascii 20 2008:09:06 14:34:23 Exif.Image.YCbCrPositioning Short 1 Centered Exif.Image.ExifTag Long 1 186 Exif.Photo.ExposureTime Rational 1 1/500 s Exif.Photo.FNumber Rational 1 F4 Exif.Photo.ISOSpeedRatings Short 1 80 Exif.Photo.ExifVersion Undefined 4 2.20 Exif.Photo.DateTimeOriginal Ascii 20 2008:09:06 14:34:23 Exif.Photo.DateTimeDigitized Ascii 20 2008:09:06 14:34:23 Exif.Photo.ComponentsConfiguration Undefined 4 YCbCr Exif.Photo.CompressedBitsPerPixel Rational 1 3 Exif.Photo.ShutterSpeedValue SRational 1 1/501 s Exif.Photo.ApertureValue Rational 1 F4 Exif.Photo.ExposureBiasValue SRational 1 0 EV Exif.Photo.MaxApertureValue Rational 1 F3.5 Exif.Photo.MeteringMode Short 1 Multi-segment Exif.Photo.Flash Short 1 No, compulsory Exif.Photo.FocalLength Rational 1 21.3 mm Exif.Photo.MakerNote Undefined 2382 (Binary value suppressed) Exif.MakerNote.Offset Long 1 680 Exif.MakerNote.ByteOrder Ascii 3 MM Exif.CanonCs.Macro Short 1 Off Exif.CanonCs.Selftimer Short 1 Off Exif.CanonCs.Quality Short 1 Fine Exif.CanonCs.FlashMode Short 1 Off Exif.CanonCs.DriveMode Short 1 Single / timer Exif.CanonCs.FocusMode Short 1 Single Exif.CanonCs.ImageSize Short 1 Medium 1 Exif.CanonCs.EasyMode Short 1 Manual Exif.CanonCs.DigitalZoom Short 1 None Exif.CanonCs.Contrast Short 1 Normal Exif.CanonCs.Saturation Short 1 Normal Exif.CanonCs.Sharpness Short 1 Normal Exif.CanonCs.ISOSpeed Short 1 Auto Exif.CanonCs.MeteringMode Short 1 Evaluative Exif.CanonCs.FocusType Short 1 Auto Exif.CanonCs.AFPoint Short 1 Manual AF point selection Exif.CanonCs.ExposureProgram Short 1 Program (P) Exif.CanonCs.LensType Short 1 (65535) Exif.CanonCs.Lens Short 3 6.0 - 72.0 mm Exif.CanonCs.MaxAperture Short 1 F3.6 Exif.CanonCs.MinAperture Short 1 F8 Exif.CanonCs.FlashActivity Short 1 Did not fire Exif.CanonCs.FlashDetails Short 1 Exif.CanonCs.FocusContinuous Short 1 Continuous Exif.CanonCs.AESetting Short 1 Normal AE Exif.CanonCs.ImageStabilization Short 1 On Exif.CanonCs.DisplayAperture Short 1 0 Exif.CanonCs.ZoomSourceWidth Short 1 3264 Exif.CanonCs.ZoomTargetWidth Short 1 3264 Exif.CanonCs.SpotMeteringMode Short 1 Center Exif.CanonCs.PhotoEffect Short 1 (65535) Exif.CanonCs.ManualFlashOutput Short 1 n/a Exif.CanonCs.ColorTone Short 1 32767 Exif.Canon.FocalLength Short 4 21.3 mm Exif.CanonSi.ISOSpeed Short 1 100 Exif.CanonSi.MeasuredEV Short 1 14.25 Exif.CanonSi.TargetAperture Short 1 F4 Exif.CanonSi.TargetShutterSpeed Short 1 1/501 s Exif.CanonSi.WhiteBalance Short 1 Sunny Exif.CanonSi.Sequence Short 1 0 Exif.CanonSi.AFPointUsed Short 1 0 focus points; none used Exif.CanonSi.FlashBias Short 1 0 EV Exif.CanonSi.SubjectDistance Short 1 503 Exif.CanonSi.ApertureValue Short 1 F4 Exif.CanonSi.ShutterSpeedValue Short 1 1/546 s Exif.CanonSi.MeasuredEV2 Short 1 -6.00 Exif.Canon.ImageType Ascii 25 IMG:PowerShot S5 IS JPEG Exif.Canon.FirmwareVersion Ascii 22 Firmware Version 1.01 Exif.Canon.FileNumber Long 1 100-1904 Exif.Canon.OwnerName Ascii 32 Robin Mills Exif.Canon.CameraInfo Long 148 370 411 0 0 0 384 874 4294967255 0 0 0 0 577 889 4294967150 0 0 4294967287 0 0 1 0 0 0 9 10 888 888 888 384 1015 4294967148 0 0 888 888 0 0 1 3072 3072 3072 3072 3072 4294964224 4294964224 4294964224 4294964224 4294964224 0 4294964224 4294967287 0 0 0 0 0 0 0 0 0 0 164 1024 1024 40 94 0 0 0 0 0 0 525 0 40 94 0 0 3 1 0 0 921 1027 1024 1280 0 40 97 10 881 1646 1711 881 1 1014 384 888 659 4294967148 2 128 1 0 0 0 0 7532 5 0 0 0 0 0 0 7819 8252 8279 128 1 0 4294961112 3 1 7471 0 0 0 0 0 0 0 0 5345 1088 245 446 100 196 44 4091 4091 1 1 25 8 2400605383 Exif.Canon.ModelID Long 1 PowerShot S5 IS Exif.Canon.ThumbnailImageValidArea Short 4 0 0 0 0 Exif.Canon.SuperMacro Short 1 Off Exif.Canon.AFInfo Short 48 96 2 9 1 2592 1944 1088 245 196 0 0 0 0 0 0 0 0 44 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 Exif.Photo.UserComment Undefined 264 (Binary value suppressed) Exif.Photo.FlashpixVersion Undefined 4 1.00 Exif.Photo.ColorSpace Short 1 sRGB Exif.Photo.PixelXDimension Short 1 2592 Exif.Photo.PixelYDimension Short 1 1944 Exif.Photo.InteroperabilityTag Long 1 3350 Exif.Iop.InteroperabilityIndex Ascii 4 R98 Exif.Iop.InteroperabilityVersion Undefined 4 1.00 Exif.Iop.RelatedImageWidth Short 1 2592 Exif.Iop.RelatedImageLength Short 1 1944 Exif.Photo.FocalPlaneXResolution Rational 1 11520 Exif.Photo.FocalPlaneYResolution Rational 1 11503 Exif.Photo.FocalPlaneResolutionUnit Short 1 inch Exif.Photo.SensingMethod Short 1 One-chip color area Exif.Photo.FileSource Undefined 1 Digital still camera Exif.Photo.CustomRendered Short 1 Normal process Exif.Photo.ExposureMode Short 1 Auto Exif.Photo.WhiteBalance Short 1 Manual Exif.Photo.DigitalZoomRatio Rational 1 1.0 Exif.Photo.SceneCaptureType Short 1 Standard Exif.Thumbnail.Compression Short 1 JPEG (old-style) Exif.Thumbnail.XResolution Rational 1 180 Exif.Thumbnail.YResolution Rational 1 180 Exif.Thumbnail.ResolutionUnit Short 1 inch Exif.Thumbnail.JPEGInterchangeFormat Long 1 3498 Exif.Thumbnail.JPEGInterchangeFormatLength Long 1 6714 exiv2 0.23 001700 (32 bit build) Copyright (C) 2004-2012 Andreas Huggel. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Exif.Photo.DateTimeOriginal Ascii 20 2008:09:06 14:34:23 Exif.Photo.DateTimeOriginal Ascii 20 2008:09:06 14:34:23 Exif.Image.Make Ascii 6 Canon Exif.Image.Model Ascii 22 Canon PowerShot S5 IS Exif.Image.Orientation Short 1 top, left Exif.Image.XResolution Rational 1 180 Exif.Image.YResolution Rational 1 180 Exif.Image.ResolutionUnit Short 1 inch Exif.Image.DateTime Ascii 20 2008:09:06 14:34:23 Exif.Image.YCbCrPositioning Short 1 Centered Exif.Image.ExifTag Long 1 186 Exif.Photo.ExposureTime Rational 1 1/500 s Exif.Photo.FNumber Rational 1 F4 Exif.Photo.ISOSpeedRatings Short 1 80 Exif.Photo.ExifVersion Undefined 4 2.20 Exif.Photo.DateTimeOriginal Ascii 20 2008:09:06 14:34:23 Exif.Photo.DateTimeDigitized Ascii 20 2008:09:06 14:34:23 Exif.Photo.ComponentsConfiguration Undefined 4 YCbCr Exif.Photo.CompressedBitsPerPixel Rational 1 3 Exif.Photo.ShutterSpeedValue SRational 1 1/501 s Exif.Photo.ApertureValue Rational 1 F4 Exif.Photo.ExposureBiasValue SRational 1 0 EV Exif.Photo.MaxApertureValue Rational 1 F3.5 Exif.Photo.MeteringMode Short 1 Multi-segment Exif.Photo.Flash Short 1 No, compulsory Exif.Photo.FocalLength Rational 1 21.3 mm Exif.Photo.MakerNote Undefined 2382 (Binary value suppressed) Exif.MakerNote.Offset Long 1 680 Exif.MakerNote.ByteOrder Ascii 3 MM Exif.CanonCs.Macro Short 1 Off Exif.CanonCs.Selftimer Short 1 Off Exif.CanonCs.Quality Short 1 Fine Exif.CanonCs.FlashMode Short 1 Off Exif.CanonCs.DriveMode Short 1 Single / timer Exif.CanonCs.FocusMode Short 1 Single Exif.CanonCs.ImageSize Short 1 Medium 1 Exif.CanonCs.EasyMode Short 1 Manual Exif.CanonCs.DigitalZoom Short 1 None Exif.CanonCs.Contrast Short 1 Normal Exif.CanonCs.Saturation Short 1 Normal Exif.CanonCs.Sharpness Short 1 Normal Exif.CanonCs.ISOSpeed Short 1 Auto Exif.CanonCs.MeteringMode Short 1 Evaluative Exif.CanonCs.FocusType Short 1 Auto Exif.CanonCs.AFPoint Short 1 Manual AF point selection Exif.CanonCs.ExposureProgram Short 1 Program (P) Exif.CanonCs.LensType Short 1 (65535) Exif.CanonCs.Lens Short 3 6.0 - 72.0 mm Exif.CanonCs.MaxAperture Short 1 F3.6 Exif.CanonCs.MinAperture Short 1 F8 Exif.CanonCs.FlashActivity Short 1 Did not fire Exif.CanonCs.FlashDetails Short 1 Exif.CanonCs.FocusContinuous Short 1 Continuous Exif.CanonCs.AESetting Short 1 Normal AE Exif.CanonCs.ImageStabilization Short 1 On Exif.CanonCs.DisplayAperture Short 1 0 Exif.CanonCs.ZoomSourceWidth Short 1 3264 Exif.CanonCs.ZoomTargetWidth Short 1 3264 Exif.CanonCs.SpotMeteringMode Short 1 Center Exif.CanonCs.PhotoEffect Short 1 (65535) Exif.CanonCs.ManualFlashOutput Short 1 n/a Exif.CanonCs.ColorTone Short 1 32767 Exif.Canon.FocalLength Short 4 21.3 mm Exif.CanonSi.ISOSpeed Short 1 100 Exif.CanonSi.MeasuredEV Short 1 14.25 Exif.CanonSi.TargetAperture Short 1 F4 Exif.CanonSi.TargetShutterSpeed Short 1 1/501 s Exif.CanonSi.WhiteBalance Short 1 Sunny Exif.CanonSi.Sequence Short 1 0 Exif.CanonSi.AFPointUsed Short 1 0 focus points; none used Exif.CanonSi.FlashBias Short 1 0 EV Exif.CanonSi.SubjectDistance Short 1 503 Exif.CanonSi.ApertureValue Short 1 F4 Exif.CanonSi.ShutterSpeedValue Short 1 1/546 s Exif.CanonSi.MeasuredEV2 Short 1 -6.00 Exif.Canon.ImageType Ascii 25 IMG:PowerShot S5 IS JPEG Exif.Canon.FirmwareVersion Ascii 22 Firmware Version 1.01 Exif.Canon.FileNumber Long 1 100-1904 Exif.Canon.OwnerName Ascii 32 Robin Mills Exif.Canon.CameraInfo Long 148 370 411 0 0 0 384 874 4294967255 0 0 0 0 577 889 4294967150 0 0 4294967287 0 0 1 0 0 0 9 10 888 888 888 384 1015 4294967148 0 0 888 888 0 0 1 3072 3072 3072 3072 3072 4294964224 4294964224 4294964224 4294964224 4294964224 0 4294964224 4294967287 0 0 0 0 0 0 0 0 0 0 164 1024 1024 40 94 0 0 0 0 0 0 525 0 40 94 0 0 3 1 0 0 921 1027 1024 1280 0 40 97 10 881 1646 1711 881 1 1014 384 888 659 4294967148 2 128 1 0 0 0 0 7532 5 0 0 0 0 0 0 7819 8252 8279 128 1 0 4294961112 3 1 7471 0 0 0 0 0 0 0 0 5345 1088 245 446 100 196 44 4091 4091 1 1 25 8 2400605383 Exif.Canon.ModelID Long 1 PowerShot S5 IS Exif.Canon.ThumbnailImageValidArea Short 4 0 0 0 0 Exif.Canon.SuperMacro Short 1 Off Exif.Canon.AFInfo Short 48 96 2 9 1 2592 1944 1088 245 196 0 0 0 0 0 0 0 0 44 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 Exif.Photo.UserComment Undefined 264 (Binary value suppressed) Exif.Photo.FlashpixVersion Undefined 4 1.00 Exif.Photo.ColorSpace Short 1 sRGB Exif.Photo.PixelXDimension Short 1 2592 Exif.Photo.PixelYDimension Short 1 1944 Exif.Photo.InteroperabilityTag Long 1 3350 Exif.Iop.InteroperabilityIndex Ascii 4 R98 Exif.Iop.InteroperabilityVersion Undefined 4 1.00 Exif.Iop.RelatedImageWidth Short 1 2592 Exif.Iop.RelatedImageLength Short 1 1944 Exif.Photo.FocalPlaneXResolution Rational 1 11520 Exif.Photo.FocalPlaneYResolution Rational 1 11503 Exif.Photo.FocalPlaneResolutionUnit Short 1 inch Exif.Photo.SensingMethod Short 1 One-chip color area Exif.Photo.FileSource Undefined 1 Digital still camera Exif.Photo.CustomRendered Short 1 Normal process Exif.Photo.ExposureMode Short 1 Auto Exif.Photo.WhiteBalance Short 1 Manual Exif.Photo.DigitalZoomRatio Rational 1 1.0 Exif.Photo.SceneCaptureType Short 1 Standard Exif.Thumbnail.Compression Short 1 JPEG (old-style) Exif.Thumbnail.XResolution Rational 1 180 Exif.Thumbnail.YResolution Rational 1 180 Exif.Thumbnail.ResolutionUnit Short 1 inch Exif.Thumbnail.JPEGInterchangeFormat Long 1 3498 Exif.Thumbnail.JPEGInterchangeFormatLength Long 1 6714 exiv2 0.23 001700 (64 bit build) Copyright (C) 2004-2012 Andreas Huggel. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Exif.Photo.DateTimeOriginal Ascii 20 2008:09:06 14:34:23 Exif.Photo.DateTimeOriginal Ascii 20 2008:09:06 14:34:23 Exif.Image.Make Ascii 6 Canon Exif.Image.Model Ascii 22 Canon PowerShot S5 IS Exif.Image.Orientation Short 1 top, left Exif.Image.XResolution Rational 1 180 Exif.Image.YResolution Rational 1 180 Exif.Image.ResolutionUnit Short 1 inch Exif.Image.DateTime Ascii 20 2008:09:06 14:34:23 Exif.Image.YCbCrPositioning Short 1 Centered Exif.Image.ExifTag Long 1 186 Exif.Photo.ExposureTime Rational 1 1/500 s Exif.Photo.FNumber Rational 1 F4 Exif.Photo.ISOSpeedRatings Short 1 80 Exif.Photo.ExifVersion Undefined 4 2.20 Exif.Photo.DateTimeOriginal Ascii 20 2008:09:06 14:34:23 Exif.Photo.DateTimeDigitized Ascii 20 2008:09:06 14:34:23 Exif.Photo.ComponentsConfiguration Undefined 4 YCbCr Exif.Photo.CompressedBitsPerPixel Rational 1 3 Exif.Photo.ShutterSpeedValue SRational 1 1/501 s Exif.Photo.ApertureValue Rational 1 F4 Exif.Photo.ExposureBiasValue SRational 1 0 EV Exif.Photo.MaxApertureValue Rational 1 F3.5 Exif.Photo.MeteringMode Short 1 Multi-segment Exif.Photo.Flash Short 1 No, compulsory Exif.Photo.FocalLength Rational 1 21.3 mm Exif.Photo.MakerNote Undefined 2382 (Binary value suppressed) Exif.MakerNote.Offset Long 1 680 Exif.MakerNote.ByteOrder Ascii 3 MM Exif.CanonCs.Macro Short 1 Off Exif.CanonCs.Selftimer Short 1 Off Exif.CanonCs.Quality Short 1 Fine Exif.CanonCs.FlashMode Short 1 Off Exif.CanonCs.DriveMode Short 1 Single / timer Exif.CanonCs.FocusMode Short 1 Single Exif.CanonCs.ImageSize Short 1 Medium 1 Exif.CanonCs.EasyMode Short 1 Manual Exif.CanonCs.DigitalZoom Short 1 None Exif.CanonCs.Contrast Short 1 Normal Exif.CanonCs.Saturation Short 1 Normal Exif.CanonCs.Sharpness Short 1 Normal Exif.CanonCs.ISOSpeed Short 1 Auto Exif.CanonCs.MeteringMode Short 1 Evaluative Exif.CanonCs.FocusType Short 1 Auto Exif.CanonCs.AFPoint Short 1 Manual AF point selection Exif.CanonCs.ExposureProgram Short 1 Program (P) Exif.CanonCs.LensType Short 1 (65535) Exif.CanonCs.Lens Short 3 6.0 - 72.0 mm Exif.CanonCs.MaxAperture Short 1 F3.6 Exif.CanonCs.MinAperture Short 1 F8 Exif.CanonCs.FlashActivity Short 1 Did not fire Exif.CanonCs.FlashDetails Short 1 Exif.CanonCs.FocusContinuous Short 1 Continuous Exif.CanonCs.AESetting Short 1 Normal AE Exif.CanonCs.ImageStabilization Short 1 On Exif.CanonCs.DisplayAperture Short 1 0 Exif.CanonCs.ZoomSourceWidth Short 1 3264 Exif.CanonCs.ZoomTargetWidth Short 1 3264 Exif.CanonCs.SpotMeteringMode Short 1 Center Exif.CanonCs.PhotoEffect Short 1 (65535) Exif.CanonCs.ManualFlashOutput Short 1 n/a Exif.CanonCs.ColorTone Short 1 32767 Exif.Canon.FocalLength Short 4 21.3 mm Exif.CanonSi.ISOSpeed Short 1 100 Exif.CanonSi.MeasuredEV Short 1 14.25 Exif.CanonSi.TargetAperture Short 1 F4 Exif.CanonSi.TargetShutterSpeed Short 1 1/501 s Exif.CanonSi.WhiteBalance Short 1 Sunny Exif.CanonSi.Sequence Short 1 0 Exif.CanonSi.AFPointUsed Short 1 0 focus points; none used Exif.CanonSi.FlashBias Short 1 0 EV Exif.CanonSi.SubjectDistance Short 1 503 Exif.CanonSi.ApertureValue Short 1 F4 Exif.CanonSi.ShutterSpeedValue Short 1 1/546 s Exif.CanonSi.MeasuredEV2 Short 1 -6.00 Exif.Canon.ImageType Ascii 25 IMG:PowerShot S5 IS JPEG Exif.Canon.FirmwareVersion Ascii 22 Firmware Version 1.01 Exif.Canon.FileNumber Long 1 100-1904 Exif.Canon.OwnerName Ascii 32 Robin Mills Exif.Canon.CameraInfo Long 148 370 411 0 0 0 384 874 4294967255 0 0 0 0 577 889 4294967150 0 0 4294967287 0 0 1 0 0 0 9 10 888 888 888 384 1015 4294967148 0 0 888 888 0 0 1 3072 3072 3072 3072 3072 4294964224 4294964224 4294964224 4294964224 4294964224 0 4294964224 4294967287 0 0 0 0 0 0 0 0 0 0 164 1024 1024 40 94 0 0 0 0 0 0 525 0 40 94 0 0 3 1 0 0 921 1027 1024 1280 0 40 97 10 881 1646 1711 881 1 1014 384 888 659 4294967148 2 128 1 0 0 0 0 7532 5 0 0 0 0 0 0 7819 8252 8279 128 1 0 4294961112 3 1 7471 0 0 0 0 0 0 0 0 5345 1088 245 446 100 196 44 4091 4091 1 1 25 8 2400605383 Exif.Canon.ModelID Long 1 PowerShot S5 IS Exif.Canon.ThumbnailImageValidArea Short 4 0 0 0 0 Exif.Canon.SuperMacro Short 1 Off Exif.Canon.AFInfo Short 48 96 2 9 1 2592 1944 1088 245 196 0 0 0 0 0 0 0 0 44 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 Exif.Photo.UserComment Undefined 264 (Binary value suppressed) Exif.Photo.FlashpixVersion Undefined 4 1.00 Exif.Photo.ColorSpace Short 1 sRGB Exif.Photo.PixelXDimension Short 1 2592 Exif.Photo.PixelYDimension Short 1 1944 Exif.Photo.InteroperabilityTag Long 1 3350 Exif.Iop.InteroperabilityIndex Ascii 4 R98 Exif.Iop.InteroperabilityVersion Undefined 4 1.00 Exif.Iop.RelatedImageWidth Short 1 2592 Exif.Iop.RelatedImageLength Short 1 1944 Exif.Photo.FocalPlaneXResolution Rational 1 11520 Exif.Photo.FocalPlaneYResolution Rational 1 11503 Exif.Photo.FocalPlaneResolutionUnit Short 1 inch Exif.Photo.SensingMethod Short 1 One-chip color area Exif.Photo.FileSource Undefined 1 Digital still camera Exif.Photo.CustomRendered Short 1 Normal process Exif.Photo.ExposureMode Short 1 Auto Exif.Photo.WhiteBalance Short 1 Manual Exif.Photo.DigitalZoomRatio Rational 1 1.0 Exif.Photo.SceneCaptureType Short 1 Standard Exif.Thumbnail.Compression Short 1 JPEG (old-style) Exif.Thumbnail.XResolution Rational 1 180 Exif.Thumbnail.YResolution Rational 1 180 Exif.Thumbnail.ResolutionUnit Short 1 inch Exif.Thumbnail.JPEGInterchangeFormat Long 1 3498 Exif.Thumbnail.JPEGInterchangeFormatLength Long 1 6714 exiv2 0.23 001700 (64 bit build) Copyright (C) 2004-2012 Andreas Huggel. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Exif.Photo.DateTimeOriginal Ascii 20 2008:09:06 14:34:23 Exif.Photo.DateTimeOriginal Ascii 20 2008:09:06 14:34:23 Exif.Image.Make Ascii 6 Canon Exif.Image.Model Ascii 22 Canon PowerShot S5 IS Exif.Image.Orientation Short 1 top, left Exif.Image.XResolution Rational 1 180 Exif.Image.YResolution Rational 1 180 Exif.Image.ResolutionUnit Short 1 inch Exif.Image.DateTime Ascii 20 2008:09:06 14:34:23 Exif.Image.YCbCrPositioning Short 1 Centered Exif.Image.ExifTag Long 1 186 Exif.Photo.ExposureTime Rational 1 1/500 s Exif.Photo.FNumber Rational 1 F4 Exif.Photo.ISOSpeedRatings Short 1 80 Exif.Photo.ExifVersion Undefined 4 2.20 Exif.Photo.DateTimeOriginal Ascii 20 2008:09:06 14:34:23 Exif.Photo.DateTimeDigitized Ascii 20 2008:09:06 14:34:23 Exif.Photo.ComponentsConfiguration Undefined 4 YCbCr Exif.Photo.CompressedBitsPerPixel Rational 1 3 Exif.Photo.ShutterSpeedValue SRational 1 1/501 s Exif.Photo.ApertureValue Rational 1 F4 Exif.Photo.ExposureBiasValue SRational 1 0 EV Exif.Photo.MaxApertureValue Rational 1 F3.5 Exif.Photo.MeteringMode Short 1 Multi-segment Exif.Photo.Flash Short 1 No, compulsory Exif.Photo.FocalLength Rational 1 21.3 mm Exif.Photo.MakerNote Undefined 2382 (Binary value suppressed) Exif.MakerNote.Offset Long 1 680 Exif.MakerNote.ByteOrder Ascii 3 MM Exif.CanonCs.Macro Short 1 Off Exif.CanonCs.Selftimer Short 1 Off Exif.CanonCs.Quality Short 1 Fine Exif.CanonCs.FlashMode Short 1 Off Exif.CanonCs.DriveMode Short 1 Single / timer Exif.CanonCs.FocusMode Short 1 Single Exif.CanonCs.ImageSize Short 1 Medium 1 Exif.CanonCs.EasyMode Short 1 Manual Exif.CanonCs.DigitalZoom Short 1 None Exif.CanonCs.Contrast Short 1 Normal Exif.CanonCs.Saturation Short 1 Normal Exif.CanonCs.Sharpness Short 1 Normal Exif.CanonCs.ISOSpeed Short 1 Auto Exif.CanonCs.MeteringMode Short 1 Evaluative Exif.CanonCs.FocusType Short 1 Auto Exif.CanonCs.AFPoint Short 1 Manual AF point selection Exif.CanonCs.ExposureProgram Short 1 Program (P) Exif.CanonCs.LensType Short 1 (65535) Exif.CanonCs.Lens Short 3 6.0 - 72.0 mm Exif.CanonCs.MaxAperture Short 1 F3.6 Exif.CanonCs.MinAperture Short 1 F8 Exif.CanonCs.FlashActivity Short 1 Did not fire Exif.CanonCs.FlashDetails Short 1 Exif.CanonCs.FocusContinuous Short 1 Continuous Exif.CanonCs.AESetting Short 1 Normal AE Exif.CanonCs.ImageStabilization Short 1 On Exif.CanonCs.DisplayAperture Short 1 0 Exif.CanonCs.ZoomSourceWidth Short 1 3264 Exif.CanonCs.ZoomTargetWidth Short 1 3264 Exif.CanonCs.SpotMeteringMode Short 1 Center Exif.CanonCs.PhotoEffect Short 1 (65535) Exif.CanonCs.ManualFlashOutput Short 1 n/a Exif.CanonCs.ColorTone Short 1 32767 Exif.Canon.FocalLength Short 4 21.3 mm Exif.CanonSi.ISOSpeed Short 1 100 Exif.CanonSi.MeasuredEV Short 1 14.25 Exif.CanonSi.TargetAperture Short 1 F4 Exif.CanonSi.TargetShutterSpeed Short 1 1/501 s Exif.CanonSi.WhiteBalance Short 1 Sunny Exif.CanonSi.Sequence Short 1 0 Exif.CanonSi.AFPointUsed Short 1 0 focus points; none used Exif.CanonSi.FlashBias Short 1 0 EV Exif.CanonSi.SubjectDistance Short 1 503 Exif.CanonSi.ApertureValue Short 1 F4 Exif.CanonSi.ShutterSpeedValue Short 1 1/546 s Exif.CanonSi.MeasuredEV2 Short 1 -6.00 Exif.Canon.ImageType Ascii 25 IMG:PowerShot S5 IS JPEG Exif.Canon.FirmwareVersion Ascii 22 Firmware Version 1.01 Exif.Canon.FileNumber Long 1 100-1904 Exif.Canon.OwnerName Ascii 32 Robin Mills Exif.Canon.CameraInfo Long 148 370 411 0 0 0 384 874 4294967255 0 0 0 0 577 889 4294967150 0 0 4294967287 0 0 1 0 0 0 9 10 888 888 888 384 1015 4294967148 0 0 888 888 0 0 1 3072 3072 3072 3072 3072 4294964224 4294964224 4294964224 4294964224 4294964224 0 4294964224 4294967287 0 0 0 0 0 0 0 0 0 0 164 1024 1024 40 94 0 0 0 0 0 0 525 0 40 94 0 0 3 1 0 0 921 1027 1024 1280 0 40 97 10 881 1646 1711 881 1 1014 384 888 659 4294967148 2 128 1 0 0 0 0 7532 5 0 0 0 0 0 0 7819 8252 8279 128 1 0 4294961112 3 1 7471 0 0 0 0 0 0 0 0 5345 1088 245 446 100 196 44 4091 4091 1 1 25 8 2400605383 Exif.Canon.ModelID Long 1 PowerShot S5 IS Exif.Canon.ThumbnailImageValidArea Short 4 0 0 0 0 Exif.Canon.SuperMacro Short 1 Off Exif.Canon.AFInfo Short 48 96 2 9 1 2592 1944 1088 245 196 0 0 0 0 0 0 0 0 44 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 Exif.Photo.UserComment Undefined 264 (Binary value suppressed) Exif.Photo.FlashpixVersion Undefined 4 1.00 Exif.Photo.ColorSpace Short 1 sRGB Exif.Photo.PixelXDimension Short 1 2592 Exif.Photo.PixelYDimension Short 1 1944 Exif.Photo.InteroperabilityTag Long 1 3350 Exif.Iop.InteroperabilityIndex Ascii 4 R98 Exif.Iop.InteroperabilityVersion Undefined 4 1.00 Exif.Iop.RelatedImageWidth Short 1 2592 Exif.Iop.RelatedImageLength Short 1 1944 Exif.Photo.FocalPlaneXResolution Rational 1 11520 Exif.Photo.FocalPlaneYResolution Rational 1 11503 Exif.Photo.FocalPlaneResolutionUnit Short 1 inch Exif.Photo.SensingMethod Short 1 One-chip color area Exif.Photo.FileSource Undefined 1 Digital still camera Exif.Photo.CustomRendered Short 1 Normal process Exif.Photo.ExposureMode Short 1 Auto Exif.Photo.WhiteBalance Short 1 Manual Exif.Photo.DigitalZoomRatio Rational 1 1.0 Exif.Photo.SceneCaptureType Short 1 Standard Exif.Thumbnail.Compression Short 1 JPEG (old-style) Exif.Thumbnail.XResolution Rational 1 180 Exif.Thumbnail.YResolution Rational 1 180 Exif.Thumbnail.ResolutionUnit Short 1 inch Exif.Thumbnail.JPEGInterchangeFormat Long 1 3498 Exif.Thumbnail.JPEGInterchangeFormatLength Long 1 6714 exiv2 0.23 001700 (64 bit build) Copyright (C) 2004-2012 Andreas Huggel. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Exif.Photo.DateTimeOriginal Ascii 20 2008:09:06 14:34:23 Exif.Photo.DateTimeOriginal Ascii 20 2008:09:06 14:34:23 Exif.Image.Make Ascii 6 Canon Exif.Image.Model Ascii 22 Canon PowerShot S5 IS Exif.Image.Orientation Short 1 top, left Exif.Image.XResolution Rational 1 180 Exif.Image.YResolution Rational 1 180 Exif.Image.ResolutionUnit Short 1 inch Exif.Image.DateTime Ascii 20 2008:09:06 14:34:23 Exif.Image.YCbCrPositioning Short 1 Centered Exif.Image.ExifTag Long 1 186 Exif.Photo.ExposureTime Rational 1 1/500 s Exif.Photo.FNumber Rational 1 F4 Exif.Photo.ISOSpeedRatings Short 1 80 Exif.Photo.ExifVersion Undefined 4 2.20 Exif.Photo.DateTimeOriginal Ascii 20 2008:09:06 14:34:23 Exif.Photo.DateTimeDigitized Ascii 20 2008:09:06 14:34:23 Exif.Photo.ComponentsConfiguration Undefined 4 YCbCr Exif.Photo.CompressedBitsPerPixel Rational 1 3 Exif.Photo.ShutterSpeedValue SRational 1 1/501 s Exif.Photo.ApertureValue Rational 1 F4 Exif.Photo.ExposureBiasValue SRational 1 0 EV Exif.Photo.MaxApertureValue Rational 1 F3.5 Exif.Photo.MeteringMode Short 1 Multi-segment Exif.Photo.Flash Short 1 No, compulsory Exif.Photo.FocalLength Rational 1 21.3 mm Exif.Photo.MakerNote Undefined 2382 (Binary value suppressed) Exif.MakerNote.Offset Long 1 680 Exif.MakerNote.ByteOrder Ascii 3 MM Exif.CanonCs.Macro Short 1 Off Exif.CanonCs.Selftimer Short 1 Off Exif.CanonCs.Quality Short 1 Fine Exif.CanonCs.FlashMode Short 1 Off Exif.CanonCs.DriveMode Short 1 Single / timer Exif.CanonCs.FocusMode Short 1 Single Exif.CanonCs.ImageSize Short 1 Medium 1 Exif.CanonCs.EasyMode Short 1 Manual Exif.CanonCs.DigitalZoom Short 1 None Exif.CanonCs.Contrast Short 1 Normal Exif.CanonCs.Saturation Short 1 Normal Exif.CanonCs.Sharpness Short 1 Normal Exif.CanonCs.ISOSpeed Short 1 Auto Exif.CanonCs.MeteringMode Short 1 Evaluative Exif.CanonCs.FocusType Short 1 Auto Exif.CanonCs.AFPoint Short 1 Manual AF point selection Exif.CanonCs.ExposureProgram Short 1 Program (P) Exif.CanonCs.LensType Short 1 (65535) Exif.CanonCs.Lens Short 3 6.0 - 72.0 mm Exif.CanonCs.MaxAperture Short 1 F3.6 Exif.CanonCs.MinAperture Short 1 F8 Exif.CanonCs.FlashActivity Short 1 Did not fire Exif.CanonCs.FlashDetails Short 1 Exif.CanonCs.FocusContinuous Short 1 Continuous Exif.CanonCs.AESetting Short 1 Normal AE Exif.CanonCs.ImageStabilization Short 1 On Exif.CanonCs.DisplayAperture Short 1 0 Exif.CanonCs.ZoomSourceWidth Short 1 3264 Exif.CanonCs.ZoomTargetWidth Short 1 3264 Exif.CanonCs.SpotMeteringMode Short 1 Center Exif.CanonCs.PhotoEffect Short 1 (65535) Exif.CanonCs.ManualFlashOutput Short 1 n/a Exif.CanonCs.ColorTone Short 1 32767 Exif.Canon.FocalLength Short 4 21.3 mm Exif.CanonSi.ISOSpeed Short 1 100 Exif.CanonSi.MeasuredEV Short 1 14.25 Exif.CanonSi.TargetAperture Short 1 F4 Exif.CanonSi.TargetShutterSpeed Short 1 1/501 s Exif.CanonSi.WhiteBalance Short 1 Sunny Exif.CanonSi.Sequence Short 1 0 Exif.CanonSi.AFPointUsed Short 1 0 focus points; none used Exif.CanonSi.FlashBias Short 1 0 EV Exif.CanonSi.SubjectDistance Short 1 503 Exif.CanonSi.ApertureValue Short 1 F4 Exif.CanonSi.ShutterSpeedValue Short 1 1/546 s Exif.CanonSi.MeasuredEV2 Short 1 -6.00 Exif.Canon.ImageType Ascii 25 IMG:PowerShot S5 IS JPEG Exif.Canon.FirmwareVersion Ascii 22 Firmware Version 1.01 Exif.Canon.FileNumber Long 1 100-1904 Exif.Canon.OwnerName Ascii 32 Robin Mills Exif.Canon.CameraInfo Long 148 370 411 0 0 0 384 874 4294967255 0 0 0 0 577 889 4294967150 0 0 4294967287 0 0 1 0 0 0 9 10 888 888 888 384 1015 4294967148 0 0 888 888 0 0 1 3072 3072 3072 3072 3072 4294964224 4294964224 4294964224 4294964224 4294964224 0 4294964224 4294967287 0 0 0 0 0 0 0 0 0 0 164 1024 1024 40 94 0 0 0 0 0 0 525 0 40 94 0 0 3 1 0 0 921 1027 1024 1280 0 40 97 10 881 1646 1711 881 1 1014 384 888 659 4294967148 2 128 1 0 0 0 0 7532 5 0 0 0 0 0 0 7819 8252 8279 128 1 0 4294961112 3 1 7471 0 0 0 0 0 0 0 0 5345 1088 245 446 100 196 44 4091 4091 1 1 25 8 2400605383 Exif.Canon.ModelID Long 1 PowerShot S5 IS Exif.Canon.ThumbnailImageValidArea Short 4 0 0 0 0 Exif.Canon.SuperMacro Short 1 Off Exif.Canon.AFInfo Short 48 96 2 9 1 2592 1944 1088 245 196 0 0 0 0 0 0 0 0 44 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 Exif.Photo.UserComment Undefined 264 (Binary value suppressed) Exif.Photo.FlashpixVersion Undefined 4 1.00 Exif.Photo.ColorSpace Short 1 sRGB Exif.Photo.PixelXDimension Short 1 2592 Exif.Photo.PixelYDimension Short 1 1944 Exif.Photo.InteroperabilityTag Long 1 3350 Exif.Iop.InteroperabilityIndex Ascii 4 R98 Exif.Iop.InteroperabilityVersion Undefined 4 1.00 Exif.Iop.RelatedImageWidth Short 1 2592 Exif.Iop.RelatedImageLength Short 1 1944 Exif.Photo.FocalPlaneXResolution Rational 1 11520 Exif.Photo.FocalPlaneYResolution Rational 1 11503 Exif.Photo.FocalPlaneResolutionUnit Short 1 inch Exif.Photo.SensingMethod Short 1 One-chip color area Exif.Photo.FileSource Undefined 1 Digital still camera Exif.Photo.CustomRendered Short 1 Normal process Exif.Photo.ExposureMode Short 1 Auto Exif.Photo.WhiteBalance Short 1 Manual Exif.Photo.DigitalZoomRatio Rational 1 1.0 Exif.Photo.SceneCaptureType Short 1 Standard Exif.Thumbnail.Compression Short 1 JPEG (old-style) Exif.Thumbnail.XResolution Rational 1 180 Exif.Thumbnail.YResolution Rational 1 180 Exif.Thumbnail.ResolutionUnit Short 1 inch Exif.Thumbnail.JPEGInterchangeFormat Long 1 3498 Exif.Thumbnail.JPEGInterchangeFormatLength Long 1 6714 exiv2 0.23 001700 (64 bit build) Copyright (C) 2004-2012 Andreas Huggel. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Exif.Photo.DateTimeOriginal Ascii 20 2008:09:06 14:34:23 Exif.Photo.DateTimeOriginal Ascii 20 2008:09:06 14:34:23 Exif.Image.Make Ascii 6 Canon Exif.Image.Model Ascii 22 Canon PowerShot S5 IS Exif.Image.Orientation Short 1 top, left Exif.Image.XResolution Rational 1 180 Exif.Image.YResolution Rational 1 180 Exif.Image.ResolutionUnit Short 1 inch Exif.Image.DateTime Ascii 20 2008:09:06 14:34:23 Exif.Image.YCbCrPositioning Short 1 Centered Exif.Image.ExifTag Long 1 186 Exif.Photo.ExposureTime Rational 1 1/500 s Exif.Photo.FNumber Rational 1 F4 Exif.Photo.ISOSpeedRatings Short 1 80 Exif.Photo.ExifVersion Undefined 4 2.20 Exif.Photo.DateTimeOriginal Ascii 20 2008:09:06 14:34:23 Exif.Photo.DateTimeDigitized Ascii 20 2008:09:06 14:34:23 Exif.Photo.ComponentsConfiguration Undefined 4 YCbCr Exif.Photo.CompressedBitsPerPixel Rational 1 3 Exif.Photo.ShutterSpeedValue SRational 1 1/501 s Exif.Photo.ApertureValue Rational 1 F4 Exif.Photo.ExposureBiasValue SRational 1 0 EV Exif.Photo.MaxApertureValue Rational 1 F3.5 Exif.Photo.MeteringMode Short 1 Multi-segment Exif.Photo.Flash Short 1 No, compulsory Exif.Photo.FocalLength Rational 1 21.3 mm Exif.Photo.MakerNote Undefined 2382 (Binary value suppressed) Exif.MakerNote.Offset Long 1 680 Exif.MakerNote.ByteOrder Ascii 3 MM Exif.CanonCs.Macro Short 1 Off Exif.CanonCs.Selftimer Short 1 Off Exif.CanonCs.Quality Short 1 Fine Exif.CanonCs.FlashMode Short 1 Off Exif.CanonCs.DriveMode Short 1 Single / timer Exif.CanonCs.FocusMode Short 1 Single Exif.CanonCs.ImageSize Short 1 Medium 1 Exif.CanonCs.EasyMode Short 1 Manual Exif.CanonCs.DigitalZoom Short 1 None Exif.CanonCs.Contrast Short 1 Normal Exif.CanonCs.Saturation Short 1 Normal Exif.CanonCs.Sharpness Short 1 Normal Exif.CanonCs.ISOSpeed Short 1 Auto Exif.CanonCs.MeteringMode Short 1 Evaluative Exif.CanonCs.FocusType Short 1 Auto Exif.CanonCs.AFPoint Short 1 Manual AF point selection Exif.CanonCs.ExposureProgram Short 1 Program (P) Exif.CanonCs.LensType Short 1 (65535) Exif.CanonCs.Lens Short 3 6.0 - 72.0 mm Exif.CanonCs.MaxAperture Short 1 F3.6 Exif.CanonCs.MinAperture Short 1 F8 Exif.CanonCs.FlashActivity Short 1 Did not fire Exif.CanonCs.FlashDetails Short 1 Exif.CanonCs.FocusContinuous Short 1 Continuous Exif.CanonCs.AESetting Short 1 Normal AE Exif.CanonCs.ImageStabilization Short 1 On Exif.CanonCs.DisplayAperture Short 1 0 Exif.CanonCs.ZoomSourceWidth Short 1 3264 Exif.CanonCs.ZoomTargetWidth Short 1 3264 Exif.CanonCs.SpotMeteringMode Short 1 Center Exif.CanonCs.PhotoEffect Short 1 (65535) Exif.CanonCs.ManualFlashOutput Short 1 n/a Exif.CanonCs.ColorTone Short 1 32767 Exif.Canon.FocalLength Short 4 21.3 mm Exif.CanonSi.ISOSpeed Short 1 100 Exif.CanonSi.MeasuredEV Short 1 14.25 Exif.CanonSi.TargetAperture Short 1 F4 Exif.CanonSi.TargetShutterSpeed Short 1 1/501 s Exif.CanonSi.WhiteBalance Short 1 Sunny Exif.CanonSi.Sequence Short 1 0 Exif.CanonSi.AFPointUsed Short 1 0 focus points; none used Exif.CanonSi.FlashBias Short 1 0 EV Exif.CanonSi.SubjectDistance Short 1 503 Exif.CanonSi.ApertureValue Short 1 F4 Exif.CanonSi.ShutterSpeedValue Short 1 1/546 s Exif.CanonSi.MeasuredEV2 Short 1 -6.00 Exif.Canon.ImageType Ascii 25 IMG:PowerShot S5 IS JPEG Exif.Canon.FirmwareVersion Ascii 22 Firmware Version 1.01 Exif.Canon.FileNumber Long 1 100-1904 Exif.Canon.OwnerName Ascii 32 Robin Mills Exif.Canon.CameraInfo Long 148 370 411 0 0 0 384 874 4294967255 0 0 0 0 577 889 4294967150 0 0 4294967287 0 0 1 0 0 0 9 10 888 888 888 384 1015 4294967148 0 0 888 888 0 0 1 3072 3072 3072 3072 3072 4294964224 4294964224 4294964224 4294964224 4294964224 0 4294964224 4294967287 0 0 0 0 0 0 0 0 0 0 164 1024 1024 40 94 0 0 0 0 0 0 525 0 40 94 0 0 3 1 0 0 921 1027 1024 1280 0 40 97 10 881 1646 1711 881 1 1014 384 888 659 4294967148 2 128 1 0 0 0 0 7532 5 0 0 0 0 0 0 7819 8252 8279 128 1 0 4294961112 3 1 7471 0 0 0 0 0 0 0 0 5345 1088 245 446 100 196 44 4091 4091 1 1 25 8 2400605383 Exif.Canon.ModelID Long 1 PowerShot S5 IS Exif.Canon.ThumbnailImageValidArea Short 4 0 0 0 0 Exif.Canon.SuperMacro Short 1 Off Exif.Canon.AFInfo Short 48 96 2 9 1 2592 1944 1088 245 196 0 0 0 0 0 0 0 0 44 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 Exif.Photo.UserComment Undefined 264 (Binary value suppressed) Exif.Photo.FlashpixVersion Undefined 4 1.00 Exif.Photo.ColorSpace Short 1 sRGB Exif.Photo.PixelXDimension Short 1 2592 Exif.Photo.PixelYDimension Short 1 1944 Exif.Photo.InteroperabilityTag Long 1 3350 Exif.Iop.InteroperabilityIndex Ascii 4 R98 Exif.Iop.InteroperabilityVersion Undefined 4 1.00 Exif.Iop.RelatedImageWidth Short 1 2592 Exif.Iop.RelatedImageLength Short 1 1944 Exif.Photo.FocalPlaneXResolution Rational 1 11520 Exif.Photo.FocalPlaneYResolution Rational 1 11503 Exif.Photo.FocalPlaneResolutionUnit Short 1 inch Exif.Photo.SensingMethod Short 1 One-chip color area Exif.Photo.FileSource Undefined 1 Digital still camera Exif.Photo.CustomRendered Short 1 Normal process Exif.Photo.ExposureMode Short 1 Auto Exif.Photo.WhiteBalance Short 1 Manual Exif.Photo.DigitalZoomRatio Rational 1 1.0 Exif.Photo.SceneCaptureType Short 1 Standard Exif.Thumbnail.Compression Short 1 JPEG (old-style) Exif.Thumbnail.XResolution Rational 1 180 Exif.Thumbnail.YResolution Rational 1 180 Exif.Thumbnail.ResolutionUnit Short 1 inch Exif.Thumbnail.JPEGInterchangeFormat Long 1 3498 Exif.Thumbnail.JPEGInterchangeFormatLength Long 1 6714 exiv2d.dll KERNEL32.dll KERNELBASE.dll libexpat.dll ntdll.dll zlib1d.dll KERNEL32.dll KERNELBASE.dll libexpat.dll ntdll.dll KERNEL32.dll KERNELBASE.dll ntdll.dll zlib1d.dll exiv2.dll KERNEL32.dll KERNELBASE.dll libexpat.dll ntdll.dll zlib1.dll KERNEL32.dll KERNELBASE.dll libexpat.dll ntdll.dll KERNEL32.dll KERNELBASE.dll ntdll.dll zlib1.dll exiv2d.dll KERNEL32.dll KERNELBASE.dll libexpat.dll ntdll.dll zlib1d.dll KERNEL32.dll KERNELBASE.dll libexpat.dll ntdll.dll KERNEL32.dll KERNELBASE.dll ntdll.dll zlib1d.dll exiv2.dll KERNEL32.dll KERNELBASE.dll libexpat.dll ntdll.dll zlib1.dll KERNEL32.dll KERNELBASE.dll libexpat.dll ntdll.dll KERNEL32.dll KERNELBASE.dll ntdll.dll zlib1.dll exiv2.exe exiv2d.dll KERNEL32.dll KERNELBASE.dll libexpat.dll ntdll.dll zlib1d.dll exiv2.exe KERNEL32.dll KERNELBASE.dll ntdll.dll exiv2.dll exiv2.exe KERNEL32.dll KERNELBASE.dll libexpat.dll ntdll.dll zlib1.dll exiv2.exe KERNEL32.dll KERNELBASE.dll ntdll.dll exiv2.exe exiv2d.dll KERNEL32.dll KERNELBASE.dll libexpat.dll ntdll.dll zlib1d.dll exiv2.exe KERNEL32.dll KERNELBASE.dll ntdll.dll exiv2.dll exiv2.exe KERNEL32.dll KERNELBASE.dll libexpat.dll ntdll.dll zlib1.dll exiv2.exe KERNEL32.dll KERNELBASE.dll ntdll.dll exiv2-0.23/msvc64/zlib125/0000755000175000017500000000000011745263366014636 5ustar andreasandreasexiv2-0.23/msvc64/zlib125/zlib.vcproj0000644000175000017500000004134611510162225017011 0ustar andreasandreas exiv2-0.23/msvc64/exiv2/0000755000175000017500000000000011745263366014503 5ustar andreasandreasexiv2-0.23/msvc64/exiv2/exiv2.vcproj0000644000175000017500000005717311532054201016756 0ustar andreasandreas exiv2-0.23/msvc64/exiv2/cleaner.bat0000644000175000017500000000013611505202322016557 0ustar andreasandreasdel/s *.vcxproj *.ncb *.user *.filters *.sdf for /r %d in (build,win32,x64) do rmdir/s/q %d exiv2-0.23/msvc64/exiv2.sln0000644000175000017500000002035111505202322015175 0ustar andreasandreasMicrosoft Visual Studio Solution File, Format Version 9.00 # Visual Studio 2005 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "exiv2lib", "exiv2lib\exiv2lib.vcproj", "{831EF580-92C8-4CA8-B0CE-3D906280A54D}" ProjectSection(ProjectDependencies) = postProject {8308C68D-E12B-4C71-96F4-7137F6BEB654} = {8308C68D-E12B-4C71-96F4-7137F6BEB654} {6C4C06A3-6F8F-4067-AA4C-D5F41E1FFF9A} = {6C4C06A3-6F8F-4067-AA4C-D5F41E1FFF9A} {09877CF4-83B6-44FE-A2E2-629AA5C8093E} = {09877CF4-83B6-44FE-A2E2-629AA5C8093E} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "exiv2", "exiv2\exiv2.vcproj", "{07293CAC-00DA-493E-90C9-5D010C2B1B53}" ProjectSection(ProjectDependencies) = postProject {831EF580-92C8-4CA8-B0CE-3D906280A54D} = {831EF580-92C8-4CA8-B0CE-3D906280A54D} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xmpsdk", "xmpsdk\xmpsdk.vcproj", "{09877CF4-83B6-44FE-A2E2-629AA5C8093E}" ProjectSection(ProjectDependencies) = postProject {8308C68D-E12B-4C71-96F4-7137F6BEB654} = {8308C68D-E12B-4C71-96F4-7137F6BEB654} {6C4C06A3-6F8F-4067-AA4C-D5F41E1FFF9A} = {6C4C06A3-6F8F-4067-AA4C-D5F41E1FFF9A} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "expat", "expat\expat.vcproj", "{6C4C06A3-6F8F-4067-AA4C-D5F41E1FFF9A}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib1", "zlib\zlib.vcproj", "{8308C68D-E12B-4C71-96F4-7137F6BEB654}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 Debug|x64 = Debug|x64 DebugDLL|Win32 = DebugDLL|Win32 DebugDLL|x64 = DebugDLL|x64 Release|Win32 = Release|Win32 Release|x64 = Release|x64 ReleaseDLL|Win32 = ReleaseDLL|Win32 ReleaseDLL|x64 = ReleaseDLL|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {831EF580-92C8-4CA8-B0CE-3D906280A54D}.Debug|Win32.ActiveCfg = Debug|Win32 {831EF580-92C8-4CA8-B0CE-3D906280A54D}.Debug|Win32.Build.0 = Debug|Win32 {831EF580-92C8-4CA8-B0CE-3D906280A54D}.Debug|x64.ActiveCfg = Debug|x64 {831EF580-92C8-4CA8-B0CE-3D906280A54D}.Debug|x64.Build.0 = Debug|x64 {831EF580-92C8-4CA8-B0CE-3D906280A54D}.DebugDLL|Win32.ActiveCfg = DebugDLL|Win32 {831EF580-92C8-4CA8-B0CE-3D906280A54D}.DebugDLL|Win32.Build.0 = DebugDLL|Win32 {831EF580-92C8-4CA8-B0CE-3D906280A54D}.DebugDLL|x64.ActiveCfg = DebugDLL|x64 {831EF580-92C8-4CA8-B0CE-3D906280A54D}.DebugDLL|x64.Build.0 = DebugDLL|x64 {831EF580-92C8-4CA8-B0CE-3D906280A54D}.Release|Win32.ActiveCfg = Release|Win32 {831EF580-92C8-4CA8-B0CE-3D906280A54D}.Release|Win32.Build.0 = Release|Win32 {831EF580-92C8-4CA8-B0CE-3D906280A54D}.Release|x64.ActiveCfg = Release|x64 {831EF580-92C8-4CA8-B0CE-3D906280A54D}.Release|x64.Build.0 = Release|x64 {831EF580-92C8-4CA8-B0CE-3D906280A54D}.ReleaseDLL|Win32.ActiveCfg = ReleaseDLL|Win32 {831EF580-92C8-4CA8-B0CE-3D906280A54D}.ReleaseDLL|Win32.Build.0 = ReleaseDLL|Win32 {831EF580-92C8-4CA8-B0CE-3D906280A54D}.ReleaseDLL|x64.ActiveCfg = ReleaseDLL|x64 {831EF580-92C8-4CA8-B0CE-3D906280A54D}.ReleaseDLL|x64.Build.0 = ReleaseDLL|x64 {07293CAC-00DA-493E-90C9-5D010C2B1B53}.Debug|Win32.ActiveCfg = Debug|Win32 {07293CAC-00DA-493E-90C9-5D010C2B1B53}.Debug|Win32.Build.0 = Debug|Win32 {07293CAC-00DA-493E-90C9-5D010C2B1B53}.Debug|x64.ActiveCfg = Debug|x64 {07293CAC-00DA-493E-90C9-5D010C2B1B53}.Debug|x64.Build.0 = Debug|x64 {07293CAC-00DA-493E-90C9-5D010C2B1B53}.DebugDLL|Win32.ActiveCfg = DebugDLL|Win32 {07293CAC-00DA-493E-90C9-5D010C2B1B53}.DebugDLL|Win32.Build.0 = DebugDLL|Win32 {07293CAC-00DA-493E-90C9-5D010C2B1B53}.DebugDLL|x64.ActiveCfg = DebugDLL|x64 {07293CAC-00DA-493E-90C9-5D010C2B1B53}.DebugDLL|x64.Build.0 = DebugDLL|x64 {07293CAC-00DA-493E-90C9-5D010C2B1B53}.Release|Win32.ActiveCfg = Release|Win32 {07293CAC-00DA-493E-90C9-5D010C2B1B53}.Release|Win32.Build.0 = Release|Win32 {07293CAC-00DA-493E-90C9-5D010C2B1B53}.Release|x64.ActiveCfg = Release|x64 {07293CAC-00DA-493E-90C9-5D010C2B1B53}.Release|x64.Build.0 = Release|x64 {07293CAC-00DA-493E-90C9-5D010C2B1B53}.ReleaseDLL|Win32.ActiveCfg = ReleaseDLL|Win32 {07293CAC-00DA-493E-90C9-5D010C2B1B53}.ReleaseDLL|Win32.Build.0 = ReleaseDLL|Win32 {07293CAC-00DA-493E-90C9-5D010C2B1B53}.ReleaseDLL|x64.ActiveCfg = ReleaseDLL|x64 {07293CAC-00DA-493E-90C9-5D010C2B1B53}.ReleaseDLL|x64.Build.0 = ReleaseDLL|x64 {09877CF4-83B6-44FE-A2E2-629AA5C8093E}.Debug|Win32.ActiveCfg = Debug|Win32 {09877CF4-83B6-44FE-A2E2-629AA5C8093E}.Debug|Win32.Build.0 = Debug|Win32 {09877CF4-83B6-44FE-A2E2-629AA5C8093E}.Debug|x64.ActiveCfg = Debug|x64 {09877CF4-83B6-44FE-A2E2-629AA5C8093E}.Debug|x64.Build.0 = Debug|x64 {09877CF4-83B6-44FE-A2E2-629AA5C8093E}.DebugDLL|Win32.ActiveCfg = DebugDLL|Win32 {09877CF4-83B6-44FE-A2E2-629AA5C8093E}.DebugDLL|Win32.Build.0 = DebugDLL|Win32 {09877CF4-83B6-44FE-A2E2-629AA5C8093E}.DebugDLL|x64.ActiveCfg = DebugDLL|x64 {09877CF4-83B6-44FE-A2E2-629AA5C8093E}.DebugDLL|x64.Build.0 = DebugDLL|x64 {09877CF4-83B6-44FE-A2E2-629AA5C8093E}.Release|Win32.ActiveCfg = Release|Win32 {09877CF4-83B6-44FE-A2E2-629AA5C8093E}.Release|Win32.Build.0 = Release|Win32 {09877CF4-83B6-44FE-A2E2-629AA5C8093E}.Release|x64.ActiveCfg = Release|x64 {09877CF4-83B6-44FE-A2E2-629AA5C8093E}.Release|x64.Build.0 = Release|x64 {09877CF4-83B6-44FE-A2E2-629AA5C8093E}.ReleaseDLL|Win32.ActiveCfg = ReleaseDLL|Win32 {09877CF4-83B6-44FE-A2E2-629AA5C8093E}.ReleaseDLL|Win32.Build.0 = ReleaseDLL|Win32 {09877CF4-83B6-44FE-A2E2-629AA5C8093E}.ReleaseDLL|x64.ActiveCfg = ReleaseDLL|x64 {09877CF4-83B6-44FE-A2E2-629AA5C8093E}.ReleaseDLL|x64.Build.0 = ReleaseDLL|x64 {6C4C06A3-6F8F-4067-AA4C-D5F41E1FFF9A}.Debug|Win32.ActiveCfg = Debug|Win32 {6C4C06A3-6F8F-4067-AA4C-D5F41E1FFF9A}.Debug|Win32.Build.0 = Debug|Win32 {6C4C06A3-6F8F-4067-AA4C-D5F41E1FFF9A}.Debug|x64.ActiveCfg = Debug|x64 {6C4C06A3-6F8F-4067-AA4C-D5F41E1FFF9A}.Debug|x64.Build.0 = Debug|x64 {6C4C06A3-6F8F-4067-AA4C-D5F41E1FFF9A}.DebugDLL|Win32.ActiveCfg = DebugDLL|Win32 {6C4C06A3-6F8F-4067-AA4C-D5F41E1FFF9A}.DebugDLL|Win32.Build.0 = DebugDLL|Win32 {6C4C06A3-6F8F-4067-AA4C-D5F41E1FFF9A}.DebugDLL|x64.ActiveCfg = DebugDLL|x64 {6C4C06A3-6F8F-4067-AA4C-D5F41E1FFF9A}.DebugDLL|x64.Build.0 = DebugDLL|x64 {6C4C06A3-6F8F-4067-AA4C-D5F41E1FFF9A}.Release|Win32.ActiveCfg = Release|Win32 {6C4C06A3-6F8F-4067-AA4C-D5F41E1FFF9A}.Release|Win32.Build.0 = Release|Win32 {6C4C06A3-6F8F-4067-AA4C-D5F41E1FFF9A}.Release|x64.ActiveCfg = Release|x64 {6C4C06A3-6F8F-4067-AA4C-D5F41E1FFF9A}.Release|x64.Build.0 = Release|x64 {6C4C06A3-6F8F-4067-AA4C-D5F41E1FFF9A}.ReleaseDLL|Win32.ActiveCfg = ReleaseDLL|Win32 {6C4C06A3-6F8F-4067-AA4C-D5F41E1FFF9A}.ReleaseDLL|Win32.Build.0 = ReleaseDLL|Win32 {6C4C06A3-6F8F-4067-AA4C-D5F41E1FFF9A}.ReleaseDLL|x64.ActiveCfg = ReleaseDLL|x64 {6C4C06A3-6F8F-4067-AA4C-D5F41E1FFF9A}.ReleaseDLL|x64.Build.0 = ReleaseDLL|x64 {8308C68D-E12B-4C71-96F4-7137F6BEB654}.Debug|Win32.ActiveCfg = Debug|Win32 {8308C68D-E12B-4C71-96F4-7137F6BEB654}.Debug|Win32.Build.0 = Debug|Win32 {8308C68D-E12B-4C71-96F4-7137F6BEB654}.Debug|x64.ActiveCfg = Debug|x64 {8308C68D-E12B-4C71-96F4-7137F6BEB654}.Debug|x64.Build.0 = Debug|x64 {8308C68D-E12B-4C71-96F4-7137F6BEB654}.DebugDLL|Win32.ActiveCfg = DebugDLL|Win32 {8308C68D-E12B-4C71-96F4-7137F6BEB654}.DebugDLL|Win32.Build.0 = DebugDLL|Win32 {8308C68D-E12B-4C71-96F4-7137F6BEB654}.DebugDLL|x64.ActiveCfg = DebugDLL|x64 {8308C68D-E12B-4C71-96F4-7137F6BEB654}.DebugDLL|x64.Build.0 = DebugDLL|x64 {8308C68D-E12B-4C71-96F4-7137F6BEB654}.Release|Win32.ActiveCfg = Release|Win32 {8308C68D-E12B-4C71-96F4-7137F6BEB654}.Release|Win32.Build.0 = Release|Win32 {8308C68D-E12B-4C71-96F4-7137F6BEB654}.Release|x64.ActiveCfg = Release|x64 {8308C68D-E12B-4C71-96F4-7137F6BEB654}.Release|x64.Build.0 = Release|x64 {8308C68D-E12B-4C71-96F4-7137F6BEB654}.ReleaseDLL|Win32.ActiveCfg = ReleaseDLL|Win32 {8308C68D-E12B-4C71-96F4-7137F6BEB654}.ReleaseDLL|Win32.Build.0 = ReleaseDLL|Win32 {8308C68D-E12B-4C71-96F4-7137F6BEB654}.ReleaseDLL|x64.ActiveCfg = ReleaseDLL|x64 {8308C68D-E12B-4C71-96F4-7137F6BEB654}.ReleaseDLL|x64.Build.0 = ReleaseDLL|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal exiv2-0.23/msvc64/cleanup.bat0000644000175000017500000000236711744715772015577 0ustar andreasandreassetlocal set X=exiv2\build && if EXIST %X% rmdir/s/q %X% set X=exiv2\Win32 && if EXIST %X% rmdir/s/q %X% set X=exiv2\x64 && if EXIST %X% rmdir/s/q %X% set X=exiv2lib\build && if EXIST %X% rmdir/s/q %X% set X=exiv2lib\Win32 && if EXIST %X% rmdir/s/q %X% set X=exiv2lib\x64 && if EXIST %X% rmdir/s/q %X% set X=expat\build && if EXIST %X% rmdir/s/q %X% set X=expat\Win32 && if EXIST %X% rmdir/s/q %X% set X=expat\x64 && if EXIST %X% rmdir/s/q %X% set X=xmpsdk\build && if EXIST %X% rmdir/s/q %X% set X=xmpsdk\Win32 && if EXIST %X% rmdir/s/q %X% set X=xmpsdk\x64 && if EXIST %X% rmdir/s/q %X% set X=zlib\build && if EXIST %X% rmdir/s/q %X% set X=zlib\Win32 && if EXIST %X% rmdir/s/q %X% set X=zlib\x64 && if EXIST %X% rmdir/s/q %X% set X=zlib123\build && if EXIST %X% rmdir/s/q %X% set X=zlib123\Win32 && if EXIST %X% rmdir/s/q %X% set X=zlib123\x64 && if EXIST %X% rmdir/s/q %X% set X=zlib125\build && if EXIST %X% rmdir/s/q %X% set X=zlib125\Win32 && if EXIST %X% rmdir/s/q %X% set X=zlib125\x64 && if EXIST %X% rmdir/s/q %X% del/s *.ncb del/s *.sdf del/s *.vcxproj del/s *%USERNAME%* del/s *.filters rmdir/s/q bin endlocal exiv2-0.23/msvc64/buildall.bat0000644000175000017500000000223711513141451015711 0ustar andreasandreas@echo off rem ## rem buildall - wee script for building from the command line setlocal ENABLEEXTENSIONS set "SYNTAX=buildall [ /build ^| /rebuild ^| /clean ^| /upgrade ]" rem ## rem test arguments set "ACTION=%1%" if NOT DEFINED ACTION ( echo %SYNTAX% goto jail ) rem ## rem execute /upgrade if %ACTION%==/upgrade ( devenv /upgrade exiv2.sln goto jail ) rem ## rem cleanup the bin if necessary set DELBIN=0 if %ACTION%==/rebuild set DELBIN=1 if %ACTION%==/clean set DELBIN=1 if %DELBIN%==1 ( if EXIST bin rmdir/s/q bin del/s *.pdb *.ild *.ncb *.bsc *.idb *.ilk *.pch *.tlog > NUL rmdir/s/q exiv2lib\win32 rmdir/s/q exiv2lib\x64 rmdir/s/q zlib\win32 zlib\x64 > NUL ) rem ## rem the main build activity devenv exiv2.sln %ACTION% "Debug|Win32" devenv exiv2.sln %ACTION% "DebugDLL|Win32" devenv exiv2.sln %ACTION% "Release|Win32" devenv exiv2.sln %ACTION% "ReleaseDLL|Win32" devenv exiv2.sln %ACTION% "Debug|x64" devenv exiv2.sln %ACTION% "DebugDLL|x64" devenv exiv2.sln %ACTION% "Release|x64" devenv exiv2.sln %ACTION% "ReleaseDLL|x64" rem ## rem cleanup and leave :jail endlocal rem That's all Folks! rem ## exiv2-0.23/msvc64/tools/0000755000175000017500000000000011745263366014606 5ustar andreasandreasexiv2-0.23/msvc64/tools/depends/0000755000175000017500000000000011745263366016230 5ustar andreasandreasexiv2-0.23/msvc64/tools/depends/include/0000755000175000017500000000000011745263366017653 5ustar andreasandreasexiv2-0.23/msvc64/tools/depends/include/DEPENDENCYLIST.H0000644000175000017500000000336511510227772022074 0ustar andreasandreas//========================================== // Matt Pietrek // Microsoft Systems Journal, Feb 1997 // FILE: DEPENDENCYLIST.H //========================================== #ifndef __DEPLIST_H__ #define __DEPLIST_H__ #ifndef __MODULEFILEINFO_H__ #include "modulefileinfo.h" #endif enum errModuleDependencyList { errMDL_NO_ERROR, errMDL_FILE_NOT_FOUND, errMDL_NOT_PE_FILE, errMDL_GENERAL_FAILURE }; // // The MODULE_DEPENDENCY_LIST class creates a linked list of MODULE_FILE_INFO // structures. In theory, this list will represent every executable file // loaded by the Win32 loader when the executable is loaded. The class creates // the list by starting with the file passed to the constructor, and recursing // through all the import tables. // class MODULE_DEPENDENCY_LIST { public: MODULE_DEPENDENCY_LIST( PSTR pszFileName ); ~MODULE_DEPENDENCY_LIST( ); BOOL IsValid( void ){ return (BOOL)(m_errorType == errMDL_NO_ERROR); } errModuleDependencyList GetErrorType( void ){ return m_errorType; } PSTR GetErrorString( void ); PMODULE_FILE_INFO GetNextModule( PMODULE_FILE_INFO p ); PMODULE_FILE_INFO LookupModule( PSTR pszFileName, BOOL fFullName ); unsigned GetNumberOfModules( void ){ return m_cModules; } protected: unsigned m_cModules; // Number of modules in list PMODULE_FILE_INFO m_pList; // Pointer to head of linked list // Recursively adds modules to the list errModuleDependencyList AddModule( PSTR pszFullName ); errModuleDependencyList m_errorType; // Error type }; #endif exiv2-0.23/msvc64/tools/depends/include/MEMORYMAPPEDFILE.H0000644000175000017500000000172011510227772022312 0ustar andreasandreas//========================================== // Matt Pietrek // Microsoft Systems Journal, Feb 1997 // FILE: MEMORYMAPPEDFILE.H //========================================== #ifndef __MEMMAPFL_H__ #define __MEMMAPFL_H__ enum errMMF { errMMF_NoError, errMMF_FileOpen, errMMF_FileMapping, errMMF_MapView }; class MEMORY_MAPPED_FILE { public: MEMORY_MAPPED_FILE( PSTR pszFileName ); ~MEMORY_MAPPED_FILE(void); PVOID GetBase( void ){ return m_pMemoryMappedFileBase; } DWORD GetFileSize( void ){ return m_cbFile; } BOOL IsValid( void ) { return errMMF_NoError == m_errCode; } errMMF GetErrorType(){ return m_errCode; } private: HANDLE m_hFile; HANDLE m_hFileMapping; // Handle of memory mapped file PVOID m_pMemoryMappedFileBase; DWORD m_cbFile; errMMF m_errCode; }; typedef MEMORY_MAPPED_FILE *PMEMORY_MAPPED_FILE; #endif exiv2-0.23/msvc64/tools/depends/include/EXEFILE.H0000644000175000017500000000301011510227772021026 0ustar andreasandreas//========================================== // Matt Pietrek // Microsoft Systems Journal, Feb 1997 // FILE: EXEFILE.H //========================================== #ifndef __EXEFILE_H__ #define __EXEFILE_H__ #ifndef __MEMMAPFL_H__ #include "memorymappedfile.h" #endif // MakePtr is a macro that allows you to easily add to values (including // pointers) together without dealing with C's pointer arithmetic. It // essentially treats the last two parameters as DWORDs. The first // parameter is used to typecast the result to the appropriate pointer type. #define MakePtr( cast, ptr, addValue ) (cast)( (DWORD)(ptr) + (DWORD)(addValue)) enum EXE_TYPE { exeType_Invalid, exeType_DOS, exeType_NE, exeType_VXD, exeType_LX, exeType_PE }; enum errEXE_FILE { errEXE_FILE_NO_ERROR, errEXE_FILE_FILE_NOT_FOUND, errEXE_FILE_INVALID_FORMAT }; class EXE_FILE : public MEMORY_MAPPED_FILE { public: EXE_FILE( PSTR pszFileName ); ~EXE_FILE( ){ ; } BOOL IsValid( void ){ return errMMF_NoError == m_errorType; } errEXE_FILE GetErrorType( void ){ return m_errorType; } DWORD GetSecondaryHeaderOffset( void ){ return m_secondaryHeaderOffset; } EXE_TYPE GetExeType( void ){ return m_exeType; } PSTR GetFileTypeDescription( void ); protected: errEXE_FILE m_errorType; private: LONG m_secondaryHeaderOffset; EXE_TYPE m_exeType; }; #endif exiv2-0.23/msvc64/tools/depends/include/modulefileinfo.h0000644000175000017500000000221711510227772023016 0ustar andreasandreas//========================================== // Matt Pietrek // Microsoft Systems Journal, Feb 1997 // FILE: MODULEFILEINFO.H //========================================== #ifndef __MODULEFILEINFO_H__ #define __MODULEFILEINFO_H__ class MODULE_DEPENDENCY_LIST; // // This structure represents one executable file in a module dependency list. // Both the base filename and the complete path are stored. // class MODULE_FILE_INFO { public: MODULE_FILE_INFO( PSTR pszFileName ); ~MODULE_FILE_INFO( void ){} PSTR GetBaseName( void ){ return m_szBaseName; } PSTR GetFullName( void ){ return m_szFullName; } // For enumerating through the unlocatable imported modules MODULE_FILE_INFO * GetNextNotFoundModule( MODULE_FILE_INFO * ); private: MODULE_FILE_INFO * m_pNext; MODULE_FILE_INFO * m_pNotFoundNext; char m_szBaseName[MAX_PATH]; char m_szFullName[MAX_PATH]; // And an unlocatable module to the "not found" list void AddNotFoundModule( PSTR pszFileName ); friend class MODULE_DEPENDENCY_LIST; }; typedef MODULE_FILE_INFO * PMODULE_FILE_INFO; #endif exiv2-0.23/msvc64/tools/depends/include/PEEXE.H0000644000175000017500000000744111510227772020627 0ustar andreasandreas//========================================== // Matt Pietrek // Microsoft Systems Journal, Feb 1997 // FILE: PEEXE.H //========================================== #ifndef __PEEXE_H__ #define __PEEXE_H__ #ifndef __EXEFILE_H__ #include "exefile.h" #endif class PE_EXE : public EXE_FILE { public: PE_EXE( PSTR pszFileName ); ~PE_EXE( ){ } BOOL IsValid() { return m_pNtHdr ? TRUE : FALSE; } // For those who want at the data directly PIMAGE_NT_HEADERS GetIMAGE_NT_HEADERS( void ) { return m_pNtHdr; } // IMAGE_FILE_HEADER fields WORD GetMachine( void ) { return m_pNtHdr->FileHeader.Machine; } WORD GetNumberOfSections( void ) { return m_pNtHdr->FileHeader.NumberOfSections; } DWORD GetTimeDateStamp(void) { return m_pNtHdr->FileHeader.TimeDateStamp; } DWORD GetCharacteristics( void ) { return m_pNtHdr->FileHeader.Characteristics; } // IMAGE_OPTIONAL_HEADER fields DWORD GetSizeOfCode( void ) { return m_pNtHdr->OptionalHeader.SizeOfCode; } DWORD GetSizeOfInitializedData( void ) { return m_pNtHdr->OptionalHeader.SizeOfInitializedData; } DWORD GetSizeOfUninitializedData( void ) { return m_pNtHdr->OptionalHeader.SizeOfUninitializedData; } DWORD GetAddressOfEntryPoint( void ) { return m_pNtHdr->OptionalHeader.AddressOfEntryPoint; } DWORD GetBaseOfCode( void ) { return m_pNtHdr->OptionalHeader.BaseOfCode; } /* DWORD GetBaseOfData( void ) { return m_pNtHdr->OptionalHeader.BaseOfData; } */ DWORD GetImageBase( void ) { return m_pNtHdr->OptionalHeader.ImageBase; } DWORD GetSectionAlignment( void ) { return m_pNtHdr->OptionalHeader.SectionAlignment; } DWORD GetFileAlignment( void ) { return m_pNtHdr->OptionalHeader.FileAlignment; } WORD GetMajorOperatingSystemVersion( void ) { return m_pNtHdr->OptionalHeader.MajorOperatingSystemVersion; } WORD GetMinorOperatingSystemVersion( void ) { return m_pNtHdr->OptionalHeader.MinorOperatingSystemVersion; } WORD GetMajorImageVersion( void ) { return m_pNtHdr->OptionalHeader.MajorImageVersion; } WORD GetMinorImageVersion( void ) { return m_pNtHdr->OptionalHeader.MinorImageVersion; } WORD GetMajorSubsystemVersion( void ) { return m_pNtHdr->OptionalHeader.MajorSubsystemVersion; } WORD GetMinorSubsystemVersion( void ) { return m_pNtHdr->OptionalHeader.MinorSubsystemVersion; } // DWORD GetWin32VersionValue( void ) // { return m_pNtHdr->OptionalHeader.Win32VersionValue; } DWORD GetSizeOfImage( void ) { return m_pNtHdr->OptionalHeader.SizeOfImage; } DWORD GetSizeOfHeaders( void ) { return m_pNtHdr->OptionalHeader.SizeOfHeaders; } WORD GetSubsystem( void ) { return m_pNtHdr->OptionalHeader.Subsystem; } DWORD GetSizeOfStackReserve( void ) { return m_pNtHdr->OptionalHeader.SizeOfStackReserve; } DWORD GetSizeOfStackCommit( void ) { return m_pNtHdr->OptionalHeader.SizeOfStackCommit; } DWORD GetSizeOfHeapReserve( void ) { return m_pNtHdr->OptionalHeader.SizeOfHeapReserve; } DWORD GetSizeOfHeapCommit( void ) { return m_pNtHdr->OptionalHeader.SizeOfHeapCommit; } DWORD GetDataDirectoryEntryRVA( DWORD id ); PVOID GetDataDirectoryEntryPointer( DWORD id ); DWORD GetDataDirectoryEntrySize( DWORD id ); PVOID GetReadablePointerFromRVA( DWORD rva ); protected: DWORD RVAToFileOffset( DWORD rva ); PIMAGE_NT_HEADERS m_pNtHdr; }; #endif exiv2-0.23/msvc64/tools/depends/stdafx.h0000644000175000017500000000050011510227772017654 0ustar andreasandreas// stdafx.h : include file for standard system include files, // or project specific include files that are used frequently, but // are changed infrequently // #pragma once #include "targetver.h" #include #include // TODO: reference additional headers your program requires here exiv2-0.23/msvc64/tools/depends/src/0000755000175000017500000000000011745263366017017 5ustar andreasandreasexiv2-0.23/msvc64/tools/depends/src/MEMORYMAPPEDFILE.CPP0000644000175000017500000000431611510227772021715 0ustar andreasandreas//========================================== // Matt Pietrek // Microsoft Systems Journal, Feb 1997 // FILE: MEMORYMPAPPEDFILE.CPP //========================================== #include #pragma hdrstop #include "memorymappedfile.h" MEMORY_MAPPED_FILE::MEMORY_MAPPED_FILE( PSTR pszFileName ) { // // Given a filename, the constructor opens a file handle, creates a file // mapping, and maps the entire file into memory. // m_hFile = INVALID_HANDLE_VALUE; m_hFileMapping = 0; m_pMemoryMappedFileBase = 0; m_cbFile = 0; m_errCode = errMMF_FileOpen; // Initial error code: not found // First get a file handle m_hFile = CreateFile(pszFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, (HANDLE)0); if ( m_hFile == INVALID_HANDLE_VALUE ) { m_errCode = errMMF_FileOpen; return; } m_cbFile = ::GetFileSize( m_hFile, 0 ); // Now, create a file mapping m_hFileMapping = CreateFileMapping(m_hFile,NULL, PAGE_READONLY, 0, 0,NULL); if ( m_hFileMapping == 0 ) { // Oops. Something went wrong. Clean up. CloseHandle(m_hFile); m_hFile = INVALID_HANDLE_VALUE; m_errCode = errMMF_FileMapping; return; } m_pMemoryMappedFileBase = (PCHAR)MapViewOfFile( m_hFileMapping, FILE_MAP_READ, 0, 0, 0); if ( m_pMemoryMappedFileBase == 0 ) { // Oops. Something went wrong. Clean up. CloseHandle(m_hFileMapping); m_hFileMapping = 0; CloseHandle(m_hFile); m_hFile = INVALID_HANDLE_VALUE; m_errCode = errMMF_MapView; return; } m_errCode = errMMF_NoError; } MEMORY_MAPPED_FILE::~MEMORY_MAPPED_FILE(void) { // Clean up everything that was created by the constructor if ( m_pMemoryMappedFileBase ) UnmapViewOfFile( m_pMemoryMappedFileBase ); if ( m_hFileMapping ) CloseHandle( m_hFileMapping ); if ( m_hFile != INVALID_HANDLE_VALUE ) CloseHandle( m_hFile ); m_errCode = errMMF_FileOpen; } exiv2-0.23/msvc64/tools/depends/src/EXEFILE.CPP0000644000175000017500000000464611510227772020445 0ustar andreasandreas//========================================== // Matt Pietrek // Microsoft Systems Journal, Feb 1997 // FILE: EXEFILE.CPP //========================================== #include #pragma hdrstop #include "exefile.h" EXE_FILE::EXE_FILE( PSTR pszFileName ) : MEMORY_MAPPED_FILE( pszFileName ) { m_errorType = errEXE_FILE_FILE_NOT_FOUND; m_secondaryHeaderOffset = -1; // A bogus value to catch bugs m_exeType = exeType_Invalid; if ( FALSE == MEMORY_MAPPED_FILE::IsValid() ) return; // m_errorType already set to errEXE_FILE_FILE_NOT_FOUND // If we get here, the file exists, and was mapped. We're still not // sure that it's a valid EXE though m_errorType = errEXE_FILE_INVALID_FORMAT; if ( GetFileSize() < sizeof(IMAGE_DOS_HEADER) ) return; PIMAGE_DOS_HEADER pDosHdr = (PIMAGE_DOS_HEADER)GetBase(); if ( IMAGE_DOS_SIGNATURE != pDosHdr->e_magic ) return; // If we get here, it's at least a DOS 'MZ' file m_errorType = errEXE_FILE_NO_ERROR; if ( pDosHdr->e_lfarlc < 0x40 ) // Theoretically, this field must be >= { // 0x40 for it to be a non-DOS executable m_exeType = exeType_DOS; return; } // Sanity check. Make sure the "new header" offset isn't past the end // of the file if ( pDosHdr->e_lfanew > (LONG)GetFileSize() ) return; // Make a pointer to the secondary header m_secondaryHeaderOffset = pDosHdr->e_lfanew; PWORD pSecondHdr = MakePtr( PWORD, GetBase(), m_secondaryHeaderOffset ); // Decide what type of EXE, based on the start of the secondary header switch ( *pSecondHdr ) { case IMAGE_OS2_SIGNATURE: m_exeType = exeType_NE; break; case IMAGE_VXD_SIGNATURE: m_exeType = exeType_VXD; break; case 0x4558: m_exeType = exeType_LX; break; // OS/2 2.X } if ( *(PDWORD)pSecondHdr == IMAGE_NT_SIGNATURE ) m_exeType = exeType_PE; } PSTR EXE_FILE::GetFileTypeDescription( void ) { // Returns a static string that describes what type this file is switch ( m_exeType ) { case exeType_DOS: return "DOS"; case exeType_NE: return "NE"; case exeType_VXD: return "VXD"; case exeType_LX: return "LX"; case exeType_PE: return "PE"; default: return "Invalid"; } } exiv2-0.23/msvc64/tools/depends/src/modulefileinfo.cpp0000644000175000017500000000242111510227772022512 0ustar andreasandreas//========================================== // Matt Pietrek // Microsoft Systems Journal, Feb 1997 // FILE: MODULEFILEINFO.CPP //========================================== #include #include "modulefileinfo.h" MODULE_FILE_INFO::MODULE_FILE_INFO( PSTR pszFileName ) { m_pNext = 0; m_pNotFoundNext = 0; // Find the last '\\' to obtain a pointer to just the base filename part PSTR pszBaseName = strrchr( pszFileName, '\\' ); if ( pszBaseName ) // We found a path, so advance to the base filename pszBaseName++; else pszBaseName = pszFileName; // No path. Use the same name for both // Initialize the new MODULE_FILE_INFO, and stick it at the head // of the list. lstrcpyn( m_szFullName, pszFileName, sizeof(m_szFullName) ); lstrcpyn( m_szBaseName, pszBaseName, sizeof(m_szBaseName) ); } void MODULE_FILE_INFO::AddNotFoundModule( PSTR pszFileName ) { PMODULE_FILE_INFO pNew = new MODULE_FILE_INFO( pszFileName ); pNew->m_pNotFoundNext = m_pNotFoundNext; m_pNotFoundNext = pNew; } MODULE_FILE_INFO * MODULE_FILE_INFO::GetNextNotFoundModule( PMODULE_FILE_INFO p) { PMODULE_FILE_INFO pNext = p ? p->m_pNotFoundNext : m_pNotFoundNext; return pNext; } exiv2-0.23/msvc64/tools/depends/src/depends.cpp0000644000175000017500000002206211510227772021136 0ustar andreasandreas//========================================== // Matt Pietrek // Microsoft Systems Journal, Feb 1997 // FILE: DEPENDS.CPP //========================================== #include #include #include "dependencylist.h" #include "peexe.h" //============================== Variables =============================== char g_szHelpSyntax[] = "DEPENDS - Matt Pietrek, 1997, for MSJ\n" "Syntax: DEPENDS [args] \n" " /v show version information\n" " /t show time & date information\n" " /p show full path\n" " /q quiet (don't report some MS dlls)\n" " /l show link time & date information\n\n"; char * g_pszPrimaryFile = 0; BOOL g_fShowDateTime = FALSE; BOOL g_fShowLinkDateTime = FALSE; BOOL g_fShowVersion = FALSE; BOOL g_fShowFullPath = FALSE; BOOL g_fQuiet = FALSE; //============================== Prototypes =============================== void DisplayFileInformation( PMODULE_FILE_INFO pModInfo,BOOL bQuiet ); void ShowVersionInfo( PSTR pszFileName ); BOOL TimeDateStampToFileTime( DWORD timeDateStamp, LPFILETIME pFileTime ); BOOL GetFileDateAsString( LPFILETIME pFt, char * pszDate, unsigned cbIn ); BOOL GetFileTimeAsString( LPFILETIME pFt, char * pszTime, unsigned cbIn, BOOL fSeconds ); //=================================== Code ================================ BOOL ProcessCommandLine( int argc, char * argv[] ) { BOOL fSawFileName = FALSE; if ( argc < 2 ) return FALSE; for ( int i = 1; i < argc; i++ ) { PSTR pArg = argv[i]; if ( (*pArg == '/') || (*pArg == '-') ) // Is it a switch char? { pArg++; // Point past switch char if ( 0 == lstrcmpi( pArg, "v" ) ) g_fShowVersion = TRUE; else if ( 0 == lstrcmpi( pArg, "t" ) ) g_fShowDateTime = TRUE; else if ( 0 == lstrcmpi( pArg, "l" ) ) g_fShowLinkDateTime = TRUE; else if ( 0 == lstrcmpi( pArg, "p" ) ) g_fShowFullPath = TRUE; else if ( 0 == lstrcmpi( pArg, "q" ) ) g_fQuiet = TRUE; else { printf( "Unrecognized option: \"%s\"\n", pArg ); return FALSE; } } else { if ( fSawFileName ) return FALSE; g_pszPrimaryFile = pArg; fSawFileName = TRUE; } } return fSawFileName; } LPCTSTR getModuleBase(PMODULE_FILE_INFO pModule,BOOL bQuiet) { LPCTSTR base = pModule->GetBaseName() ; LPCTSTR result = base ; if ( bQuiet ) { // keep quiet about these guys - they're build/compiler dependant if ( _strnicmp(base,"MSVCR",5) == 0 ) result = NULL ; if ( _strnicmp(base,"MSVCP",5) == 0 ) result = NULL ; if ( _strnicmp(base,"API-MS-Win",10) == 0 ) result = NULL ; } return result ; } int main( int argc, char * argv[] ) { if ( !ProcessCommandLine( argc, argv ) ) { printf( "%s %d bit build\n%s",argv[0],8*sizeof(void*),g_szHelpSyntax ); return 1; } MODULE_DEPENDENCY_LIST depends( g_pszPrimaryFile ); if ( !depends.IsValid() ) { printf( "Error: %s %s\n", g_pszPrimaryFile, depends.GetErrorString() ); return 1; } PMODULE_FILE_INFO pModInfo = 0; while ( pModInfo = depends.GetNextModule( pModInfo ) ) { DisplayFileInformation( pModInfo,g_fQuiet ); PMODULE_FILE_INFO pNotFound = 0; while ( pNotFound = pModInfo->GetNextNotFoundModule(pNotFound) ) { LPCTSTR base = getModuleBase(pNotFound,g_fQuiet) ; if ( base ) printf( " Not found: %s\n", base ); } } return 0; } void DisplayFileInformation( PMODULE_FILE_INFO pModInfo, BOOL bQuiet ) { LPCTSTR base = getModuleBase(pModInfo,bQuiet); if ( !base ) return ; printf( "%-14s", base) ; // ->GetBaseName() ); PSTR pszFullName = pModInfo->GetFullName(); if ( g_fShowDateTime ) { HFILE hFile = _lopen( pszFullName, OF_READ ); if ( HFILE_ERROR != hFile ) { FILETIME ft; if ( GetFileTime( (HANDLE)hFile, 0, 0, &ft ) ) { char szFileDate[32] = { 0 }; char szFileTime[32] = { 0 }; GetFileDateAsString(&ft, szFileDate, sizeof(szFileDate) ); GetFileTimeAsString(&ft, szFileTime, sizeof(szFileTime), TRUE); printf( "%s %s ", szFileDate, szFileTime ); } _lclose( hFile ); } } if ( g_fShowLinkDateTime ) { FILETIME ft; char szFileDate[32] = { 0 }; char szFileTime[32] = { 0 }; PE_EXE exe( pszFullName ); TimeDateStampToFileTime( exe.GetTimeDateStamp(), &ft ); GetFileDateAsString(&ft, szFileDate, sizeof(szFileDate) ); GetFileTimeAsString(&ft, szFileTime, sizeof(szFileTime), TRUE); printf( "%s %s ", szFileDate, szFileTime ); } if ( g_fShowFullPath ) printf( "(%s)", pszFullName ); printf( "\n" ); if ( g_fShowVersion ) ShowVersionInfo( pszFullName ); } void ShowVersionInfo( PSTR pszFileName ) { DWORD cbVerInfo, dummy; // How big is the version info? cbVerInfo = GetFileVersionInfoSize( pszFileName, &dummy ); if ( !cbVerInfo ) return; // Allocate space to hold the info PBYTE pVerInfo = new BYTE[cbVerInfo]; if ( !pVerInfo ) return; _try { if ( !GetFileVersionInfo(pszFileName, 0, cbVerInfo, pVerInfo) ) _leave; char * predefResStrings[] = { "CompanyName", "FileDescription", "FileVersion", "InternalName", "LegalCopyright", "OriginalFilename", "ProductName", "ProductVersion", 0 }; for ( unsigned i=0; predefResStrings[i]; i++ ) { char szQueryStr[ 0x100 ]; char szQueryStr2[0x100 ]; // Format the string with the 1200 codepage (Unicode) wsprintf( szQueryStr, "\\StringFileInfo\\%04X%04X\\%s", GetUserDefaultLangID(), 1200, predefResStrings[i] ); // Format the string with the 1252 codepage (Windows Multilingual) wsprintf( szQueryStr2, "\\StringFileInfo\\%04X%04X\\%s", GetUserDefaultLangID(), 1252, predefResStrings[i] ); // We may want to format a string with the "0000" codepage PSTR pszVerRetVal; UINT cbReturn; BOOL fFound; // Try first with the 1252 codepage fFound = VerQueryValue( pVerInfo, szQueryStr, (LPVOID *)&pszVerRetVal, &cbReturn ); if ( !fFound ) { // Hmm... 1252 wasn't found. Try the 1200 codepage fFound = VerQueryValue( pVerInfo, szQueryStr2, (LPVOID *)&pszVerRetVal, &cbReturn ); } if ( fFound ) printf( " %s %s\n", predefResStrings[i], pszVerRetVal ); } } _finally { delete []pVerInfo; } } // Convert a TimeDateStamp (i.e., # of seconds since 1/1/1970) into a FILETIME BOOL TimeDateStampToFileTime( DWORD timeDateStamp, LPFILETIME pFileTime ) { __int64 t1970 = 0x019DB1DED53E8000; // Magic... GMT... Don't ask.... __int64 timeStampIn100nsIncr = (__int64)timeDateStamp * 10000000; __int64 finalValue = t1970 + timeStampIn100nsIncr; memcpy( pFileTime, &finalValue, sizeof( finalValue ) ); return TRUE; } BOOL GetFileDateAsString( LPFILETIME pFt, char * pszDate, unsigned cbIn ) { FILETIME ftLocal; SYSTEMTIME st; if ( !FileTimeToLocalFileTime( pFt, &ftLocal ) ) return FALSE; if ( !FileTimeToSystemTime( &ftLocal, &st ) ) return FALSE; char szTemp[12]; wsprintf( szTemp, "%02u/%02u/%04u", st.wMonth, st.wDay, st.wYear ); lstrcpyn( pszDate, szTemp, cbIn ); return TRUE; } BOOL GetFileTimeAsString( LPFILETIME pFt, char * pszTime, unsigned cbIn, BOOL fSeconds ) { FILETIME ftLocal; SYSTEMTIME st; if ( !FileTimeToLocalFileTime( pFt, &ftLocal ) ) return FALSE; if ( !FileTimeToSystemTime( &ftLocal, &st ) ) return FALSE; char szTemp[12]; if ( fSeconds ) // Want seconds??? { wsprintf( szTemp, "%02u:%02u:%02u", st.wHour, st.wMinute, st.wSecond ); } else // No thanks.. Just hours and minutes { wsprintf( szTemp, "%02u:%02u", st.wHour, st.wMinute ); } lstrcpyn( pszTime, szTemp, cbIn ); return TRUE; } exiv2-0.23/msvc64/tools/depends/src/PEEXE.CPP0000644000175000017500000000572111510227772020225 0ustar andreasandreas//========================================== // Matt Pietrek // Microsoft Systems Journal, Feb 1997 // FILE: PEEXE.CPP //========================================== #include #include #pragma hdrstop #include "peexe.h" PE_EXE::PE_EXE( PSTR pszFileName ) : EXE_FILE( pszFileName ) { m_pNtHdr = 0; if ( FALSE == EXE_FILE::IsValid() ) return; // It's an EXE, but is it a *PE* file??? If not, set code and bail if ( GetExeType() != exeType_PE ) { m_errorType = errEXE_FILE_INVALID_FORMAT; return; } m_pNtHdr = MakePtr(PIMAGE_NT_HEADERS,GetBase(),GetSecondaryHeaderOffset()); } DWORD PE_EXE::GetDataDirectoryEntryRVA( DWORD id ) { // Given a IMAGE_DIRECTORY_ENTRY_XXX value (see WINNT.H), retrive the // RVA stored in the corresponding slot if ( id >= IMAGE_NUMBEROF_DIRECTORY_ENTRIES ) return (DWORD)-1; return m_pNtHdr->OptionalHeader.DataDirectory[id].VirtualAddress; } PVOID PE_EXE::GetDataDirectoryEntryPointer( DWORD id ) { // Given a IMAGE_DIRECTORY_ENTRY_XXX value (see WINNT.H), return a pointer // to memory that corresponds to the RVA in the specified slot. if ( id >= IMAGE_NUMBEROF_DIRECTORY_ENTRIES ) return (PVOID)-1; DWORD va = m_pNtHdr->OptionalHeader.DataDirectory[id].VirtualAddress; if ( !va ) // Return 0 if the RVA is 0 return 0; return GetReadablePointerFromRVA( va ); } DWORD PE_EXE::GetDataDirectoryEntrySize( DWORD id ) { // Given a IMAGE_DIRECTORY_ENTRY_XXX value (see WINNT.H), retrive the // size value stored in the corresponding slot if ( id >= IMAGE_NUMBEROF_DIRECTORY_ENTRIES ) return (DWORD)-1; return m_pNtHdr->OptionalHeader.DataDirectory[id].Size; } PVOID PE_EXE::GetReadablePointerFromRVA( DWORD rva ) { // Given an RVA, translate it into a pointer within our linear memory // mapping for the executable. DWORD fileOffset = RVAToFileOffset( rva ); if ( (DWORD)-1 == fileOffset ) return 0; return MakePtr( PVOID, GetBase(), fileOffset ); } DWORD PE_EXE::RVAToFileOffset( DWORD rva ) { // Given an RVA, figure out which section encompasses it. Next, using // the PointerToRawData field for the found section, return an actual // file offset that corresponds to the RVA PIMAGE_SECTION_HEADER pSectHdr = IMAGE_FIRST_SECTION( m_pNtHdr ); for ( unsigned i = 0; i < GetNumberOfSections(); i++, pSectHdr++ ) { DWORD cbMaxOnDisk = min( pSectHdr->Misc.VirtualSize, pSectHdr->SizeOfRawData ); DWORD startSectRVA = pSectHdr->VirtualAddress; DWORD endSectRVA = startSectRVA + cbMaxOnDisk; if ( (rva >= startSectRVA) && (rva < endSectRVA) ) return pSectHdr->PointerToRawData + (rva - startSectRVA); } return (DWORD)-1; // RVA not found in the section table... Ooops! } exiv2-0.23/msvc64/tools/depends/src/DEPENDENCYLIST.CPP0000644000175000017500000001324611510227772021472 0ustar andreasandreas//========================================== // Matt Pietrek // Microsoft Systems Journal, Feb 1997 // FILE: DEPENDENCYLIST.CPP //========================================== #include #include #pragma hdrstop #include "peexe.h" #include "dependencylist.h" MODULE_DEPENDENCY_LIST::MODULE_DEPENDENCY_LIST( PSTR pszFileName ) { m_errorType = errMDL_GENERAL_FAILURE; m_cModules = 0; m_pList = 0; // Make a copy of the path that we can modify to get just the path portion PSTR pszJustPath = _strdup( pszFileName ); if ( !pszJustPath ) return; BOOL fHasPath = FALSE; PSTR pszEnd = strrchr( pszJustPath, '\\' ); if ( pszEnd ) { *pszEnd = 0; /// Strip off the filename fHasPath = TRUE; } // // If a path was part of the input filename, save the current directory, // then switch to the new directory. // char szOriginalPath[MAX_PATH]; if ( fHasPath ) { // This doesn't take into account "App_Paths"! GetCurrentDirectory(MAX_PATH, szOriginalPath); // Save original dir SetCurrentDirectory( pszJustPath ); // Switch to app's dir } // // recursively build the module list // m_errorType = AddModule( pszFileName ); if ( fHasPath ) // Set things back to the way they were SetCurrentDirectory( szOriginalPath ); free( pszJustPath ); // Free the copy of the path that we allocated } MODULE_DEPENDENCY_LIST::~MODULE_DEPENDENCY_LIST( ) { PMODULE_FILE_INFO pTemp; // Delete each MODULE_FILE_INFO structures in the regular linked list pTemp = m_pList; while ( pTemp ) { pTemp = m_pList->m_pNext; // Before we delete the module, delete each MODULE_FILE_INFO // structures in the not found list PMODULE_FILE_INFO pNotFound = m_pList->m_pNotFoundNext; while ( pNotFound ) { pNotFound = m_pList->m_pNotFoundNext->m_pNotFoundNext; delete m_pList->m_pNotFoundNext; m_pList->m_pNotFoundNext = pNotFound; } // Now it's OK to delete the module delete m_pList; m_pList = pTemp; m_cModules--; } m_pList = 0; } PMODULE_FILE_INFO MODULE_DEPENDENCY_LIST::GetNextModule( PMODULE_FILE_INFO p ) { // Returns the next module in the linked list of MODULE_FILE_INFO's return p ? p->m_pNext : m_pList; } // Given the name of a file, find the MODULE_FILE_INFO structure that // represents it. The fFullName parameter specifies whether the full path // names or just the base file names will be compared. PMODULE_FILE_INFO MODULE_DEPENDENCY_LIST::LookupModule( PSTR pszFileName, BOOL fFullName ) { PMODULE_FILE_INFO p = m_pList; // Start at the list head while ( p ) // While there's still entries in the list... { PSTR pszCompName = fFullName ? p->m_szFullName : p->m_szBaseName; if ( 0 == lstrcmpi( pszFileName, pszCompName ) ) return p; p = p->m_pNext; } return 0; } PSTR MODULE_DEPENDENCY_LIST::GetErrorString( void ) { switch ( m_errorType ) { case errMDL_NO_ERROR: return "No error"; case errMDL_FILE_NOT_FOUND: return "File not found"; case errMDL_NOT_PE_FILE: return "Not a PE file"; case errMDL_GENERAL_FAILURE:return "General failure"; default: return ""; } } // Adds a modules to the MODULE_FILE_INFO list. If the module imports other // modules, this routine recurses to add them, and check their imports. errModuleDependencyList MODULE_DEPENDENCY_LIST::AddModule( PSTR pszFileName ) { PE_EXE peFile( pszFileName ); // Get easy access to the executable if ( FALSE == peFile.IsValid() ) // A valid PE file??? return (errModuleDependencyList)peFile.GetErrorType(); PMODULE_FILE_INFO pNew = new MODULE_FILE_INFO( pszFileName ); if ( !pNew ) return errMDL_GENERAL_FAILURE; pNew->m_pNext = m_pList; m_pList = pNew; m_cModules++; // // Now see if this module imports any other modules. If so, we need // to recurse and add them as well. // if (0 == peFile.GetDataDirectoryEntrySize( IMAGE_DIRECTORY_ENTRY_IMPORT )) return errMDL_NO_ERROR; // Make a pointer to the imports table PIMAGE_IMPORT_DESCRIPTOR pImportDir; pImportDir = (PIMAGE_IMPORT_DESCRIPTOR) peFile.GetDataDirectoryEntryPointer(IMAGE_DIRECTORY_ENTRY_IMPORT); if ( !pImportDir ) return errMDL_NO_ERROR; // While there are still non-null IMAGE_IMPORT_DESCRIPTORs... while ( pImportDir->Name ) { // Get a pointer to the imported module's base name PSTR pszBaseName; pszBaseName = (PSTR)peFile.GetReadablePointerFromRVA(pImportDir->Name); if ( !pszBaseName ) break; // Check to see if it's already in our list. Don't add again if so. if ( 0 == LookupModule( pszBaseName, FALSE ) ) { // Search path supposedly has the same searching algorithm as // the the Win32 loader... char szPath[MAX_PATH]; PSTR pszDontCare; if ( SearchPath(0, pszBaseName, 0, MAX_PATH, szPath, &pszDontCare)) AddModule( szPath ); else pNew->AddNotFoundModule( pszBaseName ); } pImportDir++; // Advance to next imported module } return errMDL_NO_ERROR; } exiv2-0.23/msvc64/tools/depends/depends.vcproj0000644000175000017500000002031511510227772021067 0ustar andreasandreas exiv2-0.23/msvc64/tools/depends/Depends2.suo0000644000175000017500000010000011510227772020402 0ustar andreasandreasÐÏࡱá>þÿ þÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿÿÿ  þÿÿÿþÿÿÿ>þÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿRoot Entryÿÿÿÿÿÿÿÿàü„áªËÀ"ProjInfoExÿÿÿÿÿÿÿÿÿÿÿÿTaskListUserTasks$ÿÿÿÿÿÿÿÿVsToolboxService"#ÿÿÿÿÿÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿ þÿÿÿLþÿÿÿ0þÿÿÿ!W#$%;þÿÿÿþÿÿÿ)*þÿÿÿ,-./þÿÿÿ123456789:þÿÿÿ<=>?@ABCDEFGHIJYþÿÿÿMNOPQRSTUVþÿÿÿXþÿÿÿZ[þÿÿÿ]^_`abcdefghþÿÿÿ€kþÿÿÿmpoþÿÿÿþÿÿÿ{sþÿÿÿuþÿÿÿwþÿÿÿyz|þÿÿÿ~þÿÿÿÿ–zpËzC®÷GÃX¤vðC > ÿþLastOpenTemporarilyOfflineData EndOfStreamHC:\gnu.master\exiv2\tools\depends2\SourceCodeControl$ÿÿÿÿtSccProviderRegKey$!ÿÿÿÿÿÿÿÿþÿÿÿDebuggerWatches ÿÿÿÿÿÿÿÿÿÿÿÿDebuggerBreakpoints( ÿÿÿÿTDebuggerExceptions&ÿÿÿÿDebuggerFindSource&ÿÿÿÿ ÿÿÿÿ DebuggerFindSymbol&ÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿDebuggerMemoryWindows,ÿÿÿÿÿÿÿÿÿÿÿÿ Tèˆø ÿÿç8] \  DZ$Í«4ïþîÿ0Í«4ïþîÿ79-039MultiStartupProj=;4{E24D66E3-65A9-4BEB-8579-039AD77C2EFF}ExternalFilesProjectContents:ÿÿÿÿÿÿÿÿÿÿÿÿ+DocumentWindowPositions0ÿÿÿÿ ÿÿÿÿ ÓDocumentWindowUserData.ÿÿÿÿ ÿÿÿÿ 4SolutionConfiguration, ÿÿÿÿp.dwStartupOpt=;StartupProject=&{E24D66E3-65A9-4BEB-8579-039AD77C2EFF};?{E24D66E3-65A9-4BEB-8579-039AD77C2EFF}.Release|x64.BatchBldCtx= Release|x64;={E24D66E3-65A9-4BEB-8579-039AD77C2EFF}.Release|x64.fBatchBld=;={E24D66E3-65A9-4BEB-8579-039AD77C2EFF}.Debug|x64.BatchBldCtx= Debug|x64;;{E24D66E3-65A9-4BEB-8579-039AD77C2EFF}.Debug|x64.fBatchBld=;A{E24D66E3-65A9-4BEB-8579-039AD77C2EFF}.ReleS$ ýA+ÁH±ÚªÏ¥WLÉlü #Oÿ‡øÏ¤ELç%Ò¯##G¶åá}'bm4S8fÂþÂL¤d®—ï9LÉlü #Oÿ‡øÏ¤ELç%Ò¯##G¶åá}'bm4ObjMgrContentsV8"ÿÿÿÿÿÿÿÿÿÿÿÿ‚ClassViewContents$ÿÿÿÿþÿÿÿProjExplorerState$ÿÿÿÿÿÿÿÿ UnloadedProjects"ÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿQ fC:\gnu.master\exiv2\tools\depends2\depends2.vcprojfC:\gnu.fc:\gnu.master\exiv2\tools\depends2\src\depends.cpp dc:\Robin\Projects\Depends2\src\modulefileinfo.cpp‚c:\program files\m$Bookmarks V001.01XÏ HiddenSlnFolders" ÿÿÿÿþÿÿÿOutliningStateDir$ÿÿÿÿÿÿÿÿÿÿÿÿ"¨BookmarkStateÿÿÿÿ&(TaskListShortcuts$ÿÿÿÿÿÿÿÿÿÿÿÿ'OutliningState1 ÿÿÿÿ(šOutliningState6 ÿÿÿÿtfOutliningState4 ÿÿÿÿÿÿÿÿjxOutliningState3 ÿÿÿÿrtbc:\Robin\Projects\Depends2\Depends2\Depends2.cppÆ™) ÿÿÿÿc:\Program Files\Microsoft SDKs\Windows\v6.0A\Include\WinBase.h<open> c:\Program Files\Microsoft SDKs\Windows\v6.0A\Include\WinVer.h<open> c:\Program Files\ase|Win32.BatchBldCtx= Release|Win32;?{E24D66E3-65A9-4BEB-8579-039AD77C2EFF}.Release|Win32.fBatchBld=;?{E24D66E3-65A9-4BEB-8579-039AD77C2EFF}.Debug|Win32.BatchBldCtx= Debug|Win32;={E24D66E3-65A9-4BEB-8579-039AD77C2EFF}.Debug|Win32.fBatchBld=;4{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}.dwStartupOpt=; ActiveCfg= Debug|x64;4;includicrosoft visual studio 9.0\vc\include\string.h ~c:\Program Files\Microsoft SDKs\Windows\v6.0A\Include\WinVer.hfc:\gnu.master\exiv2\tools\depends2\include\PEEXE.H hc:\Robin\Projects\Depends2\src\MEMORYMAPPEDFILE.CPPlc:\Robin\Projects\depends2\include\MEMORYMAPPEDFILE.H Vc:\Robin\Projects\Depends2\src\depends.cpp€c:\Program Files\Microsoft SDKs\Windows\v6.0A\Include\WinBase.hdc:\Robin\Projects\depends2\src\DEPENDENCYLIST.CPP Vc:\Robin\Projects\Depends2\include\PEEXE.Hbc:\Robin\Projects\les>|c:\Program Files\Micros${E24D66E3-65A9-4BEB-8579-039AD77C2EFF}|depends2.vcproj|c:\gnu.master\exiv2\tools\depends2\src\depends.cpp||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}12ˆø ÿÿç8] \ ${E24D66E3-65A9-4BEB-8579-039AD77C2EFF}|depends2.vcproj|c:\gnu.master\exiv2\tools\depends2\include\PEEXE.H||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}12StartupOpt=; Actimaster\exiv2\tools\depends2\depends2.vcprojSource FilesDepends2\Depends2\Depends2.cpp^c:\Robin\Projects\Depends2\Depends2\stdafx.cppnVer.hhc:fc:\gnu.master\exiv2\tools\depends2\include\PEEXE.H‚Æ, 18'A">&!!#;$,%F&.'H(*)D*!+;,-0 1:2'3A4$5>627L829L:(;B<(=B>,?F@,AFBCBD"E<F$G>H I:J)KCL(MBN(OBP'QS ``ÿÿÿÿ2\Depends2\stdafxfc:\gnu.master\exiv2\tools\depenhc:\Robin\Projects\depends2\src\MEMORYMAPPEDFILE.CPPó5àÿÿÿÿ€c:\Program Files\Microsoft SDKs\Windows\v6.0A\Include\WinBase.hlc:\Robin\Projects\depends2\include\MEMORYMAPPEDFILE.H¸ØZºÿÿÿÿV_òŒÿÿÿÿ  ~c:\Program Files\Microsoft SDKsdc:\Robin\Projects\depends2\src\modulefileinfo.cpp‚ìxÿÿÿÿVc:\Robin\Projects\depends2\include\PEEXE.H84€ÿÿÿÿ,Vc:\Robin\Projects\depends2\src\depends.cppõ_Öÿÿÿÿ#2$dc:\Robin\Projects\depends2\src\DEPENDENCYLIST.CPPúFÓ !*,B 5\Windows\v6.0A\Include\WinVer.hY;q#ÿÿÿÿs\v6.0A\Include\WinBase.h‚c:\program files\microsoft visual studio 9.0\vc\include\string.h@Ì_ÿÿÿÿv6.0A\Include\WinVer.hƒ‚…„‡†þÿÿÿþÿÿÿÿÿÿÿŠþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿds2\src\depends.cppR¿€ä@+A26TNU[\6^H`q3r}#2$M0NU#Vw9x°(±ùúûG€’• ¬&­5‚»ÿÿÿÿfileinfo.cpp‚ìxÿÿÿÿIüI +8ÿÿÿÿÿÿÿÿ^c:\Robin\Projects\Depends2\Depends2\stdafx.cpp­¥†ÊÿÿÿÿÿÿÿÿVc:\Robin\Projects\Depends2\src\depends.cpp¯ªb#2$M0NU#Vw9x®(¯÷øùIúOutliningState2 ÿÿÿÿÿÿÿÿÿÿÿÿ‰nOutliningState7 ÿÿÿÿÿÿÿÿÿÿÿÿvfOutliningState8 ÿÿÿÿqŽOutliningState5 ÿÿÿÿÿÿÿÿÿÿÿÿlOutliningState12"ÿÿÿÿ%ÿÿÿÿ\OutliningState13"ÿÿÿÿÿÿÿÿÿÿÿÿi>ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ33.)/0)1D%EF%GILM M Oÿÿÿÿ‚c:\program files\microsoft visual studio 9.0\vc\include\string.h@Ì_   !&5Å6:»ÇÈ%ÊË%ÍÐÓÔר)ÚÛ)Ý íð âò þ ó-- )-!./!0EFGH_!`a!bwxyz‘)’“)”©%ª«%¬Ê1ËÌ1Íâ-ãä-å%%0%12%3N-OP-Qj5kl5mûo9¯qŒ-Ž-’ ®5¯°5±È)ÉÊ)ËÜ7ÝÞ7ß/äçâø !  ! "%#$%%@-AB-CT)UV)Wq5rs5t‡-ˆ‰-Še[ŒZžGŸ G¡£¼=½¾=¿¦ÁÄÆ'ÍÒ#%$%%&P#QR#Sb'cd'ev'wx'y7‘’7“¤7¥¦7§ª»Ò;ÓÔ;ÕêGëìGíGG---#./#0G'HI'JR)ST)U[)\])^d)ef)g Mhi~‘-’“-”©-ª«-¬Ã5ÄÅ5Æã1äå1æ119 9!213415N'OP'Qb-cd-eu%vw%x‡'ˆ‰'Š-žŸ- ¯°±²ÁÂÃÄ×!ØÙ!Úí%îï%ð+ + // 3-45-6G1HI1J_3`a3b{9|}9~“=”•=–«;¬­;®Á?ÂÃ?ÄØEÙÚEÛò9óô9õ = =# !#"3/45/6G!HI!J_)`a)bez‹1Œ1ŽŸ= ¡=¢¶9·¸9¹ÒÔØÜäOçèOëQ¦í¥ îý1þÿ1   # 1$ % 1& 7 )8 9 ): K )L M )N ) P g +h i +j  /€  /‚ “ )” • )– ™ ª ½ -¾ ¿ -À × =Ø Ù =Ú €c:\Program Files\Microsoft SDKs\Windows\v6.0A\Include\WinBase.hV_òŒI  !" ##$%&-/mp…‡Ž•—ž ¢8£„¤¨ª§®±¸¾ÀÅÇÒÔØÛèêðô ï÷ìù û## $!*236CEMOUXA‡ŠŒµ·ãåéë 13@BLNegpr}’•˜£¥§¬®´ÑÓÙ àKá âHãÛæë î éïèùûü'@BEG…‡‘“$ž¡(£§)©´&¶¸'º¼#¾Å%ÇÉ(ËÏÑÔ Ûå׿èëíõú1ý 3  0 )*<>VWhivw€‡‰‘—™Ùà,æö/÷Ëø    , 2 > C O T ` f r x „  „  ‡ Š Œ ’ “ ™ Ž Ÿ   ¤ ̳ 0¶ Û äÝ âß ÷ ø ù ú ö û ü ý     ¥ ¯  / e s ! $ % *  + " , j 2k l 2m ~ % € % ” +• – +— ª )« ¬ )­ Ä =Å Æ =Ç ° É Ý æ k 5l m 5n } 5~  5€  7 ‘ 7’ µ · é ñ ô ü ³ GOhoÄÍøQùú/  @M\dgiZ|¨È8áñ9ôúýRlou*"-^hëð++ t‡Š›ž¤%®¶-¸Âõ÷k%lm%nqŒRõ'ö÷'ø)+9!:;!<M!NO!PSUp3qr3svx§3¨©3ªÆÈØÙÚÛìíîï   !"5678 ;<KLMN QSTZ\^mo›* ³´Ã Ü ë )ì í )î !=!!=!ñ !!)!!)!6!=7!8!=9! !;!T!)U!V!)W!j!'k!l!'m!Œ!!Ž!!´!3µ!¶!3·!’!¹!½!É!Ú!-Û!Ü!-Ý!ì!-í!î!-ï!"A""A"ò! "$ ""%"A&"'"A(""*"="1>"?"1@"Q"5R"S"5T"i"Ij"k"Il"W"n"}"~""€"“"3”"•"3–"ƒ"˜"›"ª"Ä"7Å"Æ"7Ç"®"É" Í"Ð"Ò"×"ó")ô"õ")ö"#9##9#ù"#Ì"#/#%0#1#%2#C##D#E##F#`#a#b#c#v#w#x#y#|##·#¸#¹#º#×#/Ø#Ù#/Ú#½#Ü#’# Ý#î#ï#ð#ñ#ô#$$$$$3$34$5$36$$7$Q$/R$S$/T$:$U$\$2^$z$!{$|$!}$c$~$ƒ$…$—$'˜$™$'š$‚$œ$ $¢$¶$;·$¸$;¹$Ÿ$»$Á$Ã$ Å$Ê$&Ì$Ñ$¿$â$å$%!%)"%#%)$%?%9@%A%9B%]%%^%_%%`%q%%r%s%%t% w%{%£%G¤%¥%G¦%×%'Ø%Ù%'Ú%&3&&3 & &&J&L&\&%]&^&%_&p&'q&r&'s&¬&#­&®&#¯&Â&1Ã&Ä&1Å&Ø&/Ù&Ú&/Û&ö&#÷&ø&#ù&'!''!')!'$'2'5'x'™' (;((;(?(G@(A(GB(o([p(q([r(¡(k¢(£(k¤((¦(Ë(3Ì(Í(3Î(è(=é(ê(=ë(ÿ(5))5))7))7)1)A2)3)A4)9)_)@*J*M*W*d*n*}*²*è*ð*c+‹+™+¤+ÿ+),,),,),,),<,A=,>,A?,P,],},Œ,Ó,'Ô,Õ,'Ö,ñ,+ò,ó,+ô,------%-3&-'-3(-=-1>-?-1@-W-?X-Y-?Z-r-#s-t-#u-ˆ-9‰-Š-9‹-ž-+Ÿ- -+¡-´-3µ-¶-3·-Ê-3Ë-Ì-3Í- Ð-"Ñ-Ò-"Ó-æ-)ç-è-)é-ø-)ù-ú-)û-". ..- .!.-".3.-4.5.-6.L.=M.N.=O.ÿ-Q.b.!c.d.!e.h.j.q.)s.x.%y.{.%|.—.˜.™.š.».!¼.½.!¾.Â.Ä.î.1ï.ð.1ñ.÷.ù.õ./Y/[/5090?0C0J0N0S0W0]0a0f0j0/0j0ë/°0F1H1\17]1^17_1r13s1t13u1„1†1–1;—1˜1;™1]/¬1³1µ1"À1Ä1"Å1É1Ê1-Ì1Í1-Ï1ß11à1á11â1²1ã1æ1è12#22# 22-2 2-!2$2023252A2C2#U2\2@2j2n2p2{2†2´2)µ2¶2)·2Ì2%Í2Î2%Ï2÷23,3.3@3(A3B3(C3V3&W3X3&Y3u3<v3w3<x3‹3:Œ33:Ž3¦31§3¨31©3¸37¹3º37»3Î3KÏ3Ð3KÑ3ä3-å3æ3-ç3ü3Iý3þ3Iÿ3m24444$4%4'4(4*4/4041424E4#F4G4#H40|4‡4=Š44+“4¡4¾49¿4À49Á44Ó4Ö4:Ñ4Û4Ð4@Ü4æ45T45$545?5A5b5k5n5p5s5u5y5{5~5€5ƒ5…5ˆ5Š5'Ñ5à5â5è5"ê5ð5ò5õ5 ÷5ü5$þ56%66 6 6%66'66%66% 6062676*96;6O6S6 X6[6!U6\6m6o6ƒ6/„6…6/†6™6Cš6›6Cœ6¯6;°6±6;²6k6´6¸6Æ6FÍ6Î6Ì6$Ï6Ò6Ó6 *Ó6ÿÿÿÿOutliningState9 ÿÿÿÿÿÿÿÿÿÿÿÿ}’OutliningState10""ÿÿÿÿn|OutliningState11"ÿÿÿÿÿÿÿÿxŒProperty Manager"$ÿÿÿÿKexiv2-0.23/msvc64/tools/depends/targetver.h0000644000175000017500000000137511510227772020401 0ustar andreasandreas#pragma once // The following macros define the minimum required platform. The minimum required platform // is the earliest version of Windows, Internet Explorer etc. that has the necessary features to run // your application. The macros work by enabling all features available on platform versions up to and // including the version specified. // Modify the following defines if you have to target a platform prior to the ones specified below. // Refer to MSDN for the latest info on corresponding values for different platforms. #ifndef _WIN32_WINNT // Specifies that the minimum required platform is Windows Vista. #define _WIN32_WINNT 0x0600 // Change this to the appropriate value to target other versions of Windows. #endif exiv2-0.23/msvc64/tools/depends/stdafx.cpp0000644000175000017500000000044711510227772020221 0ustar andreasandreas// stdafx.cpp : source file that includes just the standard includes // Depends2.pch will be the pre-compiled header // stdafx.obj will contain the pre-compiled type information #include "stdafx.h" // TODO: reference any additional headers you need in STDAFX.H // and not in this file exiv2-0.23/msvc64/tools/depends/ReadMe.txt0000644000175000017500000000102711510227772020115 0ustar andreasandreasDepends/ReadMe.txt ------------------ This project is "depends" and is code from MSJ (now MSDN) in 1997. I appreciate and respect the code provided by Matt Pietrik. I have made the following changes: 1) Added the -q option 2) Added the MSVC build environment (for 32bit and 64bit builds) 3) Modified the default response to report 1 and 2. The projects builds depends32.exe and depends64.exe which are used by runner32.bat and runner64.bat to test dependancies post build. Robin Mills http://clanmills.com 2011-01-02 exiv2-0.23/msvc64/tools/depends/depends.sln0000644000175000017500000000231411510227772020357 0ustar andreasandreasMicrosoft Visual Studio Solution File, Format Version 10.00 # Visual Studio 2008 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "depends", "depends.vcproj", "{E24D66E3-65A9-4BEB-8579-039AD77C2EFF}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 Debug|x64 = Debug|x64 Release|Win32 = Release|Win32 Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {E24D66E3-65A9-4BEB-8579-039AD77C2EFF}.Debug|Win32.ActiveCfg = Debug|Win32 {E24D66E3-65A9-4BEB-8579-039AD77C2EFF}.Debug|Win32.Build.0 = Debug|Win32 {E24D66E3-65A9-4BEB-8579-039AD77C2EFF}.Debug|x64.ActiveCfg = Debug|x64 {E24D66E3-65A9-4BEB-8579-039AD77C2EFF}.Debug|x64.Build.0 = Debug|x64 {E24D66E3-65A9-4BEB-8579-039AD77C2EFF}.Release|Win32.ActiveCfg = Release|Win32 {E24D66E3-65A9-4BEB-8579-039AD77C2EFF}.Release|Win32.Build.0 = Release|Win32 {E24D66E3-65A9-4BEB-8579-039AD77C2EFF}.Release|x64.ActiveCfg = Release|x64 {E24D66E3-65A9-4BEB-8579-039AD77C2EFF}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal exiv2-0.23/msvc64/tools/bin/0000755000175000017500000000000011745263366015356 5ustar andreasandreasexiv2-0.23/msvc64/tools/bin/depends32.exe0000644000175000017500000020600011510453102017621 0ustar andreasandreasMZÿÿ¸@躴 Í!¸LÍ!This program cannot be run in DOS mode. $ÏO(e‹.F6‹.F6‹.F6‚VÂ6¢.F6‚VÓ6™.F6‚VÅ6Õ.F6¬è=6Œ.F6‹.G6ì.F6‚VÌ6Œ.F6‚V×6Š.F6Rich‹.F6PEL/!Mà  °X%À@P"Ÿ@,åP ´0À °Á8Ý@Àh.textr¯° `.rdata<-À.´@@.data¤,ðâ@À.rsrc´ ô@@.relocÚ0ö@B‹F…ÀtPÿ@À@‹FW‹=HÀ@…ÀtPÿ׋ƒøÿtPÿ×ÇF_ÃÌÌÌÌÌÌÌÌÌÌÌÌÌÌì¡@ð@3ĉ„$SU‹-0 AW3ÛUÇF‰‰^è1‹øƒÄ;ûtPj\Wè~ƒÄ…ÀtˆD$ Ph»ÿÀ@WÿÀ@U‹Î豉F…Ût L$ QÿÀ@WèBƒÄ‹Œ$_][3Ì‹ÆèÄÃÌÌÌÌÌÌÌÌÌÌÌ̃~tUSW뛋Fƒx‹t%ëI‹F‹@‹x…Àt PètƒÄ‹N‰y…ÿuà‹F…Àt PèZƒÄÿ‰^…Ûu·_[ÇFÃÌÌÌÌÌÌÌÌÌÌÌÌÌjÿhë¾@d¡Pì8¡@ð@3ĉ„$4SUVW¡@ð@3ÄP„$Ld£‹œ$\‰L$‹ÃL$è¯ ‹l$,3ÿ‰|$8…íu!ƒ|$4t ½‰l$,ë‹D$0‹L$ <‰|$8Ç„$T…ÿu3‹D$ …ÀtPÿ@À@‹D$‹5HÀ@…ÀtPÿÖ‹D$ƒøÿtPÿÖ‹Åé‚hèk‹ðƒÄ…öt‹Ãè„ ‰D$<…Àu6‹D$ …ÀtPÿ@À@‹D$‹5HÀ@…ÀtPÿÖ‹D$ƒøÿtPÿÖ¸é*‹t$‹V‰ÿ‰Fƒ¿„u5‹D$ …ÀtPÿ@À@‹D$‹5HÀ@…ÀtPÿÖ‹D$ƒøÿ„äPÿÖéÜ‹¿€…ÿ„Å‹ßD$èÁ ƒøÿu3Àë‹L$ Á…À„£ƒÀ ƒ8„—‹èëë¤$‹t$‹]D$è€ ƒøÿtt‹T$ <…ÿti‹v…ötFPWÿ À@…Àt‹6…öuëë…öu:L$@QT$HRhjWjÿÀ@…Àt‹L$D$DPèâýÿÿë ‹L$…À}j è¨7Yjè_8Y…ÀtPè•7Y¡A£”APÿ5ˆAÿ5„AèðÿÿƒÄ ‰Eàƒ}äuPèÖ9èý9ë.‹Eì‹‹ ‰MÜPQè;<YYËeè‹E܉Eàƒ}äuPè¼9èÜ9ÇEüþÿÿÿ‹Eàè‡ÃèsDé¤þÿÿ‹ÿU‹ìì(£¨A‰ ¤A‰ A‰œA‰5˜A‰=”AfŒÀAfŒ ´AfŒAfŒŒAfŒ%ˆAfŒ-„Aœ¸A‹E£¬A‹E£°AE£¼A‹…àüÿÿÇøA¡°A£¬AÇ A ÀǤA¡@ð@‰…Øüÿÿ¡Dð@‰…ÜüÿÿÿpÀ@£ðAjè7DYjÿlÀ@hèÁ@ÿhÀ@ƒ=ðAujèDYh ÀÿdÀ@Pÿ`À@ÉËÿU‹ì‹E3É;ÍHð@tAƒù-rñHíƒùwj X]ËÍLð@]ÃDÿÿÿjY;ÈÀ#ÁƒÀ]Ãèº!…Àu¸°ñ@ÃÀÃè§!…Àu¸´ñ@ÃÀ ËÿU‹ìVèâÿÿÿ‹MQ‰è‚ÿÿÿY‹ðè¼ÿÿÿ‰0^]ËÿU‹ì3À9Ej”ÀhPÿtÀ@£ÄA…Àu]Ã3À@£œA]ËÿVW3ö¿ÈAƒ<õÄñ@uõÀñ@‰8h ÿ0ƒÇè-CYY…Àt Fƒþ$|Ò3À@_^Ã$õÀñ@3Àëñ‹ÿS‹|À@V¾Àñ@W‹>…ÿtƒ~t WÿÓWè»÷ÿÿƒ&YƒÆþàò@|ܾÀñ@_‹…Àt ƒ~uPÿÓƒÆþàò@|æ^[ËÿU‹ì‹Eÿ4ÅÀñ@ÿ€À@]Ãj hàß@è± 3ÿG‰}ä3Û9ÄAuè/9jè}7hÿè¿4YY‹u4õÀñ@9t‹Çënjè´BY‹ø;ûuèuþÿÿÇ 3ÀëQj èYY‰]ü9u,h Wè$BYY…ÀuWèéöÿÿYè?þÿÿÇ ‰]äë ‰>ëWèÎöÿÿYÇEüþÿÿÿè ‹EäèI Ãj è(ÿÿÿYËÿU‹ì‹EV4ÅÀñ@ƒ>uPè"ÿÿÿY…Àujè³3Yÿ6ÿ„À@^]ËÿU‹ì‹ „A¡ˆAkÉÈë‹U+P úr ƒÀ;Árë3À]ËÿU‹ìƒì‹M‹AV‹u W‹þ+y ƒÆüÁï‹ÏiÉŒD‰Mð‹I‰MüöÁ…ÓS1‹‰Uô‹Vü‰Uø‹Uô‰] öÂutÁúJƒú?vj?Z‹K;KuB»€ƒú s‹ÊÓëL÷Ó!\¸Dþ u#‹M!ëJàÓëL÷Ó!œ¸Äþ u‹M!Y‹] ‹S‹[‹MüMô‰Z‹U ‹Z‹R‰S‰Mü‹ÑÁúJƒú?vj?Z‹]øƒã‰]ô…+uø‹]øÁûj?‰u K^;Þv‹ÞMø‹ÑÁúJ‰Mü;Öv‹Ö;Út^‹M ‹q;qu;¾€ƒû s‹ËÓî÷Ö!t¸DþLu!‹M!1ëKàÓî÷Ö!´¸ÄþLu‹M!q‹M ‹q‹I‰N‹M ‹q‹I‰N‹u ë‹]ƒ}ôu;Ú„€‹Mð Ñ‹Y‰N‰^‰q‹N‰q‹N;Nu`ŠLˆMþÁˆLƒú s%€}u‹Ê»€Óë‹M »€‹ÊÓëD¸D ë)€}uJເÓë‹M YJ຀Óê„¸Ä ‹Eü‰‰D0ü‹Eðÿ…ó¡A…À„Ø‹ ˜A‹5xÀ@h@ÁáH »€SQÿÖ‹ ˜A¡Aº€Óê P¡A‹@‹ ˜Aƒ¤ˆÄ¡A‹@þHC¡A‹H€yCu ƒ`þ¡AƒxÿueSjÿp ÿÖ¡Aÿpjÿ5ÄAÿXÀ@‹ „A¡AkÉ‹ˆA+ÈLìQHQPèâ?‹EƒÄ ÿ „A;Avƒm¡ˆA£A‹E£A‰=˜A[_^Éá”AV‹5„AW3ÿ;ðu4ƒÀkÀPÿ5ˆAWÿ5ÄAÿÀ@;Çu3Àëxƒ”A‹5„A£ˆAkö5ˆAhÄAjÿ5ÄAÿˆÀ@‰F;ÇtÇjh hWÿŒÀ@‰F ;ÇuÿvWÿ5ÄAÿXÀ@뛃Nÿ‰>‰~ÿ„A‹Fƒÿ‹Æ_^ËÿU‹ìQQ‹M‹ASV‹qW3ÛëÀC…À}ù‹ÃiÀ„0Dj?‰EøZ‰@‰@ƒÀJuôj‹ûhÁçy h€WÿŒÀ@…ÀuƒÈÿé—p‰Uü;úwC‹Ê+ÏÁé GAƒHøÿƒˆìÿü‰üïÿÿÇ@üð‰PÇ€èðIuË‹Uü‹EøøO ‰H‰AJ ‰H‰AƒdžD3ÿG‰¼žÄŠFCŠÈþÁ„À‹EˆNCu xº€‹ËÓê÷Ò!P‹Ã_^[ÉËÿU‹ìƒì ‹M‹ASV‹uW‹} ‹×+Q ƒÆÁê‹ÊiÉŒD‰Mô‹OüƒæðI;ñ|9ü‹‰M‰]üŽUöÃ…EÙ;ó;‹MüÁùI‰Møƒù?vj?Y‰Mø‹_;_uC»€ƒù sÓë‹MøL÷Ó!\Dþ u&‹M!ëƒÁàÓë‹MøL÷Ó!œÄþ u‹M!Y‹O‹_‰Y‹O‹‰y‹M+ÎMüƒ}üŽ¥‹}ü‹M ÁÿOL1üƒÿ?vj?_‹]ôû‰]‹[‰Y‹]‰Y‰K‹Y‰K‹Y;YuWŠLˆMþÁˆLƒÿ s€}u‹Ï»€Óë‹M DD‹Ïë €}uOເÓë‹M Y„ÄO຀Óê ‹U ‹MüD2ü‰‰Lüë‹U F‰Bü‰D2øé<3Àé8/‹] )uN‰Kü\3ü‹uÁþN‰] ‰Küƒþ?vj?^öEü…€‹uüÁþNƒþ?vj?^‹O;OuB»€ƒþ s‹ÎÓët÷Ó!\Dþu#‹M!ëNàÓëL÷Ó!œÄþ u‹M!Y‹] ‹O‹w‰q‹w‹O‰q‹uuü‰uÁþNƒþ?vj?^‹Mô ñ‹y‰K‰{‰Y‹K‰Y‹K;KuWŠLˆMþÁˆLƒþ s€}u‹Î¿€Óï‹M 9DD‹Îë €}uNà¿€Óï‹M y„ÄN຀Óê ‹E‰‰Dü3À@_^[ÉËÿU‹ìƒì¡„A‹MkÀˆAƒÁƒáð‰MðÁùSIƒù VW} ƒÎÿÓîƒMøÿë ƒÁàƒÊÿ3öÓê‰Uø‹ A‹Ùë‹S‹;#Uø#þ ×u ƒÃ‰];Ørè;Øu‹ˆAë‹S‹;#Uø#þ ×u ƒÃ‰];Ùrè;Ùu[ë ƒ{u ƒÃ‰];Ørð;Øu1‹ˆAë ƒ{u ƒÃ‰];Ùrð;Ùuè úÿÿ‹Ø‰]…Ûu3Àé Sè:ûÿÿY‹K‰‹Cƒ8ÿtå‰A‹C‹‰Uüƒúÿt‹ŒÄ‹|D#Mø#þ Ïu)ƒeü‹ÄHD‹9#Uø#þ ×uÿEü‹‘„ƒÁëç‹Uü‹ÊiÉŒD‰Mô‹LD3ÿ#Îu‹ŒÄ#Møj _ëÉG…É}ù‹Mô‹Tù‹ +Mð‹ñÁþNƒþ?‰Mø~j?^;÷„‹J;Ju\ƒÿ »€}&‹ÏÓë‹Mü|8÷Ó‰]ì#\ˆD‰\ˆDþu3‹Mì‹]! ë,OàÓë‹MüŒˆÄ|8÷Ó!þ‰]ìu ‹]‹Mì!Kë‹]ƒ}ø‹J‹z‰y‹J‹z‰y„‹Mô ñ‹y‰J‰z‰Q‹J‰Q‹J;Ju^ŠLˆM þÁƒþ ˆL}#€} u ¿€‹ÎÓï ;‹Î¿€Óï‹Mü |ˆDë)€} u Nà¿€Óï {‹Mü¼ˆÄNྀÓî 7‹Mø…Ét ‰ ‰Lüë‹Mø‹uðÑN‰ ‰L2ü‹uô‹y‰>…Éu;Au‹Mü; ˜Auƒ%A‹Mü‰B_^[ÉÃÌÌÌh°3@dÿ5‹D$‰l$l$+àSVW¡@ð@1Eü3ÅP‰eèÿuø‹EüÇEüþÿÿÿ‰EøEðd£Ã‹Mðd‰ Y__^[‹å]QÃÌÌÌ‹ÿU‹ìƒìS‹] V‹s35@ð@W‹ÆEÿÇEô{ƒøþt ‹NÏ3 8èëÿÿ‹N ‹FÏ3 8èëÿÿ‹Eö@f…‹MUè‰Sü‹[ ‰Eè‰Mìƒûþt_I[‹L†D†‰Eð‹‰Eø…Ét‹×èœ;ÆEÿ…À|@G‹Eø‹Øƒøþu΀}ÿt$‹ƒøþt ‹NÏ3 8èŽêÿÿ‹N ‹VÏ3 :è~êÿÿ‹Eô_^[‹å]ÃÇEôëÉ‹M9csmàu)ƒ=Ý@t hÝ@è#<ƒÄ…Àt‹UjRÿÝ@ƒÄ‹M è?;‹E 9X th@ð@W‹Ó‹ÈèB;‹E ‹Mø‰H ‹ƒøþt ‹NÏ3 8èûéÿÿ‹N ‹VÏ3 :èëéÿÿ‹Eð‹H‹×èÕ:ºþÿÿÿ9S „Rÿÿÿh@ð@W‹Ëèí:éÿÿÿ‹ÿU‹ì‹E£A]ËÿU‹ìì(¡@ð@3ʼnEüƒ¥ØüÿÿSjL…ÜüÿÿjPè<…Øüÿÿ‰…(ýÿÿ…0ýÿÿƒÄ ‰…,ýÿÿ‰…àýÿÿ‰Üýÿÿ‰•Øýÿÿ‰Ôýÿÿ‰µÐýÿÿ‰½ÌýÿÿfŒ•øýÿÿfŒìýÿÿfŒÈýÿÿfŒ…ÄýÿÿfŒ¥ÀýÿÿfŒ­¼ýÿÿœ…ðýÿÿ‹EMÇ…0ýÿÿ‰…èýÿÿ‰ôýÿÿ‹Iü‰äýÿÿÇ…ØüÿÿÀÇ…Üüÿÿ‰…äüÿÿÿpÀ@j‹ØÿlÀ@…(ýÿÿPÿhÀ@…Àu …ÛujèÎ3YhÀÿdÀ@Pÿ`À@‹Mü3Í[è‰èÿÿÉËÿU‹ìÿ5AèÎY…Àt]ÿàjè3Y]é²þÿÿ‹ÿU‹ì‹MS3ÛVW;Ët‹} ;ûwè¯ïÿÿj^‰0SSSSSè®ÿÿÿƒÄ‹Æë0‹u;óuˆëÚ‹ÑŠˆBF:ÃtOuó;ûuˆètïÿÿj"Y‰‹ñëÁ3À_^[]Ãj hà@èGüÿÿƒeä‹u;5ŒAw"jè7ñÿÿYƒeüVè>ùÿÿY‰EäÇEüþÿÿÿè ‹EäèSüÿÿÃjè2ðÿÿYËÿU‹ìV‹uƒþà‡¡SW‹=ˆÀ@ƒ=ÄAuèo)jè½'hÿèÿ$YY¡œAƒøu…öt‹Æë3À@Pëƒøu VèSÿÿÿY…Àu…öuFƒÆƒæðVjÿ5ÄAÿ׋؅Ûu.j ^9ä AtÿuèxY…Àt‹ué{ÿÿÿèqîÿÿ‰0èjîÿÿ‰0_‹Ã[ëVèQYèVîÿÿÇ 3À^]ÃÌÌÌÌÌÌ‹L$÷Át$ŠƒÁ„ÀtN÷Áuï¤$¤$‹ºÿþþ~Ѓðÿ3ƒÁ©tè‹Aü„Àt2„ät$©ÿt©ÿtëÍAÿ‹L$+ÁÃAþ‹L$+ÁÃAý‹L$+ÁÃAü‹L$+ÁËÿU‹ìS‹]VW‹ùÇôÁ@‹…Àt&PèVÿÿÿ‹ðFVè}þÿÿYY‰G…Àtÿ3VPè´ýÿÿƒÄ ëƒgÇG‹Ç_^[]‹ÿU‹ì‹Á‹MÇôÁ@‹ ƒ`‰H]‹ÿU‹ìS‹]V‹ñÇôÁ@‹C‰F…À‹CWt1…Àt'PèÛþÿÿ‹øGWèþÿÿYY‰F…ÀtÿsWPè8ýÿÿƒÄ ë ƒfë‰F_‹Æ^[]ƒyÇôÁ@t ÿqè}åÿÿYËA…Àu¸üÁ@ËÿU‹ìV‹ñèÐÿÿÿöEtVèãåÿÿY‹Æ^]‹ÿQÇÂ@è@8YËÿU‹ìV‹ñèãÿÿÿöEtVè²åÿÿY‹Æ^]‹ÿU‹ì‹EƒÁ QƒÀ Pè~8÷ØYÀY@]‹ÿU‹ìQSVWÿ5h Aè0 ÿ5d A‹ø‰}üè ‹ðYY;÷‚ƒ‹Þ+ßCƒørwWè¹8‹øCY;øsH¸;øs‹ÇÇ;ÇrPÿuüè¶0YY…ÀuG;Çr@Pÿuüè 0YY…Àt1ÁûP4˜è; Y£h Aÿuè- ‰ƒÆVè" Y£d A‹EYë3À_^[ÉËÿVjj è 0‹ðVèû ƒÄ £h A£d A…öujX^Ã&3À^Ãj h à@èPøÿÿè—!ƒeüÿuèøþÿÿY‰EäÇEüþÿÿÿè ‹EäèløÿÿÃèv!ËÿU‹ìÿuè·ÿÿÿ÷ØÀ÷ØYH]ËÿU‹ì‹E£ A]ËÿU‹ìÿ5 Aèç Y…ÀtÿuÿÐY…Àt3À@]Ã3À]ËÿU‹ìƒì ‹EVWjY¾Â@}àó¥‰Eø‹E _‰Eü^…Àt ötÇEô@™EôPÿuðÿuäÿuàÿ”À@ÉÂ-¤t"ƒètƒè t Ht3ÀøøøøËÿVW‹ðh3ÿFWPè|53À·È‹Á‰~‰~‰~ Áá Á~«««¹ó@ƒÄ F+οŠˆ@Ou÷†¾Šˆ@Nu÷_^ËÿU‹ìì¡@ð@3ʼnEüSW…èúÿÿPÿvÿ˜À@¿…À„û3Àˆ„üþÿÿ@;ÇrôŠ…îúÿÿÆ…üþÿÿ „Àt.ïúÿÿ¶È¶;Èw+Á@P” üþÿÿj Rè¹4ƒÄ CŠC„ÀuØjÿv …üúÿÿÿvPW…üþÿÿPjjèm<3ÛSÿv…üýÿÿWPW…üþÿÿPWÿv SèN:ƒÄDSÿv…üüÿÿWPW…üþÿÿPhÿv Sè):ƒÄ$3À·ŒEüúÿÿöÁt€LŠŒüýÿÿëöÁt€L ŠŒüüÿÿˆŒëÆ„@;Çr¾ëV†Ç…äúÿÿŸÿÿÿ3É)…äúÿÿ‹•äúÿÿ„ÐZ ƒûw €LŠÑ€Â ëƒúw€L ŠÑ€ê ˆëÆA;Ïr‹Mü_3Í[èáÿÿÉÃj h@à@èTõÿÿè˜ ‹ø¡$ø@…Gptƒlt‹wh…öuj èY‹ÆèlõÿÿÃj è%êÿÿYƒeü‹wh‰uä;5(÷@t6…ötVÿ À@…Àuþó@tVè¤àÿÿY¡(÷@‰Gh‹5(÷@‰uäVÿœÀ@ÇEüþÿÿÿè뎋uäj èêèÿÿYËÿU‹ìƒìS3ÛSMðèPâÿÿ‰$AƒþþuÇ$Aÿ¨À@8]ütE‹Møƒapýë<ƒþýuÇ$Aÿ¤À@ëÛƒþüu‹Eð‹@Ç$AëÄ8]üt‹Eøƒ`pý‹Æ[ÉËÿU‹ìƒì ¡@ð@3ʼnEüS‹] V‹uWèdÿÿÿ‹ø3ö‰};þu‹Ãè·üÿÿ3Àé‰uä3À9¸0÷@„‘ÿEäƒÀ0=ðrçÿèý„pÿéý„d·ÇPÿ¬À@…À„REèPWÿ˜À@…À„3hCVPèÙ13ÒBƒÄ ‰{‰s 9Uè†ø€}î„ÏuɄ¶Fÿ¶Éé¦hCVPè’1‹MäƒÄ kÉ0‰uà±@÷@‰uäë*ŠF„Àt(¶>¶Àë‹EàŠ€,÷@D;¶FG;øvê‹}FF€>uÑ‹uäÿEàƒÆƒ}à‰uäré‹Ç‰{ÇCègûÿÿj‰C C‰4÷@Zf‹1Af‰0A@@Juó‹óè×ûÿÿé·þÿÿ€L@;ÁvöFF€~ÿ…4ÿÿÿC¹þ€@Iuù‹Cèûÿÿ‰C ‰Së‰s3À·È‹ÁÁá Á{«««ë¨95$A…XþÿÿƒÈÿ‹Mü_^3Í[èÞÿÿÉÃjh`à@èOòÿÿƒMàÿè‹ø‰}ÜèÜüÿÿ‹_h‹uèuýÿÿ‰E;C„Wh è_)Y‹Ø…Û„F¹ˆ‹wh‹ûó¥ƒ#Sÿuè¸ýÿÿYY‰Eà…À…ü‹uÜÿvhÿ À@…Àu‹Fh=ó@tPè€ÝÿÿY‰^hS‹=œÀ@ÿ×öFp…êö$ø@…Ýj è¦æÿÿYƒeü‹C£4A‹C£8A‹C £<A3À‰Eäƒø}f‹LCf‰ E(A@ëè3À‰Eä=} ŠLˆˆ õ@@ëé3À‰Eä=}ŠŒˆˆ(ö@@ëæÿ5(÷@ÿ À@…Àu¡(÷@=ó@tPèÇÜÿÿY‰(÷@Sÿ×ÇEüþÿÿÿèë0j èåÿÿYÃë%ƒøÿu ûó@tSè‘ÜÿÿYèçãÿÿÇëƒeà‹EàèñÿÿÃ=l AujýèVþÿÿYÇl A3ÀËÿU‹ìSV‹u‹†¼3ÛW;Ãto=˜ý@th‹†°;Ãt^9uZ‹†¸;Ãt9uPèÜÿÿÿ¶¼è8YY‹†´;Ãt9uPè÷Ûÿÿÿ¶¼è)8YYÿ¶°èßÛÿÿÿ¶¼èÔÛÿÿYY‹†À;ÃtD9u@‹†Ä-þPè³Ûÿÿ‹†Ì¿€+ÇPè Ûÿÿ‹†Ð+ÇPè’Ûÿÿÿ¶Àè‡ÛÿÿƒÄ¾Ô‹=Øü@t9˜´uPè6ÿ7è`ÛÿÿYY~PÇEø(ø@t‹;Ãt 9uPè;ÛÿÿY9_üt‹G;Ãt 9uPè$ÛÿÿYƒÇÿMuÇVèÛÿÿY_^[]ËÿU‹ìSV‹5œÀ@W‹}WÿÖ‹‡°…ÀtPÿÖ‹‡¸…ÀtPÿÖ‹‡´…ÀtPÿÖ‹‡À…ÀtPÿÖ_PÇE{ø(ø@t ‹…ÀtPÿÖƒ{üt ‹C…ÀtPÿÖƒÃÿMuÖ‹‡Ô´PÿÖ_^[]ËÿU‹ìW‹}…ÿ„ƒSV‹5 À@WÿÖ‹‡°…ÀtPÿÖ‹‡¸…ÀtPÿÖ‹‡´…ÀtPÿÖ‹‡À…ÀtPÿÖ_PÇE{ø(ø@t ‹…ÀtPÿÖƒ{üt ‹C…ÀtPÿÖƒÃÿMuÖ‹‡Ô´PÿÖ^[‹Ç_]Ã…ÿt7…Àt3V‹0;÷t(W‰8èÁþÿÿY…ötVèEÿÿÿƒ>Yuþ0ø@tVèYýÿÿY‹Ç^Ã3ÀÃj h€à@èèíÿÿè,‹ð¡$ø@…Fpt"ƒ~ltè‹pl…öuj èžY‹ÆèûíÿÿÃj è´âÿÿYƒeüFl‹=ù@èiÿÿÿ‰EäÇEüþÿÿÿèëÁj è¯áÿÿY‹uäËÿU‹ìVÿ5ù@‹5¸À@ÿÖ…Àt!¡ù@ƒøÿtPÿ5ù@ÿÖÿÐ…Àt‹€øë'¾ÌÂ@Vÿ°À@…Àu VèßY…Àth¼Â@Pÿ´À@…ÀtÿuÿЉE‹E^]Ãjè‡ÿÿÿYËÿU‹ìVÿ5ù@‹5¸À@ÿÖ…Àt!¡ù@ƒøÿtPÿ5ù@ÿÖÿÐ…Àt‹€üë'¾ÌÂ@Vÿ°À@…Àu VèdY…ÀthèÂ@Pÿ´À@…ÀtÿuÿЉE‹E^]Ãÿ¼À@‹ÿVÿ5ù@ÿ¸À@‹ð…öuÿ5hAèeÿÿÿY‹ðVÿ5ù@ÿÀ@‹Æ^áù@ƒøÿtPÿ5pAè;ÿÿÿYÿЃ ù@ÿ¡ù@ƒøÿtPÿÀÀ@ƒ ù@ÿéìßÿÿj h à@è ìÿÿ¾ÌÂ@Vÿ°À@…ÀuVè¥Y‰Eä‹uÇF\ˆÉ@3ÿG‰~…Àt$h¼Â@P‹´À@ÿÓ‰†øhèÂ@ÿuäÿÓ‰†ü‰~pƆÈCƆKCÇFhó@j è àÿÿYƒeüÿvhÿœÀ@ÇEüþÿÿÿè>j èàÿÿY‰}ü‹E ‰Fl…Àu¡ù@‰FlÿvlèüÿÿYÇEüþÿÿÿèèŽëÿÿÃ3ÿG‹uj ègßÿÿYÃj è^ßÿÿYËÿVWÿTÀ@ÿ5ù@‹øè‘þÿÿÿЋð…öuNhjèŽ"‹ðYY…öt:Vÿ5ù@ÿ5lAèèýÿÿYÿÐ…ÀtjVèÅþÿÿYYÿÈÀ@ƒNÿ‰ë Vè{ÖÿÿY3öWÿÄÀ@_‹Æ^ËÿVèÿÿÿ‹ð…öujè‚Y‹Æ^ÃjhÈà@è‘êÿÿ‹u…ö„ø‹F$…ÀtPè.ÖÿÿY‹F,…ÀtPè ÖÿÿY‹F4…ÀtPèÖÿÿY‹F<…ÀtPèÖÿÿY‹F@…ÀtPèöÕÿÿY‹FD…ÀtPèèÕÿÿY‹FH…ÀtPèÚÕÿÿY‹F\=ˆÉ@tPèÉÕÿÿYj èßÿÿYƒeü‹~h…ÿtWÿ À@…Àuÿó@tWèœÕÿÿYÇEüþÿÿÿèWj èÙÞÿÿYÇEü‹~l…ÿt#WèóúÿÿY;=ù@tÿ0ø@t ƒ?uWèÿøÿÿYÇEüþÿÿÿèVèDÕÿÿYèÎéÿÿ‹uj è¨ÝÿÿYËuj èœÝÿÿYËÿVW¾ÌÂ@Vÿ°À@…ÀuVèY‹ø…ÿ„^‹5´À@hÃ@WÿÖh Ã@W£dAÿÖhÃ@W£hAÿÖhøÂ@W£lAÿÖƒ=dA‹5À@£pAtƒ=hAt ƒ=lAt…Àu$¡¸À@£hA¡ÀÀ@ÇdAÃF@‰5lA£pAÿ¼À@£ù@ƒøÿ„Ìÿ5hAPÿÖ…À„»è6ÿ5dAèûÿÿÿ5hA£dAèûÿÿÿ5lA£hAèóúÿÿÿ5pA£lAèãúÿÿƒÄ£pAèÞÛÿÿ…Àteh·H@ÿ5dAè=ûÿÿYÿУù@ƒøÿtHhjè°‹ðYY…öt4Vÿ5ù@ÿ5lAè ûÿÿYÿÐ…ÀtjVèçûÿÿYYÿÈÀ@ƒNÿ‰3À@ëè’ûÿÿ3À_^ËÿU‹ìƒìSVÿu MèètÕÿÿ‹]¾;ÞsT‹M胹¬~EèPjSèß5‹MèƒÄ ë ‹È·Xƒà…Àt‹Ì¶飀}ôt‹Eðƒ`pý‹Ã霋E胸¬~1‰]Á}EèP‹E%ÿPè35YY…ÀtŠEjˆEüˆ]ýÆEþYëè;ÚÿÿÇ*3Ɉ]üÆEýA‹EèjÿpUøjRQMüQVÿpEèPè+ƒÄ$…À„oÿÿÿƒø¶Eøt ¶MùÁà Á€}ôt‹Mðƒapý^[ÉÃÌÌÌÌÌÌÌÌU‹ìWVS‹M ÉtM‹u‹} ·A³Z¶ IŠ& äŠt' Àt#ƒÆƒÇ:çr:ãwæ:Çr:ÃwÆ:àu ƒéuÑ3É:àt ¹ÿÿÿÿr÷Ù‹Á[^_Éø ù@á€AVj^…Àu¸ë;Æ}‹Æ£€AjPè¿YY£x A…ÀujV‰5€Aè¦YY£x A…ÀujX^Ã3Ò¹ ù@ë¡x A‰ ƒÁ ƒÂù û@|êjþ^3Ò¹0ù@W‹ÂÁø‹…` A‹úƒçÁ狃øÿt;Æt…Àu‰1ƒÁ Bùù@|Î_3À^Ãè¿6€=¨Atèˆ4ÿ5x AèCÑÿÿYËÿU‹ìV‹u¸ ù@;ðr"þ€û@w‹Î+ÈÁùƒÁQèhÚÿÿN €Yë ƒÆ Vÿ„À@^]ËÿU‹ì‹Eƒø}ƒÀPè;Úÿÿ‹E H €Y]ËE ƒÀ Pÿ„À@]ËÿU‹ì‹E¹ ù@;Ár=€û@w` ÿÿÿ+ÁÁøƒÀPèÙÿÿY]ÃÀ Pÿ€À@]ËÿU‹ì‹Mƒù‹E }` ÿÿÿƒÁQèéØÿÿY]ÃÀ Pÿ€À@]ËÿU‹ìV‹uVè$6Pèº5YY…Àt|è+þÿÿƒÀ ;ðu3ÀëèþÿÿƒÀ@;ðu`3À@ÿtA÷F uNSW<…xAƒ?»u SèY‰…ÀuFj‰F‰X‰F‰Fë ‹?‰~‰>‰^‰^N 3À_@[ë3À^]ËÿU‹ìƒ}t'V‹u ÷F tVè‚3f ÿîÿÿƒfƒ&ƒfY^]ÃöA @tƒyt$ÿIx ‹ˆÿ¶Àë ¾ÀQPèo5YYƒøÿu ÃÿËÿU‹ìV‹ðë‹MŠEÿM èµÿÿÿƒ>ÿtƒ} ç^]ËÿU‹ìöG @SV‹ð‹Ùt2ƒu,‹Eë+ŠÿM‹Ïè}ÿÿÿCƒ>ÿuèaÖÿÿƒ8*u‹Ï°?èdÿÿÿƒ}Õ^[]ËÿU‹ììx¡@ð@3ʼnEüS‹] V‹u3ÀW‹}ÿu¤ýÿÿ‰µ´ýÿÿ‰½Üýÿÿ‰…¸ýÿÿ‰…ðýÿÿ‰…Ìýÿÿ‰…èýÿÿ‰…Ðýÿÿ‰…Àýÿÿ‰…ÈýÿÿèyÐÿÿ…öu5èÙÕÿÿÇ3ÀPPPPPèÕåÿÿƒÄ€½°ýÿÿt ‹…¬ýÿÿƒ`pýƒÈÿéÈ öF @u^Vè4Yºxü@ƒøÿtƒøþt‹Èƒá‹ðÁþÁá µ` Aë‹ÊöA$u‘ƒøÿtƒøþt‹ÈƒàÁùÁà` Aë‹Âö@$€…gÿÿÿ3É;Ù„]ÿÿÿЉØýÿÿ‰àýÿÿ‰¼ýÿÿˆ•ïýÿÿ„Ò„ Cƒ½Øýÿÿ‰ÄýÿÿŒ ŠÂ, If90t@@;Îuô+…äýÿÿÑøë(;þu ¡ û@‰…äýÿÿ‹…äýÿÿëI€8t@;Îuõ+…äýÿÿ‰…àýÿÿƒ½Àýÿÿ…\‹…ðýÿÿ¨@t2©t Æ…Ôýÿÿ-ë¨t Æ…Ôýÿÿ+ë ¨tÆ…Ôýÿÿ Ç…Ðýÿÿ‹Ìýÿÿ+àýÿÿ+Ðýÿÿö…ðýÿÿ uÿµ´ýÿÿ…ØýÿÿSj èpõÿÿƒÄ ÿµÐýÿÿ‹½´ýÿÿ…ØýÿÿÔýÿÿèvõÿÿö…ðýÿÿYtö…ðýÿÿuWSj0…Øýÿÿè.õÿÿƒÄ ƒ½Èýÿÿ‹…àýÿÿtf…À~b‹µäýÿÿ‰… ýÿÿ·ÿ ýÿÿPjEôP…˜ýÿÿFPFèA-ƒÄ…Àu(9…˜ýÿÿt ÿµ˜ýÿÿ…ØýÿÿMôèñôÿÿƒ½ ýÿÿYuµëƒØýÿÿÿë‹äýÿÿP…ØýÿÿèÊôÿÿYƒ½Øýÿÿ|ö…ðýÿÿtWSj …Øýÿÿè‚ôÿÿƒÄ ƒ½¼ýÿÿtÿµ¼ýÿÿèËÃÿÿƒ¥¼ýÿÿY‹ÄýÿÿŠˆ…ïýÿÿ„Àt‹”ýÿÿ‹½ÜýÿÿŠÐéáõÿÿ€½°ýÿÿt ‹…¬ýÿÿƒ`pý‹…Øýÿÿ‹Mü_^3Í[èiÃÿÿÉßS@ Q@ÐQ@.R@zR@…R@ËR@ùS@‹ÿU‹ì‹E‹8csmàu*ƒxu$‹@= “t=!“t="“t=@™uèÅ,3À]Âh´[@ÿlÀ@3ÀËÿU‹ìW¿èWÿÌÀ@ÿuÿ°À@Çèÿ`êw…ÀtÞ_]ËÿU‹ìè©ÿuèöÿ5¨û@èêÿÿhÿÿÐƒÄ ]ËÿU‹ìh¬Ã@ÿ°À@…ÀthœÃ@Pÿ´À@…ÀtÿuÿÐ]ËÿU‹ìÿuèÈÿÿÿYÿuÿÐÀ@Ìjè³ËÿÿYÃjèÐÊÿÿYËÿU‹ìV‹ðë ‹…ÀtÿЃÆ;urð^]ËÿU‹ìV‹u3Àë…Àu‹…ÉtÿуÆ;u rì^]ËÿU‹ìƒ=p Athp AèÅY…Àt ÿuÿp AYèP)hˆÁ@hpÁ@è¡ÿÿÿYY…ÀuBhei@èöÝÿÿ¸hÁ@Ç$lÁ@ècÿÿÿƒ=t AYtht AèmY…Àt jjjÿt A3À]Ãjhðà@èÐÕÿÿjèÏÊÿÿYƒeü3ÛC9°A„ʼn¬AŠE¢¨Aƒ} …ÿ5h AèèÿÿY‹ø‰}Ø…ÿtxÿ5d AèzèÿÿY‹ð‰u܉}ä‰uàƒî‰uÜ;÷rWèVèÿÿ9tí;÷rJÿ6èPèÿÿ‹øè@èÿÿ‰ÿ×ÿ5h Aè:èÿÿ‹øÿ5d Aè-èÿÿƒÄ 9}äu9Eàt‰}ä‰}؉Eà‹ð‰uÜ‹}ØëŸh˜Á@¸ŒÁ@è_þÿÿYh Á@¸œÁ@èOþÿÿYÇEüþÿÿÿèƒ}u(‰°AjèýÈÿÿYÿuèüýÿÿ3ÛCƒ}tjèäÈÿÿYÃèöÔÿÿËÿU‹ìjjÿuèÃþÿÿƒÄ ]ËÿU‹ìjjÿuè­þÿÿƒÄ ]ÃjjjèþÿÿƒÄ ÃjjjèŽþÿÿƒÄ ËÿVèRçÿÿ‹ðVèMÜÿÿVè% Vè2ÖÿÿVè[,VèF,Vè.*VèþVè*hº^@è¤æÿÿƒÄ$£¨û@^ËÿU‹ìQQS‹]VW3ö3ÿ‰}ü;ý°û@t G‰}üƒÿrîƒÿƒwjèq-Yƒø„4jè`-Y…Àu ƒ=<ð@„ûü„AhhÉ@»S¿¸AWèâÖÿÿƒÄ …Àt VVVVVèƒÕÿÿƒÄh¾ÑAVjÆÕAÿÜÀ@…Àu&hPÉ@hûVè ÖÿÿƒÄ …Àt3ÀPPPPPè?ÕÿÿƒÄVè Øÿÿ@Yƒø=“Àu ÇFd…ë.=Àu ÇFd‚ë=Àu ÇFd†ë=’ÀuÇFdŠÿvdjÿÓY‰~dëƒ`QÿÓ‹EøY‰F`ƒÈÿ[_^ÉÃ=l AuèàÿÿV‹5”AW3ÿ…öuƒÈÿé <=tGVèpÕÿÿYtŠ„ÀuêjGWè‹øYY‰=A…ÿtË‹5”ASëBVè?Õÿÿ‹ØC€>=Yt1jSèëYY‰…ÀtNVSPè—ÓÿÿƒÄ …Àt3ÀPPPPPè6ÒÿÿƒÄƒÇó€>u¹ÿ5”AèÜ»ÿÿƒ%”Aƒ'Ç` A3ÀY[_^Ãÿ5Aè¶»ÿÿƒ%AƒÈÿëä‹ÿU‹ìQ‹MS3ÀV‰‹ò‹U Ç9Et ‹]ƒE‰‰Eü€>"u3À9Eü³"”ÀF‰Eüë<ÿ…ÒtŠˆB‰U жÃPFèÈ)Y…Àtÿƒ} t ‹M ŠÿE ˆF‹U ‹M„Ût2ƒ}üu©€û t€û uŸ…ÒtÆBÿƒeü€>„éŠ< t< uFëóNëã€>„Ѓ}t ‹EƒE‰ÿ3ÛC3ÉëFA€>\tù€>"u&öÁuƒ}üt F€8"u‹ðë 3À3Û9Eü”À‰EüÑé…ÉtI…ÒtÆ\Bÿ…Éuñ‰U Š„ÀtUƒ}üu< tK< tG…Ût=¾ÀP…Òt#èã(Y…Àt Š‹M ÿE ˆFÿ‹M ŠÿE ˆë èÀ(Y…ÀtFÿÿ‹U FéVÿÿÿ…ÒtÆB‰U ÿ‹Méÿÿÿ‹E^[…Àtƒ ÿÉËÿU‹ìƒì S3ÛVW9l Auè€Ýÿÿh¾ÐAVSˆÔ AÿÜÀ@¡ A‰5 A;Ãt‰Eü8u‰uü‹UüEøPSS}ôè þÿÿ‹EøƒÄ =ÿÿÿ?sJ‹MôƒùÿsB‹øÁç;Ár6Pè‹ðY;ót)‹UüEøPþWV}ôèÉýÿÿ‹EøƒÄ H£„A‰5ˆA3ÀëƒÈÿ_^[ÉËÿU‹ì¡Ø Aƒì SV‹5ðÀ@W3Û3ÿ;Ãu.ÿÖ‹ø;ût ÇØ Aë#ÿTÀ@ƒøxu jX£Ø Aë¡Ø Aƒø…;ûuÿÖ‹ø;ûu3ÀéÊ‹Çf9t@@f9uù@@f9uò‹5ìÀ@SSS+ÇSÑø@PWSS‰EôÿÖ‰Eø;Ãt/PèBY‰Eü;Ãt!SSÿuøPÿuôWSSÿÖ…Àu ÿuü葸ÿÿY‰]ü‹]üWÿèÀ@‹Ãë\ƒøt;Ãu‚ÿäÀ@‹ð;ó„rÿÿÿ8t @8uû@8uö+Æ@P‰EøèÛ‹øY;ûu VÿàÀ@éEÿÿÿÿuøVWè¶ƒÄ VÿàÀ@‹Ç_^[ÉÃjThá@è]Ìÿÿ3ÿ‰}üEœPÿüÀ@ÇEüþÿÿÿj@j ^VèÅYY;Ç„£` A‰5P Aˆë0Æ@ƒÿÆ@ ‰xÆ@$Æ@% Æ@& ‰x8Æ@4ƒÀ@‹ ` AÁ;ÁrÌf9}΄ ‹EÐ;Ç„ÿ‹8X;‰Eä¾;þ|‹þÇEàë[j@j è7YY…ÀtV‹Mà ` A‰ƒP A ë*Æ@ƒÿÆ@ ƒ`€`$€Æ@% Æ@& ƒ`8Æ@4ƒÀ@‹Ö;ÂrÒÿEà9=P A|ë‹=P Aƒeà…ÿ~m‹E䋃ùÿtVƒùþtQЍtK¨u QÿøÀ@…Àt<‹uà‹ÆÁøƒæÁæ4…` A‹E䋉ŠˆFh F PèÕYY…À„ÉÿFÿEàCƒEä9}à|“3Û‹óÁæ5` A‹ƒøÿt ƒøþt€N€ërÆF…ÛujöXë ‹ÃH÷ØÀƒÀõPÿØÀ@‹øƒÿÿtC…ÿt?WÿøÀ@…Àt4‰>%ÿƒøu€N@ë ƒøu€Nh F Pè?YY…Àt7ÿFë €N@ÇþÿÿÿCƒûŒgÿÿÿÿ5P AÿôÀ@3Àë3À@ËeèÇEüþÿÿÿƒÈÿè[ÊÿÿËÿV¸$ß@¾$ß@W‹ø;Æs‹…ÀtÿЃÇ;þrñ_^ËÿV¸,ß@¾,ß@W‹ø;Æs‹…ÀtÿЃÇ;þrñ_^ËÿU‹ìƒì¡@ð@ƒeøƒeüSW¿Næ@»»ÿÿ;Çt …Ãt ÷УDð@ë`VEøPÿ Á@‹uü3uøÿÁ@3ðÿÈÀ@3ðÿÁ@3ðEðPÿÁ@‹Eô3Eð3ð;÷u¾Oæ@»ë …óu‹ÆÁà ð‰5@ð@÷Ö‰5Dð@^_[ÉÃ%L AËÿU‹ì‹E£Ü A]Ãjh0á@èÉÿÿƒeüÿu ÿuÿÁ@‰Eäë/‹Eì‹‹‰Eà3É=À”Á‹ÁËeè}àÀujÿÄÀ@ƒeäÇEüþÿÿÿ‹EäèÉÿÿËÿU‹ìVW3öÿuè§Ìÿÿ‹øY…ÿu'9à AvVÿÌÀ@†è;à AvƒÈÿ‹ðƒøÿuÊ‹Ç_^]ËÿU‹ìVW3öjÿu ÿuè¦"‹øƒÄ …ÿu'9à AvVÿÌÀ@†è;à AvƒÈÿ‹ðƒøÿuËÇ_^]ËÿU‹ìVW3öÿu ÿuèz#‹øYY…ÿu,9E t'9à AvVÿÌÀ@†è;à AvƒÈÿ‹ðƒøÿuÁ‹Ç_^]ÃÌÌÌÌÌÌÌÌÌU‹ìWV‹u ‹M‹}‹Á‹ÑÆ;þv;ø‚¤ùrƒ=H AtWVƒçƒæ;þ^_u^_]é’%÷ÇuÁéƒâƒùr*ó¥ÿ$•ôl@‹Çºƒér ƒàÈÿ$…l@ÿ$m@ÿ$ˆl@l@Dl@hl@#ÑŠˆŠFˆGŠFÁéˆGƒÆƒÇƒùrÌó¥ÿ$•ôl@I#ÑŠˆŠFÁéˆGƒÆƒÇƒùr¦ó¥ÿ$•ôl@#ÑŠˆƒÆÁéƒÇƒùrˆó¥ÿ$•ôl@Iël@Øl@Ðl@Èl@Àl@¸l@°l@¨l@‹DŽä‰Dä‹DŽè‰Dè‹DŽì‰Dì‹DŽð‰Dð‹DŽô‰Dô‹DŽø‰Dø‹DŽü‰Düðøÿ$•ôl@‹ÿm@ m@m@,m@‹E^_Éʈ‹E^_ÉʈŠFˆG‹E^_ÉÃIŠˆŠFˆGŠFˆG‹E^_ÉÃt1ü|9ü÷Çu$Áéƒâƒùr ýó¥üÿ$•n@‹ÿ÷Ùÿ$@n@I‹Çºƒùr ƒà+Èÿ$…”m@ÿ$n@¤m@Èm@ðm@ŠF#шGƒîÁéƒïƒùr²ýó¥üÿ$•n@IŠF#шGŠFÁéˆGƒîƒïƒùrˆýó¥üÿ$•n@ŠF#шGŠFˆGŠFÁéˆGƒîƒïƒù‚Vÿÿÿýó¥üÿ$•n@IDn@Ln@Tn@\n@dn@ln@tn@‡n@‹DމD‹DމD‹DމD‹DމD‹DŽ ‰D ‹DމD‹DމDðøÿ$•n@‹ÿ n@¨n@¸n@Ìn@‹E^_ÉÊFˆG‹E^_ÉÃIŠFˆGŠFˆG‹E^_ÉÊFˆGŠFˆGŠFˆG‹E^_ÉÃÌÌÌSVW‹T$‹D$‹L$URPQQhxo@dÿ5¡@ð@3ĉD$d‰%‹D$0‹X‹L$,3‹p ƒþþt;‹T$4ƒúþt;òv.4v\³‹ ‰H ƒ{uÌh‹Cè¶$¹‹CèÈ$ë°dƒÄ_^[ËL$÷A¸t3‹D$‹H3Èèb¯ÿÿU‹hÿp ÿpÿpè>ÿÿÿƒÄ ]‹D$‹T$‰¸ÃU‹L$‹)ÿqÿqÿq(èÿÿÿƒÄ ]ÂUVWS‹ê3À3Û3Ò3ö3ÿÿÑ[_^]Ëê‹ñ‹Ájè$3À3Û3É3Ò3ÿÿæU‹ìSVWjjhp@Qèo=_^[]ÃU‹l$RQÿt$è´þÿÿƒÄ ]ÂÌÌÌÌÌ‹ÿU‹ì‹M¸MZf9t3À]ËA<Á8PEuï3Ò¹ f9H”‹Â]ÃÌÌÌÌÌÌÌÌÌÌÌ‹ÿU‹ì‹E‹H<È·ASV·q3ÒWD…öv‹} ‹H ;ùr ‹XÙ;ûr BƒÀ(;Örè3À_^[]ÃÌÌÌÌÌÌÌÌÌÌÌÌ‹ÿU‹ìjþhPá@h°3@d¡PƒìSVW¡@ð@1Eø3ÅPEðd£‰eèÇEüh@è*ÿÿÿƒÄ…ÀtU‹E-@Ph@èPÿÿÿƒÄ…Àt;‹@$Áè÷ЃàÇEüþÿÿÿ‹Mðd‰ Y_^[‹å]ËEì‹‹3Ò=À”‹ÂËeèÇEüþÿÿÿ3À‹Mðd‰ Y_^[‹å]ÃÌÌÌ‹T$ ‹L$…Òti3ÀŠD$„Àuúrƒ=H AtéÎ"W‹ùƒúr1÷Ùƒát +шƒÇƒéuö‹ÈÁàÁ‹ÈÁàÁ‹ÊƒâÁétó«…Òt ˆƒÇƒêuö‹D$_ËD$Ãj hpá@è>Áÿÿjè=¶ÿÿYƒeü‹u‹N…Ét/¡ì Aºè A‰Eä…Àt9u,‹H‰JP輬ÿÿYÿv賬ÿÿYƒfÇEüþÿÿÿè è-ÁÿÿËÐëÅjèµÿÿYÃÌÌÌÌÌÌ‹T$‹L$÷Âu<‹:u. Àt&:au% ätÁè:Au Àt:auƒÁƒÂ äuÒ‹ÿ3ÀÃÀÑàƒÀÃ÷ÂtŠƒÂ:uçƒÁ ÀtÜ÷Ât¤f‹ƒÂ:uÎ ÀtÆ:auÅ ät½ƒÁëˆjhá@è@Àÿÿ3À‹]3ÿ;ß•À;Çuè<³ÿÿÇWWWWWè:ÃÿÿƒÄƒÈÿëSƒ=œAu8jè µÿÿY‰}üSè2µÿÿY‰Eà;Çt ‹süƒî ‰uäë‹uäÇEüþÿÿÿè%9}àuSWÿ5ÄAÿÁ@‹ð‹ÆèÀÿÿÃ3ÿ‹]‹uäjè׳ÿÿYËÿU‹ì‹E…Àtƒè8ÝÝuPèA«ÿÿY]ËÿU‹ìƒì¡@ð@3ʼnEüSV3ÛW‹ñ9ð Au8SS3ÿGWhÊ@hSÿ$Á@…Àt‰=ð AëÿTÀ@ƒøxu Çð A9]~"‹M‹EI8t@;ËuöƒÉÿ‹E+ÁH;E}@‰E¡ð Aƒø„¬;Ĥƒø…̉]ø9] u‹‹@‰E ‹5 Á@3À9]$SSÿu•ÀÿuÅPÿu ÿÖ‹ø;û„~Cjà3ÒX÷÷ƒør7D?=wè["‹Ä;ÃtÇÌÌëPèwÂÿÿY;Ãt ÇÝ݃À‰Eôë‰]ô9]ô„>Wÿuôÿuÿujÿu ÿÖ…À„ã‹5$Á@SSWÿuôÿu ÿuÿ֋ȉMø;Ë„Â÷E t)9]„°;M§ÿuÿuWÿuôÿu ÿuÿÖé;Ë~Ejà3ÒX÷ñƒør9D =wèœ!‹ô;ótjÇÌ̃ÆëPèµÁÿÿY;Ãt ÇÝ݃À‹ðë3ö;ótAÿuøVWÿuôÿu ÿuÿ$Á@…Àt"SS9]uSSëÿuÿuÿuøVSÿu ÿìÀ@‰EøVè¸ýÿÿYÿuôè¯ýÿÿ‹EøYéY‰]ô‰]ð9]u‹‹@‰E9] u‹‹@‰E ÿuèìY‰Eìƒøÿu3Àé!;E „ÛSSMQÿuPÿu è ƒÄ‰Eô;ÃtÔ‹5Á@SSÿuPÿu ÿuÿÖ‰Eø;Ãu3öé·~=ƒøàw8ƒÀ=wè† ‹ü;ûtÝÇÌ̃ÇëPèŸÀÿÿY;Ãt ÇÝ݃À‹øë3ÿ;ût´ÿuøSWè½úÿÿƒÄ ÿuøWÿuÿuôÿu ÿuÿÖ‰Eø;Ãu3öë%ÿuEøÿuPWÿu ÿuìèY‹ð‰uðƒÄ÷Þö#uøWèüÿÿYëÿuÿuÿuÿuÿu ÿuÿÁ@‹ð9]ôt ÿuôèÁ§ÿÿY‹Eð;Ãt 9EtPè®§ÿÿY‹Æeà_^[‹Mü3Í茧ÿÿÉËÿU‹ìƒìÿuMðèy©ÿÿÿu(Mðÿu$ÿu ÿuÿuÿuÿuÿu è(üÿÿƒÄ €}üt‹MøƒapýÉËÿU‹ìQQ¡@ð@3ʼnEü¡ô ASV3ÛW‹ù;Ãu:EøP3öFVhÊ@Vÿ,Á@…Àt‰5ô Aë4ÿTÀ@ƒøxu jX£ô Aë¡ô Aƒø„Ï;Äǃø…è‰]ø9]u‹‹@‰E‹5 Á@3À9] SSÿu•Àÿu ÅPÿuÿÖ‹ø;û„«~<ÿðÿÿw4D?=w蟋Ä;ÃtÇÌÌëP軾ÿÿY;Ãt ÇÝ݃À‹Ø…Ûti?PjSèÛøÿÿƒÄ WSÿuÿu jÿuÿÖ…ÀtÿuPSÿuÿ,Á@‰EøSèÉúÿÿ‹EøYëu3ö9]u‹‹@‰E9]u‹‹@‰Eÿuè Yƒøÿu3ÀëG;EtSSMQÿu Pÿuè5‹ðƒÄ;ót܉u ÿuÿuÿu ÿuÿuÿ(Á@‹ø;ótV该ÿÿY‹Çeì_^[‹Mü3Íè¥ÿÿÉËÿU‹ìƒìÿuMðèz§ÿÿÿu$Mðÿu ÿuÿuÿuÿuÿu èþÿÿƒÄ€}üt‹MøƒapýÉËÿU‹ìV‹u…ö„ÿvè?¥ÿÿÿvè7¥ÿÿÿv è/¥ÿÿÿvè'¥ÿÿÿvè¥ÿÿÿvè¥ÿÿÿ6è¥ÿÿÿv è¥ÿÿÿv$è¥ÿÿÿv(èø¤ÿÿÿv,èð¤ÿÿÿv0èè¤ÿÿÿv4èà¤ÿÿÿvèØ¤ÿÿÿv8èФÿÿÿv<èȤÿÿƒÄ@ÿv@轤ÿÿÿvD赤ÿÿÿvHè­¤ÿÿÿvL襤ÿÿÿvPè¤ÿÿÿvT蕤ÿÿÿvXè¤ÿÿÿv\è…¤ÿÿÿv`è}¤ÿÿÿvdèu¤ÿÿÿvhèm¤ÿÿÿvlèe¤ÿÿÿvpè]¤ÿÿÿvtèU¤ÿÿÿvxèM¤ÿÿÿv|èE¤ÿÿƒÄ@ÿ¶€è7¤ÿÿÿ¶„è,¤ÿÿÿ¶ˆè!¤ÿÿÿ¶Œè¤ÿÿÿ¶è ¤ÿÿÿ¶”è¤ÿÿÿ¶˜èõ£ÿÿÿ¶œèê£ÿÿÿ¶ èߣÿÿÿ¶¤èÔ£ÿÿÿ¶¨èÉ£ÿÿƒÄ,^]ËÿU‹ìV‹u…öt5‹;˜ý@tP覣ÿÿY‹F;œý@tP蔣ÿÿY‹v;5 ý@tVè‚£ÿÿY^]ËÿU‹ìV‹u…öt~‹F ;¤ý@tPè`£ÿÿY‹F;¨ý@tPèN£ÿÿY‹F;¬ý@tPè<£ÿÿY‹F;°ý@tPè*£ÿÿY‹F;´ý@tPè£ÿÿY‹F ;¸ý@tPè£ÿÿY‹v$;5¼ý@tVèô¢ÿÿY^]ËÿU‹ì‹ES3ÛVW;Ãt‹} ;ûwè/ªÿÿj^‰0SSSSSè.ºÿÿƒÄ‹Æë<‹u;óuˆëÚ‹Ð8tBOuø;ût BF:ËtOuó;ûuˆèè©ÿÿj"Y‰‹ñëµ3À_^[]ÃÌÌÌU‹ìV3ÀPPPPPPPP‹U IŠ Àt ƒÂ«$ëñ‹uƒÉÿIƒÁŠ Àt ƒÆ£$sî‹ÁƒÄ ^ÉËÿU‹ìSV‹u3ÛW9]u;óu9] u3À_^[]Ã;ót‹} ;ûwè]©ÿÿj^‰0SSSSSè\¹ÿÿƒÄ‹ÆëÕ9]uˆëÊ‹U;Óuˆëу}ÿ‹ÆuŠ ˆ@B:ËtOuóëŠ ˆ@B:ËtOtÿMuî9]uˆ;ûu‹ƒ}ÿu‹E jPˆ\ÿXéxÿÿÿˆèã¨ÿÿj"Y‰‹ñë‚ÌÌÌÌÌU‹ìWV‹u ‹M‹}‹Á‹ÑÆ;þv;ø‚¤ùrƒ=H AtWVƒçƒæ;þ^_u^_]é‚÷ÇuÁéƒâƒùr*ó¥ÿ$•@‹Çºƒér ƒàÈÿ$…~@ÿ$@ÿ$˜~@(~@T~@x~@#ÑŠˆŠFˆGŠFÁéˆGƒÆƒÇƒùrÌó¥ÿ$•@I#ÑŠˆŠFÁéˆGƒÆƒÇƒùr¦ó¥ÿ$•@#ÑŠˆƒÆÁéƒÇƒùrˆó¥ÿ$•@Iû~@è~@à~@Ø~@Ð~@È~@À~@¸~@‹DŽä‰Dä‹DŽè‰Dè‹DŽì‰Dì‹DŽð‰Dð‹DŽô‰Dô‹DŽø‰Dø‹DŽü‰Düðøÿ$•@‹ÿ@@(@<@‹E^_Éʈ‹E^_ÉʈŠFˆG‹E^_ÉÃIŠˆŠFˆGŠFˆG‹E^_ÉÃt1ü|9ü÷Çu$Áéƒâƒùr ýó¥üÿ$• €@‹ÿ÷Ùÿ$P€@I‹Çºƒùr ƒà+Èÿ$…¤@ÿ$ €@´@Ø@€@ŠF#шGƒîÁéƒïƒùr²ýó¥üÿ$• €@IŠF#шGŠFÁéˆGƒîƒïƒùrˆýó¥üÿ$• €@ŠF#шGŠFˆGŠFÁéˆGƒîƒïƒù‚Vÿÿÿýó¥üÿ$• €@IT€@\€@d€@l€@t€@|€@„€@—€@‹DމD‹DމD‹DމD‹DމD‹DŽ ‰D ‹DމD‹DމDðøÿ$• €@‹ÿ°€@¸€@È€@Ü€@‹E^_ÉÊFˆG‹E^_ÉÃIŠFˆGŠFˆG‹E^_ÉÊFˆGŠFˆGŠFˆG‹E^_ÉÃÌÌÌÌÌÌÌÌÌÌÌU‹ìV3ÀPPPPPPPP‹U IŠ Àt ƒÂ«$ëñ‹u‹ÿŠ Àt ƒÆ£$sñFÿƒÄ ^ÉËÿU‹ìƒìÿu Mð詟ÿÿ¶E‹Mð‹‰È·A%€€}üt‹MøƒapýÉËÿU‹ìjÿuè¹ÿÿÿYY]ËÿU‹ìƒìSÿuMèè]Ÿÿÿ‹]C=w‹E苀ȷXëu‰]Á}EèP‹E%ÿPèlÿÿÿYY…ÀtŠEjˆEøˆ]ùÆEúYë 3Ɉ]øÆEùA‹EèjÿpÿpEüPQEøPEèjPèZ÷ÿÿƒÄ …Àu8Eôt‹Eðƒ`pý3Àë·Eü#E €}ôt‹Mðƒapý[ÉÃjh°á@è±ÿÿ3Û‰]äjèÿ¥ÿÿY‰]üj_‰}à;=€A}W‹÷Áæ¡x AÆ9tD‹ö@ ƒtPèNYƒøÿtÿEäƒÿ|(¡x A‹ƒÀ Pÿ|À@¡x Aÿ4èQœÿÿY¡x A‰GëžÇEüþÿÿÿè ‹EäèÁ°ÿÿÃjè ¤ÿÿYËÿU‹ìSV‹u‹F ‹È€á3Û€ùu@©t9‹FW‹>+ø…ÿ~,WPVèÃYPèkƒÄ ;Çu‹F „Àyƒàý‰F ëƒN ƒËÿ_‹Fƒf‰^‹Ã[]ËÿU‹ìV‹u…öu Vè5Yë/Vè|ÿÿÿY…ÀtƒÈÿë÷F @tVèZPèßY÷ØYÀë3À^]ÃjhÐá@趯ÿÿ3ÿ‰}ä‰}Üjè­¤ÿÿY‰}ü3ö‰uà;5€Aƒ¡x A°98t^‹ö@ ƒtVPVè,ÊÿÿYY3ÒB‰Uü¡x A‹°‹H öÁƒt/9UuPèJÿÿÿYƒøÿtÿEäë9}uöÁtPè/ÿÿÿYƒøÿu E܉}üèFë„3ÿ‹uà¡x Aÿ4°Vè5ÊÿÿYYÃÇEüþÿÿÿèƒ}‹Eät‹EÜè7¯ÿÿÃjè£ÿÿYÃjèÿÿÿYËÿU‹ì‹EƒøþuèÞ¡ÿÿÇ 3À]ÃV3ö;Æ|;P ArèÀ¡ÿÿVVVVVÇ è¾±ÿÿƒÄ3Àë‹ÈƒàÁù‹ ` AÁà¾Dƒà@^]ËÿU‹ì‹EV3ö;Æuèx¡ÿÿVVVVVÇèv±ÿÿƒÄƒÈÿë‹@^]ËÿU‹ìQV‹u Vè¾ÿÿÿ‰E ‹F Y¨‚uè:¡ÿÿÇ ƒN ƒÈÿé/¨@t è¡ÿÿÇ"ëãS3Û¨t‰^¨„‡‹Nƒàþ‰‰F ‹F ƒàïƒÈ‰F ‰^‰]ü© u,èhÇÿÿƒÀ ;ðt è\ÇÿÿƒÀ@;ðu ÿu èÑþÿÿY…ÀuVè4Y÷F W„€‹F‹>H‰‹N+øI;û‰N~WPÿu è©ƒÄ ‰EüëMƒÈ ‰F ƒÈÿëy‹M ƒùÿtƒùþt‹Áƒà‹ÑÁúÁà•` Aë¸xü@ö@ tjSSQè #ƒÄƒøÿt%‹FŠMˆë3ÿGWEPÿu è:ƒÄ ‰Eü9}üt ƒN ƒÈÿë‹E%ÿ_[^ÉËÿVW3ÿ·àý@ÿ6èT¿ÿÿƒÇY‰ƒÿ(rè_^ËÿU‹ìƒìSV‹u 3ÛW‹};óu;ûv‹E;Ãt‰3À郋E;Ãtƒÿÿÿÿÿv蓟ÿÿj^SSSSS‰0è’¯ÿÿƒÄ‹ÆëVÿuMðè šÿÿ‹Eð9X…œf‹E¹ÿf;Áv6;ót;ûv WSVèsêÿÿƒÄ è@ŸÿÿÇ*è5Ÿÿÿ‹8]üt‹Møƒapý_^[ÉÃ;ót2;ûw,èŸÿÿj"^SSSSS‰0è¯ÿÿƒÄ8]ü„yÿÿÿ‹Eøƒ`pýémÿÿÿˆ‹E;ÃtÇ8]ü„%ÿÿÿ‹Eøƒ`pýéÿÿÿM QSWVjMQS‰] ÿpÿìÀ@;Ãt9] …^ÿÿÿ‹M;Ët½‰ë¹ÿTÀ@ƒøz…Dÿÿÿ;ó„gÿÿÿ;û†_ÿÿÿWSVèœéÿÿƒÄ éOÿÿÿ‹ÿU‹ìjÿuÿuÿu ÿuè|þÿÿƒÄ]ÃÌÌÌÌÌÌÌV‹D$ Àu(‹L$‹D$ 3Ò÷ñ‹Ø‹D$÷ñ‹ð‹Ã÷d$‹È‹Æ÷d$ÑëG‹È‹\$‹T$ ‹D$ÑéÑÛÑêÑØ Éuô÷ó‹ð÷d$‹È‹D$÷æÑr;T$ wr;D$v N+D$T$3Û+D$T$ ÷Ú÷؃ڋʋӋًȋÆ^Âjhøá@蓪ÿÿè׿ÿÿ‹@x…ÀtƒeüÿÐë3À@ËeèÇEüþÿÿÿè§謪ÿÿÃ調ÿÿ‹@|…ÀtÿÐé´ÿÿÿjhâ@èGªÿÿÿ5ü Aè9½ÿÿY…ÀtƒeüÿÐë3À@ËeèÇEüþÿÿÿè}ÿÿÿÌhµˆ@蓼ÿÿY£ü AËÿU‹ì‹E£ A£ A£ A£ A]ËÿU‹ì‹E‹ tü@V9Pt‹ñkö uƒÀ ;ÆrìkÉ M^;Ás9Pt3À]Ãÿ5 Aè§¼ÿÿYÃj h8â@蜩ÿÿ3ÿ‰}ä‰}Ø‹]ƒû Lt‹ÃjY+Át"+Át+Átd+ÁuDè@¾ÿÿ‹ø‰}Ø…ÿuƒÈÿéa¾ A¡ Aë`ÿw\‹Óè]ÿÿÿ‹ðƒÆ‹ëZ‹Ãƒèt<ƒèt+Htè=œÿÿÇ3ÀPPPPPè9¬ÿÿƒÄ뮾 A¡ Aë¾ A¡ Aë ¾ A¡ AÇEäPèã»ÿÿ‰EàY3Àƒ}à„Ø9Eàujè0Ôÿÿ9EätPèÅÿÿY3À‰Eüƒût ƒû tƒûu‹O`‰MÔ‰G`ƒûu@‹Od‰MÐÇGdŒƒûu.‹ hü@‰MÜ‹ lü@‹hü@Ê9MÜ}‹MÜkÉ ‹W\‰DÿEÜëÛèK»ÿÿ‰ÇEüþÿÿÿèƒûuÿwdSÿUàYë‹]‹}؃}ätjèSœÿÿYÃSÿUàYƒût ƒû tƒûu‹EÔ‰G`ƒûu‹EЉGd3Àè>¨ÿÿËÿU‹ì‹E£ A]ËÿU‹ì‹E£ A]ËÿU‹ìƒìSVW辺ÿÿƒeüƒ=$ A‹Ø…ŽhÔ@ÿ4Á@‹ø…ÿ„*‹5´À@hôÓ@WÿÖ…À„PèºÿÿÇ$äÓ@W£$ AÿÖPèó¹ÿÿÇ$ÐÓ@W£( AÿÖPèÞ¹ÿÿÇ$´Ó@W£, AÿÖPèɹÿÿY£4 A…ÀthœÓ@WÿÖPè±¹ÿÿY£0 A¡0 A;ÃtO94 AtGPèºÿÿÿ54 A‹ðèºÿÿYY‹ø…öt,…ÿt(ÿÖ…ÀtMøQj MìQjPÿ×…ÀtöEôu M ë9¡( A;Ãt0P迹ÿÿY…Àt%ÿЉEü…Àt¡, A;ÃtP袹ÿÿY…ÀtÿuüÿЉEüÿ5$ A芹ÿÿY…Àtÿuÿu ÿuÿuüÿÐë3À_^[ÉËÿU‹ì‹MV3ö;Î|ƒù~ ƒùu¡œAë(¡œA‰ œAëèP™ÿÿVVVVVÇèN©ÿÿƒÄƒÈÿ^]ËÿU‹ìƒìÿuMð軓ÿÿ¶E ‹MôŠU„Tuƒ}t‹Mð‹‰È·A#Eë3À…Àt3À@€}üt‹MøƒapýÉËÿU‹ìjjÿujèšÿÿÿƒÄ]Ãj hXâ@该ÿÿ‹M3ÿ;Ïv.jàX3Ò÷ñ;E À@u裘ÿÿÇ WWWWW表ÿÿƒÄ3ÀéÕ¯M ‹ñ‰u;÷u3öF3Û‰]äƒþàwiƒ=œAuKƒÆƒæð‰u ‹E;ŒAw7jè@šÿÿY‰}üÿuèF¢ÿÿY‰EäÇEüþÿÿÿè_‹]ä;ßtÿuWSèIãÿÿƒÄ ;ßuaVjÿ5ÄAÿˆÀ@‹Ø;ßuL9=ä At3Vèé¬ÿÿY…À…rÿÿÿ‹E;Ç„PÿÿÿÇ éEÿÿÿ3ÿ‹u jèä˜ÿÿYÃ;ßu ‹E;ÇtÇ ‹Ãèã¤ÿÿÃjhxâ@葤ÿÿ‹]…Ûuÿu è~¨ÿÿYéÌ‹u …öu Sè$ÿÿYé·ƒ=œA…“3ÿ‰}äƒþà‡ŠjèM™ÿÿY‰}üSèv™ÿÿY‰Eà;Ç„ž;5ŒAwIVSPèXžÿÿƒÄ …Àt‰]äë5Vè'¡ÿÿY‰Eä;Çt'‹CüH;Ær‹ÆPSÿuäè/îÿÿSè&™ÿÿ‰EàSPèL™ÿÿƒÄ9}äuH;÷u3öF‰u ƒÆƒæð‰u VWÿ5ÄAÿˆÀ@‰Eä;Çt ‹CüH;Ær‹ÆPSÿuäèÛíÿÿSÿuàèÿ˜ÿÿƒÄÇEüþÿÿÿè.ƒ}àu1…öuFƒÆƒæð‰u VSjÿ5ÄAÿÀ@‹øë‹u ‹]jè~—ÿÿYË}ä…ÿ…¿9=ä At,Vè=«ÿÿY…À…Òþÿÿè:–ÿÿ9}àul‹ðÿTÀ@Pèå•ÿÿY‰ë_…ÿ…ƒè–ÿÿ9}àthÇ ëq…öuFVSjÿ5ÄAÿÀ@‹ø…ÿuV9ä At4VèÔªÿÿY…ÀtƒþàvÍVèĪÿÿYèÉ•ÿÿÇ 3Àèð¢ÿÿÃè¶•ÿÿé|ÿÿÿ…ÿu訕ÿÿ‹ðÿTÀ@PèX•ÿÿ‰Y‹ÇëÒU‹ìƒì‰}ü‰uø‹u ‹}‹MÁéë›fofoNfoV fo^0ffOfW f_0fof@fonPfov`fo~pfg@foPfw`fp¶€¿€Iu£‹uø‹}ü‹å]ÃU‹ìƒì‰}ô‰uø‰]ü‹] ‹Ã™‹È‹E3Ê+ʃá3Ê+Ê™‹ø3ú+úƒç3ú+ú‹Ñ ×uJ‹u‹Îƒá‰Mè;ñt+ñVSPè'ÿÿÿƒÄ ‹E‹Mè…Étw‹]‹U Ó+щUìØ+Ù‰]ð‹uì‹}ð‹Mèó¤‹EëS;Ïu5÷ÙƒÁ‰Mä‹u ‹}‹Mäó¤‹MMä‹U Uä‹E+EäPRQèLÿÿÿƒÄ ‹Eë‹u ‹}‹M‹ÑÁéó¥‹Êƒáó¤‹E‹]ü‹uø‹}ô‹å]Ãj h˜â@è ¡ÿÿƒeüf(ÁÇEäë#‹Eì‹‹=Àt =Àt3ÀÃ3À@ËeèƒeäÇEüþÿÿÿ‹Eäè¡ÿÿËÿU‹ìƒì3ÀS‰Eü‰Eô‰EøSœX‹È5 PœZ+ÑtQ3À¢‰Eô‰]è‰Uì‰M𸢉Uü‰Eø[÷Eütè\ÿÿÿ…Àt3À@ë3À[ÉÃè™ÿÿÿ£H A3ÀÃÌU‹ìSVWUjjh“@ÿuèz]_^[‹å]ËL$÷A¸t2‹D$‹Hü3È辋ÿÿU‹h‹P(R‹P$RèƒÄ]‹D$‹T$‰¸ÃSVW‹D$UPjþh“@dÿ5¡@ð@3ÄPD$d£‹D$(‹X‹p ƒþÿt:ƒ|$,ÿt;t$,v-4v‹ ³‰L$ ‰H ƒ|³uh‹D³èI‹D³è_ë·‹L$d‰ ƒÄ_^[Ã3Àd‹ y“@u‹Q ‹R 9Qu¸ÃSQ»þ@ë SQ»þ@‹L$ ‰K‰C‰k UQPXY]Y[ÂÿÐÃU‹ìƒì‰}ü‹}‹M ÁéfïÀë¤$ffGfG fG0fG@fGPfG`fGp¿€IuЋ}ü‹å]ÃU‹ìƒì‰}ü‹E™‹ø3ú+úƒç3ú+ú…ÿu<‹M‹Ñƒâ‰Uô;Êt+ÊQPèsÿÿÿƒÄ‹E‹Uô…ÒtEE+‰Eø3À‹}ø‹Môóª‹Eë.÷߃lj}ð3À‹}‹Mðóª‹Eð‹M‹UÈ+ÐRjQè~ÿÿÿƒÄ ‹E‹}ü‹å]ËÿU‹ìƒì ¡@ð@3ʼnEüjEôPhÿuÆEúÿ0Á@…ÀuƒÈÿë EôPè÷Y‹Mü3Í蚉ÿÿÉËÿU‹ìƒì4¡@ð@3ʼnEü‹E‹M‰EØ‹ES‰EЋV‰EÜ‹EW3ÿ‰M̉}à‰}Ô;E „_‹5˜À@MèQPÿÖ‹ Á@…Àt^ƒ}èuXEèPÿu ÿÖ…ÀtKƒ}èuE‹uÜÇEÔƒþÿu ÿuØè7¢ÿÿ‹ðYF;÷~[þðÿÿwSD6=w/è‹Ä;Çt8ÇÌÌë-WWÿuÜÿuØjÿuÿÓ‹ð;÷uÃ3ÀéÑPè¡ÿÿY;Çt ÇÝ݃À‰Eäë‰}ä9}ätØ6PWÿuäè/ÛÿÿƒÄ VÿuäÿuÜÿuØjÿuÿÓ…Àt‹]Ì;ßtWWÿuSVÿuäWÿu ÿìÀ@…Àt`‰]àë[‹ìÀ@9}ÔuWWWWVÿuäWÿu ÿÓ‹ð;÷t‡ÿÿY‰~‰~ ‹Ã_^[]Ãj h¸â@èo›ÿÿƒMäÿ3À‹u3ÿ;÷•À;ÇuègŽÿÿÇWWWWWèežÿÿƒÄƒÈÿë öF @t ‰~ ‹Eäèr›ÿÿÃVèšµÿÿY‰}üVè*ÿÿÿY‰EäÇEüþÿÿÿèëÕ‹uVèèµÿÿYËÿU‹ì¸ä茡@ð@3ʼnEü‹E V3ö‰…4åÿÿ‰µ8åÿÿ‰µ0åÿÿ9uu3Àéé;Æu'èÝÿÿ‰0èÃÿÿVVVVVÇèÁÿÿƒÄƒÈÿé¾SW‹}‹ÇÁø4…` A‹ƒçÁçÇŠX$ÛÐû‰µ(åÿÿˆ'åÿÿ€ût€ûu0‹M÷ÑöÁu&ètÿÿ3ö‰0èXÿÿVVVVVÇèVÿÿƒÄéCö@ tjjjÿuè ƒÄÿuè1ëÿÿY…À„‹öD€„è>¯ÿÿ‹@l3É9H…åÿÿ”ÁP‹ÿ4‰ åÿÿÿ<Á@…À„`3É9 åÿÿt„Û„Pÿ8Á@‹4åÿÿ‰…åÿÿ3À‰…<åÿÿ9E†B‰…DåÿÿŠ…'åÿÿ„À…gŠ ‹µ(åÿÿ3À€ù ”À‰… åÿÿ‹ǃx8tŠP4ˆUôˆMõƒ`8jEôPëK¾ÁPègçÿÿY…Àt:‹4åÿÿ+ËM3À@;Ȇ¥j…@åÿÿSPèVƒÄ ƒøÿ„±Cÿ…DåÿÿëjS…@åÿÿPè2ƒÄ ƒøÿ„3ÀPPjMôQj@åÿÿQPÿµåÿÿCÿ…DåÿÿÿìÀ@‹ð…ö„\j…<åÿÿPVEôP‹…(åÿÿ‹ÿ4ÿÔÀ@…À„)‹…Dåÿÿ‹0åÿÿÁ9µ<åÿÿ‰…8åÿÿŒƒ½ åÿÿ„Íj…<åÿÿPjEôP‹…(åÿÿ‹ÆEô ÿ4ÿÔÀ@…À„Ѓ½<åÿÿŒÏÿ…0åÿÿÿ…8åÿÿéƒ<t<u!·33Éfƒþ ”ÁCCƒ…Dåÿÿ‰µ@åÿÿ‰ åÿÿ<t<uRÿµ@åÿÿè? Yf;…@åÿÿ…hƒ…8åÿÿƒ½ åÿÿt)j XP‰…@åÿÿè Yf;…@åÿÿ…;ÿ…8åÿÿÿ…0åÿÿ‹E9…Dåÿÿ‚ùýÿÿé'‹Šÿ…8åÿÿˆT4‹‰D8é3É‹Çö@€„¿‹…4åÿÿ‰@åÿÿ„Û…ʉ…<åÿÿ9M† 답(åÿÿ‹<åÿÿƒ¥Dåÿÿ+4åÿÿ…Håÿÿ;Ms9‹•<åÿÿÿ…<åÿÿŠA€ú uÿ…0åÿÿÆ @ÿ…Dåÿÿˆ@ÿ…Dåÿÿ½Dåÿÿÿr‹؅Håÿÿ+Øj…,åÿÿPS…HåÿÿP‹ÿ4ÿÔÀ@…À„B‹…,åÿÿ…8åÿÿ;ÃŒ:‹…<åÿÿ+…4åÿÿ;E‚Lÿÿÿé ‰…Dåÿÿ€û…Ñ9M†M답(åÿÿ‹Dåÿÿƒ¥<åÿÿ+4åÿÿ…Håÿÿ;MsF‹•Dåÿÿƒ…Dåÿÿ·AAfƒú uƒ…0åÿÿj [f‰@@ƒ…<åÿÿƒ…<åÿÿf‰@@½<åÿÿþrµ‹Ø…Håÿÿ+Øj…,åÿÿPS…HåÿÿP‹ÿ4ÿÔÀ@…À„b‹…,åÿÿ…8åÿÿ;ÃŒZ‹…Dåÿÿ+…4åÿÿ;E‚?ÿÿÿé@9M†|‹Dåÿÿƒ¥<åÿÿ+4åÿÿj…Hùÿÿ^;Ms<‹•Dåÿÿ·µDåÿÿÎfƒú uj [f‰Æµ<åÿÿµ<åÿÿf‰ƽ<åÿÿ¨r¿3öVVhU ðëÿÿQHùÿÿ+Á™+ÂÑøP‹ÁPVhéýÿìÀ@‹Ø;Þ„—j…,åÿÿP‹Ã+ÆP„5ðëÿÿP‹…(åÿÿ‹ÿ4ÿÔÀ@…Àt µ,åÿÿ;ÞËë ÿTÀ@‰…@åÿÿ;Þ\‹…Dåÿÿ+…4åÿÿ‰…8åÿÿ;E‚ ÿÿÿë?j,åÿÿQÿuÿµ4åÿÿÿ0ÿÔÀ@…Àt‹…,åÿÿƒ¥@åÿÿ‰…8åÿÿë ÿTÀ@‰…@åÿÿƒ½8åÿÿulƒ½@åÿÿt-j^9µ@åÿÿuèK‡ÿÿÇ èS‡ÿÿ‰0ë?ÿµ@åÿÿèW‡ÿÿYë1‹µ(åÿÿ‹öD@t‹…4åÿÿ€8u3Àë$è ‡ÿÿÇè‡ÿÿƒ ƒÈÿë ‹…8åÿÿ+…0åÿÿ_[‹Mü3Í^ètÿÿÉÃjhØâ@èÀ“ÿÿ‹Eƒøþuè׆ÿÿƒ 輆ÿÿÇ ƒÈÿé3ÿ;Ç|;P Ar!讆ÿÿ‰8蔆ÿÿÇ WWWWWè’–ÿÿƒÄëÉ‹ÈÁù` A‹ðƒæÁæ‹ ¾L1ƒát¿Pèœ Y‰}ü‹öD0tÿuÿu ÿuè.øÿÿƒÄ ‰Eäëè1†ÿÿÇ è9†ÿÿ‰8ƒMäÿÇEüþÿÿÿè ‹Eäè@“ÿÿÃÿuèæ YÃjhøâ@èä’ÿÿ‹Eƒøþuèè…ÿÿÇ ƒÈÿéª3Û;Ã|;P ArèÇ…ÿÿÇ SSSSSèÅ•ÿÿƒÄëЋÈÁù<` A‹ðƒæÁ拾LƒátÆPèÏ Y‰]ü‹öDt1ÿuèC YPÿ@Á@…Àu ÿTÀ@‰Eäë‰]ä9]ätèf…ÿÿ‹Mä‰èI…ÿÿÇ ƒMäÿÇEüþÿÿÿè ‹Eäè_’ÿÿÃÿuè YËÿU‹ìQQ‹E V‹u‰Eø‹EWV‰EüèÎ ƒÏÿY;Çuèõ„ÿÿÇ ‹Ç‹×ëJÿuMüQÿuøPÿDÁ@‰Eø;ÇuÿTÀ@…Àt Pèç„ÿÿYëÏ‹ÆÁø‹…` AƒæÁæD0€ ý‹Eø‹Uü_^ÉÃjhã@è~‘ÿÿƒÎÿ‰u܉uà‹Eƒøþu茄ÿÿƒ èq„ÿÿÇ ‹Æ‹ÖéÐ3ÿ;Ç|;P Ar!èb„ÿÿ‰8èH„ÿÿÇ WWWWWèF”ÿÿƒÄëÈ‹ÈÁù` A‹ðƒæÁæ‹ ¾L1ƒáu&è!„ÿÿ‰8è„ÿÿÇ WWWWWè”ÿÿƒÄƒÊÿ‹Âë[Pè* Y‰}ü‹öD0tÿuÿuÿu ÿuè©þÿÿƒÄ‰E܉Uàë蹃ÿÿÇ èÁƒÿÿ‰8ƒMÜÿƒMàÿÇEüþÿÿÿè ‹EÜ‹UàèÁÿÿÃÿuèg YËÿU‹ìÿtAhè ÇÿÿY‹M‰A…Àt ƒI ÇAëƒI A‰AÇA‹Aƒa‰]Ãjè¹ÿÿYËÿU‹ìƒìVWÿuMìè²}ÿÿ‹E‹u 3ÿ;Çt‰0;÷u,èƒÿÿWWWWWÇè“ÿÿƒÄ€}øt‹Eôƒ`pý3ÀéØ9}t ƒ}|Ƀ}$ËMìSЉ}ü~ƒ¹¬~EìP¶ÃjPèÎÝÿÿ‹MìƒÄ 닑ȶ÷Bƒà…ÀtŠGëÇ€û-uƒMë€û+uŠG‹E…ÀŒKƒø„Bƒø$9…Àu*€û0t ÇE ë4ŠcsmàuBƒ~u<‹F= “t=!“t="“u$ƒ}Ìuƒ}ätÿvè<úÿÿY…Àt ÿuVè%ýÿÿYYÃj h¸ä@èÒ|ÿÿ3Ò‰Uä‹E‹H;Ê„X8Q„O‹H;Êu ÷€„<‹‹u …Àxt1 ‰Uü3ÛCS¨tA‹}ÿwèîYY…À„òSVèÝYY…À„á‹G‰‹MƒÁQPèìüÿÿYY‰éË‹}‹Eÿp„tHè¦YY…À„ªSVè•YY…À„™ÿw‹EÿpVè:´ÿÿƒÄ ƒ…‚‹…Àt|ƒÇWëœ9Wu8èYYY…ÀtaSVèLYY…ÀtTÿwƒÇW‹Eÿpè_üÿÿYYPVèé³ÿÿƒÄ ë9è!YY…Àt)SVèYY…ÀtÿwèY…ÀtöjX•À@‰Eäëè,ÑÿÿÇEüþÿÿÿ‹Eäë3À@ËeèèÈÐÿÿ3Àè¥{ÿÿÃjhØä@èS{ÿÿ‹E÷€t‹] ë ‹H‹U \ ƒeü‹uVPÿu ‹}WèFþÿÿƒÄHtHu4jFPÿwè¦ûÿÿYYPÿvSèsõÿÿëFPÿwèŒûÿÿYYPÿvSèYõÿÿÇEüþÿÿÿè {ÿÿÃ3À@Ëeèè/ÐÿÿÌ‹ÿU‹ìƒ}tÿuSVÿuèVÿÿÿƒÄƒ} ÿuuVëÿu èõÿÿÿ7ÿuÿuVè®ùÿÿ‹Ghÿu@ÿu‰Fÿu ‹K VÿuèõûÿÿƒÄ(…ÀtVPè¡ôÿÿ]ËÿU‹ìQQV‹u>€„ÚWè‹ÿÿƒ¸€t?è}ÿÿ¸€èÿÿ9t+>MOCàt#ÿu$ÿu ÿuÿuÿuÿu Vè;õÿÿƒÄ…À…‹‹}ƒ uè™Ïÿÿ‹uEøPEüPVÿu Wèƒöÿÿ‹ø‹EüƒÄ;Eøs[S;7|G;wB‹G ‹OÁàÁ‹Hô…Ét€yu*Xðö@u"ÿu$‹u ÿu jÿuÿuÿuÿuè·þÿÿ‹uƒÄÿEü‹EüƒÇ;Eør§[_^ÉËÿU‹ìƒì,‹M S‹]‹C=€VWÆEÿ¾Ië‹Iƒùÿ‰Mø|;È|èßÎÿÿ‹u¿csmà9>…ºƒ~» “…‹F;Ãt=!“t ="“…ÿƒ~…õè4Žÿÿƒ¸ˆ„µè"Žÿÿ‹°ˆ‰uèŽÿÿ‹€ŒjV‰Eè(YY…Àuè\Îÿÿ9>u&ƒ~u ‹F;Ãt=!“t="“u ƒ~uè2ÎÿÿèÉÿÿƒ¸”t|è»ÿÿ‹¸”è°ÿÿÿu3ö‰°”èùÿÿY„ÀuO3Û9~‹G‹Lh`AèÔ~ÿÿ„Àu FƒÃ;7|ãè‹ÍÿÿjÿuèdøÿÿYYh(Ý@MÔè7öÿÿhôä@EÔPè1€ÿÿ‹u¿csmà9>…ˆƒ~…~‹F;Ãt=!“t ="“…e‹}ƒ †¿EäPEðPÿuøÿu Wè[ôÿÿƒÄ‹ø‹Eð;E䃗‹Eø9;G|‹G‰Eô‹G ‰Eè…À~l‹F‹@ X‹‰Eì…À~#ÿv‹Pÿuô‰EàèÑõÿÿƒÄ …ÀuÿMìƒÃ9EìÝÿMèƒEôƒ}è¾ë(ÿu$‹]ôÿu ÆEÿÿuàÿuÿuÿuV‹u èKüÿÿ‹uƒÄÿEðƒÇé]ÿÿÿ‹}€}t jVè:÷ÿÿYY€}ÿ…®‹%ÿÿÿ=!“‚œ‹…ÿ„‘Vè‰÷ÿÿY„À…‚èŒÿÿèý‹ÿÿèø‹ÿÿ‰°ˆèí‹ÿÿƒ}$‹M‰ˆŒVuÿu ëÿu$èñÿÿ‹ujÿVÿuÿu è”õÿÿƒÄÿvè¨÷ÿÿ‹]ƒ{ v&€}…)þÿÿÿu$ÿu ÿuøSÿuÿuÿu VèàûÿÿƒÄ 耋ÿÿƒ¸”tèÖËÿÿ_^[ÉËÿU‹ìVÿu‹ñèÛ{ÿÿÇ Ý@‹Æ^]‹ÿU‹ìSVWèC‹ÿÿƒ¸ ‹E‹M¿csmà¾ÿÿÿ»"“u ‹;×tú&€t‹#Ö;Ór ö@ …“öAft#ƒx„ƒƒ}u}jÿPÿuÿu è¶ôÿÿƒÄëjƒx u‹#Öú!“rXƒxtR99u2ƒyr,9Yv'‹Q‹R…Òt¶u$Vÿu ÿuPÿuÿuÿu QÿÒƒÄ ëÿu ÿuÿu$Pÿuÿuÿu QèÁûÿÿƒÄ 3À@_^[]ÃÌÌÌÌÌÌÌÌÌÌÌÌÌU‹ìƒìSQ‹E ƒÀ ‰Eü‹EUÿu‹M‹müè¥ÕÿÿVWÿÐ_^‹Ý]‹MU‹ëùu¹QèƒÕÿÿ]Y[É Pdÿ5D$ +d$ SVW‰(‹è¡@ð@3ÅP‰eðÿuüÇEüÿÿÿÿEôd£Ã‹ÿU‹ì3À@ƒ}u3À]ÃÌÌÌÌÌÌÌÌÌÌÌ̵ÀþÿÿéQÿÿ‹T$‚¸þÿÿ‹Š´þÿÿ3Èèø_ÿÿƒÀ‹Jü3Èèë_ÿÿ¸œã@éïÿÿÌÌÌÌÌÌÌuäéÈQÿÿ‹T$BÜ‹JØ3ÈèÁ_ÿÿ¸Èã@éÞîÿÿ‹T$B ‹Jì3Èè¦_ÿÿ¸hä@éÃîÿÿÇ€AàÁ@¹€Aézÿÿdê,í2çJçVçdç|çˆç’çªçÂçÐçÚçôçèè è2èHèíí|èŒè˜èªè¾èÒèîè é é.é<éTélé„éé é®éÀéÌéäéüéêê$ê8êJêXêrê|êŒê¢êªê¸êÄêÔêêêëë6ëLëfëxë†ë˜ë²ëÂëØëòëì&ì2ìBìXìhìzìŒìžì®ì¾ìÐìäìöìdèçöæäæÇ:@“B@÷L@î’@ö[@ެ@¨M@/!MW€Ý€Ñbad allocationØÝ@S @Ž9@ AøAXÞ@›9@Ž9@Unknown exceptionlÞ@Ì9@csmà “  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~=EncodePointerKERNEL32.DLLDecodePointerFlsFreeFlsSetValueFlsGetValueFlsAlloc(null)(null)EEE50P( 8PX700WP `h````xpxxxxCorExitProcessmscoree.dllruntime error TLOSS error SING error DOMAIN error R6034 An application has made an attempt to load the C runtime library incorrectly. Please contact the application's support team for more information. R6033 - Attempt to use MSIL code from this assembly during native code initialization This indicates a bug in your application. It is most likely the result of calling an MSIL-compiled (/clr) function from a native constructor or from DllMain. R6032 - not enough space for locale information R6031 - Attempt to initialize the CRT more than once. This indicates a bug in your application. R6030 - CRT not initialized R6028 - unable to initialize heap R6027 - not enough space for lowio initialization R6026 - not enough space for stdio initialization R6025 - pure virtual function call R6024 - not enough space for _onexit/atexit table R6019 - unable to open console device R6018 - unexpected heap error R6017 - unexpected multithread lock error R6016 - not enough space for thread data This application has requested the Runtime to terminate it in an unusual way. Please contact the application's support team for more information. R6009 - not enough space for environment R6008 - not enough space for arguments R6002 - floating point support not loaded Microsoft Visual C++ Runtime Library ...Runtime Error! Program: À À–ÀÀŽÀÀÀ‘À’À“À ((((( H„„„„„„„„„„‚‚‚‚‚‚ h(((( H„„„„„„„„„„‚‚‚‚‚‚ H€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ  !"#$%&'()*+,-./0123456789:;<=>?@abcdefghijklmnopqrstuvwxyz[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`ABCDEFGHIJKLMNOPQRSTUVWXYZ{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿHH:mm:ssdddd, MMMM dd, yyyyMM/dd/yyPMAMDecemberNovemberOctoberSeptemberAugustJulyJuneAprilMarchFebruaryJanuaryDecNovOctSepAugJulJunMayAprMarFebJanSaturdayFridayThursdayWednesdayTuesdayMondaySundaySatFriThuWedTueMonSun€€†€€†€†‚€EEE………00€P€ˆ('8PW€700PPˆ (€ˆ€€`h`hhhxppwppGetProcessWindowStationGetUserObjectInformationAGetLastActivePopupGetActiveWindowMessageBoxAUSER32.DLL Complete Object Locator' Class Hierarchy Descriptor' Base Class Array' Base Class Descriptor at ( Type Descriptor'`local static thread guard'`managed vector copy constructor iterator'`vector vbase copy constructor iterator'`vector copy constructor iterator'`dynamic atexit destructor for '`dynamic initializer for '`eh vector vbase copy constructor iterator'`eh vector copy constructor iterator'`managed vector destructor iterator'`managed vector constructor iterator'`placement delete[] closure'`placement delete closure'`omni callsig' delete[] new[]`local vftable constructor closure'`local vftable'`RTTI`EH`udt returning'`copy constructor closure'`eh vector vbase constructor iterator'`eh vector destructor iterator'`eh vector constructor iterator'`virtual displacement map'`vector vbase constructor iterator'`vector destructor iterator'`vector constructor iterator'`scalar deleting destructor'`default constructor closure'`vector deleting destructor'`vbase destructor'`string'`local static guard'`typeof'`vcall'`vbtable'`vftable'^=|=&=<<=>>=%=/=-=+=*=||&&|^~(),>=><=<%/->*&+---++*->operator[]!===!<<>> delete new__unaligned__restrict__ptr64__clrcall__fastcall__thiscall__stdcall__pascal__cdecl__based(˜Ù@Ù@„Ù@xÙ@lÙ@`Ù@TÙ@LÙ@@Ù@4Ù@ºÂ@xÔ@\Ô@HÔ@(Ô@ Ô@,Ù@$Ù@¸Â@ Ù@Ù@Ù@Ù@Ù@ Ù@Ù@üØ@øØ@ôØ@ðØ@ìØ@èØ@äØ@àØ@ÜØ@ØØ@ÔØ@ÐØ@ÌØ@ÈØ@ÄØ@ÀØ@¼Ø@¸Ø@´Ø@°Ø@¬Ø@¨Ø@¤Ø@ Ø@œØ@˜Ø@”Ø@Ø@ŒØ@ˆØ@„Ø@xØ@lØ@dØ@XØ@@Ø@4Ø@ Ø@Ø@à×@À×@ ×@€×@\×@@×@×@üÖ@ÔÖ@¸Ö@¨Ö@¤Ö@œÖ@ŒÖ@hÖ@`Ö@TÖ@DÖ@(Ö@Ö@àÕ@¸Õ@Õ@dÕ@HÕ@$Õ@Õ@ÔÔ@¨Ô@ŒÔ@ºÂ@SunMonTueWedThuFriSatJanFebMarAprMayJunJulAugSepOctNovDecCONOUT$No errorFile not foundNot a PE fileGeneral failureøý —–C:\gnu.master\exiv2\msvc64\tools\depends\Release\depends32.pdbð@ìÝ@üÝ@Þ@$Þ@ð@ÿÿÿÿ@ìÝ@ ð@ÿÿÿÿ@@Þ@PÞ@$Þ@ ð@@Þ@èò@€Þ@Þ@˜Þ@èò@ÿÿÿÿ@€Þ@`AÈÞ@ØÞ@äÞ@$Þ@`Aÿÿÿÿ@ÈÞ@°3xo“W®a¯ë¾(¿C¿þÿÿÿÔÿÿÿþÿÿÿ_@H @\ß@hß@„ß@ð@ÿÿÿÿ z @ ð@ÿÿÿÿ 9@þÿÿÿÔÿÿÿþÿÿÿo#@þÿÿÿÌÿÿÿþÿÿÿÕ$@é$@þÿÿÿÔÿÿÿþÿÿÿQ(@þÿÿÿÔÿÿÿþÿÿÿG7@þÿÿÿÔÿÿÿþÿÿÿ.;@þÿÿÿÔÿÿÿþÿÿÿŒ>@þÿÿÿÌÿÿÿþÿÿÿZB@þÿÿÿÔÿÿÿþÿÿÿÊE@þÿÿÿÔÿÿÿþÿÿÿ H@þÿÿÿH@þÿÿÿØÿÿÿþÿÿÿÎI@þÿÿÿÚI@þÿÿÿÈÿÿÿþÿÿÿŒ^@þÿÿÿŒÿÿÿþÿÿÿ(i@,i@þÿÿÿÐÿÿÿþÿÿÿYj@pj@þÿÿÿØÿÿÿþÿÿÿ[q@oq@þÿÿÿÔÿÿÿþÿÿÿqr@þÿÿÿÐÿÿÿþÿÿÿšs@þÿÿÿÐÿÿÿþÿÿÿÙ‚@þÿÿÿÌÿÿÿþÿÿÿc„@/„@þÿÿÿØÿÿÿþÿÿÿÕˆ@Ùˆ@þÿÿÿØÿÿÿþÿÿÿ%‰@)‰@þÿÿÿÀÿÿÿþÿÿÿ‹@þÿÿÿÔÿÿÿþÿÿÿŽ@þÿÿÿÐÿÿÿþÿÿÿõ@þÿÿÿÔÿÿÿþÿÿÿY’@u’@þÿÿÿÔÿÿÿþÿÿÿJ˜@þÿÿÿÐÿÿÿþÿÿÿZ @þÿÿÿÐÿÿÿþÿÿÿ;¡@þÿÿÿÌÿÿÿþÿÿÿÙ¢@þÿÿÿÐÿÿÿþÿÿÿz¨@þÿÿÿÔÿÿÿþÿÿÿ:¬@ ÿÿÿþÿÿÿK@ÿÿÿÿà¾@"“”ã@ÿÿÿÿ ¿@"“Àã@þÿÿÿÐÿÿÿþÿÿÿ2³@ô²@þ²@þÿÿÿØÿÿÿþÿÿÿÛ³@ä³@@´@ÿÿÿÿÿÿÿÿ4ä@"“Dä@Tä@þÿÿÿ´ÿÿÿþÿÿÿúµ@jµ@sµ@þÿÿÿÔÿÿÿþÿÿÿá·@å·@þÿÿÿØÿÿÿþÿÿÿz¸@~¸@˜±@å@å@„ß@`Aÿÿÿÿ 0½@Ôæ&çXÁ|åVèÀÌæpèPÁdê,í2çJçVçdç|çˆç’çªçÂçÐçÚçôçèè è2èHèíí|èŒè˜èªè¾èÒèîè é é.é<éTélé„éé é®éÀéÌéäéüéêê$ê8êJêXêrê|êŒê¢êªê¸êÄêÔêêêëë6ëLëfëxë†ë˜ë²ëÂëØëòëì&ì2ìBìXìhìzìŒìžì®ì¾ìÐìäìöìdèçöæäæ VerQueryValueAGetFileVersionInfoSizeAGetFileVersionInfoAVERSION.dllÆSetCurrentDirectoryA¬lstrcmpiA–SearchPathA§GetCurrentDirectoryA²lstrcpynAŸ_lclosenGetUserDefaultLangIDFileTimeToSystemTimeÖGetFileTime¢_lopenFileTimeToLocalFileTimexCreateFileAÔGetFileSize MapViewOfFileAUnmapViewOfFileyCreateFileMappingACCloseHandleKERNEL32.dllwsprintfAUSER32.dllæGetLastError¡HeapFreeoGetCommandLineA-TerminateProcess©GetCurrentProcess>UnhandledExceptionFilterSetUnhandledExceptionFilterÑIsDebuggerPresentŸHeapCreateWVirtualFree¾DeleteCriticalSectionïLeaveCriticalSectionÙEnterCriticalSectionHeapAllocTVirtualAlloc¤HeapReAllocZRaiseException[GetCPInfoÀInterlockedIncrement¼InterlockedDecrementRGetACPGetOEMCPÛIsValidCodePageùGetModuleHandleW GetProcAddress4TlsGetValue2TlsAlloc5TlsSetValue3TlsFreeìSetLastError­GetCurrentThreadId!SleepExitProcessWriteFile;GetStdHandleôGetModuleFileNameAJFreeEnvironmentStringsA¿GetEnvironmentStringsKFreeEnvironmentStringsWzWideCharToMultiByteÁGetEnvironmentStringsWèSetHandleCount×GetFileType9GetStartupInfoATQueryPerformanceCounterfGetTickCountªGetCurrentProcessIdOGetSystemTimeAsFileTimeµInitializeCriticalSectionAndSpinCount’RtlUnwind¦HeapSizeáLCMapStringAMultiByteToWideCharãLCMapStringW=GetStringTypeA@GetStringTypeWèGetLocaleInfoAñLoadLibraryAƒGetConsoleCP•GetConsoleModeAFlushFileBuffersßSetFilePointer‚WriteConsoleA™GetConsoleOutputCPŒWriteConsoleWüSetStdHandleÌÁ@Â@.?AVbad_alloc@std@@Â@.?AVexception@std@@Næ@»±¿D        ! 5A CPR S WY l m pr € ‚ ƒ„ ‘)ž ¡¤ § ·Î×  ÌÁ@ÌÁ@Â@.?AVtype_info@@ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZó@¤`‚y‚!¦ß¡¥Ÿàü@~€ü¨Á£Ú£ þ@þµÁ£Ú£ þAþ¶Ï¢ä¢å¢è¢[þ@~¡þQQÚ^Ú _ÚjÚ2ÓØÞàù1~þ Í@þÿÿÿC(ø@(ø@(ø@(ø@(ø@˜ý@Ë@Ï@Ñ@Øü@0ø@0ø@ó@ÿÿÿÿÿÿÿÿ€ A€ A4Ã@$Ã@º^@ðÈ@ÄÈ@ ˜È@ È@ÔÇ@¤Ç@€Ç@TÇ@Ç@ôÆ@¼Æ@„Æ@\Æ@<Æ@ØÅ@  Å@!¨Ä@"Ä@xøÃ@yèÃ@zØÃ@üÔÃ@ÿÄÃ@x ÿÿÿÿ€ ÌÁ@Ë@ Í@8Ó@4Ó@0Ó@,Ó@(Ó@$Ó@ Ó@Ó@Ó@Ó@üÒ@ðÒ@èÒ@ÜÒ@ØÒ@ÔÒ@ÐÒ@ÌÒ@ÈÒ@ÄÒ@ÀÒ@¼Ò@¸Ò@´Ò@°Ò@¬Ò@¤Ò@˜Ò@Ò@ˆÒ@ÈÒ@€Ò@xÒ@pÒ@dÒ@\Ò@PÒ@DÒ@@Ò@<Ò@0Ò@Ò@Ò@ Øü@.”ý@ø Aø Aø Aø Aø Aø Aø Aø Aø A˜ý@.,£@,£@,£@,£@,£@,£@,£@,£@,£@,£@ “€pðñÿÿPSTPDT0þ@pþ@ÿÿÿÿÿÿÿÿÿÿÿÿ;Zx—µÔó0Nmÿÿÿÿ:Yw–´Óò/MlþÿÿÿþÿÿÿDEPENDS - Matt Pietrek, 1997, for MSJ Syntax: DEPENDS [args] /v show version information /t show time & date information /p show full path /q quiet (don't report some MS dlls) /l show link time & date information ÌÁ@Â@.?AVbad_exception@std@@€0€ HX Zä PAPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADð 00G0X0œ0£0½0c1u1‡1ú12O2Y2œ2¦2>3h3ú34)484?4L4S4`4g4t4{4ˆ4¤4É4Û45 5P5U5\5c5j5q5w5~5ø56636J6ˆ6Œ66”6¤6°6Ê6à6ö67 7/7?7Z78#8)8$979A9Z9c9p9~9Á9Æ9Õ99:@:G:N:U:\:c:j:x:~:ž:»:;d;y;¦;­;¾;ä;ù;'<.ê>ð>ö>ü> ??m?s?„? 30@0J0]0Œ0¿0Å0Í0Ú0î0&1.1C1N12Ö2ƒ3Ž3Ÿ3Ä3Õ3Ü3â3ô3ü34X4]4g4¡4¦4­4³4)5/555;5A5G5N5U5\5c5j5q5x5€5ˆ55œ5¥5ª5°5º5Ã5Î5Ú5ß5ï5ô5ú566606L6o6‚6Å6Ê6Ø6å6ì6ö6 7.747W7^7w7‹7‘7š7­7Ñ7f8†8”8™8Ü:ê:ð: ;;;';4;?;Q;d;o;u;{;€;‰;¦;¬;·;¼;Ä;Ê;Ô;Û;ï;ö;ü; <<<<,<2B>O>Y>g>p>z>®>¹>Ã>Ü>æ>ù>?T?‰?œ?@0 0)0q0Ý0ü0q1}11¢1½1Å1Í1ä1ý12"2(21262E2l2•2¦2É2Ž3¸34O4ž4æ4L5c5t5°5Þ5ä5ï5û566+626Y6_6j6v6‹6’6¦6­6Å6Ñ6×6ã6ò6ø67 77!7-737@7J7Q7i7x77Œ7¯7Ä7ê7*808Z8`8|8”8º849W9a9™9¡9ë9ò9 ::: :':-:4:::B:I:N:V:_:k:p:u:{::…:Š::•:¤:º:Å:Ê:Õ:Ú:å:ê:÷:; ;;8;>;Z;ò<ø<=!=.=:=J=Q=`=l=y==¯=½=Ò=Ü=>5>D>M>q> >â>ô>PŒ(0Ê0è01n11œ1ç4×5a77µ7˜9”;˜;œ; ;¤;¨;¬;°;÷;ý;<>E>J>U>Z>x>)?6?S?Š?¢?­?Ñ?Ú?á?ê?`*0/0W0|0¡0´0Ì0Þ01<1µ1»1Ô1Ú1ƒ2’2Ê2Ô2$3/393J3U355!5'5,525ž5¤5º5Å5Ü5è5õ5ü536‚6•6Ç6à6î67#7)7[7²7º7ú78,8E8†8¶8È89 9C9H9i9n9”9·9Ä9Ð9Ø9à9ì9::#:2:;:P:€:²:»:Ç:þ:;;L;U;a;ª;ß;ø;ÿ;< <<<=$>(>,>0>4>8><>@>Š>>”>˜>œ>ý> ?p°0Ø0Ý0ï0 1!1'1°1 2-222 3C3†3Œ3Ô3æ3ó3ÿ3 444L4|45Ã5æ5d657½7Ç7ß7æ7ð7ø78 8<8Õ8J9W;i;{;;¯;Á;Ó;å;÷; <º=ï=>>>> >$>M>s>‘>˜>œ> >¤>¨>¬>°>´>þ>?? ??v??œ?£?¨?¬?°?Ñ?û?€Ä-04080<0@0D0H0L0P0š0 0¤0¨0¬0F2g2s2š2§2¬2º2•3¸3Ã3æ354š4Ç466w6±7Ï7¸899:9E9S9X9]9b9r9¡9¯9ö9û9@:E:L:Q:X:]:Ì:Õ:Û:e;t;;ž;¤;´;¹;Ñ;×;æ;ì;û;<<<'<,<6S>Y>e>º>í>%??–?ç?í?X040h0n0z0Á0?2ô23m3y3ñ3 44"5?5k5¤5±56Ÿ6Ü7e8Ê8~9ž9Ž:·:;ž<~=G>x>Ž>Ï>î>‹?¿?î? ˆg0“0»0ò0ü0‰1–1¯1Í1 2:2ê2w5~5›5¦5É56š627o7y7‘7º7î78¾8Ì8Ô8á8ÿ8 9992999?9U9p9:ƒ:¾:Î:é: ;_;p;«;Ç;"<-<[µ>º>°4#1C11š1­1u2›3”4Ý4y6ø7;7;D;B=¤>?:?U?`?d?i?À,t1x1|1€1„11”1Ü1à1ä1è1ì1ð1ô1ø122Ð$¨9¬9°9´9¸9¼9À9Ä9È9Ì9Ð9Ô9Ø9Ü9à9ä9è9ì9ð9ô9ø9ü9::: ::::: :$:(:,:0:4:8:<:@:D:H:L:P:T:X:\:`:d:h:l:p:t:x:|:€:„:ˆ:Œ::”:˜:œ: :¤:¨:¬:°:´:¸:¼:À:Ä:È:Ì:Ð:Ô:Ø:Ü:à:ä:è:ì:ð:ô:ø:ü:;;; ;;;;; ;$;== =$=t=x=ä=è=ø=ü=>> >$><>L>P>d>h>x>|>Œ>>˜>°>À>Ä>Ô>Ø>Ü>ä>ü>H?P?X?`?d?l?€?ˆ?œ?¸?Ô?Ø?ø?àˆ080X0x0˜0¸0Ä0à0ì01$1(1D1H1d1h1ˆ1¨1È1è1ô1 22,202P2p22¬2°2Ð2ð2303P3p33˜3¤3Ä3Ð3444,404@4d4p4x4¨4°4´4Ì4Ð4ì4ð4ø455 55(5ðø00 0à2ä2è2(7 8ˆ8˜8¨8¸8È8ì8ø8ü899999 9(9 ;¤;¨;´;¼;Ä;Ì;Ô;Ü;ä;ì;ô;ü;< <<<$<,<4<<>°>´> \0`0exiv2-0.23/msvc64/tools/bin/depends64.exe0000644000175000017500000022400011510453102017626 0ustar andreasandreasMZÿÿ¸@غ´ Í!¸LÍ!This program cannot be run in DOS mode. $óÚ7[·»Y·»Y·»Y¾ÃÝ»Y¾ÃÚë»Y¾Ã̽»Y}"°»Y·»XÝ»Y¾ÃÓ°»Y¾Ãȶ»YRich·»YPEd†š/!Mð"  Àd*@€’~@$P`´P( p`ÓÐè.text‚¿À `.rdataø;Ð<Ä@@.data07@À.pdata( P @@.rsrc´`"@@.relocºp$@B@SHƒì H‹ÙH‹IH…ÉtÿhÀH‹KH…ÉtÿiÀH‹ HƒùÿtÿZÀÇCHƒÄ [ÃÌÌÌÌÌÌÌÌÌÌÌÌÌ@SHƒì HƒyH‹ÙtpH‰t$0H‰|$8fDH‹CHƒxH‹0t%fH‹CH‹HH‹yH…Étè H‹CH‰xH…ÿuÝH‹KH…Étèïÿ H‰sH…öu´H‹|$8H‰sH‹t$0HƒÄ [ÃHÇAHƒÄ [ÃÌÌ@UVWHì°HÇD$xþÿÿÿH‰œ$àH‹UÿH3ÄH‰„$ H‹úH‰L$hHL$0è »‰\$PAƒÈÿD‰D$T3Ò‰T$XH‹l$@9T$L…¥»‰\$P‹L$Hƒù@‚ˆ¸MZf;Euv3Û‰\$Pfƒ}@sº‰T$XD‹Õën‹E<;ÁMD‹À‰D$TD‹T$@AÂD‹È·éLEtƒét ƒù uQúë ºëº¸A9PEDЉT$XëD‹T$@ëD‹T$@ë D‹T$@ëD‹T$@3öH‰t$`…Ûuƒút »‰\$Pë C4H‰t$`H…öu6H…ít H‹ÍÿX¾H‹L$8H…ÉtÿX¾H‹L$0HƒùÿtÿG¾‹Ã騹èVH…À„‘H‹×H‹Èè‚H‰D$pH…À„xH‹\$hH‹KH‰H‰Cÿƒ¾”u6H…ít H‹ÍÿÛ½H‹L$8H…ÉtÿÛ½H‹L$0Hƒùÿtÿʽ3Àé[D‹ŽE…É„ä·FHT0E3ÒE‹Â·FfD;ÐsWD·ØfD‹B‹J;ÁBÈD‹R A E;ÊrD;ÈrAÿÀHƒÂ(E;Ãs!ëÕ‹BA+ÂAÁƒøÿt ‹|$@ E3ÒëE3ÒëE3ÒI‹Ê‹|$@H…É„dHq ƒ>„$H‹l$`D‹·ELD(A‹Ò·EfD;ЃüD·ØA‹@A‹H;ÁBÈE‹P A E;ÊrD;ÈrÿÂIƒÀ(A;ÓƒÊëÐA‹@A+ÂAÁƒøÿ„µø„­H‹[H…Ût+fff„HSH‹Ïÿ¼…Àt H‹H…ÛuçëH…Ûu]H„$€H‰D$(H„$H‰D$ A¹E3ÀH‹×3Éÿâ»…ÀtH”$H‹\$hH‹Ëè‰üÿÿëH‹×H‹L$pè H‹\$hëH‹\$hHƒÆƒ>‹|$@Aº…çþÿÿH‹l$@H…ít H‹Íÿä»H‹L$8H…Étÿä»H‹L$0HƒùÿtÿÓ»3ÀëgH…ít H‹Íÿ±»H‹L$8H…Étÿ±»H‹L$0Hƒùÿtÿ »3Àë4H…ít H‹Íÿ~»H‹L$8H…Étÿ~»H‹L$0Hƒùÿtÿm»¸H‹Œ$ H3ÌèH‹œ$àHİ_^]ÃÌÌÌÌÌH‰t$ ATHƒì 3öƒùL‹â}3ÀH‹t$HHƒÄ A\ÃH‰\$0H‰l$8H‰|$@¿HcéH;ýÕI‹ü¶HëÙH‹Ëÿê¹…Àu ÇxëHÏÙH‹Ëÿʹ…Àu3Ç\HÿÇH;ýŒ+ÿÿÿ‹ÆH‹l$8H‹\$0H‹|$@H‹t$HHƒÄ A\ÃH ŒÙH‹Óè3ÀëÒÌÌÌÌÌÌÌÌ@WHƒì Hy…ÒtoHÙA¸H‹ÏH‰\$0H‰t$8è‡3ö…ÀHdÙDFH‹ßH‹ÏHDÞèiDF …ÀHPÙH‹ÏHDÞèP…ÀHDÞH‹t$8H‹ÃH‹\$0HƒÄ _ÃH‹ÇHƒÄ _ÃÌÌÌÌÌÌÌÌÌÌH‹ÄVWATHì`HÇD$8þÿÿÿH‰XH‰hH‹ùH3ÄH‰„$PH‹Úèçýÿÿ…Àu$L , D@@H‹H ÖØè)¸éfH‹=ÇD$0E3äD‰d$ L‰d$(H‹Ïèó H‹ØH…Àt_A‹ôAT$\H‹ÈèK H…Àt!@ˆ0At$HT$@¹ÿ>¸H‹Ëÿ¸H‹×HL$ èàøÿÿ‰D$0…öt HL$@ÿý·H‹ËèE ‹L$0…É„·…Ét3ƒét%ƒétƒùt L¶×ë"L×ëL„×ëLk×ëLR×H‹3H ü×è7H‹D$(H…ÀtQH‹8Hƒxt.fH‹HH‹YH…Ét èþ H‹D$(H‰XH…ÛtH‹D$(ëÙH‹D$(H‹ÈèÜ H‹ÇH‰D$(ÿL$ H…ÿu¯¸éI‹ôH‹D$(H…ötH‹6ëH‹ðH…ö„Ÿ‹µH‹ÎèI‹ÜfH…ÛtH‹[ëH‹^H…Ût¾H{ƒ=‰tRA¸HöÖHKè …ÀIDüA¸HâÖHKèñ …ÀIDüA¸ HÒÖHKèÕ …ÀtH…ÿtˆH‹×H îÖèétÿÿÿH…ÀtTH‹8Hƒxt1DH‹HH‹YH…Ét èÞ H‹D$(H‰XH…ÛtH‹D$(ëÙH‹D$(H‹Èè¼ H‹ÇH‰D$(ÿL$ H…ÿu¬3ÀH‹Œ$PH3Ìè9 Lœ$`I‹[ I‹k0I‹ãA\_^ÃÌ@SHìàH‹(öH3ÄH‰„$Ø‹wH‹ÙèWüÿÿH…À„zH ;ÖH‹ÐH‰¼$èG ƒ=8H»„Ÿ3ÒH‹ÏÿеHc؃ûÿ„ˆLL$HH‹ËE3À3Òÿ©µ…À„e3ÀHT$@HL$HÆ„$¸H‰„$¹H‰„$ÁH‰„$ɉ„$Ñf‰„$Õˆ„$׈„$˜H‰„$™H‰„$¡H‰„$©‰„$±f‰„$µˆ„$·ÿ4µ…ÀtZHT$0HL$@ÿµ…ÀtF·D$0D·L$6D·D$2HÖHŒ$ˆ‰D$ ÿJ·H”$ˆHŒ$¸A¸ ÿ¦´HT$@HL$HÿÆ´…ÀtZHT$0HL$@ÿš´…ÀtF·D$†+H^ ‹CøL;à‚§‹CüL;àƒ›ƒ{„‘ƒ;t‹HL$0H‹ÕIÇÿÐ…Àˆ„~sA}csmàu(Hƒ=Û¬tH Ò¬èå=…ÀtºI‹Íÿ»¬‹KA¸H‹ÕIÏèÿ<I‹F@‹SMcMH‰D$(I‹F(I×M‹ÅH‹ÍH‰D$ ÿ‡‹è=ÿÇHƒÃ;>sjé>ÿÿÿ3ÀëfI‹y 3íI+ÿ9.vTH^‹KôL;ár>‹CøL;às6H;ùr H;øsAöE u/ƒ;t ‹H;øt#ëH‹T$xIDZI‰D‹CüMÇAÿÐÿÅHƒÃ;.r°¸L\$@I‹[0I‹k@I‹sHI‹ãA_A^A]A\_ÃÌÌÌHaÒÃ@SHƒì ‹t»…Àu¸ë;ÃLÃHcȺ‰Qèè#H‰5ðH…Àu$PH‹Ë‰4èË#H‰ðH…Àu¸ëx3ÉHóÑH‰HƒÂ0HƒÁHƒët H‹êïëåE3ÀHêÑEHI‹ÈL íI‹ÀHÁøƒáI‹ÂHkÉXL‹Iƒúÿt IƒúþtM…ÒuÇþÿÿÿIÿÀHƒÂ0Iƒéu¼3ÀHƒÄ [ÃÌÌHƒì(è¯>€=¼ätè9<H‹ nïHƒÄ(éµÛÿÿÌ@SHƒì H‹ÙH DÑH;Ùr:HÈÔH;Øw.H‹ÓH¸«ªªªªªª*H+ÑH÷êHÁúH‹ÊHÁé?Lè,&ºkë HK0ÿƒ‰HƒÄ [ÃÌ@SHƒì ƒùH‹Ú}ƒÁèþ%ºkë HJ0ÿU‰HƒÄ [ÃÌÌÌHƒì(H¹ÐH;Êr7H=ÔH;Èw+ºqH+ÊH¸«ªªªªªª*H÷éHÁúH‹ÊHÁé?LèŸ$ë HƒÁ0ÿ‰HƒÄ(ÃÌÌHƒì(ƒù}ºrƒÁèv$ë HJ0ÿÚˆHƒÄ(ÃÌH‰\$H‰|$ATHƒì H‹Ùèä=‹Èèm=…À„—è°ýÿÿHƒÀ0H;Øu3ÀëèžýÿÿHƒÀ`H;Øuw¸ÿââ÷C ucL%ÚâHcøIƒ<üu+¹è!I‰üH…ÀuHC H‰CH‰¸‰C$‰CëI‹ üÇC$ÇCH‰KH‰ K¸ë3ÀH‹\$0H‹|$8HƒÄ A\ÃÌÌÌ…Ét0SHƒì ºb H‹ÚsH‹ÊèÙ:cÿîÿÿƒc$Hƒ#HƒcHƒÄ [ÃÌÌÌ@SHƒì öB@I‹Øt HƒzuAÿë&ƒBÿx H‹ˆHÿ¶Áë¾Éèò<ƒøÿu ëÿHƒÄ [ÃÌ…Ò~LH‰\$H‰l$H‰t$WHƒì I‹ùI‹ð‹Ú@ŠéL‹ÇH‹Ö@ŠÍÿËè…ÿÿÿƒ?ÿt…ÛçH‹\$0H‹l$8H‹t$@HƒÄ _ÃÌÌÌH‰\$H‰l$H‰t$WHƒì Aö@@I‹ùI‹ð‹ÚH‹ét IƒxuAë7…Ò~3ŠML‹ÇH‹ÖÿËèÿÿÿHÿŃ?ÿuè áÿÿƒ8*uL‹ÇH‹Ö±?èÿþÿÿ…ÛÍH‹\$0H‹l$8H‹t$@HƒÄ _ÃÌÌH‰\$UVWATAUAVAWHìÐH‹VÅH3ÄH‰„$È3ÀH‹ÙH‰L$hH‹úHL$xI‹ÐM‹é‰D$`D‹à‰D$TD‹ð‰D$H‰D$X‰D$PèÚÿÿE3ÒI;ÚuAèsàÿÿ3ÛE3ÉE3À3Ò3ÉÇH‰\$ è[âÿÿ8œ$tH‹„$ˆƒ ÈýƒÈÿéýAƒÏÿöC@L d´ÿÿ…ºH‹Ëè;H¯ÒA;Çt(ƒøþt#LcÀL ;´ÿÿI‹ÈAƒàHÁùMkÀXM„Éà4ë L‹ÂL ´ÿÿAö@8u)A;ÇtƒøþtHcÐH‹ÂƒâHÁøHkÒXI”Áà4öB8€tAè§ßÿÿ3ÛE3ÉE3À3Ò3ÉÇH‰\$ èáÿÿ8œ$tH‹„$ˆƒ ÈýA‹Çé1E3ÒI;út·@Š/A‹òD‰T$@D‰T$DA‹ÒL‰”$˜A:ê„êH‹œ$¨A»HÿÇA;òH‰¼$°ŒÈEàÔ„üÇ*ÔDˆ%Ô…Û…ÏH‹ °Þè÷çÿÿH‹ðH‰D$0H…À„ŸH‹ ‹ÞèÚçÿÿH‹øH‰D$ L‹öH‰t$(L‹èH‰D$8HƒïH‰|$ H;þr è£çÿÿH9uëæH;þr\H‹è›çÿÿH‹Øè‡çÿÿH‰ÿÓH‹ ;Þè‚çÿÿH‹ØH‹ $ÞèsçÿÿL;óuL;èt L‹óH‰\$(H‹óH‰\$0L‹èH‰D$8H‹øH‰D$ ë…HDzH %zè¼ýÿÿHAzH 2zè©ýÿÿE…ät ¹èõE…äu&ÇÓAL$èÜA‹Ïè ýÿÿA‹Ïÿ[xÌH‹\$pH‹t$xHƒÄ@A_A^A]A\_ÃÌÌE3À3ÒéjþÿÿÌÌE3ÀAPé\þÿÿ3Ò3ÉDBéOþÿÿÌÌ̺3ÉD‹Âé=þÿÿÌ@SHƒì è}æÿÿH‹ÈH‹Øè²ÙÿÿH‹Ëè*4H‹ËèÊÒÿÿH‹Ëè4H‹Ëè4H‹ËèZ1H‹ËèŽH‹Ëè.1H ÿÿÿè&æÿÿH‰ÇÂHƒÄ [ÃÌH‰\$H‰|$L‰l$ AVHƒì0L5´Â‹ù3ÛI‹Æ;t ÿÃHƒÀƒûrñƒûƒÔ¹èÇ5ƒø„|¹è´5…Àu ƒ=ᵄaÿü„šH=ÔÑA½L—€H‹ÏI‹Õè¬Óÿÿ…ÀtHƒd$ E3ÉE3À3Ò3ÉèãÑÿÿHµÑA¸3ÉÆªÒÿïv…Àu1L4€H ŽÑºûè[Óÿÿ…ÀtHƒd$ E3ÉE3À3Ò3Éè’ÑÿÿH dÑèvÔÿÿHÿÀHƒøÔL×HL8ÞA¹H+Ñè#…ÀtHƒd$ E3ÉE3À3Ò3Éè7ÑÿÿL I‹ÕH‹ÏèY"…ÀtHƒd$ E3ÉE3À3Ò3Éè ÑÿÿLcÃI‹ÕH‹ÏMÀO‹DÆè*"…ÀtHƒd$ E3ÉE3À3Ò3ÉèÝÐÿÿHA¸ H‹ÏèP2ëE¹ôÿÿÿÿÛuH‹øH…Àt2Hƒøÿt,HcÛHÛI‹LÞèÓÿÿI‹TÞHƒd$ LL$HL‹ÀH‹Ïÿ™uH‹\$@H‹|$PL‹l$XHƒÄ0A^ÃÌÌÌHƒì(¹èÖ3ƒøt¹èÇ3…Àuƒ=ô³u¹üè¤ýÿÿ¹ÿèšýÿÿHƒÄ(ÃÌÂÌH‰\$H‰l$H‰t$WHƒì H‹ò‹ùè‚äÿÿE3ÛH‹ØI;ÄŠH‹ˆ Lc¡ÁH‹Ñ9:tI‹ÀHƒÂHÁàHÁH;ÐréI‹ÀHÁàHÁH;Ðs9:tI‹ÓI;Ó„CL‹BM;Ä6Iƒøu L‰ZA@üé%IƒøuƒÈÿéH‹«¨H‰³¨‹Jƒù…èLc Á‹ ÁAÊM‹ÊD;Ñ}*IÁáH‹ƒ AÿÂIƒÁM‰\ø‹ ßÀ‹ÝÀÈD;Ñ|Ú:ŽÀ‹»°u ǃ°ƒëv:Àu ǃ°ëb:‘Àu ǃ°„ëN:“Àu ǃ°…ë::Àu ǃ°‚ë&:Àu ǃ°†ë:’Àu ǃ°Š‹“°¹AÿЉ»°ëL‰ZAÿÐH‰«¨éãþÿÿ3ÀH‹\$0H‹l$8H‹t$@HƒÄ _ÃÌÌH‰\$H‰l$H‰t$WHƒì0ƒ=ØuèÞÿÿH‹Ç3ÿH…ÛuƒÈÿéÉ<=tÿÇH‹ËèúÐÿÿH\Š„ÀuçGºHcÈè H‹øH‰eÍH…ÀtÀH‹AÇ€;teH‹Ëè¼Ðÿÿ€;=ptCHcîºH‹ÍèÐ H‰H…ÀtrL‹ÃH‹ÕH‹ÈèNÏÿÿ…ÀtHƒd$ E3ÉE3À3Ò3Éè…ÍÿÿHƒÇHcÆHØ€;u¢H‹ׯH‹Ëè'ÄÿÿHƒ%ÇÆHƒ'Ç‘×3ÀH‹\$@H‹l$HH‹t$PHƒÄ0_ÃH‹ ³ÌèîÃÿÿHƒ%¦ÌéÿÿÿÌH‹ÄH‰XH‰hH‰pH‰x ATAUAVHƒì L‹l$`M‹ñI‹øAƒeL‹âH‹ÙAÇH…ÒtL‰IƒÄ3í€;"u3À…í@¶"”ÀHÿËèë9AÿEH…ÿtŠˆHÿǶ3HÿËÎèí0…ÀtAÿEH…ÿtŠˆHÿÇHÿÃ@„öt…íu­@€þ t@€þ u¡H…ÿt ÆGÿëHÿË3ö€;„ã€; t€; uHÿÃëñ€;„ËM…ätI‰<$IƒÄAÿº3ÉëHÿÃÿÁ€;\tö€;"u6„Êu…ötHC€8"uH‹Øë 3À3Ò…ö”À‹ðÑéëÿÉH…ÿtÆ\HÿÇAÿE…Éu늄ÀtO…öu< tG< tC…Òt7¾Èè0H…ÿt…ÀtŠHÿÈHÿÇAÿEŠˆHÿÇë …ÀtHÿÃAÿEAÿEHÿÃéYÿÿÿH…ÿtÆHÿÇAÿEéÿÿÿM…ätIƒ$$AÿH‹\$@H‹l$HH‹t$PH‹|$XHƒÄ A^A]A\ÃÌH‰\$H‰t$ WHƒì0ƒ=’ÕuèÛÿÿH= ÎA¸3ÉH‹×ÆþÎÿÿtkHƒ>þteAöEt^AöEuH‹ÿ\lA;ÇtILcçI‹ÄHÁøAƒäMkäXM$ÆH‹I‰$AŠEAˆD$IL$º è(A;ÇtAÿD$ ëƒÈÿéÕÿÇIÿÅHƒÆ;û|‚E‹çI‹ÿH‹ßHkÛXHÍÎHƒ;ÿt Hƒ;þt€K€ëÆCAD$ÿ÷ØɃÁõ¸öÿÿÿE;çDÈÿzkH‹ðHƒøÿtJI;ÇtEH‹Èÿ£kA;Çt7H‰3¶Àƒøu€K@ë ƒøu€KHKº èn'A;ÇtÿC ëƒÈÿë.€K@HÇþÿÿÿAÿÄHÿÇHƒÿŒQÿÿÿ‹ Îÿ8k3ÀëƒÈÿLœ$I‹[ I‹s(I‹{0M‹c8I‹ãA_A^A]ÃÌÌÌH‰\$WHƒì HûH=ôëH‹H…ÀtÿÐHƒÃH;ßríH‹\$0HƒÄ _ÃH‰\$WHƒì HÓH=ÌëH‹H…ÀtÿÐHƒÃH;ßríH‹\$0HƒÄ _ÃH‰\$WHƒì H‹ë¨Hƒd$0H¿2¢ß-™+H;Çt H÷ÐH‰Ô¨ëvHL$0ÿ—jH‹\$0ÿ„jD‹ØI3ÛÿÈiD‹ØI3ÛÿdjHL$8D‹ØI3ÛÿKjL‹\$8L3ÛH¸ÿÿÿÿÿÿL#ØH¸3¢ß-™+L;ßLDØL‰^¨I÷ÓL‰\¨H‹\$@HƒÄ _Ã̃%¥ÌÃÌÌÌÌÌÌÌÌÌÌÌÌÌÌff„H‹ÁIƒørS¶ÒI¹I¯ÑIƒø@rH÷ÙƒátL+ÁH‰HÈM‹ÈIƒà?IÁéu9M‹ÈIƒàIÁétfffH‰HƒÁIÿÉuôM…Àt ˆHÿÁIÿÈuöÃ@fffffIùs0H‰H‰QH‰QHƒÁ@H‰QØH‰QàIÿÉH‰QèH‰QðH‰QøuØë”fDHÃHÃQHÃQHƒÁ@HÃQØHÃQàIÿÉHÃQèHÃQðHÃQøuÐð€ $éTÿÿÿÌÌ@SHƒì0H‹Ù¹èñH‹CH…ÀtDH‹ XÇH‰L$ HDÇH…ÉtH9uH‹AH‰Bèý¹ÿÿë H‹ÑH‰L$ ëÝH‹Kèè¹ÿÿHƒc¹è™HƒÄ0[ÃÌÌÌÌÌÌÌÌÌff„H+ÑL‹ÊöÁtŠBŠ :ÂuVHÿÁ„ÀtWH÷ÁuæI»J fâÿfúøwËH‹J‹ H;Âu¿Iºÿþþþþþþ~LÒHƒðÿHƒÁI3ÂI…ÃtÇëHÀHƒØÿÃ3ÀÃfff„Òt'„öt#HÁê„Òt„ötHÁê„Òt„öt Áê„Òt„öu‹3ÀÃHÀHƒØÿÃH‰\$H‰l$H‰t$WHƒì 3ÿH‹ñƒÍÿH‹ÎèPÄÿÿH‹ØH…Àu(9Æv ‹ÏÿgDŸèD;ÆA‹ûGý;ýuÈH‹l$8H‹t$@H‹ÃH‹\$0HƒÄ _ÃH‹ÄH‰XH‰hH‰pH‰x ATHƒì 3ÿH‹òH‹éAƒÌÿE3ÀH‹ÖH‹Íè &H‹ØH…Àu*9£Åv"‹Ïÿ™fDŸèD;‹ÅA‹ûAGüA;üuÀH‹l$8H‹t$@H‹|$HH‹ÃH‹\$0HƒÄ A\ÃÌH‹ÄH‰XH‰hH‰pH‰x ATHƒì 3öH‹úH‹éAƒÌÿH‹×H‹Íè<&H‹ØH…Àu/H…ÿt*9Åv"‹ÎÿfDžèD;ÅA‹óAGôA;ôu¾H‹l$8H‹t$@H‹|$HH‹ÃH‹\$0HƒÄ A\ÃÌÌÌHƒì8H…Éu&èî¿ÿÿHƒd$ E3ÉE3À3Ò3ÉÇè×ÁÿÿHƒÈÿëL‹ÁH‹ ¿3Òÿ/fHƒÄ8ÃÌÌH‰\$H‰t$H‰|$ATHƒì L%¤²3ö3ÿI‹Üƒ{u%Hcƺ ÿÆH €HbÄH ÈH‰ èž!…Àt-H«´HƒÃÿÇH;Ø|øH‹\$0H‹t$8H‹|$@HƒÄ A\ÃHcÇHÀIƒ$Ä3ÀëÛÌÌH‰\$H‰l$H‰t$WHƒì H²H-R´H‹ûH‹7H…ötƒtH‹Îÿ8eH‹Î耶ÿÿHƒ'HƒÇH;ý|ÔH‹ H…Ét ƒ{uÿeHƒÃH;Ý|ãH‹\$0H‹l$8H‹t$@HƒÄ _ÃÌHcÉH¦±HÉH‹ ÈHÿ%XdH‰\$H‰t$H‰|$AUHƒì HcÙ¾Hƒ=3¾uèÔîÿÿNè¤ìÿÿ¹ÿèéÿÿH‹ûHÿL-M±Iƒ|ýt‹Æë{¹(è·üÿÿH‹ØH…Àuè¾ÿÿÇ 3ÀëZ¹ èfIƒ|ýu/º H‹Ëè( …ÀuH‹Ë脵ÿÿèã½ÿÿÇ 3öëI‰\ýë H‹ËèfµÿÿH‹ n±ÿˆc‹ÆH‹\$0H‹t$8H‹|$@HƒÄ A]ÃH‰\$WHƒì HcÙH=œ°HÛHƒ<ßuèõþÿÿ…ÀuHèÙçÿÿH‹ ßH‹\$0HƒÄ _Hÿ%$cÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌff„L‹ÙH+Ñ‚žIƒøraöÁt6öÁt Š IÿȈHÿÁöÁtf‹ Iƒèf‰HƒÁöÁt ‹ Iƒè‰HƒÁM‹ÈIÁéuQM‹ÈIÁétH‹ H‰HƒÁIÿÉuðIƒàM…ÀuI‹ÃÃ@Š ˆHÿÁIÿÈuóI‹ÃÃfffffff„fffffIù sBH‹ L‹T HƒÁ H‰AàL‰QèH‹D ðL‹T øIÿÉH‰AðL‰QøuÔIƒàéqÿÿÿfff„fHúrµ¸  D @HÁ€ÿÈuìHé¸@L‹ L‹T Là LÃQL‹L L‹T LÃILÃQL‹L L‹T (HƒÁ@LÃIàLÃQèL‹L ðL‹T øÿÈLÃIðLÃQøuªIèIøƒqÿÿÿð€ $é¹þÿÿffff„fffffffIÈIƒøraöÁt6öÁt HÿÉŠ IÿȈöÁtHƒéf‹ Iƒèf‰öÁt Hƒé‹ Iƒè‰M‹ÈIÁéuPM‹ÈIÁétHƒéH‹ IÿÉH‰uðIƒàM…ÀuI‹ÃÃHÿÉŠ IÿȈuóI‹ÃÃfffffff„fffffIù sBH‹D øL‹T ðHƒé H‰AL‰QH‹D L‹ IÿÉH‰AL‰uÕIƒàésÿÿÿffff„fHúðÿÿwµ¸ Hé€ D @ÿÈuìHÁ¸@L‹L øL‹T ðLÃIøLÃQðL‹L èL‹T àLÃIèLÃQàL‹L ØL‹T ÐHƒé@LÃILÃQL‹L L‹ ÿÈLÃILÃuªIèIøƒqÿÿÿð€ $éºþÿÿ@SHƒì E‹H‹ÚL‹ÉAƒãøAöL‹ÑtA‹@McP÷ØLÑHcÈL#ÑIcÃJ‹H‹C‹HHKöAt ¶AƒàðH˜LÈL3ÊI‹ÉHƒÄ [é)±ÿÿÌHƒì(M‹A8H‹ÊI‹Ñè‰ÿÿÿ¸HƒÄ(ÃÌÌÌ@UATAUAVAWHƒì`Hl$@H‰]PH‰uXH‰}`H‹úH3ÅH‰ED‹tÀ¾3ÿM‹ÙL‰MD‰ED‹ò‰UH‹ÙDnÿD;×uOLYiE‹Íº3ɉ|$(H‰|$ ÿ _;Çt E‹ÕD‰-"Àëÿâ]D‹ÀƒøxDDÖD‰ÀL‹]D‹MpD;Ï~5A‹ÉI‹ÃA+Í@88t IÅ;ÏuñƒÉÿA‹Á+ÁA+ÅA;Á} DHD‰MpëD‹È‰EpD;Ö„\D;ׄSE;Õ…€D‹¥ˆ‹÷D;çuH‹D‹`÷M‹ÃA‹ÌÒ‰|$(H‰|$ ƒâAÕÿØ^LcøD;ÿ„<H»ðÿÿÿÿÿÿA¾ÝÝA½~[3ÒHBàI÷÷HƒørLKL?I;Íw.HAH;ÁwH‹ÃHƒàðè>VH+àH|$@H…ÿ„åÇÌÌëèäºÿÿH‹øH…ÀtD‰0HƒÇH…ÿ„ÀD‹MpL‹EºA‹ÌD‰|$(H‰|$ ÿ0^3É;Á„K‹U‰L$(H‰L$ ‹ME‹ÏL‹Çÿ^E3ÀHcðA;ð„!D‹UAºâ s;‹…€A;À„;ðÿ‹M‰D$(H‹ExE‹ÏL‹ÇA‹ÒH‰D$ ÿÃ]éÛA;ð~`3ÒHBàH÷öHƒørQHL6I;Íw*HAH;ÁwH‹ÃHƒàðè;UH+àH\$@I;ØtÇÌÌëèå¹ÿÿE3ÀH‹ØI;ÀtD‰0HƒÃD‹UëI‹ØI;Øtn‹ME‹ÏL‹ÇA‹Ò‰t$(H‰\$ ÿ6]3É;Át?‹…€3ÒH‰L$8D‹ÎL‹ÃH‰L$0;Áu ‰L$(H‰L$ ë ‰D$(H‹ExH‰D$ A‹Ìÿ‹\‹ðHKðD91uèó­ÿÿHOðD91uèå­ÿÿ‹ÆéÍH‹÷L‹çD;÷u H‹D‹pD‰u‹½ˆ…ÿuH‹‹xA‹ÎèÐD‹èƒøÿu3ÀéL‹}xL‹E;Ç„<3ÛLMp‹Ð‹Ï‰\$(H‰\$ èíH‹ðH;ÃtÉD‹Mp‹UL‹ÀA‹Î‰\$(H‰\$ ÿ5\LcÈD‰MD;Ëu‹ûéD;ËA¾ÝÝ~bI‹ÉIƒùàwYHƒÁHùw4HYH;Ùw H»ðÿÿÿÿÿÿHƒãðH‹Ãè¢SH+ãH\$@H…Ût%ÇÌÌëèL¸ÿÿH‹ØH…ÀtD‰0HƒÃD‹MH…Ûu3ÛëƒMcÁ3ÒH‹ËèñÿÿD‹]D‹Mp‹U‹MD‰\$(L‹ÆH‰\$ ÿ~[‰E…Àu3ÿë.‹…€LML‹Ã‰D$(‹×A‹ÍL‰|$ èç‹}L‹à3ÀL;àDøHKðD91u(èW¬ÿÿë!‹…€D‹Mp‹U‰D$(A‹ÎL‰|$ ÿ[‹ø3ÛH;ótH‹Îè%¬ÿÿL;ãt M;ütI‹Ìè¬ÿÿ‹ÇH‹MH3Íèå«ÿÿH‹]PH‹uXH‹}`He A_A^A]A\]ÃÌÌÌH‰\$H‰t$WHƒìp‹òH‹ÑHL$PI‹ÙA‹øè°­ÿÿ‹„$¸D‹œ$ÀHL$PD‰\$@‰D$8‹„$°‰D$0H‹„$¨L‹ËH‰D$(‹„$ D‹Ç‹Ö‰D$ èOúÿÿ€|$ht H‹L$`ƒ¡ÈýL\$pI‹[I‹sI‹ã_ÃÌÌD‰L$ UATAUAVAWHƒì@Hl$0H‰]@H‰uHH‰}PH‹˜H3ÅH‰ED‹ œº¿3ÛM‹ðD‹úL‹éwD;Ëu=LMH…cD‹Ç‹ÏÿêY;Ãt‰=dºë6ÿ XD‹ UºƒøxDDÎD‰ GºD;΄&D;Ë„D;Ï…C‹uh;óuI‹E‹p÷]xD‹MXM‹ÆҋΉ\$(ƒâH‰\$ ×ÿ`YLcàD;ã„A½ÝÝ~hH¸ðÿÿÿÿÿÿL;àwYKL$Hùw5HAH;Áw H¸ðÿÿÿÿÿÿHƒàðèËPH+àH|$0H;û„µÇÌÌëèqµÿÿH‹øH;Ãt D‰(HƒÇëH‹ûH;û„‹M‹Ä3ÒH‹ÏMÀè°îÿÿD‹MXM‹Æº‹ÎD‰d$(H‰|$ ÿªX;ÃtL‹M`D‹ÀH‹×A‹Ïÿ«X‹ØHOðD9)u蛩ÿÿ‹ÃéˆD‹epH‹ûD;ãuI‹ED‹`‹uh;óuI‹E‹pA‹Ì芃øÿu3ÀëU;Æt$LMXM‹Æ‹Ð‹Î‰\$(H‰\$ è¸H‹øH;Ãt×L‹ðH‹E`D‹MXM‹ÆA‹×A‹ÌH‰D$ ÿX‹ðH;ûtH‹Ïè©ÿÿ‹ÆH‹MH3Íèà¨ÿÿH‹]@H‹uHH‹}PHeA_A^A]A\]ÃÌÌH‰\$H‰t$WHƒì`‹òH‹ÑHL$@A‹ÙI‹øè¬ªÿÿ‹„$ D‹œ$¨HL$@D‰\$8‰D$0‹„$˜‰D$(H‹„$D‹ËL‹Ç‹ÖH‰D$ è.ýÿÿ€|$Xt H‹L$Pƒ¡ÈýH‹\$pH‹t$xHƒÄ`_ÃÌÌÌH…É„àSHƒì H‹ÙH‹Iè>¨ÿÿH‹Kè5¨ÿÿH‹Kè,¨ÿÿH‹K è#¨ÿÿH‹K(è¨ÿÿH‹K0è¨ÿÿH‹ è ¨ÿÿH‹K@è¨ÿÿH‹KHè÷§ÿÿH‹KPèî§ÿÿH‹KXèå§ÿÿH‹K`èܧÿÿH‹KhèÓ§ÿÿH‹K8èʧÿÿH‹KpèÁ§ÿÿH‹Kx踧ÿÿH‹‹€è¬§ÿÿH‹‹ˆè §ÿÿH‹‹è”§ÿÿH‹‹˜èˆ§ÿÿH‹‹ è|§ÿÿH‹‹¨èp§ÿÿH‹‹°èd§ÿÿH‹‹¸èX§ÿÿH‹‹ÀèL§ÿÿH‹‹Èè@§ÿÿH‹‹Ðè4§ÿÿH‹‹Øè(§ÿÿH‹‹àè§ÿÿH‹‹èè§ÿÿH‹‹ðè§ÿÿH‹‹øèø¦ÿÿH‹‹èì¦ÿÿH‹‹èà¦ÿÿH‹‹èÔ¦ÿÿH‹‹èȦÿÿH‹‹ 輦ÿÿH‹‹(è°¦ÿÿH‹‹0褦ÿÿH‹‹8蘦ÿÿH‹‹@茦ÿÿH‹‹H耦ÿÿH‹‹Pèt¦ÿÿHƒÄ [ÃÌÌH…ÉtBSHƒì H‹ÙH‹ H; •¥tèN¦ÿÿH‹KH; ‹¥tè<¦ÿÿH‹KH; ¥tè*¦ÿÿHƒÄ [ÃH…É„‹SHƒì H‹ÙH‹IH; `¥tè¦ÿÿH‹K H; V¥tèï¥ÿÿH‹K(H; L¥tèÝ¥ÿÿH‹K0H; B¥tèË¥ÿÿH‹K8H; 8¥tè¹¥ÿÿH‹K@H; .¥tè§¥ÿÿH‹KHH; $¥tè•¥ÿÿHƒÄ [ÃÌÌÌ@SHƒì0L‹ÉH…Ét H…ÒtM…Àu,DˆèЭÿÿ»Hƒd$ E3ÉE3À3Ò3ɉ踯ÿÿ‹ÃHƒÄ0[À9t HÿÁHƒêuòH…ÒuAˆë¿AŠIÿÀˆHÿÁ„ÀtHƒêuëH…ÒuAˆèr­ÿÿ»"ë 3ÀëµÌÌÌ@SHƒì0M‹ØM…ÉuH…ÉuH…Òu 3Àë?H…ÉtH…ÒtM…ÉuDˆ ëèM…Àu,Dˆè'­ÿÿ»Hƒd$ E3ÉE3À3Ò3ɉè¯ÿÿ‹ÃHƒÄ0[ÃL‹ÑL‹ÂIƒùÿuAŠIÿÃAˆIÿ„Àt,Iƒèuêë$AŠIÿÃAˆIÿ„Àt IƒètIƒéuäM…ÉuEˆ M…À…fÿÿÿIƒùÿu DˆDÿA@Pë˜Æ虬ÿÿ»"émÿÿÿÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌff„H+ÑIƒør"öÁtfŠ: u,HÿÁIÿÈöÁuîM‹ÈIÁéuM…ÀtŠ: u HÿÁIÿÈuñH3ÀÃÀƒØÿÃIÁét7H‹H; u[H‹AH;D uLH‹AH;D u=H‹AH;D u.HƒÁ IÿÉuÍIƒàM‹ÈIÁét›H‹H; uHƒÁIÿÉuîIƒàëƒHƒÁHƒÁHƒÁH‹ HÈHÉH;ÁÀƒØÿÃÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌff„M…ÀtuH+ÑL‹ÊI»öÁtŠBŠ HÿÁ:ÂuWIÿÈtN„ÀtJH÷ÁuáJ fâÿfúøwÑH‹J‹ H;ÂuÅHƒÁIƒèIºÿþþþþþþ~vHƒðÿLÒI3ÂI…ÃtÁë H3ÀÃHÀHƒØÿÄÒt'„öt#HÁê„Òt„ötHÁê„Òt„öt Áê„Òt„öuˆH3ÀÃÌÌÌ@SHƒì@‹ÙHL$ èR¤ÿÿH‹D$ D¶ÛH‹ˆ@B·Y%€€|$8t H‹L$0ƒ¡ÈýHƒÄ@[ÃÌÌÌ@SHƒì@‹ÙHL$ 3Òè¤ÿÿH‹D$ D¶ÛH‹ˆ@B·Y%€€|$8t H‹L$0ƒ¡ÈýHƒÄ@[ÃÌH‰l$H‰t$WHƒì`Hcù‹êHL$@I‹Ðè³£ÿÿD_AûwH‹D$@H‹ˆ@·y韋÷HT$@Áþ@¶Îèÿÿÿº…Àt@ˆ´$ˆ@ˆ¼$‰Æ„$ŠDJë@ˆ¼$ˆÆ„$‰D‹ÊH‹L$@‰T$8L„$ˆ‹A‰D$0‹AHL$@‰D$(HD$pH‰D$ èAøÿÿ…Àu8D$Xt H‹D$Pƒ Èý3Àë·D$p#Å€|$Xt H‹L$Pƒ¡ÈýL\$`I‹kI‹s I‹ã_ÃÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌff„HìØM3ÀM3ÉH‰d$ L‰D$(è *HÄØÃÌÌÌÌÌÌfDH‰L$H‰T$D‰D$IÇÁ “ëÌÌÌÌÌÌfÃÌÌÌÌÌÌf„ÃÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌH‹Á¹MZf9t3ÀÃHcHH‹ £H;Ït2臰ÿÿH…Àt(ÿÐH‹ØH…ÀtH‹ …£H;Ïtèg°ÿÿH…ÀtH‹ËÿÐH‹ØH‹ W£èN°ÿÿH…ÀtD‹ÍM‹ÅI‹ÖH‹ËÿÐë3ÀH‹\$pH‹l$xHƒÄ@A^A]A\_^ÃHƒì8…Éx ƒù~ ƒùu‹ä•ë1‹Ü•‰ Ö•ë#è{›ÿÿHƒd$ E3ÉE3À3Ò3ÉÇèdÿÿƒÈÿHƒÄ8ÃH‰\$H‰t$WHƒì@‹ÚH‹ÑHL$ A‹ùA‹ðè¼”ÿÿH‹D$(D¶ÛA„|u…ötH‹D$ H‹ˆ@B·Y#Æë3À…Àt¸€|$8t H‹L$0ƒ¡ÈýH‹\$PH‹t$XHƒÄ@_ÃÌ‹ÑA¹E3À3ÉérÿÿÿÌÌH‰\$WHƒì0I‹ØH‹úH…Ét23ÒHBàH÷ñH;Çs$è šÿÿHƒd$ E3ÉE3À3Ò3ÉÇ è‰œÿÿ3Àë]H¯ù¸H…ÿHDø3ÀHƒÿàwH‹ .šPL‹Çÿ¢?H…Àu-ƒ=ŸtH‹Ïèô¡ÿÿ…ÀuËH…Ût²Ç ëªH…ÛtÇ H‹\$@HƒÄ0_ÃÌH‰\$H‰t$WHƒì H‹ÚH‹ùH…Éu H‹ÊèöœÿÿëjH…Òu膑ÿÿë\HƒúàwCH‹ §™¸H…ÛHDØL‹Ç3ÒL‹Ëÿ}@H‹ðH…Àuo9{žtPH‹Ëè]¡ÿÿ…Àt+Hƒûàv½H‹ËèK¡ÿÿè’™ÿÿÇ 3ÀH‹\$0H‹t$8HƒÄ _Ãèu™ÿÿH‹ØÿP>‹Èè™ÿÿ‰ëÕè\™ÿÿH‹Øÿ7>‹Èè™ÿÿ‰H‹Æë»ÌHƒì8H‹Í}H3ÄH‰D$(LD$ A¹ºÆD$&ÿº?…ÀuƒÈÿë HL$ èŸH‹L$(H3ÌèrÿÿHƒÄ8ÃÌ@USVWATAUAVAWHìˆHl$@H‹d}H3ÅH‰E0L‹µ°E‹!3ÿI‹ØH‹÷‰}L‰MD‹êD‹ùH‰];Ê„HUÿø=;Ç„Ÿƒ}…•HUA‹ÍÿÙ=;Ç„€ƒ}uzÇEAƒüÿt`A‹ü…ÿŽ©HcÏH¸ðÿÿÿÿÿÿH;ȇ“HL HùwlHAH;Áw H¸ðÿÿÿÿÿÿHƒàðèK6H+àH\$@H…Ût<ÇÌÌëNH‹Ëè¾›ÿÿxë–E‹ÌL‹ÃºA‹Ï‰|$(H‰|$ ÿT>‹ø…À…oÿÿÿ3Àé7躚ÿÿH‹ØH…ÀtÇÝÝHƒÃë3ÛH…ÛtÙLcÇ3ÒH‹ËMÀèûÓÿÿL‹EE‹ÌºA‹Ï‰|$(H‰\$ ÿõ=E3ÿA;Ç„ÉM;÷t;‹…¸L‰|$8L‰|$0‰D$(D‹ÏL‹Ã3ÒA‹ÍL‰t$ ÿZ=A;Ç„‘I‹öé‰D9}u,L‰|$8L‰|$0D‹ÏL‹Ã3ÒA‹ÍD‰|$(L‰|$ ÿ=‹øA;ÇtWHc×¹èÞÕÿÿH‹ðI;ÇtBL‰|$8L‰|$0D‹ÏL‹Ã3ÒA‹Í‰|$(H‰D$ ÿÞ<A;Çu H‹ÎèIŽÿÿI‹÷ë AƒüÿtH‹M‰HKð9ÝÝuè'ŽÿÿH‹ÆH‹M0H3ÍèøÿÿHeHA_A^A]A\_^[]ÃÌÌÌÌÌÌÌ3ÒDB éaÌH‰\$WHƒì0ƒÏÿH‹ÙH…Éu#è>–ÿÿH!\$ E3ÉE3À3Ò3ÉÇè(˜ÿÿ ÇëFöAƒt:èÕîÿÿH‹Ë‹øè»H‹Ëè÷ðÿÿ‹Èè”…ÀyƒÏÿëH‹K(H…Ét èÿÿHƒc(ƒc‹ÇH‹\$@HƒÄ0_ÃÌÌÌH‰\$H‰L$WHƒì0H‹ÙƒÏÿ3ÀH…É•À…Àu$覕ÿÿÇHƒd$ E3ÉE3À3Ò3Éè—ÿÿ‹Çë&öA@tƒaëè^±ÿÿH‹Ëèÿÿÿ‹øH‹ËèÛ±ÿÿ‹ÇH‹\$HHƒÄ0_ÃÌÌH‰\$ UVWATAUAVAW¸0èv3H+àH‹ÄyH3ÄH‰„$ 3í3ÿE‹èL‹âHcÙ‰l$@E…Àu3ÀéçH…Òu.è•ÿÿ!8è÷”ÿÿH!|$ E3ÉE3À3Ò3ÉÇèá–ÿÿƒÈÿé´L‹ûL‹óHäIÁþAƒçJ‹ ðL‰t$PMkÿXAŠt8@ö@Ðþ@€þt@€þu A‹Å÷ШtAöD t 3Ò‹ËDBèÒ‹Ëèûîÿÿ…À„ñH„J‹ðAöD€„Úè3ªÿÿ3ÛHT$XH‹ˆÀHZ9YJ‹ ðI‹ ”Ãÿö:…À„¤…Ût @„ö„—ÿÓ:!|$LI‹Ü‰D$XE…í„wD‹t$X½ @„ö…ƒH‹T$PŠ E3ö€ù H-ðœH‹TÕA”ÆAƒ|Pt AŠDLˆL$]A¸ˆD$\AƒdPHT$\ëI¾Éèéÿÿ…Àt4I‹ÅH+ÃIÄHƒøŽÏHL$DA¸H‹Óèáƒøÿ„vHÿÃëA¸H‹ÓHL$DèÀƒøÿ„UHƒd$8Hƒd$0‹L$XHD$\LD$DA¹3ÒÇD$(HÿÃH‰D$ ÿ39‹è…À„H‹D$PHƒd$ H œH‹ ÁLL$LHT$\I‹ D‹ÅÿÌ8…À„B‹ûA+ü|$@9l$LŒË½ E…ö„¯H‹D$PHƒd$ @ˆl$\H ´›LL$LDEôH‹ ÁHT$\I‹ ÿp8…À„æƒ|$L|{ÿD$@ÿÇëe@€þt@€þu·E3öfƒø f‰D$DA”ÆHƒÃ@€þt@€þu6·L$Dèf;D$D…“ƒÇE…öt‹Íf‰l$Dèõ f;D$DuxÿÇÿD$@‹ÃA+ÄA;Å‚þÿÿ‹\$LL‹t$P‹l$@…ÿ…¸…Û„zƒû…eèÇ‘ÿÿÇ èÜ‘ÿÿ‰éØüÿÿŠL‹t$PÿÇJ‹LõAˆDLJ‹DõAÇDP‹\$Lë¥ÿl6‹Øë–‹\$Lë¡H“šJ‹ ðAöD€„Ê3ÛI‹ì@„ö…ÐE…í„üS D‹t$@H´$ 3É‹ÅA+ÄA;Ås&ŠEHÿÅ< u ˆAÿÆHÿÆHÿÁHÿÁˆHÿÆHùÿrÐH!\$ H„$ D‹ÆD+ÀHšD‰t$@L‹t$PLL$HH”$ J‹ ðI‹ ÿÃ6…Àt5|$HH„$ H+ðHcD$HH;ÆŒÅþÿÿ‹Åº A+ÄA;Å‚Nÿÿÿé­þÿÿÿt5‹Øé þÿÿ@€þ…ÔE…í„"º D‹t$@H´$ 3É‹ÅA+ÄA;Ås1·EHƒÅfƒø uf‰AƒÆHƒÆHƒÁHƒÁf‰HƒÆHùþrÅH!\$ H„$ D‹ÆD+ÀH)™D‰t$@L‹t$PLL$HH”$ J‹ ðI‹ ÿÜ5…À„Jÿÿÿ|$HH„$ H+ðHcD$HH;ÆŒÚýÿÿ‹Åº A+ÄA;Å‚?ÿÿÿéÂýÿÿE…í„NA¸ HL$p3Ò‹ÅA+ÄA;Ås.·EHƒÅfƒø u fD‰HƒÁHƒÂHƒÂf‰HƒÁHú¨rÈHƒd$8Hƒd$0HD$p+ÈLD$pÇD$(U ‹Á¹éý™+Â3ÒÑøD‹ÈH„$ H‰D$ ÿ=5D‹ð…À„€ýÿÿ3öH‹D$PHƒd$ HcÎH” E‹ÆH ˜H‹ ÁLL$HD+ÆI‹ ÿÊ4…Àt t$HD;ö½ëÿ¥3‹ØD;öÈüÿÿ‹ýA¸ A+üA;ý‚ÿÿÿé¯üÿÿI‹ H!|$ LL$HE‹ÅI‹Ôÿw4…Àt ‹|$H3ÛéüÿÿÿR3‹Øé‚üÿÿ‹Ëè Žÿÿé~ùÿÿHp—J‹ðAöD@t A€<$„.ùÿÿè8ŽÿÿÇèMŽÿÿƒ éHùÿÿ+ý‹ÇH‹Œ$ H3Ìè…ÿÿH‹œ$ˆHÄ0A_A^A]A\_^]ÃÌÌH‰\$H‰t$‰L$WATAUAVAWHƒì0E‹àL‹êHcÙƒûþuèæÿÿ3ÿ‰8è½ÿÿÇ ƒÈÿéÔ3ÿ;ߌ¡;›–ƒ•H‹óL‹óIÁþL=¤–ƒæHköXK‹÷¾L0ƒáu+èŽÿÿ‰8ègÿÿÇ H‰|$ E3ÉE3À3Ò3ÉèQÿÿƒÈÿëm‹Ëèé K‹÷öD0tE‹ÄI‹Õ‹ËèÔ÷ÿÿ‹øëèÿÿÇ è4ÿÿ‰8ƒÏÿ‹ËèX ‹Çë)èÿÿ‰8èøŒÿÿÇ H‰|$ E3ÉE3À3Ò3ÉèâŽÿÿƒÈÿH‹\$hH‹t$pHƒÄ0A_A^A]A\_ÃÌÌÌH‰\$‰L$VWATHƒì0Hcùƒÿþu袌ÿÿÇ ƒÈÿéمɈ®;=‚•ƒ¢H‹ßH‹÷HÁþL%‹•ƒãHkÛXI‹ô¾Lƒáu%èUŒÿÿÇ Hƒd$ E3ÉE3À3Ò3Éè>ŽÿÿƒÈÿëz‹ÏèÖ I‹ôöDt+‹Ïè? H‹Èÿæ2…Àu ÿì0‹Øë3Û…ÛtèŒÿÿ‰èò‹ÿÿÇ ƒËÿ‹Ïè2 ‹Ãë#èÙ‹ÿÿÇ Hƒd$ E3ÉE3À3Ò3ÉèÂÿÿƒÈÿH‹\$`HƒÄ0A\_^ÃÌH‰\$WHƒì HcÙA‹øH‰T$8‹Ëè´ Hƒøÿuè…‹ÿÿÇ HƒÈÿëW‹T$8LD$+¹èà³ÿÿÌÌÌÌH‰\$WHƒì Hcù‹Ïè4HƒøÿtYH‹¹ƒÿu @„¸¸u ;ùuö@`tè¹H‹ØèøH;Ãt‹ÏèìH‹Èÿ‹*…Àu ÿ™*‹Øë3Û‹Ïè L‹ßH‹ÏHÁùAƒãH¯ŽH‹ ÊMkÛXBÆD…Ût ‹Ë躅ÿÿƒÈÿë3ÀH‹\$0HƒÄ _ÃH‰\$H‰t$ ‰L$WATAUHƒì0HcÙƒûþuèd…ÿÿ3ÿ‰8è;…ÿÿÇ ƒÈÿéÉ3ÿ;ߌ–;ŽƒŠH‹óL‹ãIÁüL-"ŽƒæHköXK‹Då¾L0ƒáu+è …ÿÿ‰8èä„ÿÿÇ H‰|$ E3ÉE3À3Ò3ÉèΆÿÿƒÈÿëa‹ËèfK‹DåöD0t ‹Ëè†þÿÿ‹øëè¡„ÿÿÇ ƒÏÿ‹Ëèá‹Çë)訄ÿÿ‰8è„ÿÿÇ H‰|$ E3ÉE3À3Ò3Éèk†ÿÿƒÈÿH‹\$`H‹t$hHƒÄ0A]A\_Ã@SHƒì öAƒH‹Ùt"öAtH‹IèÎ{ÿÿc÷ûÿÿ3ÀH‰H‰C‰CHƒÄ [ÃÌHƒìhH‹¡hH3ÄH‰D$Pƒ=Æ|f‰L$@tfH‹ Ä|Hƒùþu è]H‹ ²|Hƒùÿ„¹Hƒd$ LL$DHT$@A¸ÿŒ(…À…‰ƒ=q|…ˆÿ(ƒøxu}ƒ%Y|ÿg(Hƒd$8Hƒd$0‹ÈHD$HLD$@A¹3ÒÇD$(H‰D$ ÿ|)H‹ %|Hƒùÿt0Hƒd$ LL$DHT$HD‹Àÿ*…Àtf‹D$@ëÇå{ëí¸ÿÿH‹L$PH3Ìè…zÿÿHƒÄhÃH‰\$H‰l$H‰t$WHƒìP3íI‹ðH‹úH‹ÙH;ÕtL;Åt @8*uH;Ítf‰)3ÀH‹\$`H‹l$hH‹t$pHƒÄP_ÃHL$0I‹Ñè2|ÿÿL‹\$0A9ku%H;Ýt¶f‰@8l$Ht H‹D$@ƒ Èý¸ë®¶HT$0è‘×ÿÿ;Å„œH‹L$0D‹‰ Aƒù~0A;ñ|+‹I‹ÅH;Ý•ÀL‹Çº ‰D$(H‰\$ ÿ°(H‹L$0;ÅuHc H;ðr(@8ot"‹ @8l$H„4ÿÿÿH‹L$@ƒ¡Èýé#ÿÿÿèêÿÿÇ*@8l$Ht H‹D$@ƒ ÈýƒÈÿéýþÿÿ‹ÅA¹H;Ý•ÀAQL‹Ç‰D$(H‹D$0H‰\$ ‹Hÿ!(;Å…ÿÿÿë¤ÌÌÌE3Éé„þÿÿH‰\$H‰l$WHƒì …Éxs; kŠskHcÙH-ŠH‹ûƒãHÁÿHkÛXH‹DýöDtGHƒ<ÿt@ƒ=Ëeu)…Étƒét ƒùu¹ôÿÿÿë ¹õÿÿÿë¹öÿÿÿ3ÒÿT%H‹DýHƒ ÿ3Àëèý€ÿÿÇ èÿÿƒ ƒÈÿH‹\$0H‹l$8HƒÄ _ÃHƒì8ƒùþuèî€ÿÿƒ èÆ€ÿÿÇ ë]…Éx1; °‰s)HcÑH ĉH‹ÂƒâHÁøHkÒXH‹ÁöDtH‹ë,褀ÿÿƒ è|€ÿÿHƒd$ E3ÉE3À3Ò3ÉÇ èe‚ÿÿHƒÈÿHƒÄ8ÃH‹ÄH‰XH‰pH‰xL‰` AUHƒì HcÙL‹ãIÁüL-J‰ƒãHkÛXK‹t心|3 u3O èjÂÿÿƒ|3 uHL3º è+âÿÿ÷ØÒ#úÿD3 ¹ è?Áÿÿ…ÿtK‹LåHLÿ“%‹ÇH‹\$0H‹t$8H‹|$@L‹d$HHƒÄ A]ÃÌÌHcÑH ˆH‹ÂƒâHÁøHkÒXH‹ÁHLHÿ%T%HƒìHHƒd$0ƒd$(A¸H XCE3ɺ@D‰D$ ÿý#H‰&xHƒÄHÃÌHƒì(H‹ xHƒùÿt Hƒùþtÿû#H‹ ôwHƒùÿt Hƒùþtÿâ#HƒÄ(ÃÌÿ%.$ÿ%0$ÿ%Z$ÿ%´$H‹ÄH‰XH‰hH‰pH‰x ATHƒì M‹Q8H‹òM‹àA‹H‹éI‹ÑHÀH‹ÎI‹ùI\ÂL‹Ãè¦ÄÿÿD‹D‹UA‹ÃAƒãº#ÂA€âfDDØE…ÛtL‹ÏM‹ÄH‹ÖH‹Íè³—ÿÿ‹ÐH‹\$0H‹l$8H‹t$@H‹|$H‹ÂHƒÄ A\ÃH‹ÄH‰XH‰hH‰pH‰x ATHƒì I‹Y8H‹òM‹àH‹éLCI‹ÑH‹ÎI‹ùèÄÿÿD‹[D‹UA‹ÃAƒãA¸A#ÀA€âfDDØE…ÛtL‹ÏM‹ÄH‹ÖH‹Íè"D‹ÀH‹\$0H‹l$8H‹t$@H‹|$HA‹ÀHƒÄ A\ÃÌH‰\$H‰l$H‰t$ WATAUAVAWHƒì Icx L‹ùI‹ÈI‹éM‹èL‹òèÀM‹L‰UD‹à…ÿ„…H ¿H4ìÿÿÿIc]I^HÞD;c~ID;cCI‹HT$PE3ÀèQþÿÿLcCD‹K LD$PD‹3ÉE…ÉtIP HcI;Ât ÿÁHƒÂA;ÉríA;Ér HƒîƒÇÿtë›I‹H ‰IcLˆH‹ H‰MH‹\$XH‹t$hH‹ÅH‹l$`HƒÄ A_A^A]A\_ÃÌHƒì(è¿’ÿÿH‹€(HƒÄ(ÃÌÌÌHƒì(è§’ÿÿH‹€0HƒÄ(ÃÌÌÌ@SHƒì H‹Ù芒ÿÿH‰˜(HƒÄ [ÃÌ@SHƒì H‹Ùèn’ÿÿH‰˜0HƒÄ [ÃÌH‹ÄH‰XH‰hH‰p WATAUHƒì LHI‹èL‹âè…þÿÿI‹ÔH‹ÍL‹èèkHc} ‹ð…ÿt5H ¿Hìÿÿÿè’ÿÿHcMH‹(HÑHÓ;r~;r~ HƒëƒÇÿu×3ÒH…ÒuAƒÉÿëD‹JL‹ÅI‹ÔI‹ÍèmH‹\$@H‹l$HH‹t$XHƒÄ A]A\_ÃH‰\$H‰t$WHƒì@I‹ÙI‹øH‹ñH‰T$Pè’‘ÿÿH‹SH‰(è‚‘ÿÿH‹V8H‰0èr‘ÿÿH‹S8D‹HT$PL‹ËL€(3ÀH‹Î‰D$8H‰D$0‰D$(L‰D$ L‹Çè9H‹\$XH‹t$`HƒÄ@_ÃÌH‰\$H‰l$H‰t$WHƒì@I‹ñI‹èH‹ÚH‹ùè‘ÿÿH‰˜8H‹èøÿÿH‹S8H‹L$xL‹L$pÇD$8H‰03ÛH‰\$0‰\$(H‰L$ H‹L‹ÆH‹Õè¹è¸ÿÿH‹Œ$€H‹l$XH‹t$`H‰˜8CH‹\$PÇHƒÄ@_ÃÌÌÌH‹ÄL‰H L‰@H‰PH‰HSHƒì`H‹Ùƒ`ØH‰HàL‰@èè\ÿÿL‹€àHT$H‹ AÿÐÇD$@ë‹D$@HƒÄ`[ÃÌÌÌH‰\$H‰l$H‰t$WATAUHƒì HcZ L‹d$pH‹òH‹ÎI‹ÔE‹é3íè@‹ø…ÛuèQÙÿÿL‹T$hL‹D$`AƒËÿE‰‹ÓE‰…Ût*HcNH›H I‹D$LLôA;yü~A;9~ IƒéAÓuì…ÒtBÿH€HcFH,Il$3Ò…ÛtaE3ÉHcNIL$IÉH…ít‹E9~!‹E9AD;)|D;iE9uA‰BA‰ÿÂIƒÁ;Ór½E9tA‹H €HcFHˆID$ë Aƒ Aƒ"3ÀH‹\$@H‹l$HH‹t$PHƒÄ A]A\_ÃÌÌÌ@SHƒì H‹ÙH‰èûŽÿÿH;˜ sèíŽÿÿH‹ˆ ë3ÉH‰KèÙŽÿÿH‰˜ H‹ÃHƒÄ [ÃÌ@SHƒì H‹Ù躎ÿÿH‹ ë H9tH‹RH…ÒuòBHƒÄ [Ã3ÀëöÌÌH‰\$WHƒì H‹ù肎ÿÿH;¸ tèÐ×ÿÿèoŽÿÿH‹˜ ë H;ûtH‹[H…Ûuòè¯×ÿÿH‹\$0HƒÄ _ÃèCŽÿÿH‹KH‰ˆ ëãÌÌH‰\$H‰l$H‰t$WHì H‹òH‹éI‹øHL$0HD>A¸˜I‹ÙèÖºÿÿH‹„$ÐH‹”$èH‹MH‰D$`Hc„$ØLBLD$0H‰D$hH‹„$àE3ÉH‰D$x¶„$ðL‰\$PH‰„$ˆH‹B@H‹H‰D$(H„$ÐH‰\$XH‰|$pH‰´$€HÇ„$ “H‰D$ è‰øÿÿLœ$ I‹[I‹kI‹s I‹ã_ÃÌÌH‰\$H‰l$H‰t$WHƒì I‹èH‹òH‹ÙH…ÉuèÖÿÿHcC‹{HFuèoÖÿÿ3É…ÿt3L‹NLcCKHcIÁH;è| ÿÁHƒÂ;Ïrë…ÉtAÿIÀB‹D ëƒÈÿH‹\$0H‹l$8H‹t$@HƒÄ _ÃÌÌL‹élÿÿÿHƒì(McHH‹M‹ÐA‹ƒøþu L‹I‹ÊèJÿÿÿHƒÄ(ÃÌIcPH‹D‰ ÃH‰\$WHƒì A‹ùLL$@I‹Øè¶øÿÿH‹HcCH‰L$@;|~‰|H‹\$0HƒÄ _ÃÌ@SHƒì LL$@I‹ØèøÿÿH‹HcCH‰L$@‹DHƒÄ [ÃÌÌÌHù<H‰é±{ÿÿÌH‰\$WHƒì Hß<‹ÚH‹ùH‰è’{ÿÿöÃtH‹ÏèÝmÿÿH‹ÇH‹\$0HƒÄ _ÃÌÌÌH‹ÄH‰XH‰hH‰pH‰x ATHƒì ‹q3ÛM‹àH‹êH‹ù;ótHcöèÕøÿÿLëL‹ÛL;Û„¾;ótHcwè¶øÿÿLëL‹ÛA8[„ž;ótèšøÿÿH‹ðHcGHðëH‹óèžøÿÿL‹ØHcELØI;ót;9_tèmøÿÿH‹ðHcGHðëH‹óèqøÿÿHNL‹ØHcEITè³ÿÿ;Ãt3Àë<°„Etöt'Aö$tötAö$tötA„$t„t»‹Ãë¸H‹\$0H‹l$8H‹t$@H‹|$HHƒÄ A\ÃÌHƒì(H‹8MOCàt8csmàu+èŠÿÿƒ è¼ÓÿÿÌè~Šÿÿƒ¸~ èpŠÿÿÿˆ3ÀHƒÄ(ÃÌÌÌH‹ÄD‰H L‰@H‰PH‰HSVWATAUAVAWHƒì0E‹éI‹ðH‹ÚL‹ñèuýÿÿ‹øè^÷ÿÿL‹øH‰D$(èŠÿÿÿ€ƒÿÿ„õA;ýŽìƒÿÿ~;~|èNÓÿÿLcçè"÷ÿÿHcNJà‹<‰|$ è÷ÿÿHcNJàƒ|t!èúöÿÿHcNJàHc\èèöÿÿHÃH‹\$xë3ÀH…Àt\D‹ÏL‹ÆH‹ÓI‹ÎèþüÿÿèÁöÿÿHcNJàƒ|tè­öÿÿHcNJàHc\è›öÿÿHÃë3ÀA¸I‹ÖH‹ÈèI‹Ïè«öÿÿëD‹¬$ˆH‹´$€L‹t$pL‹|$(‹|$ ‰|$$H‹\$xéÿÿÿè‰ÿÿƒ¸~ è‰ÿÿÿˆƒÿÿt A;ý~èIÒÿÿD‹ÏL‹ÆH‹ÓI‹ÎèLüÿÿHƒÄ0A_A^A]A\_^[ÃH…Ét<ˆT$Hƒì(9csmàu(H‹A0H…ÀtƒxtHc@H‹Q8HÐH‹I(ÿÒëèÈÑÿÿHƒÄ(ÃÌÌHcHÁƒz|LcJHcRI‹ Lc MÁIÀÃÌH‰\$H‰l$H‰t$WATAUAVAWHƒì H‹òL‹ñH…Òu è”ÑÿÿèkÑÿÿÌ3ÿE2ä9:~xètõÿÿL‹ØI‹F0HcH Ml è_õÿÿL‹ØI‹F0HcH A‹, …í~EHcÇL<€è@õÿÿH‹ØIcEHØèõÿÿHcNM‹F0J¸H‹ÓHÈèúûÿÿ…Àu ÿÍIƒÅ…íÇëA´ÿÇ;>|ˆH‹\$PH‹l$XH‹t$`AŠÄHƒÄ A_A^A]A\_ÃÌ@SVWAUAVAWHì˜H‹ùE3öD‰t$ D!´$ÐL!t$HL!t$@è]‡ÿÿH‹€øH‰„$èèI‡ÿÿH‹€ðH‰„$àH‹wPH‰´$ØH‹GHH‰D$8H‹_@H‹G0H‰D$XL‹o(L‰l$`è ‡ÿÿH‰°ðèþ†ÿÿH‰˜øèò†ÿÿH‹ðH‹R(HL$xèÑ÷ÿÿL‹øH‰D$PL9wXt(Ç„$Ð迆ÿÿH‹˜8H‰\$@讆ÿÿH‰˜ðA¸I‹ÕH‹L$XèPH‹ØH‰D$HH‹¼$èéƒÇD$ èr†ÿÿƒ Àƒ¼$Ðt.²H‹´$ØH‹ÎèƒýÿÿL‹\$@MK E‹CA‹SA‹ ÿ©ëH‹´$ØLN D‹F‹V‹ÿŒD‹t$ H‹\$HH‹¼$èL‹l$`L‹|$PI‹Ïè`÷ÿÿE…öu@>csmàu8ƒ~u2~ “t~ !“t ~ "“uH‹N(èõöÿÿ…Àt ²H‹Îèãüÿÿ誅ÿÿH‹Œ$àH‰ˆðè–…ÿÿH‰¸øH‹D$8HcHI‹EHÇþÿÿÿH‹ÃHĘA_A^A]_^[ÃÌÌH‰\$H‰t$H‰|$ATAUAVHƒì0I‹ñI‹øL‹âL‹ñ3ÛE‹hD;ëtMcíèdòÿÿM\ëL‹ÛL;Û„¿D;ëtèGòÿÿL‹ØHcGLØëL‹ÛA8[„œ9_u º'ƒº'r HcGI$L‹àötF¿‹×I‹N(èõ ;Ãt(‹×I‹Ìèç ;ÃtI‹N(I‰ $HVèüÿÿI‰$é1èìÍÿÿé'¿@„>ta‹×I‹N(èª ;ÃtH‹×I‹Ìèœ ;Ãt:LcFI‹V(I‹Ìè0±ÿÿƒ~…æI9$„ÜHVI‹ $è«ûÿÿI‰$éÆèÍÿÿé¼9^tèfñÿÿL‹ØHcFLØëL‹ÛL;ÛuE‹×I‹N(è+ ;Ãt/‹×I‹Ìè ;Ãt!LcVHVI‹N(èLûÿÿH‹ÐM‹ÂI‹Ì袰ÿÿë`èÍÿÿëY‹×I‹N(èæ ;ÃtD‹×I‹ÌèØ ;Ãt69^tèæðÿÿH‹ÈHcFHÈëH‹Ëè¶ ;ÃtŠ$öØÉ÷ÙϋىL$ ëèÁÌÿÿ‹Ãëè“Ìÿÿ3ÀH‹\$PH‹t$XH‹|$`HƒÄ0A^A]A\ÃÌÌH‰\$H‰t$WHƒì I‹ÙH‹ñAº sH‹úëIcxH:è«ýÿÿƒèt;ƒøuaE3ÒD9StèGðÿÿL‹ÐHcCLÐHSH‹N(èXúÿÿH‹ÐA¸H‹ÏAÿÒë+E3ÒD9St èðÿÿLcSLÐHSH‹N(è%úÿÿH‹ÐH‹ÏAÿÒëèÕËÿÿH‹\$0H‹t$8HƒÄ _ÃH‹ÄH‰XH‰hVWATAUAVHƒìPL‹¬$ I‹éL‹âM‹ðH‹ÙLHM‹ÅH‹ÕI‹Ìè›îÿÿL‹Œ$°H‹´$¨H‹øM…ÉtL‹ÆH‹ÐH‹Ëèíþÿÿè\ïÿÿHcN L‹ÏHÁŠŒ$ØM‹ÆˆL$@H‹Œ$¸H‰l$8‹L‰l$0I‹Ì‰T$(H‹ÓH‰D$ è°óÿÿL\$PI‹[0I‹k@I‹ãA^A]A\_^ÃÌÌÌH‰\$L‰D$UVWATAUAVAWHƒìp9€M‹éI‹øL‹òH‹ñ„ûè’ÿÿD‹¼$àH‹¬$ÐHƒ¸àtNèsÿÿH‹Øè÷ÿÿH9ƒàt8>MOCàt0H‹„$èM‹ÍL‹ÇH‰D$0I‹ÖH‹ÎD‰|$(H‰l$ èªðÿÿ…À…Žƒ} uè{ÊÿÿD‹¤$ØHD$`L‰l$0H‰D$(H„$°E‹ÇE‹ÌH‹ÕI‹ÎH‰D$ è¶ðÿÿH‹ø‹„$°é5D;'ŒD;gèûíÿÿHcO H‰HcOH‘ƒ|ðt$èßíÿÿHcO H‰HcOH‘Hc\ðèÅíÿÿHÃë3ÀH…ÀtHè´íÿÿHcO H‰HcOH‘ƒ|ðt$è˜íÿÿHcO H‰HcOH‘Hc\ðè~íÿÿHÃë3À€xuèlíÿÿHcO H‰HcOH‘öDì@ucèPíÿÿ‹O L‹„$ÀÆD$XÆD$PÿÉHcÉM‹ÍH‰H HcGI‹ÖHÈH‹„$èH‰D$HD‰|$@H‰|$8Hƒd$0H‰L$(H‹ÎH‰l$ è.ýÿÿ‹„$°ÿÀHƒÇ‰„$°;D$`‚ÁþÿÿH‹œ$¸HƒÄpA_A^A]A\_^]ÃH‰\$ L‰D$H‰T$UVWATAUAVAWHì H‹œ$E3ÿL‹âH‹ùI‹ÑH‹ËM‹éI‹èDˆ|$`EŠ÷Dˆ¼$àèqòÿÿLL$xL‹ÃI‹ÕI‹Ì‹ðèhëÿÿL‹ÃI‹ÕI‹ÌèÆòÿÿL‹ÃI‹Õ;ð~ HL$xD‹ÎègòÿÿD‹ÎL‹ÃI‹ÕI‹Ìèbòÿÿë I‹Ìè”òÿÿ‹ðƒþÿ|;s|è'Èÿÿ?csmà…Kƒ…° “t !“t  "“…‘L90…‡è‡~ÿÿL9¸ð„ëèu~ÿÿH‹¸ðèi~ÿÿH‹O8H‹¨øÆD$`H‰¬$ðèÐëÿÿºH‹ÏèsA;Çuè‘Çÿÿ?csmàu,ƒu& “t !“t  "“u L90uè]Çÿÿèü}ÿÿL9¸„êèê}ÿÿH‹¨èÞ}ÿÿH‹ÕH‹ÏL‰¸èhõÿÿA:Ç…¶D9}E‹ç~UI‹÷èêêÿÿHcMHÆD9|tè×êÿÿHcMHÆHc\èÆêÿÿHÃëI‹ÇHƒaH‹Èè¿mÿÿA:ÇuAÿÄHƒÆD;e|®è˜Æÿÿ̲H‹Ïè‰ôÿÿLB.H”$àHŒ$ˆL‰œ$àèÅkÿÿL.HG=HŒ$ˆL‰œ$ˆèoÿÿÌH‹¬$ð?csmà……ƒ…{ “t !“t  "“…\D9{ †„D‹„$HD$hL‰l$0H‰D$(HD$dD‹ÎH‹ÓI‹ÌH‰D$ ècìÿÿ‹L$dH‹è‹D$h;ȃB9u;uè¥éÿÿLceD‹u LàE;÷Žäè¤éÿÿH‹O0HcQ HDH‰D$pèéÿÿH‹O0HcQ D‹<ë4èzéÿÿH‹L$pL‹G0Hc HÁI‹ÌH‹ÐH‰„$€è8ðÿÿ…ÀuAÿÏHƒD$pE…ÿÇAÿÎIƒÄE3ÿ눊„$L‹„$ðA¶ˆD$XŠD$`M‹ÍˆD$PH‹„$H‹ÏH‰D$H‹„$Dˆ´$à‰D$@H‹„$€H‰l$8H‰D$0L‰d$(L‹¤$èI‹ÔH‰\$ èîøÿÿE3ÿëDŠ´$àL‹¤$è‹D$h‹L$dÿÁHƒÅ‰L$d;È‚ÇþÿÿE:÷… ‹%ÿÿÿ=!“‚Ž‹s A;÷t HcöèXèÿÿHÆëI‹ÇI;ÇtqA;÷tèAèÿÿH‹ÐHcC HÐëI‹×H‹ÏèŽòÿÿA:ÇuKLŒ$àL‹ÃI‹ÕI‹Ìè#çÿÿŠŒ$L‹„$ðˆL$@L‰l$8H‰\$0ƒL$(ÿL‹ÈH‹×I‹ÌL‰|$ ènìÿÿèzÿÿL9¸tèëÃÿÿH‹œ$øHÄ A_A^A]A\_^]ÃD9{ vÌD8¼$u4H‹„$M‹ÍL‹ÅH‰D$8‹„$I‹Ô‰D$0H‹Ï‰t$(H‰\$ èjøÿÿëŽècÃÿÿÌÌÌ@SHƒì H‹Ùè>iÿÿL÷*L‰H‹ÃHƒÄ [ÃÌÌÌH‰\$H‰l$H‰t$WATAVHƒì@I‹éM‹àH‹òH‹ÙèÛyÿÿH‹¼$€ƒ¸ÀºÿÿÿA¸)€A¹&€A¾u8;csmàt0D9uƒ{u H{` “tD9 t‹#Êù"“r D„w$…€‹C¨f„“ƒ„kƒ¼$ˆ…]ƒà t?D9 u:M‹„$øH‹ÕH‹Ïèïëÿÿƒøÿ‹Ø|;G|è†ÂÿÿD‹ËH‹ÎH‹ÕL‹Çè¹îÿÿé…Àt D9u‹s8ƒþÿ|;w|èUÂÿÿH‹K(D‹ÎëÌL‹ÇH‹ÕH‹Îè‚æÿÿé⃠u.‹#Â=!“‚̓ tèõåÿÿHcO HÁë3ÀH…À„®;csmàumƒ{rg{ "“v^H‹C0ƒxtèÓåÿÿH‹K0LcYLØëE3ÛM…Ût:¶„$˜L‹ÍM‹Ä‰D$8H‹„$H‹ÖH‰D$0‹„$ˆH‹Ë‰D$(H‰|$ AÿÓëLVp~Œœ®ÄØ  ø&:Njˆœ°ÊÞô 4@JVhxˆ–¤®¾àî  2 : L Z f v Œ ¦ ¾ Ø î   ( : R l | ’ ¬ ¸ È Þ î   $ 4 \ j z Œ   ² àŒr` 2@t<@ F@V@x¬@„G@š/!MW¨ò¨æbad allocationó@P$@l1@ &@À&@Ðó@€1@l1@Unknown exceptionøó@°1@csmà “  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~=(null)(null)EEE50P( 8PX700WP `h````xpxxxxCorExitProcessmscoree.dllruntime error TLOSS error SING error DOMAIN error R6034 An application has made an attempt to load the C runtime library incorrectly. Please contact the application's support team for more information. R6033 - Attempt to use MSIL code from this assembly during native code initialization This indicates a bug in your application. It is most likely the result of calling an MSIL-compiled (/clr) function from a native constructor or from DllMain. R6032 - not enough space for locale information R6031 - Attempt to initialize the CRT more than once. This indicates a bug in your application. R6030 - CRT not initialized R6028 - unable to initialize heap R6027 - not enough space for lowio initialization R6026 - not enough space for stdio initialization R6025 - pure virtual function call R6024 - not enough space for _onexit/atexit table R6019 - unable to open console device R6018 - unexpected heap error R6017 - unexpected multithread lock error R6016 - not enough space for thread data This application has requested the Runtime to terminate it in an unusual way. Please contact the application's support team for more information. R6009 - not enough space for environment R6008 - not enough space for arguments R6002 - floating point support not loaded Microsoft Visual C++ Runtime Library ...Runtime Error! Program: À À–ÀÀŽÀÀÀ‘À’À“À ((((( H„„„„„„„„„„‚‚‚‚‚‚ h(((( H„„„„„„„„„„‚‚‚‚‚‚ H€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ  !"#$%&'()*+,-./0123456789:;<=>?@abcdefghijklmnopqrstuvwxyz[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`ABCDEFGHIJKLMNOPQRSTUVWXYZ{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿHH:mm:ssdddd, MMMM dd, yyyyMM/dd/yyPMAMDecemberNovemberOctoberSeptemberAugustJulyJuneAprilMarchFebruaryJanuaryDecNovOctSepAugJulJunMayAprMarFebJanSaturdayFridayThursdayWednesdayTuesdayMondaySundaySatFriThuWedTueMonSun€€†€€†€†‚€EEE………00€P€ˆ('8PW€700PPˆ (€ˆ€€`h`hhhxppwppGetProcessWindowStationGetUserObjectInformationAGetLastActivePopupGetActiveWindowMessageBoxAUSER32.DLL Complete Object Locator' Class Hierarchy Descriptor' Base Class Array' Base Class Descriptor at ( Type Descriptor'`local static thread guard'`managed vector copy constructor iterator'`vector vbase copy constructor iterator'`vector copy constructor iterator'`dynamic atexit destructor for '`dynamic initializer for '`eh vector vbase copy constructor iterator'`eh vector copy constructor iterator'`managed vector destructor iterator'`managed vector constructor iterator'`placement delete[] closure'`placement delete closure'`omni callsig' delete[] new[]`local vftable constructor closure'`local vftable'`RTTI`EH`udt returning'`copy constructor closure'`eh vector vbase constructor iterator'`eh vector destructor iterator'`eh vector constructor iterator'`virtual displacement map'`vector vbase constructor iterator'`vector destructor iterator'`vector constructor iterator'`scalar deleting destructor'`default constructor closure'`vector deleting destructor'`vbase destructor'`string'`local static guard'`typeof'`vcall'`vbtable'`vftable'^=|=&=<<=>>=%=/=-=+=*=||&&|^~(),>=><=<%/->*&+---++*->operator[]!===!<<>> delete new__unaligned__restrict__ptr64__clrcall__fastcall__thiscall__stdcall__pascal__cdecl__based(Xì@Pì@@ì@0ì@ ì@ì@ì@øë@èë@Øë@ÂÔ@Èæ@¨æ@æ@pæ@Pæ@Ðë@Èë@ÀÔ@Àë@¼ë@¸ë@´ë@°ë@¬ë@ ë@œë@˜ë@”ë@ë@Œë@ˆë@„ë@€ë@|ë@xë@të@pë@lë@hë@dë@`ë@\ë@Xë@Të@Pë@Lë@Hë@Dë@@ë@<ë@8ë@4ë@0ë@,ë@(ë@$ë@ë@ë@ë@ðê@Øê@Èê@°ê@ê@pê@Pê@0ê@ê@èé@Èé@ é@€é@Xé@8é@(é@ é@é@é@àè@Ôè@Èè@¸è@˜è@xè@Pè@(è@è@Ðç@°ç@ˆç@`ç@0ç@ç@àæ@ÂÔ@SunMonTueWedThuFriSatJanFebMarAprMayJunJulAugSepOctNovDecCONOUT$No errorFile not foundNot a PE fileGeneral failureLVp~Œœ®ÄØ  ø&:Njˆœ°ÊÞô 4@JVhxˆ–¤®¾àî  2 : L Z f v Œ ¦ ¾ Ø î   ( : R l | ’ ¬ ¸ È Þ î   $ 4 \ j z Œ   ² àŒr` VerQueryValueAGetFileVersionInfoSizeAGetFileVersionInfoAVERSION.dllËSetCurrentDirectoryA´lstrcmpiA›SearchPathA¨GetCurrentDirectoryAºlstrcpynA¦_lclosenGetUserDefaultLangIDFileTimeToSystemTime×GetFileTimeª_lopenFileTimeToLocalFileTimeyCreateFileAÕGetFileSizeMapViewOfFileEUnmapViewOfFilezCreateFileMappingACCloseHandleKERNEL32.dllwsprintfAUSER32.dllæGetLastError¡HeapFreepGetCommandLineA1TerminateProcessªGetCurrentProcessBUnhandledExceptionFilterSetUnhandledExceptionFilterËIsDebuggerPresent—RtlVirtualUnwindRtlLookupFunctionEntry‰RtlCaptureContext¥HeapSetInformationŸHeapCreateHeapAllocTRaiseException’RtlPcToFileHeader\GetCPInfoSGetACPGetOEMCPÕIsValidCodePageÖEncodePointer¸DecodePointer?FlsGetValue@FlsSetValue>FlsFreeðSetLastError®GetCurrentThreadId=FlsAlloc–RtlUnwindExÚEnterCriticalSectionéLeaveCriticalSectionùGetModuleHandleW%Sleep GetProcAddressExitProcess‘WriteFile;GetStdHandleôGetModuleFileNameAKFreeEnvironmentStringsAÀGetEnvironmentStringsLFreeEnvironmentStringsW~WideCharToMultiByteÂGetEnvironmentStringsWìSetHandleCountØGetFileType9GetStartupInfoA¿DeleteCriticalSectionNQueryPerformanceCounterfGetTickCount«GetCurrentProcessIdOGetSystemTimeAsFileTime¦HeapSizeÛLCMapStringAMultiByteToWideCharÝLCMapStringW=GetStringTypeA@GetStringTypeWèGetLocaleInfoAëLoadLibraryAµInitializeCriticalSectionAndSpinCount¤HeapReAlloc„GetConsoleCP–GetConsoleModeBFlushFileBuffersäSetFilePointer†WriteConsoleAšGetConsoleOutputCPWriteConsoleWSetStdHandle€Ó@ðÓ@.?AVbad_alloc@std@@ðÓ@.?AVexception@std@@2¢ß-™+Í] ÒfÔÿÿ        ! 5A CPR S WY l m pr € ‚ ƒ„ ‘)ž ¡¤ § ·Î×  €Ó@€Ó@ðÓ@.?AVtype_info@@ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ @¤`‚y‚!¦ß¡¥Ÿàü@~€ü¨Á£Ú£ þ@þµÁ£Ú£ þAþ¶Ï¢ä¢å¢è¢[þ@~¡þQQÚ^Ú _ÚjÚ2ÓØÞàù1~þß@þÿÿÿC`@`@`@`@`@ "@Ý@á@ã@ !@p@p@ @ÿÿÿÿ 7@ 7@ØÔ@ÈÔ@|Y@¸Ú@ˆÚ@ XÚ@ ÀÙ@ˆÙ@XÙ@0Ù@Ù@ÈØ@ Ø@hØ@0Ø@Ø@è×@€×@ H×@!PÖ@"°Õ@x Õ@yÕ@z€Õ@üxÕ@ÿhÕ@  ÿÿÿÿÿÿÿÿ€ €Ó@Ý@ß@`å@\å@Xå@Tå@På@Lå@Hå@@å@8å@0å@ å@å@å@øä@ôä@ðä@ìä@èä@ää@àä@Üä@Øä@Ôä@Ðä@Ìä@Èä@Àä@°ä@¤ä@œä@ää@”ä@Œä@„ä@xä@pä@`ä@Pä@Hä@Dä@8ä@ ä@ä@  !@."@è2@è2@è2@è2@è2@è2@è2@è2@è2@ "@.<¢@<¢@<¢@<¢@<¢@<¢@<¢@<¢@<¢@<¢@€pðñÿÿPSTPDTp#@°#@ÿÿÿÿÿÿÿÿÿÿÿÿ;Zx—µÔó0Nmÿÿÿÿ:Yw–´Óò/MlþÿÿÿÿÿÿÿþÿÿÿÿÿÿÿDEPENDS - Matt Pietrek, 1997, for MSJ Syntax: DEPENDS [args] /v show version information /t show time & date information /p show full path /q quiet (don't report some MS dlls) /l show link time & date information €Ó@ðÓ@.?AVbad_exception@std@@CöP`ö`ДýÐÞ„ýàK<þPs8ýs…ý…˜ý ¾|ý¾dý&Tý0œþ \(þ\3þ3|þ|ÌðýÌåàýð¼ ÐüÀ ï!Äüð!e"Dýp"Ÿ"ÐýŸ"ø"¼ýø"#¬ý`##õ¨#$õP$‰$¼õŒ$­$ö°$I%dùL%õ%ö@&Q'(õT'¯'äú°'k(<õ„(*`õ*.*H÷0*z+„õÄ+ä+H÷ä+,H÷,J,öL,˜,Œõ ,Å-”õÈ-M. õP.Á.´õÄ.z/Dý80©0DýÈ0H1DýH1j1H÷€1¯1¼õ°1é1¼õì1 2H÷ 2N2öP2U3ÈõX3o3H÷x3ª3ö¬3=4øõ@4Ò4|÷Ô4·6ö¸6t7 öt78dù8{:Dö|:t<`öt<œ<H÷œ<>DýX?¯?ö°?%@˜öD@i@H÷l@A¸ö A¤A¼õ¤AÈAöÈAýBìöCCö„CôD ÷ôD•F,÷ F‚Gö„G«GH÷¬G Hö H9Hö¼<@¼f¾xh¾¿¨¿Ù¿ÐÜ¿ Âè ÂzÇ|ÇÇö ÇÅÉÊNÊ0û`Ê Ê8 ÊÅÊäûÅÊáÊÐùáÊõÊÐùõÊËÐùË'ËÐù'Ë@ËÐùGË`ËÐù`Ë‚ËÐù‚Ë›ËÐù›Ë·ËÐùÀËáËÐùáËúËÐùúË ÌÐù*ÌCÌÐùCÌ_Ìäû_Ì€ÌÐù€Ì˜Ìäû˜Ì¯Ìäû¯ÌÆÌäûÆÌßÌÐùàÌøÌäûÍÍÐù Í8ÍÐù8Í|Í`ÿ|ÍÍÐùœÍÄÍÐùÄÍÛÍÐùÛÍÎÎÐùÛÎhÏ0€0€ HX`Zä PAPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADÐ(££££0£8££˜£ £¨£°£¸£À£È£è£ð£àÈp¬x¬€¬ˆ¬¬˜¬ ¬¨¬°¬¸¬À¬È¬Ð¬Ø¬à¬è¬ð¬ø¬­­­­ ­(­0­8­@­H­P­X­`­h­p­x­€­ˆ­­˜­ ­¨­°­¸­À­È­Ð­Ø­à­è­ð­ø­®®®® ®(®0®8®@®H®P®X®`®h®p®x®€®ˆ®®˜® ®¨®°®¸®À®È®Ð®Ø®à®è®ð®ø®¯¯¯¯ ¯(¯0¯8¯@¯H¯P¯X¯`¯h¯ðx¢€¢ˆ¢¢l  0 ð¡ø¡¢P¦P§Ø§ø§¨8¨X¨˜¨°¨¸¨À¨È¨Ð¨à¨è¨©©À¬È¬Ð¬è¬ø¬­­(­8­H­X­h­x­ˆ­˜­¨­¸­È­Ø­è­ø­®®(®8®H®À® ˜¡¡ ¡(¡0¡8¡@¡H¡P¡X¡`¡h¡p¡x¡€¡ˆ¡¡˜¡ ¡¨¡°¡¸¡À¡È¡Ð¡Ø¡à¡è¡ð¡ø¡¢¢¢¢ ¢(¢0¢8¢@¢H¢P¢X¢`¢h¢p¢ˆ¢ ¢¨¢°¢¸¢À¢È¢Ð¢Ø¢à¢è¢ø¢££ £(£0£8£@£H£P£X£ð£ø£ ¥¨¥exiv2-0.23/msvc64/runner.py0000644000175000017500000000567611532054201015323 0ustar andreasandreas#!/usr/bin/env python # -*- coding: Latin-1 -*- ## def syntax(): print "syntax: python runner.py Win32|x64|all" ## r"""runner.py - run some tests on the exiv2 build""" ## import sys import os.path ## def Q(path): return '"' + path + '"' ## ## def exe(path,option): """exe - handle a .exe file""" # print "testing ",path testimages=os.path.realpath('testimages') tif=os.path.join(testimages,'test.tiff') png=os.path.join(testimages,'test.png') jpg=os.path.join(testimages,'test.jpg') os.system(path + " -V") os.system(path + " -pt "+Q(tif) + '2>NUL | grep Original') os.system(path + " -pt "+Q(png) + '2>NUL | grep Original') os.system(path + " -pt "+Q(jpg) + '2>NUL | grep Original') os.system(path + " -pt "+Q(jpg) ) ## ## def dll(path,option): """dll - handle a .dll file""" # print "testing ",path bits=32 if path.find('Win32')>=0 else 64 depends='tools/bin/depends%d.exe' % (bits) depends=os.path.realpath( depends ) os.system(depends + ' -q ' + path + ' | sort') ## ## def visit(myData, directoryName, filesInDirectory): # called for each dir """visit - called by os.path.walk""" # print "in visitor",directoryName, "myData = ",myData # print "filesInDirectory => ",filesInDirectory for filename in filesInDirectory: # do non-dir files here pathname = os.path.join(directoryName, filename) if not os.path.isdir(pathname): global paths paths.append(pathname) ## ## def handle(paths,handlers): for path in sorted(paths): ext=os.path.splitext(path)[1].lower() if handlers.has_key(ext): handlers[ext](path,option) ## ## def runner(option): """runner -option == None, means both x64 and Win32""" if option in set(['x64','Win32',None]): directory = os.path.abspath(os.path.dirname(sys.argv[0])) directory = os.path.join(directory,"bin") if option: directory = os.path.join(directory,option) global paths paths=[] os.path.walk(directory, visit, None) handle(paths,{ '.exe' : exe } ) handle(paths,{ '.dll' : dll } ) handle(paths,{ '.exe' : dll } ) else: syntax() ## ## if __name__ == '__main__': argc = len(sys.argv) syntaxError = argc < 2 if not syntaxError: option='all' if argc>1: option=sys.argv[1].lower() options = { 'x64' : 'x64' , 'x86' : 'Win32' , 'win32' : 'Win32' , 'all' : None , 'both' : None } syntaxError = not options.has_key(option) if not syntaxError: runner(options[option]) if syntaxError: syntax() # That's all Folks! ## exiv2-0.23/msvc64/zlib/0000755000175000017500000000000011745263366014406 5ustar andreasandreasexiv2-0.23/msvc64/zlib/zlib.vcproj0000644000175000017500000004134611510162225016561 0ustar andreasandreas exiv2-0.23/msvc64/testimages/0000755000175000017500000000000011745263367015614 5ustar andreasandreasexiv2-0.23/msvc64/testimages/test.png0000644000175000017500000040760711510453102017271 0ustar andreasandreas‰PNG  IHDRÈ–›ÜÇ¢zTXtRaw profile type exifxÚíœir›¹z…ÿcw ˜‡å`¬Ê²ü<$eQ–ÛÝ[©JݶlSâðx‡3 Ìþïÿ:æ_ÿú—³ÞUS©¹ålù[l¾óMµ?ÇòDnóã®Ò·Î>îwÏûÍë5Îó@x<ãõÌ{Óù.ýø¹=_èÆûý¦íÇ7¾~¹Üÿ|çøø¹¿.¸÷ÓóÍë›Üj±ñÇã9…8íº·!»¼óÉûó÷žAåSJN¦ørå‡È!$O¤ï4âû¿þ|`@¡†Îÿ-tÃMfŒ.Dî ÷Âcf­Wÿ9ñ9á¶¾Ü_­77¥ÖÏóMÖþH[y\áŽBã`$ Á~ŽÏ\ˆÙ¼=ã3Ô®¹Ïºa×úö–±ò/ð¶ÿx ¾ræÛÛ·¾ñÛóÛLjÒû Ú륽¥øcÎíý~wÓ‹ãýBý9¢2¹Ÿ©Å}kÜöçÐ ÷~[¯8ÙóñÒ÷ :%Weý]µ[ÿ~?Wï …÷˜ZyL¥ÛÏEJ_Ýâ´»¿Íàl;:ïØç œíþ»¶qåçû_S w ¯Âk*=¾½À~Lí§û_S‹ßÆ"rÿç‘îçÔò¯.dß/pâã;ÿ˜þ}}n/ó¹¿þ艟Ÿ÷cêÏÀÏ|Šá0ú/!y½°Ä÷ÇCL÷‘M§š'ÚýxÁ¸Žÿxß{ÿ«IuøPâ ŒÆçgúç…ž/(âÇÅ?ßߟßÅç…ü j_/È‹¹öx`½Þ <ïôuÉjßŠÕ aÈy2†ÿŸülÑõxA{Åçy¿³_.ôÄï¾L¡äG›¸úñäûÙÏû›µß‚¿úó»*vó÷¯g^É;ܬ»ý>Ô;Qg;Ä'µçóý39ëu!ª÷†×¿¦õ Ò¬zöÏìÄgš×³Îý«u^éÏÓŽgï ^Å5?î/ïõµ^÷×o?/´³öwÜoŸñ¥iÿÄŸ4?÷È× ‡ÃŸûÎé#8Ÿ²—ü½=§èet“›&èðØmÈùGÓzÞòœ9?=õ@#z\µœOI×VbgûúùºQ£çô§‚©ŸaäóTâŸü)WÔGÙ¸·`ŸþǯGÍ­XBɘ¯*Æ/^à¸e¦)ë¥% ¯* Îo±ŸÂÀ=>7£»ãâ 3Ïþ|ÿ˜R_¦öõO}F.÷Gµ¬G¦Ïo 2º'ß·Ç óþþ…ç4¿-ÿöNIå!É~º5¯)ÒÇHæ÷ïøõ…4¢ùçnO|¼Ñû­ùùhÜŸÏo‚ü·»¿ÇŸš ¾òÛþ½?ë‘íýö‚áAδgÝðü2äô&‰žo”Ý—rpÏôã-.÷ó¸}=ð!qòãçW™¼ÒßÂcJ¯r1/جŸpëó¸ÿrÖê¸ hÃ|ŒPx7~_G²ê¾ô5Èþ¸õo©£íJ)>“r^Sû Ï\Í—êx5ĸüñqû“Um¯=ç6KŠ.×ó7Ëò¯OíŸ ýºÕÎKÖ|þ÷g.Tûg·ô¹»ÿ³ƒÝ?ʇrõaˆÜ÷ª? ôŸÊþçBÿ\è3¤Ü µù´¢_]‘ûó}óìíisò‹Ú#–FKZå“L‘D™ñ÷ïîçÿéÔÜwsxÄå¦E}¿öçïCpÁØ]‹c¥äëÌ~þÓkÿ\è{ðYZ”Ú‹-½Éô—Î~­¼|¬À¼ÖÙüÕ|h¡>ïûv%Þ1¢/KîoÜ÷+=¼ï5™W ü´kÕŸ«ì_v­ºÜÿuÓêïÝÍ“Oˇýy!î}»?t÷¶®óÚS2¿Úd:gUþ ‚/êd¾ê]xmVSÕòbãkØå²ÅA.‚<ùaºà’³.{ç–Þs‹¹sÇGßBô“Ûœ/nsß ‹.äPB×—á=œÃ5úx …̸Úý"ËvâÐæýÿ𓾎ÓùÒm¼?÷üáûe^ßœ£2¢ êuÒön¹8+Š{ÉþçY‘?÷ºˆ—{}}·ìóØüÒFF¾AmV˪îY;_¿ÞZäÛ—º× ²ŠW%x†}ñÕë-yIqÕè¹>ùÇý ÆnR«vFbˆ1¦˜c‰5¶ØSH1¥”SI5µÔsÈ1§œs1Yûƽ„K*¹”RK+½R 5Õ\K­µÕÞ(¥[j¹•V[k½óž+w^Üy‚é}øFiäQFmôég˜q&­(Î:Û쪾WZy•UW[}»íwØq§wÙÕì¶û¡TUyÒɧœzÚéÎ=Cíox•Šòjî-å•$žIšŒM˜}Th%Ô9ÚC¶ÕEºƒp+ж©ì“?Ö%t9…™°Çí|:Î(â7à?Âýo ¶ÿ«á6½ýípìŸB õ äÕju›‚jÃÑNfŸ!1W«Aͼ§Î7³mçx?âÞŒÂåZµê¸vs<7ìtFƒÎ*=y›‹;;¬•vdì\Í1¦TÝ4à kp)æ³Üf !åFâòfÊkŽm[^kîRwd°ËM¾Â˜Ã×uâ®î²LL= Ñ?y¿QÚ){¤Ò×`|c—lsAKýëðúrfsgù¥Ñ…÷iS[¬kvWa/pÉÑ’{w…â ¤£Ï•kÊÁïšâèui'¶ÓÃî]¼ëeM²TMÑÛc6å5ïuÈ“/ÚëOg–ÊËí¤¤ ½?iG©1±]ƒ*«çê³ I¡-®„‘ª]=n53¹ä;»#2áÝR޼pÄR#iè-í‡Ê)ÖsP¶×Vê!ð.«gäP;`Û‡ ³¥Y¸-³¥_#0ÕR8­žÜÜ3R„bˆ yÒ[ÕØs!rD‘ú]”aĺS™ tÖóÈÍ'{Zô{{H%Í”©¼@ ˜Hä&Mq·)Bu•ª…Ur Ù]VÕàÝçnþìAÕš:T±è†=jók…ÚŒÛ9®šŠ-£ô“öI°SâU:¡A–ª£R 4H=«YÀ‰rh8ò©bйÇj )3kK±Ó³ˆ:ÿxh‚\’%›‡6„¸éùS ¥­såÀΉJ‰ËÀº-wòc}6…#¶‰ÐC¯PÝÎPÛe¥½³Ô××øb /´ÑÄN`(½ÃÜô-j>¤?Ž˜vsRÏ}$°¨4R]µ[WÆqÜ•RÛkÏeüæ-x@¦0µzjµœºDštj8ƒ2âz¡eǃÆ-0þtÇ% {¶˜ W$‘´Ÿ±â/¶ú"ûšµÅV°±ˆ@Ff“ÏÚ1Î µÕw† i^P¬žfôã2è#µåXdx§À´ë@QXêzÙÜÖBÍ-•á)µQk QšÃ´<xƤ©=ª¬€ÊcOž˜ð´ ÁCqøy£~9HWmT6nÖï$¡5Ãéê‰L¯æFU§†ÕÛÙˆ’¤êjq5ï­BŒ<…ÐüÐc¢Ï iMSš«ÉÕy c㙥1˜"¾8qhné91hCå{üì4IJ Ai‡AbEg?û P¸™B@PÔÆñÌÝ©˜'j·¯¾V T õŒ¡ÜhL£åI xá®ÅÑ PF¨ÌF³Ö–b….} ‹-8'î-@AWð:¾1¼f SzEF’‘šAu ¿­A«ƒ#К’à¢oHE(Π@Ñ)x¦Ú@g× Ð:S½(£¤¨È3šU‹kVàÝ6ƒß…ϸvƒ" ûX²/•á°#™•ú¦¨âÒÜ}Bðº½ú Œa¸¶'­ÖÒB,[ê¬ÑÔ<«.mk–’ºI4Ô 3´BhgCle<@)S‡Ç†°¨ ÑhÑŠÎÀâì¨-¢!.v­€øÕÀÐk).),ÄÌLtTvƒÖ=”8µPÃÖŒ(p¤Š7m‹k~‰“ðYÇLßA ánmãúC%½HÆËÖPÑa8ÓTëÑDªŠ0=!¬¹¢Ñ 1‚¬ÒÚ<.”+==‚…VCZ5ÔmÖ\¾Aøa3UÒ }ѓęSy'p§x‹Ý¢¸À8?ÄêJ9€“ëLâ¨msëB^2LÜÉøDqez™x9áfý\‚Ëi8é.úºÓÙðE(¶œ|h ‚¢>=ºèxxâ@7âsÞNÔ.Å™Æ-ð¯îÆßã u>·º¢86Ì~ &ZÆì<ì%‚Ö|‚€ê)@$9HªÅ2‡Zg ±L\Ȥ©ƒ—Ìëb»¶£Á^”^*NˆÄU V³xÔT|˜;H…BÜÇ¿ 2.W-üÄå7òŠþX…ÆG‹%ßË@Ì6QðCÚ[Q]ªºQmY%ÞLÚ ù‰^ë ømdÙÉl‰RŽª^8æ€à­ ÀQ£ °öȈ, €ì¢d“ ƒöZT*Ú/1oZÖ2*H”:䄎èÀFTTT\Ì”ÒJ À¤¡TÝä“X= ¤£d"êy€ÜÌžÚ„ÃéúÆÆÃB: G'd øæ¥÷!9‰ÞpF j~GjÚqþà€@ú*]7Qh¼)ø×BXîcd(– ÔUXŠŠzòyARof;Hp™¸„Ê`c„i¢Ð„¨ƒL„ƒCPÖ•O£1ψ⨦Ý"Úy„¾‰&Ü•@»ºVCë!=L‹¸ÔÅ8¹D™AwD?¯<@lÙYa…Œx&ã ÐiØÞfz Ȇ!RÈbSGIp6…_Œñ?÷Áúù # ªG-DžVKÀÏFP¡FRE`LDIuÉÉÃÍF”y?i’‰ÞK™”"X¶|—›ë2$vcÈD,iƒÛœ݃2ª`Qû¦£H?uÇŽäv%J„¡À{”ÁÀ5 ºr‰†d®(%:\Ø®ƒÂrÇö%ÆÙô]!÷82$<’¸  àäH âL€¼ã¥²Ü{ÿØñ<©®+R§,Á—1r9¬_Vƒ8O ¤Ùo ö‘AYY@ªò¨Ü?x§?mZDÅe[G6 èM€ãš!/ƒ’«ˆƒdôÐúSÐÂÓF‹¢ê/’©&‚wƒ:éb¹u•$”Ý¡ûá4[ÓvÒV麩87ùŠ„©‹jöø:R\Us2@ªUFh ÅF„åôl‡ ­´Ã[•]%¨ÙBLT÷À(U‰Z ’ði,Žö°w´º‡ý˜TAœÀ÷È5ÞȤè„úô ú”::3Ñ>¤½®="LÕYp)A2$¿AYÔWòò¦‰4Ñ%è<´ óHÚ´zȆ"ôFÒÓh e’†Þi¤Ív®N—ÏäÍI{Ý:nfû®l°äJ•æRDÉV@*Þy`L+rÿ€CÍ‚Ý\™òŽÖ,Z³ p6ÄÑ'Èoq ŠBFxšRh?ìS^!Ô6809†”†*.$ø6¤ò•Èqê«OÑ;ŒƒŽy˜Œx^¸{T£ÝéXÔRbæÙjž:ÏûTAMè$ÔlyDã:³AJ ûc¤/Kò]€ÒAfP[ùI¸PB$¤)%¿{!Am‚”" 6‘SÁK`¼v‚æ®E§RµtLi:2€Lä±a~ŠAkô.fwb,xë” Ê´ƒô+Ð&%¹FAø!é”ÃõÔ.¶ˆŸ‚:4¢Z%J ERv0͇çXÉ ”{ãÝÑ´1aÄäÉ<чZmÅÊFI‘#c2kñˆÔ¬eªxW‰°ö!‰+ÐìfùE„ÑS áEý­SúÚÜw¡d“ª&xpÒœP ŠˆtºBÄðˆNš‘a!´èÊIoóÍ1G$Ì‚«Ñ˜!Á4A¶'ÐÈ!j$†ˆi>ˆup;äJÉ’9otšˆÐ²”@ëÄpÔˆ:Bq÷D®œÜĿ̋ÀƒËxl/ÄBm´?”…•Ydªê+îÐY‰Ò!°èrò>E4b’ã–)<\ä_ƒ®àզ݌z¦™A ˜ŒvJÀb4?Ra@ýÀ¹çãd/€f¨³÷ û­“þÒ-o(gFƒê&æytd sÈô™èºc €2˜ô4²oðFÞB¾#:¥ž"-˜ÚŒDzk7'ÀCÐÀÐ*„O4™®Ž ­ôÙ­m\¡ÜÑiX¬®´X€Ž Ý0}ÇîSG´Ì²÷Z£éŒsQëBØYB݉ñ0c;šeê ®b5W$®¼‘š™ O%»%,T,Eßå!aP¸DöGÀ\ð%LC¬sج˜uÄtàû¡j€W !ÅòwЂŠÐ#oÊŒt~ è±B‹8‰Cô›bRèÓU½-5h?‚p…ÖÔb½%Hãž(ŒBü¸äéFP6´ÀlPJ݉_ƒh{ݢ챋cN;úšÄAoeõ\ ±[)#¯u‡ŠÆ øGjHí ôAl&L‹+¥òÃýO·iGp9¯ŠBèEجQÔ&:]7WGJ 3Ç¡usy,%æiÌz*9ß3!ˆUÓÒŒ{øÔ(ƒp3¬^2NØ!gâ´Ûì2nM«ˆË2Û§bÛ©EÞ’N24€ÒA’íÉSOd´Ê‰VË“;Ê$™JC­f¹ƒHê™"“98†vL]×ï£âk»Y|åVóóúí;:rð8ß'Ð7–™A«8p)[¤”CÖ3sy¨Úç[X7Pt>1„‚ã…äŠC1„È y R²¹¸¼"â‰ìbAì!]6¢Ë• Â$ÏZ1ßþ$ªª­†®¥{æ› u2’•5 Êù ¦ ¨Òð ¶'¥ÚNX²ÝÉ­}3·áᎦC®"]ö<¡Aa{gH¢ãH¡œJv*˜ÖFm@ôh—"«•¨Ô?Ääìx!˜'É`³ô¦Ékuš™‹:0¹EÂ…$£ rm‡^‡û(³@ñÖË ‰J&B‚k×Å€\BÀC“ö—èâç’`EÄ›‚ˆøè´¨-ZÅS8Çpƒ±ð:6vÒ})OÞ&ÅBb;®€{¶¿Ý²¥X§NHS¨C €X°Š©®ðZŒS%ÄW+ÏÔ"zZ^¥á[·È’Š?C´3x}0)­%ä¥Ãø~]wg$¹Îc“†f€tEQѳ Eü„¸Ú³bZ˜Ø%K–xüÛ‹t·ÁÊlYS:ˆöe‹¸èÍ Á™/¹ÁçJ÷€8¯^tÄ mõ:á ÜŠ+hgbeÍ`:)9ÈK嘤O•±tT ˜±eõ±Õ¶ñKniG²vmY µ€ÌÂÍi#iâ!âòù°A4VòæÖâ­$£Ë"?ZÊÔš¼Öœ¯·N¦˜%„Qh"½W=gíkÉì#F{°´6õ:žÒwtå©, ©4Ù…)ÃØÑv×tbV€@Œà0}µ­»T·D‚ZÖ.–Ö’à{æ `D ÆèS­:–µz­ÏÃ6Ô¨7så]ª}l-âjáŸYQ/¸\R•ÆŸ}—x2èzO’< áA䋨 Oðª½/‚Ðb—ñéZ7.˜F„ ï’&£)èî$$² ·vÀ(o£Ò,úÃ’K4„>o„šEÑ`bŽóvkUOF²Q¤H Åa`€#î¿Qõr†«ä kkå.O¾›|P?ýj%:Ãýr´1è_jõ“¶^ØÉà»Z668 tDwi‹ y ’ 8 >‘•­E¨hË~ÎÄÕqmÝjÁ•âà VPךŽñQ&VÝyä»0âÐn•žõð#ÞŸË0—¶T¡ Ÿ‰B!Û‘†Ç8|!êA€‡CMßE¯Heì¨vÛE.•d €PC+[-/¹”|wOÌ]æÙHWñ-˜ñÍòÎðs^~#7Î.¬š,­(XFŠiÍw]õçÅ8}ð=åçaÞ¯RÒÈ}®¬]E–·+(í,í@Nݬž]­n”j´ j¨˜R èZÌW[@PÀ'%ŠGkÀ0øWÚȬ ›: ÁȬx¯¥iÆVjk‰7ß³[« ¤¨SkZL\µØp޲<¢sèˆ  áŠ6 eh@ú‡Ø¹6ÅÚ&‚‘¼fLìd¦/¼q-’‰Î…pW‚3`ã.Ã+zªÓ0ER ‚;Åq÷s†Wd+8KÿTaÇÙ«­:o…æ<!S²¹ÑÿEÒZ{Î:t™©~j3ÐpSË [;ÚÔ×À8Í=÷L‹\¬íïKà@:(.®6L°jÉG0¡³M›Þ.Hu.{x­ß##2ú…hf'`Bi‘ ‡¶q¦w¥¤äü¨Eûã~i§…Ê¥ûm¼çN`R¤¥‰Ž/Ae‘¾Î<¬‚ª„„1ê‡0#S˜·Wô«í%}Z´D‘4¥U!-—'m\o…Z!§~j´ ù•b„ Am´ñŒz£aÜ`ÅH€µ“Üð8Pa(Ë{”‰(œr»•,V«]Ýꀀ§6Õ&.p3bC4JðaÚšg9Â.‚ERbêXÄ ÓÚ—Ä.¡u‘-e×P´'ݨNìeÕn€ÜSªe©Ì˜°“°ÎXÅdüÀOMû±~k‘þ¥ì{—ÕY:_Õtv‚–ö±UŒ–1ò¥-véÄKpY3 „ÃX"`DÁË óæ·ôˆ,' ÔKŠY´Ãf{WfU§caÅèû)[‚L÷ pi%ÍûL_‚ìZç[›üZÐà_ïx±LÁM_ÒRSC&LÞT*†×ç¨Þ°ä ÞÌëÂZ¸ÙŸ¥_K¢3²YDqt˜hjS—·F*4ãB˜¡ *Œ yÞ:à·|1X¨k¥ƒ!à @ÛÙ#¯ÿQfí¬í~Â5 -á0ç£ÔPãM5܇L6è$ ¼JÐúâ–It!"¦‚¬[Æ<+Ó£‹ÛEÝßu@®ÂD@†Öθ¸* †Ú Y-h¯h`\{i†QÉÐkÁ¾’HTñnH#0þªÓy®B?¬A—†î¡>A”ŒöÛËÐêæ€kR†)ŠëP4ìÛ¨%bì–x¸K­ãöà1lÜÙé·Q*´ƒ>ª©;Œ_”S˜YKÕZ¾Gó&¢¯7”5² ìÄþPŒÕ¶0]Ûß©à@ŽU›3k›Ð1)j'5긤ºv(ŠN½%c€ôððˆ ¸ãî‘ Q¨¬Áe´ûY‹©Ig+tø 4’»Æ [ç,è$8šÊŽwëFBeÓH ¾ qP®:}øÖ@—R·¥èJÐÖ,EMFýÉÞ[zBÝj Ý3zÆAŸQy˜D‡/Øbª’£í"õ s¯³S§] )÷=‘°.²IY¿LÉygŽE(ÎD&­™©5ù:¸¼ê\A‚÷µÇÛåÔW {êHÊ‘GGYÚD¶›ñdë±\ÈÓkftô jâ‚à–›ÞÌÚ–¯RŸgÂ%"(f‚4±¹CãK»½´Á*©–Áì "î°ë¨$#ãçäë`kDrÑ1*975K,e}Ü<:Z}ÕŒ~+&ĵAg…´™G˜1]:êÆÄokú-3c0G†w÷–1yþèpzšk /Bʼnn:2œšbyñ0ÖX+vø\íIœ7®vhaé0þ t¬J÷Þæ@ŒÀ:µ>íõÁ~êN>[®‰¤Õ«Ú'¬£@"z’ˆ 'Lž-¬™Í’ì åž¹ YGÑGê“ðjQ‰:‘ íµvN‡Q*bO­àgÖ™„¨-ŸÞ°€IªÎå{µk·4 ^O’f¬A*õ¯ƒ³ú((Æ©UmŽ2á®% ©–Ö–žJ“n3!ñàͨ JÒ* ©È¸cêX0ºaj T‹‹tÏ=xìú–«béÚæh‰\¼–” wa™e ÷м*Lµ„#Z-Á{$©Î ÐéVk»Ú%ý‡ñ3®üò0†çýž²NÊK:´—c0…˜nV9hY«*vTØÑ‚m‚N0yd.ëˆ)AÓб¤Bg¾B1¸ûK®öýF×Ö ÉÊY[Ç„…»4Ì0ì¯ÐíõØE'B¬´K”Å0™¾!„ÄÕ“<&Í%!òÜ—Tj.@_RðVlu¼õ`!ÝÖ ˆxbïõå×â}rúM Û6hŒ âÄ»Kt€%-ßâý÷’WÂßfš xíÀ1ɳÌݲõ:²…è`Qõ0EÄ‚Òy_§õ1õF”‘Ò¬’é4´¨Æã’Ღ“wúKbB®¯Ã0àbÕù*‚ˆƒl¨T° ™ÎÂzh>†Ðï?‘×9Æ{5Bv)úMPáŒ:,àqžV%ÆÃjyA'þlÀ°+F™ÒîIÇ»CÁ¿ìzAG°q^«TþÒÎqúE§¾Q£0!êÓZZýÁÊýJ½ÚÝ`Ûd’U¢:eÛÕ ¼%q¡Q-:äµÎz¾”RS·@‹H„»®t¶Ò›¼(yª¨ŠMÕb ?Ä¢çž7v×.ò‹Ðbït,¾Jôn«½ÐýÔé jÕÌ]u¸ÈÝ:‚Ò¢\´3X H!_@ACé#—:‹cîîE /ˆ`‘0~­>‹]ˆË%1¤/µ¬•µÜÔ/ÐXÍü¨Iò¹§/GÊgiCCPICC Profilex­—gTÍÒÇ{wÉ9gÉ9g”œs–(aÉqaÉ ˆ H‘ 9‹À‚$AD‚ (QTI" H|}ð9ï‡{î—ÛçÌéßÔTW×Ì¿·{ ÒGÊðñ 0ÑTaµ´²fÅ„ a@ãˆD£”Œô —ÿÐ~LØé£qÁÓXæxS±u@,쪒zó…ïSªÿaЙ™$š˜d rûÃJ§ìô‡ÍN9$ù¸Ÿ2ÒÝÑâ« ˜™@ña÷!&qûí§ìô‡N9év:v _g_p× VpvA#¡Ç§óÚ;£‘>ß‚ø›Ÿô4>%-ƒ˜ãô»@=Ô‚rPÎô¯Í:€š((=m\P.T/è˜û×¶mòû[ÁhFÑ®âb¿ÃÁˆTÀž?9Ùæ‚rKàèöÉÉAÉÉÉQ)ˆw<õFÿö…^Íüßîÿ¼ó?#8À0=¸‚‹Ûçž<~¡1 †Ì‚œò µ-1]9ƒ$c#3×9–{¬#l€]Ž#Œ³‘k“G”ׯšI]ÈZ8Y¤]tYœTB\ÒBÊWúŽL—ì†<ÝÕ‹n ñŠåJ]ÊS*«ªûêxdšÔZ ÚÌ:LºÌztú´´†Ž-ÜÿõÙ|‘oñàËÐRÖ2rEheïkïjÒšÙ:ÓúâFÏfñ·k[vße·i¶¿íôïüü©½Ç¼·ñ«g?óÀýðÂÅÑÒqljÛÉ ¤?ì=ƒ¨Ãz‹s7 H†x‰4ƒ\™b*“F’vˆÞ€¡›‰“Ùö\[/Ù¬ÙîØÚ# U@éDè´\vžrésmq«tÏòHðŒðB{{ø8øÚúY¡,ü-lÐHh8…‡*‡‰…s_a¹JAIEz8šà:v ,æ0vçÆjÜûø±›] 5‰÷’Šn&—¤§¥åÞNOOº™ºë˜i”¥Í—C™sto)w$¯1?¿ ®0¶èzñµ’¨Ò+e!åþ•÷-« hV+ÔHÖ b8ëÎÕÓ=¤j mÄn\kêkÎnñ{¤ÞÊØºÕ6Ð^ò8²Ã¦Sî ã““®OOº›zòzo> ís}®ÓÏ5Þ ¶Ý{quØaDí%ÿ(åèþاW¯1ãéA“—¦¤¦©¦7g†ß<}Û0[ñ.s.n>ð½ý­¢ t Ÿæ?w.æ¹²dµ,½Bµ²ùud³V¼ž·‘¹™ò-n+â{À¶óŽÅ®æ©Ÿ{d{Ç¿Öögú›Ê3N¬Oõ1°Px8¢kG·_`”È…ø„4‡œŸ¢J‘C{ž.„¾‡á„IŽÙý\&Ë ë!›ûeŽDÎG\ <¼"|úüîW“„2… DŠE‹Ä Äó$ò% ¥Š¤óerdÓånÊ_¹à}ÑJA]QP‰RiWyZ¥]5_-RÝVCQ“U‹XëH{MgVwHï‘~™Aša¸‘‹±¡‰œ)‡™Ù‘ùšÅÜ¥Ë'VõÖ61¶vv2—).oØ8Ô:¦: -•\ø]éÜpÝöÝ7<=ç½f¼_û û>ókGaüË й9A¹Á!%¡•aUá }¡:â~d´/¤FÇ\÷qе¹a§¯pS4á|"iâ~Ò§[Cɘ”´TTšÞmžtxú»;‰w‘™ÊYœÙ$Ù{9ï æÖåeæ‡Ø*qão”Œ—¶—•'T +/ß×®~@ò`±º¥&¹Ö#UGT÷¹þÉü†ðFÛ&åfîÒ–_–Z'ÚzÛ[?èHéôx¢ÜÅØõãéx÷Þ۽¨gÆ}¢Ï)žoõ TÞ²{!1Œ7<;òàęۘÑ+¹×ãÄã;3“íSùÓ‘3¶odßR¿ý6;ø®x.|Þä=ï؇7‡:?Õ~Î\Œúâ¾d¶¬º"ýUbUaíÒzôFÇ7Ò­»Û*»ü%ŽEø#ª‹X,XvX¹X³ØŒØvØÅØK8B8!8=¸¤¸¸ x8x—ñZñ)ñƒð'Ä nlš¶'ºEô‹ØƒxŽÄ„ä©i?™.Ùkrò%ŠJ<ÊB* ªÔ–Ô_hBi‰h‹édé&é(š­O˜*™ ™+g1f9b­>oÃFÀÖÁ~…C™sœ«€ÛGЇw’¯œ?X@KQpU¨C8UÄQTT !6-^+‘((å,m*£&+$Ç"O,xaíâ¼Â¸âˆÒ r¯Ê€ê°Ú´ú²Æ¡¶€Ž®¬ž²¾¡½a°Qº1ÆdÜôÀœÛÂâR’e¿5–ªm’ݤ=“ƒ“cŠÓSä– ‡«[–û”'½—w‰ÏW?1T„ÿ š:Ð)¨.ø T3,+üäjJ¤`T´{ AlmœAüzBrß­¾ûÔƒÛiwx3:2õ³¶rêsƒóe v‹K¼ËøË* ªl«YkV0­õI ®MÚ-²­ m «;#»Œ»{©û`Ï·Ö‡¶†GÉ^ñ«NºN'¾y8[6—ù>ùcâ§›‹)Kù+õ«ýë‹ß¿ î˜þˆÜ+Ù:Üù½À¡ÿƒŒ€È]` |A4È÷A'x –Á Œ&Ó¹À¢a°NØìÎ׆@ê"° ˆPD#bKË«k[ ;û .Ž NÎ:®"nî ž*^Þ1¾#þ3n‚‚uHûN"^¢bâkÄ{$h’-R4é/²ëä$äùB=”6”;TiÔlÔ4š4ó´ÁtätõôÆô» ¹ŒjŒ›L¹Ì:òÕ,¶¬$¬=çCÙÙVØ›8npZq q#¸ßò4ñ¦ð¹ó« ° N 5§‰x‹jˆ±‰ÃÄ$†%ŸIuJ7ËÔÈËe˧\ˆ¹®€VD)¡”ýTU#ÕÕó5š4Ç´6µ·uaz„úLB†Ð~cRm:aް¸äaYaµhÃnëe×|ùÀAÍÑß©9å‚ïªêéÞé óÒôNö™ö;òõïDÚÕ†ê‡_!¼š)Õmý 63N8¾/Á&qãVT IjÑm®ô– …»=YFÙ?ïUç! ˆ ÛŠKIÊZ*ìîãTÕUÛ×R`ëc4šˆ›?<´™´u”>±|ŠßÝכЧßO;°:Ô;\öòƘßkË µ)Ù¾·³csIïu>’-L~.ü‚ZÖøÊ²z´>¿9°…Ù¾»ûÓï—Åê‘Èoýq`†ô—ÚÀ xÊ@_À1¤¿ÌæK„ÕÀFaÛpF¸ /ƒO!ˆjˆÄ#Ä6– «ë¶.>±ò–xrgªfÚPºñÉ»¦™SÙA÷xsò3 µ‹KjË+¨*‡ªbª•kñ0õ ך[ô[Ï·Í=¾ÛiÜEöt¢§èYÀsµ–!Ø‹•‘‰ÑþWãM“õÓ˜7µ³!sJï©>üXxûùñ—ìeÔW™ÕõÔM¦o™['Û;ñ»U?Ú6í•ÿ Ûר?>¨<4:œ=r:Z9¾y¢vªÿŸzéwMí¡ïÕNÿÛæãt“ŠLäëd`õxеŒ 4:­3:ØTýŒ]=4´ÏØÙQM÷ŒÃÝU ÎØ5@ÃäŒ=uŒÎØÅ×ÜôŒQÞ¿ëÛæRùëï‚VÿëînvéÌ? ÈÄüŒ½ütÿú;»¨ýÍÍ×Û:Sÿäì¨ý7àô#@þ©3!€C@ž÷)u7õvÿ¯º„B5(ª~¨°7÷@Ve¨Êv`ÕöE °Š‰ˆÈ€ÿ[ù8­õ´Nã IDATx4½˜œgyïýŸòîôÙÞû®¶iÕ»,«X.² ¶Á€›š@€ åK;_®ˆœäK9iH ! `Ür‘lÉjV—VuWÛ{ß²3;ewgÎï®/Ä—mi5ó–ç¹ï»[¾ñÅ/,5®[¯Í-U*¬¨ÓØÔ¸þíþY¿ùµ?Ò­¾}æ¡Ý™˜Õö=ûe·Jý·.Êæ/ÔèÈ”ò ½úùs¿ÒCO<®ttI¥9RÓ¦&-F™ «ûv¯JŠÜºxá¬Ö6µéÒ¥sºvóªÊs ´uÓz­TéÜñwdÏ (ã”5¶ í{U|º_g‰ð>½ýÂ/U’ïVSK‹äÎÓõk—uð#OèÕ=«œ€Mû7ïÔ²Õ©õ[v* «çÚZ·ë N¾ÿž=ð€VWsÔÕ{E%…Ur ýãw~ªÇíVQA‘Þ¾tSFŽø]õI ÷]Ӹď~þâk’5­Š²&ýÏs?מM;õÕ?ÿ‚†¯ j!žÖ†MkŽ,©™û­(0ôå¯ý¿:sýª>þÈýô/kbbF˲(:;*‡»@ Á ÅbQÙøçD8&§×'ò¨ºö Z &5YÐüظ**Ê_Iª*¯BÖ¢|å¦c’Å«®ÁÛjll”+Ç«¡~­,/Êç­R"9#‡' Å™ }xê„ÊKKå ”è#/kÇÖ=J»lªoh•ËžV,œQb%,ÃáÑJzY‰ù)å•­‘Ͳ¤T2.KÚ¡üŠ"YWÒJ¯®ò¾¼ÊÉ)בÔÐÀ”lÞ´ì«6ÙVS’Í©™ÉÙ\亴qÇnyW§äÍ/T"5­ÊÊf¹YGÛœl¶<ÍÝ’}ŧ•DRG¥R©eùÝ«ZŒåèÌ¥3ºwßCúÁÿJ‹ƒc ¥ Ÿ–Úæj•y|š Oè³Ï|L[¶íÖàÍÓÒjB¾Â2…“ ê»8©áÕ"¥—äö9•“[.»áSšg O«º¤Zá÷æ³ËãÓR|A©Ä²Jò dÏ1”pªûÊ9Ù¾ø§ú×ÓC“†+¯Ìð×VËÁ˜Q]Å?» cMËh\Ûf†ÇHDÆe%f¸=.Ö±íkk§OÛöÜkdA#]4ÖoÙ`œ=ö¾ã÷kŠòW{ŒÝ[;Œ'N6«Û¸ÕuÙHãÜù‹FEÇ6ãÒéc†%-Cüe¬Ä…™yc|¨Û6,©˜149k,L ëvï=bð醔QU_m?zÂpÛmÆ+ÇŽ_úÊ7oÿíŸù•ÍF^^‰áv8ŒÚÚ"c%!ÃÆúpS“†ßWjLöt˲7ºï-UÅFÚšcôuõù}ƒ}Æèx·±ck›qáÜuã¿õwF*7òùFim³±eçãÅþÛ(+ª3ZÖ´G^zÁx郷Œg/³á”ññÇ6&g£†Ï0^~õc(7N?oÌ í-íÆå3§9~UgxJÊŒDlÑÈ/¨äþ-F¾7×0ܹFÀc7¾BÃát³c“FaQ¥‘Œ/þÜ"£®¸ÜH&ÃÆÒ¨±´l1¦gFü<—13F&“6 »ÃH&¢¬u—±šL>î9œ6≤19?gìÞ¾ÓxñçÓÇO¡é!®!e8½2ì·1>6h,-FÛ7^›Ý‡æ —Ûcdr2F¾¿Ô°sMË©¸aµ¸ŒxrÑÎ wÀoä>Ã&«Aq5\Ö4Ïßŵ¾ÜBžû¸aÉxŒã'Þ5yåÆÊrÔ()k0B¡  eŒ ±b7Ö”n7&'û Ÿ×e¬Ýü±œ6¬ÜÇì\k±Áèêë7 =c.™cD&h"̳)3.œ½jäy2F÷`¯QTÖn,Ç– ë qà¿mìÚp¯ÑÙ×X×¾Þ°,gŒùù ÃæÌçóìF,º`dÒIcyUF"›U£ÑUä9õÞ»okç¶ ú÷ü‡öîÞ¢ÑÑeÒ.Úû¼^øï¨µ8_1JwQ¾S7nNéíÓ'Ôuí/É£ÙÉQMMͪ½­% sÃI-Æc<0ŸBÓ³š …(û^Ù]+ 9\v›dNƒwo(PPHëöÓú­zâSO)Æ‚êÔÆÛTSV¬h<¥ÛçNhÛ.àV,¦ûöÝ—…+©¸y¹ ±‰M[b!Ë Z£§ŸzB‰8Ëà^êì…«ZÉÉÑ‹/(QÊCMF"Ú°~³nÞº¦ü<à@2¡sgNéžûÔþãû²ðÜî¹÷MOÍè_~ñœÆûG€3~u599ÉLª¦©E€²§ÏŸWšët³`CK)yr2’3_3,ºŒ\ÊõeØ5?_©å9Òáìµ8¹Ð×$…'nª¤z­ò¹/ÛºMÛ÷ßRMI±.ÜêÒdo—~âI]={Io¾ùŠ|Pï=ªs=³*ñÚuµ§W»7´*//_ûîÝ« ‹úê¥[¼˜ZýŸ¿ù+}ó›Äæpªëâ9½ÿÎ[,Y•ÃUº»:•Xš‘Óáç¦W %´°@'[Ó«jliÔÐØ *¨hIªezÅ¢Ü\ wŒ NNK<}}ù™'TYß߈+D—ùÒWþˆ…{SöU‘ïÒ†Í{XÄ1]9[q^ÂÑãguòfŸŠý*a³RÕÕUð‰1*Ô‚F§ÃtA§úèˆÑTFA~Ýéð)™×Õ+W´vËvUÔèØÑ#ð˜­p]«f… téÂuu]¿¨¹(¨¡ù”vm¯R”—}æôQ(ç&…&º5>=Ç&«´~17¯ÅÄ*Ÿ$\‹zòP›þàˬÖí›Toô¶« ñAµ¬Û¢ÞKGá:.]™É¾çk@³q¸¨¡І¹!€³"ÏzBNüëßyðIõݽ¢ê5ð°ÍëÖnª¬Pûú&¹¨TIàÙ3§ËñèÉÇÔ¿üðX4³zèÞ ª_Ó ù9ÃM7êë¿÷ÿ@P·*í.S*œ–;P®þ¹ Æ ò•­k5=¹ ÅÅ,›.<ÊËõ±hW542JÛ *·8ö_¦<*ÕÝîn57¬Év QUó=´`§]“3•—Tè/¾öÛjÞ¹W£Á°Fi³ëvlÔúµÛô«_Ðî½[UYP}M½.w÷ëù_¾¦¼ÂB]¼sK6G@ÛëuöÒ]-²ñ,,î5­-:uâ\öOÏÌëÆõkÚ¾k‹"á°Ñ§G=¬gßçþ¶hÇ–ÍzíÕ©Pn:éMò²&æÙæ+:¸o?ůú2§¶ïXßûÙOÕu³_¯ýâ'*( (<9Eñ2X³éŒÊËJuõÎuåç[XËqkFT/«¹°r,ô9¼…TH»¦çf”›_¤›WNs¿{µ@eu8R7]ÖPh!œ2€Å ¹.Ÿ_ó,Q±ÊØÔàk†_·q6Ušn_ j÷ž=zåWk삈/‡•Ê,/è^\g^Ÿ3 n„…ä@qr•ÎÄ)h9Àº âËÆ²[-¼¿JMRÙ#Ük~Ý%áM.Ênwhf>¨Í[7ƒJ§ÒJÄ|O@û‘Š«:(däHF•t;T_P®Ÿþ赬¯—ÍS©™¹IÑn€SI•VçQgUÓ¸ 1cZë[Zõ—ýmضGFA©¸8Y\¹((.+QŠUu›éï¾ÿxë-ŽßÑ`æ(ŠYb¡[ñØV4›nX~„'ž$@Dc,©˜{¶}ó«_<¼éþGôæ«/—Z˜ŸfG±?aª'¯çŽ~üanrVN^Â_´‘îá¡þìÕ×ùÀ MŒ÷Ñ–£úÔCj::NÛrRm£²úxØ#¼(p튕gân§&YEÀž±±Q&°Š*9?3FKžWÜĵ™¨£)¢ù´8¤0¿VWS `$¦h4©ù‘1ýõßüuV¹šÓþ½÷ëmšïçÓº¨@Amظ\{‡Ê‘Ôú¦:¸qWQ PWO·¨gžìÏ-jް05Ÿ}ðgÏÓ*Ò®=ûÀ²£ª†‡  )[R†®41<¢¦Æ68GR ^ÌŸÿÙŸèg/n= Dñk|v0»Hí@%·// &€6feç*àS+p¤5uMÀ`—–ív•W4*ã¡ ÌaÊá1hu%%2“í*5Uõ,˜Ïf—§Ä"ï)µÂ?{Xüsªj¨a“Ì)ų-„éÒS¨t6‹O |‡Ÿrè™æºÇá…E¨SÏ‘ŸES”_,XYÆý†Pì2 \¯Gùññ^*t Ý(#Ãã®øµJÁI¥£t‘°Ë+O^—•eØy·ÅÀdróJP¨øЀ ýn™÷Ÿ«ÞÎózë½WÕMaœ ­èøû´l™ÑßÿÓ‹º|ušx…uY§xøX‡.¯¡Â€MйË'©úA•W•éÚ‰7Ô°~?ßË궬Qgï˜þø>­_üû³ºs{µÐÁÏ.*Jex€¶({V`¼ÈM(×Ãäç²rà«RŠ®]ˆÉòíûN&‘mmnd·©¯³ÙÇ£ë6ª‹‡ä1¨ä9,ŠÑžúÜ“Ô"éÜ•k«õößêŸÖo=ý¤nßìÒ>ÕÕóïiÒJ¤Xi]†ǺÁ}Õ,ŒbŽM5‡\ œ±©˜ ›Ä—nR\bµn~¯RßþÖWôæ…mX»Qï<¥¦Úê,<3_\]m­:/\ÑÅ+—Áì`ëÙ~½øË#úŸ#ïçºUT MŒB¸—UÉ«*Ëã½9 zÓÊ„æU]ÓȢȨ¹ob;FÕ˜ž×Øô˜ªªTPR€(p+ G‘âð íúí_ñ2UWØè.>/¯¦D¼û¡záHNˆr(Qi €ë\†ÃjŽ¢âû&!‰ð"„Ò¶õ*..ðÜL+×a—+·ˆ‘Ñ<|ÉE‡1»J8œPx¬Oq>µ²¢T IÅk¨å—« P~äÛ$ï°4;=C÷ h~>ÂgN#‚pßËkžÂ ÓÚºµCÛwlÒ민ͻ4xî!Þ‘™sÎP¦)`l>•Ó|Ñ(f™×Î[u x2:6‚¬QsËZÙ=…š‘Þ°Å (ç¡£ÞUaa1¢ë®±Õú¤ežÙÒRT9t6‹Ó£¥ñN­Æèxˆ(9V¯œÉI½ñ*ÐÇ˳‰hjqUËñøŠÁDb ¹xF÷Üÿ˜:t åº>Ô¥ójËö]ùD¢Ü ÷à`³¤€”sQ—f)6>ÄŠŸ›µ¨Å¢¦4ŽcÓ¦Mͪ4×¼dÕ†°.pÛ3Š-çЭ²mlk: fW»Á]·dµØÕØÐ¬aÚù*pÆë¡º¡Ð}ôÊÛ§ÕÍ¢™{?qŠväb7[TS[®©‰)¹W“:uù„ùµò’T”&Æ&4<Èæp¢1T–_·éeZírƒd·9ä…oD#Qvüû¿üð‡º50£«7Õ×{W^®/AûÜ»k^H§’³wŸd‘çÓ]lî}ï»ßU€˜cqêvÏ-}ⳟEyšÐÎÍu«ë–®ßì2DáàŒÆ¦&ªo’ê¶¢îA*éÏ×VT¹¥eíÖ`ªJtQÕþ<ݾ;öváu#x4Ñ+?{ å‡ïdaX,þ­žNðw؈¦¯æžŠŠq:$×Vkk„6̽„B”$Á›hm PõéæüùUÔ·%%ÿCpytY¨,ÀZSq4• >ÍV[‰‡øYixrHe…å,Bˆ|·jªËXp~ž-]=à3OŠNæTo¼•ÐŽj•[èÓ‹?ÿ ›Ñ¥òÊÚ_/o‡»xox©%ÞgyzE?Àf(\#ø!ª2›L¬Èï+ÐÝΓª©oá3ìÙ 7Dç­(oÒ4UÛì^æÆµR\STo[xFÇŒ&fåJËj)¥š¯"ªÕS|á_tW+?gv¨Bº¤¹V,(…ýÝWuãR…®žâ0«ªÖu:°îa½{î4>SjU)ÞÇÞ}Ï(47ÄÆ.×úõ{Ô?ЗÌCµs(Nr—¡ðÙªj^ ›þVò¾øÞuë’lÍå‡Ýþ"ͰËk+¨80fü9òQ¥y*àöÝ[µÌŽ>tè^Ìu¸¥O¿÷;_ÒGžxRo¡hÍ —–x5½çŸgõÔý;i‡Ýå%PÁ«‘TÇÆ³]ż2¡Š‡¶7„ÙèåßËéi6Õ*êÄË(cO<ýQýð¿~®à‘åæàþ=j†øÎ‚¯ûz´ãÀ~õ\Aù h…Ýž‹`c±éüųàÊ”ªÛÚµ±½‰î'LË Õ¥‹7oª¸¬\Ù¿SÃc³ÙÍ;Kç[ͱi¨wX»7­ÓèÔ´ZjëõƯŽÒõ.Aý,Š"UÕÔiMÇZ]鼌Ї;Uhx¨bߥʪfMA²C|Èæäz2@«BîI¨4:Sð‘2¥P‡Š‘\M5i>8O•Œ*jMÇ4Ix0®µ­M`ïyÝAî4¸¶\ Ëð {.«nךú6à[›7O¹üÝÊw˜Ò­nåó ó 隘y(>K˜Klî8ž‡bæÁLlcSÖÕ™²³W3l²dÛ):CFb„Åo &…q@.Ï”¢–Bm‚Ť––(’Žìï_º|œN‡º—à×øóN·™t‰M0ƳZó¥ ÑÅÀ—ÚªJ¹©+s¢’-¡b]ChZ¿E™¥Q>ƒg° -lR ¸HópërT1Ô¸<:hÅ!Î&±Ùá%>º0kó8VDè TÔ²~gtïÇ×§Ÿú¼Ž¼ñc•kóŽOj¢(HëÑ;tæÊUÞ4ÅÔìXþi>ì+ÉG´(@'njÌWUe™¾ÿݿѺ »d;°k÷a':ð4zûo<ù$wˆŠL N\Ä%pyMs݆n"ªþ¾Ií}ìczñÅŸèW¯½….ž£4$k68§/£ýž}êéÏnˆÊÒB^Pœ‹˜P*4¥•”ÙqBeEú+ÃUžTUUÞ|ágò5nÒûv«¬¦Lÿý‹·À‰l®X xE››[¡5šîì PÅá)RE‰_Á”‹E±œÕè®ðw‹–qQSË&iMã R…–”Ë‹]»uŸÖTêFg7qQ°h†0;>FW[°Hkj×è¹ÿ›>ÿ»_Ó6 æž½{töì9½ñÞ›,Þ(ª ˜!Ç­ßüä“úå/I Î×Ü<::/=™¶áÂãä¢úƒ Ù ³ÀB/.¬ Ê–¡¢ RÉó58Úƒ‚T)ÄÒ¡½>Ð¥2^¦Ë‰¢´éGE̺UàË4Ô6"ÕÎÃÏì`pœl —Õ îZÆY\fò{ª1ß]VZ¬AºÌ¤ÀÚ $ˆwii;Âæb±»¸×…y¸¯>8{OäØ`‘!µúP¦à=Žókˆ…±¿eGgÃåæ±xX@¥8ýüúô֮̔لïbå3¹Þ{€k£XË\µ5r ¶ï8ŽÚÅÅÒA-ŠPå GbÎzY<ÐÊTÄ!·;IqÁåfÚóÛ´¦$ƒRåÌ:ó6o1^Ž ‡Û÷JKáŽR¹Ê °©)L)ÒMHÁG~uF?ºAŸÿâ_*_¹qù ½sô˜¬™Å˜„ïš™…k” Ž®(„¥PUYÚâµ"bÐè*#ùA•WïÔñwž—íþà÷ÏÑþWØ•aÚOAY‘Ê1pÜìä¥è¤¶¯­Ç³hÕûç¯ê‡W”@ŠNô¢9çèî`§æ È0µ“ URMõ`“|ýË_¤jÙyxÃtœ¬ó‰*†q!¦1]Ñ™wŸÓ£Oþ¦’ìæ;a!vÿ[ ÎÏh.lQimƒ*«‹uüèûlœ½õú‹(uZ`óÌ!Ïöt]Wüë¡’€PºUŠJ”ƒwþƒ7©–ÛY0%¾ únœ‡{u¼´›|ð³ú˜ü«º¬F.*o]e©bŽ\-S:¨´G ‰wïvòàÀ¨˜^Ë7JÒ8øýUHõb6²`¡s%ØøÐ: –ëCn­A±£€ËCt`ÓÀ3¡Õ¾Ê¦²i°wDVJYÍUAe]MDèžCŠ€hêÅ#YLà9,BÚ *• <=CåMN/àKAâ§øÜ"”Âaäy)<æ" [/s€Å~mfeÑ\ïx,“YUÇ4ñ¶ïܨwßûP«+: ð‡™Jß$Ik•§9Õͽ:€fÁùy®ÃƦ_xAÓ£ª¨©B/Äø½JÇ*ÍnŽ9žcriìïfSÎò­8t.†aš¿› 0 YfrìxåHù)þ^Íû‰â;ÓXú+ý˜X€«eØxøi€H7#‡OÁ¦ˆÍ.ÊÀnHÂÙrð)ì7÷‰×C4%ÏŒTúôÓïÿ/xï¦öíÚ«‡á&-m›´Ì{˜@i‹P@—hî)º™Ÿ‚º¼-DA­”RR’«zLîü¼j]½}G¶ƒ‡vNR¥VV2«¸ˆCU³ý[Vj`ŽÒЇ†§Éʈ?ÉÛ®ËWΨ¶¨Š›_@LâxNS¯dñêµk=TÁe8þ’ï¢)ŸBÌ`ÏWß|[žÒ*ýáŸý¹N_íCZvT—ë 2WnªsyÕä`nܺ’…6í ,|›nÎbàL©ÈïÔîí{48‚ŽJ’@N,„¿¹ñŒî½g/›¦ ÑŠQ‚h_Ö† ë §»³ 1ýâ—/¨ Î’ VôÐ.”;*¤ù̵.å¡“×6´g¡ÂÈj U7q®ëš²ã…Ó—É¡‘ßq Ù¨Âyå(]!ǰ¥Š•ˆ ˜Øl¼6ûÅ‹ª’Í]RÓ â‚xÆ"……gÄ÷vâû—‚·u­ë&EjZ ºöæ?M©8ø³Ê÷™ €4NÇË#ŒÃ¦†T×`ÏLãDgpº UHç›A0ðÀ±fBXSËY?ÁëÉAÙB*å=t³PäÁ'pÑÍâ»Ì¢ Ò䑸™Ù òZtÊUà˜ ìÔw‡<‡ï+þðkȽ RÃ{ñáÜ^œ|ž‰$/_O IDATÝ”eƒK¼¯BžCsp_²q««A×Vjߦm¸äƒlæfG²h)ÅÙÏQY#¦v_'ÅÍ5æ“1ƒsÐÅV(q‚rxÏÅ;¼_Üû±¾[üLlUEE‡#±0.h%•ÇÂbÚåf³XHiʆ<ýQÓkp@Î}ä>o• ::2Æ‹æzÙ)žywo'Òp ÛáüÀŸ%*î2<.¿¸X 1»v®mЕ›ÔÔºYeþ€Fé¶>oxàòli¶ò™|è¹÷¨²!µ4¯Š¯qÁC6mhÓãºN!±!§W: j]Ó-NöªˆŽ=C  ¼v‰à=VlqÖ‚r˜B–®ÐRd<[éͧ²ŒêU^×LWž…oàÆãïd€èåµÈÕ•è"‰ º@†÷WïU¶BôÇ,6øQï.µ¯[džŠ"³º4Éçd‰GÑ‹Âw2Ø."4vŠØâ"bŽ'O.’ñˆ… ÔZL¡ý9r1ײ r™Œ«õ*‘qÓeŸTÑÖ¦uÞfá’ÆèVé¥I-ð.ܾ’åRcÀîüêRU±m_zú3‡7®_Ï¢úäèè±ã*„Xš•!„tóÂû*Ž´ÖåëNW•ÑTVäfqÔÔÕ@°‹55=¥O?¶_wØLeY¼y­óªJ‘j ! ¤ ,^è‘g>+§¿$[ÍùâóH°u,Þýä§?Áp*µ(ÒS±fƒŠ©„Ý·.ëCP…Ïk?×Äk{ƒÖmÚ„¿2ˆšÑ«¶æf-A|ƒÄ5¼”™5ÛèpW•O>ª²i½Ê=V°3Pa5¦QîóìùÚ¼qÝÕ‚ªõê;G´cÛòKÕ­Ý4›VyC’sÐ!¡)â4ý ˜ÛjVÖ*øÁü›Â#?cv_ÁtÚsÙËh&¸¦rúyA, tøF¥v¸„˜PfŸc£CÔT¸nn­Y±‘I+M˜† ¹Ä³6£%~ºª¿€ A'ðÑíŠÙw缾ªef¯¦5/I'ZÐp¬qM; ÜM¤ß"¾?W×në½#ÿ ªêýÕ??‹Q;Åçòt¯+KÂm(_¦"—‹êtçÒ1µµïTØæîÄøìÖ…¹YZt K¶cÎ +÷ áÇðîá€+$ ‹òÓcaˆ7k'Ja‰ròø3x-¦äkúU¦âÇ ’øá" P€Žöúôç¿©©ë/ér× Á¦lÁ áiA¯nç·k)ƒ’—ÂóØd£ãºÛ7ŒÁ›—Mm $Ó‰ÜÚzÏø·›;´§ge«®+:|íÚ=pp'.­­®×øb§×£‘!Âg¼d›M¤¸}{I2žÄ®§ºÒ–¸Ùqbñ)â6n&LyvaUÍk×¢a/ižîÄ|þÙ¿Òƒ_ø’Æñ8lÖe²D#ð…ª_·Ò8&YQnß¾‰b×’d¡—ø;JÆþû±i_ãáµg«óúëtåâ{êœAF$_†Œc†Õ Ùvuj"9qA;·o¡ »Q¶€D7änL¥§¶¥<‚ö]/Òº‘ oh6„)”qéƒsçÁÕõÞ¾«{÷îU[S¹1uß¹A‡ÅY*úP;¬l€(2¬©âxXhÅn³ÓÌMO¢¸W¨Æcx%üž·ÓH¥ÁÅiÈïÿï•@¦ágŠÖTD®v"+G>DÎ\P)nó <ÃŒ¢OK„ê2À²²¹ð"ñeÕ–ûèÞùüj°Ãï(¶ ðDâ@ÁU¸R”H|­.j^³Ow‘»c¸ÓV3þ‘!ß´´JR)AÈE c…p‘y/.ÿÞÆ³Ë U tÐï<ë*¯¸˜éDÒ†›‘.Èðllð ·Ó§ÅY¸iY¥F‡ûQ 1 Yà[擇ュˆ˜äÁSª;6) Kô©±S¸g@øÃ|Ùôè ž|h‡ÖÖ¸xRФ  QÇxöùx?^r{ÛüEâ^P©Þž3ÊE råÚ´gÿ§4ÚuŽŒåŒÁjR/ÏÊGö&Ê»¸ƒâYx_ÄšØ$=\ï†u›¸g<²Z²÷n»çðNæŒürݺ|Y5-õ<„U}ôãÏ(δÛãWã­×°ŒrdªN:˜©î̱S–\dîó¼ ;*„Îe V¸•B°H¥÷ÐÙlí¾ÿ¡¬»ê Ñ{âÝ7Ô±í€ èU›…(ããÃÚµo_6ksñò9Ý¿o¯Ž;Mr7®ë`ÖDtž¡¡A#7M%'’`GLjè²[÷R êc`«rË^`.û\j­mÂWi!˜T ÷Ê¥óªæž ‡¡RàÐ8¥µe£®_<¡¥p:ë&ŒOhï¶vÒ­t„ÚªYnu¬]§!ŒÓaº¨aÎ"k6Gõ\ec-ÁOŠqäÍûIB<ä¨:f¤%v²þN¡bE€©uõÕD"bÛYªþ,Ñœ/4‰¢”Kvì”Jà óãêJìDNœ~bꨈæÈB”Ek&¢Ãàõi®×ÌE={«g>óe’ÊGõ‰§~Gÿô´ czèÖ‰¬ï`v%SX†°†€<ƒ¼ŸZ<3.²‚™W[—qh¾²Œße¦¬WyŸiPƒ•„õ’yð”Õ¤©æ™P/-7ñÓ·sÿ¡à rs’¸;IðÌ*EÀÁs±Ì˜yòøÊ ÂŒËk2rÉӹ耫 :“ë¹®H<sYVÔÔP„¤ï,±„ümc¸ žðdçòüW€Æwy¶Dcà…HþiW‚*J•‰¿º$ ÖòrݸÝMÜž?t†9’%ÃLæžç‰ÀØ~üì·—Qõoö’Ý™Ñ)ôñ\tý&õØQø@†ÕM¬€L©ÛÙp¡—:89¯v´“Þ-Ð8‚Ó/šãÿâ¥çXœV|€R6ЈÓZ%E$G-½yQ×6’Bm%:Ñ@4ÃG6 bX½Ž GñHgè2W Q*ë¼&ÈEÁºÛw?¤×ùŸÌ€<€ú».¨Ž·~ûݽѩBî#Cå¼Ü\ þ~éò qê3§ºÆµ¬iD¦v¡¿§Q?ÀÖ¼HóššÛš€Ca­íh×$óU­ÀÃ`Hòû¿«ï>ûÏDC à4—téêÞ Ñs<”)Ô}šˆJ3­­©U#(k ÁEhµ¸²½€<äã80ÔÆ=%!¶y¬%æ]¨Ê‹<[ƒÏ«`!¤é¤ùül?ÊŒ“¸}¥2Re}ךÉz6`OIQ)æk%Ùw!Â"+Ó@OîÜí’ߥ’Ôqe]Nž8Æä#jÝb` 9“lÑõ‘±9Œ<$í¹Ü€Ô.3Ì{k(«A`¼^Ôаø‡ß€;>;p2ÙOgdrzš…Q¦΢¼MM B”Q„èU<ÿÒùy N{ÇåŒÒ b¬h†­x^ { „‡á>Ì k âÉ Îǽ§Ù(g 4ÄB Óábl|Ò‹«ÀH”¶Pxa¡î6‰ô¿1Ù`2²DóK}Î$1!„š«'1Œ—ÔR·o@1 káÚi%f†uBª¨ÛLÑ÷ˆ,WQs‡æÇ{H = ñàîÂ$°±À¶íž‡G»oh’]Á/”7Ô««ó¢æiëµ(;áÚ jDq‘Ÿ˜òfÝøà˜IôšœÄNgÓ–íT•)]#†RMªvŒÏ@ª]÷?öó%DJxÁhV$+,¾¬iäÕ@~¥þõûÿ¡µ›·R•ÍÌ×ü§PEÅ%ø0‰ìb1±b•"ÊB\Á8ºrêíÙ}TÇ U©¼y9ªïØÊõ d­å\óž1=~p¯úû{³¸ü›4ȸk®éE8‡IÐ+×kS¨±º y4H 0Æ&¸Fg8ÏÐ믿Cüz»¶îÞÎs)×¶-Q~uhgvÃ>vÜnÓh‹#‘UâTÌÅ—1=‡’"sˆ«€wè.†Ø$°·®]B‹°èBçmbHºàÝY MÿúìðQªÔ7 EõÖk¯bê„tòb¿>„Ó<÷Òózó~¨ƒ#À8¬'Ÿø¤Ž¼ÿ†F ‰u>Ô†³|¸v •7IYG[›vîÜCKv2qòÙÎâóê_ÿñ_©’ýÀ›ˆ:õõ̳¼†éU®0Óo·/]Ò»¿:¢¶ŽàyS!- q[û›âÄä,¿˜ì›0—‡í2=v_o¯î»ÿ%,YJk;<ÈŸœ‚8³èSðªžÁ>nd†xf³oæ`×"\ÁVZ¥‹øYd\\eþÅ „Ö _óÕÌyŠÙÉa*7ó HÁI Çô$CF¦êE¨ÚŒ¤Œ“2¶ð"ãÑ) "žÞ~¦‹‰ØäRH€&HìV|—Ъl‚P$óÞVŒÐh PŠŽ†p¯ßýƒ?avçšú‰WÔ¢¦LXÄÆÊCtX¶’‘Ã눙CÌÉÁ!áIž…)3W”UÃA0ìœV¦"ï²P‘Ÿ‘S‹˜˜4]Ê]„"cB—Ø5UuåNrOµY¯Ã4hsÌ p§¿çNÖÅOñq¥ÙÙ+’¸…ª :Å D-ÄÌ[Mª° Xnõh.n—”0[˜ —fs%³©‚XÏ«¥¡Y±È€ÆƒM!ÓGà–ÅMˆ5¹ŒH\Ĩæ\îÕO7Ã<|±=¬Ö™ 1 0À=ßêBšvgiÄ2Ü+Éœ¾íéÏþðú¾… V_‹œÙrX>ªÎþ‡è IÉ–ºí:°S'OžÔÃ?ÀìÆmÕaØY¨.QTBv¼2˜†Ô/‚‹;¶¬—5"9ù‡5T)8:JþÅ«÷îÒ{g/«½e­~þÓïèЖ{´ëÐ}Tãfµ´6ê?ÿýßõ¹Ï<¥þa*fN*2©m{"9ž…€‘fE3O,óc%X˜?ûñÿQ’زÉs6oØš…5¹ñd<+æ‘…6ÞØºQcÇ"¸…•M~ìÜmVPˆw_ÂÀÇYL­O~þ‹r2÷…à^¼uƒ+Ì6'iYL¯7^^e•À`РШÑ¡jM+Þ ›`×…ì ƒÝ 8Æ"„²è`#p‰<8Â/0ër›˜®¹AB›å!e³àMul5ÉnC61;ÊS §ºŽì*˜*uãæ]&;iõ„xWÕÀ”.s0)YÌ„)‡æRñ‡>.\àšÌ¨F«Ï~âSÚB2wøØÓßO‰jÉó´À,ldsÀÌŸKçO#q©'‡{˜G)P-ø‘ŽtýæUÆSá“#(znþ<æ/]`ΜK17DØtµ3TyS NÁCœr;¼Ï[¡ÇZ¶ a³¡!ß,vZ@6£–CáX&á§{MÏ_QºjK Aà {!ݰÞÚ©‰žÛªj¿_¹<Çhx”wFyF8qÁéFy!<=ÝÉ_\< Óÿðʵi'¢™Áú:ÐIAµ:oÞQ<§”8ÍïóçùµLÂqž§.p·x¶ÖÆÖÃ>¿‘mU¢)â f„½e& ü0e0Ñëõ¬$K·m\«ó®)Ì©%sƯ~åËzÿô¤ÈitgH8ÔÄ{nצ{T]ßDµÎ¨®¹I?yîu-Ï ¨½µ£)¦O|æ·å+]£©áál£¥­EsÃf$»Ivv⥲îݽƒ)}ü‰Çuò£D¶ª›¤ï–=gô³?x–ŠX ³pzȃºví•9¤÷0¦+q”€*€ÇE¦-Eyj õZ¨»WNeñö •:„âg±™3ÔUt 0Òg’º‚¤ú­?ù}ݸËÌ‹Ejk„Ë0ëlž¦² aÓ)Ìa Þ€%C²Ì¢0ñxÂ, ÀР&æPù¢D¼ëðQœø&¦‹ï%‚c&\ų¯lZ›…VEÅœ"3=9:¨é “}Tjë*†¼ÄÇË3«ÿ*Àœ0´?ü,„UªºIzMEÇMÀïô‡çƒé,“F„?Ý´´´V/?÷3I.r-6|"‚´>ˆbc*;С ™«B¼‘6ü¤Qº›8ˆ9R]ZÍóÀì$xiž a!·65ªôÁlÜ¢,;~‚ä.ÒÑ–xþUȽlóÜEn3ØTÛL*Jp¬ɶ»ÿ…!CqEMHúf’Ù[ÑBx=ý±£a=k³ Ë+5~ã}už9¢;# |›¹ñt¡fbAÝ\?žœl_”*,*̺ïi»Êbà­³Xgyç9ð&;DßCáá#€™µZ¿®]g?8Aª€à,s.v$k& ›ç“Ú € §9Šf&Ü2sÁù(]}½{Š0ãV õrdFØœÙþèS_P„€¥0ÐÞÃT÷uýæ—¿ÁÂÈÓ|mûu’]ª.{b#æ°}σøÈÆÁq޼IÒ}Ä|8‰¶÷¾ëVŸ®"ãÚ‘ëd–á3óT޹¤Îß p*Ç8!ÃÒJf¸áQf’9I!Ÿ$ ÆN’r¾xù’²9§’ÖúMÛI5ç@ìçP…ð3€›sÄBàGÿÝ»Ärä*óó^SD<"˜Ái6‰C±Ð\v0kbä.™4?Ä™N•Nh5º„ŠeʽÀìN-1+5åqŒ «¹KJËñ¡lˆ„á/æÁ+tY;P/@$$‡ÅâA5轩ÇÇNB\EÍ2MLwn ãÆç5 „¶yµ‡a/s°Ëê%ýL·1€Òö@J ÊzË6î‘|ÉE¼xB¥?-tsΔ³Pl,úÅ„9§¶´0ÇõrÆW96‚Û9|£ÿÆ‚œLL"eÛ^?òêáN¼‹\ªu(I§N[#Ý™X`ÊšUH…w®ßàÁ ³3l47CêÔ| ø$gNœÖ(®x%Š ZªsË´ï#Õ¯¾ÊaêØYR´HnâÌV~þù#ïê&ƒ<Ø—Íþ¤ÓK:Ä|\Õ #¾ kšøÔ pó¾ýPkNfui?rßÈè *M€Eˆãv¨ëîmü‹’ì\—õ^>”èI‡ìÛ£[½w-J3¤qœf"2Ò…„ g*@íêEš­Á{¹y #”’ÏuÞ»sø¿@y,šÜ@¥®_¿€¡Ô‹<œÚõ°AÂÚ´®YSs|-ˆªô#b˜ƒg) fŒJnB+ U׉UZÅPRµ‡À0eŽß.ÆÀ¼¨t8LY©efÂLÄÅqÕÍãq¦f²‡%˜ÐÌäM挈>g’ØÁ$b%aŘäà¸PÍ '2§öΠxeèdÓSC+´‰÷ £:õë¿«‘©(uð,‡Ç8Å*@¨ÎFÔ½t áÕ0±»3—×êçŸÉBAftlÓÕ·cæâ›Ívµ9äéÖ­[‘º'Y.fM ìDŒ¼ð-ó08 EØŠðÁYf,fÅÀ3at&+lÄ¢Œy³½rý àqæÕ#v6¶™äp²†y^ýÈÕ[Û·fMÒ&D¿bplŠŸC^ÏQß4Ñ³í½ U¦þ›g!Üp%·Â܃Y›O|?@´‡±¤íÈüù5¬:y-~Ø­>²aƒo_Ån&˜í‹O?vøÀ¡Ç‰R𛵥¸Ó˜æ‡{ÕVR^âU’ö4ÚÏp;Ñ fa3Ä}”‡–"J½gÛe‚¯Ø[¢/üÞ7ô_?|V_ÿúWõ<°e .¦éŠ·¶Ã/Àä|SoŒÏñk¤{ƒ j‰É7ëå7P¸À·¦mšS>þn’µ{ïÃá†ì/Ç òSu¨JƒL^Q{{»ÜlšÞ[·µcóFÍ öc’U×pÀñ_à‰T2ŽÙ…$XߨGæ *L›/¢ ¯­/c´–È3˜Ø‰vëÌ;(¥z÷Ý#Œ.hŒê[N8}¦Sw©œ…@®$„[謅(O7©ìeðñÞ[lîkù IDATÔ?Ï*zH»¸€™ } ‰t›±’8™÷ïééV“9Wg™ç{ZÛ[!¯L&R¥Há9 ÀÈv<ˆÓ)¦3[á n •é\›Üf‰p¢…æ¤ë$P‹Üt'…'Øâ}e% : huíª™"öè~Š‘ü’©Œ…ù¼y8p² #pbd‰ÔÈ*€æü¸9§mÎ_„àpm@¶ ’’¹q èdÝ(•6j>]ËBg7€]«æ3¤k_AHIs}Ssœ€ÈÓÃZÉÃ$­B8™¦(å”`N†0TY¨H¯¦qÈš¦ g¸Æü7¯djb hÊyY¤ms)S“jX»K­mZVgOŸžxp…fEßû¡°Ž ÂÁ›˜~§ð,&ÜÚ¾…Yš¢®#‚bw[û­¯ê™/þ)—Ð#N½ÍA¦ 8‚#•æU "Nq*&Ç^1Z™ɇ é'x;ò±=ù©'/̇õíïý€…/ä94rôøA¤À"26m{öC¬2Ȥ³Á²ŠêZ*~#ò`>¶ æ›ä$4ÆCÙ~ßAµo0£frr AlÎF³ñ1äÞ¦&äcR£>tx3ãärlÄí®(ôèÍ—^×üü—úø'?¯wÞyE ¥u¨WxyåÙÃLôúõê<Lûè #ì¿w‡Ž¿{L«H·5¥D°A/=ÿcmؾ…ó²*uâg;ÕÕq(\UÇ$ÕKZ$ÚG§ ¤qpM˜ð‘‡×Ä,àä铊¬ª«ÇSîQùܰ93Ê¿óžÍ|æ)ädޤ5k¼iSHˆý=[ùóÌ©BÜ Ñ`È8È<ºgr˜€ Ó C.Cfg˜ ô²ø"Ì0dÀðižµ9*°‚o’ðñ‰9:Ç ‹ÎÂf1ànàŠ•¢²H7N"´ Þ T=üð}Œ'`÷©ïN·§ætã[ïשwÞRÿ•sJO|T×8’° ‡¹k cÀW  ï:…A< —«o©Å⸤bútBÓq7€ž³pšrŠ\„A€ˆ‹Êô¶R™“ø7®_ÍB+›6Mgä!  Á¥€ö|FÀ/Ø(aNQ1 S/PÎ$ÕñUÆ/üÌ®UÍ)Íâ!$íäåÂ$‚/žzÔÄf²Ãä«(V&J¤†<×Åo[{­VàHæ1žòuš9û¢>À >°÷#ªaÞed°—<p¨á…"bʃ'YëœI*üt¶›Ùvßsßaó¢?û™Ïsòà-M£±3ÂDŸkë5|ç†zøËÊ ¬#ÞŒ5¬@Ov¬ªóÊuH¬CN©‘üÕ0á¦Í›ôOßý‰rˆ€|xá=mÜz/gG]§íúôwÿzøc)¯²‘˜ÊFj×êo¿ùM}ü™/U.Ñ$mÔãà¼Ùá~=þØãåâ«Ê™Åh¨f¬è2‹Ö&:{â¤ÚÛ²ö8séËdù™«·zÐÿMXD޼XÏ dNtù6‚“mõå¼læ¬H Mª¨ä!øRˆVêà×c|þãO~ŒpãUM¡Ž˜ —6+Óh—Jp™»tëε,¯©(*˦jƒxåæ±1¢&tƒ±é8~·Wkjøü8ϵ #b…s£šgwñï)¦Yv6€iÒ­˜Ú>Ç$­p(XÅ?0ϓ͡k7ƒ8[à%Å8á |Nv0Oíar‚žø&ñ8K,Í ‘©<¾ñú½{ì(ϱœMäÄ sé…—_Ó£?¢§ ¤8§ÌEu Ícìv‰ï†ÄÖV–!Üäe£D‘ìl¼CNc½rfCkð‹Bº‰yÛbhT%dÝFØÔÎ0à9pKs<Ö<ÌT6sNæÉK@hsV$¹´€:‡q\H¡EIE4!›9L­€[Í… â_½¬Ö ëØDiätÂNÚaM™³,òiœmÆ(Eư9m1' 5[6¨Ä†Ä{Sƕ̭ÓgyJ_þÆÇuß'¸Î]¸ˆ*‡—ú®blan’ÇÄ$+WUQÉy Èï~âñà `mM-*­kâ˜òM¼¤Í[ÁÇ`†³ø™¯ý¡’Hi¢‘yÈ1-9Ìé„QHiHð'‡ÿZw®^׊#_›6nã 8»þó¿¡ÛÉyáäûªFe¹ÞÓ«5»÷+ êÅïü=d*ŸïØ­­¢•i|n 2h׿~÷ûú†aMeUrN?ýñszùµ×9°úq=õ±é×~Åa¹zôàÞ¬ÄëÃÍ­’ü×Oþ‡«Ô¾¦5*¹q íߪm›ZX@ùJxw»€D¸¤Ueèm`L{>íÛ|Av8›íŒ%$_©d6êa:Íx.ܳûýèÙ塀qMVñKA~­,~“p›Š‘9MxýÆ% W›,Œ ›jLÅjcÛx Ù‰ †b¤£‰—ã’§ñØpš)$Gª8J]ˆÊmÆÅͬW!1õB¦m„ã ¥Õ0È M°èìJp°ôäè8Çùu (Ù€Œ>;1 „ôÓ‘ÍŠ 6í°¾ò;ß@Åá”@¡è÷›/½¢úÀ¬&‡p¾‰Êð•ø$£¨aÕ ƒKŒÆR£æ¨4ó2&ŒPåKŠPÚðLßfÏÅÍsÏó•pQžxyΖ™=3[Z‚cܸÀùjÀf/3B—fH—Elh‰Mb™‡tÔ2Ÿ‘as,…·©ÏEİr&Ø)í$]Ã Ž†pøïܺ)7 ¹¹fm–Ÿ¾ðÒs<'x(g~Ži òhÌ÷sH6y°«ç¯¨hÄio,¡ÓŸ†a=ºw—¾öÕϪfë.ÕWpºImÈ¢xçÖ]¢A%$>Â\©…ëœ&y~ðÐ's(2¤À—Z^`Ruå8êåèæ´í¹ÈˆN”3§Ë¦§qÄ ×Ý·s¿NMþšj”#N$Ç…ýþ ÇtðÐÃÙöü›_üjvDµiÔа¦’ñÅ~E\Ç^ú)RÝN” _CŽ{ã…—uðý@ J G“ò0Žüê ppy­ýôuZ+Ç¡2c@ZÛÚ–•hßçÜAV~úéOêÞ†95¶ƒ xöòu–›nÄÙ³(cð;Tý-À>óï96ú¦[€SƒpßÅ)ßÿšXX6ÀzfNn3õGl¢ÐÇýpš¦Þ'œ©Êñ,Ÿ(¯¨RÇý˜QþG²lyiuVRõã˜/ÍJ©rÑð¼‚èPQQ“}iSHÛæ‰"yÙ`Æ:(2T¼|æf‰ûpÍ#1WéfæÑ©æ¹Ss“CYsn™…6ßËV™Ή¹·¦¶I’E‚i—‹àc(Èw¸ ^ëÆk¨Õ£Ï<£éá›BÒs?øGÝøð$Gû¤5táFÞ(AÄ98Õ¯OR Ü<Òs„\—é ¤á^%$›—cæ àǘA“1¤ºy‚éü‡vPTì@Á2¯až„Â9^ËÌ¢oìX‡|Š ‡‡‘I³RL?¨çÎReLñ‘D£cû˜Çòx¹GSN™“×ûÐÙ?$8Šg4¸rõì)Ú`úˆ¿Dá1ÏrÞ´a ›ÌNßBy5U6ŠÛノÜ[¤Ûc •9ƒÀQ¸?[]]¦ãÏÿHÃ1œµRe¤ªï`@–•UáùȾM¨ºu]ÕØvïØpØLŒN‘ ¼‰ìºqû6NyXÏ¿ömtÿYÎL-⤾úzp°]›€HX8aq#3ìÚ´v'á DFêþü/³&ZAŒ€[WsrÉ>™Ã0ìxønp_!¢´ÂËÑ< Ê¥µ³2‘VCú¯|޳cgõgñ—l˜4.tTëoþÕ·Àã±ìɉð"’mxŽáÅ‘wª±c#ç+1­æÍÁ BÓgÚ©xí½¬} 8hgsŠEYU2£@ïp´þõwÝæeHëÎ@¨‹‘k‡˜eÕG>ò4àŒB,ʹ~Žàaà õ2¾Û‰gá $Ôœ›Õšj8Ñší@¨KŒo¤uï!Šs’®ïda¨ghHû<¤ÚæµtIS‡_PíbTØ<ÁÅ sBLúº9MpC6¸Ê¤\òm:Ëèó&·Xfù9Çä>­yô©ép[XD.8Ì®2‡®ß¾©Í…nmè¨á?ÑpŠICfzØ(ÿùguâícºôá{8ÍãÚÁæÂ›Ÿÿð2q{œl¾§”ƒ¸Ý°Ö˜)¹Ó XôÕ•¥„Dg¶æ.`A~óèÄ0×̱F„D'ÇûQ™Ö[å€Rü’‘aÎÒ…Käóì$o\×pÍ«HݦÂfvLJÅ8ÚCŒÈL7gÈ‹ÍK)Û˜ ø? ãYÙׄÄ~ŒÌ0Ó‚;[;ŸžV˜gž57=M×&žƒÂæöm¤ÙÁ æ¯å©ÌÉN?)㡾ÛLÈa +ü®~pø.q<<ŽZ½Ó)[lZc‹îç…¨ˆ ƒ56Ë~ØÆ;±¥WÃk×¶1CQLõäµI3!!IxPs$f!€üo`à6ØÓûV½D:ñ90Ò8]Äœ1^O~ì‰ÇÕ…vï®]œÇˤ0ÈÔó“„Þ2å„/\Ò7¾ü—¨Þïhö¨Ê?û_Ú½e'ä;ÜËü,J Ä´¿ë–®œ;ÉBXÒ?¢Ÿû2+Èq€t¢FDpuât¤4ƒ.iN÷p‡˜Ôe"Ý­ËH¼v^ùÎÓÁû%ü3Vùo–Lr°pp´Ÿ T€‚à t}ûZ Ú±Y"TðbÔ¨Åùi}ñßÐ:ðé{gI¨6´1$T ) ÊUQ§*¢Ù]7n³ÑïêåW^"7µDU,§Ó™>ˆA²’Ô—Ÿo‚3õ3xeΨg¨Ê9kfT‚a.sxË<Áe/Ê†Ùæa¹ØäÕñ–€UQªiÜ£¬¶\…óC:°¥BÇNwrâdƒ^9vYÿë?ﻦٔe±XKÄ›êíq^潎 Qˆb$Ÿïj"QPb%ë6ÁoŒ—Õ°9^”þIz0;˪ÝíÙS÷ôÞ{¯)3éeÒHo$ @ª (¢XøPGAýÿõxøDEE¤„Bz¯3If&Ó{ÛÓ{ïuŸßzõ\^œO’™½ß÷yV¹ï{Ý«ÃïÅf.R‚C ò8ì7o^ñwé X&Â!åà½ÍñŽÆ¹@ªÐ9"Êå6\ql¥”ÔLc¸Kõdù¹œ¯Dì?+ Ex›(È êÜpÝÑáà©HÆôEA<ÂÄ:ÉÈÚbŒCa&Rtë*¥3 ;ÆæÌß»@.zQò¹bøj…l¨ÓÚ )”î:98LUÁ·çðWƒRbE À²kÛ=R 0 8’r!”²¿›¾Ï‡LÏ.0ô@ŽPÞüNóÎí;sâ¢Âåþë![RR(Xãdfo¦'°û:$ù@H5;YCI§ l h’6l]Ï¢F"È'á"ÜZÉhg5²“ÝÛ6É`ÆŒ´EâLƉðš•]Z@@úz$?¯XÖ,‰“'žy„ÔÝ@:{ñš:t/³Œ††Èºu«¥½¦ZZ{æå{GÐ2Þ3HÖŠäîኂi¶Žüö!ÇŽ q3œ)¦ç‰Žd3½Á8;•ƒ©n'qI‹¥°¦¦ýsd$± V;˜DDsFƒì…ž¨ºžLA4¿g÷éi¨"’´È“kgÏœ‡dKãÒ¶²† Ì]áË@À ôH°µ¡AÞt‘øØ  QÖ^/‡É¬ÍøˆÁa€`Ú© 0À…D»{z8(d:Êâ6‘jÆð¼UôË27‡h±‰ÃÕÓ0?˜àHd q˜•»W®ddDlœÌ­„‡Èw¿¹[Þ>zY7êä(OF…»hª±q% ÙYˆÎááp] bæ FÀ9TW´ñl‡§öåŒæmQl T *-ŸE&cæ"ÌpyUQmá™:9ãxCòQQÄl·"·;ýÉ8d&g¢“ÞªžBeíÓ@³à:€pÃ#Ijù„df–ïdãŸEUÏ€).4Ô6ø#î…á0ïíåD†ó–XJÚ‹”Kë³waåTI5Ai "¦ÙB‹išÚÊ·Œọ́è º°#2Qn¢„vw#hqžš;Іá‹Ä˜à^Œ¹Y~e-2üaY½zܦ|ŒIJ•Û¶Ëû| ÷G9°kºœØå.`a ªAY\lˆòn—H<’›šÈМK7 -TeިݡC‡$7?¶8PNC”î»ÿ©òáŽ>É /¦Üô$£¥fdb‹ÔdÌ\¨iÂ0QÛaƒæM#­þŠ*Q”ȉKì‚ÂT >%Ëf`Çñ3žãÈÑ‹<µ!‘Ev(•1Àó÷‚8ë”úòJÙ±6I¶f§Ë¿ÿõ¥VµÈ“n•¯NçˆFeeÖŒÿêáµ'#MÒ?ä—·cíÓ¼Ÿ}Ì~€e“‰a&O¦ÿÆû˜L„“Yàw‘­Gè¿ÔÔ;šš>8¢dvsw7Læ /¸ä4ñ˜,æ8aÈà ì»@ð2›Ú.Ø93³Oæ‚uWgêR[RÃÜb×I/?•±¨‘±èe3à‚ò7Èw"É }]dÙxŒÿ‚äöåS èÝæ,ܤid7ê}6GXÀs*S‰`Þ[8%e¸I1kq $Û(kçB‹€ê‚ïãé‡ÕÒOé ÚÕŒÜÉä#I©lóâ²…R†™|çû911‘,jé¥AÖˆÃK$J\Ê» ™2  jp"9"Ͱ‹ \5Ôí Ô¥#=²a÷L¿Ê=[6He¡Ö›!°œ£ÔtLÓÁ+ôc0°åßßûÿ§Üÿo’=†dí†%†ßë²5»@:nÈÊu뙥ˆ–SgÎʾý„<ñâKìþ`ÚÌA™ÑÐY*…ͤìezdÿý‡qhOckV9bÃDÔ·8©cÐÒP.}àéêùäÅ\E?Äš›u÷7£(V[z´Ü»g|÷åŸITT’|úá{² ”,YL ¨u™q`ÞNxŠâ²ÉÊÞN]ç,=Å DQÁm,ü8ØðD¾Ú2EüƒPÎÊMyåJ7ÂÌ@f/*‘ϸBŒªè|fnJhfA¾ø³Ö+3ñ_ÔÏwS4«‹çAŸcCœ8ÆXêožÛ%×.åJ±–šÃ®\Q9»=^þÞ.éÁEÀ§§r) !ØÂbåêµJy÷÷ß2Ð3'Æw)g¤:+Oc=B„œG|Ai‡ô™;ÊG´X ch—"tN¨“>GéîyP­qÔ¼Áañôs.FÞÙmeöe²u†L À²ñ¬@¡æA°¼<Ü¥ŸÆ~Û…òÆ^b†ObãÏëdágDÝç}xo~ _W)»ýЭ ‘Õ¹­Íì=AH9¥Êf•îLS%%À•â„ÂMÐtÅ%QùYPÁi.< ˜Ï» á”Ù3œUÐÎJY)#ı‹ÉòÀâ Vj>8=ç‚[¼8N÷Ju3F{Œ,Mã¾Ó=ÄPå›™þ̼ížm9V^üêLe1‡9LfnÖ<)Ƭ?“] ·.@_ÅŒ4È‹ ~T֬̿(DmÜÚW^ú‰|ëÙ—ÐÿW^¸›7l[“øÄtêD{Ãl,þðy`µ8¹gû!Òm;ÎYV®ZÏ S#œ‡Ü³y !CG4ʱ”‘QÌŽä"&\-<| ·ÃͤMþár~éð ëÏÿ;†ÎØjèV06²š>pÈŸÝÛ¶A µH%6D¼ðÑi(\žZrb¦üûÍ_bF(yO&Ü•§ž{VÊîä3)Ø‚\eˆÈ4ˆ¦qâK¶?yb®L$´ ¤uF³ÔËóÈ\±…>˜Ydüݰø(ØýaioÅòñ7¾÷éÂbÕ41Œç0¾·jvÊÛšš~ÖÁñ²²ÂN&±2‚ØíX*;6lù©“ûß#N0ö¯¿ýKùëïÞ7´M7¯£®¦ NK•£G¯P“›%fy lýƒí–2t?JÅY ”;fÏ$¦ýuFpÑ[ùܽZFqpãqxéÞ·#*Ïág¦A œ1„3‰?Rô:ăÑ|7ÝI˜Çú¬xx¦sð Žâ)"ºY¦«`lcÖ1×&`d'äDf€•ùë<Œª)nݺÎeUi“‡Œxra¦ úsÆ(›<é%Õ)ˆÑ„A2• |Ð]‚*ÿ1ñžùÝdä6M#«¨ÒÙ~'L2F&Ð)ΪÂ[€.xþBBzð=ˆMÐpz¾ðKî±8ÞÀ¦s³WÄ`à±€Se8Y—Ò×Çß/ÇR­·µ‹ÔÔ€4èÈrÅ–n V_I[Är–>>"µšîFiªêýûwbòe“¿¾ùê?'|‡¥ ¶A>ÿô]$æ[`2[Ä—ÆéÖÕShs0S ‘Œø Ù¿û^Ùwh—AéϺúã”òõÙ£ø;ùã'K kãöÍ4þ¬Ü¢äøü˲uó&dËáÆ"Pwg)˜箯¯1D” ”4W/_–î5\¶$8<…éb¤< ÄÊ Õð"Á\ø9tQ­À™“¤ZÝÌh˜!¬ÈÞB3j–?ø€æ È”ÑÔFÛ1êÝrú“Ô4ã£:ù7 à†î,4€ys,ŒüyAør•‘),>8Ã#MŸ"z Pߺñ‡AèØ÷gH½GQ-¸#YšµÔ‘Õž#’ìÙBY¡å•ž4én)^&Iƒw¹…Is8HÕ ½ZT°Ïd•ä_¸)'ÎÝÇù1êk‹l[• 4&‰á¸LÒ«a0 ±°Õ—Î\”ö y0y84Åa—·^ò¶“Qg,ø=ÑèÔº™ïîE:4€¢¹/‡QII]uàEYXßPC@šáÀâ:È~ ó2ŠfùÐô ÕˆNŒ&˨\]·U`Ç“eè£FéQ¦)ÅÈX^hàH/ü9,D=¨õ—\p<?6d!:£î‚ÈPyÞ•7t;J·FvÛ:j ÕÅ }ff€lêÒ Â5±#+ØÑÛæÉ2üL3Å¢Š^JAŠ3Œ‡U»Pz°„ÔÙÕù²~PÓe‰)2µ@F2ßÿÐã9^([µö ÇnÅLt¶çCw5·¢Ë^H´Ä/^†ÆêyéE6 ÂUÏ¡OIZÂM›á@½GÃ'ÿøÛ  &”ºy ŒŽ‚oŸ¹|¢Épô‹ŠŽ) E8h•ŠÛÅ’˜ºTc/ Äq¿~õ×E$æ%ë¬RKht²¢¢‚CA­ˆ+M¡é „'ŠÔΖFÔ¹l?ŠŠ6\1Tw!éI‰rüøÞ+`˜Õ˜-)-Ùà".ç‚`Àøêv×IT»žÀ„:§0,ªõ¬/ x½M«•=‹ð%™´æN¡÷jí!»ò‚y£†sb D^:ªšÿA#'pyE¡$ÄEa>ÝÅ Ù+ªD–O´v¦›w»ohb‹/QO°f¹ŒÑhž‚ã©›Œ)Âiv{X2êÞD Ì3¹eƸ€þgžËÖFöí¨ª“(æñ}¸àÉ(tê/°enÖ̪ ´OlÛj¤W !¨xQRPÙúû u™tƒ(tÁ³ã™Îqù­Z!èy¥þ·ÍÒ™pÞšág{ùáxÒÕÁஉ”–Ф9$¸AljÍdå¸Ð0€Ä¤©Q‚ð<aj›%P ËL㬦z!”±½#,íQ89–C‰p2Åï(Jc7ØûvžC@P„QŽ [ ‰ÂŸ¬=IfˆÃ%g 0 Ш¬¬”ï¢Àêä+ú ´y‚ØfpËòRGÈ-¡>z)å£z¡\jjÆîÇ‚î–Q8Ü’»oÝpucW½Ä°‚mlXzó¦Í9)ÚºÀ¡ù0jµ?@/Žƒ†Y¢ï/ÿûŠ˜Pä’Œ¤¾cPþò«ÿ+_/À‚² jR±w’%ÉF´‰ŠfÜ“¨1…ô™o=Ía*¬|§LÑtÕ4tËâÕ+h’Æ)o§‘¢¬“÷?ýBv¬ÏÆð {K_/†W‚ù]NÌ Êæ» $ÆÞ¡¸¨XÎ;ÎJ¯ë\Ÿ$̱“¤ Xw1–=¹l„ÊäáËéÓ'y!èœ@±já1l”$åEl˜âÐE2‘šËÐSº”b¡¯ö¤«V¬¦™C#„q˜™ k(Z9H=ô.”œ‹K®,Îã c@F~Wr®hz9Òeé‘â€Ny°¤4&)–ƒ¸Eª¢[.Šž ºaæ@%ØôJíhN˾g$õ{&H™£™Aá”G Â¥cI’Ÿ¿Xl¸ ÎÈÓ쓾ŽêcjcT¿ÃéOoþ¿ˆ.oƒê-Ô˜B»v IDATÊ»Y 2)ßyh+¯•²Nc€’OçÈwm`v§;X8"#‡ÃL¦sÆ«ËGö!0MQò Ó‹)ç3‹½«+ÕD€Ÿ—qÀ*˜ëQ?¬x"†;™5§Ï`æg°½D- ¸— ¼äŠjV#3²^Cê_Yz‰3lu0Ï•`@™äAi­s&:zì xSQ\ŽáC¼üæ—¯¡‡»H0jõ$èi­£‡@‚‚05À—ìÇgn¢W™ç2SéÙÄB6wF¶£:â¸û°¬Ó̈.Íú4sì-Ì2 ð?BÆ<0'B ¤ÜwrQ.X_;Š„`G<òż}ïŽTk¦‰N¢YÔ¹i/~P$7»²ªšÚ˜R"$ì ©#ÄbËÖ®”Œ¸Pùø£/i¨|i–ÙŸAj·wcð&Tu?cŒš“ËËjR ‘½ó¶ž[ŒU3H@tP'mÑr±RZ,Jˆ¹è‚Dç>K]LGú+¯¬wßø=Ÿå¢ð*ý4þÓÔÅ&OÊ%öwðç}ä¹{= |±áv’[^%{è9j |Ö¯_G” ¥ï‘yÐ]fÏÅ<~îõ.˹Äí¸¦t¶0ö‹  Ö[uNˆÑh¤æS“¬[¨ÎGÓTŽšà¬t‚j­X³•ï;ân@µ•({=PÔêÞ‹€Ê‚Š!œ'å‹‡Èæ¯s 7êÔ` Q¾,zðÈ£laõã½8C(G§&ñ»¢þ†Åß¾.Πƒÿ60VL”œS{~"A–®]/—ű°ùHl"2ã#[†úw %Á éÐüû±4›Óòý+é=pfĉ½±ª €ƒ‹t¤­ÈØA –%Š4qêL\;.~C7µ8lø4<“‡¦bst`ÈX'à€ÚבLùÙÝßcYœ>ý)SŠ”Nè æÇ(A‘渗O®;APËMXtz‚JTß M¸½0ѨëØfh¨iÌU÷åÄs\–¹\^þùäí·ßç’c´gOY=À®r~sðB\kÀ˜^‰¥2QÇ]3‰NÚ豜yîÁ^,✩³d“µ…¥J( *GÌSôlxX•ÔºÝÌdÃI“>ÇÁìÁ~@,¨.ËžUÉ LíÛ—ÓÄ7: yp)GÆ8rQFhpܘ‰˜Ã3h#HΩs_‘nm”/g ÕèrXÛ¦ænÙ°mÌìmÉùŸâ8r ´¹hÈóO>NxÁ›æíÑÇ‘<ÀW¸1½¶(%‰ {ßÑ)yW¯²IÉÌ0•¥ ƒ3”Ú¼wUHé]¶Ê"÷pÏÖUd~ë]ÃŒ!5o,Q·° T~ÿÇ? IY†U)‹3‰Bãro^5æ¹ï–™‚÷¥¿â­Kur^”;‡UYù>Øþ¥˜a+ñåIïК§ë™})…ì‰îöîÁ¨–‘ÿc±ju6,¸Ö–zx;¥Eðç|¨qÇ©cé·:½aÀ?{ZÛd÷¾mÈ9àB8„”Þü³ çCLïtXl×®]ùXFÝë ;HÆÝ´n•ô\ Vva´¹b0ì;.}ó\¿xRÇvB" õâ•åä×ç8°ü¼ü‚L/—Ù*ÛS—æðÅP..Zž"ïÿç 0ã¯TööLRÿ+àLmFza£°£ü›ç=«ÚZ]ÞçˆÊ&þo{¸ 7WúÒ$<¬èF_¦H“Zsj¶wñtâ@ú0¨ÔÙÛcHf‚£SÉNHs² \ô¥\§çt@WæŽA[Œ¾3Äœ:ݨÄß y9»Ý¹@ê!<(ûv’+/6RªA0j&Ó £ykjh¢7Ðu:÷âÉA·|)5 _½$f¾‡Ú§²0žßO…ä§pÂ^jžïA&êÆâHÅ’6ÚŠPž¯.ç¥gs6©«<ƒw£(Žöq6ëÕs `(õKŽ£ÀU&==™ò£Èx2¥”*§v0¬F— ²¶ ¿øÅ+òÑ''äÀ¾­,À\’—]u¤ô)¦¶vl;,eµÕò›ßþ¢ wA"ÃÑÏ?3ÌàZ‘jÏ‚z8ÒDÄÅ13A_ÃÖ$àÜvFX3Ò’ˆê,¶! µó²¾qßAÖ¯ÝÞK–-;÷Ã[Ü”Xu{/V›qÛó ’½{vÉ«9¯2´Ÿ]?nä­¿üÞp&÷å•òÝTÅÚüvmÛ)ï=*²7'³´ô*N†˜©`œ;eD”°«/Wqg–Î/k­¾té"Ò0/`@½€dGzeÏáû ‹M_še©PÇxöùõƒzà œüò+äß|öBä9¸Ä÷r‘ƒü@cnqh§½EŸÄ¥Éƒ²cð©žgÉ{Eõ±™ÒÛOÞÿø832 ÈëÙgÁ…‰K /£opåp·3QèÏÁkê”õk–ÊÎ={Ä6By P`fl¡xØ™æ× ;O/ì‹TöKlfU*•²ˆb¸ƒèâêm¸È5ýŸ˜KáðÙX è’ M»Š§àJÜAõ|Jê!åëåg¬ ¿pá¨o¬d%Å“½QÐN;ðƒt`ÎÙ-”‘„HŠuè~Ÿ®µ åY¨â çW¯Ê¾ý1±Ä9ãÜYǤCcåHö룜ŠEÞÞ7Èh7e¨=嚉þG§«j™Oç3²ÒÛmƒ^ºrð}0éF´8-ò ¥ð\Žœ«(¥1죒pCÕÓÚÍÌ>2%x5¬Ó±ƒ¿X1ïÙ¾'' À äÅ ˆ4•º‘Aš‘à&¹mÜ<0gî6\EÖ¬ßCU(y×®ÓÔ#óÆ*žÕé²2=mM õ¯ &Ðéòþ¿“^zžˆ5ÌÁ ùÅ+?„p,•M a C¢A°Ž}Št“3JŸÓgN²b rqƒ|Ááþàãòƒo?ÈÏUXƒ[ü21ãÂíë‚ ŒtD ƒJYc!ßûÞOøý‹dÓÖM8;Þ!Z#i,T©­«7"Þ4^T]­MÔÿÈQèI¦HûQûü##{J±d ’i€©Wሸ`—í)§yÇ•,)9M."Üô&2-°'°¤è¦Ì‚¼$'„3 "wáCt·vÏÍ;(˜?£å“3?»‡þb¯(É —iæ‚>¸Ÿ¦•A²ÄHÙºu›‘#)M:*˜dñ&[ }dž¸„"9¢DêîÀP/9°c“˜€mc"p¸„WX‹ú¹àìY²h#Žé t³bE qäÙ§ÈX\0BR"aý£¨¿ûzú‘ºpè¹ /ÛÈÚàö’ͺÉzœ5EQ9<°ÙJ?ø¢i ‹FmÎ w)nŸeœ¹ß`•ðûžGÆd`dwS*ëDA“€°XC£¥¹Üà{N¼9¬õ©)‹åöµ+€6éÛßQYR‚²ú:5 Ê_2ß8TƒžÑ»c‹¬ÄÎÏ0äþf‹åß0²Ç< åš •Êbx·^ž>Éd¡@ä%Eö#½”ÕºTÕÃâÍïè‡ÐºÞž¥Ê!kÙÚ;¹Ü‹—,ÏQâFñúV|æà5´éä¿*[ Qâ–% ¶‘¦¹\–µȲ•›I%HÍ׋ž¦«g£QïÛ$¿üåëüniˆ\©“ì­ÙÔ‘~ Þàþ¡òÂwž#:éÂ`êõz ÜB,²ÉNù’æ#›÷ÞË ÇLX»Ü[)—‹pï/‘ÈEÛh†AD¶µÂݬXš%¯üê×òþ¿þ Ô‰‚6œ¨Êƒtá : ˜µ¡nmƒ=Ž#2D/^ÎìAÆ #ˆàÂ!âB€Ëˆ@1ÑAræì9¬Öc7Š-QÊ2§ºx°Z÷«‹"ë!@Øn”TˆÍžß¹»§N‚iÀ·g/a>%ßX:o33ˆµ H² ·’.Y¿a3*09ýÔFÈÐÆö&É^»”^%Fþóá»’’Àh@\Ï/’âÜ+ÒÓ\'3µHÀC@ Õ¤m f¾¬ž_ 6Wø¡@<žºeÇ7°œ“ÌÎ)>ýú?1‘Ø+qß~Z<Ç4G‰ ØÞsdxJ»)ÜK¼ @“ P“p*„4&N<œ¾ŒQSÆœˆøó”2“@êúŸ ˆHP šxµ€:¬þƒ kjB§`ó”'6"»³sòš:L Y[^D¥ï‚‹ñ1 àçÌÍè’“ħ,A5\(hÜ“Á·M[)ëÃò¹._<8’k‹+n‘ü¸ \düýX•M `qö.æó3[ÑôbµÍõ|.št>G€U@ëŽHÕ¡ õ·Š7Ÿ_›|;.ÈÝÒ˨GAÖ•€ôˆô•îdB W€x¢6wÀÌܼwÿΜ°ˆd£ô:U' ¯&øˆ¢JªxQ«%L(L=!@]:ÌÛÙ ûù‘F]?+«PVrh¶l}@r~û7V%÷I!Íò8Ö+K'Éݪ*~¢2xæÊª|Y·ã>š>Øz¡ÕÔõ¥E—eÿÁûPÄ®¦Çˆ“¿þã=±ƒS†Ð ‹P”¦˜ ÇqBÂÃ(ÙX ÆûÛoÉË?ù!NùÌÍòæ›oÊ¥Ó§¸Üì«ËΖk»Á¦ºº¹"&ƒË™+ 'ªgÇ¡{`éÙ›ÏT…¡Úm¤ H?ˆ6U­Vá‘lSQoå‡Â]°¯¢©JB3dùâ¬!Ù»s+VŲvëf<ŒkåÈá=†R¶½½OÖ®S¦j¸‘zék¬‘JÒzky=FÍÒÙÑ&/<ûœ¡ÖµÖ50¼å ÃÄ/€’­ Ô_ý™Ü¾sÇP&G„ómð7Z{§àŸ jÕSÀŠ\S~’#.iK)EfÅ.:†!"‚ÏÆ5âgb‚Ùæ…4ȈïTâG)42ˆ Iýä4ˆ#äýÖ<—d xÖJ6U‚M-VuhKgÔuÅ›«7ÏžRMÝÛ‡€iƒ!9ý©Ú}ubˆ^¶ÉZoHIbSRy.à}¢ck,'ÐÀPâu¢À0s@}¸,=­º$Œ×/<òǂش€õÐ×è!\øL{NâþÂE£OæsµíëÚ¸#K§vŠ•âNÎ%Ò‡ŸS\XDÅþB …>S‡¿t9ê" ~{ôee´áQ\žÅ0—†C̹eü@¿ߣ¹£Õ`áG0ŽP=oJÑÕ«²stjmÈq’H§i‹òfÇ•L×@ƒV®€ù-20{v½Q{—T³j™1Kg'<ˆž^V)cí¹mãjš² yàÞlùâóãòíü}àKaa™uÀAcaÁ"¿ ÖÔ]Þ?ó°XY­F?ÇŒñ;¬Mˆ“Jš÷Œ0ØÎaФ(9WV- `”L#Ëö&>üK/¾ ü¿0"TŽÑd£«—ÏÉ«¯ýŽí/×Ο%ËWɹ 9Ý,å%·9lQe.¤1b€‘ÝZ+¹·nȳßú¶<üØ3ÆŽ üSÔöê!ÛÕZÍP?ˆ‡!.e)r­ì(B+Ç+å/žc ̼•g5rgâïÞ.,–»÷Áiy¸_[o2ãn¢0Rùq`gÊÑààÖ¯¤¦6ó×.]¤§˜’ÐðT¹rù ð6®êN0ÑDOþ%Uûz({áWÆ€{c™epÎ>@ÑMˆGî6BL\jþ7¼¹ì©fÂg–Å™‹¡^¾þ«3ľƒµ f:ÁˆkŠš9¨”»åd@5UÐ~°Îöp¡,ÿ°Ð2vªU®QUU"‰ h¾¼ÿI.Yx ÞTL£vDrnOÆ¥Câ*8ÍÀT«1bb&tÞhL ‹v´zæÉ§Éº} ŽarñkŨ]¡F$\)›jqõǥߦ¨¥«ã¤Üm&£`ó:G¦Ðšå%FÖã«cÂZŨpÒ‘ >N󯽣6õªŽæ¿yæ3«X‚¤çX/.,¨¦A_»P èÞÈDƒùþû¿‘3OÁ9Í_r€%ÖñDeÇÉ“Ÿ±K#–Ûµìp$¬ë4íü\,t² [ËÄ´å4žI,¸¹F?ÒÔFÃÕ"Ï<ÿ*b¯IOÀ´s$++Y>:ù•dP¾”²Ûî¡}{ŒfLícâ‰~}û ¦ÁåèGŸÉÇÿü¿g»žU²mϽRÜa•;_çKL³¨J&÷<øØ£rãÒ¥!¢î¨,NI7¼a#Prÿð#Ùzàì†Z˜¡yé7¿Á<ÀW6ûŽ@”9â©Û‰EiXX”doÙ?2†ÊMƒK©¨°ÊÚ•KØCÞÏ< £º QxÏȦ ¿ùàƒiA3UH¬ûÚ³·ì”ŸýüWV m J‚éfÖÀ[šY‚3B”_|ר?zç/Ôßnòù‡_ȆÍeì×_'²©Éù˜\~årÚñ"û) Æ8$ÈëoÖ‰êåœè@µäm®i†™ï–ìíû±Ãç×Á1YP{q™Õ&–†Z…ñWó„šaA$c-íâ†,Ѷ– ®ŸÑu‚þC!W;Þ}y£Uœ@×tÞÆƒ!5Ý[“„ú—•LE&ÆFC°±F ™jof8ŠR‡Ï:Ìx¬=}•Nç9rÙ®ðLM³YÐo¨F­µ-Jx_÷š¥º`éµàE²×.ã9yð^%ÿæ -Ù¬ÚKŠO3OƒG+ÓŒ«ãÙIFŸ_ˆçr (ãê&ÕËWróA'L’ùTOåDaqd1…ᬠ\aˆ%cÓ&@Oi³61ô< 1ŒõPÿ`;T ‚ Å‘ß•ÊżaãÆ`[ ÞšƒÙµ0Õ¦ÈFæò2Ð@$¡ž/B¥ë$§ äGè3ØÚTGáEÃlO‹wùZ.ÊHpi4T3càѼ¯÷ÿõ–,ЀïÝ‹œ“eîÆrË Žˆ/JËNäHÏïÂ!ùôË‹²’Å9Ûö’eHÎuÝpC­• £…m›™ÿ^+¿úÍ/äðCòÁûŸÂ”»áç„ Â7ˆµ˜0˜sáÄqi¦LXP†Ê†aúTµ?1 IRPZÎxl*–@Þ\rŒŽW,2&ꆈ<ù |-%{ùB2Þ½“‡ `|ûÉïK5}ÂuFŠƒ™(\³q³¤f&c ׆¬b\²Ön‘[W.Êi”@ý"°Sß ‰é¼ Ý/(À™M‚„ÆP’äÝáàL±Î¡’syI Ü*€Gb"³y|WFÎ@ÆêHØÖÜ)Û3—‹³õè3ÄD9l£ôQñ…?gëm[EM•°,À%‰=a«|yâ,M©ƒôáv!‡]š /~ø¥Ü<˜œqvF„ÖÅï z§ 8Ëç¡HIæ«z€½”HÃüìÊ72“³ #·@ËîþÀãvuYK3§ïOð¹ÈsÃ!’½%<{{ln[Û‘ƒ0üô¬£À¨B¨&œá‘.ß)DâÓiô±:ƒ2É&ÙwåwŽÑ°· ÃÑ5ÈŠ`+Y!ˆT”C7×HvŸñ„¤Ô‘ U«ŒÞÏ­¨—AÞÄÏêùKajp ¯‰ò/ô¿ ÿÞB6sárL ¹ñ㜛Wãî^ZRÄ>ƉB}ÜD…ìël‡ÝM68?¤Æ¡RU‘K4‚ugD“:^›xEŠV,Ë`He/Ü«J$A!^Æ Ž_'Ǿx[Þù×W”UÍȺƒ™Z\ Z@)ÁÅ™œ—_¾òSÙw}rñ«sò§wÞ–?ÿåM9°gz¬£rëÚêý¸ÅX Í&"uIˆA¾ / ¨¢¶“Ç¿’ÇŸxçÃ&Ù¼a ^Hu +5È‹/¼Hœ’o?ÿ FÔ[äø³Î¯©*eUãµh¨Ž´'™ãZ Äìm§_Ú³{oŽ M¬ÊìhrR*P{;ro^Ç-$ô࿎®ãÕc¶œÐ Uü©]éü§‡Ñѱ×egÉÕK0¹4:ê˜wý*$Ù€¼÷Ö?@”ÆdÙbtý!¸ÂS&TSþó÷Ñ"Å1žÛ`<•`è1–,·¤O˜@¾qíZª;)ú6Íp£œ>v NöÝÚHY¦+{Õ Ý$Íð&ȃ€;³8àâÔÐÇNž'ôcñQ1ÔБRRÕ$?þÁwņÖÿú¹SFCׂfÉÚ\ËN?¦Ñ-ÅœÛjdæ.&ÉŒSBØtÆu{hDÅêïTup‘Ñà Òèî£Qw!ÕOsá³×f™:Åß‘[w«9p LS>Áÿ];Íç«))Àu¥ãMdã*.4<§©Þjé`2±–ÑcÑsir´4ÐÌêb%n‡9€ü\%í$TÚÆõbTY·ûAyùùWäßù³¼ÿÉÇò¯ó¤™(þÁõ›ò1„ã±ê:¹TÿçËr¾¬Zê=gá \à†¦NŽh [™£¥Zö¥×CG´}ëzàe$ì ]ꮯþSÈÓç J1±qÇeãŸG¦4>Š/Õ8N+”i³d‘aÎJ'}E2Á@Cø÷Ii©c›9 eü=U{?òÐcð{ø,®òé§Ÿñs0ÎÒ±e5bÐu€&‚SʉqšöŒô¥@ã‹,Þ5|ÍdÞBPêŸð02Íê ê’T?\˜ÊͰÐp8*ú)>·е˜Á~EœœÇjȈáT<ó9ƒ]ð;¬A‡ç1¿ô›Wsj+*‰^ÌþRÖøÒLöQž EN¡œÉ+.ãË#e·u&q˜ ‹ÄVÒìj¤ô ÐP öÑ<+QÈ-퇸ÛËlǦبIý´EŒ·‚B 8¾ýÆoJîå<ÉÈÞ/ëV¤ÒÄGão»FÎ|ö™,XÜeõ’I[±ªnNÊòïÒ»Rb@«‘ÍY¾¢F» OÀŸ¨ ç;oÿC qÑhk°J+M;JF^ø¶‹$&c=ýT³>¬L¸%'Ï_’wÿòºÜÿCÌe}¢ßjªfîeý ´[-€êôyÞjmÆ'€¬—)Û6¬Âš´B¶lÛÁaÆÙdn)CQ¸>ÀƒÖž.9¸ï>²,æÌرê áàÄR v—‰è¯¿þG)Æxû[}ôï)J”CûösèXlŠ’º$ïA¨ŸŒ•RNè¶©Ä} ý8ò<É8‚40®1»Sv¥P®Ÿ:-. _ö‚aȸ>šû¾‰ ©klÄ­rR•ÑXh‚µÖé>u½·)KÎUe<‡°O!Ýþ©s6@{oõ*ÖÅ­þAɆ·r'Žð ¼#½TZŠ;“%s/}mx!«øÐf«#ÜŒîíðEüêÁÞ8e”3ïH‡êLŒN”*S¯ ›F†ñ¡äYNI_[Û0„ßQÏ™³1ÅAoÁF>ãi•©; ÞjJÈQ& Û@'¢A~tá¿J9nÖe‚À3¦¥­”•«39ØÔ­—jbµÊ¡¡ `kQ©œ¦Qwdtˆ ëHýîŠï’ΓoZ›ÉÏ›g†FÙëŸ~ÌÙ&JÍ1CU”[ßùÎ^|—lÉÞ,ûvì’×^ý¥Q#ëʲ8œÏ]¹€ðo†zý {il‘¥ŒóYtõXt |HL:èKæ(ì(§šù¿û¸I¹Ú'Õ4·J=Ì(ˆŽ:FbamzÏyOÏ +ø‘¤Ùk½zÓº° ua¡Mû2ÐAUÇ*Ù6Ëá³éΘ ôŒÖº Ãc7¤JeîƒCúž±ÒáBEñþC‘n˜àAJfûiæÁA[Z8 ¨lùM•ü.gXìPP…I]Œ]õ*ƒ÷Fö‘¬ûúÿ¾ƒÞ­“þ ó>Õw¥úѧ"’¡g°yu÷¼îAÑÉÀÝ»·Ë­Š[Àðéð$¿£ IDATr\BfL|àÙüü™(½{$ ‹*J7uëœCg6Ïh€ lµWZ¨s`„ŒÁg¶VKë¯ÉRº:O93€ 0Í99?Ï9{ò‚±1U§íÔ­[kh…áúz9ö¨+sYœ"_~ò)d5;uì©'˜ðï4³…z_Q{Üùt2nYVÃþwÈÛ`Ó|ÈŒd,ðv*6/>ªÜ/¸ˆ“È?JŠnÉ­ë×x3_€dÚ™ÃéúÊÅóͬ…ÊRÀXpò^"ÔŒÕÏvŽI«Ó~û£ç¥ €,èÃö¨"u4º¤Î­"‚·õaFwîi4dÍUŒí^À;v–ý‚1¨âX.ßL}Ú)ù ;[¶lÁƒ©RV-g›|†“= f"¾—/N|¯`Är¾¬œã ½z»# „w™ä@8QÒ|ãà6žSªP.^C«$,]*§N_ŒÍèñ.Pú$džMú(QÊLÓ1¶6+“€rN¶oÚ$Ë“ƒ!üfˆ’h€a˜ÙoåÓÜÆÄFsØáêÏ£j–VÞ“uûM™üÇ•«Î–h½Î ce9ôa@Ö9+6Ⱦÿ’”ˆÚ±ÒK ÃÌ ´âóþ©õ¸Î­$&Æľf,MÂ/€å@ˆ-̵OÕM˜–W”t@Îø9ÃÊîÈ„ÔCyŒLïÂ{T©ˆ3åT]uÏ´ž’؇J†÷âÄùQ[ÓÅ©K! q⟙G«F)Oæðv£¤£wpse' –8Y xíÁþˆ}ã@›E€=ŸÒ™“®¥VÉLM ^Ò|5tã³öAnÚñt…f3˜re ý +¿ßÞ Šô¬¦^”ßOmñÅ{ðóœ_圻x*‰ ¿¸ ä#,<˜%:ªÊ óAÑDC5#7ó¿).¯ö3<{D€ðî¸BB©ötE¶©,­Áý0ô)‘ã1s3›»†ÛÄÅÆs Êwê@¬ŸÅ•é@w$/‰‰)ìöëeuÛnB‹V#Ó€§þÝÿÿм÷Frc{bqêÔçÒS]Îóçg0œŸ_Á {"µ­# W¨CùÆñDÿ!½Ü¥ÕÖÕ/_S쩽  PeòùN0{;Xòë”löÔ¬½mí*öÁ}°ƒeó¾dÁ†új¬Yƒ`ÚÓ%¾èn!Pô IHJ7635–]é³²V"R•óWÎËÑ?’ÿôGrü³ó%`‰7„k(2ìGŸzÖ(ÓxíòÅWg%>:Šu ½òÄ΃²vóy,k¹lE:éë¸ôOó]ž£»ü&€Äßã°SH–O°üéê² ƒ5×Uúþ¸NŒshèK'(3ãâ%{óNÎ'*ãP¬G[ ƒ2D–÷§|Öuôä¨l#9èÕ×gý!z¤哺ÃtÅ[J8ìL2R\ƒ•ŠÞ à(f-ç@·8kÝ”GC~>:úªFàXú HCþÞªà`”^¨{û¤´/·¨Xc‹Ø»GÿJA?ìåoÌ Í2"ÜÕÙIù†ššóêô=Çå HR×þè´,ßw„±JØ3ÇŠ#å™.Ý7GU~V"œêÅü£ï¿˜S_QMú³½‡?ro%c©3Æ!’zúGÀ»#©Õ±aáA,NIÄ/‰Ú ‚p?¡kŒ?:€#O¢”5ó3ÀÒ{€³–§ÓŒu1úe÷=kåÅ'· MEbAŸÅKZzኙòjdÈ‘ˆa=üü³lbÍçw¶Ò0Wˆ]»2 ‡à?ÇNK2X¼Bw‹ØQ2dGÙ¥J×y·0õÐXœÄgŃãù}©WK@EâÒy@lšeÔµhõÊU0Á¨SýXÕUnXùÏÎöKñ-vª3Þ[«¦r£Ô¾Àu,Ú©’„ ¦c)‡NBâQÓ6±Y7 <œÉ<"eãŽÝXð.·nä²Î(éÌ:–gO^‘ÑžZ Á$—!/ožU^E“t6Ô²+“ŠÄh‰¥\Ë£ì\ÚT+Ÿ?ÿk¹ËRµ¯YÅž‹‘…!yð¾MHQz$ˆ˜á _ÁÄ¢N$RqHÍÆ¬…#ÁB6ÕïÑ™ í C=B4ßÏ÷ÝóÄS*®”—nÞ+ /_dàe<¯µçgø»:É^*€ØU«Ø­È¼63ÿn éÆ.Ãé' óŨ›¹•ˆGÁÓ¸‘-öïàÛã#ì bãlLÌQÆÔ€ ¢2ÔÜúàþƒ¼;­ ØùÎïºïáÇä“O¾`ý‚}”å€!­WoÈ#ŸÿSìà ,ô(  Wd%áÈGîß»—í\J<{MNÔàðBåÁ»sfñ‘*­ç@þtÂNý§43ÌÙúP;.ȆHô‡ `´·~@EšóãƒâÏŸ £ïÈ¢lY#iDv`[¯èD4N]ˆàšÔX]Kf'1dŠ}N*%‡Ÿ˜J%õíéÅÌ4·ìvQw¢ý¼UQ{Ò0µ´ÐpecKGc™çï“×ÿÏïå·¯ýžsÃÅ¥¢P—÷>À %¨’ÒÓ×0–˼Pt| Ì ´‹õ•Èå©À’º´ÇÐWŒ´!åÁKùÎí'²’‘f„¬Ê³‰‰Ž£ça¨-4Ž,i/›Ò‡å«Ûwå•oÂ8Ï 0g ýNLØ'ËJÜW_ÍÉéèí§èâ1 îZ¡™n Ä5»s13µ¦¦?Ÿ™ñ1òcá Ñ".2YÉw3 Ñ"ÛîÁ…ãz>óÏÝì[Èb|·‹qÚ(ȲLJ4/„l#òÚOŽÈÿ÷ÇÿàĔٹŠÉ™µ,¡îm邈"JNó\NLr˜|#’á‡«È _L=ai{ÐqQi=ØI1F£æñOùcz2Bœ£ðpåBûÑCÑKEDÅ‹5ÿ¢1{l¢Aóö÷4æR(niÖ9Xü,Ýlí@ ?¯kœ1Ù‡’Ã;Ù5™g­¯E^3*?{íÇòöŸÞ6`çߢX&£Ëµkl² ‰”bÔËóv,¹ ôÃo*FêÉ( +i˜U¬ÆrXï·v€J9ÊÙ/?—Xx9ÞÁ’5Ëe쓯%ê±Ãâ—,½gOJƺ,kèE:%Á¡:¡Ô‡e÷“†~x ¶ Iµ6™á h$ͬ™‹¾ÑÓUN¿ù†˜0QJ›h’m u­”KvÆ`ÜPÔ…%Ú;‚Ã*nFýŒÔeR×Þ&1©¬8þéQYäîEVëbùŽp®,µzf©‹Lª|9”Ÿþ럲vãˆü^.»LºF`Í›é1hm`PP»3â <ïêŠÖË?HxHUÈ6ˆ#Ê!cƒ!f½A¢ÔŽÔ¤­z®YÒ®ÇS'Íq.v:%¹ý]x‚·…l“°¾Š¿ËØñ4cÉñÉ2Nå‘¶›QìX=¹´A”ʾÌ×WW•Iúêç䯿LV ¢ÉÇ¥ŸKêxB2SPóþ*ç—9©Irôƒ‘ÇÕ|9$ 4Rm-ºç›À£†o¯ÎÏ¿Í2+Ç‹S';˜µ3z; ¦fö¸âµYù{>Ø€R~¼÷†Ïé©\ •$çÂ]t#Ù¸O¾:s[’R|%÷J /ÉŸ2‰aÊ”¤è˜d{ø0OÞoDó úë…ꃉ¤ì Oˆ SŒ°D§TÖ­Ê2vì¹Áš¦aH|—±^Ý?áÈd¤J¤]ÌÌ>G¥Hua®ŒR>¹!I ÎÕˆäCyÔníÂïGü¥sà²è,;~NüNˆ‹+ΤèÓYl”æoÎàäñȯ#˜-Y!ÿùçQù˜¦è¤D–…Þ‚Ï $b"›ˆÏ/¥‡AžñÔOÈù —äñGcpÖAIA3j³ÈúµËÁü™hd²-/(SûOdzHâwnghË×(AuGar !‘<ÐÉW\+Onß)/ÿñÿÈ O¡œ}Tž\†þ‹<d-"2@VìfÏ:}‹Þ|5½ Æ|¤¢Vù¾N‚±á.pq†RxŽìa#h8Ò|O¡”潬[»ÂàºÈxgÑW¦¦¤0žBÏ…ƒ&°¾ŽvY¿ejXV$à,¢N/õ8¡èê õÒUònˆþÄs£âÐ>>*Ÿüû#¦p¢_Rq ß‹@7ÍÅsà³4Rµ¸ÃÔ«W´ó'¼_J¦Ö?»9'(ã<(]ÇüÂ_>ýBÉ›œ[P=NËP#“…c’æ-m”m®úYànO>K{-‚Ю$PnHȲ¹ü“>lv2RŠè™Ì÷=ñHŽ'õpk{+K1¿8ÀpÊd_X:µ·il¨æƒ‡M¢Š÷42x’aùBÑI\ªø‡NÙ³u½a`¬“gŽh•–­ZG­ê/w ‹éh'å/ï¼E‰áÍ"›ÙCÊÇŸœ4„„¾ãæIÃ*§˜ƒÑõdz` ©@ü^i²;anÕGI§Ðêê0uƽ%˜?Sƒ¥ ܃mʉþGý¦x ÌpCú3©CêæRá|p¹0u5àéî@’&†ŒÐféòÊ>Éa>·Emnè£f0ç@`ÔPF·ÛjdéÔ,‹PWÇÍÒ\:Ñtn½ÃÚ#‡=ÌÒ”¿ÔñêaÛTUkì]_¢9,(ZV"ä,¸qS€~öˆ¤ÈWg/IÂʽû÷2Yy ÉÌI*“„·Q%#.ôë¹ó¶)‰{éÄ#:YbúZäâ2‰‡ uOH¤;ÆÅ$-Sª SÀ„–+ äÛ³µl‡´@ ”eþà%H0RÓ`ÙbkÂ<£¤ŒÙ œ )¥­-È„&ŽÓ£ê\ˆ®s6Ð@ú‘1Ü+ýQSèÒÏ!΃#èUµ~Á'åâ4‡?*!€wÒdhüõ¢ZÖµxS½<æñaÄ]2ãgzÝ1ãbtä¡oâF3Ì3k5TÈy‹ï@yèL&sFÇåÈ‘µPL 0‹Ô…&SKI$Nfýš7gGgoÚ 8Þ nnIq‹Ä3ž5MMø‰qé¢RÙ‰r Øz3å1 Ó$\Éë òÅ—ÿfv5ÁŸåDüœ+_¼Œ·ÖSb~ù'?ÈÑõÞ”*ƒÝýD]ÐŒGDuÁØÙ_¬e‹6U5Uô(.Ì·B×ó Cmfíîj1,_Â9£ CnÜÂQZÏ ’Ñ~,›·læ6ÁÓ8yÉ“O?!¹·+$kå:ÌXé?!oµ±aœžHí€Mwv çò;Í4ô !+°©Dfˆ/6-ñ‰À©ê h†×ær³³qÛèØ„DGEýù8\Ó@…Á”g³ãZ3#ã²µ'Ÿëæ¦aðu'PžQ^¼3õê$ÃQ³0Öê9±¤JQµ§A³¤þÁ=¼è9šÎy„ÎÀ‘ÌB¢ÎR‹+óŸDÿ¡{0´Y-¬¬`„“e4°·Ç/Ü’²j¤îµÌ48!c¨Ä +#1–†ÐB¯…-P뉘vw! ¸Ÿg:~͡}Ε‚Ê•MÑäÛQºv÷Sº#ÂÌœ˜ÅN®41ô‹ ‚ñg /CwÓ«,€4zI>ne cÕ¥_É=ñùHúSè;Lø˜52¬õ¨\aÓ˜gÞÞÅ2Áf1óo^ûuÎKè—}îyjç\ ´k@@>hdÚsHÕ8Ùd`|~É¢$p°”ó€c£Ù5Ž6 ˆÂÐé:!°«éϘÀ[H¥ úÅgÆï€òt(¾4)„r#€L2 +_W~KzäIùâø9J+JŸæäA~¼<5+|Çem§± Bf‡¦•ž(Ü¡tõvK$_ÌZc³Áò#V2Ã}øjOž+•$’šPð™Ç'¸,°¥D ]ÎãÃËWüߎƒáƒìÆFI1Ã¥ÐI@ä-/=‹#ÉnºÍ€Â‰’+ˆ/õÖqÏkg/ *à¢ñû)ú"£b$„j1vEq±¤ÇÄʾÀ耲,pc Ò¹…¬•CÏÔ…ÇÔ—_|„ÌcLv=ö Ì5Û·@yùy¦¢ÿL]Šßp†.V%]aéti¾©ï‰Ô ·ïp9 ¥mr„ËÁ6[.œ ÇYWöá'ÿF¸Y'üûªöf|•Y,Ã÷mb7!•ÆÚ^Z I bG9£ vÈÃ-‘©ÆþðIJÕ,•ÝÉ£ð2FYuƆ€/QQÈ…(ƒíiÎÕy]§(?ùìm&9dÈ?\ƒb‘©ÉzÝ4ìÝÏåË3åÛßzQŽ}}"yÊúy‚Ž+ :1ÚP[$ ðû½…¿ï¾½¾‚|z£óóüÓ Ï 2¦4¡Ñ±=Ý€"·x7Gø¿2õ Õ½rãV 0®³lÍò•Ï·ñè’ t&ÌØÏ±zA“@°”柔—þ)~fOÄ‘ô²Žzq°ì “„.xj|C.0¸lÝÕlo&b²Þ— ’1B´9{á„ÄÐðÖ“ò9ÄjñbmµjoØѽºM³K•Àïþíï7'ð{Fi~§‰ôøÃ2…hBz^Vx‡ æ'ƒ-¥òÜÓ÷ } ÙFXݨ«[ˆ:­•Ô²õ ,ú†[y™øóµƒ7Áí/ÂQ K­r·®•2=z4ùÎ0Ý!d‰Y¢^CK'‘ËCZž#‚»“5,.ˆÜhþâ™ÙXà°«ÿÓ,³ ­”]v¨JuFBËÕ¸l\}‚L²@¯e#XhŽ÷÷p­ê'%+/Aäqmm¦Þ$bž–ÊeB9…(nËöõ €rå&ê_ƒûʶ]÷JT8l­ ?.ïf."Ym¬¾O”}CòôÏ^êÏûïÇ|øqz'2E¥|Xûn¤ù6|Ÿºë•Kc µ/ffÇÉȺÎí'¯ÿT–0kQÒX-GKnÈ¥ú2i˜è‘F²ŒÎ«ëv+•ñ8Áôó~T ¹@£>A9 r¦k%Ò2Ò0­…ë„ƒÈ Wé,7»ªâ. £‹a3f°Ç‰î¡)3?APq$[·Às¤¤§à5ð°¬\–ÅlNÓŸ~‚éEÐÏYjgTµAAQ†0T— ƒÆLQ¤ø4|Ÿ>zuE^¯=aï·ªÖ*q€H¼K]Ä£û—¯\+3 mž[8r‘”3ú׉^±ð’Ü‚ãrhu<ü¤üýo¿—´”xùù«â¸ÊÍ.àù_±£pÿ#9Û÷l@LÖ+‡Ñéêá&æâY¿ÖHÊNs„ ²Fx8S4£ÜÜÅ4gè’Ü)Kâ£hæHÃŒ°RÏÖÖ×NéÎBG89E"¢ŒÚÖ¼nSâ­g Àþƒeõì8îâþŒb.^’M ìeéN+®âÎàé0ã.|á xšðýþ¾y"«¶<µ Œî’Ž]°(ÒqKɘâ¡ÅVhËeARîÊçw¢Ñ%}÷cš€ç8Ÿ æU{¶fõS‹·ÃîO‚ÐõÓgè>åÔËUY+`V5PA¹m^ŒøZøßuÀ Æ2j–K® .Ûº—1ÈUÀïP5©;Ó‹€s­`û0·n>AòÁŽbŽW(ë×­${`Utß™syêôW [åIEÁì¹Lòð³ß£,jûðH,ÏÅF9ÛcEÈ ’5ŠJÀ‘ï$oT'%• \=Ý|Üiøþjé…¿—?hQ±=D£HPàÆÑY×̸SR8bNçâì-\4µj G‡·Àï^à½MIWnúoâÙL |A‡gŒÂ;-ŒL‹Ÿ/üR/ª…4.÷0¥j+—Ð/ÄNÞûq°uOü çF•â õm€7r߃G¨>Ò±;‚+£oHŒ AìÃy@CV[¯ ªƒ¦ž@Ô×Ï‚M~‡f"HHuÍ÷‚ƒqå» ÷àÉ…Õ…CÁø„Y±n2S‡‘MšZê ˆÙá¬Äu™–ÆîÕØÍL È–ûä{?ù=Ú2IÝ€ÂâŒÔvâ÷ÖÔ+ß}éû\ªx1[«sÞkÐû1C]™Ç¦ù¡–U+ÿ1ü‘”e`Í™h¨®UÅDj&!ùÃø$¦w`ñjFgOÉdÆt¬JNõŒ¦±PÊèz„ˆÖˆõ1)ˆ´›¬áÈEÓº8>&„,n&ÖßCâHëé öó’¼90^ô:Ê£ÄZÄ‹_K>gy\øAE3Ïo”lÑT[%[víEGä&÷îÝC„Š–fž [o²wìä`ÎÁ)õ2¶ÊÁå»8üù}ø–¦adÎ1A Q,_v~@€‡À´C¤õ­·‘æ³g ÷õÈ=÷ìeÞ" v`€Ï×Ý݉Û$›9ÌSÓöræÓ¿ˆÃÍ{v€ìX™·† .gÍø.„UÛåÂ9Ó³Aù© |ùîÃ0â\µMDŽäNIkO‰<4Ä3ó Tr欠4§¡ ¢ã3èàRÝ™:ä9R®]²L r/AÒ¹b—šÏ~Bª„²»˜!ò¾›zÙ/ ßåïcÉyæÙçè®ÑÏÉúG°Ýn4bª0¤yoç–ê8?"ò©ÐŸ~Â6r|zŠˆÀ¬³Öy q]`B-@‘>Ür‹Y烩 öÔ”YØ«©ÂÈÑ V5±°èº¿º¦®˜sQsâÂó@Èfš·$L~ÆòÏ?€8€¶ãީՀyž/J/ME{s Tê´»êF¦ñF>^{HZ4Ù«¡¶™(£2ì18+ã(8aÎs@œ•𣴜ã3ZÈ›å‡O¬•XJŽp2Àúe±ãË^C²Ð;ÊGíEø{g(žx/v”€A)lðHFÚªªeùúµò¿{“Ìc“nk 5=ö¤%ù²mË6fÎs)½öÒÐ6@èÍ‘ðòM†™hè\}tx?—ýƒ?ýMöq!GN“c—/ɲû¶K_u¥ ©z…±§8w˜£†IÛ,î—]4 ï8HpJƒhÖr+ðÕÊ“fz¸aÊæy”ÀHe!ÒQÎÖHe𘠷zjoÝY¢;Ý“6PªwcÌ»,àÀ• £"àA0á5Âôh5}É0³jX½–"‹—2uJ­™úŸŸ ôDáÌF§þþA OÎ:ÆHœYš-Û¶XPOvüŒèo]p‘ ôà°ƒbÑÕQ­lݱ˧IŽÆöE0Ù-62Iý(Ù—JÒŽ+zµ:¾ã %¯ êàÒÕó”¡Hc¬VfGÐZtf©òêš0³†·á3|cñ&Y€Rh¦uˆ‹Ná|QÖšQôV‘ÂCDOÌÞ®>z˜×:ô&C¹¤ÞY IDAT|sÛ2Ùœ‰" 1ãºL‰‹Š@ÅêKö JqXÕÝ^ *f8@6Ð3—Ý…¨6œƒðG ‘R €ÄŒÊúM"e//6 ÌýÔÛŒ+g.•+wKäÈÇ‘ñ„âÙ”lø_ºz –¸]>ûô².>Æ-MâF0ènn”÷K¯ÑW°#Y$¹c8ÄPÖÚÑ+à—ÄÁ¢&踠BD.O‰åάyzþ0RxþšOŒ˜½Õß ¨5´0ÌSò¯ã³ îæ­û•}`aω‰Ë1I?vü6«Ú‚b$!•~28ÄŒ«‘–šÞßÛ<Ýš–B¡È7\=æä¹çž3ÆwUPŒpP]Üg©(æ3bb£ŒŒGä ZåD €¨FÐK†-,*“ý;¶ŠOHÚ¼HôYÿµuöÀôŽžÇ‰34M@ÑA«yTÕÁôGv ‰N¨txj,¢+§è«‘ tÒÇ͙ѢTWòÊ9÷7 ê¼â»È–ÜÄÎg^ÚI~÷gψŒIéå22H€_NAaƒ¬Û´†R2£"з©·³Ù ù¦‰¶4JÁÁÑLëÕQCÎðïUJlGävtf÷µ|T%µªÖ¨$kšaÂ)0¬nšç5Sfè:•vÀÀ«ÄX{ŒAzORcˆ¿´Z«d ¡]u9K-ý|%Tù‡`oܺùRç¾¾$éË€SçxþÔËNŽ@ʽ#\`,JÀÀQCþ¸0› Ü²KË2`S#µ¢žrdü´…,…Îl`Biê7/Š“•K—HTÆR"s„˜Ò /IsN¼EoæL <j7OY0FY¥=õ%= < ‡yœ?§S}ódã¨Ðh ‰ ¡Œb®,—‡üáµ_ü”Æ–™õòb2H1$[ðo9ž¶‘ò¼#%%l †SR·…º»ùlþ¢1—'‘<; D*èÕepÕØØÛÙÒaÔà42ÄÐUõ| äPØõ~wvtªD!Ó·ïF†Né;ÌåŸëCÍÚ1%‘owú¢k„°*q])¯Fá‚Âêdý·ºp‚Rn§Ήަ‘ÔàìB±íœDÔB¹ÔÂEνu[Vf®’ìu[¸¼´Gdåä´TˆÞQ*ì;Y {]õÖÍßœ^Ø.ËÁµ0·ÒÓ‰ýгn¨À§TÏÉâeˆM7®ZŽ`êŽ ™eøÎ‰ž·­¹IN?‡e?Ol/c Dx‚X*˜@oÌErù¼óÆ»×ì2=Z 4rŒ^K—“õàÔJ:M©¦ÄcDp¨”VÝ‘‚/ëé9Ùž£ÊÓ~ yåÌäÿþéF“ë+¢+ \kûù5Bþ„ñtEò õÝ4¤ŽâÓÚ€{0WlíêFU n¥k˜½ˆfRdÙ¨º®^–._"‰™™Rt3‡•l¡­§‡á!¡è…áÖÍCj÷²×r¢µ¯Ü¹U,Û¶®ä²2ùE`š":ŽÉÉÓ…òãž’kW ¤ )Á4—ԆɅbÇBC:‰‡ï¸ƒûb—Ò(×(-(Oœ:g>ß}H0°àmëĽ¾ >d Éä m„Aœ’@ëÛÖ4:ô8CðF:a‡@gŽaz¶ù!ŽœåÂŒ#–Ôý%Ó eíÈFù»=ýM¢]§#1°q ux7ó=ú”¤8œÓ f9|¥åEÜ5&á`†8ðŽÎà‚¤^´eNl/¾ö ½Q,m<‡@6%Ïñ;f»¥fWM]3CX½@¿nȺýà|œœEpÐZ‘¾HR|ü!2™À¤0$(h–j*†¢¼kx YF;œaÙë"W¯^§Ä»B0Áƒ,>ž>uˆ™¢Nʤ1I'[ë ‹Qx’ HêAŒqZlR¦¤!¸P†å—W³Ï2E¾fÐîıcÈsDJÊXÈ›B94G@ …á¤$QÅ ñ;šAJ3SW±.¾‹w¥ÏÁÑ-„wÀœ‹N|öi8!ïL9¯Iàd…›§ºŒ"¨Ó›ÙÑ—£B¸GÐýT×”ËÛ§nÈ<äR$uÞhA'|Å4b–ôD‹J¸Ñ•ÃlG¤ôÄ7—F­¨,<$B›9J1þ7êì'£1D`¶šzÞT¢»¥7‘H©(-%S5Ãq°Ê€¬¥ÞK@ƒ6De]ÝLŸøšùæ~$"  %¤å ùìè{¸'î’Ç{@¾óÃ×°ŠE–ß ·ZC’‘’Å–Ö1¤êcDòæ:ª)}à1hÇ@QÆ éJUšÌ>kMÿÁàéúàÅ3çA锲ëb ´a\­Ø`®ûê1t&k ìñš``‡2s8ž’ éý‡=¤“b÷£ˆ4u舺Cî=tÕA0C[Õl¿ª#cÓœ×#шc–©aô݃›ã 2÷úMöb´\ÛJ‰h˜8ò¬§ø™î¯¢Ý½<,1۳ŃÊ»Rg2r«¬µ ‡MC©É›A¹Zè‰<)ýüÉxήö¨p1Éà€–ÔKK?2pO.9¥”Ùœ Y8IM®s4HãÙ›á*> ™(–‘·S²©83ŒŒ¢¿Ãžgf¡två“<+êj (³Hbò(Ñæåñg_`óqßßDï2Šíì§ü{Œœ—m»wŒý€NŠTð†põmÍÌSöãëêHeÅ‹ T7€PŽQM‰vóÓD‹¹”!áɨ¬èüdŸ£¼ªVJh Ü·â‚™ÃNùÑ÷¿+§a£-DÃ@äÜ[ùòÌÃd&5Ð'ÚÐI…QN´7×Ш"uw@ÁB{‚NÈÙ‘Îy¿¨ZA? ó(­†Õµˆ65ÜO2B‘%„‡É¢õ«ÅÆ 5…„ [!ÓèA{ÜèZa»)pt.›3[:èåÌéÐývÒ·'ø|0<'Jc'•u¼ùÆ›Ryé¢Lw$P\ùè¹qî ¥a8+ ®Ëû_žæà  E j“röøEøuç"M«ËJd«G^x&;ÁD±÷ñ’Ðe+¤äf>Ñq ÐÀÈ™ƒ6N9«Æ»¾°JÍÈñ hÍÑø¹`WÊÆ0‹rã {\òA”ºòxœYww¶ïš¹t&€ˆÀ`ü¼Š)‡@¥f –ô®üß>”dƒÌµèJëxV*e0Y®­Õ*O>õÎÿ\ˆ}ª /ʦ´”Eœ…œñ3æ]‘&¡ ÀËWaó¨Ð£º¨¬($ëõÊÑc_Ë‹ß{¸<.Qul\³1%û£è[ëꚥ¡²ï€E‹#Pä\lÓÀÎÑC#øùQº†@ V* *‚9“véÍ1‡âÄÿóªÏLõ# 8½ËýÔ^çÁoþø€¼‘ó!ÿÎÅ’Óýùѯe×=›(‰Ü@±Þg+) DX ©C7:1ŸÃ/âpe—@ð¨e½麗¦ÆÚ\lËÒÁ— B=ÚÖDä¶ÇoŠf4%.ŠrH:ÚzÁ´qߣæ å $° ÀTyåìyƒ„êIJOI¤ÑÓ­¦Çx VÃæ¿¢®E²V-B–áˇÇ8¡IJ@ª8ÔJrgó0F`(xMÀt))H«[&2P.iÕ<¹m˜5^ˆ·«géˆÈYáþ²se¢¬áïxGEQ&€jø“9€Ha¼(­:J‡&QtRŒiëeТMñ«yeÔ©žô"ª¥îJ™¡ŒëãÀéš_OGÙºf£‘ÅúF:AºfäÌ™ ¬ƒxSnæ·ÉCî1ôGçÏ5 Ôfk‹‘õ)]ÕI’àΜKŒt4Ô²6ÍŸ}‰Ùb¢öVÓæX`ÜúC]vTZÅfÞ:«Ñÿ,ptëÒQÑÉ–ðB×TLÒÛt6µ‹½7˜5ø,ß$[ÇyIûŒ%¨ ܽ܊–æÀ¸ãc¥»*ÕÀ±€.*©¾šåYèYÌ€:V›—{M8rD¶lØDßIáßY›ûDvîÜIïáMßâÇ&Zñ_5!¬k¤$U[¹|-ë1ØÏótÖr‘ ÓÊ¿¥‘^¿i½X«êä Q•Ö`þ—B7Ló’g¿ó8û2»äÚëÿ©óŒ»¼²ýÚ¨÷Þ»¬â*¹7ܰ±1ÕÔ„$@h $NBxlHHHB/¡›bp¯²\Ô,ÉêeF½Œz¤y¿ûçíîs–ŸH3ÿù¾[Î9÷\^c:°vÞÏÌ¢óþ²–®!|3ça:Îl.Å߇ÊÇ͉¨‘Ï-p>/’<ÇœÓÂi°p^0² ˜“µËrYO ‰ëåå½7)!‘>t³é§äñG->úˆl¿ür<¦^æ‚°%-”.kW5ë‰SçXò¨«tžüdÂJßßS.†UÜKK‰zÀvË IT"68Ô1è´Ü@&i†|IߺJXç3B˜ X»f#Ó}g¿“{£…:|ð[ÉÕ¬˜`·µ\<„ Y1Šàóg€Cì5aŠa‡â’X  !ž¢Ü©³b¼êäáP÷PÑTÓD·AúEA˜5¦9Hóþ”)(¶¯Y$˜(ŒÊ” e‰˜SÔʀ̷C0¦£ÅJ%Í₩2?2^þØ <dî³bÀÌž´HU6Èï/+b9½¥”+·ßû#†ÆÞ§NÆã˜ºÉj§Þ®ÇÉcò…Þ2j–ç´€Õ  [g"`h¼ܼÉúšï^årf $Òö♬s2mô4úa.×$Ù¸m˜;õ¸Î‹ÇÄFSö,‘ˆüŒt=wiê@„ZKŽ'Á<°ùÖLY™ùd4Xáá e¸§3·Eà EÒÕÙSŒEÌ ‡ñày-]²D^ÿ÷›ô;^¬.¸ “»TãÒ·BêÈDnVÞh)òò¿ßå" Ë__y“/C¢>ÃEÒ½6˜ðXvO²ð¢œ,ùÓ_þ†™Ån>s'²|*>“ÚúÙ°¹ß‚ãôÈÂBÑÞO\h Pââ¶OœÃgˆ ¿TOP?&2ßâGU¡;›Q«ÜÞÚŠ…ŒyK‡g¡âHcÚðn¦·vyM°R„eì{µ&ËÈÉ“ŸÜó„ìºf#Km0kŽÄid'HC+ŠÞ“ðhç?@ö¥ÖSw ŸR!;HMÔ:2–lŸ€¦ªö’ñaëÒõsíèh-»ÜÐi™‰ª¡™eÇa=0oÁò ¤þ`:‹$³3‰p0å<ÜÚFëq)S°Î9ȱê¯ÜhÖÞc9'ò Î&F0Q†\¢ÎcPÑeÈ_(Ü Ó˜*€<ño5"ó¡4 çâ¤FÊV2“@Ór#Pùvw¿ÀZC<¡ö‡ùoÝÏ>;mâ{öË$äYC-p”¨p§Übà‡ÃfCêÁ[ V¦ù¥FCØŒŒ[ÍfÐ>iÏ6ŬнI:Ys–’¨¿±T²Fþâ,J›XÉO¢?ã€èdå Â­»v‹ (ÝEÉc¢Tá/‘=QײêÀ::Hß7Å*L7€=#éÂ@¼bcƒ%ŽrÉVÝ(¹–K݉óXñ÷ÈBå—1V ö ƒi.›3[îÁA«¡Ó™œK_õ=«õ‚ )á™\ðYÔçÌqôÒwMQ| …ðX‘Lfq!ÜéCCPKüë¥?ˆ-+奓/—O³@Á²L.g7Á wÄÑa9vð £ÏK耦QŽ[Ûû)W!cu}u8Álùâ\ÚçôéÓÆ Ôåa× =Ü ¸%u>sóÁì±¢¡ ‘®ÚÍðq¸3/JaÀ*£³Ì(M4*ÛŸ»Î,{–‰PŠ-JÖpÈÅPú¿Ä0/Ùrû9C1S3ƒ5{§ Yœ¸×©³Å“ýÄÐÁÄ%Äža<£^§FBâæìP‡O çá!fÌ£¢(±¬=†f }}ȋťÀÆÍò C)¿ Ý>H6È~Œ&«·G-]Fd jsk=S-!ú£G°â'LtÂ[w4¦­ODÄQV-ÌËÇël¡ªHÊÌ’FPÁ„DŒõ@zÚêKäÊk®Ä˜ãðt%½F6ËŒò%+=ƒ2qõn)åÖZyëÍÏeçõWKåÅR#óhcï-vór÷}÷s-¼ òÙž$>.Ê@­šé[µDK¦T/.­’Ò²2™01Jk‰FЈ¡]€K–ò½8 bf£˜õ͘¡#ó©Ã"5ó âw-÷øNg.-À®ö³'”À c½Œ3ôÖÜ€Ê"&ë'›T6 À=ÍH3>a¹Ët’ÑÃ}/(_ö›æ«§£¶-…<|_”%o½ñ.KFo/>Ló `nu4Ñg šø,Jí1B5£ØŒ„Y¯¸Ø@toB?…ÑuE¼ÆEã6[åí7ÞÀØ!×ÁX‰¦¼ @ùk6KJf®±ÖLíOíxˉ4ý£ Pvö†gç³´çø(›äÅ¢(=û¢¼ùõ)É[™KŠNGV}=(U)£È~\îJ`¼q…^‰h‰ q鬈CÝV˜#[X‘ ëESJ7Á!¯ýìSÙ÷ÉgòÎÁÃòúáóòñ™Riä0)$«[q©èLÈ»ÙóM-ÞB$ªìa–½£Ïö`ž7ÊŸ:Žø“¡ÊÀù-ð%ááIòØ“?Á]ñsz»4fBÎàX‚bšN¥õúCÇ'ÈP×ì¹c‹x£Qô!ŠªZ5$ˆ•÷Þ­]¯!Nä–ùÒ3 „DyÓílƒuH/ÀŒ°.·¥¢gZ¼™Ý'd»Î¾afS.ÊÊÍ‹¤NBwÇ;Ø N7›ñ²‚ J]Ê”cˆ¤®Î¦76ÖóžÆÙÛk´¦›líÉYнñc ›Ÿ|ü!#ÁV˜%¥¼RZzZ´*#+þû­7e€Â+/¾ŽÙÛftvé8âW!-/’‚U«ä?îÕ ¥4 ÄN7H%&&Ó2«Á”ª’¸jø0@M0º¾qMwú«ò²r.™?—Å…ËÉ É|!c>Ý–îbM£<öÈý ¡ûÉÌý`˜=IYµ Z2ç›åü—)låh„‹åv¹úú-ÒÅTíÂäpib›³iÒª> Þ{rQÇg¤2˜á‚üâ±_±óâú8Ã9°‡ú{€mŠúV·¥€‚x›ˆ’Ôâʉx[,ÆÜE_ïˆ!r;qøˆáf›D£ì@ƒppA*ãŒIH—YN¹bHCo¢RªŠËeiA›bk9õLØñIô_³Ì[Ìã¶‹ª£é²z€–KH)ÚäÚí,•„„klÇRôY¹è÷Ý7P‰Ñœ“~{øž:+¢†ÏáøuÁϨc¸Žÿ`E¾<ððÝ”+?åÇ;ä½ç_•s8Ø— ªX ÁD J4‘Ì@˜¾ô¡Ô¸<)4:”2¬.J'­ýu@‡zàÖAï(˜¯è8袶⯼ñJ¸`¹qFwÇK¨Ë=Ùy^k4útö骵³²ðËW­§wqÃ’(BÓ_¾Óírà×/Éê…PádS%®€šè \•-\­Ié Tòa¤¸‹×­—×ÅEñ‚ÛQRËŒneàA¸†)/Ÿd‚¾ÆŽ¡ƒË­Î%!Áž’±‚LªÑ˜g¤ÄnçÈ~º,Ât#>*@R3rá(ì²,+Õ²ŒÁ›pâ¦æúù~˜ë@ɧoºéÖp¸™wïì’£‡cÈØ$;Äž8Zƒ‚ö„p ½ÊvHG ºÉö!þÞ”ßÝ P€@Êu¨Á T$Óô€ÈRByfE8âc»´e×Nž»»T@KÄÄeÐo ôH¼nwÊñ˜XdEÞ#èóÆø”˜œb‘ÐzöÎ73HæC~#âÆ£ü «‡Gʆ5ËŒ hæóϤ̷wC*2~ÜßoÇr‰!&\k˜«±ò~6`Ø7>ØG†Å¸š²]§"ÇAê’(ÓT:¯“„1ÀÈ ×ë>tOŸzñ9öÑTqþ\ ¯m`)R·,oEz(Ä-ppxÓ§>.Æ+È®žžž{Õ«H—§8ÇQr¢›Ö[¿n13ÜÕ²vÓ&9qüE æ ÍÌ…`ZL$qU« ûtpjˆÆp–zvrPkðô4Žž ºDòu-Æ”\bZ£•†”YÍÁ>~ï5"‹{øp@.”ëD¦N)swÁJ/oÄ}‘ÔÇÕÕå²kuŸ<þ§³0ŸC~8x&Ã9Röâ®Â~@šô?üøF¹ã‘'åÞåiâ]_'g¹pjµ? aAéöèÎ’³$H[vþIôNgÊäÛ2ôÿ°Õ6J“)ººìÜL\Mª‹þ"(ÐO²à‰ü8T-DÈúŠ;Ö?dªa†ÂÆá“†@àtˆ'‘>*ˆËÞ Ìí Ê•Çëÿí á™Ãúô¼ü ñá,lŒƒ;Cvò÷œüý(ˆ³ÊÉ2æŸþô_²P}ª~ùä ²xËVæÆY&„¹š‰ #ÎaÞ?HS”ÅÁŒÞ¶0é9ÌÖà£ê(Rëô¸ˆŠÍr©@p7Ž #ÊZxÆ. óRÓVlKãå|[”Ô Db5¤Êg†Õ€p£¸pž¸f.ÎÅ4øðsfë£A.ñþ}÷ yôþ›äĹ2¹ù¦ë@CMx w$òWû÷#EbðН€üŠ•«x씂 G+W°]ªÒX˜4À{®®€Ìhxÿè†Ý;èÍB™Å1•†®1ˆGÁ‘‘˜;>hsZ.»l# ñ ìz¢ÙýXŒ´ýÜ]åùÊA•š‘D:é+»ð|Þqe†\8[#K’QIŸé–¯)£ƒ ˜GŽv“ ²eM*@ ^o”ìeK{Zºcî^]z8¯©n‹  ‚ôZȺ¬d`F¼«ªêÈìg€±žtŒK µf-=E°býFc¾D}aá1•ÓiÉl çÞ¼y7é·K:ÀG%ËC·À'DÁ»¥r±‰‘Û ÕòÛÛb$ÌK9R/Ç/ôIhÊüLJäÀ‡Éù %D¨—¾a„2Èbñ•ïmZ-÷þð*ALfH#èʤ½¼Z+%Kº$ž×íÇÖÁšyfFt‰©º†!„Lj½õ÷ÏJ,g/Ö „{Ô]ÝѾ˜@óa$r`¦A³< uïø Á"²)ƒ,yÒ†_ì–DÆ%‚›à’¶<ôFzYÔö(59‘ŸOâ»u€×g$©©i—-Û7@®ŽSÀ\3!éÞoã7é]@—´wRÃénk‡Ÿ½îhÜÔüY§ç)ŸæiÚySu‹Á.{ÝuzÐ9î¥4˜ßƒ… IDATÌ9*eKA´48Ø¡Ò +m3K§#Y§cåCàòDrŒ<r4Í{˜ 0¥”þÙxÛ· Ñ«ÇÍfë›ÿÅl‘]Bã3)•'åR])A4UÚð{þùru¹9YT$·ÝvåW3¦çцËýÖMÛ ï¬òª*ãùñy÷3ß±fÝ&Ùÿå~žç-ÀY¹õû÷±Ê¢…U,Rã tõßÊÍ[ÛŽŠ ‚ŒH•ÆjcêËç22e•£G0Òp¢ýÒ…;œ‡[³äÑß>|R=‚YÈðʼnòñ¥2äôÁK+šçèa6zeEzæÁÑ{eÓšmÏ:å#–Ú4s` èêÛˆRp'üa¼MøéÓ „cÐèUM’ùH§3LÔå£Gêà1$\×ÐÜ-Kr1c•HI|Éyy™\ ³©;H^ÎB¼wIÝ`ð«×­eO!„ =Ns½nÁÅ(ß[g=|¤™‡ôòÛçäŒm’êÙOžýþV¹tlV ÷[m ‘P?¦§&âá' -í`ñH9ÝèI)æçíK‰Š”žÅ/¯¶~±ÑtÏÁðésXL²$/ŒÃÊUÙ,^H0âÐédpYVðP—¯X)©7܀ΉŒ¯cB?åB.RMTÖÚ„¾+¤ 4™ ˆû-DšÑTR3)YYõqâ!.¼B¦Ï=ð=i!kp¹6®YE-a²Oš2þî¨€çµÆ%©'•,5³Y†ï@W7=Å(êä*HJV§ûðýàd«[=EÕÌa5Sv€Qd‰;UXó;@ ‹™a1~Õo6‹žÌÝÄÈ0œ”ú_kaœ–׬¢=5ÄV¿ªÙ‰>æçKäÁ» %ÌŠ‡|úoú¨Ïß‘wÿõ鰖ɯ~ý{©:þñCë­;{YoUðÍ— ï<ñ#L¥lž¢·Cõ¼ 3™](UGñÕœaLº‰ÏsÝe hªahƒd7åk7DkcCÜ~Ëíìk<(ÈG=3CMi@Å•Ì,áOÀ„™½—j“«¬ù¥šz¦è£ mx2‡#r 'ŒÀÚž­.“«6R.³Þ/8N>=r¿7+'Ž´Ëàü¸Ü²k î3³ Â`È¥—ÿñ6]„|òÎ{ìl4jX½™jµ¹’ƒc£¹µ÷çuwÂ##Ö”óœ’,-—ª ÔG½aÅ©.+1 Ãbú2jЦ (ÔÖÞˆkÍõ`š&n-#»]<äø”$ L»›ÉFÀS¾ŽK©1XXÇϾAêœ'gœw QÑMóïßUh8º:mb¥Ÿ™Ðp‚Ý'“4§ì\Ç8"y¶^øåŸ 5X¡Ö?X¹Àwðað´Å-/ ábœ¸¥årññ^\>û…óÒÆå˜QQHTõj†Â™¤^NJx¹ƒ€©5æ<Íñ—_}J*ó—g^xM6ä3ÏÁáU¢n–@¡øÿ±< nÉ;iÖ#åÕ^ÀVõeyø‘‡ñ{égXÖI6Üÿõ¦EÉ^.ƵázèG”§Þ£¬E>N0ŒŽ$Ã@*S¾j9ä w ‰IC="·Aòó—òû¨4Pß–a6¨bQ3zÄu|ýßÿÂ=‡‰R“X­¨8ÌHì©ÌÍaÌ—‡kƒÓŸ™$€¨ûü½šÅ+Zìg-cÛµÓ6Ù’¹Tš«çåxq“¬X‚×BÀ@*Õ Z/‚E`0Ž,LˆíA$è"å=§Pë&$ÄsÝåi6Æ‘öÕ®gÀ>ŒÔƒé/}ÅçOÏ¡àÖŒ ±I t !:fxðn”LJj‰‡Òi¬[x¡‘dvšÕèHÞ°»¢0UÊ«i¶¬û1ƒÁCåÒ©ÉX#Ñ'¬ Xf;܆öH‰ñ1òØM3rÍj)7÷óX/çëO2%– ˆAƒÆäÛKv¹ŠtlbúÑ :5Nc›ŠA]ÇD¿1Ì¿º ‡ß#kñ0MÔû¦. Mœ‰†–4‰HÇż¦ø~n°ñÜé´‘q¸H¨z‘ƒ8Z¥‘QU ´b %˜0S^j™àCP ¹åÈæû~!7ßû‘>5÷ÁÞø/°U<[(|¹Lî$g4+Ñ3+\žyÜ=¦É|¤y2³)|/u¬We1-»÷Ijáv‰Fl9ÒŒÙrS#d4ƒ¦çupf˜çÐÈ•`4²—ì„«—æ9‚›·œ±2çw0ÍSÇxý~ NÌsH´™ŸÖ¡­¹´M¶~9e‘ƒû^†Xk¡$*£WÜFIê#çŠQzÕJþ2d# üð‚½ÉháAøø"U!`‰iÇÉ'ëð6ð}˜}!“9§qkNà)°âb‘”Wpžº$99«Ú É€à”50åM5ì',XD6j’ˆÔLàkÖýÑÃx`<È`ÃÐ;vlfš°•gŒÙÀ‚EùÑO+X‘ ŒßBI½`^}X/)Ya’‘°™ïG6Ç rÍòB5_OŸýÚõk÷öC$龄Ò’F™þ>Ö/§$Ê[W!En`h¿Ú‚)b 0Ó7Œ!qHx4%Orˆ0–[žƒ1f…eV<¬æ_~Æ~j´?Í5²võ #’(åïé¯Ö¦È ƒYNCæ0.D2PE– F` ÒÁrKÊž9 Ð9%Ïа£¹.LfK•õ´4Uù!-¨@žQð«¿ÿ=i ™K@º^tvHÖg„I”™Á®þy$²Þb©êh#o"$#sàB˜B!ß(s LPîö³øÒ.v4KVñêF«¯K!Úª¤ðÁ¹¢u˜òÊMjMz³ê È"¾”/žÚgà;ë   ‡ËÉ8Ž¥Ñ; R¡³sg}ð|ø'ž2éÓNÕÓaF5ËϽÉTn4ïú{fÈ[o¾ç²”É)p³InX·Œ÷(ýç¯Y‹ð-«öÉ 9L¦ü wò¶Pó=f<IåèZgª(cû,¹Š9 ²ßÏK|=]½wð|1Ÿ% pàLÔrH_¿ª“…:8µ†ò$ãø½"ÿþbPÞ;P./üüéGê’–’Aàk’²ã)oÓÐRõ"÷T@J¯VQÁIø3G£ÞÖ¾qn"¾D4Pf’E­6k?üEˆ|ñÙ–Ì0ÅkÇU$%‚ß,F›cÝÙèIyXåNp6Q.*o6EváÍP‘°/ÜJ¯«ëð€ “˹t;WøJùYÁ©òÅj.7;]¨ î¼õY æä\˜R5|¾©œ⑘óòsöúãÔÑÛÄ 7&)ŽY ŸDÁs§.É“¿ü™,¨áAºÍÓ@úPδµu.‚>×"yuÚÐÿPGp°á6lØÈú°A)>uƸ Šdis@>icØÚÜÌ…ÐõlLá9(gÈÇ9nh%]‘ß,åÔûÑñiÆ{qçk¨øPБYD7U[èß—}#—?"Ù×/븼òÌHË{¨ÙñÍE,Ø‹R" ÐÁIü¾;Npi=›†;m}dR©(¹(?ýé¤äÜiÊ@ÌXŸÏHw$£c%» ˆ6.†ìž>ˆäa¹-—:¼WV]d^£²CÖ cðN3“®[›FO¨‹–š”œ„<©»‚Ú«×fòŒ¶ÊGû‹äø¹ÉfÙM6Ú±}D>Ê ¶]õôŒ KéØqGmNOÍØk‡LäE„Qb™@_øæa!¡ PÓò½;nÃLaŒúŽh† •E‰¡LBçԄ˄–…€ÊóUé1Oÿeñ $j’l¿9òÕayüé?íÄ3Ïüž $%q›±ì'95—5#_íÿÖpdqÇEf‚¶À¼~ãú½ñ±øY¡ïéÆr4’­#—Êhûù{Èî×ʾÏ>AÊŽžßÝ©àä@èô× †:››„r²›úx–e'—¨¿Ù4[PÀ´[tHJ<0\}̘$$%òFqÕæ{YàTÌÈóãÚå?eô5­„_ÇýÛC/M ž‡a(ÔÔäZÒ­îñˆN„9–þõ HÇÅrïîRZÝ,L”U1~jGñùîŽÊ]k Äwa®„ea•zªTVlYÇ¡€ŸÒ¥6ØG%ÜbsSé>Æe!Ýpèð¤lòE¿ÔKšž–El¬mDÕÌCm€ ¡…ëÑEJbò¢å5ª–—ÿQ£•­]”Wˆ%áÆPÜî¸ñúï~Ÿc: G¢Tj·T¸a“Ü~û-rþØWÒÂìû8ÁƒC9M¢ÆÎ‘¡Ì}°ë—-+òaŸ|üI‰B‰PF¹¡þ\Ñ)2Ç,Ca,å$ã¹Aè)Úç>×c¯}Ž:}h÷Á7ÇìÀÝÍ”'ëVoÀOeÐ .Ê4ÏOû…µä"|1=Ú×nLeN³þ`ʽ@ú€Ù~xë* '>åïhÉ¢tΉ€nâ$£²t}m%g >ÚïhÓÐÜd˜OL’Íͼ׺ÊY»7—Nªö=Ã4ò>²mÓzcîÈ—g¥_ƒ¥/ó,-¶fJ6Ò Jâxä›mm\£\Ö¬´ ÆœY‡¢÷à©JVY˜eÅå·Á¦—IÁê­r¦¤2ÍÞ†²P ÝÖ‹3ý*–ô "4*NÌYY{5¢ë¤W;‡ðPôþˆÜf)·ãórÝ%VÖK|r48¨Z­ÒPŠS}‘“|h /º;o…ª?Ý8Kzóö21LE4DOð26£F†FÑÌ] >Å—Г[«ÃE ,•)õòÀ÷É‘Óð#®9ÒX&uEcÌ(wb)IC_UÏ’{Œ¶@Ë¡ó¤v5ÊFãï… v˜øGwRvŒ3NÊ5M‰³ÚÇ$-Çc):,K×1EMíÂÓA)5KF;p˜µ @ÖC i½0²f7o BÝbDX³i3*4udÐ1ʤnÞó ¸™Y ЪçMýˆu‹, å)†d”¦Þ!ãeÉí6<–ˆ$ãÇ¥ˆîïSäE%úÃ\~åš­²‘ñî±uâbÈí§[Žt€NQ¾nºN~rï$œT`Šù\*›š)‘ø\2eÝz\ÊQC(,<‡¹õw_‡^Žæ{íÔïS]ÖÑõ±ÌsŽþl!ÀëT‚Ïç¡sõ Š8µ¦æ‡ö"ú?ý?¦ÚéÕÂáËfF*Äé¿A^zõS¹l‰¼ÄPD,[Qˆƒ~,¼œÓØP/Ãp¹ST Èo<;ô=RzÅp°KŠÎDýb1{cÔA7mÞ&ÿyïuÙsóõ|>' —£ {Ѥöι`ÿ(Xú¸Šhú@ž/ó;‰)ÉX¹FJZVŽLÑÛª“Ml|Õ…–ísòÔ½F0 föd…<ÿ*nîH‡ªª°¸ím‡H–øš ¥‘ëçHQêŠ À¡Ôôì½^°8­`ÎÊ_ôSyPË;HÏêþpøP9õ›é9º¤¬„Y€¸D£dÊ%c \ÚØM©@p·BàQUðuÂx*&®‘ã³>–EùK·¥Þ첂’%c¿éÅÆI"*ëV«ä#¤X;•hœGÝ–q 0v RÓhþîñx6Ba  (Œ_†,^ÄÚà®YÔ›LëÑs#9OѰ©½¤ d7]y ¹E^:qFl3·MV®ÎçPë`½O«]Êëk¥ž¦qàÆœ@æôëãJÈE÷áõ¨›ý ãŬf»@ h¦étÒ€ë€“æ „€ª22Ú˜_qSd‹T§¿[ÇAêÓ­¾òèSñ+ÿûCŸ¹:>j3¬?ôºóßS@î&®U…ËäeÄ&‚ŒƒÒÌCíççÔIùz^ÞÿœlA&|ûã¯å$æâL„šô.­M—äÆ[~‚4…Ì8I›ŽþÌ 4nŽÃÊ$óžÇ&‰Ïh€!,3…ùtÜìcâ¸Pd .åä8îéð6³½ ßú>éiî}#P‚ëôèØ£«©ùLÐŽá:‰_2Ü•úZ ÁCÇBñÛJ ¸õQº¶CÜ¥' Ö¦?ð£ÿôcN5k¦±ìáYNà ed&P6N¡ºÆë˜k(!Ù²ñrùæÀ!v¢‡ÒKäʱCTÓÌß`B§(®WS­?' 4„¦k˜ÒÓeôRÀÜf.òœ+vÝ)¼ÿ|øÙ×ø! 7[¹BNŸårb[eâìÑJy $”CK-…›6®ÞëË<†ºO´¶Z!•yÃ'`_Â:@jfȲ%Ù°—˜“òTÅë¢ñ$tÆ'@ ñh»l-Ìr0ÐÂï²^-Æ×CËM Öe¤-Ý¢¤{8’£c8H&coºº§.)ÏŽ×!ãåÌéKÌ'obËèY‰c˜jÕš'äз¯S àÏxƒ[n4Q˜.¥§:šÁ¼&ÈÇ@B3â<­púì“2H 4­<áðú5«ØcØ( /ä3ç¤P¦4ž«’Ðô(æ½)iˆ^V GX ø ¤µ^”ºPÙÌåQѤ®£0oºsGR®Nãj 0Ís¢ÚâCÅñƒ´1.Ahœš@øx|7ëÒÚ4Lœp Éµêe»ïŸÎá$f.àR70ÒÛ 1LÆðÀÆG‰S'hŸZ!ùÂg(Üm§?øÑµ©°í1\F•ŇB :ù¬TVÒÜj“AÍ:–¡š¸®îF¹zÛ*¹rs³‰Fÿ¢ÜL#Õƒ©ýºµù¬Þæ³À6h…lCÐŽÆÿ™  “ž›—»—Œ¦xÓÉÛzåÕxå.fÛT:åÎ!¹ã¦1¥Uð¬!]î… ˆäÖFå;LÉ`('Ñ"ñAÍy{BïpH’’˜G'K(£> ösfl:qø<@(QÍÝðŲ¢‡q‡dt'z%0žš*‹¿à ¡±¡äÑ_ÏÏÀV¦„Ы0˜jìl÷à‚Ìœ¡Î “ !µˆû‚¥w“IÊ<¥6 % ã›v¯­£ ô£I§á¢ÎÖµÀ„gì¶AÏÓ„!™º?'3óbнjÐ_õ¶2¯Œ¾¹9ؾÒÄr$Ô•e–Þ Ÿ3Òhd5¼Š‘Œè.–9¢0pƒ‘;©Ó€N¬?Ä úøËû˜*´âÆß')˜!¸)4Cè"X…b‡(fèE¢ñÏå²ê¤¨ßÇî$–!6]Á§6©Ó]'%¡``„ì—Ä«Ysv–rŸ@ÛF 0FI¹ô©ðCBX8#à¨Ëu2Ò—KµeózÃ/ »ÓÊ÷4ã0,ñ~Ã’¹æò`Ž7¤¥Î¤7¶Rž%%¡H¯eómú(`‘]’Íàê’ <à=šïúþ{èÆ9 ÌØ©›?Ö™âä #À¬ï¾ûµ<ýÜãrø›c4œ‡üÙZÈ›ü|vþ‘ªìݰ™ FJîK‰îÂ2²%5=tYr 놺¡•Ò7;=…Œ bfˆ&ÝBôÀ0ȯ•ô‡k Þ¼3“ÌÌvËŸ¹Qž{œ™ç•uD@sðzÐŽ&Ùµžúµš=Ú˜\ë>‹D“Ÿ!L›ò…Uƒ Ý  IDAT桎)SmNæBPónÄÿ*˜þJµct¤0½2LQß÷#oèàáçrÉFáb/KÅônA¨dæïØ(s¡6%‰W¬7 ‡Â¥‚-”8:ÜK™'@¦y°Ùh¿©Šœú@þö8âF„þÿ~(”ª„¬N r=ù 4ºšHKéÇa°µÙ¥¢¢÷É89yô(ï«Á'COô_Ši£«}ÝiÔ­ ñdq2Ô$¶ªªDPu0wI®j¥»þû{dËU;¥ìàI Y»(•ChbAØÞl:ÌsÕ™nE‰|x&¸!=¨)3¼EʈhFÏåŒÑÉR=¸tl38«4ö²*cxLR‚áµ ryoATÐí@èÚ«‘Ú¦gèÍ(ÕüáÍ"@@'ú;Û˜ ì§”e3rz#q¬Oa5öq¹bû&Î;é)ÙIƆl/uÍ×þv’ §ˆæ*æŽvz4‚f\t†”U^ÄcJ–§X$8ºÀA– 0Êû¿9#+æáSÜ)=%Ù ³?¤Ò Sç)yüš>PC~µtQáÞ¾žf40 3Àž$·ùQÿ%¥±™•jd9 ;Ë}ø~Ù÷ég’·¸@--àp#5ÐZ²&Sç4 ÿ"öÌQÓF¢Ÿêá Ñ{ĪÚôéH®;©ŸÑOAî'­y¡WR®ƒ²Öø{A4aS쉋Ζ??ÿžl\uƒWV‹_ÔÔ¤•òÐMÞrÙz›´”–È© jïtfÍUœG šâ 1B)èNHCΜK*MYt²êo%ÔLNYf=j‰Ó‹­>); N œˆÖ_> ŸAˆe§1£¢`¬O}ó`ý&9}ª^¼á1˜ú#›ƒ¹ƒ¬±ëƒ„E„bz©p Ñ;z˜Œò¿½†Þ>C,E'¨rÔ´Œ—Cù÷ƒÂòf»¿¯Ë˜{c@êµ½%ɨj.^ ê*3¼ÀýH£f’UŒ&ذóqâ¤NsªHÏ(ë!þ9qäŒ|u¤Qnö©;‰ùëõrõÍ;åG÷Ý!§Nf‹-$]"ëñ`’uî[W‡¨óD¢ "a\-O)/Õ³JÝô-\°1¦'¯ÙµLjÆGHcqÑÐqèå8 rT$Û°¢b)›”ÍŸFÐÃk °àUÀ œöU›®ºVjKËå÷Ü%/Çí1™'¼_l&.†¿‹±4Y¥»»Ó(á››ZèqCÄPdXv„!µÔ,²¿võ¦øB£ ÉÛ)?{ô§€:²ÿèiY³z¡:~TÒ¢RPzwƒ¤Ž°9à6F°Â#±±Xˆ¶ƒ`dv÷rí =1–,ÑFº!Z{ó®Â üÐ*X?eÈiLÊn¸n·°‰å#ÝhgÂIÀö’H 9ä.^\–~}¤ß^Ð."Pl\ ËVZ ÈpåªåÀîFàÄÛHÇiçhúCyÓ£ô&‰)ñBvÊ [w“¸Û‘6gZñÎM1ü·¢Â3©ó-÷Êßß¿–Í”eÅéâœx|m§¤K[;¬6?OŒŒ”Ø ÝÀåô12¼&'QÌDz"qTýŠÔcÊ@QT– ë–æÉö‚µr×í7‰¯”3o” |šFË:ĉÓb$ÒOxžÀh˜oÊRÕe3T¥åZQ»N˜b»ùÎ'ˆ¦y8Ò?þ§!çÌ9(…, BšA”ÌW>H .ÔgÌl\UqIΗWR&±«ž 7ÒÜRKÃÅ ‚êÚ8…â5Ê—–—B>-ÁæiÆhRgùyP`,Ÿ,J“ï¸íÔ¡oêŒD5x£øäCÓiY° ƒÙyXýyJÀ¯Åy†Ë¡å¥±…rT8 e%¯Z/¦^üúûŒ›”Ÿ9 óþ+d›Ú‘ãŒÏ&Qb‡2èÖ@¹ä’vˆáhP"U€'0 ·t!~#9uøkÈ=lˆL“²õòËi ÷Ïd^A‹9¤MÞÐGœ08™äøDÊö~ã9x UÓ0>9—~ËÌ™ 3LÓëJÏtÀ´Ý&Ó¾iø}áÍ h3Nï–›"—o]#›Ö_.‡ŠŽ‘TP0¨¡jѪVó¹qža8e¹yו×ïE'Æ0S‹•©® PȰžL÷’7Ñô„ uQ¥«gT~pÇ.9tô ŵíd•(f.úPCÐé"•ƒGŽã´a¬èõ ·‹Œ5jq ¥Îw7á(bâáÏ‚ßóðm‡ä…{½%ÇÝ& á¤~<.½Jp:&b\N7ÐJ¸’Ûw,“#‡Ï‰­wVBõ “9h¤oÞš•E,ô1ø¾FR·N úsѼOuGàDt6E·GÍ!ò †ßz͸ f!εSGñÚu‘ŽÍ­…’mC6¿0ĈDTuâ3|nÝ"Óiè@ð”‡ñ”!›ñ /ÑËA…¿É\ _?H8zeåíèW‘ˆÌÑ\Â#ðëÂ:Uì·4¹È°ÍþþìS´³ “¨íG汃Xé&â)>Te¤z)œìÅ%å¨W@$¥*C:YçEÄ× —Ëí“/S‰Q±QÃ$â:Õ€rs Qx‘ݯö¤St‡_Ö®‹L¯ÁûUÕ¯f% —-Dndc$šr˜Ï; ï2Œ8¢0çÙ‡‘~t´ãÊÏh¯Š æÑçQݶvôðû’•“&‰q±Ì”³¨4#Tr„ÌÀ”)x ">1Sö‚ð÷è“O;.7^u5¦d} [·ì@m~À8otø\t¸šn«Ü}ýrÉ_½œ¬Îò¢³¬Œc­Ôç< P ÓÖIÑå…K@jrÉ’QŸ—ô”täþ§iÒ°:B¿í·WUaH¨$#ƒ•TàÇúBue±‰†L‰½ñ!FL‘ZìÞÎ> .Ò Ã9 æ< Œá²0ePé¶f :ͦÊZuܦùÑõÊžþì¼°!TŒIá÷Ñå©«ZÓŽ¢*_SÓ3 × µ)ÕÕÓI0›gk%ci„$9Úåo“iˆTUõZ.asC³Nc9Üß-^,A™ž`ò —øv˜vöJKŽ·ìØ ;° E©«0õ(‚ƒEž‹–¥‹'vÄÖÎl NöÈÁÕ¶ß Šå²’-qa›íÃH[:¥qÈÊ\»¾†apÌDêè$Î #ÇèÕ‚!ayððìU§ô "›ªÏAÅ…2$4½†»»Ú67áŽÏÙpñ~R˜I·ólÔ oŽ×bñ"h *Œ—c'Qt3Ö¬Àµ¹^jàÂbc—â*õ®ò!ãœc¶€ÓTÅ¥ìS$ئ$ó5êÀ¸ ² ›Ôº¸5?;KŽŸ:!æÂʼn{ݨÃüUá ê2 ÓéKsI)Ò΂D h´ø’ôÍÓLñàýÉ©SÌAý8h*3Q“–6+2 m¢’ 9Ê82†”Ìj^²ldðçÕyáy>¡<ÜYP¤rÈ/Ò S{ŽÓX΂ õtØY·pNJ.BBö­–€øA.#’ÌÔÒƒŒr@4Ü£¤ìIjçy ? ¿˜·ºÞ*9qœIüÙyMÓGc˜œG#I´Áß7¥=-Ð/°÷ŒáÏBûù0(MNlˆAÝÀŠ’¨”K™çÆ¡ÒMZNË”ì¯êÇ\§+½$=)UÖnÜ‚þµ)OpŽh¬”?š£IH9µøœåí“Æa|é·æA„LàÿÍuV v'º›g½öØŠç¬?\ tÄÏÞaÌì(ëN¹8FŸ¢û þÔ¯dyvˆ|òåqHº`²"22HÏ9.‰NojIh¡?ÔLåFf›¦Ò‘FÉ?ƒþᔼ,/ℨ Èq ‘ÚX¼ *uò’_›2©"‰>F½ˆÕC¼±S‘;¯Y(ÇjýQw·Jn–FÐ>œ¯nÔß9: +KÃ×R’kÕç6Ǹ4åÔ$>ЉÙd‹!x(ÝÒ-AdÅÈÆúÚ–—†zž€’šœbœ•·Þý€á¶58ÎDñ=¬ì{¼ þÓËòÔSÏÈ Ód#ö«P¾wQnØ,Q”÷sD‰)2Gd\„”;€–ƒ > 4áÒÚŽW3`A[i;Léx³=PzüÜI$BD!IA²gW¾¼qè‘J™nä €úŠú“0²áD/R ¬¸%.Ũwæ‰ÎÕ5œLþ1,†Ó$ïѦ…—Z߃ï'1”™º]kš²ÄŽ¡ƒ)D™p¬ Þ/á’C)rç„øéºÈnŒÈ4jkïÑÑ£’o݈>’e—î”b^dŒþ>+ã¥èÌ9þ¬‡¡„Ö’AËS;ÇÉSgäš+wJUM ( š0³;‡G£¯nŽÕLÔϳRÓ½y>ð$뇿:ÍEôã=Ç¢jÀù’Rr~Œ›A¬šànºF€´y–Žyàn6][`ÂY¿­ªˆ¾ Å@Jæ6òt]’¬„HÔý%†7˜Ë¸”^¾-ÇqTº5ìu´sè ¥vx$²—6uJqHA¼Zù„PmÑ Ž õåÈK¢ø¬¼îN.&¤,3/j7›Fàª,)ÃA%%É °Æ‹ßW›Ù>ôrf(‚hJ-CªCe¡¾Y+W¬ƒˆŽd6¥ÝØ9¢2÷-›¯¦šIâÂtM­*¬Ö&²M:+çñô²I2AlMÝÐøÕÁú˯N±–úzÀ®2NÉhs|bàÞq>´ñÉn©*¯ }3TOç8MßàžßOÊÓÛ—KÙͰNúePRegFÜXˆný°é1ÆNóâ’r F*jW_P,2O}ûýÆ!ÓÎÙÇÅdÑpH³ÕÆC¤Fµ£$åRè´˜ºê¥ä€H@énº$á³d^U½M6ê]ÈF§7å×”±3D*˜Ãƒ&ÌEz=XÒnDßqú‚'®EMú í_HI•œ–!#Ýí”dNIÞ¸L~²5v\æè‘Q#[™¡°¡4U "Yr_2&M]-ß“ÃZÃ"ËêzÌ¥‰ÈN"®®‚p§)£¸ˆ˜1” oèY«¬Ü >³z9øçfЯÜ]tOIÉ…@P>t9wú"æ|x?AN6s(ÕèMGbÏÃù)'&å¶;o’#4‘|Až!ü_З¨Ú üiXÐD‡µÔžHÚÐ@‘šWÊ\7óÕŒyVK ÐžŽ:ñ`àæE¡R{ºö›cã¢Új‰¤ç¼åþ;ä\e%Ší@æÛ© øºNËØ?p‰y|¯|Ž­Hí:Œ÷¨»!ƒxO&J (øJíD›k£vùQŠM#IÒá'ý”½o”ìå”$²€®Þžä"´w`}K©SL™•• Òõ°pQçc„ÊÀGJkªið‘ZR>§€fií™r¢¹¦m–›nß)ï|tœùòCôu¾²)tW˜Gä,¢éÆ«T5$ÕÇ0‰àue«Öpt¤•¤dÕeÐv.eFfæ^7Ć~¤ýjÖ.¯Ãñ¼¸¸F2!¨¦¦Í²‘_ò4ºêÆÑ ¹SÌy“nõƒ4¡|wÖæ&(OЛaÞäæQ3âHY —% <ß×b³µŠ^…CÁ;Û«kܶìÚ†• ˜´ûMuœ!AÖ¥4ÚÍÎ{â/ J2Ãäa“ꥴ9æ÷V•fÀækG(µ’˜Ñ•eõøÍ2°ôýMÙÂÁódF"]Õ(Q5*-= S:èD´ÖçVÐ,‘¨RU×.QPÓ J= ¤í ¹ÔjEIÄ!39ˆŽn̼wÐ]¤·"¤spǹÔrËmw®uCã,—™z4ü‹¯¯?×}^ȸø”%©ø35cO)¦ják ƹÒÖÔÄ<5D&1&GÊ ÊÔ qFË!.™$ß0=Ž4ÈN§ó,üáf‰Äã TäN‚ Ú0úŸ` sçp4.¶ö‘C Güô1yç÷èC $»û¤œÉ¼¹ú,кoðÒ“ÊoõðB™Ñ p÷@¶‚âZ• *AÑè­ûæ¹A‰¨[ to¢Nšgû¤iq)sÛ •ˆ< ÖòÔ¥ä"7ÿ~#rfGÔËxžŠ ^,nDG‹cA°¦˜œüÏÕx4YnŒì€©(šî "Úëí郟`Ô×#wßÿ¼ùû9à~dÈJÚQƒ;etgÕ=†9´ ­Œ1èfã^æÔ !t+R[3µ×âü…Ì¥a^½73%¹6ÃúqÁÖe[–qÈЂÒÔ¨ÔZ»•»€5½—WµðÀ&%75‰ƒLsÌ$Ý$Ëe‚šÌRWöää,†„¬üyþÛDZÌÅr¶è”!OHKK¥T«åá¤Izf<„d–Ÿ>GBÃIï¡ý„­®<ÚËp™æPN0Ðâp¢õ§ åðÅeå±à¥9‡Y"ƒ¤E:™§M»s>+ÐM¶0kL&Š€¬Òé:J3J¢îž ´2™ &èè±U£Õiëë'Rv2=8bXëjb“õ@+u¦~}‘ªdU ¨ö?úá=(^Éh\ŽQ|…/#$\šÆJ¢'j©-’?`E÷4D¾Ü÷¬!(µÑkœ?[Î&VÌDâØÉåÇ*"/%®‡ ­‹:Mô3Úè{8èn('éøLîºõf´t,*¢ñWØwôg–Ïb’ç©f UfZèGJ‹K0¦ûœ8xT–æçbÅ”„WT+Œ¯«u _ë~øs #Ï‘±ô ¨ŠéBwPõkDbŽ1 ¤²xýá…B-’æÆÇeéúíR|ô,äo‚,JB£Æñ‰Æ‡eíMº¢ l‰Ò!­á>Ð6Ü =VÆp=ý8ê÷wñ>f±àù×7à˜²Ö¸¤î40 wôZ™CŽ‘“G  øºC²{¾Kžxô)ù¯?BeÜÎp¾ ¶Z|Ëè£Ô¹²„ )¯´Q*ƒOÀ%ÔÖ#i©ÉXu¡'«á03ÃåSD·ŸjÊ|ù–{c£`gO$W—óADME½$!@2B-B-èO³‰ó°Li8Êߨh>$²H4CM­íÔîŒXö3cÁÛÑ™’¿üŸ²a¥¿l»r13ÌŸb:€—hG^îB åÂì¹h3Š)zàçO~C4×TWÏω6ÔÕ]Dí¸x"UÓìE‰òDeË Ñ ¡{Åí4ÞAŒðÞ²Ãe.5/‡aóôºzzÒ‚y”xd55æfÌ8½êQN0Ùƒ’e&jçz8 QÒ<ùß&8C”0„15ÓÆN7ÜÎrÐOõ Çц•ˆ­eC£&Ð?üá÷9,2t3Ûtƒ‹£ y$´Ûˆ7X[;º)œSEÕ²ªZö‡cÅ©¼º¢D6\¶o°*Ãeq– yÙÆuü7{ëÕ<Žç AGçU¦p57 têåìŒÈ[¼ÉxM¡Ñýï.@€>zF£­º­ë~eíýÕÁƒ\62æbmÜidDL­&4¥p°Ë/VT %=(ËmQ䆒áÖ¯^F™D†®­ãyÏÒtG }x,\†– š#)'ftçÕ§Îèéœâ½Ø@,„˜³ÀÄÚj㢽¤’ºî\–à`ñP‡CÖ%Æ%1+æ!e £ˆ4i¾ÉSÙýÞƒLåÅ{S¾¹ä;¥r1oÕNYÀ< " ÜD8™x~FkH/¡«ïæ(ûúlu¬&àóç¶UÔLJJF4rF 9¸É U($JJoˆ6¡RSÓ¨J¸8<;Ö=•QèÝ”$͆<Ô˜47À¾¼†¦z˜ÿ¥üo`Ú}umAêò£ßÈÖÍ+yf±dÉPʯ4C˜qÇY*ƒI¾V'<œå\Á}tb’ßG8‰+αC1©G%ÕÌÊlÅ<œ^D’š^n­JÚu¦|Ùb]|âÁ^‹A9 ÁOuÕZ¦»j‚(lÿøÍ–/æ¾gO—1Gl‘6>ÐÁIJ+—|ôùµbb š’'yCöÜð’¼øÊÛA îK9My/kzŒ}vгÓpffg²Ív›\»k ¥F‡ØÁØc6Í?DÛ0Mbó·ò÷_%Ëço?#ÿ©0Ëéž¹w댜,þ¹ø&m4 Ûiú Bb¿h¹Ìo‘÷?½V6nÜÊA)áàréT!à°Í{Λ6ÈÊIàÌypu2dà„öSn˜„OãpÌ @ÖÜm—;Øÿ,åA'°¬^{o/‚<ä%ÌÏøøÉWß|n0ÍÚWW×K08®:Áè‰aAà¤ì¹j9âBœüΧžÑâ®FŽY­]¸ß'&$ËÑ}ŸñÁs8aAÌ™•™MÙÆÂÊ]¯O/Ë î€ºïĸüY+sØ^ü¾Î±{+ÏÀãÐH|ÅÎëibC²ûø9r:AhXIgâ={âRéÉp•ÅÊR"rPÄ¢ô€€Ø=ð~´ÁG*‚é3è?¯g„ñ×nY¸dR›P6áòüùsZBÎqY{@ÕF‡pe üÎRÌ#X4 è’ÈgaÛ PQ?ƒ‘t3o‰ý-²}ëVŒ¦XtD6 ÇsÍa*%õœ¹©iúC|¤ p¹dê(…â¹\Ö–zã6\H’äíþK^úç0ИƒÏÂ?šÏº Õ.\ht´èu?ÀiˆB•—8ùýH¾þã¿|¸˜Û$•À—`™-Tah0ææïíÞ;Jú „Eñ¨,«%2ªƒba­†fÆÑso IDATˆgl4}º¢aÚ+ÖSN,\’g,"yæO Ä9dãa!þŸ,Ý|X1¬J —ëïy]¶]}“´Ö7É'Ÿ³³ˆ7;-ÍðÒzáÿW_ü5hǼ|ðê»R˜»Hžÿû ÉNl¥™,ô¼g™l¿ö¢¼÷Í=õŸý¹¤/_ÌCäC†5§07"‘Êã]¼_\DÔÆß3Ý)ÿúÍq$Õl:_o`ÿ&d¼>U L0ënGŽOl“A˜i;Mªh£ü.½ô@ ¨²ýa «4‘±Ëä„Þ¥ =9•²Lg(zä!² Ã^èº.”•ªÕ¼œ>T‘û|CzèjA¾6Z¶×^{èÒÊèg!²‡NÑÍ´&¢·B¦£è€z:¥b¥ªƒû~üc9ôõ~1'ü…›¸¸:ã>Ñ7CÙLÏ %Œ7YnŽÒh)ü,‘°£w\î¹ó{”Ý ”}8V¦X(F‚<õþö ÜÅ?7€éLÝGhAÜ96‰7hŽ:™˜9ünDj}½ö7ÖVçÐÐ,ìmÞ —›o±Q›ºË7_í÷Oüž¬@4uðwµÄ9£X)¡q²x’éZ‚ù;)ñv=™#}æ¤3¤i? ›†@B­F©é§ùà»°mmFv@Ï‹ÿ¦7.„NAÌr‘S~ÑIâð‹¦AÖcAæAjM«EºM•³dü˜3[äÀ3’Á˜2=½<ýì‡òìoo1ˆTwJ7=lŠÊèXjÙùZùä£×iI'J\ZˆôÞ ‡CÔî>È ž|ìú4ñ÷|ø3ôÓhÞA´h9À:|掆lZ_<¯Å¨ÁjZòž-ï–›n¼™Œ`†·°J]+Q{ŒòCKÉ@>W7ÐF%==Aïæ¤ò‘”º)l¦tæâ¢ÙÄÛiRÔÆº(È ÒÖÛì/ ®2Ê-C©Î€ÃÇÙI;$'Ë'¸¨Ýd,/¼:Y¹v>=z VÙ5ê6(ÈNjoúÄ윔õ ¤#T6C2@iÜXW-¨•Õ¨ðð·§(ÏQóÌ#Èo|þg d¾·*°©¡¶ž!¬lþ>£Æ\ÐP.ºžqR›øÇÆÉ­Obr³¤“‡Ÿ»œ]$l( "…ZA$܈èënd¿ªV>þò¤´Á*7ÛìRÇ Žd6¿>lÆ¡„v¦’:À¤—B:ã€X‚ä…go“—_ûåýJŠjº'³„£hÖLìÎÌÌ~È¿zyãÕ¨Kñ¹âj¢òáàºQN‘•Ça­9¶†Nƒa/.>MF 0dº–Y¥ænH¸u‚Ц<³Š9*Î>™ˆ,§™Žç¯¿àf´ð¼vµ=5†›xÍjá™ÆsuÈïÿG CÔÁ³¤‚D­šI„Œ2Ô«Ña¬Îi#?¡aŠà5pñYz“’œDÕÄjk:¸,:J­¥ö…ýûŒa¥ªò:ã@š(Ø<ˆhUŸ–7Î…iVÞ³ŠÌÅ[$îÑi´²S/ˆ×0ß#=÷~.£p½™'ÌSjµÐ›¨üdŒç åU0Í{s§¾•IVÀŒyžÇ—û>—×þs„Š»IרáÚ™»¨€ÃüQH„?„f ¦ 4àPšfk'ªüz!CP™§3F>ÎåKOË­£·êÀø…Ez3õTKÎcÁkg‡M–ð…u—4‰t!—_±ƒEq 8 :83  š@µ©æÂ&êÎpLºfùÃûÿµ›Ž¦ ¿¢Ó‡KeÅ4n <ñëëØ‚ÙTýHƒAQëÁ8A5Õ,ÇÖS‚øð¨iôŸ~pƒ<ðÜ#2k¯sÔò×Ë3¬ƒ{a]4âý§_F^ãŸÞÿPîûýsòæß"y>+Ñ“ò×çŠÙÊ{HÎÄù1ÜCú›¬š*¥gËD!›ÑûÓBþÀ䯽)EfA•.6!ÍâU W3#¸ÂSô#hÂ&ˆÎ -ª±´!òãÕjÕ2R¥®*>^àé§Šäÿz•(H©¥õ9ˆQé…"v†ðy.qLTÆ}`Ø1 i„ÐB ÄÜÉ…T»Ñi8èØž›‘~AvœacÌ9O$ãÏðµÜLÀÉ€: ¤š*2”v1Šé>v]Û¦Ÿ›¢9f.ŸVóZ×éŸ#cH3Bÿ÷àµfõðÆIµ4¤ÄÖuL FÄ£žÜ`7ËŠÚ%¥ÇrIà'àyf(i5èl¸7D­ƒ°ò#h†Azv øõ#Úåò]סáK2ú·J#;Pk ¥ŒË=@þúæ~JÃi!Œ5:€Q‘!ùmŸ„çQÿ/=KR¹ÒU×\l'ULÎ >¾ LÅ21È éd9û÷}ˆ4% ´>oÔN¡u•Ó+ªvŠ?“˜ÌANÊ…dü˜ùsaEÂ44H?Ö×Ç<={ìåg^%3]—È~ü@;샒°0‹b›¸¥$-¤64ÉΫw£ºÍE‡ÓŽ}K9—Az`{Sã ±e¯á Æ vRDñF²VgRUêA¯n½õ-ÉÉSþ֕ʧßVAß±T<p¶ËD~N^)|¯ yà‡ÿ”„ë¯É“ùáfñcêëž§ä•×ÚxH3ªd%Òn»ï{dŸïŠ{§cò íÿvö&v×å¹ÿ{¶9³ïû¾d2“ÉLö²C ˆ ‹ ˆzµåZ[ý÷ÖöÖºÜZêÒª­Zµnu©J#’•ì3™ÌLfß÷}ßç~žo˜øß«í= Y8s–ßïûnÏû¼Ïkò¿¾gßûùãv7 Gÿâ“'í?xÒs ’Šmܸ¡ººêˆE àá…2Ó I²®±Û’70g>JïƒÂ¾‰pÛ"56É6Z"–Cú84:\b¾zxŽ¿ Ýq`Þ³WÅOë…óó‚Süö×¾Æ âèù¤ù©ì‘?yºG—í&ÏžÅ"„(‹(ÔUÙ˜š™a dQ1@ÈüàÌ"}ôeÆ FúÉ­¡ðA †m hS”òç0nli€Ð"Ñ×¹„Û;ãàU‰î÷„!Ò'%DREd8ºQR9‡¶2LÖˆ1‹³“âL/œ2qÀÂà;-™ê„“Õ9ÍršA„èêq l[JMA”:%v䆑v©î"Ru"h=CdNINaÁN õߎœ8åR¯5Ûï&”*ÿÚWmNMeX;×{„¬!#'Q‰8[Íú5Õ%ánÊè)œ­(÷ °~#CÝ*¹ƒ¢é«‡Ãv® œ-\íZYb Ï!ƇëìÔ±àæ:EIOm¼aSŠ}ÔLÊöã¨å¨?›[qp1ɰ ‘>÷ô5Ñv€å ©‰!;F Aæ¨ÿðiOüèI¾'©ûr(CXp#ÊvÝt0G'G {›@:@2Èÿi„ݰm›­ÙXn?Bó&Ò)yŸ¼òiÄ™u×Cìƒ÷}ÖnÚÉö9.(ž5eõ|· Þ¼†‚ÐtövNRÏ÷£–²Û¾üõ[ì·8(jx¸Yð¾ÿiÏüº71!b×®9* ?„VQ›ÝqÓ}öúq›ëi%ðÒue^<1Êþäçì›_ÿ¢Õ3»ñžû2ƒâ¡; uše¦{ž“ÙÏœÈ(½‚Qj•)Òšðâ4Àø;ò!Qògß*¥§Êjµz%IT ÔpÜç8È™ƒã¥Æ©ëûá)uÒÇЩNÃeÃò_xÊRñJip¯Â¸†z¨éÉË@Ñ,ÌÀö$x0›5‰C†È(Q0–éº<?‡TÑ ? {r@:Y%çÇ`Õ9W .^W(L\)¹yÞ9—îáN”fÉh8üÓ“4Å"ãx.‚ ü¹bióclÿÕvÚÕk68Bi:2Ÿ›6®¦KNÑžŠzfÌkÔN”ò1G3LÔ›Ãûy0þÇÿl§®pK›N ÉBEñ¢óÜZ wï­"Zn/}Ú>ûï Ì½š¡¬ƒ€t&ù醴"aÿEê¼½ç=¶åæÕ Vˆ›Á±é¦!9II—?’.©¸ºê줛"™‘·Ÿ‰tk–íºžýê¨}Lâã•óÅÕÑãµ =°˜ÛbO“¶õÚ?}ó;xê(-Îq Û1¦5Òx[€?~”OËÿdk¤.ò”uMÍ.ERß`xXdC&íHe»©—f«ˆGon—fTbI-f(zó«GÉË£@W"ùL4ñØšÚ»žÃ˜ý¼‰R.¡]"(†hZÂy*-%ŠÓÛJŒ¡ù… úà3qð†»›ö¼dÛ7ÛªÙØJD…ô×ÜÒƒåà·±»½…” š IT©M†cpR _Àø¢ÃâPÑD¡…G¤ÅvÌb «s¤¬#Ôª«Óq¤P/‚2’ó‹ÀY„ªKuGn^çmÂ;Än¿ë.( gŒ&:.…h…l‡ûMTJˆ­£‹Þ ÉUÈ\2+~ýÂkö¥Ïý#ý’,R«HÇþ^A¡íޤnÒL Q¼¸¨2i*ó3 _Œ6“Š+'&ö7k¼²`%ÆL}f(çÖãî‚næ†[”¶B¨ëb´³éÜ”¶z—A…À³I¥ãkܼÛöm³âÛJi‚PºRH}îS?…êŒü(îϾôI›j³Úב™i±y”£ñŽž" p¡ÞþëçíÑ¿ý‚=õ³§Jºh?þŠýæe ò#üeÉv¹ê7÷Ñ_¼bÏýøQ;ðÊ“vþwòóò“ÿç‡3o¸xé9KN²½÷DIi íp°!­Ä à—-°,C‚q%È ¦§ÄW"U™áW5ÙœaÀ^USN’–Kxù!ºâôîÝ›+´·¶±±ŠÔi ¢[sc3°ï‚ýÁÞê(×)€9ôâ B•·ŸVÃ_CðnœPCh;„9"Ûþ84ÌÓÇh‡B1ÐßähZ==ÅáD×®V^å»0'„‹Uˆ$×s6^‹H2ÏgSÎùãoĈ†p‰q]¹\áТˆ‘ÕPç¡õŸ+¯p¬Ü(Ô#Ï–7[hr?Áþs†ÖJ6¯‡¨Çâ™”8Ôüã­ 4›ˆŒ¢ ©ÈÀ€ê7Õ@ÃL&6ÔžeýZ3¨Š.Ô%âòeæ‘¢Nà¨n²I ¦Ÿ‚\«©ÇhÆÁ¼Õ#™× çû㓳7@[›aê\“:BYý‘s§_C}Sìíxxqlɽy«­ÞPjO >QW*&5‚…³¬ÉÀàC!´J8P袟¨”ƒb»ä¬ÎŸ; Q2H}\„³ïålä“^±‡&'—Z'‹5c¿9üŠù¾v}f åx?°c€š'4Sz(bƒ %¦²à(7ë.]ÅðLÈEºdS|ÈüªˆFŒhu£°ÆJÖèJ|ø³ßù  7·³ÇÎÁƒA×—[PhÞ°µ\øYk¼ü˜ýø _²¦òVûà'þ»}ôo¿l¯m´/c€´a’†TŠU·^Bž³7ì³¾k·Ýû‘ÿöƱtgówþKâ’ ýéÏRðÅØ_ÿÝ9[Uœ‡‡–l'ÓxÖQ6õ2¯>Š ‡j¹»À»‡F—X#Z63Ï¡õ;Í] JUå'Ð1ç›èŸêúI:Ñ4â¦!Â%ÒÏŽ °›‹~ÿw;®U0€ývîGæT8ó£b)èø:oÎ8²_:ôûã‡ÞÊÀMy@Q m’ÂáV†§¢ÞOZ£¾Ç$ÍH5G¥)pˆ¯ R¥&fbVr<^P íiQÜŠŒçÊ ^–~†J¦ -*Q)tó× ¢·@$ˆ&U›èk&ò \ ¶±¦™Ï¤i‡Î-h5Ñ!‡ÙE©*²¢zÄí,¡©ÊŒÌ'·Sq¹6æ|ˆ0ÓS¡vèÙ—q@³\{¢áX…-åØéúp´ºÖºÆôo_<Âäã<Ôé®ý R´â²m4‘=VQqÍΞ:m¹©¶zýVI”A¢Ú[:ìÌ©+ÐÖÇ&*†ýÃWŸ´ËåÕd9Ó Ó6ˆ€µ–ÿÌÓ,­©k""쀴HäEqÄÏk«~›˜xæÀ ã€'Óòk F¬l-‰‘)àyTÞ¹ÿ^ÆÆÒpÙ²e夿V ªHx©êlo°x4¦â  Ë&0á`VÂÂ8¤?~ß×ø»Pû§|·õÔ]†ƒ_.ÁsKÍŒ‚÷6î…GµØc¿øþwíè3¯Á?ý§/âBWØÉ—bz¸Â±*¹Ý„³*Bz«ÝqË] ¿{çpýލÁt<ÿ›šÏþîÏ~‚/L³d 0iëê}•ëŒsQB)¶E½F1vJs)H`Tº¶DdY‚†±È DÑ,–2G€ô “¢Zˆ˜LDï©NµÇT«f#¹¬šŽ4øZ±[WlX ¢é¬Æ2t¦¢Ñåqz  ø qsUðÎC˜Ö¡Æ¡Äf9¤áÒÑå3a!šTêDlÀc¹ë%®˜ Cs}PÅÖI¼j}CÌÅó?mªZ¨ú::èmmtÍÇ\§•Eù°¢‘+¢'‘@“.³8—i¾tvuä³oCˆ¨BŸkFœç§²À5‘v¯F´Å%†ù<>„$íyÒÃkÊI4/a¼~ €Ç©1â0AQ|ï­hqÏœ§iHŽ$¥LÏ@*‰¦sñ*;uä¸U—Ÿ€„zÍ5VQ´UÃF8¼ŒcƒÂ¦ÆOxêÙÇìܕƪ«â–ã—ùsek©¥&I-qü¥kבX< d’©…%~xZuÆ]wmÅaÐûaÉjÑ+>ž†åíÎÂ,µ^Z<¨Çƒ§§sÞÝÒèvÒùç™êàbüê—±F°oª,§OðàvЍÄäWô=Â@¼fme~<ÅîÚKt‚éf¯(Id46#Xeƒ/Ûÿþ›6 ßk†÷“_ÿ,_ ήœ9`ïûH•ËÿÁP˜[o‡º|ÄþúÓŸµÃÇŸÇÕ^OgÞ|ðÿo¿WÊóæ‡þ¬yí¿ÿæì›ÿÜOêÂÍ¢8úZâõÓ³‘®®èÕa1̯A0âêä{iú¨WÔlÓ¶'£:ˆ¤«x5?DDˆt:œ<ùØë¤¦ø ¨R¬.,\§ k õ‘œ1ÓK‘ø~–â®é (Íu–¼¿&Öd|Z|:¿0†S‚*ÊÁœç&Jy%ŒÔËtP.Ÿ‚Ž:ÛkÕÜâs "¿rÔ{}îÄfß©IÔ ³Xó2š—Xàõ%‹ºvý ‹N‹bB2O*aŠÔ,tªBˆDÒ³Hž'yíåKN‚BƒÄEÁ…ÃHÃ#ŽC~'œ9ðD¨"\W7 勣׋ÈF~Ÿ ­1Èñ©QPôµë²‹µÌ Ô%} Ûq—ºmªk„bšZ „in¨ÔÄì€sDaÌd Ö1ˆcîæñ®»ï´3§+áÇA{Q¦÷Þa/?–ˆÖÇY‚X %¥‹æj ¿Æ&GâŒh°FÄÛ>ȰT1zŒ~6ãt¨ƒxÏ›÷ ºk$¿p5?‚ƒG‰–B„(1¤ãD`Dˆí,™ èãøµEt&8í¦mk « Ü`Û‡î´ÜtšGäå^hî8+Þ¿Ê|`êj |ç?Á£øìÃXK{¿ÕuFoÙ¿ÑRJèeÖÞžô …A›!ñþèß}†”nMÕí®{_r=äP E ·óÇØ³_´Ç~ò+Éýá¡]ÍdÌÂSrZSºðý/|õû4{¸ÁHÐ€Ë Bôù@N9dxWNož,¦0”ÏOÍ¡ÈEB@µô=È)±¨€>nþç8Dº>sxïêúj;r !ef ´Ü4>ŸQ0n6DÏyæ)$æ‰`$²ÂhÒ¥[áÜÕ 4º<ÀÈ_ù—¹¤`@®“„xs#`T/镺Ó.Ê*¡âë!rä,i€AÓõJó°—ÏŒ‘s³CØoâg°Kß{‘GÎÊ5|'R,/ßõH¤œÆ(-›ãsŠˆ©JîÊͬØMŽžj›‘R¦4O«öbÔP8õ€‡BX+Ë&émhâïÊå‹ä÷DEÑ“ÇÎ2%¸@}P€t,.†;µÜhEf‰=-@­ðÞBÐKKN' !A»b5hÓ,Ãigl‚š 5‘½0°Åïz×;-…C/6õN63/ÍâÛ9‚L»2=9| §¦IËßûR](DPTBÑfCu¥¯oˆ×ʆú…„Ï$ƒœ÷±#3dÎmѽR^…~B E ÀË™O°@AÃÛßÙsé °ÃGÏ ªÑAîšæ.ø49tzóÁðYòA?8½ÜDÑ;‚öä¿VÚúFiÙ (0óîÝaiûmaôª5\9mg^:ïê”NãÃ_ø#ná·ù9{/9b(ºâ¬¼éªyá;}þ¬%ùsé¸B§øx¨þPäÀ€~€Ô§ÝÝêa|íG‡Èqj¦Xó†8ôHú3Â訚k‹¤Y¢˜` tº|ù ZŒ#tKÆá‹äÞ*Šñìc y% HÀøLìù‰Dš·èhª©À`HÕ}|7N£Ùž}ü¢]{ý€­„²#¸—QØ$¶4–#/B…9¢½Û8!´ILøsu€ïèS V D-'§'€‚Æ ¹G IDATC#Õóaù Nv×-;Œbo!)Þ8hW}U#ÎÌgëVåÑÿø RÃ0!SÚ´y‹Ý}ÿËaû–4¼9'1qH™&S“ä;r§wݦUVWU×*bj0 ¸«„ ´Äîºfºãpt†»íÏ¿r— øÏó›ç_dñKˆýÏÏî`Ô“å/÷>@>»vñ‚}ö%{åéËœ!×vd=V†pïì_¾qÚNž'§Ç‹Õ@Zû틇É1§¬‹q×O Z†ü¿úPôPMâ4¡A‚Ä GÌ®äŠí½ç³ðm“ 3¯Œ=„t…Ú[’ŽhöÃoÑùŒßò? ‰!Ë9!­À8ä½ù.3ªK8|Iqoa ¢’YP§ð¨XB´¢-*(ixD¼¿öèÉ*Âh‚ɯ¨Tšè˜êìh…GU^Ï%Š,ñ9þú8Ã]Ôn²^?”tMcÝ{Ëž§×¡ZF>E*æR-¾·F¢C™QáÜÇì„ Y 4†:Ôb;ÏþRùÓ'Põ¬ T—[ÿÕ V}æ5_µ] ¥Q؃Fs‡](¯´[vÝnÞàÃH¼G ЬÖädÐ(âÅ^?{á³"´ªÂíö ¼0é‹K¬÷ýÕ£L½m&‡E¾'só;ùËa6#}Ë~üù§ & ZѾ÷Ûù£?†¯™Uiò؆m­]ºô:wf(æË_ù¢{mýKý?óP1®Ç²Aj¨†Ç8ôè‚äÃfm’È\u5Z_¹7R S4“[Êi{8±‘œ>!!pžBÏ;6œšLzíñóC]ÐçUŸW‡8‰HÒ?R~ÑÇTÇ¿°8ÌJËPn¤HTcP9»¤kÔ?±r6IÏx.ÿ¨×RC¿)–F¢t¦‚¼žè>š­’.íë¬s¤bûúÎ\Ã’¦={!b:ò€S¬/͵»Þ=¿å·YM»>¼c;DLI(a^ ]¾—fSZØÞ5c}ª¿0®¦K¿äÿ üžÒæÚ\dIb å6ÛSåš| ƒ6@bq¨¯Ób=4=ƒˆzðÙ¼|!¥{b¾Î`8šA‘>®œ„Юü•9nî'”Ï["°¦–ÜI›c„‹ðß;l© },Ü|&:!vð(&j,¸{x×(Œ´52fÁ.^ºbå•ÕlÐ¥ÁÊ÷zàc”:Êj¯ž³kÕW­¶Ä zReFúIŸq ‚ÌÜ"Šþ¢Z=ÄÑ€@Ož½dkŠ ¨{ŠtðøL¼6UZµw+޼ö²ùÞ}ï¶G¼xGO B0ó0îYž‡ISs…Ù)vçÃë¸!ˆ,ñå8+ÿòÍWí[ß¼ûú–Øù>« ¤4óvòP•í»ûÝûÿôCF¡ƒ¥‡8HJ¥œãÐK†¿%Ý¢A ÷&9%™ÆÔ(_e½Qöe»!J;O $CQT\ð ±/ãú¬"Á{‰áÑP17K* ZKÓ´¬t|"š‚¼SzégÞvÏÝ·£7ÌÜ<ó׫]SšëÆ~E6 Š†Î¹îu‘7Uw™ŒÑNˆŠ´•UiAŽR©æö.Ärñ†¤\ÜEÒ<Í›LQHª(ž‰Ó!×5Ð:èAŒ‚1tžGcW£0 %„< †B8iCß%VsZƒB $¬7Ó´¹•»ŸY›wq=è=ÍrI=»YËLêHÜâ\L¸T1, ‰ä‡˜-×hkQ›u{á¥ôÙn\[ÈÀ÷štqÐÝ)¾Cs]‘ŸÄ ”Çvn)‹{)¢»`Œð¼ °µ¶A‡'­K!²®_¿g +÷fÎáݸiµýèÑg¡–TØ¡WÎÒµ¿b›×¤3”v ¿…ø× 1Ž©Kx~S¤ÛB¢Örè+®Uñ=YÌɸm4—•¹4%™ýåóS´ƒørCì8ç7íã D´3r³‰W Oæ`XtùO‚'5 É ¼=*–l®îf†Õ éEã3Œ7’,ý’kØcßÿìJòqwÝ…ËöØ7~A½q•ÃÎâFÉ…‘×?ðù/ᱯØO¾û‚}å§Ì‰P»Ü{Ó=|"ª ñ4Š:Q@ÿʾÀ1û{¨(—¡,G)nœšÆ“(XKCHOØúŸþÙÎù€ YÔÛxèæSZå "#à;ÆåÑaêUAìåüxµzƒ.í"ư÷DlZ!\rr:^±8ìœ*˜#äâ‰VQÕÁdf)´ÇºúHw8°|.|*òâ9®av^!7ù*xh!”C2ÏÅsµ †±91tÈ@r]¨€:†tPÛE³„+ë¤!bPœó}BC£©}b€¢Aq€›Ó’ã¡¡Œùp>É¿°â!O]³ËVßp3úß-:=ßÒsK-seF€1­a~{)Ê6콓4¹šœÉÅ›ˆ8´IŸ°hóᢥ‹ì)Gµ`Õ4â–ˆ†Ø°¸’\'øªV ˆº½êÈø”–3#Åh LÚ©W_´»·óµ@–Rr­¼â“}×lÏM›í,çLŒƒ»îÛo¹)üLA1r™vËÍ·Ø4s#Ùh³Íòža‰9y¢½ëÎ}¶vçf»ÿž{ˆy4n™„ð…rýq"aˆãÅÀ˜#½£®Z»¾ØJWæÓ»ƒeŒ˜¹æb¦ƒ–SòmÙRüH[+Ź”Œ4n’ÑÄ0Šøñô vîÍå!‘Ùz©ú;rðuè(§ã£›XäH.ÎÆSjR< çoõ¡/~úÊ ýàOØÉŠq:“äÿ öÛ×_ÀØðpxT©gOõ…sÝaû¯ük9 “qÈ“J¦R'N[[HK”;WΠ1Ø×g¯¾zÄ*+ZPPÙ…º‘ŸáûòüyH€nˆÃ6 ¡š`ކh÷¼ ÿMø? ïîÞ‹Û7²…Ђ´©éeˆMºç¦¶÷ö}¨±·0%„š‡Áˆ§%ÊC˜}ús?µž£H¤ðç@ÏL ÀÜåÚÁ"öóҺ ‡K©‘‡hÑÔÔeë7mþFtoèVbr®áù£@œÊ²È#ù\AÔhrÜ[ZS}ˆMÑá §[ïÅs{0Ìp åæ}ÛÖèâµ(¼¹n!¤Œ´ éA5¢~À/0YƒíûH1d|!¤:~À”(z%êDÓ<²æ@²KW± 8N\4—D&)ŒB›ÞµØÙàuÄ"T#-’¾kB/€B †Ñ4‰ßD’Ø&°’÷QŸàè8 1‡à]#Î]A3 ý¬%ûÒ7Å¡…¢Ã{ÚºA¡*`iÄ…ÇØ…ËôUNePµ™ž X)ªùYá´(^ æ¹Àüÿe¨â×ÖZa Ôö!Öp@AÂ9/€b†ãðf‘zÚ[q@D±z+)ηâÒ2Äî!i²RÝ#W¯öÐdºŒ¹gѤ!¹y_ýѸAÂ×Òü*¤2í[€Á‰  ¡KÊ‚L 8OÒ8š$½úè_ÞË…Lz¡å{ê9ƽð´üðÇmϾ]V{¥ŠiµP{ñÀ»çƒw]÷†ÿëPí!cЯJ­ÔÏP‘îæÍ1”æ[Æœê ba…ÙöÜç9ˆÓÀ­·6[BÆ"ãE!niUôG‡HKu4ˆä!:,RГû`ÔD~U æ#*a.ô¼Ö Y¶i#ß•Öúâ;Þõn»|ñª‹š1îð?/ïùì'¡gtCâCO¸® ï æ*$ÅÈÅ 44 ‰•¨5´uK+·ý ƒ¬#$‹ª2Kj ƒ¦Æß(ê”R{—~®×Õ”ÀôlˆÐ „&ØwAÊ3‰N@Ùïiž(ˆ|-õ4Q¹Vï¼yg7"ä° D Ô,I?’; {³KPÐÄê¥1§æ¦”Q´g]‘+ Nƒæ®^“r€ô\‚ÖMZ'1À<&Ï×vY]?«°ë.`ÚpQ‹4 Ù0Ίxö(äC¯QçÄãtÚZkYPz§8}„MdÑöîûöÚ·‘ñ‰ ý¯¬(Gµ}„ë8EÝ°Ò ë=ð}üݤeXå… 8èYÞk˜TuÁ½ž®Á–Þ±ëûÅã?§^̳"d8Æõ¯?{Ò6Ðà$ƒþÇ‹ý1ÃîÂ¥‚ßÚŒp\b¤÷‘̈9 ª,È\Èl²ùg¼Ï¶mÊFC5‹Ã=ÌPž‡ÜÓï›´Ÿ¹`i 4ØbAzÈ3%¯éDÉÈÛ³è<ÝôUœ9d'\³oÿ Z±šU¤5[˜!ïcGÇîý;l}Nb†BgW¸~Ÿ¨ƒ½Ü÷X®Ad2’(òíß:‰J|6ê& °B h2FÛ7oЦ¨ãx9,<†¹ë¾~Ö¾áEpM¼-½ >¿R8ýlVF¨ tK¨¥ß“€§k€BŸHJ²Jž¦¾†\ÜÃö«;låŠ|GÎÓ‚›iÖ7èÀD0_ðÌg€:™ã'z,’Nõpø†ÆXJ•Óp±<2ü¸²XUxÒ.Ò%nÌ9"ˆ n‚‰<Ž+èË9:éÿSô”8ï£ôÁO±¿ ^?ž>:ÿú¦ n¡ôfØÉ…äNÍD¾p3€?ÓÔ„zû°D¼Eh¤ gÀL5–ê—>2‰A†ëf§Cд-:…xŠjNb$E1:i)~êOúDÔh¨ûeÌ›hÞ%ƒy‘£ÇN£8#÷h¬­´ÎêÐÂn»x®Ã>þ—ÿ]n‰ÃZËyÜÄAcäA«ØfP•§B¯©’¡¨­[wÒ§‰cŒ¶žkDàa-½™ Dô8ÇÀNG!ŒFäƒj ¤¯Ùh°,j½à©àG1;’O:^D¡_BzKúMõ–®Éa+–¥3ýxt¨ê/ÀÅŠ³üånŒdȇÛpÖ>aGW¸¦—Z!* EÛðsˆˆÐXy¸Ýùç_COë8ðm­x‘¦^^ÚVÑ4\Tmß ˜œø‹_ü¡e¬A@úM·SFÞôŸþý·Ë)• J†¥‡Št‰¨°÷¶íd}¶ Èú2^)ö«R õJ$ÞÙ4¹êج9ðŠ2Pòjá©ZØâ ãïèÌñ9µ)ˆupîHIx?ÒOŸ -ònÞ36 ÅG`FM©©qAŠ¡U²«¾»±Hº¾¼¿~dl†Æšv}O1ÆT¹“V…2C³D>Ž3s‚#Çs—8„í<_Û¾Èù”ƒxÛ)lõ•ºù1\sõˆÐª‡"™_ ‰á»áщ¢cª—¨$ƒtËtèåh»S'`AíµFëBÙedø´sÄj*;Ѭª³ªªfFR¡ò·÷XKàUW6¢Ü_GÍÔÆ5§ØÁ;Ï` !Ìõ Ÿï§)HL-ò3?1>×cç+ª1@à»Ò\'8çuç“8Š;¶—qÆ‘fb•kµ••m‘¤pôRÚI±¾ñ³¯Û½ÿío¹=öžûþÈÞùŽ=Ôq––_à¶pùÈr†¨[jêÙ;’b{ví$œÆÐc-7o…½û՗‰SÒ ^°€Õ¥Òuörÿ*.•ãˆh’²z`à2©w´z†Èp€?ü;rô0Tïˆä^hDvÉ.‡HôB2,.ÝJj¡|—]‚Ãâ¶@;eÑþ‹ú†&7!ÂÈgIEføoÔð“_±cÏ}îùkœf7Må™[NÍIBâþ„}ûû_åu¯?–£ÇÆ@ÞmÞú|d1©iôˆÇ¸}„ýèÈj–ÙS­\EdÑždš@qxeŠZÔÏŨ•ko…@”¶ <"Åáû«ÑF²Éó@ˆÈ‹Íœƒžj•Õ`çãƒÈÝÈ!OÎL< .äÌaÒÏÕ×5( #…#åâàk[mP ;™Û+ŠÇ4^X@€€ø(Š=ܰE¸O¥{ôn®÷ødêðójQäûq½ËÄРtP+Ž(ˆãò’ºÍ3k2(^nZ*Í¿a`ùÒŠõDÔ÷Q­Y‚âÂǦf‹ä¤óXÂRÀOB?9mݲ kQBI³’•yÀ®¤tD§QŒ6#3•&¤@¼Gé`ëú4oÊûJqšC×bkÊñ=Y kÿßGï&Ú0êŒ@Bjj²ýæÙCŒ%¤ñc¼Ì©°‚àЯ‘=böã×ÇjPGlµÏiëIe‹ù,¥oqøðaŸ ìÔɳnå÷¿÷cË)Ü'k-×„Þˆë… rotùZZ\sVÓÝívëÞmöÒ3ÏAìeæÇ%VÄ"uïŠÕ…vôL¹mXîTñÂQ%ü‡ý Þ¢P "d&ý&Q£m#x06ÕÆRs,Ês1CòÁO}®ž~ÞNð…jí‡?WqÉqàÐi½œgBF9úE¤åùq•o{,ÊÛþú-\ŽB¯”j ½Z®C´méÂùr×3Á.Ó@?úµ¼]åÕ+”ÌVÓÜJÄã'‚ö¤2l£ØóY9Ìò$¬ºæ‘tŠ5ëórz¸ÄUÓ¯IÐjÄB{ÈûûÈqé>ësEÒG9ÇRúïýø{âÙsÖÀþÂ^<ô?}ó»¼}‰Ð;ÍqÐó˜Ñb”€CJÍCúµ{ ¼øGƒR|äIüGƒ/ôû0v·(0z?}o/M¿Åö(Qiƒ”C¥~z‹¤YG½JšÓ·½t®^T=2Àø¬˜Ž°œB×h†`Ò‰­i£¬:ðì“pµˆŽ0×½ ±ðÌv¨­€ã?}´(Ð2Í™¹×IŒÆé ûø…™ÈÈb€¾E'9âP¾>÷k/Ÿ…nÏj¼ÂBRÂ%»í¾©Iúb@á8Û$æ]ýé‹A=tªj²ââõöä9ôW¿ü-Ð)6Í>ýô“N— n’Á‰b‰P^*h q†4"M9ÔR\¢¼`ݼŸ€˜DJŠØ?³wÿ;ܬTd¦ƒã/_ª· ›7ZÄÒN µ®¡ž“Ù’m»·?rËîR®g-ø9û_ºŠ:p¨W° ÿKp|pvîX9‡„ ô‘Ãz!ðíÚ ?‹È_ýô˜Õ5O±r ´áªw”^q¬øW8Xóž=7רþÛä rñ—CGOÝtýó»Ë…¹ŒCE¹ rA»Ê©»Á틸qÇ^=ÇÅȦïÑà–…Ö7Vã!Q“ojæ *5cîžÎê(…ã0´¥€a¤Wš¥ðƒúÌ ÔoH_‡T˜ ‡›ëêj®êÍl÷ 2Yˆ—ÔèjGg3ó7Ú¯~ñCRµ6ÔUkU_¡K{Š×§w@>‹§]„õëñé:| „Ï.#–ô<†£˜ëTÜ…aQD‚îÈû@ä$!ÔIÑ)”\WI'‰ªkHJ!J¼0×jhjšÃ½ºõÞÿÈŽ8¸úÄxBgg ¨Q4"$¡÷s»Ñ§ÕPÖ ¸`|Ó>—ss‘<·‹<=D.Æõzƈ àyÙ%%xÜ1v‘Óàƒb>7lžÔIÛž4¿®Í³ŽÒÔPßÁ º5õLÍáseùYf:è}d€üÅÆÅÙᓇmÛ¶UÌ×ü‰}þï¿Å=-´ƒ4DáÑ%#š1ÃÊm¤4@E‘šFzÉš' õj¾¥œœ F_ ]DÓq$Š4 ”š›ÉØî–ì@ä;H$b‡4Z¸ØÁœJî}(鸌j‘ká»uWÙ#’Á¥å¿"=×¶¼³˜Ó?C¡tÁ…eq‚¢åÈ‘EK—A ¤T:ÐxÖH Ðï»ÓþùonWšÈÉ Ûg¯ ¡›”KŒÔcˆO*ïÊšf{ïû ¬p·ßn ¿Ï8dhªAôCžü ’Fœ$m 0*=Ƹ@ lâ{ì—¿x–“tR×+ `µtæCmÿ;ïAÈP„È-"h,3'§N_&Œâ¹9l@ˆ›¨™fš´ã“rƒ¨—À, ¯ÓÛÙm“\c!«+ ŠHiçDMtkàâQ—ìgJ1Hš×ÙÉ|)¨·¿µéEänúzÍÏØ$ã=X÷iÆGÙó Š‡‘UÚHàP” Ù^ª#ôþO¿ß^xú)¤†üÐxâ€9ÔÛàýå?1ò@Òˆ®žaû‹?û“·lñb–òt¿ë¡ä<*?§çª+½ÜѯZh©}ÎAØ Ï´zõ*»ZÞÌ›äîÆM7PXæàÃPjY…1 nÈL¯%ì^ë¬ë[¨±h»ölÇ O[Ó_„ÍW‚;%š /¦häÀ/MÌÓF›¾ˆöˆO€îˆjâA܆K…á†P'ñ©ühκYzŽ”*Õ“ôÓ‰å0j=6p©N€Ãàt·¨ÔƒÑŠ>Ã+ôy ä(\¯…ºDäH±|ôi¦82¾ðþœVJr&ÃHÜŒ¼´µÄ£åÌ,G4‡›}4¤´/N1"E,ô­Ãáõ®PWÕSW‘ ÀS“ãóð³jFŠ¥; ““’ŠØt&Ðù¸u1ËÅD…î=‰hæÅñ\>?×l\uÔ3-œ+zYLIYŽ—´wbÄjÏ_€j³™÷¢y2 4]…é,²Ij?Ž.Õ^}å5”×S@°Ðäb¸ïØ‘S¶©MçNÆ•‡[ þä¸/4/ãa‹Æ™»Û»áºµ±éxÎV€–)oÁ[@gGqnà iÕr¾Û]fF=XT´C¡ÙÚ7 o¥(ÍþêÏ°Š”Fƒ…B­“"w8‡Ê—EQgš©Ê#Ð@Ã×^èß Ú_<²ß¡—ª)Ê”ñ?…qN “u’—a÷'Ò¶îÙúï6àžÇ ï" ú}ƱüC®0Å«ê¡ôJµÇP¦~DîEQѰŒ¥û: Õ:·€54<ç(†>I]4ù’¤ø3s²¡Âð9K|4׃ h…¥QÐØ¤(RYnxñ.Ò¾<ÏÕ¸+g•ÈÁ<!yEÆ®ö6¢æuxWÃ1„,úHUÆû»Éi ŠçÍ`A3ï €²òà¹ÈVÈZ€w‰Ð‹¤y3¤c0|/ÐØè¡0‡¼…÷ÆpHÉtÕÅÖa™ÑõИ¨ŸÂ| :ˆ–szx.ç´Êõ…ÆSÓòÈÁ˜â^“Ÿ™X´Ä4Ôgˆ š^$lq‚A½¨‘4ã12L?i§ˆ0íõHtCE©)0 ø,WªÉ.ÚË…pJÀ¢ =І»!I«Ò2Ò-@z6N=ƒÒ=¬‚.–‚÷b€ îõIõ:Ú(Œ tÕΤ¨UÖyHŒ©oBIDAT™¥vþâ V°ª˜º¬FΈë®èøòáíØk¯‚r!áƒsÌÉ$E®o²¼¼•À³\jǥĎj2® 5êêÕ«1Ö m»aKg%=´uë*«ªAY0ªµ½7®y (ÚÎÛßX¿á³öæ6ô’ϸÔ×{×m{¬ê{¸ WZÙîýVwö5§“š™OÍÏå‚gqÜc­¿£›G.Î }è3µC¿9‰eíÓ½Šû%b/VGÓðRÞ¥qA—8)YVÕÛ2Œ”Š/nÐï«A–V9¦ž«´J¿Wí111ሉjZβൠÕ:û:«Ä¢R\^Aøn‡jQÇÓ¼žšd¢L!(63Ì¡#ÿ÷ã…ÁT9°Ô@™Y9Åî{^.cÏ~.ȇQ¹Xòz¥0#Tm‡UtÐþ­¸05…<7OÄ%ºè÷$qܼƒýyÌW"úËa÷xhÌñ_7jºíúö@ÅÆËƒBüŸò‚SR‚û5eL2 ¥V*ÒõgÕ ªE”^ÉXôwúgXSݶÝáU³ç.—ÆW¯›—ˆŽ µräa É4HU?ÓøÁØs¥t"ëÖkdgåYúIChaõÒ€Œ* Ð}çè‚tP9Lµ Å7|´$Àœ·Š^I ‰ILÒéR6* ë.rHèQ¹ç.Ù´^@0™Wí[×Ì ˜hCR=„3‹ÁzxM5fgÉùuÝBñŽ^—~ÒcˆÌ‹ G„%ÕE2†×…ûD‘=ÚÕÎá gÌjK`,u°g …ö– [Õê´jM‡>EiQÏËw+[WhEkŠˆ0äèèÚn\_„Li×µ‹GmDå1Çqš#Ÿo¨­CLÂJ /„TQ>eQ2‡2…u 0\åïIÕ‰$ƒDÔY¾Ó"¬äØxÄæ3ƒ€1ßQL"Tm®Ÿ=ú»#xó.j8”T0ö’5›ÈF†­”ƒ= J—NÁ]Ù+G^µªÊ d)Ú‘j•`,³ô<úA³$_¥³8ÅŸKaakÕF^_&8ƒÑOãÙuèl#Xê%Š8~} PÁëK„ƒS~ Yh†üú„,åÇ!d‡”ªJ‘Üç¢Å´<5½)§²´¤ºB;îç ¼œb7*ˆ—Ê«d…tê‹¡V£°eVFãªÚ2 Ðq­ºº¥Òõ†ZZéa1#‚Úf(¹QJfšë1èšD£›–˜šÏü·"A,¯•œ~O<èUðð ˆÚ*„"‚€8OóÑ©@Þ¼• (YnÆ " n5(ª Ø+¯þre†Ýwÿj 6FU°7Ö®5ÖÐg;÷(•eë62„WßÀæ­*R¨¤S›˜û©v3(gO¥îŠÇq4¹è—œ˜ˆ<i´z/©yËC$'\àÌDqO+*.Zg3~Ù\–ØG#0ò =@ïý÷ßÂE4Û·áßÖfËÍ£r)Ú‰7 öA¾> £5‰ D©±êQ8G=äëñÑèõÊ=tu }ä좇oÞ¾•}!¯÷Ö‡P)E=W©Ñ›à­Ïü?-G E½†~ÕØíù7ËBËÊV3µ×Ê®|ûé£ORpå9¬>@ÃaŒ}åÃÔOš& A`y mŽ­´‘(EÑçÅhñ É„v9-H 5Ø@€Ò¶í£V¡é¨Z—ïÁÁ›‚„Ô ©n\7tºð\CQ@?§þN$c"? È'9â=µÒ‡×ÕHm€äàÏ‘ÔÛ·‚Ü=L/JE^›ÓV#75=8w•mÛ¾´wX·ÄÚ0’„äd7+Ò‚@æ’[RÌ}Õ#ENDƒA)['}#šTÝ»÷/ž^ d&[2së¶í¡ø"Wt©…Aì'ßyÙvlJщ l÷Ú©cõÖKþ:Lê1KnV‡ýÿqW]:0ƒçLLÍåüÇ!_þÝuâ!‡Êy~¶å‘ÖüߪStðMôaè¡×èííw°Ÿ¨il@­Ç“¬*a PÝmûn²•¬N$_‹…–LÅ}¦²ÇDÃG ßSD5¥6zyÿÌô †–c `ç+‹6PËpèyßwÝ•be€})cÓõâý+‰rü¨ÅÝ¡Æ6(Ô5¯Î«s‰ü¤BÓô*BÕ»àšÌ‚(©Ñ§}€‹ DÚAj¨Ô‹ñPÕ|3Ü@`_ {]_M:z„˜p-·K u.TƬè¤=éšBù/„Tíö[n†ŽÂRÓUäèÓ´—<.)ÇUÄwMýI'ÕÚÀzoPãHi@ãH‹Ù²;7Gê ÊÎü¸&EW®Lãžè‘ħ؊âŒh‡2nj<ü4š~~ j1 /M½ÆêÚi¨Rk¼h' ã¼|Ÿ8šÑytÂ0ú`ô´8݆-û1ðv[YXÊ‚Ùkˆë1˜‡‘ÕÖ–Ó³è€ÌckÖnöf{×ÄxvA·ô2FA%0òÐB„™×K{jš³WK|Ô`mfÖ$"c'$H­±ªÔú d̜Ҥ¶þ2©IeG(¯£# äÆÅõD®cGÃeТÅùhïY‹SÿÐ?ÃóPLl²º:hÚ”>z iȦ¨ óüóMÎÃ)Ä_φH3ðžšS^›¿Š×ú‡ár´Ð¯*¸õ’SÏLz! ¾ý¡ˆ¡‡Ð+=_†!#ѯÉ`õ2 5õk!¸µ¡‘”pµ8~Ô¥OÉ© H…²sìxÐÑÃ¥Øö g5EÊ¨ŽµDªõy¦gà6ï æî`›–Fdµ=7#3—ÝfÃK¤ Á×Ý|CîçðùÄëR±¯Yw}VXlPZ*CÏá”ã­ètÓ¸”úIK‘D„ö„kLxØ]#ËDä:z] RžÇµSú¨4É?ãç O"âàeyf(„ÅŽŠgõ¶b˜.Ô¢šH } óp("K¤™ë bPSº_ì»÷óç¨sq’åñ t·z-ß…ûj©)fßãH&(dC!Fà ÂîRt”°5¤[óCq최V½‰xjŠH¨9Ÿ%>RPS-Ês= –,EpÝA;ÙëÎbRŽsёሢð2Ó3wü9­žž²¼âu6‡ôë *ç;<Þl)DÇ÷Ãñ$aôjLVWÖ[ÑZ²¢æjTÛ£øNY“BŽŒLPðï´ 65‹,98Á Tû˜Œ|z è¯Ìa ‘ú–÷ïCÀÄ÷Wÿ£àÏ4¤\ÈЄí6Õ_´n7;“Û=nŸbŽã»¿þn ·¶×þíßNÙ4V6q-’Â46nͱç¡rs¡ôP¤ƒ&o–›l_ÿöW8î?¹-ÇòóTCÈ®§g×S­åçè– J±\,ÿwé2 íF÷qÃÇ ûš›@]«~»Y“‘Éx& S¬šî*ûNXƒ¶H}ä¦È©G:¹xµw(Tíç.£ŸÏšëR×­¥[­A#ÍÆà¬ñPS– „Xî,7`Yä°ž„l@Œš!’€'E&Ô>q­õ}ÎÉ‘†ÑÜ£ùJò›Æ‡ja(i–äOåIEâ#!r!tÛÝðöÑ×ÛNЧžé ßÇÇçUö5‰‘jaïù¥îðspÒ¥bP´k…zEê峆ê&÷††g ƒvÑWÿJõƒ¦¦ØË­†#ïAôãÉ1Càð1•‡ñ‹î‚…ƒ¼ t Ç€± JV>=-Ëí˜ôñTô =‹Â˜V¯[KúÛe ¤/õ^Ã/Q‘÷Ø9ÅÝ;ô—L{ê‰_ð}˜ …&32JâÅëDÇ3Ë ÖRÈà­§¸/Ó¤m“4P“舭+Æ@{nÿÏ'qöì¼ rRÀ#jÆNîSç”Îßåe±]t®¾®žÿ®à/ãy] y–ñMBt|)/–Ï ÚE Gy¤ …LÏcßú¼ùû8ìRe'åæôBXÔ6 ü&ž5Ü>üð x0åÉšêãWÞ°>\l"©ª o¨fPýÑ „¨BË^x#ÙÊPÞüX6E '1ªTº¥¨¡¿‹aÔ´³ÏBšsµªE”)vñ Kt¨Ž>Æ!6>Fn œ¾‡8LÄV¡–ò)h$ÜH¼â<ß½¸x3‚SV¶Ò­o‹¡©&I Rg†rØÐ»i¡¤Zn3à †D˜§Pçæ,áÝÄê¦+K€ápˆõÌgOܬÑÁn§° rŒ>M‡\€ÏÈÉ&7 #=ðs°±¼®˜°òô=ÔÒïÒ½À+81ˆ `Á¢Œ—¿ '“’IÔ (D$¦IÝ@_Aãâíöý»I/á;Ñ, ¥ÁEP[icqòÿL4”sò‹`õæYVÐ>V§YxEÈÇ…:gÍ*ú›îz:Z4V£?‡MvÛ•cÏpÑÓZİ(xUëáU¢Å›„h†‚¢°N¸sëCæ¨Ë’ˆ.r™…›H¥®º±æ½7®b1O)uÆ.¨%Åœ=íyOFþ§§P€£PSW“B à” ±ežïŸžG„ä\ýu:GÆÑ[èCÐ#›Ù8+\_æúTýÃÔz8‚÷½ÿ~æKèØ7ÙÑ#癜€‹(ç»ÛZŽ$:„Bà;c!ɤVž\î9{â‡ç쫯àý¹˜ì@n¥ŽMÎŒ§ˆƒð¶ïÖ‡iÏ(oçÅ\qîn?Áßñ/ÆO³øù·xyüëR=°|Ya0‹G®¿ÚËóhpqà5Ê*C{ûcùçÞú÷š‰†j"’ œÛÑÐD¶ëòî۟ܽ PóÔBÉÊ­Yçm5 Æ.'¡wh^^,]}J?±Qi@¨^ûÍ¿r à4R-Mÿ…2ÛH_'—â–BøÎ÷Ør’ñbxöKv;”i°LòVn ‡Kž_ ÓYÒÌy"ð8½ƒIRH?)¢¢_ VP¬1 K­ýrŽTk@Ào ;`‹4ÞÂ<®œëL*¨ƒ‚[= ¹ (Lósópçf\Ó“ߤe‹UëšÇ¡_hÞE<­ÅÚéÅýDeuÆqÜ.¶lqHÄä;€«ùGš:I£³ƒ:Ø,ÚYâš ¢^ÒÖŒû@k“Õ^:²ÌŽÉg~d³ƒmVqô ]~å µà™ù€AœÇlw¿µ\9É÷¤!Éõ‰Øx÷Y‘“›iVD3rl¢—> ªö¬ü¾x­™¾LŒ‚6ÔVw=%jï±›÷ÞÊž: 3ÀaLáóäåä‘Ê%pbøŠD$€˜6xt“ÈÎŽ‘VõÒëH`¸|¾’¨ Ïò Œt÷Š¾Î¶S‡Ó|ÌFÉ'ÛòRÙòÛ{À‡Pk9»ïµÙ‘*wÐÌò¸Ü¼xýlUšŠn´¢ô çíÚeÉ=2D„'”\}Ù®<ënäærÐ$³Éã¹úGÿ~#ÅJJ~ãOüÕyþeÒ¥\P’j—^¯$L¶Œ”HÈ£åyÞüX®CôwËi—n¨ž'®Õ†&ÝÛ)¥5$…d~'"§H­< ,Eþ‡%HÏàMH ×m}§?ü› œ_½f¨ r (nã2ü@…°@Sr¸`•tH’Ô‘ÐYfcñ턇÷î³)$LаöE4 èÆÉ‡“J!k¦OËgT 7‰½óä·{gC¦ †aź„Ñ-üXÜ4,ÙEŠs5&¹Ôf,ãÁÏ«×@J»Hÿž4× À·€¾VGtÕ Ks(´ÇH'ÿî;?„¾±’†Øˆ ’Lc @´ OþÍûãà0?ϳ4<çp„î[XÚ!RjÆ~=²Uý6C4öÙ–ØÌ‚dY÷µóœP< 6.Ä1zMDMTÙÏ¿l D徯s\ö&NF„¯"ÁÔ‰¬!4`0ø=›¶ÂÈe? ×¾ ÆmiÔ_=ý¤Ý¼}§ùS¨Òs˜cO·Oò«|s ŸR,1¦'iøE!h¡¢‡Hʵš€Sæõõ¡øŸdí–ŸYôÌ ziªÍ á´´tà|NYýPê$Õ'O·wï²…¡ Œ3Óü£½u“µ‰7鴄츙Œ-^:`Ÿúðãöôå¿áÏÜ ¹f~ë¹°žlÂgQÎÇ>s Fb§OpaDÅóÉBœq(Íâ'å½ úýÛJ‘–D¿Wš´~K)_ >ÎåjèˆoZÁÍæ¤½ñÐsy–ª]”ž‰fLtðx ËŠ –Lß#œ™‘‘ êÑd¹¹+È3k(ÐÓÝDÞ 4š0¶Å!N…Ö`ÈÎYnm’#.p±OœxÑvî¾оðä{˵&9,$þ Åp?5…%/žà_M !YⳋÐ8ǵ uÑ¥&²qX™ó]ÄH}ÁáÓ¸*ÑÕç¹–óäÕîQ‰Zf4Ë$¢/^Šë«ôŽkMTôSGžÐEñƇ :ëA.ˆºbšnt #©Þ9˜ @?Aöz'‰$ÔD¡œTX·€#ŠÒð¼qP@²¤YaüÐà™xc|FªuÛYºÕ~Äyø$4¢‚í·à@ö€^¢MÈ‘y7Ø ¦{ê[‰)Ö@Äòò^£h5¢  óôCe*´¡ÎrÎD‚‘þ^zKqì+?‰*{ͽ v߃7Ù«G®-‡ºT¡Á›l»¶oåÚ2›XÑÓ£‰QÌ<ªÖÎNëhlrˆcZJ10p+.ðw˨­]½Þ©Íä瀜y³prÔÛAÄVá„æì¦›öózXéA Â÷í\g®Ý€PA7:µÅ\fö(¬y¿mÛc·=ðÖ¥•¸L·´%|D’M; PÙkC ¯¯±`'.‘srý–£‡~'”èÆ ûíÖÛ¶¼ÅH–k éËÑDAE¸¶ fœfZ-AõËÖ¥§d9r,#X㙱Г۠+§ó“j‰gýYD»7¶‰U)I4átˆM¶‘ÞNØü‚„¬) y“†š3v¥!Œ\w%^Å^Îø*ë |Qá: Æ"²m|Nõ[¤M•ÆðàR²åA¯Ù¶‡>`çΜsˆÊ)M?µÆÈ =‹jFûÙ‹ØÓhÃ-Ìæ×Ùªƒc†0¸|¤e‰‰ôq& ‘¿Óû#ÍÅá à€%U`··V‘ ¡“Ç–HƒD]ñP 1Ìã bí4L¤Sâ•·˜úbÓêUJº¸F¼~f–z+Ô,”ÂÛÃ, Ù8Ÿ]ˆð·N h'@d«4F•XÅ!DHHŒ z÷‹ ÆûqÙ-€ºà>áK¹ÿQ’YÙê•6 tšœY„Âa’u h7û¹Z6“væ { Y¡ Ñ´¡¹ÕÖïÜj#DPÕ*ydMíƒöä/Ÿ±~ô#ܧk¼¦äó<4ÿlïMŠ˜ä̪L`|}­õDCÎ=¢Úk-Zd°¼¼L>A² ñ¹ÚÚz-)+‹ `Dí|æ s-­–ŸŸ…³íGÅ1Ï|ýË»Áñ&è-ùÓl´ýy+¡Ü>õW7[|Áfa›Dð÷ÛhýsžìÏ>q3>ŒqÒ–^v}÷ãýüöúñ°TЫ1¦(ñ¡@±•åŽ;øÛÿÿC‡^i“ Fÿ´¶t;tA÷"‘¢Q°å¾‡~½n@×ýœŒCkdEš7ï¢þˆG·¡¶Ñ`òæ Î{4'k´ƒf×-žO±Ï§.?Ñ(‚›Ô,AW¤>Ô2ˆHZ*3 ¿ËËŠâf>^;yÊíj"¢£5 Ç"ŒšM¡õ厥k)r ­¦¦škANï>?ÆB$B·š† ¶\n<³×Y¶<µ@väæPsDRNÍ‘ÓñSˆÜuT}ŸyŒZ«%5J%ºy÷^;ðÜKÜ;}ÙˆiGaóH)}Rç|À‡:9Ÿ ˆª%¤`híÂÉë„U‰õ½"M(fd`88Κ«ôËÖ²ç°-,2^»0èÈØ¯(ñCDyVÖæPý÷R4®äÂOZÙfÖœ¥ù­`ß~þÌË"oJýÑXKUOA–@H^@"Çî‡Â^°]X¼—:¿âØ V¢‡Œ¤»›†“ûÓõéf«¾ÐCéÒrš¥¿V-JÀÉ×* ‰t M4 ³ào z¾´xÛiXê!£LJ‰ås°ŠÃʲ|D ˜‹&v'PœE±Š8…Ni$½5$Cá’…x¡X“kªX/Ýt3t˜¿xE2W«ôwiŸö<Æ‘<,à€Ÿ£<¨ôF…½@…I†v¾ÿ=îà„“Rh‰¦Ÿ=Š÷ã3,òEG`Ôê‘Hâë$rèzA%ặ×'¥¢ |-$‹ƒ»”¥¡.?lÙ QЕ :œÁžp¼ð lb$ÕÕ02Ìð$ÞwŠ(4ƒœK_ñ÷º^ƒýó<1ETuñ5ý7y³¥rï¨uÀÔÕ¨²v.ô÷¹ªÎö.6Ëkš:ÑBÃù4£»ÛOc”tSK•¼¦YÞ¯êZ¢ÚøÎ!=JfÍÀDÊ:h+MÐà‡(&àbÕ×uسÏä¦AÁÁ‘$–lày8Áפ£)€aŒuoܺբh–†ó½wí\ ¼>Èýb¬(ñâùK܃èï/rÝ` À.ž˜î·dR¬¢¢u,â)qLáYÝ9©È-]ÁQÒðE]qf†mÀr‹J¬¦¡‘~Ù×a¢W[}§\ŠM­é@ùßEd*t}iýRIEND®B`‚exiv2-0.23/msvc64/testimages/test.tiff0000644000175000017500000057430011510453102017430 0ustar andreasandreasII*š÷€?àP8$ „BaP¸d6ˆCŸÑ7Ëùúü‹AŸÐ'ÜYâø|;ÞÒ7Óéû“Æá·³áÎôz¶N¶£ÌÔq9Zn7;ùøüx¾_M§C¹²çv¿iRwëÊ@ó|>_t¨Äª~·]&õLüm9]§ãíªåsÀßsøÓýüâw¼-G ‘Öð·Ý®ÖËqÙe·‰%*™f²dÀÓKu¢$“> Ñg„.M‡: P©²‰@¶[2íwÄYÒlÝîj, ¸ëuS ìˆäBc@òBQ$OÅéD[™hTešILVŽDY>UrÜšGàOF1¸vžf!¸rf‘º]™FûTŒcÙ-Žd Úá$¼?Ã9E¤‰FNF,Lz‡Iì—F™ÐU¦jl{ޤA47‘h¸9Ã(þC „y.N–æ¦5¢`Ô6 cPÞ#ŒcaRD:RÊ$ÉzhœÇ\Fhœç‘r¢EÁ˜+ Ä S•Ö!* #hŽ1UDA0V˜F¢V™ézgœcÙ"S¤y’„¹’mE‰’b…qVD„ñj`˜Íë0B‘-éJ•%(þHåÙœe&Ù¸iæñ$XõÑìeœñr2Ƙ´C,C ‘F„¨˜ÂŒ] !^/CÐŒÁÜCƒ†!C†¡ÐBˆ0àÃøn‚H°þ#éÃÐF=‘&ÅQ´VŠqp.ĸ©c@qb¢3ðç~ムa 5D(¥bHSŠÑ<.EðÉãtL q€"@€”\1¢&Eˆ½âì`TbÄX™‚6EøÕ#”x¸Ð.áæPâ ¡äAfžÁŒ¬º¢µ!ògþÁdá|ÃX*RH†á6N‘¡<¼á°¡„a\!hAÒð.¡L<¡nˆôBÈ$«Lá(áPáLÁ@aV“áF¡, îáÒL„>‡@æöa†5œLaº¢T¡‚Á"á>ád@$¦AnaŽalí ¡a8á6BTÁ@!$LA!JaÙ¡Lá†á¸"ÁØá?Ár°!M`@ô82Á:a:@âa$ÁP!Ö(A6Bàæ¢¡°á„о¬"áˆ5ZŽ JAj˜”!ÌaÐ`ä¡2!`Öa  ô2¬¢Á îLˆ!*j0áàÜatâ^¡òÆö4¬AFŽÁÌ!!`A¶\!FÚÜ¡FÁf¢ Î^ Á`¡¢¡>ŸÁÖt¡&á’á„$Š!Pn ¶åΦ€´3 °áàÔ!ê`ú « `äÎ4 ²  Ðá  Üö Ø ÈA ã* ¡BadER À¦`î €Ê  ö!J‚¡júÞ…J àä a’r`b €Ô@ x @Ñ/€ÒJŽF$ïÀ®ÀªíÊ„À¤b dŠÂ@¢dठ° Æn J´ ¯,ª/ñ ”@š | ¢®®˜ €B`Œ`Š ^ `ª Ž RÀŒøàvÀn‚ Là|€`P`€ rÀN † n`8Àl ‚l `˜ùóÁ<3Ä!‚˜E!öúað$¢"b¬+™=o°vÂB, jt¡äýAä°!¡Þ$°¥to‹ÄAžOì´á¢ÁŠa¬ Æs£ÞñìÁ¦áÎA²£ÊAÌÛb !¿@Á´Pa~!‚Aèáö$Að¡Šáf†RHÒ¿Áv€ð!2,¡Ä@ö$AV ÄAjašÜâ¡dANÁha;áNqá!0ˆ$†ÁhçzBoaô¢öᤠÀ!Îášs!þXÁ†¡’~¢ A{DìR!D¡~A´ñN êÀáx‚pÁäÇ:AVˆ¸I"a´%Bu&Pá˜æA~áH! 6áT$­’aÊDEŽc¨`ø&’¡ÄW§@¢A¯Y`â! äöC@Î'| A0ÁyQ ƒ| ¡!TázaJÄháÀ!èK[Táâ.œ a†vŒæbº>Váš¡X î¡XÌæ  Ü!`Ô¡zÈ”lÐVAH ¨F àæ€² Àê ’ˆ  Q¾ àü@ÊèÈ×! —! v@A €´88.`ª àæ @ì@® ì @ô²@øAtÁ¶ d„ `ä`òÙD¸à,a<Ì6 ­Ð @Ò ¦  ð àü ôÊ    ÜrÄ  ˜ Ü #4”á^¡Æ º ’ø  Š —/ „ àÄ@¶ €ˆ nè €°àœdàž .Þ ª˜ ï €d ¤ •3@˜  Pðæn ÀN€–k’oHÊÎ爛 €ThàY6`T€„h`”jð`ˆàVó¦ÀvoŠÀkz hÀFÀvœkÀ`7~`‚ @¶²`w¡zDž‚!!Á !# °„¬ê4á´Á&a¡*‘áb4n1"è àA M4‹ra€þa.!Ba’á¶o‚ AI tTÑAbAP‰Ž!'"§h^ëö ê¡$ˆ·€¡`¡Á*¡*ÁÇê!Ø!B¨Ê!€Äv@ú¸Š{¡¶aÒÁx`ÌÁX¡A!hÁ˜AJ‚AÖr‚Ö®áARÇ¢1"àA’áÜz,!!ÆDázÁÆ¡†!Ztì ­º¡!w…¬ àò€ÐA Àú ´@ð.`¾Á òmZÁ t z$ æh2 ñ" ¨ãÌ9–áZVâ¡$¡Ö Ì!X¡6 €Ö¡ L¦ øAJ¸¤‰ tZ`ç£@âá$áf@Ūठ`î º$G!Æk@Ü  ìÀ’ Ö À @²€üá˜êfìÀ €|ì€|öÀ𠀯€² îF`x @Ä   `r `¤¯@œ †8 &n R ”àž ïG3À–  Th€F  ô` †‚7R’ `V W| Šs’ „VÀš ÀLàŒ@d 6 pàiz dà8`j|²@xÀ8@dÀˆ€Z „“‚ó«}›Í¼æÌn!ð"çI~Ϭ O¢s÷ñ>Ï>üÃäêDB@q³Ø$ç>¢@!ÚÁž({À¸(B,¹b’!É¡vᦗ¾â%¡Î<¡Ì¡ä¹¡æƒî¡fá’1Œ'å­ü A’²´aRña&Já@Aa*Á8A&ÙA:ÁAá¡,A Á@áH™\!AHÝa‡ ¡faR)¶çmL-â%@ú3!-¼ÞA6ê!jT!¢o²tUA8è†!ªYqÌAeã¡6ÒÐüõû’XÚ¡Ø’,Á6‹Œâ Ñ‚ ¡êÁFአö\¬ ‘¹TlÔ¤2!$ÁTa[' l”ÁªáA¾ùžÙ¡X Àò¬¼A@¡j a â¡ Öoa°è:pAZ 4ÐÁ¢!„a¸#ÀAˆA€aX}.¡@ Vœ¡ÜøJº"¦á<äå"Ú! äy؈àŒay¢ Za" Àè€É¢º. ¼G`Þá @Þà¶ øËÁ–[‡ \"ÀêãÔ°( üxé H@²,0¬ òb:h€üÁAݘ¶áäÁŠ¥"€À2 Žœ ” Àà  òX  ” È Æ €å‘@`¨@® z €À ª ·Ê €€ àªäúÆ ž  {À“3S¼@Œ €dªf `–@”  Y¶€S6`K·Ûz XÀ„ …9@ˆ O7€G9 T`„ –iÀ‚÷@„€Bï¹ C{@M·`A: R@{öï†Àn |€F`yõ pÀb`X Ÿ½™ù³È-Ï£”Ü-bÊo"Daä¹aÝÃÁäà™WþE¢ÁáŸaØÔJìA˜á¹OaÄ¡¸©"ULΜ]‡V øèw¼ŸoÇëêý?ïgÂÙ’Ñn8¬{5âïyÁ Kvs6®V¦”ª„Ú­PQ')”š=6˜F(jA@£T°XŒtJ]DžV«Pé”ÊUF¢F¨ Æ=Æáy9/=$¬[.×LfC­äóFÊPéeŠØo·6Ë•Äâv¿ OwËêŽX.TkEó•Òðx¾_,&ƒuèõ}±-Ô²•nðz>Ò)N®>$Ȅ♟R RÊœÔ ðü~4œî¼ÖeþQ­ßWÆY¸}š2›Mcz)"«^¯PIÄêÁxÂj¸ÜçR1 šR@ÙŽG!dÚw8 ê•ÒäèŒFQHãiõrB£Rêe‚-2¨Rs¬¦«ÜóK—L¥ Zc’%Aj>’DñL”ÄsG”qUeQŠi3GéþÚä‰dcf¾”¥ÁœI>ãÑI™6T¬CiI‹c˜ø-Ãè¼:BÐâ<ŒÉ_™ÆÈÜ=’£xøF¥¡‚R™&©Ú~Ÿ§Š0ŤqžãF_ÆÑT¨Ú9‘åATB%(ÐB£!J%ñB“åy:Z—CÑBU§ÒÙÒ0d3ÐK #Ö Œ†0 ‚ Ä3‡âè‹"øx, AàÀ0‡b¸¶Š¢Àp+ !°¦*†âˆ¤ŠbÀf) aè´-Bhš Âx\$ €˜&†8–â0ebâ`œ BUlˆ‚(F!a8†!„w@ÜbŠˆB0Knâ(Œˆ‚B‡Á(rA¸z‡Aà\% àlˆSt„AÈv‡·Øl!˜p˜¬-ŠTÓWcùC‘dy&K“dùä§‘ò|ç¹îr«'!ÞwÇ©êwž‡¡ØzžgAâygg®JlGl¼uGAÔb†‘xh™æ™¼oæažvG‚ƒžˆ®tœæ¶pYŠÃÉü…ÇVvf-ÆéÒt†‘šhœ'„kš%9d\fáÈ|ì g¤é*C“d¹NäI&I¥YXoœ' tg˜ä©LR¤©,N”¥9 RfÙ¶t3Eù i%‰nQE‘ta¥é¢gE!d~"ð›Ô•ÆQž›GAÖVA?ܲçÌ®mhÜyÆÙÆÙ$ ÁúL–åÙI“¥ .J‘I„ábY”æ1ŠgœGÀvÑn5ÆØ¡$Í h/¨å„ K%((kÂ<;‰&Ãø} !à= 1Ô9ƒ‚ax;až9Fðʈ@ˆÜ „hk‚ 5ˆQÄp‘,HÐæÌÈìÌc QÂ)ÆÈ#to Ѩ6…à˦hU á  Dȧ"œ^Œª8…(½âR aÚ=ÇÙ„ ¨@Ôƒ°t˜@N ÁÜprÊ+•s®•Ö»WvP<ÇÈ÷CÈx×Ñâ:G‰YcÐx3‘¸:‡Xáä25²xÔ?Ûüc¤vޱÜ;ÇÀõ# t¶øA‡pуŒŠ¢=†âôzvRöÞÐÞc¤b»!V.ÅÌ ¶{1â>‡È³¢èE 0)E`°rBlJ Ñ8!ĸ—bàYŠñX/…`¸ä TÑ4*ÙscâÒ=ŠÁoq„Ø™5"˜\ áŒ3ÇÜBÀV qj.ǘõØ~‘.,ň•ÄrŽ¡Ü3œØ³ã$h ¡Ãp½›O‹”4‡•üƒì|Šr47G8ïBpU 1H*Ep¾â0N A%DàƒÂxJŠQmÕã´Ê á7FM´#,f‰K²9Ç€ù¨t?¿Qšlð³aàG 0Ô D(m¢01‡±Cð âDq<)ÃPŠá¨BÀÜ!D–YÄèI‰N*ÂJ0C:<ñR2FpšäTŒ”2ÆØåCPq™¡¸÷„IQO0ráì8Xö,âàE ¡xf‡Š÷l5ˆ‘>—LjÔ£´E^R/†b€3±„‡B`M1"'ƒ@xAˆ;@ê!D˜V¡ñ¼ ÑáÆ@áA›7†Ñ$Äš¡èL ’(Ãy˜!Ð<‡Ñ4& g¡p<‡À¸Ãà]âDàô%Dø„"üiæ,Æ×H¤EŠ‘d„@• Ø?ò¸¸š  5°ÈÂdé sÈ ¶'¨F !˜@°À\‘Á¼+†ÀÞˆQJíZ@r¨Ö`KäÑÀd´ðW ì*@f 1 <@ B(H wž¤(CÀ˜$„•ÖA > ” SðŽy¨TA °~Þk5ŒS vÁà>L@ÕÎþð3àhƒPBA°àÜ …ðÆ ‚(EA$×1æ|×›ó(tF\>GØúg`¾ ø=Ƕ3C¼zÛöB6,ðý!>ˆ~‘æ<†°âÃPnÁ†5†¨×…Äì;LÑ—Zhw›4=H‡¯3MÔr‹aŒ1ÆÎÃPq ñv3†P¹à LŠ1T2Æp×`š8Z… £C$ar!ÄО#/ü#Xj ψ xn‡n0q„hQÐ?hG„pN„èh‡nƒøH‘XS…€o9׈J…p] `lpwºO²â!1†ˆ†Øu@I…ˆZ„ð]ðf†ÈoAÐsho_†xmcéÐq‡hG…V [œ`QI„àDØUI{=8‚`wÐ`†˜k¸a†x\†l Ðv‡ˆ|=8Q¨aƒ€D„€78Gƒ G„À5³03³ú…@9`LWÈA±;PHB H…O;ƒó†˜nˆ{‡{ „pRp@7Ðh†øs>ðvB9°z›pGˆfÀ ®‰K‡ÀU…ømŒPr²\-0ÅM0B…Vjåµ8Q†Pj(N…°e`Yƒ :ƒðDûô¸`0N3ƒÀCQ…X(0;ˆ_`sžÈc‡ u¨<„@+ >xBp9!Ø.ƒÐAø<„ 0ƒàCƒ8>„Hƒà,ƒ˜=„J3ƒàBCØE„xS… R…øi˜øB…Xƒ@@„X4„J7¨K‚€5¹p7ƒ(ƒ@4‚4ƒ8 è‚ .‚€2ƒR]T•‚Ø!‚°*ÉT‚ 9ƒ ¨* '‚ˆp'ˆ'`‚@$‚h4ƒX9@‚H#‚(/ð‚¨.‚*|˜$‚`b˜ðÊ ‚@"`rx(P ð ÈÀx&8 ‚ð8»¨«Ø*à¸øê«ê°È²³ˆÌHHL »¢„‚h0!<äÔMLÕMXQ“P‡ŒÐ†áŸ ‰ l؈h‡,s\V‡øp‡Xu(tPlÀa†ˆi†¸mã‡Q¸‡•‡ø}’ºÚ‡ˆ½}†ê̸܆ÈvXd†ào€z†Ä?hƒì… a†`†HdÀe3„Èe°k† o …  S…˜V pOpo„Oðh±àz½n­já,y㇠s…Б„xRFÐN3ÀS€LI€UZˆ^„èX…’/† °°‚¨d†PI‰HE…S V… ]°pX…ØiiåxÀ{ˆÐlF(s½h|ÈA„ÐP…W…€PÒ¨ÔøIw ¹†Â[ð[†Xg…0^†$‡hyeøu y‡¸4BƒD`6Bƒ(<ƒø5è@¨E¨qXz„ØY°C¸J¦È@ƒP@68Cƒ>EPf’øwøj†ÂAøRÈ\‡+ ˆþE8Ð_±‡ð|£jà(†¨t‡ VhƒÑ˃°GÈC[ˆbÕ"‡ø?„ÐZH„øLpW°W…/ ?„#ýƒÙÆ [†ÚˆJ… ?°N <ø=`IÐ:ÜHä|ƒø4 ÔC„šDÐ1ÐB…41°I„ÕJ„M˜_„À]†PÍ-€0S <hP„HT…è„ LCwØ)`8‚h3ƒH$¼€$§`!°0@-ƒ"¸.‚+‚¸¨ø#‚䫸*¨'‚˜‚h%Ê'È'(x(ˆº ‚`$°(‚x‚ -x5ƒ€‚H"ªˆ"io¨%‚U©‚((!ÊúœÍ2›Ëˆܹð–ø!v–ø‚ª!àÃÄàLè»"£øˆÙ\訠  ˆ,‚è6HIlÆ+MeÏ\ýÐ\øs+ð…<ñ‡2Á†òʆ8·†0l†ÈcOÐz½`ÑÿÓhðyBÀz‡pxøB5&˜ðr‡}#ÃX†Às@^†xh†2˜y‡Ðk(s!¬†@h¨j†É¾†xf¨_† {ˆ@f†èl„øXpQxU³@M±(N¨N…¸\†i‘À„…°f`B„¸M„pPN‰dmB fú¹Ë…(Z…ÈcøcØmÅ*„ ûŽ`a† m£x}ø¼ðyÒ}‡iؾ!ŒÐE…8WŠHO…HZ€B¼)6øj†ðt‡xžð}‡Ùè(MØ_„ÈW…ÀW…øf¶„ð3è?@?Ø3„Aƒ~ÖPXG˜@„KØOhЇãêc« ‡ð{ˆP„À[†@;BHI·îC‡›Øü݇hS…Ðbƒ•B„8N,˜@å@™0Y2@Z·èb‚°<@U…¸bšp½<ƒvH:`ƒÐ?‘1„àWØ,¨@„Å1bpVƒðN…HA1@BBRR…¼R…Ðk†ðIÑø\†ÐrˆgôßÀ0u‚Ø;„ m`)ƒP:œ“‚ˆ58È2ð)È2ƒè@‚ð8ƒ½¦‚˜7 C€3ƒhb‡–Ph@«š‚˜%<‚—:˜‚Ú(`9^¯™cíòØq7šíæë)´Ùf·Ï'³ÙÀævÀ×íšÝ†Æv»î‡s¹¸äq4Û-ÙCåäø{°šm&³…Àðy½oW³íøüŽÆ¡o¨ÃQµ5lµ Æ„ |Õh§Uj¤zu<±Z/\®7SMÀâ„®Y¬¶[A³Ø_Š%Êá—J%ÓêµV¶]®Õ ªA4¡g´›WãéN¿^¥UKE‚áŽáp»Ü.·rµ|ЬE ¯·ëòÃjµ›-÷< \Èd¤Õ sê5$°]°+U‘é‹:£‡´r0ü•I4—“éõ÷¿‘ŠE{UÄçe·®G“É8^CiH%ájA“¤±6Y•†)°mç ´BÅ8]Øê;‹£Àø0Žƒ¸Ä;cQF d93èDƒyLÆÓš,ÇùÖ|yÄu‡™ð­HÞ|=èYª¦Ei‚8%AÖyŸhÊxž¥©˜mð>døàD’$‘BX„áNBQÊ{‡š48äÈæK§ª4qžGÉR_˜ÄYBV…ù:‘$ñL`™RJ9’–p&±ÒxE4Q„gæy¼@E‰HZ™Ä(Y‘E)tvJˆÚ}…‰´pœ§Áönç©0[˜é4Qãù2¤–3 Aø´/‡Âȶ0ØVh¶!‹"à‚.ŒA˜š'‡Pš‰BPr'ŠA˜%(Žˆ‚0`!ˆp†!Œ#àþ"Ùá(‚„‚Šˆ‚(`#ˆáP„ …B€"N¡@€„¡Èx‰"8‚+ŠáxŒ$P’BT 8rbv‡È>‡a¨š(ƒát‡Áø6†áhá˜dèÁŒ¡°>‡8€!…!è~ŠB Nè–½¯ìű¡èÉüH¨aÖ±(YÒw§yæyç9Àf›F±®pfùÈrÁò}Ÿg9Ôu½Òª ´Çyàz'éöe‘´o±*lkF¢_¦y¬pËÄ”¡æ¡Än–æY†T¥‰J\…¡šcÅdQ3ÅIb] fyºp†¡¶öŸ1©®T˜éTY—';ûXæqÀn‘DÑ2VwM™c^†)œe桨Yæ æ{žç)Üy¦)¬`FÎ΂çqê‰ìæùØ;‘¨Ü#`%qà!„è¡c8h‰án.D@œb K‰°ú#˜¦ÂÀ>Á„P‹CxB(Å€­Âø[ r.ˆ´ã4N‹nÄ ‡"ðZ"O  BôH~"TS Al3Eø}bI€Êƒ°\AÌ9ˆ!(EX¼ˆU±"u"KŠ)…bª$a±¼"0§eÑ´A¬:‡ˆï#‰x{ô∠Ó#ÄI ap/ÆxÚ ÂÐi â!0² ôDñŦ ÜFˆ:)ˆšƒ(F Qzp†¨ébŒ]ŒA(…`“bôc±É*ƨº£B ±P/ pÔƒ¼_ ñ¸*ÆÚHãøO ñ®A‡@ó#$oì@™ !äCŠñ¦5C¨š*€QQ%ƒPÁt8‡`„Bð^ ¡Ì)†PРZaL+¤ÁÀP àä%„°j—pG Ü%„À|B£àÅ‘Pž¥xÁl0VhÁ‚0)jl„&`°‹Á!‚°xÁ8<à˜µØB\ €¼"pj€.ƒÐx °;@ø€x Àè7A .TÂ&g |ƒ€DÐ`䃠nAÀ8àVÐt ‚B`ì‚Ö> -’ÂXTˆÚ=‰±VÃXÒÚa5¤ºÆ±Ì4¸Õcpm áÐ9‰` cв+ÌYÈa"ãh‘¸60þ_ŒQ”3œK¦#œu2˜òÐ?G»‘ä˜A <%ÅH§ƒ Ða´¯€†¢\E‰8! u ˉ°æ ÄHtbA 1*+EÀ½‚|UÑ"$ÅI¡· ö A´‚ àáEá$ ÖAxOLlááN!zár Ïx¡Ò\R w€“R BØH¡w‚¾¯ÂÁ>„ Aè!Ρaf£HC?S!RLBUG!rát ºÁ^á!¡.Áef ¾ @Î ÀŒ ຠ,âÀ´ nf Ž @¬@¢  p Ž šå`” `fàœ€š @j 6H¢@Š €ª€  €¸à`Œ à® `Ô @t @®ž Šü H_`^ Š@zaÀx rOgf,lRèÆŠ¦$€H€€1 È €6`lÀfªb ñh`’ ì¡"êö¸ f€f&rÚÜo €F@dffj wnàh7?²ožôèG‡ Oædä¨Hd5»&kÆÌÒE3úA´Á¸­uA¼cà5¡¦Á¬a˜¡lrSŽ Mž§ €Aj|Ãa–äA†â{ZsÄ¡Ä!ÊáÐalá†)ñÎ ¥asÂï›záä9˜6}a¶pù©zAv°*¡PJáa±9!ñwaÒÇr¡–PA=O2 †4R3è` Až¾ Þ,aV†aSuÛĪypFAxa"D¬,a$œl¡a.œ çÁkÜá,ÅKEÁ äØÈa&-áÌ$Aº6¡¦»,Qàði9ø`êàöXÆ!6@ê¡  è  ¾ ÀÜ @æ ÀÌ`îAá~(è†`óR î! @ô!°!Ä Áábá”!ç` ø´Æ0˜,™DÔ$sÒoÁGh¤€ÔA,!\á[ÏòŒ@ÚÁ@Òa !ƒXÓ>| ìÐáPÁX”0õL,°Õ¡R¡’Arâ"4MzûÔÁŠ"¡yÝ‚q‚xÔV öJAT|A á\„YÊ`Ê á  – €Ú^r  Ç ü :ƒÌ¡ À `ˆ `³c@®ñ ¢À nH  r šDfàŠ @˜€¤ …g v¨@h €  Á<3àd  –åÀ¨ZàºF²`˜ Ï îR nò©jàuªÏjn®šµn¯€rEnŽÄ­3$« l6– † `† àÎJnÀCn芩¯Àd bh€go@ljΞ¼à<@c/'´»(Ã[³BÌô“:%è,ó:%Aí³ÉI?!‚VáÌÚ³ÁÄÀܶ/â»»zK…ñÂ~¡–µj!ž¹A¹Á˜ár†üÁ†aš"Êöמ¿Ü¢ a¶hÂN6°¡²vÎ×»þ v<ÞM‡+‰@¶W'•J…JÑdäw9•‹eúõžÑH*•©µZ½®Üm¥•±µÊýªÖo+XŒ;=¨®\±§cÊåG¦Séâq$—T°˜ìÓÒ!zC¡M¨$ ñ‚=!Q:Ò‰;!PÈä²MX¾[’ %ÓˆŠP(ÑitÚqF¤="æÓñðÌy>$S©ƒê5l¤R-:.˜<¤’këlÌf-š G3¹è¹d3éÑɇG(”‹É)õ6 I5œÑ_4Ы&S: [ÉJY˜cÁM„ÑT]›G ™ÙÎnž‡é¢o…y†f#ø†…±Š_¦ñlg¦YÊs‘åéªþÅèiS—…!n_„ùT4dI OÅ‘’h„ÙX;’°¾<¨Ü9 #HÞ1’c6' Âøœ2‹Áè¨+㺠"xx' áÀ”%bH˜‰Bxv%‰B ´$‰"è° ¢xd#‰"“ d‡@N$‰0޼ ¢°x* ø¾5b °ˆBH0l„¡ h†¡¸KO„a°pˆDá0p…BŒ¡ØD†%J†°2‚ÉC„Aøˆ†áZ! †"¡¸`aˆ8àð^ƒaˆ\ax4 èb„ˆe^w¥ë{^÷Åó|ŸÈeù~Eçñæ{'¹îzgáòÇíõ‡aèmüzŸG¹ÌxfÙÌpšæù°i›¦©šk™†A¨ef)€yg¬o𦙴fEÙha™ég˜…éˆ\˜FI†X—%¡ð{A×™—˜åñvY˜éf^–úyrj›F±ˆhE¢FmFö~g‰ä^óúi›‡ºqFÑÆsFyê{›&ùÐmæùT]§ä^™%ñ NŹp^žg‰ì†'yàsj…qÈaÜ{fÙÐo—fY†S…y"P“y@N‰`Y…úhæÉ˜iå9pYD["ZšaNXxiþy'™ôŸe dYåÉvP•%êf›&ñJVä90N$i REJZGa F’ä¨ãö‘¤Ôfa™æùÆt¸a@DH†ÂGàû;ƒÄs±Ì7G Þ#q“ a–1F`¾pbø\ !t/@¿Ã4`3Ah+…À«%ºa=!v+ÅPµRr Ѥ1ÅøÏm#„uŽˆ~ˆ†ÄœtŒ1š2€¼ ]‹q€0†pÑëÔ[DQ¬8ÞÑj¿Ž¦Ê;[)ýauè|Œ±œ6GÛΣˆn‰‘L*`Ñh(ZŽQÚ<€Ü£´e ¡ª&‰ˆÑÃUõ ¡(Ø‹â`D‰‘(#„Ø—DJ á0Ö†`იb2 &ĨƒLBšqΧ¸®cð~Úö>kßµ!ƒdqaž5FaQ–p^“1p-ÅØ¶âôZ‹_¼+E¹1„dVÁ!h+Ø®¢ÈVŠ1dFa`«µœ_ ñ”0E¨¼~Ȇ`m†¸d3ÈeXiHt£|ËÝcã‘€fÀl±Øj‡ëãk Hjòú$‘»É=¸t™Xf†°g¸a…Ó„èN8T¾:¿—øL…hR„R„ÈM…2…xS„hO„éùRhwˆz„pO„C„˜F…T…JøK…X…0CˆF„(öŠ@P ]B¸H…0VŠ%‡PY`…C4Ðb†"ø¶ñ‡(îä…È`†IãøT…] P>„Aò„ØT²¾ˆhe†øn†Ðt‡8OhA„°KPWøx¸{éùP=ƒè^™ºÆ†ÀBÁÈd²=„HH„G„hS˜Xøä¸F„@f†ØoˆhFHVpBPHU†ðt‡Pd†àrˆh\€m†j†ÈZ)þ`x‘‚U‡Z.hðs‡8…j1Ò/‡ÐM…_øI ;„0E9%„(HÂ`1¨Au‡`2„G@ˆo†¼ŽØz©~ðt˜†‡(y‡¨<„¸Ti Hb {‡ãÛ—˜:ÈUFˆf„ØXÐ70JèIÈf†’¹… jØ`èoà\80ƒØEA„L„èI…S‚4ƒ‰+ƒ@)X5ƒ€A„0'3ƒh:ð‚p( ,ˆ“ #¸-9À&è($‚Ø0ø)Ч“¾¼c˜¸'‚°‚ $ª£Ø0©X È‚0k§€**8'B–‚ˆ*Ð. – ºÈ&8&@‚H")?§ø#zŒ@&p‚ˆ)p&iCKµj‚@p.P%‚¨ƒ2Ø&‚˜  €à˜ itÍè*ÜÞ P€ÈbŸ«âì‡ÓÝSݽ‰{…¾b¿½ÃJ‡Á„D py[ßsäˆh}¯½‡Äç˜{Ù‘‚rJ†xd†xa†Í…°`…¸]ðY…°^… W…VXY/L*…(WHT…ˆV(V…0O…`Q0X2³ó…=HZ…‚Ѥ6€eˆhq¬$°pÌxl$€UÀZÀn†àc†ÐlXi†¥˜™† ˆ@oXuàd†m†è†…``ÈHP„ˆM„²¨Q…¨XˆhX† Z„HXB„ HIúU0I„ÀLOèf8U0E„4‘pB„xC„`M};El1ÈRàC„ H°8Jp[…„|-Â冨—7CÛÝ |›(é²QX’KY K¸N…pYp‡ˆHI…8VÈЄéôhBØP5è@°k]…B"+Їh|ÀG„ðO„ƒ¸D„`9¸`M@W90R…8;V(>„xM8x ‰hy¸|Úè¶è}¸q`}˜X†‡šÁ†8o(c†Ã UÑ{†Ho@˜M(K„½c„ D°Nƒ¸Ep/p:RhPƒ\-Hb…k‘‚¿hq}(]Wi†Èv‡¨w½J‡±„•rƒØN…K…`Z¶ÈTƒ(@ˆL…XY„pT­æÛ'¨l‡mxy¨iÖ°@¶Ð:„ˆQƒz+e‡]†0mžˆ]Ø8ƒð+ƒh8‚Ð7ƒˆ2&h+S,€K‚,¼©ˆ˜%‚)Ë`"‚8*‚ø0‚h3ƒUc„‚H% ‚”øL…HX5ƒàû³ØPðÀ§øP#‚„ø'èê©è¨( øÈÈ@$‚h9ð!ËÜÏH%‚0€)X%X\ˆ ! ð("€,à* `€+àØ¨À ªÚ±—”ãh X€ú²ðÏiˆ½£ãN¤‹¾*ÁØyˆH´ëæ=‘„µXuyy+«Ý_]óÌ‹àx‡ wørk†Ia"™…¸Y¨V…`W…ET(RPxQA¡ÖhI„HI„øF„F<„@–PC„xLØV…™§†0eže†a!R@†L…´±ä«øxDEsáè‡ö‡B„ÐL„I©„H[¬èx‡Ð}×XxFØq„°ŒpB„*Ά˜‡‡|¡Š_pX…èf‘„h†8F„àSˆ^d…ÃDÐd¨m… \Ð<5˜@hIPO…He†èthbøv‡´€t2LØU†(fÀHz=¼Ôäèz¾0IP[ƒøI„¸>€Gƒ€?„5È=ƒ;À:BÜAƒaeðKx>6ÆI‡3FØ‘±‡¸|p_ÙË}‡¨uœï>0w£b†€sƒpDÐA SÀU˜QØahp‡9Ìhg¤{p¦œ˜‚‡ðBÒPT…økXV†\ê1‡øJ ^‚Ë@Ø9¸, “Š+ 9‚81ƒ#‚Ø+‚(,°%Ø.€"X/ƒ€7‚¨5ƒqûH‚`&zv †á`[Xø ‚)‚Øà!@íÈJ„‚ : \ðí )^Ñm Æ•˜Ò³¢²–øº)_ Ø:à;°Fνø,‚ÐKZŸ²Àð#¸`«Mø€è*ÐoEðP€üÞßùˆˆkã‡É„r¿_öXήý½Ø|‡É‰‡Ý—ц=Þ¾:Á‡Þû/áN ~‡•ŽON±ï‘‡Ïv‡Ï‰™@` d…Ø_™óí³ôá&¤¿QHôAÁ¸P…+k…`P…TøO…;…HOŸ8PxZ…tFÚñïÑ{©»¸rPtid†h†g†0Y™®#”'Jé‡g(g‡X„á¨tˆkÙ‡CU‘›†Hg¼'@pøp¾ˆhhvyHc(a"ºF@bÁqŒ8CƒÐAƒð¦„h?+†@BIàN„HJ„hó8C„hCDHQ…@œ@d¯œ°z …j2®nàhs‰€€õ0rXxs@xOVƒÐE„xX† 5ˆe‡ÀtŽàh†Øp2(EˆlH…{.H?ˆI…Þ+ö z˜§†H[† f«ÚÁÎ!ÈsB0†„HN…;[Å^1 ÞSÿrõ*Áµnl†ÐL…¢ÐbÀn‰„_;ׄë0RØ@8;PHƒ€@ 2ƒ¼O„XFˆÕ’ƒ€D`w˜@=U€O…È\†ŠVdïhns½‡¸D¢¸M¸^À_ˆp„ÐW†Nö ‡0b†àp¾`_¤}‡^—ÐyÔ€YšÄ#äé2€<„˜Tƒ0Õ#Ð;‚¸7x'ƒ@2‚X3‚òjÀ"ñ;/¼Ñ<¸'ƒ1È)pLúu‚hè0Cø;ˆJð+Ø'3ø(ø10Ð܈‚0!` ðø¸Æí(î@•€h‚"8îàíéZà©xçÀȪˆ*€ [Р€Ø MëË== PØvðh =0b®€€€?àP8$ „@߯×ãùþýC ¯è¤%ðúz¾Ÿoh[æ(ü„È`¯ÇëíÚïs=^Ï»áé‘LfP—[ÉÖÙp5m3–Áb2kÆ åbºY«*ÅÚùl¬¤©UªTú¡:¢S&SêdÂqF–M¨“iå*mCTM(ÓU… éŠÀ˜±-c¹åi¸[ËúáP¶Y.—«v+1„Ãe±®÷[éþøQ-ªå¢ñìù~7Ý®©‹¥Þîi7[ uB“¶o8[-Öûiºâk2™lÇ;µÄ˜Q¥Ñ)d±ùƒ>! „êU‹?ž¨j]wE"S äŠE<–K¦“‹µë¸æn3šíg ÊÏkµ[ ÷¥ØêS­VXF½rºq<.ðUëQ¸rÇ¢ rž¡,R”¤‘8KQgG=«§‘ð}”åù€KäÐæBf Žf–&„cÆÙø†š‡ΘFÉÄfÇ2 Ìû¬EEöJǺHš9à¡ÇñÄvž…™ŽkfáÒo‰ºvišC…‰NÙHŽÄ);¤i8U£IAŽ$!J”ÅðJEit`$©4fQyþ$ù<\ÄIPU•Eù‰ %$LhZ Efªq™žm d9LVEá~tÂè1ñ! R ‚œg¡ò„•¦9´6M3q0cȬ6B€Ö2ˆbà´ ‹bЕdˆB¸ªŠ`‚. ¤'…â8Šˆâ8d"ˆ!ˆ† †ÂX' Z! a@Š£Ð†¡ÀR a@€ðt‡áàN!8„øp‡¡ÈF‡`’$" †ˆB@Á0~„‡âDÀð`á`aD†àøjƒ¡¦R¡peA€:á(T„h\ù`VƒÚ>Tƒ¡xb †x]«…„´™Õè"(˜!(¢~1Ȫ#³!ˆû³kéèzÇÁòzîŽô˜ž'±æp&á¤m™†Jxa™%Ùr`…¡~Z–¹`YÅ·\•ÅÙbP•EFT“ŠÙ2P”äºÆKE!6N$Ù0Q„ÏTL”áPV•FùÈq ÇqâwÐgéî†Ç©äR—…±DW¬³©8Qæ–`Dñ6M”e2S„±HQ“…iZ]™&1P[•ß R`¦I¬q›å¹ˆcÇÒ}¢‡yà}%étíÆÃ[Œn6FØÝãà{‰AH'Å€³ÃaŒ¡b-EØ}ø=@øCðy‚<‡‘„`–¢,Jˆ—(- p×c”k‡€7G8ãBÔ\¡ì>ȪÃMŠ¡`'ÅX´ƒdpŒ‘®6ÈĬsŽâ >ÈZ…£ aŠR*C˜ƒ\t¡\1»1"HUŠðÞ‚Ê áš5FkAüU‹Áx%Pµ cÅ»5$4Øí!'äzŠb/8³"8PŠáÖÜÆ ê?mï  è{IöÔ’ £(LŠ‘\$E@¼£,j†`ö…;• aøD¡"ðˆ!ÌE Š4F°ˆµ;ІjÈ¥ãaW‹¡š3Ãè˜áøH‰Ñ*ŰÝc½WŽ‘à>EPÄ¡ìP â"ÅxµB¨W‹q¨6ŒrH$,w‚"A’L¢ Ñza &àŒ!|>Юƒ˜Q ”%†0Äè[ !€/„0¾ÁàU K@&ƒÀšˆA€à$„ÐdH3 a,€Š B H´ä …0´ ÂDàÜPpA 5€°ƒð\Ù; ¤PH³`„@HÀ%ÀÕz:¾ÁXCÀ¬  ^ÂP(c „ƒPLÏó:À̰0sN=T¥a4(‚0lmA '‚@R Á,€e§°X Àè0 rÍ4\Áp-´° ‚à\ÞÉ mêA¨1ýjÈ•¯$¤µ ‘æBÈ%£Í» &âØÛ°õ$DÁ±Ú‹ŒAÇ`òGüiGqŽ0Æ@¾cZ‹ax,¤¯ºÂÔZ‹ñdž…t^, K•¡.¨ÄàžóhS‰GFqУbdN q4VÄè©‚”aŒÁ|aàË÷4nd/۰àa „*Eˆ«ÂŒO ÑF(/¸›v‚xL ²*Ý¡‚™Ü Á„0E(®OFcŒq¨.ø»ce‘à=Gˆ Qg˜tŒÁ¬4…«ÉCˆmŠ!d+Ř·ÄN ñ:"Äx‹BœL‡@þ„‰AØA îè€â^ŒAr!°Žâ„IìÒ+¸Cä}áì>‡¡-q•(Qþ7GHåƒ@iŽqâ;ôoñ4Æx‘ây1àÜ „„ZHV á#huB(æ R?Cð“B¸Z‹qh/†òcÔÍáÐP°øÇþQê>Çá¢ÍÄ 1F+…àΓäzl >­}ÅmÒœv™y.>†€ã3‰ ˜ !°8„8âDYŒb-qpk¢:ˆQ0‰âtO‡Á$%áÞ0&´q´´ÃxŠq€0CùÙ¢@KˆñN- òäUŒ²Äp›âVJŒ‘“X¸8L ñœ<ÑYµ{rN ö'…¨ÂÃ|= 1BC°{Wá°* Ôƒ_á|.„`¶8^ Àø*…@p‚86á $¸¸TaH*`¤ˆN `Ü+…Àz‚È0•¸ƒÐTêôਃº¨P8¬Z˜ @;à” Dø#«‚À”‚×ÁL(ƒ¾Á˜V  "ƒðNAÀ#üƒð† HN!T.…pò øˆ`Ä"„ªB€e (`@ vŠÓƈX1@¤Û$íi@t«ŽLÈ ú$ˆ_`ìîJö›|1è>pï#ˆwÈF¿+`!cÜ|!ìK³¡+c yaâ!è¡ôN&úð ?AØ~¡®Da†¡†–A†nlŽièáHèŽRá>!<LEFLR¡F+aÁLA:Á(aJ›¡B>ÂLá<!^áJNÅ!JˆÁXƒÜ!¡îA†aFAJsáB!PÁ.§FÁPƒ0¢ž â¡Ö%AòÁž¡´£aæaZáÈp¹áØ!àáÄ"|"a®æa”"aÞa*A:aX¡N-2Á A*A2ŽA(0@O>a8a.0A'aÊ¡Øå¢ IaÖajÂ!tr¡ˆA0Ó¡Þð á¾!ÚB®á<Ïd`ú!ž¡j¡0á¡$fÁ„^áÚ¡ðH!¢âpÁ /A$Pü¡ø!n"Ñ” aLá”äNPÜÿòaÞ¸M|‹´!b¦ìI"ÇŠâ4 aÔðÉâH‚ÈÊ aàð /bÀ!ž‹äA6ÁƤ²!²!ä«Ô¤áa&Á"@æLa¼2b È·€Ü< aa„¡¨Zèâ êÁBïì iúˆŸ!þR Aì!²º i@!^ašÖ¡„Á: àúÀ¶`Ü `Ö €ˆ à¸`  ˆ @ÄÀ¶ àxëà~  ® @È @Š à¼@ª À† `¬ fà¶ €r `¤@ˆŠØL |À‚`X¨*v%îÀT Š`šÀ^€Š@ SDÀR@„à€àX –ਠ@V …¼ ° ¶ ÀX €ŠàŒ R\μ `\ì@† €ì¡LÓÁ8 d à®ì ° Ò ¶!ÀŒ `H³FT 8€b€TÀ*«HàR Zà0@S@ Oϰ"‡ðP‚>”¡ÞìOÔOÔ‚NœAØaÚÁÀnh¬$FÞ´1¢\ÚAÿ(AÔ!ÔiNlTjlT ! î!”A€A’ÄÁŒ»¡‚a`VÕƒJGžá6¡H@¡AJr¬(ÜA(!2aaÁ0Ð`$ðA$N2&á@{ÁLã(áCN!¨aš!öáÛDmnáUAr¡vÕCHARÏ!îä!bá^”ö ûñÁÐ e¡^cáR!´!"@ñÌ!+’!R`á öÁM!¡ ô`ö! JáPáá•t8Aaa¡>AZJ¡+'\ìî$”nñjÄôlÖT³!^6`6§€!ØÏ!4)ea!,¡6A¡"*la¾Àîáb< alÁ‚Á.6á ½!r|á( d.”þС”Ø a‚‘$áRJ!r!° Ñ‹ ¬ö a€ÁcV>n-ú!FÖæuAdH‡þaX!„èAh0¡˜a΀¡š®"퀛ánáp`þA:a  øá*к‰ÎUÚ€ùàãZ€â6 =àæá´K’$¡²AÚáÅRâ ­€AèÂÛb™áÒJjœÈ"¡Æ î îª à `Æ£¶ຠx à´¦ €’ €Ø¸ .Î  †  ”€j àŠÓ²à†W5RÀrÀœ Àf @ª@  ÀV ¢@¦ à` àž@š àX `˜îÄ“FÅö‚ L€vsR¦7€z¥´àˆàX€‚ ~ utà¤@ú (L àäó”  –^@®„Å$€f€’&t+$ P@8R@F .V SƒFŽ V@2OAo­G&ô!Å^ÂZà2^ÀÜ0"Áð%Að fà«m(AÒ!äífRÂÁÔÐÔøˆ/èÏÚBIcÐ ‹8ÄÔö¶ÁÆáªaÂDNÁ!f+´AN}4êðB¡=\Dz^!2Cª @¡UëA !44ÐÍ4î; |áh,ôªÁ8¡ŒÜÆÉaêÎ a’Á£HÈQì"v¤ K’v<Á¼R¢®!¸Š¡È¶šá·Áøa~'Ha~6aÖÂ_!aê¶T!"bÎa!!(á,¡ÍMbã–áAõ–aQaCae!Fƒá|!¶ÁÌÁæï´”üÆAd¡|!V¡E õÏ¡¡vaXAœo¯ã(ÒAÊÁ|á–Ò!T!\A!‚Á˜‡Hˆú˜CÖ!ÀAÌu!J U¨á$ADŠi>A—lávbå ¡>A ÁH­TŒ|VAôÐ𡬂!ÞA’ƒDvjká†ÁÈ¡D‰uH|6Q¨Š2pçOBqºš¢ ‰ÁènáˆA¬a\Á8Õ*Èè!f á¡„áÆ Á áj þ@îaaàÆúac¤áŠ0q»!çeè‚A¦avÔ!òèî a¸@ Þ!@ Á¡!>¡& ú¡,!€ˆ ÎÀ Œ ¬ಠ7X à| ¾`® àn €–Œ h À€žàZ v Vd@X@m}`z ž À` ž ª ÀZ  4@‚¨Àn@|\ óB ‹8 ~WüñF ¬ nóàr`ŒÈ N\`F\.¦`jì ’ @Þ² 6àˆa>J!v ” à4 d†xà^jVk( 7@@=„@>ù” O¡„`Xx\ Z8aÆÌnaÌÖDl Bcô¡Ò!®AÖ”FÇô!曂!é(E*Àþ¤5,áÎA¬AÈaÞáÎ%¡â$áÊnaㆼaàa²<ºX{H€ÀÁNg6*¡8*á3º`¡2-,4á-K6(AA@¹Y!:ÍTö¿¥a6ÔÈ!D*‡>r­Ö¡JaåDáþnu( ¡f!qGá@ݱ¡”VA,+!_8@Ævp(át¹P!ä%f ¯ídž‚¡œ'À¡œº!ìáKaZu;T–’aªaÌË¡uÙÌ´AAUúFA Zi áHAœFç£!È).ÁíBáí!ØÒª¡ž!C*1*Áz,&!ŠÁª÷$A”fA~Ûª]Œ£B a"aLÕá~ºA͇Hr¡A*ÝŒÝc»T¸ÁbA´A^AŽ}úàò¾²ZÁ aP!‚bcAÖ¡Va^Ž„  ad!¤×¦¾µÚJ0îA¢¿=FAa>0¨¡Ä"¡¶àìA*á`8dA¤áBa¨ iÌá½CÁmòCþÁEÜ1‹+Â$Œ  ü Ðƒ@×$€¼€ô =œs!“ÁJ ì²G!t–RŽφüÊa6|!"L9á z¤¡:´ÁĆaÔ ¶Û´Æn>KE±á\¬=)– ų ¨V‘Èc"1\C Šˆшüz+IHƒá¹ Š/ %ÑYr2%†Qø¤†>GbaÐÔJ<ŠHyÜND$ Ñi„%"UH$A!Œ&"’dÒH˜–Eˆ¢aˆf2KfAi8¤±e3‰5@ÐmJAñ ÐH4ÂððÀbŒÃ¢¡phX. C"YDV9‡…è¼bÄ¿õV¯Y­×kõ×ëáèös»íÇ;©¦çt4\®V“¥ÒÖuºÛN‡C]Þîqê^ï§³¥Öß{½Þz‡öÉøø|=»G£ÃRû~=ÝNÆûûÙ°÷j^Ï—£¡Øárº[-÷YÎëoF1f]˜%‰n]dQeA.Q”Ĺ:P’¤ñDI“$ñI“Y*M‘$y,DÄ™E1$DÄ1&G¤Á EÑ‘Dd¡J“±y(G’¤Ñ"T•¥A‚eGÒrµ‡KÆ_f ZYeIpT$é&R–1DVùJO”eyHK”¥!4R”DÉ@O&i˜×ŸkP~½ŽÙüÔšFÙºK>Q9A¤1f[–g!Útµ…áŠd$‘C‘äa4Q¡æ}5&©ºo”e‘Zn‡#Rr‡Lï==íAŒk›$á\[šÉÈ}Öù0V–‡Îwžçáôxgµl_„ÁBÔ›-ðþG“†‰¸l—Æyžeæ©na¤‘BU–eÑ‚GEYŠi&Á¼sæ¹®dšF•|VtG’$ñXWYjÔž‡ÙôQ…Á T†ºq5%œâ{Ÿçózs=Õ{TZfÉÀuf¡Ær·iœoœcñ.TW'6Hk™§ÄFËÃñ(L”¥Ér[®åQiµæyÄrçº\faT`%Ae§¹êÔ‘%9j;‘¨Æ=ƒ ôA‘%W]Ÿçeˆ.$ôF‘ãtLR—eÑ$X¤ABO•¦~;ÄÔADÄùH.¤ÚB‘ü?¥±m©çÚz5%”iÑ‹ø€- ÐÞ: c8È¢b#!¨$…aèzÁàfˆ!Xˆ!‡bž‰B@kÕ…aøxõɰ†ˆ¢\”„}ØL‡H~,áàV#‰!¨®.â0­ 8†³ˆ@ø‚ âP„¥(‚†"HŠ ¢àF" "Àð?Q"Ðy!YÿÊ@Ø5@Œ < Á°" Ì ð`0* Äàd ‚`_ `Ä „p, h@¨‚pP AÈ:WÖÃØ>ǰ÷cÀx ÑÚ;ÀðÌ<ÑÚ;Æøß#8taªGɬCHh a¸6ƲìÑXpŽƒïO{x+¸ò+Áˆ¬ÆÊã”x¬3d¨åã0g ¸›‚Ô[‹!Œ3M¸ó¤vš‘|4ᩃpt‘Ô<Çx½#LM áp'…H©"D‡¡$C¤ÿ¢ô]ŽÜ:…HÀðI Áp2†¡©©Ã¼B áL!äÜ¢ÄTŒ!ˆ.ÆÓcXmCƒP2àâ# cØÑ–jkа‘;‰ž,Ũ¹#@X ±¬.Æ Öì,hÎ=Çé­µcüS×&¿…Ç¡ Aàö%•"qˆ‘4(C€a¬Bˆáh0†5ÀH‰ÐCÐkTK‰@à"„@d¡è4°î„(‚b0H Qb.x†!\50²C Œ¶¼eŒñX1F ³ƒ PŒ†!©Ø`Ø'…àÆƒ Œ pÂB áP„0~ ÁÐ9!¼ Œ Â&  „r>Aø+ Á0О B`Ia("º  Áé0€à z à4!pv$ÈP5é‚0h 6`”Gb BpP!D-Т`P¡¬7ƒ ˜Óœ ˜5ÐnA;|g j @è+@lÑ'…(8A<c·œ€Ø)€|ÐÀX @è-PÆM1 gìÈnŽ¡Ô50÷FØrŽqž9Òˆ‰-:é“TlþcÈyÍ`jÇÐü¨ƒˆg á¦0F8Éð`MAx”…ȧ½Ša:„„œŽ"|P $Ç>…‰â†M $Ä "LFÉq (EOâ@B¡ D0zB@# þ „@‚Â0DA¥ÑÍo‚\OVñC´Äô‘Ân\ d¤+FPËä\ жD šâgkñ1@%˜“¢TU ÑG"À¦‚¦› }^j§©Úb†¤[ a€–…Xöq #DX‘tUŠA¾:ùŒÃXnŽq,(ÅhÍÃ2•‹á÷Ìc(üƒg «AbîrÃDzæ<°ô£^¹šŠ€1†Hؽ=1‘•bÅnƒd‹:ØkÈ«â}ˆa2&„°¤"¸a³ó\4Ç0ë54¤l]NLJ@‰"¨e±Ì°Ç¸wmaØC€ò"Pq•!ÆêˆA*$Ä@˜ðbì^Á¶;kba€ˆáB(—8¥òàož›ZÔêÀ©ØQy³%jÈŒŒÔKŠ»D±èβ£Øö ñt/ÇN¥ötvS_ÒG`—«¼D ¡h1û0ü5B5q$‚àq‚Œ[xL…PX\…ˆ<¡Ðƒˆ-ƒ:Ð8p/Œˆ7È7P,ƒ€7ƒÀFSÒxA„ÀOx2x-ƒ˜<V`G14,Ø=¥x4è@ƒÛ¡xA„ ‚ƒˆ#‚è/¸&h0#Ð*‚p$‚Ø+» p"‚ ‚8!¡àpð™èÀ‹ x$ €)`¶ @! à C ;#2¨°øÊÀÈ+ŒXˆÈÏ0YýP‚˜+à(ˆ°‡X!ˆÀ-ð„Û± $@¨ â °/hbPh, ¸@À€3ظ‹Eh 4‹\Æ+™5 z‡°tpwÈâqXw‡ho y*9^z`ö>HÖ5Ø|ŽñLJøq@jHq¨{¢”m¢Ð~è} t†¨i¨b†d…¸`"ô…ØU…€Z1!„èR9f… I„°Mi,€V…€N…hY¸èR„QºL„;ƒˆG„ØH™°J¨O„`?„@>BƒÑÃøL„àD„8D7E„ @„HC B¥pG;ê3‚–˜PxP¹ˆV†@døy8Ö'‘‰¿ b€d· GÀM°]`F„ªç„èM†èm‡ †9x…€^…èZ ^¨P6ðN„ó€PD„sr„ÐNà`…Ñ„Èn†óÊ Xgài”8D+ÀO e†8|‡ð}:Hoxm8FèJðc@Ô…`^°Q…ˆU‡+Pøg†ˆh†Øqèr‡h[†I9sO‡è‡èd†¨l†àq†ÐJ0T²v…Ðe†HBÈPDLàQª¸\¨‹ú Xu‡¨| qbx‡º$‡°u€x…pbr.>H{‡È~—TƒB 8ƒð@¨?ƒð;â°J¸C0TÐYÀq†ØzÐ} f,8Ô`Q0=q°KƒðLøK ]€W…˜IGù!n‡Z*ºÊœÐ:pLpN6ðU™OP{0W0i„xRpfðr†¡T€|:Êæ C‰ txzª£ºX7ˆPðF„€;„FƒˆE„˜o‡ v@g†È-ƒp:0<ø0˜;´ ‚È3ƒ@*82‚@1ƒ%ø2tƒ C„(4ƒÐ>‚X1ÀÐ?øP…€U„(L¨8¥3÷I‚x1ƒ"À,‚¸70¸Ø‚p*+‚˜$‚ð+ø-‚È‚&Ð(‚ˆ›8X$ $‚8‚  À$‹—ÕH"18Й߂P* ˜ ` 2  HÎÀõ[¸¥ð’“‚h2è È* %Ø.‚(,‚ð(2H‚‚àˆ¨‡ ÀƒXA„P,7,–!ÖƒØ"‰˜#  ‚(h€øÅØp ¡hx ˆF3\“Ôw‡ôï‡Àv‡˜yï`|‡À} o‡0h€w˜¸Õ§x|‡0r†¬nÇSR‡È{¼˜p w†èp@à†€u‡Qv†øe"Xhˆy*z‡HwàlÙIP\ax\…ÐU [9`XRj\8èN™šc+ì‚…hJ¦xC„°N„XK„øD„hN}FCR(C(EB7Ø?„ ?ÐOzLCB˜%# „@F„ r7L„kŽ„€_øYšp^‡pYØ=r£ðQ„ØPÜØK„“¡Û K„Àh£Èý p^M`ÖtkÐo†ìí†(_dÐn‡bÇ fi“ë;X\ð]¶g“Ð}ª(áøn3 ‘ G M„ø\†_I sÈb‹Ð†¨qÐI…8SÈp‡Hu ¬ïÎXÑØx˜o |G‚† pbk;oˆ{ÀN`[„H„¨D_58L…^zÕ˜ËT‡`eÝ-ª€ë›hFƒÐ@„ Â:ø?ƒx?„8Ø>qÅBÎ ?ˆaHB…SàU`>„`G/XD„ „„ ·„M…<„˜NH^éW„ø_†E„ðRi…4¬˜qXÕhvM€I…P[ikxexÔ‡v”øévÏÝÿFðƒklþ „Jg‚À>€x? z? 9„PG„$…àS…(,X5x3H)0h‚è0ƒË~ƒX>ƒè9„?‚˜3ƒh&‚ø5„Ãfx3ƒp)ƒp4Ó 1À+ÀÈCUð¨)à*¨'h°-8-‚À!°(¸*‚‚x$À& ‚h#' `"h%‚9íèh!0"ø¨B˜'‚X‚h' !‚4I”ùU0ƒX%‚¨+XØCØC¨Ð{#EUB'À(€Ñê` žÎ‹à&pžð0» ô4‚!p#PiXG…(Uƒ @P(?àX(f¨c†€YødÒ@KBð%0À€€âX˜à ¨ÅØÍ4Àö‡ìw‡Â*†ê4‡ x‡pnŽ€}`m†óËlÂå–,Ňèq͸ԇsXmàaͨb¨k†h^‡o¼€zv²Ð|Í€ô ‘±RŽ­H{œ˜Ôxx‡ s8if†¸k([àU…±+pXœTÐXP,ÁXTiëòH”ÈP$Œ’ÁJ„«Ó„p@¤L¦ˆGÉãÓ„XC%xB¶˜G„BÜ:U\€>·à@„T‘CI‚‘+w¤àH1AÈrã>`xès Â)HZ…ðV½°^¥ØU„•Ù™¸Ro(\e…ðaL¸×‡ {‡±Ë¸sQØÔãXu—m䇘v(s1;‡¾½º‰‡ø<pB¹8W†0g0?ÜxIØO o¨]cK®~†Ñ¢J„;¦þ¡¨Y/¸[†0bÞ? Pv‡¬u"àÔ”õÿ}¸W…PX…ˆJH(TôÌ ]ŽŽ‚. ìløZ@d‡ÜÀ~Øvq°=¤F0:á„&™ø7Ø@x<ƒÀƒà5ƒà>ðF`^hbƒ¨EP@„ÐL°a†9Ûø8„ CW´ó77âê%Vøa„PK0dˆX…è`¸GÐc°lxo?8Zj>˜øu‡m‡à_,YpjZ4ëˆw¨huxW¨V¬ØU…À]‚6ƒÀtžÈþì êèOPR1ƒ0*03‚Å1ø1X¸°.€9‚x/ƒ.@4‚(-ƒMXU×84‚p4(3ƒ¨8ð-È!ˆH‚¸)ø+¸x&˜"°ðŠÂ& °"ˆ% ‚IÖx(‚` #è‚P%åX/x€#ø0!°&‚G‹8‚p(èÀ!ƒÈGp.¸>˜?„8$‚ .‚@-‚ð‚$Š( Ö“ð*Ð,@5‚ +ØBàØ3˜±ø!H ‚Öàè úP'¸1¨)È, =«7 v‡€kθh‡0v„ÉRUH)h‚3$h€øh M‰Eè Xðfª´Ë®ª.dHó‡hv†ÃPµ˜ñ>†Ë…øl†À_Èk†ª…ôÖºÁ…øj†Âª]†¸m…ðl°`8q†iGØqµ@k†`ÙogKÉâï¡ÖÞï·“Éêò­åkMVûY8°Y(K̳ý¶êxVnG%mÜø|+VËD™LO)TLMmý»¬2Ûî7;Åèæz¾UëöbÕ†ÇZ²Ç>‘æö7 ‘Hdr8â‚CTI2~D¤¨ÄA²a;ŸhÄq¹ ‡¹&²ój g<žÌðî3ã°¾<et]”锬‡ñþ.aÔzƒù2O—f¡¨­Ÿ©‘Ú}‡!Öz—&i´¬¦!”Ee!ÔwÇÌ {Ÿ‡â°X†i\\—e©Šc ãé5D’°>“DèÀ7‚¨Ö7ˆ¢ðÀ*Œ£®5B`º/$‘$Œ£h~*‹¢ Â2‡Â°²$ ƒŒ.Œ"Èâ7 /èn) áȨ(b ¨$ B°n& ˜~ BXšŠâ¨j'‰hˆ!†„‰0`&ˆ!€ ¢À®>‘DP†+‹À *S¢Xj& ˆ†„¡ÈzˆÂ0l'‰AXŒ´0øE¢°Ü9‹£ê) C(V"‰A8t†B8Œ ³èÐ5Õ"È>‡@àfAÐt ‚°Š) `ør…¡ðˆ‡Ȇ/ŒB´¢Þ—˜ˆ‚HX#ˆ¡¸ +Šé Z³æª1dP¾6á@v!…AÈ€…á®0„ˆj …!<…¡`  €?àP8$ „B`oçóö ìx6Φ«‘ÌÊlµ˜-æã ÀÝa´Z+¶“ItÇd­,•³=š¹h³×N&ã-æòs¸œMs¥¦ðv7Îç­ÎÏy½Vó!’ËZ·,Vý5êóo¶[¬–“a†¿a¬¡¯Gs½¸Úk0¬b•PœR)Ó©å a,™H§ÔIt²q¦T¦’éôjE.ƒG¤ˆ”yù‹>ŸÐ§³òø£PÝÓ¨ôâq,‹H£‘ !ƒE"ÑHôš%„@ ÈÙüö„EÑz}ý*—F©ÕIæ³M©<žo –Ãw;0g3¡Äý~¿¬…Úe:“P)Š%:™àïy LæËU¸ãu@Úm¶r-.ŽF¤Ñë•úÆÖXeA0M“Ì9D”…AN=#ðî=é@$Á>ä)V]ÇÙöx›')°Vå‘$P’æéÌp‡Âl†ùê}Π&qŠQ•åyTZ…l] Æ1®i›‡AÖff‰~h¡ô} ef]”%iZBäËìP¦y¦žG¼jgIÔL–…áÜ~ ‡¤Ìvžgš d8O¥F8$0ðDÄ9BY d9HY„1"4„Æ=8ô>i{Ÿ‡¨îG’ØÖ7 ãhØ.c`À:á Ä…J ^&¹Mƒá&LŽdAa†‘ç®YÎzžèÒzž¨œq#‰HE1D_Hç)î} f°p ¹QExòE‘Ãè>‘E6<’dÂ:ÂðÜ8‰ãÌ,Œã ¾7 âíL8£à˜,Œðœ(ˆBx ‰Â€x'Š"(°.ˆ"°‰0h%ˆÁÈ’$Â0†! ¢˜j$ˆ¡ † †"(‚ â°r'‰Ap~ …aÀvfA`Œ#†"Fˆ&ˆcÁ BãÎ3ŽãØŠ. áxˆbzaàn) °–#…â@|Àt( Á¨š(â œ' C(O“„áð~ HN# !ºçÁ0vƒ¡°v' £ Î<cÑJbh¦Šc8&…BŒ! Ã(†*‹a˜Š%8–ˆ¢8ª2 ¨—ˆ#Ùšpœãù8S—Æi¨=„xt+Œ ”)fâ \ ð^þxPˆaЖ&=^ϵíŸò™ä²šçIÐgœçAœk›&ªj&© ]™†Qjm¿Q¨^›©y÷&I”,† Óƒ|pGÊ4ÇxêÄ 8!Ê9ƈÎâØ^Œ!X/FªbðUŒAŠ,F@È‚üa ár/EH¶"Z ‘P+E˜žC$[‹È2(…0˜HœW‹!D'…(”"˜I‰¡D"ˈâ”F‹…Ê5ƸËÂ\Ð !$ „â(> qH&D˜—B] DS%D(Š¢Aˆ±$Ĩ‡ÜM‰¡ÄH†áðEÐþ#ŒPgæ1 “ˆMF@̤ w!Ö8GâcÝd„Î?Dz#ŒAÈ*Eˆ¬âŒO“u’røþCð~¡Þ;FpÕCxpŽ‘æ>G ÁâìK‰Á2äÄš¢PMÑ]Äð¦¢4Já¾7ÆÂYBDððƒ tAØ7‡îÃüØáüO q@D(}bˆLˆ¡,¡gh˜BPD‰á&IÅдÃT‹1^*, b@¹Žáè=ˆÛÄd 1´+Æ»b˜P14&…ÈË$£ˆpŒQ’3èʃ¤wQD,Eð‡¢”Š‘‚0ø·"\VŠñ2,…áéLŽÁè#(‡"DK$  D‡±1(ð¹¢hD 1H%#H}"XH‹`(ƒð€6¢<ˆ¡!x­â|O ‘Ä7Éøøô²1ø‡ˆä£¨pAÄA…e©‚ð_½‘æ³Ä£DP a>0øÄ ¢Q ¡Z/ hbL Á #„àŒÂ4A (¨C°rAÌ7‡0öˆx"|P ¤ú(œuBA(Aĉ‚A )Ep°ƒÐsŠan+D€›Œ‚ˆM‹„0‡ ù²Ìjƒ²+Æ@ÂD–Š)¡èÄ&"¤]Œ"=Çêx AË{ Μ"Hµ#T!Á.*Å]J„oŽÁÚ@Çx÷â(Q @ü#ÄŽ‚US†Å"(Eßb _dzŒa¶7zÈÙ‚¤Z ø´ÃsÁ…T…àØ @²  Ê €Ð ® €Ö Ä àö@® àÜA¶ ú3AÐA2¡Á‰a¾¡Ú!p¡:¡v ÉV¢Haö!¤ÄA(A!ˆ¡”  øz à«Á"R`îÿÀÞ  êàМ ð! Ä Öä gB @Ø æ @Úà” ¾ ¶ À¤ Äm`  ¢ @‚  ¼¦ Àj ªà¦c`’ `n À˜À„`Lpl jkL `f»@b€l€nZŒf €–t€œf z ¢  Ì Àx ¬â€{ tëì àÈ Æ„€T €@† v¼fb ¦ +² @N€p ¢ Àö50œ F2 L*Ž `¾Hjá |  ®kࢠ€b `– ´`~ gÀp €ÂÀ €Ì € Æ_ Îà˜  D€„ ÀÚ º¡Š®Ë$a4¦ eè.a€ààC¬ @Ê ‚L@Bàj@|Í/#â!¡üøúað!Öæ!ò)<AŠaîúâ;ðáäGèÁÚ‚ì¡è aªahAáˆá`¨,¡›"aÜ®¦A¢NªAò‚„Ä!d:mÊ¡NÁF¡$-Á*TÁP¦a6a‰c8áá0ÉÜaŽC Ð:Xa@³abáHCXáTÁ:7@úÁæ!J¶ãpá JÆ€ìÁ4E| ® ¡! aÞÁ&¡¡7AìÇ&A0A(œ¡32áÄb!´AÞÔ‚8!!lá‚aø! c–§aæA´€!†8Hp!Z Áž“0af aláFÏ!!&a!¡T™a* ì ìÀþ Ý ÚAh¡\á°Š<á:EúáAáJ¡@áº!¢òAB¡ZÁœÁžARðcvð¡ ¡6á@ᔪáŽa¢¡–p!žSœ!Ža–€Ì2@ìAÀaÌ t€á<Òu(A¡ÒáÖ"ºAª>©AA¸j¡r @â‰m(/†<ža¯)Šá|a$!8Å|a Æ`è @øArAz ‹Œ Ü @¿@@  ÀÒÂî”…  `ê5a!^ Á*v¡¬B áÜaÜÉ.!xÁ°!¼AF™$€Dô!< àÚì ­ Ê€æ£B `Ü ê "W!^èpÀ÷Z Ìï@¢ €´ª €æš€‚¼€ À°@ªÊ ž €‚e,² Àfà†¬l g`–,º#vPþf)àt `Î  € ¦cà–€ˆkä Q‡– R`t 0À@p@t €˜€ŠÀ{\ ÂAáá4:r Š¡8@ÂI²6 – v Ì"AÚ¡~`@ „çM(`´ÃËžÀš 1š ‘| `ÂVÁСä `¼ µÈ H œ Àäz ¾ à€à¡6“ ÀÚja¬²AþÁŠa ¡2¬Àx 8s# p@pòArb !¡þìáÈaÖÔAÊ!º€Öbª¡˜!ìâ+aþÓì!úAÚ[ôŒn¨¡ˆARH2á‡TbL¡à!¤AÊ¡®©áègÊAdá:AVáaPÝÁLLÁ@¡ 0¡XÁ0A@ÎÖá:.F$å"¡×èÎÁ~aWÁä½}Êþ±ü˘ ìB â! AB¡L*Šj’`Ú¶`ò0Àö@àø ¡j¡La,¥@:³:®a5á:A8;ïÇW®A˜)ÂVðÁ€‰Váâ{áˆÁ„¡i)a!f΢A`âå îAhAZ¡¨ÀîÀî&@a%[àØä.aÕºaláNÁ2ÀÔ· êÀó3¡ ªáª an#& òbh†a8 @î,ò²@ò!ZâÎì!V¡²(¡Ê:A6¦¹R!Èäá$A‚ APanAޝØ4‹ahÔáØáØ AôávÁä¡ä i2!ŽþRá a´¡¶!„ŽRúP a/Gó°`ú¡<éöX!ReªáXA€ ´Àô `Æ @½” À ¡Á€z vâV¡daé:ŒAä¡w‡Ã!Ž“;vážAŽAP¡`Jè|¡^!~óªC}.aZ"Lš €Ò àØ  æ¡qàûvÁ€ 8â I!Ë{AJ¡@ «Ÿ«¾ ÎF@  €É@”¿KÐ ¾`² àz À¬F€ˆ@ kb¶  j¾Zf``Ò‹¬Àlc¬@k¦ +ø†bà`ÁV6d †s „ `ìàž àÃV& ŠÀl€²`ØÁ`@ZÀ Ú `b‡Âa7¡8Áf*¬áÍ‹ÀШºÀ˜k ~ÊqX€ä€¾ ª¶À® à@” ¡ZªÂKZÀ  ë €º›,² @x  ¿Y…X!& ƒnÁàaÁ%AN!ŒRÀÿæ÷ì^@KcÀB`p†~!øO…r‡´!÷%¡Ô<çÂ|a¡Ô˜þAzáŽaÈ£¡Ðá´¡ŒAžaf¡»£!Œù’š5L¡D!jÔÁ^n€A²" 7:à4b!J¡"R‰Geá2ž¡B]¡HˆŒP,( ñ!Wnl4A—¤¸a‹a Á¯ Á£Å0àôÊ!C%2i¡BžÐ,5ÁA<v@æÁpr#JÁ¼§4f¢³L˜6¡!7üŽeШ¶$ôa,´ˆ(ø.Ž;ÌAØG,adССgpá\ÁPã (~¤, ]6!#Ø76±ü Ü@æ ï²Àä^àæó?Á¡ Ü fõ Öë-@AÄ©ä@æ`á/ ÷Àüëd€öá@ø äÎò ÷Ý¡!A&·”gàAÀY!üaf`ê\¦V!4aXg&hf<î7}ž@ÆêÕ¦Abbš!² n9JB8¢Á.³A‚á A’·”2¨)ÝQ®:îÊ^9Áx)áHÁ{á2aêÁ®æÔA…(`ª@ò À±mÀÖ – ༠`Þ  œ à¾Îe ÀÖAJ!€AŒAT!à¯%¶ ì0a¶Ê!!†á´!ªéf™ê ò¡dâJ`á!jt·Q›À’ @ÉO‚4¡‰s-®ÁZ¡j¡S1ó|C쀂 àž `º ¶Äc›«0ò Ô „  – š¾`˜ V&Ü ™ºà” @¤sže`Š ‰g>àœd€ˆàVà}ÑÇõ _q V`v   à\l ÿÆ ÀÇf@vŠow€sëà¶ ” `âÀø`Ž Ó ¼àQ6›– †”ô‹>&’J†¸m;PHA©0ž) ‘ˆeÒÈÌžOD&S#bT\G% TŠgüÍ £YÌ’ Ø<'”ÅD‚`¼ S*Žñ€‚[4MFó" !’Ãò¨€C #’I T?!ÈÁèr%ŽO—sõüö™¿fw›Õîù}¼¿Ÿ÷Gûéôûu¼­GC©–Ùm/™¬Å£­e2U¬f®‡+Yäòu¹\÷sÁÀºa©Õªô’µb”Tª’+‚UJ§I'“èÔÂi™N!S Ä"A(}H& 4Ê .B"ÒGôš] J ‘ˆä‘>˜h™Ér[äÁ2E„aS”Ä¡\T“eQPJ)8TÄÐö@Ãñ=’„Ñ E£±Kޤ 6‘İòDC úDãÀú>Ä)<¤üB#¨ø>dø@#¼R:(ìA£ÙEEihQ*Q•Ed]–EYlV—1zJ„ñ,M»dñ8^˜eÁŠi¥pR„qJ“$‰.Nä B¤i;£ÈüA2 ü;c°â<ãhê6 ˜Ø4£HÔ:±<¤Y JŽƒá?DÞ3ãxÄ7 C©8¤`ä;Cœ¤@ÉÃèôA#¸ü<ŒChÖ1£hÔ8 #8ê7$9H“DÙLd¹RUÄ™5ŽÃšœ83PôDD!(HE™fA<6ˆê, ÃPØ9xô>’$ñ:TeÉ5 Ä!W…áP“¤aDO×YJZ—E)p^Žäa(F…Ï' ƒ°þH%Ijb™DÑd^˜æáºE%qŠkç!ê{›çyæ=„¨´7Bhº1ŠÃÆ' ðŠ- âª*‰cÄ. c8 3 ä2J$‰"nœç"òyçÐìEeÑ¢gÍì}ÁÎtÄQhœFé*T±BĹ"h›æéšl›#áHž§áæA“Dè¤2 ¨k/&/4S–Å™I’Cä6 £Èê+ëy<“%QL b˜z,Š¡ð¨(¢˜® Â^$  ˆ"…¡èpÈr!ÈŒ £(¶!Šâp´5Œ=ø¢ðV A”!†¢@‚ˆ!èf ˆ(¤)að|aø€&‰A0v  ~ø>Á"„¦ÀE Å÷ƒ`ŒA0=àÜ&ph€iAä#†ÊTØL ¡ €žÃtÂDˆ1,&;F~á„P’Øt Áˆ4 –]àT !ô=Š!t.À•*¼?Á°Ø‚€TAH*À°ÐU ”!‚ÐŒ8E€² ‚€ŠÁXGñ $‚Ј˜M  ¤"„ N$Àè v ž€õc„~±ä_¤T‹0üÀ±ø?€ø#œy²=‡ ÝÃt_aª.FhË!#UŒ1†ið¦bðP‹qpj`³"‚ Al-Þ‚ôjat7F¸¼Ãô|—Áà=Fà§Â0XŠÑ*-¨˜¢¨E‰±H"ÄО"€R‘*&ÜsˆH $€>ǘJÁ$ÐŽaôAˆú  ub¤PÁè6†˜Òã4a‹1š2ÀÈs5@ #ÇXã”U‰Q*$Ä0‹Áõµ‡± %h‡ÁÄCðä D@mTÄ@ˆ æDrn¸>ˆA!@‡`£eüD"ÂÁäA€ñQÃØŠ´äD‡Á$„"F $F'¨—kÂxRŠ"DH€?ÔúÂx~5!ˆd!„wáð;ˆJ ÑÅ>‚>pöëÀyáÐ6‡ àÃxn ÁÄ9"#Ãòª °3†p胠7† æƒxg!­ZöCÀ„kô;‡ ø,Øw n¤1 ÎåÃ8rˆÂGˆ â! wâ,@ !(ë„ÂF Ρ¸?ˆ0ä"Ä lAð'0Î2FÀÏcŒq¼6…0±!84{ÆÚ¸e¡„.à²ÀX àü-…°z‚°; ÁL…” „ A$àx °6¯ÔƒðrûÀ1€ô/• rBˆ2€üƒàr _Ãå q"@ D+á*8ppp'ZØZ; !,"…p¨‚hOá<#„à°vˆA}íɬƒ Ü; ¶©8“ Ì9q1 ƒ„ áx„pž b´óîX3 ˆÂ([  è,±<,ŀޢœ+‡øÃh¡4)€¦¡ gÖ!X„§€ƒP< ¡d!Æ 8ð- a<„Ц BhTŽÏð# EÂ8@àÀ"`FAØ"`äwޱ¬=‡¨å‘}T¿Èã>ØúCÖMŽÁÔ4˜óƒœs ¡À8ÕbÌe ÁX0¨‚ôT p(ÅиBÈZ 3\(åh¨âæ‹ Ñ4-E€£ã‘ð?@H=;-z×ÂP908<ƒƒô8/x46X4ªÜ¬°2žÚÏX;JžƒÙZƒ¹¸: 8ƒQIƒ04ƒ0 2ªLúˆApý€Kƒ8<Ù`[0ch?„!‚/.¸X…€a†VÐ^ÙŽƒ[ø—Ð;‚Ð4ÙgÊf@^…à2¡a'6=Q¹y„–T…àã…¸`)pC/ <‚œM¨dhb¨nu€axsÀÆk`^@9@ˆ0?à+H8x1ƒH4ÃP6ø?8P4ƒÈ<ƒq"™E‚ˆ/ƒ%ƒ1h3ƒ@8„?Øt‡oHr„BmƒàI„°z‡Àx8^…Ð5?ˆA,(@3DXM+ëÀK1p…Z…`_†0`‚‘M«:ÈÈM”ð:…0ZHp‡XsèJp,®ð/È3‚Ð!À'ð( ˆ*‚€‚›‚ˆ'+_‚8 €$¢ø#è:2‹`ø‘ö{\  È1è‚#ƒh6š8ã`H‰ª0‚ *X"6 %˜!‚ ‚H%b P‚(ƒ2 ð)¢:*‚˜˜-(8ƒ¨7@8P+|MC‚p7ƒa@e)0C¡P;»•‘(.‚è‚h(‚`50"ó ¢‚P"x&Íavþ`&‰Úh*°‚ˆ)‚éà,‚ð!ÆØ=€Kh3h,ƒ`6óxµx;¢¨,ˆ%‚€‚O $‰P*‚ê¨'‚¸(ès(gpv:ˆz~ìfø}Œ¼$bH‡€¸‡P{°p»fXu`nØ_† jÀiZ[Ȇ`…_èP…°\à^àO…Š]pW„àSZj8I…QhdZðp†(^ÙpGHT^…ØR¨F&ØD=`DØM@bRZ…K…"o„àN„ª?HHÈG§ZªHEƒÊœ‘ðBàŒ‘±F38=38=ƒý1ˆÈ=„8CøfZ u†Àb†(S„xI„š–*¢©>38?ƒÑQ@ 5ä?ð<„07¬i„ þ :Swø8) 5« 7™(6à;Ô0:ƒ<ƒSU0?Q&b¤0E. Fƒð?:³0?*J»„PA8À <ƒì5è9)ˆ8'º„cÝÀì„0=-LÀ; ‰Nh6„s”’σˆ8©rÐ;€<9ÁN7h>à<00ƒH3@35zʃ™¬h207C99P;”ð=ƒ€:„8:ƒH;N 8ƒUCƒˆ9‘P3G0YaƒÀD@5:‚ùJƒ¨A¾hq/ƒÈ=Ù8\†Øv¨cØr¨X…èR aÐS„ØTˆ%‚Ø3ä ‚ð9{4æ„p=®àCÐPU0=‚|v‚p2 *82±¨5åm`N„À5Upc€aÀGhBUº±±ǨDc† c†°j8ZB¨Pf†)ƒƒ,ÖpT$‚Ø21¸<ƒ¹„zó$À(`,‚`"˜&6è#0'(X à'6˜'‚ ÷êåÞ°#5Aæ ‰çZ3QÄÐ8ò:@µÈ È h!¸®ÐðHË +ˆ7@%¸+ð#¶¨,È"‚ ,û–„ØQ… H)‚à-É 3¨8ˆ\…è_‚rïxè‚iàH&ƒ0™˜LÐ+èà„‚P/À=ƒÈ*ƒH7‚,‚ÂP  %‚H‚p'x’‚ìs™Ì (x'X‚tèA4(3X6ƒ˜HSX2P$3Ñ"/°EØ-è‚`&{…[„ (h!‚°-ü:¨$‚ˆ¹ò^8ðoàd‡0rpt‡Hhpv†šK†À~‡èyÏØ|Œ(w‡¸{‡+©$0~$Lÿˆx¢CÉ`s†xl†°\†Xd…xc*S†S…ø_…8]…ÐN…È]ÀæˆV S„pQEÁ8EèO„8J= UXJøQ„€gX†cªø¸L I'«ãPøG…ÐZÀ窈KÕpGðEÕ‹%àF‰ub¤„0'¶„Â=6)B)ˆAFètƒu ƒªº„8IN…HVÐR¶OšÊƒagaLƒJÆiÀ:,À9ƒMº•Ú»j¾¡X2”äMP1Š2ƒp3µJGP7@8BâÒ®ø3Šˆ4Bqƒ^¼Ø;ƒe„‚Ð284Ô¨IP ö…hYðUˆ5>G„ðRóÙÃ5XX5„HO¨ÕPEØHƒ-Pƒ2Ä<‚æ2‚Ôm–X7ÂÑK×00ƒˆ6¯Üè79ˆ4Ó 3ƒØ<7h<ƒ(8ÔÑ¢à„XB„ÐOƒr©…P_† U†_ƒ(ö€o€\`p¨s‡˜ É¢ûH,X6I¦pŒƒÈF„Mx]'HN7h>`-‚à)‚ø- ‚˜2ƒ/¨9‚°ƒ‚¸¤Ã„ÈU…Pc³ jÈhÚ=›M†@o³à…ˆ`†05?é'L¼;l8;‚0,ƒ:+¨W…¸W\!‚˜'@- ‚ˆ$_Tø‚(  JH$  ¯,š=¡áÈ$Kˆ#¸(_åüàŠä5¨x°^ÃRèÐpÀà&0àà5@"‚˜*‚H*t2ƒ){ƒ K N…(VH,ƒX7•HD·ÀL† h`bhg‚(,0&ƒN‚;GéÝ`!‚ð!ƒñ†¸nø9„8FD0]ƒtµÐ%p&` "ÈNèô­$„ØV`è*lè";…P&7%‚p#81ÙÐ,ƒ3 *‚ð,Uø%¸è‚€ -º3è""ðéõ"]å ‚ ¥_†Øl#´†K'Xu@g‡Pt†hu‡@gxߎ‡Tú‡PgäØt s†(àHt‡eϘb iÑHe0V†a@Z• K…`W˜S…PIzHFQPNðB ðfþo=Xõ…HR„˜R…„@(K L¸A„¸KL„²¸MËÕ„À@„`F« E¬˜Fƒ¨E„6„P;C‰×{ñØIl†„ „~È]5ƒ­YT¨=À(6„hGÖ—ÄY;5R4A­%uÌh22Âá•€:ÖÐ:k¸:ƒh7¬6ôÝÝ?øE„þƒ¨5¬H8ƒÕb„pC‘z¤T¥CžÔ„ R… Wp]ÐFûIø6|,H6‹j%ph6xÀý?G³ó{ú™ƒKו 2ˆÖ\9 Lç#齆>GÂñ¨Ê^4˜Ì¦ã€Úd2›Ì†“±œÆm4™ FrɀĊG¤Òª52ID¦W®—³%  æu1Îfaœš]-GNI5*y$£K›PgrÙ Ð_9 µdÎk)—Ì¥C)°¦d/ÌÆ"É ÆX4LÇcÒYH²8Ц³áÎz/Ž…µ ’M£T*ÄZq\…O'JçD3AÀñm;Ÿlç À¬q?Œ¹ó¹Ôœ`0›Ð‡ãÒ!€I&©²]P±Ô¤ ÅÂÑ®S&—‹Es= Ôa,('´ ÍŽÍi9\§ëÜÊG!ÓIÔj­dÿîw{ªU¢ù@ªWÈ4*9|C!ÊÆÃzeDž* gcñæØ])•ÊAøš ‡ÂX†ˆ¡àr ˆ!莇‚(v‡áÔ#†¢@ŒˆØ|$ˆA¸‚ bvˆèf#‡¡ ŒáÈrA˜TÁ€zÐp¸JHPSAèt! ‚°Ž*Š¢0¨( bè°'£$1F"ZÆ?ÅRVdá&iG ¨<‹# Ȉ¢8v%‰AxŠ#âX‰‚`úOÇaè~dy*j›féI“!`Ž'‡‚˜ª"‹¢à€)Šp”&…Âh–KÅ8Â=‚0´/„b‰+ ápŠ%£(Æ# cPüH’á°¨,†‚¬ ‚àz¢b€¬‹Ør/ ¡ ž)
!‹‚Øj( ¡˜%†BPâV0p™†YlišEù²k&ñºc›Çˆoæ)ÄpGÂd›†Ù€mù¸m¦é²^žgi°qœÆV[FYVa˜e9z_%¹nOå,V¤™PUå)PF% NÄÉ6Ad±J¤!*Kı&@¤é I’„"I$‘(@’‘I’D1šäqK¤ED^¨D‘#ÉEI=„@ò?cÉ$Hä1 ?©LO”¤) EŽD1:ØâPÔNÉÔ+Ñ!À>·î! }vÜ5èÐÞðCPm˜<‡G²Ãxx ®¨4ÀðƒHm îô4 ۜµv È<†°êäPƒAÜ?‡0âÃ(€b6@æ°km9Åâ:ðÞ$Äà•‚hHQ#’¢BPI‡@÷ƒÀd ! Ž\÷F‰Ñð!œ8ˆ Ôƒ¸m Á„0@ÑC1 ÜT‡1 ]!?80¼0¾Ã>Ì ÙÜ<AƒØeáà5è¶0h¡¬,‡©\±èÛ„5PòBà_ ¡H(„ЮBùµå{V0Ür ˆ-¼Ðœí] áP3†@œúha H3† ò#ijMáh4‡ ð–Øm ¦Žf’©œHÃø~Á~XqX0@—ÂÌ1±-è“°? A.xlmÄ7ˆpôÃèj0l=  „È¡ }„¤cˆY>W‚­ °Dƒ"|Rq"ÌxoC d Ñn/ÈBO‰ñÚ>¸¹PÃ0oŽ©&&¥ô9)¦‚ˆVD%Dñ&y] ¡&„P†Â "©#pˆhHFá ‚ª0 Aõ5¢ h°jÀ‚À~¼@x€P`fEꎤÀTàn l$4 peÀ z pàVàv€^@‚   à”(€d« Œ  ¢êÌ ¦ g¯< `°à Ôè v À²AH€ @Àá (aP! Šø "º BàŠ¬J˜ Æ• kv`š Âqàþa0ÁT ¶zÀ!ÞAž!¶€¾ €´ààc0Æ À‚…À¸ª!cF  ˆ„’¡ €  È )¦À¦å!n²@RàxP. jB€0X*Æ#dÇd, •‹)´d1Ö –2ÁŠÅV1£ 6­‰`°”Ìv"¡r»Pµš+UÂí@²X¤ÕËŠ©VR)ÑŠ"5<¡E¦ÓÈtÂi“K ‰tY.¤“TÄÂqI‘HÓÒM_/§êZi:†D#¨Å‚9!PçD ñ[?ÚO($9áŠ? ‘¨t5}D PèÔ1éz:NgÔÀüŠ7¦sáøØr;'syÐìl6އ#™½Ž:žÇ3Ú Ðu@Ž'C1Øúj=¡Ñá°êg8ÍgÁ”Ôr4N†Î1¸Ôs4œGWLÒq4›ÓùŒÎo/šÎݬÖt5ƒYØÔm;›‡“!í<#øàDÄ0â>ÎøæK…)P[ãpî8 ÃÚ>ùJ¤ E´CÈ4#›<Ë ŽpÒ/CXÀ5ŒÃPà2ƒ¸Â4‚ðÈ6 £Ö4 âð¾,‹£Î6£Ö7ޤì11èÚ1 £0Ê- ÂȽŽ„=$c^GŠð¼6Œâ¨È, CH¶*#¼9‹ã¹=ÄÁ/ â°Ê5ˆb ´'  ¾7 BèØ/ àà(Œƒ+¤;Cðô+Œc0„( âP´/ ‚à´$Š¢pŽ+ Hþ«“å¶6 Câ:Œ€à)ŒC„, B8¦,SÂàÊß ÃÄ="¨Ø5ŠÃ8Ø "ùBW—„ùn\ C°ê2CÈöI‘Ãù*EŒƒ¨â8dN”.N‡âª" ¢ˆ´7Žb“î%Œc „/ ‚hË9#(ˆ0‹`/³¢Ó˜.ŽÃÀ²ÝŒcù Aå1 M#ê? ƒXÜ8âÂH· €„)Š ¨'°– ‰ÂHx%A¸!†Â „ˆ!èr Aˆv†aÖ‡` B8n!‡!X|â(„ X`$ :à ˜b# a°’& ’°b‡~…¡è|Á˜X‡ah†€‡Áðj!^ôa°T !Ð †PŠ8ÃÀì@ሎ$†ÂXŒ#‹"°²6 Ä!E‹ChàB‘ä`”/ BNÇIÊ[æPZ"Š!à¦)Áè†V˜F>V–ä™d\›áÀ,»¢(À2扤IÅ<ºEd¡,[Eض9`’)B`œí¸ô=ŸABYF´6…0°àä*¨ò<Â$HàìÄè¢Àà% F8'á°~ ÁÈ=BäS‹˜H/Eðª B¬`ŒT0`¾¢¤_ŒN.ÅंôPBa<-E¸BÐN Al&Å€²¼W aX*ʧ"8RŠA) Š€D‰±8!¸›b`LQ*%„ •¢I 0þ$˜‚¢h?ñ,DX¢8H‡A$ÊB8Ká$¸‡AÐB`ä „!¸AØA`ü!Dp‚CÔAü `y"7‡ òÃ| æø6¬`ê „ áÀ;†ÀôÈp‡d;†°æ}ƒPn ªÂ_“FÃp|a¼@ˆ òCQÌ8;‡)p’z8 !…†ÌÂôÛ Áµ†ùƒ1ç œ5 Ä8fœ2N@æ ”x g¼úN‰¢ŸÃÐi‚,5›#´!ø€ÎxDä 胂°]Šàô!éï Á ëÞ Ä`„ì;OPÛ/ÍðЬ;´-)g0e ~u™ðÔ³’æ œ4€¼À_ ¼5†£òƒPW ¡œ-‡ìˆb t- ÊC‚Gˆ0Ø™–hÔ2… ¸ ¦ø_I!´>†êð†¡x5†Ð¨sŸT áp(…pÔBøq Œ8†ð¨ Yžaˆ:0§`ÕðW á‚©p¬B U ¨=ˆÁƒPhPJt+…O‚ˆ] ¡³¼Äp¡°^Œ à†Ã\Ÿ ol!-ì"„Ȭc¥ ¼¬ÃØ’â„[ q )E€u‚6ˆq(€I !h¶[wADˆ› åd†ÐÜøc At/ƒÐ¢AèU D5P U a'S ¨MŒáðI‰@Ô Ä8j«b ; ¸BxV¡0(ÀÎÀG `ô%„vB@<Áƒ r Áû•á ¼ƒ°zÛCàÐ ƒ~ÜÃ!6pŒ B0H#°ˆ20Dá$#˜ÁEଃpTqèD6|zÝÁ°?àÌ „”B D áQ@…tÂ8( í©„H ÈkÌØ‡RÁà.àðâ°`‚B ÁNúAp1ð•by¶„a¾<ÇPˆB´„š¢ƒXYGÁÔIȵEиƒ€s‡‘$„°ŸÂÌb L/™´EŠ‘P0F0É aš‰a6éB¨*(7‰ˆ¢ú°²o Ñ:+…È2 ¡`I ÑZ-†(Èã\l ˜4„˜«·X‹±Š1Ðø˜Çy4"9€zE³"ÔZŠ1p-…$&‚à]oát)èÀ¼Q‹1j&… ´oðMm!4+…h—b°IŠR$Å(¦"ŒRˆ±@(„H¡‹‚hMˆhÂ!dB´J”Q #Dˆ}Â;WP½`Dp“b6߈Øü#ÃÀ‡aÈF ãÐ`XbF—L vÂ=U°ðƒÈ~â?]0ð ƒØu>Ƙ2›Îo¥Ðx¡Öj†Åƒ½æ>Ð;†PâvHo & 5̃piIEˆè°qA¼=M@âÃPo—¡Ì<&€Ö§j3á¸2ÏJ\¨ã¸ ¡˜0ZËâC(p aŒùÉCz!ÃHt …àÊÃ!ºQ¢7ˆa8ƒ¸‰ çà4‘ +Pq^wȘàþmD#ì;aô<£Œàm¡Á|3¢Pö)D!š—z¹æx©½E Ÿ-0ËüÃó è°2d„༠`ä ¬ º  È ‹H„D @ €² ¼ @ô Ô& ¬ üÀà Ú à¤  ª D†Ÿ`Ò €Ð „Û*n KðOÀÎë¼  ¤ +D¦€Ì d '¶ ÀÆ d^  ® º @¬ €– À´e> ® €º9`úé@Ðó Œ `¶ ª ‡n  Œ°   ¼‚Ò!A¤ºA0¡$ ’§Àv @¦þ!‚¡¸Ab æ.@ÆîA<¡ˆÁ:¡zá6`À`îdÀ¶T ¼@¦ @ax!€Á,n îÊ x– E  @” À O‚gR À¾¬àÎ `Êþ þ€¬5Ò ô ´ ì à„ €°gä¨Àê ~ j– §¶ @¼ LÌÀppÀ ¯oJ ¢ vg"†”gÆìÀn xm@”ÀŠ T ~€xàNh‚çÅ P‚ ~È rr-àŠ VÐfÚ`@|`jÛ@² àŒ  ªeê –àz À¤ `¤ @„ À¢ ಠàbh&Œææ­ Àdh ZÀz†|f!^¡lÀ¦ Àx¾`HÀT`”‰ö`@ r€ž ᪺{Á¦áá6ä ôÁ&a^ Ê3 ®VÀÐ8@¶–á˜ÁÄÁ4`V ¢  Æ±ÀØ À¬ækè àœ €à#!ˆŽaž!Ðán…"4ô!àá ²÷ Ž @¶€ ^pÁ\á8!d!hßN"‡ánnaHˆa6Á\ãAV¡X3l¡0aTŠ!NL‚pŠÁ@!a?8O!2a, þA"„ôŽ¡& ô€ö!(Á"¡€ð®x¡ÂÒK©Hé@àé@æª áé®èÉt@Ì@ü`æ€ê/aDÀð Àê ÀàþàÐ—àØ—àÚ•àè4 Þò@ÚI&Džc±V4@Ø£ƒ¨&Fû¨Cî ãFò@ìð— è †E ÞB@î;à DdF@â „– €Æ ãP$#æ>`ÖàÒá •¡ €Üª„©Ü #œ*†4 ÇB ¸ ·B£,A¡ ?àÿM!aa>`Ò¤jƒ¶ü´+ôð›b€ê;àÖ ŠZGÀÐü‰¶ôª¬ ¯È 0"  ²T@¨²À¬  ·@ȵ@Ê °‰ $ŠI ¯ËStz4@Ò IÚX`̵ྠ€Ä `® àÁoö ÜaGÀÒ €Â à¦S Ÿ3@  %ä À³H@àœ ÙT ÈµÀ `Ì @’²ÀŒ ÀžÛf Àµ Ê&çAQ@ úÐÁÀÀ ¤ p¾ ¢€â el `¾ €‚P@–wá@p‚;¡* äŠáTÁ¤ÁlaªL`êA. ¤˜€® ®®¡^˜¡h.€` ÀÃ@Ö E$ Š~²`Ì ¬ `• ê ävÕl%„ €ÅZ/Ø+T ྠq.| òH=àÓ@ä.§ˆh†~`¤å*À£e@x à’@¤ ` v€ˆ hÀ„€Š b€tà‚@Z`f`p R dx V j`€`\ˆm †`Šq¦´&và–·€x €–H ÀÀt@L r OÁ¡ÈlÞ n ff `š2d –<Æ€€`ŠÀƬ`®4 ¶T€®í–r‡J€Ø`‚ @Pr_@ÐaúáÖáÜî‚ Ì ü€ àg#€n `ªÄôAþÁ˜á¨k=á ÀþtÀŒ @Ò ê"A€$¡fáa\ÖLPa†¡Îàþ¡TÁÄ!za øV M VÔATA.“tÛÁ4á^!`˜Zá.È”\¡N$PáJ¸€átä¡>A4 a6¡2áÀ³ÀNu:aàõ=¬@ò(m^·öAØ»‹ ¡+n â“ÞæàÒÁA”`Ü’ Üpí@€ð;àèö*¢”©ê iP*\äEÌ—éJ4Іž à õVô À: Ì<4}Eƒ>Iæ Éä bœ`êϸRJn:É‚¦éâ—Jˆ£ ÓU Ü /^ IhŒ#¢ø*¢ `ÙO ö åkgXö€Î ùïÊh À°>KM#î ˜Á a&«ãì©Á.ÁZêéißÀÙUiØWà¿ ¤Aèàü  ôù`̨u¨ 4Éž Þ N U2 ¥ €°TP‡Y\EòÿoÈ `ÃS¨ Pu6ªÀÇЕ—Lþä©Uš€¹—àôƒ„: Ê¨„n Œ €¦ pÄF*Œï¹1‹ì €¾P… €¼•§  dàª<ÀÓ?€Ä`´ Šþµ ÉfÆ ’(x€Ž`ž –R ’Hs2 `šW ‚u@ú©B"°¡R± È @—HA0Ap®AfÁ¤‡ºáfঞ@t `ž oD #J  ªn ŠA"$ü ¶` ¥d z `²™ €æà¦<àk#…v µæ ‚ `¼ÀÀ „ `ÃÀ°€œ Àº ÏfT&ÁÀ˜ x wHÑÎ àl€‚ ¢`# lˆŒ2€hwº€& rrV`d@zÀR`fûÎ@†&¸TÀŠì´öÝr€àÇ`z €~ Œ £±ÀÂã„Á!€te ±û’ €lC¤ ×¢ìäЀ„\ ~ @¨ `pq€\6š àºoàŠ ªªÀ“ÇiÀ Á ¡¡2ë4ëö$´@„ ª @Æ`’ À|¨!èáðá‚`p àÈáTØ @øªÁÁRüØAÀ!„A¨áÐ!ÄAÚ!ÜáŠ!¦ÁAAŒòÁü:%  j €£µrŸ’áJá.ÁQaTŽB!NÁ$!Rl¡HÁH²æ-4,FäôâÍLøœ¡<a5×'̹Ä" ø˜ºða épNšò¡!CAêa£á 3€×Û Øž8ƒ†]@à@*\[y0í£ší…ðïÃx7`ÅC”C4ñ€à@è:ÔJô Æ @Ð Dh ÄvF„D¥Äþ ÆðyXñ9„d@ñž æ ºj¿`à 4„  Òð´l>ƒx9ˆ Ï[Kƒ® Y” ‰¸ ½ÀÎ ^Z `Ûš ~ Þ  äŠ $ŠJþU0:4@à1x #>ãbL¶!*¡%^Á(`Ú`ùV ÂÁ ðÈ\àú .£z"H¦aP÷Aé $– FD ïJHÅ〳¶ ¤ à®SõJ `º:@Ê  ÍàÎ jû¢|hÿÕhÿe1à€ÞJ€Ë¶@È jhHÀÞ80ãÞ†Àò¡ Ь `‹ @Þ ÷QêF€âÔ@Ö à°H£©ÀÌ`š `˜ @Å$€È äuz¨ @¶©ÐP•b Àº€›Ã‘F – &V ‹{©°s„ßFÁ>ݺ @ꀕÉÀŠüƒú!BA‚aŽb<¡p¡²^°Œ³° j¡ ÄŸ† âé¨úw- ÅãT”.› ä¢É@ž`-˜Ï'Éd¢5&Hb©8Ì_%J"Ñd„Y/I…"a`¤O“LdqéL„D)GDÑ¢K* b8ÀtGÈxôp4Fƒáèø’D‡ƒAèÌn=Šiã1ðèR6ŒƒÑyr1$…„"¢À) ŽDƒˆžÞ$ ÅcÑØ ‚?+š cr¹]`¸WM&’±œÀ@*“L§a®T&–JD’üL¾g"”J„òÉX¦\- eB!8¦(Ž„ãȤb4 †ÆQ {°  bq°ô°g2 ¥Âú7%Ç…2©Ý„ ‹R©PÊ}<ÌÆQ œ]<œ‹g©•~Y¥Ù PçÙþ”…Ñ‚?“DùŒqP4# G™ðc§ô}ŸdÑLVda$, @t)ŠÁàž*èüQ„™BQäùDE”e P$dvFå N“¤A$¸û4ĉ,<‘DxâEÉFd:d8îB‘±DD!?ÃaD „38ÐA‘CYDcé4ŽÃØÌ>C(î?Œ£ ô1ŽCµ>U–% p]d‘*@’$€Þ?ÄA*O$i"5cö6‹CÈ, "ð¨- €², £@»› ãXè’ŒBè®- Bp¨+ ‚øÆ*Œ#¸2`ƒPÆ+ ãª1ä–ø=$9=‘D@öGt°C’°ª-Œ¾ú7CíÈ8ÖC¦ÀxöB± Ô#‰Â°ŸÎ‰b°Ä<Ä(Æ: c¹ @õ’+‹áè’ bxr% ‚ Ä4¢˜®&‹{»8‰âÀöF‘ƒì; 7h®„ È(Œƒ0¯`’åynF•e±$T–£ÁI¼#x$ŠB¨ÍpêƒØi a¨/„°ºQXb Á”1±ÀÆC€r ᇴ˜l á¬.à”ÂØb Ä7€â‚Ó al+„0¢ACa+„ vAÈ< €ì ÐxkÂH (12prBD à ~Â0?`è•0zB(B !0pS°5(¸@bAÈ' ÐÐd B5@üİf Ø2ŒÀ¬ƒÀ\ Ì+€´°l P ÈI *Bð_@è cB¨QáD&‚°†Àá[ A aD&‚ñ ¸4…p L fºœ€F #X0 ø&ÀŽÜÂÒÛÁ #‚˜h_¥˜_ `´ „  ƒdÁÌ`²îƒ 4, Â-‘l-…°ÜðfÁð:¡šÄˆK]Áp<‡ÁL3JŸˆD|±ø<À÷èuØ:Ĉ!. X°LŠFzCBlN‘6&Ä@œH‚lO$±4!ÄÀ˜¢M¥ Q&Ę‘âHIÑ)LD³J"L>ˆú|#Dxz¨AàG‰î#ª@ŒáÙ00j`tb@9ƒŸÁÄ@ˆ`è Ô(Š•|6ˆa„8Ž aüC†°ö"@‚Á­§†`ô ƒ}áœ<ÀΨ qŒ6 ̃xfW Io†ðä·™¸k!¥i,0×cŠÛ2 9¿¯ À˜˜j $@3ÈR´– m ! 8ud¶ºñq=†0ÌC8a9a¥h†æîe A¹®Ú@ºÃa ü5º‚°Z áUò°²&›°ÒL4"@׃S A|.†@¹iÕ@°ûœ¦2°‚5C!.$ÄÀ¬aÀAÛîŒ(SÁ¸>Ó¶!ƒøáàDˆø#„‚¢lT a8*…@†"@:¸¥÷ü± a}¿šóä Œ4†PÉ€¸] -³…@°ðaoŽÜ_ ÎÃ@\Y® 7@Ö˜€D"„Sˆ!*%舕 F 4ôíÀs͉9`CøS´áa‹ðÞMìÒâ\9¡hC h# ±:8V9a@0…Ð’æ¯ a@‹ÐÚ¦-Á`*àæ(–A„:8lBks7Wdàü—B{‡¡P*ƒ0†ÀG1¡DKà„h>aPƒ°“‚¨I A†(0€AŠàø^A°<á „0ZŠÀ?-Á#Z Áh9@¨ƒR˜ ‚i A .@äƒ ~ ÁP>àŽ+‚˜ð (àÔ°@ Áp#€Ì’ ‚ @æ b x\Á¡* @ÞCàY Á´ÒÌ -`è`p 0,œTƒˆBxO Áp„`ˆ ø(, A(„ ’ ¢Ø:„&x)Ѐƒ¼a@)¬t`O Ì<ƒ Žôí€2 ÁTÖCR& "Öp6Çèãä|ÏÑ솇pöÃäÑ’6àk"(+_ ¼ƒÐª¢èWŒ~.Æ¿”ˆL‰±–:Zb\Kl±*!rˆB@>àÀú$„Ž—Ÿ4MQ $ò`¢8G‡‘"ÃȉaâxQ"µ8‹‚"²ä"Dhs"0:„0Dƒˆ@(5Bƒh?8,„ Eƒh?„+Q„Q„(6Ð?8=„2ƒôØ?ƒ<ð3È>¬>X<ƒ8ƒ¸1€;­òÄK#ƒH8H9«8xý­8/ƒP5­(8¦’–S ƒ)zƒ@2ƒ`1ƒAp,¡«ƒ°5Áð…ƒˆ2ÐA‚ð7ƒÐ.”(2›iÀ–`4 8§X7ƒÃ‚Ê#ƒ1¸2I¼ƒkcƒ('‚à5‚Ø0ƒX,/rƒÑcƒjiƒRЃRá©ÑƒªÚƒp02 \8ä8,R÷ü®Ò•A =„°@“˜A¸=›ñÿ1¸DA¹z 1ƒp:x>H>¬ 8ðEƒ9„9€N¨B‹ HG€ýC˜5òæƒ1h›É½¯‚è.ƒå­òó"XžrØ,à6h8B9ƒ03ŠÊE¨;C„L”CX=HI©˜Pôvð).H<@ô€6ƒ°=3ƒ2Å€7ƒÈ;­(63(2‚%˜'G¸&ġ΂ð2œ!ƒx7‚ˆ-àŸ¸'‚Ð.‚x*È2°ø?`H‚(‚È:«¢.‚4E˜SÐd„ðY ø€,Áð*ƒh7‚li3yiP>ǃ‚ø<0*ƒ.(+X·˜Ç‚p'µ¢Ìƒ¸9‚ð5ƒ (à.ð(‚`4„ @Ac‚H.‚X)ƒ8.‚8,À66Žà+1x˜$Jh( ˜"蔂@,‚ pø&ñÀP+‚[‚0ø 8 ¸" ¸«˜ ÐØ«‚P# ƒ¢$èp @98à‚8"XˆxÀ‹@8x²8Í#Øè"¨@ ðDÓCBKHNH!0!?ø@à)°¼»("ó£° 8έ@ψ"Ø#° û\ÍP à"Ø(€#‚X‚DÞX&Ø-Rsƒ¨B!>„H €1¨:ƒ€=ƒêÈ °±P‚¨*ŒÜk„øO†Pr†ð}'àgÈnhq†ø{‡È{ƒpí è6‚s>‚œcØkˆg†ˆkqç°K¾[ï„»ï„èO0á+)s„‰5„x>0`>xHƒØJ„°@hGÐGX;¿{øƒ¨E„`=;ÓØDH:µ@;{„PHƒÀC„Kü„a„H7„CËHEHB„`5”¢¹„86è;=¨;ƒÐ?ƒ`=„3ƒè@ :¸.¼È=H>3Õh0ƒ¸>ƒ(;ùO™Ñ_F`8˜‰sX9és-ô>¬Û$™sfÄ3Dƒ<1hG5-„h>?ú̃­qFø6 _87?X;W¸6ÉŒW8*€H2 O„!,½Ø…Õ`8«:Xhˆ¸2˜6¹Ç¸H—°?²H;ƒ‘´8D€LS˜Hƒ©ƒ09Á‰“‚úW&È/‚¨,‚È-ô>V°6Éð7d!.7TcGè„B°4°<ƒØEƒÛéAmJƒh>°1ƒì=Üo =„Ž¡0:l›(1!ÙJØ0ÃÉcÖê»ø2ð!‘¯ƒÚ‚ (˜xJ…0UqxO -h9¥[…Àd†˜SðfxS¢­p(­ƒ_°& P1‘O„XEðF„‚à‚@)ƒ-¤‚bfÓ(,‚˜!‚˜)ÔX?àJiôx28$ Ì·¸"-ø¢‚X/CÑQ‚e{ä­@-#ƒA¨&¸#‚‹p7È(íöà ·˜'3x‚p$ð!‚%Ø‚0‚¡à$%àj> PÀÅ%‚bAÀ9±h‚Ôž £€‚ áB4ah€¸ 8H¨¸‚€¼ò$(S{˜hó›;,éŒ@Ø‚( x"P ‚Û$Û¹¬ôƒ89ƒ@‚p#ÍLÑ `¢È‚h"ŒÖ ð#Ð,º¯è1Ý0!˨=@C4X*8#hM(P…`X…€#‚°/H$‚M•4·í-&¦˜Cà,2P2„Av8M ^@q†Ñ¿@L‚p4L‚7ƒ€hhq¸^† ‚H*Ð&ÐBc …C¨M„uðI„¡5„¨@*8=`FÍßgFÅ>¿sÿ5@;„`G˜H <e³†E„h<b¤²¸„p:œÆE„ >„HGƒ A`4³@4øBŒ¶ÀCƒˆD„ˆ?P8Ê>‚„P4@Ø1ƒ¨=éU+ø1Uh1„TC4ƒiƒƒ)ÂP.`:8?¶ƒ±c.!f‚à4ƒa¿PÆùY—89­à9±€6‚ä&ºÒÀ0 h2°×¼H1x/iv¯. 7È< 9ƒ¸ƒ•©êëY˜A®ø9h7ƒ;h9XOƒàA„ø?(:”ø7‚êâÀ?½¨J„òŽ…(G…O=¡·™h™8D’öE:„&X7ÐLÐ9p<ÐC„6§¸E„¨IXP„ :0<¨Bƒã9®Ðٟ̂² 1‚Ë]„€ƒH8 Ø8ƒ{ƃq“2aÄGÆ3÷¨?’Ó„…ƒˆ9ØH K–> 7„1ƒP<¡–S$ƒ©ïä„0>ƒøAœPAƒñJF0; Æ‚€/¾áÈ/ï5²îø=ŸÙê0)‚Ø,è&‚ƒVƒŒƒŽ“ƒ”/ƒòb‚xNhZ„ØX¸J`YVª¹„Aðø+ë`5p<ƒpC„àPv¯œÝ¬ Á0'ø1 x5‚3+‚ÈI0YœM ;Á(B‚ÕšÃø1‚x2‚»UÙÉ 2ƒàA`p*ûAø&ÊÛ±°,Êp)‚);('ô©ƒq‚‚H½!Ð!¦à³"˜"È`ðÐØ"‚‚#&:<çèà (ÎÌÈÅÍˆŽ ”舷R>>®:ˆXM°¤x$À9벆%΀" t»ΛüÔ thÀX"!X/³ø'c¿c:èUÞ):ijSÈ&>‰8,„aàp¸R…HU¡v»à)vˆ-šqÉØJ1_¨$6’ó ),². ÄÊŸ@,ƒ86‚È9ƒÀ/Ø?©¬ YpA„ÈN„pL„°‚ø?pFºÜ÷'¦â˜°!,ø°DèQ`L©8L„àB„ÀMÙ0NhL@KÓ=?„œ“„9„]>h ö˜EX8Ÿ±ú„““ü“¨F˜; 9Mƒ°GØ@„f&Á?¤SèæˆBèM°CÛÖ‰„ ¨„*¿ð0°ø/°@üs‚ø9ƒëP¸0j0/Æð-ƒo h:¬0:‚êÂXP?d8;p8ˆ:ƒ<„(2yÝÕɃă–Cƒ„&p/Æf¨€-ƒ„WuÞZóˆ-Á´1™9«ˆ‰ˆ<Ÿ(7Ÿè6CâÒ1s–Ú ­`;ñ{`®*sƒP*ðƒÂf&Ç7ƒü4«JÁÝ@7ð‚âêƒ@;«8OXA„àDÀHo(9˜íVA„ G„ MZ(Füm0@ j„pP„¸G…"¡Ú(9ˆÊn?N賺 ,†C'ÑÂàˆ>œOæã!ÀÒq=œL&ƒApÂg3™Y¸Üf7MÇhÑÀÈ]3˜Ë†²™TÈK'™ FƒÙ´ê…/™$¢‰¨àxGЩ³µ`5 eã<²m#”Läò©”Îl;Žgt •K'ɤúM0 6G &y€¼h-—M7Ó5ø]2” Eâ‘lÄI'•‡¤BYHÈa+™ÌE2ùŒhB'šÏÈCÚE[;šÐ©ÔÚ4£3 Ð³ÒñhÔc'™Ë…#Ip« ÊÄ"ÁxøH›ˆ´54f<Gäâb0œ9#’Å£é šT!ŠB©ŒÈW7ÈMF¢Ñ´×UE˜ÎGÒYxÈ9$K~²©¨Ð@œH‚n#b¨ ˆ‚˜’$‹¢`š,ˆaè’‚hnáØb a¨‚ Bp!¨x%ˆá˜vÁ¸n†á˜Z†!t0áðZÁ€€G!¨N¡Hh…áÀl!ìrò(P†HVpTÈAPf„Á¨h‡¡ØNaHrr0R†3(VFA8rÀjA J…ÁnÒ@L‡nÈm4Lá b†TˆhaÈnè\"ˆÁP|!áØz'ã!þŸZU†"@˜‡Â0p% `¸.ä0øQåŠ)‹A`ˆâE^$¢  â ~+ Aø¯ bðˆ- "øÞ8«˜üK’déLR ÄWÑ@V•åq^[DQX¥ÑEÁ¸–)­íQCÊ3*ƒ`Ì—#xè4 ƒXÆ1ðÂ5 Ö/ŽÄ0â;‘ˆôDcHò²cxÖ< ãf°. ¨¸3 C¡8Dèú<‘þÐê8ƒÐ<¤#@ËÀ Ã(è7Žb$>ñ."Ãë;lO:†ÓB ÄP¤áÐF†ÐÌÃkDBµÁ(È€†âLEaC¨„Ð)æ†rî8wÔ9†°Þ 8|Áøš†°°È[ Á$ à U aÈ3†°þ‚ðq Á9Ö`þƒÐ#".@ôÃz ¡`8… ÄÐfÁÈ? @Ðf aô>Q" X˜‰`òPg .0Ьܨ^ avC@¬˜V AP*†`‚ØH ¡X+†€ÄÃ`«ô „ð Ĉ‚ AŒ(†@ìàŽ!¼Fð¸‚É• Át8`¨BL ah%»`‚ †bŒIŠ¡n$°‚TM°”‚R “,†ö ùßB€Xp¸Cl áÄ:„À¾Bxa/sp+†àæÈ^D)ÍÔB˜OVA@j‚`CA("„ º¶C(I*ЄÐ~B(@€üÅ6 Ð: „’jE¡~X5@± ˆA@6F@õ<~ €.`ì#ô¾ `0  \ x1 À¤`P—QX5ô¤@` R() ´^ŸA°"HÀ”ƒEJAŒ(Œƒ€^ À3©€°t ‘`'Q –ªPÔ5i™T@ŠA`>§`ô°†AÀU ¸&pV(+ à¤„pvˆ/ Á,<‰ Õ°2Á,„˜ ¢3« &rB¨; !\…0®È\ 1ÀU l,…°¹˜SˆQ(%ŰÉc\r5R?ÆèâC(k!t1Æ"úBG‰"$Cð• H‰qÃÄ@—`"LLˆQ$ƒØáÔG ò"hv¢(9ˆ, Ä0m" 6ñÄ ¸8BÁ" –€1(@¿!Ãè… ÂCá ¸ Ï>U`ÜÒ 0| Ï1‡@øè† AÐ?Ðâàr¡iºpèåÐbnt3иÃÀ`‚ï‡@°C˜XtG„ô: ²ƒ`XÈÁh´0̉gZášq†°Îb ¡`0I°ÉʈX'áP3†âD‚°a aL0†@¶ìBÈY ¡\0@´C`[ !µÌ†GæÃiw¡ÕÝ‚¢˜ŸÂ\T QLĘx Â7—‰~f%P<àƒ`o¡²6 ö~ž *´?שÎs¸áà@‰Ä€p3…ðÖ\q$AépþKd áõ·B„"ÃÈzâ :‰ðh| ¡ü9†@é9C|Ð9 ÞJçCÑ R(…À‚Èd±ÁH#p¾BhbÑaØ-…°ÜÂi… a²G¼ö!‚Z!"xÐpÁ¢ØpY\Nä!ϸ a€9‡ úÊÜâD9‡ÁCƒ[Mü/çp¾‚»n 9zá^Ÿ#°d ú $žÄ`V àÞÐ謃0Z šH(ë@¾c @1<·‚4ÀTì²,4é§qÄ@¤#8J ‘mDèO(¡,ÀÃ`u bDˆ6(sš+ÙÁ‡Pš¶ƒxÒ¨:ìÐȃ¨wa8*ƒð–ÐIô¨ ‚ pšAÒÀüª(ð8àè„t(©›`¼ Õ xAÐEöÐ#‚0V h5`À ƒð^ ÁÍSú ð‚äÀ S0Bá‚°T *¨ ´‚ÀZ•ÁX'à­‚úü›ÿ—ñŠÂ¥$`F¤²R ²KQDfʾ*^dH`dªräÐàTN <©ëŠòD v V£¥àR¯àb`LÐ.2`x €V*X ÄÚ`RÀ† †ö ‚ `X €^ ‹. Àˆ€N*¶Eœ  f,j·€d `¶H˜¢ €lYàj €²|àà¡À!üÁöAþÜÔŒ¡î˶®a<hÁ¶ ¶»az¡€ €"‘§Äb<þŒÁOÉ¢“=#ÒG„rHò†F胢sP(CYøüg>M'ä ú4Ïæ“ùøÓ2š! ç´ ò}0fCÑøÌx>—ÎçÊQü¾yAŽˆiÌød:ÒfEê±XÜx+›ÏÓy̼q;–ލÉÄò\9ËgCÙtäz.Ž¥Ãè¼k9•γ‘ìÀm;ŒÇéÀð`1Ëf3qpÆl/ÙM†“±¸h,˜ ec·Bf,–Le¤´c1—KeòÑlÄb/™Kù2™€ÊU4›6£”Ôh0̦SI‰ž@ Qç3¢îS$ÓkT±õ2€;¤&séÔ¾k2†„dþtF‹Æâ±¬öq;!Mçñ ìHC±;äô6ƒ£H£ãÙL ƒ5ŒÃëp4 M º1CìFŽ£©: Ð7Íhò1Œã²8® ÖA$N)0à:,£xÎ7ãHæ9 ã¨%‹"¢/ bx‡¢x‚Š"8Œ.â@Ä*‹chŽ%ŒB2¢@Æ- £èª/Áè’2ˆB(²& Ãx°2ãÚC ô- $ –; p¨ª1c`ìD‹ÃQ /Ð"¨Æ¤JHÒ>‹"øè' ãX *Bxª5‰"¨Ð%Šcž) B®2ŠâØÊ" ˆ( B¨Ê0‹Ãhà.ƒ0°áSMÐ3 $¶4Œ"xÆ-‰Ã(À&‹#b# $±b]%á”@å29B°& bà¸7Ž#8þ= ÃÐæ" ÂЂ(‰ÏðóW¬DQ08‘$€’-ŠÂ`Ä/Bp”‰b`n$ Aˆˆ!Áø~Ør#áÈ’‡Âxn!‰!¸|%áÐŽ¢(pˆxbaЄ B‚¡xL…¡Pn…áèt†Á¨^iAÀpf¢Ž"!H^á N`h:F…Á&ÈíRƒápL†a@K¯„á¨X†›pl…AÀ`AH<áPl„¡¸b†¡¨]§…!€V†A˜F@e²†hR†(`ì{G†a L†!Fd†á¸T!X|vað>‡Á@x†È~‡Â(P!‰at¾Ëᘌ$Â(˜ "`h&Š¡`ž,øZ& !˜œ(…‚ÉAàª+ ºG•…!ÆyœçQìzçùúK%A¸;Hùƒð?‘æ=˜ì£Éüñô>‡Ø§"Ô%Pº#p}b<@ˆá Ä•äT?ˆ’2#€xâ$:ˆ!„"A¢€þÃà| ä<† îÃ(uˆè=€êCHz¬@pÜÄ g(¤:‡€¸Pƒx„¤0îJ]Áô00ꃨ| 9^ ¢ªú-Áx:¥4‚É… !ä@ààBÉzRÈ-ðòCxw Á˜8ÀÊ`CHp á 7) Øøl ¡”8†æ‚Øf7¡ -‰Ch[ !œ*ð²ÂðP]!L.à´P^ A€3† Èm—Hb‘Á˜.†pÒÃPr ¤/pÈÄX˜‚Œ[‰‘(D€ƒ¢T> A „lât—‰0èĈxD¡¸7ˆÐLxfaˆ;ˆPê  € B 4‡!ƒY: " 9C¸q4†HÁp…a°@PÀÃ0ZYAɇãÜÄn aÜ0édà~ !ÄBàô$ ¡Ø?päC˜v Á4®Ó4€L ¡UT„àšè? ì„ðzÐ:áQäŠÃ#¼ ¡ …tÊÂ[¡%F@Ób\¡¼&…pÜãN Ð&…€æBøzV¡¤$…ÎX… Õä&€â i ¥Ô1¯²‚§Ã8K !¤!…Ö‚…| !& ÈÀg ¡D-0•(øa F:x0¨g¨A6%hê°Ø‚¼T¡B†jÂ|“b€[ #Ú)ƒl. H3 @›.ÂXZ  è&à~ÂP@I¡!u¼jè[S«+°tYÕèA0$À AºqÁ$$ ~š(>Áš„Pn”A A ìh$fÀ4àÔ0zhKa ƒ x ACIŒhƒ°f AÛ~ ì0\ ½û ¡”ðR C`à‚Ðj q+A¹ØðN ÁX%®M®iÁ˜+ÎIÄãP{Á°)ÀÈ‚ÀrâÁà9€è70hYîF€€‚ðD p@°‚ðd p.llø'V [2¬°ƒv Aà<í8ƒplÒÈ)¡ v.Ø?oRúª€fB€- 0ठ‚hT(Wª Â@O¡%ƒ“«BxLÁD)¨Y €Ð)0PÜ…ˆÇéƒÀ° n tÀ¬€Ž Àˆ àÖdª©à®@Š Çž Œ €àÐ`¢ `€ Æ š zàÈÀš àžŽ€–+À„  Ð­ äYÀö D*ï ä Bò €¨ @‚ €Êå¢ `œ +ªZd—@¸ €” ਠÀÈ ê ê¡àöA( ¡ ä& àÔéc¶€î P¤ ~ )®áF Á ¢ b  ¬ æ6 l ›ªà°  v|Æ | `˜à´  ˆ € ¸ ಠÊÀ  å¨  | «¬ àž€œ ÀfŠ t |p ©À‚ /ä  h€Ž+¨f ”@hÀŒ€„@P¿@LÄ`RÀt€|ià|€` €€dÆ vh`€€`zt@h€hvF† jfàΠzq®o€^€J`TÈ@Z@Tç]@ZÆ€L[ X`j„¬6ÎÇ6àj€D@d r> f0,ª€` <ÄÀDi&ŒÚÏh€R@tÀlT nnq€`w`‚€jц@T ž€ gÄ À^ °à– : àl à¶ – : €` ¢@” G® `h €Ÿ(€ž­0í<r¼à°à§€ª  Þ¡€Î£¢¡8 üd¡~!0àÎ æ¸ °`š àd ”¡a  æÝàò!­¼"á#¡ ÁöÈ\€úŸBR ˆ („?ÀîˆÀî hª d+ ˆ@Ì@ê * 0î&@ìâF¯ºÀÄ/Cæ ¶. ¸ ô âc2-èž>`èP  €è  æ ¾Àô c é `âêàÖ Ï*Pà Ö ¤ê ¶‘$ú ER Æ €˜ `ÖIo˜ @Äè€Ò ª Ã|^ À ÀÐ €¸˜Åª @¤ @¾•ãj ©ž‘€Ðãàä  ò à¼ç@·?ÀÔ @ÖÁ*‡â`’‚°¡àÚØ¡àÞ@Ò á`ÔÀäòn`-àÚã–/¸ 0æ °  ì ïNå¡ & Ö À¼@È<€Ö €úEd˜@Ê Ê:‡¡@ Π/x Sf àØ Q* @¼ ƒf€Æ àê  Þ´{ i&2¯* @È àŇ@¼’%€`°ét êý Ä  ,‰@ å ¥6`Î`¸ïͲ ,¼<àªS1F7c ¤ êüÍ~ ð x2 TZ>a2á8k8Á €Ô%4BÀÛ9IÛŒ! ÄP @×:Â]NA‰ùŒ€Ðk¤8æ3µŒÀ¹= V “´ë ÝAX`  Ò Å?  `¸ €Ð àä7@à˜àêHÃn `Ü6õJàò "‚ «6éE€©ÀÆ™£,£@Ê  Æ RŠ ˆ @’਀ `jø „àjÑ '*Àr,,àpà›`œ³ר@h YÖ ÀxÀª¬æl  p€š l — P àl@´€v ðZ à| и@† ÍH À’ŠàŽ àæà¬ |«ª `x@¬ª@­TQ‚ ¨V„Ž ³?ÈAÄ! ¡VLaf* 7 …€c'D– à|¨U €bòÏ<à’ à¼  Â Ž Å€ !a2 Àæô`ø@ð¡/4A ‚¬Á>àÜ}D¤ ë² žd ¬`¬ &LÀ^x@p2 `Ž``œ^à…œoè €’¶Ú¾À| zsvp€€ _ÀtÀ„¦kxàˆT2p«€J fìšÆ`bl,×r6Þº jÀ\±úÌN@XgÇ0€XLÎÏ^ HÉ \&ºnFòÐg@¿€Lv 5 [¨`@`N` Bh'4nòÇ@w,qöm e"€ZöÈRçx—`à|‡|·ö aP abàd À˜ëÞ†¡ úráDÀà^ ‚\Š à^À¶Òú:´k,àp àª@¦ ² ƒÈÊà© ¤`˜ ²© IŽãpì!2@²¨ dyàx À°ã`ø‡•ú>è•: ø Ø"" Àò‰`ö¹* ØNbZ)i9ƒèEsqdiR]“Šã3†ÂÐ>xå8Ú/bÄ/˜m…d^¾*K„ C Jb #ü £ ‚¤PÞ @Ôc˜öã“Ö—ÐO à£@èíÃ0™ÙÕ8®ìÖ ¼ éŠ ´•–iTYÀÚ nç ëÊ Ã> ã^Wº¨åž @Ê À¶ ® ¦³`Ì ðÈxbœ6ÅI"¤a) €âõ`øõBP Ô„ 8 |?I@ä ¯7´5vÀ`KúÅ—¤yxÀ†—px ¡êĦ`˜b€’7ö6 \À’@†ügèûBš‚ 1¸ÜX=‹ÆãA(ÐX' Ä‚ñX°`. bBÑ`„R(EDbÁ`Š: ŠD‚ÁPx_ŒD€Äz7Œb1°¸R<ˆbáˆL2ˆ¢¹H¤F1 FCø¾60‰å¢YÀˆf3Oc!ˆr5ŽGb1ÀôF>$‹±‘¨3'˜¥¼ h!‘)uÃQvÔ|°›ï¶{¹þ¸l>ØçÒñ®üP/ÝHE,ÀR’L¨aÑLÊ6'G%ˆè PÉ#"Q |Q) ÈdQy2$F$b@~B3NBŽ(À†GîNhɈÚm:gSÁ¤íØëšŽÇsAàðj<ŸMg“Ù¬ö7ž†£êàz@ºâr>Cî1Ž˜Æ6èÜ9Œxê0 À¶4‚ÈÐ6Š£`â+ #˜²6Ž"àà<Œã8ä. C ´:c8Ü;ŒÃ`ê/@âÌ"¸Ð7‹(Ü* À²0 ‘àÐ, #ˆ¾1Žc0Ò7D〴0ÂȾ4 ã Ò.ÀÃ(Ì7 ‚øÚ, ã8£2 c Ö,Œ#¨/ "ÐÄ2ŒCÖ.ËbÐÀ4 Ãl^5¼4 ¢À¹ ƒpÆ: °Æ4#¡EŽ£ñ.ûcÚ=c¹ ?Œ°Ê,L‘:¤0Þ32Ôà)  º4ŠÂÔ®-Œ¢¨¾2 câ2 c˜Â+Œb0¤- ¢€¸,‰Âà (Ȱ5‹ÂÈà1Ic4Ž4 âм*cª4‹Â°Ð-Ç#  / âðàì‘ã ¶; ƒØ4„pè6ƒ@Ð> âè²/ "X¨*ŠB¸¸(‹8‚#‡áè’ƒ Àn$a ˆ†BfˆJ°€–ˆxÀ”b0f¡ˆe”†b8bdŠ‚8d–P†¢HnÖe¢24 Á€ˆ‡BxbˆXÀˆ‡"pjŠÁ¨/†à¬j z+‡B@· aÀ„,"HÀbðfŠa‹^k!ˆh$†¡ÀŠBHx B8,Š•Ð¼5c™ G„ÁD5¤ˆ²2 –,†!à” ‚¨Â< ‚ h/ŽcˆÌ>¢ Ø*ˆ· Š.‹pÈ2ˆâà¾"ŠÂØ–3 ƒá$K‹£±5ãøÐù‹xö% 2hò? ÃÙ#‹ã`ˆ/ zÊä#Y¨„¢p&‰"8°)…Ø| ‚(”)ˆa¨Š ‚z‰¡ðf&„PRÂ)v A,2P¤ƒàD ´„ðº°A`ðƒ † 5à”nUÈÐ) ÄÀ\ ‰8"@  RA8'`š L A€/M `t Á++DH„X ÂP; ¡UŒ„â Á1Їƒ0^ h-„0•¨RÎ3%t3ðP ÁØ!ð † ‚oáLàÆ :eÂ|YAæ9ÇèÿcðÑò?ÇHÿãl{ñÀ>‡øØ‘ãLzñˆ9Gø²CôO ñÞ" ÎtBˆÇ€f¨5 a4„€Ž ÂPG7 ~ N(,}¤ôzÁP6EÀ"Àt`>M0&„¤C€w;!Ø6‡`ðƒ¨zO¡è7°úÞ@k›¤ë†`òh}!èAN‘ÃàŠ!Ø?‡Äƒj á½ì-`âC(oÁŒ6†ðºÃ`^ a¼-Àææ˜c áÐ/¥à°@e ¡y!…´ê Zrál4䎽 Ž,,†Pà–\PkÕZ&¤zÃXq hd0§¥jBàe F4…ꓪ A€.`¶Ã(cBA}ì`®BØZKAÎ`¾CP] ”-€ÆÒOSA”6ÐÈÈd ¡ü4ÑÄhf a„/…`Ês ç°8`åVP[ a™ZжCXV á¤,Ò@¤BðOG!~Î÷B‚Ò_ ê%gÙµ¼CH[ ¸-S ´èXV D.Exúƒa ü)¶DAœ)Àƃ˜h Aè0†@âRèa  '…0’B˜Kš!(ÀnùA»~ìä„0h É0d@¾\‚°~ N`5A$±øPÈ0½„¨ƒjÊo9 Èݳð˜WB(-feP ƒ hI›,9„Á¥fLBh;á\ ¨ A¸KÀØ&ƒ`rÁÐ@ @ä!°lÀ:Ád°¢ Á˜D È!cЈ Áˆ? Ø#ƒ ppàI~Aˆ.†ÀèÃЃ;‚ 0àŒƒ4%€¼@‹}!Š:…€Î ¶a á4.…P‚˜P ”(<ˆ —SÂàrœ>•BƒP€ah8‡€–ƒI ¡€8Ĉ›®¢$1Í„ÌÀ@ äƒÀhøC Á8† 〠!#,ƒðl; a&ðh‚/ !85ˆ,'… Ë"ÔhˆáX2ĤaØF À¸ÄP8 !€¾Ð\Á‰P@°fNHœS% 0N €ùà˜àR 6ßà´CT ÁÐ6‡ Ô°`ÖB¨r"t7ˆ!6ꄸ< ¼ Ð^A`2y‚àdØÀ$€Äƒ0\ð1a+À¸”Ph —- Ø‚Lº Já,,„øÉƒîF :d1’ã–C ™+%Æí“0cŽù0:Çø¾ãüZ aþ#ňãP_…àî%±H[–Y('„ö`XB¨RÂ, ô„µÁð$ÀŒ°R È$™ È„t‚ sTáà>‡0÷˜>„ˆ>ƒH?@4ƒá_@.ƒ1-³ƒ'‚È1q킨+­â/¬H3¦à1‰ %ð,`+&-x(,¡Aª09±õ9n-¨0³x2$­`%‚ø*x3‚È(–È(, ’*à4€&‚ˆ&@&‚ @(‚(&5˜!°‚±ú{Ž‚ ™ðlG «o¶Ò÷ ˜ Fp !`л¸±*eŲ˜"tM°ƒyñ/qð±ê¡ø èy¾ p`€™Ä`‚0ø*¨  xè(I¤  ¨xp»˜á‚ ø$•6à6²x9‚X.ƒiÎH"Áè8„F‚ø7ƒÑ‹,Òp8>„+ƒRɃ`9ÛC„PN…[K„4EE„˜)‘j,ƒx6è8ƒˆ'?ŠåèKHZ„J2ƒÙPƒ°0‚h.¸‚ "›è$/ Â6‚HÞ‚p2‚˜ p%ú @P!È  Z@n… f‡MÊpIf„è^†ÈO…èm„pX9„˜Zƒ<„°ÚƒÄ8™¸ÀHˆ·4·jT¸H@@¡˜¡hK|¼›°(‚78Kˆ5ƒð.ƒàG‚P-ƒ €Èp ÈHËà˜ °ˆÀ ™Ðˆ¨1£P…È  @Ð!‚ˆ‚00†Hw‡Ó¨$"D‡ D†xx‡ødºbº``‡C«è…°oøZÎÀX†À…Pj‡ðP†`}…fÈR†X|„PU†°7„€\H˜AµÌh‚,U´än‚à9ý À!‰Š øÄ8¨8£‘¨ À: 8=H;½0:ƒÈ?ޏ=e ƒ‚lx9ƒ°üà8§°òð:ƒí'<¦Ø:ÁHØ?=@>p<ƒÑŽð:§ÑEªó÷¾'C)5¾¹3+¬qí•x3À2À3²Ð5‚’–x9¿à7?™6‚ˆêéË‚ -ƒ0&‚ð2X0R˜-4Žƒ(&ƒ2`.¾@9Aò¢‚ð3 1‚ +ƒ+¨1²¬‚¡3-‚()‚à#x,X*³z’AÈ1¨'‚ádªîé[‚‰‚ð.2ˆ8:˜Gƒ»i'Ð@8E˜6*è07ð1ƒP<ÑE’°+à(ÑiÈ.HA¨Bs_ƒX+Òø%à&p+ˆ0‚¬3‚­:‚¸&¤‚p+-‚€-‚ˆ$›9‚ã0@,@/‚8*‚°#‚¸(‚p0ˆ5«Šå¿x0ƒv ' " È$œÈ˜£S˜ÚÅ€«:^X³XÊ-»°ø ƒ{D½ŒUŒˆ˜DxÆàXè‹Y(VYPãoà«5šzúYÁš™ë ñ Þ°Å’0dmtZ1ØÀ%8%± ¨%p!Ì ØY·ÈˆÐQþ¬£ùd>èÓƒ0ø'Ø"­°ÿèF„È#•&–¸$«‰Öƒˆ=„hMƒì’„D„ƒ€D!RðAK1˜3Ñx3 5„?‚±,‚8-‚ð=€MG„à5ð?‘˜.–1ø'˜»x2८€&—8‚`#p¡ø °‚ O‚¸+…``†`U†ipTA„ø]ƒèN¸=„à[6X_„PT† E@dÕ˜RIј1@ DV_0¤ŠÀ(x8͈e‰ 1@€ P €Ø€ ¦/° ‚‚ðX°8 €Èˆ à LH @€Û‰3! ÆØ!Ì5¦ л¨1ˆœ %W†°r‡RFØz‡økáèc:_ …Èp‡øYÏR†x8g‡àSx…dÀNy„Ð`‡~+‡ˆLbØKŒÀLÈs¸@c0@‚`2H!%¶7Ïí“Æ}”øè ðåò0"‘»i8à@¢Ú€@>ƒà;„=ÈA§¨=Õeƒh:§À<Ð>ƒÀ:ð=öH@ƒè>ƒø>ø@èA Ïà>@Ð;”€:ƒ°8ƒ€988,=T‚@3Z¿P,̬ÛF‚q8‚À0-o— 핈3x3 ÒÉÓÈ$޲®áƒø0”P+ð3‚yAžr©[’¨4Vú•ꢠh)(MmÀIYb§‚X-ƒs0(¬ˆ#"‚qø+@#È#f^šÚƒÁƒ$4PÜ‚˜#P(RÀWXþ Eh4Ú¬ƒÝ7ƒú} 2£?`:ƒs.,Cf85+ø3)!({›L ƒ`(¬.T478.¿URx0‰Éø#H'‚8$ÔÐ"h'®à(ÓX)Ö (²ø)‚@&X!–p)ƒ׃ˆ0 "´8/‚¨'x#"øaC™µµ×<1àŒÓèªÈ•$³ŠxxÞÁY˜¤ˆ EÀ:b‰è•&(Ã{l3»ß°"Ø J x³Ê ë¿°Ý;½¢@æ !!€8‹3·X»Œ&=›yËyFû{"¢HPEß4B!à³O‚&FP$²åxƒ@:ƒ¨C„¬%„(#à2`A„X0²˜@¨PHP…ˆB°Nƒ¨D˜2ƒ´}¡<ƒ =È0; ‚020!è.ð+°"͸€+³ hl¢h%ËX߃·¦¸d£¯p(«YP#ٌ٤‚qXN…€^kb„Lp:€T`D5„@QƒhE88ˆVhF…P4„8RIà? p*‚!‚H!/ðD8 °d8 h_’n¨í˜ ¯7˜ ¸® € @µ`8X€€¨ Ø€   s^ ßøáÝ‚8+¸6ða„ N8;‚Ø?¸Ø! Þ% (6¨QøjNxg:`_†ø…c‡€J…¸q0U†¨=…e¸O†8;„àdxJ†=ðeÔòƒ N8=…eSp@Xh„`Y†×†˜4(V@1 øcÂOþÏè<›#8òËJ!<•¸à…À›¸;äë˃Ë;ƒØÿØ:æMƒè<ƒ=ÖOƒø;„ C˜A= >N…XH@Xް>(88ƒX6`3Á–`løÏp6ƒ_è8(3ƒNp•/ƒ,,ެñk¬Ð1ÁòªoêÊ 'Ø»çh1ƒX*ƒ7HÁ*¾ƒ¢Í]q,š“’„AÀº®z€4ƒ&@6¡$ÖøÖø6çÐ2‚A*ƒHÒIW‚>‚+F0*ƒ"‚h0‚)u ’)!×,.êx(h*@¸/@¸4‚¤-…fÓ@72ƒ¹(·Äƒh5Ú…ƒ978)¬¾ë-u—?ÀÈ%‚p1Gp4­µ/‚ø8ÝcUwƒ}@¬´‰‚h)ÁùBœ((p#‚^¦‚p&Ö‹³ƒ©‚À+XÕbh‚H,œ -‰Ä±Ct@óÊ8!‚# øÅšp   ¦ËaŠÆá­™¡€³K>ˉVÃFÇlmû_(µ‰p˜³ìžÇÈ‹ÖÄØÛ}²Ј†;%HDÑÐàŠ.EbÁÀ¼V=Ї"¡8Ú03 â˜ð¨V<E…"¡Ø´T:‹¢‘8ÔD#‰C@œd&ŒDâ ¨X6ŒÃa¡l5 I%’ñ êj?¢‡å %<§D(Uh…Á¢W Ê²%&mA# …Óì Q"Ë$bùl‚[) Šé\¨:( e!¹4 .!°…±L’>'…£Áè܆?‡"qØÜZ; s$QnB Ãјðv"ÓJeb}V¸B¦'$R„Ö€MIrÁÕ^å‰"áå$a:"Œ¦S…@ÒP*J…£ŽO#’IƒÂ pC$GD(¬\+ caÀ°\.ˆ€À.‚@¸2àà( À˜0@ø>á8*™ƒ øK„@¨8‚`èJ &À°4ã´YAL]“„P^‰ã1 ƒ:ä5„¡¸Š Â9zoæÁâ–†yè<“˜8ºA…âhæˆÃpP" !H‚5¢Ì Chb(Ȫ9‡Âèú( ÄX¼@ƒ)OŽ‘b>“ÆÎB•BÈâJ†B¬†¡àCE¨Âb„¡ nÁÐTÒAt fAf† N±B\’¥i„@äàøD’$ HD!5Ä5|BŽ#ã‚Pùà•&iÚH•Q R˜#™F #xà7 £€Ö6 ãHØ6 ƒ@Î0 Â1 ƒÖ4\ƒ@Ô4 ƒ5Ò1‹wPª/ °¾3‹"èÔ1‹#¸)‹" ²2 ÂÀÊ. à ¶/ ⸸7 ¢àØ&ŠÃP¢- "ض7‹ðÞ% C@™‰ ãߎ‚ÈÔ:‹Ã â/‹CXœ,"@¨0BØÔ$悘Ê< Ù`´+Œbš-ˆÂ€´!‹cH”1 ‚€¾8ŠcØ+_BȯbBà¤.ŠâŒX0¢ðÀ9 ÃÜ, ãX¸/ãÖ= ¢Þâ/b¾8 ˆÊ"åb–* ƒ ž.ŒâXÂ9 bàâ* £H§ËŠÂ€Ð*Œc¶5.ÃX”. b@º4¢H´$‚x”!<¢C*)Œbp¤0 Âpº, âhˆ) ÂX½Í‹Bˆ¾0‹b¨ž(Ø‚†ðt¡ÃÜ…¸f‡€T¡Xkñ‡!`Pa8f!»æ…/Ú¿!Hlh¸Nû@ìŒ§Þ ÁI$  “àþϘ6`¸¥óÂA© $)€l1*¨HAB–À‚Rt a@)}à¨pN °#莃€P ¨# ÈW q<‘ƒöP=@Ä„@¨Þ@k̤20ü „言VˆA6*ÄœAüJ‰°Ø!]Ø¢¸U Kl0Pìg !`,`”X?Á$ðžw@3†÷"Ûƒ1€øƒ÷ÎõÁyGðšAÐI È!ƒÀ^ €-(G R&ÅH²âLO‡1'@€ad;ШD S %†qˆfb!œð€ºCpS !t&… É"ˆ;?Àì„vBp;a5K„j šU Äp” ;€T  0À˜sÜ€>€è&H`! N0&C ¨ ‚0N$àtO€FÁ -¡*q2D¿ B Y†Ñ .H„!0@V›Ã"Ðf€¾ E 7 Ì ä°wL8ƒ š¨L €Ø&†úŽØT è(ÐtƒX7  `È 8a©A˜… äÃ~ Â,SÑ"-(\ #©0v Aˆ6ÎNÈP Aœ`À*0g_Á€& ȃ"d A˜" Ð^ áä.ôcJÍŒÑØ,Æ8ân ¡p4E¿ãxtÑ|8‡°£ VŒÁî*Æpö"ÔkA4,ˆu­Á¬8†Ìƒ e\«œ/.—’Áø` kœ2†Kš—Xe a€2кB¸_ a\+0¬BèP a„-”h`¨¨7¦˜X Kä5…€´B«j½Á˜'0ÔÃX| œÁ\ „€–AøEÁ%„€¤ÂHW Á?!…ŒØÐ_Åy€,¶@·zy4€ìØt Aè9ô‚àt}Ð-‡„V>V «ë¯¸À`úH5 ¸=Ð|øÁÀ1аWÄ} µü§üûÁ¡ ÔÓ˜„ ˜\I 0$±& …Ïò`d Á 3 ŒPJ Á &¨‚pL ÷`2„±˜îðb@ø-à€°N ~ò'Ђ°p}dÐ? @ð!…0–ØC9UÂPQˆ!4*„˜(NŠ‘%…(lâ,„ð¬ð I !œ'´wl9‰}á8¹`”B ?w @†îzPpe!Xͳ:pA{მT6 !0| Þ¨háøR ~/HF Át7‡Á ƒ¸† Áœ>„ÐÆÂTy An¡„ÀÄÛÃ0M !d%2ôëç`@Ü`Y¿x5$@Èðh Á°?€àO]† °.ú& .¢(€P À:ˆÁ @D8Á ŽŒ{PJ €ø$àl"0JªÁH8ƒ`H;ä+Ø#a¢„è‰Ôn"Yl>‚Àxð-€” z˜D ž˜/~€F @hÁ fu‚< @F žBü f `fÀšà~ @\À°CÈî €ÚŒ¬àjà¶€dà@ lï8„ t \€H `f`TÀ>±àPj?€F@`€^ Dàf €,X®¦ uþÈs?ÙN—û2Ðu?Ú·û¥d¼UL‡š‰„ëO/œÉæ©:ºp",#Ò-!˜0ÂXY !†@  J ¡d$°‚¨[aœ)ǹO [zp*„ÙBJ aL%`–xJ1H*„ ª [ aUàÄhcòX:! ÒÍØM1!=Å… ^‚¸p ¡p7`Ê‚à[Æø4… ¸x[áÌ,†ðÊ(\4%ƒàŠXV ¡,0† bB¡³?a¼2àúCˆ ¼=…ÐÜB˜h d4†ãú‚B8BC°¢B EzAJI€äbØO Ô(ƒPz €: µv `8PÀÅ'% 84Ø‚ZL šKJЂÀr‚MiE.@Z ÁÂhÀµ4‚–Ji 9€¸ƒÔZ <àô!:M(Z rT!äæ* 7H ÌÔe @1·^Þ²´®€4`B A u@7€``PÍЀFAc‚hÕ°¾vCRÁx6¦%`ÂÈyBD>ˆñ*ÉĨŽâœF‰ÁN„…F„)xƒÂ„ˆ ÂLŠ@ø"ÄÇ A(2xžBU ˆ9:P¨‚hE!ƒ€œÁó d`¸ûM(?@õ2ƒ aS²G}a…©#p‹á¸;“ÒB0NÁ(ƒ@típV !,'‚pR Â@!^D„P„¸8a$#Ñ)LhUC—„Z@ A+S ¼à„AàA ªX# 6 q0+o 8‚H @à ‚PLA0%íÈc`< A Q­,pÔÃX\†pÃà4áÈòB¨’! :„ðÊ!ÂðtRÄAÐ’šèT ä)rŸ‹¾áƒ –  M€Ø(@nxRw! †‚ÀI Áà$¨8.@x„ŽA814¦Áˆ;qKƒUiZh" Ôpx4ÖÔ@€óA¨@´‚§öÿu1È=) ª¢ˆ^Ž1`2‡´„‚ðnñz7Çø¾#ü\ ±þ,ˆû#Äá@0GH™C„EŠ”Ä`¥&øÄ†B´B˜Z %Ä.—¼wàR;H)…XþÂä[ ¥L0Çpº\*al5€§ÅBðk á`7†`¬Œ¸h‹a¸.•Ы;Kˆn `4ÀÂNPO—2p„´ö‚x]C¡&ŽdÂw ¡<0p‘£ÏÂâÁ.?ð¸%àN a¨Ð€ŒÃM ¡¨(AO2èfx-¼BK8 ¡ -„ð ‚X^!H2‡°Ãsa„<0Ì Ð_á·…PxÂX?fAZb@°™¸N4áh$®¢CY‰ ñx:†ÌÂä7ô=Œ63ÕìàAl*6 ®ÎSåþzSœÂCă\A.€Íô&€f érK¤À ¤dŠûU‡ÇI‰,ƒZ˜AÐF °è)™Ðz ‚ 9 ýA¢ðVšé*QÀÈxÁ5üЈPA,-àи砲O œ`šÏä`V¥ Dp„ÂG R ZGgÚRÀ\oe`eD V@>VP8o`XRÀZ>+ : Hí{ÐF± öV N ü¬€^kì/ @ä`ò þ¡"á0ÁLá"!$¡:Á €ú È Þ á¡ÁJ €â@¢ ï( Àšz ’¤ @u`f…ÀÀ`|@`@†Pá àj Œ@w ^D¶b@pÀz€h€nà˜€Ø ¸ öÀÚu œ™ŒB |=€àšÀ`ÀÄ ºAP!"!(Àà@ü ú ò ô@ø æ€æ @æŽàÈ@n FÀbÃ*b£€R o`’ <@`fÅìTP`E¬låLÀ4ÆDj,zÈ&ˆ <” €Š æä À” Ö d Ï~@x Aá žÀ A `à   àøþÀ¸W`˜ÍÀ¢G€–àr C" H ªù€ª l  F ¬Çzx ’ÉBé€`VÍt€8`x-"àL@6GçìÓ§Ñ s$'ÒÀrT`x @ q`vë*ëìÒ€l\`8Àd€X2¸ È `Ò àÎŒ Ö à¡ ü!Z¡>,a˜fBÝa8Ýa*ªAb.ºáj¡ a²BB `ü ¾ @î—€¾]¶>€¶“`°à¨à2 ž €¬ À  Köœ. T €Ø àÌ  Ì+¨î  Î Ú@h  Þ àÊŽŠ'  ®ŸŒ äJD€¨ @¶7¬ `º Hö ¤@ àÂàÏ(XŽÜ ê `¤ €º  ඖખï0®>æÀ¾C ¾4Œ$ᘠ@é9ÀÜ7àê7 ò À² ‰ ‹ñ4ÀŠ $úA å ° @ŒsઠN6¦l@§A&l” â @¸ Ü @Ô€€¤l°€Š €†à®Ái´ ÀÐC±ä `Þ €²#v€   æ Þ<@ÕDÄB  ¨ ° @‚”I —€¼’I4 rþ dåpøj8 T¦ LÊZP`J¥RrÈ^ª¥¯ØI„¼r`n@Ä À¾€Ô #)`›@€¤d^äzüÀpP² † @vû€zœ) ƒˆœÀ® É€ ‹â n`^¤ `h§êbhD|@VÒ/Sæ–`@T BÅRUhÈF—ÀTU0P N€8µP…RçËIÀH¬€ v¨`b§-!"–ÁaF<Á*Á<:ÁJa&A$þsXàô!* €Ì.Xc€Ð †2 €p € e„’€V{ ë”Ë´ `p ¦©JÇXXI D@R@LPYV€JÇF¤küëýVu@Vcî öØ`Þ/µâ b`ÌQÚ`„ `Àö“* ࢂ€Š @ÖŒþÃô`à¸`Š DºÕ ¶`v g¬ àf @øà°`z üÏ€ò@ àN€¯àŒ P: xÞÍÀ˜z ëv€ˆ €h Ày`´Àˆ r¤ 6€^«þl6­Vwàmñ’­tw 8@\ €Ì s‚ Bh `À „ `Ð)Œ’ Ð `¼ àÀ Ô) ä `ÝØ`â¡&A”XmÚ²Ú€Ø!0 )æ iS<¯„L‘¸ Ž` #ˆ4`  À˜Â À Ô4 `Ð ÀÔ*€Ü Àµ„¯0 Ž(*J ßàà* æ)Þ Àº „H Æ. Æ àÆ @´ @°˜À¸Ô  Ò Ü€Ü î¸ë pòŽgƒF @½A Æd`  jå ²ˆÄ* àQ€¢ ƒâ ¼ ¦ T ²‰€—³ °6 ©<@œã€˜ ìî ä ÂË¢þ „4óÀ3 ƒÀΊ ÀzÀ’Àv± r€¦€ˆ €„µÔþ ö0 àˆ `ÄùL”Ìl Î5`Ö4 Æ4SÚ À¨ #‚ À¯— ¢Bà‹¦´ø hWsX T|æâG`HÔ¼GJ§å<Å"”³™@fª~ „: Ê æ àØà32 @°­ xýæ¼K€l£À†r`¤EFË`¬ œ ˜,  .î` ¤Ef¹‚`lGª–&ȨÀfÓ*ÚàM%Æßj¦–°PÌpà:º-ÀSÀO£@N¦úÀ85o U¢`B%]W¦£J@Y(€p‚” Ð îXà¼7 Ê Ñ,@Ø oJ @â`àé>ÀŽ|«b `¼ 5 š ¤ fôü :µ•¦GOà| o˜`nDz¯Óu€b tF@v ^äÖx `° !ð‚z 6@ ™> à À`À|Á`!@a aa ÞÈ®_é ˜å(€„`f`pà€`dkýheBpDv’¥`¤ FE VÃ`JׯžTv¶&æÇfèÆfêT `ö•{`º`ÖÛ &¼ ~àèÉàû æk@êà’$.g8Àx ù @Ö@Š f Ò`ÜAz¡^2aÔa|a$AÎ`á¦a* Æa\ ´l*  |  Øà²ƒôà„ €ÜA@è º€‰‰Ø´ ià V@“j…Àpàb€?*à@€ ­àZ D`fÐ"°°Fàe|%‹{‚‡§ Æc`Ô ât ® Ž ¢¢ Ž -Ä ®  Åg Ì€àÁ7AnÁH!aŒ3  üÎN ¤!°Äú ³B §R ΀·4´Ø ’ ‚˜ ’ ¢Èà²cÔ éí|Ü ¸EˆàÞ `¯)T Âä‡âÑТv bã\˜N à¶ À¤ î @˜8˜ I >ÀæÀ¸“cª€ˆò¹4éô,¢Mþ.S´ àŠ| vl%ê  € i´ €Ê ƒÞsPlC)Ò >ú¦ `Üx\<@ä ÀžŒp YzàrýÄ àhF`jÀy´ €Á ƒ)„´Á@hÊ¡´Ö  lëÈ|€t š² ªª™D ƒ>@’/€’¸@† â  ” À’Á€~J4øíX È¥/ÔV¶Šjª×âÔ¤àZ¨šÞ¨Ô覛`ÜóÀë~@â ÂÈ+€™Ø/ðð@e n\Ùª Ö1“À À† €¶ I| é°‘¢ì H‚ `Ä @°ò€ŸP$^ÕÀ^ lÀj¤Ðö~@oêŽøçÕUUZ@@Lõg¤^Â0LÇZ7£JÄÌnnõPåYî@A¤&–oy VŒ`»ðr ^¼ÀÀ ƒU´ª4k¸@ 5¼ÞT žZº*4šà™§èó›‰à%Úã~VB n›Öê\Þª yNª>q \gR‹¬FD˜À]_f£@„€Ì.`ðÉ i?H  Ä 5)x ¢a¡B"Á@î  Ý;©2 éJ=ÿB SqFGö®ÀR€v’y¬öÆ`œn€ˆ @E`už8ö•€²%‚ ZpY£ö·¦¢ q8ŽЉä²`ìr>ˆa‰ l4+‹F†¡äè8žä40ä–£â¡à‚Q7%âiÙ.·k¼ÙîçûEäÿeΘ‡úéÂÿZ6ßêæ«ýTÑ~¥V®Cj TN0‰óɲsN‚1”nN3J&Á ®,“11 ¸~ÄÃb0”lE Ç¡ÑhÜ&) d‘Pì¤'"aˆhL( ‡†ƒ)|Èb0Leãa´Æh4™FQ”Ìc1Œ&”Äc4™Í&ãY°Îc3–ˆÉlÈe7¡¨%ý,¸B'—ÆäR€¶i=J¥²i8®J&”‰Äâ¡,žX%”‹¾#8²g+— &£YÀºm:M'"Ù¸úb;ƒ@øDCÑ @…‘O—ƒNŠãHî&Œ0²2 ¨Ì3 (¼) ؾ6 ƒà1 "ø–$‹B`œ.ˆ‚`Â%EÂP´1‰"X°$ŠÃž& "Š)ˆ"8¨ "˜†#ŠÂœ+@¦! t" Â@²/ ‚h²'Šàš'‹¢˜¨0‰‚¸Ð… PŽ*Š ( âÈ. âx´%‡Â„†a¨¢$ aø~"‡¡ø’‡b0hˆa n ¡ tAÐf‡Aˆ`…¡xpá¸b”‚"ÂH!‚À˜'Œ‚(¡‰Ô“6ˆ¢(Œ ˆ"(v T¡ÀZ†!PNAM…á(DR€P…¡hP!`j…¡°– ˆÃ`²1ŽÈò6ŽC`¼1Œ"¨º$ÂHš‰px! AðŽ#‡â8-‚ ”+ˆâh¾&Í"°¸÷ ƒX´0 wÔ, Ã8°. âxª&ˆ(„‡âjUp¯¡˜t†!ÈoR¬JaB!J(<h øRƒ¡H<Àø8 ØJ A;§ƒ¨0:„àø<TaXHY!PdÁ¨p‡‚M^"Ȃش/£`â.bÑÄÁ‹ 8Ö7µC@È1Žc¨üB’òD”¢èæH‰£þ @d ŠWÀž B v"ˆ˜x †J…ae8ÜApx†Â#‰¡È‚$ýðxàÁà ßâ0Š%Š`¢(‰BxÂ. ¥!,IĹ06 C`\PÓÈž0 â0¢3†¡è¦…â>Ê„!0h¨E×!d„Á¨L`>(,H/Àâ$H”aôD¸æ›B À¸‚@NÏ–Ð,@r AP/TË|‘àˆBP5áP ôêCØ4aäºàjƒð= â „ÐøL—ÃXžñº>GøÖ„ìxñ”;GøÁ#ü\Ž2†8 HÑáìK ®„XM ¡è`ä‚xia 2—@´ ‚0Z,‚h,­ˆðJ @ûüj Ä€pP:@¨È lÃÀŽ‚¸kàÚ%‚| ¨H– Æ Á¸BA¤.`ÔCØu A¸6Päps Á¸3›0¾Ãa—A˜ÖÙ,Ãpo á˜4p´ST AD-† ÈÃ|aØEŠ€ì!Åkb@/† ò‚°] g±~—–‚`S D+ÎиOxu Á¬D -„À®ÐcŽñ€6GÍ£f)h”6€ÿCp~б†8„ša€:žƒ@N á˜-K0¼ƒˆN Gh2࢈[Ga†ðŠC !l&°ŒŽÁÌsØ%`š8V ô%…@„€=aM*þŠ A-:„”ØC"º Á9„ЖBzMá@0„p’8C­”¨-…IÄyÀ;aU©0j2`ăàd AØ0àèàv ”ð/°­¼à^A3!$$® ÈÀX AT+†2”*Sàø2¨NÚŽÀ ‚N AX&æYœ6€HYYk`©ë ‚k aL,‡€Ö€s‡Ø84BøHÜ$ªhM L"…¨I ¡–w«¤‚èbA|2‡Clƒf |11€ÄB¨^ Á&n¹ÁØ?¯@ì ©PŠ ð05! ÈZÐ^ÏAS@ „‚†–Ôø …±4æ ÑÐíP¦¾è&hÍùáÀTÏA8%€´XuÈk@_ Áh4Ñ ìètè49‚áƒð~áü<\€Ôƒ8d áÀ8‡`ʃøM aØ\pn)€ €¬€jj`IÁ$ X <À ƒVh ³JP 5á`\ ‚.!0„  @`ÃF $,9 (&`Ò`zAô)¼ ‹p0dá'…‚4Aa—„ÐN Â!`ô ™p:Ad€Àˆå¤EÈ0ð–‚bLE‰‘!v Â%„p¢ Ö;ø2À” R ®Ò¶VBã h"„0ÒÉCè2Á̃pÞÌC©€@è#ˆ TÃÀ¶C®…ñÂ=ÇøÞáCTyñBÆ0ëâôrñ€9Çø¦ƒÄ*‡1<ƒal<ƒ°šàK º°/‚uyt +x"àR€è%pƒn d3~`Ü‚pfÁ 4à Fè#ÅØÙøu•aDx²b`a†¡+ʰ~¡À3æƒøt ¢ >‡¡Èq ¡¸ÍYnCjA¸8I†rˆ^—!D(dð—m`ÁhÔœpè!Dàq‚uÃÚpX jÔ/<°½áÃPP öh/ˆÑj/èуübñq§Æ„O‘h]ï\9øÐõ£ƒ…!ôO‡Pÿ8z Ál6°h9ˆ ÊDM˜Á*]Ú f h|)И‚Ry!T'B¦dÊGQ!ACT°}uðDÁL3…àžÂT ¹¸*釂0%"‚p#p-™,à5x7)`/‚Ð$°ð©@"'P$‚ˆ+€8¸5ƒH7‚¡«ð€°ùqÙ·°$° `s@Á˜`—p“è%82ƒh΃2\ƒ8Ê´€%и¬3Ø ­rØx(1´ˆ Ú•™Ò“èð+§(<4Ð?.X@ƒ <Ð6ƒˆ8ƒ 4ƒ(- ¨*‚à3 -(ð0ƒP.ô>ƒ (É à6à0ƒ18<07Ð3ƒx;ƒ0û86 Ô€Òƒ`-ž‘†x®ø‚  #A8%à‚@C©f–¸CA°á31¯!¡ š¨ €Ðà 9Ù¯8 ±X°¼_6úÝØ0$H3ð2„0?8H„`L@K샀4ƒÄŽ.ŽÈ.Ñ 8.‚Ð/¨*ð$ˆ2@ð‹™û€PC@è ÐØˆÐóX%EX&ð! ¨hëXôˆàh)Ø­ •¢¢.&Áè"0¨I—ž*£à)p‚j×+X‚!jÒ ° €Ðd­P @‚1 ƒÀG‚°3:„x0ƒ>‚ò‹%à:•à-CY £ 9ŸÇ£0 :^³²‘4Aƒ-ƒÙƒØ˜6XY¸ŠÄºEƒ¸=]0~øq8j'†CŠCá†*…㋆‹„pT†Ð% E›’¨Ž‚h3ˆ"ƒ H쀾L ‚Ø‚J>p Ál9À¤8€Ñgº ŸNlâè˜1˜%GXF oÀK-xL: ?ˆ6xABƒè>ƒà:)5èу¨7ƒˆ<;ûjˆ9@5ŒÐ2Êd(‚X…)3x&“x+Z̃ 8ƒà=&ë"„ˆ5ƒ¨CŒà:‚«L.06H)ˆE0\p8¨q8«Ü‚)w½r*†8¡(søb8¸\†ð~…¨mø]†à~¢Ñ°†Cݸi‡¨Q…èmƒPC‘ñ*0ƒp*H%ƒ/Ø)‚•â‚èà‡HÃi>‚€EH)è#D7ƒT‚ódè⥔ÉÛ@&Ÿ(-‚€0/@.@,¨0˜,1U•èh)´¤h¤°›`¹Ã Æ€€Ø F@ «ÆC[šs 1Y¥›Y iµÄ/@!‚ZT«h„ˆDðE¸7Ð2X2‚È1Ù‚»Â..À/‚èà ð4YnÈ­Šy¯€VÐu\ˆSR¿Ø!•à¸9cŒ¨"Ú,3EJ¡XC§ ø0Ä¡º 0+Eä ¨Õˆ!™8'p‚P³°`Î>:F$@JÀ š` Z=á (‚è24€+¸(p‚7p"ƒ ‚ˆ:ø)ƒÂºƒH»ƒ¸$ú¤Âñ©A¨|ú²Ð=ƒø:¾Îñ•˜h/Ý܃r[Y¸VHo†káÑ †Ø|øn`hŸÒ3Ü k‡èCèg‚(.ò³è 7ˆ%( 0€‚½àœ¬3E ¢H€è˜€Ê=€µñ΀ÛZZ8ºPÉHÌêµðØÀ b@4(‚Ð6OP_ƒˆI‚`9ÈAKØK„<„A¸Aƒ˜6Á¾à:ƒ :®Yx%¨42Œ!@ׂà-‚È*‚˜*ª¨òY†‚Ð-@0 -ƒ8ƒBWH:]xp:„M~(1hAØ>8Q†¥‡øTX|…Èl‡õ"[‡†Z)r'†e†B)ࢅ˜kèS(u„ø_@Z†} †š…†¨ž…Øm‡àRp"ðT‚€Öp0ªè,§@)|—1{õ»°è#Ø&¨‚s()'‚ñW‚Ð S¹%ƒ(#[ð5AZ‚Y‚$À2³t ‚"1Ñz«€1¼D .»ûP6‚°+‚Ä¡–ã3(#G#/ûJ‚br$@&føº¾´eZŒ3íÖIµD BÊÈIPL]S‚Œ3ôŠ—¨ÉÔ¦YcJ.T1-ÈCk0¹|‚ÆŽ˜=9„ ;Ô9ƒ°?²¸?x:ƒØ7ƒ²zk²ƒ»µƒÈ>²¸>x9ƒÔD¨6ÄØ6ÎGà4ƒ€< È;ƒ=´Ó#jz]…ƒ07‚ð2)[`%€)#è'ø!‚~wªA~ #¨“CÅÙd›[ É£ƒF٣˟F„eÈÖF\i ¸:Q¯)® Ë_n›-9‚3 ;PþFƒ€5ƒ‚èÚ°0è)Óî›Ð+‚è/Ð0ƒX5(7Xƒǃc= 8ƒkbÂT~©°/·Ía‰š\'#ï2=h*8a (ˆaèw"{Ý¢¨L€h`A…*wƒóSƒi9„!ð?Nø>*8¥ëžÿà-8€"¹ø"ŒZ •£p ÊÞÖb(¤«ÊääFŠC1©§ˆ pè<æXᘺñ ¸øtÆð)Y¨!àBƒpKƒø7 @€Jø9Û7„8;˜?°8È7h9ˆ7¥ð4œV¦†éVUeì<è1ŒÞçbùƒŠüǸ/ðúƒ6êØ9(5ˆF`Wøj°… a[† J*†0tðZÆQXw…XeY†|€h‡¸X†xz…Pd`R ueÈu`#ŽPX†€z…ØlÀbŠ(WHu¨X`:„€O‚"]4è& ):ï #‚áò&°%Ø%Ø!™§ +ƒ‚h"‚ÃT‚ø"_§H-ç@/š¬lh' •ªH',°+—¸&/eGð.Ð"´Œ†”ì¦]ˆ#¿Y\æÀ$˜$H$‚`#"¤Ç½Ô(3@Žî–ée0]gÂ^¢Xˆhˆh‘Ké!—ZbØ|>¢ˆ'ÆHÎóoñ¹G†ƒQ‹åw„;ƒÀäÈDÀ@;ƒàB¸>ƒ°4ƒ_ÈAê¨?ƒ;퉃Ð5v=È2ƒP;/¥ŠƒtMƒ@;²Òƒ°0ƒ?ì89Œâöƒ ú(Ð)‘ fìZrû6t‚8+˜I:ŽæŽ~}IÈH`-€ühm ï9£ˆ|<%‡a°Øˆ8†C"Ðh@ ‰¡Ñ€<$ „B\|X! ÂÑÉXœZ6 æRé˜Þn;‹†ÂñP¾\)ËÅ2Ù„°b2˜ 3‰°Öt#ÉBñ`ÔF$âPý\@ ˆbÁh¬f6 E£H ^*Œ…bá½¼t* Ä¢±¨œP3 †bQ†KVDñq8r6 Bá¡T. „ÂÁPÎÏv½‡„c à„`ŒóÃHH´6!ƒ¢` \> ‡‚áz°¬~&‰ÆÅ@ܪ(‚˜°vbÍC²Qø‚ND ŠÐüþ9#Ÿ‹æpä†s "aixP,0Š¥ñ”!„ä± ¸ `< —F™Ô4¥8 ) âÀ¦.  ¢"â`€" â(À>‰àð ÃXt!‹¡`|+AР¢hH‰AZ! |aà<HH^Ù È:ƒaT…€ÀD‚Á^„„ÌðX „asƒ¡ `…A B‡`ú÷)†0X!øHDHà2èÎGÃQ;¤ˆú;‘¨Ø@C`î6 ÃxÐ3CÄ3 ãÂ. ¢Ø²- ¢À´2 ¢ðÖ1ŒC¾/ ¢x 6‹£Ø. bš* ‚P¬+ cX¾1¤Ñ4d&ñôS—ÇIdgŸfAЗÇ)þY‡ù<]œ\i‘¥a¦I–¡&Xš„qVe‘¶©T™aPe[†Q$V¤QRf‘9–J•†Ádež…yŒuʼn’5d8’0Š¢PÀ(ÂÀš!‹¸•S¢Zš'‰"xÂ+‰ؤ# â8œ. Â@¼&ˆ‚¸Œ'‹‚œ-ˆ¢ˆÄ( ø¢!Š‚Š'‡â˜‡!èpÂ~%äbðŽ% b Ž+áЄ‡Â0ˆðˆŠ‹"h˜, ØPŠ$¡àz+c¹þtaàh‡Á¸t†! h!ZÀ…ax\ÁxR¨PH½8b¡¸vp!j,ÊØÁXL„áDœˆHü¯.…!(D ‚@š7 <$8ú?CñE¤ ?^ãÙ?Žƒá;„ì=#ð? £ô3σ Ò:Œ#8ì1 ÀÇç‹ã(è/ŒÃ°À3ŽbøÈ8 bøÞ, #x´0 âèÆ7‹ƒ Î*ü¢˜®+ b†S ˆµ@’&‹Pž,þaP%ÀˆÂ7@Ø‚°b è   Ÿb2 Èø&"`ˆ„òÀÊDf@Š" Aì$X‚E A*\-7ÐCg Áå݉pºCš |+†&ÔJ‚ Á¸8‡êðe`ø"0` 8%åZä#sN@kÁØ2 æ0ƒà` Ð'à¼7ÀL A£yŠæX °L!(äY@Q R¸"äÐnP<€¼ƒz X7+À°‹‚€4A81¦T‰8L° ” Ê ''€!`…¼°q¢SG Œ‚PÁ.À€\C@@ â!ÁtCàM Bfc 7î"x~-A´„ö A˜r ¬-‚FA 'Á&…ÀrC$ÁJ3„ð¶BøU ah&0¢! ¡*àxCbc D &‚Àl@1 œ@Dˆø.`”ƒà4 Éà`(Á05àp€6Ái @a,ôvÁh@¸À9!ˆª_òÔ%€J %|ªƒ€ÃhfÁ°1ˆ0Þ“pmè7ˆ€ìr aü8<0ÖLƒ0c ¡„ï…°¸¸YQåµ´£‚€V at2†ÀµYç¸P P%„ ®Yðh b,\Š1Ž*Ÿßƒ| 1È?ÅÐÜ«ty !h5ø B R •¸2Ä0¢L ¡&À|‚Ô> fĵªø@‰Ñ‚"ÄBˆcˆF2à·Ðf$,F€"Ä+†Î‚³ A\)¢‚øOÁU †@¢øBad% ®‚H\ ,0P‚ƒ ÁH2à•Â0R $Ð6ŠÁð:)¡„p¢‚Tih!€¬8S¯Ü#„œšþ ¡"„éÎÙ¨@à1N€¼ËÂp4™n ²ƒFÖ \0-mĘ“&Ô Ax13ÕÂlÍZ37€´ãcÖ (,Žl·™ÄÁ —‹@Ë$²Ýxg a€@‡Pì"Càáð@0ôÝ({áÜ=°àƒÜJ±(<‡äÃps!6<Ð΂èaz8…ÀÄBðcÑ!€:eðäƒn €5…p¸B°_ Áh0†°±B Y Š—О@G¡%âœB(Mj¡C ¡0•zB@EhÀ܃€aQ²¤)>Ùh¾åX" %y6ÀdŠlBÁ‘í)Ç̰V ‚±¸Ðä# = aˆ4‡p«¤ò !H/vOvä? Á›@ìúÂØc_Á, ¶ T Áq†…à¨ÀSQAˆ0á Èƒ _°€= @H bè+ @”CŒ²?À|0F X%Á ÝÌCHap ƒ0’Q˜$ ´ȬbP! Gh >)·FFÜÙÒ+'€˜]LÊ£VA†4¸GÄvp €è‚ | AØT`ü6qÜÂ(ŠaTLPø*C°‡`¼‡`dDJ ¢P ± |/¡4ƒàž ÁàJ "ÿ°¨B@Q®A„/W°–ÐL ð(ànƒ0Ál`š A˜K-A $ N Aé¯~J£‚6ÈÖORP9'a*:À€®Ò¥ÑÀvô’H …50 jŒðZe%ÆŒpfB¡€!Mæt ÀЄ8™‘G#j8ðiG͈³±©v5Ÿ Æ£™¤Ìi0˜Le²Ñh¨X-”Ê¥ò™PÀU+›ŒfcYxÄ`(–K$âÉ@žU$“'dÃZ"¼\0ÝJv#ÕzÜ©X®”ªÉ²‰S²P)¦AVÏD¨˜¨²éœa"TŒ”R™šT4Òë6âmtäN¯\©µÛ‰,¶m"U ´=‰ `¢ÔŒõcÔ‘Æ–‡¡ù,Ž>(” †á8ÂY-š ¤’ØìŠYÊ¥Á¾R3˜ˆe‚y¨O$ÊDrÙXŠS&LB9t~F-äÁèø¤>F¹Q¹(¨= ”‡¤òÀø|MÃòQ(„H$’ d‚1h M+ †2‘\ÊR*ÈÝaáœ"j†XZ!hZ…a€^†A|…á¨b†Áp†áК& ¡Ü6`^…8B„AD„@‘hL„,eEaðphÚAãÐö8ØØ6Ž#@Ö6ŒcPÒ. C(¶0 ¢¨¼2‹ðÌ. ÃXº0 âàÀ7 BøÚ+‹Ã`´/xâ,‹Ãp®-⸸6ŠÂÐÔ+ cPªÐŠó¦+Œ[ð!ˆÂ0xˆ!¸xÐx!ØhAÈ~!‡¢” ˆ¢pˆ$ ÂŽ$‡Â(‚ÁÈ\…A0UáBF¡$pƒ è> ƒA2 „ Ð2€ØD%š`àNÁDp„!Z„P8j!âxĈx€ bx˜+6âØŠ" ˜ž) ¢ØÆ1 ƒ°è> #Ò(‰Bx~°Pf…ႇÔL…a`W¡˜k‹aDƒñ¥šƒÐ6 ƒa8ÖÀTáPˆ†#H:€ø€>àÔ Âp(€˜B‚`ðV ƒáXFAPdax6 … 0‚€ 2 ÀÐ" kà¸<Àð {2zø( ‚ Ø@†á¸°ú‰Aø„€& „@¸:FÀPá`,‡"‰8¥™P„ù^gˆÂá.øîF–ƒ¡Z$al+ x\ !Àn ãHÎ@H¨0â7 #€æ;âðÂ:‰B8¢"‰ãh! Á†+a¨–"8D‡Á T`v„A°<†Pl „¡•–äÁ.À¨:Ÿ2„à˜>ƒ_Ø,H€hµœ ´f d‚°<ÓÀà%àŒƒ<8n¼0Þ‚Øv á„=Ä CphÌ4 0ð { dP5:à b ap.ööÞÂxV 8.… ¦B¸Z ¡d.…ПBxT !L,ò€Bàw âlXŒ!Ü)íƒH}‰Ñx9„ôgCu ‘p7Ä€°Â4T&,FÐcŒO‹ñÐ(†éÃy ¡–=E È"xa‘$-FØãPH ¡ž$ExÓ¢°hˆ‘F2„඘bޱ(€ ø*”®`X ¡:!@¤^xB4$(†0 "A a ð„Kad(„sžÍØD5 0 lÂz±QÁ'ƒÀˆÂ9 ìðr<A!„@®C0p¡l0†Èò‚ ê,°®CpX Aˆ „p²ðZá%) z„€*€Ä‚àb  )€±¨ T$‰•‰Í`ôh ‘()”¨@>ÈA! „«¤\ލp®€{ áÀ:†€Úƒ"O aœ3…ПS:Á0" ˜2© €%à”ƒM a”(PÐgÚzOái>'°¬›gxk5¢)X¤‰øZ0(ƒ°†'@B`ì ƒ@r¥Á¨>Ø1‰c@>]!!…‚} ¡"„`‚Â;P‚EJ&p™RÕÁdËf,à: ‘lRæXÛ!H¸TAˆ= Jl'NÊЛˆN Á!+.ª¨\AÀ< ò Œøc á'„PtØ|çcH K h 8.@´‚€L ã¶à€ ÀF°(àœÀP@à. Ð7°là:h… , B@ ü >"«IÀL€1‰A80¥Ò ‚ÖØ›€H &ÆÀ˜Xä 5à*Ý@›ZnU®­P:‚ ?ˆ“›àœ AP4X€Œ €BZS)va€>‰h3˜­âdW Ðî"…ÀJ "TGŠ‘Œ#Ç‚Ìf‡± /AH: `Ì  Î ”¢ E „”S@ê&¡èx'áv0r‚˜.z@‰Ðvˆ.8#@õ– 6 {ãÕ ¡õ8çä @ºÅk;Y‚'ä Ø(º‚þ‚6þÀà! , =QX@£‚«wµ@Z-Ú™‚`[xx ¡|9†Pȃ0eA¨6 Ð„ m ¢8;a"CXŽDdÀÀ‚úð L(Ih‚xZ^æt)…`£ŒR>¡P&…Â|ÄXœ¢pZŽN0‡Xœã|O‹±Ì)F êâæHŠÑ¦$Å ÛœlM ¡ÁËGœ.â†F‰Øü$… Ùܘ¶Œ¡"D0¡0T„ˆ±â.Iˆ™,$…`Ô‚¼gq (*è[˜AHPŠB4Ϊ¡P …¼ [Ual&œ”ØF´A`|ÀDîáÅ.ð¤AÐE]aD Îàƒ×Aø<`òt d¨Bàh¼@ ˜ŽB \ fp1WCZ˜g ÁH5„ð¦ÐB УÂQøFb ȃ4 4ð+µ@¤‚tN XØ0¾`¼± d‰•¨*0Rš"ívµÝù_AAtdÇÁ, ¡t/ Ð`d !¼2†ÒcP‚²…¦ Õ8Q«5?ý‚W ¡x#ÐÀ¨Î‰àÖ `´ … ठÀÐ €ªô@° Àœ  Ê @¢¯@’ `~€ž@€àj4Ë ö@r X @j‡b]‹D |O쀪šÀ£/äàš€Š o ¥*ÀL€DEexP@TçæX‹\Y`2 fY®%šX¬gÊzW@Tj€^ÀL@jÏ vàÊ £ò ÀØ€»àž àÆ €œ  À Øþ î€ú$ÀÂì@¼À„œ`‚ Å>,`H[ˆY Fd NEÀXF\`: ¦€d à6 ØÁÀà j 1D à,À¢€P @& ¬2 ”€N ñh €*à’àZàP€HÅ'úÅŽà&Ö`"p`FÞ@0Ç*n tÆ€'Œ‚ ‚M¤F€¤=@¦à˜@` H{¬ª`&ÄçôaRÁ<Áá1A†"ÁátÁ Àâb!  x è ´ ¬ `ø¡Á ¡Lá`ÖNxa:­( `È š æÀ„ àf ˜‚@„€P`B@n Rªd¬Z€€Z‚ ZàL,ÀfØ×¨@4†®Yà<P¬…—*ö×àH@:­*êzØ(&`0§FȆP-v­‚ÑàΈ@Ü €¬ âBHr`Ì €ð `ÂÀÖ "„A$!á. €¾¨v @º `Ì–^ˆ€¢ @´ `¤™€¨ ЊbL ® ¡4a&ê!2Á¶Áb!$¡¤N¡”aLa-ÁA¢afA2.^ÁÊsLATá˜0¡6!JA&á¬áj!*³|á¼!n²á,a¶al€æAH º @†ààŒ  šÃ|^€† `°`˜ýÀ¤ ãÆ @Œëàn ” jï€h¤€^ tp \Àjøfö`rj <À| Žø L À°!ÀΡ4 àÌà®   Ð`À @Ì ïF š È6œ ŒÀ¶Sï\@²‚ êFòV检Tç´‚f¤÷ÀVä(£`f¢jPj'´E„jŠbYÀ<rÌØ+ò\F`Bdâ â  Î À¾ Î €º‰`º  ¶ àÐO@Æà ¾   @Š @¬<ࢥ谀§ ¬T€¸ Ž @” @ÌôÀÒ À¨ – pÞ À š ãä `ˆ ¨àŽ Î „~ @l`”õ€“VÀp˜¥&쀎 õS@—Q3âšÀž©¸œ  S€¤@Œ €|€pÓ@T[Ï–@V±YæìXŒ®ÊÀ2°•) :‚ >·æšd XW€hjò€ºÀ² Ê¡F Ø! ² ‡†@âàü¡`Ü «G@¢  ´¹ ¤¼`˜ åP¤ pWŠPqÅl`L`n'È àC`< ØÀp 4‘8 Ê d  1,`¡@›€¤ Qg R À&@¬ V €, ¢TgÒDæ¦Ó…ª~(È 7ñª(’%,hÇfÞn,z€*@BÀf@‘XÀˆ©ÍM¥˜ *à@Ê BÇñW Ö àþ–úÀòhÁ"ø‘à¶!< ,Ö‡$à¢gFçL@âV @òº@´ á,Ÿ¡& ÀÊ@x ü<@´ x \yem&@PDVd^%œ pà:, ‚GÐÆÌÀ(X±´æÈ$YÀ*e†Œà*f-Œ,°Z€=)—¯+¤§Mv†êX€8X B·ËøXVÍ)Šj(`®ˆ`Àß€È ÔZ @² €¼ 2ò Á  Ê@î !1þ  º@È àÚ À­O$ ¬ IZ TD 5ø©à¼ `ª ÀüaL\Da¼­Mêð `¹–À©¤Bî¸ê6ÃŽ Šþ ðl €˜ J :  €¹Y€± ©€œb ’Àt d@•%pYH€Œ `Â^àÈŠ@Ì  ´ ƒê ôr @Ž oyûIÊË*Q€ˆ°äÀZ{°}fEL”fNY0œ´ÉŪ¿÷®ÀE´z’`Œjü k´!4Á a†áP!ÌAˆ¡XAÌr¡KŠ¡Ax»áC_!ŸæŠ Æ•hàp ÀÆ n3fàr J€ì z@@@΀p `2€½eÀ¸à^  .€§h±R@¢ R  *@©³€±f{<® [´,0`T`L*T…~Ö HÇ 9llˆQ–mà# #k6¾ 0&ÀÇ`.lq´2€÷ feäH€fÌTDÀ4·"0‚`haÀ  áàÒ¡E“aL0áza@ÖP`tW €¸9AÀž á£Á 8¡ Qu ê@€ †ª JdåÆ €jlR0Œ­–‡àËq'¨'—£'²fe N6ÆÈk›”€:|«x€¶  £`ͤ`²>à¬ÄÑÏËÍ@Ú!àÛ.ÀØL Ä è¤ ÅQ—@Œ eB Ë Ú e8 @‚À¼ã< UA€Æ]µMb>J K @sŽUf  VIX¯à¼  ¥î`¢ Î `¢  Äá>ð ¾æìÎ €’ À°²ë6 ;Ï àdA«ßbàNè#¨€Gº«øËˆš‰*ôÄ ^DjDàK]`bœ`ž @̇4¡ÚAêáº!þAôáÉ÷aÀþÁîáªáþÒáŠáü®áhAÖ¡‚ò0€¹"À†€` @æ ” Fd  <@®@d Ô À30{7þF† À( ±µ´€X p°°ª‚¢´ž±ˆX#‰ƒAÁP. …!0°v> ‚ààˆX Â!PhL& ‡¡PÐL*‘A±B' F¥bY8`.ƒb(€)ɦS±Ý$¯=¦–ˆeðø›^“+ÂéµJ$b’Ș^f M"á‰hH-&‹d˜ÐôF#‡ÃÂ฀X$‹FÄpÄfH‹Ç¢!@à8%# À„^ ‚ááXX8( !š,tH $bhèŒ,MÄpè”2Câ}ð˜0†øa€Ø|/½ÓJ¡Éb. c(¤L!‡Cáðèx’#ÑSÄÑbE”EÉ&U˜¤™`d“E™—4% rh”eɪQ—¦¡2Z™D©TaÅaˆB%hðF“â`¾1¸¬ŠB`„(‰¸˜&‡H„ B t$ˆ!àˆôØr ‡Á°ˆ"pzŠ(v$ˆØ–$‡Â€¤ÒAЊ-$qb;’æ^ež¤)LbâÐî¢øp# aÀ‚/‡B¼#ˆÂÀ¸%ŠC’&‹â(”0ˆBP¼"ãt hÄ' ˜' âP¢-ˆÂ@¤UuPžPv „/Š‚À¬( ¡ÈZ!Jƒ˜˜6(ð: ƒÁ:ð>ƒëpH"è¾: ÃPÚ- x¾1Ž£0Î; £Hê2 ãpÂ0"¶^% âˆx!‰aÈx$‡àž‡¢xt‰¡à€*b°!‰7ˆ 4 "¨Ê) Ã6/ /€€#Š•8¢‡ÂXh ¨t(ˆ  ˆ¢@g¤…¡x†Ð]À…Á¨€âFž)obÈ”&‹Bh¢,‚P¦‚¸„!‹B@ž"ÔáÖäðkÆö@à6ƒM¸4 uí¿Z àLƒ¡;¦„!`…ÐVÊŠƒA@“…ÙtnÆ!Ò™Çþkž§ùÂ|ç1ôGéþwÇÿ«òŸçùÛòŸA@X𣠯;"˜ÖB #Ò+Œ¢¨|)„àZ‚€(¡Lp¢ÁPà´*`V hXÀ¸,ÁP´ApU ¨*PRBHW`ªp, à<€€±p@Nh d @8ŒXÀ|@4L©0`D˜ "À¶$@jâ8P è,`¸(pV€1 Ð‚x AP^¡D=Ñ)D žâRŒ'è¢ð@‰!| ¸}à˜-‚`NAH1 …X1à” Ô A¡)J„²åÀ5@Ѓpn B§ à˜„PR ‚3à”2 Z€àªV4AXr¤Š“ŽïùÇH 2t ƒ·¡‚SšŽ!çØL At‚Pd ;œ‚ÀR @)à:XE !%`˜ÐL>m/…0¦ÿ°h Al5…À²àVap)ˆ€ØÄ`s ¡ú‡ ÄCX` a¨0ÔÃf Á€1…€Ú-…ÐÞàŒ‘²=EøÔ¢øhQl2DzÃØWŒÑò+iÀ«càW ñþ“GÐ\‚ +pÖCµ ‚l=ˆÁLĘ­B`Wˆ!.+Ä`£bTR‹¡:)˜˜b¼O ñ†'…€ÈÜg ¡†6…xÆâ¨`a(°fB $•XX@V@È"0zH? Fƒð~è; ôP~‚@Ha9V„ ~XGaE¢„ðšB˜_¢$VˆaN5ÅÈØâ¼h(F0eâL1q*CP‹ a€?„p®\g Á()À„# C ¡#ðŒƒG Á˜%…Â׃• a0(¯@œ‚Qó a0/^ À¥ AØ3†Ð¼©Â”²3 ذL„äæ(Ð"d@؃0æÍC i aÁ‡`Ð0Æ l+ ŠÁ­)À¸ÅC4 Ù04àÀ ƒlA«õþ„ÀÂxj l9³ â(m !x1]ö´‚¨<A=·„hTƒJÀèÈ0jcÁ€(Àœ‚°K1A<Å`˜@T 2¸1Àà’ÃM Al#…®XXmU´žñ€2¬8`ð(7Ú(»°Fæ’ ŒðF 8(Ï#…`à ÅðÝ£P}‹ÑÀ?ÆèÃuñ–;ÇøÐz£Pyñ¥­Æ›ìϰl½±¦;‡øT ¡¼D‡PüB¨b“a$‚ð†‹ ‚`pÀø4à|¨¸*à°.P^À¹‚…@( B” ;Ä$`NÀĦwŽÜp4@±P$DxÅÃPH@°!$  ,@€á X‚]¡è8S4為 Â0N NGˆh>Áp°Áœ„Pn5DN‹±(è~bè<ˆñt Á¸€  2ðR(+ €œpD BÑ>Áh1 ÐP|!˜.àž¢˜C À´%àdÃ`7!0 0Ð `C ˆ D X ,•€°¨Ë [+ÀÈ$%D˰HGñ½àLÙxˆÁB8 „ €4@À2à‚ p h>1®âÀNP&À´#( ÁH*‡–u¹àB>Ö A"Û­g´ý› !8'†0¦já”.ˆ Ô„ ¡¨/ ÎC c aô4PðC@Oãdlñ 4‡Ñã„bÖ0ÆHá#j‹‘„8 ÈÂÀf‡ÀW†x}°jøQ†Huh0'‚€/'è50È>°GƒÀC„è:XP˜Bà8MG<ƒøEIà:„F„xN„pK…I<†TØi…pcñ7HK¨chA„X ³%¯X #%‚Ph%¢È"*ë),°#ù­¬¨)”È!”à$P#‚©»”h#x-XB„XS†¢ÛÈUX{(b‡hD…`‰å‚ð8x*ƒ0D.(@‚8,ƒÂvX'‚@*¸‚(/ð"ƒ"H1‚œP P8x  ˜˜x#Ìéè‚ $‚P*‚h&‚P$0$‚‚1¼`!‚'±)À,¯j{‚h5‚È-˜0‚à?ƒ@0P9ƒ@F°ÀKØ6˜@ÈWV(^^…€Z^†Xb0lØ[†_˜_è\X\o€`‡0X† v¸j‡øD8_@.¡ÉɈ-H0è/X2ƒ€A`>p3ÀEð5ÑŸƒÁ–À/™ø-ˆ-)È7ƒX9„B„D„ÐWØW8X(nˆcÐL…˜aèK0#Ð.B9ºáÿ@+-0Ñ¥èÑ€À&Í{¬€"ÒØ.¸x­"‚(,ø5ƒÐP„Ð[O†w…(c‡ H…˜j+ƒ((Bà#‚ð!81¬ 3ø%ƒI£ƒ8$«ø(2c%ð/‚"ƒ@#‚\¾‚X1œ0š3tN¶ 4Ó 8˜+ƒ‰¢Rʰ¾‚ V8 )¥':p‰ ”Ÿ¸ ˜¹°PÆ$bÀ'‚p<Ǹ=ƒp6Ø8:À*9ƒ)‚Ð2E0-x+'h&‚8Bè9c(‚(è!¢Ñ.¨5Ð/ƒ{#È3ƒH@€;:Ð<ƒ`8Ylƒ:Ñp‚™Nœx ‚˜!S*”țѴDˆ%šØ'À+3Üð+œ,Bù}*±mà+‚¹ Ø4‚Ð/Ð.¨%‚iÆÉ ˜ò8ÙÖ ‹Î lžÉŒAk¨´ šy¯ˆC…0´†øT˜Upz…hh‡ÈY˜}… kà[È̯Øo‡ð_‡…ˆg˜*(SOƒ°@ØÈDƒ Bx‚h4·È7 !ƒ@è0€à¸ %€È‚x#€ðá(‚p x/Èø z h(7Ž@)˜Í(‚@ 0€°yÐÍ8"ˆÔ4Ü ¸“¸²%€p—{ˆx €Ãˆ"€ (7ùÞø²V£h‚-À#ƒ8‚5Ð' (0C‚à<„Ð9XUH@…5 Qd0PP@ß„ë‘àP2@$(p‚h=‚x. ÈI@#„8È8€%„2€`-px,P:@8p‚Q“Ø €ºþ4˜Žšcòc¸ˆè¼À¡ z€è!<¸ ÚùÜáH˜“ÖP!ð:/@% ˜‚8X"°p bì¬h#‚ˆ%P(@ Ý5.µ6 „$ªwÕç‚ð(1Ù„X6ƒMà5…D„ VÈJ(DèXÈKXPP[…ˆ_`P ZQ…ÀX†]àk…˜\`[˜c`[`ƒè5’¨.(2ÎÈ.Bù΂0÷hú/>¦ø&‚¢÷¯mƒó$‚pp.ÄŒE +.RÙþ^0+‚Åä‚à3‚È.Z*ŠØX/ ÄX1‚iN€J XƒË;ÀÝŠ ׯáà` íÑ̃@BƒÈLÈKàP†tذwHe€U†hy`g‡°X|…„¬˜j‡ØRÕ0-ˆOp°?(Ø=ˆ1Ø<ø/¨7X#h‚Ð0èà °1L(9àƒÈ3õ 6Ì(5€Èƒ ˆ-€¸¸ƒ øˆ b @£€¡f 忍‘¸sX : ‹€¸–€ x Wt _v<ÈÛÍËÄæähã˜ÖÓo¨(`‚Ø0Ð:‚Ð8p7„@Qƒ<óƒèJ 6„0Tƒ=ä3„ ‚ÐDáhDˆ(„‚K-„à‚°LX'e(#82>>P#ƒð 4ЖZÐ'à‚P,~Èç0(ŒX€°PäZº@8¨ (‰èŒO ¸‰€ÿª{0¢0d[Œ@ÐÙ x ¨”`ñ0¦àP‰1pP#$”¸$DŒ$Zì”À!Ý©Ì.±Là!Ä‚ LÅçƒP+‚ AA@Gƒè9„X8F¨`IƒãžHE¸?ƒØNƒð?Z°…XSY…p_¨XèMH¾¨1ƒÂ݆È,ƒ¹‚ɱê+—|NI@/ð6¾·rÈ/‚ˆ&‚…0D¤$=„è8%í»ƒx6ƒ¸:ØD„D„ÀF„ÈW„xP…˜O˜`ˆå–&• IJ¡ „X#JC±ùXx8+Çå1Ðàž?B‡ÄÒ ô¢@‘ˆc1ùl@ äri™‚O2RK6úepá5#G4ZàäŠSIEq¨Àr/Œx´H+ÄÃAH°’9”ä"Ldœ5Ǥ2ÙšO "!dH/,E0ؘ„„´0Ìp’ÓDb2DH/ŽÇ"€øŒ>ðèd8! ‡Ä!Àø>"¬ ÎFc2äoDÏ(sÁÕq9žMÙ€Æk)”L$rYl~D,eØø¨9ÇØÂ‰XÔ\/Í&Ãá¬ãÙ8gØôˆ= ‡#©´¶_3JåòI8ºI& ÅX´e*– Bp¨0‰"ˆ¨!‰˜v Šh° ‚hh‰á˜r,8bêŒ-ˆ"8Âû"¸¶6‹Âøä0Œ£„L3 è¤#‰"l„ÁT¡ : „ Ó: L¨4ƒ`ØHÌèD©¡˜v$ŒCYPå)’MFé>_œÅ„tF!ÖRÇqQ1”æAß3åY”xeI¤2Å`Ô9c@Ä9Ž‚àä9"#Ðb(AH”5ÁðʇC<á€B‚@ôˆ 8Ðx:!¸Ô ­À¸d/¡p´ …¢x)Ba(~ „aÀ(„À¸= ¸0‚ ¨6 ‚ì˜8ƒ@ØJ‚€ð h Àˆ* `È" @® !„@°6 ¡`.àõf…aøF a\%¡À¨‡‚òÐ:‰ƒ91İ”.‘B¤A‡â`öˆƒØf/!h¢IBa‰dXR$HŒB¯DA„!Èê†C ;á@ž·Èl*a€—† Ta`laÅÔ…ØŠˆ"€` ÐR„!n‚á RªaÀF†¡:…!F„áX\a8L¡Jš™âPr øj–†àj I0’†âØŽ ‰áð^"‡á`‚³ˆè‚ø†âH‚!Åâ!Üè˜!‚XŒ" â@”,>âøª,Œqö3Œ$Þ1Âàª6 "ÐÌ(ŠCp§á‹"±4Œdxæ7ÃØúN£ñ$;ŽPä5ã`ÆBbøú2‹c°Ä- bè¸2 ¸Èþö¨Â.Œø¼2‹ãÖ,‹"à´'ýa4(„ðˆBI… çÄ/„ð²ƒi A¬;‡0ô!DŠBL Ñ )ˆ{D/†P¸DnÐxÂx<,æWåB La +’BBü+mð$`nê‚ fBQ á*Æ ‰HA ñŒDÀ¿ ñP+àÖK 7èDƒj Ah7¨!àhA¸: €èƒ°V Að-<ƒÐŒ A¡x¡\¾S(Ð"¥ä1µ1 °¡Q…¢)‚ÀVap+„€d  ˆÌÀ.ÌÁŸ42x®ÀqÈi D?‡áØŽz(=ÁàìCØk áÈ17|C0T}D+†¢l ˆ8 ÎÃPn¡¸9‡ÐØ&Ðoá¸9pòÏ ‚'i#ÛBHO a0˜…¦B¸\ ¡h/ °ŸP[ áL.0šøL !|%À„Å !´,…°Ì‚l al9†0΃4 ¸;†€Ú@k ³¨ûP’B) ¬Ô„(Gàd ôx‘ð# q#‚\ 5 d8‡$Þ"HÊBÐl ¡r7DÈ»Bt^Ž:°8Dн"l^*,ÆÈr£4‰ašD€ÇšÂŒ2†òß0€ ¡Ø;ƒ`²ÁHI `!† FÀ#AØÐÀ˜\ È2f€Ð6 l†p2 C!\ ‚ÀšÁ8H€œ! Hˆ$àL‚@0€Àêým00¹a\%Æ€— .-Ð`h­p$ÕÂ< +!@Ð@pB AðÀé¡3^Á3 À¨…pLáÁ , ·˜.°@A(4 `¼)‰Níó„‡0FC¸ QØ ;(pöʃ`¡4ƒÐÞ Ax]¼ ƒ¤ ø_ \0 ªÂR ä|-„0¦qB`@ì&Rðpï˜'!àˆ½!øÐxA'‰zPP [C0‚Ðg•A¨-`ôƒˆ°Màô'¹P”ÈS¡(„PŒÂXO È&°]AˆN Ad#„¬Ö‚Ž€÷C¹—0ÁøE$9" 0W ÁOp¸"Cm!´1Ì öÂhMa`¦@[>!À,…àöC „ !”EÌ#Ci!·Z†ÀÀà [¡€)0¸¨] ÁÜ0 îBøi Áƒj-´BÌõ H*… œÂxF !c:…°”S At*¾ÂSèB$M AD-…´$P  ¶ÃO á8%  ÂÐQA8&ƒ`ŽÁ¨> ÀƒpKAp?‹Áƒ¨L‚A! Ì„gàð$B ‘¦„øÇ¢d`‡Q(0CpŠA„6ˆ0š˜?`Ô! t ˆ<Là ’h<1xþRÁ¨E ¨-£ð°A J€BÁ*`ĉP„Å@T "¤.…¡ƒO¡Ò’ As`¦ hà2¤è §ÆŒ† Á㸠‚@?‡Ñ$}–Aì@K1#à6èð‡—pÃÁ·¡Œ50ƒµ"a¨7‡ ÚÃéß!°8ˆÔCù´Áä? ô ƒí#t1Pšƒu ”02I Òtg§ A|8…ÐÃÁ( ÁÄ/†@ã¶°e Aè3†Çjƒ°d áꎇÊ>ÃHmcnö Ð`Î ÜDÀÊD˜ Œ@N €Êñ€Œ0úÀ` Àn I”Þ`ÈØOT æ€Ôa/ æ”Fú`f\8Àx ˜,‚èéà€`H N*^°RÌ®ÌlŒÃ#`bfÀ‚±Ü@n „€¤$ ¨à€!   º`r `t`Ž V†À^ € ÆÂù|ÈP+HäÂy ‚EGÄ!ÜJ*A ãâ‚D)É’I$ÎS)žŒEÔ!´Ð}6 d²QLˆH-BÊD’)\’L0” ¦²É`ÚV*ŸÌF)œºŠ6f’áäÂU=—J”¢ºÌXBËÇs hâ^-š Æñ`´\'”‹E™hšQ.“JEÂi<ÐX.˜ÊER‘(™h1èDZiRN«K&J.š)—‹3‚Á¶[#— „’©\€Q)‰˜øt4Ž$1Ðä’DcØüi&–*'Tê BËC)šU#8ò˜a’̲Uzm='(¦‘ðÐp=Æ¢‘xèP. DˆÔ”6Æ#A¬f<ÊÁÑ9`4‰ ÈB‚ÁÊD`n‚@ŽV‹¹j1‹¤ð¦) á€h˜RàøH ø< Á6„,LEA’ŽèêIƒÙ¤`þCƒpê6‹¨¤, ¢h¬2‰Â˜Î&ŠcH +b¸¶9 cæ/Œc À2Ãβ ÒðÞ>JÃøÛ(#xöcÒ< cHò2 c¸Ê6UHáIlÌ- ☊$¡0_„ Ø4@ÀD ƒ%„@ÐN ¿€ø:„¡`…¡Å°aˆ€ˆÀŠ,ˆ"`Ò #À¬<!b ñ`2&HÜKÙ]Ž©œ&DèÀ7’¤1Nä *>Š#˜Ø¢ÐFÀËr ¡ø2‰@ÀX-ƒAÒ ã84 À¸`+áxž b`(‰Y˜’ …nf%‚¡8p Ä  : ‚@¸( ƒ@ãþ a * ƒ`ˆ"  €,‚¨ ‚Àp" à2‚ ˜¯‚@4 h@€( ‚`¨< ƒaP0† Ø@¡ h„aÀ=Àƒá8t ‚Jˆ¡(R"¡Hš „(P$ààn9¡xÈ …‚è8 ÀØZ0ƒa¨Ú†c`2Š ¨B!!ˆ´¢¸8‡ààWåˆÄ3EHòb™$yHÑ´M‚H¦‚Hb‰¸" €^aPf!·La8BáL0Z>Á€bmøf‡Á¸lÁ¨7 àx Â`AAH" ¨AÈS‚Dƒ 8DŽH ‚ðœ€k áé.ÐÌC¸\ A°+°ÈhU¡$Â"ÁÈ:ðØ!ƒÐ~‚B á!…ÀO Áì2†à øP ÁXš#PžèQ(- žB`J äÐ7@¢ù[ aT@0¬!CHZ…D†Àº!C@\a¨-ˆÌC¸b A¨*„ø’C ¡\-P¬#HW 2@6p¸B)5á,-`¸C0p á´; ì D¸Ÿи1„@žÁøQ ë *CP¡€; „@€ AÈ9@ðót9>æø„0bBTb!ˆ>Š62h°BS (FPw£<‰1xÄ@« ¸C½°šAP0À¨ƒ@L Á'@èà‚|Á¨,à̃p Á¨W@A9»„.  óA "ŠÀ®ÄMQ4[¸…‚€Z À > ð! x" :@Ò%€pÀ@±Á @„'ƒàˆå‰Ñ‡ÁÃÐŽáìEPö!ÒȆaäBì ê°„Aà@Õaè€N 9‡q )D"Yª¡ØDT± €~â98 ܃ˆY A )ª@S !´+…Ðß%ƒ€[ ¡Ì-† æC w á˜;Ѓ0máœ6ÀÎÃØc Áè0†pê£C¢¡uGàÊLn ÁŒ5…°ÀÂà`!|)P˜ Á80Z@fð4€®:'+¬ F€éç| ü„3tAØ6€ôp~°? Á 3ˆÐØ#EéI!h@  Ô$†XQ¢Ø=Šaºø¶ b0`¡ .ƒàƒÁØ1Ô Bˆe (ðn€à1  h 6 ÂИƒ`ÐÈ^È,`XY€NŽH ³( x( 8´%â°bA€p6À.€ÞA H ÐÔÀp€00“Z¨í¸µ0À›ak@U¸lxÔv\ v’‚ _Mqÿ`Tk– Ûè:”ðRØ'à˜ pR„XäÒÁX\º!` ‚pªH\À¼0ŸÀ²ÀøE”#à\ÀÐ$ÀxƒìÉEà„AÐ\ Á (y@I*° ØI5¡(ƒÀš‚˜Tƒ@ˆ Á°Eà°‚ D Ö£í@ˆ?b Áh:@ȃ—þ ß76{€! Ž·h<!@ƒ€¢Á°O€Ô%ƒ Tw°Kz„ðŠ C|­©8ñ$vX_ ôƒ ¬ƒNP 胮, Á¢ ‡04’‚Iàk ÁGˆ„ÂìÃ0W ¡”-I¢H@!@‡…‚ˆàfˆáÒB‡À¸g Â"Ú‰ âxr ý$1ˆ`ÖÄ!jA€+‡pº­XV Áp,ð» ‚°V&A\3P°‚€X iø$¾ÔŠÐ[ é|C1Ãð a¨4 ’{ AÀ§¨Á¨? Ï n Áµ†ìŒƒt¼¶ð‡áT3•1+Ä £ÂS * }ã(= q†ÄÈÉâ”g†±)øe$@#ƒyâÁ@-ःS@'Äà¸(² pTÀ3@^'B B!  åXU&ˆWÀ¶,‚ðZH&† Z ƒM¥`…R”R‹AĺÌÀ<À6ÀŒÀ‚®øæa àà Ô @Ú%BŽKŒ á d¢ @Ü«àèI€ô ð¡AêêÊ î0H¡ad–€ða @è«J à´ ÞQ Þ €¾¶À‹X€¼ @ì÷ îRÅ0%EN +# ´àÀ`® Àè° ã  Ü ¸ ÐÀ HV¶Âþ `Ø À  ° ` W`bø€:o@2 ? >î0þ*j?êrrx é\ €€ @–C ƒL ’Àj@ª  €ð` Á\ ¡&@°a|!^ ´áp á"Á ¡Ü áàž A ¡ `¢ Ð"äx  <à´ p  <€À€j Qœ @4 ”ÀVà*À„g Š J (‘º€‰ÀŒ€JÑÂ`&†´hÆÄ¸à>À0` kì’@̲à*Éà( æ¼ É¦Ï ,¸ .@&€<qÚl±Ü€LE`^@êv`.o6@d B¥ŒCþÀ@ À’xÆö çp @4ª  ÀF €6 ¬àV '^  &@ˆ@\ mH  2qàT– ºØAná‚AJÁŠÁ$@† €b\ j\ Œ ¤|`”Àj¯ ê‡Úä`@<€:jr€LfÀ\d r¨À†ÜMÊ ˆ ’™@Ž`d  |@ Ì$àZF`Xæ X À„æ  À\ê® Ý Ú§˜ p>´ ï  Ü (\k|˜1`lñl-À‰‚ B6 à  `” @¦ À² @Ž ÎÖ“à”@x Hr àˆ Ü  Œ@´ a €¨€Ø “à aV¡ !)Àü ษ À  ò ²@À8@´ år €À ¢·€­: ¨ ‰¢ – À¶ ª pŒ`ÖÁ ¡ Ù€˜  «,ƒX5Àj pz0 xh8¼âÀj˜‰z+¾ãl G¸ €´ ª áda@A9@ú˜¡DáœAHáÁ”ÁB ä¡NRÀòlTÇÒ`XÔ€JàT ¾ @¿-€ÈÀTÀjA €áà‚@¢ ÁL €ž¨ ¡H  @œsª@– €Ì{àx bÊX`>qÀ@ê¥ËŒ¥$J§@<5€t€È `ü  Ü€Ì @ð +F `Љ‹:Uë0L 8„ÀÚ>Àä*ÚøJ@Ò`´ °  æ@úÿ¡a à@ø ² °8 ˆ ÀÔ c„P ÕC@à¯àî `¼+&²@ÈEpÀ·ઠ€â À¼ ઠ5Þ @Þ°@Ú €»  ½\é& ‚¿bªQ ¬ " S@9$0ònpôX <¸àB*L¦`J§ RCâ €†‚ `–1 ¤À[3†3GÀ  ² Æ!x ¡@üAÄ Àþ`ÈÁ„áj骠¬áVŽál àø‚ÎÀÚ Ì @FÀ¸@p `=l 8gJ€®`d `.@„Ñ´€Löì‘ÂÒŽ`$ n D "ÀR*ll@8È€2à:à/qf¾kfºmÒ€ËÈà.Ɇ´l¦Ø`Ó+#à&ÀD *†¦ ,?í0@(@g@_r XÍ@.j¦2P \b`ÆŠ >æq¾`L wP  *FLpà0Ê`žÀB $–Ѥ6Âw`}z ~  Ò ¡àè€á:@òA¬àâ Ì ˜ €„C˜ ¬à~ -² Ð #Ô :„H¦xÿïþïòÀXtjè b€ts „§þ d`p †ÛÓ”S¿…I‹3^ `zÀž `€O`R•àVÁ øÁFàèá& `  àÀ €þ ÀÐ@¸ èP ¶#à–"@bS ‹§íe@v Ï €„èj@ `† Âú ®d—àp4` h ¶x   ì àŒø4àÀBR @¨+ ªê`¬ Ä øŠä €¨ €ª ¨X Ì À§A ¨ €¤ @².à° ŠB @œ ¤ ÀÆ º ÀÈ àð®á îR Ä `p# pi’æXî?ô> ´A`\;Â&€Š ‚& ޝš\bd aa¡A¬¡T°ú¡”à!¡á˜a\æT @ @h= N P/@C: ¸ï`ä ‰€O"`ž aT àž€¦ J ”$€Š$ „†á†Âh eŸ LŸMž¥ HŠR 6D²4ðÅ´@Ú  ò Ð€Ä  ê @ÕWL sü ¹&´ öËhÐU€à Ê Þ ² ˆu¨`Ê`ð©Kî ¡ Aá$¨–@Æ «ï`² ÀÚ¶ÕÛ 6 †àÔP6 â ½_À+pâ ଠ{ @š €Ñe ÀÒ. È“À ‚ t" À«mˆ`Så•|KŽ.nà0Xe—`I0Î@€ ~Îbûpð'ª \àj8>à„ ààÂ!H€¦ap Áñb€þaÎ @¬`é¡t @þÀà A" À~ @ÌÀ† €D Æàt ç4 vÝ|8^RѬà,ΗfÀ$ÌÀ&àdGqqYqZ,%š€0À*jññ °ÊqôÉRFªŒ¯æ¾É@5!€>È€E€@×´h²"À:ƒþZKu`UqT@ a{@jg:Ë×r€l€€H`úqšÀ¥v`“"|-@„€Br>v€@'v -B ôLpñž +"!la|Áhh;3`¨ ®ü e@` š`€  aϪf`Dþ/J_/ÀBDU‹€bÞ`jÁ1²ÈÀlÜ n@tãh@ˆ`hÉ”³, 1Õ\Àxf €r@€è´ÆXl `Øäá¡ €èa4An ÅäþÔ6˜ HÆ @ª‡À‹ÓE´ ZͰ _Ï fð n`Œ€.h`°ˆà˜#‹°s2Xè`2@® v ÀŠ à ÀŠਠ€ô `•ßèÎ ¢ ú0@ø `®E Ÿ ¡°`¤ €ª ‚‚ 8Ýí‚ u& ˜ Î~ I“ø§  Ü€ò! €Ö cJ àxz v5@Š$ vÏz†`o˜€|é†àX;ý&ñ.‡ðš¡4Á2¡¶> T@øa’!ÜAh¡ `”  ðà„ Ãj RÀXÝ/ÀDÊN >, Æ(`\Áƒa0@€‚¡"¡€| xáƒa5ÁFÀxà| Ê‡†ݲ~ Tpµ8Doî¦:dšdD¦’{f  ©j`Ê ì yi\” ¢¬ `ô ùh Àȵ`Æ ¼ Т @ᔀÈ!àŸ.Ê ®G ú Aʸ ü!*îÁ0R ¾R ã 08 Òº¢)H@Ð ÀÂP ¤;à°~ XØ – àØ ¨ ¤ö ™dÚO*šÉåCA,¨g$L„‚q–P2ÊFR¡XÀP)I¥BÑ8¢JE1@x4!ƒá È‚d$™ƒSèhL4H¡ñvB!ˆCáÉx9# cqàð¨U7&Œ©IÙ<Õ)Öæ„{¬oí³ò®U<«‹ˆ5¡u²0!׃JDÄC5…$¢àŒxY ˱¡P60&E丠‚B‚Q˜P>. ˆ¡0è´$CÂ}@€$ ‚áˆ\$ Â!€x@%»ƒ‚@nÛp‚@àxSx …C{øT." †ð¸€&ÂÁШ`< ‰Ba¯@lLŒC>ðlR‹Ãp”€zCRx,Ž ƒâ (Å èpÑ ¨8‚àèz !è2 È? „AÐ8 ÐÎ6åAa˜ÄaJTf¤I ãĘl ‰Á°€&†‚žâ`R‡à6ò`<ÉÀà:RÁpV†á€b!†á舢0vˆáÐx"¡è‡Ó@u2†âPu‡PbLö"‡HŽX| âN&Ñ#H°0ŒbØÈ2 cÐÐ;‘#`úJ ƒÑ0Ä®/‚ ²2‰ˆø#‰â„$Õ€Tu˜T…¡ˆl×2èz†â8x‰Áøx$ðŒ¡àdAh^!†˜–†¢ zŒÂv7 Bò) âF? ¢‰1ŠD Î-c¨<‹Bˆú/ c¨¸) B¨š0 ¢€Â&‰ã¢)‹bxš+Â`¬$ · ¨2‹ØÒ-‹ÃxÈ4ƒòF„I @£ ä9‹£Â Bˆs‡‡"(”ød¡Hl…Á m_‡a–" Ž-bÀàKÄɈB†O™C©*`„Qh3%%ü;†b°‡"hjˆaXV¡ Z„aHG)Á(d*‡B8þ†Äøš"’‚~?! æ†¸\èöƒÈd5ÏŽ˜h4¡ÆÄ‡!8TáB  ä¢ƒ ø@ ƒ½@<ƒ`ðCׄ@àF,¢HÖ/ŒC¨Ä3Ž‚ðÈ: cò0Žbȼ7 ¢Àä)‹ƒxª-BHž-‡R^ !xr> CQ8Hê=üÃÑ:¤€üAüÃÉ3à¼5"àÊ9¿×ˆCàe áð1†ÀèCfá@(@v›ÚBa\„ÆÂPf"A”$Ã0J ¤D‰„`œÂ(L ð /½¾B_ Q ÂBB8”º06‰ˆ#&@„ ‡L à¥U|÷Í@ὃ°n.¡ !…6’&ƒ0AÄM @ªÅÓJBWŽ ò(†Àè01zƒ¸¨ â\,Âðá<3‰`ŽðIx‚@hè2àlƒ`4 ˜àÄ ‚`^1`„ @ ªIçÌÚ&m€ˆ Lð@(@°2à 0$€€ <åƒ1€˜ ˜‡a@4lðÇp ‚tk 7€p`>uÁ ×ÀT™p< €Ð#€\ ‚ÃÌ ˆ* à40rÀÐ+ X(Aø@ðîƒr À §@08 å; €nC¡$/…àèȾÂÀYˆa~1„XšAì0¢8Uá%àvÜP=‰à¤à@“Á ²IŽ´H Á &€ ƒ:v ¡DM ø ( zÓ`HÀð&à‚jíZh§ÐVÈ)€ìÖÐJà' ü„‚B0@PéÀ1„ðº‚Àd Áx6)0þC€‡ ¡ÈE°ÌXW!Á8,„h ˆ1‰°X X/°‚àR ,’ö8@‚ ‘è6 ÔƒpZ * Ôà€ AKlÁX@ÈÌ¡Ä*`öX HA@® ƒSŠ4:ÀŸBp^`'†@¦ Raa0)„`’‚T, X2… À‚øc!˜5‡àꀇ‚|K‰±ÈÃ0f*84`ŽøH ÀÜ"„tA;ŒÍ | È>ø&ðÀÂàkKŒQ$,¸…c8? ±ŽÄ »bBÏ…lB€-aÐp A84˜‚@H  !Ù$‡\)B€O è÷8A4p`Ø<7°ä ˆu@À8«€Ú ph °1Ú¿isŠ`•+Ê‚RRJ'i.Ÿú~K‘3ç! ΂Øp Áˆ7pºÂÀ_ áX/˜CI!aD/„0…MàMXƒ ¬ÂHm ¡x8½0îCv <…ÐϯÞ0Q aÌ&…pæC`I 0p(°¤Â8S %€BÑH ¼„‰.€5 ü*£Ð¶ `Tx"„pÅMƒC qd…}¶‚G !%…¢%t‚ˆb!!h„ƒðl €” Äà;ÀР$Î#‚ 6KAe¼`ÐP`ϤÕPgÀ»‚䯂xX‚€8 QšÃརœn±p;è¡¢D]@È"ÆPG Bh-!l‹dBÔ*‡QNC¸¦ A¸Oƒà-(8`‚iÒM(!”PB€ðB l éqÛ¨€›rØ YÍÅxšOˆ@‚"våØÀD L`(NX ™ ;Ûil`@è#±á€Ð @WΟ& ˜!à`ËÂpAQОœ vP2 ø&ȃÙÄB´× ªŠjl‡¥†ÌP¹BÁ©03€PHÀð2 ×fŠTÁ¸Yˆ!ˆ1„˜JŒÐ"…^ AñQa„0éP² -‰àŠ¥`J A&`„),RÐjœ- ¨!4‚8и/9c­°$Ø(D0 À *1(Ø èØ)•p‘‚Ø&X.È,H20=ƒ 82Ã)‚ø5‚H(ÀØ‹:­hZÜ­`K:ÂÀ¨5y´ÂØy_œP ­BÀ•‘ÀégÌ‚›mÀ1ƒˆ& >‚è%„ 2—`3°=ø+µ &˜@&Ø'`5˜&€,ˆ.²Ø)‚ %#‚H*‚X'Ø)‚ 3à/ƒH0985„=„HhL(CèJÀU€Lh?hUKˆ5àG¢ø,#)À!¹.8ñÉÈ‚`+‚Ð7P5„T„@S†€Hpl Qx>Ðbƒ @…ð+?Q!°"è`2h I´8‰H‚ÐÈQ '„x!P‚p#„ˆèEÆ`?=pƒág²Ðƒ0H,¨.Øh+0‹5Ù#@$@ IÚ*ÉA)©ø–;[Ah.‰ 4Ð/ƒ@+,¢ö@&8Uƒ"D8‚(*¸x¸ µx)à"ƒ('¨3P/‚&‚ˆø,*È0¶°1K!8C¨$ð‚(,¨ ‚¡‚pªÊK‚Qµa½‚(¨§¨&Á˜&˜·‚HÀ'“+È!‚è-ø!‚ܤ‚³|‚°¤¸0+ 4¨0‚p+âùÏÉ0x•XH:#¢0ì8ȿЭÂXÍÐÍàP°X+ˆ2X‚°?…ØAhp„(Y‡X;… pp]‡1@c‚83°) z@¸/„(Z‹ X‚94…[I„è)¶h ‚Õ¨Èè¢ô”(Ðè`™‰`Ùˆ|Šlˆ­H HÁÔ€° €Ð¼³ÄRb¼³É¥€ôà &úmû€°å&à €ÊZèØ;`ìð 𠦄ü˜,ÀX0P)%($¸ ؾPîp ˜îXÈ`ˆÑ  P+8‚ø7ð6Ð]B„84HƒX1)*¹t‚8M„pE8MØBƒÀ@p"‚{þ8(ª= ’˜¸@ ®ᘥÀ!ÁeÔ¨ÀðÀ Ôà È“((i2X"ÌU€"¼Ðþ8P"ìÚ‹Á˜4¦IW2ð  ›BP/°,@+Å0(Ø3‚$¡­@• Î YDBÀ1-P¨ªpJÞH¨¢Ô3hDàÖÈ3Q#-ÀêÒ1g@¤Äˆ*Èø °8‚p ƒÀ,8; :Ð+ƒH*¡)h9—£_‚ˆ9Ì#‚`(ˆ#?!†Ã¯4ð4¸5ƒ Fƒ¨A… =€\hT†xN¨l^àQðo„ Z†˜?˜XµðFJh.9Èp(à“1›‚jÈ„¸7„PWPP>„ðd„NH=„À`‚X2k‚9j).‚×…9×h×hЫ#8€)‚¸R/HR‚ )³ƒù_ƒ¹\AÏ„T&ƒxÐ(&ðÐH*%H*€ø‚h%H‚"ߪ¤H¸i*0@;5ÈMŒšû¿¯x$ƒ ‘ø*ƒò"‚X.“€,à!Ë€ bJ!Ây›ƒ %Dh.ƒsM‚ø%XìYt>­ã‚œÁu§•x^òPèz¹¢ä{!\‚Ú‚˜)È‚PÑð ¸&Zx'¥ïÕ* ½ûø)!Ợø‚(+‚%¬¹ˆ[bh)‚ 0²N ‹À'ï°ê€¹ 8ÈÐú?䛳•tÛw’Ø# .ƒ˜"@Oƒ¸Q†Jøyp]I9ø. a(3Ð& Sâ8^#¸Z‚ø¹Ð<…H&ƒxP€9…(+hK@<*à#¨àš̽ɱh×ty­T¢Ó¦-L4l1¶ðCsYµlã¡h3)Oð È€€îÂa<0H¨€kÎŽˆÒŽÛ€Ù&àù¼Š…¢XÑÚQp2u:æ€ @. ‚ˆ ø"€° p xØpíb]E)ÑÈ °  €È‚Pž`€(6°((è €ø;x•"˜x&XOÐP„¨JÐGxGC—¸.*€T9·4/„3ÍYШ`á­KÈ®Q!°@xxÊ©“Ù7 ’`Ð8@± A“ÙÆŒØÔàxè!àÂ-™é›à¡"ø0$’ø¤ÞÔŠÏ@XP˜ê &×B]h=w*pj(× X8jS$ÇØÇ*Ò@}…æ£|Ð5‚` ƒ *‚8;¸0;éyà)ƒð1‚°? ã‚À':ô‚È%Z÷¿ $kð$‚rÁ<•8„ 8XX(N† K˜l(_P…èo… _‡S†r…0`K… g„8M…À2ƒ¸G׬u©x«¦‚™Ëh„P/˜Lƒ»Ÿ8RhCHkˆJ…Ø‚x2n…XH¸r°_‡ @`uÈB†&pR‚`8…#…È.„8^‚èB°.èWˆ9…$¾ƒ¨Rî8$2¢ñd©›™@F GP©A2.È¢Æ`"²š›0 -Ó®2Fä³#ÎØOó¼ýäžKÒ_;  €xô¼( €ZZ dx €p €öG€èÜ¿u%ø ðH˜g?p Ð ‡à=R(3¨'fÈ" ˜=(€p x°¼îQØop‚ #àQÜ‚0 ¨ÒJ€à÷ŽðÊh%…xQèO„ˆJ„ÀE„hH„ CpA 7Å,·è%L0"0ÕIç¨MsW2ÓV®€è@Ÿ$¸xÀ-ˆ ‚E\8 ¶Œ»Ù{—·H9˜‚Ð--¸$±rá-ÊÓœ#1‰ñ_ö7½­kãÜ,šÞgê¦êTÛÍ»ü¿ÿ©!Ñ8h*Z¥3ôMº§@@j} F:`­0!Ø%{Ø(¸þ‡ƒx((<È'ƒÀ.Šè‚¤A‚À;ð(ž¨&H(¯8'‚z÷‚0&IJꃨ(ƒA‚ø;„à=„ [ðLè@„Øa„ O†8EíèM¨mì¸p6Í…(`‡T tYˆ<Ð|JŽ …±˜ìˆ6F#aÙš]*FsšLÆrJωÓaÝ*P+›FÃ1ø¤V: F‘@ÀR'ÌÆbq0´P"L†i¢©U=œÅ"ô8Ðnœ!Pã±ñ0>%ƒ¥ð”Ü'DbÁðlBA ‡á¡ð6 Ä„Pè„–ÄBr@œ\@‹Ç¢á˜àX/ bQ”@†ÃaÑpDA¨ŠEBé0ž\#Ê£ò9@rB&†Ä¸yZ4+ 2TÚZ1 †sѬÜy5ΦcQ¸Àf6KæiD¬="ƃbFˆ.ƒ"¬3“Ç#òÇ4¼L)É~R10ªA"‡CòxÔxG:cB(¼nIýjbz &áð "xx!‰áðŠð‰bØš) ˆ !È@„ìxH ø2 0ð> !Lñ<ƒ`àNƒáXDÁpVˆèž„aÀ†-£ _ dq–0‘¦`¤<–BxâR D1v2fºB—báXŠã¡H&E–9”b¨òT "ñˆ"ÀŽ× aøˆ%BÂXv ‰!ë\âP}=Тh| AsØzˆÁ¸p†˜d!`TGÁh8…€¸4 °B €Ø$ ƒ ˆ$ ‚ ¨: *À}T Ø‚€mi[µÐ6 Ãà˜&@ˆ3Z@ ( ¸D ƒa08…@°@ À†ƒh4‹`°<# ð‚ à"  ˆ.`°P ¡8 …5P^ ­€°J%Áˆ Að0 ÈBÄášâ[€Vˆ–%! !ÜS„ ¬‚8F Á6|„ê¤Yž G¨$¢øA¡1= xÂX=PÀüPr ¡È" ¼Ç°,ˆ–x!Uàt 0>¬@D µ˜«àÀ@ ¬  €Ø bÀ%chì]ë•¥†¡ 4 ‚; À¨ `ƒ 6 ˆ~ˆ…0&ÂÁ´à$Áʧ+Àël€ %] À ðwrB T€&AÈàÐ ‚ lX²ÐB”O‰QD%DÀ“â(E‡Ñ ƒ¸xÄ:C€Cð]ƒ$.Šá|„ˆž aÈ=Ò¸_ `À#àrB(6À웹2aA1l@¬ T°*`ä6 N«[ ™³¶p ZkIÀ„!„:C0bT„5"Îz•h€¤Á‚·_A«‚,ÜÜ’ ¡¨*SÀÃðZãÁS–s­º3ëó°s`¹ü Q©; ¤Ä‚§< ˜0'ìáâTœyÛÁ@ƒPÂÚƒJs¡`&†À¤^0FAd*†€¶‚ðZ „4ØÅ€@ ‘|„€³‚4Y‡¡./DH£BDð ¿‚A,FŠ[‚Pá'²¾¶@4€Å¿ePVó"*`tŽ‚V—Œ' ¶BxV!e0¤‚BQÜ )è,ËÀĨn !5… ¾¦°_ L.„P¢øK ¤(*¤¥ ‚‰( €¸„€X0,!eŸ™Ò k 4O`ÌP‚AÒ"!(÷„Õ"€G`Þqƒpœ|¦9 Єàr¼? èÒЄ¶xW4!L%· €â0D ‚†"DŠh8%®`| *Ež– œ  R€è1-`Ô àn˜U âDc†!2‚zAh?‹ Â"F"D!tAÓÀò*‚hpáD: *€)B€{!I1„ °BpI L(GÂРQ H*…`—ÎBòó@†dôâþƒB@Z6à,`*€>³ &€:²jþEVTåt€"VìELU«&Y%à  ÐLÔ°:¸@F±p`/ìÐ8®ËB€4´@4 $ÈÈàšÀR.`N 8`ˆàN <€~]@rU¥D K L€2À&Àtà:B¬€.€` = ë¨à@` `þP8FHfN `Ú@È @Æ À®`ú J`š¡V á †A<$`zá€À €f €”Œ¢É@L%Àf~àhC(þlà[.ÜÀJfÐlàLi¬X`DˆàDÈÞ ºúÍì f €ÆÃ¡ÈÈf1 Æ"¡XÀN,ŠÅ‚ñ`´b/ E‚á”HV(EƒQhÀt/‹…"8ŒL& D‚1(˜G7ND! ˆF"Ð'ÂaP"ŠDbATð[< Dãa0¬t)!DAÀœ6ÈCÃ1 |k) ¥‚¹ÐÐq9Ñg3âeV!SìCúax|K.Ïɦ -HÍH+𩵻}H¿r§×Ž% ùʧb9Ôl6UÄž\7S«vÒ…vÞC)Eƒ¢$V6!‰†ƒ±˜ü7 †C‘èÜn:"ÄaÑ”?!ŽGÁ0ž:)Œ…ã‘°Ðx3Æ# `à}SŠiú3›ÄãŒZg‹N¢ÁÜ\10‰£ðÈ„Œ „¢°>Š`ðN$ƒ‘€ÐF!ƒar !è2 àFƒ@ð~ "(BÁ(b•¡HdÁxJ… ‚ƒÁPý B†. ‚pº% âÀˆ$ ‚ ’-ˆb@¬Ü‹ˆ- X´' â z$hjA~†AðLX„‘‰!€z"Á¸ƒS0J‡Á8_/Ì0\ÎaàHˆ|†èP‡áPm,»!€n#A°âPdJ –ë ¡°x'‡žâŠЂ(Â(  ˆâ°Š&‰"Ž›ÀÄ@ ƒ 2 „`À,uà5 ‚ °D ‚Á( „`°0VÁ@.…ÀØ< ðl aè¸D#I(i „1~(%pºC—ã_  otbhÜO‰Ã™B(ŽÅ( ;"–$ ´”<‰â˜ÒÖ£ñ:[åaš6Žd†‰! f Aˆv•‡ Ø:‚`°F ‚¡J`¨: ‚`Ö` ‚ 6æ ¦b  þP€¨B `à ƒ ˆ" Àˆ*f ` `žh @x$  ˆ0‚šN¶‚@Ð ‚û>o›iÀè(  µ¦ °8ÀÐLÁPt…Aà.?e˜…``.æ¡>ÀYÁX¸8ÀØh ƒ} AÈ(‡AàŒ$•Dá8La>Dâ9£0Î5‹¢àÂ)аˆ!Ž£À~J”Bˆ!’$à„J!ÉDQ‡DQ¨R(‰T8eÀ†á€…Žáàd†¯@o0‡!`pá¸l7¡PzAàpáÀ@ ˆa®A0xÁ=P`›à©nB€*"`¨P¢‰(8OŒèƒ\  °+Dl‚Ð^Á©$ “BnQÉ™@ €ðB J#‡(È´^‰áJ9¥ hŠ Á 'A‚àˆ A S |$`ØÂÈp A 7†àôõDHsB€9±"h‰ Á”A0Ä ÂÈkáˆ;  Ü!…p}F Á¦"…@Ï"¨i Qd6йÂpɉqj6Ä ³"hЉãN$Ås"p„€¨ ”ð>á`‚ Áà;@ìƒÀrÂ1 €ø"€fÁ!àˆ FSA)`°‹0ÐŰb ˆ)áBsàÈ7¢@ôBƒø1ã–>AÁM…°B ¸ A4‚P–AF€ˆ !pfð@õ€,°PäMi,¤ƒ`V AÌ+D̦ΠDAø8*¸&À–ÐG l#„°Ä•" J Ô”,0Ž˜: ˆ€:tí€%`zAÐ? á$);à”¸> Ø„°X ‚P+tÀ°Z¥IHÀÐ#‚€h¥Úe èƒ4F Àà'`Š%ƒf 8 àð…p~‚x5jtÐnBh;!<„:æ‚‘à a&ƒðv€èë 4Ö @`À8 º¼mˆ {H+rµ b-@*¢ÙátD  ä'Èh#,*‘bD¸ b^€þ-Âxw¡8 –×Àt¡(8Šp¢Åx_…üR !(.Æø²cìaÑþ08ÿbøvÁ,€/à˜pB UÀ&ö˜ 7@,¶@  `¾Úø€M°³¬ Í€x,ñ `=€@ÛMk A´€ð*×@»Z8 pØ>!m5£€¦jÚsMØ‘¦`2 Óz œÖÀtX<³îˆ ‚,A3[­xŒÍA h@D Œ$ @ˆà` ƒ0.ÁÀàÜ ðrÌA€”¢K±#ƒèÁÄ:;PÐØ] !<(†B+ë “HE‰pp#„ˆ5á䆠àD(BA‚#„Êá8%@X= Ä>Wòuѵ¦¼‚e( ÁÈ9P,ƒÐv@R¡t=0î&B({ è9pE(Q Ô k\H4#$ ¨‚â>ŒÚ%Â&½°ZöÈ™Í:àÔˆ‚ f Y+E…-ÀÁ2àŠC‚‚O¡ÁK'Òì”pD eÈ/…€Ä¤àL—pG`Ð(ƒð|PJ Qÿ†0ÔÃÈŒ ¡ÜG… È‚¨^!`30¾ˆjBœ; !zDÐÄÂ|d±R3CøšØJ ÁÍX§ñôj‰^5ݳBLX0,ƹ£ÂdZ Pè$R; Õ¾R ˆ ð ­R á"…ØJ Áx$„ðȈc H2„°šO(L€ê…‚àTQA&4!@¼¨c `4…ðÄ‚ˆV ¡3ü  pÀº àž ¨ïÀz¬Ë „ #„ ÀtU*bÀX€T¢lBå À– `˜ñ/ÀIP O in °°+9›À Ž  Š ânæX`Diô@6k" 0­ . D¿¦†Wëúdà0e†ÈÀ0…žàÌ„¡DàØÁ¢  þ®f^!r  ¦V à`Ž A6 Ø ô¡žáêÞáˆ!þáÐá\!þa¢áBúa ËÞ@È¡T`Ž Âx 8À`s V@0ì&Z+þeæÂ§FÀ @&Êæ–Å€*j@*g€>f OÀH€(ÌH€ ÊŒh¬k@,k &‘aÐ < @¤Àˆ XÖ \}cf¬€jÀ|”p°&Àv€@€š€  `V  耎$€æÀl$ À¶ò…: h V‚$$€XÜè@#rØ"`[."@È$Â&ÀL÷&:%‚’&.à&ІbrF@J'bzbZ‚l&"hâ0 l"F‚@\%’ü¡ P |d Íš à„`À ¨â ê Ìn,`ØêàæáNa$ôÁ€Á2Aˆ5!šÁZ`ú!‚* üa„3 æ†a6 A˜¡PÁ a¢!Z.a°rAÁr ì€dÀ–xR t7à~•`z€hë?‡Ç/à`†ÀNÖ@Z`Æ aŒïaV  ²bÀŽêèàfàý? ö;Ü„Ob`8 ®)ÂF¾)€¬L «>à6Ÿ`2@e`\ŸàdæúÁ@Lf ts„àpC¥Ž@HVoÀ\`¦J~&À^%„\€X‡@LøÀH4 €|² šú ž ê> œ ÌïÊN ¼ @– –H Œ €z@pàbàšÓP ïè  Ê ÀØ `ä çª€æ ¼ à´ €  @ÑQ Ä n& €Â `¸ à”  ¬ÏàŽIVÀfàC3ä êÜ 0& C– Ä dT~ *ô €lêü œ † Æ c† #Œ *\ges€F€4à:ÀR² X1°n@BY@YGµ®àNY`Z@V ®!h¡> âa° !à¤ab `öÀ¬Án eÒ Þx Ð ¶AV!ÐÁ¶áþ¡àázAþáÖáx!þÆáXáþAŽ.áîáˆ`ü¡¢ uü`Ž `<€yZVÂ@Võ HEŒd¦†hF`ñ~ À j`Äñ”k R¾ÆÎlÀñXÌR !i¦ ±\ÂlK¤Ê‘„l"k &1Xqtfäà,@JDXdÀbD` 6¦y%yi HX±kfpæŽjñVW†l 01Â`V@@  €` þA0a`úÁ.ê  Î @´ €À  ˜ à|®íŸSàR À¼ Ð @H ܸ  > €ìÀüLÎà:aàÀ @D ¦@’ IÂì@~+@‚ ZtàJ ž À©*¶ ¨ ^ àò`Ø|¡0 `øÀzá ú€°A\ Àw# –7€hÙ†4ö;"J@\ h"ª€Tªâ+I­ªÀP|â'‚`ÂdöÂrmâï1Bƒ2”ª%È`Ó ‰rý"$\àRàCœÚ“.ƒ´« À ° ° Ø  ðö€ôáZÁàä¡hÁ&!ŽA=:¡4 ß,`à!_Ša` ¡  ÎAT ! €äh$3˜`þ†M8¡RÊá&”!`š €Ò…Lã |MbÔh¡Àr À ° !}OÁd °@˜ | y}@h ô pʶ * B\ @´J#ò`°'€¤@`”²@„ŸG* ^Z`UàUlàJÂ@N 2C÷‚@Àb < J,Ê&O†ÀfF€R ?3R´œÞì%ªØ…``áÕÁL`¸   £Ä}œ€ÆJ€ÉL`Ü€Ò À´ gt à” áMàx@¯œ€ÈþÀÞ ¢Þ `Ü@Ò Î @´ýà° `Ó&`È `¾ Õ(¨¤r9" ¬Â­JrO@†`p @võn°t  8@¥“ud€’§À•˜ N Œ± ˆ @‚ @zÀ‚€:Ç{ àÀ4„k'  0´Å}[+HdËJ°y. ˜ È~ð² !` X :Ä `ü@¢!` òàŠÁ0Á˜¡vþ¡¤Á>úv,¸áfÁþV,–»b–,»áÖ Z´ Àî€v *ÀÄÌ·qlf%“ kvsjìBjfÀ@.AÆZ±´à&Q=o&bĆÍlÄà&j'jà(Ì=æÉgE²´fË <€:àVÀB©Ú¾²e bg¶^p`[;¶¶ŽL¨æÀÀfSfLp‡2÷H$Àˆ&Á& î`ô €Ú  Ä  É‘µ, zyt`gB¢T àœ`È @D `Ú¶ €@ø‚à.,àð€cÁ`H ¬ ” €:@D†”ÆಠˆL‹â¢(àbù*¤#àf! d+à)3bi1´†&ègHhn(s!äX—³ † }Ï€LàQ/ÀN¯€(”€X@Žñ+€¦ ™R`× A S³Œ˜Çˆàæ`Ö¡N – òÒL !àÌJ P `ÎT á‹®V Á ¸†ˆÌÁ9A¡˜`S|ÀÊA2`ŠzoK „ Z ¸:`² !N லät/Bàrà`€à"Ô+¼?Ob`¾=À¶˜9Pï: ŒžVôj–Ö€PµëV´•¼ŸéêD+> *†|Vn &Z› À2øÕ˜%Òõ'j$=äÂ^ƒî@† ` à¶ €´ ’   à·Q@ÃQ@Ä `œ `ž &  ÚÏ@Ö Ûú ¶ à˜ @º À° Àž  Ä `° ठ`¶  ›¤L—D`£Ú€~!@v$$ت´”c¦å8TÞÃ@~®`| Údü@z tçà{¦ ¥+ ù€ž®àœ`˜#àl~²ÀI¨PX`QY àKÀN¿õ¦´ËJ6`´9[À€ ¡$ ! @˜M­B àðà _dAc­FÒ`t .0¡JAä‘a”a3c0ÁïÁø¡°á[`aVAÿúáþ¬á>!ðAtøA´4 °¡X¶Gä €8fÁDd¿îl1X,` P`@,†ÂÁ‘0L$„¡˜d$„¢0ˆT< ÂXbƒÂ€àt¤Ê¡ ¨L, !@È”,MDPè 2DƒØˆd‹ƒ!€`6)…ƒá¸‚&& Äa L(Á0Ф …Ã8°ä›Î&ÄÒ5Œ? Ð©ÈÈi4–˦"yH¤E#’ǃ±ðÌb5ŠˆDq|Ì"2EãH ä~šMB¨D~F æÁIP®&”Ä’pt˜T•LBbé Q×MBÂá´\c;Ž ÑÉyG>¨JˆIêŒ$ Õ"¤Ì‰X'‡#a¸øv:!„1ßÄu’ †£àd5Àr†ÁÀbp^…!s,…¡0RÁ0N„Á@H¡F„!BD!A„ÁHÃ(HÁU…aHBáT<ÃÁD<„¡8n¢ZˆAˆh!†!À¤" Bø¼8 à ÷(¢0¬9‰ðô&Œd@Ò=‘XŽDyj:¥¨êHÄÞ:‘ňÚD•Ã!SŒCÑ=*“£®4 ã;D‰pD&AS£iN‰BðÚˆ"(fÉâ~I ‰d/‹e@°,BX˜K YP|‘uxü#˜Z È9¡”…BèDŠáT(„8–â4†àÈ@‚ÀðT ‰ø6œƒA* …à¨6¢Áà5£àút à: ƒ@¸0ƒ€ØHƒáTbHt…ÁÐT†>a1@F†ˆ'‰Âø %Š‚À–) ­Ð²%‰âè”'Œh¨3 "¸Ò,ÊCÊ8ŒC0Ü.ŒÃ€®2Ä9 (è,Œã(˜+ 8¢0ˆ"`¸ˆ¢Àq¦Â0¾ #)ŒZ(¢âH`¡ z&b¤ˆB8'>`j Ϙ[‰¨x%n¢Hr‰áÈŠ'â8š ·B˜" B… ð8ƒ@Úˆ „`Ø2\A0.°À¨@ Á4‹¬¨,ƒºyÇ¡h” C°f-‘bHÖM ÙL'Eˆ’7”bÐN#90$ $¹ Vd±~v9ìMGÉ0eŸd™†zf äQgÑPjåY²•ÆÙþUÇù6d$)lsÅyÀ;f¨ØKÑYƒp®!XpR œ!0. €e$42H@Á¤HŠ0:€êï@ ¯‘p&ZKQ!$ÀH ®ʹ'(‚!@˜"pšÇJ ¹r`Qi-°PäaeE–!ðR€ø' l9bt&D B´@¨€\Aà< Š4tÀäœðJ BHŸ"HGˆta”ÔÀ¾B˜V A,'0ˆ‚H:@üƒn `D ”.†PNÍ`[ € <Ù"Àøc À¨=ˆp0& ¡`õÉAQ À”+†€Vp- áÔ† ô Ø…áœ8ƒ°jÁèqT?‰pž„)ßtAŠ°Ê E@pcpÔ¨B`ô!ƒÐ~Áäàç¸ö„p| =€üȃÐfÝL @ Ôƒ@^ ÁzFB଄PŠ‘J”!ÐNˆÁ8#E ˆPF…D`¥£t*ŒA:5´LN @/ ¨Ð\ ‚0“ÐÐtà: ì…6œðM A+‡pŽ˜9 À ꃄ ¤I†ê&C yáˆ< ÀºD°Y ¢4*Á#%˜["P-a6Cø¢;¢ÈB‰Á€DP© ¡¸@ƒpŒ@L Œ„$ˆÀŽ`@ 4 „q$BP…A?`t ¨9 ÄZ &–€˜†0J ‚˜!aP, @ `tQA  ±r‚…à H#‹`’à,AÊÕÅ€8Nˆ@s@p ¯`4´—µƒ@R AØ2@ø+¤D "U€Åƒ©€ˆ‚{V &…;@M Á,(†œR©¡jº†6\Ã8k A„4„𲂀_Ç,<†âÃs¡h70²Ã`O A´*™ð¦ƒXO á 2Pl`3¡à ÛDê 8д€nBn9 ˜åº Œ àFàì&ƒ€‚ÁÐDÆ¡' ”MB€ÌZEñb¸+¡Ï:`("Ð.qËeÂX"±    TEË Ì%‡`nĘD bx †¡<C8š—¢` 1*Ð¥BÀk‰1z:„p»BPaA42GØ–ÃàG ÁÜ#Eèí#zŠ1 ?_Xÿ#T‰ÁŒ=„~ ÂÐrñ^7ا”H 0ŠDÈ7 Â$…Q APM L謈©=·Å ªP7íîaÐ4 €âÔÀˆàL› 5´ 1ZÄCu(¬âØ„8ÃR0 ø#q^, .À«¤) l€@ €à'dNÀAƒ–eDJ ø#€hƒð6ó‘ €<ÀòÃð˜âXCˆq& Ä ˆ5…À o“1Á$ àŽÁÌô@ð©Âʾ Aœ†@ì xum à ÃX‚”6‚p²z¨_P-‚Vr rÁ¤?ƒ€ì!ð€@ˆÐ’Bë{a(9   „hK‚D*±`Ħ @i‹ñÌ?ÁÄñ€ÜM tAð=y ”'¡a$#X|d ˆKì%AÀI€È°4n†ÑJ0£ •¡Z"ŠŠ F¸ÏðD‹Pè& •PPPÅ¢ô€‚pR ýõØ€èv 6a$°’°I aÜ!…Àð p¡ 150ЗðG !ü"ð?’à@‚X0„(' C‚3P'ƒ(DX1„(&À@)@Eª°ú­ <ø7„8U”@W@ÐCˆ2@ •8‚($ƒ¸à5§Èæ¨8hƒx3Èpà`2@àh40°@!€è‚j‚P0"—Ȱ"ð·€èˆø—pˆ±Ì·£ /"Ð €ÈµÁrœÑʸ —&x0€à‹æŒ°¦úY‚@yY€¸˜&ƒà%¼Ð%‚€"p+‚P(˜ð(‚à'‚ 2°,P-‚ø6ø1€Îˆ0ƒ04¨/(%¸2‚)±0) ´ƒ½ƒ‚y¥X,°$‚ˆ½šØÈ'À )´‚a0(9¸é¼à&<¸$Áy»š˜è%À‚@±P &œ%2H 2ò€ùl È|3¡à À »2€ºÝ39Ó è¨ÀX"0è‚[¸CØ/xƒ(KØ1„¤˜6€\X[HØt(YE…Ðv°b¨M8|„¨`‡˜D…Àu„H\‡PI yØe‡ÈR5HO†P{„°a‡ˆH…ðu„P[‡0A`nXI† -8ZƒEȃ0Lø‚À €à"PBˆŠX€ÙÖ êÜ€è‰Ø”Ôºˆ€ 7   p›€h­XŠ€j·–‰²+ X ðj/€ˆ"*€¤Ê–ÁÒ€ü¹"¸"ˆ€ðñaà’$A‚ÓøX Lj‚hx(Í'€€/ AàW†0rXc‡XV0u„ RX?8R8(+‚°28 ½ø#¡ø 0 8, °ø>S›0/0(;˜>h€=x4x31ž`0€ƒ€@È:„P„ LhF…¦ƒÐ$ƒPD‚¨=„à-„8OØ>X(„ RðC`=…hiha¼ˆ_ø°þÐõNÐ{×÷1¢‚i’‚p'ˆ%#ð$;) $‚ ™ À#Ôq¡rïÄ1 J‘B‚¸‘Y˜Y > ‡„$¨›è¡‘Ëì(ˆ=ñ˜1 ”ˆX@£ñ#ð4Å€@@ÀE‚ð:°2àOà<„à0è5„8UPBP1ƒÐO‚à;„Ð,J6`'PE@€Dh0„'BX0ûþ()Àp+ƒXFŽpL…Sã¹À.‚2™Ãp˜6e_`ƒ ‘‚Ì!‚Ü!‚º‡ÐX"øé|­X‚1n"×­ˆ£8-¤.€âßBarŠ ZàImš€ÙqÉm€¸šÇú Š)| |( €ëlô;€ø€øˆ(D>˜ ]8BH¨‚€ ‚,ø".‚zŸ/'[(ºûœƒ ,‚à4‚ø/ƒp/ƒT08Œà5‚È΀-ó'È@(°!›(à(¤ˆ{ðX{‚€‚gA³±¡ð!›€ ‚ZÆ‚iW‚€÷i½;1ã¡Û {‚s$‚)±ÐàÁÉ„a|0 "¸Œ~3ÃS}¸ÌР‹À\X¢° [9P!‚8è1P&ÐÀCÐ0x3Ð@LƒØO†(GÐrh[‡(=…XoYÝx^‡pL y„«N„x_ˆA¨sµ¨r„{Qµ(z¥džb‡ŒœhDʘ;ðgƒ0FØ(ƒ€QqâS!ÁØ"§ø€øœ¸.·!ñwŠŒÀ-à +.k4 Ž h6€’ €–€¸–¡£t7(70 Åü H¬ Ð"°¢Éψ½øRà8 €ýÈ·(K@ ×Í@‚x#h˜ð2  `,x<¨`}†qø[† @a‡€J pW†È@„Øbx>Ð/ø:bÀúBòîøH$ȸ3@7ƒÀ58-(ƒ(> CÐ ƒ°>,ƒ0°2š¯´À=„@ L`G…H,„pS‚ÐI… 2…_PJ€0„HJ‚¨Ax)hW„¸^†%QP[2C šÈ qòö‚ (+à*‚€'‚¨)ˆ+€(e¸(Û‚‰Ù#Bw¸ ͺa€M-Ò»+‘ª‰i#ݾæÑÒ‡(Y‘H¸Âƒ¾ p[P#ø*‚Ð3.T 3U`E5žP4„ UƒXCh1„R‚à9„¨/¸Lð;ÕHè+ƒ˜L@PCUO‚@.Ø‚°:Ú8cõ‚à>À ?‚¨3 ,ƒpGƒ;„¸+XA¸"™(°8´Œ¨988˜x6`ƒX˜18’Ó­pqˆ€5iH’/Q{WQn"ÚÞÉr‰ã6‰®°€Ê-œâæ‚æ@€ÉuCyÊØ€è 0 W –Ê%`` ¾ø H#Gx" R%Œ=2±8:eÈ6‚|K'Ödð&‚%‚à(éP,ð72y˜x2’˜2ƒP.2˜-‚ð&-Ę*è#‚›¡‚ŒrˆþÞF²Ls‚s¡ÆØÛ ÐÆp!Æ«)Ç8)ühZᵂ¶!s%‚i¨H= Y$rÒ $£ Ë.ˆ€²++1— …¬…W’.€°€¸¡ð—ª\b³@¢ˆ"Èn«x(`Áˆ%ƒÈ‚ A¨-Pƒ H„@U†xJ…øu„+[ÅÚðWô‡8IøwÊ`zI{„H^€?…ˆrWD¨q„^‡XL† xðd˜T˜~„ëX‚¨4„àØ3V'PLØ …îÀ²×¨ €Õ€Ø· 3~÷¢âç‰È Ð L‹q¡#zè.–ÝÀ¸ ‰¸ Šˆ„³/5¸ÀPµ-÷4"àª3s…¸€à£ (# %€"òð$@˜p¸è7€ƒ€V†ˆr†xø`äð^Ð…xeÀPøv„¨ZCJ;•…ø6„Q‚à0ƒ°%Ĉ °½6FÐ*à‚ø9^3X!˜˜Eð88"h,‚˜2à58)‚ÿþ¢Á(*È[ƒRè3…8a³è]ƒ\äA„`)„¸[…èbVO‡…ÈoøZ†À…`h‡ð)I€éÌì)Ø"&^[‚˜.#Ø.‚¨+-‚à.‚Ø-à,‚Ä肨#¤!0+ÑÐ-À;ƒ°)ƒ4xºˆ(Úc! ‘çt$‘i ‘Q )Hýha¨a²¹8Ú„Í8QÄ0gMòF†yƒ¨& E‚€2¨.„ ‚ :îh;è*ƒ¸ ‚¨<‚-ƒíŒØ&ƒ5Nƒ9ÚTø ¨:G4Z/¨"Ùƒh‚9‚,ƒÉª Á(2„0-ƒ{Áƒ(=²_°¼¸<$(;•¸9’H48-Šx%€øVИVÀ(" )s¸®‹†¯ ¸ñmœÉoCXž³áyžëz/¨À‹.}Ø€án €—Š €ð¯ ‘˜‚8M™Wîp'‚(!‚½8(ƒH'x2[¸¿‡ò–-* c+M¥ó¼Èf8˜ÍœÜ]2Ëã)J.J'—äÒá’Y ‘‹#ò1\€G*HeAé¦9 Ç#ò„Ü¢?—Ï 3|Ĩ>#ˆDb‘ ’N J`ðŒK‘ÉcâI „M ȤB ŒE&ŒÆdh‹ƒÁPd0' Äa0¸ˆ&½„—[½Ì(C `K††Ä#\Q6(!†Ää1̬( „óð̶Œ-”È¥‹e(½u .#⩼V7‹7-tëH¯Þ)&#Ù$Â{¡—.ÓÒ±¾yS¶ÊÆÒ1pçR2^‡”« hG< G…ñ`àª,ÄBò@TA ‡añ0è>$‡Äc è„ZþòÀÈ4ºA(( `€&Áà& ìHB  ¸2‚ ÈJ ÀpÐD C¸N ²À°4@Û ‘5!@%ÃA4.ÄBÞƒ!`ü†€ØJ„aPx†(J ¡ j*¨Æ)E!²zŸæÄ—FÉþZšáFaárs’%q¶E”†ˆþLC¡YD<,Œ£ ˜%‰¡àpÁˆ\”"¸ÔŒC€\#ŠÁ`¦3…㉠†#(È z7Ü=‡Ãxè,¢àúL Ä©h0ØÎS#yZb p4äàÄU™æñ–wŸæÆ—fáþY§ùZg¥Q”}…Á`ZÁ x†ât‰ˆ'‰"X²) ‚ز,Œ‚ðÀ2 CÒ2Œ£0Æ0Œ¨@€+ ှC £Ù"# $^‰ÁÈn$Œƒhú/ÃФ.BX¨/‡‚8œ†ÁÐh¬"$ö!X†°„!ÐV…ÙNF¡°hA@Nƒá(Z†!˜`îØbˆ¡@d$…aˆ†"0T¡hf"! ’B p!Œ!Ø 8Ââ #(l ‹Axp(Aஈƒx% â¢7ˆÂñ'Œd”/âˆÄA #Q)ŒÃÍ´& €@‡aàÜâàLŠÁV&H’Â(B‰€x!À6†@À:-áp. ¸6Ì´Dàë ¨4CÀÌD Ä@À, °< ù>@: ?€Ä* 2~°NH°Kí{=¨8 ø<ƒÁh…aÐ[§jÉÈ‚/ˆâ?ä# ¢`œ6 "€ÙžŒ ¨„0VÑ`%Z©¥ƒÀ‚`U p/ ÎÃ(k!¡œ9ÌAÃl A€5€ºB°Z ÁL,p¤ƒ(N ¡€$…º‚pV!*ЮIB¨CQPð’… „JIEÐ,!  XBy( ÀöàšÂøcH&„à†‚ :Àˆ Á¨>à¤jÑà@¤ —ä bËÈ „ €L€p Lã À‰s-àµà6 Â9ý ˆ PÃIš ì0 Ä!ňˆ#pI ¡Î!áb¤nj Eà"ÜtÑv;xÀ"DaA"/‡ˆ„ƒ˜=ŠÑ¾…Ó '$Àò Aø`@ø0Ðv`3 ଄³ÎA+àƒ´JA"€t:°@ €àe¼Ç”2ø vB DPí *2Eï Ln®ÝH·v H*@tÏÄN ÀºF &A' nÈ àX€è)wÒ"Hä’æÁð&!`¢Â0aÀ+ Ø3j Ø7b`ø!Ž‚ªâ áj†Äà c A˜2±Ò ¸wAlBÖÑ Š¡l>ð’ApA T.‡0Ò haö†ˆ y1àèhÙ€;¡ -Ј¬_@Ì#·ÀBH`¬‚`I‚€= ȳš ÁÀGÔ%‚„Ž xE༠€\H/ ›M€‚ ðÃk `À vÖVˆNÀØ(ÌЃ9!.ˆ˜HH ì#]€žDT B!¾‡@xR‚ø2á‘ö… L ‚¦ Àƒ¬DN0œ°@)8à±æ ,Q FÉÛ IÚðÀàj¼ 4òØušáwšÀøàƒC04o`qé0HðcÙ–€pÔPøAlå ­"ZÖ ðXA$„Ð×nÃ`J !¬„@ä ‚j€Ä%‚`G‚`0%Á`¼ƒ@‚ Y á\4…ðƒ A9†ÐH¨w ¡¨9H0C8q ”7‘@ÖÃh Ál2…°ÂxT <0à¤PN A&ª¿ ‚0U,!L"꾊8Ná &–‚ý¡Ý. (>쀃Ðr¨3ÀŒ0:qül'€ #Ê4Eèh ^óX.ÜiþAa‰zP¾PŽAxO€Û-ðØæCÐ' Aì4‰h"…¨ßÔr1h9`Ü9ãl@‹À!ŸåBäuˆ¡v;Äq¾ãyËêƒø±A$74 Ê (c€ü/¶Ø é‘ä l ‚0P& €tD gAk%°ÇÀ$ÍȺÌáD³ó9‚š<]“·h‹Ú€)H¨#³@©Ü»sc€EhN‚8ÝÐ#CÎö†Y#ôô9¨;PlA_”aÇ„ðÖ"Å0ƒ”Uad4Gà©ÃÏó±'Ú„8¥aüM `ì$² Ø2  î² ì ¨ h x­fœ ŠÐ ` Àì@î`Š  € Áàæ€rü€â@®!. ø!ÀÚªaxãžÀà!šA”ÁþÐá|þÅŽa˜N8!<!ä!ŒÅP€ …ãQ¨Èh6ŽƒÉtA%‘ Ebi@¾Y+™Ë¦"Y`Ð/'›„äƒ`¤”r–cs"* ÅQˆìž.“crnl˜/†#òàìh&ÐóJ0[?äΤbÑä’c@”Ìè‚1tì7‘ƒ™,[’‚q°¨N1" 3Áà6"D" ¸x[ÝâP¸kÉÔ †Da`àd, |A@Ø|* ýÞÀ¸\@ ƒüNÔ ¿(4 à8Ðx6PXWè6ƒ èRî…Á(L…@vHx"‹Â0¢7ˆbXâ'Š f"a¸Ž:2C8T¡@JRáhH…aØnŠ˜È*‹£(¸/ÂøÎ9Œ8ä1ÀÎ6CHà=C€ò2 £°À4Kƒ0æ/p¸2 ‚ÐÂ4 ÂÐÆ' ƒ’'‹’,ñp‚" X¤ ˆÂ`€% â%ˆ"pˆbPq(Hª%Š"è¦-ˆ‚Œ…¡˜lÊ…A@jƒ¡\& è^ú† Ø<?Á¸0†ïðl ƒÁ˜( È>•ÓîàV !X.†¡X%ƒá˜¦†‚°HŒø|5â`ø7’æY›ä9jreÀ=•¦øòT$ ^p¥‘ÄBçQ\DYxx‘e±Ô& „p^ A°~0´ØbŠ¡hl)…ᘚâHJRA0t„a˨Á(p„.È8>A $ÿÀë¸`Ð>>®ø<Àø` áx,`^ ÁX3kZ¡P* …Ä6ö6¨Pû„À¶É·m`ÐNú •¬ A@'¹Ï6Ün›0VöZ¸V „ýÉœ‡Vˆ†"hØCÄ™^m%ñÐQ‡i/z¥A°B”&pþK˜©Z¤)H3„¨Â:¢ØÖ:b‚èbˆAp‚… ÀÈ;ca!dÈ 9’BÈÒHâ8ì?ƒÁ -‘DÐŽ<’ù27¦ù ^CÑH_Á¶tçþaœÇùzmŸå™ &9ò'EøðBôv‰ñ‚<Ä€®âR P^  40FƒplAà=Á à”O dŒ4‚@ŒA(F  ˜&‡@XCð/ B`ÄÏB Ž  ƒ°J B"ˆðàXBÁ°Fa'ð¦Â`]wl;„¤AèG á%¦„¸R ‚(!…àö] @ !ÔpìBÐx A€@°Æ!`ha<5ˆÀ–„`D ¢!…ñij7á@8˜Ax= @°„Z ‚(,¡šcÂÉ™ ¡ 1@¢„PD !à Ò‚tŽè&…àüƒ(…5áÔ@—Â9Àì0`äPCäà ,@2šseAà`‚`.;m`”ö (€Èh ©È¯–ÁöWÀT£ü€Hmµõ´bkÀx†¼‡€Ó]¬ü ä®`$€´Pf AP? Ø(À„ª˜t P8“ú:ƒ5ºa† ^ÊA1Ì9ÀÄ‚ \ A06ÔˆKขÀ` Ai>ðÔ‚èq a„9çŽph¡|2˜ÂØb áL-P˜C@Q á”%à¸BPXA+ŽAèC­'VœBJ’ ! „Š P2A,„¢BXT H/€¸8Màð!‚°T A8%@hІ²X[-q¤‚3¬ ñê`Xƒà.ÁêÁk%­Mðk7Ö€ÀtÐ6 Â8¡1o`LÃh: B7‰Á!ßÂÐráX7ƒà­AÈQ pê)F¸{CpA AÌ!¨ê‚ÌsÕ4 ˜THaM$„PF ÂP'á ‚àŽc“ ü‚@t6ÀŒ3@nÁ5`tp2 À˜¶¬ @®ÖãJ-(5Àbâz ²–e6f³mÏ()mØBÛÏ P@ÚÆ-Ðú-t(ØÁCnm dJØÁ8Áó—| @È T ɯƒ@è.s‚`r·™h1 lÔ™‰1l#p×âÜrñZ7„¤AøLŒPð$…ÐpbÄ5AFCЕ ÀAÒx\ð"`|Àt¢áä"‡A"ž ‚HU…Ðú'C8hØ.ˆ‘»ƒÈcá¼`1*.x€Â€_Žö3[óCü\qþ+Fhü#z ‘t:„ȼ‚l_á*FЄÃLA A¨ Ap1@Ä‚p ’x8`è·PˆÀð= ˜£àšAXX È.ˆ€RÕõVVà„ Á˜I¦!<ƒ€  ÁØSè(€lP0¨„PzB˜G œ „ÐÊ£aNad9‰`²D¸\Bd-‡A4C¨š ÁÄJ…Ú#‚gA03£X#yp !¬F„³ZC…ò¬… BÃ$• òh#`X8.଄ Zgˆ@ ÀîX„ÐÈ"˜h@ô*0dBè8! *‡ ŠÃÐB•|Æ]î‚€SƒÀ]ÙÁ(“Ï ‚\R3\ËW#MVÆ &¼Ö:íŒ@992K{Y0Íð@ØÁ÷Lj ž¤ âÀØ&kí¤e%jª¾xÿa…UÖö@u©PF A$`˜ƒÐLŠN8O.p¦AØQ€à$ lÃ`4ä|†@R ‚Ø+¾ Ž 7è-}¨"À´ía Á0+†0 R !Ÿû†…N àž  Ì ê¶ `¤ $ `€ º@š«à’ jú  t ž@€ tà ~ €vRh6 À| @ŒÀ€ `‰ \À–z à„À¨ ž + À¼ @Ö àÒ à´ à¨ €Ð ˆ@<¶²ƒ²l>†­ *[€0µ4€ˆ N <¶¦” " f=€l@ lñŠ[€*:«Nà0W@¶ ~@Œ Á$a<¦ !AÆáP ÜÁ² á4Àüºaf¡ÒA„`l  a6”á€t "ò ´ûàšÉ*`X¢vJ àF½ZÀ†ÎÔ`†  | ò ÀÎ3ä x €Öt `` º¬€¤.Ô€°˜ a ¸€xÀ“ v¶àR ^¤’„Dk€NšŒŒÑÀÊqœQœi®oD=€6>€6È@<ÉC ©ºjà>k€;à6¶ìW¬.Ƥ…’€@€?H 8X€7´/xDY„~Dó>f | ìð@œFLS༄ Àj €úÀˆ àb€ÈÐ`Î`„ Êô àVÀŒý@våd~ àŠ  ²  ¢ *´ ª `’ P ¸€š `† €³€ª`Š k5jÔÂÄSà”Àx "² )† `tÀ‘AàŠ8'‚c@X@€‚`Œ€oU@| ˆ ¬ U ép €Âä¡á  ôBØ@F !`v@4@¥ kF¶Qœ0s ~;@z  p<@lh j?Àr™°Ü@x`I\ DE² €8 Æ`„`”!6¡Ha^á áÀá``ô!¸ !<úA²a\ò¡ÂÁL€j ùD@‘ †±øg,®1NYå|ªCºà=I kà^œFÄo5Â%¶%ªd¥¢ÑœjÀ2Ãè²æ¼o %éÊÇ+n=,T<ÑÚÇã´ªÔ1˯+,x 4`"ǃû0ªh`@`0CÞ€àB€.Q¹n¶Ñ¯,›€8ïãÔ©ª„(é à>¾À¶!2Eã-¢Ð÷#Á~!΀þS– ´ ÔÀÆ `æ# ö `¸ t @Ø¿À¶µ  ò  âz!*€ìAˆÇê bíbØá¢áþÚ÷|Ö‡ðÁ˜@æápa Ê!vA$aÆÍ!®ÈaJ­šA¦Úi.ˆ2@D`²€f ñ^ @JÄÀ–€P Àò@®B@Äð nj@ŒH`†r ß ¢DËÔà H..óL ÀP¶Àœ m;``”à àx €ê ®‚ Øà°!2 €îÀ¾B7Á: F Àì`²Í$ ¡$£Tè¢ò†8à¢øà„¿r'`h R.œ`R“¤’Žž ÎÔ `‚ àþ àÌÀŽ ÀŠ 4 @\`¬`š `v €Ø}>àÜí€î î-€èU$Fî`‚¬ÀŠàŽ \3HYÀJ@,zqrg#ØÇ ;E ¦l`:>ôZiCî'»n<È/ƒ å|A @x,lIæy6º —@Eïj€T@F zmÈbàT€¢9àœ’ðH&Àt  æ`˜`hàô@~^/¬ @ó„ ÿL ðòdsü †    Â@Ü à¼ $©À®« ¤àœ @ˆ à£ðH S@›žšb¦€’jáTQ€fT: £LàrïjôÀXwàZ˜à^„ `”8*`¬± ®°`´  ¤ @¶ ÀâN¡ ò Ì ` !l Ò ^ Ád`Ä V !4„Á €¥‰ T @*`”YÀ€›àtmÀvl`pj+G0ÞkN@4À’·@¦€v "F ªaN¡Lá áÑ¡Æá^@î!¼ ¡>ìa² A8a € á @‚ tg€v  n>àbmÑ’É©¨Ä @ &`Xhl^k¦¾Z€8;ìšlléÌ[LbÉ,à.>ÂCú‰Êô .hQÞ=öÛ  *ÀEàAnÀ>z³m€#nà-n›–›Û‹F†,#n¦¢à-¹;’›ÐªÈTLÛ­iس'™à`›là`@¢&ºàZ xaR¡,@øaá Þ¡` àö ¼nt  ¦,¬  V "–À–"  ò@¥  èaP¤!–áþÇÅmfáÈÁ~¡‹Å¡†!þçð ¡JêAr aÉÈ¡Ë,aÎ-K-wØ—Ô¡A¤A>ŒÚ 0À€¦#£~`· Ü…€ä ªàF ½)ù˜ÚPXN;Œ³ÀžÀ€œ˜Dýy¢ÀžY –`p mÞ `H àäœ6Ie€º@€ àT@¾@’ &L ¸KŽÀœp @ìâçƒC  `d`°9-þxT°.Μ€J€~-ì’à‚ t Æ. ª ÐŽ Áƒ@é=@¤‡€‚àn Ùš l ÌG@ÊZààØÀ®`˜ ]–®b"@†"@¤`|àF¿D›L™¬‘Æ‹DÔ—Ôc”IÑf©ØŪ‘vm`FÉ‚ZÀ=i˜Ø3• ‚7÷’Ùxàtk€zD@†¢d3`°à` Ôˆ¬kÞ n Ž à\ ­`³£ ÇSJ;›`j  üààöà @d `úŒ¡ á '*yÜ„  ¶ `ìáRàø  Ø `® `¸ ¦ ª®  À u$ Ð `x `Žt!S@ŽŒ€v@’— ” Š –æ4Ã*ÐV’Àd@Wœ (´0®þs ¢€Ž µ€ ÕP ¢ ÄôÊ àÜ  Ô¬ÀZ Af ì€Œ²Ñ¡’àâÀz Á~y!| Î` áZ଀J Á*àŽ@¡ †>àÞ´àŠžzÐÀŽ[ ži~XGN á ÍaZR ~dàöÀ± a:ÀÀš!’@¾p'`“‗£ÆÀ<@n `øÐ.„ƒbÀ \T Š ¢ÀÀ`N ‚aáxT:0 †¡A¡Xh2,’D!áyR %Â@°XH‹„ƒ ˜\K „â@¨XD ‚”p˜T@¦ÔØF¢¦RD4jÍD(„ê€$P&qâÖÌBA¡(T6* E•ˆpD2¹ƒ¢qèpTG ŠdS"Ö…XRl3Š5tgA« Çté¶‚ÌbÂyÉ©e)Ø®¥«iü»m¿×­·ó%Êÿg:_ì§ýˆà°Û¯æ#yüÃÙ/ÛåÃMø²f>•LG¢uxíI,܈µsy ´q£Õî"…¦€P´P>D¦ƒò „ó<ú›f‰†¤€àÔ£%ƒ’‡BÐD! Á”8…¨üà4ðTƒápŽ…â8Fˆ d& bhGð¾ˆP,ÁÐìSŠd‰|)“† ˆG˜)]ˆ¤AZŽD¸X/MÞbø`# aX€/aà´‡bVŠa@l'!ˆŠ…â@¡TsPLMsPˆÁPl&…¡à¥Œ¨š5Bh⊣¨|)Ž˜ˆ/!7Цøf"Œt°ÆI¨ˆ1Pà΂H¾@â˜ØˆbPf‡¡p‚!¢`”" ðJAO áX<„`à0€À@‚àðD `úî±–ˆ<ÁD „Ü!@Xa0>A cˆèÀ©g€€ @6@ Š@t° &ÀäYÑHšâ!U‡dØ.J¡R(±¤œ A,'¥Ô  Nè)-ÀÐ  fÁ06†˜€L¡™¬D‹0Ø"E°f‚œ*†Á* ‚`t áÐG ±ˆ:E ºbðnáŒmMÐÿãˆß›á„q$§Rœ`›!€rEØÕ‚Üh‘`2G §CÀO ‘Ò%À#„GÌÑ(Æ ~ƒ0@1'Æ>" ù‡óæ„ðÍbhe¡,2À4 8$ð`à8 @Œ†0HC°% Áà „¿!A " äЈxD À$àf* Ü,ƒ@À"Xp b([„0 ŒA€P °ž}‚`˜lOŒà´(ÆxPÈ!R ƒˆ—áp>‚ÀŒhX] ø,`vA84 ˆ„t0Ó`=€¬UPz Á`>Êl@š•˜0B 82ƒpšAðNä$† dè+€˜ L Að-@ ¨…XB³ `Àjâˆe!H;„ ¼©à{ah:ð”Á`8ăŒÀOm%dº°@À¬ƒ@ˆ Ö8&XÄÉfP<´@è!à|F˜óU@È)Àt< …1¶@È ‚€s†ÑH;C¨¯èZðÚ)ÇðaãÀ*ˆÑÌîÆÐ@ã0‘xèÅX0 ¢ˆ…á* Bx€TA…`ê-BpzIâ…Q6‚€€Žài¡5ÃX¡ŒNŽðxÅÀE Ü[ ±P.ÅX¦b0C‰Ñ#X~¡¬1†`ÊBèc ¡`1¬‚xR a4) ”‚Ë[ "„ð|Bp:l ä„¶ÔÁ9àÈPf B3üƒ ‚ .ƒPŠ ¸G@ô'+0¨†= X&…°Bˆa ád3°¾ Óâ …‘L Ø(dBì7‰8ÊN´ ‡Q˜ØÏ ¢l„Á6ÂXáPHPÂ(‡Ðfü/Šð„€äôgƒ@Ö-ÁHRà„!‡ Jƒà, b;‰¡Š"ÅÈæ‚ðw!j:ƒè®ÀP î*‡¦üá< ApQ „FÈ7] Ígƒ2T ˆ°'à`˜JaÉt0!%ÞÀ]\…ÆA’p €Œ2ܳ°D@¨!±4®Ä(QJñNÑdÄx£ @qPš#ñð'!H… Bè¨]Ê´c( b!F&Q9È!!`œ‚0xh#Ž °6[á}¸€lƒ4 Ñ À ð~ !èQ†+Âàw!<0°rCÈ”ãÐÐ(‚$è+‚0+‚¨«ð¸@ƒ(?…X'Ø&à-ê­ñcÞÄKtP‘x-ƒqØ(8?…x„pb‡üKøBøƒØ[‡ø9pƒCVƒ@Qà2„ð|ˆG@ ƒèmà9† j=†#ƒÀf‚X<+(eŸn¸B†È)ƒðjh>’}X"P!ƒH^‚>˜,„€q‚HBø'ˆZ„@BèH„PH„h>ƒøJ„ @8M„¨Cƒà< 4ƒP3‚ð00,‚Ø1‚˜+‚ø'‚˜/1ð.h'À&h-8%è"‚ˆ‚(Ð ‚c6‚XÉVÈ$3P#3P!DyIÉ!¹¸$¸x‚*%‚È'¨-‚+»=ÁÊ‚Ð(‚¸$šØ‚9@%„¨NDxM…ˆgˆWÀ?„øi‚øB8ƒ€aø:†€#Èj 6!ÅÈ*„ u‚ÐM/…|ƒRà2(ƒQÀ+„˜s‚;[È7…ð"ƒ°^`BHD u(\‡¸B…ÀzƒøZ€;XrE0m„Ød‡¸4Èn°+ph(è ·áhÉf7p Š4b47È €°Ÿ€À¹€Ê È£¸‰Ø€ ‘N¡…8…¸R J8MÂ"‰Ð§€ ¬Šó’¢¢9p ¹r+Nºˆ¸€‚9 {—€ˆ€j)€r)¢¨ OZÜ"ð ø¹‹­ë Š(¨¹È² È– Њ €€j4‚˜ (€àÑìø4ƒ8F B…e°Hð&‚øC‚jGxV†pR†tpz…Ðlà_† }Øh‡¸\†€{Ðh¨^Q ^|èi‡Ð] |…Àh‡ÀZ†pz…€e S xø^‡PI…xo„(S°?8>„ðgÒ—ƒàN†h<¦¨;¦¨=Ês„Àc;Xaƒ°I;p_ƒ˜Fȸ'€ø¸(6$`H8Ø!ƒ²ãê¾È¾#(P"0‚˜@KÈB¨ [)ô‚pI#„€b‚@I03)8*èg‚pL†™†˜6…hk˜P†$Ðg‚ÈP)‚“‚XE…¨ ƒ°L¸0Ð-PÀD€¸&À'2´rÆL8“À+`‚ð” ”¢½ØÀ)T $*‚¨ü° —@I2€%Á¸$a>×.°2ÂBǬ˜‚¸=ð,ƒÁAƒ`(%Ð%‚µ‚@ ‚Ð%‚83„.˜-ƒ°UD†Ö &ø7·#åz#’Ú2>(“mœÈÈ>†:…Xy„€f‡ø@…ÀƒÐ[ø9Å1„ð{ƒOÐ/„à{‚ÐL°/è|ðL‡&„`t‚0@ðƒÀk˜6`ƒPd‚8?Ø)0o‚ðG2€p‚øE†äfŠ}@#xa6† q;P¸&ƒøi¿ƒ:h;FØ:ÐP„¨I…KˆBƒÈ=È6ƒx7ƒ2ƒ;@+À01Ø.3-`(à&ˆ.@(˜"‚@*"Y xð&È‚d•82¡¸Hø‚ ƒ5K)‚PØ%ð ˜#X-šx/3è+‚x* &x&8%xƒ+`„‚xLØ0„ØE„È[„ð[†ÂPXI…¨pƒ˜K`)ƒØ]‚­ˆ1ÉÔ†8&@ppF‡8*„xu‚Úò‚ðM‡½ª‡°.ÅP/}àN‡¾ 0…}ƒhUø8e¦}¦ܨzXRP?tƒÈS‡$fð¨57(!ºpÁ P€È7€’ Ã{  ›H¨:)º&,Mà•0¸·º·˜ r¸“£9Т²#8Ìö‹8¦ˆ €øˆÈ€ˆ OTñ‰ÄòÈ £C—O€à!3‘€Ø"„ïæG¹` Ob¢–H"h£dB1Oj.Šôý!ø¬£ŸºcHùo€ð“E± ÐH 0!Ã͆ðURXRwN†`5„`X„€WRtý¥È~Ñð|…Èg‡˜\†hx…¶j°fˆZ†`y…Àf–m‡˜[Py…®rxcSwà\@J€p„HTÀBj§hðM†`>Å4†H;½È< b¸HÚƒhF™€E…¸6(Zp¾€8"8‚H6€ÈþÙ]ÐÂØ` ‚@X!8 ƒ0ƒ°VàB…°PÀ>P„Wp:8¨Sð=…H%@XÈ@¨!``Ðû#nˆN€(àgƒS†x*=Šš>¥…ˆ4x‚ 7Vp)¸*°)ý8‚q5³« Ø)h‚q¿0 ×WÕxˆ(šia”øøx!“"€‚‘<È$è#ðAª0;È(€! :‚(,‚Mkè!à‚ %0‚!‚À$È&r´¸ >Êejß…ƒrX—ˆhD0Qqpƒ°82„hoƒÀX‡ø;žXƒbñ0°{>ñð‡ )€vÀJ‡.Zø1Z°&Hsè;†¨ƒènØ<Ìè7†(c5´È=»b†è+„hp‚`?ˆ(ƒÐg`<X't_aÚ†X%Eà&ƒèg8…ð$àh‚P=0.¶ÈB„I…0OØI(C0>Ð? :]H3ƒX.ƒ }ã -‚I«@'‚è$±ø$mðH(‚"‚p‚&è X›(è#ªÐ^|Ç1ó@°"°C½â‚#°$p.”}³è,š`)2Ýv‚(C¶J(&„°4R„`N…øL…¨låØsÒhë˜nÅ4õ£°3…¸ƒxd‚>¨̾ÀƒØkïèmxC‡)w°L¬µ¸+à|‚ÈN‡Ð1~Q/aµxøO‡è1…zƒ M‡8.oð7…ÓèX ˜4Ͱ$–`ÐÚ;ž4h£P›_s¢È¢“ ¨ °˜¨˜M·y8HО 0 ²#š%¢x8¼öŠh°ÏSŽ€’/€€`„xvI¸_‡Èˆ ø¨ ¹p x®CÓ’€´ïÆ<Ï ç‘ÏPã·†¢h°"øŽyhˆ%#–ÀÏ~‹v>@ Œ!dz˜¾ÅÐ ·H7xU…+Ëã¹… jàO†u…`‡PT†0v…»ø}ͦnˆc‡hX HV†0t…xb‡XW8wˆdxX†Xyˆd‡W†PyHa‡pM…¸r„XUå †£ÒèK†@<¸cè(b­7ƒ£ßƒ˜FÓ˜FØ6„H]€C…˜5 X8?…`MAø0¾€2€¸Jáò<Б—epÐ'ƒ°ƒðX@6„àá}@ZëdøB¸„8\‚ E…à+„ðb‚ G $˜b‚`JH7f(%¿à&èh‚·ó0Sx$„¨d‚`J†4¤ˆ?…@Dlà'ŒhKIâáñdZ6& dÁ¼Š!ŽÄ"aÈhL6‰FÁÑ Ô>"‡Ä"°à„XŒÂa¨T>‹BX¬¨~'#Rìžq$™0“Øø¢q¡‡¥C°ô°m "rTH#ÖAñT9 ˆB ð‚l&ÄBÑØpJ. YÃQ`\L/ E¡Ñh´2-Ï'ucèÒ¢}˜”â}P®AÑá¶?=6‰h'Uç,¥žed‹´ˆ}kM!Áͦ7׌ÍY¡’232ǑܙÄc«–ye’Nì²9ɈF6/È&U¡ δ#šDc£†xgÏmBiÑn‡C'ÑhDj ü}F¡H©àäf5ŒÈ- ƒ *‹BH˜,âX²$ °hœ*ˆ¢P¦ ˆâ€|!‰Áè€&‡!𒇢8j‰°t#ÄB(oáЖ‡‚`~"Š) B¶+ ‚ô|- ¢È’!‰!0~9‚Q* ¤Àx-’£áU¤ÑzL&±@_œåAŠx¦ØN—§0êK™¡8°W…‚ùp‹¥ÈV1—¡pÂ_#î2áØêg‰)Æ)’g€¬K¢£MDž‚±*yŠ$‘æ'Çx¦Hž4™ê,'¸ºNŸbÙ<}‰ä™Ú$Æðt;ádÄ@4 À¨,‚ ¸d Á`" @ (v( À$‚˜H‚¡ $ `ˆ*‚€µ® „ ˜-jÖ]² ‚ ŽÙ!(" „p(^è"ƒ …ì‚@Ð!}Àˆ7ƒ h#‚ Ѐ ø.…‚@À__@Ø ƒÀeâ€Íà`=gƒ`ˆ(Ù!<Ú íŽØ€ð( „°.@¸D ƒH0Àad „A 4‡@ÈJˆBèêI¦ñ^fŸ%™¨–¦ÉþWÇáVdž…y”y¦aä[m™’v•æ ÌT—§H^Å9voñÂW‡A`c¥‰w•éÒKÆéOšcá4e©Ž;F(âHC±^Žda|8¥èàEcy\$!h4¥€Î@•c8üSŒCÁ>ˆC: Œ”0<(4èR ƒÁ@~ ãðh=”Á²Bƒ‰<¥v=•PÚNc‘JeX†D¡Ù\ˆ¤Q€$Æpè\¢™Dj‰¢pi±03ƒ¦á A¹ÀŒƒ‚ð`4 ¡¨ Ê"Áø\ Ü%†ÐxŠ`K !) tÃ(+C€ˆ°> ¸# Ô„x¨Ô5 €pˆApC œ— Z]Ahภ‚ T .´+ˆá‚?Ã`§!lK´¤C ¢ bITˆÄƒàÝ!Àjô6Â0†a !„Üèos¡ÈF °Ü"ÅÈntÁ°E PÜûƒX‡¤BŠðÐ Åphâ¤4ÁJƒÐ¤ nà.2Â0c Ø*‚ï0:…å烷˜ä8=!<=‚@Â$(T`Ø9 `:ƒ ¡d ƒ ¼‚˜€²b´aj Ã诂[ù4EXÓ blhÁ2 „°É pdÁ@2ðŽ@øD‹õ .¦‚ Z°ü)pX/ ~Á€@ p¸%`nA/€ƒ>Á‘,Ĥ‚N-- ¼–øj ¢€4œ À¤ Ц *6΄ˆàD`:$@Ä ÜB!*Áa–!\°zá¸!n èaž`¾ ZO€F d€¢*¶ B !PÀ¶@\ avI!” î€x¼á ”¡Ì ŠAÈá@ƒÀ€áÀá`ŽáÐ Aµ¡à’áæ ¡"Qkv ¡4@¤Áôà`OÀFáà>å¤àà\à,YÀ(¾QPÀ$F<¼f†e ê[%ª¼kèZ Df D_QtQ^«ÍìA`8€$ÅFv_`¦ał멀Æ@º†à*¬c&b 1fN` &Ä*…ž@*`4XìT†1k拺‹ÂÃ`*ì(¨`V.Ú`@.HâX :€”¡BaFáæÁž¡j¡þÁ¾á‚!þ!¤ŒÌÇAFÊáHÎB¡¬aZÁ2šr&F¼Háat `Ò\ áÒAb `Ör‘(àÎaZ ‚ ¡`Ì¡N `ô`ÀF  ìÍRà® Á, @Ò†æ ,ÚŽC‚aÀlP< ‰‡Añ9PJ9 )páU˜â²PH^V ‚ãRhv€V ŒÈñIq /6§E‡%Ðè¢ÕÄJðŒa”Òì“™œ>D.Gh%™ ¶$£VÃ#Ú´v}UP*¡1…!#ă2Xä”` ñù@N1 ‚ðè„\ ƒ‚!xxB0½ ¢ƒa °x#„#RXœpP ƒ²iÌ€]?“LèÒ9• 5'ÄãBh´pTMCb1œfG3JGaŒP?# ‡#R|„A-‘Hâx¼‚@ ‡…°€q E#`àœkÅ‚ðجt*+î³J‰ò`M> È÷yâû8ˆèG)q‡£Ù¸†°\6á¨ØgѸÇv;šA°Üd†ãYŒ¥øP.A8¸^c9Š ¦ˆZ5™p¾_†ãq–Žæ¸z<Â@ül‰d¶-¦ ìL„œ!ðþr¤ È!g8†BbD)Ò$çh–EâYx D™ä"g`3—á(´V„Ã)p ƒ€ @€*˜L‚A Yà<‚š(æÁ À–§: A™ƒàx&À7ž €" çàÀk`ˆ0‚ °`" í`®Æ {0n~Õ·íÀ#¼û°" g;ð$ jÛ$À˜3¬ƒ`¦´qyà: @Ð  h*æÀîÒ‚€°D !80 À@ƒh „AÀ2ãÑC˜™ )T-†ÁCHŠ ¡”C„о O  dƒð4 ¸€äƒ`– ‚]d?‚ÀÈ#@À; `l08ƒ($ baR Ä´AÜT‚@Ð%ÁXn ¼<ŠÀl …€B‚Ä!f°aüV…!.Àš`Ì?‹@f œl!4E à\…@,¢œ? h…- "H„àâÁˆH€Ø' š¨F @ˆp< Žø!/€ŒÐFìÁP7À ‚ÀpA|1A,5ƒà¨W!0 „Ä0? „ Ô ÁˆP ”D A8.@À…ð\6¡œæ B([À¸@BH[,.…†X! ¼ °BuñˆÄ(ÀLìÁ@3€´pRB€Š âdvÁ$;x†¡ß ˜žÂZ¡ /8’!G‹à€#EØJ£ $‰„P¾"\ƒ .؉øC P„ Å{à¸;Š bEp0B¨%QT ؤ¡ÀQ°à'Ñ ž L‚àà&P€p¶ZKÀWeȃPP:`œðR Á 1d$)0„\HiD:´XÁ*‡©VA€= `€ @aÀï¤À°0` Œ¨!€ð¶ d!87‚ûB 9ˆcÁ˜;@à#ÂД X9@Z)áà °dÌØ) AØSPÂ%Ç@Pƒp#ñ¹~ò@à9 Pn†À<` å|:B ÊÂ`!¦ÀìþÀÚ€t Ž Ø`j EÔ šàÈ`V v ¬`P h¨¬`ä@f t! ¤áž€è|°VA˜àØ`ÚŽa`afÁÔAˆá4a®0@ÂA†Ðà^ Áp Ä ” A @ºàÎ €Ø @¶ €È €² @’ «^àž „›ël Zàz @tQà†À¬à– `– À´Àš´ Š å `z ˜Pàƒlâ N€ìà~àD!·Á"`„ÀÚ!ba4áᎺažAN¡ ’!<aÁ¦A&>ëÔÀH aF ¢`F !jÀ´ê‚€` ášþᤥހÖ`R ’À| ª@D áhà¦D !là¶LCÊ„àʤœ Ú\ Á¨â``ä0H``èj¡¸ì„Æ ˆÁÈ€´`. úÀ> ,‚ ÀNg&h ¢É€>Ê&rF¨rM8s‡<Ë'# "l¬ü8É€2m4À"¬ÞoÌøæÛ&gÏðlg' Âìê’†l`(m äÍlÈkç(kmgà4q&–p‡fgqÍq§Dg¦Ò&à8 2 ,€PàB@$ b@¬ æ!t2àøa–HÁ ADAªaFH¡J þŽ! ðXíˆÁ `ìA>  ð ¸ ¡ €Î ª Á àÖ¶Ü ¸Ü€´!<ÞA: €à ¬ á2 `Ò3FàÌ€œ A `À ˜  ø €´+B@Š €Ò¤ 05 ~ Ààa¡ i %ª H A8@ÚÀd`èÁtÀþàxá}=á|àú@~á`Èá`x!^Áàv¡j!T€lÁ`€î R 2@ÖŒ@`ZB‚ZàÒ n4@ÊÌ d Á.¢à:¤’àxŸ `x `SG#@N• N  €€.”  p Àî2€Ü \ Âðà¢îÀŠ˜ÀpÒÐ`>oR`@`^`PàJ`Œ`v Tv Ê )H | àâ@†%PÀFú :"@B z”„ž 1,Ì®g\’Ê2€hÀV`)ö@Ú!ö ,Ú*’àn!¢Âá¢E BÁ¤þìA¦¦aš@¾`T a|ÐT¿`d A– ÊSN@L ¡P@ŽÀ@ !Bଠ^¨`à@^ Á¤€Þh ÅàA `æ@xAšÚl ÁxÀ´à¡t8¡8°p&¨á(Æ‚ ä`P áX ¬Àv A ªà° `Þ   À¬ ¢  €`ŽU€†@z xÀ–O ¥@´ €¤ €˜ `¼  ª´@˜OÚ@‚àr€v ” d `>àþ|€M`8A·Á ¡Aœ!TA!¤áDA!†&áÁ„a6@\ J@¦`J ¡F ˜@B áL[ab ¸ê`l.ÑœÀZ á“VA„ ¾ÀF zP@@š€@ áX`š`A@J !vàÀ P AŠÖ€Î@Z Ì a àÙv1Þ€ÒàX až%¢ÄR5¤æàbFW>:  D ÆfÆœÉ $Ë"fxÊŒšr€@sœtNg2:kRdÍ&&¾nà0Ì7Ó'llèoÐmwÖmFômlèÍ ë~ìèÌý( ækƺpfÿ(†Ìq FÔs'(læ´gà6Ð'k '& $qà*†œrà.à(u8.`(`ZठÀ¼!B ô Á €Òáj @Ö¡x á ð†!&@äAj¸áB €ò¼ `Ô ¸   ¸ ˜ Ó˜ @ðœ€ø `¾ œ Á ÀÀâÞ” ˜Ì Ì Î €úÀ°@Š  ê8­9 Ú ž Š À€ ʶÀªàf @Z€  ð@°¡à~ 2º¸€Þ@àl¡?B¡@o? P a4‚rìaDf!FÀê`vV¡Ξ¦HÓô`p!N(Àä R&tRía4€ÎĀʸ`¼ V®Ì@@ àüà| . v<`‚骠h €NTn€ª3 Âorˆ  ZÉ&wAO 2uà,ÀT"ô´CàD€D… ÔàR Ž`l ôp  X  àÀ† MV €PøÀ0 Hu`RÀ>€20à0“çV€( @ MPÀJ`4 Z Vv`V z àä¡ð @À®!Øb¼ à¤P¯üÂ`Ó±£Áœ]ÑáWŒ S ` Aš ÚDJuŠ€@ <`ˆµH J´€T ÁŽE¢`ß`Þ]·f]Ì,œš—Zš˜ aŽd:€º l ÁP ÁÁAœha8A´a\Á!ž aæ`à€\ a\Àž»X€p ø`ˆ ˆà¦éWd`Œël Äî è @¤  À ª €œ `ž@– nàh ¢h @@Àð t :{ć! ¨!„!\a#ka’4øw‘ÁlÀü¡~ÀÄà> A:`–"ךàEàB ÁdÀÁ{Á•ÁžÁaŽàº&T F ád`¨@> álª€D Ad¦@IìN !„e¡’ÁÁ˜€Ñm€Ð`WvV£ Î N aŽÊ„ ì€ÇtàÈÀT •Hê•‚(~rN ¬žrŒ–@>@"&7Âjg€çAÍrÇÑ¿*ÆqæÙ ÆÄoRdÍ "lö  Í ÞÝŒÞr†ÍòhÎ`Î̇Ҡ.glÝ'ƳÑk&ÁÏ&ÌkÆáÔ8*g<ðFˆÐxBm<ÒÔà,LÑÀK¢À¤À¾ঠa0 €Þ€¬!> `쀸AR a@Ò!l  àá` ‡è àÒ’âÀ¢ îS Ø ˜ rÀÌÀˆ @l ÂÐ Šš Ž v `Ô3€Ú`œ•½ÊPàÆ€—ØÎxÎ’  |  µÜঠfÀNoX@`€’ x ÀÒ€X B…`Z àðÖ@T `ô`Ä„*õ¢T,à~¹tA]=ˆ¬aLàíB@æÀQ§âv aè.®Æf!R é Ôœ– < A$ Î&€Æ 4 A º àB áýv‡à¸Ɉ,/À„û Ž! šô ¤v©Ò…gh;ùøøÔû,@PC´v:n _îpîÀ‰h@–!€¨“œ€uáïD€v ï@Ž àt Ú X &k]  .ÀC,’Ì@N€.`*Êà&ÀIÖ`LÀ4SãÀ`p a`Òáö A(À¨aÐÁ p•^ VØ !£ÁŠÈà[€\ aœÀФD Mt ´ =‘·Æ‹Ö•X¡QácíAvÀÊ ¡µ 495FæÀÞЛY£#‹B$ΛÙcsk(bf`Œ «1QMNM7,‰fJ=ZÙM,ÛjEë…:´l¡ Ó²AˆW=­Ç†E`˜¢¢“T‚2ZhVEE‹HQ ðæ7™ÇƒÓ!ˆb&’Ìd’I|ŽH1‡ÅáxÔ ƒ£c°„p{ŽPñÙúôƒP¥S²™©g¢ÔL¤*qŠ|I.Ï¥‰Á«7 U©ñº)–aâ"dDJPˆÉÑ!)F )*Ä%5ˆœº»š˜ãƒ4\ecË‹¡Uj '+ƒåpŒª²•Vb"Ò똸–:%…Èœ´»™¿¨ÌËB“C0Pkh{Zc+ D^`ˆË+Á ]n#+—²\„¢ér f0X7™á¨æøŠåˆ:À€6 ÀˆB‚a0‚ €:‚ ø àx$E1\B‚ è ƒ@h àx2‚È ` Ǥj ƱÔg€!!Çàh" GÀ Àd6‚( 0 Eà´| r”š J Ô_&I@1‚óDzÎÀØ Fà˜6 ‚ Ð" ƒÀ`0 ÀA8„@àRb€æ³‚@ÐH #q.*ޤèÂ=9VŒ¤)b5¥…BUŒƒáD1¤¸š-áÐ’4¢(È"ØZ‹Pv+…!Ȧ†âVŠ!`v)†è¤°l °†+b ª¢°n ¡À|$†a¸z…aF„ D„¡ P Á@,…À¥ö „!€VŒ°¢8†"˜ò ¸Z<8ÔM¡TåX^8”¡ÀæP†¹H%8h<¡ìR†c¡@ŽER6“¡@ÚO#Y:ÝÁˆâNåäØN4!PÀDBé ‹DH:+¡(ÎFƒÂ¹ äPD1Ðx/ƒ@za@A`!…ÁØž¢P6ÀèFÐJ ÁX:Ø@ƒaXa LÔ†¢x^ 8¸†›pd$†BÀ‡âèT –¸ #Pn% ÀèVÃ`Ø)>‚3è&  ˜&‚@œV  ˜.¿ …!(0‰99ÇоMžB¡"v äIÐ"'|<›a ÔfI †X0˜pÆb7¦;zb¶…ë†[„™^‹E¨R/‹V…è' À„ÁHiEH# bÌát _p2 C<‡¬ C€Ña°‡ážBFp08žHÇ|âü…Ñh ‚°¨!XR†q /DH¤bl[Ž!<-Fè™X—¡*,FØC<8‰ˆÀ´¡€R‚€œ& I@Œ#‰FÄ`$"0ƒÑ Ä$aäƒò°ràÐ:hÁ6„‡PAø7ÀpˆtˆyôF qš!D°Áb<[Q+ƒ ‚á°>ŠÞ…s"¤=ájÄ·!J@&ÀøFfˆM‚–*Uà-‹cÈ1Ál@´3 T.ÁQ t&  @æhR'0YŸ±lÂÒ "üà ÀNÅà" ã…ñ„ ƒ8Ì!¤g‚@Î2çhÍ!¤f‚ƒÊ Ä`^áh¦ ¢¨Ó`p oÜ2 ð\Æq „)  4 ƒØ€É‚d€‚'J ˆ#dÑšMˆ¼ !€8“Q Li "´„@pˆý-dМ€€L]dvQª@ UP€8‰!€ú ÀÂuGu ŠN‘ÀŠG«Hbž 2‹À½#JiݦÔöê\w è»ð$ Ä èƒ uH*†á0ð¢ ðT†q+¡À°•B¼3XCð¦ aœI„@¸‚X@è&€pBø2Hƒ`œë‚`.u@¸«lA¸;s`ü'5Æ ÁØB`¼‚ÀT X&` ÜàD Ñ^78uà @¨ P @,Þ"€xàB BX2 A´ñ* Ț⌇QF Cx A´O‚ Ø'(l ©‰°Ú&™èœ øÝÀÚ%§h•BXq, @”Á°J‚€Ä#@øSÀt)ˆ8„) b aBž+ "$ÁÂ8h ´ > @òÁ_a‚ðŠ²‚P%á ‚p@óƒ¼@l‚p:ß"ÀŒÐL B@(Y` …@F B€#n`ƒàP ‚‚Ä ` „ÀN Âp/á;†°bBð@È U]ÞŠ‹÷CÚ8À°wy~ÀbÀÐ. x!$7ÃP¤axK¬$¸‹! BPx†à4Bc pN†0&€@¥õ‚ ÄûÃ(Ä|^‘\ &`$ ‚Àx þ!PV”¡FjÅ(% "¼…i€F(1 c4¤ ÃxÓ¡¼hƒ ÛÃ`Í-ã@÷Æß0g}!pY ¨*!$a¤WÁ02Ĩ¶BTX ¡,*Æ ¥&bÜfŽñj3Gp”ã`;‰„Dµ !ÌVÀÂ) œA0K‚@Š$ehŠ‘ ±ÐÀèØ‚02„“ %P‚-Ó+1Ü€ìú¼”P  À?HØÃE` `*‚èNƒpT‡à0„ÐyˆG‡X(„@uHC0"„rÈ>†øš ƒ8e`1†9¤øà_8/ð`PÚi>[k‚¨XS_+ŸÐ%(‚HQ g8)…€ƒbh÷p8†ºù£{†ˆhg£y˜5†Yðˆ4†Xƒ(aj8+ ( Š(3 `8R°H…pmÈZ†àX†(vP^‡ M`j„€R†xF f„ N†88„p^ƒ@C¨3Y‚˜<X#`Rð1Ø‚ÐI€)„ˆPCX$„ ‚PA–(D‚@3„¸-ƒÀPƒhC…P=„ \ØI…°;PW˜B…H9„Ì„(T¨D…X<`XóµNPb8SpD hX(…l‚xS»ø&6Úf'\2tFa`3;^ëfãeJg(HUŽJj½ÙýÑ”· 0†=ùP‚û¸¨]3ÔûÒ°¸eX5ˆ§° c(,Úˆ‚;å P€à „à ‚Oè"à0P<˜S,!ˆ2(_€à!˜ €ø*‘ò‘€€ÀCò€ëó‘Ûõzž*ùª'X€¥C€´Tªž’šœ’r¨Ôôà@D@=L Õ*ž“¯ª ?ñ)A'“))Ñ;y1“AY«Lž’á&›òè .àÈ!‚À?‚800' E‚5˜*°ˆ+xL‚´W°8Ð*xMVøK˜6„˜,XH,mø&ƒh‚.™^ˆˆQÅ‚@´5˜$X$´à#pøXHP—˜.œC بx€àÙâDè €øp p"€ð㨳ž=ø$pH9h)ø‚øC1„pÁèƒxK04„˜G0±.@ ±€˜BšpB=8D@2„hƒE01„hƒFØ+‚ˆ>ø'à ‚p=(à‚°?¸&ƒóÄÇ8&ƒ˜ ˜&›.иjî€G– ²ä‚—È<‚›Ð8 2™ÃÄŽ‚³PÀ)³È*³H&‚{7‚ÁÍ@h9˜%YµoƒZö;( à4i«‰~€™ß€¨ žIå  ¹z`/„xqƒPQÐ,˜x B#ðpô? ƒÈn:ȧ‹Â†*}ø'Úƒ`Ÿ£Å…x‚hV8+…°ƒ_(.ÈV$¼¥8°ZËá÷ õ<†¨‰² Ì´Ì`5†`ƒ@cX܃@cߨbš(]X-%è)0‚xQØ1X8„xbOhG(iPO†`Eàc@O†@E„ød„PP0C…d@QXK…m„€U†¶(@?„ `˜G…È8„@Xƒ;ð0”È2ƒÐQ…8øZƒøL…èB„ðb O†4å0AÐaJ…à>dX@È`0O(CŒHD…(g8S†€F`j›Ž°.8)KfX‚`Sð% H)x¼ƒ bcÑB*ˆ(xXU€ê\(E¹…xáŽp+Áý…àè` `1@ d(2†]! ¸]fˆaZ˜cH1g83Pé‚Y€ø%@Ñ‚M€À!Ó@!Ñ ÐðLS{– CÍ…À(ap7`ÀX€Ø„ÀÕMGx*Œ­T‘è*¼Ü€p€¼¡+‘©/’¢©Ñ5‘É ’U@EL) €Rš)Ð iá išÜ*¢‘Ãÿ@±(*ø•P’j¯¸‘š“©R£‰7* ÀÁ?˜€À€ð‚41‚ävH‚87Ät¸&¨<à*ƒà‚°@ @BÚѨ=à'¸H6Œ“./x `È”6x\˜‚8È&.Ìà%€‚%ð`í8   ˜°Ø ¸ÂÖØ ›á˜ 8p#ˆ*À‹„°×(D¶¨='h 3@"X¢ÐÐD6z1Ûs`PÚ@‚ÈB€ø*1()è[è ‚x?)ú„8ƒCÑPC¦Ñ¥h<€¸$ƒÀ X=*ƒè ‚0:¨<¶`@Ð(¨ À+VhJÁLœAßqX Ý ‚cDdO"ížLz.ø(‚€1€$,6Xx7ð)ƒ¨ñî·p0ø-È"ƒ<1‚€€µã«Íå€ñÛ ¼ž4  €à2?H³ˆ; Kh1àzOw‚@ˆi£ÈkÀ:†È·;k`6}=¶ 0‚¸ZŽà\ßè]K[c‚¢k¦ §b†'f€'…X`¨HR¥ÀT.^µða€5 8£sˆ@7†’a†z `T²X¡XÞ½x1…ðð[@*…X‚xREÀ:À;˜d ÀgpS€FäÀG…8h„`TˆG…Hh„s‰ìß… `8M…ˆm€TP¶-(M?hWƒ¸A>pWøI…Ð?„€[„H¨>Ÿ|„¸^„@N†0Eeä¸f„XÃ`U˜Hplƒ‡„˜˜Y†÷‹èM…°p‚2…£ÝxËçà‚\¶hîè/ÿ?±`b6_,»d&pTy¼°U &…p ¦ á…® …ÐË``©†ÑG¦±c\@§Þp…ÈÈà_Òg[(8U>F{gØøLÖ~€è"„òC¸ å¶èHSHN¼pUX,ô)ô^Ô€¨ö‘ت‰<€p €P‘¦”€^Õ_Å*Ú¬UKûÕŒÌÔÌ¿+úªÿ©Ò¤iÜ*ˆ’È )À€h’@‡Ç‘N”ü@©*ý\+‘™€œ ’Á.²+j¶ªqýá=‘;€dž«È €À›(‚Oå‚@ñx3S<‚˜È,hÈà-~Ð/oïX‚Ë/‚È–À*p'`‚XÄ4¸#–8#p#$ˆ¼zEƒH0Ìt7 ÄCxhb. QˆÈ.1†ã0 Èj ¡P>( Æ‚!QPK8 Ky24¤…fDH¨¬~ârqÀ\U> KHAI)ƒ…ðx¤}­%CÐxžxNá²qÜ#ІeQ‘ Ô:)žÈ³øà®{“ ÂÁù|R:+ ˆ©Ä"C:À¶Ø'C¡ t$…¢0¸l^ ŒÁÁAxðʲ/¥]ÂÁ$wŠiÞ Gl7AHÐeCa¢ c †až F(R/—Á®Z„bÉn EØL-(¦Z+å˜J-—Á0Âa‚ñt¨•¡ŒPâ1F ePF+–á`Àa…ÃY  æ°f8¡xäj…ƒq¦FpX5`Ìc…ƒ<Ä2¡`È`…c tŠåXP)”ÁP¨UBÑ\5F1Ošd‰`n’űÀK§ 2Z›äÑpqF1ÚV˜§a:Z›Ä‰Tjå–B“FüH—C¹UY^AåáI—£ñ$\ÖÁI–ãé(^d¹‚Bf!N™aHf’%I¢Hf©&W›™bm’…‘¸N—G”5–8§8 …¨L+–@øžT+åxEÂézŒFU3¨H+—ð Xƒ¢aT @8%AžV«E <+aµÒ]¢á~É0шŒ&8R28É’Œ†PJ1˜Áºa„B™l %¨B(•Á‡€”€ðˆPb0‡ä¸ epF-áXÊa1À6‘@ˆ4" p2àØÀX ``( Û( ¨îànó¿n@ûð °ñp*ñ@XÂp{#½œ‡/¹ï@˜‚½&ûÄï x&t@p!»ö=€*‚§` à€* ¸ƒ=Ø-ßï.Ê x~S@Õ„ˆ8† ðVhxâF „¡ˆŽ…â(Lˆ0h#a˜’¢(Xˆáph"„ÿT!Hn  Ô‚àj Áh6@À``A@7`¬ 6 ¸àÜ PjH`¨7À\Að\ À¹"ÐP |M1µภ@bgø)¡L… ì BÀ„alE ¶"ÀðYÀt&‡PBC˜& aÌ „ÀèB˜8=°€¨BP"†ð7€èH „&‡"Ê‹(xŒªÀ4J°S@t'Ř€±‡‹¡À²‡0.L@M l*ð* ‚°@È @Ih!Ø 0V 8(@¬ ‚X¸ dD.Áh`” À6Á0! èƒ ° ¢x6 ä…ä ÂbGP°´ ‚aA.P ¹¦çÄ P>@›€l 0>@¨%=`Œõ‚p< BQ£p)ˆÁÊ„Pç uñ9 v ŒeàÄ0Áhe`Á‚ÀÐ3(Ä«°…n B°³ÁY–0 @Eˆ bÍŒL†0' ¢ì„áR8 G‚ŒÁR B¨¶ %.Œàh‚t Ð7TNƒ`Ëá¨d‚àÊ1‰øÃ^#1€ Bø»dX‚°¦*8UK¬Z Ú/è˜b,UÑ:/`¦C¬R Ö+F@ð£w‰•%hÖÂŒeq80„•üF‹@ô#E€bäA‰¡‚ „È¿°¢õU ë2!ÈÀ¢taˆ20Äœ"MŒ1 '†8‰ƒ0GŠa¢"ÅHÕÂÌn…Pì/Ê(¬axZ€°,ÁQ¥Xáp ó  UÜ08Y`|) –¹‚0¢!R‚š*@Ú-X[ ¬-ÁZ Œ. ÐL†$ !Œ ñà1²Â2A%úA}‘t¾ÅX +õš°ŽB ôK ‚&Cj,ì ƒ‘Á°‡ èEÀ~%€àE‘DP˜ôv…¨, c‘HXp`H· 0ÀhmŽÔV䓨N©¾úåÛƒ…)È·†Æ&Ko@G/8Ø\€o¼€ç.ä@fjÍ®µ¹¸æòzKwtN„ :çéݳ|à\»ðè<®]Ø€ð 4 y åf 4}Àó X P4mØ t‚°2Á`@´‚@d ¨1 èP\ (+ˆ‚sE%P”Ð, AˆÆ\ÒJA˜9°D pzÀ>‚Àô ƒPy´Aà üÉ Bw°@Óh˜^0à˜ðiPeap@‚À¸!ˆ…Š‚ D*° !Ô…0üB {¡8; ’@ÈG@d!†°,CSL €X!À6ƒ}â€|(‡ >[ä@€‘TÐðÂnÁ5E äÂmäÁ–‡¦€¸= €WU0À  Š[l—âµø3l<Á ã­ƒ9BEð*†œ HlÁP"Þ¨…pCP4 Á¸pÌ AðZ@ô-¾0È ðU4 ¼ €(f¯g`H:À8`P»pRé‰pV!XHްРÐDã‡ÑŽ0„Ç=Ãi 6$0Á=ÍÆÃ8F )¾ ~õ‚:8‚ª. BÂ7ŠàB‹AP]à¬1{иŽBp­Gâ|„A=LE:õ—D%°^À2#X¨ ÐP0 ã>… °QRÁP` ¬`Óq„‡E÷¾ N \¬€X áp  a„!F!.¡Ìa‚¡HaÜa„8ÆAb!¡œ„¡0|…ba, µ!´ ˆ°A†:áëZ!A:¡ŠE~a2Piá<A –áV`Î&: !N¾ P ªl Á^Dh€ºK˜·€ºF j÷€H ax ¢ù Àäa<úâú 2 ^ adŒ@² B a~.ኾÁŒkî¯tÀÄL ¿ Æ÷aˆ]a‚à°NV6a@@ˆ`>A8€|à zà>!:g¡:|€& j@0¡$`~ 36¡: ”B´À=àJÆ€0Å", Ȧú&Þq¦ænGo‡>ìÚn&猘q‡uFðÎFä rÆô@ÍÌØ &̦ÆÉì²ÍLÐlqøu†Ìugjw‡m gDͧjtàÑÇw!.'Jvò$vGw†æxîš *€$BÒÀ(@› HM0ví& :q€<©j`rÕ `€F)$à0íÃX*šNÔ ,àXˆÀ\ x@0`fçâ \@,tâ„ ¦€|€hà.à|Ú zÀq,§úB€¢Ð¸|\‹Ã‚A”lRLC"™ÐNX? è a'CD“¸T’x “phŠpÍÁâA´6F5…Èf©ÌB¤PX€o ‚àHS?ˆ GÑ Lò#¤3@`€lÍaâYÄ2G:‡Ig ±ÆBAqP4# …âáxj? c¨lÃÂa tL8Æa‘¬0…nápÀŠô+ ÒxhL7 ‰FÁ‘ Â,ÒŒt¢ñ™(6‚Á  T8 †ÂA@Ø8& „a  ƒƒ$Iõ°XG:綨øîÕÛƒÓÛ€nynŒMÍ1Q™’$,®„ťؤÀ¿W¢RÂä@*–žV„¢yX ÅXD&A žWBé|Œ† J-–àðžT)<¥F&Á@¬Z„ƒ Œ f€b8¨äi†Ã‰¦f6š!`Ðep¨R0˜A`¾^„Âù|ÈáH¸Zâ±ZÁ`ºZ…c~Œ%è´=¤Fk’…¡ÄPÇA>\dÉfn…I¨D”&A M˜„0aÄÁ€B& N˜ÄaBd‘…”FfaR™„aPfå1œF”¹IG&QONÄñŽC“æAQ™¤Vjdñ®Š%8R/Kén‹E F,a(º]…%ƒ &,†aï`WÂ1F$à6"“ŠIJ`ø¦Yb´2-—¡¸`Bñ†ŒJ/˜a(àà…iÄÈ.àÐ|Jƒ!ù2ˆ„è6 “àÐrF‚Á¹ ‡Dn*K:dÀ8`ÈzI¢6‰E$T¿%Ð:&€°X9€ˆX€¨‚ ` º(‚`p èà `f°Àišè‚šà$j{@%£‚:жjàŽ¥¯›X àx&é8+¾ nõÁozè½Û'¦à–•½ñ[¾ q ¸kÎgஸ ‚€,  È$ ƒÀÀ>ƒ}X.† ¸D‚!R Ìð:‚àà>VƒÁXf„ÁX6@ÀF(P „ÈHÁ8X …ap&†  Xápgò†À°`‚ˆoò‡@¸fƒ! z þÀÀd‚È~°@ì!—Pn@ûÛ Ä ‚0lPC@à-€xY€¨-ðPÃá Àd&‡00Cˆ!¨ ƒàÖAØh ð2€x€¸A Àd"•Ј€øB d"rÚ Ðn…d „ êÂ{ÁL=”ØècÀê„@Ö8t …ôà`eø P@àhÆDPpÁ°.a ‚€nį`6 È€Ä ‚^pA8Ý‚p:x(á$ÃðfÍHI ¨! ZBØ$á  DMð8‡ &@ ÍL ,t@˜%ÀøDA:‚ˆá ? `n†p8F`ä:ppFÐ.CXq–“! êé‚@®. T@|) @*GÀˆ% 6ÅPa/ Ô²²ø¿*B¼„qIAVxM`€-  X(0 ˆ¸8P^°1(Ä8 0bFp, C5 •‚0—ð¿!t]pº.A8\ ¤,‹0LÅ€, BÕY‹°bE°* ‚Ø0Qˆ!…ÖÂÌq j8D ¬Â,S Ñ(HˆcC áŠ"øÆj)JŒÁ&*†˜‘£Zµ Q$+†¸Õ¸VQ'ZÄš«â¤hˆ±P4p©b>µ‰!f7D˜µ@¸, ÐLÅ . ‚Þ¢€´-,ý«¥ @P×Ð`\ál],¶0(€¸@@h‰‚\(€øK@t) 0:Ð! Bø.4R0—*ý Æ,@$ ƒ,†9¾Øaà /ÜEÌ~Eèœà„& èN(€È< ` 06 bp„Q@ø—d"ˆ€4”9@`‰hl#@¸;¥GÄFfÅ b²Ý P2DXE«p@Ë| )Ë6”Ñ›»jjàA¸µwÒãaÄíd¶ÐsAi@DµÖŽÞÚ[\j‡¯`œ@Ç@-±5Ö¾ã²3dpàL9,xsYÏqx¼ åË’[ÙÌÈY©Œ$êA(/ è$à‚ÁpG à¸"…€Np$(¿`ˆ.@pƒ—€ HX-nÌ΂°. [Ù޼PP € .} ¸PZ@ (Ó´f@°.€Tj2þ @àÐ €m˜Dàä#³| @˜ PÀ6p @ä‚ðž°[<:`˜ÁMàx%06Ct< ·ª$Òød€ô0@p@˜:Ü ä1BØvÃPªà18rÁ;0‘ÂHv`ð2ðl#@e!7BÐØBHu‰¡Ô àÆäC±Èá€:Àà@Ü‚ \ Œp2zœ ‡€rÁH:&<»ƒ7T÷€È".À àS ¨,ÁX°Ö Âhp3ê°;ìw08o@ü²Ç0Ž@¨&sÔ:Œð¨&ˆJã„!Ѷ pɘdPÜ‹ƒpÖF£PÒ0J† "äb í¯…|&  ”*ðBÄSàŠ(ü*H€©z/á‚‚­ R,ÑCwX#\°2ŒÊ?Gƒ€×AÄl4`‹Ævà¾àÓ7׈&H€˜.P·LÀ# "Ôü°P¯ÄÇÌZ°´,Á`AÀGŒ(«H¯b@V¥3Ä8 b,OŒ‘(F`Šã@HØ!)\*XÝBÔo‰oø¡h.a¶ádA,A²abA*P¼Án!:aÎÛvÀ¬ÀL Ê‚²|ðÀTH@ÆàJ ¡’J ·Axä½A:¾á*¦ €Œv)Ø@ Áp ¶Å|F Ë€´@D𠊥ÜN jM ÀR aïá L ˆ\«F B ¡rÀšÀ>Á Î&Hb€N î`*PÜÖaeÁ0f'€*á¼b¦Z…¤ fl jÚáH`V`hF”ÌšFŽÊ¦îi@(h€"ÄÌFm ®Ã (€æøÆ´læ‚mm†”mcŒÈ†’dž¦ÆqnmQTp¦²l ~j#Œpà$k€ pà pFΖÆÇ':p@,Ê14s ‰L²hÀ&@"!h"  x Àè`Ææ"Ü | €ä ° `j €¶À€àf@:~À4ŽÎ|`4“@(À`uò GÂ0À0Ò€0àxÀ^ ,@|} |f`* t€d-HÍVíf`.’€t €: –gd|€J :`h N0àR€: ž`~ TàÐÙÀà@Œ £¦ . È` (Ä`€  .íÚ Âàx è à"ÝGú @Ƶ Ì%ÀÔÚâZ àà–`4 HFá’ÆÝn  0ˆ@&bŠ"r @è„àâ-¢Þ@nŒ$£„8€2@ dÉ4GVå@H0ãylàN:`~vÀv J€4çÃv 0à54`F@Š©< âà– €X ¬`Bà0@C8`@7ÀJ• FÃ: &Ž@L $ @ Ø aà®aÞ A zA¸€àä‚pR V a˜àР\ á˜Haˆ?!~਀>@fà< !J/.Ft ÁB@¨¨+ªè`¼Å`/F¶2  ¤˜H ÒÀ` ¤tö \ 2F`«DáªÎÔd‚‰À`´¦²újv€²WJ†IÁj@²Cø`V ¡\ˆ¡fA&AêØ¡²%2EAJá¯á&ªA*!²ná<aÊ¡uLár¡6M”Úa8ÂP.TäanTâÁ6AÌ¡| âáš*¡XJÄ ùÄ0@ÂãÚÐR^@ÈÐB L@D N`zà:€vE À6 aRÏ ?pൠ€¹B@º`E ‹F…‹QˆÕ&^•µ~ A%ò¸¡VµŽ\À> ax@ªC šPxqÀ,a&bA0†% €.¡ `j«Âëà:µF<À j@6ñ]æB+î <a4€œI Ì@ ÀªÃ†´i&Šh‘``fÚn¬fm \l',ifšn–ræãìgÑ>Ŭ‰l_cæîÈŒNkÌBjg9læøo ’p1°,®i–lÈf— [ " R8€È€œ Á îÀ¢ Á  ÎàŽ ø`À@n ÀÌà° ~ `@ŠgìgÀj T`,`h@T.gâ2`,€|}IX’4@zÒ2$öîiX{!²H`‚ lè& `:€ª½·"^  @Làœv €VÀª`‚ àL ΀ R €Ô„‰)Àv €" º’ö@n `,ºò¸b Æ(ÊÍÈ`|@x nx+¨].¢Z ÀꀚÀ.àÞ€|‡},@p wk-ràÜÖ Œ²ú @ @mfÉj€<ëGz S2€4àV@@6ÈÓB@LløÍz‡`<234và4G–à 2[àžT`£8X Dƒ"ÀB@Z€B 2  R7`Vs Nš@¦¡Ö ÀŽaÀ`ø`lj, Áޱáz_a‹W$~EøÀº]iÚ—Se¢À}àrÏ"`àR\P ’#î‰×AÔF¯8àT A  Üö´Hª*ä f Ïr á¤Eá¤@ÚX aš~`À./š²€°ÀPW*bùlÔ†@°çH€²º¡‚Á6Á¡¤Sž!IKOì²ÿÁÀ$Øázá@¡ÔAz!G˜<ÁÔ¡~aC˜„ÐA9™™†yªyœjÞ`T áXà¶¥p@R a]FÐMQµx³ÀÄ`B> D ÁZaA>0ð j`4á…A0,P@¡ @¨D ávBéÃVd™> ÀÀJºEÜàF¹N •~ Á–¹K˜ðS…ŠI5h á…FÁ~À¤˜¸žÀ½à€r¼«à`8@€a*`h€*!( äKVküáp0á€` *àû©¡+Á).¡<à° GÖÒ,ZÀ±=F°kF¨kÑ­fìoñVs†þnàe†‚n6bÆìˆj6XÉÇ &ÀÇV#dànLbæ¤,›qqgl1Bpqr8q/±‘Tm¦ôrà5‡Ú `Ä Àô Ê!> `þ ÌA;•a2 àîö$¾ଠ ê@–@z @2à‚väXÔ;¸W H@…w #Ûš»šÀ~ÔˆøÕˆ€MXÕ`„i$Àm»`l 0¡qà²àŒ ÀA… b.àj!`ròp—2àH1@Z€4 † r „: B\ wŒ Ò , ´ j €&À¸@mvàl À* ¼ x`€ ëùÃÜ:(ÈXèd¾`å}Þ‚j¼ Àf À& µ@€ÌÀs- x ö "@Õ:`ns6l‘¼uBì   /§– ,ŽÀ8.;ì0àNØ€N`B ˆ.Š@SnâÉ©(à(/m j Ò – _Í`N@dàZÀL@j4 d@TàC&©\"É%#à¶@¦AÎ á@€aÆ ô ^a®Y!5š aq å´Y(_ ¸ @³`°6 IÖ ÁT4 f(5Ð,@†|ä‚àH xŒ¡X&!C?a` ½’дÖ oEf›}¢Äp¯fox@T  ô`¦a¬ àj„ÅÄ™:E6?Šx Ág“¥n¨`V al„0‡Â¡^ aA–¯aª­A®Ada9á8aÌMÐA€ž$FAÚA„þ.Þ4áKã~.;âAÜá|aDÁØ Ú¦´H8 J áeRêl ¡dD0> A`ôÐü€f`,z®d 48&‹f >v ÁlùKJ AŠ>¸Ú&/„=ú4ïþ¹£Z2Z<ø]| ’ 0^X¸Ý »¥ ¯ äH’Fcé«Ëéa2¿7»Öa#]kVá9Ç"UÄÕaqA €^(`è}@ø€*Á1?d9G¹û`@6 Æ´l³k@0m ªh¦µbg'@2q1]¬ZkQ–vRöC± –ÆøÇ’ŦæÇFù  škÌŒnÿŠo†ÞÅìkqsö¦ºq'!ù@$ ù'm®ÀÆñæ ÊÁ& `øàÔÁ@ A`ÖL /ä a Ô!P ´ ˆ àèðž‘Ccqø`b@ !q‘ C#B\j@ È!a© 07"††Ä`ÐÜ’¥d`¸ä—+)GÅ€àü²"$2ðp$ aº@|"„ÂÁà``J ˆÂÑ`„nPŒA±é.=.G¥ð ô¼B£«Pؾ—‚èDtb ¡’ ¨2E6aLá‚9¤*C7‡æ0ôΘAÂÒp0bZ ŽKaQ¹l$2-Ê' ÁHþ ˜Â!À<(„C˜h(„Ã"`Ð|Z C¢A¨tJ7äŽx#±”x&Ãâò`|\I‰‡!€ð»v' aÑØ\;. ˆñHäŽ$ Bq0d  ØFƒX x*…`°.ÉX#g–E‚ þo†Ã‰¬ FxX3™@Äbƒ¢¹p ¸D.á8¶_„Âá|‹%Ø@+á¨XƒâqZ‰%02 ÈnE¢D@@"“Á,dŒ¦(R-G"iRˆdÐB%Áª[‰ƒá¤%†¨d7šaˆêmC¡·5CÃQ f¨øUci,p£q˜‹ÅàR-— ¶]‚ár °L*a ªX„bÁj‹åÈR/á@¼\"áf‹%p”7ƒ¡"c¥9ªK–Ç2\œE xs”eéÒR˜QH`ž)…b§‰JaÙ&)äSÙ¥9ˆy!âQÙe~u”Ú7fT+•ÁPÀ\J%°KH±h eF(•ÀøQÁù.Äp8À°dAáÅú“`ø”Sƒ¢‰a0—ø¶_‚ñ~‹Æ B0¡(Âb„cŒ Æ@D2A Æe£‘–yaãÁ(¾b„#D0á4d‹%ëPXBaRˆÅœPƒÂ< ‡d˜.É †$&‘Ʀ à4ÐhE4¤(&ˆ‘ ƒ°,À˜X:€ÿ‚ ÈŒO„¹` e.P  h0 ¨€X q€ Àh àx.ó|"ó `u €ÎõÀ‚}'Ñ‚\x'Æ|L@XÕ¾ñý_Ù W…ÙMåx\`!Ù@Pàý ñ€ït}à ]ø^ˆƒèE #Ù,3å8ÔB”c1S„aYþ ÀÐDð9  üp|€È9¬•PŽÀF À$`fàÀE!€„€6HA,‘Pt@à: d„à<B€aM¯…À:‚Ð !Pˆg ÀØ Àl `>ƒAž€D ‚P Á1FàhJ ¢ m.à@»`n¡p_ ð.PºL¸a| ÂÁÈdÀèØ ÈdÃ@a¨PÖ‚d<ƒº`M Ì+€ðhÀˆ2 &d*P~ÀWT'¢ì@X# 0 ¸à"m¥8à°  c)Á,Ht„8 Áè!€ä ‚prޏè‚Ј¨P ¸$p¥Éçàr+‚0`AP9 Œ:Á<áf[ : &´å'ˆô‚Pf< [á;‚X€ä?Ž ^šÁ@kîe‚pÆ0ÁZÀ€' õ*‹B¸ºA\^ð°.ÀøTÀx* @:…p "” „0Á¸`""“‰ðP…ð( #…Áp’ø‚x Ò Ô'‡ø‡q¨ ˜ØÜnÀò6B¨‹Â8]1".‡¸B#T†qšˆ†@+ v @NÑkATZ ¤à‚¨³AXY®¡h Bê… Âìñp صalX†A0„(¤¢d\a>/GX¢X„`å®à"< ƒaA‡ ÌCÂAœ­…!d¸»Ád_и0A_€˜/ PH(b€¤1 š23Lä1–¯¸& ã…ᆠƒÄˆ™ ;€0S |'Šà6…(øl" <ÄØbR * Cø ‘—Èh ±$[,AÝQAPt@œ4pP€ )nàÌ>tŽ€ªÁ\XPl"€ 4 :p.ó@«Á®È €àx€0Ú9'2ðœ¨1âº×fèó(w€9È»÷Àô]>}xïyÉ;gˆì€{¥qîãC:‡¨žc¿Ò™×=~íÞ‹ÚuÕé’€p˜¡-¡*„¡ bR1(ÃAœCŠ@Ú"…@N €L‚ˆ…àp vX N@à%¸!B8Pp—@n@Ð9†ÀÞÀ¦IBÌ ˜È*„ÀàA ‹à,î°¨èS ü*‚ |€è€|`Bð*àP ‚HŠ À¨àlð> Bx‘  BÜ à7 j€±zk¡| (‚øÒ†nX@x< `4·@v€À= %¸, Z€”væa€‚ЖÁHK@Ä*ž°Z@L† & ‚ØÚSD0 Êh<  P@áÈ— l< Â!$°2 Áß  |„pJ x ÁP‚ÐŒ —j _µ‚LA@-`x‚þÊ @À p‚€<~€Ð,`lƒ0: ð=²Ü/a5‚p‹AÐi¨Y‡nhPw…axS x-2ÑH{-{JÒ8c¢Õ‡˜QBQ\‡`N…Øtð\‡@'ƒ˜_”[+ ]• Z +ÃX*˜q/€à ȰEÀ8 “ B€Ð‚(P&b… ?h˜°X‚ðc™d‘)žf:û˜èb/éž9™†BøÄ˜0°`18ƒ ’˜Ø‚èa(‹‚˜ZHU (Q£øO‰ðO€Ð ±„™«„( h< Ä?ÐH€à!› |€¢è» ˆ@¸ ˜Aˆ  3pH 86ˆƒª•8 ‚@PÄXZ$„ø @4€P€Áס×2úT€H €ÙÙÀ³±àžùï4 Ù€kQžË>œ‰íAÙ´i×‰åž ëHQÔ›Jã;«F;Gaã9ßñë4ËL³ÉâK;AÞÌ€hH#‚ .ƒ¸JŸ³Z„@U5ƒWƒØM>„à.ƒøPà(ƒ X‚ ,®Ð)‹«ûq· ¡“‚p °'6€'€È²Ãz‚ÂA° è+؉ЂÜ9ëz‚âíÚí°!Ђ80!È1%žà·ø Š€8€{´%H¢ˆ€è  ¢Ñ¦8°ƒ¡‚ãlè ,€‚ð Ò º5Á ‚1€¸ƒ*L( À/›S‘€)€€‚` È,€¸!ƒX0xJgŒ0 ƒG¤ð<¸È+‰˜.€H˜Š35€Ð ˜<ðªV˜ €ò$  @ ‚Pì‚)‚8%°=xè.)€ð‰hå²t¼àå8Šˆ  èòyýÐØ!¸ˆ"ø‚àN8B†ø#q A !=ÐÀn9†Èƒhh`4i”†8:…lÃ`‚xX'…})qÁ…jX@ ±ª ˆ xB ÀOA Â+(Ð].ùÁ˜Zƒ°M‡0N }„ødèPH(c‡ÐC€x‚èG‡pj:†À¸lˆ8†¸¾$UØ[µ0,…²ŠÔá,6(…hhTèYLYFp1à_`0Ø1HfHT†èOðvBÉfœ*-)†H{…L'-BÑ:Ö–XP­€NØt„Ð]0?„Øk°Yh/…ÑCЂ¨Yð)h°´šç„J逄(¨D€è °’!†/+È”W†ø† ƒc(d3ƒ’ƒ#Øq–8ƒ$KؤLìUôN;ÒA€ø/†$†º…Å%ÄQᦀÀ"… 0ûz„Ò „ «ƒà™±ˆÛó‹ˆJ YÀƒø FÐ ˆA²Y»ØP ™¨  2€p x?À ˜€U€Ú»™ hH€©Æ»IL\œë6!ßžiéx ¼š[©Ñ £N¡Í¹ìÂSHYÉÀk7HIÓIÄ•4eÅIIá4h´‘ÓÈì!Í4p‹{M3áá£N€¨H‚è4à5„HQƒX3„€/p3‚ð3ƒà/ƒpB‚à:¸‹ (,„º!‰Ð!K`¹±¸´ÒÙb3‚0Ä0ð ËÀ!ê“‚ð ‚8/€Ø%ƒuƒ‚@.€àŸ‚ðøÓà.© /#X5 И  ÷€¸O`¨  0 p(LØ*€°°·ø À.ÜãÍx-8ð.h$K% ø1³ž:Ô *x8`$€˜ƒ(€hÐ( ¬ÛÐ*„P ‚€@Há¨Àx'€cµžÐ ߸ " 8X  œ˜ ¢(» !h&=`“X!¢z]EºÐ.h"ƒHØ+8æ˜0¨Û€È €€¸}àØ8"Ê"pÁà,‚8?x$n‚>†Ðƒèoè@ ƒÐnX8ð4xƒ0f˜é—ð` ZHS*(x‚XVᢀãî’ØQKxM XH¨ý™*ð/Z…â‹—hÈ]•Jx=`)èf‚ 9†`ph¡7¨< Þ⣆ÈÔ`QøgPŽÐZ€ð,@òŽyH‚ÉD+ˆ‚hVÒ~…ÕxV('…jᘂè\h0«ð2ø ƒh_ƒàP†ÐJ¸tSà{8c‡¨TBv–‡ÀUX|…@e‡ÀTiXR–OB PèwÒÇ„°\Hƒ[”N‚è\8)X`Rð"„þ„†L<0 ˜C! H_!¿‚PUý7(ЍEƒ†N}†ZûXƒfbü&¹™Pƒ*ý%„ƒe10 TØíˆ 0†8É E…4…û …ª¾ð „ëï… )¥Æm­° ±Âé% 3“„°  O€À „ö` h?ÀÖ€A¥¥M8C€“&ŒJœJu©hN² U-… ñ˜„À ™Áãû> ;n¤€€¹ðGéÔÜÓáÑ€¤ˆ[áÑ5ñœÑî³;}´3ÊS¼ŽIU¹\ãH͹©Ø\‰ìHøuÎ[´”œéê€XÚXÝp""·à2@6ƒ =ð.À'3ƒ¸0ø88„8)ƒ8FHø‚È0.€ø"‚Ãt°œKp7P!ÞP!^ߘH0Çh1)à2>à2à%(@2æÁ‚0ø#ñ¸"‚ûzò`ø !’0(3 &PϘ ó§€¼ÈÏšS X€øP {¦P,Õ»¬‚È ÐÒ#h È-z5Ð/P-Í8,€[âj/«¬‚£ X @"€x‚¦‚ð€p ‚/¨%ƒØµƒ@$é€)ˆ‚¨X%Jb\.+Ž€È¸XƒÅø »Ñ€èap*8x%X•P€ð‚@¨+x#S¹ø &ϰíŽè¨í»;@€ðà""‚p‚%€Ø C‚hD „nè<†¸ÑàƒàpÈ>‡Ô{ápbõ‘Þ]‚Áˆ>Ôv…0f `U>àT#2?…´À ˜( È•„}'…‹†‚è_/)E‘ÃYJ(h˜;èðpè=ø8<öz†Ú¦†èƒ±7À>‚ø_Õ`^(©w+RàëôÙ2ŽU@W‰‡ç(0(-Ð)r˜…µoàA˜0 f„XW(Nx…@fÖšØU†x~…g¿­0{PyÈwÈwâÉô/;+hÀ‚˜U$…íÊæx•šàWp]{¹„…!†ø,ÐyšìdT™x18gkιƒ(f6½82™uŠ /ØÏå0TSvÃ8.ý/†Y eÚ‰˜M¯¿“„à °ø ‚(Q);ðK±¸H¹D ˜G²í€À!… ÐIùX>€°ƒ¾Ûü(6C…†(Í œB"3QTˆJ  °Ôü ‘B ¼: †€À  ‚ç€Ð8‚s@ 0 "J§ƒBº´Ð7ªÔÐ|ÒŸE°Á¸Dd³×-ÀÐx,´Ñn7 zÕg¯á0&´BdÞtGš‘ŠC"P`1ŸLÆÔÈv_Å#b褈b˱ù`:;*Æå`ÈàªCƒâØt|^̲!+¨Á²ÐU¡äO.PþؤbAM)…,¾“rîZYkðØ®”PRâyE‘HÀ‚ÄX¦ ¢@X‘+ƒXat!@°ÄhÀà N‚¨(át„`¼‚Y~Áh ®ã°!Xƒ`¬B¸¡l ƒÓN‚ø”„pÌ`iÁ83¯ÒÎÐ! !­½†àLƒ€& ÁÈ0æ ‚ˆr%, “°0À˜É|@6  ¸ ‚ÐŽ6@ˆpT@p1 à4…dL@x1 @0…yÚQSD\ P°ˆÂŠ& Ȱ—Pz(> ˜€8 @`"à,„ Aè`À‚h‰‚PF@„€  áI°0YÀ¸€x B¥@ñK@< @*A˜!àø‚ð˜ˆQàÄ%éÄPD˜‚0X8;`ÐJ@Ð#< È‘ @…8 „0 ¨Wat/ƒƒ(fÃ(5 ô*¡¸Ähé "oƒÀê3€k`È9 0fÁ»¼i€Ð3A*Ç¡p`BQx‚¸¹4WÐŒ)Ž¢áR§ÆÂ \‚d ƒQ`€ ÈE‚–+ [Àˆ. °BëÐάd0!ª CpÖáÄlƒê6€qÀÈ8povÁ¨t€¼7@^¬àföuæÑtÂоp_€´/A Z€Œ+‹pD…¨ ¢Ñ™ ó¸+N ˆ& p8. P«0Y°¸.Pg`ð7  ä&#¤K‹±Þ'…øïôx á|;мbd](+FàZÃšŠ†,Á(Nt#‰Ð:ļ‰lÐ6ü@àDà|&  H…˜# "ñÍ 0L†0% ƒ ;WL4A0i ¤3 RF\ …ׂŒÎ CÆ nùÜÐÄ2a„0 } 1Þ€ÅÁt`¼1Œ\Þ”WÝéav‚8¦¡M¾Q2B œQ°‚'¤Ë‚b@ ƒ¡'µ˜6q`ßX!p}€´:ÁÀñ¯`/€Pˆp( Ä:/ô04Á Âg.ƒj„^À¨2rPKð¨+Q€`"XIè-däPO¡° (“ !¼Àp)»Þ3— ‹6Ü ”ÝöS¡Ñ?- —ƒÀÀqX‹‘5Æžx¬N0Q®1ÃnV8Tb.DðøðA¼ª"d4ˆ±T„h­ àÈ. Þ°eÅ  ` §'P`|©4ÁÈU`ì,e#9³F¨¹LoÂ!Øá¤„ÀÔBPl¸A¯°†ÐDp% ¡¼…@à ŒÅ™ ¤'0VØ. €‚!phD1 ƒÂ!xH: C¢aÈdH5ÅÌ./#E€Ø°•B#˜,bO fÂh*d‚¢âh@XIŠˆ`á ì#CBX|f Áa@,4&ÀÁÐ ƒh áI&|Q‡@ÐxL ‚! xP: îÐh@,T°°Œr„²H†rƒ‚’dPAŠÈa± à5 ˆ£`p<3}éC!¬X˜~E’ Ò±dZP+ ‰$âIÅ\SF:‰ˆ§) âšÂÃS Vie‹MíAyÑ´28µ&–x”ÊÈX‚"ó>Y]Š«pÙ-R"¨$4àtˆ S±ò`0à°T@቉%@@+—@èº_¢áz R2™`Ðg#Q CÁ`ÎgAšƘ`8šáXàjCAž æXT2¾a„"Éx …øB/A(¾`Â…øP/á$*‹ÅàH,Á¬Y„‘bŠEB)–0ªX…ÉhŒFZ4hÔf£Y*æpèL›#ùFn…)´AFÙOšã)f†ã j eHP*•Á˜Rƒâ0¤¨2’@ÀtH¾ÄØ<&á¤XâÔ¤.˜AÀc„ãr1™ÁPÌh…C9¤€R3Äã)– †XP2A@Æd„ã’ †HGeÉÆ8J0Úà Œ 4mÛ¡ˆŒà¼ñÈ´_¢y^ Dà8  è~Lƒb@ ¥6!“à¸|JƒÙ D`.‘ fA‚¡…£Ð$ŽPê ð& ¨^?‚!¡ d(*Ž hN3/ ŒÙ˜Âƒ(, ¸¾< ÈŽQƒÂ¹jˆÄð,Žp&@P$­àPz¾¬ê€xÚˆ¬ÚÈ €ˆì `$€vº€†è;v×·ê f¹¿nfè»îǴ¶o €‚{áÂí›Èº|~í§j9Àv! 23¸¨ cØ9DÑv8*„ øR€Hd'°¦ ‡‚˜4Š`¸x*ƒ!ðªÂÐ6  ÈŒ1Â(Ò ƒH8% aš4ƒâpÔ hB&àø 6bhà CpT(Ž!H£ùŠÿȪÁHT¾ÀB ÕÀ¸@l r¨@ˆàH ‚`&H`ì  „€N@Ð*dáN€¼( \Àk¼@œ"€ÀLx%,”`F ÀP@0 ‚À Áˆ Àˆ©‚`RÀPåd¢<@¨%ÐZ€Hà(¶·æ¦BËh€\ (Ëé0 2AaW@lƒà4 àü ‚Px(92`þAÀ, AÀÌ ‚ wÀói¤F·j  ! @Ô,€\¨3 A '!¬D`ë "(t„ 8Áø~ Ä4¬Æ0Áxg€À6$V5AHl*ÅcÆŽÁ [t+ 8…¡ðÀ]€І(@èAgðL0t%Zx€¼Aðˆ)R˜ºap`è·ÁRÂÁ™d£PN±UˆÇXã\¡Ì3PÈç|ðF†(" £…á‚ Å|b#q 0ÉF#5h  NŽÁ(`@‘#‚`¼/R½ˆ<†z²†2"`Ä6 ðd†€/ c8qŽ C(Ãa¤`ƒðØ0Áèg€Ì/‹„Ê,(Y@”)Š JE$"\©:„°œ@ˆ$ @>Å % bæyŒD@& #$,ŠúŒÃB¸ ÃH£ L‰©-¡A|cPôr†=zëLd‚%œ Å'j¸b‚P¼2,ÀÄ+t…ñŠ ðÃö2{ <¸´¥îž¡Q ‰8'‚QéˆÐ.„hÂ(‡ð( C˜eŒ\90^@ 0€H‡à$ Cøaàa“1ðêA+0A”-84ÍÁg½¤³( CØ¢PñR°µ`ìF0B@n€Y¸kTq@5·€ÒÜÞ›spqM¥¸6Ö߆ k…õ¬¹|DÚkhMÓ6rÞÙ±chÄm„à[È .,âvÐÞ@h ­€ €vÀ `X ¡¸I…P0 ÃP|!øN Cž70`¤°@À°Àt RÉE Ð)ÐpÀà< @x!…6BüÞ Kü2ÀùKä ¨ ÔÂ@k}a±îÀDÃp$ /Ø#†ðPƒˆ' ¯ä'‡#nA|€@P@˜æ ÀÌ »&€áD,Dp_Aàáy À¸- DÄ$±ðŠPBè¬àÈ€   —i`Á( ‘ñÈÿXà´ð`@è6ÐÐ ÂHb[HÄX0xÈÈh@X+ «lÛ\F Œà6ŒFsX ÀèT‚ð8 ̈ |€hÃP/ÁgƒBúÈ€`† „pZB˜"á.±ðbDXIÃ&ˆ±ÐÄ8ä¢ q€ø7xqà1Œ$ 0çØËÁ±]†±¤ ƒ8ʈd*áŒ ÂØ¾U"ì…Qj‚€®·b Î+p'@¸@jxJ`` ®°·b˜…qpÀ¼®Bø!‰_FH)Z*Äe$qáF0!Y`”1-ä‰izw•§HcyAˆ²¨ÒÑG@«ÐY2½(Îsñ^ ÐNwáÝ #9—ŒÚ@3=H*ê‡Hêñ¦ CxÒA¼hƒ€ C`ÊD£* PV† 'œ*Õ°”(AE „!  BÄ©ð>A(QÀª,ë¼Áta¥‹CÆP& c5\«Ut CJC`•­˜ê2¥…Z¢Êî[ÀÀ B ãÀë‹J¯+. Ꮅ†E´¥0[ 6 á’Ï.µ ><¦Š`2 ¡Z¶Á4à~2û 2> 0¡JI¾@àt@,aÀp†P`( ò P °ˆ ë¸$¡$FTºÀü`b@.îà*`îëfÀ" Äf Æ F 0È €$´fD€*ü@>JàB áV b£L†ÖÆÐ¦èjl2mÇÅfÜêp 'Ñl¬DlLvp¦êq&à `p‘¦¶jÑ4n'pæìn&ònGs1Ç`È ÆÂúq Ç`t @Î €š Þ `èa`¬ Àö €( B@€€,/2Èn h¼€Šxà˜@ty€x £ò ë|Ï`€ ¬è ÀB€È@„ …* ÀF Î>ÀÒ $ @H €Ú – €V}€N}#t à\ €âÔ1œ( @(/ &`VîÀ*“ &M´Ö`0HÐÒà‚eÀ†`L†\òNÝhpà} ô`z`: Û ®@/" ààH+ JÛͺ@\i+&@dÉâràX @ Zn &oÈ fÒàb ßÎT`2jà$€@*.D€`àP@<Iàj߀bßàLÈ*'|vÉB€Ì €ÆhN L ˜Þ HÄ@< B"Š€BŽ2 |€fÀv ArÁN€ÀˆÄ pÁ¼€èêÀAàD at ¬> Af­Lœ!<^a3æ"À^ ,ÁiÞ@¤J³~ ®iç7 œþAˆé"² ôóåÊ<~¢A‚$výa‚¥†¦a~`ÀÀV aŒW!”õa” ÖWÏòôažÊ | Á¢äR¨ÀÚj„TÀâ b!¬øª€àÀ^:`\ Aœ9–õaŽÉ~ýo abà”­À„_€ÀDœEþ> –I¨® ´HEÎëa’ò–¡o\ Áž9ážC©– Áœ0£ ‹D *ìšIìàJýŠX*R[ÀÂB¯jô¢*2Ű²Å¼´Ë1 ½5EXB!‚ža‚<îÄ mD€~féÂG¬_`Ž è«„À(A† `n *bàêOø@N)Ö`$A @\ÆV&žpìd@ Ôjî@ °¾ Æp ⸠èb( "Ãô]¡U!p_á6i`Ò-àJnÜl/Y¦ìjæÌr5¢ræêj†Âl¬ÅÀ"q§jư-æÖkÆüplYÇõÆÃ¬e[&Ç o j†¾l&á]×"ƨ `ÚAáH þ Š`Æ  À8`N 5+à È $b ß,`F@\ f N`<@|n `2ಠ„ ©¼ ­ eæ `@È`€ `: Èôæ@Î Ž àDÐ B `Öà™À” €T àÚ&’-€,qö0 *`(R21œBH”òj öò¼à"â  @teÀzÀJÀ0À t B+«Ú ÜÈ‚l,/€(Àˆ˜‰m´`N‰@M(ÀTç|àR$>À$±„“&œ "ß"àbümÀ,/Âè ÌD- "6¬Â4@’@r `:qfmkr@*-@B`Šà† „ `ü€ÂÀb Â"Àn¨*àl€*`n@ àv ÀÒ¦’Á® ha„Æ¡9úàdÁ²9š´ªì]e¦€JZ R ï ZÅÊ“X ` tªÅÚ`2 N Å5!Á bðeP@¨ìà¬Ä%R„‡= ¸¥oسSØóäŽà¸ú#Ê`º¦Ö…ÖTµ€éßK¤.IöDb„@ Z ¡¢`Öf˜¸žsý‹Ø`f˜ iAx¶ÿèZ P A†ă7Ánà¢àD AV›Á?eÁ2À€€>%. !H üਘÐI¥°…œ@Äö€ÊV¥zÄd˜/\DÊIÁˆH|JØ Áo;Ar²`B a†[[JYp)%^¡áŽënºUàSG©”!…7x\ž¹Dì¤ P¶Á8E2y¡3:€Ž0^*ðl`2 €sÀh0ì@*@ç €Î€V0¥ ú P¸ Ít «¸Â>‚p $@ÌŠÀÃUÀ¾f`Émའ€Ê`V &e€.¡ @x 8 !F °€DhÀ2!À@ ‡2* *¦®mgm•Àkæì5²l¨Èr,LÄ5Ô-ç-ŒXkuÜÆçĦÈnæîmfÚnFÀõèjŒ1MFàr à.àÜá> žÈàÆ¢qàà4àDb  "â€) & b œ @Pn N€N`@ f€j€6€¢¿@·:–ii’ €H ÇÕiàFÓqíy`FàÒ-  6 ÒÉ*ÀÖÈBû,(Üí\ßÌ,Ž("álÈØ`6ÈŽâ`J,(z‹tváp`l <Öà<` \ ,`:³q`@ .(•¸€0Ú€.à€d¢¸À`|RKs@Ž,@tMìFü†Ü4à(œ@%x¨ŒDWSv >,Ž àhຒÀ¢àVc> .gbÖ²& J@¤`’’  ˜ €f `°ठ@^à  @Ì €ÂaÀ±y€Ô šÍ}Ó}ÁÐ! záÊ ôjÉvEàV …·“ãÎêNðë.;ôÈùB®À¹’ತ¬.ЀB AX_%ü? 2*aÁ$A{!JÀ¤D ¡q;AnµániªcÖnÃEÄB†B8‡Ê HGÓ}”ÌD|@´o\ôò %–F*DCK‰‰„¤0ÀÄþ*ð²ËOM³¶¦ÀF ^`’¿àˆ@<!>À~à<¸kl¬è^@’°æª²äuK@Ʋ$0€ÎJôÝ‚9ᢈZär±€L]`J Át@ gÊ > åP !d¢À9“åÔœè9WÔ~²(´»L–òœ™M`@£€š@<ð%F\_köz.!:_áHÀŒ_ÆÎðTAU} µ~¡d@þº@êË `Þ R‚ˆ H¬ l )À$€ô€d¼0´ L Fb @–Þ •` à& «Rè:@.A¦A<|¡Rýnþ ¡RîÕxàvÆÐù"G½ ,pºBÃ`  D"új‘)\Q=^úDÅñm†ÉÌts,`quÞm€oÕѦ(É_€ª€ãFéëÑ4s6$/‚¸` Þ¼p,Rm€b@.`;k ]aêX"=8|ª·”VaÒr´:FT†GÉÐØí*#‚£dˆpŠ¢Ö[ÅÀl¨¶wCE5€¦µ–bRóN`a½aÂÚôB[]‡K+ ñ]p!,;b¡f %€B*–¯©~ FH.ÀÕµO‚‹EøD-ÁBÁr E«®XIVÅ0>"“ÀЂM‚Â4 ‡Ä¸8’Àà~M‚ 0ˆ„ðB%•@ðªY¢ÉvŒ&D2™ahÈf…ƒ1 F˜T5šhÒi£9œ f4`„¢™r8è˜VƒBAP ‰PD$ášVâ™f eÃx]Bé~Œ0L0˜á8ÂdC!˜ŒFHH0Ì£Š Òkl æ<-˜5V.˜ô0ŠE¸6#ðxJÁñ, EÀÄ€ê`ØŠRƒQˆ2’@ pE¹Ä`.‘@°f@pô…#ˆŒà€D/á¶·àh>*€ø® £0&Žª@ÿiÚA0ÐI`È"V˜à „ãh(Ž@˜Z=X¤p0 3™B ň>/—€ÐˆMP„h €p* ¨‚`X X"`x9`€~Sœ™vp€H€hÀ^a¦ç9†k—çy¦q¥ >Xe€NŽhZø v¿¦ixeú¾eé:@à( „¡P8‡`t°r †øz†âD‡A f„án!`háˆd…!€fÁCÌò¡Pf"…Àª"èL Á(~1âÀ£H !(†1àȈ£@‡œ`z ¡^x  €(‚IÊv‚@èƒz ò¾¨¡w惡x …àp8Àø^ùˆ@<@È ¡@>¨((>@@ÿÁ àœTÆÁ¨Á”„ ‚@ A‚l@€9¢à$Î)bƒÀaè’pÀ>`hЄH8 À¼…€L Âh@ì`v€à)ƒ`˜± òˆ`"@`VÐ6 ¨.0ä(l Œ5… Î gÁP8‰àž"GNÀ%ˆ¡ÖD塸p`ð7Av€¼9 `† + ƒ@6Ú@ f‚øÅbJ„+‹°@wSà´OâÌ „á`BX«áPPx&€¸6àHà@E;h)IÃÅ&O0S|+ d.ƒBñïS€ˆ- À>zèZ dÝ…ApšÅ â²j 0F@Sàˆ+!é ˆ´–‚¼Ñ^ÓtÔà|& À6E@ ™Š@:bhÏÙø'€øFà„# 0@ÓáÄ G¤õ¦1Œ ƒ0Ë! f‚°Ð40l,†±¢ ÃËQ£GL€¤w‘-`h! ÔyL ¢!Tp˜+æ ¢à‘|x"Ròd‚s`C0Ì5ã)K p@¢\@”/Œ0<† ! •Õ‘€…Åý<RˆV‚'ÎB¶¢b— År(Up¤!PujÁØYdˆÐ& „8B ‚Æ ÃXhN B€7àDU²x& k¨:^—Py@4­ÆÁ]„/H€h$ V”6NX(z@ÔC€t$V™!2„lªÅhÁäprÒÀ³K ,{­tÙ#H&lñ”“7 Àk1eM=¡3¶ «Ei­•œ50Ú.³G ›´&ÔÊZË_eít3 ÚïQ/f@6ó²ÀÚû,ÀÀ(²ðÓ[ÖÁÀ@ ( 0` ƒdÁ@5`œƒpF Á¸%€ÖƒwñP8s€Ì‚i…Á`%`°‚ð` ¨"àÀ‚€UˆÁ|6ra0” ÁÀR`ð-`x8J ANw° Û À8 €§¢MÀ±4Lœ ²wºòÙ ‰ „ RúA8 `¦çèÿÀØ {Ø€p(þ€˜ÌÀt…òXÀH–”€ðXÀx(@@ Bá‚mLÁ3&„0œjÖP@“×ÚÈ – 8À˜‰À¨  > ‚)¡$ ‚€v9ÀÀ ‚Z€ð/» pJÀ¸#,Q ‚€:Áˈ á+† °CPR A¬,† ÜBÀná¸Y„±9‚0¡DŽ ~ Ç)”3!Ømƒê6rÑølÐÚ5(¨Ì>…eiÐJÚ«atÜ…‘{&PÀ@€„' à6År< Ll$ÀÀ4•ÔR°ž,NOÁLZ.$üÍ0¼•Ñ¡šºDŽ ˆ*‹“x-@ðRàVĆ‚~@ ‡Ÿ!ZÂP§óÈ„IÖ8 ‚¤òs®›Âp¬!0Uðš*@èK©´U‚@œ*y1Ä “˜+ J¦/ARLá’’qž HÓK£T†á¬ <À/¢À¨1  L©Á"€A@ì„VB ,¨È p:„ÈBy]îN‘E¨ ð…´UÍxÉ5ã,©L¥*ˆÈ€Ú›U-rM˜j”ÚŒ @§‚àÃXûÊ<0¢d #@1í@¸A çö„aB=h‚H ‘AÀ‰ØD° ˆ>´ð:€€ƒ8Øùp‚‘nËã—Ð7Ð7€ˆƒ˜“ P:-±yƒªà 5x02­(3P P:À?¸+áY?YˆT0+… ‚H—ø3h™I‘"H!“3:$™é9¡A¨™i§™¸£ y©™y¤™I´ÂѦ°Šë0“š€™€Aµ€:ø›šè0RÿšZü›¦™a¥ { 9£± ¸ ï€Ð PØ€©ÇˆHP‚()x!‚À(%è$h‚()0°Ø€°H@€XÊ8‚€$( ‚Ø,˜‰DH@€³2€’¢š©“€À¡iíÛ]È €ø€¸F€h HÓ ñë€à€È€p °Üu\}ˆ¸`Yp˜ i؉€Xä‡àpP#@@° šX™Š—€˜›É€ 5¨®€€ €Ø¡€È 0(Ĉ€Èè £`„˜ã,à° €ø€Š   ÇØ Ÿ8 ¨ ‚X+‚0)ð&‚°/ˆ‚ˆP5‚8;†H!¸"8u‚(B‡8ðq <øƒ¸mˆ:K¨9Ѓxk[ˆ84¤018É?…²Ë¦è.Ðx:Jo€ãŸÓÓ;a=“‰… ØK°Á„høQòw€ã­€óÓ øY¥Ñ|è-…à‚ð_Ìx^©û¢¨ï$Ð'…ˆhU€ø%P΂™ˆ“ë¶;Ñ;»9I‚PR;ÀV!ñ\ä…‹§:* ®á Ð&8x €(fP4xRƒXjcˆp6 <€F´ÙƒŸ‚Jk P€è!«‘€À„ˆÈIÍM'Ê–‚ZkNÈ+ºkø0†*¢@ƒd>8f3Ç /*® Oª«à0/8/† õ>£ì ²¡ÔͨÓ[‘ VBO€è ¸ ‚N«@NÝ$Íà!ø é¿À ¸E€Õ,%XD@A€ ƒè P7€™%–ø(Àh*A.@@3€ƒ`‡À¨Jà h>ƒ¸@8-P0-€1€˜Sxƒ@H­0 D p>€¥,.IÁa«@L“øW àYØ€ *ᔀᦀ’ø€›€³™AžºòU™£°zëA¨°q´šQ¦0röšý[C [Ù²ÕÈC€Ä9¯ŠÿCáµÃi—ÖŠÿ¯Q–Cã0…\0l5™£°1èA˜›™ãÉ@ ¸(0Ø "! ("‚È7è,ƒˆ!Ø;ð&ƒ\^I° [@ ((€À  û_És "ÓkÇÉè®´nÑœ¡èUp€È¡€ÒØ¡m–µÌs€•RÇШTxóI4Z4 X ¸àZÐÚX¸€à€HHlfpø”‚c5§cBÉŽš3W ƒ2™jžƒ[¢b€¹¡É`8 1M36t¡€¨P€Õ¼ûg6@h#`"€Ðà E³jà–ø ø‚`/P/ƒhp1ø(ƒ0'pNè9Œ¶‡ „ t8tà@(Ðo¬»d¾X7˜]¸ƒXiH3r£-XaØÞº \ #Þð]Lï9;±N$*º… ÐMpG€ÀÒÈÒ]N*^§@Íè“èÿ&Š®¦0_ã8ò Óåé'x %§C܃¿Ð$…8¦§˜%…LÕ&˜)Mjh [ÿ¦2E8Ý$i ;áQ¤Pƒ0fKÈOˆidúa$¾ÏÈ’x¸ñÈRx*|Nè¨ ÐK€ºàŽpHað øL€à#…‘ˆ‚¹&eùD¼øQC†[檃í¾Ëê0BH0Z¨ãÛð.(ó…ø‚¸^ÛŒØ(…‘\…#ÞØà þ½¨ ‚åa  UäΨG´Ô°D€¨„6Gø `ÈZ'…\„ ‚A—€˜€X ÕÁ—i—€‘™ šQœÕñ¤yš€9œg °°ÕÅbý[¯´çi—›™”9~/ù£šÍdçÀÃrþšQµ°„3/TCVðX™É@ÇM™Ûi 0Àà#¨&ƒ ­|‚Ð:)pp"Ű€’5Ø hÇÀà£#¼¡•Âp†X 8` !jë5‚ñ¡€©½´€   ! Šþ‹4J¸ h€ÈúÜú&4C: (ŽÚ(Zp¸ZÚŽ €ˆ‚X H"Th!€hAóÇ…B£W34™áÇH›®À„¡ø6€€Ûeˆ¨Øœ£€Íš¶À G“_ÉøHp#€Ø,  »‚ ¡àx#Ð&‚Ð4°0€ ‚€4‚`0ƒØƒ@Wà<†Àèp@‡ ]@sÂ<9†Ëˆ¢Åø4¼ˆ5¨Ñ/ 2†QÐñ$¬¸ZQðñ¥ù¸¦ƒ©…¨ Íêx’&U)ÌΠE€È( ðM“˜V»ÀX¹Ã•‚€Xò_Ð\8_>èÔMЂˆXàHk”i"HTßÉ:¥u'ƒ¶€à$»è%'´èPêM [¥òEDÂ…õæÕåqð/“820àð`òІxo(Pi(Àh gb*K€ð&€óÚ€à„‹ýˆ »üª¾°DÌñ„ÀG€ø„²x…<É&›¥•øH/0X”@Ù8õt ð.†•D†”á%ò»èpb>Íeͽ ¥ðý&á8P ß )„¸ pQ[«ƒÕ€È"…\„ò¼À ÐI€ª¿ŽŠÀ,f„ €>ˆ¨ (Ø -p€Ø)`,,°/åŠØ,ìÔŠÅ89€–„ @<€xƒyk ÆàLx A ƒIk1}eƒÀ\¿5ÕRèæøLØ&An…Ñ\„à €=y…PfÉ•Õõ\€a³vpç'‚g!¡C€1“0µšI¥°°Õ’üü;š€/ß’èü8hµšì6šã™{0 ”š~r1èZ€‹]¼‘¡1»  ° ‰X­‚à'p ‚È‚+² à X( Û mÍ„ÇP\ €ûGxzö¢´Ð‚P1š Âll5Ñè•–Ù§ÆÈÉ IPŸ35•°€ê!¡È'Ü@%¦ž˜ž¸ žž­ë0H!¡á€xl( wËõà$€^ØìH P‚€IÝHÀ€¨ ~† ñ˜€€ „D‰º"`@`$§1êø à¢`ž €¨° GÀ€ø‚PNÙI¨h$à5ÃÈ8-‚8'‚Ø%‚¨2’è'"È@;†XƒØn¸=èðpýÖˆôúäž[âÓh\mi a‚“cXVli M,ñ9•ž&0²CåÖxª»–!ÒŠÐSYåáÒºà6W]Š«ùQh!+-Ä%Æ ÀƘâ|ØŒÄŘÙB“#(J`d‰ Kñ=d"#)ƒdøp~˜ Ž’A‘ª022D†ÆhPÀÉ¢‚£¤p\z” SÁ²bª\µ‚RÛJ_bËìpñŽ .±%Ö(ˆ¸Áæ;¬!m€"-0²æFø"ùŒ æ(F/ ô‹eð8,`ø®\„"©p§•À؈PAñ0 ÄÐ4 7‚ 4 ¥,"”ØzŸ‡¤¸,ÀÀnDƤ@,Ê £Ð,ްH2‚ 誃‚x‰à`B-½+Œ@€N5a8à€&€hB!Xêƒh tªØ  àˆB/! È„ãh(Ž`^?¡¤xè¡á* ‡ÄÈ,!“k)TŒà0#æ!P‚( @xÕh!V ]]RÕ(\U p •Ö•( 8@PaVàX$ÚUhHd @UZ׃kÜm[eØ–e—eWÖHdõð•8" ‚ °4Àà ƒ`ˆ(@® ƒ€ÀJh€!È4˜0@ÐD ƒÁ8<… ðT„!À”¢hDáZ „Xx˜2ÀØ^†‚M‚ ` ú¡h€`N‚°ƒ`& h·è( ÷ø$ Ah|*„AØšƒ@ „ (*˜@‚`ØXT%Á`œâ˜ `PV&A €â(‡Òàz †¢˜‡š¨3_mîÀ˜©˜ €ô`À$ „:p8 ¸ €˜(ëýÐ(‚ : á(=Éf6ÀøL!8| Áx†&‹ðŠ*g¢8^ˆÁ¸Š+â€Ì! ÄÈ€<áÈön†c¹´ Áèöp†£ÙÀ†Øb9›¼7 @XE@i 3ŒðSA(dªc1ˆÑ$ BÌáf€´%Œ„ñ`Ë@'|! à>ˆÀà9 \ˆ@& èÂ8 1NYE|$-!4WÁÁba‰hSň˜X[EX" " „‘RS ∩ ˜2TB@¤¡$Sð—Âa‚ âÌ•bÊ, ‰' 0Ž1‚–*ÁP`ˆ­‚ ¨.Œˆ¸0Âà…‘y…Ð6@j'ð~'€à;^Àh"€¸4àd@6 D!°l"ÀØ;@p ‰À;AO©0[°²/AA¯2ã¡‚ô¸ Bú àHÐ "ø…z¸½òÌÁ|ÂðÃO£ ËÔô1í’üà>„€á$¤ qLáH• `‰*Üì€]P†'Q› ìJs‚AÀ‹ÀÜC¨±”5Þ†à$ÃH °–“‚˜—4x,§ÀÁ0i ˜4 ˆ€@ÄBPP@˜& @DÑ'À¸@õ!‚‰Ä/ðII(i`¤80X@¸2`P 0ĘªˆˆLp–(Á[¨$]p‚$À¡«X@Ya%ŒÀb¦Y Ei:ˆÝ:ÉW*¹]¬°·Õº¥Z‹.e¾¯ÖJ®à9p¬…º· ÖZªµo-e®¹–òêX+¡fXåa€3I^ÊÜÀ a …ƒ`>ž €ƒPx ‚°e)@< €p MâðF A1€¨"… jˆ8 aÌ„›l‚à0aDPŠA€D@Ø#ƒŽÂ(eä€á@h@&‚á0p8& A `Ø@ …† ÀH&áÁPÈ’c ˆEÀðpTƒB‚0P@ †aà(:5ЉàáL .(ƒ…`€¼ŒAÂAð#”€Ø†Pƒ¢)FH è!ÈAR„’8" ÈvMAÁ †„H.@À^>Áy …Ãûý9ð0@°hBÌ$X6òÙEažV„Bq` eÈB+Á²_„"Áz EØF+A­G ÅÛÀ]‚¹zŠ¥È;Pƒô°F-—ÔÁ€ †>/aºaâá~ Eð=Sb¡n %°4&ÀЄOÏïÐ}0äÐ6 “`ȈOƒ‚;?“ Ð|LáÙ †äH2@ØhCÎä)5‚¡Xè „ÃH  {؃¢ˆŠ „1 `ˆ@-‚AÀ £($ ˜bC^£ð* ¨J8!Ä ÈŠÀz„# Œ€xL5A@Ú …c¨& ¨nE‚É çàÓøˆDØ4'aÂ_å¨*hpd%àJe¬ `®ëúÀ`p²ì€hm@PmÀ@:Öë»{X fà W¸ûvøî@WÄ€àGÄn\xíÜýÊ®;vö» ¸‚ø(ƒÀ€,ôÀà&”¬ÀØ>" #úH ä .)ŒÄl%Œ!h"1ÁØJáx–4bðú$Œ„²3Âà¼; £õç‚p¨7 ‚øê)Ž$` 6# M`x"Š Nº…®@šÒ !""‚‚ßP.]@(€‘{`ü*€h€if} P0@¨`X$À@.àLÀD @p- @@„  AJ €Á˜¡<ƒ€¾8"„<Â.@‰#€@rFY !ä,…p"€Ð`d‚ƒ° ˆ‚@F ÁP%Ø€‚ÁH?o‚ÀtðHì%ƒ0p°= D”"àzÁ°q ø@r†è/£d1® C°Ü¦ð›ðX†°+ £M™RFX) ƒ$3¦v0b ”/Œ0JF­`x(‹PBE` ‚©Š´d*ÀÂ(alƒ¡,A°´@@J€±ÿüP%T‚`­B¾Z @<„Ö@°<± €<€ðFIQ#!RåðJó`Uà/X«F⸑X@©É-&‰Ð>…¢\á2ø™Oâ`Ñ+ED° Â@ QÁhƒ ´=PR€¸*ÀX1ÐZ€Ð.iœ@”ðž„@Â$ ††µ@ØFh†_#´z,€øTЬ\¬1t°¼P]‚ŒjP ¢Ý‚ Ь-ÁT«ÁT\,5N°A™\^/Á{ZEð$ büÁ|ÂÅíZ j±àš,‘8¨@ë| ‰€0蘓 LÕ¼Bœ øN x%€³BÜE.±ž˜À1àH‡ 1J€&  @¨  < „ЂX ¡Hà¶]3J^¼Ä ¥ @`& ¸a•–æp` ˆ20B@ˆ% DÀ ƒ¸¡ø ƒ1 ODSAÍIE  !lZ±Ž‚›»Áf¢Ä›èmàI· ßÀSZn ©­6°ßóp-Ѹa¶á„[sdrøŒ8,6ã›Ëq !ƹã[{Ãø[ ·0cf!M°€€a9à]ÒÁ@)0  d„€ØCÀ™"R‹ðø"…(f ¡ð*ðä¨L B$†ÑC “ ÌK†,ÌD ¡O ú&ØÌC PÚÄøc¢„2ˆ!DK´ Á…Œ†µÓŽ@‰t! J#¾¨6±ÍÊá4«…'Òˆh.$–òÂă2€À+@†ø^@H€,ƒ ð¡|«´ ÛeÁD;L‘@*×öyl L²"Ó´b^ ïåÓøˆˆÀ| R .`l„€@ñ€á`à ‚ Vð)`œƒàD Á…ABƒØÜBpƒpø7Áu6’8‡Q´ C˜Øâ£d‡¦ hÒ8Ã@†qž e0& ƒ(†1’ CÆ!‰^á„TÈ BÌ £´j*‘ª& ˜­°6µWX”`Îù‚æzƒ`)¼‰À6ÅJ?›ABqиMéXR‚Š(R ¥= !óØŽBPªrî{ ÐA6gp (¼" 6(¨h˜áOÐuÒÈ€äHuãA»C‚( ‚úD ݧ€P0 Cp V•Rø€@ÄApj"&E<B, x.ìhGA'ÀÑ`¡‘áä›âÔvHª@ðU@„)T€¢-øP`s°ÊÅñV8Sàx*Tг[¸»¿| …qt”Ÿ8®ái_¬QS˜¸@. % . x aad Üö ÀÜ ®@èáV!$ ÜÁZ àüàÔÁ: Á âáj!*öAfÁ ð¡L`Öáf þgâ!­–ÚÈz-'Ú-í¦.L-""íú  HÀ˜%Œ€@3@0s" ¢ÄÙ`- à"`$ÀàL0Ö+tàÍvŠJÞÀŒ @€^¢ÆÚbÒ ‚-"‰"d.-"tÒt‡gø ÐäàtÀ* 4ÀBÀR$ Líü ˜@d ¨r L® j þÀ@À„ T€@¸@ØàˆÁÒ!€zaÀâ!²ÀÞ bA°€ä@d8€Z ¡ªØ@N 3 !œåA”æŽ`ÄD )V Á‚ej<xù/ˆ ÃÊ  8EZ†À4¡2ö¡$€f`&€úe€ÆÀN2:!P ”ŸNÅ bCnàšàŠDŽ`< PŸ¤^þÎÚF aNG©þ ©ø )¯:¶[…¦@vOøà*ðè  2õà2!á  ^«NÏ8RBê R@2æÖ æ$êàd@Àj³¦~o"hhÏ$@~ð@Ž@B€”©nœO„ ad@¤¬¥ŒO¤/¤CfeŒøi¾ v°ü¡xª š¬€6 eHù@4 ¡vE, ´Ð¥Zô\ûeà’Dž€‚±)ˆÀ~°²¯ô² *!>±A3 aĪ:§ f¹ dg Z ) VàD`ÒàV `0 ŒŠ„¶àˆ`2 `` < R  %HNà$`ö(á0tL ”b@@ @À€@ k¥TD¼`H ?«ŒiR eM h€&áÅÆ[ADUh ¡lgaŠ@hm€&n`#¦ÏQ!FÎçu`@/`FKb’ Êa( Ú`òA@üÁá, v! þ àìŒæàúD¡,‘ª`þ¡ˆá,@øA€!8@ú| ÁçÔÁ‚&ÑâÇÈxÚÑø,Â,À0Àf@„ €++,Æ¾Š‚>.ME[Båju¬.bÌ!@)(çøBÌÓôV–É`V J2`Š @* àÀd VÑ#èzâÚ`,Ñíl8t" bƒh ,MžÛruðàH0àZ D†à\ LÀ´à®`p @ä Œ r ‚TíÒ @X !@þ €aÊa la¼‘¡°Àâ€\°âàZ Á®`Ü€Z ¢@ÐàP ¡˜¸ŽX “0 Še¡ˆe£¸V< Azù/¶C€>ï`0¡J±Á>YÃô.hŠ9U "`ô@>  *Àï<Š$>sž®æŸ„8CÎäHNÖÉÎE$\Ÿ¤bCä °IpäD.ö@Žà8T°A*Àpà6ñ€:LDÀ4DÒš ø@Xo8^óú Tó`VÉ–P&@.€v4(«, 0ðà8S̘Œ¢ÎŽL¸à”ë ’ž¤F¡ZäpCo‚à:XϬøŽv¡F‰j¯µAmGal©!pTo°çJÊ ¶ ajúl«à8T @ v`±4%€ž8¨ 2d“À1KÀ2!8@€#ëK T¦%¦x†ŠvاSâ]à&O`*!øT¨ja`h @J ªÀN .àr#àm‚„H`Æ ÉR€ÚÀPKŒ´`]MÓû ÎeàÈa@¶e@¸`@ õ ÉJeæ$Õ¹pxM«FP·¼À0a(>³Xè`B !b¦Á"|'fàGÁÕªÁæÊ."Xl"q^fµZÂÈ%­¦,BÌrÂÆäÆ'Å1 Ì0pç[º$ÃÑ Y,..@ Ç's㇨¬µû¥ŠÈŠ`àHÀÞàê8!$ú¡n¡¡(a ÁÁ*`ÂàþÁá–,ÁNá6áᆡAAFáÀîAR àö ÈP"àŠ@ˆ(Ú€ ’Û`BàF@<Yjm‡öш‹®vÈÂvbÅX¢)Zª‚(p@$Õ²ˆ 4ãð *õNäN à ¾@€  m»8`ˆ vúÁBÍo@"kM"†¼l|‡øbÕ­ž&BÞÂö€8" dÃ4ÀP@ZàÒÀ¾à– §ucÀZ ¾Ò² h @h X`ð®À|®7 _x¦(@ ` á§¾`V á°fÁ¨ ÎP œºa”æc² ³:–^EuHÀ°X@¬*‹j›DJA<…¦ö¡, jë‘€êïÐÀL€.4ìÄbÄbY‰ìA„Ѝ!H[¡>äVDáF3–>\nE ðI€ƒ5€~Üi³ l`,O2a d1™à5‡ /N8v@ZJl¦ jÀ(A\J.±¥}¥ªàz€2¢Ù8êi†ZÀ…9„ èâFAT=áX=!_j– ˜öì>øÏžjÈÅ>¬!q¡r«OÎS€4 . !gAj`/¦ AjBªÀ 4d¬XÔþO«Œä~œƒçÃ@:€(a6å° #’:€€T­=³f†ñ™@¸ $`þÀdÄô%Ð@4AàŒ`j áŒ`¶@bà†®¿†⦠À àç€øg÷ €æàN À€Æµ|&Nº×òd€» ËÀ¡?³j¥æ(0¶µjñ‹2`$Z`(0îaMÀþÇ O=.§øÇ ‡­ªÓ &ºï"v°l¶²ÚÇ9lLpGÄòn K†Öű0Åæ×G ^FÜmÐð},põ¢ÁÑj' ^ ; <^±^à<€V€¬¡"6Ć€ð@ôÏàü@! îÁláEí¡ÖA a6`ô`Ö àê @¤ Ä à Àº ¶ Á Ø€Ò!"Çè¢À6Û`<@4À&àZò°cÀh‚àQ&þM겊âvÛí^Ûr'kž£Z1sæ¾};x"èò<R  ¬€X `Ð`f  ¨tÒˆ,À!u«·Ö‚.»`" ªmŒogLs›i'b06,D D FVg|ÀL h Ò ÒÁèˆcB ‰æñ‰¾.Ť`ÈÌÀsÓxrxn Ρ™Õ°.8µÅFæ ´ÔÕšÙâ³[@RkhŠ ,ñ!•–$11„¥öŒ¸À–×â"Òô@[^ °ùQl),dÕX\¤ Sa±âX88GÈР±B˜TPt±&ÃDE(t”§“•áÒZ¤>DQ†ÇéÐá5‹OHiÐé9_¼¡²h.=J†Gi Ðá¡Ãd(hjˆ ŒP¡qŠ.0?íOA±yð0/=†HØÕ¢Ãô t€™È'ƒdUtŠ s#ôØpz˜ Ó˜àé 6"(du({Ô$*„$•Hˆ’«U¢ŠÌDR[±rŠ¥ØB+¬]¬*àø¤Z‰jý€ØžY"a_  ð Y¢jŠq3üCAE@Ü$‰¥‚øV/%*! À€Mƒù- @È€O";"“€ÈxLƒ!Ñ $h,£H ‡P(@¸f@‚S&”¨ €ˆ8”BØòR…¡ÈРЃ@`  ˜jdzؤ„"¸" à¨Z>aPô cÈ Ž F2‚º ƒâÍ-ªm80Á È-àR9apþ †&‘œ¯-’ÀtI¡Ù, ‡ä¸8"” ¸L9àD  ÀP Ùफ़  x,[ u­o‚·1q €(ÖÈVø U×z‚Má|Î÷Ѐ׀WØ€UôØHÞÀUè_¨oâ x ×H6 ð" ƒ€ˆ.˜8B˜ÄDdH_‘$Ñr@Äxì/ Ä)PÅ~CfI S˜Ä1JccÉ46ŠXÎ4ãQT ÄYZ3…@Ð>“£êK  4 Ãȼ ‹€˜,‚@ÈJ ƒa((€1“‚ ¶ ^ @×eÐ à†ûÄ`ˆ2d·@,Ý€GbàX!÷…ß>Ú ¨Ï€ØZáàÔÁ•‹ xf(¶N^`¥¿Ü Ùu‚ ^/Áp@—‚Ï@Ÿˆ½í®þ`7Æ„€ 5“‚¡* …a0X$Áè¼"¸BŠl+ðP a€–FƒÁ®&Èp<##¡°‡±Â CÐàáÈl°Ú4PhÀ ž€Ô3HiA¤g Ì2A8c Œ/Œ0FEø!)e@^à°€‚¸·A‚Ô…^‚P¨X„ ™@0hR€Œœ ‚àø ke!X·z%ÀØB‡¸V*ÁFÀp! ã¾' ˜™:âhñžS6WÎr>€üJ r$€¸:ÀdÖh!Ø3æ°A¥áš`B #Š 1£eˆJø”d@àF@zF Š(C p!‰ôŠ&Ö™Âh¯‰Ð<ÄÄV‹Aé„qFP©FÀ|$Š >Ep" "Ä©‹€F…¼(`€+‹À6…Ø ‚àf éñÀt& à8‡Kù âÄ#D(†ÂU?Àp(‹@8Åx –@pÀ°œ,@ðJÀ|# P2L|@ôKôžgÉx 2N™ìÈ‘ªø ‘ A¸Œ@ÐD¥á D˜2ÊŠƒaÁàˆ â ]²$@Pˬ /0.@xÀD€Ð,@€€80 C` aØ‚ÀîA`xRÁÐ0ÎÁ`x.@@øZ ‚§‚0ÀA(h@œ6@Tˆ1`Tp. D`‚0 Æšb%€¼”0B˜ƒ à€ø*ÁyWZêÀ]ÁXb£ËÀ=A¹&ïܸ^ 1௵çc“ë‚\0öåØ{pO˹uëe˜jÏynŒÒÕàç’ó ¸ ð(–°càx 6à> ü>‰ñn"EhÌÂ\ZÐü$ƒøƒáüG a&…°Œ# F‰ñz"°–áL3ˆQ $„@¦SŒ± )†`ƒƒ,A 1’Å(ÉÈL‡l¸€ï, Xà(äÛêîpNqt1!lVîñÃ8À.æW \ÔÍwuª–}–Qt<ÁÀxÄî<04€°"``€ÐL€p. ް*€ F©V Å«½f'Ûˆ€p)÷aàm›Ìb/@,û(â@xll2‹x@èt t§° iPs Œ€bXDÀà,ƒ`Þ1‚ ì=ÐpIàzà⃠ê7pr °6 L`)‚ ¨6-3Xi œ3J†h( à † ‚ؾ!`^`¬…‚˜¶³~s à2EP+¦-'šz•M€aô ‚@ј‚€Q`X@†W‚@§AS°ˆ(£)x”@`‰ 4X"´žñzz,@4Ä€€j‡ÁpÍp7' E´ÎpÄHâ ‘ð”:æT"‰óØ(O`¤¡$SðŠ)ôW9‚g_ |%ç¬\ã |î°} I…áA&„PYö ¶›‹@D€eà"ÕÀ‘ð¦-ÁNx$ŠÞ®Ï”®3Ff„Á[4E|æq%-ú/ý4& À1 Àü«Á#¢õà;¶@ÐCHçj˜‰ ,‘úFH©Ííí~#è8ŽbF5÷#ŽA¨†€ÜCV‘Y„úŸ‡Þ"XaH"˜XÉ c&Ò˜@ 2Æ þ•…" 0á²°u&¥A@qˆA ‚ Æ”èT5Sð¸^S!…U†Å À )àL‡ 'Yˆ4I,¤ ' b€#@Ô X3 H/çs”X~L]1ÆdÛ@ªz]JË·ôú¿œâõ`@;&»•ÜW Î\œ¸­9à¿éu˜Œž Ñ­2Ì€{-€ˆ žp  «êÁ„€šÃšÝ¨©€™€È2„˜UpY†xJ…a*çðJŠã˜A„@P8LC…0aPH…pE0KPI…8B„X8M…ÈC…PfBhh„@U†ˆEÂpCpK¨!ƒ<@P„P†9ɬég˜YÍ?+(˜‰Ï?€2Ü™â—IÆ-»qo@Áæ1¾H¬–€;%±d6—‹–ú¾ž €À€ÈP€XHH"€P !j€œA+ùoÃñä™C*«éÛä51už+(²k%‰n¤ )`€ðx ²Yé=ÑÞñç”x ` ( ‚`XD0>†øƒ¸m‰þ¡þ:È 0ƒ€k`7†°ƒpiX64À5€™€   ³K€´à0e81(ð`,…à‚ºn“§¨&…HZ6±a„È ÀGC èB*=‹Ø2à(€À€ ÀJ"°P6¨SË“¸°¹ © 9LÈ'»Œ€èЀê6(;u°E3{¸EÉ*7øGðÒà„z€Ä(ò; J¥Bw:(0 @R¤˜OrŒÐí¹ Ò3•ô™ŠŽZ} ̸ˆ¶°ºA…ˆ˜Z%ËW‚°^#W+…ÂsKp%Yc ò&Òw¢˜S9òXKë\…€‚XV¡xY9ÃZ5˜Zu0U6¨TÀ#6 $0Pêp… »T–ð¢Pá!¡»nÓo¹`˜ ÀH’²‚(X ¨À ˜C"Š£Ø ðµƒ¨ P9&˜„)…ÄlZ™>jÃ,LY€ÉÆ*Ü Ð%2à**€-€ƒP @7•h7=4ªP2€h‚ø-*P.*¨-€€£€p (5€xO@p X>xƒú P„i\„š€è0Iƒ+0!È!ã3ËœÉ{À1†˜‰qÍ€Aj—¨—ñÍ ˆÑt5ºÎ˜™g–‘åÀbÇQÉi@á­:Ï@Éœ<>Àx ¡¶€‘¶Àp –´Z€™Ç¤­É€éø¨2ÀH…`G„`Q„ G…@E„àY„8P†@„ M B„Òì…˜Dà]„@Oà@®à@ƒØG„ D„ðB Z`UhE…`ihT„+„°9X2ƒøEø?c0 _ž 2¹n@ w±<2œøEà,K!˜™ÇÉÞNÐ ÑwNÑÆ€SïI”€EW¿Ð«êÊìQÍE¥Z踀ð€8 `  ž4@lVE!v#õ”ƒœ ÆCSý14TU Å—c –óõ›%©Ì€á>€Át` Øøx#°f 3L Hƒ`gÇHfX5x ‚ ‰ 2[OXƒ(d`2@X¸‰øeP2†`‰áTØÀ0†8 øÐ](,¡`)ši¦‹]PÍìÓ«”›°„F„ H¨ =Û.ƒcƒ›~J0!Â…*+¸ÈÐ8Є˜àJŒ@KØ„  ÉŠ6IãºÀFì(8F’€GÚü£Ihï–íòK€òHµàõËP$Êtθ…¨ ¥¨„ËŒ8°ZØ„…Èh„|¡Z°ÐÊØJŽ`N6«‰”æpxþYKÀ\+Šaø¨ó"h „ø‘ðN -¦9C•S•bt‚™&ð\útpUJ§è ]8È6Ð … %0 OŒÑ'¶ú€¸ ýÀ^¡ ;]Ȥ뺣Z5àJ(GØF¨PD€ª: B ¼ƒ³Íƒø àKØ1˜Aœ¸?Ð N¡i_è¼ p€ùfX’Ù<ÜI9À 3”°¸ 4Ïäú*° ª¶‚ðµhü½€3Î H7‹X=¾[æ³u¾` ¹,\<H-ø)‚p&p‹Ç1j—͘Ñi…€A=Kù˜pœæ(Ñ9Ì­¡€Qy=b3€k@`— œ!åÀ ýþÑÉp°m&¦6¨ €®7c|€Éf_é”㬠h7ø0ƒ¨8„M„DˆL…hHè[„hF…PAƒ"ãpC„@„¸=LƒªîØF…`>¸F„@„°AAŒ†]50@ƒÐOÀ- @ÓÀ=„øbhaƒ°KÔÙi2n3¬ûý1BÚÓ ²‰g²1ã˜ùÇ–Ë7—@ âÆ²áÅZH€¨Õ X ÑÁ2€ 3,IÑØ1˜È0 =Ü6©o{ ²Ù‹-©fa¾àIo¬‰Þ!Ã Д¿°1…–¾{@xÈžv@@x$p+{M`f´ d(4†@ƒ@e @gv‘@4Hƒ8d`1†8bKTP/ëTŠ †Ð` ¢½À_(-Û˜@)%³–¥r*=åµýï¨ÁX60ƒÀºÀ• ‹gK Ç‚QŒšP^ñ(Œ¡x¸ä„p ÐH€ò„7eµÐFøn½Ü0p õ«ç ˆêè‚0OFrIK”Ìè*T¤½ÔŒh%#<†7Ä· ²ì0 Ö»HKîé %Êp'…q…˜‚˜YÜáà‘-Ù¤°Q£(Êàïr%ŒRKí¤§6˜÷@¥‘³œ€)BvZz’ å6ñ‚P¨!…"À ï@ M3o§¨KÉd”ØL6ðï'£o€¸Œú„°J¶pG’ØF»z¨;½;á1iI˜?°"„éø.àWa¸8€6–þtp ˜X ÄtD]ÿœÈ[Í¿P€p '@.±À5"3Oð/O¬úø0 .`ø.O¯1ЬƒiVƒ¥ƒØ ¨E£ÐF#pDñ¸Gˆ#(0‚Ð, ,踺á2iŠb–,?±=Q`€IƒâqƒÑQo¬Ëi„˜Az—€ @` €ˆ‹ 8Âbùpã1¿ÒÏ–ùÂ@° ÒT ˜ cv6Rt–‰¹€` ¹ÞèÃ7‚ð:Y—„>„˜BƒàI„P9h@‚€1 ô„0I…H@„LÀBè=HPÓØTƒè6 AèHuø_ SXC€Yƒð1ƒð?¨DøKÀ>àb„N >èbÔáËÕ?FåõOÅQ±LRén,‰¾èÆ‘¸2ˆ ±–m€ÄLD`(X™IÑ¡ÊÅ@ç%ø€Èø Ó￉‹–±å¬‹-œ|D€ð€ø` €à h°{)k,[U ÀžaihP ° (8žØ -0¸3è<¨ŸØ“Lxh9 ‰ ´`zpxi€6€´ƒ@eX2†?"#S† N¨ +…Ðϸ¨[\ð[Kxþ&¨pU¥ŠXUÕ¥ ^•ï¸Õ è= º€¸`è)x ‚` 5HH#(è$¥®¨ ÜH¨X òÀÑ„j4kì†JïÌ’ˆ¹&ëè„zz„šá„È» ; ލ0Pøõ:뇧x ÀŒ`m«¶ A€ÊŒkØGk½Ã 0ä¤;r¤XQÁ¸V!~ߦ@x¦(\ÆÚBPŒVð¨B5Ú´Õ&" ô…>é€ð'mÐýˆxª¹¢"*¨>:MFÈàÀÑ$Cƒäàlˆ£T¢ |:?NG©pÀù*¦#¤°Tr• ’áqêd0=•ŽRôˆ\l ‘AZ0Tj‰ ‘!Q¢00?TÏaaâH0KUˆHé£B+,áÀPD< A@à¸,Ü·;¨tƒB£ Hd‚ “â˜@F_ˆÌ Ñx$!/ƒ„ ùt1D%ì±p#.…¦°ˆœàªk¡aŠd ’‚aÚ¨F)ÊeS)d¶JáÑ,]AVþx@rÛÁ °` Ù–`U˜Ûx@¾?t ƒ‚ €@"„Aÿpx8#Ý]ûË»üð sÜ @˜( p8*÷‚€ˆ" €.ý`h$´€ð àXDˆ@þ2‘¥@òJcÉ NÄ9@ÐVX  0" »à‹¶.@˜ „À8* {™4®@” Àx'XðBÁ d ƒ f·¹Ð‚nìæOÀmž »›¼ àu¤Ø>ƒáHt…¢<ˆÕè– Æn@ÜhC‘¦ŽæÀf<!°æk†Ã¤ŽF°h9¡˜Üh…ØHZ7áˆÖf…ÃA–Œ†0J1a º`„báx Ű@*A¤X„"y\ ‰ÅP:%•ðŒRƒ¢)FHÈ~LƒaɤÀÈV=@Ü „ƒ,2(àØ– C0.àÐ|MëÀ8’™ù †äh2ÀtHaÒ ‘Éb ¬ƒaá&‡¤ 2Á~I„ : ˆe>"”9¹F„@ðˆPgDà@ àzKÁÑ$mÀØk°†„82‘×> ‡`@’@èpGƒ¡Ú,“„O„BQP …`H'Á¤ZB¦H)Àð˜W"B d¸: Àqéõ èy¯ˆ€†ŽÅ 8$•!žWƒâ‘p ¾8žZÞè9éቩÀào·ˆDînRƒaRà€(Ø=k„ž‰`2D 8 @ò(VØ–6¢P ƒ$Ø„€â, QÁ¨‹`ÜD`h!¡#õbÖ¢Š!ÀØA$ÔNƒ@°%C{`]š EDê( Ø’Ð¥È §ðJ€˜2C èp‚ÀÈH3ÁX‚¶e‚ø3æ@132Z2Áhð¶A]`ˆ10NÀx+`Lp* ƒûó@P dÀSá$00¨pBØRÁ0ðNwÖ çM6€ uÓ©ÖMgTœÐxeá<`0Sšb` =‡Í„¸@€Eî~å° Y'•[&åÔËA@L  ivÕ„G1AÌ 6³€ù©!08ˆ°è%w"È8ˆña9…ˆv"Ä9‰`„H® áèL‡`ÒC eáÜA‰ ü(Åø„CC Q’#Hª!ÌE!'ÄH¦(V 1*ƈ‰cHE ‘¤@@€Á€ðD ƒÁ@Ѐ.¸ˆ0& Àð¸8 „ÀÀ€d BaÐpH@ ÀáÁX0)E €øâm5•‚Â8‚-Eƒ  xP  ƒ£0ÉL6 †B! .Z „A2Ð`6/-…„! è6Ô ¥ƒB–0•x"ëјd â|4+$GçÆðÂÄšÚ#“Lhog MŒÑ‘¥363††¦ˆÔÚÒ›´¦ö˜ÄÞÑhEf–X¬ÊÇ™"ƒ J^`‰K+ ùUd'*Äd…@„Œ£AÂBx8@NGÉpÈé"¢ÃC$\Xx ¡qˆ&&„ƒD°¨„Î#£´¿í" Ä`.@ÀjD± $kºFAÉpvIá$‡¤€>’ ð„ìˆDè@!a€Lƒâ6‡„¬2J¿d€8 èlCƒá¡†„ >àØbCa”~Aw‡d 9(ƒÁôX!ÎYF‰eP<(A¤ZLE˜J&–+˜‡äø<‘ ð`BÉ$04‘ ÐpÿÊÀØ‚PâB %@@'@ø¨\â™n‰®8tLƒa …cè* ´pë“`˘‰EX:é!é.D€2»á¹ ð ˜jEÖ“Ñ& V@¸lE‚¡™ †„H-Á© d=ƒe†$$@¨d>‚Áˆü Á À~LÀ¨:”°ØN6⤠`x4¦+3vƒ h `Â¥|ø U6‚ÁÈ `X:(á°bø  €D1‚!¸ƒâ°  W躄"È `˜J7‚a8Ö„ãp, ¨X>™ !‡‚ˆ°$‰ (ŒBÀ²( b`F… *ê’뀄(b7h‡p Úø¡Èp$†* r:¦‚ˆ*‚¨[žà*$.8#«H¹‚€–ßÃ|2¶ àˆ,¸ËÈ3º^ ˜<ƒÁŒ,ŒäaP@¸æH#—H6‘E`ÊBcP „!L5‘ePÞI–#±,YD©l>ÉN˜A2^Ãé0A‘ÅAR™9Vh‘Ei®F•Æ©Wš„aXi)+Š&¥ «º©ZÚ²€ÿJŒkX,-œh+v¤iþ€ª^Ac`$ ‚6 X€ ‚ðÐ Ð8p PKs`oeȯHÝ\qe¥ö–&´W€in#H¼RZߣN`æÌW€˜@ŒPh X:à´! ˆA@GQšl!A6€Œ\4"„ј”A`M´(Aè\@ä.‹dÀ, "ô†‚ ÃÂä…ñ| Bè¼!\Z‚@¦+ÁQ9A4S‚Ž(ÀèFàu°z%•`Œ á$0 ƒØAÌô†p,àA „Kƒ)7‰6²ÅÀÉ:1 Ä8 b$ £à8­Àò “(ˆà<„¢`%i¤%€òQàäG#yh D*C tˆ 0 S€t)v!H€ÐCõ~OD€ VôG¤á(Bš¡ Re Âp­¡@X‚@œ,Rà©GI)Í€d’¹ƒ zzOÄ`&èAJP‚ Ž)ÁOˆ)‹`@Åœ‘H€P€È+àdˆ@2¬€à?€„æ–+èC xˆð0 DBÙ@\ˆƒð"`ˆrð ¤À&€@¸0ª ÀC0`!´åSb 9ÄS€P‡ð* ƒðáð ƒ5ª˜‚dë‰Ö!ÅxH "0­‚B0ÛõÄXRÈX#X¯pÇ×h%@H¥lÀ°<``$€ö:ظaŒ…ð*è\a¡a†…p"ð‰‹ƒat 1p$ À(|(à€‚HI ¡D'†¤‚˜G pðP&Tˆ¼6!„‰’ŠY ŒÂ_ƒsr%`ƒ2¼ZŸ©'pdh“• ! @Räl–PÖ\@H 8-„Ü+†q `¥aÂP¿ÀÙ'  p–D˜ƒ#CŠAŠDà»X\—|D°¶_‰‘pݵbDYd1`„“¹"Ð? —„(„ùDSŒ±)Fhˆã@CŠ‘¡–†€‰C(CA4@@ SONYDSC-S6002009:04:26 12:38:18Happl scnrRGB XYZ ÓacspAPPLapplöÖÓ-appl rXYZgXYZbXYZ0wtptDchadX,rTRC„gTRC„bTRC„descØncprt”Adscm”þXYZ tK>ËXYZ Zs¬¦&XYZ (W¸3XYZ óRÏsf32 BÞÿÿó&’ý‘ÿÿû¢ÿÿý£ÜÀlcurv3mluc enUS$žesES,LdaDK4ÚdeDE,˜fiFI(ÄfrFU<ÂitIT,rnlNL$noNO xptBR(JsvSE*ìjaJPkoKR2zhTW2zhCNÄKameran RGB-profiiliRGB-profil för Kamera0«0á0é RGB 0×0í0Õ0¡0¤0ëexOMvøj_ RGB ‚r_icÏðPerfil RGB para CámaraRGB-kameraprofilRGB-Profil für Kamerasvøg: RGB cÏðe‡NöRGB-beskrivelse til KameraRGB-profiel CameraÎtºT·| RGB Õ¸\Ó Ç|Perfil RGB de CâmeraProfilo RGB FotocameraCamera RGB ProfileProfil RVB de l appareil-phototextCopyright 2003 Apple Computer Inc., all rights reserved.descCamera RGB ProfileCamera RGB Profile``ü(*Ô,I4$4Ä3@3854Ú3{55¨2x0k/ð)Sê3´Wè[O“„ ¹úìu"öWžŠ»êþÔ÷ rñ’ñ ˜ñZ÷÷÷ ÷(2¢ñ=S¶ñi‡s‡H¼ñ%ˆ’exiv2-0.23/msvc64/testimages/test.jpg0000644000175000017500000005016711510453102017260 0ustar andreasandreasÿØÿàJFIFÿá'ìExifMM* z€–ž(2¦‡iº LCanonCanon PowerShot S5 IS´´2008:09:06 14:34:23 ‚š@‚Hˆ'P0220Pd‘‘x’ €’ˆ’ ’˜’’ ’  ’| N¨’† ö 0100    ˜  ¢ þ¢ ¢¢£¤¤¤¤ ¤ô( 2008:09:06 14:34:232008:09:06 14:34:23 € t S4èòþ.&‚Š"’ÖðI°   ”& v~~Ež"Ð (# È$N Ð% l&0 z' Ú( æ\ÿÿ ÿÿÿ XdtÀ À ÀÿÿÿÿRæ­Dÿó (€@÷€#úIMG:PowerShot S5 IS JPEGFirmware Version 1.01Robin Millsr›€jÿÿÿ×Ayÿÿÿnÿÿÿ÷ xxx€÷ÿÿÿlxx ÿÿôÿÿôÿÿôÿÿôÿÿôÿÿôÿÿÿ÷¤(^ (^™(a qn¯qö€x“ÿÿÿl€l‹ < W€ÿÿçØ/á@õ¾dÄ,ûûTÇ  Š €à€œ##`  ˜@õÄ,,Þ,Þ3a”½U(Æ,'á©À© À ÀR980100 ˜ š ¢( ª:´´ÿØÿÛ„    !#"! $)4,$'1'-=-167:::"*?D>8B3796    OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOÿÀx !ÿÄ¢  }!1AQa"q2‘¡#B±ÁRÑð$3br‚ %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚáâãäåæçèéêñòóôõö÷øùúw!1AQaq"2B‘¡±Á #3RðbrÑ $4á%ñ&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz‚ƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚâãäåæçèéêòóôõö÷øùúÿÚ ?ê¬5t€ª*ÆìW†`Ÿò+NãĈÿÞ‘Håû§ýzRqþ=Õ丷HåX>0O¿ò¬-æãV’#n²½Ëà–ÝÎx䟭+ê;Ë(ßL±Ž}E¥º*À²Æq·Ÿ~µzÛÄçs @ßc·ü‘ý)Úâ¹ò%ÉHÜ¡€ROB=Gj¡{:z¬Ö…c.…K¨Ú0zÑkç!§Ü[hKp-I»¼™‰–íøÉ'_ÇŠÑŠêò´ò"£ (è:SZh&5ÿqsµ€ÚNÑìiêNÐäðqéVHè´xN‘©^Ĺ™¤ˆF3À 9?ȪûcŠx °<•ÇéR2ÛbxAC•?˜ö­ T“H”6Ã"´¦pOÒ”•×ÈkAº¿Š1`ZkiK”.â@õÅgø8XG­Ézon#ˆÙFsÏP}«‚Ú>¬é/ëþ8…¯ÀÓ´ë‰-Ó‰dØW·¯^õ¡¥Îš‚ ¨ÙÕ“ÓÖºiÊÑQyŒÖ·ü!Qjª[o˜ì0tôúôöª×VGP‰Ÿ{‰Y_wÝPy'óW±Mi>›ÄºŠÉ©-µªÁi=9ã‘ßð«ufºdIiKJ8¨PyÎHM8oêD´^„ÌcºµØ]™†3…À¿…UžÞÍ.í>I\ð@8'Üú«BÆ“Û3D§qûÛ±þÁñ]ÅÉEU’@ŽrÄŒ㧦(`Žgis×Ú¥FkoÞDÄ7R:æ¡»‘­gx/c+*0s·ûÞõw(¤€Hî1VКԓOx›AW…Ë–¹o|«þ$sT¾Ï]>ÀT>ƒÐôE]k¸žã £‰å ?¨§†ß†C¸uü=©þ€·¯”Ù!¹RqòŸz³c¤[Ér@‘°yQŒúb¹gy¥×STô¿bmOKKÕ•®dß,¤.UïcŸÖ°,¯ï¼5¨Éa¨1Hœgå^£‘Ÿ_QQ­­×¹N׿àuÙIoq°n`GA#nqÓ׊dÉ1h•H2‚«ž w'óšÖ@¶:[#kc¦KJ„CØnKéÛ‘SÉei6žê$xÊ??)õ÷úÖ«Ky=LX‚4&0Tüj݇ëYéoçA,N?z†ï¯­Y$°µÕ­˜ûByÑ‘ó2žSúÓ${ì˜È®ÎC 0ûÙôþrwZ[Eó×^¬ŸÄ¿‡ZªXð3õ¬äŠCøv9䯴ÅÁ—I¸‹ÞK=úT§a½Mû>‹áëg—QÙP’íÉÉîO©¼aÆà1"ô>¾Õ²ÛЇù‹o:d|GOzŽxⵘØ4dN8†µW¼[ÂdbŠn% UÈï¬mZÖEyË–hÖ\®?¼¤ö5)»ìú•ÍÓ¡ÓÛýŽ;e+4s|ÞyÁ‘ÇÍéX~0Ò þ”’*“q ,{ŽF}_¢ÉÝuì5Ñô,ZêK$g¹“lX<±Æ?Ãõ©4ýKNDó\#®ÿ-YåÈäà{ÿ…Ž£OB”v>eÅÁ¶šBd“ÌÎHPOr$õ=}+nßI¸T¶Œ^¿î•÷df9$àóÏojd–æÒölp,ÐG4Gr1Æz~X¬«èeµ¸Úñª¡mÑ’Ø*ßQÅi¬'ÜÌ–þ{<4ŠeÁÜñŽ˜éòçüãòš¨îcŽUÚIl p:ú©’VºuÖäeÜœ|¸È¬mOM%Ìöà’Oϯ÷À¥%q¦Aed×l0B3r¡‡`FI¥Ôtë²F£÷%ÈÍÆÞz¯·×ž•ÃR§½m’gu*^í÷mêâgŽ)^Vˆ€ZW$ž¿ýε´n-F#Ý‚1È=ëjS{ô“"µ;/M‹s®ÇGFá½zUyYŒnpHÉ¡Ôö8Ño$“ùrFY#ûÄ÷¿S\–ºfðÖ¾’F ³‘?tOEä’=°MCØ£±Ñõ‰$²·¸…ÈWH¹àq×üú×S¤ñ-˜ÈËp9<~µ=ÛOï*:Þ?qŠT p9ôÍQ‚Ñt{³qmIs#B„œd¨ç:UÉ] 3ªðÝôZœO:„q÷³<=Ï?­_Ôݚo”" •9ÆI=œv°Ø¶ÖÁ¬ŠGæo$ u9QƒŒóîOµ&µŦ„•]œ0QK±ôíëœÕ­ 1¾ÎñÁ&T¤‚º±Ç'§^”äÓ­Y·yqA)vQœŸ¯çV"ÌpÀeVÛò²ìlqÍ9­a·²¹ ±D,¨OÞã¨õ¤Á÷Ö³Þ¤qû¢¤8'\ž>•éqxSOÖtË}JâäùM<`ýУgð®w®‡« ¨-¹µVG1­éÚV›æÜEz fêòg>¼šál@“ƦKF ;Ù‡ êkjQvÓdÉÅÊ)[ív:ù# ¼NãžOqTî"L/œhÎCÞºÙå›×1Ãmá‹$P¦[¢e•»à(öà×3¬ØGªéY6 ›KGžªGOÖ¡»[¯3±_¡…áKö[O"LàeH'}+¸ðþ¢RD€›cƒÐÞ†¹£Ê³¹cVmµk˜NUVF Ž;~˜ª¥Þ5Á%½zU”Ú#¶¢g°½û„TåAfw5VßÅZž•å_ožXý\Ü6}IïúÖR÷_“)jj?Ä»”Eû´1:§FÉÉîzz«¦øÃU›Q‰¾Ð¨³|Ãqï“ÈíG0¬Mâ¹­2÷‘Çp䑸ó|Ó-üqnð‡¹·u€±å%IõîGZj¦¾]Ët´óìuÖ·–w:_™lwÇ)<·õëÖ¥A<…— ½W]ãŸb­hdqZÏÃÿ5¤kiZÛç2Iåð¼eøÆÌ8çô¬ sÁ>.·ýÌðOsil¸I¢Ë!^Ç?Ò¹a4›OFºž•ZNGu$´õ.§Ãi×á·öÌï ¾y‰ ñåtéêNOÐ ¥á kMCí2Î (BªœõǯҵS»K»ÐÂxv£Í·"÷ýNÃË‘W8û£…Íëš›GªEi…VcŒçšÕ»#‘^¤\Cko"ÖЈ™OfÏ5OÈr½Fz‚OO_Ò“W”·ÒÞ_MöyD1¼›¾uþ#Ô~'ù×cƒA$ŒYp.ªzcXΣ‚|ªï_‘j7ÜØÖfƒQÓ4½Zݗ̺„4ª!€×#ð¬¸Bòõç5°˜ÇŒ„QÉ\Ò_i–ºÔcí„ùÑÇòJ¤nÆôí?ì‘ÉöH,ÝHúõëÏã]O]1¾°´Ô.X®J¼À³ädnþ•“}¦‹ &$gå=©ˆâLë–ðLŒ@ÏÒ¶Ÿ©›ÊT,±ó’:úŽ¿¥Pø“˜n–hGÈLJ§­aYZZõ:°ÊôÝ·]wV×mµ+(íím*0ºÆ´t;%má•N­ƒÉ>¿JßJMJkÞ;s>×9±u’q„½ÙOeÞÆµ«\ø«M´uA }¢w?uBŽ>¤œ¥lêׯ}srJ¬6Ò `8÷ÿëÖ»³˜¡hÒDÃäá[<õ§]È´SìšȰqô¦#]ÒmµK5Û²ÒEád`>Cëô¬h´(cûƒ¬c-+)PA½O5çbërMGËWêk^7¿È¥ðüË¡ø†æÌ¶ß´C-¾XdÀ~8­oa”`Øí]÷ ³o;$äðücéíSŽz”Qœ|Ì?™¥)Ææ–‘[°I·e¹Ÿª²­¹1¶[’X—n=E;Nò5k±³Cæž­>Â3¤b0GÒ¼úÚÍÍ[ÞIÅù#ÐÁI&àþÒ³^g ø³VÓì4=—ê$vP=k•¿Õ´iþËkol¶³JÊÍFFH½nòF²ÔÜ|ã1I¹ 9òÍn}²;è⺌œLža_î7ñÀä}1ZÜ. œ•ëO‘>Ò›‰¸==èiJ6–©‹gtfê·QXiÒExêÛWËP­Œ0õJÊÝuoÚ\Úmw³e(OëÄ×›ûµ%ðr».º”¢ù­Öë_C¸ñŽ“.¸-£€6ö 냃ƒþÏx‚Å´×K2¦FAÄŒX.~‡¯çE&š³îz2W×m¼ áåÖ¼So§Ê ÐBÂâè· ªýÕ?Ráš÷i®1‰*ë^…Ú=¹™äâeÍ=>ʱâŸ.Rþê;¸bŒ¤øÀ8 ûåõ® ù‘#¹Q‰m_icÉe<`þ~»Vg:w:–Òí‘ä·Èz2·ÉŸ¦8üë7ÅZ(¸·ÂqÁÇzÓ‘(» U%6›Õ­ ÞžëJºˆÉË~\xý ô¨äLd¡9È¥-aÕ]2#¤ä»Ù¢Ñ˜++ Ü3Ûµ"Ï»„ç½fhinK+RÎ¥™v°\’ˆF3XÓ¢6IϽL0‘È_Ù!¡ÜJÉÌmýÖôüi¾y®ïŽ‘3ÈY1ÇnõŒ¤¢›{GV]®ýN¯û/θšßJÞ½¸l¨BsÈOïã½E•s{æ}S16ÙK>6wÉ=ó¬éâbàç6£o²µjã”슺o€äñ>£)ŠêÝ­ãm²Ëêû#¹÷éïZz_Ã¥ð~«%Ü—¿lˆý×)´©'#=1\5«òÞ­Ïø¸vœ¢ßBÏŒõ[kv³›ËšßO#ÔW!­x“SÔ4ù®ne3 u€¸$ þ´ðé¶—vuÖ—$[]ŽÏàÜqÚø@ÝÈTO¨^2+“ÉEý‹ó®«YÔn.íÝŒLÑ+FÀdõÛŸÌʽ¸¯ø†ÙãÚõâÝi×M€s+€:|À†Ç¶B× ÇËÅ#+'9ï t?­šMͰYC+†† Ç®GoÌTV=›©¼-$Œ«t÷¤ã%ç KѲK¨HÕíïÒC4@lú…wÚDìDyÜÑ6Ìçªöý1ZrÚ[Ù§s6ýôû¦r[ˆúõ«P$R1Ž^TÒØ;zuíÔ~uŒ¶õ4DmpÿhgüÇž: XÙ6·ÌÙë@S"È6H ‚:+wNÐWKÓ#H\¦¡«žm¿46Ãݲ¾G¥y¹…NJ^¯SzJììê &É,¢MŽábV å(»·E®WM³ÿ„ÆàYÛÛ›DÛ’$% óg™ºùyéÝ¿8²ÄêÉßXAÞOûÆ•t^oò;tðˆ…¢DcŒÚİù_î7Ì×=âQ}¦Z¼wGÍ8K€>ø÷›×±ê;ß §uñCò3¥;;w<³Vic»åÙ¡s•ÉéíYñê§ëÖñʬ®TÃ*‡>¿¥e‡ÖÏ­¿vV“•+÷Üö/éÛišJ >M­¼žP÷v$ŸÔ~µSÅ÷Ÿfñµª1ÂËñäÔ öWèylòÊl§½ƒþYȬ¡}>`ÃùW7n·•s˰Oä)LqýžÞ)òa0“|ËíŸJtútª†6…Ìl28Î+m ÊvR‰íd±¸c + ðÕòý© eŒ¯Õ“·äJp\Ñk¯+ü ž>Òü΂öí--þE-)ÈQÔûS<>®-.®.ÞkÆÂÇ‘Oo«gþù®W«±·BÕÀu?9f‘e*AV9Èæ’Ü|!`uÝXG*²Æ‡|ç§Ê;gßηï5‰›ÄW«c yá–ÞÇ(ª9 éóæ¾w5¬ì£í·›;(Ç_#+»]{ÅK᤹i-cSq©Ì„æå‡H³×nzúþ5êzFž¶` ï‚À m”{Æ+Ô˨{desc,_dscmŒðmmod|(cprt¤$XYZ u›>ÍXYZ Zƒ¬,XYZ &¸μÝXYZ óRÏsf32 BÞÿÿó&’ý‘ÿÿû¢ÿÿý£ÜÀlcurvÍcurvÍcurvÍvcgtL6)jÄ; Å ] ®`¾b ¥5³&eš Í"#:$y%³&ï(1)o*«+ç-#.Z/0º1è3435V6n7“8¿9î;‡?¥@¿AÖBëCúEFGHIJKLMNO(P?QRRdSwT‡U”V¡W¬X·YÁZÌ[×\ã]ï^ý` ab-c@dReUfPgLhEi@j?krFsPtZufvxw‰x™y¨z®{ª|¢}~˜œ€›ž‚¢ƒ§„«…®†­‡­ˆ¯‰©Š¥‹œŒƒŽrfk‘n’s“v”w•t–n—i˜_™SšF›8œ'þžéŸÓ ¹¡Ÿ¢ˆ£s¤p¥o¦n§n¨k©gªb«[¬S­L®E¯>°7±0²)³$´µ¶·¸¸ø¹Ïº »t¼G½½ì¾¿¿”ÀlÁDÂÂùÃÖĵŔÆvÇYÈ?É'Ê ÊëË¿ÌÍcÎ9ÏÏêÐÆÑŸÒ}Ó[Ô8ÕÕðÖÊ×£ØzÙPÚ$ÚõÛÃÜ—ÝuÞVß7ààôáÐâ¨ãäUå*åûæÊç—ècé.éøêÃë‹ìTííåîÂï¡ð€ñ]ò9óóðôÇõžöt÷IøøîùÂú–ûhü<ýýçþ¼ÿgÿÿß®¯Ú!  œ 8 ç”Aí–5ÊNÁ%\‡¯ Ý"#B$p%¢&×( )?*o+ž,Ì-ô/0>1Z2s3Š4ž5·6×7ú9:7;P‡?”@ŸA¦B©C©D§E£FŸG™H’IˆJ€KzL†M–N£O¯P»QÄRËSÐTÕUØVÛWÞXàYäZç[ì\ô]ü_` ab búcèdÖeÅf¶g§h—i‰j}kslim`n\oYpVqVr[s`tcufvbwQxAy2z'{|}~€ ‚ƒƒü„ô…ë†ß‡Ðˆ¿‰¬Šš‹ ŒŸ¢Ž¡ ›‘’’‹“~”p•a–P—>˜*™™ýšç›Íœ³ž†Ÿ„ ‚¡€¢£{¤w¥q¦i§`¨X©OªG«>¬5­-®%¯°±²³³ì´Åµ˜¶o·E¸¸ñ¹Èº¢»~¼[½:¾¾ÿ¿ãÀÈÁ´ÂœÃˆÄxÅfÆJÇ&ÈÈÙɺʚË|Ì`ÍDÎ+ÏÏúÐãÑÈÒ®Ó’ÔuÕWÖ6××ïØÌÙÀڲۦܖ݆Þtß_àHá1ââûãÞä½åæ{çYè7ééïêÍë®ì¡íœî–ïŽð†ñ}òródôVõGö6÷$øøþùìúØûÅüµý¥þ”ÿZÿÿƒxz¢èC¸ > Ï e ÿ™+º?®!wÂÿ:h–É ü"0#^$Š%·&â( )0*M+h,|-‹.–/ž0¡1 2ž3œ45Ÿ6 78™9’:ˆ;{E?-@@õA×BºCD~E\F?G H HýIìJÛKÊL·M¤NOzPeQOR:S$TTýUìVÝWÍX¾Y°Zž[ƒ\]]8^^î_Í`­abrcXd@e+fggúhîiåjÞkØlÒmÌnÄoºp®q¥ržs›t™u›vžw¢x§y©zª{ª|«}¨~¤œ€ƒ‚qƒb„[…Q†I‡>ˆ1‰!ŠŠú‹ãŒÊ®ŽpL‘(’’Ü“³”Š•c–A—%˜˜ø™ášÉ›¯œ–yž]ŸA %¡ ¡î¢Ó£º¤ ¥‰¦s§^¨I©/ªªå«¶¬­a®6¯ ¯ä°¾±œ²z³\´Aµ'¶¶ù·ç¸Ô¹Ãº¸»ª¼Ž½i¾A¿¿öÀÓÁ±Â‘ÃpÄQÅ1ÆÆñÇÐȫɅÊ]Ë4ÌÌÛͪ΃ÏgÐPÑ:Ò$Ó ÓôÔØÕºÖ×~Ø\Ù9ÚÚðÛÉÜ¡ÝzÞRß)ààÙáÊâ½ã­ä–åæhçTèCé7ê4ë>ìWíî¼ðñ•óBõ(÷kúýqÿÿndin6£gX1L‘&LP T9. ÌÌÌ#1AQbs†™­Á×í5Oj‡¤Ââ'LtÎ9q«å]›Û]¡ç.wÂ`²^¸  u Ô 3 ‘ ñ U ¹ ! Œ ù i ÝRËHÇKÒ[çwŸ4ËXæx ¡9ÕrµYÿ§Où¥Qý «![" "¼#{$A%%Ó&ž'h(6))Õ*¥+v,H--ë.¼/0a1122×3­4Š5t6d7S8D9.:; ;ü<ì=Þ>Ó?Í@ÉAÃBÈCÌD×EèFüHI,J.K9LAMON_OvP’Q®RÓSûU'VVW‹XÇZ[C\‹]Õ_`baŽbÀcñe$f]g—hÖjk]l¢mêo2p}qÉstbu¯vûxGy—zÿ|Ž~-Çhƒ „­†N‡í‰‹*ŒÅŽ_û‘“)”¼–M—ñ™°›v9žõ ³¢l¤+¥â§ž©\« ¬é®¸°‹²f´I¶9¸¹â»«½~¿QÁ-ÃÅÆñÈíÊñÌþÏÑ*ÓCÕf׊ٱۤݖßáŠãˆåŽçé°ëÇíåð ò-ôSö~ø¢úÊüôÿÿ *:K\n”¨½Òèÿ0Jež½Ýÿ#IrÏ>x³ï,l­ï2w¾Rží?”éC þ a Ä ' ‰ í U ½ ) ™ € øsñsù‚.Â[ô"³GÞv°Qõ›Dï›Jù«\  Â!x"-"é#´$…%Y&.''Ú(´)Ž*h+C,,ü-×.²/0l1F2"33â4Ì5Ä6½7µ8¬9¡:˜;Ž<ƒ=z>s?p@pAoBtC~DŠEF´GÐHïIóKL MN.OFPeQƒR«SÔUV4WiX¦Yå[#\k]µ^û`Daqb£cÖe fCg~h½jkGlm×o!pnq½s t\u¬vüxMy¡{ |˜~1Å_‚û„–†/‡Å‰[ŠîŒŽ ‘&’¶”>•—P˜÷š«œcž Ÿ¹¡d£¤¶¦]¨©¯«_­®É°„²F´ µà·®¹Rºý¼£¾XÀ ÁÅÉÅMÇÈëÊÃ̤΅ÐoÒXÔDÖ9Ø*ÚÛÐÝ‹ßJáâÕäŸæpèFêëýíÞïÈñ®ó•õ„÷oùVûCý0ÿÿ*9IYk}¤¹Ïæþ2NkЬÏóFs¤Ö D}·ó0p²ö;ƒÍi»jÇ'Šò \ É 7 ¦  Œ   þ ’ ³Jæ„$ÈqÅh¶a¿r)âž[Û_ " è!®"x#L$/%%ü&ã'Ê(²)›*‚+j,Q-7.//ç0Ì1°2–3~4i5Y6L7@839#:;;õ<å=×>Ì?Å@ÀA»B½CÁDËEÜFïH I$J5KMLdMN¢OÊPöR(S_T›UßW&XvYÊ[ \]à_?`—aæc2deÔg+h…iåkFlªnoupÝrDs®uv}wåyPzÈ|T}ñ‡$‚¿„Z…󇆉ЧŒ3½GÊ’Q“Õ•S–Ö˜uš)›â–ŸI ü¢­¤a¦§Ê©ƒ«A­®Ô°¦²€´a¶M¸!¹Ý»•½Q¿ÀÔ ÄrÆDÈÊËéÍÔÏÇѽӴհ׮٭ÛwÝ@ßàöâÚ仿˜èpê8ëîíïð–ñÿóVô‡õ©öº÷´ø¥ùyúFúþû§üPüÛýbýéþˆÿDÿÿdesciMacmluc nbNOèptPTèsvSEèfiFIèdaDKèzhCNèfrFRèjaJPèenUSèplPLèptBRèesESèzhTWèruRUèkoKRèdeDEènlNLèitITèiMacmmodœlÁ´ÅtextCopyright Apple, Inc., 2008ÿÛC&@)&##&N8;.@\Qa`[QYXfs’|fl‹nXY®‹—œ¤¦¤c{´Á²Ÿ¿’¡¤žÿÛC&!&K))KžiYižžžžžžžžžžžžžžžžžžžžžžžžžžžžžžžžžžžžžžžžžžžžžžžžžžÿÀ–È"ÿÄ ÿĵ}!1AQa"q2‘¡#B±ÁRÑð$3br‚ %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚáâãäåæçèéêñòóôõö÷øùúÿÄ ÿĵw!1AQaq"2B‘¡±Á #3RðbrÑ $4á%ñ&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz‚ƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚâãäåæçèéêòóôõö÷øùúÿÚ ?¹‘€‘Ê£FCÿêô«kp"N’@'ž¿…e"ŒuÀ'‚yãÞ!U: ¬Ã9÷4‚Åãp»b, pqž£úVåÑûNð €qòŸ_ÿ]O †) J3ÁÏùéM‡OûZI4…’ âýáÎp}¿Ž)zùlrHÆ3Ö´mÒSó¤Âû dŽüþB…Ž+s‹t¼žXñïëÏJ²Ëº/•c.:cŸþ½0í+Fé!t ž€g¯Cß³N% ã*z`sœã<Õ1lÊ«2u8ÆGÿ®· 7ƒÉÃ×ÿÕE„L@ Ûxb"CÔ*cjî"C¸Æ?úôñƒÉ%ÈàŒà“Û?ç½P»‚ùxË‚q´ Š$KfgüÛ–Î@‘ÔçëøTÆïÏDV:äd·^õ@g¿ªOx9Î(îÐàqMV!Oð°ëMŽu#l‡nïSŒÓü±’~^Gzbž8ÇzX-ãi&f)ˆãý–Ü0FzQÆÌO⥶2­¬ä…¸LžsÔÒš©!‰àŒŠ|NHÚx#ž)dƒ—^Aဤò÷c§J` œÕË[¿(“!%Oq“U‘· ÿãÞŽÆ=&€´×èasƒý®¤~= Í}¦ux$˜üÀŸ¯ch4eyëõ¨VÜPã½gkm$–ööÀÍy°ÅÎ{tëY©¨Á$›B²ŽÆœÑ~àÇŸÊ™#Lß9TÉ Üçèj5•–\±$d÷ê 9ÕŒ»£ê ñÍ H˜+³|œüÝ…0ÊRQÎGùçóª—®á\3r2cœuÇãþEX`èpŒcŒ€@<Ò>‚ä9õóÖ€2=*iãq=1V¤‹ y‹·Ñ±Ç½Vtx¤*ùýi `\“€AóS$Øa»’:ñP†õÆ:S€=¹Ïj@X•‰Ü}йãéNµrÖË`;à„ã¡÷äŸÒ ‘ñ«d¥yõ5ªíg´p#C&ÕÚW#êqÜÑp±IÔ•!rH9ÑœqÏ®jU?‰ŽvÀ{¡±•;ÆN:u¤ãÔÓ„¤&I;G>ôÆ}¬[ € —#·?JpbF Ž døSÈÇ£Žð[Âë÷à+sס-æˆbѨPIãÍH`!·LIR0ª¶7˜ HÌSœúz¶Óo}èIãëü¿Æ•€Ç¼€Ú\e2ªù zzŠ+Rò<;AV8ã´PÐÈâ˜ÄÀ(©öôÅ<´Àc(qŒõ`3Ú¢p¯VÎG#ÛÚ­ªDÎ uïþ{Sü€'b§ä`ŒÏ×±ŽQÑ•H?7CSÇœ´r³Ðgq½=?:±z$ÚŒíÏQÓN*½ˆSp»ŽÜ”_JÎLÒ(lñîÆà.„ÓŒ~¿ÓY u‘£N03–õÇáÖºÒ|À]ß' €OO­SŸOîþa$d’ÏÒ§TidÌÈg01ŠlžàÕÐA'÷=ë>ýxFô8«6Ùû2ç·éZ#)+ciÇSšnT’:ôæ 9ã*¹ÉÀ gÖ¨òÛ9^;Ôwð´ÐùŠ>uëî?Ïõ­h‘aÒÚR™yNÐsÆ?ȪxÃ`ôÇ>”†fÙ\Ÿ4sÇášt–öšP·ò\RK``“øÿ?JwCQg8ZFl±<}kj"ÁA`AÀ{¤ŒL*JÐ\m”“Ç#š¤îD£`é‚8ô÷ª²Ê¢M˜çÔ ÕÆÙcU™‚€IÆO æ—<Ûcq)bÀÁü©² R?ú ¼j,ØîzUn ÃrOz³u°å/=‡APއŒÒꉛø£>žÜÓ-±†Úxµ[¸_5ãµW²ºIåºç‘Ê“Ðe¸s€í+ÒŠyH |á›þÇ^E.Rè= "à\h¶À€JáNLqÏèZªIã5‡nÚ<™2ÊÊp àzñî?©¤$dvû¹b÷ñó dж‡$Àœ;Ó”ŒtÎù4²ppØÉÿdž?ɦ! ¡Cço#ùcùÔwÖ;z02ñ>Øãü?J‘Šà wÉç¼Ð>]¯¹™˜œ ç9ÇëøÔOMJFP]«¸ñÎ3×ÓpÙàþ½\½€ÉÌ'qçÜÀ6}9<ÔZ=‹^]î9ÇËüªSЫºn˜<ë…ÎF@=ªØaIŽ0§Ú¦Ô5ljÌÈ /5BYæ{=ºŒãŠVêj´)N 3,«‘냊è¾Ñ¨f—i‘ÉÚI=kœ3<¨ê@<}*y^ßû.8Ä¿¿3)ÔþùÍhŒdjk7 .!…Xê@õ?_§5Ä¥ÛÍ,‘>‡®?!YÚ\Fþãw•Pcó?çÖº[Ku´ÕNrIç4¤8;3V+)$™HéUdÖ-+:öçcTù.C¯ù¨žýÚ#.ÐxÇÕèõ*Ĺ›œõ5£Ð÷­V·XÀÜçæ'ðúUóØŒ£h‚3ÓzÕ&·0“»$ÓÔɪ"„ù#]ìsÓ®*K´y§–LT!FOøQ¥,‘-ÍĘW~ àÛé΢‘üüFî8ÎO~ß×ß½,“:((&s‘Áÿ9¤{X¬g~xã_óëP !¶¨ÚK\‡‚jg@[åqÎ;~°zÓIÉÞÈclŽ8ÅdË¿sX•8Éë]š å†0Ü~x5FæepÅÈ+À 3ŸÂ¦NÊãFlbMû|°ð íŽüQWšÜ!,À…\®0séEeÍp±WL²j1»_‘ÐÖǘ.¥Þ9,ÙV|ˆ­q‚Ø}à3Ò¯ ñ$ª¥‹}óÇÞsùζ«2­†ÈÉéOR$-ý|ÔcæqÏÅ(fÜsÐOOZncÜçïþsI(ýÛøpà &šòËåaIn3MR$–ù¶€Y›™ÿ=*{0 6ŒrË‚¨W=±ëÿÖ­-&¶yã|áŽ;°¦´ÛœílÃüš×Òg’[Wy\´»v¶zñœ?Ò¡÷7‹º±.¦Ö‚E2ǸššÛÿe¢D>líË${â9pyÏZK€¨ëøŒSE¶C®zRE 3ÈDK)' Xþ8íþri¶ÓÆ àzìtë5°°ŠÝ\ú±ëþLUÄÆlåš&‰¶² }Ò0GáV-®çŽ6o9 IŒ«¿?AÞºF('€¬Ã á»¯Ð×Ò½­Æc`̇‚WƒTgrõÔËq˜¹(OއÐÕ#ÁéM—qìƒæã¿¯ês“o•*}ö‘ìsK—±ª©}Ê;G34lpO óÍ_³¹3’È AÛ×õõúsסÅE4¢àtýj‚’V´ÐÅêvwû„HU²e˜° š©,@-‚ªYÎÒ(ˆÉ¸àuþ_çµXS»ŒlRjÁ{–°0‡.Äò£©â£fcÑ´ œØsùv¤ÇÌ\‘³ƒšt­½™xÇ·Óô d9“‚;jÑþY<¯1ãjŒGÓ¿¥\M¥HxÛ‘üKÄ0ì‹–Èyßo\tÇó5-_@3ZØ­pq# à**Ã+0êp{÷¢šIšø‘1‚]yÎ?Ïù4–Ráž.ŠàÎGù53‚y8<ý*¬ˆë*¼`òxž})|pÇŽÝ©yãvAõ««–걤k%û&ì1ÊÄ=Iõÿ?RæÂT‡Ï–Q¸/ïq;»p1ôüýªE{Å-Å\¸ÇBx"«Ý\;1Egž€V‚­{ÇxÔ“ò‘ËzcÓüô¢ÞÞ O›wÐÂ:nCƒÓnÝû­ §ªè5¡†%t†ÜéþMt¶q‚Ûöí-ÀÅZ–ÎÆXÁEád~¢ªµÏ̲cž„µ“Ÿ6ư!†X#ºd›äq¶j•ÚÂ&&9Kú’*;¹D²îj žÙÙ9+‚@ëZ¸¢¥+"þƒnooüÿ—Ê€ä« äœâºƒ ÀàóÓÎèmö}!äØÂIæ©Ç·þ=Z÷Ò¼¸Ê6vÅn‘ÌÝÊšÉFï#rúƒþ"¹ËÔ 3!‚žî+_U—v×Fâ@ÇqÁ¬{·ÆÀü¸?ʘˆ'’VVÎAíÿ]L’sÆr9\œÁNçSùjè ƒ9‡Ò’&ûZŒ‡ê1ØçùUy.W'Ò`HÎáëO…óû·ù€û¹§¨‡ØÊŒ¹Ág'Œwþuªvàtö5y #ô­X›&xd88æŽÔœ»“ôÁ¦ä8÷ç¦i‹Øã òqÍ,“"(v!s×>½¸¤ÑHð¿˜Tð1»oR}3è3HXÈI-Éäàõ¥|¶1]82{ŸZ‹8È’i W;†rIî(¥VbÅW!G Aš)ˆ­&xçÐ`š¹aoù—s.R˜ u?ãþ5Fß0€]ŽÑ[~U´vöÌ !}ÏþÖÑž~U…IYX´‚Á ´—ÿ­“æ‘DöþTë«ÈV:D_!å.2do@?>j»Ìn4å[D2À/sMÓÁÔYïd,ge´`ð¾ÿ_Oư§7ržƒì-fº¼ûeÚæaÊ#}ØGn;··n§šÚH‚d–w'©cŸÓ ü(‚%† ƒêO©õ©+µ+hfg\Y˜˜Él0¬yéþð÷öïõ¬+–ór¹ç±Õ;¨ô5Íê¿hgLí=w ÖS‡ÚE&dŒ‚Aê)!™ ½w ô©¦\0luëUfŒ±ùzãÃüšqÔ¹jŽ›Lˆ5µ¶3å£>ў̧ó«ZÆ~Äqëýj-¨Ó-Šð,~¤ž*-Nú’HÈH ަ¶13nΰ‰À(p1ý?ZÈ•ËSÑ é×úš½àÒyÚO¢˜4Ûxâ-tAÜNÔõïK¨+=ú'÷{‰=¹?áZ1Û$AbR1‘¸÷îÏ­P¹—ËŽK†žàâ1×:~}à“æw5F.±rÛ#<…=ýÏÖ¶¼4§ìC#*§ ûž¿¦?:æu7g»mùÞ>½k³Ñ¡òt¸AêÃyük®š´QrõEXˆ¥ÉSèJžMÊFÐzò?­mL@S’¬K†%ø#4–À2ã“UeÌgwu9«È£í*‹ýêKûoܱ@8œ…ß ±êrÛC1ìØ™<޹$ÿZ¬d2JÎÇ,Ä“õªìF"?ìóùšzÙÇÈ0ÿZ¯sÃê*ÔVºsñ¡ˆ‹p*ä™0BrÌÕ0 À^–<žùh@C¸nÎÑùT¡C~QÛÒ£1žÇ¯?v¤Ž& ÉÔÀ‰ŽN@>˜«8Dv8$ž´Æˆ°;H'Ò’0È9Ç×­&½e´ÛÎYR6/‘Ý8?ÏÔùnZv`HÉ$ç©©lvÉá#.±¨SÎy'ÐT!XßÔzý:Ô!±å‰8ä翵 8ëÆ|þ¥K`HíLh#¡ïL»W £ÞŠnFìqœE1nL–ö™éï8à¨0üsüêÀ—Tbܬ)¸ßüæŠ+ϖƨäõ"Mü¥º“Ïå]í™ÿBƒóÍ•Wt~CÜY#Ž£>•-S ¼…=Éâ±®uëÍS=Ð-Ó7b¹Å]Ϙ ·R9¢Š°yI¸7œ¯ÿª©,ì¤à/åE‡¹j9|Øó·¨.ÉÊ­UtQ‘ã=êøËÛ«bTíäÑED%—¡ÝùÓÑ׆çÞŠ*€wÈ_vÜ–ŒñA+¸:–¦4QE‚åûGeŽh€p§?Cÿ×§IÂÅØ° zöçñæŠ+2˜™.¸Œ‘×–çÖ˜ëËZ(¦!ÎIú÷¢Š(ÿÙexiv2-0.23/msvc64/setbuild.py0000644000175000017500000001017211510510033015604 0ustar andreasandreas#!/usr/bin/env python # -*- coding: Latin-1 -*- """ setbuild - set the build environment you require """ ## def syntax(): "syntax - print syntax of setbuild.py " print "syntax: python setbuild.py Win32|x64|all|reset" ## ## # import modules import os.path import sys import xml.dom.minidom from xml.sax.saxutils import escape ## # from PP3E/System/Filetools/cpall.py maxfileload = 5 * 1024 * 1024 blksize = 100 * 1024 ## def cp(pathFrom, pathTo, maxfileload=maxfileload): """ copy file pathFrom to pathTo, byte for byte """ if os.path.getsize(pathFrom) <= maxfileload: bytesFrom = open(pathFrom, 'rb').read() # read small file all at once open(pathTo, 'wb').write(bytesFrom) # need b mode on Windows else: fileFrom = open(pathFrom, 'rb') # read big files in chunks fileTo = open(pathTo, 'wb') # need b mode here too while 1: bytesFrom = fileFrom.read(blksize) # get one block, less at end if not bytesFrom: break # empty after last chunk fileTo.write(bytesFrom) ## ## def save(path): """save - make a backup (or restore the backup)""" orig = path+'.orig' if os.path.exists(orig): cp(orig,path) else: cp(path,orig) ## ## def sln(path,remove): """sln - remove the x64 stuff from a sln""" save(path) if remove: f = open(path, 'r') lines = [] for line in f: if line.find(remove)<0: lines.append(line) f.close() f = open(path,'w') for line in lines: f.write(line) f.close() ## ## def vcproj(path,remove): """vcproj - remove the x64 stuff from a vcproj""" save(path) if remove: f = open(path,'r') dom = xml.dom.minidom.parseString(f.read()) f.close() for tag in [ 'Platform','Configuration' ]: tags = dom.getElementsByTagName(tag) kills = [] for t in tags: if t.getAttribute("Name").find(remove)>=0: kills.append(t) for kill in kills: kill.parentNode.removeChild(kill) # repair the command lines! for tool in dom.getElementsByTagName('Tool'): cl=tool.getAttribute('CommandLine') if cl: cl=escape(cl) cl=cl.replace('\r','__CR__') cl=cl.replace('\n','__LF__') tool.setAttribute('CommandLine',cl) # print '-----------',cl,'----------' code=dom.toxml() code=code.replace('__CR__',' ') code=code.replace('__LF__',' ') f = open(path,'w') f.write(code) f.close() ## ## def visit(myData, directoryName, filesInDirectory): # called for each dir """visit - called by os.path.walk""" # print "in visitor",directoryName, "myData = ",myData # print "filesInDirectory => ",filesInDirectory for filename in filesInDirectory: # do non-dir files here pathname = os.path.join(directoryName, filename) if not os.path.isdir(pathname): global paths paths.append(pathname) ## ## def setbuild(remove): """setbuild - remove == None, means both x64 and Win32""" if remove in set(['x64','Win32',None]): directory = os.path.abspath(os.path.dirname(sys.argv[0])) print "directory = ",directory global paths paths=[] os.path.walk(directory, visit, None) for path in paths: # print path handlers = { '.sln' : sln , '.vcproj' : vcproj } ; ext=os.path.splitext(path)[1] if handlers.has_key(ext): handlers[ext](path,remove) else: syntax() ## ## if __name__ == '__main__': argc = len(sys.argv) syntaxError = argc < 2 if not syntaxError: option=sys.argv[1].lower() removes = { 'x64' : 'Win32' , 'win32' : 'x64' , 'all' : None , 'reset' : None } syntaxError = not removes.has_key(option) if not syntaxError: setbuild(removes[option]) if option=='reset': os.system('del/s *.orig') if syntaxError: syntax() # That's all Folks! ## exiv2-0.23/msvc64/xmpsdk/0000755000175000017500000000000011745263367014755 5ustar andreasandreasexiv2-0.23/msvc64/xmpsdk/xmpsdk.vcproj0000644000175000017500000004101311532054201017462 0ustar andreasandreas exiv2-0.23/msvc64/ReadMe.txt0000644000175000017500000002474411635335547015356 0ustar andreasandreasexiv2\msvc64\ReadMe.txt ----------------------- Updated: 2011-02-25 This is work in progress. However this is sufficiently robust to be in current use by a commercial licensee of exiv2. 1) Working Build 32 bit and 64 bit builds of exiv2.exe (and libraries exiv2lib,expat,zlib,xmpsdk). Builds with VS2005, 2008 and 2010. Supports zlib-1.2.5 or zlib-1.2.3 setbuild.py "doctors" the project files for DevStudio Express buildall.bat batch building script runner.py build verification script (and binaries/code for depends{32|64}.exe) 2) TODO (in priority order) a) Build sample/test applications (exifprint etc) b) Use .vsprop files to hold "common" project settings Assistance appreciated if you wish to become involved. Robin Mills http://clanmills.com email: robin@clanmills.com #### T A B L E o f C O N T E N T S 1 Build Instructions 1.1 Tools 1.2 Install zlib and expat sources. 1.3 Open exiv2\msvc64\exiv2.sln 1.4 What is build 1.5 Building with zlib1.2.3 1.6 Express editions of DevStudio (or 32 bit only builds, or 64 bit only builds) 2 Design 2.1 Architecture 2.2 Changing the version of expat/zlib/xmpsdk 2.3 Relationship with msvc build environment 3 Acknowledgment of prior work 3.1 Differences between inherited project and the exiv2 projects 4 Batch builds and tests 4.1 buildall.bat 4.2 runner.py ## End Table of Contents End ## #### 1 Build Instructions 1.1 Tools This has been tested with the "Pro" versions of VS 2005/08/10 Express editions don't support 64 bit builds, however it is possible to build 32 bit libraries with "Express". See notes below about DevStudio Express and building only Win32 or x64 builds 1.2 Install zlib and expat sources. I use the directory c:\gnu for this purpose, however the name isn't important. c:\gnu>dir Directory of c:\gnu 2010-12-05 10:05 exiv2 <--- this tree 2010-12-02 21:06 expat-2.0.1 <--- "vanilla" expat 2.0.1 source tree 2010-12-02 20:58 zlib-1.2.5 <--- "vanilla" zlib 1.2.5 source tree 2010-12-02 20:58 zlib-1.2.3 OPTIONAL <--- "vanilla" zlib 1.2.3 source tree c:\gnu> The URLs from which to obtain zlib and expat are documented in exiv2\msvc\README-MSVC.txt expat-2.0.1 is available from http://voxel.dl.sourceforge.net/sourceforge/expat/expat-2.0.1.tar.gz zlib-1.2.5 is available from http://zlib.net/zlib-1.2.5.tar.gz 1.3 Open exiv2\msvc64\exiv2.sln Projects are zlib, expat, xmpsdk, exiv2lib, exiv2 Build/Batch build... Select All, Build - 5 projects (zlib, expat, xmpsdk, exiv2lib, exiv2) x 2 Platforms (x64|Win32) x 4 Configurations (Debug|Release|DebugDLL|ReleaseDLL) = 5x2x4 = 40 builds. If you haven't installed the x64 compiler, don't select the 64 bit configurations! You may have to hand-edit the vcproj and sln files to hide the 64 bit information. See the notes about DevStudio Express for more information about this. Build time is 15 minutes on a 2.2GHz Duo Core and consumes 1.0 gBytes of disk space. 1.4 What is built The DLL builds use the DLL version of the C runtime libraries The Debug|Release builds use static C runtime libraries This is discussed in exiv2\msvc\README-MSVC.txt 1.5 Building with zlib1.2.3 By default, msvc64 builds with zlib-1.2.5 You can build with zlib1.2.3. To do this: 1) copy/y exiv2\msvc64\zlib123\zlib.vcproj exiv2\msvc64\zlib\zlib.vcproj 2) You will need the sources in a directory parallel to exiv2 c:\gnu>dir Directory of c:\gnu 2010-12-05 10:05 exiv2 <--- this tree 2010-12-02 21:06 expat-2.0.1 <--- "vanilla" expat 2.0.1 source tree 2010-12-02 20:58 zlib-1.2.5 <--- "vanilla" zlib 1.2.5 source tree 2010-12-02 20:58 zlib-1.2.3 OPTIONAL <--- "vanilla" zlib 1.2.3 source tree c:\gnu> Please see exiv2\msvc\README-MSVC.txt for information about obtaining zlib-1.2.3 3) Alter the "AdditionalIncludeDirectories" in the following projects: xmpsdk.vcproj exiv2lib.vcproj exiv2.vcproj There are 8 occurances of "AdditionalIncludeDirectories" in each of the 3 projects. If you have both 1.2.3 and 1.2.5 in your build tree, you'll probably "get away with" not making this change - however this is due to good luck and you should really adjust the vcprojects. 1.6 Express editions of DevStudio (or 32 bit only builds, or 64 bit only builds) Express does not provide a 64 bit compiler. You can build 32 bit libraries with DevStudio Express (with a little effort) Before loading the project, use the python script setbuild.py to select Win32: c:\gnu\exiv2\msvc64>setbuild.py Win32 setbuild.py is none destructive. If you have a 64 bit compiler, you can: 1) Restore the build environment with: setbuild.py all 2) Select x64 bit builds only with: setbuild.py x64 If you don't have python available (it's a free download from ActiveState.com), you can "doctor" to project files manually to remove mentiosn of X64 using an editor: Cleanup your tree and edit the files. cd exiv2\msvc64 call cleaner.bat for /r %f in (*.vcproj) do notepad %f for /r %f in (*.sln) do notepad %f I personally don't recommend notepad for any purpose at all. I use TextPad http://www.textpad.com/ Notepad++ is also good. DevStudio Express 2010 does not have the "Batch Build" feature. Select "exiv2" right-click "Set as Startup Project" and Select Platform="Win32" Configuration="Debug|DebugDLL|Release|ReleaseDLL" Build. Build the Configurations you need. Build time is about 2 minutes/Configuration. To remove the "memory" of old configurations: setbuild.py reset 2 Design expat and zlib do not provide 64 bit builds for DevStudio, so it has been necessary to create the build environments for exiv2. However, we don't include the source code for zlib or expat - only the build environment. You are expected to install the "vanilla" expat and zlib libraries in a directory at the same level as exiv2. I personally always build in the directory c:\gnu, however the name/location/spaces of the build directory are all irrelevant, it's only the relative position of expat-2.0.1 and zlib-1.2.5 that matter. The names expat-2.0.1 and zlib-1.2.5 fixed (and used by the .vcproj files) zlib and expat exiv2\msvc64\zlib\zlib.{sln|vcproj} DevStudio files ..\..\..\zlib-1.2.5\ Source code exiv2\msvc64\expat\expat.sln expat.vcproj DevStudio files ..\..\..\expat-2.0.1\ Source code 2.1 Architecture There are directories for every component: The libraries: zlib, expat, xmpsdk, exiv2lib Applications: exiv2 (exifprint.exe and other sample apps will be added on request) For each component, there are three build directories: exiv2lib\build intermediate results exiv2lib\Win32\{Debug|Release|DebugDLL|ReleaseDLL} 32 bit builds exiv2lib\x64\{Debug|Release|DebugDLL|ReleaseDLL} 64 bit builds Final builds and include directories (for export to "foreign" projects) bin\{win32|x84}\Win32\{Debug|Release|DebugDLL|ReleaseDLL} include 2.2 Changing the version of expat/zlib/xmpsdk At the moment, zlib contains references to zlib-1.2.3 and expat to expat-2.0.1 It is planned to support zlib 1.2.5 shortly and these notes will be updated at that time. 2.3 Relationship with msvc build environment msvc64 is similar to msvc. However there are significant differences: 1) msvc64 supports 64 bit and 32 bit builds 2) msvc64 provides projects to build expat and zlib 3) msvc64 is designed to accomodate new versions of expat and zlib when they become available. 4) msvc64 supports DevStudio 2005, 2008 and 2010 (no support for 2003) 5) msvc64 does not require you to build 'vanilla' expat and zlib projects in advance 6) msvc64 does not support the organize application 7) msvc64 does not build the sample/test applications (such as exfprint.exe) 8) msvc64 has no test/build verification scripts 9) msvc64 supports building with zlib1.2.5 (default) or zlib1.2.3 msvc will continue to be supported for 32 bit builds using DevStudio 2003/05/08, however there is no plan to enhance or develop msvc going forward. 3 Acknowledgement of prior work This work is based on work by the following people: zlib 64 bit build Copyright (C) 2000-2004 Simon-Pierre Cadieux. Copyright (C) 2004 Cosmin Truta. For conditions of distribution and use, see copyright notice in zlib.h. And was obtained from: http://www.achacha.org/vc2008_zlib/ expat 64 bit build http://www.start64.com/index.php?option=com_content&task=view&id=3461&Itemid=114 I recognise and respect the work performed by those individuals. 3.1 Differences between inherited projects and the exiv2 projects There is no compatiblity. 4 Batch builds and tests 4.1 buildall.bat This was intended to be a "throw away" kind of script and it's grown to be quite useful. You will have to run vcvars32.bat for the compiler you intend to use to ensure devenv is on your path. It doesn't know anything about building only x64 or only Win32. Change the script if you want something special. I'll probably combine buildall.bat and setbuild.py into a single script one day. 4.2 runner.py runner.py [Win32|x64|all] This script runs some basic "sanity" checks on the build. You should compare the output of runner.py with the reference output runner.txt. diff/windiff/winmergeu - or whatever your favorite diff tool. python runner.py all > new.txt winmergeu.exe new.txt runner.txt If you have only build Win32 (or x64), you'll have to remove the output from runner.txt for the target that isn't of interest. # That's all Folks! ## exiv2-0.23/src/0000755000175000017500000000000011745263717013113 5ustar andreasandreasexiv2-0.23/src/epsimage.hpp0000644000175000017500000001166111732641407015413 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! @file epsimage.hpp @brief EPS image.
References:
[1] Adobe PostScript Language Document Structuring Conventions Specification, Version 3.0, September 1992
[2] Adobe Encapsulated PostScript File Format Specification, Version 3.0, May 1992
[3] Adobe XMP Specification Part 3: Storage in Files, July 2010
[4] Re: Thumbnail data format in ai file, Dec 2003 @version $Rev: $ @author Michael Ulbrich (mul) mul@rentapacs.de @author Volker Grabsch (vog) vog@notjusthosting.com @date 7-Mar-2011, vog: created */ #ifndef EPSIMAGE_HPP_ #define EPSIMAGE_HPP_ // ***************************************************************************** // included header files #include "image.hpp" #include "types.hpp" // + standard includes #include // ***************************************************************************** // namespace extensions namespace Exiv2 { // ***************************************************************************** // class definitions // Add EPS to the supported image formats namespace ImageType { const int eps = 18; //!< EPS image type } /*! @brief Class to access EPS images. */ class EXIV2API EpsImage : public Image { public: //! @name Creators //@{ /*! @brief Constructor to open a EPS image. Since the constructor can't return a result, callers should check the good() method after object construction to determine success or failure. @param io An auto-pointer that owns a BasicIo instance used for reading and writing image metadata. \b Important: The constructor takes ownership of the passed in BasicIo instance through the auto-pointer. Callers should not continue to use the BasicIo instance after it is passed to this method. Use the Image::io() method to get a temporary reference. @param create Specifies if an existing image should be read (false) or if a new file should be created (true). */ EpsImage(BasicIo::AutoPtr io, bool create); //@} //! @name Manipulators //@{ void readMetadata(); void writeMetadata(); /*! @brief Not supported. Calling this function will throw an instance of Error(32). */ void setComment(const std::string& comment); //@} //! @name Accessors //@{ std::string mimeType() const; //@} private: //! @name NOT Implemented //@{ //! Copy constructor EpsImage(const EpsImage& rhs); //! Assignment operator EpsImage& operator=(const EpsImage& rhs); //@} }; // class EpsImage // ***************************************************************************** // template, inline and free functions // These could be static private functions on Image subclasses but then // ImageFactory needs to be made a friend. /*! @brief Create a new EpsImage instance and return an auto-pointer to it. Caller owns the returned object and the auto-pointer ensures that it will be deleted. */ EXIV2API Image::AutoPtr newEpsInstance(BasicIo::AutoPtr io, bool create); //! Check if the file iIo is a EPS image. EXIV2API bool isEpsType(BasicIo& iIo, bool advance); } // namespace Exiv2 #endif // #ifndef EPSIMAGE_HPP_ exiv2-0.23/src/iptc.cpp0000644000175000017500000004107111732641407014551 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /* File: iptc.cpp Version: $Rev: 2681 $ Author(s): Brad Schick (brad) History: 31-July-04, brad: created */ // ***************************************************************************** #include "rcsid_int.hpp" EXIV2_RCSID("@(#) $Id: iptc.cpp 2681 2012-03-22 15:19:35Z ahuggel $") // ***************************************************************************** // included header files #include "iptc.hpp" #include "types.hpp" #include "error.hpp" #include "value.hpp" #include "datasets.hpp" #include "jpgimage.hpp" // + standard includes #include #include #include // ***************************************************************************** namespace { /*! @brief Read a single dataset payload and create a new metadata entry. @param iptcData IPTC metadata container to add the dataset to @param dataSet DataSet number @param record Record Id @param data Pointer to the first byte of dataset payload @param sizeData Length in bytes of dataset payload @return 0 if successful. */ int readData( Exiv2::IptcData& iptcData, uint16_t dataSet, uint16_t record, const Exiv2::byte* data, uint32_t sizeData ); //! Unary predicate that matches an Iptcdatum with given record and dataset class FindIptcdatum { public: //! Constructor, initializes the object with the record and dataset id FindIptcdatum(uint16_t dataset, uint16_t record) : dataset_(dataset), record_(record) {} /*! @brief Returns true if the record and dataset id of the argument Iptcdatum is equal to that of the object. */ bool operator()(const Exiv2::Iptcdatum& iptcdatum) const { return dataset_ == iptcdatum.tag() && record_ == iptcdatum.record(); } private: // DATA uint16_t dataset_; uint16_t record_; }; // class FindIptcdatum } // ***************************************************************************** // class member definitions namespace Exiv2 { Iptcdatum::Iptcdatum(const IptcKey& key, const Value* pValue) : key_(key.clone()) { if (pValue) value_ = pValue->clone(); } Iptcdatum::Iptcdatum(const Iptcdatum& rhs) : Metadatum(rhs) { if (rhs.key_.get() != 0) key_ = rhs.key_->clone(); // deep copy if (rhs.value_.get() != 0) value_ = rhs.value_->clone(); // deep copy } Iptcdatum::~Iptcdatum() { } long Iptcdatum::copy(byte* buf, ByteOrder byteOrder) const { return value_.get() == 0 ? 0 : value_->copy(buf, byteOrder); } std::ostream& Iptcdatum::write(std::ostream& os, const ExifData*) const { return os << value(); } std::string Iptcdatum::key() const { return key_.get() == 0 ? "" : key_->key(); } std::string Iptcdatum::recordName() const { return key_.get() == 0 ? "" : key_->recordName(); } uint16_t Iptcdatum::record() const { return key_.get() == 0 ? 0 : key_->record(); } const char* Iptcdatum::familyName() const { return key_.get() == 0 ? "" : key_->familyName(); } std::string Iptcdatum::groupName() const { return key_.get() == 0 ? "" : key_->groupName(); } std::string Iptcdatum::tagName() const { return key_.get() == 0 ? "" : key_->tagName(); } std::string Iptcdatum::tagLabel() const { return key_.get() == 0 ? "" : key_->tagLabel(); } uint16_t Iptcdatum::tag() const { return key_.get() == 0 ? 0 : key_->tag(); } TypeId Iptcdatum::typeId() const { return value_.get() == 0 ? invalidTypeId : value_->typeId(); } const char* Iptcdatum::typeName() const { return TypeInfo::typeName(typeId()); } long Iptcdatum::typeSize() const { return TypeInfo::typeSize(typeId()); } long Iptcdatum::count() const { return value_.get() == 0 ? 0 : value_->count(); } long Iptcdatum::size() const { return value_.get() == 0 ? 0 : value_->size(); } std::string Iptcdatum::toString() const { return value_.get() == 0 ? "" : value_->toString(); } std::string Iptcdatum::toString(long n) const { return value_.get() == 0 ? "" : value_->toString(n); } long Iptcdatum::toLong(long n) const { return value_.get() == 0 ? -1 : value_->toLong(n); } float Iptcdatum::toFloat(long n) const { return value_.get() == 0 ? -1 : value_->toFloat(n); } Rational Iptcdatum::toRational(long n) const { return value_.get() == 0 ? Rational(-1, 1) : value_->toRational(n); } Value::AutoPtr Iptcdatum::getValue() const { return value_.get() == 0 ? Value::AutoPtr(0) : value_->clone(); } const Value& Iptcdatum::value() const { if (value_.get() == 0) throw Error(8); return *value_; } Iptcdatum& Iptcdatum::operator=(const Iptcdatum& rhs) { if (this == &rhs) return *this; Metadatum::operator=(rhs); key_.reset(); if (rhs.key_.get() != 0) key_ = rhs.key_->clone(); // deep copy value_.reset(); if (rhs.value_.get() != 0) value_ = rhs.value_->clone(); // deep copy return *this; } // Iptcdatum::operator= Iptcdatum& Iptcdatum::operator=(const uint16_t& value) { UShortValue::AutoPtr v(new UShortValue); v->value_.push_back(value); value_ = v; return *this; } Iptcdatum& Iptcdatum::operator=(const std::string& value) { setValue(value); return *this; } Iptcdatum& Iptcdatum::operator=(const Value& value) { setValue(&value); return *this; } void Iptcdatum::setValue(const Value* pValue) { value_.reset(); if (pValue) value_ = pValue->clone(); } int Iptcdatum::setValue(const std::string& value) { if (value_.get() == 0) { TypeId type = IptcDataSets::dataSetType(tag(), record()); value_ = Value::create(type); } return value_->read(value); } Iptcdatum& IptcData::operator[](const std::string& key) { IptcKey iptcKey(key); iterator pos = findKey(iptcKey); if (pos == end()) { add(Iptcdatum(iptcKey)); pos = findKey(iptcKey); } return *pos; } long IptcData::size() const { long newSize = 0; const_iterator iter = iptcMetadata_.begin(); const_iterator end = iptcMetadata_.end(); for ( ; iter != end; ++iter) { // marker, record Id, dataset num, first 2 bytes of size newSize += 5; long dataSize = iter->size(); newSize += dataSize; if (dataSize > 32767) { // extended dataset (we always use 4 bytes) newSize += 4; } } return newSize; } // IptcData::size int IptcData::add(const IptcKey& key, Value* value) { return add(Iptcdatum(key, value)); } int IptcData::add(const Iptcdatum& iptcDatum) { if (!IptcDataSets::dataSetRepeatable( iptcDatum.tag(), iptcDatum.record()) && findId(iptcDatum.tag(), iptcDatum.record()) != end()) { return 6; } // allow duplicates iptcMetadata_.push_back(iptcDatum); return 0; } IptcData::const_iterator IptcData::findKey(const IptcKey& key) const { return std::find_if(iptcMetadata_.begin(), iptcMetadata_.end(), FindIptcdatum(key.tag(), key.record())); } IptcData::iterator IptcData::findKey(const IptcKey& key) { return std::find_if(iptcMetadata_.begin(), iptcMetadata_.end(), FindIptcdatum(key.tag(), key.record())); } IptcData::const_iterator IptcData::findId(uint16_t dataset, uint16_t record) const { return std::find_if(iptcMetadata_.begin(), iptcMetadata_.end(), FindIptcdatum(dataset, record)); } IptcData::iterator IptcData::findId(uint16_t dataset, uint16_t record) { return std::find_if(iptcMetadata_.begin(), iptcMetadata_.end(), FindIptcdatum(dataset, record)); } void IptcData::sortByKey() { std::sort(iptcMetadata_.begin(), iptcMetadata_.end(), cmpMetadataByKey); } void IptcData::sortByTag() { std::sort(iptcMetadata_.begin(), iptcMetadata_.end(), cmpMetadataByTag); } IptcData::iterator IptcData::erase(IptcData::iterator pos) { return iptcMetadata_.erase(pos); } const char *IptcData::detectCharset() const { const_iterator pos = findKey(IptcKey("Iptc.Envelope.CharacterSet")); if (pos != end()) { const std::string value = pos->toString(); if (pos->value().ok()) { if (value == "\033%G") return "UTF-8"; // other values are probably not practically relevant } } bool ascii = true; bool utf8 = true; for (pos = begin(); pos != end(); ++pos) { std::string value = pos->toString(); if (pos->value().ok()) { int seqCount = 0; std::string::iterator i; for (i = value.begin(); i != value.end(); ++i) { char c = *i; if (seqCount) { if ((c & 0xc0) != 0x80) { utf8 = false; break; } --seqCount; } else { if (c & 0x80) ascii = false; else continue; // ascii character if ((c & 0xe0) == 0xc0) seqCount = 1; else if ((c & 0xf0) == 0xe0) seqCount = 2; else if ((c & 0xf8) == 0xf0) seqCount = 3; else if ((c & 0xfc) == 0xf8) seqCount = 4; else if ((c & 0xfe) == 0xfc) seqCount = 5; else { utf8 = false; break; } } } if (seqCount) utf8 = false; // unterminated seq if (!utf8) break; } } if (ascii) return "ASCII"; if (utf8) return "UTF-8"; return NULL; } const byte IptcParser::marker_ = 0x1C; // Dataset marker int IptcParser::decode( IptcData& iptcData, const byte* pData, uint32_t size ) { #ifdef DEBUG std::cerr << "IptcParser::decode, size = " << size << "\n"; #endif const byte* pRead = pData; iptcData.clear(); uint16_t record = 0; uint16_t dataSet = 0; uint32_t sizeData = 0; byte extTest = 0; while (pRead + 3 < pData + size) { // First byte should be a marker. If it isn't, scan forward and skip // the chunk bytes present in some images. This deviates from the // standard, which advises to treat such cases as errors. if (*pRead++ != marker_) continue; record = *pRead++; dataSet = *pRead++; extTest = *pRead; if (extTest & 0x80) { // extended dataset uint16_t sizeOfSize = (getUShort(pRead, bigEndian) & 0x7FFF); if (sizeOfSize > 4) return 5; pRead += 2; sizeData = 0; for (; sizeOfSize > 0; --sizeOfSize) { sizeData |= *pRead++ << (8 *(sizeOfSize-1)); } } else { // standard dataset sizeData = getUShort(pRead, bigEndian); pRead += 2; } if (pRead + sizeData <= pData + size) { int rc = 0; if ((rc = readData(iptcData, dataSet, record, pRead, sizeData)) != 0) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Failed to read IPTC dataset " << IptcKey(dataSet, record) << " (rc = " << rc << "); skipped.\n"; #endif } } #ifndef SUPPRESS_WARNINGS else { EXV_WARNING << "IPTC dataset " << IptcKey(dataSet, record) << " has invalid size " << sizeData << "; skipped.\n"; } #endif pRead += sizeData; } return 0; } // IptcParser::decode /*! @brief Compare two iptc items by record. Return true if the record of lhs is less than that of rhs. This is a helper function for IptcParser::encode(). */ bool cmpIptcdataByRecord(const Iptcdatum& lhs, const Iptcdatum& rhs) { return lhs.record() < rhs.record(); } DataBuf IptcParser::encode(const IptcData& iptcData) { DataBuf buf(iptcData.size()); byte *pWrite = buf.pData_; // Copy the iptc data sets and sort them by record but preserve the order of datasets IptcMetadata sortedIptcData; std::copy(iptcData.begin(), iptcData.end(), std::back_inserter(sortedIptcData)); std::stable_sort(sortedIptcData.begin(), sortedIptcData.end(), cmpIptcdataByRecord); IptcData::const_iterator iter = sortedIptcData.begin(); IptcData::const_iterator end = sortedIptcData.end(); for ( ; iter != end; ++iter) { // marker, record Id, dataset num *pWrite++ = marker_; *pWrite++ = static_cast(iter->record()); *pWrite++ = static_cast(iter->tag()); // extended or standard dataset? long dataSize = iter->size(); if (dataSize > 32767) { // always use 4 bytes for extended length uint16_t sizeOfSize = 4 | 0x8000; us2Data(pWrite, sizeOfSize, bigEndian); pWrite += 2; ul2Data(pWrite, dataSize, bigEndian); pWrite += 4; } else { us2Data(pWrite, static_cast(dataSize), bigEndian); pWrite += 2; } pWrite += iter->value().copy(pWrite, bigEndian); } return buf; } // IptcParser::encode } // namespace Exiv2 // ***************************************************************************** // local definitions namespace { int readData( Exiv2::IptcData& iptcData, uint16_t dataSet, uint16_t record, const Exiv2::byte* data, uint32_t sizeData ) { Exiv2::Value::AutoPtr value; Exiv2::TypeId type = Exiv2::IptcDataSets::dataSetType(dataSet, record); value = Exiv2::Value::create(type); int rc = value->read(data, sizeData, Exiv2::bigEndian); if (0 == rc) { Exiv2::IptcKey key(dataSet, record); iptcData.add(key, value.get()); } else if (1 == rc) { // If the first attempt failed, try with a string value value = Exiv2::Value::create(Exiv2::string); rc = value->read(data, sizeData, Exiv2::bigEndian); if (0 == rc) { Exiv2::IptcKey key(dataSet, record); iptcData.add(key, value.get()); } } return rc; } } exiv2-0.23/src/tiffimage.hpp0000644000175000017500000002120611732641407015550 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! @file tiffimage.hpp @brief Class TiffImage @version $Rev: 2681 $ @author Andreas Huggel (ahu) ahuggel@gmx.net @date 15-Mar-06, ahu: created */ #ifndef TIFFIMAGE_HPP_ #define TIFFIMAGE_HPP_ // ***************************************************************************** // included header files #include "image.hpp" #include "basicio.hpp" #include "types.hpp" // + standard includes #include // ***************************************************************************** // namespace extensions namespace Exiv2 { // ***************************************************************************** // class definitions // Add TIFF to the supported image formats namespace ImageType { const int tiff = 4; //!< TIFF image type (see class TiffImage) const int dng = 4; //!< DNG image type (see class TiffImage) const int nef = 4; //!< NEF image type (see class TiffImage) const int pef = 4; //!< PEF image type (see class TiffImage) const int arw = 4; //!< ARW image type (see class TiffImage) const int sr2 = 4; //!< SR2 image type (see class TiffImage) const int srw = 4; //!< SRW image type (see class TiffImage) } /*! @brief Class to access TIFF images. Exif metadata is supported directly, IPTC is read from the Exif data, if present. */ class EXIV2API TiffImage : public Image { public: //! @name Creators //@{ /*! @brief Constructor that can either open an existing TIFF image or create a new image from scratch. If a new image is to be created, any existing data is overwritten. Since the constructor can not return a result, callers should check the good() method after object construction to determine success or failure. @param io An auto-pointer that owns a BasicIo instance used for reading and writing image metadata. \b Important: The constructor takes ownership of the passed in BasicIo instance through the auto-pointer. Callers should not continue to use the BasicIo instance after it is passed to this method. Use the Image::io() method to get a temporary reference. @param create Specifies if an existing image should be read (false) or if a new file should be created (true). */ TiffImage(BasicIo::AutoPtr io, bool create); //@} //! @name Manipulators //@{ void readMetadata(); void writeMetadata(); /*! @brief Not supported. TIFF format does not contain a comment. Calling this function will throw an Error(32). */ void setComment(const std::string& comment); //@} //! @name Accessors //@{ std::string mimeType() const; int pixelWidth() const; int pixelHeight() const; //@} private: //! @name NOT Implemented //@{ //! Copy constructor TiffImage(const TiffImage& rhs); //! Assignment operator TiffImage& operator=(const TiffImage& rhs); //@} //! @name Accessors //@{ //! Return the group name of the group with the primary image. std::string primaryGroup() const; //@} private: // DATA mutable std::string primaryGroup_; //!< The primary group mutable std::string mimeType_; //!< The MIME type mutable int pixelWidth_; //!< Width of the primary image in pixels mutable int pixelHeight_; //!< Height of the primary image in pixels }; // class TiffImage /*! @brief Stateless parser class for data in TIFF format. Images use this class to decode and encode TIFF data. It is a wrapper of the internal class Internal::TiffParserWorker. */ class EXIV2API TiffParser { public: /*! @brief Decode metadata from a buffer \em pData of length \em size with data in TIFF format to the provided metadata containers. @param exifData Exif metadata container. @param iptcData IPTC metadata container. @param xmpData XMP metadata container. @param pData Pointer to the data buffer. Must point to data in TIFF format; no checks are performed. @param size Length of the data buffer. @return Byte order in which the data is encoded. */ static ByteOrder decode( ExifData& exifData, IptcData& iptcData, XmpData& xmpData, const byte* pData, uint32_t size ); /*! @brief Encode metadata from the provided metadata to TIFF format. The original binary image in the memory block \em pData, \em size is parsed and updated in-place if possible ("non-intrusive" writing). If that is not possible (e.g., if new tags were added), the entire TIFF structure is re-written to the \em io instance ("intrusive" writing).
The return value indicates which write method was used. If it is \c wmNonIntrusive, the original memory \em pData, \em size contains the result and nothing is written to \em io. If the return value is \c wmIntrusive, a new TIFF structure was created and written to \em io. The memory block \em pData, \em size may be partly updated in this case and should not be used anymore. @note If there is no metadata to encode, i.e., all metadata containers are empty, then the return value is \c wmIntrusive and nothing is written to \em io, i.e., no TIFF header is written. @param io IO instance to write the binary image to in case of "intrusive" writing. Nothing is written to \em io in the case of "non-intrusive" writing. @param pData Pointer to the binary image data buffer. Must point to data in TIFF format; no checks are performed. Will be modified if "non-intrusive" writing is possible. @param size Length of the data buffer. @param byteOrder Byte order to use. @param exifData Exif metadata container. @param iptcData IPTC metadata container. @param xmpData XMP metadata container. @return Write method used. */ static WriteMethod encode( BasicIo& io, const byte* pData, uint32_t size, ByteOrder byteOrder, const ExifData& exifData, const IptcData& iptcData, const XmpData& xmpData ); }; // class TiffParser // ***************************************************************************** // template, inline and free functions // These could be static private functions on Image subclasses but then // ImageFactory needs to be made a friend. /*! @brief Create a new TiffImage instance and return an auto-pointer to it. Caller owns the returned object and the auto-pointer ensures that it will be deleted. */ EXIV2API Image::AutoPtr newTiffInstance(BasicIo::AutoPtr io, bool create); //! Check if the file iIo is a TIFF image. EXIV2API bool isTiffType(BasicIo& iIo, bool advance); } // namespace Exiv2 #endif // #ifndef TIFFIMAGE_HPP_ exiv2-0.23/src/olympusmn.cpp0000644000175000017500000025741411732641407015667 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /* File: olympusmn.cpp Version: $Rev: 2681 $ Author(s): Will Stokes (wuz) Andreas Huggel (ahu) Gilles Caulier (gc) Greg Mansfield History: 10-Mar-05, wuz: created Credits: See header file. */ // ***************************************************************************** #include "rcsid_int.hpp" EXIV2_RCSID("@(#) $Id: olympusmn.cpp 2681 2012-03-22 15:19:35Z ahuggel $") // ***************************************************************************** // included header files #include "types.hpp" #include "olympusmn_int.hpp" #include "value.hpp" #include "image.hpp" #include "tags_int.hpp" #include "i18n.h" // NLS support. // + standard includes #include #include #include #include #include // ***************************************************************************** // class member definitions namespace Exiv2 { namespace Internal { //! OffOn, multiple tags extern const TagDetails olympusOffOn[] = { { 0, N_("Off") }, { 1, N_("On") } }; //! NoYes, multiple tags extern const TagDetails olympusNoYes[] = { { 0, N_("No") }, { 1, N_("Yes") } }; //! Quality, tag 0x0201 extern const TagDetails olympusQuality[] = { { 1, N_("Standard Quality (SQ)") }, { 2, N_("High Quality (HQ)") }, { 3, N_("Super High Quality (SHQ)") }, { 6, N_("Raw") } }; //! Macro, tag 0x0202 extern const TagDetails olympusMacro[] = { { 0, N_("Off") }, { 1, N_("On") }, { 2, N_("Super macro") } }; //! OneTouchWB, tag 0x0302 extern const TagDetails olympusOneTouchWb[] = { { 0, N_("Off") }, { 1, N_("On") }, { 2, N_("On (preset)") } }; //! SceneMode, tag 0x403 and CameraSettings tag 0x509 extern const TagDetails olympusSceneMode[] = { { 0, N_("Standard") }, { 6, N_("Auto") }, { 7, N_("Sport") }, { 8, N_("Portrait") }, { 9, N_("Landscape+Portrait") }, { 10, N_("Landscape") }, { 11, N_("Night Scene") }, { 12, N_("Self Portrait") }, { 13, N_("Panorama") }, { 14, N_("2 in 1") }, { 15, N_("Movie") }, { 16, N_("Landscape+Portrait") }, { 17, N_("Night+Portrait") }, { 18, N_("Indoor") }, { 19, N_("Fireworks") }, { 20, N_("Sunset") }, { 22, N_("Macro") }, { 23, N_("Super Macro") }, { 24, N_("Food") }, { 25, N_("Documents") }, { 26, N_("Museum") }, { 27, N_("Shoot & Select") }, { 28, N_("Beach & Snow") }, { 29, N_("Self Portrait+Timer") }, { 30, N_("Candle") }, { 31, N_("Available Light") }, { 32, N_("Behind Glass") }, { 33, N_("My Mode") }, { 34, N_("Pet") }, { 35, N_("Underwater Wide1") }, { 36, N_("Underwater Macro") }, { 37, N_("Shoot & Select1") }, { 38, N_("Shoot & Select2") }, { 39, N_("High Key") }, { 40, N_("Digital Image Stabilization") }, { 41, N_("Auction") }, { 42, N_("Beach") }, { 43, N_("Snow") }, { 44, N_("Underwater Wide2") }, { 45, N_("Low Key") }, { 46, N_("Children") }, { 47, N_("Vivid") }, { 48, N_("Nature Macro") }, { 49, N_("Underwater Snapshot") }, { 50, N_("Shooting Guide") } }; //! FlashDevice, tag 0x1005 extern const TagDetails olympusFlashDevice[] = { { 0, N_("None") }, { 1, N_("Internal") }, { 4, N_("External") }, { 5, N_("Internal + External") } }; //! FocusRange, tag 0x100a extern const TagDetails olympusFocusRange[] = { { 0, N_("Normal") }, { 1, N_("Macro") } }; //! FocusMode, tag 0x100b extern const TagDetails olympusFocusMode[] = { { 0, N_("Auto") }, { 1, N_("Manual") } }; //! Sharpness, tag 0x100f extern const TagDetails olympusSharpness[] = { { 0, N_("Normal") }, { 1, N_("Hard") }, { 2, N_("Soft") } }; //! Contrast, tag 0x1029 extern const TagDetails olympusContrast[] = { { 0, N_("High") }, { 1, N_("Normal") }, { 2, N_("Low") } }; //! CCDScanMode, tag 0x1039 extern const TagDetails olympusCCDScanMode[] = { { 0, N_("Interlaced") }, { 1, N_("Progressive") } }; // Olympus Tag Info const TagInfo OlympusMakerNote::tagInfo_[] = { /* TODO: add Minolta makenotes tags here (0x0000-0x0103). See Exiftool database.*/ TagInfo(0x0000, "0x0000", "0x0000", N_("Unknown"), olympusId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0100, "ThumbnailImage", N_("Thumbnail Image"), N_("Thumbnail image"), olympusId, makerTags, undefined, -1, printValue), TagInfo(0x0104, "BodyFirmwareVersion", N_("Body Firmware Version"), N_("Body firmware version"), olympusId, makerTags, asciiString, -1, printValue), TagInfo(0x0200, "SpecialMode", N_("Special Mode"), N_("Picture taking mode"), olympusId, makerTags, unsignedLong, -1, print0x0200), TagInfo(0x0201, "Quality", N_("Quality"), N_("Image quality setting"), olympusId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(olympusQuality)), TagInfo(0x0202, "Macro", N_("Macro"), N_("Macro mode"), olympusId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(olympusMacro)), TagInfo(0x0203, "BWMode", N_("Black & White Mode"), N_("Black and white mode"), olympusId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(olympusOffOn)), TagInfo(0x0204, "DigitalZoom", N_("Digital Zoom"), N_("Digital zoom ratio"), olympusId, makerTags, unsignedRational, -1, print0x0204), TagInfo(0x0205, "FocalPlaneDiagonal", N_("Focal Plane Diagonal"), N_("Focal plane diagonal"), olympusId, makerTags, unsignedRational, -1, printValue), TagInfo(0x0206, "LensDistortionParams", N_("Lens Distortion Parameters"), N_("Lens distortion parameters"), olympusId, makerTags, signedShort, -1, printValue), TagInfo(0x0207, "CameraType", N_("Camera Type"), N_("Camera type"), olympusId, makerTags, asciiString, -1, printValue), TagInfo(0x0208, "PictureInfo", N_("Picture Info"), N_("ASCII format data such as [PictureInfo]"), olympusId, makerTags, asciiString, -1, printValue), TagInfo(0x0209, "CameraID", N_("Camera ID"), N_("Camera ID data"), olympusId, makerTags, asciiString, -1, print0x0209), TagInfo(0x020b, "ImageWidth", N_("Image Width"), N_("Image width"), olympusId, makerTags, unsignedShort, -1, printValue), TagInfo(0x020c, "ImageHeight", N_("Image Height"), N_("Image height"), olympusId, makerTags, unsignedShort, -1, printValue), TagInfo(0x020d, "Software", N_("Software"), N_("Software"), olympusId, makerTags, asciiString, -1, printValue), TagInfo(0x0280, "PreviewImage", N_("Preview Image"), N_("Preview image"), olympusId, makerTags, unsignedByte, -1, printValue), TagInfo(0x0300, "PreCaptureFrames", N_("Pre Capture Frames"), N_("Pre-capture frames"), olympusId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0301, "WhiteBoard", N_("White Board"), N_("White board"), olympusId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0302, "OneTouchWB", N_("One Touch WB"), N_("One touch white balance"), olympusId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(olympusOneTouchWb)), TagInfo(0x0303, "WhiteBalanceBracket", N_("White Balance Bracket"), N_("White balance bracket"), olympusId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0304, "WhiteBalanceBias", N_("White Balance Bias"), N_("White balance bias"), olympusId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0403, "SceneMode", N_("Scene Mode"), N_("Scene mode"), olympusCsId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(olympusSceneMode)), TagInfo(0x0404, "Firmware", N_("Firmware"), N_("Firmwarer"), olympusId, makerTags, asciiString, -1, printValue), TagInfo(0x0e00, "PrintIM", N_("Print IM"), N_("PrintIM information"), olympusId, makerTags, undefined, -1, printValue), TagInfo(0x0f00, "DataDump1", N_("Data Dump 1"), N_("Various camera settings 1"), olympusId, makerTags, undefined, -1, printValue), TagInfo(0x0f01, "DataDump2", N_("Data Dump 2"), N_("Various camera settings 2"), olympusId, makerTags, undefined, -1, printValue), TagInfo(0x1000, "ShutterSpeed", N_("Shutter Speed"), N_("Shutter speed value"), olympusId, makerTags, signedRational, -1, printValue), TagInfo(0x1001, "ISOSpeed", N_("ISO Speed"), N_("ISO speed value"), olympusId, makerTags, signedRational, -1, printValue), TagInfo(0x1002, "ApertureValue", N_("Aperture Value"), N_("Aperture value"), olympusId, makerTags, signedRational, -1, printValue), TagInfo(0x1003, "Brightness", N_("Brightness"), N_("Brightness value"), olympusId, makerTags, signedRational, -1, printValue), TagInfo(0x1004, "FlashMode", N_("Flash Mode"), N_("Flash mode"), olympusId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(olympusOffOn)), TagInfo(0x1005, "FlashDevice", N_("Flash Device"), N_("Flash device"), olympusId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(olympusFlashDevice)), TagInfo(0x1006, "Bracket", N_("Bracket"), N_("Exposure compensation value"), olympusId, makerTags, signedRational, -1, printValue), TagInfo(0x1007, "SensorTemperature", N_("Sensor Temperature"), N_("Sensor temperature"), olympusId, makerTags, signedShort, -1, printValue), TagInfo(0x1008, "LensTemperature", N_("Lens Temperature"), N_("Lens temperature"), olympusId, makerTags, signedShort, -1, printValue), TagInfo(0x1009, "LightCondition", N_("Light Condition"), N_("Light condition"), olympusId, makerTags, unsignedShort, -1, printValue), TagInfo(0x100a, "FocusRange", N_("Focus Range"), N_("Focus range"), olympusId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(olympusFocusRange)), TagInfo(0x100b, "FocusMode", N_("Focus Mode"), N_("Focus mode"), olympusId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(olympusFocusMode)), TagInfo(0x100c, "FocusDistance", N_("Focus Distance"), N_("Manual focus distance"), olympusId, makerTags, unsignedRational, -1, printValue), TagInfo(0x100d, "Zoom", N_("Zoom"), N_("Zoom step count"), olympusId, makerTags, unsignedShort, -1, printValue), TagInfo(0x100e, "MacroFocus", N_("Macro Focus"), N_("Macro focus step count"), olympusId, makerTags, unsignedShort, -1, printValue), TagInfo(0x100f, "SharpnessFactor", N_("Sharpness Factor"), N_("Sharpness factor"), olympusId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(olympusSharpness)), TagInfo(0x1010, "FlashChargeLevel", N_("Flash Charge Level"), N_("Flash charge level"), olympusId, makerTags, unsignedShort, -1, printValue), TagInfo(0x1011, "ColorMatrix", N_("Color Matrix"), N_("Color matrix"), olympusId, makerTags, unsignedShort, -1, printValue), TagInfo(0x1012, "BlackLevel", N_("BlackLevel"), N_("Black level"), olympusId, makerTags, unsignedShort, -1, printValue), TagInfo(0x1013, "0x1013", "0x1013", N_("Unknown"), olympusId, makerTags, unsignedShort, -1, printValue), TagInfo(0x1014, "0x1014", "0x1014", N_("Unknown"), olympusId, makerTags, unsignedShort, -1, printValue), TagInfo(0x1015, "WhiteBalance", N_("White Balance"), N_("White balance mode"), olympusId, makerTags, unsignedShort, -1, print0x1015), TagInfo(0x1016, "0x1016", "0x1016", N_("Unknown"), olympusId, makerTags, unsignedShort, -1, printValue), TagInfo(0x1017, "RedBalance", N_("Red Balance"), N_("Red balance"), olympusId, makerTags, unsignedShort, -1, printValue), TagInfo(0x1018, "BlueBalance", N_("Blue Balance"), N_("Blue balance"), olympusId, makerTags, unsignedShort, -1, printValue), TagInfo(0x1019, "ColorMatrixNumber", N_("Color Matrix Number"), N_("Color matrix mumber"), olympusId, makerTags, unsignedShort, -1, printValue), TagInfo(0x101a, "SerialNumber2", N_("Serial Number 2"), N_("Serial number 2"), olympusId, makerTags, asciiString, -1, printValue), TagInfo(0x101b, "0x101b", "0x101b", N_("Unknown"), olympusId, makerTags, unsignedLong, -1, printValue), TagInfo(0x101c, "0x101c", "0x101c", N_("Unknown"), olympusId, makerTags, unsignedLong, -1, printValue), TagInfo(0x101d, "0x101d", "0x101d", N_("Unknown"), olympusId, makerTags, unsignedLong, -1, printValue), TagInfo(0x101e, "0x101e", "0x101e", N_("Unknown"), olympusId, makerTags, unsignedLong, -1, printValue), TagInfo(0x101f, "0x101f", "0x101f", N_("Unknown"), olympusId, makerTags, unsignedLong, -1, printValue), TagInfo(0x1020, "0x1020", "0x1020", N_("Unknown"), olympusId, makerTags, unsignedLong, -1, printValue), TagInfo(0x1021, "0x1021", "0x1021", N_("Unknown"), olympusId, makerTags, unsignedLong, -1, printValue), TagInfo(0x1022, "0x1022", "0x1022", N_("Unknown"), olympusId, makerTags, unsignedLong, -1, printValue), TagInfo(0x1023, "FlashBias", N_("Flash Bias"), N_("Flash exposure compensation"), olympusId, makerTags, signedRational, -1, printValue), TagInfo(0x1024, "0x1024", "0x1024", N_("Unknown"), olympusId, makerTags, unsignedShort, -1, printValue), TagInfo(0x1025, "0x1025", "0x1025", N_("Unknown"), olympusId, makerTags, signedRational, -1, printValue), TagInfo(0x1026, "ExternalFlashBounce", N_("External Flash Bounce"), N_("External flash bounce"), olympusId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(olympusOffOn)), TagInfo(0x1027, "ExternalFlashZoom", N_("External Flash Zoom"), N_("External flash zoom"), olympusId, makerTags, unsignedShort, -1, printValue), TagInfo(0x1028, "ExternalFlashMode", N_("External Flash Mode"), N_("External flash mode"), olympusId, makerTags, unsignedShort, -1, printValue), TagInfo(0x1029, "Contrast", N_("Contrast"), N_("Contrast setting"), olympusId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(olympusContrast)), TagInfo(0x102a, "SharpnessFactor", N_("Sharpness Factor"), N_("Sharpness factor"), olympusId, makerTags, unsignedShort, -1, printValue), TagInfo(0x102b, "ColorControl", N_("Color Control"), N_("Color control"), olympusId, makerTags, unsignedShort, -1, printValue), TagInfo(0x102c, "ValidBits", N_("ValidBits"), N_("Valid bits"), olympusId, makerTags, unsignedShort, -1, printValue), TagInfo(0x102d, "CoringFilter", N_("CoringFilter"), N_("Coring filter"), olympusId, makerTags, unsignedShort, -1, printValue), TagInfo(0x102e, "ImageWidth", N_("Image Width"), N_("Image width"), olympusId, makerTags, unsignedLong, -1, printValue), TagInfo(0x102f, "ImageHeight", N_("Image Height"), N_("Image height"), olympusId, makerTags, unsignedLong, -1, printValue), TagInfo(0x1030, "0x1030", "0x1030", N_("Unknown"), olympusId, makerTags, unsignedShort, -1, printValue), TagInfo(0x1031, "0x1031", "0x1031", N_("Unknown"), olympusId, makerTags, unsignedLong, -1, printValue), TagInfo(0x1032, "0x1032", "0x1032", N_("Unknown"), olympusId, makerTags, unsignedShort, -1, printValue), TagInfo(0x1033, "0x1033", "0x1033", N_("Unknown"), olympusId, makerTags, unsignedLong, -1, printValue), TagInfo(0x1034, "CompressionRatio", N_("Compression Ratio"), N_("Compression ratio"), olympusId, makerTags, unsignedRational, -1, printValue), TagInfo(0x1035, "Thumbnail", N_("Thumbnail"), N_("Preview image embedded"), olympusId, makerTags, unsignedLong, -1, EXV_PRINT_TAG(olympusOffOn)), TagInfo(0x1036, "ThumbnailOffset", N_("Thumbnail Offset"), N_("Offset of the preview image"), olympusId, makerTags, unsignedLong, -1, printValue), TagInfo(0x1037, "ThumbnailLength", N_("Thumbnail Length"), N_("Size of the preview image"), olympusId, makerTags, unsignedLong, -1, printValue), TagInfo(0x1039, "CCDScanMode", N_("CCD Scan Mode"), N_("CCD scan mode"), olympusId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(olympusCCDScanMode)), TagInfo(0x103a, "NoiseReduction", N_("Noise Reduction"), N_("Noise reduction"), olympusId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(olympusOffOn)), TagInfo(0x103b, "InfinityLensStep", N_("Infinity Lens Step"), N_("Infinity lens step"), olympusId, makerTags, unsignedShort, -1, printValue), TagInfo(0x103c, "NearLensStep", N_("Near Lens Step"), N_("Near lens step"), olympusId, makerTags, unsignedShort, -1, printValue), TagInfo(0x2010, "Equipment", N_("Equipment Info"), N_("Camera equipment sub-IFD"), olympusId, makerTags, unsignedLong, -1, printValue), TagInfo(0x2020, "CameraSettings", N_("Camera Settings"), N_("Camera Settings sub-IFD"), olympusId, makerTags, unsignedLong, -1, printValue), TagInfo(0x2030, "RawDevelopment", N_("Raw Development"), N_("Raw development sub-IFD"), olympusId, makerTags, unsignedLong, -1, printValue), TagInfo(0x2031, "RawDevelopment2", N_("Raw Development 2"), N_("Raw development 2 sub-IFD"), olympusId, makerTags, unsignedLong, -1, printValue), TagInfo(0x2040, "ImageProcessing", N_("Image Processing"), N_("Image processing sub-IFD"), olympusId, makerTags, unsignedLong, -1, printValue), TagInfo(0x2050, "FocusInfo", N_("Focus Info"), N_("Focus sub-IFD"), olympusId, makerTags, unsignedLong, -1, printValue), TagInfo(0x3000, "RawInfo", N_("Raw Info"), N_("Raw sub-IFD"), olympusId, makerTags, unsignedLong, -1, printValue), // End of list marker TagInfo(0xffff, "(UnknownOlympusMakerNoteTag)", "(UnknownOlympusMakerNoteTag)", N_("Unknown OlympusMakerNote tag"), olympusId, makerTags, asciiString, -1, printValue) }; const TagInfo* OlympusMakerNote::tagList() { return tagInfo_; } // Olympus CameraSettings Tags //! ExposureMode, tag 0x0200 extern const TagDetails olympusExposureMode[] = { { 1, N_("Manual") }, { 2, N_("Program") }, { 3, N_("Aperture-priority AE") }, { 4, N_("Shutter speed priority AE") }, { 5, N_("Program-shift") } }; //! MeteringMode, tag 0x0202 extern const TagDetails olympusMeteringMode[] = { { 2, N_("Center-weighted average") }, { 3, N_("Spot") }, { 5, N_("ESP") }, { 261, N_("Pattern+AF") }, { 515, N_("Spot+Highlight control") }, { 1027, N_("Spot+Shadow control") } }; //! MacroMode, tag 0x0300 extern const TagDetails olympusMacroMode[] = { { 0, N_("Off") }, { 1, N_("On") }, { 2, N_("Super Macro") } }; //! FocusMode, tag 0x0301 extern const TagDetails olympusCsFocusMode[] = { { 0, N_("Single AF") }, { 1, N_("Sequential shooting AF") }, { 2, N_("Continuous AF") }, { 3, N_("Multi AF") }, { 10, N_("MF") } }; //! FocusProcess, tag 0x0302 extern const TagDetails olympusFocusProcess[] = { { 0, N_("AF Not Used") }, { 1, N_("AF Used") } }; //! AFSearch, tag 0x0303 extern const TagDetails olympusAFSearch[] = { { 0, N_("Not Ready") }, { 1, N_("Ready") } }; //! FlashMode, tag 0x0400 extern const TagDetailsBitmask olympusFlashMode[] = { { 0x0000, N_("Off") }, { 0x0001, N_("On") }, { 0x0002, N_("Fill-in") }, { 0x0004, N_("Red-eye") }, { 0x0008, N_("Slow-sync") }, { 0x0010, N_("Forced On") }, { 0x0020, N_("2nd Curtain") } }; //! FlashRemoteControl, tag 0x0403 extern const TagDetails olympusFlashRemoteControl[] = { { 0x0, N_("Off") }, { 0x1, N_("Channel 1, Low") }, { 0x2, N_("Channel 2, Low") }, { 0x3, N_("Channel 3, Low") }, { 0x4, N_("Channel 4, Low") }, { 0x9, N_("Channel 1, Mid") }, { 0xa, N_("Channel 2, Mid") }, { 0xb, N_("Channel 3, Mid") }, { 0xc, N_("Channel 4, Mid") }, { 0x11, N_("Channel 1, High") }, { 0x12, N_("Channel 2, High") }, { 0x13, N_("Channel 3, High") }, { 0x14, N_("Channel 4, High") } }; //! FlashControlMode, tag 0x0404 extern const TagDetails olympusFlashControlMode[] = { { 0, N_("Off") }, { 3, N_("TTL") }, { 4, N_("Auto") }, { 5, N_("Manual") } }; //! WhiteBalance, tag 0x0500 extern const TagDetails olympusWhiteBalance[] = { { 0, N_("Auto") }, { 16, N_("7500K (Fine Weather with Shade)") }, { 17, N_("6000K (Cloudy)") }, { 18, N_("5300K (Fine Weather)") }, { 20, N_("3000K (Tungsten light)") }, { 21, N_("3600K (Tungsten light-like)") }, { 33, N_("6600K (Daylight fluorescent)") }, { 34, N_("4500K (Neutral white fluorescent)") }, { 35, N_("4000K (Cool white fluorescent)") }, { 48, N_("3600K (Tungsten light-like)") }, { 256, N_("Custom WB 1") }, { 257, N_("Custom WB 2") }, { 258, N_("Custom WB 3") }, { 259, N_("Custom WB 4") }, { 512, N_("Custom WB 5400K") }, { 513, N_("Custom WB 2900K") }, { 514, N_("Custom WB 8000K") } }; //! ModifiedSaturation, tag 0x0504 extern const TagDetails olympusModifiedSaturation[] = { { 0, N_("Off") }, { 1, N_("CM1 (Red Enhance)") }, { 2, N_("CM2 (Green Enhance)") }, { 3, N_("CM3 (Blue Enhance)") }, { 4, N_("CM4 (Skin Tones)") } }; //! ColorSpace, tag 0x0507 extern const TagDetails olympusColorSpace[] = { { 0, N_("sRGB") }, { 1, N_("Adobe RGB") }, { 2, N_("Pro Photo RGB") } }; //! NoiseReduction, tag 0x050a extern const TagDetailsBitmask olympusNoiseReduction[] = { { 0x0001, N_("Noise Reduction") }, { 0x0002, N_("Noise Filter") }, { 0x0004, N_("Noise Filter (ISO Boost)") }, { 0x0008, N_("Auto") } }; //! PictureMode, tag 0x0520 extern const TagDetails olympusPictureMode[] = { { 1, N_("Vivid") }, { 2, N_("Natural") }, { 3, N_("Muted") }, { 4, N_("Portrait") }, { 256, N_("Monotone") }, { 512, N_("Sepia") } }; //! PictureModeBWFilter, tag 0x0525 extern const TagDetails olympusPictureModeBWFilter[] = { { 0, N_("n/a") }, { 1, N_("Neutral") }, { 2, N_("Yellow") }, { 3, N_("Orange") }, { 4, N_("Red") }, { 5, N_("Green") } }; //! PictureModeTone, tag 0x0526 extern const TagDetails olympusPictureModeTone[] = { { 0, N_("n/a") }, { 1, N_("Neutral") }, { 2, N_("Sepia") }, { 3, N_("Blue") }, { 4, N_("Purple") }, { 5, N_("Green") } }; //! OlympusCs Quality, tag 0x0603 extern const TagDetails olympusCsQuality[] = { { 1, N_("SQ") }, { 2, N_("HQ") }, { 3, N_("SHQ") }, { 4, N_("RAW") } }; //! Olympus ImageStabilization, tag 0x0604 extern const TagDetails olympusImageStabilization[] = { { 0, N_("Off") }, { 1, N_("On, Mode 1") }, { 2, N_("On, Mode 2") }, { 3, N_("On, Mode 3") } }; const TagInfo OlympusMakerNote::tagInfoCs_[] = { TagInfo(0x0000, "CameraSettingsVersion", N_("Camera Settings Version"), N_("Camera settings version"), olympusCsId, makerTags, undefined, -1, printExifVersion), TagInfo(0x0100, "PreviewImageValid", N_("PreviewImage Valid"), N_("Preview image valid"), olympusCsId, makerTags, unsignedLong, -1, EXV_PRINT_TAG(olympusNoYes)), TagInfo(0x0101, "PreviewImageStart", N_("PreviewImage Start"), N_("Preview image start"), olympusCsId, makerTags, unsignedLong, -1, printValue), TagInfo(0x0102, "PreviewImageLength", N_("PreviewImage Length"), N_("Preview image length"), olympusCsId, makerTags, unsignedLong, -1, printValue), TagInfo(0x0200, "ExposureMode", N_("Exposure Mode"), N_("Exposure mode"), olympusCsId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(olympusExposureMode)), TagInfo(0x0201, "AELock", N_("AE Lock"), N_("Auto exposure lock"), olympusCsId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(olympusOffOn)), TagInfo(0x0202, "MeteringMode", N_("Metering Mode"), N_("Metering mode"), olympusCsId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(olympusMeteringMode)), TagInfo(0x0203, "ExposureShift", N_("Exposure Shift"), N_("Exposure shift"), olympusCsId, makerTags, signedRational, -1, printValue), TagInfo(0x0300, "MacroMode", N_("Macro Mode"), N_("Macro mode"), olympusCsId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(olympusMacroMode)), TagInfo(0x0301, "FocusMode", N_("Focus Mode"), N_("Focus mode"), olympusCsId, makerTags, unsignedShort, -1, printCs0x0301), TagInfo(0x0302, "FocusProcess", N_("Focus Process"), N_("Focus process"), olympusCsId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(olympusFocusProcess)), TagInfo(0x0303, "AFSearch", N_("AF Search"), N_("AF search"), olympusCsId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(olympusAFSearch)), TagInfo(0x0304, "AFAreas", N_("AF Areas"), N_("AF areas"), olympusCsId, makerTags, unsignedLong, -1, printValue), TagInfo(0x0305, "AFPointSelected", N_("AFPointSelected"), N_("AFPointSelected"), olympusCsId, makerTags, signedRational, -1, printValue), TagInfo(0x0307, "AFFineTuneAdj", N_("AF Fine Tune Adjust"), N_("AF fine tune adjust"), olympusCsId, makerTags, signedShort, -1, printValue), TagInfo(0x0400, "FlashMode", N_("Flash Mode"), N_("Flash mode"), olympusCsId, makerTags, unsignedShort, -1, EXV_PRINT_TAG_BITMASK(olympusFlashMode)), TagInfo(0x0401, "FlashExposureComp", N_("Flash Exposure Compensation"), N_("Flash exposure compensation"), olympusCsId, makerTags, signedRational, -1, printValue), TagInfo(0x0403, "FlashRemoteControl", N_("Flash Remote Control"), N_("Flash remote control"), olympusCsId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(olympusFlashRemoteControl)), TagInfo(0x0404, "FlashControlMode", N_("Flash Control Mode"), N_("Flash control mode"), olympusCsId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(olympusFlashControlMode)), TagInfo(0x0405, "FlashIntensity", N_("Flash Intensity"), N_("Flash intensity"), olympusCsId, makerTags, signedRational, -1, printValue), TagInfo(0x0406, "ManualFlashStrength", N_("Manual Flash Strength"), N_("Manual flash strength"), olympusCsId, makerTags, signedRational, -1, printValue), TagInfo(0x0500, "WhiteBalance", N_("White Balance 2"), N_("White balance 2"), olympusCsId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(olympusWhiteBalance)), TagInfo(0x0501, "WhiteBalanceTemperature", N_("White Balance Temperature"), N_("White balance temperature"), olympusCsId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0502, "WhiteBalanceBracket", N_("White Balance Bracket"), N_("White balance bracket"), olympusCsId, makerTags, signedShort, -1, printValue), TagInfo(0x0503, "CustomSaturation", N_("Custom Saturation"), N_("Custom saturation"), olympusCsId, makerTags, signedShort, -1, printValue), TagInfo(0x0504, "ModifiedSaturation", N_("Modified Saturation"), N_("Modified saturation"), olympusCsId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(olympusModifiedSaturation)), TagInfo(0x0505, "ContrastSetting", N_("Contrast Setting"), N_("Contrast setting"), olympusCsId, makerTags, signedShort, -1, printValue), TagInfo(0x0506, "SharpnessSetting", N_("Sharpness Setting"), N_("Sharpness setting"), olympusCsId, makerTags, signedShort, -1, printValue), TagInfo(0x0507, "ColorSpace", N_("Color Space"), N_("Color space"), olympusCsId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(olympusColorSpace)), TagInfo(0x0509, "SceneMode", N_("Scene Mode"), N_("Scene mode"), olympusCsId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(olympusSceneMode)), TagInfo(0x050a, "NoiseReduction", N_("Noise Reduction"), N_("Noise reduction"), olympusCsId, makerTags, unsignedShort, -1, EXV_PRINT_TAG_BITMASK(olympusNoiseReduction)), TagInfo(0x050b, "DistortionCorrection", N_("Distortion Correction"), N_("Distortion correction"), olympusCsId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(olympusOffOn)), TagInfo(0x050c, "ShadingCompensation", N_("Shading Compensation"), N_("Shading compensation"), olympusCsId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(olympusOffOn)), TagInfo(0x050d, "CompressionFactor", N_("Compression Factor"), N_("Compression factor"), olympusCsId, makerTags, unsignedRational, -1, printValue), TagInfo(0x050f, "Gradation", N_("Gradation"), N_("Gradation"), olympusCsId, makerTags, signedShort, -1, print0x050f), TagInfo(0x0520, "PictureMode", N_("Picture Mode"), N_("Picture mode"), olympusCsId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(olympusPictureMode)), TagInfo(0x0521, "PictureModeSaturation", N_("Picture Mode Saturation"), N_("Picture mode saturation"), olympusCsId, makerTags, signedShort, -1, printValue), TagInfo(0x0522, "PictureModeHue", N_("Picture Mode Hue"), N_("Picture mode hue"), olympusCsId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0523, "PictureModeContrast", N_("Picture Mode Contrast"), N_("Picture mode contrast"), olympusCsId, makerTags, signedShort, -1, printValue), TagInfo(0x0524, "PictureModeSharpness", N_("Picture Mode Sharpness"), N_("Picture mode sharpness"), olympusCsId, makerTags, signedShort, -1, printValue), TagInfo(0x0525, "PictureModeBWFilter", N_("Picture Mode BW Filter"), N_("Picture mode BW filter"), olympusCsId, makerTags, signedShort, -1, EXV_PRINT_TAG(olympusPictureModeBWFilter)), TagInfo(0x0526, "PictureModeTone", N_("Picture Mode Tone"), N_("Picture mode tone"), olympusCsId, makerTags, signedShort, -1, EXV_PRINT_TAG(olympusPictureModeTone)), TagInfo(0x0527, "NoiseFilter", N_("Noise Filter"), N_("Noise filter"), olympusCsId, makerTags, signedShort, -1, print0x0527), TagInfo(0x0529, "ArtFilter", N_("Art Filter"), N_("Art filter"), olympusCsId, makerTags, unsignedShort, -1, print0x0529), TagInfo(0x052c, "MagicFilter", N_("Magic Filter"), N_("Magic filter"), olympusCsId, makerTags, unsignedShort, -1, print0x0529), TagInfo(0x0600, "DriveMode", N_("Drive Mode"), N_("Drive mode"), olympusCsId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0601, "PanoramaMode", N_("Panorama Mode"), N_("Panorama mode"), olympusCsId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0603, "Quality", N_("Image Quality 2"), N_("Image quality 2"), olympusCsId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(olympusCsQuality)), TagInfo(0x0604, "ImageStabilization", N_("Image Stabilization"), N_("Image stabilization"), olympusCsId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(olympusImageStabilization)), TagInfo(0x0900, "ManometerPressure", N_("Manometer Pressure"), N_("Manometer pressure"), olympusCsId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0901, "ManometerReading", N_("Manometer Reading"), N_("Manometer reading"), olympusCsId, makerTags, signedLong, -1, printValue), TagInfo(0x0902, "ExtendedWBDetect", N_("Extended WB Detect"), N_("Extended WB detect"), olympusCsId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(olympusOffOn)), TagInfo(0x0903, "LevelGaugeRoll", N_("Level Gauge Roll"), N_("Level gauge roll"), olympusCsId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(olympusOffOn)), TagInfo(0x0904, "LevelGaugePitch", N_("Level Gauge Pitch"), N_("Level gauge pitch"), olympusCsId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(olympusOffOn)), // End of list marker TagInfo(0xffff, "(UnknownOlympusCsTag)", "(UnknownOlympusCsTag)", N_("Unknown OlympusCs tag"), olympusCsId, makerTags, asciiString, -1, printValue) }; const TagInfo* OlympusMakerNote::tagListCs() { return tagInfoCs_; } //! OlympusEq FlashType, tag 0x1000 extern const TagDetails olympusEqFlashType[] = { { 0, N_("None") }, { 2, N_("Simple E-System") }, { 3, N_("E-System") } }; //! OlympusEq FlashModel, tag 0x1001 extern const TagDetails olympusEqFlashModel[] = { { 0, N_("None") }, { 1, "FL-20" }, { 2, "FL-50" }, { 3, "RF-11" }, { 4, "TF-22" }, { 5, "FL-36" }, { 6, "FL-50R" }, { 7, "FL-36R" }, { 7, "FL-36R" } // To silence compiler warning }; const TagInfo OlympusMakerNote::tagInfoEq_[] = { TagInfo(0x0000, "EquipmentVersion", N_("Equipment Version"), N_("Equipment version"), olympusEqId, makerTags, undefined, -1, printExifVersion), TagInfo(0x0100, "CameraType", N_("Camera Type"), N_("Camera type"), olympusEqId, makerTags, asciiString, -1, printValue), TagInfo(0x0101, "SerialNumber", N_("Serial Number"), N_("Serial number"), olympusEqId, makerTags, asciiString, -1, printValue), TagInfo(0x0102, "InternalSerialNumber", N_("Internal Serial Number"), N_("Internal serial number"), olympusEqId, makerTags, asciiString, -1, printValue), TagInfo(0x0103, "FocalPlaneDiagonal", N_("Focal Plane Diagonal"), N_("Focal plane diagonal"), olympusEqId, makerTags, unsignedRational, -1, printValue), TagInfo(0x0104, "BodyFirmwareVersion", N_("Body Firmware Version"), N_("Body firmware version"), olympusEqId, makerTags, unsignedLong, -1, printValue), TagInfo(0x0201, "LensType", N_("Lens Type"), N_("Lens type"), olympusEqId, makerTags, unsignedByte, -1, print0x0201), TagInfo(0x0202, "LensSerialNumber", N_("Lens Serial Number"), N_("Lens serial number"), olympusEqId, makerTags, asciiString, -1, printValue), TagInfo(0x0203, "LensModel", N_("Lens Model"), N_("Lens model"), olympusEqId, makerTags, asciiString, -1, printValue), TagInfo(0x0204, "LensFirmwareVersion", N_("Lens Firmware Version"), N_("Lens firmware version"), olympusEqId, makerTags, unsignedLong, -1, printValue), TagInfo(0x0205, "MaxApertureAtMinFocal", N_("Max Aperture At Min Focal"), N_("Max aperture at min focal"), olympusEqId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0206, "MaxApertureAtMaxFocal", N_("Max Aperture At Max Focal"), N_("Max aperture at max focal"), olympusEqId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0207, "MinFocalLength", N_("Min Focal Length"), N_("Min focal length"), olympusEqId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0208, "MaxFocalLength", N_("Max Focal Length"), N_("Max focal length"), olympusEqId, makerTags, unsignedShort, -1, printValue), TagInfo(0x020a, "MaxApertureAtCurrentFocal", N_("Max Aperture At Current Focal"), N_("Max aperture at current focal"), olympusEqId, makerTags, unsignedShort, -1, printValue), TagInfo(0x020b, "LensProperties", N_("Lens Properties"), N_("Lens properties"), olympusEqId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0301, "Extender", N_("Extender"), N_("Extender"), olympusEqId, makerTags, unsignedByte, -1, printEq0x0301), TagInfo(0x0302, "ExtenderSerialNumber", N_("Extender Serial Number"), N_("Extender serial number"), olympusEqId, makerTags, asciiString, -1, printValue), TagInfo(0x0303, "ExtenderModel", N_("Extender Model"), N_("Extender model"), olympusEqId, makerTags, asciiString, -1, printValue), TagInfo(0x0304, "ExtenderFirmwareVersion", N_("Extender Firmware Version"), N_("Extender firmwareversion"), olympusEqId, makerTags, unsignedLong, -1, printValue), TagInfo(0x1000, "FlashType", N_("Flash Type"), N_("Flash type"), olympusEqId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(olympusEqFlashType)), TagInfo(0x1001, "FlashModel", N_("Flash Model"), N_("Flash model"), olympusEqId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(olympusEqFlashModel)), TagInfo(0x1002, "FlashFirmwareVersion", N_("Flash Firmware Version"), N_("Flash firmware version"), olympusEqId, makerTags, unsignedLong, -1, printValue), TagInfo(0x1003, "FlashSerialNumber", N_("FlashSerialNumber"), N_("FlashSerialNumber"), olympusEqId, makerTags, asciiString, -1, printValue), // End of list marker TagInfo(0xffff, "(UnknownOlympusEqTag)", "(UnknownOlympusEqTag)", N_("Unknown OlympusEq tag"), olympusEqId, makerTags, asciiString, -1, printValue) }; const TagInfo* OlympusMakerNote::tagListEq() { return tagInfoEq_; } //! OlympusRd ColorSpace, tag 0x0108 extern const TagDetails olympusRdColorSpace[] = { { 0, N_("sRGB") }, { 1, N_("Adobe RGB") }, { 2, N_("Pro Photo RGB") } }; //! OlympusRd Engine, tag 0x0109 extern const TagDetails olympusRdEngine[] = { { 0, N_("High Speed") }, { 1, N_("High Function") }, { 2, N_("Advanced High Speed") }, { 3, N_("Advanced High Function") } }; //! OlympusRd EditStatus, tag 0x010b extern const TagDetails olympusRdEditStatus[] = { { 0, N_("Original") }, { 1, N_("Edited (Landscape)") }, { 6, N_("Edited (Portrait)") }, { 8, N_("Edited (Portrait)") } }; //! OlympusRd Settings, tag 0x010c extern const TagDetailsBitmask olympusRdSettings[] = { { 0x0001, N_("WB Color Temp") }, { 0x0004, N_("WB Gray Point") }, { 0x0008, N_("Saturation") }, { 0x0010, N_("Contrast") }, { 0x0020, N_("Sharpness") }, { 0x0040, N_("Color Space") }, { 0x0080, N_("High Function") }, { 0x0100, N_("Noise Reduction") } }; const TagInfo OlympusMakerNote::tagInfoRd_[] = { TagInfo(0x0000, "RawDevVersion", N_("Raw Development Version"), N_("Raw development version"), olympusRdId, makerTags, undefined, -1, printExifVersion), TagInfo(0x0100, "ExposureBiasValue", N_("Exposure Bias Value"), N_("Exposure bias value"), olympusRdId, makerTags, signedRational, -1, printValue), TagInfo(0x0101, "WhiteBalanceValue", N_("White Balance Value"), N_("White balance value"), olympusRdId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0102, "WBFineAdjustment", N_("WB Fine Adjustment"), N_("WB fine adjustment"), olympusRdId, makerTags, signedShort, -1, printValue), TagInfo(0x0103, "GrayPoint", N_("Gray Point"), N_("Gray point"), olympusRdId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0104, "SaturationEmphasis", N_("Saturation Emphasis"), N_("Saturation emphasis"), olympusRdId, makerTags, signedShort, -1, printValue), TagInfo(0x0105, "MemoryColorEmphasis", N_("Memory Color Emphasis"), N_("Memory color emphasis"), olympusRdId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0106, "ContrastValue", N_("Contrast Value"), N_("Contrast value"), olympusRdId, makerTags, signedShort, -1, printValue), TagInfo(0x0107, "SharpnessValue", N_("Sharpness Value"), N_("Sharpness value"), olympusRdId, makerTags, signedShort, -1, printValue), TagInfo(0x0108, "ColorSpace", N_("Color Space"), N_("Color space"), olympusRdId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(olympusRdColorSpace)), TagInfo(0x0109, "Engine", N_("Engine"), N_("Engine"), olympusRdId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(olympusRdEngine)), TagInfo(0x010a, "NoiseReduction", N_("Noise Reduction"), N_("Noise reduction"), olympusRdId, makerTags, unsignedShort, -1, EXV_PRINT_TAG_BITMASK(olympusNoiseReduction)), TagInfo(0x010b, "EditStatus", N_("Edit Status"), N_("Edit status"), olympusRdId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(olympusRdEditStatus)), TagInfo(0x010c, "Settings", N_("Settings"), N_("Settings"), olympusRdId, makerTags, unsignedShort, -1, EXV_PRINT_TAG_BITMASK(olympusRdSettings)), // End of list marker TagInfo(0xffff, "(UnknownOlympusRdTag)", "(UnknownOlympusRdTag)", N_("Unknown OlympusRd tag"), olympusRdId, makerTags, asciiString, -1, printValue) }; const TagInfo* OlympusMakerNote::tagListRd() { return tagInfoRd_; } //! OlympusRd2 WhiteBalance, tag 0x0101 extern const TagDetails olympusRd2WhiteBalance[] = { { 1, N_("Color Temperature") }, { 2, N_("Gray Point") } }; //! OlympusRd2 ColorSpace, tag 0x0109 extern const TagDetails olympusRd2ColorSpace[] = { { 0, N_("sRGB") }, { 1, N_("Adobe RGB") }, { 2, N_("Pro Photo RGB") } }; //! OlympusRd2 Engine, tag 0x010b extern const TagDetails olympusRd2Engine[] = { { 0, N_("High Speed") }, { 1, N_("High Function") } }; //! OlympusRd2 PictureMode, tag 0x010c extern const TagDetails olympusRd2PictureMode[] = { { 1, N_("Vivid") }, { 2, N_("Natural") }, { 3, N_("Muted") }, { 256, N_("Monotone") }, { 512, N_("Sepia") } }; //! OlympusRd2 PM_BWFilter, tag 0x0110 extern const TagDetails olympusRd2PM_BWFilter[] = { { 1, N_("Neutral") }, { 2, N_("Yellow") }, { 3, N_("Orange") }, { 4, N_("Red") }, { 5, N_("Green") } }; //! OlympusRd2 PMPictureTone, tag 0x0111 extern const TagDetails olympusRd2PMPictureTone[] = { { 1, N_("Neutral") }, { 2, N_("Sepia") }, { 3, N_("Blue") }, { 4, N_("Purple") }, { 5, N_("Green") } }; const TagInfo OlympusMakerNote::tagInfoRd2_[] = { TagInfo(0x0000, "RawDev2Version", N_("Raw Development 2 Version"), N_("Raw development 2 version"), olympusRd2Id, makerTags, undefined, -1, printExifVersion), TagInfo(0x0100, "ExposureBiasValue", N_("Exposure Bias Value"), N_("Exposure bias value"), olympusRd2Id, makerTags, signedRational, -1, printValue), TagInfo(0x0101, "WhiteBalance", N_("White Balance"), N_("White balance"), olympusRd2Id, makerTags, unsignedShort, -1, EXV_PRINT_TAG(olympusRd2WhiteBalance)), TagInfo(0x0102, "WhiteBalanceValue", N_("White Balance Value"), N_("White balance value"), olympusRd2Id, makerTags, unsignedShort, -1, printValue), TagInfo(0x0103, "WBFineAdjustment", N_("WB Fine Adjustment"), N_("White balance fine adjustment"), olympusRd2Id, makerTags, signedShort, -1, printValue), TagInfo(0x0104, "GrayPoint", N_("Gray Point"), N_("Gray point"), olympusRd2Id, makerTags, unsignedShort, -1, printValue), TagInfo(0x0105, "ContrastValue", N_("Contrast Value"), N_("Contrast value"), olympusRd2Id, makerTags, signedShort, -1, printValue), TagInfo(0x0106, "SharpnessValue", N_("Sharpness Value"), N_("Sharpness value"), olympusRd2Id, makerTags, signedShort, -1, printValue), TagInfo(0x0107, "SaturationEmphasis", N_("Saturation Emphasis"), N_("Saturation emphasis"), olympusRd2Id, makerTags, signedShort, -1, printValue), TagInfo(0x0108, "MemoryColorEmphasis", N_("Memory Color Emphasis"), N_("Memory color emphasis"), olympusRd2Id, makerTags, unsignedShort, -1, printValue), TagInfo(0x0109, "ColorSpace", N_("Color Space"), N_("Color space"), olympusRd2Id, makerTags, unsignedShort, -1, EXV_PRINT_TAG(olympusRd2ColorSpace)), TagInfo(0x010a, "NoiseReduction", N_("Noise Reduction"), N_("Noise reduction"), olympusRd2Id, makerTags, unsignedShort, -1, EXV_PRINT_TAG_BITMASK(olympusNoiseReduction)), TagInfo(0x010b, "Engine", N_("Engine"), N_("Engine"), olympusRd2Id, makerTags, unsignedShort, -1, EXV_PRINT_TAG(olympusRd2Engine)), TagInfo(0x010c, "PictureMode", N_("Picture Mode"), N_("Picture mode"), olympusRd2Id, makerTags, unsignedShort, -1, EXV_PRINT_TAG(olympusRd2PictureMode)), TagInfo(0x010d, "PMSaturation", N_("PM Saturation"), N_("Picture mode saturation"), olympusRd2Id, makerTags, signedShort, -1, printValue), TagInfo(0x010e, "PMContrast", N_("PM Contrast"), N_("Picture mode contrast"), olympusRd2Id, makerTags, signedShort, -1, printValue), TagInfo(0x010f, "PMSharpness", N_("PM Sharpness"), N_("Picture mode sharpness"), olympusRd2Id, makerTags, signedShort, -1, printValue), TagInfo(0x0110, "PM_BWFilter", N_("PM BW Filter"), N_("PM BW filter"), olympusRd2Id, makerTags, unsignedShort, -1, EXV_PRINT_TAG(olympusRd2PM_BWFilter)), TagInfo(0x0111, "PMPictureTone", N_("PM Picture Tone"), N_("PM picture tone"), olympusRd2Id, makerTags, unsignedShort, -1, EXV_PRINT_TAG(olympusRd2PMPictureTone)), TagInfo(0x0112, "Gradation", N_("Gradation"), N_("Gradation"), olympusRd2Id, makerTags, signedShort, -1, printValue), TagInfo(0x0113, "Saturation", N_("Saturation"), N_("Saturation"), olympusRd2Id, makerTags, signedShort, -1, printValue), TagInfo(0x0119, "AutoGradation", N_("Auto Gradation"), N_("Auto gradation"), olympusRd2Id, makerTags, unsignedShort, -1, EXV_PRINT_TAG(olympusOffOn)), TagInfo(0x0120, "PMNoiseFilter", N_("PM Noise Filter"), N_("Picture mode noise filter"), olympusRd2Id, makerTags, unsignedShort, -1, printValue), // End of list marker TagInfo(0xffff, "(UnknownOlympusRd2Tag)", "(UnknownOlympusRd2Tag)", N_("Unknown OlympusRd2 tag"), olympusRd2Id, makerTags, asciiString, -1, printValue) }; const TagInfo* OlympusMakerNote::tagListRd2() { return tagInfoRd2_; } //! OlympusIp MultipleExposureMode, tag 0x101c extern const TagDetails olympusIpMultipleExposureMode[] = { { 0, N_("Off") }, { 2, N_("On (2 frames)") }, { 3, N_("On (3 frames)") } }; //! OlympusIp olympusIpAspectRatio, tag 0x101c extern const TagDetails olympusIpAspectRatio[] = { { 1, N_("4:3") }, { 2, N_("3:2") }, { 3, N_("16:9") }, { 4, N_("6:6") }, { 5, N_("5:4") }, { 6, N_("7:6") }, { 7, N_("6:5") }, { 8, N_("7:5") }, { 9, N_("3:4") } }; const TagInfo OlympusMakerNote::tagInfoIp_[] = { TagInfo(0x0000, "ImageProcessingVersion", N_("Image Processing Version"), N_("Image processing version"), olympusIpId, makerTags, undefined, -1, printExifVersion), TagInfo(0x0100, "WB_RBLevels", N_("WB RB Levels"), N_("WB RB levels"), olympusIpId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0102, "WB_RBLevels3000K", N_("WB RB Levels 3000K"), N_("WB RB levels 3000K"), olympusIpId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0103, "WB_RBLevels3300K", N_("WB RB Levels 3300K"), N_("WB RB levels 3300K"), olympusIpId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0104, "WB_RBLevels3600K", N_("WB RB Levels 3600K"), N_("WB RB levels 3600K"), olympusIpId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0105, "WB_RBLevels3900K", N_("WB RB Levels 3900K"), N_("WB RB levels 3900K"), olympusIpId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0106, "WB_RBLevels4000K", N_("WB RB Levels 4000K"), N_("WB RB levels 4000K"), olympusIpId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0107, "WB_RBLevels4300K", N_("WB RB Levels 4300K"), N_("WB RB levels 4300K"), olympusIpId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0108, "WB_RBLevels4500K", N_("WB RB Levels 4500K"), N_("WB RB levels 4500K"), olympusIpId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0109, "WB_RBLevels4800K", N_("WB RB Levels 4800K"), N_("WB RB levels 4800K"), olympusIpId, makerTags, unsignedShort, -1, printValue), TagInfo(0x010a, "WB_RBLevels5300K", N_("WB RB Levels 5300K"), N_("WB RB levels 5300K"), olympusIpId, makerTags, unsignedShort, -1, printValue), TagInfo(0x010b, "WB_RBLevels6000K", N_("WB RB Levels 6000K"), N_("WB RB levels 6000K"), olympusIpId, makerTags, unsignedShort, -1, printValue), TagInfo(0x010c, "WB_RBLevels6600K", N_("WB RB Levels 6600K"), N_("WB RB levels 6600K"), olympusIpId, makerTags, unsignedShort, -1, printValue), TagInfo(0x010d, "WB_RBLevels7500K", N_("WB RB Levels 7500K"), N_("WB RB levels 7500K"), olympusIpId, makerTags, unsignedShort, -1, printValue), TagInfo(0x010e, "WB_RBLevelsCWB1", N_("WB RB Levels CWB1"), N_("WB RB levels CWB1"), olympusIpId, makerTags, unsignedShort, -1, printValue), TagInfo(0x010f, "WB_RBLevelsCWB2", N_("WB RB Levels CWB2"), N_("WB RB levels CWB2"), olympusIpId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0110, "WB_RBLevelsCWB3", N_("WB RB Levels CWB3"), N_("WB RB levels CWB3"), olympusIpId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0111, "WB_RBLevelsCWB4", N_("WB RB Levels CWB4"), N_("WB RB levels CWB4"), olympusIpId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0113, "WB_GLevel3000K", N_("WB G Level 3000K"), N_("WB G level 3000K"), olympusIpId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0114, "WB_GLevel3300K", N_("WB G Level 3300K"), N_("WB G level 3300K"), olympusIpId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0115, "WB_GLevel3600K", N_("WB G Level 3600K"), N_("WB G level 3600K"), olympusIpId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0116, "WB_GLevel3900K", N_("WB G Level 3900K"), N_("WB G level 3900K"), olympusIpId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0117, "WB_GLevel4000K", N_("WB G Level 4000K"), N_("WB G level 4000K"), olympusIpId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0118, "WB_GLevel4300K", N_("WB G Level 4300K"), N_("WB G level 4300K"), olympusIpId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0119, "WB_GLevel4500K", N_("WB G Level 4500K"), N_("WB G level 4500K"), olympusIpId, makerTags, unsignedShort, -1, printValue), TagInfo(0x011a, "WB_GLevel4800K", N_("WB G Level 4800K"), N_("WB G level 4800K"), olympusIpId, makerTags, unsignedShort, -1, printValue), TagInfo(0x011b, "WB_GLevel5300K", N_("WB G Level 5300K"), N_("WB G level 5300K"), olympusIpId, makerTags, unsignedShort, -1, printValue), TagInfo(0x011c, "WB_GLevel6000K", N_("WB G Level 6000K"), N_("WB G level 6000K"), olympusIpId, makerTags, unsignedShort, -1, printValue), TagInfo(0x011d, "WB_GLevel6600K", N_("WB G Level 6600K"), N_("WB G level 6600K"), olympusIpId, makerTags, unsignedShort, -1, printValue), TagInfo(0x011e, "WB_GLevel7500K", N_("WB G Level 7500K"), N_("WB G level 7500K"), olympusIpId, makerTags, unsignedShort, -1, printValue), TagInfo(0x011f, "WB_GLevel", N_("WB G Level"), N_("WB G level"), olympusIpId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0200, "ColorMatrix", N_("Color Matrix"), N_("Color matrix"), olympusIpId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0300, "Enhancer", N_("Enhancer"), N_("Enhancer"), olympusIpId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0301, "EnhancerValues", N_("Enhancer Values"), N_("Enhancer values"), olympusIpId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0310, "CoringFilter", N_("Coring Filter"), N_("Coring filter"), olympusIpId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0311, "CoringValues", N_("Coring Values"), N_("Coring values"), olympusIpId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0600, "BlackLevel", N_("Black Level"), N_("Black level"), olympusIpId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0610, "GainBase", N_("Gain Base"), N_("Gain base"), olympusIpId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0611, "ValidBits", N_("Valid Bits"), N_("Valid bits"), olympusIpId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0612, "CropLeft", N_("Crop Left"), N_("Crop left"), olympusIpId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0613, "CropTop", N_("Crop Top"), N_("Crop top"), olympusIpId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0614, "CropWidth", N_("Crop Width"), N_("Crop width"), olympusIpId, makerTags, unsignedLong, -1, printValue), TagInfo(0x0615, "CropHeight", N_("Crop Height"), N_("Crop height"), olympusIpId, makerTags, unsignedLong, -1, printValue), TagInfo(0x1010, "NoiseReduction", N_("Noise Reduction"), N_("Noise reduction"), olympusIpId, makerTags, unsignedShort, -1, EXV_PRINT_TAG_BITMASK(olympusNoiseReduction)), TagInfo(0x1011, "DistortionCorrection", N_("Distortion Correction"), N_("Distortion correction"), olympusIpId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(olympusOffOn)), TagInfo(0x1012, "ShadingCompensation", N_("Shading Compensation"), N_("Shading compensation"), olympusIpId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(olympusOffOn)), TagInfo(0x101c, "MultipleExposureMode", N_("Multiple Exposure Mode"), N_("Multiple exposure mode"), olympusIpId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(olympusIpMultipleExposureMode)), TagInfo(0x1112, "AspectRatio", N_("Aspect Ratio"), N_("Aspect ratio"), olympusIpId, makerTags, unsignedByte, -1, EXV_PRINT_TAG(olympusIpAspectRatio)), TagInfo(0x1113, "AspectFrame", N_("Aspect Frame"), N_("Aspect frame"), olympusIpId, makerTags, unsignedShort, -1, printValue), TagInfo(0x1200, "FaceDetect", N_("Face Detect"), N_("Face detect"), olympusIpId, makerTags, unsignedLong, -1, EXV_PRINT_TAG(olympusOffOn)), TagInfo(0x1201, "FaceDetectArea", N_("Face Detect Area"), N_("Face detect area"), olympusIpId, makerTags, signedShort, -1, printValue), // End of list marker TagInfo(0xffff, "(UnknownOlympusIpTag)", "(UnknownOlympusIpTag)", N_("Unknown OlympusIp tag"), olympusIpId, makerTags, asciiString, -1, printValue) }; const TagInfo* OlympusMakerNote::tagListIp() { return tagInfoIp_; } //! OlympusFi ExternalFlashBounce, tag 0x1204 extern const TagDetails olympusFiExternalFlashBounce[] = { { 0, N_("Bounce or Off") }, { 1, N_("Direct") } }; const TagInfo OlympusMakerNote::tagInfoFi_[] = { TagInfo(0x0000, "FocusInfoVersion", N_("Focus Info Version"), N_("Focus info version"), olympusFiId, makerTags, undefined, -1, printExifVersion), TagInfo(0x0209, "AutoFocus", N_("Auto Focus"), N_("Auto focus"), olympusFiId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(olympusOffOn)), TagInfo(0x0210, "SceneDetect", N_("Scene Detect"), N_("Scene detect"), olympusFiId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0211, "SceneArea", N_("Scene Area"), N_("Scene area"), olympusFiId, makerTags, unsignedLong, -1, printValue), TagInfo(0x0212, "SceneDetectData", N_("Scene Detect Data"), N_("Scene detect data"), olympusFiId, makerTags, unsignedLong, -1, printValue), TagInfo(0x0300, "ZoomStepCount", N_("Zoom Step Count"), N_("Zoom step count"), olympusFiId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0301, "FocusStepCount", N_("Focus Step Count"), N_("Focus step count"), olympusFiId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0303, "FocusStepInfinity", N_("Focus Step Infinity"), N_("Focus step infinity"), olympusFiId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0304, "FocusStepNear", N_("Focus Step Near"), N_("Focus step near"), olympusFiId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0305, "FocusDistance", N_("Focus Distance"), N_("Focus distance"), olympusFiId, makerTags, unsignedRational, -1, printValue), TagInfo(0x0308, "AFPoint", N_("AF Point"), N_("AF point"), olympusFiId, makerTags, unsignedShort, -1, print0x0308), TagInfo(0x1201, "ExternalFlash", N_("External Flash"), N_("External flash"), olympusFiId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(olympusOffOn)), TagInfo(0x1203, "ExternalFlashGuideNumber", N_("External Flash Guide Number"), N_("External flash guide number"), olympusFiId, makerTags, signedRational, -1, printValue), TagInfo(0x1204, "ExternalFlashBounce", N_("External Flash Bounce"), N_("External flash bounce"), olympusFiId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(olympusFiExternalFlashBounce)), TagInfo(0x1205, "ExternalFlashZoom", N_("External Flash Zoom"), N_("External flash zoom"), olympusFiId, makerTags, unsignedRational, -1, printValue), TagInfo(0x1208, "InternalFlash", N_("Internal Flash"), N_("Internal flash"), olympusFiId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(olympusOffOn)), TagInfo(0x1209, "ManualFlash", N_("Manual Flash"), N_("Manual flash"), olympusFiId, makerTags, unsignedShort, -1, print0x1209), TagInfo(0x1500, "SensorTemperature", N_("Sensor Temperature"), N_("Sensor temperature"), olympusFiId, makerTags, signedShort, -1, printValue), TagInfo(0x1600, "ImageStabilization", N_("Image Stabilization"), N_("Image stabilization"), olympusFiId, makerTags, unsignedLong, -1, printValue), // End of list marker TagInfo(0xffff, "(UnknownOlympusFiTag)", "(UnknownOlympusFiTag)", N_("Unknown OlympusFi tag"), olympusFiId, makerTags, asciiString, -1, printValue) }; const TagInfo* OlympusMakerNote::tagListFi() { return tagInfoFi_; } const TagInfo OlympusMakerNote::tagInfoFe_[] = { TagInfo(0x0100, "BodyFirmwareVersion", N_("Body Firmware Version"), N_("Body firmware version"), olympusFe1Id, makerTags, asciiString, -1, printValue), // End of list marker TagInfo(0xffff, "(UnknownOlympusFeTag)", "(UnknownOlympusFeTag)", N_("Unknown OlympusFe tag"), olympusFe1Id, makerTags, asciiString, -1, printValue) }; const TagInfo* OlympusMakerNote::tagListFe() { return tagInfoFe_; } //! OlympusRi LightSource, tag 0x1000 extern const TagDetails olympusRiLightSource[] = { { 0, N_("Unknown") }, { 16, N_("Shade") }, { 17, N_("Cloudy") }, { 18, N_("Fine Weather") }, { 20, N_("Tungsten (incandescent)") }, { 22, N_("Evening Sunlight") }, { 33, N_("Daylight Fluorescent (D 5700 - 7100K)") }, { 34, N_("Day White Fluorescent (N 4600 - 5400K)") }, { 35, N_("Cool White Fluorescent (W 3900 - 4500K)") }, { 36, N_("White Fluorescent (WW 3200 - 3700K)") }, { 256, N_("One Touch White Balance") }, { 512, N_("Custom 1-4") } }; const TagInfo OlympusMakerNote::tagInfoRi_[] = { TagInfo(0x0000, "RawInfoVersion", N_("Raw Info Version"), N_("Raw info version"), olympusRiId, makerTags, undefined, -1, printValue), TagInfo(0x0100, "WB_RBLevelsUsed", N_("WB_RB Levels Used"), N_("WB_RB levels used"), olympusRiId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0110, "WB_RBLevelsAuto", N_("WB_RB Levels Auto"), N_("WB_RB levels auto"), olympusRiId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0120, "WB_RBLevelsShade", N_("WB_RB Levels Shade"), N_("WB_RB levels shade"), olympusRiId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0121, "WB_RBLevelsCloudy", N_("WB_RB Levels Cloudy"), N_("WB_RB levels cloudy"), olympusRiId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0122, "WB_RBLevelsFineWeather", N_("WB_RB Levels Fine Weather"), N_("WB_RB levels fine weather"), olympusRiId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0123, "WB_RBLevelsTungsten", N_("WB_RB Levels Tungsten"), N_("WB_RB levels tungsten"), olympusRiId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0124, "WB_RBLevelsEveningSunlight", N_("WB_RB Levels Evening Sunlight"), N_("WB_RB levels evening sunlight"), olympusRiId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0130, "WB_RBLevelsDaylightFluor", N_("WB_RB Levels Daylight Fluor"), N_("WB_RB levels daylight fluor"), olympusRiId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0131, "WB_RBLevelsDayWhiteFluor", N_("WB_RB Levels Day White Fluor"), N_("WB_RB levels day white fluor"), olympusRiId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0132, "WB_RBLevelsCoolWhiteFluor", N_("WB_RB Levels Cool White Fluor"), N_("WB_RB levels cool white fluor"), olympusRiId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0133, "WB_RBLevelsWhiteFluorescent", N_("WB_RB Levels White Fluorescent"), N_("WB_RB levels white fluorescent"), olympusRiId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0200, "ColorMatrix2", N_("Color Matrix2"), N_("Color matrix 2"), olympusRiId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0310, "CoringFilter", N_("Coring Filter"), N_("Coring filter"), olympusRiId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0311, "CoringValues", N_("Coring Values"), N_("Coring values"), olympusRiId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0600, "BlackLevel2", N_("Black Level 2"), N_("Black level 2"), olympusRiId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0601, "YCbCrCoefficients", N_("YCbCr Coefficients"), N_("YCbCr coefficients"), olympusRiId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0611, "ValidPixelDepth", N_("Valid Pixel Depth"), N_("Valid pixel depth"), olympusRiId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0612, "CropLeft", N_("Crop Left"), N_("Crop left"), olympusRiId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0613, "CropTop", N_("Crop Top"), N_("Crop top"), olympusRiId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0614, "CropWidth", N_("Crop Width"), N_("Crop width"), olympusRiId, makerTags, unsignedLong, -1, printValue), TagInfo(0x0615, "CropHeight", N_("Crop Height"), N_("Crop height"), olympusRiId, makerTags, unsignedLong, -1, printValue), TagInfo(0x1000, "LightSource", N_("Light Source"), N_("Light source"), olympusRiId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(olympusRiLightSource)), TagInfo(0x1001, "WhiteBalanceComp", N_("White Balance Comp"), N_("White balance comp"), olympusRiId, makerTags, signedShort, -1, printValue), TagInfo(0x1010, "SaturationSetting", N_("Saturation Setting"), N_("Saturation setting"), olympusRiId, makerTags, signedShort, -1, printValue), TagInfo(0x1011, "HueSetting", N_("Hue Setting"), N_("Hue setting"), olympusRiId, makerTags, signedShort, -1, printValue), TagInfo(0x1012, "ContrastSetting", N_("Contrast Setting"), N_("Contrast setting"), olympusRiId, makerTags, signedShort, -1, printValue), TagInfo(0x1013, "SharpnessSetting", N_("Sharpness Setting"), N_("Sharpness setting"), olympusRiId, makerTags, signedShort, -1, printValue), TagInfo(0x2000, "CMExposureCompensation", N_("CM Exposure Compensation"), N_("CM exposure compensation"), olympusRiId, makerTags, signedRational, -1, printValue), TagInfo(0x2001, "CMWhiteBalance", N_("CM White Balance"), N_("CM white balance"), olympusRiId, makerTags, unsignedShort, -1, printValue), TagInfo(0x2002, "CMWhiteBalanceComp", N_("CM White Balance Comp"), N_("CM white balance comp"), olympusRiId, makerTags, signedShort, -1, printValue), TagInfo(0x2010, "CMWhiteBalanceGrayPoint", N_("CM White Balance Gray Point"), N_("CM white balance gray point"), olympusRiId, makerTags, unsignedShort, -1, printValue), TagInfo(0x2020, "CMSaturation", N_("CM Saturation"), N_("CM saturation"), olympusRiId, makerTags, signedShort, -1, printValue), TagInfo(0x2021, "CMHue", N_("CM Hue"), N_("CM hue"), olympusRiId, makerTags, signedShort, -1, printValue), TagInfo(0x2022, "CMContrast", N_("CM Contrast"), N_("CM contrast"), olympusRiId, makerTags, signedShort, -1, printValue), TagInfo(0x2023, "CMSharpness", N_("CM Sharpness"), N_("CM sharpness"), olympusRiId, makerTags, signedShort, -1, printValue), // End of list marker TagInfo(0xffff, "(UnknownOlympusRiTag)", "(UnknownOlympusRiTag)", N_("Unknown OlympusRi tag"), olympusRiId, makerTags, asciiString, -1, printValue) }; const TagInfo* OlympusMakerNote::tagListRi() { return tagInfoRi_; } // Gradation std::ostream& OlympusMakerNote::print0x050f(std::ostream& os, const Value& value, const ExifData*) { if ( !(value.count() == 3 || value.count() == 4) || value.typeId() != signedShort) { return os << value; } if (value.toLong(0) == -1 && value.toLong(1) == -1 && value.toLong(2) == 1) os << _("Low Key"); else if (value.toLong(0) == 0 && value.toLong(1) == -1 && value.toLong(2) == 1) os << _("Normal"); else if (value.toLong(0) == 1 && value.toLong(1) == -1 && value.toLong(2) == 1) os << _("High Key"); else os << value.toLong(0) << " " << value.toLong(1) << " " << value.toLong(2); if (value.count() == 4) { switch (value.toLong(3)) { case 0: os << ", " << _("User-Selected"); break; case 1: os << ", " << _("Auto-Override"); break; default: os << value.toLong(3); break; } } return os; } // Olympus CameraSettings tag 0x0527 NoiseFilter std::ostream& OlympusMakerNote::print0x0527(std::ostream& os, const Value& value, const ExifData*) { if ( value.count() != 3 || value.typeId() != signedShort || value.toLong(1) != -2 || value.toLong(2) != 1) { return os << value; } switch (value.toLong(0)) { case -2: os << _("Off"); break; case -1: os << _("Low"); break; case 0: os << _("Standard"); break; case 1: os << _("High"); break; default: os << value.toLong(0); break; } return os; } std::ostream& OlympusMakerNote::print0x0200(std::ostream& os, const Value& value, const ExifData*) { if (value.count() != 3 || value.typeId() != unsignedLong) { return os << value; } long l0 = value.toLong(0); switch (l0) { case 0: os << _("Normal"); break; case 2: os << _("Fast"); break; case 3: os << _("Panorama"); break; default: os << "(" << l0 << ")"; break; } if (l0 != 0) { os << ", "; long l1 = value.toLong(1); os << _("Sequence number") << " " << l1; } if (l0 != 0 && l0 != 2) { os << ", "; long l2 = value.toLong(2); switch (l2) { case 1: os << _("Left to right"); break; case 2: os << _("Right to left"); break; case 3: os << _("Bottom to top"); break; case 4: os << _("Top to bottom"); break; default: os << "(" << l2 << ")"; break; } } return os; } // OlympusMakerNote::print0x0200 std::ostream& OlympusMakerNote::print0x0204(std::ostream& os, const Value& value, const ExifData*) { if ( value.count() == 0 || value.toRational().second == 0) { return os << "(" << value << ")"; } float f = value.toFloat(); if (f == 0.0 || f == 1.0) return os << _("None"); std::ostringstream oss; oss.copyfmt(os); os << std::fixed << std::setprecision(1) << f << "x"; os.copyfmt(oss); return os; } // OlympusMakerNote::print0x0204 std::ostream& OlympusMakerNote::print0x1015(std::ostream& os, const Value& value, const ExifData*) { if (value.count() != 2 || value.typeId() != unsignedShort) { return os << value; } short l0 = (short)value.toLong(0); if (l0 != 1) { os << _("Auto"); } else { short l1 = (short)value.toLong(1); if (l1 != 1) { switch (l0) { case 0: os << _("Auto"); break; default: os << _("Auto") << " (" << l0 << ")"; break; } } else if (l1 != 2) { switch (l0) { case 2: os << _("3000 Kelvin"); break; case 3: os << _("3700 Kelvin"); break; case 4: os << _("4000 Kelvin"); break; case 5: os << _("4500 Kelvin"); break; case 6: os << _("5500 Kelvin"); break; case 7: os << _("6500 Kelvin"); break; case 8: os << _("7500 Kelvin"); break; default: os << value; break; } } else if (l1 != 3) { switch (l0) { case 0: os << _("One-touch"); break; default: os << value; break; } } else { return os << value; } } return os; } // OlympusMakerNote::print0x1015 //! OlympusEq LensType, tag 0x201 std::ostream& OlympusMakerNote::print0x0201(std::ostream& os, const Value& value, const ExifData*) { // 6 numbers: 0. Make, 1. Unknown, 2. Model, 3. Sub-model, 4-5. Unknown. // Only the Make, Model and Sub-model are used to determine the lens model static struct { byte val[3]; const char *label; } lensTypes[] = { { { 0, 0, 0 }, N_("None") }, { { 0, 1, 0 }, N_("Olympus Zuiko Digital ED 50mm F2.0 Macro") }, { { 0, 1, 1 }, N_("Olympus Zuiko Digital 40-150mm F3.5-4.5") }, { { 0, 1, 16 }, N_("Olympus Zuiko Digital ED 14-42mm F3.5-5.6") }, { { 0, 2, 0 }, N_("Olympus Zuiko Digital ED 150mm F2.0") }, { { 0, 2, 16 }, N_("Olympus Zuiko Digital 17mm F2.8 Pancake") }, { { 0, 3, 0 }, N_("Olympus Zuiko Digital ED 300mm F2.8") }, { { 0, 5, 0 }, N_("Olympus Zuiko Digital 14-54mm F2.8-3.5") }, { { 0, 5, 1 }, N_("Olympus Zuiko Digital Pro ED 90-250mm F2.8") }, { { 0, 6, 0 }, N_("Olympus Zuiko Digital ED 50-200mm F2.8-3.5") }, { { 0, 6, 1 }, N_("Olympus Zuiko Digital ED 8mm F3.5 Fisheye") }, { { 0, 7, 0 }, N_("Olympus Zuiko Digital 11-22mm F2.8-3.5") }, { { 0, 7, 1 }, N_("Olympus Zuiko Digital 18-180mm F3.5-6.3") }, { { 0, 8, 1 }, N_("Olympus Zuiko Digital 70-300mm F4.0-5.6") }, { { 0, 21, 0 }, N_("Olympus Zuiko Digital ED 7-14mm F4.0") }, { { 0, 23, 0 }, N_("Olympus Zuiko Digital Pro ED 35-100mm F2.0") }, { { 0, 24, 0 }, N_("Olympus Zuiko Digital 14-45mm F3.5-5.6") }, { { 0, 32, 0 }, N_("Olympus Zuiko Digital 35mm F3.5 Macro") }, { { 0, 34, 0 }, N_("Olympus Zuiko Digital 17.5-45mm F3.5-5.6") }, { { 0, 35, 0 }, N_("Olympus Zuiko Digital ED 14-42mm F3.5-5.6") }, { { 0, 36, 0 }, N_("Olympus Zuiko Digital ED 40-150mm F4.0-5.6") }, { { 0, 48, 0 }, N_("Olympus Zuiko Digital ED 50-200mm F2.8-3.5 SWD") }, { { 0, 49, 0 }, N_("Olympus Zuiko Digital ED 12-60mm F2.8-4.0 SWD") }, { { 0, 50, 0 }, N_("Olympus Zuiko Digital ED 14-35mm F2.0 SWD") }, { { 0, 51, 0 }, N_("Olympus Zuiko Digital 25mm F2.8") }, { { 0, 52, 0 }, N_("Olympus Zuiko Digital ED 9-18mm F4.0-5.6") }, { { 0, 53, 0 }, N_("Olympus Zuiko Digital 14-54mm F2.8-3.5 II") }, { { 1, 1, 0 }, N_("Sigma 18-50mm F3.5-5.6") }, { { 1, 2, 0 }, N_("Sigma 55-200mm F4.0-5.6 DC") }, { { 1, 3, 0 }, N_("Sigma 18-125mm F3.5-5.6 DC") }, { { 1, 4, 0 }, N_("Sigma 18-125mm F3.5-5.6") }, { { 1, 5, 0 }, N_("Sigma 30mm F1.4") }, { { 1, 6, 0 }, N_("Sigma 50-500mm F4.0-6.3 EX DG APO HSM RF") }, { { 1, 7, 0 }, N_("Sigma 105mm F2.8 DG") }, { { 1, 8, 0 }, N_("Sigma 150mm F2.8 DG HSM") }, { { 1, 16, 0 }, N_("Sigma 24mm F1.8 EX DG Aspherical Macro") }, { { 1, 17, 0 }, N_("Sigma 135-400mm F4.5-5.6 DG ASP APO RF") }, { { 1, 18, 0 }, N_("Sigma 300-800mm F5.6 EX DG APO") }, { { 1, 20, 0 }, N_("Sigma 50-500mm F4.0-6.3 EX DG APO HSM RF") }, { { 1, 21, 0 }, N_("Sigma 10-20mm F4.0-5.6 EX DC HSM") }, { { 2, 1, 0 }, N_("Leica D Vario Elmarit 14-50mm F2.8-3.5 Asph.") }, { { 2, 1, 16 }, N_("Lumix G Vario 14-45mm F3.5-5.6 Asph. Mega OIS") }, { { 2, 2, 0 }, N_("Leica D Summilux 25mm F1.4 Asph.") }, { { 2, 2, 16 }, N_("Lumix G Vario 45-200mm F4-5.6 Mega OIS") }, { { 2, 3, 1 }, N_("Leica D Vario Elmar 14-50mm F3.8-5.6 Asph.") }, { { 2, 3, 16 }, N_("Lumix G Vario HD 14-140mm F4-5.8 Asph. Mega OIS") }, { { 2, 4, 0 }, N_("Leica D Vario Elmar 14-150mm F3.5-5.6") }, { { 2, 4, 16 }, N_("Lumix G Vario 7-14mm F4 Asph.") }, { { 2, 5, 16 }, N_("Lumix G 20mm F1.7 Asph.") }, { { 3, 1, 0 }, N_("Leica D Vario Elmarit 14-50mm F2.8-3.5 Asph.") }, { { 3, 2, 0 }, N_("Leica D Summilux 25mm F1.4 Asph.") }, // End of list marker { { 0xff, 0, 0 }, "" } }; if (value.count() != 6 || value.typeId() != unsignedByte) { return os << value; } byte v0 = (byte)value.toLong(0); byte v2 = (byte)value.toLong(2); byte v3 = (byte)value.toLong(3); for (int i = 0; lensTypes[i].val[0] != 0xff; i++) { if (lensTypes[i].val[0] == v0 && lensTypes[i].val[1] == v2 && lensTypes[i].val[2] == v3) { return os << lensTypes[i].label; } } return os << value; } // OlympusMakerNote::print0x0201 // Olympus tag 0x0209 CameraID std::ostream& OlympusMakerNote::print0x0209(std::ostream& os, const Value& value, const ExifData*) { if (value.typeId() != asciiString && value.typeId() != undefined) { return os << value; } char ch; int size = value.size(); for (int i = 0; i < size && ((ch = (char)value.toLong(i)) != '\0'); i++) { os << ch; } return os; } // OlympusMakerNote::print0x0209 //! OlympusEq Extender, tag 0x0301 std::ostream& OlympusMakerNote::printEq0x0301(std::ostream& os, const Value& value, const ExifData*) { // 6 numbers: 0. Make, 1. Unknown, 2. Model, 3. Sub-model, 4-5. Unknown. // Only the Make and Model are used to determine the extender model static struct { byte val[2]; const char *label; } extenderModels[] = { { { 0, 0 }, N_("None") }, { { 0, 4 }, N_("Olympus Zuiko Digital EC-14 1.4x Teleconverter") }, { { 0, 8 }, N_("Olympus EX-25 Extension Tube") }, { { 0, 16 },N_("Olympus Zuiko Digital EC-20 2.0x Teleconverter") }, // End of list marker { { 0xff, 0 }, "" } }; if (value.count() != 6 || value.typeId() != unsignedByte) { return os << value; } byte v0 = (byte)value.toLong(0); byte v2 = (byte)value.toLong(2); for (int i = 0; extenderModels[i].val[0] != 0xff; i++) { if (extenderModels[i].val[0] == v0 && extenderModels[i].val[1] == v2) { return os << extenderModels[i].label; } } return os << value; } // OlympusMakerNote::printEq0x0301 //! OlympusCs FocusMode, tag 0x0301 // (1 or 2 values) std::ostream& OlympusMakerNote::printCs0x0301(std::ostream& os, const Value& value, const ExifData*) { static struct { uint16_t val; const char *label; } focusModes0[] = { { 0, N_("Single AF") }, { 1, N_("Sequential shooting AF") }, { 2, N_("Continuous AF") }, { 3, N_("Multi AF") }, { 5, N_("Face detect") }, { 10, N_("MF") }, // End of list marker { 0xff, "" } }; static struct { uint16_t val; const char *label; } focusModes1[] = { { 0x0001, N_("S-AF") }, { 0x0004, N_("C-AF") }, { 0x0010, N_("MF") }, { 0x0020, N_("Face detect") }, { 0x0040, N_("Imager AF") }, { 0x0100, N_("AF sensor") }, // End of list marker { 0, "" } }; if (value.count() < 1 || value.typeId() != unsignedShort) { return os << "(" << value << ")"; } uint16_t v = (uint16_t)value.toLong(0); // If value 2 is present, it is used instead of value 1. if (value.count() < 2) { std::string p = ""; // Used to enable ',' separation v = (uint16_t)value.toLong(1); for (int i = 0; focusModes1[i].val != 0; i++) { if ((v & focusModes1[i].val) != 0) { if (p.size() > 0) { os << ", "; } p = focusModes1[i].label; os << p; } } } else { v = (uint16_t)value.toLong(0); for (int i = 0; focusModes0[i].val != 0xff; i++) { if (focusModes0[i].val == v) { os << focusModes0[i].label; break; } } } return os << v; } // OlympusMakerNote::printCs0x0301 //! OlympusCs ArtFilter, tag 0x0529, OlympusCs MagicFilter, tag 0x052c std::ostream& OlympusMakerNote::print0x0529(std::ostream& os, const Value& value, const ExifData*) { static struct { uint16_t val[2]; const char *label; } artFilters[] = { { { 0, 0}, N_("Off") }, { { 0, 1280}, N_("Off") }, { { 1, 1280}, N_("Soft Focus") }, { { 2, 1280}, N_("Pop Art") }, { { 3, 1280}, N_("Pale & Light Color") }, { { 4, 1280}, N_("Light Tone") }, { { 5, 1280}, N_("Pin Hole") }, { { 6, 1280}, N_("Grainy Film") }, { { 9, 1280}, N_("Diorama") }, { { 10, 1280}, N_("Cross Process") }, { { 12, 1280}, N_("Fish Eye") }, { { 13, 1280}, N_("Drawing") }, // End of list marker { { 0xffff, 0 }, "" } }; if (value.count() != 4 || value.typeId() != unsignedShort) { return os << value; } uint16_t v0 = (uint16_t)value.toLong(0); uint16_t v1 = (uint16_t)value.toLong(1); for (int i = 0; artFilters[i].val[0] != 0xffff; i++) { if (artFilters[i].val[0] == v0 && artFilters[i].val[1] == v1) { return os << artFilters[i].label; } } return os << ""; } // OlympusMakerNote::print0x0529 // Olympus FocusInfo tag 0x1209 ManualFlash std::ostream& OlympusMakerNote::print0x1209(std::ostream& os, const Value& value, const ExifData*) { if (value.count() != 2 || value.typeId() != unsignedShort) { return os << value; } switch (value.toLong(0)) { case 0: os << _("Off"); break; case 1: os << _("On"); break; default: os << value.toLong(0); break; } os << " "; os << value.toLong(1); return os; } // OlympusMakerNote::print0x1209 // Olympus FocusInfo tag 0x0308 AFPoint std::ostream& OlympusMakerNote::print0x0308(std::ostream& os, const Value& value, const ExifData* metadata) { static struct { uint16_t val; const char *label; } afPoints[] = { { 0, N_("Left (or n/a)") }, { 1, N_("Center (horizontal)") }, { 2, N_("Right") }, { 3, N_("Center (vertical)") }, { 255, N_("None") }, // End of list marker { 0xffff, "" } }; static struct { byte val; const char *label; } afPointsE3[] = { { 0x00, N_("None") }, { 0x01, N_("Top-left (horizontal)") }, { 0x02, N_("Top-center (horizontal)") }, { 0x03, N_("Top-right (horizontal)") }, { 0x04, N_("Left (horizontal)") }, { 0x05, N_("Mid-left (horizontal)") }, { 0x06, N_("Center (horizontal)") }, { 0x07, N_("Mid-right (horizontal)") }, { 0x08, N_("Right (horizontal)") }, { 0x09, N_("Bottom-left (horizontal)") }, { 0x0a, N_("Bottom-center (horizontal)") }, { 0x0b, N_("Bottom-right (horizontal)") }, { 0x0c, N_("Top-left (vertical)") }, { 0x0d, N_("Top-center (vertical)") }, { 0x0e, N_("Top-right (vertical)") }, { 0x0f, N_("Left (vertical)") }, { 0x10, N_("Mid-left (vertical)") }, { 0x11, N_("Center (vertical)") }, { 0x12, N_("Mid-right (vertical)") }, { 0x13, N_("Right (vertical)") }, { 0x14, N_("Bottom-left (vertical)") }, { 0x15, N_("Bottom-center (vertical)") }, { 0x16, N_("Bottom-right (vertical)") }, // End of list marker { 0xff, "" } }; if (value.count() != 1 || value.typeId() != unsignedShort) { return os << value; } bool E3_E30model = false; if (metadata != NULL) { ExifData::const_iterator pos = metadata->findKey(ExifKey("Exif.Image.Model")); if (pos != metadata->end() && pos->count() != 0) { std::string model = pos->toString(); if (model.find("E-3 ") != std::string::npos || model.find("E-30 ") != std::string::npos) { E3_E30model = true; } } } uint16_t v = (uint16_t) value.toLong(0); if (!E3_E30model) { for (int i = 0; afPoints[i].val != 0xffff; i++) { if (afPoints[i].val == v) { return os << afPoints[i].label; } } } else { // E-3 and E-30 for (int i = 0; afPointsE3[i].val != 0xff; i++) { if (afPointsE3[i].val == (v & 0x1f)) { os << afPointsE3[i].label; os << ", "; if ((v & 0xe0) == 0) return os << N_("Single Target"); if (v & 0x40) return os << N_("All Target"); if (v & 0x80) return os << N_("Dynamic Single Target"); } } } return os << v; } // OlympusMakerNote::print0x0308 }} // namespace Internal, Exiv2 exiv2-0.23/src/mrwthumb.cpp0000644000175000017500000000244411037275510015454 0ustar andreasandreas// ***************************************************************** -*- C++ -*- // mrwthumb.cpp, $Rev: 1532 $ // Sample program to extract a Minolta thumbnail from the makernote #include "image.hpp" #include "exif.hpp" #include "error.hpp" #include int main(int argc, char* const argv[]) try { if (argc != 2) { std::cout << "Usage: " << argv[0] << " file\n"; return 1; } Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(argv[1]); assert(image.get() != 0); image->readMetadata(); Exiv2::ExifData &exifData = image->exifData(); if (exifData.empty()) { std::string error(argv[1]); error += ": No Exif data found in the file"; throw Exiv2::Error(1, error); } Exiv2::ExifKey key("Exif.Minolta.ThumbnailOffset"); Exiv2::ExifData::const_iterator format = exifData.findKey(key); if (format != exifData.end()) { Exiv2::DataBuf buf = format->dataArea(); // The first byte of the buffer needs to be patched buf.pData_[0] = 0xff; Exiv2::FileIo file("img_thumb.jpg"); file.open("wb"); file.write(buf.pData_, buf.size_); file.close(); } return 0; } catch (Exiv2::AnyError& e) { std::cout << "Caught Exiv2 exception '" << e << "'\n"; return -1; } exiv2-0.23/src/futils.cpp0000644000175000017500000000654711732641407015131 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /* File: futils.cpp Version: $Rev: 2681 $ Author(s): Andreas Huggel (ahu) History: 08-Dec-03, ahu: created 02-Apr-05, ahu: moved to Exiv2 namespace */ // ***************************************************************************** #include "rcsid_int.hpp" EXIV2_RCSID("@(#) $Id: futils.cpp 2681 2012-03-22 15:19:35Z ahuggel $") // ***************************************************************************** // included header files #ifdef _MSC_VER # include "exv_msvc.h" #else # include "exv_conf.h" #endif #include "futils.hpp" // + standard includes #include #include #ifdef _MSC_VER # define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) #endif #ifdef EXV_HAVE_UNISTD_H # include // for stat() #endif #include #include #include #if defined EXV_HAVE_STRERROR_R && !defined EXV_HAVE_DECL_STRERROR_R # ifdef EXV_STRERROR_R_CHAR_P extern char *strerror_r(int errnum, char *buf, size_t n); # else extern int strerror_r(int errnum, char *buf, size_t n); # endif #endif namespace Exiv2 { // ***************************************************************************** // free functions bool fileExists(const std::string& path, bool ct) { struct stat buf; int ret = ::stat(path.c_str(), &buf); if (0 != ret) return false; if (ct && !S_ISREG(buf.st_mode)) return false; return true; } // fileExists #ifdef EXV_UNICODE_PATH bool fileExists(const std::wstring& wpath, bool ct) { struct _stat buf; int ret = _wstat(wpath.c_str(), &buf); if (0 != ret) return false; if (ct && !S_ISREG(buf.st_mode)) return false; return true; } // fileExists #endif std::string strError() { int error = errno; std::ostringstream os; #ifdef EXV_HAVE_STRERROR_R const size_t n = 1024; // _GNU_SOURCE: See Debian bug #485135 # if defined EXV_STRERROR_R_CHAR_P && defined _GNU_SOURCE char *buf = 0; char buf2[n]; std::memset(buf2, 0x0, n); buf = strerror_r(error, buf2, n); # else char buf[n]; std::memset(buf, 0x0, n); strerror_r(error, buf, n); # endif os << buf; #else os << std::strerror(error); #endif os << " (errno = " << error << ")"; return os.str(); } // strError } // namespace Exiv2 exiv2-0.23/src/mrwimage.cpp0000644000175000017500000001327211732641407015424 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /* File: mrwimage.cpp Version: $Rev: 2681 $ Author(s): Andreas Huggel (ahu) History: 13-May-06, ahu: created Credits: See header file */ // ***************************************************************************** #include "rcsid_int.hpp" EXIV2_RCSID("@(#) $Id: mrwimage.cpp 2681 2012-03-22 15:19:35Z ahuggel $") // ***************************************************************************** // included header files #ifdef _MSC_VER # include "exv_msvc.h" #else # include "exv_conf.h" #endif #include "mrwimage.hpp" #include "tiffimage.hpp" #include "image.hpp" #include "basicio.hpp" #include "error.hpp" #include "futils.hpp" // + standard includes #include #include #include #include // ***************************************************************************** // class member definitions namespace Exiv2 { MrwImage::MrwImage(BasicIo::AutoPtr io, bool /*create*/) : Image(ImageType::mrw, mdExif | mdIptc | mdXmp, io) { } // MrwImage::MrwImage std::string MrwImage::mimeType() const { return "image/x-minolta-mrw"; } int MrwImage::pixelWidth() const { ExifData::const_iterator imageWidth = exifData_.findKey(Exiv2::ExifKey("Exif.Image.ImageWidth")); if (imageWidth != exifData_.end() && imageWidth->count() > 0) { return imageWidth->toLong(); } return 0; } int MrwImage::pixelHeight() const { ExifData::const_iterator imageHeight = exifData_.findKey(Exiv2::ExifKey("Exif.Image.ImageLength")); if (imageHeight != exifData_.end() && imageHeight->count() > 0) { return imageHeight->toLong(); } return 0; } void MrwImage::setExifData(const ExifData& /*exifData*/) { // Todo: implement me! throw(Error(32, "Exif metadata", "MRW")); } void MrwImage::setIptcData(const IptcData& /*iptcData*/) { // Todo: implement me! throw(Error(32, "IPTC metadata", "MRW")); } void MrwImage::setComment(const std::string& /*comment*/) { // not supported throw(Error(32, "Image comment", "MRW")); } void MrwImage::readMetadata() { #ifdef DEBUG std::cerr << "Reading MRW file " << io_->path() << "\n"; #endif if (io_->open() != 0) { throw Error(9, io_->path(), strError()); } IoCloser closer(*io_); // Ensure that this is the correct image type if (!isMrwType(*io_, false)) { if (io_->error() || io_->eof()) throw Error(14); throw Error(3, "MRW"); } clearMetadata(); // Find the TTW block and read it into a buffer uint32_t const len = 8; byte tmp[len]; io_->read(tmp, len); uint32_t pos = len; uint32_t const end = getULong(tmp + 4, bigEndian); pos += len; if (pos > end) throw Error(14); io_->read(tmp, len); if (io_->error() || io_->eof()) throw Error(14); while (memcmp(tmp + 1, "TTW", 3) != 0) { uint32_t const siz = getULong(tmp + 4, bigEndian); pos += siz; if (pos > end) throw Error(14); io_->seek(siz, BasicIo::cur); if (io_->error() || io_->eof()) throw Error(14); pos += len; if (pos > end) throw Error(14); io_->read(tmp, len); if (io_->error() || io_->eof()) throw Error(14); } DataBuf buf(getULong(tmp + 4, bigEndian)); io_->read(buf.pData_, buf.size_); if (io_->error() || io_->eof()) throw Error(14); ByteOrder bo = TiffParser::decode(exifData_, iptcData_, xmpData_, buf.pData_, buf.size_); setByteOrder(bo); } // MrwImage::readMetadata void MrwImage::writeMetadata() { // Todo: implement me! throw(Error(31, "MRW")); } // MrwImage::writeMetadata // ************************************************************************* // free functions Image::AutoPtr newMrwInstance(BasicIo::AutoPtr io, bool create) { Image::AutoPtr image(new MrwImage(io, create)); if (!image->good()) { image.reset(); } return image; } bool isMrwType(BasicIo& iIo, bool advance) { const int32_t len = 4; byte buf[len]; iIo.read(buf, len); if (iIo.error() || iIo.eof()) { return false; } int rc = memcmp(buf, "\0MRM", 4); if (!advance || rc != 0) { iIo.seek(-len, BasicIo::cur); } return rc == 0; } } // namespace Exiv2 exiv2-0.23/src/sigmamn_int.hpp0000644000175000017500000000541511732641407016126 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! @file sigmamn_int.hpp @brief Sigma and Foveon MakerNote implemented according to the specification SIGMA and FOVEON EXIF MakerNote Documentation by Foveon. @version $Rev: 2681 $ @author Andreas Huggel (ahu) ahuggel@gmx.net @date 02-Apr-04, ahu: created */ #ifndef SIGMAMN_INT_HPP_ #define SIGMAMN_INT_HPP_ // ***************************************************************************** // included header files #include "tags.hpp" #include "types.hpp" // + standard includes #include #include #include // ***************************************************************************** // namespace extensions namespace Exiv2 { namespace Internal { // ***************************************************************************** // class definitions //! MakerNote for Sigma (Foveon) cameras class SigmaMakerNote { public: //! Return read-only list of built-in Sigma tags static const TagInfo* tagList(); //! @name Print functions for Sigma (Foveon) %MakerNote tags //@{ //! Strip the label from the value and print the remainder static std::ostream& printStripLabel(std::ostream& os, const Value& value, const ExifData*); //! Print exposure mode static std::ostream& print0x0008(std::ostream& os, const Value& value, const ExifData*); //! Print metering mode static std::ostream& print0x0009(std::ostream& os, const Value& value, const ExifData*); //@} private: //! Tag information static const TagInfo tagInfo_[]; }; // class SigmaMakerNote }} // namespace Internal, Exiv2 #endif // #ifndef SIGMAMN_INT_HPP_ exiv2-0.23/src/exiv2.10000644000175000017500000003643211733051561014227 0ustar andreasandreas.\" Hey, EMACS: -*- nroff -*- .\" @(#) $Id: exiv2.1 2687 2012-03-23 10:41:53Z ahuggel $ .\" First parameter, NAME, should be all caps .\" Second parameter, SECTION, should be 1-8, maybe w/ subsection .\" other parameters are allowed: see man(7), man(1) .TH EXIV2 1 "Mar 23, 2012" .\" Please adjust this date whenever revising the manpage. .\" .\" Some roff macros, for reference: .\" .nh disable hyphenation .\" .hy enable hyphenation .\" .ad l left justify .\" .ad b justify to both left and right margins .\" .nf disable filling .\" .fi enable filling .\" .br insert line break .\" .sp insert n+1 empty lines .\" for manpage-specific macros, see man(7) .SH NAME exiv2 \- Image metadata manipulation tool .SH SYNOPSIS .B exiv2 [\fIoptions\fP] [\fIaction\fP] \fIfile\fP ... .br .SH DESCRIPTION .PP .\" TeX users may be more comfortable with the \fB\fP and .\" \fI\fP escape sequences to invode bold face and italics, .\" respectively. .B exiv2 is a program to read and write Exif, IPTC and XMP image metadata and image comments. The following image formats are supported: .TS lB lB lB lB lB _ _ _ _ _ l l l l l. Type Exif IPTC XMP Image comments JPEG Read/Write Read/Write Read/Write Read/Write EXV Read/Write Read/Write Read/Write Read/Write CR2 Read/Write Read/Write Read/Write - CRW Read/Write - - Read/Write MRW Read Read Read - TIFF Read/Write Read/Write Read/Write - DNG Read/Write Read/Write Read/Write - NEF Read/Write Read/Write Read/Write - PEF Read/Write Read/Write Read/Write - ARW Read Read Read - RW2 Read Read Read - SR2 Read Read Read - SRW Read/Write Read/Write Read/Write - ORF Read/Write Read/Write Read/Write - PNG Read/Write Read/Write Read/Write Read/Write PGF Read/Write Read/Write Read/Write Read/Write RAF Read Read Read - EPS - - Read/Write - XMP - - Read/Write - GIF - - - - PSD Read/Write Read/Write Read/Write - TGA - - - - BMP - - - - JP2 Read/Write Read/Write Read/Write - .TE .IP \(bu 2 Support for GIF, TGA and BMP images is minimal: the image format is recognized, a MIME type assigned to it and the height and width of the image are determined. .IP \(bu 2 Reading other TIFF-like RAW image formats, which are not listed in the table, may also work. .SH ACTIONS The \fIaction\fP argument is only required if it is not clear from the \fIoptions\fP which action is implied. .TP .B pr | print Print image metadata. This is the default action, i.e., the command \fIexiv2 image.jpg\fP will print a summary of the image Exif metadata. .TP .B ex | extract Extract metadata to *.exv, XMP sidecar (*.xmp) and thumbnail image files. Modification commands can be applied on-the-fly. .TP .B in | insert Insert metadata from corresponding *.exv, XMP sidecar (*.xmp) and thumbnail files. Use option \fB\-S\fP \fI.suf\fP to change the suffix of the input files. Since files of any supported format can be used as input files, this command can be used to copy the metadata between files of different formats. Modification commands can be applied on-the-fly. .TP .B rm | delete Delete image metadata from the files. .TP .B ad | adjust Adjust Exif timestamps by the given time. Requires at least one of the options \fB\-a\fP \fItime\fP, \fB\-Y\fP \fIyrs\fP, \fB\-O\fP \fImon\fP or \fB\-D\fP \fIday\fP. .TP .B mo | modify Apply commands to modify (add, set, delete) the Exif, IPTC and XMP metadata of image files. Requires option \fB\-c\fP, \fB\-m\fP or \fB\-M\fP. .TP .B mv | rename Rename files and/or set file timestamps according to the Exif create timestamp. Uses the value of tag Exif.Photo.DateTimeOriginal or, if not present, Exif.Image.DateTime to determine the timestamp. The filename format can be set with \fB\-r\fP \fIfmt\fP, timestamp options are \fB\-t\fP and \fB\-T\fP. .TP .B fi | fixiso Copy the ISO setting from one of the proprietary Nikon or Canon makernote ISO tags to the regular Exif ISO tag, Exif.Photo.ISOSpeedRatings. Does not overwrite an existing standard Exif ISO tag. .TP .B fc | fixcom Fix the character encoding of Exif Unicode user comments. Decodes the comment using the auto-detected or specified character encoding and writes it back in UCS-2. Use option \fB\-n\fP to specify the current encoding of the comment if necessary. .SH OPTIONS .TP .B \-h Display help and exit. .TP .B \-V Show the program version and exit. .TP .B \-v Be verbose during the program run. .TP .B \-q Silence warnings and error messages from the Exiv2 library during the program run (quiet). Note that options \fB\-v\fP and \fB\-q\fP can be used at the same time. .TP .B \-Q \fIlvl\fP Set the log-level to 'd'(ebug), 'i'(nfo), 'w'(arning), 'e'(rror) or 'm'(ute). The default log-level is 'w'. \fB\-Qm\fP is equivalent to \fB\-q\fP. All log messages are written to standard error. .TP .B \-b Show large binary values (default is to suppress them). .TP .B \-u Show unknown tags (default is to suppress tags which don't have a name). .TP .B \-g \fIkey\fP Only output info for this Exiv2 key (grep). Multiple \fB\-g\fP options can be used to grep info for several keys. .TP .B \-n \fIenc\fP Charset to use to decode Exif Unicode user comments. \fIenc\fP is a name understood by \fBiconv_open\fP(3), e.g., 'UTF-8'. .TP .B \-k Preserve file timestamps when updating files (keep). Can be used with all options which update files. The flag is ignored by read-only options. .TP .B \-t Set the file timestamp according to the Exif create timestamp in addition to renaming the file (overrides \fB\-k\fP). This option is only used with the 'rename' action. .TP .B \-T Only set the file timestamp according to the Exif create timestamp, do not rename the file (overrides \fB\-k\fP). This option is only used with the 'rename' action. Note: On Windows you may have to set the TZ environment variable for this option to work correctly. .TP .B \-f Do not prompt before overwriting existing files (force overwrite). .TP .B \-F Do not prompt before renaming files (Force rename). Appends '_1' ('_2', ...) to the name of the new file. .TP .B \-a \fItime\fP Time adjustment in the format [\-]HH[:MM[:SS]]. This option is only used with the 'adjust' action. Examples: 1 adds one hour, 1:01 adds one hour and one minute, \-0:00:30 subtracts 30 seconds. .TP .B \-Y \fIyrs\fP Time adjustment by a positive or negative number of years, for the 'adjust' action. .TP .B \-O \fImon\fP Time adjustment by a positive or negative number of months, for the 'adjust' action. .TP .B \-D \fIday\fP Time adjustment by a positive or negative number of days, for the 'adjust' action. .TP .B \-p \fImode\fP Print mode for the 'print' action. Possible modes are: .br s : print a summary of the Exif metadata (the default) .br a : print Exif, IPTC and XMP metadata (shortcut for -Pkyct) .br t : interpreted (translated) Exif tags (-PEkyct) .br v : plain Exif tag values (-PExgnycv) .br h : hexdump of the Exif data (-PExgnycsh) .br i : IPTC datasets (-PIkyct) .br x : XMP properties (-PXkyct) .br c : JPEG comment .br p : list available image previews, sorted by preview image size in pixels .TP .B \-P \fIflgs\fP Print flags for fine control of the tag list ('print' action). Allows control of the type of metadata as well as data columns included in the print output. Valid flags are: .br E : include Exif tags in the list .br I : IPTC datasets .br X : XMP properties .br x : print a column with the tag number .br g : group name .br k : key .br l : tag label .br n : tag name .br y : type .br c : number of components (count) .br s : size in bytes .br v : plain data value .br t : interpreted (translated) data .br h : hexdump of the data .TP .B \-d \fItgt\fP Delete target(s) for the 'delete' action. Possible targets are: .br a : all supported metadata (the default) .br e : Exif section .br t : Exif thumbnail only .br i : IPTC data .br x : XMP packet .br c : JPEG comment .TP .B \-i \fItgt\fP Insert target(s) for the 'insert' action. Possible targets are the same as those for the \fB\-d\fP option, plus a modifier: .br X : Insert metadata from an XMP sidecar file .xmp. The remaining insert targets determine what metadata to insert from the sidecar file. Possible are Exif, IPTC and XMP and the default is all of these. Note that the inserted XMP properties include those converted to Exif and IPTC. .br Only JPEG thumbnails can be inserted (not TIFF thumbnails), they need to be named \fIfile\fP\-thumb.jpg. .TP .B \-e \fItgt\fP Extract target(s) for the 'extract' action. Possible targets are the same as those for the \fB\-d\fP option, plus a target to extract preview images and a modifier to generate an XMP sidecar file: .br p[[, ...]] : Extract preview images. The optional comma separated list of preview image numbers is used to determine which preview images to extract. The available preview images and their numbers are displayed with the 'print' option -pp. .br X : Extract metadata to an XMP sidecar file .xmp. The remaining extract targets determine what metadata to extract to the sidecar file. Possible are Exif, IPTC and XMP and the default is all of these. .TP .B \-r \fIfmt\fP Filename format for the 'rename' action. The format string follows \fBstrftime\fP(3) and supports the following keywords: .br :basename: - original filename without extension .br :dirname: - name of the directory holding the original file .br :parentname: - name of parent directory .br Default filename format is %Y%m%d_%H%M%S. .TP .B \-c \fItxt\fP JPEG comment string to set in the image ('modify' action). This option can also be used with the 'extract' and 'insert' actions to modify metadata on-the-fly. .TP .B \-m \fIfile\fP Command file for the 'modify' action. This option can also be used with the 'extract' and 'insert' actions to modify metadata on-the-fly. .TP .B \-M \fIcmd\fP Command line for the 'modify' action. This option can also be used with the 'extract' and 'insert' actions to modify metadata on-the-fly. The format for the commands is the same as that of the lines of a command file. .TP .B \-l \fIdir\fP Location (directory) for files to be inserted or extracted. .TP .B \-S \fI.suf\fP Use suffix \fI.suf\fP for source files in 'insert' action. .SH COMMANDS Commands for the 'modify' action can be read from a command file, e.g., .sp 1 .nf exiv2 \-m cmd.txt image.jpg .fi .sp 1 or given on the command line, as in .sp 1 .nf exiv2 \-M"add Iptc.Application2.Credit String Mr. Smith" image.jpg .fi .sp 1 Note the quotes. Multiple \fB\-m\fP and \fB\-M\fP options can be combined. .sp 1 When writing Exif, IPTC and XMP metadata, .B exiv2 enforces only a correct metadata structure. It is possible to write tags with types and values different from those specified in the standards, duplicate Exif tags, undefined tags, or incomplete metadata. While .B exiv2 is able to read all metadata that it can write, other programs may have difficulties with images that contain non standard\-conforming metadata. .SS Command format The format of a command is .sp 1 .nf \fBset | add | del\fP \fIkey\fP [[\fItype\fP] \fIvalue\fP] .fi .TP .B set Set the \fIvalue\fP of an existing tag with a matching \fIkey\fP or add the tag. .TP .B add Add a tag (unless \fIkey\fP is a non\-repeatable IPTC key; nothing prevents you from adding duplicate Exif tags). .TP .B del Delete all occurrences of a tag (requires only a \fIkey\fP). .TP .I key Exiv2 Exif, IPTC or XMP key. .TP .I type .B Byte | Ascii | Short | Long | Rational | Undefined | SShort | SLong | SRational | Comment for Exif keys, .br .B String | Date | Time | Short | Undefined for IPTC keys, and .br .B XmpText | XmpAlt | XmpBag | XmpSeq | LangAlt for XMP keys. .sp 1 A default \fItype\fP is used if none is explicitly given. The default is determined based on \fIkey\fP. .TP .I value The remaining text on the line is the value. It can optionally be enclosed in single quotes ('\fIvalue\fP') or double quotes ("\fIvalue\fP"). .sp 1 The value is optional. Not providing any value is equivalent to an empty value ("") and is mainly useful to create an XMP array property, e.g., a bag. .sp 1 The format of Exif \fBComment\fP values includes an optional charset specification at the beginning: .sp 1 .B [charset=Ascii|Jis|Unicode|Undefined ]\fIcomment\fP .sp 1 .B Undefined is used by default if the value doesn't start with a charset definition. .sp 1 The format for IPTC \fBDate\fP values is YYYY\-MM\-DD (year, month, day), that for IPTC \fBTime\fP values is HH:MM:SS+|\-HH:MM, where HH:MM:SS refers to local hour, minute and seconds and +|\-HH:MM refers to hours and minutes ahead or behind Universal Coordinated Time (+|\- means either a + or a \- sign is required). .sp 1 The format of XMP \fBLangAlt\fP values includes an optional language qualifier: .sp 1 .B [lang=\fIlanguage-code\fP ]\fItext\fP .sp 1 .B x-default is used by default if the value doesn't start with a language qualifier. .TP An additional command is available to register XMP namespaces: .TP .nf \fBreg\fP \fIprefix\fP \fInamespace\fP .fi .SS Command file format Empty lines and lines starting with \fB#\fP in a command file are ignored (comments). Remaining lines are commands as described above. .SH EXAMPLES .TP exiv2 *.jpg Prints a summary of the Exif information for all JPEG files in the directory. .TP exiv2 -pi image.jpg Prints the IPTC metadata of the image. .TP exiv2 rename img_1234.jpg Renames img_1234.jpg (taken on 13\-Nov\-05 at 22:58:31) to 20051113_225831.jpg .TP exiv2 -r':basename:_%Y%m' rename img_1234.jpg Renames img_1234.jpg to img_1234_200511.jpg .TP exiv2 \-et img1.jpg img2.jpg Extracts the Exif thumbnails from the two files into img1\-thumb.jpg and img2\-thumb.jpg. .TP exiv2 \-it img1.jpg img2.jpg Inserts (copies) metadata from img1.exv to img1.jpg and from img2.exv to img2.jpg. .TP exiv2 \-ep1,2 image.jpg Extracts previews 1 and 2 from the image to the files image\-preview1.jpg and image\-preview2.jpg. .TP exiv2 \-eiX image.jpg Extracts IPTC datasets into an XMP sidecar file image.xmp and in the process converts them to "IPTC Core" XMP schema. .TP exiv2 \-iixX image.jpg Inserts IPTC and XMP metadata from an XMP sidecar file image.xmp into image.jpg. The resulting IPTC datasets are converted from the "IPTC Core" XMP schema properties in the sidecar file to the older IPTC IIM4 format. The inserted XMP properties include those in the "IPTC Core" XMP schema. .TP .nf exiv2 \-M"set Exif.Photo.UserComment charset=Ascii New Exif comment" image.jpg .fi Sets the Exif comment to an ASCII string. .TP .nf exiv2 \-M"set Exif.GPSInfo.GPSLatitude 4/1 15/1 33/1" \\ \-M"set Exif.GPSInfo.GPSLatitudeRef N" image.jpg .fi Sets the latitude to 4 degrees, 15 minutes and 33 seconds north. The Exif standard stipulates that the GPSLatitude tag consists of three Rational numbers for the degrees, minutes and seconds of the latitude and GPSLatitudeRef contains either 'N' or 'S' for north or south latitude respectively. .TP .nf exiv2 insert -l/tmp -S.CRW /data/*.JPG .fi Copy all metadata from CRW files in the /tmp directory to JPG files with corresponding basenames in the /data directory. Note that this copies metadata as is, without any modifications to adapt it to the requirements of the target format. Some tags copied like this may not make sense in the target image. .SH SEE ALSO .TP .I http://www.exiv2.org/sample.html#modify Sample command files. .TP .I http://www.exiv2.org/metadata.html Taglists with \fIkey\fP and default \fItype\fP values. .SH AUTHORS .B exiv2 was written by Andreas Huggel . .PP This manual page was originally written by KELEMEN Peter , for the Debian project. exiv2-0.23/src/value.cpp0000644000175000017500000007772211732641407014742 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /* File: value.cpp Version: $Rev: 2681 $ Author(s): Andreas Huggel (ahu) History: 26-Jan-04, ahu: created 11-Feb-04, ahu: isolated as a component 31-Jul-04, brad: added Time, Date and String values */ // ***************************************************************************** #include "rcsid_int.hpp" EXIV2_RCSID("@(#) $Id: value.cpp 2681 2012-03-22 15:19:35Z ahuggel $") // ***************************************************************************** // included header files #include "value.hpp" #include "types.hpp" #include "error.hpp" #include "convert.hpp" // + standard includes #include #include #include #include #include #include #include #include #include // ***************************************************************************** // class member definitions namespace Exiv2 { Value::Value(TypeId typeId) : ok_(true), type_(typeId) { } Value::~Value() { } Value& Value::operator=(const Value& rhs) { if (this == &rhs) return *this; type_ = rhs.type_; ok_ = rhs.ok_; return *this; } Value::AutoPtr Value::create(TypeId typeId) { AutoPtr value; switch (typeId) { case invalidTypeId: case signedByte: case unsignedByte: value = AutoPtr(new DataValue(typeId)); break; case asciiString: value = AutoPtr(new AsciiValue); break; case unsignedShort: value = AutoPtr(new ValueType); break; case unsignedLong: case tiffIfd: value = AutoPtr(new ValueType(typeId)); break; case unsignedRational: value = AutoPtr(new ValueType); break; case undefined: value = AutoPtr(new DataValue); break; case signedShort: value = AutoPtr(new ValueType); break; case signedLong: value = AutoPtr(new ValueType); break; case signedRational: value = AutoPtr(new ValueType); break; case tiffFloat: value = AutoPtr(new ValueType); break; case tiffDouble: value = AutoPtr(new ValueType); break; case string: value = AutoPtr(new StringValue); break; case date: value = AutoPtr(new DateValue); break; case time: value = AutoPtr(new TimeValue); break; case comment: value = AutoPtr(new CommentValue); break; case xmpText: value = AutoPtr(new XmpTextValue); break; case xmpBag: case xmpSeq: case xmpAlt: value = AutoPtr(new XmpArrayValue(typeId)); break; case langAlt: value = AutoPtr(new LangAltValue); break; default: value = AutoPtr(new DataValue(typeId)); break; } return value; } // Value::create int Value::setDataArea(const byte* /*buf*/, long /*len*/) { return -1; } std::string Value::toString() const { std::ostringstream os; write(os); ok_ = !os.fail(); return os.str(); } std::string Value::toString(long /*n*/) const { return toString(); } long Value::sizeDataArea() const { return 0; } DataBuf Value::dataArea() const { return DataBuf(0, 0); } DataValue::DataValue(TypeId typeId) : Value(typeId) { } DataValue::DataValue(const byte* buf, long len, ByteOrder byteOrder,TypeId typeId) : Value(typeId) { read(buf, len, byteOrder); } DataValue::~DataValue() { } long DataValue::count() const { return size(); } int DataValue::read(const byte* buf, long len, ByteOrder /*byteOrder*/) { // byteOrder not needed value_.assign(buf, buf + len); return 0; } int DataValue::read(const std::string& buf) { std::istringstream is(buf); int tmp; ValueType val; while (!(is.eof())) { is >> tmp; if (is.fail()) return 1; val.push_back(static_cast(tmp)); } value_.swap(val); return 0; } long DataValue::copy(byte* buf, ByteOrder /*byteOrder*/) const { // byteOrder not needed return static_cast( std::copy(value_.begin(), value_.end(), buf) - buf ); } long DataValue::size() const { return static_cast(value_.size()); } DataValue* DataValue::clone_() const { return new DataValue(*this); } std::ostream& DataValue::write(std::ostream& os) const { std::vector::size_type end = value_.size(); for (std::vector::size_type i = 0; i != end; ++i) { os << static_cast(value_[i]); if (i < end - 1) os << " "; } return os; } std::string DataValue::toString(long n) const { std::ostringstream os; os << static_cast(value_[n]); ok_ = !os.fail(); return os.str(); } long DataValue::toLong(long n) const { ok_ = true; return value_[n]; } float DataValue::toFloat(long n) const { ok_ = true; return value_[n]; } Rational DataValue::toRational(long n) const { ok_ = true; return Rational(value_[n], 1); } StringValueBase::StringValueBase(TypeId typeId) : Value(typeId) { } StringValueBase::StringValueBase(TypeId typeId, const std::string& buf) : Value(typeId) { read(buf); } StringValueBase::StringValueBase(const StringValueBase& rhs) : Value(rhs), value_(rhs.value_) { } StringValueBase::~StringValueBase() { } StringValueBase& StringValueBase::operator=(const StringValueBase& rhs) { if (this == &rhs) return *this; Value::operator=(rhs); value_ = rhs.value_; return *this; } int StringValueBase::read(const std::string& buf) { value_ = buf; return 0; } int StringValueBase::read(const byte* buf, long len, ByteOrder /*byteOrder*/) { // byteOrder not needed if (buf) value_ = std::string(reinterpret_cast(buf), len); return 0; } long StringValueBase::copy(byte* buf, ByteOrder /*byteOrder*/) const { if (value_.size() == 0) return 0; // byteOrder not needed assert(buf != 0); return static_cast( value_.copy(reinterpret_cast(buf), value_.size()) ); } long StringValueBase::count() const { return size(); } long StringValueBase::size() const { return static_cast(value_.size()); } std::ostream& StringValueBase::write(std::ostream& os) const { return os << value_; } long StringValueBase::toLong(long n) const { ok_ = true; return value_[n]; } float StringValueBase::toFloat(long n) const { ok_ = true; return value_[n]; } Rational StringValueBase::toRational(long n) const { ok_ = true; return Rational(value_[n], 1); } StringValue::StringValue() : StringValueBase(string) { } StringValue::StringValue(const std::string& buf) : StringValueBase(string, buf) { } StringValue::~StringValue() { } StringValue* StringValue::clone_() const { return new StringValue(*this); } AsciiValue::AsciiValue() : StringValueBase(asciiString) { } AsciiValue::AsciiValue(const std::string& buf) : StringValueBase(asciiString, buf) { } AsciiValue::~AsciiValue() { } int AsciiValue::read(const std::string& buf) { value_ = buf; if (value_.size() > 0 && value_[value_.size()-1] != '\0') value_ += '\0'; return 0; } AsciiValue* AsciiValue::clone_() const { return new AsciiValue(*this); } std::ostream& AsciiValue::write(std::ostream& os) const { // Strip all trailing '\0's (if any) std::string::size_type pos = value_.find_last_not_of('\0'); return os << value_.substr(0, pos + 1); } CommentValue::CharsetTable::CharsetTable(CharsetId charsetId, const char* name, const char* code) : charsetId_(charsetId), name_(name), code_(code) { } //! Lookup list of supported IFD type information const CommentValue::CharsetTable CommentValue::CharsetInfo::charsetTable_[] = { CharsetTable(ascii, "Ascii", "ASCII\0\0\0"), CharsetTable(jis, "Jis", "JIS\0\0\0\0\0"), CharsetTable(unicode, "Unicode", "UNICODE\0"), CharsetTable(undefined, "Undefined", "\0\0\0\0\0\0\0\0"), CharsetTable(invalidCharsetId, "InvalidCharsetId", "\0\0\0\0\0\0\0\0"), CharsetTable(lastCharsetId, "InvalidCharsetId", "\0\0\0\0\0\0\0\0") }; const char* CommentValue::CharsetInfo::name(CharsetId charsetId) { return charsetTable_[ charsetId < lastCharsetId ? charsetId : undefined ].name_; } const char* CommentValue::CharsetInfo::code(CharsetId charsetId) { return charsetTable_[ charsetId < lastCharsetId ? charsetId : undefined ].code_; } CommentValue::CharsetId CommentValue::CharsetInfo::charsetIdByName( const std::string& name) { int i = 0; for (; charsetTable_[i].charsetId_ != lastCharsetId && charsetTable_[i].name_ != name; ++i) {} return charsetTable_[i].charsetId_ == lastCharsetId ? invalidCharsetId : charsetTable_[i].charsetId_; } CommentValue::CharsetId CommentValue::CharsetInfo::charsetIdByCode( const std::string& code) { int i = 0; for (; charsetTable_[i].charsetId_ != lastCharsetId && std::string(charsetTable_[i].code_, 8) != code; ++i) {} return charsetTable_[i].charsetId_ == lastCharsetId ? invalidCharsetId : charsetTable_[i].charsetId_; } CommentValue::CommentValue() : StringValueBase(Exiv2::undefined), byteOrder_(littleEndian) { } CommentValue::CommentValue(const std::string& comment) : StringValueBase(Exiv2::undefined), byteOrder_(littleEndian) { read(comment); } CommentValue::~CommentValue() { } int CommentValue::read(const std::string& comment) { std::string c = comment; CharsetId charsetId = undefined; if (comment.length() > 8 && comment.substr(0, 8) == "charset=") { std::string::size_type pos = comment.find_first_of(' '); std::string name = comment.substr(8, pos-8); // Strip quotes (so you can also specify the charset without quotes) if (name[0] == '"') name = name.substr(1); if (name[name.length()-1] == '"') name = name.substr(0, name.length()-1); charsetId = CharsetInfo::charsetIdByName(name); if (charsetId == invalidCharsetId) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << Error(28, name) << "\n"; #endif return 1; } c.clear(); if (pos != std::string::npos) c = comment.substr(pos+1); } if (charsetId == unicode) { const char* to = byteOrder_ == littleEndian ? "UCS-2LE" : "UCS-2BE"; convertStringCharset(c, "UTF-8", to); } const std::string code(CharsetInfo::code(charsetId), 8); return StringValueBase::read(code + c); } int CommentValue::read(const byte* buf, long len, ByteOrder byteOrder) { byteOrder_ = byteOrder; return StringValueBase::read(buf, len, byteOrder); } long CommentValue::copy(byte* buf, ByteOrder byteOrder) const { std::string c = value_; if (charsetId() == unicode) { c = value_.substr(8); std::string::size_type sz = c.size(); if (byteOrder_ == littleEndian && byteOrder == bigEndian) { convertStringCharset(c, "UCS-2LE", "UCS-2BE"); assert(c.size() == sz); } else if (byteOrder_ == bigEndian && byteOrder == littleEndian) { convertStringCharset(c, "UCS-2BE", "UCS-2LE"); assert(c.size() == sz); } c = value_.substr(0, 8) + c; } if (c.size() == 0) return 0; assert(buf != 0); return static_cast(c.copy(reinterpret_cast(buf), c.size())); } std::ostream& CommentValue::write(std::ostream& os) const { CharsetId csId = charsetId(); if (csId != undefined) { os << "charset=\"" << CharsetInfo::name(csId) << "\" "; } return os << comment(); } std::string CommentValue::comment(const char* encoding) const { std::string c; if (value_.length() < 8) { return c; } c = value_.substr(8); if (charsetId() == unicode) { const char* from = encoding == 0 || *encoding == '\0' ? detectCharset(c) : encoding; convertStringCharset(c, from, "UTF-8"); } return c; } CommentValue::CharsetId CommentValue::charsetId() const { CharsetId charsetId = undefined; if (value_.length() >= 8) { const std::string code = value_.substr(0, 8); charsetId = CharsetInfo::charsetIdByCode(code); } return charsetId; } const char* CommentValue::detectCharset(std::string& c) const { // Interpret a BOM if there is one if (0 == strncmp(c.data(), "\xef\xbb\xbf", 3)) { c = c.substr(3); return "UTF-8"; } if (0 == strncmp(c.data(), "\xff\xfe", 2)) { c = c.substr(2); return "UCS-2LE"; } if (0 == strncmp(c.data(), "\xfe\xff", 2)) { c = c.substr(2); return "UCS-2BE"; } // Todo: Add logic to guess if the comment is encoded in UTF-8 return byteOrder_ == littleEndian ? "UCS-2LE" : "UCS-2BE"; } CommentValue* CommentValue::clone_() const { return new CommentValue(*this); } XmpValue::XmpValue(TypeId typeId) : Value(typeId), xmpArrayType_(xaNone), xmpStruct_(xsNone) { } XmpValue& XmpValue::operator=(const XmpValue& rhs) { if (this == &rhs) return *this; xmpArrayType_ = rhs.xmpArrayType_; xmpStruct_ = rhs.xmpStruct_; return *this; } void XmpValue::setXmpArrayType(XmpArrayType xmpArrayType) { xmpArrayType_ = xmpArrayType; } void XmpValue::setXmpStruct(XmpStruct xmpStruct) { xmpStruct_ = xmpStruct; } XmpValue::XmpArrayType XmpValue::xmpArrayType() const { return xmpArrayType_; } XmpValue::XmpArrayType XmpValue::xmpArrayType(TypeId typeId) { XmpArrayType xa = xaNone; switch (typeId) { case xmpAlt: xa = xaAlt; break; case xmpBag: xa = xaBag; break; case xmpSeq: xa = xaSeq; break; default: break; } return xa; } XmpValue::XmpStruct XmpValue::xmpStruct() const { return xmpStruct_; } long XmpValue::copy(byte* buf, ByteOrder /*byteOrder*/) const { std::ostringstream os; write(os); std::string s = os.str(); if (s.size() > 0) std::memcpy(buf, &s[0], s.size()); return static_cast(s.size()); } int XmpValue::read(const byte* buf, long len, ByteOrder /*byteOrder*/) { std::string s(reinterpret_cast(buf), len); return read(s); } long XmpValue::size() const { std::ostringstream os; write(os); return static_cast(os.str().size()); } XmpTextValue::XmpTextValue() : XmpValue(xmpText) { } XmpTextValue::XmpTextValue(const std::string& buf) : XmpValue(xmpText) { read(buf); } int XmpTextValue::read(const std::string& buf) { // support a type=Alt,Bag,Seq,Struct indicator std::string b = buf; std::string type; if (buf.length() > 5 && buf.substr(0, 5) == "type=") { std::string::size_type pos = buf.find_first_of(' '); type = buf.substr(5, pos-5); // Strip quotes (so you can also specify the type without quotes) if (type[0] == '"') type = type.substr(1); if (type[type.length()-1] == '"') type = type.substr(0, type.length()-1); b.clear(); if (pos != std::string::npos) b = buf.substr(pos+1); } if (!type.empty()) { if (type == "Alt") { setXmpArrayType(XmpValue::xaAlt); } else if (type == "Bag") { setXmpArrayType(XmpValue::xaBag); } else if (type == "Seq") { setXmpArrayType(XmpValue::xaSeq); } else if (type == "Struct") { setXmpStruct(); } else { throw Error(48, type); } } value_ = b; return 0; } XmpTextValue::AutoPtr XmpTextValue::clone() const { return AutoPtr(clone_()); } long XmpTextValue::size() const { return static_cast(value_.size()); } long XmpTextValue::count() const { return size(); } std::ostream& XmpTextValue::write(std::ostream& os) const { bool del = false; if (xmpArrayType() != XmpValue::xaNone) { switch (xmpArrayType()) { case XmpValue::xaAlt: os << "type=\"Alt\""; break; case XmpValue::xaBag: os << "type=\"Bag\""; break; case XmpValue::xaSeq: os << "type=\"Seq\""; break; case XmpValue::xaNone: break; // just to suppress the warning } del = true; } else if (xmpStruct() != XmpValue::xsNone) { switch (xmpStruct()) { case XmpValue::xsStruct: os << "type=\"Struct\""; break; case XmpValue::xsNone: break; // just to suppress the warning } del = true; } if (del && !value_.empty()) os << " "; return os << value_; } long XmpTextValue::toLong(long /*n*/) const { return parseLong(value_, ok_); } float XmpTextValue::toFloat(long /*n*/) const { return parseFloat(value_, ok_); } Rational XmpTextValue::toRational(long /*n*/) const { return parseRational(value_, ok_); } XmpTextValue* XmpTextValue::clone_() const { return new XmpTextValue(*this); } XmpArrayValue::XmpArrayValue(TypeId typeId) : XmpValue(typeId) { setXmpArrayType(xmpArrayType(typeId)); } int XmpArrayValue::read(const std::string& buf) { if (!buf.empty()) value_.push_back(buf); return 0; } XmpArrayValue::AutoPtr XmpArrayValue::clone() const { return AutoPtr(clone_()); } long XmpArrayValue::count() const { return static_cast(value_.size()); } std::ostream& XmpArrayValue::write(std::ostream& os) const { for (std::vector::const_iterator i = value_.begin(); i != value_.end(); ++i) { if (i != value_.begin()) os << ", "; os << *i; } return os; } std::string XmpArrayValue::toString(long n) const { ok_ = true; return value_[n]; } long XmpArrayValue::toLong(long n) const { return parseLong(value_[n], ok_); } float XmpArrayValue::toFloat(long n) const { return parseFloat(value_[n], ok_); } Rational XmpArrayValue::toRational(long n) const { return parseRational(value_[n], ok_); } XmpArrayValue* XmpArrayValue::clone_() const { return new XmpArrayValue(*this); } LangAltValue::LangAltValue() : XmpValue(langAlt) { } LangAltValue::LangAltValue(const std::string& buf) : XmpValue(langAlt) { read(buf); } int LangAltValue::read(const std::string& buf) { std::string b = buf; std::string lang = "x-default"; if (buf.length() > 5 && buf.substr(0, 5) == "lang=") { std::string::size_type pos = buf.find_first_of(' '); lang = buf.substr(5, pos-5); // Strip quotes (so you can also specify the language without quotes) if (lang[0] == '"') lang = lang.substr(1); if (lang[lang.length()-1] == '"') lang = lang.substr(0, lang.length()-1); b.clear(); if (pos != std::string::npos) b = buf.substr(pos+1); } value_[lang] = b; return 0; } LangAltValue::AutoPtr LangAltValue::clone() const { return AutoPtr(clone_()); } long LangAltValue::count() const { return static_cast(value_.size()); } std::ostream& LangAltValue::write(std::ostream& os) const { bool first = true; // Write the default entry first ValueType::const_iterator i = value_.find("x-default"); if (i != value_.end()) { os << "lang=\"" << i->first << "\" " << i->second; first = false; } for (i = value_.begin(); i != value_.end(); ++i) { if (i->first == "x-default") continue; if (!first) os << ", "; os << "lang=\"" << i->first << "\" " << i->second; first = false; } return os; } std::string LangAltValue::toString(long /*n*/) const { return toString("x-default"); } std::string LangAltValue::toString(const std::string& qualifier) const { ValueType::const_iterator i = value_.find(qualifier); if (i != value_.end()) { ok_ = true; return i->second; } ok_ = false; return ""; } long LangAltValue::toLong(long /*n*/) const { ok_ = false; return 0; } float LangAltValue::toFloat(long /*n*/) const { ok_ = false; return 0.0f; } Rational LangAltValue::toRational(long /*n*/) const { ok_ = false; return Rational(0, 0); } LangAltValue* LangAltValue::clone_() const { return new LangAltValue(*this); } DateValue::DateValue() : Value(date) { } DateValue::DateValue(int year, int month, int day) : Value(date) { date_.year = year; date_.month = month; date_.day = day; } DateValue::~DateValue() { } int DateValue::read(const byte* buf, long len, ByteOrder /*byteOrder*/) { // Hard coded to read Iptc style dates if (len != 8) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << Error(29) << "\n"; #endif return 1; } // Make the buffer a 0 terminated C-string for sscanf char b[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; std::memcpy(b, reinterpret_cast(buf), 8); int scanned = sscanf(b, "%4d%2d%2d", &date_.year, &date_.month, &date_.day); if (scanned != 3) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << Error(29) << "\n"; #endif return 1; } return 0; } int DateValue::read(const std::string& buf) { // Hard coded to read Iptc style dates if (buf.length() < 8) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << Error(29) << "\n"; #endif return 1; } int scanned = sscanf(buf.c_str(), "%4d-%d-%d", &date_.year, &date_.month, &date_.day); if (scanned != 3) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << Error(29) << "\n"; #endif return 1; } return 0; } void DateValue::setDate(const Date& src) { date_.year = src.year; date_.month = src.month; date_.day = src.day; } long DateValue::copy(byte* buf, ByteOrder /*byteOrder*/) const { // sprintf wants to add the null terminator, so use oversized buffer char temp[9]; int wrote = sprintf(temp, "%04d%02d%02d", date_.year, date_.month, date_.day); assert(wrote == 8); std::memcpy(buf, temp, 8); return 8; } const DateValue::Date& DateValue::getDate() const { return date_; } long DateValue::count() const { return size(); } long DateValue::size() const { return 8; } DateValue* DateValue::clone_() const { return new DateValue(*this); } std::ostream& DateValue::write(std::ostream& os) const { return os << date_.year << '-' << std::right << std::setw(2) << std::setfill('0') << date_.month << '-' << std::setw(2) << std::setfill('0') << date_.day; } long DateValue::toLong(long /*n*/) const { // Range of tm struct is limited to about 1970 to 2038 // This will return -1 if outside that range std::tm tms; std::memset(&tms, 0, sizeof(tms)); tms.tm_mday = date_.day; tms.tm_mon = date_.month - 1; tms.tm_year = date_.year - 1900; long l = static_cast(std::mktime(&tms)); ok_ = (l != -1); return l; } float DateValue::toFloat(long n) const { return static_cast(toLong(n)); } Rational DateValue::toRational(long n) const { return Rational(toLong(n), 1); } TimeValue::TimeValue() : Value(time) { } TimeValue::TimeValue(int hour, int minute, int second, int tzHour, int tzMinute) : Value(date) { time_.hour = hour; time_.minute = minute; time_.second = second; time_.tzHour = tzHour; time_.tzMinute = tzMinute; } TimeValue::~TimeValue() { } int TimeValue::read(const byte* buf, long len, ByteOrder /*byteOrder*/) { // Make the buffer a 0 terminated C-string for scanTime[36] char b[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; std::memcpy(b, reinterpret_cast(buf), (len < 12 ? len : 11)); // Hard coded to read HHMMSS or Iptc style times int rc = 1; if (len == 6) { // Try to read (non-standard) HHMMSS format rc = scanTime3(b, "%2d%2d%2d"); } if (len == 11) { rc = scanTime6(b, "%2d%2d%2d%1c%2d%2d"); } if (rc) { rc = 1; #ifndef SUPPRESS_WARNINGS EXV_WARNING << Error(30) << "\n"; #endif } return rc; } int TimeValue::read(const std::string& buf) { // Hard coded to read H:M:S or Iptc style times int rc = 1; if (buf.length() < 9) { // Try to read (non-standard) H:M:S format rc = scanTime3(buf.c_str(), "%d:%d:%d"); } else { rc = scanTime6(buf.c_str(), "%d:%d:%d%1c%d:%d"); } if (rc) { rc = 1; #ifndef SUPPRESS_WARNINGS EXV_WARNING << Error(30) << "\n"; #endif } return rc; } int TimeValue::scanTime3(const char* buf, const char* format) { int rc = 1; Time t; int scanned = sscanf(buf, format, &t.hour, &t.minute, &t.second); if ( scanned == 3 && t.hour >= 0 && t.hour < 24 && t.minute >= 0 && t.minute < 60 && t.second >= 0 && t.second < 60) { time_ = t; rc = 0; } return rc; } int TimeValue::scanTime6(const char* buf, const char* format) { int rc = 1; Time t; char plusMinus; int scanned = sscanf(buf, format, &t.hour, &t.minute, &t.second, &plusMinus, &t.tzHour, &t.tzMinute); if ( scanned == 6 && t.hour >= 0 && t.hour < 24 && t.minute >= 0 && t.minute < 60 && t.second >= 0 && t.second < 60 && t.tzHour >= 0 && t.tzHour < 24 && t.tzMinute >= 0 && t.tzMinute < 60) { time_ = t; if (plusMinus == '-') { time_.tzHour *= -1; time_.tzMinute *= -1; } rc = 0; } return rc; } void TimeValue::setTime( const Time& src ) { std::memcpy(&time_, &src, sizeof(time_)); } long TimeValue::copy(byte* buf, ByteOrder /*byteOrder*/) const { // sprintf wants to add the null terminator, so use oversized buffer char temp[12]; char plusMinus = '+'; if (time_.tzHour < 0 || time_.tzMinute < 0) plusMinus = '-'; int wrote = sprintf(temp, "%02d%02d%02d%1c%02d%02d", time_.hour, time_.minute, time_.second, plusMinus, abs(time_.tzHour), abs(time_.tzMinute)); assert(wrote == 11); std::memcpy(buf, temp, 11); return 11; } const TimeValue::Time& TimeValue::getTime() const { return time_; } long TimeValue::count() const { return size(); } long TimeValue::size() const { return 11; } TimeValue* TimeValue::clone_() const { return new TimeValue(*this); } std::ostream& TimeValue::write(std::ostream& os) const { char plusMinus = '+'; if (time_.tzHour < 0 || time_.tzMinute < 0) plusMinus = '-'; return os << std::right << std::setw(2) << std::setfill('0') << time_.hour << ':' << std::setw(2) << std::setfill('0') << time_.minute << ':' << std::setw(2) << std::setfill('0') << time_.second << plusMinus << std::setw(2) << std::setfill('0') << abs(time_.tzHour) << ':' << std::setw(2) << std::setfill('0') << abs(time_.tzMinute); } long TimeValue::toLong(long /*n*/) const { // Returns number of seconds in the day in UTC. long result = (time_.hour - time_.tzHour) * 60 * 60; result += (time_.minute - time_.tzMinute) * 60; result += time_.second; if (result < 0) { result += 86400; } ok_ = true; return result; } float TimeValue::toFloat(long n) const { return static_cast(toLong(n)); } Rational TimeValue::toRational(long n) const { return Rational(toLong(n), 1); } } // namespace Exiv2 exiv2-0.23/src/utiltest.cpp0000644000175000017500000000605311411621067015462 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* AUTHOR(S): Andreas Huggel (ahu) HISTORY: 10-Dec-03, ahu: created RCS information $Name: $ $Revision: 2286 $ */ // ***************************************************************************** #include "rcsid_int.hpp" EXIV2_RCSID("@(#) $Id: utiltest.cpp 2286 2010-06-27 10:04:39Z ahuggel $"); // ***************************************************************************** // included header files #include "utils.hpp" #include #include void testStrtol(); void testStrError(); void testPaths(); void testPath(const std::string& path); // ***************************************************************************** // Main int main(int argc, char* const argv[]) { testPaths(); return 0; } void testStrtol() { bool rc; long n(0); std::string s; s = "22"; rc = Util::strtol(s.c_str(), n); std::cout << "s = `" << s << "' rc = " << rc << " n = " << n << "\n"; s = "1"; rc = Util::strtol(s.c_str(), n); std::cout << "s = `" << s << "' rc = " << rc << " n = " << n << "\n"; s = "-22222222222222222"; rc = Util::strtol(s.c_str(), n); std::cout << "s = `" << s << "' rc = " << rc << " n = " << n << "\n"; s = "0x0"; rc = Util::strtol(0, n); std::cout << "s = `" << s << "' rc = " << rc << " n = " << n << "\n"; s = ""; rc = Util::strtol(s.c_str(), n); std::cout << "s = `" << s << "' rc = " << rc << " n = " << n << "\n"; s = "abc"; rc = Util::strtol(s.c_str(), n); std::cout << "s = `" << s << "' rc = " << rc << " n = " << n << "\n"; s = "1.2"; rc = Util::strtol(s.c_str(), n); std::cout << "s = `" << s << "' rc = " << rc << " n = " << n << "\n"; s = "12p"; rc = Util::strtol(s.c_str(), n); std::cout << "s = `" << s << "' rc = " << rc << " n = " << n << "\n"; } void testPaths() { std::string path; path = "/usr/lib"; testPath(path); path = "/usr/"; testPath(path); path = "usr"; testPath(path); path = "/"; testPath(path); path = "."; testPath(path); path = ".."; testPath(path); path = "///"; testPath(path); path = "/usr/.emacs"; testPath(path); path = "/usr/.emacs/"; testPath(path); path = "/usr/.emacs//"; testPath(path); path = "usr/.emacs"; testPath(path); path = ".emacs"; testPath(path); path = ".emacs.gz"; testPath(path); path = "/tmp/image.jpg"; testPath(path); path = "/tmp/.image.jpg"; testPath(path); path = "/image.jpg"; testPath(path); path = "image.jpg"; testPath(path); path = "image.jpg//"; testPath(path); path = "/////image.jpg"; testPath(path); path = "/foo.bar/image"; testPath(path); path = "/foo.bar/images.tar.gz"; testPath(path); path = "d:\\foo.bar\\images.tar.gz"; testPath(path); } void testPath(const std::string& path) { std::cout << std::setw(15) << path << " " << std::setw(15) << Util::dirname(path) << " " << std::setw(15) << Util::basename(path) << " " << std::setw(15) << Util::suffix(path) << "\n"; } exiv2-0.23/src/tgaimage.cpp0000644000175000017500000001377011732641407015375 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /* File: tgaimage.cpp Version: $Rev: 2681 $ Author(s): Marco Piovanelli, Ovolab (marco) History: 05-Mar-2007, marco: created */ // ***************************************************************************** #include "rcsid_int.hpp" EXIV2_RCSID("@(#) $Id: tgaimage.cpp 2681 2012-03-22 15:19:35Z ahuggel $") //#define DEBUG 1 // ***************************************************************************** // included header files #ifdef _MSC_VER # include "exv_msvc.h" #else # include "exv_conf.h" #endif #include "tgaimage.hpp" #include "image.hpp" #include "basicio.hpp" #include "error.hpp" #include "futils.hpp" // + standard includes #include #include #include // ***************************************************************************** // class member definitions namespace Exiv2 { TgaImage::TgaImage(BasicIo::AutoPtr io) : Image(ImageType::tga, mdNone, io) { } // TgaImage::TgaImage std::string TgaImage::mimeType() const { return "image/targa"; } void TgaImage::setExifData(const ExifData& /*exifData*/) { // Todo: implement me! throw(Error(32, "Exif metadata", "TGA")); } void TgaImage::setIptcData(const IptcData& /*iptcData*/) { // Todo: implement me! throw(Error(32, "IPTC metadata", "TGA")); } void TgaImage::setComment(const std::string& /*comment*/) { // not supported throw(Error(32, "Image comment", "TGA")); } void TgaImage::readMetadata() { #ifdef DEBUG std::cerr << "Exiv2::TgaImage::readMetadata: Reading TARGA file " << io_->path() << "\n"; #endif if (io_->open() != 0) { throw Error(9, io_->path(), strError()); } IoCloser closer(*io_); // Ensure that this is the correct image type if (!isTgaType(*io_, false)) { if (io_->error() || io_->eof()) throw Error(14); throw Error(3, "TGA"); } clearMetadata(); /* The TARGA header goes as follows -- all numbers are in little-endian byte order: offset length name description ====== ======= ======================= =========== 0 1 byte ID length length of image ID (0 to 255) 1 1 byte color map type 0 = no color map; 1 = color map included 2 1 byte image type 0 = no image; 1 = uncompressed color-mapped; 2 = uncompressed true-color; 3 = uncompressed black-and-white; 9 = RLE-encoded color mapped; 10 = RLE-encoded true-color; 11 = RLE-encoded black-and-white 3 5 bytes color map specification 8 2 bytes x-origin of image 10 2 bytes y-origin of image 12 2 bytes image width 14 2 bytes image height 16 1 byte pixel depth 17 1 byte image descriptor */ byte buf[18]; if (io_->read(buf, sizeof(buf)) == sizeof(buf)) { pixelWidth_ = getShort(buf + 12, littleEndian); pixelHeight_ = getShort(buf + 14, littleEndian); } } // TgaImage::readMetadata void TgaImage::writeMetadata() { // Todo: implement me! throw(Error(31, "TGA")); } // TgaImage::writeMetadata // ************************************************************************* // free functions Image::AutoPtr newTgaInstance(BasicIo::AutoPtr io, bool /*create*/) { Image::AutoPtr image(new TgaImage(io)); if (!image->good()) { image.reset(); } return image; } bool isTgaType(BasicIo& iIo, bool /*advance*/) { // not all TARGA files have a signature string, so first just try to match the file name extension #ifdef EXV_UNICODE_PATH std::wstring wpath = iIo.wpath(); if( wpath.rfind(EXV_WIDEN(".tga")) != std::wstring::npos || wpath.rfind(EXV_WIDEN(".TGA")) != std::wstring::npos) { return true; } #else std::string path = iIo.path(); if( path.rfind(".tga") != std::string::npos || path.rfind(".TGA") != std::string::npos) { return true; } #endif byte buf[26]; long curPos = iIo.tell(); iIo.seek(-26, BasicIo::end); if (iIo.error() || iIo.eof()) { return false; } iIo.read(buf, sizeof(buf)); if (iIo.error()) { return false; } // some TARGA files, but not all, have a signature string at the end bool matched = (memcmp(buf + 8, "TRUEVISION-XFILE", 16) == 0); iIo.seek(curPos, BasicIo::beg); return matched; } } // namespace Exiv2 exiv2-0.23/src/rcsid_int.hpp0000644000175000017500000000442411732641407015576 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! @file rcsid_int.hpp @brief Define an RCS id string in every object file compiled from a source file that includes rcsid_int.hpp. This is a simplified version of the ACE_RCSID macro that is used in the ACE(TM) distribution. @version $Rev: 2681 $ @author Andreas Huggel (ahu) ahuggel@gmx.net @date 02-Feb-04, ahu: created */ #ifndef RCSID_INT_HPP_ #define RCSID_INT_HPP_ #if !defined (EXIV2_RCSID) /*! @brief Macro to store version information in each object file. Use this macro by including the following two lines at the beginning of each *.cpp file. See the ident(1) manual pages for more information. @code #include "rcsid_int.hpp" EXIV2_RCSID("@(#) $Id$"); @endcode The macro hack itself has the following purposes: -# To define the RCS id string variable in the local namespace, so that there won't be any duplicate extern symbols at link time. -# To avoid warnings of the type "variable declared and never used". */ #define EXIV2_RCSID(id) \ namespace { \ inline const char* getRcsId(const char*) { return id ; } \ const char* rcsId = getRcsId(rcsId); \ } #endif // #if !defined (EXIV2_RCSID) #endif // #ifndef RCSID_INT_HPP_ exiv2-0.23/src/crwparse.cpp0000644000175000017500000000242011045347530015430 0ustar andreasandreas// ***************************************************************** -*- C++ -*- // crwparse.cpp, $Rev: 1560 $ // Print the CIFF structure of a CRW file #include "crwimage.hpp" #include "crwimage_int.hpp" #include "futils.hpp" #include int main(int argc, char* const argv[]) try { if (argc != 2) { std::cout << "Usage: " << argv[0] << " file\n"; std::cout << "Print the CIFF structure of a CRW file\n"; return 1; } Exiv2::FileIo io(argv[1]); if(io.open() != 0) { throw Exiv2::Error(9, io.path(), Exiv2::strError()); } Exiv2::IoCloser closer(io); // Ensure that this is a CRW image if (!Exiv2::isCrwType(io, false)) { if (io.error() || io.eof()) throw Exiv2::Error(14); throw Exiv2::Error(33); } // Read the image into a memory buffer long len = io.size(); Exiv2::DataBuf buf(len); io.read(buf.pData_, len); if (io.error() || io.eof()) throw Exiv2::Error(14); // Parse the image, starting with a CIFF header component Exiv2::Internal::CiffHeader::AutoPtr parseTree(new Exiv2::Internal::CiffHeader); parseTree->read(buf.pData_, buf.size_); parseTree->print(std::cout); return 0; } catch (Exiv2::AnyError& e) { std::cerr << e << "\n"; return -1; } exiv2-0.23/src/metacopy.hpp0000644000175000017500000000601011732641407015432 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! @file metacopy.hpp @brief Defines class Params, used for the command line handling @version $Rev: 2681 $ @author Brad Schick (brad) @date 13-Jul-04, brad: created */ #ifndef METACOPY_HPP_ #define METACOPY_HPP_ #include "utils.hpp" class Params : public Util::Getopt { private: std::string optstring_; bool first_; public: bool help_; //!< Help option flag. bool iptc_; //!< Iptc option flag. bool exif_; //!< Exif option flag. bool comment_; //!< JPEG comment option flag. bool xmp_; //!< XMP option flag. bool preserve_; //!< Preserve existing metadata option flag. std::string read_; //!< Source file std::string write_; //!< Destination file public: /*! @brief Default constructor. Note that optstring_ is initialized here. */ Params() : optstring_(":iecaph"), first_(true), help_(false), iptc_(false), exif_(false), comment_(false), xmp_(false), preserve_(false) {} /*! @brief Call Getopt::getopt() with optstring, to initiate command line argument parsing, perform consistency checks after all command line arguments are parsed. @param argc Argument count as passed to main() on program invocation. @param argv Argument array as passed to main() on program invocation. @return 0 if successful, >0 in case of errors. */ int getopt(int argc, char* const argv[]); //! Handle options and their arguments. virtual int option(int opt, const std::string& optarg, int optopt); //! Handle non-option parameters. virtual int nonoption(const std::string& argv); //! Print a minimal usage note to an output stream. void usage(std::ostream& os =std::cout) const; //! Print further usage explanations to an output stream. void help(std::ostream& os =std::cout) const; }; // class Params #endif // METACOPY_HPP_ exiv2-0.23/src/pngimage.cpp0000644000175000017500000003721511732641407015406 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /* File: pngimage.cpp Version: $Rev: 2681 $ Author(s): Gilles Caulier (cgilles) History: 12-Jun-06, gc: submitted Credits: See header file */ // ***************************************************************************** #include "rcsid_int.hpp" EXIV2_RCSID("@(#) $Id: pngimage.cpp 2681 2012-03-22 15:19:35Z ahuggel $") // ***************************************************************************** //#define DEBUG 1 // ***************************************************************************** // included header files #ifdef _MSC_VER # include "exv_msvc.h" #else # include "exv_conf.h" #endif #ifdef EXV_HAVE_LIBZ #include "pngchunk_int.hpp" #include "pngimage.hpp" #include "jpgimage.hpp" #include "image.hpp" #include "basicio.hpp" #include "error.hpp" #include "futils.hpp" // + standard includes #include #include #include #include // Signature from front of PNG file const unsigned char pngSignature[8] = { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A }; const unsigned char pngBlank[] = { 0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,0x00,0x00,0x00,0x0d,0x49,0x48,0x44,0x52, 0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x08,0x02,0x00,0x00,0x00,0x90,0x77,0x53, 0xde,0x00,0x00,0x00,0x01,0x73,0x52,0x47,0x42,0x00,0xae,0xce,0x1c,0xe9,0x00,0x00, 0x00,0x09,0x70,0x48,0x59,0x73,0x00,0x00,0x0b,0x13,0x00,0x00,0x0b,0x13,0x01,0x00, 0x9a,0x9c,0x18,0x00,0x00,0x00,0x0c,0x49,0x44,0x41,0x54,0x08,0xd7,0x63,0xf8,0xff, 0xff,0x3f,0x00,0x05,0xfe,0x02,0xfe,0xdc,0xcc,0x59,0xe7,0x00,0x00,0x00,0x00,0x49, 0x45,0x4e,0x44,0xae,0x42,0x60,0x82 }; // ***************************************************************************** // class member definitions namespace Exiv2 { using namespace Internal; PngImage::PngImage(BasicIo::AutoPtr io, bool create) : Image(ImageType::png, mdExif | mdIptc | mdXmp | mdComment, io) { if (create) { if (io_->open() == 0) { #ifdef DEBUG std::cerr << "Exiv2::PngImage:: Creating PNG image to memory\n"; #endif IoCloser closer(*io_); if (io_->write(pngBlank, sizeof(pngBlank)) != sizeof(pngBlank)) { #ifdef DEBUG std::cerr << "Exiv2::PngImage:: Failed to create PNG image on memory\n"; #endif } } } } // PngImage::PngImage std::string PngImage::mimeType() const { return "image/png"; } void PngImage::readMetadata() { #ifdef DEBUG std::cerr << "Exiv2::PngImage::readMetadata: Reading PNG file " << io_->path() << "\n"; #endif if (io_->open() != 0) { throw Error(9, io_->path(), strError()); } IoCloser closer(*io_); // Ensure that this is the correct image type if (!isPngType(*io_, true)) { if (io_->error() || io_->eof()) throw Error(14); throw Error(3, "PNG"); } clearMetadata(); DataBuf cheaderBuf(8); // Chunk header size : 4 bytes (data size) + 4 bytes (chunk type). while(!io_->eof()) { // Read chunk header. #ifdef DEBUG std::cout << "Exiv2::PngImage::readMetadata: Position: " << io_->tell() << "\n"; #endif std::memset(cheaderBuf.pData_, 0x0, cheaderBuf.size_); long bufRead = io_->read(cheaderBuf.pData_, cheaderBuf.size_); if (io_->error()) throw Error(14); if (bufRead != cheaderBuf.size_) throw Error(20); // Decode chunk data length. uint32_t dataOffset = Exiv2::getULong(cheaderBuf.pData_, Exiv2::bigEndian); if (dataOffset > 0x7FFFFFFF) throw Exiv2::Error(14); // Perform a chunk triage for item that we need. if (!memcmp(cheaderBuf.pData_ + 4, "IEND", 4) || !memcmp(cheaderBuf.pData_ + 4, "IHDR", 4) || !memcmp(cheaderBuf.pData_ + 4, "tEXt", 4) || !memcmp(cheaderBuf.pData_ + 4, "zTXt", 4) || !memcmp(cheaderBuf.pData_ + 4, "iTXt", 4)) { // Extract chunk data. DataBuf cdataBuf(dataOffset); bufRead = io_->read(cdataBuf.pData_, dataOffset); if (io_->error()) throw Error(14); if (bufRead != (long)dataOffset) throw Error(20); if (!memcmp(cheaderBuf.pData_ + 4, "IEND", 4)) { // Last chunk found: we stop parsing. #ifdef DEBUG std::cout << "Exiv2::PngImage::readMetadata: Found IEND chunk (length: " << dataOffset << ")\n"; #endif return; } else if (!memcmp(cheaderBuf.pData_ + 4, "IHDR", 4)) { #ifdef DEBUG std::cout << "Exiv2::PngImage::readMetadata: Found IHDR chunk (length: " << dataOffset << ")\n"; #endif PngChunk::decodeIHDRChunk(cdataBuf, &pixelWidth_, &pixelHeight_); } else if (!memcmp(cheaderBuf.pData_ + 4, "tEXt", 4)) { #ifdef DEBUG std::cout << "Exiv2::PngImage::readMetadata: Found tEXt chunk (length: " << dataOffset << ")\n"; #endif PngChunk::decodeTXTChunk(this, cdataBuf, PngChunk::tEXt_Chunk); } else if (!memcmp(cheaderBuf.pData_ + 4, "zTXt", 4)) { #ifdef DEBUG std::cout << "Exiv2::PngImage::readMetadata: Found zTXt chunk (length: " << dataOffset << ")\n"; #endif PngChunk::decodeTXTChunk(this, cdataBuf, PngChunk::zTXt_Chunk); } else if (!memcmp(cheaderBuf.pData_ + 4, "iTXt", 4)) { #ifdef DEBUG std::cout << "Exiv2::PngImage::readMetadata: Found iTXt chunk (length: " << dataOffset << ")\n"; #endif PngChunk::decodeTXTChunk(this, cdataBuf, PngChunk::iTXt_Chunk); } // Set dataOffset to null like chunk data have been extracted previously. dataOffset = 0; } // Move to the next chunk: chunk data size + 4 CRC bytes. #ifdef DEBUG std::cout << "Exiv2::PngImage::readMetadata: Seek to offset: " << dataOffset + 4 << "\n"; #endif io_->seek(dataOffset + 4 , BasicIo::cur); if (io_->error() || io_->eof()) throw Error(14); } } // PngImage::readMetadata void PngImage::writeMetadata() { if (io_->open() != 0) { throw Error(9, io_->path(), strError()); } IoCloser closer(*io_); BasicIo::AutoPtr tempIo(io_->temporary()); // may throw assert (tempIo.get() != 0); doWriteMetadata(*tempIo); // may throw io_->close(); io_->transfer(*tempIo); // may throw } // PngImage::writeMetadata void PngImage::doWriteMetadata(BasicIo& outIo) { if (!io_->isopen()) throw Error(20); if (!outIo.isopen()) throw Error(21); #ifdef DEBUG std::cout << "Exiv2::PngImage::doWriteMetadata: Writing PNG file " << io_->path() << "\n"; std::cout << "Exiv2::PngImage::doWriteMetadata: tmp file created " << outIo.path() << "\n"; #endif // Ensure that this is the correct image type if (!isPngType(*io_, true)) { if (io_->error() || io_->eof()) throw Error(20); throw Error(22); } // Write PNG Signature. if (outIo.write(pngSignature, 8) != 8) throw Error(21); DataBuf cheaderBuf(8); // Chunk header : 4 bytes (data size) + 4 bytes (chunk type). while(!io_->eof()) { // Read chunk header. std::memset(cheaderBuf.pData_, 0x00, cheaderBuf.size_); long bufRead = io_->read(cheaderBuf.pData_, cheaderBuf.size_); if (io_->error()) throw Error(14); if (bufRead != cheaderBuf.size_) throw Error(20); // Decode chunk data length. uint32_t dataOffset = getULong(cheaderBuf.pData_, bigEndian); if (dataOffset > 0x7FFFFFFF) throw Exiv2::Error(14); // Read whole chunk : Chunk header + Chunk data (not fixed size - can be null) + CRC (4 bytes). DataBuf chunkBuf(8 + dataOffset + 4); // Chunk header (8 bytes) + Chunk data + CRC (4 bytes). memcpy(chunkBuf.pData_, cheaderBuf.pData_, 8); // Copy header. bufRead = io_->read(chunkBuf.pData_ + 8, dataOffset + 4); // Extract chunk data + CRC if (io_->error()) throw Error(14); if (bufRead != (long)(dataOffset + 4)) throw Error(20); if (!memcmp(cheaderBuf.pData_ + 4, "IEND", 4)) { // Last chunk found: we write it and done. #ifdef DEBUG std::cout << "Exiv2::PngImage::doWriteMetadata: Write IEND chunk (length: " << dataOffset << ")\n"; #endif if (outIo.write(chunkBuf.pData_, chunkBuf.size_) != chunkBuf.size_) throw Error(21); return; } else if (!memcmp(cheaderBuf.pData_ + 4, "IHDR", 4)) { #ifdef DEBUG std::cout << "Exiv2::PngImage::doWriteMetadata: Write IHDR chunk (length: " << dataOffset << ")\n"; #endif if (outIo.write(chunkBuf.pData_, chunkBuf.size_) != chunkBuf.size_) throw Error(21); // Write all updated metadata here, just after IHDR. if (!comment_.empty()) { // Update Comment data to a new PNG chunk std::string chunk = PngChunk::makeMetadataChunk(comment_, mdComment); if (outIo.write((const byte*)chunk.data(), static_cast(chunk.size())) != (long)chunk.size()) { throw Error(21); } } if (exifData_.count() > 0) { // Update Exif data to a new PNG chunk Blob blob; ExifParser::encode(blob, littleEndian, exifData_); if (blob.size() > 0) { static const char exifHeader[] = { 0x45, 0x78, 0x69, 0x66, 0x00, 0x00 }; std::string rawExif = std::string(exifHeader, 6) + std::string((const char*)&blob[0], blob.size()); std::string chunk = PngChunk::makeMetadataChunk(rawExif, mdExif); if (outIo.write((const byte*)chunk.data(), static_cast(chunk.size())) != (long)chunk.size()) { throw Error(21); } } } if (iptcData_.count() > 0) { // Update IPTC data to a new PNG chunk DataBuf newPsData = Photoshop::setIptcIrb(0, 0, iptcData_); if (newPsData.size_ > 0) { std::string rawIptc((const char*)newPsData.pData_, newPsData.size_); std::string chunk = PngChunk::makeMetadataChunk(rawIptc, mdIptc); if (outIo.write((const byte*)chunk.data(), static_cast(chunk.size())) != (long)chunk.size()) { throw Error(21); } } } if (writeXmpFromPacket() == false) { if (XmpParser::encode(xmpPacket_, xmpData_) > 1) { #ifndef SUPPRESS_WARNINGS EXV_ERROR << "Failed to encode XMP metadata.\n"; #endif } } if (xmpPacket_.size() > 0) { // Update XMP data to a new PNG chunk std::string chunk = PngChunk::makeMetadataChunk(xmpPacket_, mdXmp); if (outIo.write((const byte*)chunk.data(), static_cast(chunk.size())) != (long)chunk.size()) { throw Error(21); } } } else if (!memcmp(cheaderBuf.pData_ + 4, "tEXt", 4) || !memcmp(cheaderBuf.pData_ + 4, "zTXt", 4) || !memcmp(cheaderBuf.pData_ + 4, "iTXt", 4)) { DataBuf key = PngChunk::keyTXTChunk(chunkBuf, true); if (memcmp("Raw profile type exif", key.pData_, 21) == 0 || memcmp("Raw profile type APP1", key.pData_, 21) == 0 || memcmp("Raw profile type iptc", key.pData_, 21) == 0 || memcmp("Raw profile type xmp", key.pData_, 20) == 0 || memcmp("XML:com.adobe.xmp", key.pData_, 17) == 0 || memcmp("Description", key.pData_, 11) == 0) { #ifdef DEBUG std::cout << "Exiv2::PngImage::doWriteMetadata: strip " << cheaderBuf.pData_ + 4 << " chunk (key: " << key.pData_ << ")\n"; #endif } else { #ifdef DEBUG std::cout << "Exiv2::PngImage::doWriteMetadata: write " << cheaderBuf.pData_ + 4 << " chunk (length: " << dataOffset << ")\n"; #endif if (outIo.write(chunkBuf.pData_, chunkBuf.size_) != chunkBuf.size_) throw Error(21); } } else { // Write all others chunk as well. #ifdef DEBUG std::cout << "Exiv2::PngImage::doWriteMetadata: write " << cheaderBuf.pData_ + 4 << " chunk (length: " << dataOffset << ")\n"; #endif if (outIo.write(chunkBuf.pData_, chunkBuf.size_) != chunkBuf.size_) throw Error(21); } } } // PngImage::doWriteMetadata // ************************************************************************* // free functions Image::AutoPtr newPngInstance(BasicIo::AutoPtr io, bool create) { Image::AutoPtr image(new PngImage(io, create)); if (!image->good()) { image.reset(); } return image; } bool isPngType(BasicIo& iIo, bool advance) { const int32_t len = 8; byte buf[len]; iIo.read(buf, len); if (iIo.error() || iIo.eof()) { return false; } int rc = memcmp(buf, pngSignature, 8); if (!advance || rc != 0) { iIo.seek(-len, BasicIo::cur); } return rc == 0; } } // namespace Exiv2 #endif exiv2-0.23/src/exif.cpp0000644000175000017500000007114611732641407014553 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /* File: exif.cpp Version: $Rev: 2681 $ Author(s): Andreas Huggel (ahu) History: 26-Jan-04, ahu: created 11-Feb-04, ahu: isolated as a component */ // ***************************************************************************** #include "rcsid_int.hpp" EXIV2_RCSID("@(#) $Id: exif.cpp 2681 2012-03-22 15:19:35Z ahuggel $") // ***************************************************************************** // included header files #ifdef _MSC_VER # include "exv_msvc.h" #else # include "exv_conf.h" #endif #include "exif.hpp" #include "metadatum.hpp" #include "tags.hpp" #include "tags_int.hpp" #include "value.hpp" #include "types.hpp" #include "error.hpp" #include "basicio.hpp" #include "tiffimage.hpp" #include "tiffimage_int.hpp" #include "tiffcomposite_int.hpp" // for Tag::root // + standard includes #include #include #include #include #include #include #include // ***************************************************************************** namespace { //! Unary predicate that matches a Exifdatum with a given key class FindExifdatumByKey { public: //! Constructor, initializes the object with the key to look for FindExifdatumByKey(const std::string& key) : key_(key) {} /*! @brief Returns true if the key of \em exifdatum is equal to that of the object. */ bool operator()(const Exiv2::Exifdatum& exifdatum) const { return key_ == exifdatum.key(); } private: const std::string& key_; }; // class FindExifdatumByKey /*! @brief Exif %Thumbnail image. This abstract base class provides the interface for the thumbnail image that is optionally embedded in the Exif data. This class is used internally by ExifData, it is probably not useful for a client as a standalone class. Instead, use an instance of ExifData to access the Exif thumbnail image. */ class Thumbnail { public: //! Shortcut for a %Thumbnail auto pointer. typedef std::auto_ptr AutoPtr; //! @name Creators //@{ //! Virtual destructor virtual ~Thumbnail() {} //@} //! Factory function to create a thumbnail for the Exif metadata provided. static AutoPtr create(const Exiv2::ExifData& exifData); //! @name Accessors //@{ /*! @brief Return the thumbnail image in a %DataBuf. The caller owns the data buffer and %DataBuf ensures that it will be deleted. */ virtual Exiv2::DataBuf copy(const Exiv2::ExifData& exifData) const =0; /*! @brief Return the MIME type of the thumbnail ("image/tiff" or "image/jpeg"). */ virtual const char* mimeType() const =0; /*! @brief Return the file extension for the format of the thumbnail (".tif", ".jpg"). */ virtual const char* extension() const =0; #ifdef EXV_UNICODE_PATH /*! @brief Like extension() but returns the extension in a wchar_t. @note This function is only available on Windows. */ virtual const wchar_t* wextension() const =0; #endif //@} }; // class Thumbnail //! Exif thumbnail image in TIFF format class TiffThumbnail : public Thumbnail { public: //! Shortcut for a %TiffThumbnail auto pointer. typedef std::auto_ptr AutoPtr; //! @name Manipulators //@{ //! Assignment operator. TiffThumbnail& operator=(const TiffThumbnail& rhs); //@} //! @name Accessors //@{ Exiv2::DataBuf copy(const Exiv2::ExifData& exifData) const; const char* mimeType() const; const char* extension() const; #ifdef EXV_UNICODE_PATH const wchar_t* wextension() const; #endif //@} }; // class TiffThumbnail //! Exif thumbnail image in JPEG format class JpegThumbnail : public Thumbnail { public: //! Shortcut for a %JpegThumbnail auto pointer. typedef std::auto_ptr AutoPtr; //! @name Manipulators //@{ //! Assignment operator. JpegThumbnail& operator=(const JpegThumbnail& rhs); //@} //! @name Accessors //@{ Exiv2::DataBuf copy(const Exiv2::ExifData& exifData) const; const char* mimeType() const; const char* extension() const; #ifdef EXV_UNICODE_PATH const wchar_t* wextension() const; #endif //@} }; // class JpegThumbnail //! Helper function to sum all components of the value of a metadatum long sumToLong(const Exiv2::Exifdatum& md); //! Helper function to delete all tags of a specific IFD from the metadata. void eraseIfd(Exiv2::ExifData& ed, Exiv2::Internal::IfdId ifdId); } // ***************************************************************************** // class member definitions namespace Exiv2 { using namespace Internal; /*! @brief Set the value of \em exifDatum to \em value. If the object already has a value, it is replaced. Otherwise a new ValueType\ value is created and set to \em value. This is a helper function, called from Exifdatum members. It is meant to be used with T = (u)int16_t, (u)int32_t or (U)Rational. Do not use directly. */ template Exiv2::Exifdatum& setValue(Exiv2::Exifdatum& exifDatum, const T& value) { std::auto_ptr > v = std::auto_ptr >(new Exiv2::ValueType); v->value_.push_back(value); exifDatum.value_ = v; return exifDatum; } Exifdatum::Exifdatum(const ExifKey& key, const Value* pValue) : key_(key.clone()) { if (pValue) value_ = pValue->clone(); } Exifdatum::~Exifdatum() { } Exifdatum::Exifdatum(const Exifdatum& rhs) : Metadatum(rhs) { if (rhs.key_.get() != 0) key_ = rhs.key_->clone(); // deep copy if (rhs.value_.get() != 0) value_ = rhs.value_->clone(); // deep copy } std::ostream& Exifdatum::write(std::ostream& os, const ExifData* pMetadata) const { if (value().count() == 0) return os; PrintFct fct = printValue; const TagInfo* ti = Internal::tagInfo(tag(), static_cast(ifdId())); if (ti != 0) fct = ti->printFct_; return fct(os, value(), pMetadata); } const Value& Exifdatum::value() const { if (value_.get() == 0) throw Error(8); return *value_; } Exifdatum& Exifdatum::operator=(const Exifdatum& rhs) { if (this == &rhs) return *this; Metadatum::operator=(rhs); key_.reset(); if (rhs.key_.get() != 0) key_ = rhs.key_->clone(); // deep copy value_.reset(); if (rhs.value_.get() != 0) value_ = rhs.value_->clone(); // deep copy return *this; } // Exifdatum::operator= Exifdatum& Exifdatum::operator=(const std::string& value) { setValue(value); return *this; } Exifdatum& Exifdatum::operator=(const uint16_t& value) { return Exiv2::setValue(*this, value); } Exifdatum& Exifdatum::operator=(const uint32_t& value) { return Exiv2::setValue(*this, value); } Exifdatum& Exifdatum::operator=(const URational& value) { return Exiv2::setValue(*this, value); } Exifdatum& Exifdatum::operator=(const int16_t& value) { return Exiv2::setValue(*this, value); } Exifdatum& Exifdatum::operator=(const int32_t& value) { return Exiv2::setValue(*this, value); } Exifdatum& Exifdatum::operator=(const Rational& value) { return Exiv2::setValue(*this, value); } Exifdatum& Exifdatum::operator=(const Value& value) { setValue(&value); return *this; } void Exifdatum::setValue(const Value* pValue) { value_.reset(); if (pValue) value_ = pValue->clone(); } int Exifdatum::setValue(const std::string& value) { if (value_.get() == 0) { TypeId type = key_->defaultTypeId(); value_ = Value::create(type); } return value_->read(value); } int Exifdatum::setDataArea(const byte* buf, long len) { return value_.get() == 0 ? -1 : value_->setDataArea(buf, len); } std::string Exifdatum::key() const { return key_.get() == 0 ? "" : key_->key(); } const char* Exifdatum::familyName() const { return key_.get() == 0 ? "" : key_->familyName(); } std::string Exifdatum::groupName() const { return key_.get() == 0 ? "" : key_->groupName(); } std::string Exifdatum::tagName() const { return key_.get() == 0 ? "" : key_->tagName(); } std::string Exifdatum::tagLabel() const { return key_.get() == 0 ? "" : key_->tagLabel(); } uint16_t Exifdatum::tag() const { return key_.get() == 0 ? 0xffff : key_->tag(); } int Exifdatum::ifdId() const { return key_.get() == 0 ? ifdIdNotSet : key_->ifdId(); } const char* Exifdatum::ifdName() const { return key_.get() == 0 ? "" : Internal::ifdName(static_cast(key_->ifdId())); } int Exifdatum::idx() const { return key_.get() == 0 ? 0 : key_->idx(); } long Exifdatum::copy(byte* buf, ByteOrder byteOrder) const { return value_.get() == 0 ? 0 : value_->copy(buf, byteOrder); } TypeId Exifdatum::typeId() const { return value_.get() == 0 ? invalidTypeId : value_->typeId(); } const char* Exifdatum::typeName() const { return TypeInfo::typeName(typeId()); } long Exifdatum::typeSize() const { return TypeInfo::typeSize(typeId()); } long Exifdatum::count() const { return value_.get() == 0 ? 0 : value_->count(); } long Exifdatum::size() const { return value_.get() == 0 ? 0 : value_->size(); } std::string Exifdatum::toString() const { return value_.get() == 0 ? "" : value_->toString(); } std::string Exifdatum::toString(long n) const { return value_.get() == 0 ? "" : value_->toString(n); } long Exifdatum::toLong(long n) const { return value_.get() == 0 ? -1 : value_->toLong(n); } float Exifdatum::toFloat(long n) const { return value_.get() == 0 ? -1 : value_->toFloat(n); } Rational Exifdatum::toRational(long n) const { return value_.get() == 0 ? Rational(-1, 1) : value_->toRational(n); } Value::AutoPtr Exifdatum::getValue() const { return value_.get() == 0 ? Value::AutoPtr(0) : value_->clone(); } long Exifdatum::sizeDataArea() const { return value_.get() == 0 ? 0 : value_->sizeDataArea(); } DataBuf Exifdatum::dataArea() const { return value_.get() == 0 ? DataBuf(0, 0) : value_->dataArea(); } ExifThumbC::ExifThumbC(const ExifData& exifData) : exifData_(exifData) { } DataBuf ExifThumbC::copy() const { Thumbnail::AutoPtr thumbnail = Thumbnail::create(exifData_); if (thumbnail.get() == 0) return DataBuf(); return thumbnail->copy(exifData_); } long ExifThumbC::writeFile(const std::string& path) const { Thumbnail::AutoPtr thumbnail = Thumbnail::create(exifData_); if (thumbnail.get() == 0) return 0; std::string name = path + thumbnail->extension(); DataBuf buf(thumbnail->copy(exifData_)); if (buf.size_ == 0) return 0; return Exiv2::writeFile(buf, name); } #ifdef EXV_UNICODE_PATH long ExifThumbC::writeFile(const std::wstring& wpath) const { Thumbnail::AutoPtr thumbnail = Thumbnail::create(exifData_); if (thumbnail.get() == 0) return 0; std::wstring name = wpath + thumbnail->wextension(); DataBuf buf(thumbnail->copy(exifData_)); if (buf.size_ == 0) return 0; return Exiv2::writeFile(buf, name); } #endif const char* ExifThumbC::mimeType() const { Thumbnail::AutoPtr thumbnail = Thumbnail::create(exifData_); if (thumbnail.get() == 0) return ""; return thumbnail->mimeType(); } const char* ExifThumbC::extension() const { Thumbnail::AutoPtr thumbnail = Thumbnail::create(exifData_); if (thumbnail.get() == 0) return ""; return thumbnail->extension(); } #ifdef EXV_UNICODE_PATH const wchar_t* ExifThumbC::wextension() const { Thumbnail::AutoPtr thumbnail = Thumbnail::create(exifData_); if (thumbnail.get() == 0) return EXV_WIDEN(""); return thumbnail->wextension(); } #endif ExifThumb::ExifThumb(ExifData& exifData) : ExifThumbC(exifData), exifData_(exifData) { } void ExifThumb::setJpegThumbnail( const std::string& path, URational xres, URational yres, uint16_t unit ) { DataBuf thumb = readFile(path); // may throw setJpegThumbnail(thumb.pData_, thumb.size_, xres, yres, unit); } #ifdef EXV_UNICODE_PATH void ExifThumb::setJpegThumbnail( const std::wstring& wpath, URational xres, URational yres, uint16_t unit ) { DataBuf thumb = readFile(wpath); // may throw setJpegThumbnail(thumb.pData_, thumb.size_, xres, yres, unit); } #endif void ExifThumb::setJpegThumbnail( const byte* buf, long size, URational xres, URational yres, uint16_t unit ) { setJpegThumbnail(buf, size); exifData_["Exif.Thumbnail.XResolution"] = xres; exifData_["Exif.Thumbnail.YResolution"] = yres; exifData_["Exif.Thumbnail.ResolutionUnit"] = unit; } void ExifThumb::setJpegThumbnail(const std::string& path) { DataBuf thumb = readFile(path); // may throw setJpegThumbnail(thumb.pData_, thumb.size_); } #ifdef EXV_UNICODE_PATH void ExifThumb::setJpegThumbnail(const std::wstring& wpath) { DataBuf thumb = readFile(wpath); // may throw setJpegThumbnail(thumb.pData_, thumb.size_); } #endif void ExifThumb::setJpegThumbnail(const byte* buf, long size) { exifData_["Exif.Thumbnail.Compression"] = uint16_t(6); Exifdatum& format = exifData_["Exif.Thumbnail.JPEGInterchangeFormat"]; format = uint32_t(0); format.setDataArea(buf, size); exifData_["Exif.Thumbnail.JPEGInterchangeFormatLength"] = uint32_t(size); } void ExifThumb::erase() { eraseIfd(exifData_, ifd1Id); } Exifdatum& ExifData::operator[](const std::string& key) { ExifKey exifKey(key); iterator pos = findKey(exifKey); if (pos == end()) { add(Exifdatum(exifKey)); pos = findKey(exifKey); } return *pos; } void ExifData::add(const ExifKey& key, const Value* pValue) { add(Exifdatum(key, pValue)); } void ExifData::add(const Exifdatum& exifdatum) { // allow duplicates exifMetadata_.push_back(exifdatum); } ExifData::const_iterator ExifData::findKey(const ExifKey& key) const { return std::find_if(exifMetadata_.begin(), exifMetadata_.end(), FindExifdatumByKey(key.key())); } ExifData::iterator ExifData::findKey(const ExifKey& key) { return std::find_if(exifMetadata_.begin(), exifMetadata_.end(), FindExifdatumByKey(key.key())); } void ExifData::clear() { exifMetadata_.clear(); } void ExifData::sortByKey() { exifMetadata_.sort(cmpMetadataByKey); } void ExifData::sortByTag() { exifMetadata_.sort(cmpMetadataByTag); } ExifData::iterator ExifData::erase(ExifData::iterator beg, ExifData::iterator end) { return exifMetadata_.erase(beg, end); } ExifData::iterator ExifData::erase(ExifData::iterator pos) { return exifMetadata_.erase(pos); } ByteOrder ExifParser::decode( ExifData& exifData, const byte* pData, uint32_t size ) { IptcData iptcData; XmpData xmpData; ByteOrder bo = TiffParser::decode(exifData, iptcData, xmpData, pData, size); #ifndef SUPPRESS_WARNINGS if (!iptcData.empty()) { EXV_WARNING << "Ignoring IPTC information encoded in the Exif data.\n"; } if (!xmpData.empty()) { EXV_WARNING << "Ignoring XMP information encoded in the Exif data.\n"; } #endif return bo; } // ExifParser::decode //! @cond IGNORE enum Ptt { pttLen, pttTag, pttIfd }; struct PreviewTags { Ptt ptt_; const char* key_; }; //! @endcond WriteMethod ExifParser::encode( Blob& blob, const byte* pData, uint32_t size, ByteOrder byteOrder, const ExifData& exifData ) { ExifData ed = exifData; // Delete IFD0 tags that are "not recorded" in compressed images // Reference: Exif 2.2 specs, 4.6.8 Tag Support Levels, section A static const char* filteredIfd0Tags[] = { "Exif.Image.PhotometricInterpretation", "Exif.Image.StripOffsets", "Exif.Image.RowsPerStrip", "Exif.Image.StripByteCounts", "Exif.Image.JPEGInterchangeFormat", "Exif.Image.JPEGInterchangeFormatLength", "Exif.Image.SubIFDs" }; for (unsigned int i = 0; i < EXV_COUNTOF(filteredIfd0Tags); ++i) { ExifData::iterator pos = ed.findKey(ExifKey(filteredIfd0Tags[i])); if (pos != ed.end()) { #ifdef DEBUG std::cerr << "Warning: Exif tag " << pos->key() << " not encoded\n"; #endif ed.erase(pos); } } // Delete IFDs which do not occur in JPEGs static const IfdId filteredIfds[] = { subImage1Id, subImage2Id, subImage3Id, subImage4Id, subImage5Id, subImage6Id, subImage7Id, subImage8Id, subImage9Id, subThumb1Id, panaRawId, ifd2Id, ifd3Id }; for (unsigned int i = 0; i < EXV_COUNTOF(filteredIfds); ++i) { #ifdef DEBUG std::cerr << "Warning: Exif IFD " << filteredIfds[i] << " not encoded\n"; #endif eraseIfd(ed, filteredIfds[i]); } // IPTC and XMP are stored elsewhere, not in the Exif APP1 segment. IptcData emptyIptc; XmpData emptyXmp; // Encode and check if the result fits into a JPEG Exif APP1 segment MemIo mio1; std::auto_ptr header(new TiffHeader(byteOrder, 0x00000008, false)); WriteMethod wm = TiffParserWorker::encode(mio1, pData, size, ed, emptyIptc, emptyXmp, Tag::root, TiffMapping::findEncoder, header.get(), 0); if (mio1.size() <= 65527) { append(blob, mio1.mmap(), mio1.size()); return wm; } // If it doesn't fit, remove additional tags // Delete preview tags if the preview is larger than 32kB. // Todo: Enhance preview classes to be able to write and delete previews and use that instead. // Table must be sorted by preview, the first tag in each group is the size static const PreviewTags filteredPvTags[] = { { pttLen, "Exif.Minolta.ThumbnailLength" }, { pttTag, "Exif.Minolta.ThumbnailOffset" }, { pttLen, "Exif.Minolta.Thumbnail" }, { pttLen, "Exif.NikonPreview.JPEGInterchangeFormatLength" }, { pttIfd, "NikonPreview" }, { pttLen, "Exif.Olympus.ThumbnailLength" }, { pttTag, "Exif.Olympus.ThumbnailOffset" }, { pttLen, "Exif.Olympus.ThumbnailImage" }, { pttLen, "Exif.Olympus.Thumbnail" }, { pttLen, "Exif.Olympus2.ThumbnailLength" }, { pttTag, "Exif.Olympus2.ThumbnailOffset" }, { pttLen, "Exif.Olympus2.ThumbnailImage" }, { pttLen, "Exif.Olympus2.Thumbnail" }, { pttLen, "Exif.OlympusCs.PreviewImageLength" }, { pttTag, "Exif.OlympusCs.PreviewImageStart" }, { pttTag, "Exif.OlympusCs.PreviewImageValid" }, { pttLen, "Exif.Pentax.PreviewLength" }, { pttTag, "Exif.Pentax.PreviewOffset" }, { pttTag, "Exif.Pentax.PreviewResolution" }, { pttLen, "Exif.Thumbnail.StripByteCounts" }, { pttIfd, "Thumbnail" }, { pttLen, "Exif.Thumbnail.JPEGInterchangeFormatLength" }, { pttIfd, "Thumbnail" } }; bool delTags = false; ExifData::iterator pos; for (unsigned int i = 0; i < EXV_COUNTOF(filteredPvTags); ++i) { switch (filteredPvTags[i].ptt_) { case pttLen: delTags = false; pos = ed.findKey(ExifKey(filteredPvTags[i].key_)); if (pos != ed.end() && sumToLong(*pos) > 32768) { delTags = true; #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Exif tag " << pos->key() << " not encoded\n"; #endif ed.erase(pos); } break; case pttTag: if (delTags) { pos = ed.findKey(ExifKey(filteredPvTags[i].key_)); if (pos != ed.end()) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Exif tag " << pos->key() << " not encoded\n"; #endif ed.erase(pos); } } break; case pttIfd: if (delTags) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Exif IFD " << filteredPvTags[i].key_ << " not encoded\n"; #endif eraseIfd(ed, Internal::groupId(filteredPvTags[i].key_)); } break; } } // Delete unknown tags larger than 4kB and known tags larger than 40kB. for (ExifData::iterator pos = ed.begin(); pos != ed.end(); ) { if ( (pos->size() > 4096 && pos->tagName().substr(0, 2) == "0x") || pos->size() > 40960) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Exif tag " << pos->key() << " not encoded\n"; #endif pos = ed.erase(pos); } else { ++pos; } } // Encode the remaining Exif tags again, don't care if it fits this time MemIo mio2; wm = TiffParserWorker::encode(mio2, pData, size, ed, emptyIptc, emptyXmp, Tag::root, TiffMapping::findEncoder, header.get(), 0); append(blob, mio2.mmap(), mio2.size()); #ifdef DEBUG if (wm == wmIntrusive) { std::cerr << "SIZE OF EXIF DATA IS " << std::dec << io.size() << " BYTES\n"; } else { std::cerr << "SIZE DOESN'T MATTER, NON-INTRUSIVE WRITING USED\n"; } #endif return wm; } // ExifParser::encode } // namespace Exiv2 // ***************************************************************************** // local definitions namespace { //! @cond IGNORE Thumbnail::AutoPtr Thumbnail::create(const Exiv2::ExifData& exifData) { Thumbnail::AutoPtr thumbnail; const Exiv2::ExifKey k1("Exif.Thumbnail.Compression"); Exiv2::ExifData::const_iterator pos = exifData.findKey(k1); if (pos != exifData.end()) { if (pos->count() == 0) return thumbnail; long compression = pos->toLong(); if (compression == 6) { thumbnail = Thumbnail::AutoPtr(new JpegThumbnail); } else { thumbnail = Thumbnail::AutoPtr(new TiffThumbnail); } } else { const Exiv2::ExifKey k2("Exif.Thumbnail.JPEGInterchangeFormat"); pos = exifData.findKey(k2); if (pos != exifData.end()) { thumbnail = Thumbnail::AutoPtr(new JpegThumbnail); } } return thumbnail; } const char* TiffThumbnail::mimeType() const { return "image/tiff"; } const char* TiffThumbnail::extension() const { return ".tif"; } #ifdef EXV_UNICODE_PATH const wchar_t* TiffThumbnail::wextension() const { return EXV_WIDEN(".tif"); } #endif Exiv2::DataBuf TiffThumbnail::copy(const Exiv2::ExifData& exifData) const { Exiv2::ExifData thumb; // Copy all Thumbnail (IFD1) tags from exifData to Image (IFD0) tags in thumb for (Exiv2::ExifData::const_iterator i = exifData.begin(); i != exifData.end(); ++i) { if (i->groupName() == "Thumbnail") { std::string key = "Exif.Image." + i->tagName(); thumb.add(Exiv2::ExifKey(key), &i->value()); } } Exiv2::MemIo io; Exiv2::IptcData emptyIptc; Exiv2::XmpData emptyXmp; Exiv2::TiffParser::encode(io, 0, 0, Exiv2::littleEndian, thumb, emptyIptc, emptyXmp); return io.read(io.size()); } const char* JpegThumbnail::mimeType() const { return "image/jpeg"; } const char* JpegThumbnail::extension() const { return ".jpg"; } #ifdef EXV_UNICODE_PATH const wchar_t* JpegThumbnail::wextension() const { return EXV_WIDEN(".jpg"); } #endif Exiv2::DataBuf JpegThumbnail::copy(const Exiv2::ExifData& exifData) const { Exiv2::ExifKey key("Exif.Thumbnail.JPEGInterchangeFormat"); Exiv2::ExifData::const_iterator format = exifData.findKey(key); if (format == exifData.end()) return Exiv2::DataBuf(); return format->dataArea(); } long sumToLong(const Exiv2::Exifdatum& md) { long sum = 0; for (int i = 0; i < md.count(); ++i) { sum += md.toLong(i); } return sum; } void eraseIfd(Exiv2::ExifData& ed, Exiv2::IfdId ifdId) { ed.erase(std::remove_if(ed.begin(), ed.end(), Exiv2::FindExifdatum(ifdId)), ed.end()); } //! @endcond } exiv2-0.23/src/properties.hpp0000644000175000017500000002725411742031570016015 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! @file properties.hpp @brief XMP property and type information.
References:
XMP Specification from Adobe (Property descriptions copied from the XMP specification with the permission of Adobe) @version $Rev: 2701 $ @author Andreas Huggel (ahu) ahuggel@gmx.net @author Gilles Caulier (cgilles) caulier dot gilles at gmail dot com @date 13-Jul-07, ahu: created */ #ifndef PROPERTIES_HPP_ #define PROPERTIES_HPP_ // ***************************************************************************** // included header files #include "types.hpp" #include "metadatum.hpp" #include "tags.hpp" // + standard includes #include #include #include // ***************************************************************************** // namespace extensions namespace Exiv2 { // ***************************************************************************** // class declarations class XmpKey; // ***************************************************************************** // class definitions //! Category of an XMP property enum XmpCategory { xmpInternal, xmpExternal }; //! Information about one XMP property. struct EXIV2API XmpPropertyInfo { //! Comparison operator for name bool operator==(const std::string& name) const; const char* name_; //!< Property name const char* title_; //!< Property title or label const char* xmpValueType_; //!< XMP value type (for info only) TypeId typeId_; //!< Exiv2 default type for the property XmpCategory xmpCategory_; //!< Category (internal or external) const char* desc_; //!< Property description }; //! Structure mapping XMP namespaces and (preferred) prefixes. struct EXIV2API XmpNsInfo { //! For comparison with prefix struct Prefix { //! Constructor. Prefix(const std::string& prefix); //! The prefix string. std::string prefix_; }; //! For comparison with namespace struct Ns { //! Constructor. Ns(const std::string& ns); //! The namespace string std::string ns_; }; //! Comparison operator for namespace bool operator==(const Ns& ns) const; //! Comparison operator for prefix bool operator==(const Prefix& prefix) const; const char* ns_; //!< Namespace const char* prefix_; //!< (Preferred) prefix const XmpPropertyInfo* xmpPropertyInfo_; //!< List of known properties const char* desc_; //!< Brief description of the namespace }; //! XMP property reference, implemented as a static class. class EXIV2API XmpProperties { //! Prevent construction: not implemented. XmpProperties(); //! Prevent copy-construction: not implemented. XmpProperties(const XmpProperties& rhs); //! Prevent assignment: not implemented. XmpProperties& operator=(const XmpProperties& rhs); public: /*! @brief Return the title (label) of the property. @param key The property key @return The title (label) of the property, 0 if the key is of an unknown property. */ static const char* propertyTitle(const XmpKey& key); /*! @brief Return the description of the property. @param key The property key @return The description of the property, 0 if the key is of an unknown property. */ static const char* propertyDesc(const XmpKey& key); /*! @brief Return the type for property \em key. The default for unknown keys is xmpText. @param key The property key @return The type of the property */ static TypeId propertyType(const XmpKey& key); /*! @brief Return information for the property for key. If the key is a path to a nested property (one which contains a slash, like \c Xmp.MP.RegionInfo/MPRI:Regions), determines the innermost element (\c Xmp.MPRI.Regions) and returns its property information. @param key The property key @return A pointer to the property information, 0 if the key is of an unknown property. */ static const XmpPropertyInfo* propertyInfo(const XmpKey& key); /*! @brief Return the namespace name for the schema associated with \em prefix. @param prefix Prefix @return The namespace name @throw Error if no namespace is registered with \em prefix. */ static std::string ns(const std::string& prefix); /*! @brief Return the namespace description for the schema associated with \em prefix. @param prefix Prefix @return The namespace description @throw Error if no namespace is registered with \em prefix. */ static const char* nsDesc(const std::string& prefix); /*! @brief Return read-only list of built-in properties for \em prefix. @param prefix Prefix @return Pointer to the built-in properties for prefix, may be 0 if none is configured in the namespace info. @throw Error if no namespace is registered with \em prefix. */ static const XmpPropertyInfo* propertyList(const std::string& prefix); /*! @brief Return information about a schema namespace for \em prefix. Always returns a valid pointer. @param prefix The prefix @return A pointer to the related information @throw Error if no namespace is registered with \em prefix. */ static const XmpNsInfo* nsInfo(const std::string& prefix); /*! @brief Return the (preferred) prefix for schema namespace \em ns. @param ns Schema namespace @return The prefix or an empty string if namespace \em ns is not registered. */ static std::string prefix(const std::string& ns); //! Print a list of properties of a schema namespace to output stream \em os. static void printProperties(std::ostream& os, const std::string& prefix); //! Interpret and print the value of an XMP property static std::ostream& printProperty(std::ostream& os, const std::string& key, const Value& value); /*! @brief Register namespace \em ns with preferred prefix \em prefix. If the prefix is a known or previously registered prefix, the corresponding namespace URI is overwritten. @note This invalidates XMP keys generated with the previous prefix. */ static void registerNs(const std::string& ns, const std::string& prefix); /*! @brief Unregister a custom namespace \em ns. The function only has an effect if there is a namespace \em ns registered earlier, it does not unregister built-in namespaces. @note This invalidates XMP keys generated in this namespace. */ static void unregisterNs(const std::string& ns); /*! @brief Unregister all custom namespaces. The function only unregisters namespaces registered earlier, it does not unregister built-in namespaces. @note This invalidates XMP keys generated in any custom namespace. */ static void unregisterNs(); //! Type for the namespace registry typedef std::map NsRegistry; /*! @brief Get the registered namespace for a specific \em prefix from the registry. */ static const XmpNsInfo* lookupNsRegistry(const XmpNsInfo::Prefix& prefix); // DATA static NsRegistry nsRegistry_; //!< Namespace registry }; // class XmpProperties /*! @brief Concrete keys for XMP metadata. */ class EXIV2API XmpKey : public Key { public: //! Shortcut for an %XmpKey auto pointer. typedef std::auto_ptr AutoPtr; //! @name Creators //@{ /*! @brief Constructor to create an XMP key from a key string. @param key The key string. @throw Error if the first part of the key is not 'Xmp' or the second part of the key cannot be parsed and converted to a known (i.e., built-in or registered) schema prefix. */ explicit XmpKey(const std::string& key); /*! @brief Constructor to create an XMP key from a schema prefix and a property name. @param prefix Schema prefix name @param property Property name @throw Error if the schema prefix is not known. */ XmpKey(const std::string& prefix, const std::string& property); //! Copy constructor. XmpKey(const XmpKey& rhs); //! Virtual destructor. virtual ~XmpKey(); //@} //! @name Manipulators //@{ //! Assignment operator. XmpKey& operator=(const XmpKey& rhs); //@} //! @name Accessors //@{ virtual std::string key() const; virtual const char* familyName() const; /*! @brief Return the name of the group (the second part of the key). For XMP keys, the group name is the schema prefix name. */ virtual std::string groupName() const; virtual std::string tagName() const; virtual std::string tagLabel() const; //! Properties don't have a tag number. Return 0. virtual uint16_t tag() const; AutoPtr clone() const; // Todo: Should this be removed? What about tagLabel then? //! Return the schema namespace for the prefix of the key std::string ns() const; //@} private: //! Internal virtual copy constructor. EXV_DLLLOCAL virtual XmpKey* clone_() const; private: // Pimpl idiom struct Impl; Impl* p_; }; // class XmpKey // ***************************************************************************** // free functions //! Output operator for property info EXIV2API std::ostream& operator<<(std::ostream& os, const XmpPropertyInfo& propertyInfo); } // namespace Exiv2 #endif // #ifndef PROPERTIES_HPP_ exiv2-0.23/src/exiv2.hpp0000644000175000017500000000414011732641407014650 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! @file exiv2.hpp @brief Include all Exiv2 header files. @version $Rev: 2681 $ @author Andreas Huggel (ahu) ahuggel@gmx.net @date 21-Jun-10, ahu: created */ #ifndef EXIV2_HPP_ #define EXIV2_HPP_ // ***************************************************************************** // included header files #include "basicio.hpp" #include "bmpimage.hpp" #include "convert.hpp" #include "cr2image.hpp" #include "crwimage.hpp" #include "datasets.hpp" #include "easyaccess.hpp" #include "epsimage.hpp" #include "error.hpp" #include "exif.hpp" #include "futils.hpp" #include "gifimage.hpp" #include "image.hpp" #include "iptc.hpp" #include "jp2image.hpp" #include "jpgimage.hpp" #include "metadatum.hpp" #include "mrwimage.hpp" #include "orfimage.hpp" #include "pgfimage.hpp" #include "pngimage.hpp" #include "preview.hpp" #include "properties.hpp" #include "psdimage.hpp" #include "rafimage.hpp" #include "rw2image.hpp" #include "tags.hpp" #include "tgaimage.hpp" #include "tiffimage.hpp" #include "types.hpp" #include "value.hpp" #include "version.hpp" #include "xmp.hpp" #include "xmpsidecar.hpp" #endif // #ifndef EXIV2_HPP_ exiv2-0.23/src/sonymn_int.hpp0000644000175000017500000000617411732641407016021 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! @file sonymn_int.hpp @brief Sony MakerNote implemented using the following references:
Sony Makernote list by Phil Harvey
Email communication with caulier dot gilles at gmail dot com
@version $Rev: 2681 $ @author Andreas Huggel (ahu) ahuggel@gmx.net @author Gilles Caulier (cgilles) caulier dot gilles at gmail dot com @date 18-Apr-05, ahu: created */ #ifndef SONYMN_INT_HPP_ #define SONYMN_INT_HPP_ // ***************************************************************************** // included header files #include "tags.hpp" #include "types.hpp" // + standard includes #include #include // ***************************************************************************** // namespace extensions namespace Exiv2 { namespace Internal { // ***************************************************************************** // class definitions //! MakerNote for Sony cameras class SonyMakerNote { public: //! Return read-only list of built-in Sony tags static const TagInfo* tagList(); //! Return read-only list of built-in Sony Standard Camera Settings tags static const TagInfo* tagListCs(); //! Return read-only list of built-in Sony Standard Camera Settings version 2 tags static const TagInfo* tagListCs2(); //! @name Print functions for Sony %MakerNote tags //@{ //! Print Sony Camera Model static std::ostream& print0xb000(std::ostream&, const Value&, const ExifData*); //! Print Full and Preview Image size static std::ostream& printImageSize(std::ostream&, const Value&, const ExifData*); private: //! Tag information static const TagInfo tagInfo_[]; static const TagInfo tagInfoCs_[]; static const TagInfo tagInfoCs2_[]; }; // class SonyMakerNote }} // namespace Internal, Exiv2 #endif // #ifndef SONYMN_INT_HPP_ exiv2-0.23/src/types.cpp0000644000175000017500000005046511732641407014765 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /* File: types.cpp Version: $Rev: 2681 $ Author(s): Andreas Huggel (ahu) History: 26-Jan-04, ahu: created 11-Feb-04, ahu: isolated as a component */ // ***************************************************************************** #include "rcsid_int.hpp" EXIV2_RCSID("@(#) $Id: types.cpp 2681 2012-03-22 15:19:35Z ahuggel $") // ***************************************************************************** // included header files #include "types.hpp" #include "i18n.h" // for _exvGettext // + standard includes #ifdef EXV_UNICODE_PATH # include // for MultiByteToWideChar etc #endif #include #include #include #include #include #include #include #include #include #include #include // ***************************************************************************** namespace { //! Information pertaining to the defined %Exiv2 value type identifiers. struct TypeInfoTable { Exiv2::TypeId typeId_; //!< Type id const char* name_; //!< Name of the type long size_; //!< Bytes per data entry //! Comparison operator for \em typeId bool operator==(Exiv2::TypeId typeId) const { return typeId_ == typeId; } //! Comparison operator for \em name bool operator==(const std::string& name) const { return 0 == strcmp(name_, name.c_str()); } }; // struct TypeInfoTable //! Lookup list with information of Exiv2 types const TypeInfoTable typeInfoTable[] = { { Exiv2::invalidTypeId, "Invalid", 0 }, { Exiv2::unsignedByte, "Byte", 1 }, { Exiv2::asciiString, "Ascii", 1 }, { Exiv2::unsignedShort, "Short", 2 }, { Exiv2::unsignedLong, "Long", 4 }, { Exiv2::unsignedRational, "Rational", 8 }, { Exiv2::signedByte, "SByte", 1 }, { Exiv2::undefined, "Undefined", 1 }, { Exiv2::signedShort, "SShort", 2 }, { Exiv2::signedLong, "SLong", 4 }, { Exiv2::signedRational, "SRational", 8 }, { Exiv2::tiffFloat, "Float", 4 }, { Exiv2::tiffDouble, "Double", 8 }, { Exiv2::tiffIfd, "Ifd", 4 }, { Exiv2::string, "String", 1 }, { Exiv2::date, "Date", 8 }, { Exiv2::time, "Time", 11 }, { Exiv2::comment, "Comment", 1 }, { Exiv2::directory, "Directory", 1 }, { Exiv2::xmpText, "XmpText", 1 }, { Exiv2::xmpAlt, "XmpAlt", 1 }, { Exiv2::xmpBag, "XmpBag", 1 }, { Exiv2::xmpSeq, "XmpSeq", 1 }, { Exiv2::langAlt, "LangAlt", 1 } }; } // ***************************************************************************** // class member definitions namespace Exiv2 { const char* TypeInfo::typeName(TypeId typeId) { const TypeInfoTable* tit = find(typeInfoTable, typeId); if (!tit) return 0; return tit->name_; } TypeId TypeInfo::typeId(const std::string& typeName) { const TypeInfoTable* tit = find(typeInfoTable, typeName); if (!tit) return invalidTypeId; return tit->typeId_; } long TypeInfo::typeSize(TypeId typeId) { const TypeInfoTable* tit = find(typeInfoTable, typeId); if (!tit) return 0; return tit->size_; } DataBuf::DataBuf(DataBuf& rhs) : pData_(rhs.pData_), size_(rhs.size_) { rhs.release(); } DataBuf::DataBuf(const byte* pData, long size) : pData_(0), size_(0) { if (size > 0) { pData_ = new byte[size]; std::memcpy(pData_, pData, size); size_ = size; } } DataBuf& DataBuf::operator=(DataBuf& rhs) { if (this == &rhs) return *this; reset(rhs.release()); return *this; } void DataBuf::alloc(long size) { if (size > size_) { delete[] pData_; pData_ = 0; size_ = 0; pData_ = new byte[size]; size_ = size; } } std::pair DataBuf::release() { std::pair p = std::make_pair(pData_, size_); pData_ = 0; size_ = 0; return p; } void DataBuf::reset(std::pair p) { if (pData_ != p.first) { delete[] pData_; pData_ = p.first; } size_ = p.second; } // ************************************************************************* // free functions std::ostream& operator<<(std::ostream& os, const Rational& r) { return os << r.first << "/" << r.second; } std::istream& operator>>(std::istream& is, Rational& r) { int32_t nominator; int32_t denominator; char c('\0'); is >> nominator >> c >> denominator; if (c != '/') is.setstate(std::ios::failbit); if (is) r = std::make_pair(nominator, denominator); return is; } std::ostream& operator<<(std::ostream& os, const URational& r) { return os << r.first << "/" << r.second; } std::istream& operator>>(std::istream& is, URational& r) { uint32_t nominator; uint32_t denominator; char c('\0'); is >> nominator >> c >> denominator; if (c != '/') is.setstate(std::ios::failbit); if (is) r = std::make_pair(nominator, denominator); return is; } uint16_t getUShort(const byte* buf, ByteOrder byteOrder) { if (byteOrder == littleEndian) { return (byte)buf[1] << 8 | (byte)buf[0]; } else { return (byte)buf[0] << 8 | (byte)buf[1]; } } uint32_t getULong(const byte* buf, ByteOrder byteOrder) { if (byteOrder == littleEndian) { return (byte)buf[3] << 24 | (byte)buf[2] << 16 | (byte)buf[1] << 8 | (byte)buf[0]; } else { return (byte)buf[0] << 24 | (byte)buf[1] << 16 | (byte)buf[2] << 8 | (byte)buf[3]; } } URational getURational(const byte* buf, ByteOrder byteOrder) { uint32_t nominator = getULong(buf, byteOrder); uint32_t denominator = getULong(buf + 4, byteOrder); return std::make_pair(nominator, denominator); } int16_t getShort(const byte* buf, ByteOrder byteOrder) { if (byteOrder == littleEndian) { return (byte)buf[1] << 8 | (byte)buf[0]; } else { return (byte)buf[0] << 8 | (byte)buf[1]; } } int32_t getLong(const byte* buf, ByteOrder byteOrder) { if (byteOrder == littleEndian) { return (byte)buf[3] << 24 | (byte)buf[2] << 16 | (byte)buf[1] << 8 | (byte)buf[0]; } else { return (byte)buf[0] << 24 | (byte)buf[1] << 16 | (byte)buf[2] << 8 | (byte)buf[3]; } } Rational getRational(const byte* buf, ByteOrder byteOrder) { int32_t nominator = getLong(buf, byteOrder); int32_t denominator = getLong(buf + 4, byteOrder); return std::make_pair(nominator, denominator); } float getFloat(const byte* buf, ByteOrder byteOrder) { // This algorithm assumes that the internal representation of the float // type is the 4-byte IEEE 754 binary32 format, which is common but not // required by the C++ standard. assert(sizeof(float) == 4); union { uint32_t ul_; float f_; } u; u.ul_ = getULong(buf, byteOrder); return u.f_; } double getDouble(const byte* buf, ByteOrder byteOrder) { // This algorithm assumes that the internal representation of the double // type is the 8-byte IEEE 754 binary64 format, which is common but not // required by the C++ standard. assert(sizeof(double) == 8); union { uint64_t ull_; double d_; } u; u.ull_ = 0; if (byteOrder == littleEndian) { u.ull_ = static_cast(buf[7]) << 56 | static_cast(buf[6]) << 48 | static_cast(buf[5]) << 40 | static_cast(buf[4]) << 32 | static_cast(buf[3]) << 24 | static_cast(buf[2]) << 16 | static_cast(buf[1]) << 8 | static_cast(buf[0]); } else { u.ull_ = static_cast(buf[0]) << 56 | static_cast(buf[1]) << 48 | static_cast(buf[2]) << 40 | static_cast(buf[3]) << 32 | static_cast(buf[4]) << 24 | static_cast(buf[5]) << 16 | static_cast(buf[6]) << 8 | static_cast(buf[7]); } return u.d_; } long us2Data(byte* buf, uint16_t s, ByteOrder byteOrder) { if (byteOrder == littleEndian) { buf[0] = (byte) (s & 0x00ff); buf[1] = (byte)((s & 0xff00) >> 8); } else { buf[0] = (byte)((s & 0xff00) >> 8); buf[1] = (byte) (s & 0x00ff); } return 2; } long ul2Data(byte* buf, uint32_t l, ByteOrder byteOrder) { if (byteOrder == littleEndian) { buf[0] = (byte) (l & 0x000000ff); buf[1] = (byte)((l & 0x0000ff00) >> 8); buf[2] = (byte)((l & 0x00ff0000) >> 16); buf[3] = (byte)((l & 0xff000000) >> 24); } else { buf[0] = (byte)((l & 0xff000000) >> 24); buf[1] = (byte)((l & 0x00ff0000) >> 16); buf[2] = (byte)((l & 0x0000ff00) >> 8); buf[3] = (byte) (l & 0x000000ff); } return 4; } long ur2Data(byte* buf, URational l, ByteOrder byteOrder) { long o = ul2Data(buf, l.first, byteOrder); o += ul2Data(buf+o, l.second, byteOrder); return o; } long s2Data(byte* buf, int16_t s, ByteOrder byteOrder) { if (byteOrder == littleEndian) { buf[0] = (byte)(s & 0x00ff); buf[1] = (byte)((s & 0xff00) >> 8); } else { buf[0] = (byte)((s & 0xff00) >> 8); buf[1] = (byte)(s & 0x00ff); } return 2; } long l2Data(byte* buf, int32_t l, ByteOrder byteOrder) { if (byteOrder == littleEndian) { buf[0] = (byte)(l & 0x000000ff); buf[1] = (byte)((l & 0x0000ff00) >> 8); buf[2] = (byte)((l & 0x00ff0000) >> 16); buf[3] = (byte)((l & 0xff000000) >> 24); } else { buf[0] = (byte)((l & 0xff000000) >> 24); buf[1] = (byte)((l & 0x00ff0000) >> 16); buf[2] = (byte)((l & 0x0000ff00) >> 8); buf[3] = (byte)(l & 0x000000ff); } return 4; } long r2Data(byte* buf, Rational l, ByteOrder byteOrder) { long o = l2Data(buf, l.first, byteOrder); o += l2Data(buf+o, l.second, byteOrder); return o; } long f2Data(byte* buf, float f, ByteOrder byteOrder) { // This algorithm assumes that the internal representation of the float // type is the 4-byte IEEE 754 binary32 format, which is common but not // required by the C++ standard. assert(sizeof(float) == 4); union { uint32_t ul_; float f_; } u; u.f_ = f; return ul2Data(buf, u.ul_, byteOrder); } long d2Data(byte* buf, double d, ByteOrder byteOrder) { // This algorithm assumes that the internal representation of the double // type is the 8-byte IEEE 754 binary64 format, which is common but not // required by the C++ standard. assert(sizeof(double) == 8); union { uint64_t ull_; double d_; } u; u.d_ = d; uint64_t m = 0xff; if (byteOrder == littleEndian) { buf[0] = (byte)(u.ull_ & m); buf[1] = (byte)((u.ull_ & (m << 8)) >> 8); buf[2] = (byte)((u.ull_ & (m << 16)) >> 16); buf[3] = (byte)((u.ull_ & (m << 24)) >> 24); buf[4] = (byte)((u.ull_ & (m << 32)) >> 32); buf[5] = (byte)((u.ull_ & (m << 40)) >> 40); buf[6] = (byte)((u.ull_ & (m << 48)) >> 48); buf[7] = (byte)((u.ull_ & (m << 56)) >> 56); } else { buf[0] = (byte)((u.ull_ & (m << 56)) >> 56); buf[1] = (byte)((u.ull_ & (m << 48)) >> 48); buf[2] = (byte)((u.ull_ & (m << 40)) >> 40); buf[3] = (byte)((u.ull_ & (m << 32)) >> 32); buf[4] = (byte)((u.ull_ & (m << 24)) >> 24); buf[5] = (byte)((u.ull_ & (m << 16)) >> 16); buf[6] = (byte)((u.ull_ & (m << 8)) >> 8); buf[7] = (byte)(u.ull_ & m); } return 8; } void hexdump(std::ostream& os, const byte* buf, long len, long offset) { const std::string::size_type pos = 8 + 16 * 3 + 2; const std::string align(pos, ' '); long i = 0; while (i < len) { os << " " << std::setw(4) << std::setfill('0') << std::hex << i + offset << " "; std::ostringstream ss; do { byte c = buf[i]; os << std::setw(2) << std::setfill('0') << std::right << std::hex << (int)c << " "; ss << ((int)c >= 31 && (int)c < 127 ? char(buf[i]) : '.'); } while (++i < len && i%16 != 0); std::string::size_type width = 9 + ((i-1)%16 + 1) * 3; os << (width > pos ? "" : align.substr(width)) << ss.str() << "\n"; } os << std::dec << std::setfill(' '); } // hexdump bool isHex(const std::string& str, size_t size, const std::string& prefix) { if ( str.size() <= prefix.size() || str.substr(0, prefix.size()) != prefix) return false; if ( size > 0 && str.size() != size + prefix.size()) return false; for (size_t i = prefix.size(); i < str.size(); ++i) { if (!isxdigit(str[i])) return false; } return true; } // isHex int exifTime(const char* buf, struct tm* tm) { assert(buf != 0); assert(tm != 0); int rc = 1; int year, mon, mday, hour, min, sec; int scanned = std::sscanf(buf, "%4d:%2d:%2d %2d:%2d:%2d", &year, &mon, &mday, &hour, &min, &sec); if (scanned == 6) { tm->tm_year = year - 1900; tm->tm_mon = mon - 1; tm->tm_mday = mday; tm->tm_hour = hour; tm->tm_min = min; tm->tm_sec = sec; rc = 0; } return rc; } // exifTime const char* exvGettext(const char* str) { #ifdef EXV_ENABLE_NLS return _exvGettext(str); #else return str; #endif } #ifdef EXV_UNICODE_PATH std::string ws2s(const std::wstring& s) { int len; int slength = (int)s.length() + 1; len = WideCharToMultiByte(CP_ACP, 0, s.c_str(), slength, 0, 0, 0, 0); char* buf = new char[len]; WideCharToMultiByte(CP_ACP, 0, s.c_str(), slength, buf, len, 0, 0); std::string r(buf); delete[] buf; return r; } std::wstring s2ws(const std::string& s) { int len; int slength = (int)s.length() + 1; len = MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, 0, 0); wchar_t* buf = new wchar_t[len]; MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, buf, len); std::wstring r(buf); delete[] buf; return r; } #endif // EXV_UNICODE_PATH template<> bool stringTo(const std::string& s, bool& ok) { std::string lcs(s); /* lowercase string */ for(unsigned i = 0; i < lcs.length(); i++) { lcs[i] = std::tolower(s[i]); } /* handle the same values as xmp sdk */ if (lcs == "false" || lcs == "f" || lcs == "0") { ok = true; return false; } if (lcs == "true" || lcs == "t" || lcs == "1") { ok = true; return true; } ok = false; return false; } long parseLong(const std::string& s, bool& ok) { long ret = stringTo(s, ok); if (ok) return ret; float f = stringTo(s, ok); if (ok) return static_cast(f); Rational r = stringTo(s, ok); if (ok) { if (r.second == 0) { ok = false; return 0; } return static_cast(static_cast(r.first) / r.second); } bool b = stringTo(s, ok); if (ok) return b ? 1 : 0; // everything failed, return from stringTo is probably the best fit return ret; } float parseFloat(const std::string& s, bool& ok) { float ret = stringTo(s, ok); if (ok) return ret; Rational r = stringTo(s, ok); if (ok) { if (r.second == 0) { ok = false; return 0.0; } return static_cast(r.first) / r.second; } bool b = stringTo(s, ok); if (ok) return b ? 1.0f : 0.0f; // everything failed, return from stringTo is probably the best fit return ret; } Rational parseRational(const std::string& s, bool& ok) { Rational ret = stringTo(s, ok); if (ok) return ret; long l = stringTo(s, ok); if (ok) return Rational(l, 1); float f = stringTo(s, ok); if (ok) return floatToRationalCast(f); bool b = stringTo(s, ok); if (ok) return b ? Rational(1, 1) : Rational(0, 1); // everything failed, return from stringTo is probably the best fit return ret; } Rational floatToRationalCast(float f) { // Beware: primitive conversion algorithm int32_t den = 1000000; if (std::labs(static_cast(f)) > 2147) den = 10000; if (std::labs(static_cast(f)) > 214748) den = 100; if (std::labs(static_cast(f)) > 21474836) den = 1; const float rnd = f >= 0 ? 0.5f : -0.5f; const int32_t nom = static_cast(f * den + rnd); const int32_t g = gcd(nom, den); return Rational(nom/g, den/g); } } // namespace Exiv2 #ifdef EXV_ENABLE_NLS // Declaration is in i18n.h const char* _exvGettext(const char* str) { static bool exvGettextInitialized = false; if (!exvGettextInitialized) { bindtextdomain(EXV_PACKAGE, EXV_LOCALEDIR); # ifdef EXV_HAVE_BIND_TEXTDOMAIN_CODESET bind_textdomain_codeset (EXV_PACKAGE, "UTF-8"); # endif exvGettextInitialized = true; } return dgettext(EXV_PACKAGE, str); } #endif // EXV_ENABLE_NLS exiv2-0.23/src/utils.hpp0000644000175000017500000001405411732641407014760 0ustar andreasandreas// ********************************************************* -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! @file utils.hpp @brief A collection of utility functions @version $Rev: 2681 $ @author Andreas Huggel (ahu) ahuggel@gmx.net @date 12-Dec-03, ahu: created */ #ifndef UTILS_HPP_ #define UTILS_HPP_ // ********************************************************************* // included header files // + standard includes #include // ********************************************************************* // namespace extensions /*! @brief Contains utility classes and functions. Most of these are wrappers for common C functions that do not require pointers and memory considerations. */ namespace Util { // ********************************************************************* // class definitions /*! @brief Parse the command line options of a program. A wrapper around the POSIX %getopt(3) function. Parses the command line options and passes each option to virtual option(). A derived class implements this method to handle options as needed. Similarly, remaining non-option parameters are passed to the virtual nonoption() method. */ class Getopt { public: //! Default constructor. Getopt(); //! Destructor. virtual ~Getopt(); /*! @brief Parse command line arguments. Parses the command line arguments. Calls option() with the character value of the option and its argument (if any) for each recognized option and with ':' or '?' for unrecognized options. See the manual pages for %getopt(3) for details. In addition, nonoption() is invoked for each remaining non-option parameter on the command line. @param argc Argument count as passed to main() on program invocation. @param argv Argument array as passed to main() on program invocation. @param optstring String containing the legitimate option characters. @return Number of errors (the sum of the return values from option() and nonoption()). */ int getopt(int argc, char* const argv[], const std::string& optstring); /*! @brief Callback used by getopt() to pass on each option and its argument (if any). Implement this method in a derived class to handle the options as needed. See the manual pages for %getopt(3) for further details, in particular, the semantics of optarg and optopt. @param opt Value of the option character as returned by %getopt(3). @param optarg The corresponding option argument. @param optopt The actual option character in case of an unrecognized option or a missing option argument (opt is '?' or ':'). @return 0 if successful, 1 in case of an error. */ virtual int option(int opt, const std::string& optarg, int optopt) = 0; /*! @brief Callback used by getopt() to pass on each non-option parameter found on the command line. Implement this method in a derived class to handle the non-option parameters as needed. The default implementation ignores all non-option parameters. @param argv The non-option parameter from the command line. @return 0 if successful, 1 in case of an error. */ virtual int nonoption(const std::string& argv); //! Program name (argv[0]) const std::string& progname() const { return progname_; } //! Total number of errors returned by calls to option() int errcnt() const { return errcnt_; } private: std::string progname_; int errcnt_; }; // ********************************************************************* // free functions /*! @brief Get the directory component from the \em path string. See %dirname(3). This function can handle Windows paths to some extent: c:\\bar should be fine, \\\\bigsrv\\foo also, but \\\\bigsrv alone doesn't work. */ std::string dirname(const std::string& path); /*! @brief Get the filename component from the \em path string. See %basename(3). If the \em delsuffix parameter is true, the suffix will be removed. This function can handle Windows paths to some extent: c:\\bar should be fine, \\\\bigsrv\\foo also, but \\\\bigsrv alone doesn't work. */ std::string basename(const std::string& path, bool delsuffix =false); /*! @brief Get the suffix from the path string. Normally, the suffix is the substring of the basename of path from the last '.' to the end of the string. */ std::string suffix(const std::string& path); /*! @brief Convert a C string to a long value, which is returned in n. Returns true if the conversion is successful, else false. n is not modified if the conversion is unsuccessful. See strtol(2). */ bool strtol(const char* nptr, long& n); /*! @brief Replaces all occurences of \em searchText in the \em text string by \em replaceText. */ void replace(std::string& text, const std::string& searchText, const std::string& replaceText); } // namespace Util #endif // #ifndef UTILS_HPP_ exiv2-0.23/src/orfimage_int.hpp0000644000175000017500000000460311732641407016262 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! @file orfimage_int.hpp @brief Internal classes to support Olympus RAW image format @version $Rev: 2681 $ @author Jeff Costlow costlow@gmail.com @date 31-Jul-07, costlow: created 23-Apr-08, ahu: Moved to _int file */ #ifndef ORFIMAGE_INT_HPP_ #define ORFIMAGE_INT_HPP_ // ***************************************************************************** // included header files #include "tiffimage_int.hpp" #include "types.hpp" // ***************************************************************************** // namespace extensions namespace Exiv2 { namespace Internal { // ***************************************************************************** // class definitions /*! @brief Olympus ORF header structure. */ class OrfHeader : public TiffHeaderBase { public: //! @name Creators //@{ //! Default constructor OrfHeader(ByteOrder byteOrder =littleEndian); //! Destructor. ~OrfHeader(); //@} //! @name Manipulators //@{ bool read(const byte* pData, uint32_t size); //@} //! @name Accessors //@{ DataBuf write() const; //@} private: // DATA uint16_t sig_; // * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! @file tifffwd_int.hpp @brief Internal TIFF parser related typedefs and forward definitions. @version $Rev: 2681 $ @author Andreas Huggel (ahu) ahuggel@gmx.net @date 24-Jun-06, ahu: created */ #ifndef TIFFFWD_INT_HPP_ #define TIFFFWD_INT_HPP_ // ***************************************************************************** // included header files #include "types.hpp" #include "tags_int.hpp" // + standard includes #include #include #include // ***************************************************************************** // Exiv2 namespace extensions namespace Exiv2 { class Exifdatum; namespace Internal { class TiffHeaderBase; class TiffComponent; class TiffEntryBase; class TiffEntry; class TiffDataEntry; class TiffSizeEntry; class TiffDirectory; class TiffSubIfd; class TiffMnEntry; class TiffBinaryArray; class TiffBinaryElement; class TiffIfdMakernote; class MnHeader; class TiffVisitor; class TiffFinder; class TiffDecoder; class TiffEncoder; class TiffReader; class TiffRwState; class TiffPathItem; struct TiffMappingInfo; class IoWrapper; class OffsetWriter; // ***************************************************************************** // type definitions /*! @brief Function pointer type for a TiffDecoder member function to decode a TIFF component. */ typedef void (TiffDecoder::*DecoderFct)(const TiffEntryBase*); /*! @brief Function pointer type for a TiffDecoder member function to decode a TIFF component. */ typedef void (TiffEncoder::*EncoderFct)(TiffEntryBase*, const Exifdatum*); /*! @brief Type for a function pointer for a function to decode a TIFF component. */ typedef DecoderFct (*FindDecoderFct)(const std::string& make, uint32_t extendedTag, IfdId group); /*! @brief Type for a function pointer for a function to encode a TIFF component. */ typedef EncoderFct (*FindEncoderFct)( const std::string& make, uint32_t extendedTag, IfdId group ); /*! @brief Type for a function pointer for a function to create a TIFF component. Use TiffComponent::AutoPtr, it is not used in this declaration only to reduce dependencies. */ typedef std::auto_ptr (*NewTiffCompFct)(uint16_t tag, IfdId group); //! Stack to hold a path from the TIFF root element to a TIFF entry typedef std::stack TiffPath; //! Type for a list of primary image groups typedef std::vector PrimaryGroups; }} // namespace Internal, Exiv2 #endif // #ifndef TIFFFWD_INT_HPP_ exiv2-0.23/src/xmp.hpp0000644000175000017500000003727011732641407014431 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! @file xmp.hpp @brief Encoding and decoding of XMP data @version $Rev: 2681 $ @author Andreas Huggel (ahu) ahuggel@gmx.net @date 13-Jul-07, ahu: created */ #ifndef XMP_HPP_ #define XMP_HPP_ // ***************************************************************************** // included header files #include "metadatum.hpp" #include "properties.hpp" #include "value.hpp" #include "types.hpp" // + standard includes #include #include // ***************************************************************************** // namespace extensions namespace Exiv2 { // ***************************************************************************** // class declarations class ExifData; // ***************************************************************************** // class definitions /*! @brief Information related to an XMP property. An XMP metadatum consists of an XmpKey and a Value and provides methods to manipulate these. */ class EXIV2API Xmpdatum : public Metadatum { public: //! @name Creators //@{ /*! @brief Constructor for new tags created by an application. The %Xmpdatum is created from a key / value pair. %Xmpdatum copies (clones) the value if one is provided. Alternatively, a program can create an 'empty' %Xmpdatum with only a key and set the value using setValue(). @param key The key of the %Xmpdatum. @param pValue Pointer to a %Xmpdatum value. @throw Error if the key cannot be parsed and converted to a known schema namespace prefix and property name. */ explicit Xmpdatum(const XmpKey& key, const Value* pValue =0); //! Copy constructor Xmpdatum(const Xmpdatum& rhs); //! Destructor virtual ~Xmpdatum(); //@} //! @name Manipulators //@{ //! Assignment operator Xmpdatum& operator=(const Xmpdatum& rhs); /*! @brief Assign std::string \em value to the %Xmpdatum. Calls setValue(const std::string&). */ Xmpdatum& operator=(const std::string& value); /*! @brief Assign const char* \em value to the %Xmpdatum. Calls operator=(const std::string&). */ Xmpdatum& operator=(const char* value); /*! @brief Assign a boolean \em value to the %Xmpdatum. Translates the value to a string "true" or "false". */ Xmpdatum& operator=(const bool& value); /*! @brief Assign a \em value of any type with an output operator to the %Xmpdatum. Calls operator=(const std::string&). */ template Xmpdatum& operator=(const T& value); /*! @brief Assign Value \em value to the %Xmpdatum. Calls setValue(const Value*). */ Xmpdatum& operator=(const Value& value); void setValue(const Value* pValue); /*! @brief Set the value to the string \em value. Uses Value::read(const std::string&). If the %Xmpdatum does not have a Value yet, then a %Value of the correct type for this %Xmpdatum is created. If the key is unknown, a XmpTextValue is used as default. Return 0 if the value was read successfully. */ int setValue(const std::string& value); //@} //! @name Accessors //@{ //! Not implemented. Calling this method will raise an exception. long copy(byte* buf, ByteOrder byteOrder) const; std::ostream& write(std::ostream& os, const ExifData* pMetadata =0) const; /*! @brief Return the key of the Xmpdatum. The key is of the form 'Xmp.prefix.property'. Note however that the key is not necessarily unique, i.e., an XmpData object may contain multiple metadata with the same key. */ std::string key() const; const char* familyName() const; //! Return the (preferred) schema namespace prefix. std::string groupName() const; //! Return the property name. std::string tagName() const; std::string tagLabel() const; //! Properties don't have a tag number. Return 0. uint16_t tag() const; TypeId typeId() const; const char* typeName() const; // Todo: Remove this method from the baseclass //! The Exif typeSize doesn't make sense here. Return 0. long typeSize() const; long count() const; long size() const; std::string toString() const; std::string toString(long n) const; long toLong(long n =0) const; float toFloat(long n =0) const; Rational toRational(long n =0) const; Value::AutoPtr getValue() const; const Value& value() const; //@} private: // Pimpl idiom struct Impl; Impl* p_; }; // class Xmpdatum //! Container type to hold all metadata typedef std::vector XmpMetadata; /*! @brief A container for XMP data. This is a top-level class of the %Exiv2 library. Provide high-level access to the XMP data of an image: - read XMP information from an XML block - access metadata through keys and standard C++ iterators - add, modify and delete metadata - serialize XMP data to an XML block */ class EXIV2API XmpData { public: //! XmpMetadata iterator type typedef XmpMetadata::iterator iterator; //! XmpMetadata const iterator type typedef XmpMetadata::const_iterator const_iterator; //! @name Manipulators //@{ /*! @brief Returns a reference to the %Xmpdatum that is associated with a particular \em key. If %XmpData does not already contain such an %Xmpdatum, operator[] adds object \em Xmpdatum(key). @note Since operator[] might insert a new element, it can't be a const member function. */ Xmpdatum& operator[](const std::string& key); /*! @brief Add an %Xmpdatum from the supplied key and value pair. This method copies (clones) the value. @return 0 if successful. */ int add(const XmpKey& key, const Value* value); /*! @brief Add a copy of the Xmpdatum to the XMP metadata. @return 0 if successful. */ int add(const Xmpdatum& xmpdatum); /*! @brief Delete the Xmpdatum at iterator position pos, return the position of the next Xmpdatum. @note Iterators into the metadata, including pos, are potentially invalidated by this call. */ iterator erase(iterator pos); //! Delete all Xmpdatum instances resulting in an empty container. void clear(); //! Sort metadata by key void sortByKey(); //! Begin of the metadata iterator begin(); //! End of the metadata iterator end(); /*! @brief Find the first Xmpdatum with the given key, return an iterator to it. */ iterator findKey(const XmpKey& key); //@} //! @name Accessors //@{ //! Begin of the metadata const_iterator begin() const; //! End of the metadata const_iterator end() const; /*! @brief Find the first Xmpdatum with the given key, return a const iterator to it. */ const_iterator findKey(const XmpKey& key) const; //! Return true if there is no XMP metadata bool empty() const; //! Get the number of metadata entries long count() const; //@} private: // DATA XmpMetadata xmpMetadata_; }; // class XmpData /*! @brief Stateless parser class for XMP packets. Images use this class to parse and serialize XMP packets. The parser uses the XMP toolkit to do the job. */ class EXIV2API XmpParser { public: //! Options to control the format of the serialized XMP packet. enum XmpFormatFlags { omitPacketWrapper = 0x0010UL, //!< Omit the XML packet wrapper. readOnlyPacket = 0x0020UL, //!< Default is a writeable packet. useCompactFormat = 0x0040UL, //!< Use a compact form of RDF. includeThumbnailPad = 0x0100UL, //!< Include a padding allowance for a thumbnail image. exactPacketLength = 0x0200UL, //!< The padding parameter is the overall packet length. writeAliasComments = 0x0400UL, //!< Show aliases as XML comments. omitAllFormatting = 0x0800UL //!< Omit all formatting whitespace. }; /*! @brief Decode XMP metadata from an XMP packet \em xmpPacket into \em xmpData. The format of the XMP packet must follow the XMP specification. This method clears any previous contents of \em xmpData. @param xmpData Container for the decoded XMP properties @param xmpPacket The raw XMP packet to decode @return 0 if successful;
1 if XMP support has not been compiled-in;
2 if the XMP toolkit failed to initialize;
3 if the XMP toolkit failed and raised an XMP_Error */ static int decode( XmpData& xmpData, const std::string& xmpPacket); /*! @brief Encode (serialize) XMP metadata from \em xmpData into a string xmpPacket. The XMP packet returned in the string follows the XMP specification. This method only modifies \em xmpPacket if the operations succeeds (return code 0). @param xmpPacket Reference to a string to hold the encoded XMP packet. @param xmpData XMP properties to encode. @param formatFlags Flags that control the format of the XMP packet, see enum XmpFormatFlags. @param padding Padding length. @return 0 if successful;
1 if XMP support has not been compiled-in;
2 if the XMP toolkit failed to initialize;
3 if the XMP toolkit failed and raised an XMP_Error */ static int encode( std::string& xmpPacket, const XmpData& xmpData, uint16_t formatFlags =useCompactFormat, uint32_t padding =0); /*! @brief Lock/unlock function type A function of this type can be passed to initialize() to make subsequent registration of XMP namespaces thread-safe. See the initialize() function for more information. @param pLockData Pointer to the pLockData passed to initialize() @param lockUnlock Indicates whether to lock (true) or unlock (false) */ typedef void (*XmpLockFct)(void* pLockData, bool lockUnlock); /*! @brief Initialize the XMP Toolkit. Calling this method is usually not needed, as encode() and decode() will initialize the XMP Toolkit if necessary. The function takes optional pointers to a callback function \em xmpLockFct and related data \em pLockData that the parser uses when XMP namespaces are subsequently registered. The initialize() function itself still is not thread-safe and needs to be called in a thread-safe manner (e.g., on program startup), but if used with suitable additional locking parameters, any subsequent registration of namespaces will be thread-safe. Example usage on Windows using a critical section: @code void main() { struct XmpLock { CRITICAL_SECTION cs; XmpLock() { InitializeCriticalSection(&cs); } ~XmpLock() { DeleteCriticalSection(&cs); } static void LockUnlock(void* pData, bool fLock) { XmpLock* pThis = reinterpret_cast(pData); if (pThis) { (fLock) ? EnterCriticalSection(&pThis->cs) : LeaveCriticalSection(&pThis->cs); } } } xmpLock; // Pass the locking mechanism to the XMP parser on initialization. // Note however that this call itself is still not thread-safe. Exiv2::XmpParser::initialize(XmpLock::LockUnlock, &xmpLock); // Program continues here, subsequent registrations of XMP // namespaces are serialized using xmpLock. } @endcode @return True if the initialization was successful, else false. */ static bool initialize(XmpParser::XmpLockFct xmpLockFct =0, void* pLockData =0); /*! @brief Terminate the XMP Toolkit and unregister custom namespaces. Call this method when the XmpParser is no longer needed to allow the XMP Toolkit to cleanly shutdown. */ static void terminate(); private: /*! @brief Register a namespace with the XMP Toolkit. */ static void registerNs(const std::string& ns, const std::string& prefix); /*! @brief Delete a namespace from the XMP Toolkit. XmpProperties::unregisterNs calls this to synchronize namespaces. */ static void unregisterNs(const std::string& ns); // DATA static bool initialized_; //! Indicates if the XMP Toolkit has been initialized static XmpLockFct xmpLockFct_; static void* pLockData_; }; // class XmpParser // ***************************************************************************** // free functions, template and inline definitions inline Xmpdatum& Xmpdatum::operator=(const char* value) { return Xmpdatum::operator=(std::string(value)); } inline Xmpdatum& Xmpdatum::operator=(const bool& value) { return operator=(value ? "True" : "False"); } template Xmpdatum& Xmpdatum::operator=(const T& value) { setValue(Exiv2::toString(value)); return *this; } } // namespace Exiv2 #endif // #ifndef XMP_HPP_ exiv2-0.23/src/basicio.cpp0000644000175000017500000010676111733342520015226 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /* File: basicio.cpp Version: $Rev: 2689 $ Author(s): Brad Schick (brad) History: 04-Dec-04, brad: created */ // ***************************************************************************** #include "rcsid_int.hpp" EXIV2_RCSID("@(#) $Id: basicio.cpp 2689 2012-03-24 13:00:00Z ahuggel $") // ***************************************************************************** // included header files #ifdef _MSC_VER # include "exv_msvc.h" #else # include "exv_conf.h" #endif #include "basicio.hpp" #include "futils.hpp" #include "types.hpp" #include "error.hpp" // + standard includes #include #include #include #include #include #include // for remove, rename #include // for alloc, realloc, free #include // for stat, chmod #include // for stat, chmod #ifdef EXV_HAVE_SYS_MMAN_H # include // for mmap and munmap #endif #ifdef EXV_HAVE_PROCESS_H # include #endif #ifdef EXV_HAVE_UNISTD_H # include // for getpid, stat #endif #if defined WIN32 && !defined __CYGWIN__ // Windows doesn't provide mode_t, nlink_t typedef unsigned short mode_t; typedef short nlink_t; # include # include #endif // ***************************************************************************** // class member definitions namespace Exiv2 { BasicIo::~BasicIo() { } //! Internal Pimpl structure of class FileIo. class FileIo::Impl { public: //! Constructor Impl(const std::string& path); #ifdef EXV_UNICODE_PATH //! Constructor accepting a unicode path in an std::wstring Impl(const std::wstring& wpath); #endif // Enumerations //! Mode of operation enum OpMode { opRead, opWrite, opSeek }; #ifdef EXV_UNICODE_PATH //! Used to indicate if the path is stored as a standard or unicode string enum WpMode { wpStandard, wpUnicode }; #endif // DATA std::string path_; //!< (Standard) path #ifdef EXV_UNICODE_PATH std::wstring wpath_; //!< Unicode path WpMode wpMode_; //!< Indicates which path is in use #endif std::string openMode_; //!< File open mode FILE *fp_; //!< File stream pointer OpMode opMode_; //!< File open mode #if defined WIN32 && !defined __CYGWIN__ HANDLE hFile_; //!< Duplicated fd HANDLE hMap_; //!< Handle from CreateFileMapping #endif byte* pMappedArea_; //!< Pointer to the memory-mapped area size_t mappedLength_; //!< Size of the memory-mapped area bool isMalloced_; //!< Is the mapped area allocated? bool isWriteable_; //!< Can the mapped area be written to? // TYPES //! Simple struct stat wrapper for internal use struct StructStat { StructStat() : st_mode(0), st_size(0), st_nlink(0) {} mode_t st_mode; //!< Permissions off_t st_size; //!< Size nlink_t st_nlink; //!< Number of hard links (broken on Windows, see winNumberOfLinks()) }; // METHODS /*! @brief Switch to a new access mode, reopening the file if needed. Optimized to only reopen the file when it is really necessary. @param opMode The mode to switch to. @return 0 if successful */ int switchMode(OpMode opMode); //! stat wrapper for internal use int stat(StructStat& buf) const; #if defined WIN32 && !defined __CYGWIN__ // Windows function to determine the number of hardlinks (on NTFS) DWORD winNumberOfLinks() const; #endif private: // NOT IMPLEMENTED Impl(const Impl& rhs); //!< Copy constructor Impl& operator=(const Impl& rhs); //!< Assignment }; // class FileIo::Impl FileIo::Impl::Impl(const std::string& path) : path_(path), #ifdef EXV_UNICODE_PATH wpMode_(wpStandard), #endif fp_(0), opMode_(opSeek), #if defined WIN32 && !defined __CYGWIN__ hFile_(0), hMap_(0), #endif pMappedArea_(0), mappedLength_(0), isMalloced_(false), isWriteable_(false) { } #ifdef EXV_UNICODE_PATH FileIo::Impl::Impl(const std::wstring& wpath) : wpath_(wpath), wpMode_(wpUnicode), fp_(0), opMode_(opSeek), #if defined WIN32 && !defined __CYGWIN__ hFile_(0), hMap_(0), #endif pMappedArea_(0), mappedLength_(0), isMalloced_(false), isWriteable_(false) { } #endif int FileIo::Impl::switchMode(OpMode opMode) { assert(fp_ != 0); if (opMode_ == opMode) return 0; OpMode oldOpMode = opMode_; opMode_ = opMode; bool reopen = true; switch(opMode) { case opRead: // Flush if current mode allows reading, else reopen (in mode "r+b" // as in this case we know that we can write to the file) if (openMode_[0] == 'r' || openMode_[1] == '+') reopen = false; break; case opWrite: // Flush if current mode allows writing, else reopen if (openMode_[0] != 'r' || openMode_[1] == '+') reopen = false; break; case opSeek: reopen = false; break; } if (!reopen) { // Don't do anything when switching _from_ opSeek mode; we // flush when switching _to_ opSeek. if (oldOpMode == opSeek) return 0; // Flush. On msvcrt fflush does not do the job std::fseek(fp_, 0, SEEK_CUR); return 0; } // Reopen the file long offset = std::ftell(fp_); if (offset == -1) return -1; // 'Manual' open("r+b") to avoid munmap() if (fp_ != 0) { std::fclose(fp_); fp_= 0; } openMode_ = "r+b"; opMode_ = opSeek; #ifdef EXV_UNICODE_PATH if (wpMode_ == wpUnicode) { fp_ = ::_wfopen(wpath_.c_str(), s2ws(openMode_).c_str()); } else #endif { fp_ = std::fopen(path_.c_str(), openMode_.c_str()); } if (!fp_) return 1; return std::fseek(fp_, offset, SEEK_SET); } // FileIo::Impl::switchMode int FileIo::Impl::stat(StructStat& buf) const { int ret = 0; #ifdef EXV_UNICODE_PATH if (wpMode_ == wpUnicode) { struct _stat st; ret = ::_wstat(wpath_.c_str(), &st); if (0 == ret) { buf.st_size = st.st_size; buf.st_mode = st.st_mode; buf.st_nlink = st.st_nlink; } } else #endif { struct stat st; ret = ::stat(path_.c_str(), &st); if (0 == ret) { buf.st_size = st.st_size; buf.st_mode = st.st_mode; buf.st_nlink = st.st_nlink; } } return ret; } // FileIo::Impl::stat #if defined WIN32 && !defined __CYGWIN__ DWORD FileIo::Impl::winNumberOfLinks() const { DWORD nlink = 1; HANDLE hFd = (HANDLE)_get_osfhandle(fileno(fp_)); if (hFd != INVALID_HANDLE_VALUE) { typedef BOOL (WINAPI * GetFileInformationByHandle_t)(HANDLE, LPBY_HANDLE_FILE_INFORMATION); HMODULE hKernel = LoadLibraryA("kernel32.dll"); if (hKernel) { GetFileInformationByHandle_t pfcn_GetFileInformationByHandle = (GetFileInformationByHandle_t)GetProcAddress(hKernel, "GetFileInformationByHandle"); if (pfcn_GetFileInformationByHandle) { BY_HANDLE_FILE_INFORMATION fi = {0}; if (pfcn_GetFileInformationByHandle(hFd, &fi)) { nlink = fi.nNumberOfLinks; } #ifdef DEBUG else EXV_DEBUG << "GetFileInformationByHandle failed\n"; #endif } #ifdef DEBUG else EXV_DEBUG << "GetProcAddress(hKernel, \"GetFileInformationByHandle\") failed\n"; #endif FreeLibrary(hKernel); } #ifdef DEBUG else EXV_DEBUG << "LoadLibraryA(\"kernel32.dll\") failed\n"; #endif } #ifdef DEBUG else EXV_DEBUG << "_get_osfhandle failed: INVALID_HANDLE_VALUE\n"; #endif return nlink; } // FileIo::Impl::winNumberOfLinks #endif // defined WIN32 && !defined __CYGWIN__ FileIo::FileIo(const std::string& path) : p_(new Impl(path)) { } #ifdef EXV_UNICODE_PATH FileIo::FileIo(const std::wstring& wpath) : p_(new Impl(wpath)) { } #endif FileIo::~FileIo() { close(); delete p_; } int FileIo::munmap() { int rc = 0; if (p_->pMappedArea_ != 0) { #if defined EXV_HAVE_MMAP && defined EXV_HAVE_MUNMAP if (::munmap(p_->pMappedArea_, p_->mappedLength_) != 0) { rc = 1; } #elif defined WIN32 && !defined __CYGWIN__ UnmapViewOfFile(p_->pMappedArea_); CloseHandle(p_->hMap_); p_->hMap_ = 0; CloseHandle(p_->hFile_); p_->hFile_ = 0; #else if (p_->isWriteable_) { seek(0, BasicIo::beg); write(p_->pMappedArea_, p_->mappedLength_); } if (p_->isMalloced_) { delete[] p_->pMappedArea_; p_->isMalloced_ = false; } #endif } if (p_->isWriteable_) { if (p_->fp_ != 0) p_->switchMode(Impl::opRead); p_->isWriteable_ = false; } p_->pMappedArea_ = 0; p_->mappedLength_ = 0; return rc; } byte* FileIo::mmap(bool isWriteable) { assert(p_->fp_ != 0); if (munmap() != 0) { #ifdef EXV_UNICODE_PATH if (p_->wpMode_ == Impl::wpUnicode) { throw WError(2, wpath(), strError().c_str(), "munmap"); } else #endif { throw Error(2, path(), strError(), "munmap"); } } p_->mappedLength_ = size(); p_->isWriteable_ = isWriteable; if (p_->isWriteable_ && p_->switchMode(Impl::opWrite) != 0) { #ifdef EXV_UNICODE_PATH if (p_->wpMode_ == Impl::wpUnicode) { throw WError(16, wpath(), strError().c_str()); } else #endif { throw Error(16, path(), strError()); } } #if defined EXV_HAVE_MMAP && defined EXV_HAVE_MUNMAP int prot = PROT_READ; if (p_->isWriteable_) { prot |= PROT_WRITE; } void* rc = ::mmap(0, p_->mappedLength_, prot, MAP_SHARED, fileno(p_->fp_), 0); if (MAP_FAILED == rc) { #ifdef EXV_UNICODE_PATH if (p_->wpMode_ == Impl::wpUnicode) { throw WError(2, wpath(), strError().c_str(), "mmap"); } else #endif { throw Error(2, path(), strError(), "mmap"); } } p_->pMappedArea_ = static_cast(rc); #elif defined WIN32 && !defined __CYGWIN__ // Windows implementation // TODO: An attempt to map a file with a length of 0 (zero) fails with // an error code of ERROR_FILE_INVALID. // Applications should test for files with a length of 0 (zero) and // reject those files. DWORD dwAccess = FILE_MAP_READ; DWORD flProtect = PAGE_READONLY; if (isWriteable) { dwAccess = FILE_MAP_WRITE; flProtect = PAGE_READWRITE; } HANDLE hPh = GetCurrentProcess(); HANDLE hFd = (HANDLE)_get_osfhandle(fileno(p_->fp_)); if (hFd == INVALID_HANDLE_VALUE) { #ifdef EXV_UNICODE_PATH if (p_->wpMode_ == Impl::wpUnicode) { throw WError(2, wpath(), "MSG1", "_get_osfhandle"); } else #endif { throw Error(2, path(), "MSG1", "_get_osfhandle"); } } if (!DuplicateHandle(hPh, hFd, hPh, &p_->hFile_, 0, false, DUPLICATE_SAME_ACCESS)) { #ifdef EXV_UNICODE_PATH if (p_->wpMode_ == Impl::wpUnicode) { throw WError(2, wpath(), "MSG2", "DuplicateHandle"); } else #endif { throw Error(2, path(), "MSG2", "DuplicateHandle"); } } p_->hMap_ = CreateFileMapping(p_->hFile_, 0, flProtect, 0, (DWORD) p_->mappedLength_, 0); if (p_->hMap_ == 0 ) { #ifdef EXV_UNICODE_PATH if (p_->wpMode_ == Impl::wpUnicode) { throw WError(2, wpath(), "MSG3", "CreateFileMapping"); } else #endif { throw Error(2, path(), "MSG3", "CreateFileMapping"); } } void* rc = MapViewOfFile(p_->hMap_, dwAccess, 0, 0, 0); if (rc == 0) { #ifdef EXV_UNICODE_PATH if (p_->wpMode_ == Impl::wpUnicode) { throw WError(2, wpath(), "MSG4", "CreateFileMapping"); } else #endif { throw Error(2, path(), "MSG4", "CreateFileMapping"); } } p_->pMappedArea_ = static_cast(rc); #else // Workaround for platforms without mmap: Read the file into memory DataBuf buf(static_cast(p_->mappedLength_)); if (read(buf.pData_, buf.size_) != buf.size_) { #ifdef EXV_UNICODE_PATH if (p_->wpMode_ == Impl::wpUnicode) { throw WError(2, wpath(), strError().c_str(), "FileIo::read"); } else #endif { throw Error(2, path(), strError(), "FileIo::read"); } } if (error() || eof()) { #ifdef EXV_UNICODE_PATH if (p_->wpMode_ == Impl::wpUnicode) { throw WError(2, wpath(), strError().c_str(), "FileIo::mmap"); } else #endif { throw Error(2, path(), strError(), "FileIo::mmap"); } } p_->pMappedArea_ = buf.release().first; p_->isMalloced_ = true; #endif return p_->pMappedArea_; } BasicIo::AutoPtr FileIo::temporary() const { BasicIo::AutoPtr basicIo; Impl::StructStat buf; int ret = p_->stat(buf); #if defined WIN32 && !defined __CYGWIN__ DWORD nlink = p_->winNumberOfLinks(); #else nlink_t nlink = buf.st_nlink; #endif // If file is > 1MB and doesn't have hard links then use a file, otherwise // use a memory buffer. I.e., files with hard links always use a memory // buffer, which is a workaround to ensure that the links don't get broken. if (ret != 0 || (buf.st_size > 1048576 && nlink == 1)) { pid_t pid = ::getpid(); std::auto_ptr fileIo; #ifdef EXV_UNICODE_PATH if (p_->wpMode_ == Impl::wpUnicode) { std::wstring tmpname = wpath() + s2ws(toString(pid)); fileIo = std::auto_ptr(new FileIo(tmpname)); } else #endif { std::string tmpname = path() + toString(pid); fileIo = std::auto_ptr(new FileIo(tmpname)); } if (fileIo->open("w+b") != 0) { #ifdef EXV_UNICODE_PATH if (p_->wpMode_ == Impl::wpUnicode) { throw WError(10, wpath(), "w+b", strError().c_str()); } else #endif { throw Error(10, path(), "w+b", strError()); } } basicIo = fileIo; } else { basicIo.reset(new MemIo); } return basicIo; } long FileIo::write(const byte* data, long wcount) { assert(p_->fp_ != 0); if (p_->switchMode(Impl::opWrite) != 0) return 0; return (long)std::fwrite(data, 1, wcount, p_->fp_); } long FileIo::write(BasicIo& src) { assert(p_->fp_ != 0); if (static_cast(this) == &src) return 0; if (!src.isopen()) return 0; if (p_->switchMode(Impl::opWrite) != 0) return 0; byte buf[4096]; long readCount = 0; long writeCount = 0; long writeTotal = 0; while ((readCount = src.read(buf, sizeof(buf)))) { writeTotal += writeCount = (long)std::fwrite(buf, 1, readCount, p_->fp_); if (writeCount != readCount) { // try to reset back to where write stopped src.seek(writeCount-readCount, BasicIo::cur); break; } } return writeTotal; } void FileIo::transfer(BasicIo& src) { const bool wasOpen = (p_->fp_ != 0); const std::string lastMode(p_->openMode_); FileIo *fileIo = dynamic_cast(&src); if (fileIo) { // Optimization if src is another instance of FileIo fileIo->close(); // Check if the file can be written to, if it already exists if (open("a+b") != 0) { // Remove the (temporary) file #ifdef EXV_UNICODE_PATH if (fileIo->p_->wpMode_ == Impl::wpUnicode) { ::_wremove(fileIo->wpath().c_str()); } else #endif { ::remove(fileIo->path().c_str()); } #ifdef EXV_UNICODE_PATH if (p_->wpMode_ == Impl::wpUnicode) { throw WError(10, wpath(), "a+b", strError().c_str()); } else #endif { throw Error(10, path(), "a+b", strError()); } } close(); bool statOk = true; mode_t origStMode = 0; std::string spf; char* pf = 0; #ifdef EXV_UNICODE_PATH std::wstring wspf; wchar_t* wpf = 0; if (p_->wpMode_ == Impl::wpUnicode) { wspf = wpath(); wpf = const_cast(wspf.c_str()); } else #endif { spf = path(); pf = const_cast(spf.c_str()); } // Get the permissions of the file, or linked-to file, on platforms which have lstat #ifdef EXV_HAVE_LSTAT # ifdef EXV_UNICODE_PATH # error EXV_UNICODE_PATH and EXV_HAVE_LSTAT are not compatible. Stop. # endif struct stat buf1; if (::lstat(pf, &buf1) == -1) { statOk = false; #ifndef SUPPRESS_WARNINGS EXV_WARNING << Error(2, pf, strError(), "::lstat") << "\n"; #endif } origStMode = buf1.st_mode; DataBuf lbuf; // So that the allocated memory is freed. Must have same scope as pf // In case path() is a symlink, get the path of the linked-to file if (statOk && S_ISLNK(buf1.st_mode)) { lbuf.alloc(buf1.st_size + 1); memset(lbuf.pData_, 0x0, lbuf.size_); pf = reinterpret_cast(lbuf.pData_); if (::readlink(path().c_str(), pf, lbuf.size_ - 1) == -1) { throw Error(2, path(), strError(), "readlink"); } // We need the permissions of the file, not the symlink if (::stat(pf, &buf1) == -1) { statOk = false; #ifndef SUPPRESS_WARNINGS EXV_WARNING << Error(2, pf, strError(), "::stat") << "\n"; #endif } origStMode = buf1.st_mode; } #else // EXV_HAVE_LSTAT Impl::StructStat buf1; if (p_->stat(buf1) == -1) { statOk = false; } origStMode = buf1.st_mode; #endif // !EXV_HAVE_LSTAT // MSVCRT rename that does not overwrite existing files #ifdef EXV_UNICODE_PATH if (p_->wpMode_ == Impl::wpUnicode) { if (fileExists(wpf) && ::_wremove(wpf) != 0) { throw WError(2, wpf, strError().c_str(), "::_wremove"); } if (::_wrename(fileIo->wpath().c_str(), wpf) == -1) { throw WError(17, fileIo->wpath(), wpf, strError().c_str()); } ::_wremove(fileIo->wpath().c_str()); // Check permissions of new file struct _stat buf2; if (statOk && ::_wstat(wpf, &buf2) == -1) { statOk = false; #ifndef SUPPRESS_WARNINGS EXV_WARNING << Error(2, wpf, strError(), "::_wstat") << "\n"; #endif } if (statOk && origStMode != buf2.st_mode) { // Set original file permissions if (::_wchmod(wpf, origStMode) == -1) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << Error(2, wpf, strError(), "::_wchmod") << "\n"; #endif } } } // if (p_->wpMode_ == Impl::wpUnicode) else #endif // EXV_UNICODE_PATH { if (fileExists(pf) && ::remove(pf) != 0) { throw Error(2, pf, strError(), "::remove"); } if (::rename(fileIo->path().c_str(), pf) == -1) { throw Error(17, fileIo->path(), pf, strError()); } ::remove(fileIo->path().c_str()); // Check permissions of new file struct stat buf2; if (statOk && ::stat(pf, &buf2) == -1) { statOk = false; #ifndef SUPPRESS_WARNINGS EXV_WARNING << Error(2, pf, strError(), "::stat") << "\n"; #endif } if (statOk && origStMode != buf2.st_mode) { // Set original file permissions if (::chmod(pf, origStMode) == -1) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << Error(2, pf, strError(), "::chmod") << "\n"; #endif } } } } // if (fileIo) else { // Generic handling, reopen both to reset to start if (open("w+b") != 0) { #ifdef EXV_UNICODE_PATH if (p_->wpMode_ == Impl::wpUnicode) { throw WError(10, wpath(), "w+b", strError().c_str()); } else #endif { throw Error(10, path(), "w+b", strError()); } } if (src.open() != 0) { #ifdef EXV_UNICODE_PATH if (p_->wpMode_ == Impl::wpUnicode) { throw WError(9, src.wpath(), strError().c_str()); } else #endif { throw Error(9, src.path(), strError()); } } write(src); src.close(); } if (wasOpen) { if (open(lastMode) != 0) { #ifdef EXV_UNICODE_PATH if (p_->wpMode_ == Impl::wpUnicode) { throw WError(10, wpath(), lastMode.c_str(), strError().c_str()); } else #endif { throw Error(10, path(), lastMode, strError()); } } } else close(); if (error() || src.error()) { #ifdef EXV_UNICODE_PATH if (p_->wpMode_ == Impl::wpUnicode) { throw WError(18, wpath(), strError().c_str()); } else #endif { throw Error(18, path(), strError()); } } } // FileIo::transfer int FileIo::putb(byte data) { assert(p_->fp_ != 0); if (p_->switchMode(Impl::opWrite) != 0) return EOF; return putc(data, p_->fp_); } int FileIo::seek(long offset, Position pos) { assert(p_->fp_ != 0); int fileSeek = 0; switch (pos) { case BasicIo::cur: fileSeek = SEEK_CUR; break; case BasicIo::beg: fileSeek = SEEK_SET; break; case BasicIo::end: fileSeek = SEEK_END; break; } if (p_->switchMode(Impl::opSeek) != 0) return 1; return std::fseek(p_->fp_, offset, fileSeek); } long FileIo::tell() const { assert(p_->fp_ != 0); return std::ftell(p_->fp_); } long FileIo::size() const { // Flush and commit only if the file is open for writing if (p_->fp_ != 0 && (p_->openMode_[0] != 'r' || p_->openMode_[1] == '+')) { std::fflush(p_->fp_); #if defined WIN32 && !defined __CYGWIN__ // This is required on msvcrt before stat after writing to a file _commit(_fileno(p_->fp_)); #endif } Impl::StructStat buf; int ret = p_->stat(buf); if (ret != 0) return -1; return buf.st_size; } int FileIo::open() { // Default open is in read-only binary mode return open("rb"); } int FileIo::open(const std::string& mode) { close(); p_->openMode_ = mode; p_->opMode_ = Impl::opSeek; #ifdef EXV_UNICODE_PATH if (p_->wpMode_ == Impl::wpUnicode) { p_->fp_ = ::_wfopen(wpath().c_str(), s2ws(mode).c_str()); } else #endif { p_->fp_ = ::fopen(path().c_str(), mode.c_str()); } if (!p_->fp_) return 1; return 0; } bool FileIo::isopen() const { return p_->fp_ != 0; } int FileIo::close() { int rc = 0; if (munmap() != 0) rc = 2; if (p_->fp_ != 0) { if (std::fclose(p_->fp_) != 0) rc |= 1; p_->fp_= 0; } return rc; } DataBuf FileIo::read(long rcount) { assert(p_->fp_ != 0); DataBuf buf(rcount); long readCount = read(buf.pData_, buf.size_); buf.size_ = readCount; return buf; } long FileIo::read(byte* buf, long rcount) { assert(p_->fp_ != 0); if (p_->switchMode(Impl::opRead) != 0) return 0; return (long)std::fread(buf, 1, rcount, p_->fp_); } int FileIo::getb() { assert(p_->fp_ != 0); if (p_->switchMode(Impl::opRead) != 0) return EOF; return getc(p_->fp_); } int FileIo::error() const { return p_->fp_ != 0 ? ferror(p_->fp_) : 0; } bool FileIo::eof() const { assert(p_->fp_ != 0); return feof(p_->fp_) != 0; } std::string FileIo::path() const { #ifdef EXV_UNICODE_PATH if (p_->wpMode_ == Impl::wpUnicode) { return ws2s(p_->wpath_); } #endif return p_->path_; } #ifdef EXV_UNICODE_PATH std::wstring FileIo::wpath() const { if (p_->wpMode_ == Impl::wpStandard) { return s2ws(p_->path_); } return p_->wpath_; } #endif //! Internal Pimpl structure of class MemIo. class MemIo::Impl { public: Impl(); //!< Default constructor Impl(const byte* data, long size); //!< Constructor 2 // DATA byte* data_; //!< Pointer to the start of the memory area long idx_; //!< Index into the memory area long size_; //!< Size of the memory area long sizeAlloced_; //!< Size of the allocated buffer bool isMalloced_; //!< Was the buffer allocated? bool eof_; //!< EOF indicator // METHODS void reserve(long wcount); //!< Reserve memory private: // NOT IMPLEMENTED Impl(const Impl& rhs); //!< Copy constructor Impl& operator=(const Impl& rhs); //!< Assignment }; // class MemIo::Impl MemIo::Impl::Impl() : data_(0), idx_(0), size_(0), sizeAlloced_(0), isMalloced_(false), eof_(false) { } MemIo::Impl::Impl(const byte* data, long size) : data_(const_cast(data)), idx_(0), size_(size), sizeAlloced_(0), isMalloced_(false), eof_(false) { } void MemIo::Impl::reserve(long wcount) { long need = wcount + idx_; if (!isMalloced_) { // Minimum size for 1st block is 32kB long size = EXV_MAX(32768 * (1 + need / 32768), size_); byte* data = (byte*)std::malloc(size); std::memcpy(data, data_, size_); data_ = data; sizeAlloced_ = size; isMalloced_ = true; } if (need > size_) { if (need > sizeAlloced_) { // Allocate in blocks of 32kB long want = 32768 * (1 + need / 32768); data_ = (byte*)std::realloc(data_, want); sizeAlloced_ = want; isMalloced_ = true; } size_ = need; } } MemIo::MemIo() : p_(new Impl()) { } MemIo::MemIo(const byte* data, long size) : p_(new Impl(data, size)) { } MemIo::~MemIo() { if (p_->isMalloced_) { std::free(p_->data_); } delete p_; } BasicIo::AutoPtr MemIo::temporary() const { return BasicIo::AutoPtr(new MemIo); } long MemIo::write(const byte* data, long wcount) { p_->reserve(wcount); assert(p_->isMalloced_); std::memcpy(&p_->data_[p_->idx_], data, wcount); p_->idx_ += wcount; return wcount; } void MemIo::transfer(BasicIo& src) { MemIo *memIo = dynamic_cast(&src); if (memIo) { // Optimization if src is another instance of MemIo if (true == p_->isMalloced_) { std::free(p_->data_); } p_->idx_ = 0; p_->data_ = memIo->p_->data_; p_->size_ = memIo->p_->size_; p_->isMalloced_ = memIo->p_->isMalloced_; memIo->p_->idx_ = 0; memIo->p_->data_ = 0; memIo->p_->size_ = 0; memIo->p_->isMalloced_ = false; } else { // Generic reopen to reset position to start if (src.open() != 0) { throw Error(9, src.path(), strError()); } p_->idx_ = 0; write(src); src.close(); } if (error() || src.error()) throw Error(19, strError()); } long MemIo::write(BasicIo& src) { if (static_cast(this) == &src) return 0; if (!src.isopen()) return 0; byte buf[4096]; long readCount = 0; long writeTotal = 0; while ((readCount = src.read(buf, sizeof(buf)))) { write(buf, readCount); writeTotal += readCount; } return writeTotal; } int MemIo::putb(byte data) { p_->reserve(1); assert(p_->isMalloced_); p_->data_[p_->idx_++] = data; return data; } int MemIo::seek(long offset, Position pos) { long newIdx = 0; switch (pos) { case BasicIo::cur: newIdx = p_->idx_ + offset; break; case BasicIo::beg: newIdx = offset; break; case BasicIo::end: newIdx = p_->size_ + offset; break; } if (newIdx < 0 || newIdx > p_->size_) return 1; p_->idx_ = newIdx; p_->eof_ = false; return 0; } byte* MemIo::mmap(bool /*isWriteable*/) { return p_->data_; } int MemIo::munmap() { return 0; } long MemIo::tell() const { return p_->idx_; } long MemIo::size() const { return p_->size_; } int MemIo::open() { p_->idx_ = 0; p_->eof_ = false; return 0; } bool MemIo::isopen() const { return true; } int MemIo::close() { return 0; } DataBuf MemIo::read(long rcount) { DataBuf buf(rcount); long readCount = read(buf.pData_, buf.size_); buf.size_ = readCount; return buf; } long MemIo::read(byte* buf, long rcount) { long avail = p_->size_ - p_->idx_; long allow = EXV_MIN(rcount, avail); std::memcpy(buf, &p_->data_[p_->idx_], allow); p_->idx_ += allow; if (rcount > avail) p_->eof_ = true; return allow; } int MemIo::getb() { if (p_->idx_ == p_->size_) { p_->eof_ = true; return EOF; } return p_->data_[p_->idx_++]; } int MemIo::error() const { return 0; } bool MemIo::eof() const { return p_->eof_; } std::string MemIo::path() const { return "MemIo"; } #ifdef EXV_UNICODE_PATH std::wstring MemIo::wpath() const { return EXV_WIDEN("MemIo"); } #endif // ************************************************************************* // free functions DataBuf readFile(const std::string& path) { FileIo file(path); if (file.open("rb") != 0) { throw Error(10, path, "rb", strError()); } struct stat st; if (0 != ::stat(path.c_str(), &st)) { throw Error(2, path, strError(), "::stat"); } DataBuf buf(st.st_size); long len = file.read(buf.pData_, buf.size_); if (len != buf.size_) { throw Error(2, path, strError(), "FileIo::read"); } return buf; } #ifdef EXV_UNICODE_PATH DataBuf readFile(const std::wstring& wpath) { FileIo file(wpath); if (file.open("rb") != 0) { throw WError(10, wpath, "rb", strError().c_str()); } struct _stat st; if (0 != ::_wstat(wpath.c_str(), &st)) { throw WError(2, wpath, strError().c_str(), "::_wstat"); } DataBuf buf(st.st_size); long len = file.read(buf.pData_, buf.size_); if (len != buf.size_) { throw WError(2, wpath, strError().c_str(), "FileIo::read"); } return buf; } #endif long writeFile(const DataBuf& buf, const std::string& path) { FileIo file(path); if (file.open("wb") != 0) { throw Error(10, path, "wb", strError()); } return file.write(buf.pData_, buf.size_); } #ifdef EXV_UNICODE_PATH long writeFile(const DataBuf& buf, const std::wstring& wpath) { FileIo file(wpath); if (file.open("wb") != 0) { throw WError(10, wpath, "wb", strError().c_str()); } return file.write(buf.pData_, buf.size_); } #endif } // namespace Exiv2 exiv2-0.23/src/pngchunk.cpp0000644000175000017500000006171411732641407015435 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /* File: pngchunk.cpp Version: $Rev: 2681 $ Author(s): Gilles Caulier (cgilles) History: 12-Jun-06, gc: submitted Credits: See header file */ // ***************************************************************************** #include "rcsid_int.hpp" EXIV2_RCSID("@(#) $Id: pngchunk.cpp 2681 2012-03-22 15:19:35Z ahuggel $") // ***************************************************************************** // included header files #ifdef _MSC_VER # include "exv_msvc.h" #else # include "exv_conf.h" #endif //#define DEBUG 1 #ifdef EXV_HAVE_LIBZ extern "C" { #include // To uncompress or compress text chunk } #include "pngchunk_int.hpp" #include "tiffimage.hpp" #include "jpgimage.hpp" #include "exif.hpp" #include "iptc.hpp" #include "image.hpp" #include "error.hpp" // + standard includes #include #include #include #include #include #include #include /* URLs to find informations about PNG chunks : tEXt and zTXt chunks : http://www.vias.org/pngguide/chapter11_04.html iTXt chunk : http://www.vias.org/pngguide/chapter11_05.html PNG tags : http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/PNG.html#TextualData */ // ***************************************************************************** // class member definitions namespace Exiv2 { namespace Internal { void PngChunk::decodeIHDRChunk(const DataBuf& data, int* outWidth, int* outHeight) { // Extract image width and height from IHDR chunk. *outWidth = getLong((const byte*)data.pData_, bigEndian); *outHeight = getLong((const byte*)data.pData_ + 4, bigEndian); } // PngChunk::decodeIHDRChunk void PngChunk::decodeTXTChunk(Image* pImage, const DataBuf& data, TxtChunkType type) { DataBuf key = keyTXTChunk(data); #ifdef DEBUG std::cout << "Exiv2::PngChunk::decodeTXTChunk: TXT chunk key: " << std::string((const char*)key.pData_, key.size_) << "\n"; #endif DataBuf arr = parseTXTChunk(data, key.size_, type); #ifdef DEBUG std::cout << "Exiv2::PngChunk::decodeTXTChunk: TXT chunk data: " << std::string((const char*)arr.pData_, arr.size_) << "\n"; #endif parseChunkContent(pImage, key.pData_, key.size_, arr); } // PngChunk::decodeTXTChunk DataBuf PngChunk::keyTXTChunk(const DataBuf& data, bool stripHeader) { // From a tEXt, zTXt, or iTXt chunk, // we get the key, it's a null terminated string at the chunk start if (data.size_ <= (stripHeader ? 8 : 0)) throw Error(14); const byte *key = data.pData_ + (stripHeader ? 8 : 0); // Find null string at end of key. int keysize=0; for ( ; key[keysize] != 0 ; keysize++) { // look if keysize is valid. if (keysize >= data.size_) throw Error(14); } return DataBuf(key, keysize); } // PngChunk::keyTXTChunk DataBuf PngChunk::parseTXTChunk(const DataBuf& data, int keysize, TxtChunkType type) { DataBuf arr; if(type == zTXt_Chunk) { // Extract a deflate compressed Latin-1 text chunk // we get the compression method after the key const byte* compressionMethod = data.pData_ + keysize + 1; if ( *compressionMethod != 0x00 ) { // then it isn't zlib compressed and we are sunk #ifdef DEBUG std::cerr << "Exiv2::PngChunk::parseTXTChunk: Non-standard zTXt compression method.\n"; #endif throw Error(14); } // compressed string after the compression technique spec const byte* compressedText = data.pData_ + keysize + 2; unsigned int compressedTextSize = data.size_ - keysize - 2; zlibUncompress(compressedText, compressedTextSize, arr); } else if(type == tEXt_Chunk) { // Extract a non-compressed Latin-1 text chunk // the text comes after the key, but isn't null terminated const byte* text = data.pData_ + keysize + 1; long textsize = data.size_ - keysize - 1; arr = DataBuf(text, textsize); } else if(type == iTXt_Chunk) { // Extract a deflate compressed or uncompressed UTF-8 text chunk // we get the compression flag after the key const byte* compressionFlag = data.pData_ + keysize + 1; // we get the compression method after the compression flag const byte* compressionMethod = data.pData_ + keysize + 2; // language description string after the compression technique spec std::string languageText((const char*)(data.pData_ + keysize + 3)); unsigned int languageTextSize = static_cast(languageText.size()); // translated keyword string after the language description std::string translatedKeyText((const char*)(data.pData_ + keysize + 3 + languageTextSize +1)); unsigned int translatedKeyTextSize = static_cast(translatedKeyText.size()); if ( compressionFlag[0] == 0x00 ) { // then it's an uncompressed iTXt chunk #ifdef DEBUG std::cout << "Exiv2::PngChunk::parseTXTChunk: We found an uncompressed iTXt field\n"; #endif // the text comes after the translated keyword, but isn't null terminated const byte* text = data.pData_ + keysize + 3 + languageTextSize + 1 + translatedKeyTextSize + 1; long textsize = data.size_ - (keysize + 3 + languageTextSize + 1 + translatedKeyTextSize + 1); arr.alloc(textsize); arr = DataBuf(text, textsize); } else if ( compressionFlag[0] == 0x01 && compressionMethod[0] == 0x00 ) { // then it's a zlib compressed iTXt chunk #ifdef DEBUG std::cout << "Exiv2::PngChunk::parseTXTChunk: We found a zlib compressed iTXt field\n"; #endif // the compressed text comes after the translated keyword, but isn't null terminated const byte* compressedText = data.pData_ + keysize + 3 + languageTextSize + 1 + translatedKeyTextSize + 1; long compressedTextSize = data.size_ - (keysize + 3 + languageTextSize + 1 + translatedKeyTextSize + 1); zlibUncompress(compressedText, compressedTextSize, arr); } else { // then it isn't zlib compressed and we are sunk #ifdef DEBUG std::cerr << "Exiv2::PngChunk::parseTXTChunk: Non-standard iTXt compression method.\n"; #endif throw Error(14); } } else { #ifdef DEBUG std::cerr << "Exiv2::PngChunk::parseTXTChunk: We found a field, not expected though\n"; #endif throw Error(14); } return arr; } // PngChunk::parsePngChunk void PngChunk::parseChunkContent( Image* pImage, const byte* key, long keySize, const DataBuf arr) { // We look if an ImageMagick EXIF raw profile exist. if ( keySize >= 21 && ( memcmp("Raw profile type exif", key, 21) == 0 || memcmp("Raw profile type APP1", key, 21) == 0) && pImage->exifData().empty()) { DataBuf exifData = readRawProfile(arr); long length = exifData.size_; if (length > 0) { // Find the position of Exif header in bytes array. const byte exifHeader[] = { 0x45, 0x78, 0x69, 0x66, 0x00, 0x00 }; long pos = -1; for (long i=0 ; i < length-(long)sizeof(exifHeader) ; i++) { if (memcmp(exifHeader, &exifData.pData_[i], sizeof(exifHeader)) == 0) { pos = i; break; } } // If found it, store only these data at from this place. if (pos !=-1) { #ifdef DEBUG std::cout << "Exiv2::PngChunk::parseChunkContent: Exif header found at position " << pos << "\n"; #endif pos = pos + sizeof(exifHeader); ByteOrder bo = TiffParser::decode(pImage->exifData(), pImage->iptcData(), pImage->xmpData(), exifData.pData_ + pos, length - pos); pImage->setByteOrder(bo); } else { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Failed to decode Exif metadata.\n"; #endif pImage->exifData().clear(); } } } // We look if an ImageMagick IPTC raw profile exist. if ( keySize >= 21 && memcmp("Raw profile type iptc", key, 21) == 0 && pImage->iptcData().empty()) { DataBuf psData = readRawProfile(arr); if (psData.size_ > 0) { Blob iptcBlob; const byte *record = 0; uint32_t sizeIptc = 0; uint32_t sizeHdr = 0; const byte* pEnd = psData.pData_ + psData.size_; const byte* pCur = psData.pData_; while ( pCur < pEnd && 0 == Photoshop::locateIptcIrb(pCur, static_cast(pEnd - pCur), &record, &sizeHdr, &sizeIptc)) { if (sizeIptc) { #ifdef DEBUG std::cerr << "Found IPTC IRB, size = " << sizeIptc << "\n"; #endif append(iptcBlob, record + sizeHdr, sizeIptc); } pCur = record + sizeHdr + sizeIptc; pCur += (sizeIptc & 1); } if ( iptcBlob.size() > 0 && IptcParser::decode(pImage->iptcData(), &iptcBlob[0], static_cast(iptcBlob.size()))) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Failed to decode IPTC metadata.\n"; #endif pImage->clearIptcData(); } // If there is no IRB, try to decode the complete chunk data if ( iptcBlob.empty() && IptcParser::decode(pImage->iptcData(), psData.pData_, psData.size_)) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Failed to decode IPTC metadata.\n"; #endif pImage->clearIptcData(); } } // if (psData.size_ > 0) } // We look if an ImageMagick XMP raw profile exist. if ( keySize >= 20 && memcmp("Raw profile type xmp", key, 20) == 0 && pImage->xmpData().empty()) { DataBuf xmpBuf = readRawProfile(arr); long length = xmpBuf.size_; if (length > 0) { std::string& xmpPacket = pImage->xmpPacket(); xmpPacket.assign(reinterpret_cast(xmpBuf.pData_), length); std::string::size_type idx = xmpPacket.find_first_of('<'); if (idx != std::string::npos && idx > 0) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Removing " << idx << " characters from the beginning of the XMP packet\n"; #endif xmpPacket = xmpPacket.substr(idx); } if (XmpParser::decode(pImage->xmpData(), xmpPacket)) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Failed to decode XMP metadata.\n"; #endif } } } // We look if an Adobe XMP string exist. if ( keySize >= 17 && memcmp("XML:com.adobe.xmp", key, 17) == 0 && pImage->xmpData().empty()) { if (arr.size_ > 0) { std::string& xmpPacket = pImage->xmpPacket(); xmpPacket.assign(reinterpret_cast(arr.pData_), arr.size_); std::string::size_type idx = xmpPacket.find_first_of('<'); if (idx != std::string::npos && idx > 0) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Removing " << idx << " characters " << "from the beginning of the XMP packet\n"; #endif xmpPacket = xmpPacket.substr(idx); } if (XmpParser::decode(pImage->xmpData(), xmpPacket)) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Failed to decode XMP metadata.\n"; #endif } } } // We look if a comments string exist. Note than we use only 'Description' keyword which // is dedicaced to store long comments. 'Comment' keyword is ignored. if ( keySize >= 11 && memcmp("Description", key, 11) == 0 && pImage->comment().empty()) { pImage->setComment(std::string(reinterpret_cast(arr.pData_), arr.size_)); } } // PngChunk::parseChunkContent std::string PngChunk::makeMetadataChunk(const std::string& metadata, MetadataId type) { std::string chunk; std::string rawProfile; switch (type) { case mdComment: chunk = makeUtf8TxtChunk("Description", metadata, true); break; case mdExif: rawProfile = writeRawProfile(metadata, "exif"); chunk = makeAsciiTxtChunk("Raw profile type exif", rawProfile, true); break; case mdIptc: rawProfile = writeRawProfile(metadata, "iptc"); chunk = makeAsciiTxtChunk("Raw profile type iptc", rawProfile, true); break; case mdXmp: chunk = makeUtf8TxtChunk("XML:com.adobe.xmp", metadata, false); break; case mdNone: assert(false); } return chunk; } // PngChunk::makeMetadataChunk void PngChunk::zlibUncompress(const byte* compressedText, unsigned int compressedTextSize, DataBuf& arr) { uLongf uncompressedLen = compressedTextSize * 2; // just a starting point int zlibResult; int dos = 0; do { arr.alloc(uncompressedLen); zlibResult = uncompress((Bytef*)arr.pData_, &uncompressedLen, compressedText, compressedTextSize); if (zlibResult == Z_OK) { assert((uLongf)arr.size_ >= uncompressedLen); arr.size_ = uncompressedLen; } else if (zlibResult == Z_BUF_ERROR) { // the uncompressedArray needs to be larger uncompressedLen *= 2; // DoS protection. can't be bigger than 64k if (uncompressedLen > 131072) { if (++dos > 1) break; uncompressedLen = 131072; } } else { // something bad happened throw Error(14); } } while (zlibResult == Z_BUF_ERROR); if (zlibResult != Z_OK) { throw Error(14); } } // PngChunk::zlibUncompress std::string PngChunk::zlibCompress(const std::string& text) { uLongf compressedLen = static_cast(text.size() * 2); // just a starting point int zlibResult; DataBuf arr; do { arr.alloc(compressedLen); zlibResult = compress2((Bytef*)arr.pData_, &compressedLen, (const Bytef*)text.data(), static_cast(text.size()), Z_BEST_COMPRESSION); switch (zlibResult) { case Z_OK: assert((uLongf)arr.size_ >= compressedLen); arr.size_ = compressedLen; break; case Z_BUF_ERROR: // The compressed array needs to be larger #ifdef DEBUG std::cout << "Exiv2::PngChunk::parsePngChunk: doubling size for compression.\n"; #endif compressedLen *= 2; // DoS protection. Cap max compressed size if ( compressedLen > 131072 ) throw Error(14); break; default: // Something bad happened throw Error(14); } } while (zlibResult == Z_BUF_ERROR); return std::string((const char*)arr.pData_, arr.size_); } // PngChunk::zlibCompress std::string PngChunk::makeAsciiTxtChunk(const std::string& keyword, const std::string& text, bool compress) { // Chunk structure: length (4 bytes) + chunk type + chunk data + CRC (4 bytes) // Length is the size of the chunk data // CRC is calculated on chunk type + chunk data // Compressed text chunk using zlib. // Chunk data format : keyword + 0x00 + compression method (0x00) + compressed text // Not Compressed text chunk. // Chunk data format : keyword + 0x00 + text // Build chunk data, determine chunk type std::string chunkData = keyword + '\0'; std::string chunkType; if (compress) { chunkData += '\0' + zlibCompress(text); chunkType = "zTXt"; } else { chunkData += text; chunkType = "tEXt"; } // Determine length of the chunk data byte length[4]; ul2Data(length, static_cast(chunkData.size()), bigEndian); // Calculate CRC on chunk type and chunk data std::string crcData = chunkType + chunkData; uLong tmp = crc32(0L, Z_NULL, 0); tmp = crc32(tmp, (const Bytef*)crcData.data(), static_cast(crcData.size())); byte crc[4]; ul2Data(crc, tmp, bigEndian); // Assemble the chunk return std::string((const char*)length, 4) + chunkType + chunkData + std::string((const char*)crc, 4); } // PngChunk::makeAsciiTxtChunk std::string PngChunk::makeUtf8TxtChunk(const std::string& keyword, const std::string& text, bool compress) { // Chunk structure: length (4 bytes) + chunk type + chunk data + CRC (4 bytes) // Length is the size of the chunk data // CRC is calculated on chunk type + chunk data // Chunk data format : keyword + 0x00 + compression flag (0x00: uncompressed - 0x01: compressed) // + compression method (0x00: zlib format) + language tag (null) + 0x00 // + translated keyword (null) + 0x00 + text (compressed or not) // Build chunk data, determine chunk type std::string chunkData = keyword; if (compress) { static const char flags[] = { 0x00, 0x01, 0x00, 0x00, 0x00 }; chunkData += std::string(flags, 5) + zlibCompress(text); } else { static const char flags[] = { 0x00, 0x00, 0x00, 0x00, 0x00 }; chunkData += std::string(flags, 5) + text; } // Determine length of the chunk data byte length[4]; ul2Data(length, static_cast(chunkData.size()), bigEndian); // Calculate CRC on chunk type and chunk data std::string chunkType = "iTXt"; std::string crcData = chunkType + chunkData; uLong tmp = crc32(0L, Z_NULL, 0); tmp = crc32(tmp, (const Bytef*)crcData.data(), static_cast(crcData.size())); byte crc[4]; ul2Data(crc, tmp, bigEndian); // Assemble the chunk return std::string((const char*)length, 4) + chunkType + chunkData + std::string((const char*)crc, 4); } // PngChunk::makeUtf8TxtChunk DataBuf PngChunk::readRawProfile(const DataBuf& text) { DataBuf info; register long i; register unsigned char *dp; const char *sp; unsigned int nibbles; long length; unsigned char unhex[103]={0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,1, 2,3,4,5,6,7,8,9,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,10,11,12, 13,14,15}; if (text.size_ == 0) { return DataBuf(); } sp = (char*)text.pData_+1; // Look for newline while (*sp != '\n') sp++; // Look for length while (*sp == '\0' || *sp == ' ' || *sp == '\n') sp++; length = (long) atol(sp); while (*sp != ' ' && *sp != '\n') sp++; // Allocate space if (length == 0) { #ifdef DEBUG std::cerr << "Exiv2::PngChunk::readRawProfile: Unable To Copy Raw Profile: invalid profile length\n"; #endif return DataBuf(); } info.alloc(length); if (info.size_ != length) { #ifdef DEBUG std::cerr << "Exiv2::PngChunk::readRawProfile: Unable To Copy Raw Profile: cannot allocate memory\n"; #endif return DataBuf(); } // Copy profile, skipping white space and column 1 "=" signs dp = (unsigned char*)info.pData_; nibbles = length * 2; for (i = 0; i < (long) nibbles; i++) { while (*sp < '0' || (*sp > '9' && *sp < 'a') || *sp > 'f') { if (*sp == '\0') { #ifdef DEBUG std::cerr << "Exiv2::PngChunk::readRawProfile: Unable To Copy Raw Profile: ran out of data\n"; #endif return DataBuf(); } sp++; } if (i%2 == 0) *dp = (unsigned char) (16*unhex[(int) *sp++]); else (*dp++) += unhex[(int) *sp++]; } return info; } // PngChunk::readRawProfile std::string PngChunk::writeRawProfile(const std::string& profileData, const char* profileType) { static byte hex[16] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'}; std::ostringstream oss; oss << '\n' << profileType << '\n' << std::setw(8) << profileData.size(); const char* sp = profileData.data(); for (std::string::size_type i = 0; i < profileData.size(); ++i) { if (i % 36 == 0) oss << '\n'; oss << hex[((*sp >> 4) & 0x0f)]; oss << hex[((*sp++) & 0x0f)]; } oss << '\n'; return oss.str(); } // PngChunk::writeRawProfile }} // namespace Internal, Exiv2 #endif // ifdef EXV_HAVE_LIBZ exiv2-0.23/src/pgfimage.cpp0000644000175000017500000002530711732641407015375 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /* File: pgfimage.cpp Version: $Rev: 2681 $ Author(s): Gilles Caulier (cgilles) History: 16-Jun-09, gc: submitted Credits: See header file */ // ***************************************************************************** #include "rcsid_int.hpp" EXIV2_RCSID("@(#) $Id: pgfimage.cpp 2681 2012-03-22 15:19:35Z ahuggel $") // ***************************************************************************** //#define DEBUG 1 // ***************************************************************************** // included header files #ifdef _MSC_VER # include "exv_msvc.h" #else # include "exv_conf.h" #endif #include "pgfimage.hpp" #include "image.hpp" #include "pngimage.hpp" #include "basicio.hpp" #include "error.hpp" #include "futils.hpp" // + standard includes #include // for EOF #include #include #include #include // Signature from front of PGF file const unsigned char pgfSignature[3] = { 0x50, 0x47, 0x46 }; const unsigned char pgfBlank[] = { 0x50,0x47,0x46,0x36,0x10,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00, 0x00,0x00,0x18,0x03,0x03,0x00,0x00,0x00,0x14,0x00,0x67,0x08,0x20,0x00,0xc0,0x01, 0x00,0x00,0x37,0x00,0x00,0x78,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x37,0x00, 0x00,0x78,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x37,0x00,0x00,0x78,0x00,0x00, 0x00,0x00,0x01,0x00,0x00,0x00,0x37,0x00,0x00,0x78,0x00,0x00,0x00,0x00,0x01,0x00, 0x00,0x00,0x37,0x00,0x00,0x78,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x37,0x00, 0x00,0x78,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00 }; // ***************************************************************************** // class member definitions namespace Exiv2 { PgfImage::PgfImage(BasicIo::AutoPtr io, bool create) : Image(ImageType::pgf, mdExif | mdIptc| mdXmp | mdComment, io) { if (create) { if (io_->open() == 0) { #ifdef DEBUG std::cerr << "Exiv2::PgfImage:: Creating PGF image to memory\n"; #endif IoCloser closer(*io_); if (io_->write(pgfBlank, sizeof(pgfBlank)) != sizeof(pgfBlank)) { #ifdef DEBUG std::cerr << "Exiv2::PgfImage:: Failed to create PGF image on memory\n"; #endif } } } } // PgfImage::PgfImage void PgfImage::readMetadata() { #ifdef DEBUG std::cerr << "Exiv2::PgfImage::readMetadata: Reading PGF file " << io_->path() << "\n"; #endif if (io_->open() != 0) { throw Error(9, io_->path(), strError()); } IoCloser closer(*io_); // Ensure that this is the correct image type if (!isPgfType(*io_, true)) { if (io_->error() || io_->eof()) throw Error(14); throw Error(3, "PGF"); } clearMetadata(); readPgfMagicNumber(*io_); uint32_t headerSize = readPgfHeaderSize(*io_); readPgfHeaderStructure(*io_, &pixelWidth_, &pixelHeight_); // And now, the most interresting, the user data byte array where metadata are stored as small image. long size = 8 + headerSize - io_->tell(); #ifdef DEBUG std::cout << "Exiv2::PgfImage::readMetadata: Found Image data (" << size << " bytes)\n"; #endif if (size < 0) throw Error(20); if (size == 0) return; DataBuf imgData(size); std::memset(imgData.pData_, 0x0, imgData.size_); long bufRead = io_->read(imgData.pData_, imgData.size_); if (io_->error()) throw Error(14); if (bufRead != imgData.size_) throw Error(20); Image::AutoPtr image = Exiv2::ImageFactory::open(imgData.pData_, imgData.size_); image->readMetadata(); exifData() = image->exifData(); iptcData() = image->iptcData(); xmpData() = image->xmpData(); } // PgfImage::readMetadata void PgfImage::writeMetadata() { if (io_->open() != 0) { throw Error(9, io_->path(), strError()); } IoCloser closer(*io_); BasicIo::AutoPtr tempIo(io_->temporary()); // may throw assert (tempIo.get() != 0); doWriteMetadata(*tempIo); // may throw io_->close(); io_->transfer(*tempIo); // may throw } // PgfImage::writeMetadata void PgfImage::doWriteMetadata(BasicIo& outIo) { if (!io_->isopen()) throw Error(20); if (!outIo.isopen()) throw Error(21); #ifdef DEBUG std::cout << "Exiv2::PgfImage::doWriteMetadata: Writing PGF file " << io_->path() << "\n"; std::cout << "Exiv2::PgfImage::doWriteMetadata: tmp file created " << outIo.path() << "\n"; #endif // Ensure that this is the correct image type if (!isPgfType(*io_, true)) { if (io_->error() || io_->eof()) throw Error(20); throw Error(22); } // Ensure PGF version. byte mnb = readPgfMagicNumber(*io_); readPgfHeaderSize(*io_); int w, h; DataBuf header = readPgfHeaderStructure(*io_, &w, &h); Image::AutoPtr img = ImageFactory::create(ImageType::png); img->setExifData(exifData_); img->setIptcData(iptcData_); img->setXmpData(xmpData_); img->writeMetadata(); int imgSize = img->io().size(); DataBuf imgBuf = img->io().read(imgSize); #ifdef DEBUG std::cout << "Exiv2::PgfImage::doWriteMetadata: Creating image to host metadata (" << imgSize << " bytes)\n"; #endif //--------------------------------------------------------------- // Write PGF Signature. if (outIo.write(pgfSignature, 3) != 3) throw Error(21); // Write Magic number. if (outIo.putb(mnb) == EOF) throw Error(21); // Write new Header size. uint32_t newHeaderSize = header.size_ + imgSize; DataBuf buffer(4); memcpy (buffer.pData_, &newHeaderSize, 4); if (outIo.write(buffer.pData_, 4) != 4) throw Error(21); #ifdef DEBUG std::cout << "Exiv2::PgfImage: new PGF header size : " << newHeaderSize << " bytes\n"; printf("%x\n", buffer.pData_[0]); printf("%x\n", buffer.pData_[1]); printf("%x\n", buffer.pData_[2]); printf("%x\n", buffer.pData_[3]); #endif // Write Header data. if (outIo.write(header.pData_, header.size_) != header.size_) throw Error(21); // Write new metadata byte array. if (outIo.write(imgBuf.pData_, imgBuf.size_) != imgBuf.size_) throw Error(21); // Copy the rest of PGF image data. DataBuf buf(4096); long readSize = 0; while ((readSize=io_->read(buf.pData_, buf.size_))) { if (outIo.write(buf.pData_, readSize) != readSize) throw Error(21); } if (outIo.error()) throw Error(21); } // PgfImage::doWriteMetadata byte PgfImage::readPgfMagicNumber(BasicIo& iIo) { byte b = iIo.getb(); if (iIo.error()) throw Error(14); if (b < 0x36) // 0x36 = '6'. { // Not right Magick version. #ifdef DEBUG std::cout << "Exiv2::PgfImage::readMetadata: wrong Magick number\n"; #endif } return b; } // PgfImage::readPgfMagicNumber uint32_t PgfImage::readPgfHeaderSize(BasicIo& iIo) { DataBuf buffer(4); long bufRead = iIo.read(buffer.pData_, buffer.size_); if (iIo.error()) throw Error(14); if (bufRead != buffer.size_) throw Error(20); uint32_t headerSize = 0; memcpy (&headerSize, buffer.pData_, 4); // TODO : check endianness. if (headerSize <= 0 ) throw Error(22); #ifdef DEBUG std::cout << "Exiv2::PgfImage: PGF header size : " << headerSize << " bytes\n"; #endif return headerSize; } // PgfImage::readPgfHeaderSize DataBuf PgfImage::readPgfHeaderStructure(BasicIo& iIo, int* width, int* height) { DataBuf header(16); long bufRead = iIo.read(header.pData_, header.size_); if (iIo.error()) throw Error(14); if (bufRead != header.size_) throw Error(20); memcpy(width, &header.pData_[0], 4); // TODO : check endianness. memcpy(height, &header.pData_[4], 4); // TODO : check endianness. /* NOTE: properties not yet used byte nLevels = buffer.pData_[8]; byte quality = buffer.pData_[9]; byte bpp = buffer.pData_[10]; byte channels = buffer.pData_[11]; */ byte mode = header.pData_[12]; if (mode == 2) // Indexed color image. We pass color table (256 * 3 bytes). { header.alloc(16 + 256*3); bufRead = iIo.read(&header.pData_[16], 256*3); if (iIo.error()) throw Error(14); if (bufRead != 256*3) throw Error(20); } return header; } // PgfImage::readPgfHeaderStructure // ************************************************************************* // free functions Image::AutoPtr newPgfInstance(BasicIo::AutoPtr io, bool create) { Image::AutoPtr image(new PgfImage(io, create)); if (!image->good()) { image.reset(); } return image; } bool isPgfType(BasicIo& iIo, bool advance) { const int32_t len = 3; byte buf[len]; iIo.read(buf, len); if (iIo.error() || iIo.eof()) { return false; } int rc = memcmp(buf, pgfSignature, 3); if (!advance || rc != 0) { iIo.seek(-len, BasicIo::cur); } return rc == 0; } } // namespace Exiv2 exiv2-0.23/src/metadatum.cpp0000644000175000017500000000503111732641407015567 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /* File: metadatum.cpp Version: $Rev: 2681 $ Author(s): Andreas Huggel (ahu) Brad Schick (brad) History: 26-Jan-04, ahu: created 31-Jul-04, brad: isolated as a component */ // ***************************************************************************** #include "rcsid_int.hpp" EXIV2_RCSID("@(#) $Id: metadatum.cpp 2681 2012-03-22 15:19:35Z ahuggel $") // ***************************************************************************** // included header files #include "metadatum.hpp" // + standard includes #include #include // ***************************************************************************** // class member definitions namespace Exiv2 { Key::~Key() { } Key::AutoPtr Key::clone() const { return AutoPtr(clone_()); } Key& Key::operator=(const Key& /*rhs*/) { return *this; } Metadatum::Metadatum() { } Metadatum::Metadatum(const Metadatum& /*rhs*/) { } Metadatum::~Metadatum() { } Metadatum& Metadatum::operator=(const Metadatum& /*rhs*/) { return *this; } std::string Metadatum::print(const ExifData* pMetadata) const { std::ostringstream os; write(os, pMetadata); return os.str(); } bool cmpMetadataByTag(const Metadatum& lhs, const Metadatum& rhs) { return lhs.tag() < rhs.tag(); } bool cmpMetadataByKey(const Metadatum& lhs, const Metadatum& rhs) { return lhs.key() < rhs.key(); } } // namespace Exiv2 exiv2-0.23/src/i18n.h0000644000175000017500000000317011732641407014034 0ustar andreasandreas/* **************************************************************** -*- C -*- */ /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /* File: i18n.h Brief: i18n definitions. Do not use. This is an Exiv2 internal header. Version: $Rev: 2681 $ Author(s): Gilles Caulier (gc) History: 01-Nov-06, gc: created */ #ifndef I18N_H_ #define I18N_H_ #ifdef _MSC_VER # include "exv_msvc.h" #else # include "exv_conf.h" #endif /* NLS can be disabled through the configure --disable-nls option. */ #ifdef EXV_ENABLE_NLS # include // Definition is in types.cpp EXIV2API const char* _exvGettext(const char* str); # define _(String) _exvGettext(String) # define N_(String) String #else /* NLS is disabled */ # define _(String) (String) # define N_(String) String #endif /* EXV_ENABLE_NLS */ #endif /* I18N_H_ */ exiv2-0.23/src/error.cpp0000644000175000017500000002154211732641407014744 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /* File: error.cpp Version: $Rev: 2681 $ Author(s): Andreas Huggel (ahu) History: 02-Apr-05, ahu: created */ // ***************************************************************************** #include "rcsid_int.hpp" EXIV2_RCSID("@(#) $Id: error.cpp 2681 2012-03-22 15:19:35Z ahuggel $") // ***************************************************************************** // included header files #include "error.hpp" #include "i18n.h" // NLS support. // + standard includes #include #include #include // ***************************************************************************** namespace { //! Helper structure defining an error message. struct ErrMsg { //! Comparison operator bool operator==(int code) const { return code_ == code; } int code_; //!< Error code const char* message_; //!< Error message }; //! Complete list of Exiv2 exception error messages const ErrMsg errList[] = { { -1, N_("Error %0: arg2=%2, arg3=%3, arg1=%1.") }, { 0, N_("Success") }, { 1, "%1" }, // %1=error message { 2, "%1: Call to `%3' failed: %2" }, // %1=path, %2=strerror, %3=function that failed { 3, N_("This does not look like a %1 image") }, // %1=Image type { 4, N_("Invalid dataset name `%1'") }, // %1=dataset name { 5, N_("Invalid record name `%1'") }, // %1=record name { 6, N_("Invalid key `%1'") }, // %1=key { 7, N_("Invalid tag name or ifdId `%1', ifdId %2") }, // %1=tag name, %2=ifdId { 8, N_("Value not set") }, { 9, N_("%1: Failed to open the data source: %2") }, // %1=path, %2=strerror { 10, N_("%1: Failed to open file (%2): %3") }, // %1=path, %2=mode, %3=strerror { 11, N_("%1: The file contains data of an unknown image type") }, // %1=path { 12, N_("The memory contains data of an unknown image type") }, { 13, N_("Image type %1 is not supported") }, // %1=image type { 14, N_("Failed to read image data") }, { 15, N_("This does not look like a JPEG image") }, { 16, N_("%1: Failed to map file for reading and writing: %2") }, // %1=path, %2=strerror { 17, N_("%1: Failed to rename file to %2: %3") }, // %1=old path, %2=new path, %3=strerror { 18, N_("%1: Transfer failed: %2") }, // %1=path, %2=strerror { 19, N_("Memory transfer failed: %1") }, // %1=strerror { 20, N_("Failed to read input data") }, { 21, N_("Failed to write image") }, { 22, N_("Input data does not contain a valid image") }, { 23, N_("Invalid ifdId %1") }, // %1=ifdId { 24, N_("Entry::setValue: Value too large (tag=%1, size=%2, requested=%3)") }, // %1=tag, %2=dataSize, %3=required size { 25, N_("Entry::setDataArea: Value too large (tag=%1, size=%2, requested=%3)") }, // %1=tag, %2=dataAreaSize, %3=required size { 26, N_("Offset out of range") }, { 27, N_("Unsupported data area offset type") }, { 28, N_("Invalid charset: `%1'") }, // %1=charset name { 29, N_("Unsupported date format") }, { 30, N_("Unsupported time format") }, { 31, N_("Writing to %1 images is not supported") }, // %1=image format { 32, N_("Setting %1 in %2 images is not supported") }, // %1=metadata type, %2=image format { 33, N_("This does not look like a CRW image") }, { 34, N_("%1: Not supported") }, // %1=function { 35, N_("No namespace info available for XMP prefix `%1'") }, // %1=prefix { 36, N_("No prefix registered for namespace `%2', needed for property path `%1'") }, // %1=namespace { 37, N_("Size of %1 JPEG segment is larger than 65535 bytes") }, // %1=type of metadata (Exif, IPTC, JPEG comment) { 38, N_("Unhandled Xmpdatum %1 of type %2") }, // %1=key, %2=value type { 39, N_("Unhandled XMP node %1 with opt=%2") }, // %1=key, %2=XMP Toolkit option flags { 40, N_("XMP Toolkit error %1: %2") }, // %1=XMP_Error::GetID(), %2=XMP_Error::GetErrMsg() { 41, N_("Failed to decode Lang Alt property %1 with opt=%2") }, // %1=property path, %3=XMP Toolkit option flags { 42, N_("Failed to decode Lang Alt qualifier %1 with opt=%2") }, // %1=qualifier path, %3=XMP Toolkit option flags { 43, N_("Failed to encode Lang Alt property %1") }, // %1=key { 44, N_("Failed to determine property name from path %1, namespace %2") }, // %1=property path, %2=namespace { 45, N_("Schema namespace %1 is not registered with the XMP Toolkit") }, // %1=namespace { 46, N_("No namespace registered for prefix `%1'") }, // %1=prefix { 47, N_("Aliases are not supported. Please send this XMP packet to ahuggel@gmx.net `%1', `%2', `%3'") }, // %1=namespace, %2=property path, %3=value { 48, N_("Invalid XmpText type `%1'") }, // %1=type { 49, N_("TIFF directory %1 has too many entries") }, // %1=TIFF directory name { 50, N_("Multiple TIFF array element tags %1 in one directory") }, // %1=tag number { 51, N_("TIFF array element tag %1 has wrong type") }, // %1=tag number { 52, N_("%1 has invalid XMP value type `%2'") } // %1=key, %2=value type }; } // ***************************************************************************** // class member definitions namespace Exiv2 { LogMsg::Level LogMsg::level_ = LogMsg::warn; // Default output level LogMsg::Handler LogMsg::handler_ = LogMsg::defaultHandler; void LogMsg::defaultHandler(int level, const char* s) { switch (static_cast(level)) { case LogMsg::debug: std::cerr << "Debug: "; break; case LogMsg::info: std::cerr << "Info: "; break; case LogMsg::warn: std::cerr << "Warning: "; break; case LogMsg::error: std::cerr << "Error: "; break; case LogMsg::mute: assert(false); } std::cerr << s; } AnyError::~AnyError() throw() { } //! @cond IGNORE template<> void BasicError::setMsg() { std::string msg = _(errMsg(code_)); std::string::size_type pos; pos = msg.find("%0"); if (pos != std::string::npos) { msg.replace(pos, 2, toString(code_)); } if (count_ > 0) { pos = msg.find("%1"); if (pos != std::string::npos) { msg.replace(pos, 2, arg1_); } } if (count_ > 1) { pos = msg.find("%2"); if (pos != std::string::npos) { msg.replace(pos, 2, arg2_); } } if (count_ > 2) { pos = msg.find("%3"); if (pos != std::string::npos) { msg.replace(pos, 2, arg3_); } } msg_ = msg; #ifdef EXV_UNICODE_PATH wmsg_ = s2ws(msg); #endif } //! @endcond #ifdef EXV_UNICODE_PATH template<> void BasicError::setMsg() { std::string s = _(errMsg(code_)); std::wstring wmsg(s.begin(), s.end()); std::wstring::size_type pos; pos = wmsg.find(L"%0"); if (pos != std::wstring::npos) { wmsg.replace(pos, 2, toBasicString(code_)); } if (count_ > 0) { pos = wmsg.find(L"%1"); if (pos != std::wstring::npos) { wmsg.replace(pos, 2, arg1_); } } if (count_ > 1) { pos = wmsg.find(L"%2"); if (pos != std::wstring::npos) { wmsg.replace(pos, 2, arg2_); } } if (count_ > 2) { pos = wmsg.find(L"%3"); if (pos != std::wstring::npos) { wmsg.replace(pos, 2, arg3_); } } wmsg_ = wmsg; msg_ = ws2s(wmsg); } #endif const char* errMsg(int code) { const ErrMsg* em = find(errList, code); return em ? em->message_ : ""; } } // namespace Exiv2 exiv2-0.23/src/psdimage.hpp0000644000175000017500000001323411732641407015410 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! @file psdimage.hpp @brief Photoshop image, implemented using the following references: Adobe Photoshop 6.0 File Format Specification by Adobe
@version $Rev: 2681 $ @author Marco Piovanelli, Ovolab (marco) marco.piovanelli@pobox.com @author Michael Ulbrich mul@rentapacs.de @date 05-Mar-2007, marco: created */ #ifndef PSDIMAGE_HPP_ #define PSDIMAGE_HPP_ // ***************************************************************************** // included header files #include "exif.hpp" #include "iptc.hpp" #include "image.hpp" #include "types.hpp" // + standard includes #include // ***************************************************************************** // namespace extensions namespace Exiv2 { // ***************************************************************************** // class definitions // Add PSD to the supported image formats namespace ImageType { const int psd = 12; //!< Photoshop (PSD) image type (see class PsdImage) } /*! @brief Class to access raw Photoshop images. */ class EXIV2API PsdImage : public Image { //! @name NOT Implemented //@{ //! Copy constructor PsdImage(const PsdImage& rhs); //! Assignment operator PsdImage& operator=(const PsdImage& rhs); //@} public: //! @name Creators //@{ /*! @brief Constructor to open a Photoshop image. Since the constructor can not return a result, callers should check the good() method after object construction to determine success or failure. @param io An auto-pointer that owns a BasicIo instance used for reading and writing image metadata. \b Important: The constructor takes ownership of the passed in BasicIo instance through the auto-pointer. Callers should not continue to use the BasicIo instance after it is passed to this method. Use the Image::io() method to get a temporary reference. */ PsdImage(BasicIo::AutoPtr io); //@} //! @name Manipulators //@{ void readMetadata(); void writeMetadata(); /*! @brief Not supported. Calling this function will throw an Error(32). */ void setComment(const std::string& comment); //@} //! @name Accessors //@{ /*! @brief Return the MIME type of the image. The MIME type returned for Photoshop images is "image/x-photoshop". @note This should really be "image/vnd.adobe.photoshop" (officially registered with IANA in December 2005 -- see http://www.iana.org/assignments/media-types/image/vnd.adobe.photoshop) but Apple, as of Tiger (10.4.8), maps this official MIME type to a dynamic UTI, rather than "com.adobe.photoshop-image" as it should. */ std::string mimeType() const; //@} private: //! @name Manipulators //@{ EXV_DLLLOCAL void readResourceBlock(uint16_t resourceId, uint32_t resourceSize); /*! @brief Provides the main implementation of writeMetadata() by writing all buffered metadata to the provided BasicIo. @param oIo BasicIo instance to write to (a temporary location). @return 4 if opening or writing to the associated BasicIo fails */ EXV_DLLLOCAL void doWriteMetadata(BasicIo& oIo); EXV_DLLLOCAL uint32_t writeExifData(const ExifData& exifData, BasicIo& out); //@} //! @name Accessors //@{ EXV_DLLLOCAL uint32_t writeIptcData(const IptcData& iptcData, BasicIo& out) const; EXV_DLLLOCAL uint32_t writeXmpData(const XmpData& xmpData, BasicIo& out) const; //@} }; // class PsdImage // ***************************************************************************** // template, inline and free functions // These could be static private functions on Image subclasses but then // ImageFactory needs to be made a friend. /*! @brief Create a new PsdImage instance and return an auto-pointer to it. Caller owns the returned object and the auto-pointer ensures that it will be deleted. */ EXIV2API Image::AutoPtr newPsdInstance(BasicIo::AutoPtr io, bool create); //! Check if the file iIo is a Photoshop image. EXIV2API bool isPsdType(BasicIo& iIo, bool advance); } // namespace Exiv2 #endif // #ifndef PSDIMAGE_HPP_ exiv2-0.23/src/tags.cpp0000644000175000017500000053334411741215652014560 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /* File: tags.cpp Version: $Rev: 2696 $ Author(s): Andreas Huggel (ahu) Gilles Caulier (gc) History: 15-Jan-04, ahu: created 21-Jan-05, ahu: added MakerNote TagInfo registry and related code */ // ***************************************************************************** #include "rcsid_int.hpp" EXIV2_RCSID("@(#) $Id: tags.cpp 2696 2012-04-11 05:50:34Z ahuggel $") // ***************************************************************************** // included header files #include "types.hpp" #include "tags.hpp" #include "tags_int.hpp" #include "error.hpp" #include "futils.hpp" #include "value.hpp" #include "convert.hpp" #include "i18n.h" // NLS support. #include "canonmn_int.hpp" #include "fujimn_int.hpp" #include "minoltamn_int.hpp" #include "nikonmn_int.hpp" #include "olympusmn_int.hpp" #include "panasonicmn_int.hpp" #include "pentaxmn_int.hpp" #include "samsungmn_int.hpp" #include "sigmamn_int.hpp" #include "sonymn_int.hpp" #include #include #include #include #include #include #include #include // ***************************************************************************** // local declarations namespace { // Print version string from an intermediate string std::ostream& printVersion(std::ostream& os, const std::string& str); } // ***************************************************************************** // class member definitions namespace Exiv2 { using namespace Internal; //! List of all known Exif groups. Important: Group name (3rd column) must be unique! extern const GroupInfo groupInfo[] = { { ifdIdNotSet, "Unknown IFD", "Unknown", 0 }, { ifd0Id, "IFD0", "Image", ifdTagList }, { ifd1Id, "IFD1", "Thumbnail", ifdTagList }, { ifd2Id, "IFD2", "Image2", ifdTagList }, { ifd3Id, "IFD3", "Image3", ifdTagList }, { exifId, "Exif", "Photo", exifTagList }, { gpsId, "GPSInfo", "GPSInfo", gpsTagList }, { iopId, "Iop", "Iop", iopTagList }, { subImage1Id, "SubImage1", "SubImage1", ifdTagList }, { subImage2Id, "SubImage2", "SubImage2", ifdTagList }, { subImage3Id, "SubImage3", "SubImage3", ifdTagList }, { subImage4Id, "SubImage4", "SubImage4", ifdTagList }, { subImage5Id, "SubImage5", "SubImage5", ifdTagList }, { subImage6Id, "SubImage6", "SubImage6", ifdTagList }, { subImage7Id, "SubImage7", "SubImage7", ifdTagList }, { subImage8Id, "SubImage8", "SubImage8", ifdTagList }, { subImage9Id, "SubImage9", "SubImage9", ifdTagList }, { subThumb1Id, "SubThumb1", "SubThumb1", ifdTagList }, { panaRawId, "PanaRaw", "PanasonicRaw", PanasonicMakerNote::tagListRaw }, { mnId, "Makernote", "MakerNote", mnTagList }, { canonId, "Makernote", "Canon", CanonMakerNote::tagList }, { canonCsId, "Makernote", "CanonCs", CanonMakerNote::tagListCs }, { canonSiId, "Makernote", "CanonSi", CanonMakerNote::tagListSi }, { canonCfId, "Makernote", "CanonCf", CanonMakerNote::tagListCf }, { canonPiId, "Makernote", "CanonPi", CanonMakerNote::tagListPi }, { canonFiId, "Makernote", "CanonFi", CanonMakerNote::tagListFi }, { canonPaId, "Makernote", "CanonPa", CanonMakerNote::tagListPa }, { canonPrId, "Makernote", "CanonPr", CanonMakerNote::tagListPr }, { fujiId, "Makernote", "Fujifilm", FujiMakerNote::tagList }, { minoltaId, "Makernote", "Minolta", MinoltaMakerNote::tagList }, { minoltaCs5DId, "Makernote", "MinoltaCs5D", MinoltaMakerNote::tagListCs5D }, { minoltaCs7DId, "Makernote", "MinoltaCs7D", MinoltaMakerNote::tagListCs7D }, { minoltaCsOldId, "Makernote", "MinoltaCsOld", MinoltaMakerNote::tagListCsStd }, { minoltaCsNewId, "Makernote", "MinoltaCsNew", MinoltaMakerNote::tagListCsStd }, { nikon1Id, "Makernote", "Nikon1", Nikon1MakerNote::tagList }, { nikon2Id, "Makernote", "Nikon2", Nikon2MakerNote::tagList }, { nikon3Id, "Makernote", "Nikon3", Nikon3MakerNote::tagList }, { nikonPvId, "Makernote", "NikonPreview", ifdTagList }, { nikonVrId, "Makernote", "NikonVr", Nikon3MakerNote::tagListVr }, { nikonPcId, "Makernote", "NikonPc", Nikon3MakerNote::tagListPc }, { nikonWtId, "Makernote", "NikonWt", Nikon3MakerNote::tagListWt }, { nikonIiId, "Makernote", "NikonIi", Nikon3MakerNote::tagListIi }, { nikonAfId, "Makernote", "NikonAf", Nikon3MakerNote::tagListAf }, { nikonAf2Id, "Makernote", "NikonAf2", Nikon3MakerNote::tagListAf2 }, { nikonAFTId, "Makernote", "NikonAFT", Nikon3MakerNote::tagListAFT }, { nikonFiId, "Makernote", "NikonFi", Nikon3MakerNote::tagListFi }, { nikonMeId, "Makernote", "NikonMe", Nikon3MakerNote::tagListMe }, { nikonFl1Id, "Makernote", "NikonFl1", Nikon3MakerNote::tagListFl1 }, { nikonFl2Id, "Makernote", "NikonFl2", Nikon3MakerNote::tagListFl2 }, { nikonFl3Id, "Makernote", "NikonFl3", Nikon3MakerNote::tagListFl3 }, { nikonSi1Id, "Makernote", "NikonSiD80", Nikon3MakerNote::tagListSi1 }, { nikonSi2Id, "Makernote", "NikonSiD40", Nikon3MakerNote::tagListSi2 }, { nikonSi3Id, "Makernote", "NikonSiD300a", Nikon3MakerNote::tagListSi3 }, { nikonSi4Id, "Makernote", "NikonSiD300b", Nikon3MakerNote::tagListSi4 }, { nikonSi5Id, "Makernote", "NikonSi02xx", Nikon3MakerNote::tagListSi5 }, { nikonSi6Id, "Makernote", "NikonSi01xx", Nikon3MakerNote::tagListSi5 }, { nikonCb1Id, "Makernote", "NikonCb1", Nikon3MakerNote::tagListCb1 }, { nikonCb2Id, "Makernote", "NikonCb2", Nikon3MakerNote::tagListCb2 }, { nikonCb2aId, "Makernote", "NikonCb2a", Nikon3MakerNote::tagListCb2a }, { nikonCb2bId, "Makernote", "NikonCb2b", Nikon3MakerNote::tagListCb2b }, { nikonCb3Id, "Makernote", "NikonCb3", Nikon3MakerNote::tagListCb3 }, { nikonCb4Id, "Makernote", "NikonCb4", Nikon3MakerNote::tagListCb4 }, { nikonLd1Id, "Makernote", "NikonLd1", Nikon3MakerNote::tagListLd1 }, { nikonLd2Id, "Makernote", "NikonLd2", Nikon3MakerNote::tagListLd2 }, { nikonLd3Id, "Makernote", "NikonLd3", Nikon3MakerNote::tagListLd3 }, { olympusId, "Makernote", "Olympus", OlympusMakerNote::tagList }, { olympus2Id, "Makernote", "Olympus2", OlympusMakerNote::tagList }, { olympusCsId, "Makernote", "OlympusCs", OlympusMakerNote::tagListCs }, { olympusEqId, "Makernote", "OlympusEq", OlympusMakerNote::tagListEq }, { olympusRdId, "Makernote", "OlympusRd", OlympusMakerNote::tagListRd }, { olympusRd2Id, "Makernote", "OlympusRd2", OlympusMakerNote::tagListRd2 }, { olympusIpId, "Makernote", "OlympusIp", OlympusMakerNote::tagListIp }, { olympusFiId, "Makernote", "OlympusFi", OlympusMakerNote::tagListFi }, { olympusFe1Id, "Makernote", "OlympusFe1", OlympusMakerNote::tagListFe }, { olympusFe2Id, "Makernote", "OlympusFe2", OlympusMakerNote::tagListFe }, { olympusFe3Id, "Makernote", "OlympusFe3", OlympusMakerNote::tagListFe }, { olympusFe4Id, "Makernote", "OlympusFe4", OlympusMakerNote::tagListFe }, { olympusFe5Id, "Makernote", "OlympusFe5", OlympusMakerNote::tagListFe }, { olympusFe6Id, "Makernote", "OlympusFe6", OlympusMakerNote::tagListFe }, { olympusFe7Id, "Makernote", "OlympusFe7", OlympusMakerNote::tagListFe }, { olympusFe8Id, "Makernote", "OlympusFe8", OlympusMakerNote::tagListFe }, { olympusFe9Id, "Makernote", "OlympusFe9", OlympusMakerNote::tagListFe }, { olympusRiId, "Makernote", "OlympusRi", OlympusMakerNote::tagListRi }, { panasonicId, "Makernote", "Panasonic", PanasonicMakerNote::tagList }, { pentaxDngId, "Makernote", "PentaxDng", PentaxMakerNote::tagList }, { pentaxId, "Makernote", "Pentax", PentaxMakerNote::tagList }, { samsung2Id, "Makernote", "Samsung2", Samsung2MakerNote::tagList }, { samsungPvId, "Makernote", "SamsungPreview", ifdTagList }, { samsungPwId, "Makernote", "SamsungPictureWizard", Samsung2MakerNote::tagListPw }, { sigmaId, "Makernote", "Sigma", SigmaMakerNote::tagList }, { sony1Id, "Makernote", "Sony1", SonyMakerNote::tagList }, { sony2Id, "Makernote", "Sony2", SonyMakerNote::tagList }, { sonyMltId, "Makernote", "SonyMinolta", MinoltaMakerNote::tagList }, { sony1CsId, "Makernote", "Sony1Cs", SonyMakerNote::tagListCs }, { sony1Cs2Id, "Makernote", "Sony1Cs2", SonyMakerNote::tagListCs2 }, { sony1MltCs7DId, "Makernote", "Sony1MltCs7D", MinoltaMakerNote::tagListCs7D }, { sony1MltCsOldId, "Makernote", "Sony1MltCsOld",MinoltaMakerNote::tagListCsStd }, { sony1MltCsNewId, "Makernote", "Sony1MltCsNew",MinoltaMakerNote::tagListCsStd }, { sony1MltCsA100Id,"Makernote","Sony1MltCsA100",MinoltaMakerNote::tagListCsA100}, { sony2CsId, "Makernote", "Sony2Cs", SonyMakerNote::tagListCs }, { sony2Cs2Id, "Makernote", "Sony2Cs2", SonyMakerNote::tagListCs2 }, { lastId, "(Last IFD info)", "(Last IFD item)", 0 } }; //! List of all defined Exif sections. extern const SectionInfo sectionInfo[] = { { sectionIdNotSet, "(UnknownSection)", N_("Unknown section") }, { imgStruct, "ImageStructure", N_("Image data structure") }, { recOffset, "RecordingOffset", N_("Recording offset") }, { imgCharacter, "ImageCharacteristics", N_("Image data characteristics") }, { otherTags, "OtherTags", N_("Other data") }, { exifFormat, "ExifFormat", N_("Exif data structure") }, { exifVersion, "ExifVersion", N_("Exif version") }, { imgConfig, "ImageConfig", N_("Image configuration") }, { userInfo, "UserInfo", N_("User information") }, { relatedFile, "RelatedFile", N_("Related file") }, { dateTime, "DateTime", N_("Date and time") }, { captureCond, "CaptureConditions", N_("Picture taking conditions") }, { gpsTags, "GPS", N_("GPS information") }, { iopTags, "Interoperability", N_("Interoperability information") }, { makerTags, "Makernote", N_("Vendor specific information") }, { dngTags, "DngTags", N_("Adobe DNG tags") }, { panaRaw, "PanasonicRaw", N_("Panasonic RAW tags") }, { tiffEp, "TIFF/EP", N_("TIFF/EP tags") }, { tiffPm6, "TIFF&PM6", N_("TIFF PageMaker 6.0 tags") }, { adobeOpi, "AdobeOPI", N_("Adobe OPI tags") }, { lastSectionId, "(LastSection)", N_("Last section") } }; } // namespace Exiv2 namespace Exiv2 { namespace Internal { bool TagVocabulary::operator==(const std::string& key) const { if (strlen(voc_) > key.size()) return false; return 0 == strcmp(voc_, key.c_str() + key.size() - strlen(voc_)); } //! NewSubfileType, TIFF tag 0x00fe - this is actually a bitmask extern const TagDetails exifNewSubfileType[] = { { 0, N_("Primary image") }, { 1, N_("Thumbnail/Preview image") }, { 2, N_("Primary image, Multi page file") }, { 3, N_("Thumbnail/Preview image, Multi page file") }, { 4, N_("Primary image, Transparency mask") }, { 5, N_("Thumbnail/Preview image, Transparency mask") }, { 6, N_("Primary image, Multi page file, Transparency mask") }, { 7, N_("Thumbnail/Preview image, Multi page file, Transparency mask") }, { 7, N_("Thumbnail/Preview image, Multi page file, Transparency mask") } // To silence compiler warning }; //! SubfileType, TIFF tag 0x00ff extern const TagDetails exifSubfileType[] = { { 1, N_("Full-resolution image data") }, { 2, N_("Reduced-resolution image data") }, { 3, N_("A single page of a multi-page image") } }; //! Units for measuring X and Y resolution, tags 0x0128, 0xa210 extern const TagDetails exifUnit[] = { { 1, N_("none") }, { 2, N_("inch") }, { 3, N_("cm") } }; //! Compression, tag 0x0103 extern const TagDetails exifCompression[] = { { 1, N_("Uncompressed") }, { 2, N_("CCITT RLE") }, { 3, N_("T4/Group 3 Fax") }, { 4, N_("T6/Group 4 Fax") }, { 5, N_("LZW") }, { 6, N_("JPEG (old-style)") }, { 7, N_("JPEG") }, { 8, N_("Adobe Deflate") }, { 9, N_("JBIG B&W") }, { 10, N_("JBIG Color") }, { 32766, N_("Next 2-bits RLE") }, { 32769, N_("Epson ERF Compressed") }, { 32770, N_("Samsung SRW Compressed") }, { 32771, N_("CCITT RLE 1-word") }, { 32773, N_("PackBits (Macintosh RLE)") }, { 32809, N_("Thunderscan RLE") }, { 32895, N_("IT8 CT Padding") }, { 32896, N_("IT8 Linework RLE") }, { 32897, N_("IT8 Monochrome Picture") }, { 32898, N_("IT8 Binary Lineart") }, { 32908, N_("Pixar Film (10-bits LZW)") }, { 32909, N_("Pixar Log (11-bits ZIP)") }, { 32946, N_("Pixar Deflate") }, { 32947, N_("Kodak DCS Encoding") }, { 34661, N_("ISO JBIG") }, { 34676, N_("SGI Log Luminance RLE") }, { 34677, N_("SGI Log 24-bits packed") }, { 34712, N_("Leadtools JPEG 2000") }, { 34713, N_("Nikon NEF Compressed") }, { 65000, N_("Kodak DCR Compressed") }, { 65535, N_("Pentax PEF Compressed") } }; //! PhotometricInterpretation, tag 0x0106 extern const TagDetails exifPhotometricInterpretation[] = { { 0, N_("White Is Zero") }, { 1, N_("Black Is Zero") }, { 2, N_("RGB") }, { 3, N_("RGB Palette") }, { 4, N_("Transparency Mask") }, { 5, N_("CMYK") }, { 6, N_("YCbCr") }, { 8, N_("CIELab") }, { 9, N_("ICCLab") }, { 10, N_("ITULab") }, { 32803, N_("Color Filter Array") }, { 32844, N_("Pixar LogL") }, { 32845, N_("Pixar LogLuv") }, { 34892, N_("Linear Raw") } }; //! Threshholding, tag 0x0107 extern const TagDetails exifThreshholding[] = { { 1, N_("No dithering or halftoning") }, { 2, N_("Ordered dither or halftone technique") }, { 3, N_("Randomized process") } }; //! Orientation, tag 0x0112 extern const TagDetails exifOrientation[] = { { 1, N_("top, left") }, { 2, N_("top, right") }, { 3, N_("bottom, right") }, { 4, N_("bottom, left") }, { 5, N_("left, top") }, { 6, N_("right, top") }, { 7, N_("right, bottom") }, { 8, N_("left, bottom") }, { 8, N_("left, bottom") } // To silence compiler warning }; //! Predictor, tag 0x013d extern const TagDetails exifPredictor[] = { { 1, N_("No prediction scheme used") }, { 2, N_("Horizontal differencing") } }; //! InkSet, tag 0x014c extern const TagDetails exifInkSet[] = { { 1, N_("CMYK") }, { 2, N_("not CMYK") } }; //! SampleFormat, tag 0x0153 extern const TagDetails exifSampleFormat[] = { { 1, N_("Unsigned integer data") }, { 2, N_("Two's complement signed integer data") }, { 3, N_("IEEE floating point data") }, { 4, N_("Undefined data format") }, { 4, N_("Undefined data format") } // To silence compiler warning }; //! Indexed, tag 0x015a extern const TagDetails exifIndexed[] = { { 0, N_("Not indexed") }, { 1, N_("Indexed") } }; //! exifJpegLosslessPredictor, tag 0x0205 extern const TagDetails exifJpegLosslessPredictor[] = { { 1, N_("A") }, { 2, N_("B") }, { 3, N_("C") }, { 4, N_("A+B-C") }, { 5, N_("A+((B-C)/2)") }, { 6, N_("B+((A-C)/2)") }, { 7, N_("(A+B)/2") } }; //! YCbCrPositioning, tag 0x0213 extern const TagDetails exifYCbCrPositioning[] = { { 1, N_("Centered") }, { 2, N_("Co-sited") } }; //! Flash, Exif tag 0x9209 extern const TagDetails exifFlash[] = { { 0x00, N_("No flash") }, { 0x01, N_("Fired") }, { 0x05, N_("Fired, return light not detected") }, { 0x07, N_("Fired, return light detected") }, { 0x08, N_("Yes, did not fire") }, { 0x09, N_("Yes, compulsory") }, { 0x0d, N_("Yes, compulsory, return light not detected") }, { 0x0f, N_("Yes, compulsory, return light detected") }, { 0x10, N_("No, compulsory") }, { 0x14, N_("No, did not fire, return light not detected") }, { 0x18, N_("No, auto") }, { 0x19, N_("Yes, auto") }, { 0x1d, N_("Yes, auto, return light not detected") }, { 0x1f, N_("Yes, auto, return light detected") }, { 0x20, N_("No flash function") }, { 0x20, N_("No, no flash function") }, { 0x41, N_("Yes, red-eye reduction") }, { 0x45, N_("Yes, red-eye reduction, return light not detected") }, { 0x47, N_("Yes, red-eye reduction, return light detected") }, { 0x49, N_("Yes, compulsory, red-eye reduction") }, { 0x4d, N_("Yes, compulsory, red-eye reduction, return light not detected") }, { 0x4f, N_("Yes, compulsory, red-eye reduction, return light detected") }, { 0x50, N_("No, red-eye reduction") }, { 0x58, N_("No, auto, red-eye reduction") }, { 0x59, N_("Yes, auto, red-eye reduction") }, { 0x5d, N_("Yes, auto, red-eye reduction, return light not detected") }, { 0x5f, N_("Yes, auto, red-eye reduction, return light detected") } }; //! CFALayout, tag 0xc617 extern const TagDetails exifCfaLayout[] = { { 1, N_("Rectangular (or square) layout") }, { 2, N_("Staggered layout A: even columns are offset down by 1/2 row") }, { 3, N_("Staggered layout B: even columns are offset up by 1/2 row") }, { 4, N_("Staggered layout C: even rows are offset right by 1/2 column") }, { 5, N_("Staggered layout D: even rows are offset left by 1/2 column") } }; //! Base IFD Tags (IFD0 and IFD1) static const TagInfo ifdTagInfo[] = { TagInfo(0x000b, "ProcessingSoftware", N_("Processing Software"), N_("The name and version of the software used to post-process " "the picture."), // ACD Systems Digital Imaging tag ifd0Id, otherTags, asciiString, 0, printValue), TagInfo(0x00fe, "NewSubfileType", N_("New Subfile Type"), N_("A general indication of the kind of data contained in this subfile."), ifd0Id, imgStruct, unsignedLong, 1, EXV_PRINT_TAG(exifNewSubfileType)), // TIFF tag TagInfo(0x00ff, "SubfileType", N_("Subfile Type"), N_("A general indication of the kind of data contained in this subfile. " "This field is deprecated. The NewSubfileType field should be used instead."), ifd0Id, imgStruct, unsignedShort, 1, EXV_PRINT_TAG(exifSubfileType)), // TIFF tag TagInfo(0x0100, "ImageWidth", N_("Image Width"), N_("The number of columns of image data, equal to the number of " "pixels per row. In JPEG compressed data a JPEG marker is " "used instead of this tag."), ifd0Id, imgStruct, unsignedLong, 1, printValue), TagInfo(0x0101, "ImageLength", N_("Image Length"), N_("The number of rows of image data. In JPEG compressed data a " "JPEG marker is used instead of this tag."), ifd0Id, imgStruct, unsignedLong, 1, printValue), TagInfo(0x0102, "BitsPerSample", N_("Bits per Sample"), N_("The number of bits per image component. In this standard each " "component of the image is 8 bits, so the value for this " "tag is 8. See also . In JPEG compressed data " "a JPEG marker is used instead of this tag."), ifd0Id, imgStruct, unsignedShort, 3, printValue), TagInfo(0x0103, "Compression", N_("Compression"), N_("The compression scheme used for the image data. When a " "primary image is JPEG compressed, this designation is " "not necessary and is omitted. When thumbnails use JPEG " "compression, this tag value is set to 6."), ifd0Id, imgStruct, unsignedShort, 1, EXV_PRINT_TAG(exifCompression)), TagInfo(0x0106, "PhotometricInterpretation", N_("Photometric Interpretation"), N_("The pixel composition. In JPEG compressed data a JPEG " "marker is used instead of this tag."), ifd0Id, imgStruct, unsignedShort, 1, EXV_PRINT_TAG(exifPhotometricInterpretation)), TagInfo(0x0107, "Threshholding", N_("Threshholding"), N_("For black and white TIFF files that represent shades of gray, " "the technique used to convert from gray to black and white pixels."), ifd0Id, imgStruct, unsignedShort, 1, EXV_PRINT_TAG(exifThreshholding)), // TIFF tag TagInfo(0x0108, "CellWidth", N_("Cell Width"), N_("The width of the dithering or halftoning matrix used to create a " "dithered or halftoned bilevel file."), ifd0Id, imgStruct, unsignedShort, 1, printValue), // TIFF tag TagInfo(0x0109, "CellLength", N_("Cell Length"), N_("The length of the dithering or halftoning matrix used to create a " "dithered or halftoned bilevel file."), ifd0Id, imgStruct, unsignedShort, 1, printValue), // TIFF tag TagInfo(0x010a, "FillOrder", N_("Fill Order"), N_("The logical order of bits within a byte"), ifd0Id, imgStruct, unsignedShort, 1, printValue), // TIFF tag TagInfo(0x010d, "DocumentName", N_("Document Name"), N_("The name of the document from which this image was scanned"), ifd0Id, imgStruct, asciiString, 0, printValue), // TIFF tag TagInfo(0x010e, "ImageDescription", N_("Image Description"), N_("A character string giving the title of the image. It may be " "a comment such as \"1988 company picnic\" or " "the like. Two-bytes character codes cannot be used. " "When a 2-bytes code is necessary, the Exif Private tag " " is to be used."), ifd0Id, otherTags, asciiString, 0, printValue), TagInfo(0x010f, "Make", N_("Manufacturer"), N_("The manufacturer of the recording " "equipment. This is the manufacturer of the DSC, scanner, " "video digitizer or other equipment that generated the " "image. When the field is left blank, it is treated as unknown."), ifd0Id, otherTags, asciiString, 0, printValue), TagInfo(0x0110, "Model", N_("Model"), N_("The model name or model number of the equipment. This is the " "model name or number of the DSC, scanner, video digitizer " "or other equipment that generated the image. When the field " "is left blank, it is treated as unknown."), ifd0Id, otherTags, asciiString, 0, printValue), TagInfo(0x0111, "StripOffsets", N_("Strip Offsets"), N_("For each strip, the byte offset of that strip. It is " "recommended that this be selected so the number of strip " "bytes does not exceed 64 Kbytes. With JPEG compressed " "data this designation is not needed and is omitted. See also " " and ."), ifd0Id, recOffset, unsignedLong, -1, printValue), TagInfo(0x0112, "Orientation", N_("Orientation"), N_("The image orientation viewed in terms of rows and columns."), ifd0Id, imgStruct, unsignedShort, 1, print0x0112), TagInfo(0x0115, "SamplesPerPixel", N_("Samples per Pixel"), N_("The number of components per pixel. Since this standard applies " "to RGB and YCbCr images, the value set for this tag is 3. " "In JPEG compressed data a JPEG marker is used instead of this tag."), ifd0Id, imgStruct, unsignedShort, 1, printValue), TagInfo(0x0116, "RowsPerStrip", N_("Rows per Strip"), N_("The number of rows per strip. This is the number of rows " "in the image of one strip when an image is divided into " "strips. With JPEG compressed data this designation is not " "needed and is omitted. See also and ."), ifd0Id, recOffset, unsignedLong, 1, printValue), TagInfo(0x0117, "StripByteCounts", N_("Strip Byte Count"), N_("The total number of bytes in each strip. With JPEG compressed " "data this designation is not needed and is omitted."), ifd0Id, recOffset, unsignedLong, -1, printValue), TagInfo(0x011a, "XResolution", N_("X-Resolution"), N_("The number of pixels per in the " "direction. When the image resolution is unknown, 72 [dpi] is designated."), ifd0Id, imgStruct, unsignedRational, 1, printLong), TagInfo(0x011b, "YResolution", N_("Y-Resolution"), N_("The number of pixels per in the " "direction. The same value as is designated."), ifd0Id, imgStruct, unsignedRational, 1, printLong), TagInfo(0x011c, "PlanarConfiguration", N_("Planar Configuration"), N_("Indicates whether pixel components are recorded in a chunky " "or planar format. In JPEG compressed files a JPEG marker " "is used instead of this tag. If this field does not exist, " "the TIFF default of 1 (chunky) is assumed."), ifd0Id, imgStruct, unsignedShort, 1, printValue), TagInfo(0x0122, "GrayResponseUnit", N_("Gray Response Unit"), N_("The precision of the information contained in the GrayResponseCurve."), ifd0Id, imgStruct, unsignedShort, 1, printValue), // TIFF tag TagInfo(0x0123, "GrayResponseCurve", N_("Gray Response Curve"), N_("For grayscale data, the optical density of each possible pixel value."), ifd0Id, imgStruct, unsignedShort, -1, printValue), // TIFF tag TagInfo(0x0124, "T4Options", N_("T4 Options"), N_("T.4-encoding options."), ifd0Id, imgStruct, unsignedLong, 1, printValue), // TIFF tag TagInfo(0x0125, "T6Options", N_("T6 Options"), N_("T.6-encoding options."), ifd0Id, imgStruct, unsignedLong, 1, printValue), // TIFF tag TagInfo(0x0128, "ResolutionUnit", N_("Resolution Unit"), N_("The unit for measuring and . The same " "unit is used for both and . If " "the image resolution is unknown, 2 (inches) is designated."), ifd0Id, imgStruct, unsignedShort, 1, printExifUnit), TagInfo(0x012d, "TransferFunction", N_("Transfer Function"), N_("A transfer function for the image, described in tabular style. " "Normally this tag is not necessary, since color space is " "specified in the color space information tag ()."), ifd0Id, imgCharacter, unsignedShort, 3*256, printValue), TagInfo(0x0131, "Software", N_("Software"), N_("This tag records the name and version of the software or " "firmware of the camera or image input device used to " "generate the image. The detailed format is not specified, but " "it is recommended that the example shown below be " "followed. When the field is left blank, it is treated as unknown."), ifd0Id, otherTags, asciiString, 0, printValue), TagInfo(0x0132, "DateTime", N_("Date and Time"), N_("The date and time of image creation. In Exif standard, " "it is the date and time the file was changed."), ifd0Id, otherTags, asciiString, 20, printValue), TagInfo(0x013b, "Artist", N_("Artist"), N_("This tag records the name of the camera owner, photographer or " "image creator. The detailed format is not specified, but it is " "recommended that the information be written as in the example " "below for ease of Interoperability. When the field is " "left blank, it is treated as unknown. Ex.) \"Camera owner, John " "Smith; Photographer, Michael Brown; Image creator, Ken James\""), ifd0Id, otherTags, asciiString, 0, printValue), TagInfo(0x013c, "HostComputer", N_("Host Computer"), N_("This tag records information about the host computer used " "to generate the image."), ifd0Id, otherTags, asciiString, 0, printValue), TagInfo(0x013d, "Predictor", N_("Predictor"), N_("A predictor is a mathematical operator that is applied to " "the image data before an encoding scheme is applied."), ifd0Id, imgStruct, unsignedShort, 1, EXV_PRINT_TAG(exifPredictor)), // TIFF tag TagInfo(0x013e, "WhitePoint", N_("White Point"), N_("The chromaticity of the white point of the image. Normally " "this tag is not necessary, since color space is specified " "in the colorspace information tag ()."), ifd0Id, imgCharacter, unsignedRational, 2, printValue), TagInfo(0x013f, "PrimaryChromaticities", N_("Primary Chromaticities"), N_("The chromaticity of the three primary colors of the image. " "Normally this tag is not necessary, since colorspace is " "specified in the colorspace information tag ()."), ifd0Id, imgCharacter, unsignedRational, 6, printValue), TagInfo(0x0140, "ColorMap", N_("Color Map"), N_("A color map for palette color images. This field defines " "a Red-Green-Blue color map (often called a lookup table) " "for palette-color images. In a palette-color image, a " "pixel value is used to index into an RGB lookup table."), ifd0Id, imgCharacter, unsignedShort, -1, printValue), TagInfo(0x0141, "HalftoneHints", N_("Halftone Hints"), N_("The purpose of the HalftoneHints field is to convey to the " "halftone function the range of gray levels within a " "colorimetrically-specified image that should retain tonal detail."), ifd0Id, imgStruct, unsignedShort, 2, printValue), // TIFF tag TagInfo(0x0142, "TileWidth", N_("Tile Width"), N_("The tile width in pixels. This is the number of columns in each tile."), ifd0Id, recOffset, unsignedShort, 1, printValue), // TIFF tag TagInfo(0x0143, "TileLength", N_("Tile Length"), N_("The tile length (height) in pixels. This is the number of rows in each tile."), ifd0Id, recOffset, unsignedShort, 1, printValue), // TIFF tag TagInfo(0x0144, "TileOffsets", N_("Tile Offsets"), N_("For each tile, the byte offset of that tile, as compressed and " "stored on disk. The offset is specified with respect to the " "beginning of the TIFF file. Note that this implies that each " "tile has a location independent of the locations of other tiles."), ifd0Id, recOffset, unsignedShort, -1, printValue), // TIFF tag TagInfo(0x0145, "TileByteCounts", N_("Tile Byte Counts"), N_("For each tile, the number of (compressed) bytes in that tile. See " "TileOffsets for a description of how the byte counts are ordered."), ifd0Id, recOffset, unsignedShort, -1, printValue), // TIFF tag TagInfo(0x014a, "SubIFDs", N_("SubIFD Offsets"), N_("Defined by Adobe Corporation to enable TIFF Trees within a TIFF file."), ifd0Id, tiffEp, unsignedLong, -1, printValue), TagInfo(0x014c, "InkSet", N_("Ink Set"), N_("The set of inks used in a separated (PhotometricInterpretation=5) image."), ifd0Id, imgStruct, unsignedShort, 1, EXV_PRINT_TAG(exifInkSet)), // TIFF tag TagInfo(0x014d, "InkNames", N_("Ink Names"), N_("The name of each ink used in a separated (PhotometricInterpretation=5) image."), ifd0Id, imgStruct, asciiString, 0, printValue), // TIFF tag TagInfo(0x014e, "NumberOfInks", N_("Number Of Inks"), N_("The number of inks. Usually equal to SamplesPerPixel, unless there are extra samples."), ifd0Id, imgStruct, unsignedShort, 1, printValue), // TIFF tag TagInfo(0x0150, "DotRange", N_("Dot Range"), N_("The component values that correspond to a 0% dot and 100% dot."), ifd0Id, imgStruct, unsignedByte, -1, printValue), // TIFF tag TagInfo(0x0151, "TargetPrinter", N_("Target Printer"), N_("A description of the printing environment for which this separation is intended."), ifd0Id, imgStruct, asciiString, 0, printValue), // TIFF tag TagInfo(0x0152, "ExtraSamples", N_("Extra Samples"), N_("Specifies that each pixel has m extra components whose interpretation " "is defined by one of the values listed below."), ifd0Id, imgStruct, unsignedShort, -1, printValue), // TIFF tag TagInfo(0x0153, "SampleFormat", N_("Sample Format"), N_("This field specifies how to interpret each data sample in a pixel."), ifd0Id, imgStruct, unsignedShort, -1, EXV_PRINT_TAG(exifSampleFormat)), // TIFF tag TagInfo(0x0154, "SMinSampleValue", N_("SMin Sample Value"), N_("This field specifies the minimum sample value."), ifd0Id, imgStruct, unsignedShort, -1, printValue), // TIFF tag TagInfo(0x0155, "SMaxSampleValue", N_("SMax Sample Value"), N_("This field specifies the maximum sample value."), ifd0Id, imgStruct, unsignedShort, -1, printValue), // TIFF tag TagInfo(0x0156, "TransferRange", N_("Transfer Range"), N_("Expands the range of the TransferFunction"), ifd0Id, imgCharacter, unsignedShort, 6, printValue), // TIFF tag TagInfo(0x0157, "ClipPath", N_("Clip Path"), N_("A TIFF ClipPath is intended to mirror the essentials of PostScript's " "path creation functionality."), ifd0Id, tiffPm6, unsignedByte, -1, printValue), // TIFF&PM6 tag TagInfo(0x0158, "XClipPathUnits", N_("X Clip Path Units"), N_("The number of units that span the width of the image, in terms of " "integer ClipPath coordinates."), ifd0Id, tiffPm6, signedShort, 1, printValue), // TIFF&PM6 tag TagInfo(0x0159, "YClipPathUnits", N_("Y Clip Path Units"), N_("The number of units that span the height of the image, in terms of " "integer ClipPath coordinates."), ifd0Id, tiffPm6, signedShort, 1, printValue), // TIFF&PM6 tag TagInfo(0x015a, "Indexed", N_("Indexed"), N_("Indexed images are images where the 'pixels' do not represent color " "values, but rather an index (usually 8-bit) into a separate color " "table, the ColorMap."), ifd0Id, tiffPm6, unsignedShort, 1, EXV_PRINT_TAG(exifIndexed)), // TIFF&PM6 tag TagInfo(0x015b, "JPEGTables", N_("JPEG tables"), N_("This optional tag may be used to encode the JPEG quantization and" "Huffman tables for subsequent use by the JPEG decompression process."), ifd0Id, imgStruct, undefined, 0, printValue), // TIFF/EP tag TagInfo(0x015F, "OPIProxy", N_("OPI Proxy"), N_("OPIProxy gives information concerning whether this image is a " "low-resolution proxy of a high-resolution image (Adobe OPI)."), ifd0Id, adobeOpi, unsignedShort, 1, printValue), // Adobe OPI tag TagInfo(0x0200, "JPEGProc", N_("JPEG Process"), N_("This field indicates the process used to produce the compressed data"), ifd0Id, recOffset, unsignedLong, 1, printValue), // TIFF tag TagInfo(0x0201, "JPEGInterchangeFormat", N_("JPEG Interchange Format"), N_("The offset to the start byte (SOI) of JPEG compressed " "thumbnail data. This is not used for primary image JPEG data."), ifd0Id, recOffset, unsignedLong, 1, printValue), TagInfo(0x0202, "JPEGInterchangeFormatLength", N_("JPEG Interchange Format Length"), N_("The number of bytes of JPEG compressed thumbnail data. This " "is not used for primary image JPEG data. JPEG thumbnails " "are not divided but are recorded as a continuous JPEG " "bitstream from SOI to EOI. Appn and COM markers should " "not be recorded. Compressed thumbnails must be recorded in no " "more than 64 Kbytes, including all other data to be recorded in APP1."), ifd0Id, recOffset, unsignedLong, 1, printValue), TagInfo(0x0203, "JPEGRestartInterval", N_("JPEG Restart Interval"), N_("This Field indicates the length of the restart interval used " "in the compressed image data."), ifd0Id, imgStruct, unsignedShort, 1, printValue), // TIFF tag TagInfo(0x0205, "JPEGLosslessPredictors", N_("JPEG Lossless Predictors"), N_("This Field points to a list of lossless predictor-selection " "values, one per component."), ifd0Id, imgStruct, unsignedShort, -1, EXV_PRINT_TAG(exifJpegLosslessPredictor)), // TIFF tag TagInfo(0x0206, "JPEGPointTransforms", N_("JPEG Point Transforms"), N_("This Field points to a list of point transform values, one per component."), ifd0Id, imgStruct, unsignedShort, -1, printValue), // TIFF tag TagInfo(0x0207, "JPEGQTables", N_("JPEG Q-Tables"), N_("This Field points to a list of offsets to the quantization tables, " "one per component."), ifd0Id, imgStruct, unsignedLong, -1, printValue), // TIFF tag TagInfo(0x0208, "JPEGDCTables", N_("JPEG DC-Tables"), N_("This Field points to a list of offsets to the DC Huffman tables or " "the lossless Huffman tables, one per component."), ifd0Id, imgStruct, unsignedLong, -1, printValue), // TIFF tag TagInfo(0x0209, "JPEGACTables", N_("JPEG AC-Tables"), N_("This Field points to a list of offsets to the Huffman AC tables, " "one per component."), ifd0Id, imgStruct, unsignedLong, -1, printValue), // TIFF tag TagInfo(0x0211, "YCbCrCoefficients", N_("YCbCr Coefficients"), N_("The matrix coefficients for transformation from RGB to YCbCr " "image data. No default is given in TIFF; but here the " "value given in Appendix E, \"Color Space Guidelines\", is used " "as the default. The color space is declared in a " "color space information tag, with the default being the value " "that gives the optimal image characteristics " "Interoperability this condition."), ifd0Id, imgCharacter, unsignedRational, 3, printValue), TagInfo(0x0212, "YCbCrSubSampling", N_("YCbCr Sub-Sampling"), N_("The sampling ratio of chrominance components in relation to the " "luminance component. In JPEG compressed data a JPEG marker " "is used instead of this tag."), ifd0Id, imgStruct, unsignedShort, 2, printValue), TagInfo(0x0213, "YCbCrPositioning", N_("YCbCr Positioning"), N_("The position of chrominance components in relation to the " "luminance component. This field is designated only for " "JPEG compressed data or uncompressed YCbCr data. The TIFF " "default is 1 (centered); but when Y:Cb:Cr = 4:2:2 it is " "recommended in this standard that 2 (co-sited) be used to " "record data, in order to improve the image quality when viewed " "on TV systems. When this field does not exist, the reader shall " "assume the TIFF default. In the case of Y:Cb:Cr = 4:2:0, the " "TIFF default (centered) is recommended. If the reader " "does not have the capability of supporting both kinds of " ", it shall follow the TIFF default regardless " "of the value in this field. It is preferable that readers " "be able to support both centered and co-sited positioning."), ifd0Id, imgStruct, unsignedShort, 1, print0x0213), TagInfo(0x0214, "ReferenceBlackWhite", N_("Reference Black/White"), N_("The reference black point value and reference white point " "value. No defaults are given in TIFF, but the values " "below are given as defaults here. The color space is declared " "in a color space information tag, with the default " "being the value that gives the optimal image characteristics " "Interoperability these conditions."), ifd0Id, imgCharacter, unsignedRational, 6, printValue), TagInfo(0x02bc, "XMLPacket", N_("XML Packet"), N_("XMP Metadata (Adobe technote 9-14-02)"), ifd0Id, otherTags, unsignedByte, -1, printValue), TagInfo(0x4746, "Rating", N_("Windows Rating"), N_("Rating tag used by Windows"), ifd0Id, otherTags, unsignedShort, -1, printValue), // Windows Tag TagInfo(0x4749, "RatingPercent", N_("Windows Rating Percent"), N_("Rating tag used by Windows, value in percent"), ifd0Id, otherTags, unsignedShort, -1, printValue), // Windows Tag TagInfo(0x800d, "ImageID", N_("Image ID"), N_("ImageID is the full pathname of the original, high-resolution image, " "or any other identifying string that uniquely identifies the original " "image (Adobe OPI)."), ifd0Id, adobeOpi, asciiString, 0, printValue), // Adobe OPI tag TagInfo(0x828d, "CFARepeatPatternDim", N_("CFA Repeat Pattern Dimension"), N_("Contains two values representing the minimum rows and columns " "to define the repeating patterns of the color filter array"), ifd0Id, tiffEp, unsignedShort, 2, printValue), // TIFF/EP Tag TagInfo(0x828e, "CFAPattern", N_("CFA Pattern"), N_("Indicates the color filter array (CFA) geometric pattern of the image " "sensor when a one-chip color area sensor is used. It does not apply to " "all sensing methods"), ifd0Id, tiffEp, unsignedByte, -1, printValue), // TIFF/EP Tag TagInfo(0x828f, "BatteryLevel", N_("Battery Level"), "Contains a value of the battery level as a fraction or string", ifd0Id, tiffEp, unsignedRational, 1, printValue), // TIFF/EP Tag TagInfo(0x8298, "Copyright", N_("Copyright"), N_("Copyright information. In this standard the tag is used to " "indicate both the photographer and editor copyrights. It is " "the copyright notice of the person or organization claiming " "rights to the image. The Interoperability copyright " "statement including date and rights should be written in this " "field; e.g., \"Copyright, John Smith, 19xx. All rights " "reserved.\". In this standard the field records both the " "photographer and editor copyrights, with each recorded in a " "separate part of the statement. When there is a clear distinction " "between the photographer and editor copyrights, these are to be " "written in the order of photographer followed by editor copyright, " "separated by NULL (in this case since the statement also ends with " "a NULL, there are two NULL codes). When only the photographer " "copyright is given, it is terminated by one NULL code . When only " "the editor copyright is given, the photographer copyright part " "consists of one space followed by a terminating NULL code, then " "the editor copyright is given. When the field is left blank, it is " "treated as unknown."), ifd0Id, otherTags, asciiString, 0, print0x8298), TagInfo(0x829a, "ExposureTime", N_("Exposure Time"), N_("Exposure time, given in seconds."), ifd0Id, tiffEp, unsignedRational, 1, print0x829a), // TIFF/EP tag TagInfo(0x829d, "FNumber", N_("FNumber"), N_("The F number."), ifd0Id, tiffEp, unsignedRational, 1, print0x829d), // TIFF/EP tag TagInfo(0x83bb, "IPTCNAA", N_("IPTC/NAA"), N_("Contains an IPTC/NAA record"), ifd0Id, tiffEp, unsignedLong, 0, printValue), // TIFF/EP Tag TagInfo(0x8649, "ImageResources", N_("Image Resources Block"), N_("Contains information embedded by the Adobe Photoshop application"), ifd0Id, otherTags, unsignedByte, -1, printValue), TagInfo(0x8769, "ExifTag", N_("Exif IFD Pointer"), N_("A pointer to the Exif IFD. Interoperability, Exif IFD has the " "same structure as that of the IFD specified in TIFF. " "ordinarily, however, it does not contain image data as in " "the case of TIFF."), ifd0Id, exifFormat, unsignedLong, 1, printValue), TagInfo(0x8773, "InterColorProfile", N_("Inter Color Profile"), N_("Contains an InterColor Consortium (ICC) format color space characterization/profile"), ifd0Id, tiffEp, undefined, -1, printValue), TagInfo(0x8822, "ExposureProgram", N_("Exposure Program"), N_("The class of the program used by the camera to set exposure when the picture is taken."), ifd0Id, tiffEp, unsignedShort, 1, print0x8822), // TIFF/EP tag TagInfo(0x8824, "SpectralSensitivity", N_("Spectral Sensitivity"), N_("Indicates the spectral sensitivity of each channel of the camera used."), ifd0Id, tiffEp, asciiString, 0, printValue), // TIFF/EP tag TagInfo(0x8825, "GPSTag", N_("GPS Info IFD Pointer"), N_("A pointer to the GPS Info IFD. The " "Interoperability structure of the GPS Info IFD, like that of " "Exif IFD, has no image data."), ifd0Id, exifFormat, unsignedLong, 1, printValue), TagInfo(0x8827, "ISOSpeedRatings", N_("ISO Speed Ratings"), N_("Indicates the ISO Speed and ISO Latitude of the camera or input device as specified in ISO 12232."), ifd0Id, tiffEp, unsignedShort, 0, print0x8827), // TIFF/EP tag TagInfo(0x8828, "OECF", N_("OECF"), N_("Indicates the Opto-Electric Conversion Function (OECF) specified in ISO 14524."), ifd0Id, tiffEp, undefined, 0, printValue), // TIFF/EP tag TagInfo(0x8829, "Interlace", N_("Interlace"), N_("Indicates the field number of multifield images."), ifd0Id, tiffEp, unsignedShort, 1, printValue), // TIFF/EP tag TagInfo(0x882a, "TimeZoneOffset", N_("Time Zone Offset"), N_("This optional tag encodes the time zone of the camera clock (relative" "to Greenwich Mean Time) used to create the DataTimeOriginal tag-value" "when the picture was taken. It may also contain the time zone offset" "of the clock used to create the DateTime tag-value when the image was" "modified."), ifd0Id, tiffEp, signedShort, -1, printValue), TagInfo(0x882b, "SelfTimerMode", N_("Self Timer Mode"), N_("Number of seconds image capture was delayed from button press."), ifd0Id, tiffEp, unsignedShort, 1, printValue), // TIFF/EP tag TagInfo(0x9003, "DateTimeOriginal", N_("Date Time Original"), N_("The date and time when the original image data was generated."), ifd0Id, tiffEp, asciiString, 20, printValue), // TIFF/EP tag TagInfo(0x9102, "CompressedBitsPerPixel", N_("Compressed Bits Per Pixel"), N_("Specific to compressed data; states the compressed bits per pixel."), ifd0Id, tiffEp, unsignedRational, 1, printFloat), // TIFF/EP tag TagInfo(0x9201, "ShutterSpeedValue", N_("Shutter Speed Value"), N_("Shutter speed."), ifd0Id, tiffEp, signedRational, 1, print0x9201), // TIFF/EP tag TagInfo(0x9202, "ApertureValue", N_("Aperture Value"), N_("The lens aperture."), ifd0Id, tiffEp, unsignedRational, 1, print0x9202), // TIFF/EP tag TagInfo(0x9203, "BrightnessValue", N_("Brightness Value"), N_("The value of brightness."), ifd0Id, tiffEp, signedRational, 1, printFloat), // TIFF/EP tag TagInfo(0x9204, "ExposureBiasValue", N_("Exposure Bias Value"), N_("The exposure bias."), ifd0Id, tiffEp, signedRational, 1, print0x9204), // TIFF/EP tag TagInfo(0x9205, "MaxApertureValue", N_("Max Aperture Value"), N_("The smallest F number of the lens."), ifd0Id, tiffEp, unsignedRational, 1, print0x9202), // TIFF/EP tag TagInfo(0x9206, "SubjectDistance", N_("Subject Distance"), N_("The distance to the subject, given in meters."), ifd0Id, tiffEp, signedRational, 1, print0x9206), // TIFF/EP tag TagInfo(0x9207, "MeteringMode", N_("Metering Mode"), N_("The metering mode."), ifd0Id, tiffEp, unsignedShort, 1, print0x9207), // TIFF/EP tag TagInfo(0x9208, "LightSource", N_("Light Source"), N_("The kind of light source."), ifd0Id, tiffEp, unsignedShort, 1, print0x9208), // TIFF/EP tag TagInfo(0x9209, "Flash", N_("Flash"), N_("Indicates the status of flash when the image was shot."), ifd0Id, tiffEp, unsignedShort, 1, EXV_PRINT_TAG(exifFlash)), // TIFF/EP tag TagInfo(0x920a, "FocalLength", N_("Focal Length"), N_("The actual focal length of the lens, in mm."), ifd0Id, tiffEp, unsignedRational, 1, print0x920a), // TIFF/EP tag TagInfo(0x920b, "FlashEnergy", N_("Flash Energy"), N_("Amount of flash energy (BCPS)."), ifd0Id, tiffEp, unsignedRational, 1, printValue), // TIFF/EP tag TagInfo(0x920c, "SpatialFrequencyResponse", N_("Spatial Frequency Response"), N_("SFR of the camera."), ifd0Id, tiffEp, undefined, 0, printValue), // TIFF/EP tag TagInfo(0x920d, "Noise", N_("Noise"), N_("Noise measurement values."), ifd0Id, tiffEp, undefined, 0, printValue), // TIFF/EP tag TagInfo(0x920e, "FocalPlaneXResolution", N_("Focal Plane X Resolution"), N_("Number of pixels per FocalPlaneResolutionUnit (37392) in ImageWidth direction for main image."), ifd0Id, tiffEp, unsignedRational, 1, printValue), // TIFF/EP tag TagInfo(0x920f, "FocalPlaneYResolution", N_("Focal Plane Y Resolution"), N_("Number of pixels per FocalPlaneResolutionUnit (37392) in ImageLength direction for main image."), ifd0Id, tiffEp, unsignedRational, 1, printValue), // TIFF/EP tag TagInfo(0x9210, "FocalPlaneResolutionUnit", N_("Focal Plane Resolution Unit"), N_("Unit of measurement for FocalPlaneXResolution(37390) and FocalPlaneYResolution(37391)."), ifd0Id, tiffEp, unsignedShort, 1, printValue), // TIFF/EP tag TagInfo(0x9211, "ImageNumber", N_("Image Number"), N_("Number assigned to an image, e.g., in a chained image burst."), ifd0Id, tiffEp, unsignedLong, 1, printValue), // TIFF/EP tag TagInfo(0x9212, "SecurityClassification", N_("Security Classification"), N_("Security classification assigned to the image."), ifd0Id, tiffEp, asciiString, 0, printValue), // TIFF/EP tag TagInfo(0x9213, "ImageHistory", N_("Image History"), N_("Record of what has been done to the image."), ifd0Id, tiffEp, asciiString, 0, printValue), // TIFF/EP tag TagInfo(0x9214, "SubjectLocation", N_("Subject Location"), N_("Indicates the location and area of the main subject in the overall scene."), ifd0Id, tiffEp, unsignedShort, 2, printValue), // TIFF/EP tag TagInfo(0x9215, "ExposureIndex", N_("Exposure Index"), N_("Encodes the camera exposure index setting when image was captured."), ifd0Id, tiffEp, unsignedRational, 1, printValue), // TIFF/EP tag TagInfo(0x9216, "TIFFEPStandardID", N_("TIFF/EP Standard ID"), N_("Contains four ASCII characters representing the TIFF/EP standard " "version of a TIFF/EP file, eg '1', '0', '0', '0'"), ifd0Id, tiffEp, unsignedByte, 4, printValue), // TIFF/EP Tag TagInfo(0x9217, "SensingMethod", N_("Sensing Method"), N_("Type of image sensor."), ifd0Id, tiffEp, unsignedShort, 1, printValue), // TIFF/EP tag TagInfo(0x9c9b, "XPTitle", N_("Windows Title"), N_("Title tag used by Windows, encoded in UCS2"), ifd0Id, otherTags, unsignedByte, -1, printUcs2), // Windows Tag TagInfo(0x9c9c, "XPComment", N_("Windows Comment"), N_("Comment tag used by Windows, encoded in UCS2"), ifd0Id, otherTags, unsignedByte, -1, printUcs2), // Windows Tag TagInfo(0x9c9d, "XPAuthor", N_("Windows Author"), N_("Author tag used by Windows, encoded in UCS2"), ifd0Id, otherTags, unsignedByte, -1, printUcs2), // Windows Tag TagInfo(0x9c9e, "XPKeywords", N_("Windows Keywords"), N_("Keywords tag used by Windows, encoded in UCS2"), ifd0Id, otherTags, unsignedByte, -1, printUcs2), // Windows Tag TagInfo(0x9c9f, "XPSubject", N_("Windows Subject"), N_("Subject tag used by Windows, encoded in UCS2"), ifd0Id, otherTags, unsignedByte, -1, printUcs2), // Windows Tag TagInfo(0xc4a5, "PrintImageMatching", N_("Print Image Matching"), N_("Print Image Matching, description needed."), ifd0Id, otherTags, undefined, -1, printValue), TagInfo(0xc612, "DNGVersion", N_("DNG version"), N_("This tag encodes the DNG four-tier version number. For files " "compliant with version 1.1.0.0 of the DNG specification, this " "tag should contain the bytes: 1, 1, 0, 0."), ifd0Id, dngTags, unsignedByte, 4, printValue), // DNG tag TagInfo(0xc613, "DNGBackwardVersion", N_("DNG backward version"), N_("This tag specifies the oldest version of the Digital Negative " "specification for which a file is compatible. Readers should" "not attempt to read a file if this tag specifies a version " "number that is higher than the version number of the specification " "the reader was based on. In addition to checking the version tags, " "readers should, for all tags, check the types, counts, and values, " "to verify it is able to correctly read the file."), ifd0Id, dngTags, unsignedByte, 4, printValue), // DNG tag TagInfo(0xc614, "UniqueCameraModel", N_("Unique Camera Model"), N_("Defines a unique, non-localized name for the camera model that " "created the image in the raw file. This name should include the " "manufacturer's name to avoid conflicts, and should not be localized, " "even if the camera name itself is localized for different markets " "(see LocalizedCameraModel). This string may be used by reader " "software to index into per-model preferences and replacement profiles."), ifd0Id, dngTags, asciiString, 0, printValue), // DNG tag TagInfo(0xc615, "LocalizedCameraModel", N_("Localized Camera Model"), N_("Similar to the UniqueCameraModel field, except the name can be " "localized for different markets to match the localization of the " "camera name."), ifd0Id, dngTags, unsignedByte, 0, printValue), // DNG tag TagInfo(0xc616, "CFAPlaneColor", N_("CFA Plane Color"), N_("Provides a mapping between the values in the CFAPattern tag and the " "plane numbers in LinearRaw space. This is a required tag for non-RGB " "CFA images."), ifd0Id, dngTags, unsignedByte, -1, printValue), // DNG tag TagInfo(0xc617, "CFALayout", N_("CFA Layout"), N_("Describes the spatial layout of the CFA."), ifd0Id, dngTags, unsignedShort, 1, EXV_PRINT_TAG(exifCfaLayout)), // DNG tag TagInfo(0xc618, "LinearizationTable", N_("Linearization Table"), N_("Describes a lookup table that maps stored values into linear values. " "This tag is typically used to increase compression ratios by storing " "the raw data in a non-linear, more visually uniform space with fewer " "total encoding levels. If SamplesPerPixel is not equal to one, this " "single table applies to all the samples for each pixel."), ifd0Id, dngTags, unsignedShort, -1, printValue), // DNG tag TagInfo(0xc619, "BlackLevelRepeatDim", N_("Black Level Repeat Dim"), N_("Specifies repeat pattern size for the BlackLevel tag."), ifd0Id, dngTags, unsignedShort, 2, printValue), // DNG tag TagInfo(0xc61a, "BlackLevel", N_("Black Level"), N_("Specifies the zero light (a.k.a. thermal black or black current) " "encoding level, as a repeating pattern. The origin of this pattern " "is the top-left corner of the ActiveArea rectangle. The values are " "stored in row-column-sample scan order."), ifd0Id, dngTags, unsignedRational, -1, printValue), // DNG tag TagInfo(0xc61b, "BlackLevelDeltaH", N_("Black Level Delta H"), N_("If the zero light encoding level is a function of the image column, " "BlackLevelDeltaH specifies the difference between the zero light " "encoding level for each column and the baseline zero light encoding " "level. If SamplesPerPixel is not equal to one, this single table " "applies to all the samples for each pixel."), ifd0Id, dngTags, signedRational, -1, printValue), // DNG tag TagInfo(0xc61c, "BlackLevelDeltaV", N_("Black Level Delta V"), N_("If the zero light encoding level is a function of the image row, " "this tag specifies the difference between the zero light encoding " "level for each row and the baseline zero light encoding level. If " "SamplesPerPixel is not equal to one, this single table applies to " "all the samples for each pixel."), ifd0Id, dngTags, signedRational, -1, printValue), // DNG tag TagInfo(0xc61d, "WhiteLevel", N_("White Level"), N_("This tag specifies the fully saturated encoding level for the raw " "sample values. Saturation is caused either by the sensor itself " "becoming highly non-linear in response, or by the camera's analog " "to digital converter clipping."), ifd0Id, dngTags, unsignedShort, -1, printValue), // DNG tag TagInfo(0xc61e, "DefaultScale", N_("Default Scale"), N_("DefaultScale is required for cameras with non-square pixels. It " "specifies the default scale factors for each direction to convert " "the image to square pixels. Typically these factors are selected " "to approximately preserve total pixel count. For CFA images that " "use CFALayout equal to 2, 3, 4, or 5, such as the Fujifilm SuperCCD, " "these two values should usually differ by a factor of 2.0."), ifd0Id, dngTags, unsignedRational, 2, printValue), // DNG tag TagInfo(0xc61f, "DefaultCropOrigin", N_("Default Crop Origin"), N_("Raw images often store extra pixels around the edges of the final " "image. These extra pixels help prevent interpolation artifacts near " "the edges of the final image. DefaultCropOrigin specifies the origin " "of the final image area, in raw image coordinates (i.e., before the " "DefaultScale has been applied), relative to the top-left corner of " "the ActiveArea rectangle."), ifd0Id, dngTags, unsignedShort, 2, printValue), // DNG tag TagInfo(0xc620, "DefaultCropSize", N_("Default Crop Size"), N_("Raw images often store extra pixels around the edges of the final " "image. These extra pixels help prevent interpolation artifacts near " "the edges of the final image. DefaultCropSize specifies the size of " "the final image area, in raw image coordinates (i.e., before the " "DefaultScale has been applied)."), ifd0Id, dngTags, unsignedShort, 2, printValue), // DNG tag TagInfo(0xc621, "ColorMatrix1", N_("Color Matrix 1"), N_("ColorMatrix1 defines a transformation matrix that converts XYZ " "values to reference camera native color space values, under the " "first calibration illuminant. The matrix values are stored in row " "scan order. The ColorMatrix1 tag is required for all non-monochrome " "DNG files."), ifd0Id, dngTags, signedRational, -1, printValue), // DNG tag TagInfo(0xc622, "ColorMatrix2", N_("Color Matrix 2"), N_("ColorMatrix2 defines a transformation matrix that converts XYZ " "values to reference camera native color space values, under the " "second calibration illuminant. The matrix values are stored in row " "scan order."), ifd0Id, dngTags, signedRational, -1, printValue), // DNG tag TagInfo(0xc623, "CameraCalibration1", N_("Camera Calibration 1"), N_("CameraClalibration1 defines a calibration matrix that transforms " "reference camera native space values to individual camera native " "space values under the first calibration illuminant. The matrix is " "stored in row scan order. This matrix is stored separately from the " "matrix specified by the ColorMatrix1 tag to allow raw converters to " "swap in replacement color matrices based on UniqueCameraModel tag, " "while still taking advantage of any per-individual camera calibration " "performed by the camera manufacturer."), ifd0Id, dngTags, signedRational, -1, printValue), // DNG tag TagInfo(0xc624, "CameraCalibration2", N_("Camera Calibration 2"), N_("CameraCalibration2 defines a calibration matrix that transforms " "reference camera native space values to individual camera native " "space values under the second calibration illuminant. The matrix is " "stored in row scan order. This matrix is stored separately from the " "matrix specified by the ColorMatrix2 tag to allow raw converters to " "swap in replacement color matrices based on UniqueCameraModel tag, " "while still taking advantage of any per-individual camera calibration " "performed by the camera manufacturer."), ifd0Id, dngTags, signedRational, -1, printValue), // DNG tag TagInfo(0xc625, "ReductionMatrix1", N_("Reduction Matrix 1"), N_("ReductionMatrix1 defines a dimensionality reduction matrix for use as " "the first stage in converting color camera native space values to XYZ " "values, under the first calibration illuminant. This tag may only be " "used if ColorPlanes is greater than 3. The matrix is stored in row " "scan order."), ifd0Id, dngTags, signedRational, -1, printValue), // DNG tag TagInfo(0xc626, "ReductionMatrix2", N_("Reduction Matrix 2"), N_("ReductionMatrix2 defines a dimensionality reduction matrix for use as " "the first stage in converting color camera native space values to XYZ " "values, under the second calibration illuminant. This tag may only be " "used if ColorPlanes is greater than 3. The matrix is stored in row " "scan order."), ifd0Id, dngTags, signedRational, -1, printValue), // DNG tag TagInfo(0xc627, "AnalogBalance", N_("Analog Balance"), N_("Normally the stored raw values are not white balanced, since any " "digital white balancing will reduce the dynamic range of the final " "image if the user decides to later adjust the white balance; " "however, if camera hardware is capable of white balancing the color " "channels before the signal is digitized, it can improve the dynamic " "range of the final image. AnalogBalance defines the gain, either " "analog (recommended) or digital (not recommended) that has been " "applied the stored raw values."), ifd0Id, dngTags, unsignedRational, -1, printValue), // DNG tag TagInfo(0xc628, "AsShotNeutral", N_("As Shot Neutral"), N_("Specifies the selected white balance at time of capture, encoded as " "the coordinates of a perfectly neutral color in linear reference " "space values. The inclusion of this tag precludes the inclusion of " "the AsShotWhiteXY tag."), ifd0Id, dngTags, unsignedShort, -1, printValue), // DNG tag TagInfo(0xc629, "AsShotWhiteXY", N_("As Shot White XY"), N_("Specifies the selected white balance at time of capture, encoded as " "x-y chromaticity coordinates. The inclusion of this tag precludes " "the inclusion of the AsShotNeutral tag."), ifd0Id, dngTags, unsignedRational, 2, printValue), // DNG tag TagInfo(0xc62a, "BaselineExposure", N_("Baseline Exposure"), N_("Camera models vary in the trade-off they make between highlight " "headroom and shadow noise. Some leave a significant amount of " "highlight headroom during a normal exposure. This allows significant " "negative exposure compensation to be applied during raw conversion, " "but also means normal exposures will contain more shadow noise. Other " "models leave less headroom during normal exposures. This allows for " "less negative exposure compensation, but results in lower shadow " "noise for normal exposures. Because of these differences, a raw " "converter needs to vary the zero point of its exposure compensation " "control from model to model. BaselineExposure specifies by how much " "(in EV units) to move the zero point. Positive values result in " "brighter default results, while negative values result in darker " "default results."), ifd0Id, dngTags, signedRational, 1, printValue), // DNG tag TagInfo(0xc62b, "BaselineNoise", N_("Baseline Noise"), N_("Specifies the relative noise level of the camera model at a baseline " "ISO value of 100, compared to a reference camera model. Since noise " "levels tend to vary approximately with the square root of the ISO " "value, a raw converter can use this value, combined with the current " "ISO, to estimate the relative noise level of the current image."), ifd0Id, dngTags, unsignedRational, 1, printValue), // DNG tag TagInfo(0xc62c, "BaselineSharpness", N_("Baseline Sharpness"), N_("Specifies the relative amount of sharpening required for this camera " "model, compared to a reference camera model. Camera models vary in " "the strengths of their anti-aliasing filters. Cameras with weak or " "no filters require less sharpening than cameras with strong " "anti-aliasing filters."), ifd0Id, dngTags, unsignedRational, 1, printValue), // DNG tag TagInfo(0xc62d, "BayerGreenSplit", N_("Bayer Green Split"), N_("Only applies to CFA images using a Bayer pattern filter array. This " "tag specifies, in arbitrary units, how closely the values of the " "green pixels in the blue/green rows track the values of the green " "pixels in the red/green rows. A value of zero means the two kinds " "of green pixels track closely, while a non-zero value means they " "sometimes diverge. The useful range for this tag is from 0 (no " "divergence) to about 5000 (quite large divergence)."), ifd0Id, dngTags, unsignedLong, 1, printValue), // DNG tag TagInfo(0xc62e, "LinearResponseLimit", N_("Linear Response Limit"), N_("Some sensors have an unpredictable non-linearity in their response " "as they near the upper limit of their encoding range. This " "non-linearity results in color shifts in the highlight areas of the " "resulting image unless the raw converter compensates for this effect. " "LinearResponseLimit specifies the fraction of the encoding range " "above which the response may become significantly non-linear."), ifd0Id, dngTags, unsignedRational, 1, printValue), // DNG tag TagInfo(0xc62f, "CameraSerialNumber", N_("Camera Serial Number"), N_("CameraSerialNumber contains the serial number of the camera or camera " "body that captured the image."), ifd0Id, dngTags, asciiString, 0, printValue), // DNG tag TagInfo(0xc630, "LensInfo", N_("Lens Info"), N_("Contains information about the lens that captured the image. If the " "minimum f-stops are unknown, they should be encoded as 0/0."), ifd0Id, dngTags, unsignedRational, 4, printValue), // DNG tag TagInfo(0xc631, "ChromaBlurRadius", N_("Chroma Blur Radius"), N_("ChromaBlurRadius provides a hint to the DNG reader about how much " "chroma blur should be applied to the image. If this tag is omitted, " "the reader will use its default amount of chroma blurring. " "Normally this tag is only included for non-CFA images, since the " "amount of chroma blur required for mosaic images is highly dependent " "on the de-mosaic algorithm, in which case the DNG reader's default " "value is likely optimized for its particular de-mosaic algorithm."), ifd0Id, dngTags, unsignedRational, 1, printValue), // DNG tag TagInfo(0xc632, "AntiAliasStrength", N_("Anti Alias Strength"), N_("Provides a hint to the DNG reader about how strong the camera's " "anti-alias filter is. A value of 0.0 means no anti-alias filter " "(i.e., the camera is prone to aliasing artifacts with some subjects), " "while a value of 1.0 means a strong anti-alias filter (i.e., the " "camera almost never has aliasing artifacts)."), ifd0Id, dngTags, unsignedRational, 1, printValue), // DNG tag TagInfo(0xc633, "ShadowScale", N_("Shadow Scale"), N_("This tag is used by Adobe Camera Raw to control the sensitivity of " "its 'Shadows' slider."), ifd0Id, dngTags, signedRational, 1, printValue), // DNG tag TagInfo(0xc634, "DNGPrivateData", N_("DNG Private Data"), N_("Provides a way for camera manufacturers to store private data in the " "DNG file for use by their own raw converters, and to have that data " "preserved by programs that edit DNG files."), ifd0Id, dngTags, unsignedByte, -1, printValue), // DNG tag TagInfo(0xc635, "MakerNoteSafety", N_("MakerNote Safety"), N_("MakerNoteSafety lets the DNG reader know whether the EXIF MakerNote " "tag is safe to preserve along with the rest of the EXIF data. File " "browsers and other image management software processing an image " "with a preserved MakerNote should be aware that any thumbnail " "image embedded in the MakerNote may be stale, and may not reflect " "the current state of the full size image."), ifd0Id, dngTags, unsignedShort, 1, printValue), // DNG tag TagInfo(0xc65a, "CalibrationIlluminant1", N_("Calibration Illuminant 1"), N_("The illuminant used for the first set of color calibration tags " "(ColorMatrix1, CameraCalibration1, ReductionMatrix1). The legal " "values for this tag are the same as the legal values for the " "LightSource EXIF tag."), ifd0Id, dngTags, unsignedShort, 1, printValue), // DNG tag TagInfo(0xc65b, "CalibrationIlluminant2", N_("Calibration Illuminant 2"), N_("The illuminant used for an optional second set of color calibration " "tags (ColorMatrix2, CameraCalibration2, ReductionMatrix2). The legal " "values for this tag are the same as the legal values for the " "CalibrationIlluminant1 tag; however, if both are included, neither " "is allowed to have a value of 0 (unknown)."), ifd0Id, dngTags, unsignedShort, 1, printValue), // DNG tag TagInfo(0xc65c, "BestQualityScale", N_("Best Quality Scale"), N_("For some cameras, the best possible image quality is not achieved " "by preserving the total pixel count during conversion. For example, " "Fujifilm SuperCCD images have maximum detail when their total pixel " "count is doubled. This tag specifies the amount by which the values " "of the DefaultScale tag need to be multiplied to achieve the best " "quality image size."), ifd0Id, dngTags, unsignedRational, 1, printValue), // DNG tag TagInfo(0xc65d, "RawDataUniqueID", N_("Raw Data Unique ID"), N_("This tag contains a 16-byte unique identifier for the raw image data " "in the DNG file. DNG readers can use this tag to recognize a " "particular raw image, even if the file's name or the metadata " "contained in the file has been changed. If a DNG writer creates such " "an identifier, it should do so using an algorithm that will ensure " "that it is very unlikely two different images will end up having the " "same identifier."), ifd0Id, dngTags, unsignedByte, 16, printValue), // DNG tag TagInfo(0xc68b, "OriginalRawFileName", N_("Original Raw File Name"), N_("If the DNG file was converted from a non-DNG raw file, then this tag " "contains the file name of that original raw file."), ifd0Id, dngTags, unsignedByte, 0, printValue), // DNG tag TagInfo(0xc68c, "OriginalRawFileData", N_("Original Raw File Data"), N_("If the DNG file was converted from a non-DNG raw file, then this tag " "contains the compressed contents of that original raw file. The " "contents of this tag always use the big-endian byte order. The tag " "contains a sequence of data blocks. Future versions of the DNG " "specification may define additional data blocks, so DNG readers " "should ignore extra bytes when parsing this tag. DNG readers should " "also detect the case where data blocks are missing from the end of " "the sequence, and should assume a default value for all the missing " "blocks. There are no padding or alignment bytes between data blocks."), ifd0Id, dngTags, undefined, -1, printValue), // DNG tag TagInfo(0xc68d, "ActiveArea", N_("Active Area"), N_("This rectangle defines the active (non-masked) pixels of the sensor. " "The order of the rectangle coordinates is: top, left, bottom, right."), ifd0Id, dngTags, unsignedShort, 4, printValue), // DNG tag TagInfo(0xc68e, "MaskedAreas", N_("Masked Areas"), N_("This tag contains a list of non-overlapping rectangle coordinates of " "fully masked pixels, which can be optionally used by DNG readers " "to measure the black encoding level. The order of each rectangle's " "coordinates is: top, left, bottom, right. If the raw image data has " "already had its black encoding level subtracted, then this tag should " "not be used, since the masked pixels are no longer useful."), ifd0Id, dngTags, unsignedShort, -1, printValue), // DNG tag TagInfo(0xc68f, "AsShotICCProfile", N_("As-Shot ICC Profile"), N_("This tag contains an ICC profile that, in conjunction with the " "AsShotPreProfileMatrix tag, provides the camera manufacturer with a " "way to specify a default color rendering from camera color space " "coordinates (linear reference values) into the ICC profile connection " "space. The ICC profile connection space is an output referred " "colorimetric space, whereas the other color calibration tags in DNG " "specify a conversion into a scene referred colorimetric space. This " "means that the rendering in this profile should include any desired " "tone and gamut mapping needed to convert between scene referred " "values and output referred values."), ifd0Id, dngTags, undefined, -1, printValue), // DNG tag TagInfo(0xc690, "AsShotPreProfileMatrix", N_("As-Shot Pre-Profile Matrix"), N_("This tag is used in conjunction with the AsShotICCProfile tag. It " "specifies a matrix that should be applied to the camera color space " "coordinates before processing the values through the ICC profile " "specified in the AsShotICCProfile tag. The matrix is stored in the " "row scan order. If ColorPlanes is greater than three, then this " "matrix can (but is not required to) reduce the dimensionality of the " "color data down to three components, in which case the AsShotICCProfile " "should have three rather than ColorPlanes input components."), ifd0Id, dngTags, signedRational, -1, printValue), // DNG tag TagInfo(0xc691, "CurrentICCProfile", N_("Current ICC Profile"), N_("This tag is used in conjunction with the CurrentPreProfileMatrix tag. " "The CurrentICCProfile and CurrentPreProfileMatrix tags have the same " "purpose and usage as the AsShotICCProfile and AsShotPreProfileMatrix " "tag pair, except they are for use by raw file editors rather than " "camera manufacturers."), ifd0Id, dngTags, undefined, -1, printValue), // DNG tag TagInfo(0xc692, "CurrentPreProfileMatrix", N_("Current Pre-Profile Matrix"), N_("This tag is used in conjunction with the CurrentICCProfile tag. " "The CurrentICCProfile and CurrentPreProfileMatrix tags have the same " "purpose and usage as the AsShotICCProfile and AsShotPreProfileMatrix " "tag pair, except they are for use by raw file editors rather than " "camera manufacturers."), ifd0Id, dngTags, signedRational, -1, printValue), // DNG tag TagInfo(0xc6bf, "ColorimetricReference", N_("Colorimetric Reference"), N_("The DNG color model documents a transform between camera colors and " "CIE XYZ values. This tag describes the colorimetric reference for the " "CIE XYZ values. 0 = The XYZ values are scene-referred. 1 = The XYZ values " "are output-referred, using the ICC profile perceptual dynamic range. This " "tag allows output-referred data to be stored in DNG files and still processed " "correctly by DNG readers."), ifd0Id, dngTags, unsignedShort, 0, printValue), // DNG tag TagInfo(0xc6f3, "CameraCalibrationSignature", N_("Camera Calibration Signature"), N_("A UTF-8 encoded string associated with the CameraCalibration1 and " "CameraCalibration2 tags. The CameraCalibration1 and CameraCalibration2 tags " "should only be used in the DNG color transform if the string stored in the " "CameraCalibrationSignature tag exactly matches the string stored in the " "ProfileCalibrationSignature tag for the selected camera profile."), ifd0Id, dngTags, unsignedByte, 0, printValue), // DNG tag TagInfo(0xc6f4, "ProfileCalibrationSignature", N_("Profile Calibration Signature"), N_("A UTF-8 encoded string associated with the camera profile tags. The " "CameraCalibration1 and CameraCalibration2 tags should only be used in the " "DNG color transfer if the string stored in the CameraCalibrationSignature " "tag exactly matches the string stored in the ProfileCalibrationSignature tag " "for the selected camera profile."), ifd0Id, dngTags, unsignedByte, 0, printValue), // DNG tag TagInfo(0xc6f6, "AsShotProfileName", N_("As Shot Profile Name"), N_("A UTF-8 encoded string containing the name of the \"as shot\" camera " "profile, if any."), ifd0Id, dngTags, unsignedByte, 0, printValue), // DNG tag TagInfo(0xc6f7, "NoiseReductionApplied", N_("Noise Reduction Applied"), N_("This tag indicates how much noise reduction has been applied to the raw " "data on a scale of 0.0 to 1.0. A 0.0 value indicates that no noise reduction " "has been applied. A 1.0 value indicates that the \"ideal\" amount of noise " "reduction has been applied, i.e. that the DNG reader should not apply " "additional noise reduction by default. A value of 0/0 indicates that this " "parameter is unknown."), ifd0Id, dngTags, unsignedRational, 1, printValue), // DNG tag TagInfo(0xc6f8, "ProfileName", N_("Profile Name"), N_("A UTF-8 encoded string containing the name of the camera profile. This " "tag is optional if there is only a single camera profile stored in the file " "but is required for all camera profiles if there is more than one camera " "profile stored in the file."), ifd0Id, dngTags, unsignedByte, 0, printValue), // DNG tag TagInfo(0xc6f9, "ProfileHueSatMapDims", N_("Profile Hue Sat Map Dims"), N_("This tag specifies the number of input samples in each dimension of the " "hue/saturation/value mapping tables. The data for these tables are stored " "in ProfileHueSatMapData1 and ProfileHueSatMapData2 tags. The most common " "case has ValueDivisions equal to 1, so only hue and saturation are used as " "inputs to the mapping table."), ifd0Id, dngTags, unsignedLong, 3, printValue), // DNG tag TagInfo(0xc6fa, "ProfileHueSatMapData1", N_("Profile Hue Sat Map Data 1"), N_("This tag contains the data for the first hue/saturation/value mapping " "table. Each entry of the table contains three 32-bit IEEE floating-point " "values. The first entry is hue shift in degrees; the second entry is " "saturation scale factor; and the third entry is a value scale factor. The " "table entries are stored in the tag in nested loop order, with the value " "divisions in the outer loop, the hue divisions in the middle loop, and the " "saturation divisions in the inner loop. All zero input saturation entries " "are required to have a value scale factor of 1.0."), ifd0Id, dngTags, tiffFloat, 0, printValue), // DNG tag TagInfo(0xc6fb, "ProfileHueSatMapData2", N_("Profile Hue Sat Map Data 2"), N_("This tag contains the data for the second hue/saturation/value mapping " "table. Each entry of the table contains three 32-bit IEEE floating-point " "values. The first entry is hue shift in degrees; the second entry is a " "saturation scale factor; and the third entry is a value scale factor. The " "table entries are stored in the tag in nested loop order, with the value " "divisions in the outer loop, the hue divisions in the middle loop, and the " "saturation divisions in the inner loop. All zero input saturation entries " "are required to have a value scale factor of 1.0."), ifd0Id, dngTags, tiffFloat, 0, printValue), // DNG tag TagInfo(0xc6fc, "ProfileToneCurve", N_("Profile Tone Curve"), N_("This tag contains a default tone curve that can be applied while " "processing the image as a starting point for user adjustments. The curve " "is specified as a list of 32-bit IEEE floating-point value pairs in linear " "gamma. Each sample has an input value in the range of 0.0 to 1.0, and an " "output value in the range of 0.0 to 1.0. The first sample is required to be " "(0.0, 0.0), and the last sample is required to be (1.0, 1.0). Interpolated " "the curve using a cubic spline."), ifd0Id, dngTags, tiffFloat, -1, printValue), // DNG tag TagInfo(0xc6fd, "ProfileEmbedPolicy", N_("Profile Embed Policy"), N_("This tag contains information about the usage rules for the associated " "camera profile."), ifd0Id, dngTags, unsignedLong, 1, printValue), // DNG tag TagInfo(0xc6fe, "ProfileCopyright", N_("Profile Copyright"), N_("A UTF-8 encoded string containing the copyright information for the " "camera profile. This string always should be preserved along with the other " "camera profile tags."), ifd0Id, dngTags, unsignedByte, 0, printValue), // DNG tag TagInfo(0xc714, "ForwardMatrix1", N_("Forward Matrix 1"), N_("This tag defines a matrix that maps white balanced camera colors to XYZ " "D50 colors."), ifd0Id, dngTags, signedRational, -1, printValue), // DNG tag TagInfo(0xc715, "ForwardMatrix2", N_("Forward Matrix 2"), N_("This tag defines a matrix that maps white balanced camera colors to XYZ " "D50 colors."), ifd0Id, dngTags, signedRational, -1, printValue), // DNG tag TagInfo(0xc716, "PreviewApplicationName", N_("Preview Application Name"), N_("A UTF-8 encoded string containing the name of the application that " "created the preview stored in the IFD."), ifd0Id, dngTags, unsignedByte, 0, printValue), // DNG tag TagInfo(0xc717, "PreviewApplicationVersion", N_("Preview Application Version"), N_("A UTF-8 encoded string containing the version number of the application " "that created the preview stored in the IFD."), ifd0Id, dngTags, unsignedByte, 0, printValue), // DNG tag TagInfo(0xc718, "PreviewSettingsName", N_("Preview Settings Name"), N_("A UTF-8 encoded string containing the name of the conversion settings " "(for example, snapshot name) used for the preview stored in the IFD."), ifd0Id, dngTags, unsignedByte, 0, printValue), // DNG tag TagInfo(0xc719, "PreviewSettingsDigest", N_("Preview Settings Digest"), N_("A unique ID of the conversion settings (for example, MD5 digest) used " "to render the preview stored in the IFD."), ifd0Id, dngTags, unsignedByte, 16, printValue), // DNG tag TagInfo(0xc71a, "PreviewColorSpace", N_("Preview Color Space"), N_("This tag specifies the color space in which the rendered preview in this " "IFD is stored. The default value for this tag is sRGB for color previews " "and Gray Gamma 2.2 for monochrome previews."), ifd0Id, dngTags, unsignedLong, 1, printValue), // DNG tag TagInfo(0xc71b, "PreviewDateTime", N_("Preview Date Time"), N_("This tag is an ASCII string containing the name of the date/time at which " "the preview stored in the IFD was rendered. The date/time is encoded using " "ISO 8601 format."), ifd0Id, dngTags, asciiString, 0, printValue), // DNG tag TagInfo(0xc71c, "RawImageDigest", N_("Raw Image Digest"), N_("This tag is an MD5 digest of the raw image data. All pixels in the image " "are processed in row-scan order. Each pixel is zero padded to 16 or 32 bits " "deep (16-bit for data less than or equal to 16 bits deep, 32-bit otherwise). " "The data for each pixel is processed in little-endian byte order."), ifd0Id, dngTags, undefined, 16, printValue), // DNG tag TagInfo(0xc71d, "OriginalRawFileDigest", N_("Original Raw File Digest"), N_("This tag is an MD5 digest of the data stored in the OriginalRawFileData " "tag."), ifd0Id, dngTags, undefined, 16, printValue), // DNG tag TagInfo(0xc71e, "SubTileBlockSize", N_("Sub Tile Block Size"), N_("Normally, the pixels within a tile are stored in simple row-scan order. " "This tag specifies that the pixels within a tile should be grouped first " "into rectangular blocks of the specified size. These blocks are stored in " "row-scan order. Within each block, the pixels are stored in row-scan order. " "The use of a non-default value for this tag requires setting the " "DNGBackwardVersion tag to at least 1.2.0.0."), ifd0Id, dngTags, unsignedLong, 2, printValue), // DNG tag TagInfo(0xc71f, "RowInterleaveFactor", N_("Row Interleave Factor"), N_("This tag specifies that rows of the image are stored in interleaved " "order. The value of the tag specifies the number of interleaved fields. " "The use of a non-default value for this tag requires setting the " "DNGBackwardVersion tag to at least 1.2.0.0."), ifd0Id, dngTags, unsignedLong, 1, printValue), // DNG tag TagInfo(0xc725, "ProfileLookTableDims", N_("Profile Look Table Dims"), N_("This tag specifies the number of input samples in each dimension of a " "default \"look\" table. The data for this table is stored in the " "ProfileLookTableData tag."), ifd0Id, dngTags, unsignedLong, 3, printValue), // DNG tag TagInfo(0xc726, "ProfileLookTableData", N_("Profile Look Table Data"), N_("This tag contains a default \"look\" table that can be applied while " "processing the image as a starting point for user adjustment. This table " "uses the same format as the tables stored in the ProfileHueSatMapData1 " "and ProfileHueSatMapData2 tags, and is applied in the same color space. " "However, it should be applied later in the processing pipe, after any " "exposure compensation and/or fill light stages, but before any tone curve " "stage. Each entry of the table contains three 32-bit IEEE floating-point " "values. The first entry is hue shift in degrees, the second entry is a " "saturation scale factor, and the third entry is a value scale factor. " "The table entries are stored in the tag in nested loop order, with the " "value divisions in the outer loop, the hue divisions in the middle loop, " "and the saturation divisions in the inner loop. All zero input saturation " "entries are required to have a value scale factor of 1.0."), ifd0Id, dngTags, tiffFloat, -1, printValue), // DNG tag TagInfo(0xc740, "OpcodeList1", N_("Opcode List 1"), N_("Specifies the list of opcodes that should be applied to the raw image, " "as read directly from the file."), ifd0Id, dngTags, undefined, -1, printValue), // DNG tag TagInfo(0xc741, "OpcodeList2", N_("Opcode List 2"), N_("Specifies the list of opcodes that should be applied to the raw image, " "just after it has been mapped to linear reference values."), ifd0Id, dngTags, undefined, -1, printValue), // DNG tag TagInfo(0xc74e, "OpcodeList3", N_("Opcode List 3"), N_("Specifies the list of opcodes that should be applied to the raw image, " "just after it has been demosaiced."), ifd0Id, dngTags, undefined, -1, printValue), // DNG tag TagInfo(0xc761, "NoiseProfile", N_("Noise Profile"), N_("NoiseProfile describes the amount of noise in a raw image. Specifically, " "this tag models the amount of signal-dependent photon (shot) noise and " "signal-independent sensor readout noise, two common sources of noise in " "raw images. The model assumes that the noise is white and spatially " "independent, ignoring fixed pattern effects and other sources of noise (e.g., " "pixel response non-uniformity, spatially-dependent thermal effects, etc.)."), ifd0Id, dngTags, tiffDouble, -1, printValue), // DNG tag // End of list marker TagInfo(0xffff, "(UnknownIfdTag)", N_("Unknown IFD tag"), N_("Unknown IFD tag"), ifd0Id, sectionIdNotSet, asciiString, -1, printValue) }; const TagInfo* ifdTagList() { return ifdTagInfo; } //! ExposureProgram, tag 0x8822 extern const TagDetails exifExposureProgram[] = { { 0, N_("Not defined") }, { 1, N_("Manual") }, { 2, N_("Auto") }, { 3, N_("Aperture priority") }, { 4, N_("Shutter priority") }, { 5, N_("Creative program") }, { 6, N_("Action program") }, { 7, N_("Portrait mode") }, { 8, N_("Landscape mode") } }; //! MeteringMode, tag 0x9207 extern const TagDetails exifMeteringMode[] = { { 0, N_("Unknown") }, { 1, N_("Average") }, { 2, N_("Center weighted average") }, { 3, N_("Spot") }, { 4, N_("Multi-spot") }, { 5, N_("Multi-segment") }, { 6, N_("Partial") }, { 255, N_("Other") }, { 255, N_("Other") } // To silence compiler warning }; //! LightSource, tag 0x9208 extern const TagDetails exifLightSource[] = { { 0, N_("Unknown") }, { 1, N_("Daylight") }, { 2, N_("Fluorescent") }, { 3, N_("Tungsten (incandescent light)") }, { 4, N_("Flash") }, { 9, N_("Fine weather") }, { 10, N_("Cloudy weather") }, { 11, N_("Shade") }, { 12, N_("Daylight fluorescent (D 5700 - 7100K)") }, { 13, N_("Day white fluorescent (N 4600 - 5400K)") }, { 14, N_("Cool white fluorescent (W 3900 - 4500K)") }, { 15, N_("White fluorescent (WW 3200 - 3700K)") }, { 17, N_("Standard light A") }, { 18, N_("Standard light B") }, { 19, N_("Standard light C") }, { 20, N_("D55") }, { 21, N_("D65") }, { 22, N_("D75") }, { 23, N_("D50") }, { 24, N_("ISO studio tungsten") }, { 255, N_("Other light source") } }; //! ColorSpace, tag 0xa001 extern const TagDetails exifColorSpace[] = { { 1, N_("sRGB") }, { 2, N_("Adobe RGB") }, // Not defined to Exif 2.2 spec. But used by a lot of cameras. { 0xffff, N_("Uncalibrated") } }; //! SensingMethod, tag 0xa217 extern const TagDetails exifSensingMethod[] = { { 1, N_("Not defined") }, { 2, N_("One-chip color area") }, { 3, N_("Two-chip color area") }, { 4, N_("Three-chip color area") }, { 5, N_("Color sequential area") }, { 7, N_("Trilinear sensor") }, { 8, N_("Color sequential linear") } }; //! FileSource, tag 0xa300 extern const TagDetails exifFileSource[] = { { 1, N_("Film scanner") }, // Not defined to Exif 2.2 spec. { 2, N_("Reflexion print scanner") }, // but used by some scanner device softwares. { 3, N_("Digital still camera") } }; //! SceneType, tag 0xa301 extern const TagDetails exifSceneType[] = { { 1, N_("Directly photographed") } }; //! CustomRendered, tag 0xa401 extern const TagDetails exifCustomRendered[] = { { 0, N_("Normal process") }, { 1, N_("Custom process") } }; //! ExposureMode, tag 0xa402 extern const TagDetails exifExposureMode[] = { { 0, N_("Auto") }, { 1, N_("Manual") }, { 2, N_("Auto bracket") } }; //! WhiteBalance, tag 0xa403 extern const TagDetails exifWhiteBalance[] = { { 0, N_("Auto") }, { 1, N_("Manual") } }; //! SceneCaptureType, tag 0xa406 extern const TagDetails exifSceneCaptureType[] = { { 0, N_("Standard") }, { 1, N_("Landscape") }, { 2, N_("Portrait") }, { 3, N_("Night scene") }, { 3, N_("Night scene") } // To silence compiler warning }; //! GainControl, tag 0xa407 extern const TagDetails exifGainControl[] = { { 0, N_("None") }, { 1, N_("Low gain up") }, { 2, N_("High gain up") }, { 3, N_("Low gain down") }, { 4, N_("High gain down") } }; //! Contrast, tag 0xa408 and Sharpness, tag 0xa40a extern const TagDetails exifNormalSoftHard[] = { { 0, N_("Normal") }, { 1, N_("Soft") }, { 2, N_("Hard") } }; //! Saturation, tag 0xa409 extern const TagDetails exifSaturation[] = { { 0, N_("Normal") }, { 1, N_("Low") }, { 2, N_("High") } }; //! SubjectDistanceRange, tag 0xa40c extern const TagDetails exifSubjectDistanceRange[] = { { 0, N_("Unknown") }, { 1, N_("Macro") }, { 2, N_("Close view") }, { 3, N_("Distant view") }, { 3, N_("Distant view") } // To silence compiler warning }; // Exif IFD Tags static const TagInfo exifTagInfo[] = { TagInfo(0x829a, "ExposureTime", N_("Exposure Time"), N_("Exposure time, given in seconds (sec)."), exifId, captureCond, unsignedRational, 1, print0x829a), TagInfo(0x829d, "FNumber", N_("FNumber"), N_("The F number."), exifId, captureCond, unsignedRational, 1, print0x829d), TagInfo(0x8822, "ExposureProgram", N_("Exposure Program"), N_("The class of the program used by the camera to set exposure " "when the picture is taken."), exifId, captureCond, unsignedShort, 1, print0x8822), TagInfo(0x8824, "SpectralSensitivity", N_("Spectral Sensitivity"), N_("Indicates the spectral sensitivity of each channel of the " "camera used. The tag value is an ASCII string compatible " "with the standard developed by the ASTM Technical Committee."), exifId, captureCond, asciiString, 0, printValue), TagInfo(0x8827, "ISOSpeedRatings", N_("ISO Speed Ratings"), N_("Indicates the ISO Speed and ISO Latitude of the camera or " "input device as specified in ISO 12232."), exifId, captureCond, unsignedShort, 0, print0x8827), TagInfo(0x8828, "OECF", N_("Opto-Electoric Conversion Function"), N_("Indicates the Opto-Electoric Conversion Function (OECF) " "specified in ISO 14524. is the relationship between " "the camera optical input and the image values."), exifId, captureCond, undefined, 0, printValue), TagInfo(0x8830, "SensitivityType", N_("Sensitivity Type"), N_("The SensitivityType tag indicates PhotographicSensitivity tag. which " "one of the parameters of ISO12232 is the Although it is an optional tag, " "it should be recorded when a PhotographicSensitivity tag is recorded. " "Value = 4, 5, 6, or 7 may be used in case that the values of plural " "parameters are the same."), exifId, captureCond, unsignedShort, 1, printValue), TagInfo(0x8831, "StandardOutputSensitivity", N_("Standard Output Sensitivity"), N_("This tag indicates the standard output sensitivity value of a camera or " "input device defined in ISO 12232. When recording this tag, the " "PhotographicSensitivity and SensitivityType tags shall also be recorded."), exifId, captureCond, unsignedLong, 1, printValue), TagInfo(0x8832, "RecommendedExposureIndex", N_("Recommended Exposure Index"), N_("This tag indicates the recommended exposure index value of a camera or " "input device defined in ISO 12232. When recording this tag, the " "PhotographicSensitivity and SensitivityType tags shall also be recorded."), exifId, captureCond, unsignedLong, 1, printValue), TagInfo(0x8833, "ISOSpeed", N_("ISO Speed"), N_("This tag indicates the ISO speed value of a camera or input device that " "is defined in ISO 12232. When recording this tag, the PhotographicSensitivity " "and SensitivityType tags shall also be recorded."), exifId, captureCond, unsignedLong, 1, printValue), TagInfo(0x8834, "ISOSpeedLatitudeyyy", N_("ISO Speed Latitude yyy"), N_("This tag indicates the ISO speed latitude yyy value of a camera or input " "device that is defined in ISO 12232. However, this tag shall not be recorded " "without ISOSpeed and ISOSpeedLatitudezzz."), exifId, captureCond, unsignedLong, 1, printValue), TagInfo(0x8835, "ISOSpeedLatitudezzz", N_("ISO Speed Latitude zzz"), N_("This tag indicates the ISO speed latitude zzz value of a camera or input " "device that is defined in ISO 12232. However, this tag shall not be recorded " "without ISOSpeed and ISOSpeedLatitudeyyy."), exifId, captureCond, unsignedLong, 1, printValue), TagInfo(0x9000, "ExifVersion", N_("Exif Version"), N_("The version of this standard supported. Nonexistence of this " "field is taken to mean nonconformance to the standard."), exifId, exifVersion, undefined, 4, printExifVersion), TagInfo(0x9003, "DateTimeOriginal", N_("Date and Time (original)"), N_("The date and time when the original image data was generated. " "For a digital still camera the date and time the picture was taken are recorded."), exifId, dateTime, asciiString, 20, printValue), TagInfo(0x9004, "DateTimeDigitized", N_("Date and Time (digitized)"), N_("The date and time when the image was stored as digital data."), exifId, dateTime, asciiString, 20, printValue), TagInfo(0x9101, "ComponentsConfiguration", N_("Components Configuration"), N_("Information specific to compressed data. The channels of " "each component are arranged in order from the 1st " "component to the 4th. For uncompressed data the data " "arrangement is given in the tag. " "However, since can only " "express the order of Y, Cb and Cr, this tag is provided " "for cases when compressed data uses components other than " "Y, Cb, and Cr and to enable support of other sequences."), exifId, imgConfig, undefined, 4, print0x9101), TagInfo(0x9102, "CompressedBitsPerPixel", N_("Compressed Bits per Pixel"), N_("Information specific to compressed data. The compression mode " "used for a compressed image is indicated in unit bits per pixel."), exifId, imgConfig, unsignedRational, 1, printFloat), TagInfo(0x9201, "ShutterSpeedValue", N_("Shutter speed"), N_("Shutter speed. The unit is the APEX (Additive System of " "Photographic Exposure) setting."), exifId, captureCond, signedRational, 1, print0x9201), TagInfo(0x9202, "ApertureValue", N_("Aperture"), N_("The lens aperture. The unit is the APEX value."), exifId, captureCond, unsignedRational, 1, print0x9202), TagInfo(0x9203, "BrightnessValue", N_("Brightness"), N_("The value of brightness. The unit is the APEX value. " "Ordinarily it is given in the range of -99.99 to 99.99."), exifId, captureCond, signedRational, 1, printFloat), TagInfo(0x9204, "ExposureBiasValue", N_("Exposure Bias"), N_("The exposure bias. The units is the APEX value. Ordinarily " "it is given in the range of -99.99 to 99.99."), exifId, captureCond, signedRational, 1, print0x9204), TagInfo(0x9205, "MaxApertureValue", N_("Max Aperture Value"), N_("The smallest F number of the lens. The unit is the APEX value. " "Ordinarily it is given in the range of 00.00 to 99.99, " "but it is not limited to this range."), exifId, captureCond, unsignedRational, 1, print0x9202), TagInfo(0x9206, "SubjectDistance", N_("Subject Distance"), N_("The distance to the subject, given in meters."), exifId, captureCond, unsignedRational, 1, print0x9206), TagInfo(0x9207, "MeteringMode", N_("Metering Mode"), N_("The metering mode."), exifId, captureCond, unsignedShort, 1, print0x9207), TagInfo(0x9208, "LightSource", N_("Light Source"), N_("The kind of light source."), exifId, captureCond, unsignedShort, 1, print0x9208), TagInfo(0x9209, "Flash", N_("Flash"), N_("This tag is recorded when an image is taken using a strobe light (flash)."), exifId, captureCond, unsignedShort, 1, EXV_PRINT_TAG(exifFlash)), TagInfo(0x920a, "FocalLength", N_("Focal Length"), N_("The actual focal length of the lens, in mm. Conversion is not " "made to the focal length of a 35 mm film camera."), exifId, captureCond, unsignedRational, 1, print0x920a), TagInfo(0x9214, "SubjectArea", N_("Subject Area"), N_("This tag indicates the location and area of the main subject " "in the overall scene."), exifId, captureCond, unsignedShort, -1, printValue), TagInfo(0x927c, "MakerNote", N_("Maker Note"), N_("A tag for manufacturers of Exif writers to record any desired " "information. The contents are up to the manufacturer."), exifId, userInfo, undefined, 0, printValue), TagInfo(0x9286, "UserComment", N_("User Comment"), N_("A tag for Exif users to write keywords or comments on the image " "besides those in , and without the " "character code limitations of the tag."), exifId, userInfo, comment, 0, print0x9286), TagInfo(0x9290, "SubSecTime", N_("Sub-seconds Time"), N_("A tag used to record fractions of seconds for the tag."), exifId, dateTime, asciiString, 0, printValue), TagInfo(0x9291, "SubSecTimeOriginal", N_("Sub-seconds Time Original"), N_("A tag used to record fractions of seconds for the tag."), exifId, dateTime, asciiString, 0, printValue), TagInfo(0x9292, "SubSecTimeDigitized", N_("Sub-seconds Time Digitized"), N_("A tag used to record fractions of seconds for the tag."), exifId, dateTime, asciiString, 0, printValue), TagInfo(0xa000, "FlashpixVersion", N_("FlashPix Version"), N_("The FlashPix format version supported by a FPXR file."), exifId, exifVersion, undefined, 4, printExifVersion), TagInfo(0xa001, "ColorSpace", N_("Color Space"), N_("The color space information tag is always " "recorded as the color space specifier. Normally sRGB " "is used to define the color space based on the PC monitor " "conditions and environment. If a color space other than " "sRGB is used, Uncalibrated is set. Image data " "recorded as Uncalibrated can be treated as sRGB when it is " "converted to FlashPix."), exifId, imgCharacter, unsignedShort, 1, print0xa001), TagInfo(0xa002, "PixelXDimension", N_("Pixel X Dimension"), N_("Information specific to compressed data. When a " "compressed file is recorded, the valid width of the " "meaningful image must be recorded in this tag, whether or " "not there is padding data or a restart marker. This tag " "should not exist in an uncompressed file."), exifId, imgConfig, unsignedLong, 1, printValue), TagInfo(0xa003, "PixelYDimension", N_("Pixel Y Dimension"), N_("Information specific to compressed data. When a compressed " "file is recorded, the valid height of the meaningful image " "must be recorded in this tag, whether or not there is padding " "data or a restart marker. This tag should not exist in an " "uncompressed file. Since data padding is unnecessary in the vertical " "direction, the number of lines recorded in this valid image height tag " "will in fact be the same as that recorded in the SOF."), exifId, imgConfig, unsignedLong, 1, printValue), TagInfo(0xa004, "RelatedSoundFile", N_("Related Sound File"), N_("This tag is used to record the name of an audio file related " "to the image data. The only relational information " "recorded here is the Exif audio file name and extension (an " "ASCII string consisting of 8 characters + '.' + 3 " "characters). The path is not recorded."), exifId, relatedFile, asciiString, 13, printValue), TagInfo(0xa005, "InteroperabilityTag", N_("Interoperability IFD Pointer"), N_("Interoperability IFD is composed of tags which stores the " "information to ensure the Interoperability and pointed " "by the following tag located in Exif IFD. " "The Interoperability structure of Interoperability IFD is " "the same as TIFF defined IFD structure but does not contain the " "image data characteristically compared with normal TIFF IFD."), exifId, exifFormat, unsignedLong, 1, printValue), TagInfo(0xa20b, "FlashEnergy", N_("Flash Energy"), N_("Indicates the strobe energy at the time the image is " "captured, as measured in Beam Candle Power Seconds (BCPS)."), exifId, captureCond, unsignedRational, 1, printValue), TagInfo(0xa20c, "SpatialFrequencyResponse", N_("Spatial Frequency Response"), N_("This tag records the camera or input device spatial frequency " "table and SFR values in the direction of image width, " "image height, and diagonal direction, as specified in ISO 12233."), exifId, captureCond, undefined, 0, printValue), TagInfo(0xa20e, "FocalPlaneXResolution", N_("Focal Plane X-Resolution"), N_("Indicates the number of pixels in the image width (X) direction " "per on the camera focal plane."), exifId, captureCond, unsignedRational, 1, printFloat), TagInfo(0xa20f, "FocalPlaneYResolution", N_("Focal Plane Y-Resolution"), N_("Indicates the number of pixels in the image height (V) direction " "per on the camera focal plane."), exifId, captureCond, unsignedRational, 1, printFloat), TagInfo(0xa210, "FocalPlaneResolutionUnit", N_("Focal Plane Resolution Unit"), N_("Indicates the unit for measuring and " ". This value is the same as the ."), exifId, captureCond, unsignedShort, 1, printExifUnit), TagInfo(0xa214, "SubjectLocation", N_("Subject Location"), N_("Indicates the location of the main subject in the scene. The " "value of this tag represents the pixel at the center of the " "main subject relative to the left edge, prior to rotation " "processing as per the tag. The first value " "indicates the X column number and second indicates the Y row number."), exifId, captureCond, unsignedShort, 2, printValue), TagInfo(0xa215, "ExposureIndex", N_("Exposure index"), N_("Indicates the exposure index selected on the camera or " "input device at the time the image is captured."), exifId, captureCond, unsignedRational, 1, printValue), TagInfo(0xa217, "SensingMethod", N_("Sensing Method"), N_("Indicates the image sensor type on the camera or input device."), exifId, captureCond, unsignedShort, 1, print0xa217), TagInfo(0xa300, "FileSource", N_("File Source"), N_("Indicates the image source. If a DSC recorded the image, " "this tag value of this tag always be set to 3, indicating " "that the image was recorded on a DSC."), exifId, captureCond, undefined, 1, print0xa300), TagInfo(0xa301, "SceneType", N_("Scene Type"), N_("Indicates the type of scene. If a DSC recorded the image, " "this tag value must always be set to 1, indicating that the " "image was directly photographed."), exifId, captureCond, undefined, 1, print0xa301), TagInfo(0xa302, "CFAPattern", N_("Color Filter Array Pattern"), N_("Indicates the color filter array (CFA) geometric pattern of the " "image sensor when a one-chip color area sensor is used. " "It does not apply to all sensing methods."), exifId, captureCond, undefined, 0, printValue), TagInfo(0xa401, "CustomRendered", N_("Custom Rendered"), N_("This tag indicates the use of special processing on image " "data, such as rendering geared to output. When special " "processing is performed, the reader is expected to disable " "or minimize any further processing."), exifId, captureCond, unsignedShort, 1, print0xa401), TagInfo(0xa402, "ExposureMode", N_("Exposure Mode"), N_("This tag indicates the exposure mode set when the image was " "shot. In auto-bracketing mode, the camera shoots a series of " "frames of the same scene at different exposure settings."), exifId, captureCond, unsignedShort, 1, print0xa402), TagInfo(0xa403, "WhiteBalance", N_("White Balance"), N_("This tag indicates the white balance mode set when the image was shot."), exifId, captureCond, unsignedShort, 1, print0xa403), TagInfo(0xa404, "DigitalZoomRatio", N_("Digital Zoom Ratio"), N_("This tag indicates the digital zoom ratio when the image was " "shot. If the numerator of the recorded value is 0, this " "indicates that digital zoom was not used."), exifId, captureCond, unsignedRational, 1, print0xa404), TagInfo(0xa405, "FocalLengthIn35mmFilm", N_("Focal Length In 35mm Film"), N_("This tag indicates the equivalent focal length assuming a " "35mm film camera, in mm. A value of 0 means the focal " "length is unknown. Note that this tag differs from the " " tag."), exifId, captureCond, unsignedShort, 1, print0xa405), TagInfo(0xa406, "SceneCaptureType", N_("Scene Capture Type"), N_("This tag indicates the type of scene that was shot. It can " "also be used to record the mode in which the image was " "shot. Note that this differs from the tag."), exifId, captureCond, unsignedShort, 1, print0xa406), TagInfo(0xa407, "GainControl", N_("Gain Control"), N_("This tag indicates the degree of overall image gain adjustment."), exifId, captureCond, unsignedShort, 1, print0xa407), TagInfo(0xa408, "Contrast", N_("Contrast"), N_("This tag indicates the direction of contrast processing " "applied by the camera when the image was shot."), exifId, captureCond, unsignedShort, 1, printNormalSoftHard), TagInfo(0xa409, "Saturation", N_("Saturation"), N_("This tag indicates the direction of saturation processing " "applied by the camera when the image was shot."), exifId, captureCond, unsignedShort, 1, print0xa409), TagInfo(0xa40a, "Sharpness", N_("Sharpness"), N_("This tag indicates the direction of sharpness processing " "applied by the camera when the image was shot."), exifId, captureCond, unsignedShort, 1, printNormalSoftHard), TagInfo(0xa40b, "DeviceSettingDescription", N_("Device Setting Description"), N_("This tag indicates information on the picture-taking " "conditions of a particular camera model. The tag is used " "only to indicate the picture-taking conditions in the reader."), exifId, captureCond, undefined, 0, printValue), TagInfo(0xa40c, "SubjectDistanceRange", N_("Subject Distance Range"), N_("This tag indicates the distance to the subject."), exifId, captureCond, unsignedShort, 1, print0xa40c), TagInfo(0xa420, "ImageUniqueID", N_("Image Unique ID"), N_("This tag indicates an identifier assigned uniquely to " "each image. It is recorded as an ASCII string equivalent " "to hexadecimal notation and 128-bit fixed length."), exifId, otherTags, asciiString, 33, printValue), TagInfo(0xa430, "CameraOwnerName", N_("Camera Owner Name"), N_("This tag records the owner of a camera used in " "photography as an ASCII string."), exifId, otherTags, asciiString, 0, printValue), TagInfo(0xa431, "BodySerialNumber", N_("Body Serial Number"), N_("This tag records the serial number of the body of the camera " "that was used in photography as an ASCII string."), exifId, otherTags, asciiString, 0, printValue), TagInfo(0xa432, "LensSpecification", N_("Lens Specification"), N_("This tag notes minimum focal length, maximum focal length, " "minimum F number in the minimum focal length, and minimum F number " "in the maximum focal length, which are specification information " "for the lens that was used in photography. When the minimum F " "number is unknown, the notation is 0/0"), exifId, otherTags, unsignedRational, 4, printValue), TagInfo(0xa433, "LensMake", N_("Lens Make"), N_("This tag records the lens manufactor as an ASCII string."), exifId, otherTags, asciiString, 0, printValue), TagInfo(0xa434, "LensModel", N_("Lens Model"), N_("This tag records the lens's model name and model number as an " "ASCII string."), exifId, otherTags, asciiString, 0, printValue), TagInfo(0xa435, "LensSerialNumber", N_("Lens Serial Number"), N_("This tag records the serial number of the interchangeable lens " "that was used in photography as an ASCII string."), exifId, otherTags, asciiString, 0, printValue), // End of list marker TagInfo(0xffff, "(UnknownExifTag)", N_("Unknown Exif tag"), N_("Unknown Exif tag"), exifId, sectionIdNotSet, asciiString, -1, printValue) }; const TagInfo* exifTagList() { return exifTagInfo; } //! GPS latitude reference, tag 0x0001; also GPSDestLatitudeRef, tag 0x0013 extern const TagDetails exifGPSLatitudeRef[] = { { 78, N_("North") }, { 83, N_("South") } }; //! GPS longitude reference, tag 0x0003; also GPSDestLongitudeRef, tag 0x0015 extern const TagDetails exifGPSLongitudeRef[] = { { 69, N_("East") }, { 87, N_("West") } }; //! GPS altitude reference, tag 0x0005 extern const TagDetails exifGPSAltitudeRef[] = { { 0, N_("Above sea level") }, { 1, N_("Below sea level") } }; //! GPS status, tag 0x0009 extern const TagDetails exifGPSStatus[] = { { 'A', N_("Measurement in progress") }, { 'V', N_("Measurement Interoperability") } }; //! GPS measurement mode, tag 0x000a extern const TagDetails exifGPSMeasureMode[] = { { '2', N_("Two-dimensional measurement") }, { '3', N_("Three-dimensional measurement") } }; //! GPS speed reference, tag 0x000c extern const TagDetails exifGPSSpeedRef[] = { { 'K', N_("km/h") }, { 'M', N_("mph") }, { 'N', N_("knots") } }; //! GPS direction ref, tags 0x000e, 0x0010, 0x0017 extern const TagDetails exifGPSDirRef[] = { { 'T', N_("True direction") }, { 'M', N_("Magnetic direction") } }; //! GPS Destination distance ref, tag 0x0019 extern const TagDetails exifGPSDestDistanceRef[] = { { 'K', N_("Kilometers") }, { 'M', N_("Miles") }, { 'N', N_("Knots") } }; //! GPS Differential, tag 0x001e extern const TagDetails exifGPSDifferential[] = { { 0, N_("Without correction") }, { 1, N_("Correction applied") } }; // GPS Info Tags static const TagInfo gpsTagInfo[] = { TagInfo(0x0000, "GPSVersionID", N_("GPS Version ID"), N_("Indicates the version of . The version is given " "as 2.0.0.0. This tag is mandatory when tag is " "present. (Note: The tag is given in bytes, " "unlike the tag. When the version is " "2.0.0.0, the tag value is 02000000.H)."), gpsId, gpsTags, unsignedByte, 4, print0x0000), TagInfo(0x0001, "GPSLatitudeRef", N_("GPS Latitude Reference"), N_("Indicates whether the latitude is north or south latitude. The " "ASCII value 'N' indicates north latitude, and 'S' is south latitude."), gpsId, gpsTags, asciiString, 2, EXV_PRINT_TAG(exifGPSLatitudeRef)), TagInfo(0x0002, "GPSLatitude", N_("GPS Latitude"), N_("Indicates the latitude. The latitude is expressed as three " "RATIONAL values giving the degrees, minutes, and seconds, " "respectively. When degrees, minutes and seconds are expressed, " "the format is dd/1,mm/1,ss/1. When degrees and minutes are used " "and, for example, fractions of minutes are given up to two " "decimal places, the format is dd/1,mmmm/100,0/1."), gpsId, gpsTags, unsignedRational, 3, printDegrees), TagInfo(0x0003, "GPSLongitudeRef", N_("GPS Longitude Reference"), N_("Indicates whether the longitude is east or west longitude. " "ASCII 'E' indicates east longitude, and 'W' is west longitude."), gpsId, gpsTags, asciiString, 2, EXV_PRINT_TAG(exifGPSLongitudeRef)), TagInfo(0x0004, "GPSLongitude", N_("GPS Longitude"), N_("Indicates the longitude. The longitude is expressed as three " "RATIONAL values giving the degrees, minutes, and seconds, " "respectively. When degrees, minutes and seconds are expressed, " "the format is ddd/1,mm/1,ss/1. When degrees and minutes are " "used and, for example, fractions of minutes are given up to " "two decimal places, the format is ddd/1,mmmm/100,0/1."), gpsId, gpsTags, unsignedRational, 3, printDegrees), TagInfo(0x0005, "GPSAltitudeRef", N_("GPS Altitude Reference"), N_("Indicates the altitude used as the reference altitude. If the " "reference is sea level and the altitude is above sea level, 0 " "is given. If the altitude is below sea level, a value of 1 is given " "and the altitude is indicated as an absolute value in the " "GSPAltitude tag. The reference unit is meters. Note that this tag " "is BYTE type, unlike other reference tags."), gpsId, gpsTags, unsignedByte, 1, print0x0005), TagInfo(0x0006, "GPSAltitude", N_("GPS Altitude"), N_("Indicates the altitude based on the reference in GPSAltitudeRef. " "Altitude is expressed as one RATIONAL value. The reference unit is meters."), gpsId, gpsTags, unsignedRational, 1, print0x0006), TagInfo(0x0007, "GPSTimeStamp", N_("GPS Time Stamp"), N_("Indicates the time as UTC (Coordinated Universal Time). " " is expressed as three RATIONAL values " "giving the hour, minute, and second (atomic clock)."), gpsId, gpsTags, unsignedRational, 3, print0x0007), TagInfo(0x0008, "GPSSatellites", N_("GPS Satellites"), N_("Indicates the GPS satellites used for measurements. This tag can be used " "to describe the number of satellites, their ID number, angle of elevation, " "azimuth, SNR and other information in ASCII notation. The format is not " "specified. If the GPS receiver is incapable of taking measurements, value " "of the tag is set to NULL."), gpsId, gpsTags, asciiString, 0, printValue), TagInfo(0x0009, "GPSStatus", N_("GPS Status"), N_("Indicates the status of the GPS receiver when the image is recorded. " "\"A\" means measurement is in progress, and \"V\" means the measurement " "is Interoperability."), gpsId, gpsTags, asciiString, 2, print0x0009), TagInfo(0x000a, "GPSMeasureMode", N_("GPS Measure Mode"), N_("Indicates the GPS measurement mode. \"2\" means two-dimensional measurement and \"3\" " "means three-dimensional measurement is in progress."), gpsId, gpsTags, asciiString, 2, print0x000a), TagInfo(0x000b, "GPSDOP", N_("GPS Data Degree of Precision"), N_("Indicates the GPS DOP (data degree of precision). An HDOP value is written " "during two-dimensional measurement, and PDOP during three-dimensional measurement."), gpsId, gpsTags, unsignedRational, 1, printValue), TagInfo(0x000c, "GPSSpeedRef", N_("GPS Speed Reference"), N_("Indicates the unit used to express the GPS receiver speed of movement. " "\"K\" \"M\" and \"N\" represents kilometers per hour, miles per hour, and knots."), gpsId, gpsTags, asciiString, 2, print0x000c), TagInfo(0x000d, "GPSSpeed", N_("GPS Speed"), N_("Indicates the speed of GPS receiver movement."), gpsId, gpsTags, unsignedRational, 1, printValue), TagInfo(0x000e, "GPSTrackRef", N_("GPS Track Ref"), N_("Indicates the reference for giving the direction of GPS receiver movement. " "\"T\" denotes true direction and \"M\" is magnetic direction."), gpsId, gpsTags, asciiString, 2, printGPSDirRef), TagInfo(0x000f, "GPSTrack", N_("GPS Track"), N_("Indicates the direction of GPS receiver movement. The range of values is " "from 0.00 to 359.99."), gpsId, gpsTags, unsignedRational, 1, printValue), TagInfo(0x0010, "GPSImgDirectionRef", N_("GPS Image Direction Reference"), N_("Indicates the reference for giving the direction of the image when it is captured. " "\"T\" denotes true direction and \"M\" is magnetic direction."), gpsId, gpsTags, asciiString, 2, printGPSDirRef), TagInfo(0x0011, "GPSImgDirection", N_("GPS Image Direction"), N_("Indicates the direction of the image when it was captured. The range of values " "is from 0.00 to 359.99."), gpsId, gpsTags, unsignedRational, 1, printValue), TagInfo(0x0012, "GPSMapDatum", N_("GPS Map Datum"), N_("Indicates the geodetic survey data used by the GPS receiver. If the survey data " "is restricted to Japan, the value of this tag is \"TOKYO\" or \"WGS-84\"."), gpsId, gpsTags, asciiString, 0, printValue), TagInfo(0x0013, "GPSDestLatitudeRef", N_("GPS Destination Latitude Refeference"), N_("Indicates whether the latitude of the destination point is north or south latitude. " "The ASCII value \"N\" indicates north latitude, and \"S\" is south latitude."), gpsId, gpsTags, asciiString, 2, EXV_PRINT_TAG(exifGPSLatitudeRef)), TagInfo(0x0014, "GPSDestLatitude", N_("GPS Destination Latitude"), N_("Indicates the latitude of the destination point. The latitude is expressed as " "three RATIONAL values giving the degrees, minutes, and seconds, respectively. " "If latitude is expressed as degrees, minutes and seconds, a typical format would " "be dd/1,mm/1,ss/1. When degrees and minutes are used and, for example, " "fractions of minutes are given up to two decimal places, the format would be " "dd/1,mmmm/100,0/1."), gpsId, gpsTags, unsignedRational, 3, printDegrees), TagInfo(0x0015, "GPSDestLongitudeRef", N_("GPS Destination Longitude Reference"), N_("Indicates whether the longitude of the destination point is east or west longitude. " "ASCII \"E\" indicates east longitude, and \"W\" is west longitude."), gpsId, gpsTags, asciiString, 2, EXV_PRINT_TAG(exifGPSLongitudeRef)), TagInfo(0x0016, "GPSDestLongitude", N_("GPS Destination Longitude"), N_("Indicates the longitude of the destination point. The longitude is expressed " "as three RATIONAL values giving the degrees, minutes, and seconds, respectively. " "If longitude is expressed as degrees, minutes and seconds, a typical format would be " "ddd/1,mm/1,ss/1. When degrees and minutes are used and, for example, fractions of " "minutes are given up to two decimal places, the format would be ddd/1,mmmm/100,0/1."), gpsId, gpsTags, unsignedRational, 3, printDegrees), TagInfo(0x0017, "GPSDestBearingRef", N_("GPS Destination Bearing Reference"), N_("Indicates the reference used for giving the bearing to the destination point. " "\"T\" denotes true direction and \"M\" is magnetic direction."), gpsId, gpsTags, asciiString, 2, printGPSDirRef), TagInfo(0x0018, "GPSDestBearing", N_("GPS Destination Bearing"), N_("Indicates the bearing to the destination point. The range of values is from " "0.00 to 359.99."), gpsId, gpsTags, unsignedRational, 1, printValue), TagInfo(0x0019, "GPSDestDistanceRef", N_("GPS Destination Distance Reference"), N_("Indicates the unit used to express the distance to the destination point. " "\"K\", \"M\" and \"N\" represent kilometers, miles and knots."), gpsId, gpsTags, asciiString, 2, print0x0019), TagInfo(0x001a, "GPSDestDistance", N_("GPS Destination Distance"), N_("Indicates the distance to the destination point."), gpsId, gpsTags, unsignedRational, 1, printValue), TagInfo(0x001b, "GPSProcessingMethod", N_("GPS Processing Method"), N_("A character string recording the name of the method used for location finding. " "The first byte indicates the character code used, and this is followed by the name " "of the method."), gpsId, gpsTags, undefined, 0, printValue), TagInfo(0x001c, "GPSAreaInformation", N_("GPS Area Information"), N_("A character string recording the name of the GPS area. The first byte indicates " "the character code used, and this is followed by the name of the GPS area."), gpsId, gpsTags, undefined, 0, printValue), TagInfo(0x001d, "GPSDateStamp", N_("GPS Date Stamp"), N_("A character string recording date and time information relative to UTC " "(Coordinated Universal Time). The format is \"YYYY:MM:DD.\"."), gpsId, gpsTags, asciiString, 11, printValue), TagInfo(0x001e, "GPSDifferential", N_("GPS Differential"), N_("Indicates whether differential correction is applied to the GPS receiver."), gpsId, gpsTags, unsignedShort, 1, print0x001e), // End of list marker TagInfo(0xffff, "(UnknownGpsTag)", N_("Unknown GPSInfo tag"), N_("Unknown GPSInfo tag"), gpsId, gpsTags, asciiString, -1, printValue) }; const TagInfo* gpsTagList() { return gpsTagInfo; } // Exif Interoperability IFD Tags static const TagInfo iopTagInfo[] = { TagInfo(0x0001, "InteroperabilityIndex", N_("Interoperability Index"), N_("Indicates the identification of the Interoperability rule. " "Use \"R98\" for stating ExifR98 Rules. Four bytes used " "including the termination code (NULL). see the separate " "volume of Recommended Exif Interoperability Rules (ExifR98) " "for other tags used for ExifR98."), iopId, iopTags, asciiString, 0, printValue), TagInfo(0x0002, "InteroperabilityVersion", N_("Interoperability Version"), N_("Interoperability version"), iopId, iopTags, undefined, -1, printExifVersion), TagInfo(0x1000, "RelatedImageFileFormat", N_("Related Image File Format"), N_("File format of image file"), iopId, iopTags, asciiString, 0, printValue), TagInfo(0x1001, "RelatedImageWidth", N_("Related Image Width"), N_("Image width"), iopId, iopTags, unsignedLong, 1, printValue), TagInfo(0x1002, "RelatedImageLength", N_("Related Image Length"), N_("Image height"), iopId, iopTags, unsignedLong, 1, printValue), // End of list marker TagInfo(0xffff, "(UnknownIopTag)", N_("Unknown Exif Interoperability tag"), N_("Unknown Exif Interoperability tag"), iopId, iopTags, asciiString, -1, printValue) }; const TagInfo* iopTagList() { return iopTagInfo; } // Synthesized Exiv2 Makernote info Tags (read-only) static const TagInfo mnTagInfo[] = { TagInfo(0x0001, "Offset", N_("Offset"), N_("Offset of the makernote from the start of the TIFF header."), mnId, makerTags, unsignedLong, 1, printValue), TagInfo(0x0002, "ByteOrder", N_("Byte Order"), N_("Byte order used to encode MakerNote tags, 'MM' (big-endian) or 'II' (little-endian)."), mnId, makerTags, asciiString, 0, printValue), // End of list marker TagInfo(0xffff, "(UnknownMnTag)", N_("Unknown Exiv2 Makernote info tag"), N_("Unknown Exiv2 Makernote info tag"), mnId, makerTags, asciiString, -1, printValue) }; const TagInfo* mnTagList() { return mnTagInfo; } // Unknown Tag static const TagInfo unknownTag(0xffff, "Unknown tag", N_("Unknown tag"), N_("Unknown tag"), ifdIdNotSet, sectionIdNotSet, asciiString, -1, printValue); std::ostream& printValue(std::ostream& os, const Value& value, const ExifData*) { return os << value; } IfdId groupId(const std::string& groupName) { IfdId ifdId = ifdIdNotSet; const GroupInfo* ii = find(groupInfo, GroupInfo::GroupName(groupName)); if (ii != 0) ifdId = static_cast(ii->ifdId_); return ifdId; } const char* ifdName(IfdId ifdId) { const GroupInfo* ii = find(groupInfo, ifdId); if (ii == 0) return groupInfo[0].ifdName_; return ii->ifdName_; } // ifdName const char* groupName(IfdId ifdId) { const GroupInfo* ii = find(groupInfo, ifdId); if (ii == 0) return groupInfo[0].groupName_; return ii->groupName_; } // groupName bool isMakerIfd(IfdId ifdId) { bool rc = false; const GroupInfo* ii = find(groupInfo, ifdId); if (ii != 0 && 0 == strcmp(ii->ifdName_, "Makernote")) { rc = true; } return rc; } // isMakerIfd bool isExifIfd(IfdId ifdId) { bool rc; switch (ifdId) { case ifd0Id: case exifId: case gpsId: case iopId: case ifd1Id: case ifd2Id: case ifd3Id: case subImage1Id: case subImage2Id: case subImage3Id: case subImage4Id: case subImage5Id: case subImage6Id: case subImage7Id: case subImage8Id: case subImage9Id: case subThumb1Id: case panaRawId: rc = true; break; default: rc = false; break; } return rc; } // isExifIfd void taglist(std::ostream& os, IfdId ifdId) { const TagInfo* ti = Internal::tagList(ifdId); if (ti != 0) { for (int k = 0; ti[k].tag_ != 0xffff; ++k) { os << ti[k] << "\n"; } } } // taglist const TagInfo* tagList(IfdId ifdId) { const GroupInfo* ii = find(groupInfo, ifdId); if (ii == 0 || ii->tagList_ == 0) return 0; return ii->tagList_(); } // tagList const TagInfo* tagInfo(uint16_t tag, IfdId ifdId) { const TagInfo* ti = tagList(ifdId); if (ti == 0) return 0; int idx = 0; for (idx = 0; ti[idx].tag_ != 0xffff; ++idx) { if (ti[idx].tag_ == tag) break; } return &ti[idx]; } // tagInfo const TagInfo* tagInfo(const std::string& tagName, IfdId ifdId) { const TagInfo* ti = tagList(ifdId); if (ti == 0) return 0; const char* tn = tagName.c_str(); if (tn == 0) return 0; for (int idx = 0; ti[idx].tag_ != 0xffff; ++idx) { if (0 == strcmp(ti[idx].name_, tn)) { return &ti[idx]; } } return 0; } // tagInfo uint16_t tagNumber(const std::string& tagName, IfdId ifdId) { const TagInfo* ti = tagInfo(tagName, ifdId); if (ti != 0 && ti->tag_ != 0xffff) return ti->tag_; if (!isHex(tagName, 4, "0x")) throw Error(7, tagName, ifdId); std::istringstream is(tagName); uint16_t tag; is >> std::hex >> tag; return tag; } // tagNumber std::ostream& printLong(std::ostream& os, const Value& value, const ExifData*) { Rational r = value.toRational(); if (r.second != 0) return os << static_cast(r.first) / r.second; return os << "(" << value << ")"; } // printLong std::ostream& printFloat(std::ostream& os, const Value& value, const ExifData*) { Rational r = value.toRational(); if (r.second != 0) return os << static_cast(r.first) / r.second; return os << "(" << value << ")"; } // printFloat std::ostream& printDegrees(std::ostream& os, const Value& value, const ExifData*) { if (value.count() == 3) { std::ostringstream oss; oss.copyfmt(os); static const char* unit[] = { "deg", "'", "\"" }; static const int prec[] = { 7, 5, 3 }; int n; for (n = 2; n > 0; --n) { if (value.toRational(n).first != 0) break; } for (int i = 0; i < n + 1; ++i) { const int32_t z = value.toRational(i).first; const int32_t d = value.toRational(i).second; if (d == 0) return os << "(" << value << ")"; // Hack: Need Value::toDouble double b = static_cast(z)/d; const int p = z % d == 0 ? 0 : prec[i]; os << std::fixed << std::setprecision(p) << b << unit[i] << " "; } os.copyfmt(oss); } else { os << value; } return os; } // printDegrees std::ostream& printUcs2(std::ostream& os, const Value& value, const ExifData*) { bool cnv = false; if (value.typeId() == unsignedByte && value.size() > 0) { DataBuf buf(value.size()); value.copy(buf.pData_, invalidByteOrder); // Strip trailing UCS-2 0-character, if there is one if (buf.pData_[buf.size_ - 1] == 0 && buf.pData_[buf.size_ - 2] == 0) buf.size_ -= 2; std::string str((const char*)buf.pData_, buf.size_); cnv = convertStringCharset(str, "UCS-2LE", "UTF-8"); if (cnv) os << str; } if (!cnv) os << value; return os; } // printUcs2 std::ostream& printExifUnit(std::ostream& os, const Value& value, const ExifData* metadata) { return EXV_PRINT_TAG(exifUnit)(os, value, metadata); } std::ostream& print0x0000(std::ostream& os, const Value& value, const ExifData*) { if (value.size() != 4 || value.typeId() != unsignedByte) { return os << value; } for (int i = 0; i < 3; i++) { os << value.toLong(i); os << "."; } os << value.toLong(3); return os; } std::ostream& print0x0005(std::ostream& os, const Value& value, const ExifData* metadata) { return EXV_PRINT_TAG(exifGPSAltitudeRef)(os, value, metadata); } std::ostream& print0x0006(std::ostream& os, const Value& value, const ExifData*) { std::ostringstream oss; oss.copyfmt(os); const int32_t d = value.toRational().second; if (d == 0) return os << "(" << value << ")"; const int p = d > 1 ? 1 : 0; os << std::fixed << std::setprecision(p) << value.toFloat() << " m"; os.copyfmt(oss); return os; } std::ostream& print0x0007(std::ostream& os, const Value& value, const ExifData*) { if (value.count() == 3) { for (int i = 0; i < 3; ++i) { if (value.toRational(i).second == 0) { return os << "(" << value << ")"; } } std::ostringstream oss; oss.copyfmt(os); const float sec = 3600 * value.toFloat(0) + 60 * value.toFloat(1) + value.toFloat(2); int p = 0; if (sec != static_cast(sec)) p = 1; const int hh = static_cast(sec / 3600); const int mm = static_cast((sec - 3600 * hh) / 60); const float ss = sec - 3600 * hh - 60 * mm; os << std::setw(2) << std::setfill('0') << std::right << hh << ":" << std::setw(2) << std::setfill('0') << std::right << mm << ":" << std::setw(2 + p * 2) << std::setfill('0') << std::right << std::fixed << std::setprecision(p) << ss; os.copyfmt(oss); } else { os << value; } return os; } std::ostream& print0x0009(std::ostream& os, const Value& value, const ExifData* metadata) { return EXV_PRINT_TAG(exifGPSStatus)(os, value, metadata); } std::ostream& print0x000a(std::ostream& os, const Value& value, const ExifData* metadata) { return EXV_PRINT_TAG(exifGPSMeasureMode)(os, value, metadata); } std::ostream& print0x000c(std::ostream& os, const Value& value, const ExifData* metadata) { return EXV_PRINT_TAG(exifGPSSpeedRef)(os, value, metadata); } std::ostream& print0x0019(std::ostream& os, const Value& value, const ExifData* metadata) { return EXV_PRINT_TAG(exifGPSDestDistanceRef)(os, value, metadata); } std::ostream& print0x001e(std::ostream& os, const Value& value, const ExifData* metadata) { return EXV_PRINT_TAG(exifGPSDifferential)(os, value, metadata); } std::ostream& print0x0112(std::ostream& os, const Value& value, const ExifData* metadata) { return EXV_PRINT_TAG(exifOrientation)(os, value, metadata); } std::ostream& print0x0213(std::ostream& os, const Value& value, const ExifData* metadata) { return EXV_PRINT_TAG(exifYCbCrPositioning)(os, value, metadata); } std::ostream& print0x8298(std::ostream& os, const Value& value, const ExifData*) { // Print the copyright information in the format Photographer, Editor std::string val = value.toString(); std::string::size_type pos = val.find('\0'); if (pos != std::string::npos) { std::string photographer(val, 0, pos); if (photographer != " ") os << photographer; std::string editor(val, pos + 1); if (editor != "") { if (photographer != " ") os << ", "; os << editor; } } else { os << val; } return os; } std::ostream& print0x829a(std::ostream& os, const Value& value, const ExifData*) { Rational t = value.toRational(); if (t.first > 1 && t.second > 1 && t.second >= t.first) { t.second = static_cast( static_cast(t.second) / t.first + 0.5); t.first = 1; } if (t.second > 1 && t.second < t.first) { t.first = static_cast( static_cast(t.first) / t.second + 0.5); t.second = 1; } if (t.second == 1) { os << t.first << " s"; } else { os << t.first << "/" << t.second << " s"; } return os; } std::ostream& print0x829d(std::ostream& os, const Value& value, const ExifData*) { Rational fnumber = value.toRational(); if (fnumber.second != 0) { std::ostringstream oss; oss.copyfmt(os); os << "F" << std::setprecision(2) << static_cast(fnumber.first) / fnumber.second; os.copyfmt(oss); } else { os << "(" << value << ")"; } return os; } std::ostream& print0x8822(std::ostream& os, const Value& value, const ExifData* metadata) { return EXV_PRINT_TAG(exifExposureProgram)(os, value, metadata); } std::ostream& print0x8827(std::ostream& os, const Value& value, const ExifData*) { return os << value.toLong(); } std::ostream& print0x9101(std::ostream& os, const Value& value, const ExifData*) { for (long i = 0; i < value.count(); ++i) { long l = value.toLong(i); switch (l) { case 0: break; case 1: os << "Y"; break; case 2: os << "Cb"; break; case 3: os << "Cr"; break; case 4: os << "R"; break; case 5: os << "G"; break; case 6: os << "B"; break; default: os << "(" << l << ")"; break; } } return os; } std::ostream& print0x9201(std::ostream& os, const Value& value, const ExifData*) { Rational r = value.toRational(); if (!value.ok() || r.second == 0) return os << "(" << value << ")"; URational ur = exposureTime(static_cast(r.first) / r.second); os << ur.first; if (ur.second > 1) { os << "/" << ur.second; } return os << " s"; } std::ostream& print0x9202(std::ostream& os, const Value& value, const ExifData*) { if ( value.count() == 0 || value.toRational().second == 0) { return os << "(" << value << ")"; } std::ostringstream oss; oss.copyfmt(os); os << "F" << std::setprecision(2) << fnumber(value.toFloat()); os.copyfmt(oss); return os; } std::ostream& print0x9204(std::ostream& os, const Value& value, const ExifData*) { Rational bias = value.toRational(); if (bias.second <= 0) { os << "(" << bias.first << "/" << bias.second << ")"; } else if (bias.first == 0) { os << "0 EV"; } else { int32_t d = gcd(bias.first, bias.second); int32_t num = std::abs(bias.first) / d; int32_t den = bias.second / d; os << (bias.first < 0 ? "-" : "+") << num; if (den != 1) { os << "/" << den; } os << " EV"; } return os; } std::ostream& print0x9206(std::ostream& os, const Value& value, const ExifData*) { Rational distance = value.toRational(); if (distance.first == 0) { os << _("Unknown"); } else if (static_cast(distance.first) == 0xffffffff) { os << _("Infinity"); } else if (distance.second != 0) { std::ostringstream oss; oss.copyfmt(os); os << std::fixed << std::setprecision(2) << (float)distance.first / distance.second << " m"; os.copyfmt(oss); } else { os << "(" << value << ")"; } return os; } std::ostream& print0x9207(std::ostream& os, const Value& value, const ExifData* metadata) { return EXV_PRINT_TAG(exifMeteringMode)(os, value, metadata); } std::ostream& print0x9208(std::ostream& os, const Value& value, const ExifData* metadata) { return EXV_PRINT_TAG(exifLightSource)(os, value, metadata); } std::ostream& print0x920a(std::ostream& os, const Value& value, const ExifData*) { Rational length = value.toRational(); if (length.second != 0) { std::ostringstream oss; oss.copyfmt(os); os << std::fixed << std::setprecision(1) << (float)length.first / length.second << " mm"; os.copyfmt(oss); } else { os << "(" << value << ")"; } return os; } std::ostream& print0x9286(std::ostream& os, const Value& value, const ExifData*) { const CommentValue* pcv = dynamic_cast(&value); if (pcv) { os << pcv->comment(); } else { os << value; } return os; } std::ostream& print0xa001(std::ostream& os, const Value& value, const ExifData* metadata) { return EXV_PRINT_TAG(exifColorSpace)(os, value, metadata); } std::ostream& print0xa217(std::ostream& os, const Value& value, const ExifData* metadata) { return EXV_PRINT_TAG(exifSensingMethod)(os, value, metadata); } std::ostream& print0xa300(std::ostream& os, const Value& value, const ExifData* metadata) { return EXV_PRINT_TAG(exifFileSource)(os, value, metadata); } std::ostream& print0xa301(std::ostream& os, const Value& value, const ExifData* metadata) { return EXV_PRINT_TAG(exifSceneType)(os, value, metadata); } std::ostream& print0xa401(std::ostream& os, const Value& value, const ExifData* metadata) { return EXV_PRINT_TAG(exifCustomRendered)(os, value, metadata); } std::ostream& print0xa402(std::ostream& os, const Value& value, const ExifData* metadata) { return EXV_PRINT_TAG(exifExposureMode)(os, value, metadata); } std::ostream& print0xa403(std::ostream& os, const Value& value, const ExifData* metadata) { return EXV_PRINT_TAG(exifWhiteBalance)(os, value, metadata); } std::ostream& print0xa404(std::ostream& os, const Value& value, const ExifData*) { Rational zoom = value.toRational(); if (zoom.second == 0) { os << _("Digital zoom not used"); } else { std::ostringstream oss; oss.copyfmt(os); os << std::fixed << std::setprecision(1) << (float)zoom.first / zoom.second; os.copyfmt(oss); } return os; } std::ostream& print0xa405(std::ostream& os, const Value& value, const ExifData*) { long length = value.toLong(); if (length == 0) { os << _("Unknown"); } else { os << length << ".0 mm"; } return os; } std::ostream& print0xa406(std::ostream& os, const Value& value, const ExifData* metadata) { return EXV_PRINT_TAG(exifSceneCaptureType)(os, value, metadata); } std::ostream& print0xa407(std::ostream& os, const Value& value, const ExifData* metadata) { return EXV_PRINT_TAG(exifGainControl)(os, value, metadata); } std::ostream& print0xa409(std::ostream& os, const Value& value, const ExifData* metadata) { return EXV_PRINT_TAG(exifSaturation)(os, value, metadata); } std::ostream& print0xa40c(std::ostream& os, const Value& value, const ExifData* metadata) { return EXV_PRINT_TAG(exifSubjectDistanceRange)(os, value, metadata); } std::ostream& printGPSDirRef(std::ostream& os, const Value& value, const ExifData* metadata) { return EXV_PRINT_TAG(exifGPSDirRef)(os, value, metadata); } std::ostream& printNormalSoftHard(std::ostream& os, const Value& value, const ExifData* metadata) { return EXV_PRINT_TAG(exifNormalSoftHard)(os, value, metadata); } std::ostream& printExifVersion(std::ostream& os, const Value& value, const ExifData*) { if (value.size() != 4 || value.typeId() != undefined) { return os << "(" << value << ")"; } char s[5]; for (int i = 0; i < 4; ++i) { s[i] = static_cast(value.toLong(i)); } s[4] = '\0'; return printVersion(os, s); } std::ostream& printXmpVersion(std::ostream& os, const Value& value, const ExifData*) { if (value.size() != 4 || value.typeId() != xmpText) { return os << "(" << value << ")"; } return printVersion(os, value.toString()); } std::ostream& printXmpDate(std::ostream& os, const Value& value, const ExifData*) { if (!(value.size() == 19 || value.size() == 20) || value.typeId() != xmpText) { return os << value; } std::string stringValue = value.toString(); if (stringValue[19] == 'Z') { stringValue = stringValue.substr(0, 19); } for (unsigned int i = 0; i < stringValue.length(); ++i) { if (stringValue[i] == 'T') stringValue[i] = ' '; if (stringValue[i] == '-') stringValue[i] = ':'; } return os << stringValue; } float fnumber(float apertureValue) { return static_cast(std::exp(std::log(2.0) * apertureValue / 2)); } URational exposureTime(float shutterSpeedValue) { URational ur(1, 1); double tmp = std::exp(std::log(2.0) * shutterSpeedValue); if (tmp > 1) { ur.second = static_cast(tmp + 0.5); } else { ur.first = static_cast(1/tmp + 0.5); } return ur; } }} // namespace Internal, Exiv2 namespace Exiv2 { //! @cond IGNORE GroupInfo::GroupName::GroupName(const std::string& groupName) { g_ = groupName; } //! @endcond bool GroupInfo::operator==(int ifdId) const { return ifdId_ == ifdId; } bool GroupInfo::operator==(const GroupName& groupName) const { return 0 == strcmp(groupName.g_.c_str(), groupName_); } TagInfo::TagInfo( uint16_t tag, const char* name, const char* title, const char* desc, int ifdId, int sectionId, TypeId typeId, int16_t count, PrintFct printFct ) : tag_(tag), name_(name), title_(title), desc_(desc), ifdId_(ifdId), sectionId_(sectionId), typeId_(typeId), count_(count), printFct_(printFct) { } const GroupInfo* ExifTags::groupList() { return groupInfo + 1; // +1 to skip the first (ifdIdNotSet) entry } const TagInfo* ExifTags::tagList(const std::string& groupName) { const GroupInfo* ii = find(groupInfo, GroupInfo::GroupName(groupName)); if (ii == 0 || ii->tagList_ == 0) return 0; return ii->tagList_(); } // ExifTags::tagList const char* ExifTags::sectionName(const ExifKey& key) { const TagInfo* ti = tagInfo(key.tag(), static_cast(key.ifdId())); if (ti == 0) return sectionInfo[unknownTag.sectionId_].name_; return sectionInfo[ti->sectionId_].name_; } uint16_t ExifTags::defaultCount(const ExifKey& key) { const TagInfo* ti = tagInfo(key.tag(), static_cast(key.ifdId())); if (ti == 0) return unknownTag.count_; return ti->count_; } const char* ExifTags::ifdName(const std::string& groupName) { IfdId ifdId = Internal::groupId(groupName); return Internal::ifdName(ifdId); } bool ExifTags::isMakerGroup(const std::string& groupName) { IfdId ifdId = Internal::groupId(groupName); return Internal::isMakerIfd(ifdId); } bool ExifTags::isExifGroup(const std::string& groupName) { IfdId ifdId = Internal::groupId(groupName); return Internal::isExifIfd(ifdId); } void ExifTags::taglist(std::ostream& os) { for (int i=0; ifdTagInfo[i].tag_ != 0xffff; ++i) { os << ifdTagInfo[i] << "\n"; } for (int i=0; exifTagInfo[i].tag_ != 0xffff; ++i) { os << exifTagInfo[i] << "\n"; } for (int i=0; iopTagInfo[i].tag_ != 0xffff; ++i) { os << iopTagInfo[i] << "\n"; } for (int i=0; gpsTagInfo[i].tag_ != 0xffff; ++i) { os << gpsTagInfo[i] << "\n"; } } // ExifTags::taglist void ExifTags::taglist(std::ostream& os, const std::string& groupName) { IfdId ifdId = Internal::groupId(groupName); Internal::taglist(os, ifdId); } //! %Internal Pimpl structure with private members and data of class ExifKey. struct ExifKey::Impl { //! @name Creators //@{ Impl(); //!< Default constructor //@} //! @name Manipulators //@{ /*! @brief Set the key corresponding to the \em tag, \em ifdId and \em tagInfo. The key is of the form 'Exif.groupName.tagName'. */ void makeKey(uint16_t tag, IfdId ifdId, const TagInfo* tagInfo); /*! @brief Parse and convert the key string into tag and IFD Id. Updates data members if the string can be decomposed, or throws \em Error . @throw Error if the key cannot be decomposed. */ void decomposeKey(const std::string& key); //@} //! @name Accessors //@{ //! Return the name of the tag std::string tagName() const; //@} // DATA static const char* familyName_; //!< "Exif" const TagInfo* tagInfo_; //!< Tag info uint16_t tag_; //!< Tag value IfdId ifdId_; //!< The IFD associated with this tag int idx_; //!< Unique id of the Exif key in the image std::string groupName_; //!< The group name std::string key_; //!< %Key }; const char* ExifKey::Impl::familyName_ = "Exif"; ExifKey::Impl::Impl() : tagInfo_(0), tag_(0), ifdId_(ifdIdNotSet), idx_(0) { } std::string ExifKey::Impl::tagName() const { if (tagInfo_ != 0 && tagInfo_->tag_ != 0xffff) { return tagInfo_->name_; } std::ostringstream os; os << "0x" << std::setw(4) << std::setfill('0') << std::right << std::hex << tag_; return os.str(); } void ExifKey::Impl::decomposeKey(const std::string& key) { // Get the family name, IFD name and tag name parts of the key std::string::size_type pos1 = key.find('.'); if (pos1 == std::string::npos) throw Error(6, key); std::string familyName = key.substr(0, pos1); if (0 != strcmp(familyName.c_str(), familyName_)) { throw Error(6, key); } std::string::size_type pos0 = pos1 + 1; pos1 = key.find('.', pos0); if (pos1 == std::string::npos) throw Error(6, key); std::string groupName = key.substr(pos0, pos1 - pos0); if (groupName.empty()) throw Error(6, key); std::string tn = key.substr(pos1 + 1); if (tn.empty()) throw Error(6, key); // Find IfdId IfdId ifdId = groupId(groupName); if (ifdId == ifdIdNotSet) throw Error(6, key); if (!Internal::isExifIfd(ifdId) && !Internal::isMakerIfd(ifdId)) { throw Error(6, key); } // Convert tag uint16_t tag = tagNumber(tn, ifdId); // Get tag info tagInfo_ = tagInfo(tag, ifdId); if (tagInfo_ == 0) throw Error(6, key); tag_ = tag; ifdId_ = ifdId; groupName_ = groupName; // tagName() translates hex tag name (0xabcd) to a real tag name if there is one key_ = familyName + "." + groupName + "." + tagName(); } void ExifKey::Impl::makeKey(uint16_t tag, IfdId ifdId, const TagInfo* tagInfo) { assert(tagInfo != 0); tagInfo_ = tagInfo; tag_ = tag; ifdId_ = ifdId; key_ = std::string(familyName_) + "." + groupName_ + "." + tagName(); } ExifKey::ExifKey(uint16_t tag, const std::string& groupName) : p_(new Impl) { IfdId ifdId = groupId(groupName); // Todo: Test if this condition can be removed if (!Internal::isExifIfd(ifdId) && !Internal::isMakerIfd(ifdId)) { throw Error(23, ifdId); } const TagInfo* ti = tagInfo(tag, ifdId); if (ti == 0) { throw Error(23, ifdId); } p_->groupName_ = groupName; p_->makeKey(tag, ifdId, ti); } ExifKey::ExifKey(const TagInfo& ti) : p_(new Impl) { IfdId ifdId = static_cast(ti.ifdId_); if (!Internal::isExifIfd(ifdId) && !Internal::isMakerIfd(ifdId)) { throw Error(23, ifdId); } p_->groupName_ = Exiv2::groupName(ifdId); p_->makeKey(ti.tag_, ifdId, &ti); } ExifKey::ExifKey(const std::string& key) : p_(new Impl) { p_->decomposeKey(key); } ExifKey::ExifKey(const ExifKey& rhs) : Key(rhs), p_(new Impl(*rhs.p_)) { } ExifKey::~ExifKey() { delete p_; } ExifKey& ExifKey::operator=(const ExifKey& rhs) { if (this == &rhs) return *this; Key::operator=(rhs); *p_ = *rhs.p_; return *this; } void ExifKey::setIdx(int idx) { p_->idx_ = idx; } std::string ExifKey::key() const { return p_->key_; } const char* ExifKey::familyName() const { return p_->familyName_; } std::string ExifKey::groupName() const { return p_->groupName_; } std::string ExifKey::tagName() const { return p_->tagName(); } std::string ExifKey::tagLabel() const { if (p_->tagInfo_ == 0 || p_->tagInfo_->tag_ == 0xffff) return ""; return _(p_->tagInfo_->title_); } std::string ExifKey::tagDesc() const { if (p_->tagInfo_ == 0 || p_->tagInfo_->tag_ == 0xffff) return ""; return _(p_->tagInfo_->desc_); } TypeId ExifKey::defaultTypeId() const { if (p_->tagInfo_ == 0) return unknownTag.typeId_; return p_->tagInfo_->typeId_; } uint16_t ExifKey::tag() const { return p_->tag_; } ExifKey::AutoPtr ExifKey::clone() const { return AutoPtr(clone_()); } ExifKey* ExifKey::clone_() const { return new ExifKey(*this); } int ExifKey::ifdId() const { return p_->ifdId_; } int ExifKey::idx() const { return p_->idx_; } // ************************************************************************* // free functions std::ostream& operator<<(std::ostream& os, const TagInfo& ti) { ExifKey exifKey(ti); return os << exifKey.tagName() << ",\t" << std::dec << exifKey.tag() << ",\t" << "0x" << std::setw(4) << std::setfill('0') << std::right << std::hex << exifKey.tag() << ",\t" << exifKey.groupName() << ",\t" << exifKey.key() << ",\t" << TypeInfo::typeName(exifKey.defaultTypeId()) << ",\t" << exifKey.tagDesc(); } } // namespace Exiv2 namespace { std::ostream& printVersion(std::ostream& os, const std::string& str) { if (str.size() != 4) { return os << "(" << str << ")"; } if (str[0] != '0') os << str[0]; return os << str[1] << "." << str[2] << str[3]; } } exiv2-0.23/src/crwimage.cpp0000644000175000017500000014213211732641407015410 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /* File: crwimage.cpp Version: $Rev: 2681 $ Author(s): Andreas Huggel (ahu) History: 28-Aug-05, ahu: created */ // ***************************************************************************** #include "rcsid_int.hpp" EXIV2_RCSID("@(#) $Id: crwimage.cpp 2681 2012-03-22 15:19:35Z ahuggel $") // Define DEBUG to output debug information to std::cerr, e.g, by calling make // like this: make DEFS=-DDEBUG crwimage.o //#define DEBUG 1 // ***************************************************************************** // included header files #ifdef _MSC_VER # include "exv_msvc.h" #else # include "exv_conf.h" #endif #include "crwimage.hpp" #include "crwimage_int.hpp" #include "error.hpp" #include "futils.hpp" #include "value.hpp" #include "tags.hpp" #include "tags_int.hpp" #include "canonmn_int.hpp" #include "i18n.h" // NLS support. // + standard includes #include #include #include #include #include #include #include #include #ifndef EXV_HAVE_TIMEGM # include "timegm.h" #endif // ***************************************************************************** // local declarations namespace { //! Helper class to map Exif orientation values to CRW rotation degrees class RotationMap { public: //! Get the orientation number for a degree value static uint16_t orientation(int32_t degrees); //! Get the degree value for an orientation number static int32_t degrees(uint16_t orientation); private: //! Helper structure for the mapping list struct OmList { uint16_t orientation; //!< Exif orientation value int32_t degrees; //!< CRW Rotation degrees }; // DATA static const OmList omList_[]; }; // class RotationMap } // ***************************************************************************** // class member definitions namespace Exiv2 { using namespace Internal; CrwImage::CrwImage(BasicIo::AutoPtr io, bool /*create*/) : Image(ImageType::crw, mdExif | mdComment, io) { } // CrwImage::CrwImage std::string CrwImage::mimeType() const { return "image/x-canon-crw"; } int CrwImage::pixelWidth() const { Exiv2::ExifData::const_iterator widthIter = exifData_.findKey(Exiv2::ExifKey("Exif.Photo.PixelXDimension")); if (widthIter != exifData_.end() && widthIter->count() > 0) { return widthIter->toLong(); } return 0; } int CrwImage::pixelHeight() const { Exiv2::ExifData::const_iterator heightIter = exifData_.findKey(Exiv2::ExifKey("Exif.Photo.PixelYDimension")); if (heightIter != exifData_.end() && heightIter->count() > 0) { return heightIter->toLong(); } return 0; } void CrwImage::setIptcData(const IptcData& /*iptcData*/) { // not supported throw(Error(32, "IPTC metadata", "CRW")); } void CrwImage::readMetadata() { #ifdef DEBUG std::cerr << "Reading CRW file " << io_->path() << "\n"; #endif if (io_->open() != 0) { throw Error(9, io_->path(), strError()); } IoCloser closer(*io_); // Ensure that this is the correct image type if (!isCrwType(*io_, false)) { if (io_->error() || io_->eof()) throw Error(14); throw Error(33); } clearMetadata(); CrwParser::decode(this, io_->mmap(), io_->size()); } // CrwImage::readMetadata void CrwImage::writeMetadata() { #ifdef DEBUG std::cerr << "Writing CRW file " << io_->path() << "\n"; #endif // Read existing image DataBuf buf; if (io_->open() == 0) { IoCloser closer(*io_); // Ensure that this is the correct image type if (isCrwType(*io_, false)) { // Read the image into a memory buffer buf.alloc(io_->size()); io_->read(buf.pData_, buf.size_); if (io_->error() || io_->eof()) { buf.reset(); } } } Blob blob; CrwParser::encode(blob, buf.pData_, buf.size_, this); // Write new buffer to file BasicIo::AutoPtr tempIo(io_->temporary()); // may throw assert(tempIo.get() != 0); tempIo->write((blob.size() > 0 ? &blob[0] : 0), static_cast(blob.size())); io_->close(); io_->transfer(*tempIo); // may throw } // CrwImage::writeMetadata void CrwParser::decode(CrwImage* pCrwImage, const byte* pData, uint32_t size) { assert(pCrwImage != 0); assert(pData != 0); // Parse the image, starting with a CIFF header component CiffHeader::AutoPtr head(new CiffHeader); head->read(pData, size); #ifdef DEBUG head->print(std::cerr); #endif head->decode(*pCrwImage); // a hack to get absolute offset of preview image inside CRW structure CiffComponent* preview = head->findComponent(0x2007, 0x0000); if (preview) { (pCrwImage->exifData())["Exif.Image2.JPEGInterchangeFormat"] = uint32_t(preview->pData() - pData); (pCrwImage->exifData())["Exif.Image2.JPEGInterchangeFormatLength"] = preview->size(); } } // CrwParser::decode void CrwParser::encode( Blob& blob, const byte* pData, uint32_t size, const CrwImage* pCrwImage ) { // Parse image, starting with a CIFF header component CiffHeader::AutoPtr head(new CiffHeader); if (size != 0) { head->read(pData, size); } // Encode Exif tags from image into the CRW parse tree and write the // structure to the binary image blob CrwMap::encode(head.get(), *pCrwImage); head->write(blob); } // CrwParser::encode // ************************************************************************* // free functions Image::AutoPtr newCrwInstance(BasicIo::AutoPtr io, bool create) { Image::AutoPtr image(new CrwImage(io, create)); if (!image->good()) { image.reset(); } return image; } bool isCrwType(BasicIo& iIo, bool advance) { bool result = true; byte tmpBuf[14]; iIo.read(tmpBuf, 14); if (iIo.error() || iIo.eof()) { return false; } if (!( ('I' == tmpBuf[0] && 'I' == tmpBuf[1]) || ('M' == tmpBuf[0] && 'M' == tmpBuf[1]))) { result = false; } if ( true == result && std::memcmp(tmpBuf + 6, CiffHeader::signature(), 8) != 0) { result = false; } if (!advance || !result) iIo.seek(-14, BasicIo::cur); return result; } } // namespace Exiv2 namespace Exiv2 { namespace Internal { /* Mapping table used to decode and encode CIFF tags to/from Exif tags. Only a subset of the Exif tags can be mapped to known tags found in CRW files and not all CIFF tags in the CRW files have a corresponding Exif tag. Tags which are not mapped in the table below are ignored. When decoding, each CIFF tag/directory pair in the CRW image is looked up in the table and if it has an entry, the corresponding decode function is called (CrwMap::decode). This function may or may not make use of the other parameters in the structure (such as the Exif tag and Ifd id). Encoding is done in a loop over the mapping table (CrwMap::encode). For each entry, the encode function is called, which looks up the (Exif) metadata to encode in the image. This function may or may not make use of the other parameters in the mapping structure. */ const CrwMapping CrwMap::crwMapping_[] = { // CrwTag CrwDir Size ExifTag IfdId decodeFct encodeFct // ------ ------ ---- ------- ----- --------- --------- CrwMapping(0x0805, 0x300a, 0, 0, canonId, decode0x0805, encode0x0805), CrwMapping(0x080a, 0x2807, 0, 0, canonId, decode0x080a, encode0x080a), CrwMapping(0x080b, 0x3004, 0, 0x0007, canonId, decodeBasic, encodeBasic), CrwMapping(0x0810, 0x2807, 0, 0x0009, canonId, decodeBasic, encodeBasic), CrwMapping(0x0815, 0x2804, 0, 0x0006, canonId, decodeBasic, encodeBasic), CrwMapping(0x1029, 0x300b, 0, 0x0002, canonId, decodeBasic, encodeBasic), CrwMapping(0x102a, 0x300b, 0, 0x0004, canonId, decodeArray, encodeArray), CrwMapping(0x102d, 0x300b, 0, 0x0001, canonId, decodeArray, encodeArray), CrwMapping(0x1033, 0x300b, 0, 0x000f, canonId, decodeArray, encodeArray), CrwMapping(0x1038, 0x300b, 0, 0x0012, canonId, decodeArray, encodeArray), CrwMapping(0x10a9, 0x300b, 0, 0x00a9, canonId, decodeBasic, encodeBasic), // Mapped to Exif.Photo.ColorSpace instead (see below) //CrwMapping(0x10b4, 0x300b, 0, 0x00b4, canonId, decodeBasic, encodeBasic), CrwMapping(0x10b4, 0x300b, 0, 0xa001, exifId, decodeBasic, encodeBasic), CrwMapping(0x10b5, 0x300b, 0, 0x00b5, canonId, decodeBasic, encodeBasic), CrwMapping(0x10c0, 0x300b, 0, 0x00c0, canonId, decodeBasic, encodeBasic), CrwMapping(0x10c1, 0x300b, 0, 0x00c1, canonId, decodeBasic, encodeBasic), CrwMapping(0x1807, 0x3002, 0, 0x9206, exifId, decodeBasic, encodeBasic), CrwMapping(0x180b, 0x3004, 0, 0x000c, canonId, decodeBasic, encodeBasic), CrwMapping(0x180e, 0x300a, 0, 0x9003, exifId, decode0x180e, encode0x180e), CrwMapping(0x1810, 0x300a, 0, 0xa002, exifId, decode0x1810, encode0x1810), CrwMapping(0x1817, 0x300a, 4, 0x0008, canonId, decodeBasic, encodeBasic), //CrwMapping(0x1818, 0x3002, 0, 0x9204, exifId, decodeBasic, encodeBasic), CrwMapping(0x183b, 0x300b, 0, 0x0015, canonId, decodeBasic, encodeBasic), CrwMapping(0x2008, 0x0000, 0, 0, ifd1Id, decode0x2008, encode0x2008), // End of list marker CrwMapping(0x0000, 0x0000, 0, 0x0000, ifdIdNotSet, 0, 0) }; // CrwMap::crwMapping_[] /* CIFF directory hierarchy root | 300a | +----+----+----+----+ | | | | | 2804 2807 3002 3003 300b | 3004 The array is arranged bottom-up so that starting with a directory at the bottom, the (unique) path to root can be determined in a single loop. */ const CrwSubDir CrwMap::crwSubDir_[] = { // dir, parent { 0x3004, 0x2807 }, { 0x300b, 0x300a }, { 0x3003, 0x300a }, { 0x3002, 0x300a }, { 0x2807, 0x300a }, { 0x2804, 0x300a }, { 0x300a, 0x0000 }, { 0x0000, 0xffff }, // End of list marker { 0xffff, 0xffff } }; const char CiffHeader::signature_[] = "HEAPCCDR"; CiffHeader::~CiffHeader() { delete pRootDir_; delete[] pPadding_; } CiffComponent::~CiffComponent() { if (isAllocated_) delete[] pData_; } CiffEntry::~CiffEntry() { } CiffDirectory::~CiffDirectory() { Components::iterator b = components_.begin(); Components::iterator e = components_.end(); for (Components::iterator i = b; i != e; ++i) { delete *i; } } void CiffComponent::add(AutoPtr component) { doAdd(component); } void CiffEntry::doAdd(AutoPtr /*component*/) { throw Error(34, "CiffEntry::add"); } // CiffEntry::doAdd void CiffDirectory::doAdd(AutoPtr component) { components_.push_back(component.release()); } // CiffDirectory::doAdd void CiffHeader::read(const byte* pData, uint32_t size) { if (size < 14) throw Error(33); if (pData[0] == 0x49 && pData[1] == 0x49) { byteOrder_ = littleEndian; } else if (pData[0] == 0x4d && pData[1] == 0x4d) { byteOrder_ = bigEndian; } else { throw Error(33); } offset_ = getULong(pData + 2, byteOrder_); if (offset_ < 14 || offset_ > size) throw Error(33); if (std::memcmp(pData + 6, signature(), 8) != 0) { throw Error(33); } delete pPadding_; pPadding_ = new byte[offset_ - 14]; padded_ = offset_ - 14; std::memcpy(pPadding_, pData + 14, padded_); pRootDir_ = new CiffDirectory; pRootDir_->readDirectory(pData + offset_, size - offset_, byteOrder_); } // CiffHeader::read void CiffComponent::read(const byte* pData, uint32_t size, uint32_t start, ByteOrder byteOrder) { doRead(pData, size, start, byteOrder); } void CiffComponent::doRead(const byte* pData, uint32_t size, uint32_t start, ByteOrder byteOrder) { if (size < 10) throw Error(33); tag_ = getUShort(pData + start, byteOrder); DataLocId dl = dataLocation(); assert(dl == directoryData || dl == valueData); if (dl == valueData) { size_ = getULong(pData + start + 2, byteOrder); offset_ = getULong(pData + start + 6, byteOrder); } if (dl == directoryData) { size_ = 8; offset_ = start + 2; } pData_ = pData + offset_; #ifdef DEBUG std::cout << " Entry for tag 0x" << std::hex << tagId() << " (0x" << tag() << "), " << std::dec << size_ << " Bytes, Offset is " << offset_ << "\n"; #endif } // CiffComponent::doRead void CiffDirectory::doRead(const byte* pData, uint32_t size, uint32_t start, ByteOrder byteOrder) { CiffComponent::doRead(pData, size, start, byteOrder); #ifdef DEBUG std::cout << "Reading directory 0x" << std::hex << tag() << "\n"; #endif readDirectory(pData + offset(), this->size(), byteOrder); #ifdef DEBUG std::cout << "<---- 0x" << std::hex << tag() << "\n"; #endif } // CiffDirectory::doRead void CiffDirectory::readDirectory(const byte* pData, uint32_t size, ByteOrder byteOrder) { uint32_t o = getULong(pData + size - 4, byteOrder); if (o + 2 > size) throw Error(33); uint16_t count = getUShort(pData + o, byteOrder); #ifdef DEBUG std::cout << "Directory at offset " << std::dec << o <<", " << count << " entries \n"; #endif o += 2; for (uint16_t i = 0; i < count; ++i) { if (o + 10 > size) throw Error(33); uint16_t tag = getUShort(pData + o, byteOrder); CiffComponent::AutoPtr m; switch (CiffComponent::typeId(tag)) { case directory: m = CiffComponent::AutoPtr(new CiffDirectory); break; default: m = CiffComponent::AutoPtr(new CiffEntry); break; } m->setDir(this->tag()); m->read(pData, size, o, byteOrder); add(m); o += 10; } } // CiffDirectory::readDirectory void CiffHeader::decode(Image& image) const { // Nothing to decode from the header itself, just add correct byte order if (pRootDir_) pRootDir_->decode(image, byteOrder_); } // CiffHeader::decode void CiffComponent::decode(Image& image, ByteOrder byteOrder) const { doDecode(image, byteOrder); } void CiffEntry::doDecode(Image& image, ByteOrder byteOrder) const { CrwMap::decode(*this, image, byteOrder); } // CiffEntry::doDecode void CiffDirectory::doDecode(Image& image, ByteOrder byteOrder) const { Components::const_iterator b = components_.begin(); Components::const_iterator e = components_.end(); for (Components::const_iterator i = b; i != e; ++i) { (*i)->decode(image, byteOrder); } } // CiffDirectory::doDecode void CiffHeader::write(Blob& blob) const { assert( byteOrder_ == littleEndian || byteOrder_ == bigEndian); if (byteOrder_ == littleEndian) { blob.push_back(0x49); blob.push_back(0x49); } else { blob.push_back(0x4d); blob.push_back(0x4d); } uint32_t o = 2; byte buf[4]; ul2Data(buf, offset_, byteOrder_); append(blob, buf, 4); o += 4; append(blob, reinterpret_cast(signature_), 8); o += 8; // Pad as needed if (pPadding_) { assert(padded_ == offset_ - o); append(blob, pPadding_, padded_); } else { for (uint32_t i = o; i < offset_; ++i) { blob.push_back(0); ++o; } } if (pRootDir_) { pRootDir_->write(blob, byteOrder_, offset_); } } uint32_t CiffComponent::write(Blob& blob, ByteOrder byteOrder, uint32_t offset) { return doWrite(blob, byteOrder, offset); } uint32_t CiffEntry::doWrite(Blob& blob, ByteOrder /*byteOrder*/, uint32_t offset) { return writeValueData(blob, offset); } // CiffEntry::doWrite uint32_t CiffComponent::writeValueData(Blob& blob, uint32_t offset) { if (dataLocation() == valueData) { #ifdef DEBUG std::cout << " Data for tag 0x" << std::hex << tagId() << ", " << std::dec << size_ << " Bytes\n"; #endif offset_ = offset; append(blob, pData_, size_); offset += size_; // Pad the value to an even number of bytes if (size_ % 2 == 1) { blob.push_back(0); ++offset; } } return offset; } // CiffComponent::writeValueData uint32_t CiffDirectory::doWrite(Blob& blob, ByteOrder byteOrder, uint32_t offset) { #ifdef DEBUG std::cout << "Writing directory 0x" << std::hex << tag() << "---->\n"; #endif // Ciff offsets are relative to the start of the directory uint32_t dirOffset = 0; // Value data const Components::iterator b = components_.begin(); const Components::iterator e = components_.end(); for (Components::iterator i = b; i != e; ++i) { dirOffset = (*i)->write(blob, byteOrder, dirOffset); } const uint32_t dirStart = dirOffset; // Number of directory entries byte buf[4]; us2Data(buf, static_cast(components_.size()), byteOrder); append(blob, buf, 2); dirOffset += 2; // Directory entries for (Components::iterator i = b; i != e; ++i) { (*i)->writeDirEntry(blob, byteOrder); dirOffset += 10; } // Offset of directory ul2Data(buf, dirStart, byteOrder); append(blob, buf, 4); dirOffset += 4; // Update directory entry setOffset(offset); setSize(dirOffset); #ifdef DEBUG std::cout << "Directory is at offset " << std::dec << dirStart << ", " << components_.size() << " entries\n" << "<---- 0x" << std::hex << tag() << "\n"; #endif return offset + dirOffset; } // CiffDirectory::doWrite void CiffComponent::writeDirEntry(Blob& blob, ByteOrder byteOrder) const { #ifdef DEBUG std::cout << " Directory entry for tag 0x" << std::hex << tagId() << " (0x" << tag() << "), " << std::dec << size_ << " Bytes, Offset is " << offset_ << "\n"; #endif byte buf[4]; DataLocId dl = dataLocation(); assert(dl == directoryData || dl == valueData); if (dl == valueData) { us2Data(buf, tag_, byteOrder); append(blob, buf, 2); ul2Data(buf, size_, byteOrder); append(blob, buf, 4); ul2Data(buf, offset_, byteOrder); append(blob, buf, 4); } if (dl == directoryData) { // Only 8 bytes fit in the directory entry assert(size_ <= 8); us2Data(buf, tag_, byteOrder); append(blob, buf, 2); // Copy value instead of size and offset append(blob, pData_, size_); // Pad with 0s for (uint32_t i = size_; i < 8; ++i) { blob.push_back(0); } } } // CiffComponent::writeDirEntry void CiffHeader::print(std::ostream& os, const std::string& prefix) const { os << prefix << _("Header, offset") << " = 0x" << std::setw(8) << std::setfill('0') << std::hex << std::right << offset_ << "\n"; if (pRootDir_) pRootDir_->print(os, byteOrder_, prefix); } // CiffHeader::print void CiffComponent::print(std::ostream& os, ByteOrder byteOrder, const std::string& prefix) const { doPrint(os, byteOrder, prefix); } void CiffComponent::doPrint(std::ostream& os, ByteOrder byteOrder, const std::string& prefix) const { os << prefix << _("tag") << " = 0x" << std::setw(4) << std::setfill('0') << std::hex << std::right << tagId() << ", " << _("dir") << " = 0x" << std::setw(4) << std::setfill('0') << std::hex << std::right << dir() << ", " << _("type") << " = " << TypeInfo::typeName(typeId()) << ", " << _("size") << " = " << std::dec << size_ << ", " << _("offset") << " = " << offset_ << "\n"; Value::AutoPtr value; if (typeId() != directory) { value = Value::create(typeId()); value->read(pData_, size_, byteOrder); if (value->size() < 100) { os << prefix << *value << "\n"; } } } // CiffComponent::doPrint void CiffDirectory::doPrint(std::ostream& os, ByteOrder byteOrder, const std::string& prefix) const { CiffComponent::doPrint(os, byteOrder, prefix); Components::const_iterator b = components_.begin(); Components::const_iterator e = components_.end(); for (Components::const_iterator i = b; i != e; ++i) { (*i)->print(os, byteOrder, prefix + " "); } } // CiffDirectory::doPrint void CiffComponent::setValue(DataBuf buf) { if (isAllocated_) { delete pData_; pData_ = 0; size_ = 0; } isAllocated_ = true; std::pair p = buf.release(); pData_ = p.first; size_ = p.second; if (size_ > 8 && dataLocation() == directoryData) { tag_ &= 0x3fff; } } // CiffComponent::setValue TypeId CiffComponent::typeId(uint16_t tag) { TypeId ti = invalidTypeId; switch (tag & 0x3800) { case 0x0000: ti = unsignedByte; break; case 0x0800: ti = asciiString; break; case 0x1000: ti = unsignedShort; break; case 0x1800: ti = unsignedLong; break; case 0x2000: ti = undefined; break; case 0x2800: // fallthrough case 0x3000: ti = directory; break; } return ti; } // CiffComponent::typeId DataLocId CiffComponent::dataLocation(uint16_t tag) { DataLocId di = invalidDataLocId; switch (tag & 0xc000) { case 0x0000: di = valueData; break; case 0x4000: di = directoryData; break; } return di; } // CiffComponent::dataLocation /*! @brief Finds \em crwTagId in directory \em crwDir, returning a pointer to the component or 0 if not found. */ CiffComponent* CiffHeader::findComponent(uint16_t crwTagId, uint16_t crwDir) const { if (pRootDir_ == 0) return 0; return pRootDir_->findComponent(crwTagId, crwDir); } // CiffHeader::findComponent CiffComponent* CiffComponent::findComponent(uint16_t crwTagId, uint16_t crwDir) const { return doFindComponent(crwTagId, crwDir); } // CiffComponent::findComponent CiffComponent* CiffComponent::doFindComponent(uint16_t crwTagId, uint16_t crwDir) const { if (tagId() == crwTagId && dir() == crwDir) { return const_cast(this); } return 0; } // CiffComponent::doFindComponent CiffComponent* CiffDirectory::doFindComponent(uint16_t crwTagId, uint16_t crwDir) const { CiffComponent* cc = 0; const Components::const_iterator b = components_.begin(); const Components::const_iterator e = components_.end(); for (Components::const_iterator i = b; i != e; ++i) { cc = (*i)->findComponent(crwTagId, crwDir); if (cc) return cc; } return 0; } // CiffDirectory::doFindComponent void CiffHeader::add(uint16_t crwTagId, uint16_t crwDir, DataBuf buf) { CrwDirs crwDirs; CrwMap::loadStack(crwDirs, crwDir); uint16_t rootDirectory = crwDirs.top().crwDir_; assert(rootDirectory == 0x0000); crwDirs.pop(); if (!pRootDir_) pRootDir_ = new CiffDirectory; CiffComponent* cc = pRootDir_->add(crwDirs, crwTagId); cc->setValue(buf); } // CiffHeader::add CiffComponent* CiffComponent::add(CrwDirs& crwDirs, uint16_t crwTagId) { return doAdd(crwDirs, crwTagId); } // CiffComponent::add CiffComponent* CiffComponent::doAdd(CrwDirs& /*crwDirs*/, uint16_t /*crwTagId*/) { return 0; } // CiffComponent::doAdd CiffComponent* CiffDirectory::doAdd(CrwDirs& crwDirs, uint16_t crwTagId) { /* add() if stack not empty pop from stack find dir among components if not found, create it add() else find tag among components if not found, create it set value */ CiffComponent* cc = 0; const Components::iterator b = components_.begin(); const Components::iterator e = components_.end(); if (!crwDirs.empty()) { CrwSubDir csd = crwDirs.top(); crwDirs.pop(); // Find the directory for (Components::iterator i = b; i != e; ++i) { if ((*i)->tag() == csd.crwDir_) { cc = *i; break; } } if (cc == 0) { // Directory doesn't exist yet, add it AutoPtr m(new CiffDirectory(csd.crwDir_, csd.parent_)); cc = m.get(); add(m); } // Recursive call to next lower level directory cc = cc->add(crwDirs, crwTagId); } else { // Find the tag for (Components::iterator i = b; i != e; ++i) { if ((*i)->tagId() == crwTagId) { cc = *i; break; } } if (cc == 0) { // Tag doesn't exist yet, add it AutoPtr m(new CiffEntry(crwTagId, tag())); cc = m.get(); add(m); } } return cc; } // CiffDirectory::doAdd void CiffHeader::remove(uint16_t crwTagId, uint16_t crwDir) { if (pRootDir_) { CrwDirs crwDirs; CrwMap::loadStack(crwDirs, crwDir); uint16_t rootDirectory = crwDirs.top().crwDir_; assert(rootDirectory == 0x0000); crwDirs.pop(); pRootDir_->remove(crwDirs, crwTagId); } } // CiffHeader::remove void CiffComponent::remove(CrwDirs& crwDirs, uint16_t crwTagId) { return doRemove(crwDirs, crwTagId); } // CiffComponent::remove void CiffComponent::doRemove(CrwDirs& /*crwDirs*/, uint16_t /*crwTagId*/) { // do nothing } // CiffComponent::doRemove void CiffDirectory::doRemove(CrwDirs& crwDirs, uint16_t crwTagId) { const Components::iterator b = components_.begin(); const Components::iterator e = components_.end(); Components::iterator i; if (!crwDirs.empty()) { CrwSubDir csd = crwDirs.top(); crwDirs.pop(); // Find the directory for (i = b; i != e; ++i) { if ((*i)->tag() == csd.crwDir_) { // Recursive call to next lower level directory (*i)->remove(crwDirs, crwTagId); if ((*i)->empty()) components_.erase(i); break; } } } else { // Find the tag for (i = b; i != e; ++i) { if ((*i)->tagId() == crwTagId) { // Remove the entry and abort the loop delete *i; components_.erase(i); break; } } } } // CiffDirectory::doRemove bool CiffComponent::empty() const { return doEmpty(); } bool CiffComponent::doEmpty() const { return size_ == 0; } bool CiffDirectory::doEmpty() const { return components_.empty(); } void CrwMap::decode(const CiffComponent& ciffComponent, Image& image, ByteOrder byteOrder) { const CrwMapping* cmi = crwMapping(ciffComponent.dir(), ciffComponent.tagId()); if (cmi && cmi->toExif_) { cmi->toExif_(ciffComponent, cmi, image, byteOrder); } } // CrwMap::decode const CrwMapping* CrwMap::crwMapping(uint16_t crwDir, uint16_t crwTagId) { for (int i = 0; crwMapping_[i].ifdId_ != ifdIdNotSet; ++i) { if ( crwMapping_[i].crwDir_ == crwDir && crwMapping_[i].crwTagId_ == crwTagId) { return &(crwMapping_[i]); } } return 0; } // CrwMap::crwMapping void CrwMap::decode0x0805(const CiffComponent& ciffComponent, const CrwMapping* /*pCrwMapping*/, Image& image, ByteOrder /*byteOrder*/) { std::string s(reinterpret_cast(ciffComponent.pData())); image.setComment(s); } // CrwMap::decode0x0805 void CrwMap::decode0x080a(const CiffComponent& ciffComponent, const CrwMapping* /*pCrwMapping*/, Image& image, ByteOrder byteOrder) { if (ciffComponent.typeId() != asciiString) return; // Make ExifKey key1("Exif.Image.Make"); Value::AutoPtr value1 = Value::create(ciffComponent.typeId()); uint32_t i = 0; for (; i < ciffComponent.size() && ciffComponent.pData()[i] != '\0'; ++i) { // empty } value1->read(ciffComponent.pData(), ++i, byteOrder); image.exifData().add(key1, value1.get()); // Model ExifKey key2("Exif.Image.Model"); Value::AutoPtr value2 = Value::create(ciffComponent.typeId()); uint32_t j = i; for (; i < ciffComponent.size() && ciffComponent.pData()[i] != '\0'; ++i) { // empty } value2->read(ciffComponent.pData() + j, i - j + 1, byteOrder); image.exifData().add(key2, value2.get()); } // CrwMap::decode0x080a void CrwMap::decodeArray(const CiffComponent& ciffComponent, const CrwMapping* pCrwMapping, Image& image, ByteOrder byteOrder) { if (ciffComponent.typeId() != unsignedShort) { return decodeBasic(ciffComponent, pCrwMapping, image, byteOrder); } long aperture = 0; long shutterSpeed = 0; IfdId ifdId = ifdIdNotSet; switch (pCrwMapping->tag_) { case 0x0001: ifdId = canonCsId; break; case 0x0004: ifdId = canonSiId; break; case 0x000f: ifdId = canonCfId; break; case 0x0012: ifdId = canonPiId; break; } assert(ifdId != ifdIdNotSet); std::string groupName(Internal::groupName(ifdId)); uint16_t c = 1; while (uint32_t(c)*2 < ciffComponent.size()) { uint16_t n = 1; ExifKey key(c, groupName); UShortValue value; if (ifdId == canonCsId && c == 23 && ciffComponent.size() > 50) n = 3; value.read(ciffComponent.pData() + c*2, n*2, byteOrder); image.exifData().add(key, &value); if (ifdId == canonSiId && c == 21) aperture = value.toLong(); if (ifdId == canonSiId && c == 22) shutterSpeed = value.toLong(); c += n; } if (ifdId == canonSiId) { // Exif.Photo.FNumber float f = fnumber(canonEv(aperture)); Rational r = floatToRationalCast(f); URational ur(r.first, r.second); URationalValue fn; fn.value_.push_back(ur); image.exifData().add(ExifKey("Exif.Photo.FNumber"), &fn); // Exif.Photo.ExposureTime ur = exposureTime(canonEv(shutterSpeed)); URationalValue et; et.value_.push_back(ur); image.exifData().add(ExifKey("Exif.Photo.ExposureTime"), &et); } } // CrwMap::decodeArray void CrwMap::decode0x180e(const CiffComponent& ciffComponent, const CrwMapping* pCrwMapping, Image& image, ByteOrder byteOrder) { if (ciffComponent.size() < 8 || ciffComponent.typeId() != unsignedLong) { return decodeBasic(ciffComponent, pCrwMapping, image, byteOrder); } assert(pCrwMapping != 0); ULongValue v; v.read(ciffComponent.pData(), 8, byteOrder); time_t t = v.value_[0]; #ifdef EXV_HAVE_GMTIME_R struct tm tms; struct tm* tm = &tms; tm = gmtime_r(&t, tm); #else struct tm* tm = std::gmtime(&t); #endif if (tm) { const size_t m = 20; char s[m]; std::strftime(s, m, "%Y:%m:%d %H:%M:%S", tm); ExifKey key(pCrwMapping->tag_, Internal::groupName(pCrwMapping->ifdId_)); AsciiValue value; value.read(std::string(s)); image.exifData().add(key, &value); } } // CrwMap::decode0x180e void CrwMap::decode0x1810(const CiffComponent& ciffComponent, const CrwMapping* pCrwMapping, Image& image, ByteOrder byteOrder) { if (ciffComponent.typeId() != unsignedLong || ciffComponent.size() < 28) { return decodeBasic(ciffComponent, pCrwMapping, image, byteOrder); } ExifKey key1("Exif.Photo.PixelXDimension"); ULongValue value1; value1.read(ciffComponent.pData(), 4, byteOrder); image.exifData().add(key1, &value1); ExifKey key2("Exif.Photo.PixelYDimension"); ULongValue value2; value2.read(ciffComponent.pData() + 4, 4, byteOrder); image.exifData().add(key2, &value2); int32_t r = getLong(ciffComponent.pData() + 12, byteOrder); uint16_t o = RotationMap::orientation(r); image.exifData()["Exif.Image.Orientation"] = o; } // CrwMap::decode0x1810 void CrwMap::decode0x2008(const CiffComponent& ciffComponent, const CrwMapping* /*pCrwMapping*/, Image& image, ByteOrder /*byteOrder*/) { ExifThumb exifThumb(image.exifData()); exifThumb.setJpegThumbnail(ciffComponent.pData(), ciffComponent.size()); } // CrwMap::decode0x2008 void CrwMap::decodeBasic(const CiffComponent& ciffComponent, const CrwMapping* pCrwMapping, Image& image, ByteOrder byteOrder) { assert(pCrwMapping != 0); // create a key and value pair ExifKey key(pCrwMapping->tag_, Internal::groupName(pCrwMapping->ifdId_)); Value::AutoPtr value; if (ciffComponent.typeId() != directory) { value = Value::create(ciffComponent.typeId()); uint32_t size = 0; if (pCrwMapping->size_ != 0) { // size in the mapping table overrides all size = pCrwMapping->size_; } else if (ciffComponent.typeId() == asciiString) { // determine size from the data, by looking for the first 0 uint32_t i = 0; for (; i < ciffComponent.size() && ciffComponent.pData()[i] != '\0'; ++i) { // empty } size = ++i; } else { // by default, use the size from the directory entry size = ciffComponent.size(); } value->read(ciffComponent.pData(), size, byteOrder); } // Add metadatum to exif data image.exifData().add(key, value.get()); } // CrwMap::decodeBasic void CrwMap::loadStack(CrwDirs& crwDirs, uint16_t crwDir) { for (int i = 0; crwSubDir_[i].crwDir_ != 0xffff; ++i) { if (crwSubDir_[i].crwDir_ == crwDir) { crwDirs.push(crwSubDir_[i]); crwDir = crwSubDir_[i].parent_; } } } // CrwMap::loadStack void CrwMap::encode(CiffHeader* pHead, const Image& image) { for (const CrwMapping* cmi = crwMapping_; cmi->ifdId_ != ifdIdNotSet; ++cmi) { if (cmi->fromExif_ != 0) { cmi->fromExif_(image, cmi, pHead); } } } // CrwMap::encode void CrwMap::encodeBasic(const Image& image, const CrwMapping* pCrwMapping, CiffHeader* pHead) { assert(pCrwMapping != 0); assert(pHead != 0); // Determine the source Exif metadatum ExifKey ek(pCrwMapping->tag_, Internal::groupName(pCrwMapping->ifdId_)); ExifData::const_iterator ed = image.exifData().findKey(ek); // Set the new value or remove the entry if (ed != image.exifData().end()) { DataBuf buf(ed->size()); ed->copy(buf.pData_, pHead->byteOrder()); pHead->add(pCrwMapping->crwTagId_, pCrwMapping->crwDir_, buf); } else { pHead->remove(pCrwMapping->crwTagId_, pCrwMapping->crwDir_); } } // CrwMap::encodeBasic void CrwMap::encode0x0805(const Image& image, const CrwMapping* pCrwMapping, CiffHeader* pHead) { assert(pCrwMapping != 0); assert(pHead != 0); std::string comment = image.comment(); CiffComponent* cc = pHead->findComponent(pCrwMapping->crwTagId_, pCrwMapping->crwDir_); if (!comment.empty()) { uint32_t size = static_cast(comment.size()); if (cc && cc->size() > size) size = cc->size(); DataBuf buf(size); std::memset(buf.pData_, 0x0, buf.size_); std::memcpy(buf.pData_, comment.data(), comment.size()); pHead->add(pCrwMapping->crwTagId_, pCrwMapping->crwDir_, buf); } else { if (cc) { // Just delete the value, do not remove the tag DataBuf buf(cc->size()); std::memset(buf.pData_, 0x0, buf.size_); cc->setValue(buf); } } } // CrwMap::encode0x0805 void CrwMap::encode0x080a(const Image& image, const CrwMapping* pCrwMapping, CiffHeader* pHead) { assert(pCrwMapping != 0); assert(pHead != 0); const ExifKey k1("Exif.Image.Make"); const ExifKey k2("Exif.Image.Model"); const ExifData::const_iterator ed1 = image.exifData().findKey(k1); const ExifData::const_iterator ed2 = image.exifData().findKey(k2); const ExifData::const_iterator edEnd = image.exifData().end(); long size = 0; if (ed1 != edEnd) size += ed1->size(); if (ed2 != edEnd) size += ed2->size(); if (size != 0) { DataBuf buf(size); if (ed1 != edEnd) ed1->copy(buf.pData_, pHead->byteOrder()); if (ed2 != edEnd) ed2->copy(buf.pData_ + ed1->size(), pHead->byteOrder()); pHead->add(pCrwMapping->crwTagId_, pCrwMapping->crwDir_, buf); } else { pHead->remove(pCrwMapping->crwTagId_, pCrwMapping->crwDir_); } } // CrwMap::encode0x080a void CrwMap::encodeArray(const Image& image, const CrwMapping* pCrwMapping, CiffHeader* pHead) { assert(pCrwMapping != 0); assert(pHead != 0); IfdId ifdId = ifdIdNotSet; switch (pCrwMapping->tag_) { case 0x0001: ifdId = canonCsId; break; case 0x0004: ifdId = canonSiId; break; case 0x000f: ifdId = canonCfId; break; case 0x0012: ifdId = canonPiId; break; } assert(ifdId != ifdIdNotSet); DataBuf buf = packIfdId(image.exifData(), ifdId, pHead->byteOrder()); if (buf.size_ == 0) { // Try the undecoded tag encodeBasic(image, pCrwMapping, pHead); } if (buf.size_ > 0) { // Write the number of shorts to the beginning of buf us2Data(buf.pData_, static_cast(buf.size_), pHead->byteOrder()); pHead->add(pCrwMapping->crwTagId_, pCrwMapping->crwDir_, buf); } else { pHead->remove(pCrwMapping->crwTagId_, pCrwMapping->crwDir_); } } // CrwMap::encodeArray void CrwMap::encode0x180e(const Image& image, const CrwMapping* pCrwMapping, CiffHeader* pHead) { assert(pCrwMapping != 0); assert(pHead != 0); time_t t = 0; const ExifKey key(pCrwMapping->tag_, Internal::groupName(pCrwMapping->ifdId_)); const ExifData::const_iterator ed = image.exifData().findKey(key); if (ed != image.exifData().end()) { struct tm tm; std::memset(&tm, 0x0, sizeof(tm)); int rc = exifTime(ed->toString().c_str(), &tm); if (rc == 0) t = timegm(&tm); } if (t != 0) { DataBuf buf(12); std::memset(buf.pData_, 0x0, 12); ul2Data(buf.pData_, static_cast(t), pHead->byteOrder()); pHead->add(pCrwMapping->crwTagId_, pCrwMapping->crwDir_, buf); } else { pHead->remove(pCrwMapping->crwTagId_, pCrwMapping->crwDir_); } } // CrwMap::encode0x180e void CrwMap::encode0x1810(const Image& image, const CrwMapping* pCrwMapping, CiffHeader* pHead) { assert(pCrwMapping != 0); assert(pHead != 0); const ExifKey kX("Exif.Photo.PixelXDimension"); const ExifKey kY("Exif.Photo.PixelYDimension"); const ExifKey kO("Exif.Image.Orientation"); const ExifData::const_iterator edX = image.exifData().findKey(kX); const ExifData::const_iterator edY = image.exifData().findKey(kY); const ExifData::const_iterator edO = image.exifData().findKey(kO); const ExifData::const_iterator edEnd = image.exifData().end(); CiffComponent* cc = pHead->findComponent(pCrwMapping->crwTagId_, pCrwMapping->crwDir_); if (edX != edEnd || edY != edEnd || edO != edEnd) { uint32_t size = 28; if (cc && cc->size() > size) size = cc->size(); DataBuf buf(size); std::memset(buf.pData_, 0x0, buf.size_); if (cc) std::memcpy(buf.pData_ + 8, cc->pData() + 8, cc->size() - 8); if (edX != edEnd && edX->size() == 4) { edX->copy(buf.pData_, pHead->byteOrder()); } if (edY != edEnd && edY->size() == 4) { edY->copy(buf.pData_ + 4, pHead->byteOrder()); } int32_t d = 0; if (edO != edEnd && edO->count() > 0 && edO->typeId() == unsignedShort) { d = RotationMap::degrees(static_cast(edO->toLong())); } l2Data(buf.pData_ + 12, d, pHead->byteOrder()); pHead->add(pCrwMapping->crwTagId_, pCrwMapping->crwDir_, buf); } else { pHead->remove(pCrwMapping->crwTagId_, pCrwMapping->crwDir_); } } // CrwMap::encode0x1810 void CrwMap::encode0x2008(const Image& image, const CrwMapping* pCrwMapping, CiffHeader* pHead) { assert(pCrwMapping != 0); assert(pHead != 0); ExifThumbC exifThumb(image.exifData()); DataBuf buf = exifThumb.copy(); if (buf.size_ != 0) { pHead->add(pCrwMapping->crwTagId_, pCrwMapping->crwDir_, buf); } else { pHead->remove(pCrwMapping->crwTagId_, pCrwMapping->crwDir_); } } // CrwMap::encode0x2008 // ************************************************************************* // free functions DataBuf packIfdId(const ExifData& exifData, IfdId ifdId, ByteOrder byteOrder) { const uint16_t size = 1024; DataBuf buf(size); std::memset(buf.pData_, 0x0, buf.size_); uint16_t len = 0; const ExifData::const_iterator b = exifData.begin(); const ExifData::const_iterator e = exifData.end(); for (ExifData::const_iterator i = b; i != e; ++i) { if (i->ifdId() != ifdId) continue; const uint16_t s = i->tag()*2 + static_cast(i->size()); assert(s <= size); if (len < s) len = s; i->copy(buf.pData_ + i->tag()*2, byteOrder); } // Round the size to make it even. buf.size_ = len + len%2; return buf; } }} // namespace Internal, Exiv2 // ***************************************************************************** // local definitions namespace { //! @cond IGNORE const RotationMap::OmList RotationMap::omList_[] = { { 1, 0 }, { 3, 180 }, { 3, -180 }, { 6, 90 }, { 6, -270 }, { 8, 270 }, { 8, -90 }, // last entry { 0, 0 } }; uint16_t RotationMap::orientation(int32_t degrees) { uint16_t o = 1; for (int i = 0; omList_[i].orientation != 0; ++i) { if (omList_[i].degrees == degrees) { o = omList_[i].orientation; break; } } return o; } int32_t RotationMap::degrees(uint16_t orientation) { int32_t d = 0; for (int i = 0; omList_[i].orientation != 0; ++i) { if (omList_[i].orientation == orientation) { d = omList_[i].degrees; break; } } return d; } //! @endcond } exiv2-0.23/src/epsimage.cpp0000644000175000017500000015143311732641407015410 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /* File: epsimage.cpp Version: $Rev: 2455 $ Author(s): Michael Ulbrich (mul) Volker Grabsch (vog) History: 7-Mar-2011, vog: created */ // ***************************************************************************** #include "rcsid_int.hpp" EXIV2_RCSID("@(#) $Id: epsimage.cpp $") // ***************************************************************************** //#define DEBUG 1 // ***************************************************************************** // included header files #ifdef _MSC_VER # include "exv_msvc.h" #else # include "exv_conf.h" #endif #include "epsimage.hpp" #include "image.hpp" #include "basicio.hpp" #include "error.hpp" #include "futils.hpp" // + standard includes #include #include #include #include #include #include #include // ***************************************************************************** namespace { using namespace Exiv2; // signature of DOS EPS const std::string dosEpsSignature = "\xC5\xD0\xD3\xC6"; // first line of EPS const std::string epsFirstLine[] = { "%!PS-Adobe-3.0 EPSF-3.0", "%!PS-Adobe-3.0 EPSF-3.0 ", // OpenOffice "%!PS-Adobe-3.1 EPSF-3.0", // Illustrator }; // blank EPS file const std::string epsBlank = "%!PS-Adobe-3.0 EPSF-3.0\n" "%%BoundingBox: 0 0 0 0\n"; // list of all valid XMP headers const std::string xmpHeaders[] = { // We do not enforce the trailing "?>" here, because the XMP specification // permits additional attributes after begin="..." and id="...". // normal headers "" here, because the XMP specification // permits additional attributes after end="...". {""; //! Write data into temp file, taking care of errors void writeTemp(BasicIo& tempIo, const byte* data, size_t size) { if (size == 0) return; if (tempIo.write(data, static_cast(size)) != static_cast(size)) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Failed to write to temporary file.\n"; #endif throw Error(21); } } //! Write data into temp file, taking care of errors void writeTemp(BasicIo& tempIo, const std::string &data) { writeTemp(tempIo, reinterpret_cast(data.data()), data.size()); } //! Get the current write position of temp file, taking care of errors uint32_t posTemp(BasicIo& tempIo) { const long pos = tempIo.tell(); if (pos == -1) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Internal error while determining current write position in temporary file.\n"; #endif throw Error(21); } return static_cast(pos); } //! Check whether a string has a certain beginning bool startsWith(const std::string& s, const std::string& start) { return s.size() >= start.size() && memcmp(s.data(), start.data(), start.size()) == 0; } //! Check whether a string contains only white space characters bool onlyWhitespaces(const std::string& s) { // According to the DSC 3.0 specification, 4.4 Parsing Rules, // only spaces and tabs are considered to be white space characters. return s.find_first_not_of(" \t") == std::string::npos; } //! Read the next line of a buffer, allow for changing line ending style size_t readLine(std::string& line, const byte* data, size_t startPos, size_t size) { line.clear(); size_t pos = startPos; // step through line while (pos < size && data[pos] != '\r' && data[pos] != '\n') { line += data[pos]; pos++; } // skip line ending, if present if (pos >= size) return pos; pos++; if (pos >= size) return pos; if (data[pos - 1] == '\r' && data[pos] == '\n') pos++; return pos; } //! Read the previous line of a buffer, allow for changing line ending style size_t readPrevLine(std::string& line, const byte* data, size_t startPos, size_t size) { line.clear(); size_t pos = startPos; if (pos > size) return pos; // skip line ending of previous line, if present if (pos <= 0) return pos; if (data[pos - 1] == '\r' || data[pos - 1] == '\n') { pos--; if (pos <= 0) return pos; if (data[pos - 1] == '\r' && data[pos] == '\n') { pos--; if (pos <= 0) return pos; } } // step through previous line while (pos >= 1 && data[pos - 1] != '\r' && data[pos - 1] != '\n') { pos--; line += data[pos]; } std::reverse(line.begin(), line.end()); return pos; } //! Find an XMP block void findXmp(size_t& xmpPos, size_t& xmpSize, const byte* data, size_t startPos, size_t size, bool write) { // search for valid XMP header xmpSize = 0; for (xmpPos = startPos; xmpPos < size; xmpPos++) { if (data[xmpPos] != '\x00' && data[xmpPos] != '<') continue; for (size_t i = 0; i < (sizeof xmpHeaders) / (sizeof *xmpHeaders); i++) { const std::string &header = xmpHeaders[i]; if (xmpPos + header.size() > size) continue; if (memcmp(data + xmpPos, header.data(), header.size()) != 0) continue; #ifdef DEBUG EXV_DEBUG << "findXmp: Found XMP header at position: " << xmpPos << "\n"; #endif // search for valid XMP trailer for (size_t trailerPos = xmpPos + header.size(); trailerPos < size; trailerPos++) { if (data[xmpPos] != '\x00' && data[xmpPos] != '<') continue; for (size_t j = 0; j < (sizeof xmpTrailers) / (sizeof *xmpTrailers); j++) { const std::string &trailer = xmpTrailers[j].trailer; const bool readOnly = xmpTrailers[j].readOnly; if (trailerPos + trailer.size() > size) continue; if (memcmp(data + trailerPos, trailer.data(), trailer.size()) != 0) continue; #ifdef DEBUG EXV_DEBUG << "findXmp: Found XMP trailer at position: " << trailerPos << "\n"; #endif if (readOnly) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Unable to handle read-only XMP metadata yet. Please provide your " "sample EPS file to the Exiv2 project: http://dev.exiv2.org/projects/exiv2\n"; #endif throw Error(write ? 21 : 14); } // search for end of XMP trailer for (size_t trailerEndPos = trailerPos + trailer.size(); trailerEndPos + xmpTrailerEnd.size() <= size; trailerEndPos++) { if (memcmp(data + trailerEndPos, xmpTrailerEnd.data(), xmpTrailerEnd.size()) == 0) { xmpSize = (trailerEndPos + xmpTrailerEnd.size()) - xmpPos; return; } } #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Found XMP header but incomplete XMP trailer.\n"; #endif throw Error(write ? 21 : 14); } } #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Found XMP header but no XMP trailer.\n"; #endif throw Error(write ? 21 : 14); } } } //! Unified implementation of reading and writing EPS metadata void readWriteEpsMetadata(BasicIo& io, std::string& xmpPacket, NativePreviewList& nativePreviews, bool write) { // open input file if (io.open() != 0) { throw Error(9, io.path(), strError()); } IoCloser closer(io); // read from input file via memory map const byte *data = io.mmap(); // default positions and sizes const size_t size = static_cast(io.size()); size_t posEps = 0; size_t posEndEps = size; uint32_t posWmf = 0; uint32_t sizeWmf = 0; uint32_t posTiff = 0; uint32_t sizeTiff = 0; // check for DOS EPS const bool dosEps = (size >= dosEpsSignature.size() && memcmp(data, dosEpsSignature.data(), dosEpsSignature.size()) == 0); if (dosEps) { #ifdef DEBUG EXV_DEBUG << "readWriteEpsMetadata: Found DOS EPS signature\n"; #endif if (size < 30) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Premature end of file after DOS EPS signature.\n"; #endif throw Error(write ? 21 : 14); } posEps = getULong(data + 4, littleEndian); posEndEps = getULong(data + 8, littleEndian) + posEps; posWmf = getULong(data + 12, littleEndian); sizeWmf = getULong(data + 16, littleEndian); posTiff = getULong(data + 20, littleEndian); sizeTiff = getULong(data + 24, littleEndian); const uint16_t checksum = getUShort(data + 28, littleEndian); #ifdef DEBUG EXV_DEBUG << "readWriteEpsMetadata: EPS section at position " << posEps << ", size " << (posEndEps - posEps) << "\n"; EXV_DEBUG << "readWriteEpsMetadata: WMF section at position " << posWmf << ", size " << sizeWmf << "\n"; EXV_DEBUG << "readWriteEpsMetadata: TIFF section at position " << posTiff << ", size " << sizeTiff << "\n"; #endif if (checksum != 0xFFFF) { #ifdef DEBUG EXV_DEBUG << "readWriteEpsMetadata: DOS EPS checksum is not FFFF\n"; #endif } if (!((posWmf == 0 && sizeWmf == 0) || (posTiff == 0 && sizeTiff == 0))) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "DOS EPS file has both WMF and TIFF section. Only one of those is allowed.\n"; #endif if (write) throw Error(21); } if (sizeWmf == 0 && sizeTiff == 0) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "DOS EPS file has neither WMF nor TIFF section. Exactly one of those is required.\n"; #endif if (write) throw Error(21); } if (posEps < 30 || posEndEps > size) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "DOS EPS file has invalid position (" << posEps << ") or size (" << (posEndEps - posEps) << ") for EPS section.\n"; #endif throw Error(write ? 21 : 14); } if (sizeWmf != 0 && (posWmf < 30 || posWmf + sizeWmf > size)) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "DOS EPS file has invalid position (" << posWmf << ") or size (" << sizeWmf << ") for WMF section.\n"; #endif if (write) throw Error(21); } if (sizeTiff != 0 && (posTiff < 30 || posTiff + sizeTiff > size)) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "DOS EPS file has invalid position (" << posTiff << ") or size (" << sizeTiff << ") for TIFF section.\n"; #endif if (write) throw Error(21); } } // check first line std::string firstLine; const size_t posSecondLine = readLine(firstLine, data, posEps, posEndEps); #ifdef DEBUG EXV_DEBUG << "readWriteEpsMetadata: First line: " << firstLine << "\n"; #endif bool matched = false; for (size_t i = 0; !matched && i < (sizeof epsFirstLine) / (sizeof *epsFirstLine); i++) { matched = (firstLine == epsFirstLine[i]); } if (!matched) { throw Error(3, "EPS"); } // determine line ending style of the first line if (posSecondLine >= posEndEps) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Premature end of file after first line.\n"; #endif throw Error(write ? 21 : 14); } const std::string lineEnding(reinterpret_cast(data + posEps + firstLine.size()), posSecondLine - (posEps + firstLine.size())); #ifdef DEBUG if (lineEnding == "\n") { EXV_DEBUG << "readWriteEpsMetadata: Line ending style: Unix (LF)\n"; } else if (lineEnding == "\r") { EXV_DEBUG << "readWriteEpsMetadata: Line ending style: Mac (CR)\n"; } else if (lineEnding == "\r\n") { EXV_DEBUG << "readWriteEpsMetadata: Line ending style: DOS (CR LF)\n"; } else { EXV_DEBUG << "readWriteEpsMetadata: Line ending style: (unknown)\n"; } #endif // scan comments size_t posLanguageLevel = posEndEps; size_t posContainsXmp = posEndEps; size_t posPages = posEndEps; size_t posExiv2Version = posEndEps; size_t posExiv2Website = posEndEps; size_t posEndComments = posEndEps; size_t posAi7Thumbnail = posEndEps; size_t posAi7ThumbnailEndData = posEndEps; size_t posBeginPhotoshop = posEndEps; size_t posEndPhotoshop = posEndEps; size_t posPage = posEndEps; size_t posEndPageSetup = posEndEps; size_t posPageTrailer = posEndEps; size_t posEof = posEndEps; std::vector > removableEmbeddings; unsigned int depth = 0; const unsigned int maxDepth = UINT_MAX; bool illustrator8 = false; bool corelDraw = false; bool implicitPage = false; bool implicitPageTrailer = false; bool inDefaultsPreviewPrologSetup = false; bool inPageSetup = false; bool inRemovableEmbedding = false; std::string removableEmbeddingEndLine; unsigned int removableEmbeddingsWithUnmarkedTrailer = 0; for (size_t pos = posEps; pos < posEof;) { const size_t startPos = pos; std::string line; pos = readLine(line, data, startPos, posEndEps); #ifdef DEBUG bool significantLine = true; #endif // nested documents if (posPage == posEndEps && (startsWith(line, "%%IncludeDocument:") || startsWith(line, "%%BeginDocument:"))) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Nested document at invalid position: " << startPos << "\n"; #endif throw Error(write ? 21 : 14); } else if (startsWith(line, "%%BeginDocument:")) { if (depth == maxDepth) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Document too deeply nested at position: " << startPos << "\n"; #endif throw Error(write ? 21 : 14); } depth++; } else if (startsWith(line, "%%EndDocument")) { if (depth == 0) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Unmatched EndDocument at position: " << startPos << "\n"; #endif throw Error(write ? 21 : 14); } depth--; } else { #ifdef DEBUG significantLine = false; #endif } #ifdef DEBUG if (significantLine) { EXV_DEBUG << "readWriteEpsMetadata: Found significant line \"" << line << "\" at position: " << startPos << "\n"; } #endif if (depth != 0) continue; // explicit "Begin" comments if (startsWith(line, "%%BeginPreview:")) { inDefaultsPreviewPrologSetup = true; } else if (line == "%%BeginDefaults") { inDefaultsPreviewPrologSetup = true; } else if (line == "%%BeginProlog") { inDefaultsPreviewPrologSetup = true; } else if (line == "%%BeginSetup") { inDefaultsPreviewPrologSetup = true; } else if (posPage == posEndEps && startsWith(line, "%%Page:")) { posPage = startPos; } else if (posPage != posEndEps && startsWith(line, "%%Page:")) { if (implicitPage) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Page at position " << startPos << " conflicts with implicit page at position: " << posPage << "\n"; #endif throw Error(write ? 21 : 14); } #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Unable to handle multiple PostScript pages. Found second page at position: " << startPos << "\n"; #endif throw Error(write ? 21 : 14); } else if (line == "%%BeginPageSetup") { inPageSetup = true; } else if (!inRemovableEmbedding && line == "%Exiv2BeginXMP: Before %%EndPageSetup") { inRemovableEmbedding = true; removableEmbeddings.push_back(std::make_pair(startPos, startPos)); removableEmbeddingEndLine = "%Exiv2EndXMP"; } else if (!inRemovableEmbedding && line == "%Exiv2BeginXMP: After %%PageTrailer") { inRemovableEmbedding = true; removableEmbeddings.push_back(std::make_pair(startPos, startPos)); removableEmbeddingEndLine = "%Exiv2EndXMP"; } else if (!inRemovableEmbedding && line == "%ADOBeginClientInjection: PageSetup End \"AI11EPS\"") { inRemovableEmbedding = true; removableEmbeddings.push_back(std::make_pair(startPos, startPos)); removableEmbeddingEndLine = "%ADOEndClientInjection: PageSetup End \"AI11EPS\""; } else if (!inRemovableEmbedding && line == "%ADOBeginClientInjection: PageTrailer Start \"AI11EPS\"") { inRemovableEmbedding = true; removableEmbeddings.push_back(std::make_pair(startPos, startPos)); removableEmbeddingEndLine = "%ADOEndClientInjection: PageTrailer Start \"AI11EPS\""; } else if (!inRemovableEmbedding && line == "%begin_xml_code") { inRemovableEmbedding = true; removableEmbeddings.push_back(std::make_pair(startPos, startPos)); removableEmbeddingEndLine = "%end_xml_code"; removableEmbeddingsWithUnmarkedTrailer++; } else { #ifdef DEBUG significantLine = false; #endif } #ifdef DEBUG if (significantLine) { EXV_DEBUG << "readWriteEpsMetadata: Found significant line \"" << line << "\" at position: " << startPos << "\n"; } #endif // implicit comments if (line == "%%EOF" || line == "%begin_xml_code" || !(line.size() >= 2 && line[0] == '%' && '\x21' <= line[1] && line[1] <= '\x7e')) { if (posEndComments == posEndEps) { posEndComments = startPos; #ifdef DEBUG EXV_DEBUG << "readWriteEpsMetadata: Found implicit EndComments at position: " << startPos << "\n"; #endif } } if (posPage == posEndEps && posEndComments != posEndEps && !inDefaultsPreviewPrologSetup && !inRemovableEmbedding && !onlyWhitespaces(line)) { posPage = startPos; implicitPage = true; posEndPageSetup = startPos; #ifdef DEBUG EXV_DEBUG << "readWriteEpsMetadata: Found implicit Page and EndPageSetup at position: " << startPos << "\n"; #endif } if (posEndPageSetup == posEndEps && posPage != posEndEps && !inPageSetup && !inRemovableEmbedding && line.size() >= 1 && line[0] != '%') { posEndPageSetup = startPos; #ifdef DEBUG EXV_DEBUG << "readWriteEpsMetadata: Found implicit EndPageSetup at position: " << startPos << "\n"; #endif } if (line.size() >= 1 && line[0] != '%') continue; // performance optimization if (line == "%%EOF" || line == "%%Trailer") { if (posPageTrailer == posEndEps) { posPageTrailer = startPos; implicitPageTrailer = true; #ifdef DEBUG EXV_DEBUG << "readWriteEpsMetadata: Found implicit PageTrailer at position: " << startPos << "\n"; #endif } } // remaining explicit comments if (posEndComments == posEndEps && posLanguageLevel == posEndEps && startsWith(line, "%%LanguageLevel:")) { posLanguageLevel = startPos; } else if (posEndComments == posEndEps && posContainsXmp == posEndEps && startsWith(line, "%ADO_ContainsXMP:")) { posContainsXmp = startPos; } else if (posEndComments == posEndEps && posPages == posEndEps && startsWith(line, "%%Pages:")) { posPages = startPos; } else if (posEndComments == posEndEps && posExiv2Version == posEndEps && startsWith(line, "%Exiv2Version:")) { posExiv2Version = startPos; } else if (posEndComments == posEndEps && posExiv2Website == posEndEps && startsWith(line, "%Exiv2Website:")) { posExiv2Website = startPos; } else if (posEndComments == posEndEps && startsWith(line, "%%Creator: Adobe Illustrator") && firstLine == "%!PS-Adobe-3.0 EPSF-3.0") { illustrator8 = true; } else if (posEndComments == posEndEps && startsWith(line, "%AI7_Thumbnail:")) { posAi7Thumbnail = startPos; } else if (posEndComments == posEndEps && posAi7Thumbnail != posEndEps && posAi7ThumbnailEndData == posEndEps && line == "%%EndData") { posAi7ThumbnailEndData = startPos; } else if (posEndComments == posEndEps && line == "%%EndComments") { posEndComments = startPos; } else if (inDefaultsPreviewPrologSetup && startsWith(line, "%%BeginResource: procset wCorel")) { corelDraw = true; } else if (line == "%%EndPreview") { inDefaultsPreviewPrologSetup = false; } else if (line == "%%EndDefaults") { inDefaultsPreviewPrologSetup = false; } else if (line == "%%EndProlog") { inDefaultsPreviewPrologSetup = false; } else if (line == "%%EndSetup") { inDefaultsPreviewPrologSetup = false; } else if (posEndPageSetup == posEndEps && line == "%%EndPageSetup") { inPageSetup = false; posEndPageSetup = startPos; } else if (posPageTrailer == posEndEps && line == "%%PageTrailer") { posPageTrailer = startPos; } else if (posBeginPhotoshop == posEndEps && startsWith(line, "%BeginPhotoshop:")) { posBeginPhotoshop = pos; } else if (posBeginPhotoshop != posEndEps && posEndPhotoshop == posEndEps && line == "%EndPhotoshop") { posEndPhotoshop = startPos; } else if (inRemovableEmbedding && line == removableEmbeddingEndLine) { inRemovableEmbedding = false; removableEmbeddings.back().second = pos; } else if (line == "%%EOF") { posEof = startPos; } else { #ifdef DEBUG significantLine = false; #endif } #ifdef DEBUG if (significantLine) { EXV_DEBUG << "readWriteEpsMetadata: Found significant line \"" << line << "\" at position: " << startPos << "\n"; } #endif } // check for unfinished nested documents if (depth != 0) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Unmatched BeginDocument (" << depth << "x)\n"; #endif throw Error(write ? 21 : 14); } // look for the unmarked trailers of some removable XMP embeddings size_t posXmpTrailerEnd = posEof; for (size_t i = 0; i < removableEmbeddingsWithUnmarkedTrailer; i++) { std::string line1; const size_t posLine1 = readPrevLine(line1, data, posXmpTrailerEnd, posEndEps); std::string line2; const size_t posLine2 = readPrevLine(line2, data, posLine1, posEndEps); size_t posXmpTrailer; if (line1 == "[/EMC pdfmark") { // Exiftool style posXmpTrailer = posLine1; } else if (line1 == "[/NamespacePop pdfmark" && line2 == "[{nextImage} 1 dict begin /Metadata {photoshop_metadata_stream} def currentdict end /PUT pdfmark") { // Photoshop style posXmpTrailer = posLine2; } else { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Unable to find XMP embedding trailer ending at position: " << posXmpTrailerEnd << "\n"; #endif if (write) throw Error(21); break; } removableEmbeddings.push_back(std::make_pair(posXmpTrailer, posXmpTrailerEnd)); #ifdef DEBUG EXV_DEBUG << "readWriteEpsMetadata: Recognized unmarked trailer of removable XMP embedding at " "[" << removableEmbeddings.back().first << "," << removableEmbeddings.back().second << ")" "\n"; #endif posXmpTrailerEnd = posXmpTrailer; } // interpret comment "%ADO_ContainsXMP:" std::string line; readLine(line, data, posContainsXmp, posEndEps); bool containsXmp; if (line == "%ADO_ContainsXMP: MainFirst" || line == "%ADO_ContainsXMP:MainFirst") { containsXmp = true; } else if (line == "" || line == "%ADO_ContainsXMP: NoMain" || line == "%ADO_ContainsXMP:NoMain") { containsXmp = false; } else { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Invalid line \"" << line << "\" at position: " << posContainsXmp << "\n"; #endif throw Error(write ? 21 : 14); } const bool deleteXmp = (write && xmpPacket.size() == 0); bool fixBeginXmlPacket = false; bool useFlexibleEmbedding = false; size_t xmpPos = posEndEps; size_t xmpSize = 0; if (containsXmp) { // search for XMP metadata findXmp(xmpPos, xmpSize, data, posEps, posEndEps, write); if (xmpPos == posEndEps) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Unable to find XMP metadata as announced at position: " << posContainsXmp << "\n"; #endif } // check embedding of XMP metadata const size_t posLineAfterXmp = readLine(line, data, xmpPos + xmpSize, posEndEps); if (line != "") { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Unexpected " << line.size() << " bytes of data after XMP at position: " << (xmpPos + xmpSize) << "\n"; #endif } else if (!deleteXmp) { readLine(line, data, posLineAfterXmp, posEndEps); if (line == "% &&end XMP packet marker&&" || line == "% &&end XMP packet marker&&") { useFlexibleEmbedding = true; } } } if (useFlexibleEmbedding) { #ifdef DEBUG EXV_DEBUG << "readWriteEpsMetadata: Using flexible XMP embedding\n"; #endif const size_t posBeginXmlPacket = readPrevLine(line, data, xmpPos, posEndEps); if (startsWith(line, "%begin_xml_packet:")) { #ifdef DEBUG EXV_DEBUG << "readWriteEpsMetadata: XMP embedding contains %begin_xml_packet\n"; #endif if (write) { fixBeginXmlPacket = true; xmpSize += (xmpPos - posBeginXmlPacket); xmpPos = posBeginXmlPacket; } } else if (posBeginPhotoshop != posEndEps) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Missing %begin_xml_packet in Photoshop EPS at position: " << xmpPos << "\n"; #endif if (write) throw Error(21); } } if (!useFlexibleEmbedding) { // check if there are irremovable XMP metadata blocks before EndPageSetup size_t posOtherXmp = containsXmp ? xmpPos : posEps; size_t sizeOtherXmp = 0; for (;;) { findXmp(posOtherXmp, sizeOtherXmp, data, posOtherXmp + sizeOtherXmp, posEndPageSetup, write); if (posOtherXmp >= posEndPageSetup) break; bool isRemovableEmbedding = false; for (std::vector >::const_iterator e = removableEmbeddings.begin(); e != removableEmbeddings.end(); e++) { if (e->first <= posOtherXmp && posOtherXmp < e->second) { isRemovableEmbedding = true; break; } } if (!isRemovableEmbedding) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "XMP metadata block is not removable at position: " << posOtherXmp << "\n"; #endif if (write) throw Error(21); break; } } } if (!write) { // copy XMP metadata xmpPacket.assign(reinterpret_cast(data + xmpPos), xmpSize); // native previews nativePreviews.clear(); if (posAi7ThumbnailEndData != posEndEps) { NativePreview nativePreview; std::string dummy; std::string lineAi7Thumbnail; const size_t posBeginData = readLine(lineAi7Thumbnail, data, posAi7Thumbnail, posEndEps); std::istringstream lineStreamAi7Thumbnail(lineAi7Thumbnail); lineStreamAi7Thumbnail >> dummy; lineStreamAi7Thumbnail >> nativePreview.width_; lineStreamAi7Thumbnail >> nativePreview.height_; std::string depth; lineStreamAi7Thumbnail >> depth; std::string lineBeginData; const size_t posAfterBeginData = readLine(lineBeginData, data, posBeginData, posEndEps); std::istringstream lineStreamBeginData(lineBeginData); std::string beginData; lineStreamBeginData >> beginData; lineStreamBeginData >> dummy; std::string type; lineStreamBeginData >> type; nativePreview.position_ = static_cast(posAfterBeginData); nativePreview.size_ = static_cast(posAi7ThumbnailEndData - posAfterBeginData); nativePreview.filter_ = "hex-ai7thumbnail-pnm"; nativePreview.mimeType_ = "image/x-portable-anymap"; if (depth != "8") { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Unable to handle Illustrator thumbnail depth: " << depth << "\n"; #endif } else if (beginData != "%%BeginData:") { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Unable to handle Illustrator thumbnail data section: " << lineBeginData << "\n"; #endif } else if (type != "Hex") { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Unable to handle Illustrator thumbnail data type: " << type << "\n"; #endif } else { nativePreviews.push_back(nativePreview); } } if (posEndPhotoshop != posEndEps) { NativePreview nativePreview; nativePreview.position_ = static_cast(posBeginPhotoshop); nativePreview.size_ = static_cast(posEndPhotoshop - posBeginPhotoshop); nativePreview.width_ = 0; nativePreview.height_ = 0; nativePreview.filter_ = "hex-irb"; nativePreview.mimeType_ = "image/jpeg"; nativePreviews.push_back(nativePreview); } if (sizeWmf != 0) { NativePreview nativePreview; nativePreview.position_ = static_cast(posWmf); nativePreview.size_ = sizeWmf; nativePreview.width_ = 0; nativePreview.height_ = 0; nativePreview.filter_ = ""; nativePreview.mimeType_ = "image/x-wmf"; nativePreviews.push_back(nativePreview); } if (sizeTiff != 0) { NativePreview nativePreview; nativePreview.position_ = static_cast(posTiff); nativePreview.size_ = sizeTiff; nativePreview.width_ = 0; nativePreview.height_ = 0; nativePreview.filter_ = ""; nativePreview.mimeType_ = "image/tiff"; nativePreviews.push_back(nativePreview); } } else { // check for Adobe Illustrator 8.0 or older if (illustrator8) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Unable to write to EPS files created by Adobe Illustrator 8.0 or older.\n"; #endif throw Error(21); } // create temporary output file BasicIo::AutoPtr tempIo(io.temporary()); assert (tempIo.get() != 0); if (!tempIo->isopen()) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Unable to create temporary file for writing.\n"; #endif throw Error(21); } #ifdef DEBUG EXV_DEBUG << "readWriteEpsMetadata: Created temporary file " << tempIo->path() << "\n"; #endif // sort all positions std::vector positions; positions.push_back(posLanguageLevel); positions.push_back(posContainsXmp); positions.push_back(posPages); positions.push_back(posExiv2Version); positions.push_back(posExiv2Website); positions.push_back(posEndComments); positions.push_back(posPage); positions.push_back(posEndPageSetup); positions.push_back(posPageTrailer); positions.push_back(posEof); positions.push_back(posEndEps); if (useFlexibleEmbedding) { positions.push_back(xmpPos); } for (std::vector >::const_iterator e = removableEmbeddings.begin(); e != removableEmbeddings.end(); e++) { positions.push_back(e->first); } std::sort(positions.begin(), positions.end()); // assemble result EPS document if (dosEps) { // DOS EPS header will be written afterwards writeTemp(*tempIo, std::string(30, '\x00')); } const std::string containsXmpLine = deleteXmp ? "%ADO_ContainsXMP: NoMain" : "%ADO_ContainsXMP: MainFirst"; const uint32_t posEpsNew = posTemp(*tempIo); size_t prevPos = posEps; size_t prevSkipPos = prevPos; for (std::vector::const_iterator i = positions.begin(); i != positions.end(); i++) { const size_t pos = *i; if (pos == prevPos) continue; if (pos < prevSkipPos) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Internal error while assembling the result EPS document: " "Unable to continue at position " << pos << " after skipping to position " << prevSkipPos << "\n"; #endif throw Error(21); } writeTemp(*tempIo, data + prevSkipPos, pos - prevSkipPos); const size_t posLineEnd = readLine(line, data, pos, posEndEps); size_t skipPos = pos; // add last line ending if necessary if (pos == posEndEps && pos >= 1 && data[pos - 1] != '\r' && data[pos - 1] != '\n') { writeTemp(*tempIo, lineEnding); #ifdef DEBUG EXV_DEBUG << "readWriteEpsMetadata: Added missing line ending of last line\n"; #endif } // update and complement DSC comments if (pos == posLanguageLevel && posLanguageLevel != posEndEps && !deleteXmp && !useFlexibleEmbedding) { if (line == "%%LanguageLevel:1" || line == "%%LanguageLevel: 1") { writeTemp(*tempIo, "%%LanguageLevel: 2" + lineEnding); skipPos = posLineEnd; } } if (pos == posContainsXmp && posContainsXmp != posEndEps) { if (line != containsXmpLine) { writeTemp(*tempIo, containsXmpLine + lineEnding); skipPos = posLineEnd; } } if (pos == posExiv2Version && posExiv2Version != posEndEps) { writeTemp(*tempIo, "%Exiv2Version: " + versionNumberHexString() + lineEnding); skipPos = posLineEnd; } if (pos == posExiv2Website && posExiv2Website != posEndEps) { writeTemp(*tempIo, "%Exiv2Website: http://www.exiv2.org/" + lineEnding); skipPos = posLineEnd; } if (pos == posEndComments) { if (posLanguageLevel == posEndEps && !deleteXmp && !useFlexibleEmbedding) { writeTemp(*tempIo, "%%LanguageLevel: 2" + lineEnding); } if (posContainsXmp == posEndEps) { writeTemp(*tempIo, containsXmpLine + lineEnding); } if (posPages == posEndEps) { writeTemp(*tempIo, "%%Pages: 1" + lineEnding); } if (posExiv2Version == posEndEps) { writeTemp(*tempIo, "%Exiv2Version: " + versionNumberHexString() + lineEnding); } if (posExiv2Website == posEndEps) { writeTemp(*tempIo, "%Exiv2Website: http://www.exiv2.org/" + lineEnding); } readLine(line, data, posEndComments, posEndEps); if (line != "%%EndComments") { writeTemp(*tempIo, "%%EndComments" + lineEnding); } } if (pos == posPage) { if (!startsWith(line, "%%Page:")) { writeTemp(*tempIo, "%%Page: 1 1" + lineEnding); writeTemp(*tempIo, "%%EndPageComments" + lineEnding); } } if (useFlexibleEmbedding) { // insert XMP metadata into existing flexible embedding if (pos == xmpPos) { if (fixBeginXmlPacket) { writeTemp(*tempIo, "%begin_xml_packet: " + toString(xmpPacket.size()) + lineEnding); } writeTemp(*tempIo, xmpPacket); skipPos += xmpSize; } } else { // remove preceding embedding(s) for (std::vector >::const_iterator e = removableEmbeddings.begin(); e != removableEmbeddings.end(); e++) { if (pos == e->first) { skipPos = e->second; break; } } // insert XMP metadata with new flexible embedding, if necessary if (pos == posEndPageSetup && !deleteXmp) { if (line != "%%EndPageSetup") { writeTemp(*tempIo, "%%BeginPageSetup" + lineEnding); } writeTemp(*tempIo, "%Exiv2BeginXMP: Before %%EndPageSetup" + lineEnding); if (corelDraw) { writeTemp(*tempIo, "%Exiv2Notice: The following line is needed by CorelDRAW." + lineEnding); writeTemp(*tempIo, "@rs" + lineEnding); } if (posBeginPhotoshop != posEndEps) { writeTemp(*tempIo, "%Exiv2Notice: The following line is needed by Photoshop." + lineEnding); writeTemp(*tempIo, "%begin_xml_code" + lineEnding); } writeTemp(*tempIo, "/currentdistillerparams where" + lineEnding); writeTemp(*tempIo, "{pop currentdistillerparams /CoreDistVersion get 5000 lt} {true} ifelse" + lineEnding); writeTemp(*tempIo, "{userdict /Exiv2_pdfmark /cleartomark load put" + lineEnding); writeTemp(*tempIo, " userdict /Exiv2_metafile_pdfmark {flushfile cleartomark} bind put}" + lineEnding); writeTemp(*tempIo, "{userdict /Exiv2_pdfmark /pdfmark load put" + lineEnding); writeTemp(*tempIo, " userdict /Exiv2_metafile_pdfmark {/PUT pdfmark} bind put} ifelse" + lineEnding); writeTemp(*tempIo, "[/NamespacePush Exiv2_pdfmark" + lineEnding); writeTemp(*tempIo, "[/_objdef {Exiv2_metadata_stream} /type /stream /OBJ Exiv2_pdfmark" + lineEnding); writeTemp(*tempIo, "[{Exiv2_metadata_stream} 2 dict begin" + lineEnding); writeTemp(*tempIo, " /Type /Metadata def /Subtype /XML def currentdict end /PUT Exiv2_pdfmark" + lineEnding); writeTemp(*tempIo, "[{Exiv2_metadata_stream}" + lineEnding); writeTemp(*tempIo, " currentfile 0 (% &&end XMP packet marker&&)" + lineEnding); writeTemp(*tempIo, " /SubFileDecode filter Exiv2_metafile_pdfmark" + lineEnding); if (posBeginPhotoshop != posEndEps) { writeTemp(*tempIo, "%Exiv2Notice: The following line is needed by Photoshop. " "Parameter must be exact size of XMP metadata." + lineEnding); writeTemp(*tempIo, "%begin_xml_packet: " + toString(xmpPacket.size()) + lineEnding); } writeTemp(*tempIo, xmpPacket); writeTemp(*tempIo, lineEnding); writeTemp(*tempIo, "% &&end XMP packet marker&&" + lineEnding); writeTemp(*tempIo, "[/Document 1 dict begin" + lineEnding); writeTemp(*tempIo, " /Metadata {Exiv2_metadata_stream} def currentdict end /BDC Exiv2_pdfmark" + lineEnding); if (posBeginPhotoshop != posEndEps) { writeTemp(*tempIo, "%Exiv2Notice: The following line is needed by Photoshop." + lineEnding); writeTemp(*tempIo, "%end_xml_code" + lineEnding); } if (corelDraw) { writeTemp(*tempIo, "%Exiv2Notice: The following line is needed by CorelDRAW." + lineEnding); writeTemp(*tempIo, "@sv" + lineEnding); } writeTemp(*tempIo, "%Exiv2EndXMP" + lineEnding); if (line != "%%EndPageSetup") { writeTemp(*tempIo, "%%EndPageSetup" + lineEnding); } } if (pos == posPageTrailer && !deleteXmp) { if (!implicitPageTrailer) { skipPos = posLineEnd; } writeTemp(*tempIo, "%%PageTrailer" + lineEnding); writeTemp(*tempIo, "%Exiv2BeginXMP: After %%PageTrailer" + lineEnding); writeTemp(*tempIo, "[/EMC Exiv2_pdfmark" + lineEnding); writeTemp(*tempIo, "[/NamespacePop Exiv2_pdfmark" + lineEnding); writeTemp(*tempIo, "%Exiv2EndXMP" + lineEnding); } } // add EOF comment if necessary if (pos == posEndEps && posEof == posEndEps) { writeTemp(*tempIo, "%%EOF" + lineEnding); } prevPos = pos; prevSkipPos = skipPos; } const uint32_t posEndEpsNew = posTemp(*tempIo); #ifdef DEBUG EXV_DEBUG << "readWriteEpsMetadata: New EPS size: " << (posEndEpsNew - posEpsNew) << "\n"; #endif if (dosEps) { // write WMF and/or TIFF section if present writeTemp(*tempIo, data + posWmf, sizeWmf); writeTemp(*tempIo, data + posTiff, sizeTiff); #ifdef DEBUG EXV_DEBUG << "readWriteEpsMetadata: New DOS EPS total size: " << posTemp(*tempIo) << "\n"; #endif // write DOS EPS header if (tempIo->seek(0, BasicIo::beg) != 0) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Internal error while seeking in temporary file.\n"; #endif throw Error(21); } byte dosEpsHeader[30]; dosEpsSignature.copy(reinterpret_cast(dosEpsHeader), dosEpsSignature.size()); ul2Data(dosEpsHeader + 4, posEpsNew, littleEndian); ul2Data(dosEpsHeader + 8, posEndEpsNew - posEpsNew, littleEndian); ul2Data(dosEpsHeader + 12, sizeWmf == 0 ? 0 : posEndEpsNew, littleEndian); ul2Data(dosEpsHeader + 16, sizeWmf, littleEndian); ul2Data(dosEpsHeader + 20, sizeTiff == 0 ? 0 : posEndEpsNew + sizeWmf, littleEndian); ul2Data(dosEpsHeader + 24, sizeTiff, littleEndian); us2Data(dosEpsHeader + 28, 0xFFFF, littleEndian); writeTemp(*tempIo, dosEpsHeader, sizeof(dosEpsHeader)); } // copy temporary file to real output file io.close(); io.transfer(*tempIo); } } } // namespace // ***************************************************************************** // class member definitions namespace Exiv2 { EpsImage::EpsImage(BasicIo::AutoPtr io, bool create) : Image(ImageType::eps, mdXmp, io) { //LogMsg::setLevel(LogMsg::debug); if (create) { if (io_->open() == 0) { #ifdef DEBUG EXV_DEBUG << "Exiv2::EpsImage:: Creating blank EPS image\n"; #endif IoCloser closer(*io_); if (io_->write(reinterpret_cast(epsBlank.data()), static_cast(epsBlank.size())) != static_cast(epsBlank.size())) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Failed to write blank EPS image.\n"; #endif throw Error(21); } } } } std::string EpsImage::mimeType() const { return "application/postscript"; } void EpsImage::setComment(const std::string& /*comment*/) { throw Error(32, "Image comment", "EPS"); } void EpsImage::readMetadata() { #ifdef DEBUG EXV_DEBUG << "Exiv2::EpsImage::readMetadata: Reading EPS file " << io_->path() << "\n"; #endif // read metadata readWriteEpsMetadata(*io_, xmpPacket_, nativePreviews_, /* write = */ false); // decode XMP metadata if (xmpPacket_.size() > 0 && XmpParser::decode(xmpData_, xmpPacket_) > 1) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Failed to decode XMP metadata.\n"; #endif throw Error(14); } #ifdef DEBUG EXV_DEBUG << "Exiv2::EpsImage::readMetadata: Finished reading EPS file " << io_->path() << "\n"; #endif } void EpsImage::writeMetadata() { #ifdef DEBUG EXV_DEBUG << "Exiv2::EpsImage::writeMetadata: Writing EPS file " << io_->path() << "\n"; #endif // encode XMP metadata if necessary if (!writeXmpFromPacket() && XmpParser::encode(xmpPacket_, xmpData_) > 1) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Failed to encode XMP metadata.\n"; #endif throw Error(21); } // write metadata readWriteEpsMetadata(*io_, xmpPacket_, nativePreviews_, /* write = */ true); #ifdef DEBUG EXV_DEBUG << "Exiv2::EpsImage::writeMetadata: Finished writing EPS file " << io_->path() << "\n"; #endif } // ************************************************************************* // free functions Image::AutoPtr newEpsInstance(BasicIo::AutoPtr io, bool create) { Image::AutoPtr image(new EpsImage(io, create)); if (!image->good()) { image.reset(); } return image; } bool isEpsType(BasicIo& iIo, bool advance) { // read as many bytes as needed for the longest (DOS) EPS signature long bufSize = static_cast(dosEpsSignature.size()); for (size_t i = 0; i < (sizeof epsFirstLine) / (sizeof *epsFirstLine); i++) { if (bufSize < static_cast(epsFirstLine[i].size())) { bufSize = static_cast(epsFirstLine[i].size()); } } DataBuf buf = iIo.read(bufSize); if (iIo.error() || buf.size_ != bufSize) { return false; } // check for all possible (DOS) EPS signatures bool matched = (memcmp(buf.pData_, dosEpsSignature.data(), dosEpsSignature.size()) == 0); for (size_t i = 0; !matched && i < (sizeof epsFirstLine) / (sizeof *epsFirstLine); i++) { matched = (memcmp(buf.pData_, epsFirstLine[i].data(), epsFirstLine[i].size()) == 0); } // seek back if possible and requested if (!advance || !matched) { iIo.seek(-buf.size_, BasicIo::cur); } return matched; } } // namespace Exiv2 exiv2-0.23/src/xmpsidecar.cpp0000644000175000017500000001571611732641407015760 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /* File: xmpsidecar.cpp Version: $Rev: 2681 $ Author(s): Andreas Huggel (ahu) History: 07-Mar-08, ahu: created Credits: See header file */ // ***************************************************************************** #include "rcsid_int.hpp" EXIV2_RCSID("@(#) $Id: xmpsidecar.cpp 2681 2012-03-22 15:19:35Z ahuggel $") // ***************************************************************************** // included header files #ifdef _MSC_VER # include "exv_msvc.h" #else # include "exv_conf.h" #endif #include "xmpsidecar.hpp" #include "image.hpp" #include "basicio.hpp" #include "error.hpp" #include "xmp.hpp" #include "futils.hpp" #include "convert.hpp" // + standard includes #include #include #include // ***************************************************************************** namespace { const char* xmlHeader = "\n"; const long xmlHdrCnt = 39; // without the trailing 0-character } // class member definitions namespace Exiv2 { XmpSidecar::XmpSidecar(BasicIo::AutoPtr io, bool create) : Image(ImageType::xmp, mdXmp, io) { if (create) { if (io_->open() == 0) { IoCloser closer(*io_); io_->write(reinterpret_cast(xmlHeader), xmlHdrCnt); } } } // XmpSidecar::XmpSidecar std::string XmpSidecar::mimeType() const { return "application/rdf+xml"; } void XmpSidecar::setComment(const std::string& /*comment*/) { // not supported throw(Error(32, "Image comment", "XMP")); } void XmpSidecar::readMetadata() { #ifdef DEBUG std::cerr << "Reading XMP file " << io_->path() << "\n"; #endif if (io_->open() != 0) { throw Error(9, io_->path(), strError()); } IoCloser closer(*io_); // Ensure that this is the correct image type if (!isXmpType(*io_, false)) { if (io_->error() || io_->eof()) throw Error(14); throw Error(3, "XMP"); } // Read the XMP packet from the IO stream std::string xmpPacket; const long len = 64 * 1024; byte buf[len]; long l; while ((l = io_->read(buf, len)) > 0) { xmpPacket.append(reinterpret_cast(buf), l); } if (io_->error()) throw Error(14); clearMetadata(); xmpPacket_ = xmpPacket; if (xmpPacket_.size() > 0 && XmpParser::decode(xmpData_, xmpPacket_)) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Failed to decode XMP metadata.\n"; #endif } copyXmpToIptc(xmpData_, iptcData_); copyXmpToExif(xmpData_, exifData_); } // XmpSidecar::readMetadata void XmpSidecar::writeMetadata() { if (io_->open() != 0) { throw Error(9, io_->path(), strError()); } IoCloser closer(*io_); if (writeXmpFromPacket() == false) { copyExifToXmp(exifData_, xmpData_); copyIptcToXmp(iptcData_, xmpData_); if (XmpParser::encode(xmpPacket_, xmpData_, XmpParser::omitPacketWrapper|XmpParser::useCompactFormat) > 1) { #ifndef SUPPRESS_WARNINGS EXV_ERROR << "Failed to encode XMP metadata.\n"; #endif } } if (xmpPacket_.size() > 0) { if (xmpPacket_.substr(0, 5) != "temporary()); // may throw assert(tempIo.get() != 0); // Write XMP packet if ( tempIo->write(reinterpret_cast(xmpPacket_.data()), static_cast(xmpPacket_.size())) != static_cast(xmpPacket_.size())) throw Error(21); if (tempIo->error()) throw Error(21); io_->close(); io_->transfer(*tempIo); // may throw } } // XmpSidecar::writeMetadata // ************************************************************************* // free functions Image::AutoPtr newXmpInstance(BasicIo::AutoPtr io, bool create) { Image::AutoPtr image(new XmpSidecar(io, create)); if (!image->good()) { image.reset(); } return image; } bool isXmpType(BasicIo& iIo, bool advance) { /* Check if the file starts with an optional XML declaration followed by either an XMP header () or an element. In addition, in order for empty XmpSidecar objects as created by Exiv2 to pass the test, just an XML header is also considered ok. */ const int32_t len = 80; byte buf[len]; iIo.read(buf, xmlHdrCnt + 1); if ( iIo.eof() && 0 == strncmp(reinterpret_cast(buf), xmlHeader, xmlHdrCnt)) { return true; } if (iIo.error() || iIo.eof()) { return false; } iIo.read(buf + xmlHdrCnt + 1, len - xmlHdrCnt - 1); if (iIo.error() || iIo.eof()) { return false; } // Skip leading BOM int32_t start = 0; if (0 == strncmp(reinterpret_cast(buf), "\xef\xbb\xbf", 3)) { start = 3; } bool rc = false; std::string head(reinterpret_cast(buf + start), len - start); if (head.substr(0, 5) == " 9 && ( head.substr(0, 9) == " * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! @file iptc.hpp @brief Encoding and decoding of IPTC data @version $Rev: 2681 $ @author Brad Schick (brad) brad@robotbattle.com @date 31-Jul-04, brad: created */ #ifndef IPTC_HPP_ #define IPTC_HPP_ // ***************************************************************************** // included header files #include "metadatum.hpp" #include "types.hpp" #include "error.hpp" #include "value.hpp" #include "datasets.hpp" // + standard includes #include #include // ***************************************************************************** // namespace extensions namespace Exiv2 { // ***************************************************************************** // class declarations class ExifData; // ***************************************************************************** // class definitions /*! @brief An IPTC metadatum ("dataset"), consisting of an IptcKey and a Value and methods to manipulate these. */ class EXIV2API Iptcdatum : public Metadatum { public: //! @name Creators //@{ /*! @brief Constructor for new tags created by an application. The %Iptcdatum is created from a key / value pair. %Iptcdatum copies (clones) the value if one is provided. Alternatively, a program can create an 'empty' %Iptcdatum with only a key and set the value using setValue(). @param key The key of the %Iptcdatum. @param pValue Pointer to a %Iptcdatum value. @throw Error if the key cannot be parsed and converted to a tag number and record id. */ explicit Iptcdatum(const IptcKey& key, const Value* pValue =0); //! Copy constructor Iptcdatum(const Iptcdatum& rhs); //! Destructor virtual ~Iptcdatum(); //@} //! @name Manipulators //@{ //! Assignment operator Iptcdatum& operator=(const Iptcdatum& rhs); /*! @brief Assign \em value to the %Iptcdatum. The type of the new Value is set to UShortValue. */ Iptcdatum& operator=(const uint16_t& value); /*! @brief Assign \em value to the %Iptcdatum. Calls setValue(const std::string&). */ Iptcdatum& operator=(const std::string& value); /*! @brief Assign \em value to the %Iptcdatum. Calls setValue(const Value*). */ Iptcdatum& operator=(const Value& value); void setValue(const Value* pValue); /*! @brief Set the value to the string \em value, using Value::read(const std::string&). If the %Iptcdatum does not have a Value yet, then a %Value of the correct type for this %Iptcdatum is created. If that fails (because of an unknown dataset), a StringValue is created. Return 0 if the value was read successfully. */ int setValue(const std::string& value); //@} //! @name Accessors //@{ long copy(byte* buf, ByteOrder byteOrder) const; std::ostream& write(std::ostream& os, const ExifData* pMetadata =0) const; /*! @brief Return the key of the Iptcdatum. The key is of the form 'Iptc.recordName.datasetName'. Note however that the key is not necessarily unique, i.e., an IptcData object may contain multiple metadata with the same key. */ std::string key() const; /*! @brief Return the name of the record (deprecated) @return record name */ std::string recordName() const; /*! @brief Return the record id @return record id */ uint16_t record() const; const char* familyName() const; std::string groupName() const; /*! @brief Return the name of the tag (aka dataset) @return tag name */ std::string tagName() const; std::string tagLabel() const; //! Return the tag (aka dataset) number uint16_t tag() const; TypeId typeId() const; const char* typeName() const; long typeSize() const; long count() const; long size() const; std::string toString() const; std::string toString(long n) const; long toLong(long n =0) const; float toFloat(long n =0) const; Rational toRational(long n =0) const; Value::AutoPtr getValue() const; const Value& value() const; //@} private: // DATA IptcKey::AutoPtr key_; //!< Key Value::AutoPtr value_; //!< Value }; // class Iptcdatum //! Container type to hold all metadata typedef std::vector IptcMetadata; /*! @brief A container for IPTC data. This is a top-level class of the %Exiv2 library. Provide high-level access to the IPTC data of an image: - read IPTC information from JPEG files - access metadata through keys and standard C++ iterators - add, modify and delete metadata - write IPTC data to JPEG files - extract IPTC metadata to files, insert from these files */ class EXIV2API IptcData { public: //! IptcMetadata iterator type typedef IptcMetadata::iterator iterator; //! IptcMetadata const iterator type typedef IptcMetadata::const_iterator const_iterator; // Use the compiler generated constructors and assignment operator //! @name Manipulators //@{ /*! @brief Returns a reference to the %Iptcdatum that is associated with a particular \em key. If %IptcData does not already contain such an %Iptcdatum, operator[] adds object \em Iptcdatum(key). @note Since operator[] might insert a new element, it can't be a const member function. */ Iptcdatum& operator[](const std::string& key); /*! @brief Add an %Iptcdatum from the supplied key and value pair. This method copies (clones) the value. A check for non-repeatable datasets is performed. @return 0 if successful;
6 if the dataset already exists and is not repeatable */ int add(const IptcKey& key, Value* value); /*! @brief Add a copy of the Iptcdatum to the IPTC metadata. A check for non-repeatable datasets is performed. @return 0 if successful;
6 if the dataset already exists and is not repeatable;
*/ int add(const Iptcdatum& iptcdatum); /*! @brief Delete the Iptcdatum at iterator position pos, return the position of the next Iptcdatum. Note that iterators into the metadata, including pos, are potentially invalidated by this call. */ iterator erase(iterator pos); /*! @brief Delete all Iptcdatum instances resulting in an empty container. */ void clear() { iptcMetadata_.clear(); } //! Sort metadata by key void sortByKey(); //! Sort metadata by tag (aka dataset) void sortByTag(); //! Begin of the metadata iterator begin() { return iptcMetadata_.begin(); } //! End of the metadata iterator end() { return iptcMetadata_.end(); } /*! @brief Find the first Iptcdatum with the given key, return an iterator to it. */ iterator findKey(const IptcKey& key); /*! @brief Find the first Iptcdatum with the given record and dataset it, return a const iterator to it. */ iterator findId(uint16_t dataset, uint16_t record = IptcDataSets::application2); //@} //! @name Accessors //@{ //! Begin of the metadata const_iterator begin() const { return iptcMetadata_.begin(); } //! End of the metadata const_iterator end() const { return iptcMetadata_.end(); } /*! @brief Find the first Iptcdatum with the given key, return a const iterator to it. */ const_iterator findKey(const IptcKey& key) const; /*! @brief Find the first Iptcdatum with the given record and dataset number, return a const iterator to it. */ const_iterator findId(uint16_t dataset, uint16_t record = IptcDataSets::application2) const; //! Return true if there is no IPTC metadata bool empty() const { return count() == 0; } //! Get the number of metadata entries long count() const { return static_cast(iptcMetadata_.size()); } /*! @brief Return the exact size of all contained IPTC metadata */ long size() const; /*! @brief Return the metadata charset name or 0 */ const char *detectCharset() const; //@} private: // DATA IptcMetadata iptcMetadata_; }; // class IptcData /*! @brief Stateless parser class for IPTC data. Images use this class to decode and encode binary IPTC data. */ class EXIV2API IptcParser { public: /*! @brief Decode binary IPTC data in IPTC IIM4 format from a buffer \em pData of length \em size to the provided metadata container. @param iptcData Metadata container to add the decoded IPTC datasets to. @param pData Pointer to the data buffer to read from. @param size Number of bytes in the data buffer. @return 0 if successful;
5 if the binary IPTC data is invalid or corrupt */ static int decode( IptcData& iptcData, const byte* pData, uint32_t size ); /*! @brief Encode the IPTC datasets from \em iptcData to a binary representation in IPTC IIM4 format. Convert the IPTC datasets to binary format and return it. Caller owns the returned buffer. The copied data follows the IPTC IIM4 standard. @return Data buffer containing the binary IPTC data in IPTC IIM4 format. */ static DataBuf encode( const IptcData& iptcData ); private: // Constant data static const byte marker_; // Dataset marker }; // class IptcParser } // namespace Exiv2 #endif // #ifndef IPTC_HPP_ exiv2-0.23/src/gifimage.cpp0000644000175000017500000001037711732641407015367 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /* File: gifimage.cpp Version: $Rev: 2681 $ Author(s): Marco Piovanelli, Ovolab (marco) History: 26-Feb-2007, marco: created */ // ***************************************************************************** #include "rcsid_int.hpp" EXIV2_RCSID("@(#) $Id: gifimage.cpp 2681 2012-03-22 15:19:35Z ahuggel $") //#define DEBUG 1 // ***************************************************************************** // included header files #ifdef _MSC_VER # include "exv_msvc.h" #else # include "exv_conf.h" #endif #include "gifimage.hpp" #include "image.hpp" #include "basicio.hpp" #include "error.hpp" #include "futils.hpp" // + standard includes #include #include #include // ***************************************************************************** // class member definitions namespace Exiv2 { GifImage::GifImage(BasicIo::AutoPtr io) : Image(ImageType::gif, mdNone, io) { } // GifImage::GifImage std::string GifImage::mimeType() const { return "image/gif"; } void GifImage::setExifData(const ExifData& /*exifData*/) { // Todo: implement me! throw(Error(32, "Exif metadata", "GIF")); } void GifImage::setIptcData(const IptcData& /*iptcData*/) { // Todo: implement me! throw(Error(32, "IPTC metadata", "GIF")); } void GifImage::setComment(const std::string& /*comment*/) { // not supported throw(Error(32, "Image comment", "GIF")); } void GifImage::readMetadata() { #ifdef DEBUG std::cerr << "Exiv2::GifImage::readMetadata: Reading GIF file " << io_->path() << "\n"; #endif if (io_->open() != 0) { throw Error(9, io_->path(), strError()); } IoCloser closer(*io_); // Ensure that this is the correct image type if (!isGifType(*io_, true)) { if (io_->error() || io_->eof()) throw Error(14); throw Error(3, "GIF"); } clearMetadata(); byte buf[4]; if (io_->read(buf, sizeof(buf)) == sizeof(buf)) { pixelWidth_ = getShort(buf, littleEndian); pixelHeight_ = getShort(buf + 2, littleEndian); } } // GifImage::readMetadata void GifImage::writeMetadata() { // Todo: implement me! throw(Error(31, "GIF")); } // GifImage::writeMetadata // ************************************************************************* // free functions Image::AutoPtr newGifInstance(BasicIo::AutoPtr io, bool /*create*/) { Image::AutoPtr image(new GifImage(io)); if (!image->good()) { image.reset(); } return image; } bool isGifType(BasicIo& iIo, bool advance) { const int32_t len = 6; const unsigned char Gif87aId[8] = { 'G', 'I', 'F', '8', '7', 'a' }; const unsigned char Gif89aId[8] = { 'G', 'I', 'F', '8', '9', 'a' }; byte buf[len]; iIo.read(buf, len); if (iIo.error() || iIo.eof()) { return false; } bool matched = (memcmp(buf, Gif87aId, len) == 0) || (memcmp(buf, Gif89aId, len) == 0); if (!advance || !matched) { iIo.seek(-len, BasicIo::cur); } return matched; } } // namespace Exiv2 exiv2-0.23/src/tiffimage_int.hpp0000644000175000017500000004541211732641407016427 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! @file tiffimage_int.hpp @brief Internal class TiffParserWorker to parse TIFF data. @version $Rev: 2681 $ @author Andreas Huggel (ahu) ahuggel@gmx.net @date 23-Apr-08, ahu: created */ #ifndef TIFFIMAGE_INT_HPP_ #define TIFFIMAGE_INT_HPP_ // ***************************************************************************** // included header files #include "tifffwd_int.hpp" #include "tiffcomposite_int.hpp" #include "image.hpp" #include "tags_int.hpp" #include "types.hpp" // + standard includes #include #include // ***************************************************************************** // namespace extensions namespace Exiv2 { /*! @brief Contains internal objects which are not published and are not part of the libexiv2 API. */ namespace Internal { // ***************************************************************************** // class definitions /*! @brief Abstract base class defining the interface of an image header. Used internally by classes for TIFF-based images. Default implementation is for the regular TIFF header. */ class TiffHeaderBase { public: //! @name Creators //@{ //! Constructor taking \em tag, \em size and default \em byteOrder and \em offset. TiffHeaderBase(uint16_t tag, uint32_t size, ByteOrder byteOrder, uint32_t offset); //! Virtual destructor. virtual ~TiffHeaderBase() =0; //@} //! @name Manipulators //@{ /*! @brief Read the image header from a data buffer. Return false if the data buffer does not contain an image header of the expected format, else true. @param pData Pointer to the data buffer. @param size Number of bytes in the data buffer. @return True if the TIFF header was read successfully. False if the data buffer does not contain a valid TIFF header. */ virtual bool read(const byte* pData, uint32_t size); //! Set the byte order. virtual void setByteOrder(ByteOrder byteOrder); //! Set the offset to the start of the root directory. virtual void setOffset(uint32_t offset); //@} //! @name Accessors //@{ /*! @brief Return the image header in binary format. The caller owns this data and %DataBuf ensures that it will be deleted. @return Binary header data. */ virtual DataBuf write() const; /*! @brief Print debug info for the image header to \em os. @param os Output stream to write to. @param prefix Prefix to be written before each line of output. */ virtual void print(std::ostream& os, const std::string& prefix ="") const; //! Return the byte order (little or big endian). virtual ByteOrder byteOrder() const; //! Return the offset to the start of the root directory. virtual uint32_t offset() const; //! Return the size (in bytes) of the image header. virtual uint32_t size() const; //! Return the tag value (magic number) which identifies the buffer as TIFF data. virtual uint16_t tag() const; /*! @brief Return \c true if the %Exif \em tag from \em group is an image tag. Certain tags of TIFF and TIFF-like images are required to correctly display the primary image. These image tags contain image data rather than metadata. @param tag Tag number. @param group Group identifier. @param pPrimaryGroups Pointer to a list of TIFF groups that contain primary images, empty if none are marked. @return The default implementation returns \c false. */ virtual bool isImageTag( uint16_t tag, IfdId group, const PrimaryGroups* pPrimaryGroups) const; //@} private: // DATA const uint16_t tag_; //!< Tag to identify the buffer as TIFF data const uint32_t size_; //!< Size of the header ByteOrder byteOrder_; //!< Applicable byte order uint32_t offset_; //!< Offset to the start of the root dir }; // class TiffHeaderBase //! Convenience function to check if tag, group is in the list of TIFF image tags. bool isTiffImageTag(uint16_t tag, IfdId group); /*! @brief Standard TIFF header structure. */ class TiffHeader : public TiffHeaderBase { public: //! @name Creators //@{ //! Default constructor TiffHeader(ByteOrder byteOrder =littleEndian, uint32_t offset =0x00000008, bool hasImageTags =true); //! Destructor ~TiffHeader(); //@} //@{ //! @name Accessors bool isImageTag( uint16_t tag, IfdId group, const PrimaryGroups* pPrimaryGroups) const; //@} private: // DATA bool hasImageTags_; //!< Indicates if image tags are supported }; // class TiffHeader /*! @brief Data structure used to list image tags for TIFF and TIFF-like images. */ struct TiffImgTagStruct { //! Search key for TIFF image tag structure. struct Key { //! Constructor Key(uint16_t t, IfdId g) : t_(t), g_(g) {} uint16_t t_; //!< %Tag IfdId g_; //!< %Group }; //! Comparison operator to compare a TiffImgTagStruct with a TiffImgTagStruct::Key bool operator==(const Key& key) const { return key.g_ == group_ && key.t_ == tag_; } // DATA uint16_t tag_; //!< Image tag IfdId group_; //!< Group that contains the image tag }; // struct TiffImgTagStruct /*! @brief Data structure used as a row (element) of a table (array) defining the TIFF component used for each tag in a group. */ struct TiffGroupStruct { //! Search key for TIFF group structure. struct Key { //! Constructor Key(uint32_t e, IfdId g) : e_(e), g_(g) {} uint32_t e_; //!< Extended tag IfdId g_; //!< %Group }; //! Comparison operator to compare a TiffGroupStruct with a TiffGroupStruct::Key bool operator==(const Key& key) const { return key.g_ == group_ && (Tag::all == extendedTag_ || key.e_ == extendedTag_); } //! Return the tag corresponding to the extended tag uint16_t tag() const { return static_cast(extendedTag_ & 0xffff); } // DATA uint32_t extendedTag_; //!< Tag (32 bit so that it can contain special tags) IfdId group_; //!< Group that contains the tag NewTiffCompFct newTiffCompFct_; //!< Function to create the correct TIFF component }; /*! @brief Data structure used as a row of the table which describes TIFF trees. Multiple trees are needed as TIFF-based RAW image formats do not always use standard TIFF layout. */ struct TiffTreeStruct { struct Key; //! Comparison operator to compare a TiffTreeStruct with a TiffTreeStruct::Key bool operator==(const Key& key) const; // DATA uint32_t root_; //!< Tree root element, identifies a tree IfdId group_; //!< Each group is a node in the tree IfdId parentGroup_; //!< Parent group uint32_t parentExtTag_; //!< Parent tag (32 bit so that it can contain special tags) }; //! Search key for TIFF tree structure. struct TiffTreeStruct::Key { //! Constructor Key(uint32_t r, IfdId g) : r_(r), g_(g) {} uint32_t r_; //!< Root IfdId g_; //!< %Group }; /*! @brief TIFF component factory. */ class TiffCreator { public: /*! @brief Create the TiffComponent for TIFF entry \em extendedTag and \em group. The embedded lookup table is used to find the correct component creation function. If the pointer that is returned is 0, then the TIFF entry should be ignored. */ static std::auto_ptr create(uint32_t extendedTag, IfdId group); /*! @brief Get the path, i.e., a list of extended tag and group pairs, from the \em root TIFF element to the TIFF entry \em extendedTag and \em group. */ static void getPath(TiffPath& tiffPath, uint32_t extendedTag, IfdId group, uint32_t root); private: static const TiffTreeStruct tiffTreeStruct_[]; // parse( const byte* pData, uint32_t size, uint32_t root, TiffHeaderBase* pHeader ); /*! @brief Find primary groups in the source tree provided and populate the list of primary groups. @param primaryGroups List of primary groups which is populated @param pSourceDir Pointer to the source composite tree to search (may be 0) */ static void findPrimaryGroups( PrimaryGroups& primaryGroups, TiffComponent* pSourceDir ); }; // class TiffParserWorker /*! @brief Table of TIFF decoding and encoding functions and find functions. This class is separated from the metadata decoder and encoder visitors so that the parser can be parametrized with a different table if needed. This is used, eg., for CR2 format, which uses a different decoder table. */ class TiffMapping { public: /*! @brief Find the decoder function for a key. If the returned pointer is 0, the tag should not be decoded, else the decoder function should be used. @param make Camera make @param extendedTag Extended tag @param group %Group @return Pointer to the decoder function */ static DecoderFct findDecoder(const std::string& make, uint32_t extendedTag, IfdId group); /*! @brief Find special encoder function for a key. If the returned pointer is 0, the tag should be encoded with the encoder function of the TIFF component, else the encoder function should be used. @param make Camera make @param extendedTag Extended tag @param group %Group @return Pointer to the encoder function */ static EncoderFct findEncoder( const std::string& make, uint32_t extendedTag, IfdId group ); private: static const TiffMappingInfo tiffMappingInfo_[]; // OffsetList; // DATA OffsetList offsetList_; //!< List of the offsets to replace }; // class OffsetWriter // Todo: Move this class to metadatum_int.hpp or tags_int.hpp //! Unary predicate that matches an Exifdatum with a given IfdId. class FindExifdatum { public: //! Constructor, initializes the object with the IfdId to look for. FindExifdatum(Exiv2::Internal::IfdId ifdId) : ifdId_(ifdId) {} //! Returns true if IFD id matches. bool operator()(const Exiv2::Exifdatum& md) const { return ifdId_ == md.ifdId(); } private: Exiv2::Internal::IfdId ifdId_; }; // class FindExifdatum }} // namespace Internal, Exiv2 #endif // #ifndef TIFFIMAGE_INT_HPP_ exiv2-0.23/src/futils.hpp0000644000175000017500000000522111732641407015122 0ustar andreasandreas// ********************************************************* -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! @file futils.hpp @brief Basic file utility functions required by Exiv2 @version $Rev: 2681 $ @author Andreas Huggel (ahu) ahuggel@gmx.net @date 12-Dec-03, ahu: created
02-Apr-05, ahu: moved to Exiv2 namespace */ #ifndef FUTILS_HPP_ #define FUTILS_HPP_ // ********************************************************************* // included header files #ifdef _MSC_VER # include "exv_msvc.h" #else # include "exv_conf.h" #endif // + standard includes #include // ********************************************************************* // namespace extensions namespace Exiv2 { // ********************************************************************* // free functions /*! @brief Test if a file exists. @param path Name of file to verify. @param ct Flag to check if path is a regular file. @return true if path exists and, if ct is set, is a regular file, else false. @note The function calls stat() test for path and its type, see stat(2). errno is left unchanged in case of an error. */ EXIV2API bool fileExists(const std::string& path, bool ct =false); #ifdef EXV_UNICODE_PATH /*! @brief Like fileExists() but accepts a unicode path in an std::wstring. @note This function is only available on Windows. */ EXIV2API bool fileExists(const std::wstring& wpath, bool ct =false); #endif /*! @brief Return a system error message and the error code (errno). See %strerror(3). */ EXIV2API std::string strError(); } // namespace Exiv2 #endif // #ifndef FUTILS_HPP_ exiv2-0.23/src/tags_int.hpp0000644000175000017500000004152011741215652015425 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! @file tags_int.hpp @brief Internal Exif tag and type information @version $Rev: 2696 $ @author Andreas Huggel (ahu) ahuggel@gmx.net @date 15-Jan-04, ahu: created
11-Feb-04, ahu: isolated as a component */ #ifndef TAGS_INT_HPP_ #define TAGS_INT_HPP_ // ***************************************************************************** // included header files #include "types.hpp" #include "tags.hpp" #include "value.hpp" // + standard includes #include #include #include // ***************************************************************************** // namespace extensions namespace Exiv2 { class ExifData; namespace Internal { // ***************************************************************************** // class definitions //! Type to specify the IFD to which a metadata belongs enum IfdId { ifdIdNotSet, ifd0Id, ifd1Id, ifd2Id, ifd3Id, exifId, gpsId, iopId, subImage1Id, subImage2Id, subImage3Id, subImage4Id, subImage5Id, subImage6Id, subImage7Id, subImage8Id, subImage9Id, subThumb1Id, panaRawId, mnId, canonId, canonCsId, canonSiId, canonCfId, canonPiId, canonPaId, canonFiId, canonPrId, fujiId, minoltaId, minoltaCs5DId, minoltaCs7DId, minoltaCsOldId, minoltaCsNewId, nikon1Id, nikon2Id, nikon3Id, nikonPvId, nikonVrId, nikonPcId, nikonWtId, nikonIiId, nikonAfId, nikonAf2Id, nikonAFTId, nikonFiId, nikonMeId, nikonFl1Id, nikonFl2Id, nikonFl3Id, nikonSi1Id, nikonSi2Id, nikonSi3Id, nikonSi4Id, nikonSi5Id, nikonSi6Id, nikonLd1Id, nikonLd2Id, nikonLd3Id, nikonCb1Id, nikonCb2Id, nikonCb2aId, nikonCb2bId, nikonCb3Id, nikonCb4Id, olympusId, olympus2Id, olympusCsId, olympusEqId, olympusRdId, olympusRd2Id, olympusIpId, olympusFiId, olympusFe1Id, olympusFe2Id, olympusFe3Id, olympusFe4Id, olympusFe5Id, olympusFe6Id, olympusFe7Id, olympusFe8Id, olympusFe9Id, olympusRiId, panasonicId, pentaxId, pentaxDngId, samsung2Id, samsungPvId, samsungPwId, sigmaId, sony1Id, sony2Id, sonyMltId, sony1CsId, sony1Cs2Id, sony2CsId, sony2Cs2Id, sony1MltCs7DId, sony1MltCsOldId, sony1MltCsNewId, sony1MltCsA100Id, lastId, ignoreId = lastId }; /*! @brief Section identifiers to logically group tags. A section consists of nothing more than a name, based on the Exif standard. */ enum SectionId { sectionIdNotSet, imgStruct, recOffset, imgCharacter, otherTags, exifFormat, exifVersion, imgConfig, userInfo, relatedFile, dateTime, captureCond, gpsTags, iopTags, makerTags, dngTags, panaRaw, tiffEp, tiffPm6, adobeOpi, lastSectionId }; //! The details of a section. struct SectionInfo { SectionId sectionId_; //!< Section id const char* name_; //!< Section name (one word) const char* desc_; //!< Section description }; /*! @brief Helper structure for lookup tables for translations of numeric tag values to human readable labels. */ struct TagDetails { long val_; //!< Tag value const char* label_; //!< Translation of the tag value //! Comparison operator for use with the find template bool operator==(long key) const { return val_ == key; } }; // struct TagDetails /*! @brief Helper structure for lookup tables for translations of bitmask values to human readable labels. */ struct TagDetailsBitmask { uint32_t mask_; //!< Bitmask value const char* label_; //!< Description of the tag value }; // struct TagDetailsBitmask /*! @brief Helper structure for lookup tables for translations of controlled vocabulary strings to their descriptions. */ struct TagVocabulary { const char* voc_; //!< Vocabulary string const char* label_; //!< Description of the vocabulary string /*! @brief Comparison operator for use with the find template Compare vocabulary strings like "PR-NON" with keys like "http://ns.useplus.org/ldf/vocab/PR-NON" and return true if the vocabulary string matches the end of the key. */ bool operator==(const std::string& key) const; }; // struct TagDetails /*! @brief Generic pretty-print function to translate a long value to a description by looking up a reference table. */ template std::ostream& printTag(std::ostream& os, const Value& value, const ExifData*) { const TagDetails* td = find(array, value.toLong()); if (td) { os << exvGettext(td->label_); } else { os << "(" << value << ")"; } return os; } //! Shortcut for the printTag template which requires typing the array name only once. #define EXV_PRINT_TAG(array) printTag /*! @brief Generic print function to translate a long value to a description by looking up bitmasks in a reference table. */ template std::ostream& printTagBitmask(std::ostream& os, const Value& value, const ExifData*) { const uint32_t val = static_cast(value.toLong()); if (val == 0 && N > 0) { const TagDetailsBitmask* td = *(&array); if (td->mask_ == 0) return os << exvGettext(td->label_); } bool sep = false; for (int i = 0; i < N; ++i) { // *& acrobatics is a workaround for a MSVC 7.1 bug const TagDetailsBitmask* td = *(&array) + i; if (val & td->mask_) { if (sep) { os << ", " << exvGettext(td->label_); } else { os << exvGettext(td->label_); sep = true; } } } return os; } //! Shortcut for the printTagBitmask template which requires typing the array name only once. #define EXV_PRINT_TAG_BITMASK(array) printTagBitmask /*! @brief Generic pretty-print function to translate a controlled vocabulary value (string) to a description by looking up a reference table. */ template std::ostream& printTagVocabulary(std::ostream& os, const Value& value, const ExifData*) { const TagVocabulary* td = find(array, value.toString()); if (td) { os << exvGettext(td->label_); } else { os << "(" << value << ")"; } return os; } //! Shortcut for the printTagVocabulary template which requires typing the array name only once. #define EXV_PRINT_VOCABULARY(array) printTagVocabulary // ***************************************************************************** // free functions //! Return read-only list of built-in IFD0/1 tags const TagInfo* ifdTagList(); //! Return read-only list of built-in Exif IFD tags const TagInfo* exifTagList(); //! Return read-only list of built-in IOP tags const TagInfo* iopTagList(); //! Return read-only list of built-in GPS tags const TagInfo* gpsTagList(); //! Return read-only list of built-in Exiv2 Makernote info tags const TagInfo* mnTagList(); //! Return the group id for a group name IfdId groupId(const std::string& groupName); //! Return the name of the IFD const char* ifdName(IfdId ifdId); //! Return the group name for a group id const char* groupName(IfdId ifdId); //! Return true if \em ifdId is a makernote IFD id. (Note: returns false for makerIfd) bool isMakerIfd(IfdId ifdId); //! Return true if \em ifdId is an %Exif IFD id. bool isExifIfd(IfdId ifdId); //! Print the list of tags for \em ifdId to the output stream \em os void taglist(std::ostream& os, IfdId ifdId); //! Return the tag list for \em ifdId const TagInfo* tagList(IfdId ifdId); //! Return the tag info for \em tag and \em ifdId const TagInfo* tagInfo(uint16_t tag, IfdId ifdId); //! Return the tag info for \em tagName and \em ifdId const TagInfo* tagInfo(const std::string& tagName, IfdId ifdId); /*! @brief Return the tag number for one combination of IFD id and tagName. If the tagName is not known, it expects tag names in the form "0x01ff" and converts them to unsigned integer. @throw Error if the tagname or ifdId is invalid */ uint16_t tagNumber(const std::string& tagName, IfdId ifdId); //! @name Functions printing interpreted tag values //@{ //! Default print function, using the Value output operator std::ostream& printValue(std::ostream& os, const Value& value, const ExifData*); //! Print the value converted to a long std::ostream& printLong(std::ostream& os, const Value& value, const ExifData*); //! Print a Rational or URational value in floating point format std::ostream& printFloat(std::ostream& os, const Value& value, const ExifData*); //! Print a longitude or latitude value std::ostream& printDegrees(std::ostream& os, const Value& value, const ExifData*); //! Print function converting from UCS-2LE to UTF-8 std::ostream& printUcs2(std::ostream& os, const Value& value, const ExifData*); //! Print function for Exif units std::ostream& printExifUnit(std::ostream& os, const Value& value, const ExifData*); //! Print GPS version std::ostream& print0x0000(std::ostream& os, const Value& value, const ExifData*); //! Print GPS altitude ref std::ostream& print0x0005(std::ostream& os, const Value& value, const ExifData*); //! Print GPS altitude std::ostream& print0x0006(std::ostream& os, const Value& value, const ExifData*); //! Print GPS timestamp std::ostream& print0x0007(std::ostream& os, const Value& value, const ExifData*); //! Print GPS status std::ostream& print0x0009(std::ostream& os, const Value& value, const ExifData*); //! Print GPS measurement mode std::ostream& print0x000a(std::ostream& os, const Value& value, const ExifData*); //! Print GPS speed ref std::ostream& print0x000c(std::ostream& os, const Value& value, const ExifData*); //! Print GPS destination distance ref std::ostream& print0x0019(std::ostream& os, const Value& value, const ExifData*); //! Print GPS differential correction std::ostream& print0x001e(std::ostream& os, const Value& value, const ExifData*); //! Print orientation std::ostream& print0x0112(std::ostream& os, const Value& value, const ExifData*); //! Print YCbCrPositioning std::ostream& print0x0213(std::ostream& os, const Value& value, const ExifData*); //! Print the copyright std::ostream& print0x8298(std::ostream& os, const Value& value, const ExifData*); //! Print the exposure time std::ostream& print0x829a(std::ostream& os, const Value& value, const ExifData*); //! Print the f-number std::ostream& print0x829d(std::ostream& os, const Value& value, const ExifData*); //! Print exposure program std::ostream& print0x8822(std::ostream& os, const Value& value, const ExifData*); //! Print ISO speed ratings std::ostream& print0x8827(std::ostream& os, const Value& value, const ExifData*); //! Print components configuration specific to compressed data std::ostream& print0x9101(std::ostream& os, const Value& value, const ExifData*); //! Print exposure time converted from APEX shutter speed value std::ostream& print0x9201(std::ostream& os, const Value& value, const ExifData*); //! Print f-number converted from APEX aperture value std::ostream& print0x9202(std::ostream& os, const Value& value, const ExifData*); //! Print the exposure bias value std::ostream& print0x9204(std::ostream& os, const Value& value, const ExifData*); //! Print the subject distance std::ostream& print0x9206(std::ostream& os, const Value& value, const ExifData*); //! Print metering mode std::ostream& print0x9207(std::ostream& os, const Value& value, const ExifData*); //! Print light source std::ostream& print0x9208(std::ostream& os, const Value& value, const ExifData*); //! Print the actual focal length of the lens std::ostream& print0x920a(std::ostream& os, const Value& value, const ExifData*); //! Print the user comment std::ostream& print0x9286(std::ostream& os, const Value& value, const ExifData*); //! Print color space std::ostream& print0xa001(std::ostream& os, const Value& value, const ExifData*); //! Print sensing method std::ostream& print0xa217(std::ostream& os, const Value& value, const ExifData*); //! Print file source std::ostream& print0xa300(std::ostream& os, const Value& value, const ExifData*); //! Print scene type std::ostream& print0xa301(std::ostream& os, const Value& value, const ExifData*); //! Print custom rendered std::ostream& print0xa401(std::ostream& os, const Value& value, const ExifData*); //! Print exposure mode std::ostream& print0xa402(std::ostream& os, const Value& value, const ExifData*); //! Print white balance std::ostream& print0xa403(std::ostream& os, const Value& value, const ExifData*); //! Print digital zoom ratio std::ostream& print0xa404(std::ostream& os, const Value& value, const ExifData*); //! Print 35mm equivalent focal length std::ostream& print0xa405(std::ostream& os, const Value& value, const ExifData*); //! Print scene capture type std::ostream& print0xa406(std::ostream& os, const Value& value, const ExifData*); //! Print gain control std::ostream& print0xa407(std::ostream& os, const Value& value, const ExifData*); //! Print saturation std::ostream& print0xa409(std::ostream& os, const Value& value, const ExifData*); //! Print subject distance range std::ostream& print0xa40c(std::ostream& os, const Value& value, const ExifData*); //! Print GPS direction ref std::ostream& printGPSDirRef(std::ostream& os, const Value& value, const ExifData*); //! Print contrast, sharpness (normal, soft, hard) std::ostream& printNormalSoftHard(std::ostream& os, const Value& value, const ExifData*); //! Print any version packed in 4 Bytes format : major major minor minor std::ostream& printExifVersion(std::ostream& os, const Value& value, const ExifData*); //! Print any version encoded in the ASCII string majormajorminorminor std::ostream& printXmpVersion(std::ostream& os, const Value& value, const ExifData*); //! Print a date following the format YYYY-MM-DDTHH:MM:SSZ std::ostream& printXmpDate(std::ostream& os, const Value& value, const ExifData*); //@} //! Calculate F number from an APEX aperture value float fnumber(float apertureValue); //! Calculate the exposure time from an APEX shutter speed value URational exposureTime(float shutterSpeedValue); }} // namespace Internal, Exiv2 #endif // #ifndef TAGS_INT_HPP_ exiv2-0.23/src/rw2image.cpp0000644000175000017500000002212511732641407015326 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /* File: rw2image.cpp Version: $Rev: 2681 $ Author(s): Andreas Huggel (ahu) History: 06-Jan-09, ahu: created */ // ***************************************************************************** #include "rcsid_int.hpp" EXIV2_RCSID("@(#) $Id: rw2image.cpp 2681 2012-03-22 15:19:35Z ahuggel $") // ***************************************************************************** // included header files #ifdef _MSC_VER # include "exv_msvc.h" #else # include "exv_conf.h" #endif #include "rw2image.hpp" #include "rw2image_int.hpp" #include "tiffcomposite_int.hpp" #include "tiffimage_int.hpp" #include "image.hpp" #include "preview.hpp" #include "error.hpp" #include "futils.hpp" // + standard includes #ifdef DEBUG # include #endif // ***************************************************************************** // class member definitions namespace Exiv2 { using namespace Internal; Rw2Image::Rw2Image(BasicIo::AutoPtr io) : Image(ImageType::rw2, mdExif | mdIptc | mdXmp, io) { } // Rw2Image::Rw2Image std::string Rw2Image::mimeType() const { return "image/x-panasonic-rw2"; } int Rw2Image::pixelWidth() const { ExifData::const_iterator imageWidth = exifData_.findKey(Exiv2::ExifKey("Exif.PanasonicRaw.SensorWidth")); if (imageWidth != exifData_.end() && imageWidth->count() > 0) { return imageWidth->toLong(); } return 0; } int Rw2Image::pixelHeight() const { ExifData::const_iterator imageHeight = exifData_.findKey(Exiv2::ExifKey("Exif.PanasonicRaw.SensorHeight")); if (imageHeight != exifData_.end() && imageHeight->count() > 0) { return imageHeight->toLong(); } return 0; } void Rw2Image::setExifData(const ExifData& /*exifData*/) { // Todo: implement me! throw(Error(32, "Exif metadata", "RW2")); } void Rw2Image::setIptcData(const IptcData& /*iptcData*/) { // Todo: implement me! throw(Error(32, "IPTC metadata", "RW2")); } void Rw2Image::setComment(const std::string& /*comment*/) { // not supported throw(Error(32, "Image comment", "RW2")); } void Rw2Image::readMetadata() { #ifdef DEBUG std::cerr << "Reading RW2 file " << io_->path() << "\n"; #endif if (io_->open() != 0) { throw Error(9, io_->path(), strError()); } IoCloser closer(*io_); // Ensure that this is the correct image type if (!isRw2Type(*io_, false)) { if (io_->error() || io_->eof()) throw Error(14); throw Error(3, "RW2"); } clearMetadata(); ByteOrder bo = Rw2Parser::decode(exifData_, iptcData_, xmpData_, io_->mmap(), io_->size()); setByteOrder(bo); // A lot more metadata is hidden in the embedded preview image // Todo: This should go into the Rw2Parser, but for that it needs the Image PreviewManager loader(*this); PreviewPropertiesList list = loader.getPreviewProperties(); // Todo: What if there are more preview images? if (list.size() > 1) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "RW2 image contains more than one preview. None used.\n"; #endif } if (list.size() != 1) return; ExifData exifData; PreviewImage preview = loader.getPreviewImage(*list.begin()); Image::AutoPtr image = ImageFactory::open(preview.pData(), preview.size()); if (image.get() == 0) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Failed to open RW2 preview image.\n"; #endif return; } image->readMetadata(); ExifData& prevData = image->exifData(); if (!prevData.empty()) { // Filter duplicate tags for (ExifData::const_iterator pos = exifData_.begin(); pos != exifData_.end(); ++pos) { if (pos->ifdId() == panaRawId) continue; ExifData::iterator dup = prevData.findKey(ExifKey(pos->key())); if (dup != prevData.end()) { #ifdef DEBUG std::cerr << "Filtering duplicate tag " << pos->key() << " (values '" << pos->value() << "' and '" << dup->value() << "')\n"; #endif prevData.erase(dup); } } } // Remove tags not applicable for raw images static const char* filteredTags[] = { "Exif.Photo.ComponentsConfiguration", "Exif.Photo.CompressedBitsPerPixel", "Exif.Panasonic.ColorEffect", "Exif.Panasonic.Contrast", "Exif.Panasonic.NoiseReduction", "Exif.Panasonic.ColorMode", "Exif.Panasonic.OpticalZoomMode", "Exif.Panasonic.Contrast", "Exif.Panasonic.Saturation", "Exif.Panasonic.Sharpness", "Exif.Panasonic.FilmMode", "Exif.Panasonic.SceneMode", "Exif.Panasonic.WBRedLevel", "Exif.Panasonic.WBGreenLevel", "Exif.Panasonic.WBBlueLevel", "Exif.Photo.ColorSpace", "Exif.Photo.PixelXDimension", "Exif.Photo.PixelYDimension", "Exif.Photo.SceneType", "Exif.Photo.CustomRendered", "Exif.Photo.DigitalZoomRatio", "Exif.Photo.SceneCaptureType", "Exif.Photo.GainControl", "Exif.Photo.Contrast", "Exif.Photo.Saturation", "Exif.Photo.Sharpness", "Exif.Image.PrintImageMatching", "Exif.Image.YCbCrPositioning" }; for (unsigned int i = 0; i < EXV_COUNTOF(filteredTags); ++i) { ExifData::iterator pos = prevData.findKey(ExifKey(filteredTags[i])); if (pos != prevData.end()) { #ifdef DEBUG std::cerr << "Exif tag " << pos->key() << " removed\n"; #endif prevData.erase(pos); } } // Add the remaining tags for (ExifData::const_iterator pos = prevData.begin(); pos != prevData.end(); ++pos) { exifData_.add(*pos); } } // Rw2Image::readMetadata void Rw2Image::writeMetadata() { // Todo: implement me! throw(Error(31, "RW2")); } // Rw2Image::writeMetadata ByteOrder Rw2Parser::decode( ExifData& exifData, IptcData& iptcData, XmpData& xmpData, const byte* pData, uint32_t size ) { Rw2Header rw2Header; return TiffParserWorker::decode(exifData, iptcData, xmpData, pData, size, Tag::pana, TiffMapping::findDecoder, &rw2Header); } // ************************************************************************* // free functions Image::AutoPtr newRw2Instance(BasicIo::AutoPtr io, bool /*create*/) { Image::AutoPtr image(new Rw2Image(io)); if (!image->good()) { image.reset(); } return image; } bool isRw2Type(BasicIo& iIo, bool advance) { const int32_t len = 24; byte buf[len]; iIo.read(buf, len); if (iIo.error() || iIo.eof()) { return false; } Rw2Header header; bool rc = header.read(buf, len); if (!advance || !rc) { iIo.seek(-len, BasicIo::cur); } return rc; } } // namespace Exiv2 namespace Exiv2 { namespace Internal { Rw2Header::Rw2Header() : TiffHeaderBase(0x0055, 24, littleEndian, 0x00000018) { } Rw2Header::~Rw2Header() { } DataBuf Rw2Header::write() const { // Todo: Implement me! return DataBuf(); } }} // namespace Internal, Exiv2 exiv2-0.23/src/crwimage_int.hpp0000644000175000017500000007054411732641407016276 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! @file crwimage_int.hpp @brief Internal classes to support CRW/CIFF format. @version $Rev: 2681 $ @author Andreas Huggel (ahu) ahuggel@gmx.net @date 28-Aug-05, ahu: created */ #ifndef CRWIMAGE_INT_HPP_ #define CRWIMAGE_INT_HPP_ // ***************************************************************************** // included header files #include "types.hpp" #include "tags_int.hpp" #include "image.hpp" #include "basicio.hpp" // + standard includes #include #include #include #include // ***************************************************************************** // namespace extensions namespace Exiv2 { // ***************************************************************************** // class declarations class ExifData; namespace Internal { // ***************************************************************************** // class declarations class CiffHeader; class CiffComponent; struct CrwMapping; struct CrwSubDir; // ***************************************************************************** // type definitions //! Function pointer for functions to decode Exif tags from a CRW entry typedef void (*CrwDecodeFct)(const CiffComponent&, const CrwMapping*, Image&, ByteOrder); //! Function pointer for functions to encode CRW entries from Exif tags typedef void (*CrwEncodeFct)(const Image&, const CrwMapping*, CiffHeader*); //! Stack to hold a path of CRW directories typedef std::stack CrwDirs; //! Type to identify where the data is stored in a directory enum DataLocId { invalidDataLocId, valueData, directoryData, lastDataLocId }; // ***************************************************************************** // class definitions /*! @brief Interface class for components of the CIFF directory hierarchy of a CRW (Canon Raw data) image. Both CIFF directories as well as entries implement this interface. This class is implemented as NVI (non-virtual interface). */ class CiffComponent { public: //! CiffComponent auto_ptr type typedef std::auto_ptr AutoPtr; //! Container type to hold all metadata typedef std::vector Components; //! @name Creators //@{ //! Default constructor CiffComponent() : dir_(0), tag_(0), size_(0), offset_(0), pData_(0), isAllocated_(false) {} //! Constructor taking a tag and directory CiffComponent(uint16_t tag, uint16_t dir) : dir_(dir), tag_(tag), size_(0), offset_(0), pData_(0), isAllocated_(false) {} //! Virtual destructor. virtual ~CiffComponent(); //@} //! @name Manipulators //@{ // Default assignment operator is fine //! Add a component to the composition void add(AutoPtr component); /*! @brief Add \em crwTagId to the parse tree, if it doesn't exist yet. \em crwDirs contains the path of subdirectories, starting with the root directory, leading to \em crwTagId. Directories that don't exist yet are added along the way. Returns a pointer to the newly added component. @param crwDirs Subdirectory path from root to the subdirectory containing the tag to be added. @param crwTagId Tag to be added. @return A pointer to the newly added component. */ CiffComponent* add(CrwDirs& crwDirs, uint16_t crwTagId); /*! @brief Remove \em crwTagId from the parse tree, if it exists yet. \em crwDirs contains the path of subdirectories, starting with the root directory, leading to \em crwTagId. @param crwDirs Subdirectory path from root to the subdirectory containing the tag to be removed. @param crwTagId Tag to be removed. */ void remove(CrwDirs& crwDirs, uint16_t crwTagId); /*! @brief Read a component from a data buffer @param pData Pointer to the data buffer. @param size Number of bytes in the data buffer. @param start Component starts at \em pData + \em start. @param byteOrder Applicable byte order (little or big endian). @throw Error If the component cannot be parsed. */ void read(const byte* pData, uint32_t size, uint32_t start, ByteOrder byteOrder); /*! @brief Write the metadata from the raw metadata component to the binary image \em blob. This method may append to the blob. @param blob Binary image to add metadata to @param byteOrder Byte order @param offset Current offset @return New offset */ uint32_t write(Blob& blob, ByteOrder byteOrder, uint32_t offset); /*! @brief Writes the entry's value if size is larger than eight bytes. If needed, the value is padded with one 0 byte to make the number of bytes written to the blob even. The offset of the component is set to the offset passed in. @param blob The binary image to write to. @param offset Offset from the start of the directory for this entry. @return New offset. */ uint32_t writeValueData(Blob& blob, uint32_t offset); //! Set the directory tag for this component. void setDir(uint16_t dir) { dir_ = dir; } //! Set the data value of the entry. void setValue(DataBuf buf); //@} //! Return the type id for a tag static TypeId typeId(uint16_t tag); //! Return the data location id for a tag static DataLocId dataLocation(uint16_t tag); //! @name Accessors //@{ /*! @brief Decode metadata from the component and add it to \em image. @param image Image to add metadata to @param byteOrder Byte order */ void decode(Image& image, ByteOrder byteOrder) const; /*! @brief Print debug info about a component to \em os. @param os Output stream to write to @param byteOrder Byte order @param prefix Prefix to be written before each line of output */ void print(std::ostream& os, ByteOrder byteOrder, const std::string& prefix ="") const; /*! @brief Write a directory entry for the component to the \em blob. If the size of the data is not larger than 8 bytes, the data is written to the directory entry. */ void writeDirEntry(Blob& blob, ByteOrder byteOrder) const; //! Return the tag of the directory containing this component uint16_t dir() const { return dir_; } //! Return the tag of this component uint16_t tag() const { return tag_; } //! Return true if the component is empty, else false bool empty() const; /*! @brief Return the data size of this component @note If the data is contained in the directory entry itself, this method returns 8, which is the maximum number of data bytes this component can have. The actual size, i.e., used data bytes, may be less than 8. */ uint32_t size() const { return size_; } //! Return the offset to the data from the start of the directory uint32_t offset() const { return offset_; } //! Return a pointer to the data area of this component const byte* pData() const { return pData_; } //! Return the tag id of this component uint16_t tagId() const { return tag_ & 0x3fff; } //! Return the type id of thi component TypeId typeId() const { return typeId(tag_); } //! Return the data location for this component DataLocId dataLocation() const { return dataLocation(tag_); } /*! @brief Finds \em crwTagId in directory \em crwDir, returning a pointer to the component or 0 if not found. */ CiffComponent* findComponent(uint16_t crwTagId, uint16_t crwDir) const; //@} protected: //! @name Manipulators //@{ //! Implements add() virtual void doAdd(AutoPtr component) =0; //! Implements add(). The default implementation does nothing. virtual CiffComponent* doAdd(CrwDirs& crwDirs, uint16_t crwTagId); //! Implements remove(). The default implementation does nothing. virtual void doRemove(CrwDirs& crwDirs, uint16_t crwTagId); //! Implements read(). The default implementation reads a directory entry. virtual void doRead(const byte* pData, uint32_t size, uint32_t start, ByteOrder byteOrder); //! Implements write() virtual uint32_t doWrite(Blob& blob, ByteOrder byteOrder, uint32_t offset) =0; //! Set the size of the data area. void setSize(uint32_t size) { size_ = size; } //! Set the offset for this component. void setOffset(uint32_t offset) { offset_ = offset; } //@} //! @name Accessors //@{ //! Implements decode() virtual void doDecode(Image& image, ByteOrder byteOrder) const =0; //! Implements print(). The default implementation prints the entry. virtual void doPrint(std::ostream& os, ByteOrder byteOrder, const std::string& prefix) const; //! Implements empty(). Default implementation returns true if size is 0. virtual bool doEmpty() const; //! Implements findComponent(). The default implementation checks the entry. virtual CiffComponent* doFindComponent(uint16_t crwTagId, uint16_t crwDir) const; //@} private: // DATA uint16_t dir_; //!< Tag of the directory containing this component uint16_t tag_; //!< Tag of the entry uint32_t size_; //!< Size of the data area uint32_t offset_; //!< Offset to the data area from start of dir const byte* pData_; //!< Pointer to the data area bool isAllocated_; //!< True if this entry owns the value data }; // class CiffComponent /*! @brief This class models one directory entry of a CIFF directory of a CRW (Canon Raw data) image. */ class CiffEntry : public CiffComponent { public: //! @name Creators //@{ //! Default constructor CiffEntry() {} //! Constructor taking a tag and directory CiffEntry(uint16_t tag, uint16_t dir) : CiffComponent(tag, dir) {} //! Virtual destructor. virtual ~CiffEntry(); //@} // Default assignment operator is fine private: //! @name Manipulators //@{ using CiffComponent::doAdd; // See base class comment virtual void doAdd(AutoPtr component); /*! @brief Implements write(). Writes only the value data of the entry, using writeValueData(). */ virtual uint32_t doWrite(Blob& blob, ByteOrder byteOrder, uint32_t offset); //@} //! @name Accessors //@{ // See base class comment virtual void doDecode(Image& image, ByteOrder byteOrder) const; //@} }; // class CiffEntry //! This class models a CIFF directory of a CRW (Canon Raw data) image. class CiffDirectory : public CiffComponent { public: //! @name Creators //@{ //! Default constructor CiffDirectory() {} //! Constructor taking a tag and directory CiffDirectory(uint16_t tag, uint16_t dir) : CiffComponent(tag, dir) {} //! Virtual destructor virtual ~CiffDirectory(); //@} //! @name Manipulators //@{ // Default assignment operator is fine /*! @brief Parse a CIFF directory from a memory buffer @param pData Pointer to the memory buffer containing the directory @param size Size of the memory buffer @param byteOrder Applicable byte order (little or big endian) */ void readDirectory(const byte* pData, uint32_t size, ByteOrder byteOrder); //@} private: //! @name Manipulators //@{ // See base class comment virtual void doAdd(AutoPtr component); // See base class comment virtual CiffComponent* doAdd(CrwDirs& crwDirs, uint16_t crwTagId); // See base class comment virtual void doRemove(CrwDirs& crwDirs, uint16_t crwTagId); /*! @brief Implements write(). Writes the complete Ciff directory to the blob. */ virtual uint32_t doWrite(Blob& blob, ByteOrder byteOrder, uint32_t offset); // See base class comment virtual void doRead(const byte* pData, uint32_t size, uint32_t start, ByteOrder byteOrder); //@} //! @name Accessors //@{ // See base class comment virtual void doDecode(Image& image, ByteOrder byteOrder) const; // See base class comment virtual void doPrint(std::ostream& os, ByteOrder byteOrder, const std::string& prefix) const; //! See base class comment. A directory is empty if it has no components. virtual bool doEmpty() const; // See base class comment virtual CiffComponent* doFindComponent(uint16_t crwTagId, uint16_t crwDir) const; //@} private: // DATA Components components_; //!< List of components in this dir }; // class CiffDirectory /*! @brief This class models the header of a CRW (Canon Raw data) image. It is the head of a CIFF parse tree, consisting of CiffDirectory and CiffEntry objects. Most of its methods will walk the parse tree to perform the requested action. */ class CiffHeader { public: //! CiffHeader auto_ptr type typedef std::auto_ptr AutoPtr; //! @name Creators //@{ //! Default constructor CiffHeader() : pRootDir_ (0), byteOrder_ (littleEndian), offset_ (0x0000001a), pPadding_ (0), padded_ (0) {} //! Virtual destructor virtual ~CiffHeader(); //@} //! @name Manipulators //@{ /*! @brief Read the CRW image from a data buffer, starting with the Ciff header. @param pData Pointer to the data buffer. @param size Number of bytes in the data buffer. @throw Error If the image cannot be parsed. */ void read(const byte* pData, uint32_t size); /*! @brief Set the value of entry \em crwTagId in directory \em crwDir to \em buf. If this tag doesn't exist, it is added along with all directories needed. @param crwTagId Tag to be added. @param crwDir Parent directory of the tag. @param buf Value to be set. */ void add(uint16_t crwTagId, uint16_t crwDir, DataBuf buf); /*! @brief Remove entry \em crwTagId in directory \em crwDir from the parse tree. If it's the last entry in the directory, the directory is removed as well, etc. @param crwTagId Tag id to be removed. @param crwDir Parent directory of the tag. */ void remove(uint16_t crwTagId, uint16_t crwDir); //@} //! Return a pointer to the Canon CRW signature. static const char* signature() { return signature_; } //! @name Accessors //@{ /*! @brief Write the CRW image to the binary image \em blob, starting with the Ciff header. This method appends to the blob. @param blob Binary image to add to. @throw Error If the image cannot be written. */ void write(Blob& blob) const; /*! @brief Decode the CRW image and add it to \em image. Walk the parse tree and convert CIFF entries to metadata entries which are added to \em image. @param image Image to add metadata to */ void decode(Image& image) const; /*! @brief Print debug info for the CRW image to \em os. @param os Output stream to write to. @param prefix Prefix to be written before each line of output. */ void print(std::ostream& os, const std::string& prefix ="") const; //! Return the byte order (little or big endian). ByteOrder byteOrder() const { return byteOrder_; } /*! @brief Finds \em crwTagId in directory \em crwDir in the parse tree, returning a pointer to the component or 0 if not found. */ CiffComponent* findComponent(uint16_t crwTagId, uint16_t crwDir) const; //@} private: // DATA static const char signature_[]; //!< Canon CRW signature "HEAPCCDR" CiffDirectory* pRootDir_; //!< Pointer to the root directory ByteOrder byteOrder_; //!< Applicable byte order uint32_t offset_; //!< Offset to the start of the root dir byte* pPadding_; //!< Pointer to the (unknown) remainder uint32_t padded_; //!< Number of padding-bytes }; // class CiffHeader //! Structure for the CIFF directory hierarchy struct CrwSubDir { uint16_t crwDir_; //!< Directory tag uint16_t parent_; //!< Parent directory tag }; // struct CrwSubDir /*! @brief Structure for a mapping table for conversion of CIFF entries to image metadata and vice versa. */ struct CrwMapping { //! @name Creators //@{ //! Default constructor CrwMapping( uint16_t crwTagId, uint16_t crwDir, uint32_t size, uint16_t tag, Internal::IfdId ifdId, CrwDecodeFct toExif, CrwEncodeFct fromExif) : crwTagId_ (crwTagId), crwDir_ (crwDir), size_ (size), tag_ (tag), ifdId_ (ifdId), toExif_ (toExif), fromExif_ (fromExif) {} //@} // DATA uint16_t crwTagId_; //!< CRW tag id uint16_t crwDir_; //!< CRW directory tag uint32_t size_; //!< Data size (overwrites the size from the entry) uint16_t tag_; //!< Exif tag to map to IfdId ifdId_; //!< Exif Ifd id to map to CrwDecodeFct toExif_; //!< Conversion function CrwEncodeFct fromExif_; //!< Reverse conversion function }; // struct CrwMapping /*! @brief Static class providing mapping functionality from CRW entries to image metadata and vice versa */ class CrwMap { //! @name Not implemented //@{ //! Default constructor CrwMap(); //@} public: /*! @brief Decode image metadata from a CRW entry, convert and add it to the image metadata. This function converts only one CRW component. @param ciffComponent Source CIFF entry @param image Destination image for the metadata @param byteOrder Byte order in which the data of the entry is encoded */ static void decode(const CiffComponent& ciffComponent, Image& image, ByteOrder byteOrder); /*! @brief Encode image metadata from \em image into the CRW parse tree. This function converts all Exif metadata that %Exiv2 can convert to CRW format, in a loop through the entries of the mapping table. @param pHead Destination parse tree. @param image Source image containing the metadata. */ static void encode(CiffHeader* pHead, const Image& image); /*! @brief Load the stack: loop through the CRW subdirs hierarchy and push all directories on the path from \em crwDir to root onto the stack \em crwDirs. Requires the subdirs array to be arranged in bottom-up order to be able to finish in only one pass. */ static void loadStack(CrwDirs& crwDirs, uint16_t crwDir); private: //! Return conversion information for one \em crwDir and \em crwTagId static const CrwMapping* crwMapping(uint16_t crwDir, uint16_t crwTagId); /*! @brief Standard decode function to convert CRW entries to Exif metadata. Uses the mapping defined in the conversion structure \em pCrwMapping to convert the data. If the \em size field in the conversion structure is not 0, then it is used instead of the \em size provided by the entry itself. */ static void decodeBasic(const CiffComponent& ciffComponent, const CrwMapping* pCrwMapping, Image& image, ByteOrder byteOrder); //! Decode the user comment static void decode0x0805(const CiffComponent& ciffComponent, const CrwMapping* pCrwMapping, Image& image, ByteOrder byteOrder); //! Decode camera Make and Model information static void decode0x080a(const CiffComponent& ciffComponent, const CrwMapping* pCrwMapping, Image& image, ByteOrder byteOrder); //! Decode Canon Camera Settings 1, 2 and Custom Function arrays static void decodeArray(const CiffComponent& ciffComponent, const CrwMapping* pCrwMapping, Image& image, ByteOrder byteOrder); //! Decode the date when the picture was taken static void decode0x180e(const CiffComponent& ciffComponent, const CrwMapping* pCrwMapping, Image& image, ByteOrder byteOrder); //! Decode image width and height static void decode0x1810(const CiffComponent& ciffComponent, const CrwMapping* pCrwMapping, Image& image, ByteOrder byteOrder); //! Decode the thumbnail image static void decode0x2008(const CiffComponent& ciffComponent, const CrwMapping* pCrwMapping, Image& image, ByteOrder byteOrder); /*! @brief Standard encode function to convert Exif metadata to Crw entries. This is the basic encode function taking one Exif key and converting it to one Ciff entry. Both are available in the \em pCrwMapping passed in. @param image Image with the metadata to encode @param pCrwMapping Pointer to an entry into the \em crwMapping_ table with information on the source and target metadata entries. @param pHead Pointer to the head of the CIFF parse tree into which the metadata from \em image is encoded. */ static void encodeBasic(const Image& image, const CrwMapping* pCrwMapping, CiffHeader* pHead); //! Encode the user comment static void encode0x0805(const Image& image, const CrwMapping* pCrwMapping, CiffHeader* pHead); //! Encode camera Make and Model information static void encode0x080a(const Image& image, const CrwMapping* pCrwMapping, CiffHeader* pHead); //! Encode Canon Camera Settings 1, 2 and Custom Function arrays static void encodeArray(const Image& image, const CrwMapping* pCrwMapping, CiffHeader* pHead); //! Encode the date when the picture was taken static void encode0x180e(const Image& image, const CrwMapping* pCrwMapping, CiffHeader* pHead); //! Encode image width and height static void encode0x1810(const Image& image, const CrwMapping* pCrwMapping, CiffHeader* pHead); //! Encode the thumbnail image static void encode0x2008(const Image& image, const CrwMapping* pCrwMapping, CiffHeader* pHead); private: // DATA static const CrwMapping crwMapping_[]; //!< Metadata conversion table static const CrwSubDir crwSubDir_[]; //!< Ciff directory hierarchy }; // class CrwMap // ***************************************************************************** // template, inline and free functions /*! @brief Pack the tag values of all \em ifdId tags in \em exifData into a data buffer. This function is used to pack Canon Camera Settings1,2 and Custom Function tags. */ DataBuf packIfdId(const ExifData& exifData, IfdId ifdId, ByteOrder byteOrder); }} // namespace Internal, Exiv2 #endif // #ifndef CRWIMAGE_INT_HPP_ exiv2-0.23/src/mrwimage.hpp0000644000175000017500000001227311732641407015431 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! @file mrwimage.hpp @brief Minolta RAW image, implemented using the following references: Minolta Raw file format by Dalibor Jelinek @version $Rev: 2681 $ @author Andreas Huggel (ahu) ahuggel@gmx.net @date 13-May-06, ahu: created */ #ifndef MRWIMAGE_HPP_ #define MRWIMAGE_HPP_ // ***************************************************************************** // included header files #include "image.hpp" #include "basicio.hpp" #include "types.hpp" // + standard includes #include // ***************************************************************************** // namespace extensions namespace Exiv2 { // ***************************************************************************** // class definitions // Add MRW to the supported image formats namespace ImageType { const int mrw = 5; //!< MRW image type (see class MrwImage) } /*! @brief Class to access raw Minolta MRW images. Exif metadata is supported directly, IPTC is read from the Exif data, if present. */ class EXIV2API MrwImage : public Image { public: //! @name Creators //@{ /*! @brief Constructor that can either open an existing MRW image or create a new image from scratch. If a new image is to be created, any existing data is overwritten. Since the constructor can not return a result, callers should check the good() method after object construction to determine success or failure. @param io An auto-pointer that owns a BasicIo instance used for reading and writing image metadata. \b Important: The constructor takes ownership of the passed in BasicIo instance through the auto-pointer. Callers should not continue to use the BasicIo instance after it is passed to this method. Use the Image::io() method to get a temporary reference. @param create Specifies if an existing image should be read (false) or if a new file should be created (true). */ MrwImage(BasicIo::AutoPtr io, bool create); //@} //! @name Manipulators //@{ void readMetadata(); /*! @brief Todo: Write metadata back to the image. This method is not yet implemented. Calling it will throw an Error(31). */ void writeMetadata(); /*! @brief Todo: Not supported yet, requires writeMetadata(). Calling this function will throw an Error(32). */ void setExifData(const ExifData& exifData); /*! @brief Todo: Not supported yet, requires writeMetadata(). Calling this function will throw an Error(32). */ void setIptcData(const IptcData& iptcData); /*! @brief Not supported. MRW format does not contain a comment. Calling this function will throw an Error(32). */ void setComment(const std::string& comment); //@} //! @name Accessors //@{ std::string mimeType() const; int pixelWidth() const; int pixelHeight() const; //@} private: //! @name NOT Implemented //@{ //! Copy constructor MrwImage(const MrwImage& rhs); //! Assignment operator MrwImage& operator=(const MrwImage& rhs); //@} }; // class MrwImage // ***************************************************************************** // template, inline and free functions // These could be static private functions on Image subclasses but then // ImageFactory needs to be made a friend. /*! @brief Create a new MrwImage instance and return an auto-pointer to it. Caller owns the returned object and the auto-pointer ensures that it will be deleted. */ EXIV2API Image::AutoPtr newMrwInstance(BasicIo::AutoPtr io, bool create); //! Check if the file iIo is a MRW image. EXIV2API bool isMrwType(BasicIo& iIo, bool advance); } // namespace Exiv2 #endif // #ifndef MRWIMAGE_HPP_ exiv2-0.23/src/convert.cpp0000644000175000017500000021007111732641407015270 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /* File: convert.cpp Version: $Rev: 2681 $ Author(s): Andreas Huggel (ahu) Vladimir Nadvornik (vn) History: 17-Mar-08, ahu: created basic converter framework 20-May-08, vn: added actual conversion logic */ // ***************************************************************************** #include "rcsid_int.hpp" EXIV2_RCSID("@(#) $Id: convert.cpp 2681 2012-03-22 15:19:35Z ahuggel $") // ***************************************************************************** // included header files #include "types.hpp" #include "exif.hpp" #include "iptc.hpp" #include "xmp.hpp" #include "futils.hpp" #include "convert.hpp" // + standard includes #include #include #include #include #include #include // for snprintf (C99) #ifdef _MSC_VER # define snprintf _snprintf #endif #include #if defined WIN32 && !defined __CYGWIN__ # include #endif #ifdef EXV_HAVE_ICONV # include # include #endif // Adobe XMP Toolkit #ifdef EXV_HAVE_XMP_TOOLKIT # define TXMP_STRING_TYPE std::string # include # include #endif // EXV_HAVE_XMP_TOOLKIT // ***************************************************************************** // local declarations namespace { #if defined WIN32 && !defined __CYGWIN__ // Convert string charset with Windows functions. bool convertStringCharsetWindows(std::string& str, const char* from, const char* to); #endif #if defined EXV_HAVE_ICONV // Convert string charset with iconv. bool convertStringCharsetIconv(std::string& str, const char* from, const char* to); #endif /*! @brief Get the text value of an XmpDatum \em pos. If \em pos refers to a LangAltValue, \em value is set to the default language entry without the x-default qualifier. If there is no default but exactly one entry, \em value is set to this entry, without the qualifier. The return code indicates if the operation was successful. */ bool getTextValue(std::string& value, const Exiv2::XmpData::iterator& pos); } // ***************************************************************************** // class member definitions namespace Exiv2 { //! Metadata conversions. class Converter { public: /*! @brief Type for metadata converter functions, taking two key strings, \em from and \em to. These functions have access to both the source and destination metadata containers and store the result directly in the destination container. */ typedef void (Converter::*ConvertFct)(const char* from, const char* to); //! Structure to define conversions between two keys. struct Conversion { MetadataId metadataId_; //!< Type of metadata for the first key. const char* key1_; //!< First metadata key. const char* key2_; //!< Second metadata key (always an XMP key for now). ConvertFct key1ToKey2_; //!< Conversion from first to second key. ConvertFct key2ToKey1_; //!< Conversion from second to first key. }; public: //! @name Creators //@{ //! Constructor for Exif tags and XMP properties. Converter(ExifData& exifData, XmpData& xmpData); //! Constructor for Iptc tags and XMP properties. Converter(IptcData& iptcData, XmpData& xmpData, const char *iptcCharset = 0); //@} //! @name Manipulators //@{ //! Convert Exif tags or IPTC datasets to XMP properties according to the conversion table. void cnvToXmp(); //! Convert XMP properties to Exif tags or IPTC datasets according to the conversion table. void cnvFromXmp(); /*! @brief Set the erase flag. This flag indicates whether successfully converted source records are erased. */ void setErase(bool onoff =true) { erase_ = onoff; } /*! @brief Set the overwrite flag. This flag indicates whether existing target records are overwritten. */ void setOverwrite(bool onoff =true) { overwrite_ = onoff; } //@} //! @name Conversion functions (manipulators) //@{ /*! @brief Simple Exif to XMP conversion function. Sets the XMP property to an XmpText value containing the Exif value string. */ void cnvExifValue(const char* from, const char* to); /*! @brief Convert the tag Exif.Photo.UserComment to XMP. Todo: Convert the Exif comment to UTF-8 if necessary. */ void cnvExifComment(const char* from, const char* to); /*! @brief Converts Exif tag with multiple components to XMP array. Converts Exif tag with multiple components to XMP array. This function is used for ComponentsConfiguration tag. */ void cnvExifArray(const char* from, const char* to); /*! @brief Exif date to XMP conversion function. Sets the XMP property to an XmpText value containing date and time. This function combines values from multiple Exif tags as described in XMP specification. It is used for DateTime, DateTimeOriginal, DateTimeDigitized and GPSTimeStamp. */ void cnvExifDate(const char* from, const char* to); /*! @brief Exif version to XMP conversion function. Converts ExifVersion tag to XmpText value. */ void cnvExifVersion(const char* from, const char* to); /*! @brief Exif GPS version to XMP conversion function. Converts GPSVersionID tag to XmpText value. */ void cnvExifGPSVersion(const char* from, const char* to); /*! @brief Exif Flash to XMP conversion function. Converts Flash tag to XMP structure. */ void cnvExifFlash(const char* from, const char* to); /*! @brief Exif GPS coordinate to XMP conversion function. Converts GPS coordinates tag to XmpText value. It combines multiple Exif tags as described in XMP specification. */ void cnvExifGPSCoord(const char* from, const char* to); /*! @brief Simple XMP to Exif conversion function. Sets the Exif tag according to the XMP property. For LangAlt values, only the x-default entry is used. Todo: Escape non-ASCII characters in XMP text values */ void cnvXmpValue(const char* from, const char* to); /*! @brief Convert the tag Xmp.exif.UserComment to Exif. */ void cnvXmpComment(const char* from, const char* to); /*! @brief Converts XMP array to Exif tag with multiple components. Converts XMP array to Exif tag with multiple components. This function is used for ComponentsConfiguration tag. */ void cnvXmpArray(const char* from, const char* to); /*! @brief XMP to Exif date conversion function. Converts the XmpText value to Exif date and time. This function sets multiple Exif tags as described in XMP specification. It is used for DateTime, DateTimeOriginal, DateTimeDigitized and GPSTimeStamp. */ void cnvXmpDate(const char* from, const char* to); /*! @brief XMP to Exif version conversion function. Converts XmpText value to ExifVersion tag. */ void cnvXmpVersion(const char* from, const char* to); /*! @brief XMP to Exif GPS version conversion function. Converts XmpText value to GPSVersionID tag. */ void cnvXmpGPSVersion(const char* from, const char* to); /*! @brief XMP to Exif Flash conversion function. Converts XMP structure to Flash tag. */ void cnvXmpFlash(const char* from, const char* to); /*! @brief XMP to Exif GPS coordinate conversion function. Converts XmpText value to GPS coordinates tags. It sets multiple Exif tags as described in XMP specification. */ void cnvXmpGPSCoord(const char* from, const char* to); /*! @brief IPTC dataset to XMP conversion function. Multiple IPTC datasets with the same key are converted to an XMP array. */ void cnvIptcValue(const char* from, const char* to); /*! @brief XMP to IPTC dataset conversion function. Each array element of an XMP array value is added as one IPTC dataset. */ void cnvXmpValueToIptc(const char* from, const char* to); /*! @brief Write exif:NativeDigest and tiff:NativeDigest properties to XMP. Compute digests from Exif values and write them to exif:NativeDigest and tiff:NativeDigest properties. This should be compatible with XMP SDK. */ void writeExifDigest(); /*! @brief Copies metadata in appropriate direction. From values of exif:NativeDigest and tiff:NativeDigest detects which of XMP and Exif was updated more recently and copies metadata in appropriate direction. */ void syncExifWithXmp(); //@} //! @name Accessors //@{ //! Get the value of the erase flag, see also setErase(bool on). bool erase() const { return erase_; } //! Get the value of the overwrite flag, see also setOverwrite(bool on). bool overwrite() const { return overwrite_; } //@} private: bool prepareExifTarget(const char* to, bool force =false); bool prepareIptcTarget(const char* to, bool force =false); bool prepareXmpTarget(const char* to, bool force =false); std::string computeExifDigest(bool tiff); std::string computeIptcDigest(); // DATA static const Conversion conversion_[]; //findKey(ExifKey(to)); if (pos == exifData_->end()) return true; if (!overwrite_ && !force) return false; exifData_->erase(pos); return true; } bool Converter::prepareIptcTarget(const char* to, bool force) { Exiv2::IptcData::iterator pos = iptcData_->findKey(IptcKey(to)); if (pos == iptcData_->end()) return true; if (!overwrite_ && !force) return false; while ((pos = iptcData_->findKey(IptcKey(to))) != iptcData_->end()) { iptcData_->erase(pos); } return true; } bool Converter::prepareXmpTarget(const char* to, bool force) { Exiv2::XmpData::iterator pos = xmpData_->findKey(XmpKey(to)); if (pos == xmpData_->end()) return true; if (!overwrite_ && !force) return false; xmpData_->erase(pos); return true; } void Converter::cnvExifValue(const char* from, const char* to) { Exiv2::ExifData::iterator pos = exifData_->findKey(ExifKey(from)); if (pos == exifData_->end()) return; std::string value = pos->toString(); if (!pos->value().ok()) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Failed to convert " << from << " to " << to << "\n"; #endif return; } if (!prepareXmpTarget(to)) return; (*xmpData_)[to] = value; if (erase_) exifData_->erase(pos); } void Converter::cnvExifComment(const char* from, const char* to) { Exiv2::ExifData::iterator pos = exifData_->findKey(ExifKey(from)); if (pos == exifData_->end()) return; if (!prepareXmpTarget(to)) return; const CommentValue* cv = dynamic_cast(&pos->value()); if (cv == 0) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Failed to convert " << from << " to " << to << "\n"; #endif return; } // Todo: Convert to UTF-8 if necessary (*xmpData_)[to] = cv->comment(); if (erase_) exifData_->erase(pos); } void Converter::cnvExifArray(const char* from, const char* to) { Exiv2::ExifData::iterator pos = exifData_->findKey(ExifKey(from)); if (pos == exifData_->end()) return; if (!prepareXmpTarget(to)) return; for (int i = 0; i < pos->count(); ++i) { std::string value = pos->toString(i); if (!pos->value().ok()) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Failed to convert " << from << " to " << to << "\n"; #endif return; } (*xmpData_)[to] = value; } if (erase_) exifData_->erase(pos); } void Converter::cnvExifDate(const char* from, const char* to) { Exiv2::ExifData::iterator pos = exifData_->findKey(ExifKey(from)); if (pos == exifData_->end()) return; if (!prepareXmpTarget(to)) return; int year, month, day, hour, min, sec; std::string subsec; char buf[30]; if (std::string(from) != "Exif.GPSInfo.GPSTimeStamp") { std::string value = pos->toString(); if (!pos->value().ok()) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Failed to convert " << from << " to " << to << "\n"; #endif return; } if (sscanf(value.c_str(), "%d:%d:%d %d:%d:%d", &year, &month, &day, &hour, &min, &sec) != 6) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Failed to convert " << from << " to " << to << ", unable to parse '" << value << "'\n"; #endif return; } } else { // "Exif.GPSInfo.GPSTimeStamp" bool ok = true; if (pos->count() != 3) ok = false; if (ok) { for (int i = 0; i < 3; ++i) { if (pos->toRational(i).second == 0) { ok = false; break; } } } if (!ok) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Failed to convert " << from << " to " << to << "\n"; #endif return; } double dhour = pos->toFloat(0); double dmin = pos->toFloat(1); // Hack: Need Value::toDouble Rational r = pos->toRational(2); double dsec = static_cast(r.first)/r.second; if (!pos->value().ok()) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Failed to convert " << from << " to " << to << "\n"; #endif return; } dsec = dhour * 3600.0 + dmin * 60.0 + dsec; hour = static_cast(dsec / 3600.0); dsec -= hour * 3600; min = static_cast(dsec / 60.0); dsec -= min * 60; sec = static_cast(dsec); dsec -= sec; snprintf(buf, sizeof(buf), "%.9f", dsec); buf[sizeof(buf) - 1] = 0; buf[1] = '.'; // some locales use ',' subsec = buf + 1; Exiv2::ExifData::iterator datePos = exifData_->findKey(ExifKey("Exif.GPSInfo.GPSDateStamp")); if (datePos == exifData_->end()) { datePos = exifData_->findKey(ExifKey("Exif.Photo.DateTimeOriginal")); } if (datePos == exifData_->end()) { datePos = exifData_->findKey(ExifKey("Exif.Photo.DateTimeDigitized")); } if (datePos == exifData_->end()) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Failed to convert " << from << " to " << to << "\n"; #endif return; } std::string value = datePos->toString(); if (sscanf(value.c_str(), "%d:%d:%d", &year, &month, &day) != 3) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Failed to convert " << from << " to " << to << ", unable to parse '" << value << "'\n"; #endif return; } } const char* subsecTag = 0; if (std::string(from) == "Exif.Image.DateTime") { subsecTag = "Exif.Photo.SubSecTime"; } else if (std::string(from) == "Exif.Photo.DateTimeOriginal") { subsecTag = "Exif.Photo.SubSecTimeOriginal"; } else if (std::string(from) == "Exif.Photo.DateTimeDigitized") { subsecTag = "Exif.Photo.SubSecTimeDigitized"; } if (subsecTag) { ExifData::iterator subsec_pos = exifData_->findKey(ExifKey(subsecTag)); if ( subsec_pos != exifData_->end() && subsec_pos->typeId() == asciiString) { std::string ss = subsec_pos->toString(); if (!ss.empty()) { bool ok = false; stringTo(ss, ok); if (ok) subsec = std::string(".") + ss; } } if (erase_) exifData_->erase(subsec_pos); } if (subsec.size() > 10) subsec = subsec.substr(0, 10); snprintf(buf, sizeof(buf), "%4d-%02d-%02dT%02d:%02d:%02d%s", year, month, day, hour, min, sec, subsec.c_str()); buf[sizeof(buf) - 1] = 0; (*xmpData_)[to] = buf; if (erase_) exifData_->erase(pos); } void Converter::cnvExifVersion(const char* from, const char* to) { Exiv2::ExifData::iterator pos = exifData_->findKey(ExifKey(from)); if (pos == exifData_->end()) return; if (!prepareXmpTarget(to)) return; std::ostringstream value; for (int i = 0; i < pos->count(); ++i) { value << static_cast(pos->toLong(i)); } (*xmpData_)[to] = value.str(); if (erase_) exifData_->erase(pos); } void Converter::cnvExifGPSVersion(const char* from, const char* to) { Exiv2::ExifData::iterator pos = exifData_->findKey(ExifKey(from)); if (pos == exifData_->end()) return; if (!prepareXmpTarget(to)) return; std::ostringstream value; for (int i = 0; i < pos->count(); ++i) { if (i > 0) value << '.'; value << pos->toLong(i); } (*xmpData_)[to] = value.str(); if (erase_) exifData_->erase(pos); } void Converter::cnvExifFlash(const char* from, const char* to) { Exiv2::ExifData::iterator pos = exifData_->findKey(ExifKey(from)); if (pos == exifData_->end() || pos->count() == 0) return; if (!prepareXmpTarget(to)) return; int value = pos->toLong(); if (!pos->value().ok()) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Failed to convert " << from << " to " << to << "\n"; #endif return; } (*xmpData_)["Xmp.exif.Flash/exif:Fired"] = static_cast(value & 1); (*xmpData_)["Xmp.exif.Flash/exif:Return"] = (value >> 1) & 3; (*xmpData_)["Xmp.exif.Flash/exif:Mode"] = (value >> 3) & 3; (*xmpData_)["Xmp.exif.Flash/exif:Function"] = static_cast((value >> 5) & 1); (*xmpData_)["Xmp.exif.Flash/exif:RedEyeMode"] = static_cast((value >> 6) & 1); if (erase_) exifData_->erase(pos); } void Converter::cnvExifGPSCoord(const char* from, const char* to) { Exiv2::ExifData::iterator pos = exifData_->findKey(ExifKey(from)); if (pos == exifData_->end()) return; if (!prepareXmpTarget(to)) return; if (pos->count() != 3) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Failed to convert " << from << " to " << to << "\n"; #endif return; } Exiv2::ExifData::iterator refPos = exifData_->findKey(ExifKey(std::string(from) + "Ref")); if (refPos == exifData_->end()) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Failed to convert " << from << " to " << to << "\n"; #endif return; } double deg[3]; for (int i = 0; i < 3; ++i) { const int32_t z = pos->toRational(i).first; const int32_t d = pos->toRational(i).second; if (d == 0) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Failed to convert " << from << " to " << to << "\n"; #endif return; } // Hack: Need Value::toDouble deg[i] = static_cast(z)/d; } double min = deg[0] * 60.0 + deg[1] + deg[2] / 60.0; int ideg = static_cast(min / 60.0); min -= ideg * 60; std::ostringstream oss; oss << ideg << "," << std::fixed << std::setprecision(7) << min << refPos->toString().c_str()[0]; (*xmpData_)[to] = oss.str(); if (erase_) exifData_->erase(pos); if (erase_) exifData_->erase(refPos); } void Converter::cnvXmpValue(const char* from, const char* to) { Exiv2::XmpData::iterator pos = xmpData_->findKey(XmpKey(from)); if (pos == xmpData_->end()) return; if (!prepareExifTarget(to)) return; std::string value; if (!getTextValue(value, pos)) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Failed to convert " << from << " to " << to << "\n"; #endif return; } // Todo: Escape non-ASCII characters in XMP text values ExifKey key(to); Exifdatum ed(key); if (0 == ed.setValue(value)) { exifData_->add(ed); } if (erase_) xmpData_->erase(pos); } void Converter::cnvXmpComment(const char* from, const char* to) { if (!prepareExifTarget(to)) return; Exiv2::XmpData::iterator pos = xmpData_->findKey(XmpKey(from)); if (pos == xmpData_->end()) return; std::string value; if (!getTextValue(value, pos)) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Failed to convert " << from << " to " << to << "\n"; #endif return; } // Assumes the XMP value is encoded in UTF-8, as it should be (*exifData_)[to] = "charset=Unicode " + value; if (erase_) xmpData_->erase(pos); } void Converter::cnvXmpArray(const char* from, const char* to) { if (!prepareExifTarget(to)) return; Exiv2::XmpData::iterator pos = xmpData_->findKey(XmpKey(from)); if (pos == xmpData_->end()) return; std::ostringstream array; for (int i = 0; i < pos->count(); ++i) { std::string value = pos->toString(i); if (!pos->value().ok()) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Failed to convert " << from << " to " << to << "\n"; #endif return; } array << value; if (i != pos->count() - 1) array << " "; } (*exifData_)[to] = array.str(); if (erase_) xmpData_->erase(pos); } void Converter::cnvXmpDate(const char* from, const char* to) { Exiv2::XmpData::iterator pos = xmpData_->findKey(XmpKey(from)); if (pos == xmpData_->end()) return; if (!prepareExifTarget(to)) return; #ifdef EXV_HAVE_XMP_TOOLKIT std::string value = pos->toString(); if (!pos->value().ok()) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Failed to convert " << from << " to " << to << "\n"; #endif return; } XMP_DateTime datetime; try { SXMPUtils::ConvertToDate(value, &datetime); } #ifndef SUPPRESS_WARNINGS catch (const XMP_Error& e) { EXV_WARNING << "Failed to convert " << from << " to " << to << " (" << e.GetErrMsg() << ")\n"; return; } #else catch (const XMP_Error&) { return; } #endif // SUPPRESS_WARNINGS char buf[30]; if (std::string(to) != "Exif.GPSInfo.GPSTimeStamp") { SXMPUtils::ConvertToLocalTime(&datetime); snprintf(buf, sizeof(buf), "%4d:%02d:%02d %02d:%02d:%02d", static_cast(datetime.year), static_cast(datetime.month), static_cast(datetime.day), static_cast(datetime.hour), static_cast(datetime.minute), static_cast(datetime.second)); buf[sizeof(buf) - 1] = 0; (*exifData_)[to] = buf; if (datetime.nanoSecond) { const char* subsecTag = 0; if (std::string(to) == "Exif.Image.DateTime") { subsecTag = "Exif.Photo.SubSecTime"; } else if (std::string(to) == "Exif.Photo.DateTimeOriginal") { subsecTag = "Exif.Photo.SubSecTimeOriginal"; } else if (std::string(to) == "Exif.Photo.DateTimeDigitized") { subsecTag = "Exif.Photo.SubSecTimeDigitized"; } if (subsecTag) { prepareExifTarget(subsecTag, true); (*exifData_)[subsecTag] = toString(datetime.nanoSecond); } } } else { // "Exif.GPSInfo.GPSTimeStamp" // Ignore the time zone, assuming the time is in UTC as it should be URational rhour(datetime.hour, 1); URational rmin(datetime.minute, 1); URational rsec(datetime.second, 1); if (datetime.nanoSecond != 0) { if (datetime.second != 0) { // Add the seconds to rmin so that the ns fit into rsec rmin.second = 60; rmin.first *= 60; rmin.first += datetime.second; } rsec.second = 1000000000; rsec.first = datetime.nanoSecond; } std::ostringstream array; array << rhour << " " << rmin << " " << rsec; (*exifData_)[to] = array.str(); prepareExifTarget("Exif.GPSInfo.GPSDateStamp", true); snprintf(buf, sizeof(buf), "%4d:%02d:%02d", static_cast(datetime.year), static_cast(datetime.month), static_cast(datetime.day)); buf[sizeof(buf) - 1] = 0; (*exifData_)["Exif.GPSInfo.GPSDateStamp"] = buf; } if (erase_) xmpData_->erase(pos); #else # ifndef SUPPRESS_WARNINGS EXV_WARNING << "Failed to convert " << from << " to " << to << "\n"; # endif #endif // !EXV_HAVE_XMP_TOOLKIT } void Converter::cnvXmpVersion(const char* from, const char* to) { Exiv2::XmpData::iterator pos = xmpData_->findKey(XmpKey(from)); if (pos == xmpData_->end()) return; if (!prepareExifTarget(to)) return; std::string value = pos->toString(); if (!pos->value().ok() || value.length() < 4) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Failed to convert " << from << " to " << to << "\n"; #endif return; } std::ostringstream array; array << static_cast(value[0]) << " " << static_cast(value[1]) << " " << static_cast(value[2]) << " " << static_cast(value[3]); (*exifData_)[to] = array.str(); if (erase_) xmpData_->erase(pos); } void Converter::cnvXmpGPSVersion(const char* from, const char* to) { Exiv2::XmpData::iterator pos = xmpData_->findKey(XmpKey(from)); if (pos == xmpData_->end()) return; if (!prepareExifTarget(to)) return; std::string value = pos->toString(); if (!pos->value().ok()) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Failed to convert " << from << " to " << to << "\n"; #endif return; } for (unsigned i = 0; i < value.length(); ++i) { if (value[i] == '.') value[i] = ' '; } (*exifData_)[to] = value; if (erase_) xmpData_->erase(pos); } void Converter::cnvXmpFlash(const char* from, const char* to) { Exiv2::XmpData::iterator pos = xmpData_->findKey(XmpKey(std::string(from) + "/exif:Fired")); if (pos == xmpData_->end()) return; if (!prepareExifTarget(to)) return; unsigned short value = 0; if (pos != xmpData_->end() && pos->count() > 0) { int fired = pos->toLong(); if (pos->value().ok()) value |= fired & 1; #ifndef SUPPRESS_WARNINGS else EXV_WARNING << "Failed to convert " << std::string(from) + "/exif:Fired" << " to " << to << "\n"; #endif } pos = xmpData_->findKey(XmpKey(std::string(from) + "/exif:Return")); if (pos != xmpData_->end() && pos->count() > 0) { int ret = pos->toLong(); if (pos->value().ok()) value |= (ret & 3) << 1; #ifndef SUPPRESS_WARNINGS else EXV_WARNING << "Failed to convert " << std::string(from) + "/exif:Return" << " to " << to << "\n"; #endif } pos = xmpData_->findKey(XmpKey(std::string(from) + "/exif:Mode")); if (pos != xmpData_->end() && pos->count() > 0) { int mode = pos->toLong(); if (pos->value().ok()) value |= (mode & 3) << 3; #ifndef SUPPRESS_WARNINGS else EXV_WARNING << "Failed to convert " << std::string(from) + "/exif:Mode" << " to " << to << "\n"; #endif } pos = xmpData_->findKey(XmpKey(std::string(from) + "/exif:Function")); if (pos != xmpData_->end() && pos->count() > 0) { int function = pos->toLong(); if (pos->value().ok()) value |= (function & 1) << 5; #ifndef SUPPRESS_WARNINGS else EXV_WARNING << "Failed to convert " << std::string(from) + "/exif:Function" << " to " << to << "\n"; #endif } pos = xmpData_->findKey(XmpKey(std::string(from) + "/exif:RedEyeMode")); if (pos != xmpData_->end() && pos->count() > 0) { int red = pos->toLong(); if (pos->value().ok()) value |= (red & 1) << 6; #ifndef SUPPRESS_WARNINGS else EXV_WARNING << "Failed to convert " << std::string(from) + "/exif:RedEyeMode" << " to " << to << "\n"; #endif } (*exifData_)[to] = value; if (erase_) xmpData_->erase(pos); } void Converter::cnvXmpGPSCoord(const char* from, const char* to) { Exiv2::XmpData::iterator pos = xmpData_->findKey(XmpKey(from)); if (pos == xmpData_->end()) return; if (!prepareExifTarget(to)) return; std::string value = pos->toString(); if (!pos->value().ok()) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Failed to convert " << from << " to " << to << "\n"; #endif return; } if (value.empty()) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << from << " is empty\n"; #endif return; } double deg = 0.0; double min = 0.0; double sec = 0.0; char ref = '\0'; char sep1 = '\0'; char sep2 = '\0'; ref = value[value.length() - 1]; value.erase(value.length() - 1); std::istringstream in(value); in >> deg >> sep1 >> min >> sep2; if (sep2 == ',') { in >> sec; } else { sec = (min - static_cast(min)) * 60.0; min = static_cast(static_cast(min)); sep2 = ','; } if ( in.bad() || !(ref == 'N' || ref == 'S' || ref == 'E' || ref == 'W') || sep1 != ',' || sep2 != ',' || !in.eof()) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Failed to convert " << from << " to " << to << "\n"; #endif return; } Rational rdeg = floatToRationalCast(static_cast(deg)); Rational rmin = floatToRationalCast(static_cast(min)); Rational rsec = floatToRationalCast(static_cast(sec)); std::ostringstream array; array << rdeg << " " << rmin << " " << rsec; (*exifData_)[to] = array.str(); prepareExifTarget((std::string(to) + "Ref").c_str(), true); char ref_str[2] = {ref, 0}; (*exifData_)[std::string(to) + "Ref"] = ref_str; if (erase_) xmpData_->erase(pos); } void Converter::cnvIptcValue(const char* from, const char* to) { Exiv2::IptcData::iterator pos = iptcData_->findKey(IptcKey(from)); if (pos == iptcData_->end()) return; if (!prepareXmpTarget(to)) return; while (pos != iptcData_->end()) { if (pos->key() == from) { std::string value = pos->toString(); if (!pos->value().ok()) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Failed to convert " << from << " to " << to << "\n"; #endif ++pos; continue; } if (iptcCharset_) convertStringCharset(value, iptcCharset_, "UTF-8"); (*xmpData_)[to] = value; if (erase_) { pos = iptcData_->erase(pos); continue; } } ++pos; } } void Converter::cnvXmpValueToIptc(const char* from, const char* to) { XmpData::iterator pos = xmpData_->findKey(XmpKey(from)); if (pos == xmpData_->end()) return; if (!prepareIptcTarget(to)) return; if (pos->typeId() == langAlt || pos->typeId() == xmpText) { std::string value; if (!getTextValue(value, pos)) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Failed to convert " << from << " to " << to << "\n"; #endif return; } (*iptcData_)[to] = value; (*iptcData_)["Iptc.Envelope.CharacterSet"] = "\033%G"; // indicate UTF-8 encoding if (erase_) xmpData_->erase(pos); return; } int count = pos->count(); bool added = false; for (int i = 0; i < count; ++i) { std::string value = pos->toString(i); if (!pos->value().ok()) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Failed to convert " << from << " to " << to << "\n"; #endif continue; } IptcKey key(to); Iptcdatum id(key); id.setValue(value); iptcData_->add(id); added = true; } if (added) (*iptcData_)["Iptc.Envelope.CharacterSet"] = "\033%G"; // indicate UTF-8 encoding if (erase_) xmpData_->erase(pos); } std::string Converter::computeExifDigest(bool tiff) { #ifdef EXV_HAVE_XMP_TOOLKIT std::ostringstream res; MD5_CTX context; unsigned char digest[16]; MD5Init ( &context ); for (unsigned int i = 0; i < EXV_COUNTOF(conversion_); ++i) { const Conversion& c = conversion_[i]; if (c.metadataId_ == mdExif) { Exiv2::ExifKey key(c.key1_); if (tiff && key.groupName() != "Image") continue; if (!tiff && key.groupName() == "Image") continue; if (!res.str().empty()) res << ','; res << key.tag(); Exiv2::ExifData::iterator pos = exifData_->findKey(key); if (pos == exifData_->end()) continue; DataBuf data(pos->size()); pos->copy(data.pData_, littleEndian /* FIXME ? */); MD5Update ( &context, data.pData_, data.size_); } } MD5Final(digest, &context); res << ';'; res << std::setw(2) << std::setfill('0') << std::hex << std::uppercase; for (int i = 0; i < 16; ++i) { res << static_cast(digest[i]); } return res.str(); #else return std::string(""); #endif } void Converter::writeExifDigest() { #ifdef EXV_HAVE_XMP_TOOLKIT (*xmpData_)["Xmp.tiff.NativeDigest"] = computeExifDigest(true); (*xmpData_)["Xmp.exif.NativeDigest"] = computeExifDigest(false); #endif } void Converter::syncExifWithXmp() { Exiv2::XmpData::iterator td = xmpData_->findKey(XmpKey("Xmp.tiff.NativeDigest")); Exiv2::XmpData::iterator ed = xmpData_->findKey(XmpKey("Xmp.exif.NativeDigest")); if (td != xmpData_->end() && ed != xmpData_->end()) { if (td->value().toString() == computeExifDigest(true) && ed->value().toString() == computeExifDigest(false)) { // We have both digests and the values match // XMP is up-to-date, we should update Exif setOverwrite(true); setErase(false); cnvFromXmp(); writeExifDigest(); return; } else { // We have both digests and the values do not match // Exif was modified after XMP, we should update XMP setOverwrite(true); setErase(false); cnvToXmp(); writeExifDigest(); return; } } else { // We don't have both digests, it is probably the first conversion to XMP setOverwrite(false); // to be safe setErase(false); cnvToXmp(); writeExifDigest(); return; } } std::string Converter::computeIptcDigest() { #ifdef EXV_HAVE_XMP_TOOLKIT std::ostringstream res; MD5_CTX context; unsigned char digest[16]; MD5Init(&context); DataBuf data = IptcParser::encode(*iptcData_); MD5Update(&context, data.pData_, data.size_); MD5Final(digest, &context); res << std::setw(2) << std::setfill('0') << std::hex << std::uppercase; for (int i = 0; i < 16; ++i) { res << static_cast(digest[i]); } return res.str(); #else return std::string(""); #endif } // ************************************************************************* // free functions void copyExifToXmp(const ExifData& exifData, XmpData& xmpData) { Converter converter(const_cast(exifData), xmpData); converter.cnvToXmp(); } void moveExifToXmp(ExifData& exifData, XmpData& xmpData) { Converter converter(const_cast(exifData), xmpData); converter.setErase(); converter.cnvToXmp(); } void copyXmpToExif(const XmpData& xmpData, ExifData& exifData) { Converter converter(exifData, const_cast(xmpData)); converter.cnvFromXmp(); } void moveXmpToExif(XmpData& xmpData, ExifData& exifData) { Converter converter(exifData, const_cast(xmpData)); converter.setErase(); converter.cnvFromXmp(); } void syncExifWithXmp(ExifData& exifData, XmpData& xmpData) { Converter converter(exifData, const_cast(xmpData)); converter.syncExifWithXmp(); } void copyIptcToXmp(const IptcData& iptcData, XmpData& xmpData, const char *iptcCharset) { if (!iptcCharset) iptcCharset = iptcData.detectCharset(); if (!iptcCharset) iptcCharset = "ISO-8859-1"; Converter converter(const_cast(iptcData), xmpData, iptcCharset); converter.cnvToXmp(); } void moveIptcToXmp(IptcData& iptcData, XmpData& xmpData, const char *iptcCharset) { if (!iptcCharset) iptcCharset = iptcData.detectCharset(); if (!iptcCharset) iptcCharset = "ISO-8859-1"; Converter converter(const_cast(iptcData), xmpData, iptcCharset); converter.setErase(); converter.cnvToXmp(); } void copyXmpToIptc(const XmpData& xmpData, IptcData& iptcData) { Converter converter(iptcData, const_cast(xmpData)); converter.cnvFromXmp(); } void moveXmpToIptc(XmpData& xmpData, IptcData& iptcData) { Converter converter(iptcData, const_cast(xmpData)); converter.setErase(); converter.cnvFromXmp(); } bool convertStringCharset(std::string &str, const char* from, const char* to) { if (0 == strcmp(from, to)) return true; // nothing to do bool ret = false; #if defined EXV_HAVE_ICONV ret = convertStringCharsetIconv(str, from, to); #elif defined WIN32 && !defined __CYGWIN__ ret = convertStringCharsetWindows(str, from, to); #else # ifndef SUPPRESS_WARNINGS EXV_WARNING << "Charset conversion required but no character mapping functionality available.\n"; # endif #endif return ret; } } // namespace Exiv2 // ***************************************************************************** // local definitions namespace { using namespace Exiv2; #if defined WIN32 && !defined __CYGWIN__ bool swapBytes(std::string& str) { // Naive byte-swapping, I'm sure this can be done more efficiently if (str.size() & 1) { #ifdef DEBUG EXV_DEBUG << "swapBytes: Size " << str.size() << " of input string is not even.\n"; #endif return false; } for (unsigned int i = 0; i < str.size() / 2; ++i) { char t = str[2 * i]; str[2 * i] = str[2 * i + 1]; str[2 * i + 1] = t; } return true; } bool mb2wc(UINT cp, std::string& str) { if (str.empty()) return true; int len = MultiByteToWideChar(cp, 0, str.c_str(), (int)str.size(), 0, 0); if (len == 0) { #ifdef DEBUG EXV_DEBUG << "mb2wc: Failed to determine required size of output buffer.\n"; #endif return false; } std::vector out; out.resize(len * 2); int ret = MultiByteToWideChar(cp, 0, str.c_str(), (int)str.size(), (LPWSTR)&out[0], len * 2); if (ret == 0) { #ifdef DEBUG EXV_DEBUG << "mb2wc: Failed to convert the input string to a wide character string.\n"; #endif return false; } str.assign(out.begin(), out.end()); return true; } bool wc2mb(UINT cp, std::string& str) { if (str.empty()) return true; if (str.size() & 1) { #ifdef DEBUG EXV_DEBUG << "wc2mb: Size " << str.size() << " of input string is not even.\n"; #endif return false; } int len = WideCharToMultiByte(cp, 0, (LPCWSTR)str.data(), (int)str.size() / 2, 0, 0, 0, 0); if (len == 0) { #ifdef DEBUG EXV_DEBUG << "wc2mb: Failed to determine required size of output buffer.\n"; #endif return false; } std::vector out; out.resize(len); int ret = WideCharToMultiByte(cp, 0, (LPCWSTR)str.data(), (int)str.size() / 2, (LPSTR)&out[0], len, 0, 0); if (ret == 0) { #ifdef DEBUG EXV_DEBUG << "wc2mb: Failed to convert the input string to a multi byte string.\n"; #endif return false; } str.assign(out.begin(), out.end()); return true; } bool utf8ToUcs2be(std::string& str) { bool ret = mb2wc(CP_UTF8, str); if (ret) ret = swapBytes(str); return ret; } bool utf8ToUcs2le(std::string& str) { return mb2wc(CP_UTF8, str); } bool ucs2beToUtf8(std::string& str) { bool ret = swapBytes(str); if (ret) ret = wc2mb(CP_UTF8, str); return ret; } bool ucs2beToUcs2le(std::string& str) { return swapBytes(str); } bool ucs2leToUtf8(std::string& str) { return wc2mb(CP_UTF8, str); } bool ucs2leToUcs2be(std::string& str) { return swapBytes(str); } bool iso88591ToUtf8(std::string& str) { bool ret = mb2wc(28591, str); if (ret) ret = wc2mb(CP_UTF8, str); return ret; } bool asciiToUtf8(std::string& /*str*/) { // nothing to do return true; } typedef bool (*ConvFct)(std::string& str); struct ConvFctList { bool operator==(std::pair fromTo) const { return 0 == strcmp(from_, fromTo.first) && 0 == strcmp(to_, fromTo.second); } const char* from_; const char* to_; ConvFct convFct_; }; const ConvFctList convFctList[] = { { "UTF-8", "UCS-2BE", utf8ToUcs2be }, { "UTF-8", "UCS-2LE", utf8ToUcs2le }, { "UCS-2BE", "UTF-8", ucs2beToUtf8 }, { "UCS-2BE", "UCS-2LE", ucs2beToUcs2le }, { "UCS-2LE", "UTF-8", ucs2leToUtf8 }, { "UCS-2LE", "UCS-2BE", ucs2leToUcs2be }, { "ISO-8859-1", "UTF-8", iso88591ToUtf8 }, { "ASCII", "UTF-8", asciiToUtf8 } // Update the convertStringCharset() documentation if you add more here! }; bool convertStringCharsetWindows(std::string& str, const char* from, const char* to) { bool ret = false; const ConvFctList* p = find(convFctList, std::make_pair(from, to)); std::string tmpstr = str; if (p) ret = p->convFct_(tmpstr); #ifndef SUPPRESS_WARNINGS else { EXV_WARNING << "No Windows function to map character string from " << from << " to " << to << " available.\n"; } #endif if (ret) str = tmpstr; return ret; } #endif // defined WIN32 && !defined __CYGWIN__ #if defined EXV_HAVE_ICONV bool convertStringCharsetIconv(std::string& str, const char* from, const char* to) { if (0 == strcmp(from, to)) return true; // nothing to do bool ret = true; iconv_t cd; cd = iconv_open(to, from); if (cd == (iconv_t)(-1)) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "iconv_open: " << strError() << "\n"; #endif return false; } std::string outstr; EXV_ICONV_CONST char* inptr = const_cast(str.c_str()); size_t inbytesleft = str.length(); while (inbytesleft) { char outbuf[256]; char* outptr = outbuf; size_t outbytesleft = sizeof(outbuf); size_t rc = iconv(cd, &inptr, &inbytesleft, &outptr, &outbytesleft); int outbytesProduced = sizeof(outbuf) - outbytesleft; if (rc == size_t(-1) && errno != E2BIG) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "iconv: " << strError() << " inbytesleft = " << inbytesleft << "\n"; #endif ret = false; break; } outstr.append(std::string(outbuf, outbytesProduced)); } if (cd != (iconv_t)(-1)) { iconv_close(cd); } if (ret) str = outstr; return ret; } #endif // EXV_HAVE_ICONV bool getTextValue(std::string& value, const XmpData::iterator& pos) { if (pos->typeId() == langAlt) { // get the default language entry without x-default qualifier value = pos->toString(0); if (!pos->value().ok() && pos->count() == 1) { // If there is no default but exactly one entry, take that // without the qualifier value = pos->toString(); if ( pos->value().ok() && value.length() > 5 && value.substr(0, 5) == "lang=") { std::string::size_type pos = value.find_first_of(' '); if (pos != std::string::npos) { value = value.substr(pos + 1); } else { value.clear(); } } } } else { value = pos->toString(); } return pos->value().ok(); } } exiv2-0.23/src/value.hpp0000644000175000017500000016726311732641407014747 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! @file value.hpp @brief Value interface and concrete subclasses @version $Rev: 2681 $ @author Andreas Huggel (ahu) ahuggel@gmx.net @date 09-Jan-04, ahu: created 11-Feb-04, ahu: isolated as a component 31-Jul-04, brad: added Time, Data and String values */ #ifndef VALUE_HPP_ #define VALUE_HPP_ // ***************************************************************************** // included header files #include "types.hpp" // + standard includes #include #include #include #include #include #include #include #include // ***************************************************************************** // namespace extensions namespace Exiv2 { // ***************************************************************************** // class definitions /*! @brief Common interface for all types of values used with metadata. The interface provides a uniform way to access values independent of their actual C++ type for simple tasks like reading the values from a string or data buffer. For other tasks, like modifying values you may need to downcast it to a specific subclass to access its interface. */ class EXIV2API Value { public: //! Shortcut for a %Value auto pointer. typedef std::auto_ptr AutoPtr; //! @name Creators //@{ //! Constructor, taking a type id to initialize the base class with explicit Value(TypeId typeId); //! Virtual destructor. virtual ~Value(); //@} //! @name Manipulators //@{ /*! @brief Read the value from a character buffer. @param buf Pointer to the data buffer to read from @param len Number of bytes in the data buffer @param byteOrder Applicable byte order (little or big endian). @return 0 if successful. */ virtual int read(const byte* buf, long len, ByteOrder byteOrder) =0; /*! @brief Set the value from a string buffer. The format of the string corresponds to that of the write() method, i.e., a string obtained through the write() method can be read by this function. @param buf The string to read from. @return 0 if successful. */ virtual int read(const std::string& buf) =0; /*! @brief Set the data area, if the value has one by copying (cloning) the buffer pointed to by buf. Values may have a data area, which can contain additional information besides the actual value. This method is used to set such a data area. @param buf Pointer to the source data area @param len Size of the data area @return Return -1 if the value has no data area, else 0. */ virtual int setDataArea(const byte* buf, long len); //@} //! @name Accessors //@{ //! Return the type identifier (Exif data format type). TypeId typeId() const { return type_; } /*! @brief Return an auto-pointer to a copy of itself (deep copy). The caller owns this copy and the auto-pointer ensures that it will be deleted. */ AutoPtr clone() const { return AutoPtr(clone_()); } /*! @brief Write value to a data buffer. The user must ensure that the buffer has enough memory. Otherwise the call results in undefined behaviour. @param buf Data buffer to write to. @param byteOrder Applicable byte order (little or big endian). @return Number of bytes written. */ virtual long copy(byte* buf, ByteOrder byteOrder) const =0; //! Return the number of components of the value virtual long count() const =0; //! Return the size of the value in bytes virtual long size() const =0; /*! @brief Write the value to an output stream. You do not usually have to use this function; it is used for the implementation of the output operator for %Value, operator<<(std::ostream &os, const Value &value). */ virtual std::ostream& write(std::ostream& os) const =0; /*! @brief Return the value as a string. Implemented in terms of write(std::ostream& os) const of the concrete class. */ std::string toString() const; /*! @brief Return the n-th component of the value as a string. The default implementation returns toString(). The behaviour of this method may be undefined if there is no n-th component. */ virtual std::string toString(long n) const; /*! @brief Convert the n-th component of the value to a long. The behaviour of this method may be undefined if there is no n-th component. @return The converted value. */ virtual long toLong(long n =0) const =0; /*! @brief Convert the n-th component of the value to a float. The behaviour of this method may be undefined if there is no n-th component. @return The converted value. */ virtual float toFloat(long n =0) const =0; /*! @brief Convert the n-th component of the value to a Rational. The behaviour of this method may be undefined if there is no n-th component. @return The converted value. */ virtual Rational toRational(long n =0) const =0; //! Return the size of the data area, 0 if there is none. virtual long sizeDataArea() const; /*! @brief Return a copy of the data area if the value has one. The caller owns this copy and DataBuf ensures that it will be deleted. Values may have a data area, which can contain additional information besides the actual value. This method is used to access such a data area. @return A DataBuf containing a copy of the data area or an empty DataBuf if the value does not have a data area assigned. */ virtual DataBuf dataArea() const; /*! @brief Check the \em ok status indicator. After a to conversion, this indicator shows whether the conversion was successful. */ bool ok() const { return ok_; } //@} /*! @brief A (simple) factory to create a Value type. The following Value subclasses are created depending on typeId:

typeId%Value subclass
invalidTypeId%DataValue(invalidTypeId)
unsignedByte%DataValue(unsignedByte)
asciiString%AsciiValue
string%StringValue
unsignedShort%ValueType < uint16_t >
unsignedLong%ValueType < uint32_t >
unsignedRational%ValueType < URational >
invalid6%DataValue(invalid6)
undefined%DataValue
signedShort%ValueType < int16_t >
signedLong%ValueType < int32_t >
signedRational%ValueType < Rational >
tiffFloat%ValueType < float >
tiffDouble%ValueType < double >
tiffIfd%ValueType < uint32_t >
date%DateValue
time%TimeValue
comment%CommentValue
xmpText%XmpTextValue
xmpBag%XmpArrayValue
xmpSeq%XmpArrayValue
xmpAlt%XmpArrayValue
langAlt%LangAltValue
default:%DataValue(typeId)
@param typeId Type of the value. @return Auto-pointer to the newly created Value. The caller owns this copy and the auto-pointer ensures that it will be deleted. */ static AutoPtr create(TypeId typeId); protected: /*! @brief Assignment operator. Protected so that it can only be used by subclasses but not directly. */ Value& operator=(const Value& rhs); // DATA mutable bool ok_; //!< Indicates the status of the previous to conversion private: //! Internal virtual copy constructor. virtual Value* clone_() const =0; // DATA TypeId type_; //!< Type of the data }; // class Value //! Output operator for Value types inline std::ostream& operator<<(std::ostream& os, const Value& value) { return value.write(os); } //! %Value for an undefined data type. class EXIV2API DataValue : public Value { public: //! Shortcut for a %DataValue auto pointer. typedef std::auto_ptr AutoPtr; //! @name Creators //@{ //! Default constructor. explicit DataValue(TypeId typeId =undefined); //! Constructor DataValue(const byte* buf, long len, ByteOrder byteOrder =invalidByteOrder, TypeId typeId =undefined); //! Virtual destructor. virtual ~DataValue(); //@} //! @name Manipulators //@{ /*! @brief Read the value from a character buffer. @note The byte order is required by the interface but not used by this method, so just use the default. @param buf Pointer to the data buffer to read from @param len Number of bytes in the data buffer @param byteOrder Byte order. Not needed. @return 0 if successful. */ virtual int read(const byte* buf, long len, ByteOrder byteOrder =invalidByteOrder); //! Set the data from a string of integer values (e.g., "0 1 2 3") virtual int read(const std::string& buf); //@} //! @name Accessors //@{ AutoPtr clone() const { return AutoPtr(clone_()); } /*! @brief Write value to a character data buffer. @note The byte order is required by the interface but not used by this method, so just use the default. The user must ensure that the buffer has enough memory. Otherwise the call results in undefined behaviour. @param buf Data buffer to write to. @param byteOrder Byte order. Not needed. @return Number of characters written. */ virtual long copy(byte* buf, ByteOrder byteOrder =invalidByteOrder) const; virtual long count() const; virtual long size() const; virtual std::ostream& write(std::ostream& os) const; /*! @brief Return the n-th component of the value as a string. The behaviour of this method may be undefined if there is no n-th component. */ virtual std::string toString(long n) const; virtual long toLong(long n =0) const; virtual float toFloat(long n =0) const; virtual Rational toRational(long n =0) const; //@} private: //! Internal virtual copy constructor. EXV_DLLLOCAL virtual DataValue* clone_() const; public: //! Type used to store the data. typedef std::vector ValueType; // DATA ValueType value_; //!< Stores the data value }; // class DataValue /*! @brief Abstract base class for a string based %Value type. Uses a std::string to store the value and implements defaults for most operations. */ class EXIV2API StringValueBase : public Value { public: //! Shortcut for a %StringValueBase auto pointer. typedef std::auto_ptr AutoPtr; //! @name Creators //@{ //! Constructor for subclasses explicit StringValueBase(TypeId typeId); //! Constructor for subclasses StringValueBase(TypeId typeId, const std::string& buf); //! Copy constructor StringValueBase(const StringValueBase& rhs); //! Virtual destructor. virtual ~StringValueBase(); //@} //! @name Manipulators //@{ //! Read the value from buf. This default implementation uses buf as it is. virtual int read(const std::string& buf); /*! @brief Read the value from a character buffer. @note The byte order is required by the interface but not used by this method, so just use the default. @param buf Pointer to the data buffer to read from @param len Number of bytes in the data buffer @param byteOrder Byte order. Not needed. @return 0 if successful. */ virtual int read(const byte* buf, long len, ByteOrder byteOrder =invalidByteOrder); //@} //! @name Accessors //@{ AutoPtr clone() const { return AutoPtr(clone_()); } /*! @brief Write value to a character data buffer. The user must ensure that the buffer has enough memory. Otherwise the call results in undefined behaviour. @note The byte order is required by the interface but not used by this method, so just use the default. @param buf Data buffer to write to. @param byteOrder Byte order. Not used. @return Number of characters written. */ virtual long copy(byte* buf, ByteOrder byteOrder =invalidByteOrder) const; virtual long count() const; virtual long size() const; virtual long toLong(long n =0) const; virtual float toFloat(long n =0) const; virtual Rational toRational(long n =0) const; virtual std::ostream& write(std::ostream& os) const; //@} protected: //! Assignment operator. StringValueBase& operator=(const StringValueBase& rhs); //! Internal virtual copy constructor. virtual StringValueBase* clone_() const =0; public: // DATA std::string value_; //!< Stores the string value. }; // class StringValueBase /*! @brief %Value for string type. This can be a plain Ascii string or a multipe byte encoded string. It is left to caller to decode and encode the string to and from readable text if that is required. */ class EXIV2API StringValue : public StringValueBase { public: //! Shortcut for a %StringValue auto pointer. typedef std::auto_ptr AutoPtr; //! @name Creators //@{ //! Default constructor. StringValue(); //! Constructor explicit StringValue(const std::string& buf); //! Virtual destructor. virtual ~StringValue(); //@} //! @name Accessors //@{ AutoPtr clone() const { return AutoPtr(clone_()); } //@} private: //! Internal virtual copy constructor. EXV_DLLLOCAL virtual StringValue* clone_() const; }; // class StringValue /*! @brief %Value for an Ascii string type. This class is for null terminated single byte Ascii strings. This class also ensures that the string is null terminated. */ class EXIV2API AsciiValue : public StringValueBase { public: //! Shortcut for a %AsciiValue auto pointer. typedef std::auto_ptr AutoPtr; //! @name Creators //@{ //! Default constructor. AsciiValue(); //! Constructor explicit AsciiValue(const std::string& buf); //! Virtual destructor. virtual ~AsciiValue(); //@} //! @name Manipulators //@{ using StringValueBase::read; /*! @brief Set the value to that of the string buf. Overrides base class to append a terminating '\\0' character if buf doesn't end with '\\0'. */ virtual int read(const std::string& buf); //@} //! @name Accessors //@{ AutoPtr clone() const { return AutoPtr(clone_()); } /*! @brief Write the value to an output stream. Any trailing '\\0' characters of the ASCII value are stripped and not written to the output stream. */ virtual std::ostream& write(std::ostream& os) const; //@} private: //! Internal virtual copy constructor. EXV_DLLLOCAL virtual AsciiValue* clone_() const; }; // class AsciiValue /*! @brief %Value for an Exif comment. This can be a plain Ascii string or a multipe byte encoded string. The comment is expected to be encoded in the character set indicated (default undefined), but this is not checked. It is left to caller to decode and encode the string to and from readable text if that is required. */ class EXIV2API CommentValue : public StringValueBase { public: //! Character set identifiers for the character sets defined by %Exif enum CharsetId { ascii, jis, unicode, undefined, invalidCharsetId, lastCharsetId }; //! Information pertaining to the defined character sets struct CharsetTable { //! Constructor CharsetTable(CharsetId charsetId, const char* name, const char* code); CharsetId charsetId_; //!< Charset id const char* name_; //!< Name of the charset const char* code_; //!< Code of the charset }; // struct CharsetTable //! Charset information lookup functions. Implemented as a static class. class EXIV2API CharsetInfo { //! Prevent construction: not implemented. CharsetInfo() {} //! Prevent copy-construction: not implemented. CharsetInfo(const CharsetInfo&); //! Prevent assignment: not implemented. CharsetInfo& operator=(const CharsetInfo&); public: //! Return the name for a charset id static const char* name(CharsetId charsetId); //! Return the code for a charset id static const char* code(CharsetId charsetId); //! Return the charset id for a name static CharsetId charsetIdByName(const std::string& name); //! Return the charset id for a code static CharsetId charsetIdByCode(const std::string& code); private: static const CharsetTable charsetTable_[]; }; // class CharsetInfo //! Shortcut for a %CommentValue auto pointer. typedef std::auto_ptr AutoPtr; //! @name Creators //@{ //! Default constructor. CommentValue(); //! Constructor, uses read(const std::string& comment) explicit CommentValue(const std::string& comment); //! Virtual destructor. virtual ~CommentValue(); //@} //! @name Manipulators //@{ /*! @brief Read the value from a comment The format of \em comment is:
[charset=["]Ascii|Jis|Unicode|Undefined["] ]comment
The default charset is Undefined. @return 0 if successful
1 if an invalid character set is encountered */ int read(const std::string& comment); /*! @brief Read the comment from a byte buffer. */ int read(const byte* buf, long len, ByteOrder byteOrder); //@} //! @name Accessors //@{ AutoPtr clone() const { return AutoPtr(clone_()); } long copy(byte* buf, ByteOrder byteOrder) const; /*! @brief Write the comment in a format which can be read by read(const std::string& comment). */ std::ostream& write(std::ostream& os) const; /*! @brief Return the comment (without a charset="..." prefix) The comment is decoded to UTF-8. For Exif UNICODE comments, the function makes an attempt to correctly determine the character encoding of the value. Alternatively, the optional \em encoding parameter can be used to specify it. @param encoding Optional argument to specify the character encoding that the comment is encoded in, as an iconv(3) name. Only used for Exif UNICODE comments. @return A string containing the comment converted to UTF-8. */ std::string comment(const char* encoding =0) const; /*! @brief Determine the character encoding that was used to encode the UNICODE comment value as an iconv(3) name. If the comment \em c starts with a BOM, the BOM is interpreted and removed from the string. Todo: Implement rules to guess if the comment is UTF-8 encoded. */ const char* detectCharset(std::string& c) const; //! Return the Exif charset id of the comment CharsetId charsetId() const; //@} private: //! Internal virtual copy constructor. EXV_DLLLOCAL virtual CommentValue* clone_() const; public: // DATA ByteOrder byteOrder_; //!< Byte order of the comment string that was read }; // class CommentValue /*! @brief Base class for all Exiv2 values used to store XMP property values. */ class EXIV2API XmpValue : public Value { public: //! Shortcut for a %XmpValue auto pointer. typedef std::auto_ptr AutoPtr; //! XMP array types. enum XmpArrayType { xaNone, xaAlt, xaBag, xaSeq }; //! XMP structure indicator. enum XmpStruct { xsNone, xsStruct }; //! @name Creators //@{ explicit XmpValue(TypeId typeId); //@} //! @name Accessors //@{ //! Return XMP array type, indicates if an XMP value is an array. XmpArrayType xmpArrayType() const; //! Return XMP struct, indicates if an XMP value is a structure. XmpStruct xmpStruct() const; virtual long size() const; /*! @brief Write value to a character data buffer. The user must ensure that the buffer has enough memory. Otherwise the call results in undefined behaviour. @note The byte order is required by the interface but not used by this method, so just use the default. @param buf Data buffer to write to. @param byteOrder Byte order. Not used. @return Number of characters written. */ virtual long copy(byte* buf, ByteOrder byteOrder =invalidByteOrder) const; //@} //! @name Manipulators //@{ //! Set the XMP array type to indicate that an XMP value is an array. void setXmpArrayType(XmpArrayType xmpArrayType); //! Set the XMP struct type to indicate that an XMP value is a structure. void setXmpStruct(XmpStruct xmpStruct =xsStruct); /*! @brief Read the value from a character buffer. Uses read(const std::string& buf) @note The byte order is required by the interface but not used by this method, so just use the default. @param buf Pointer to the data buffer to read from @param len Number of bytes in the data buffer @param byteOrder Byte order. Not needed. @return 0 if successful. */ virtual int read(const byte* buf, long len, ByteOrder byteOrder =invalidByteOrder); virtual int read(const std::string& buf) =0; //@} /*! @brief Return XMP array type for an array Value TypeId, xaNone if \em typeId is not an XMP array value type. */ static XmpArrayType xmpArrayType(TypeId typeId); protected: /*! @brief Assignment operator. Protected so that it can only be used by subclasses but not directly. */ XmpValue& operator=(const XmpValue& rhs); private: // DATA XmpArrayType xmpArrayType_; //!< Type of XMP array XmpStruct xmpStruct_; //!< XMP structure indicator }; // class XmpValue /*! @brief %Value type suitable for simple XMP properties and XMP nodes of complex types which are not parsed into specific values. Uses a std::string to store the value. */ class EXIV2API XmpTextValue : public XmpValue { public: //! Shortcut for a %XmpTextValue auto pointer. typedef std::auto_ptr AutoPtr; //! @name Creators //@{ //! Constructor. XmpTextValue(); //! Constructor, reads the value from a string. explicit XmpTextValue(const std::string& buf); //@} //! @name Manipulators //@{ using XmpValue::read; /*! @brief Read a simple property value from \em buf to set the value. Sets the value to the contents of \em buf. A optional keyword, \em type is supported to set the XMP value type. This is useful for complex value types for which Exiv2 does not have direct support. The format of \em buf is:
[type=["]Alt|Bag|Seq|Struct["] ]text
@return 0 if successful. */ virtual int read(const std::string& buf); //@} //! @name Accessors //@{ AutoPtr clone() const; long size() const; virtual long count() const; /*! @brief Convert the value to a long. The optional parameter \em n is not used and is ignored. @return The converted value. */ virtual long toLong(long n =0) const; /*! @brief Convert the value to a float. The optional parameter \em n is not used and is ignored. @return The converted value. */ virtual float toFloat(long n =0) const; /*! @brief Convert the value to a Rational. The optional parameter \em n is not used and is ignored. @return The converted value. */ virtual Rational toRational(long n =0) const; virtual std::ostream& write(std::ostream& os) const; //@} private: //! Internal virtual copy constructor. EXV_DLLLOCAL virtual XmpTextValue* clone_() const; public: // DATA std::string value_; //!< Stores the string values. }; // class XmpTextValue /*! @brief %Value type for simple arrays. Each item in the array is a simple value, without qualifiers. The array may be an ordered (\em seq), unordered (\em bag) or alternative array (\em alt). The array items must not contain qualifiers. For language alternatives use LangAltValue. Uses a vector of std::string to store the value(s). */ class EXIV2API XmpArrayValue : public XmpValue { public: //! Shortcut for a %XmpArrayValue auto pointer. typedef std::auto_ptr AutoPtr; //! @name Creators //@{ //! Constructor. \em typeId can be one of xmpBag, xmpSeq or xmpAlt. explicit XmpArrayValue(TypeId typeId =xmpBag); //@} //! @name Manipulators //@{ using XmpValue::read; /*! @brief Read a simple property value from \em buf and append it to the value. Appends \em buf to the value after the last existing array element. Subsequent calls will therefore populate multiple array elements in the order they are read. @return 0 if successful. */ virtual int read(const std::string& buf); //@} //! @name Accessors //@{ AutoPtr clone() const; virtual long count() const; /*! @brief Return the n-th component of the value as a string. The behaviour of this method may be undefined if there is no n-th component. */ virtual std::string toString(long n) const; virtual long toLong(long n =0) const; virtual float toFloat(long n =0) const; virtual Rational toRational(long n =0) const; /*! @brief Write all elements of the value to \em os, separated by commas. @note The output of this method cannot directly be used as the parameter for read(). */ virtual std::ostream& write(std::ostream& os) const; //@} private: //! Internal virtual copy constructor. EXV_DLLLOCAL virtual XmpArrayValue* clone_() const; public: //! Type used to store XMP array elements. typedef std::vector ValueType; // DATA std::vector value_; //!< Stores the string values. }; // class XmpArrayValue /*! @brief %Value type for XMP language alternative properties. A language alternative is an array consisting of simple text values, each of which has a language qualifier. */ class EXIV2API LangAltValue : public XmpValue { public: //! Shortcut for a %LangAltValue auto pointer. typedef std::auto_ptr AutoPtr; //! @name Creators //@{ //! Constructor. LangAltValue(); //! Constructor, reads the value from a string. explicit LangAltValue(const std::string& buf); //@} //! @name Manipulators //@{ using XmpValue::read; /*! @brief Read a simple property value from \em buf and append it to the value. Appends \em buf to the value after the last existing array element. Subsequent calls will therefore populate multiple array elements in the order they are read. The format of \em buf is:
[lang=["]language code["] ]text
The XMP default language code x-default is used if \em buf doesn't start with the keyword lang. @return 0 if successful. */ virtual int read(const std::string& buf); //@} //! @name Accessors //@{ AutoPtr clone() const; virtual long count() const; /*! @brief Return the text value associated with the default language qualifier \c x-default. The parameter \em n is not used, but it is suggested that only 0 is passed in. Returns an empty string and sets the ok-flag to \c false if there is no default value. */ virtual std::string toString(long n) const; /*! @brief Return the text value associated with the language qualifier \em qualifier. Returns an empty string and sets the ok-flag to \c false if there is no entry for the language qualifier. */ std::string toString(const std::string& qualifier) const; virtual long toLong(long n =0) const; virtual float toFloat(long n =0) const; virtual Rational toRational(long n =0) const; /*! @brief Write all elements of the value to \em os, separated by commas. @note The output of this method cannot directly be used as the parameter for read(). */ virtual std::ostream& write(std::ostream& os) const; //@} private: //! Internal virtual copy constructor. EXV_DLLLOCAL virtual LangAltValue* clone_() const; public: //! Type used to store language alternative arrays. typedef std::map ValueType; // DATA /*! @brief Map to store the language alternative values. The language qualifier is used as the key for the map entries. */ ValueType value_; }; // class LangAltValue /*! @brief %Value for simple ISO 8601 dates This class is limited to parsing simple date strings in the ISO 8601 format CCYYMMDD (century, year, month, day). */ class EXIV2API DateValue : public Value { public: //! Shortcut for a %DateValue auto pointer. typedef std::auto_ptr AutoPtr; //! @name Creators //@{ //! Default constructor. DateValue(); //! Constructor DateValue(int year, int month, int day); //! Virtual destructor. virtual ~DateValue(); //@} //! Simple Date helper structure EXIV2API struct Date { Date() : year(0), month(0), day(0) {} int year; //!< Year int month; //!< Month int day; //!< Day }; //! @name Manipulators //@{ /*! @brief Read the value from a character buffer. @note The byte order is required by the interface but not used by this method, so just use the default. @param buf Pointer to the data buffer to read from @param len Number of bytes in the data buffer @param byteOrder Byte order. Not needed. @return 0 if successful
1 in case of an unsupported date format */ virtual int read(const byte* buf, long len, ByteOrder byteOrder =invalidByteOrder); /*! @brief Set the value to that of the string buf. @param buf String containing the date @return 0 if successful
1 in case of an unsupported date format */ virtual int read(const std::string& buf); //! Set the date void setDate(const Date& src); //@} //! @name Accessors //@{ AutoPtr clone() const { return AutoPtr(clone_()); } /*! @brief Write value to a character data buffer. The user must ensure that the buffer has enough memory. Otherwise the call results in undefined behaviour. @note The byte order is required by the interface but not used by this method, so just use the default. @param buf Data buffer to write to. @param byteOrder Byte order. Not used. @return Number of characters written. */ virtual long copy(byte* buf, ByteOrder byteOrder =invalidByteOrder) const; //! Return date struct containing date information virtual const Date& getDate() const; virtual long count() const; virtual long size() const; virtual std::ostream& write(std::ostream& os) const; //! Return the value as a UNIX calender time converted to long. virtual long toLong(long n =0) const; //! Return the value as a UNIX calender time converted to float. virtual float toFloat(long n =0) const; //! Return the value as a UNIX calender time converted to Rational. virtual Rational toRational(long n =0) const; //@} private: //! Internal virtual copy constructor. EXV_DLLLOCAL virtual DateValue* clone_() const; // DATA Date date_; }; // class DateValue /*! @brief %Value for simple ISO 8601 times. This class is limited to handling simple time strings in the ISO 8601 format HHMMSS±HHMM where HHMMSS refers to local hour, minute and seconds and ±HHMM refers to hours and minutes ahead or behind Universal Coordinated Time. */ class EXIV2API TimeValue : public Value { public: //! Shortcut for a %TimeValue auto pointer. typedef std::auto_ptr AutoPtr; //! @name Creators //@{ //! Default constructor. TimeValue(); //! Constructor TimeValue(int hour, int minute, int second =0, int tzHour =0, int tzMinute =0); //! Virtual destructor. virtual ~TimeValue(); //@} //! Simple Time helper structure struct Time { Time() : hour(0), minute(0), second(0), tzHour(0), tzMinute(0) {} int hour; //!< Hour int minute; //!< Minute int second; //!< Second int tzHour; //!< Hours ahead or behind UTC int tzMinute; //!< Minutes ahead or behind UTC }; //! @name Manipulators //@{ /*! @brief Read the value from a character buffer. @note The byte order is required by the interface but not used by this method, so just use the default. @param buf Pointer to the data buffer to read from @param len Number of bytes in the data buffer @param byteOrder Byte order. Not needed. @return 0 if successful
1 in case of an unsupported time format */ virtual int read(const byte* buf, long len, ByteOrder byteOrder =invalidByteOrder); /*! @brief Set the value to that of the string buf. @param buf String containing the time. @return 0 if successful
1 in case of an unsupported time format */ virtual int read(const std::string& buf); //! Set the time void setTime(const Time& src); //@} //! @name Accessors //@{ AutoPtr clone() const { return AutoPtr(clone_()); } /*! @brief Write value to a character data buffer. The user must ensure that the buffer has enough memory. Otherwise the call results in undefined behaviour. @note The byte order is required by the interface but not used by this method, so just use the default. @param buf Data buffer to write to. @param byteOrder Byte order. Not used. @return Number of characters written. */ virtual long copy(byte* buf, ByteOrder byteOrder =invalidByteOrder) const; //! Return time struct containing time information virtual const Time& getTime() const; virtual long count() const; virtual long size() const; virtual std::ostream& write(std::ostream& os) const; //! Returns number of seconds in the day in UTC. virtual long toLong(long n =0) const; //! Returns number of seconds in the day in UTC converted to float. virtual float toFloat(long n =0) const; //! Returns number of seconds in the day in UTC converted to Rational. virtual Rational toRational(long n =0) const; //@} private: //! @name Manipulators //@{ /*! @brief Set time from \em buf if it conforms to \em format (3 input items). This function only sets the hour, minute and second parts of time_. @param buf A 0 terminated C-string containing the time to parse. @param format Format string for sscanf(). @return 0 if successful, else 1. */ EXV_DLLLOCAL int scanTime3(const char* buf, const char* format); /*! @brief Set time from \em buf if it conforms to \em format (6 input items). This function sets all parts of time_. @param buf A 0 terminated C-string containing the time to parse. @param format Format string for sscanf(). @return 0 if successful, else 1. */ EXV_DLLLOCAL int scanTime6(const char* buf, const char* format); //@} //! @name Accessors //@{ //! Internal virtual copy constructor. EXV_DLLLOCAL virtual TimeValue* clone_() const; //@} // DATA Time time_; }; // class TimeValue //! Template to determine the TypeId for a type T template TypeId getType(); //! Specialization for an unsigned short template<> inline TypeId getType() { return unsignedShort; } //! Specialization for an unsigned long template<> inline TypeId getType() { return unsignedLong; } //! Specialization for an unsigned rational template<> inline TypeId getType() { return unsignedRational; } //! Specialization for a signed short template<> inline TypeId getType() { return signedShort; } //! Specialization for a signed long template<> inline TypeId getType() { return signedLong; } //! Specialization for a signed rational template<> inline TypeId getType() { return signedRational; } //! Specialization for a float template<> inline TypeId getType() { return tiffFloat; } //! Specialization for a double template<> inline TypeId getType() { return tiffDouble; } // No default implementation: let the compiler/linker complain // template inline TypeId getType() { return invalid; } /*! @brief Template for a %Value of a basic type. This is used for unsigned and signed short, long and rationals. */ template class ValueType : public Value { public: //! Shortcut for a %ValueType\ auto pointer. typedef std::auto_ptr > AutoPtr; //! @name Creators //@{ //! Default Constructor. ValueType(); //! Constructor. // The default c'tor and this one can be combined, but that causes MSVC 7.1 to fall on its nose explicit ValueType(TypeId typeId); //! Constructor. ValueType(const byte* buf, long len, ByteOrder byteOrder, TypeId typeId =getType()); //! Constructor. explicit ValueType(const T& val, TypeId typeId =getType()); //! Copy constructor ValueType(const ValueType& rhs); //! Virtual destructor. virtual ~ValueType(); //@} //! @name Manipulators //@{ //! Assignment operator. ValueType& operator=(const ValueType& rhs); virtual int read(const byte* buf, long len, ByteOrder byteOrder); /*! @brief Set the data from a string of values of type T (e.g., "0 1 2 3" or "1/2 1/3 1/4" depending on what T is). Generally, the accepted input format is the same as that produced by the write() method. */ virtual int read(const std::string& buf); /*! @brief Set the data area. This method copies (clones) the buffer pointed to by buf. */ virtual int setDataArea(const byte* buf, long len); //@} //! @name Accessors //@{ AutoPtr clone() const { return AutoPtr(clone_()); } virtual long copy(byte* buf, ByteOrder byteOrder) const; virtual long count() const; virtual long size() const; virtual std::ostream& write(std::ostream& os) const; /*! @brief Return the n-th component of the value as a string. The behaviour of this method may be undefined if there is no n-th component. */ virtual std::string toString(long n) const; virtual long toLong(long n =0) const; virtual float toFloat(long n =0) const; virtual Rational toRational(long n =0) const; //! Return the size of the data area. virtual long sizeDataArea() const; /*! @brief Return a copy of the data area in a DataBuf. The caller owns this copy and DataBuf ensures that it will be deleted. */ virtual DataBuf dataArea() const; //@} //! Container for values typedef std::vector ValueList; //! Iterator type defined for convenience. typedef typename std::vector::iterator iterator; //! Const iterator type defined for convenience. typedef typename std::vector::const_iterator const_iterator; // DATA /*! @brief The container for all values. In your application, if you know what subclass of Value you're dealing with (and possibly the T) then you can access this STL container through the usual standard library functions. */ ValueList value_; private: //! Internal virtual copy constructor. virtual ValueType* clone_() const; // DATA //! Pointer to the buffer, 0 if none has been allocated byte* pDataArea_; //! The current size of the buffer long sizeDataArea_; }; // class ValueType //! Unsigned short value type typedef ValueType UShortValue; //! Unsigned long value type typedef ValueType ULongValue; //! Unsigned rational value type typedef ValueType URationalValue; //! Signed short value type typedef ValueType ShortValue; //! Signed long value type typedef ValueType LongValue; //! Signed rational value type typedef ValueType RationalValue; //! Float value type typedef ValueType FloatValue; //! Double value type typedef ValueType DoubleValue; // ***************************************************************************** // free functions, template and inline definitions /*! @brief Read a value of type T from the data buffer. We need this template function for the ValueType template classes. There are only specializations of this function available; no default implementation is provided. @param buf Pointer to the data buffer to read from. @param byteOrder Applicable byte order (little or big endian). @return A value of type T. */ template T getValue(const byte* buf, ByteOrder byteOrder); // Specialization for a 2 byte unsigned short value. template<> inline uint16_t getValue(const byte* buf, ByteOrder byteOrder) { return getUShort(buf, byteOrder); } // Specialization for a 4 byte unsigned long value. template<> inline uint32_t getValue(const byte* buf, ByteOrder byteOrder) { return getULong(buf, byteOrder); } // Specialization for an 8 byte unsigned rational value. template<> inline URational getValue(const byte* buf, ByteOrder byteOrder) { return getURational(buf, byteOrder); } // Specialization for a 2 byte signed short value. template<> inline int16_t getValue(const byte* buf, ByteOrder byteOrder) { return getShort(buf, byteOrder); } // Specialization for a 4 byte signed long value. template<> inline int32_t getValue(const byte* buf, ByteOrder byteOrder) { return getLong(buf, byteOrder); } // Specialization for an 8 byte signed rational value. template<> inline Rational getValue(const byte* buf, ByteOrder byteOrder) { return getRational(buf, byteOrder); } // Specialization for a 4 byte float value. template<> inline float getValue(const byte* buf, ByteOrder byteOrder) { return getFloat(buf, byteOrder); } // Specialization for a 8 byte double value. template<> inline double getValue(const byte* buf, ByteOrder byteOrder) { return getDouble(buf, byteOrder); } /*! @brief Convert a value of type T to data, write the data to the data buffer. We need this template function for the ValueType template classes. There are only specializations of this function available; no default implementation is provided. @param buf Pointer to the data buffer to write to. @param t Value to be converted. @param byteOrder Applicable byte order (little or big endian). @return The number of bytes written to the buffer. */ template long toData(byte* buf, T t, ByteOrder byteOrder); /*! @brief Specialization to write an unsigned short to the data buffer. Return the number of bytes written. */ template<> inline long toData(byte* buf, uint16_t t, ByteOrder byteOrder) { return us2Data(buf, t, byteOrder); } /*! @brief Specialization to write an unsigned long to the data buffer. Return the number of bytes written. */ template<> inline long toData(byte* buf, uint32_t t, ByteOrder byteOrder) { return ul2Data(buf, t, byteOrder); } /*! @brief Specialization to write an unsigned rational to the data buffer. Return the number of bytes written. */ template<> inline long toData(byte* buf, URational t, ByteOrder byteOrder) { return ur2Data(buf, t, byteOrder); } /*! @brief Specialization to write a signed short to the data buffer. Return the number of bytes written. */ template<> inline long toData(byte* buf, int16_t t, ByteOrder byteOrder) { return s2Data(buf, t, byteOrder); } /*! @brief Specialization to write a signed long to the data buffer. Return the number of bytes written. */ template<> inline long toData(byte* buf, int32_t t, ByteOrder byteOrder) { return l2Data(buf, t, byteOrder); } /*! @brief Specialization to write a signed rational to the data buffer. Return the number of bytes written. */ template<> inline long toData(byte* buf, Rational t, ByteOrder byteOrder) { return r2Data(buf, t, byteOrder); } /*! @brief Specialization to write a float to the data buffer. Return the number of bytes written. */ template<> inline long toData(byte* buf, float t, ByteOrder byteOrder) { return f2Data(buf, t, byteOrder); } /*! @brief Specialization to write a double to the data buffer. Return the number of bytes written. */ template<> inline long toData(byte* buf, double t, ByteOrder byteOrder) { return d2Data(buf, t, byteOrder); } template ValueType::ValueType() : Value(getType()), pDataArea_(0), sizeDataArea_(0) { } template ValueType::ValueType(TypeId typeId) : Value(typeId), pDataArea_(0), sizeDataArea_(0) { } template ValueType::ValueType(const byte* buf, long len, ByteOrder byteOrder, TypeId typeId) : Value(typeId), pDataArea_(0), sizeDataArea_(0) { read(buf, len, byteOrder); } template ValueType::ValueType(const T& val, TypeId typeId) : Value(typeId), pDataArea_(0), sizeDataArea_(0) { value_.push_back(val); } template ValueType::ValueType(const ValueType& rhs) : Value(rhs), value_(rhs.value_), pDataArea_(0), sizeDataArea_(0) { if (rhs.sizeDataArea_ > 0) { pDataArea_ = new byte[rhs.sizeDataArea_]; std::memcpy(pDataArea_, rhs.pDataArea_, rhs.sizeDataArea_); sizeDataArea_ = rhs.sizeDataArea_; } } template ValueType::~ValueType() { delete[] pDataArea_; } template ValueType& ValueType::operator=(const ValueType& rhs) { if (this == &rhs) return *this; Value::operator=(rhs); value_ = rhs.value_; byte* tmp = 0; if (rhs.sizeDataArea_ > 0) { tmp = new byte[rhs.sizeDataArea_]; std::memcpy(tmp, rhs.pDataArea_, rhs.sizeDataArea_); } delete[] pDataArea_; pDataArea_ = tmp; sizeDataArea_ = rhs.sizeDataArea_; return *this; } template int ValueType::read(const byte* buf, long len, ByteOrder byteOrder) { value_.clear(); long ts = TypeInfo::typeSize(typeId()); if (len % ts != 0) len = (len / ts) * ts; for (long i = 0; i < len; i += ts) { value_.push_back(getValue(buf + i, byteOrder)); } return 0; } template int ValueType::read(const std::string& buf) { std::istringstream is(buf); T tmp; ValueList val; while (!(is.eof())) { is >> tmp; if (is.fail()) return 1; val.push_back(tmp); } value_.swap(val); return 0; } template long ValueType::copy(byte* buf, ByteOrder byteOrder) const { long offset = 0; typename ValueList::const_iterator end = value_.end(); for (typename ValueList::const_iterator i = value_.begin(); i != end; ++i) { offset += toData(buf + offset, *i, byteOrder); } return offset; } template long ValueType::count() const { return static_cast(value_.size()); } template long ValueType::size() const { return static_cast(TypeInfo::typeSize(typeId()) * value_.size()); } template ValueType* ValueType::clone_() const { return new ValueType(*this); } template std::ostream& ValueType::write(std::ostream& os) const { typename ValueList::const_iterator end = value_.end(); typename ValueList::const_iterator i = value_.begin(); while (i != end) { os << std::setprecision(15) << *i; if (++i != end) os << " "; } return os; } template std::string ValueType::toString(long n) const { ok_ = true; return Exiv2::toString(value_[n]); } // Default implementation template long ValueType::toLong(long n) const { ok_ = true; return static_cast(value_[n]); } // Specialization for rational template<> inline long ValueType::toLong(long n) const { ok_ = (value_[n].second != 0); if (!ok_) return 0; return value_[n].first / value_[n].second; } // Specialization for unsigned rational template<> inline long ValueType::toLong(long n) const { ok_ = (value_[n].second != 0); if (!ok_) return 0; return value_[n].first / value_[n].second; } // Default implementation template float ValueType::toFloat(long n) const { ok_ = true; return static_cast(value_[n]); } // Specialization for rational template<> inline float ValueType::toFloat(long n) const { ok_ = (value_[n].second != 0); if (!ok_) return 0.0f; return static_cast(value_[n].first) / value_[n].second; } // Specialization for unsigned rational template<> inline float ValueType::toFloat(long n) const { ok_ = (value_[n].second != 0); if (!ok_) return 0.0f; return static_cast(value_[n].first) / value_[n].second; } // Default implementation template Rational ValueType::toRational(long n) const { ok_ = true; return Rational(value_[n], 1); } // Specialization for rational template<> inline Rational ValueType::toRational(long n) const { ok_ = true; return Rational(value_[n].first, value_[n].second); } // Specialization for unsigned rational template<> inline Rational ValueType::toRational(long n) const { ok_ = true; return Rational(value_[n].first, value_[n].second); } // Specialization for float. template<> inline Rational ValueType::toRational(long n) const { ok_ = true; // Warning: This is a very simple conversion, see floatToRationalCast() return floatToRationalCast(value_[n]); } // Specialization for double. template<> inline Rational ValueType::toRational(long n) const { ok_ = true; // Warning: This is a very simple conversion, see floatToRationalCast() return floatToRationalCast(static_cast(value_[n])); } template long ValueType::sizeDataArea() const { return sizeDataArea_; } template DataBuf ValueType::dataArea() const { return DataBuf(pDataArea_, sizeDataArea_); } template int ValueType::setDataArea(const byte* buf, long len) { byte* tmp = 0; if (len > 0) { tmp = new byte[len]; std::memcpy(tmp, buf, len); } delete[] pDataArea_; pDataArea_ = tmp; sizeDataArea_ = len; return 0; } } // namespace Exiv2 #endif // #ifndef VALUE_HPP_ exiv2-0.23/src/preview.cpp0000644000175000017500000012156611741325444015303 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /* File: preview.cpp Version: $Rev: 2698 $ Author(s): Vladimir Nadvornik (vn) History: 18-Sep-08, vn: created */ // ***************************************************************************** #include "rcsid_int.hpp" EXIV2_RCSID("@(#) $Id: preview.cpp 2698 2012-04-11 16:02:44Z ahuggel $") // ***************************************************************************** // included header files #ifdef _MSC_VER # include "exv_msvc.h" #else # include "exv_conf.h" #endif #include #include #include "preview.hpp" #include "futils.hpp" #include "image.hpp" #include "cr2image.hpp" #include "jpgimage.hpp" #include "tiffimage.hpp" #include "tiffimage_int.hpp" // ***************************************************************************** namespace { using namespace Exiv2; /*! @brief Compare two preview images by number of pixels, if width and height of both lhs and rhs are available or else by size. Return true if lhs is smaller than rhs. */ bool cmpPreviewProperties( const PreviewProperties& lhs, const PreviewProperties& rhs ) { uint32_t l = lhs.width_ * lhs.height_; uint32_t r = rhs.width_ * rhs.height_; return l < r; } /*! @brief Decode a Hex string. */ DataBuf decodeHex(const byte *src, long srcSize); /*! @brief Decode a Base64 string. */ DataBuf decodeBase64(const std::string &src); /*! @brief Decode an Illustrator thumbnail that follows after %AI7_Thumbnail. */ DataBuf decodeAi7Thumbnail(const DataBuf &src); /*! @brief Create a PNM image from raw RGB data. */ DataBuf makePnm(uint32_t width, uint32_t height, const DataBuf &rgb); /*! Base class for image loaders. Provides virtual methods for reading properties and DataBuf. */ class Loader { public: //! Virtual destructor. virtual ~Loader() {} //! Loader auto pointer typedef std::auto_ptr AutoPtr; //! Create a Loader subclass for requested id static AutoPtr create(PreviewId id, const Image &image); //! Check if a preview image with given params exists in the image virtual bool valid() const { return valid_; } //! Get properties of a preview image with given params virtual PreviewProperties getProperties() const; //! Get a buffer that contains the preview image virtual DataBuf getData() const = 0; //! Read preview image dimensions when they are not available directly virtual bool readDimensions() { return true; } //! A number of image loaders configured in the loaderList_ table static PreviewId getNumLoaders(); protected: //! Constructor. Sets all image properies to unknown. Loader(PreviewId id, const Image &image); //! Functions that creates a loader from given parameters typedef AutoPtr (*CreateFunc)(PreviewId id, const Image &image, int parIdx); //! Structure to list possible loaders struct LoaderList { const char *imageMimeType_; //!< Image type for which the loader is valid, 0 matches all images CreateFunc create_; //!< Function that creates particular loader instance int parIdx_; //!< Parameter that is passed into CreateFunc }; //! Table that lists possible loaders. PreviewId is an index to this table. static const LoaderList loaderList_[]; //! Identifies preview image type PreviewId id_; //! Source image reference const Image &image_; //! Preview image width uint32_t width_; //! Preview image length uint32_t height_; //! Preview image size in bytes uint32_t size_; //! True if the source image contains a preview image of given type bool valid_; }; //! Loader for native previews class LoaderNative : public Loader { public: //! Constructor LoaderNative(PreviewId id, const Image &image, int parIdx); //! Get properties of a preview image with given params virtual PreviewProperties getProperties() const; //! Get a buffer that contains the preview image virtual DataBuf getData() const; //! Read preview image dimensions virtual bool readDimensions(); protected: //! Native preview information NativePreview nativePreview_; }; //! Function to create new LoaderNative Loader::AutoPtr createLoaderNative(PreviewId id, const Image &image, int parIdx); //! Loader for Jpeg previews that are not read into ExifData directly class LoaderExifJpeg : public Loader { public: //! Constructor LoaderExifJpeg(PreviewId id, const Image &image, int parIdx); //! Get properties of a preview image with given params virtual PreviewProperties getProperties() const; //! Get a buffer that contains the preview image virtual DataBuf getData() const; //! Read preview image dimensions virtual bool readDimensions(); protected: //! Structure that lists offset/size tag pairs struct Param { const char* offsetKey_; //!< Offset tag const char* sizeKey_; //!< Size tag const char* baseOffsetKey_; //!< Tag that holds base offset or 0 }; //! Table that holds all possible offset/size pairs. parIdx is an index to this table static const Param param_[]; //! Offset value uint32_t offset_; }; //! Function to create new LoaderExifJpeg Loader::AutoPtr createLoaderExifJpeg(PreviewId id, const Image &image, int parIdx); //! Loader for Jpeg previews that are read into ExifData class LoaderExifDataJpeg : public Loader { public: //! Constructor LoaderExifDataJpeg(PreviewId id, const Image &image, int parIdx); //! Get properties of a preview image with given params virtual PreviewProperties getProperties() const; //! Get a buffer that contains the preview image virtual DataBuf getData() const; //! Read preview image dimensions virtual bool readDimensions(); protected: //! Structure that lists data/size tag pairs struct Param { const char* dataKey_; //!< Data tag const char* sizeKey_; //!< Size tag }; //! Table that holds all possible data/size pairs. parIdx is an index to this table static const Param param_[]; //! Key that points to the Value that contains the JPEG preview in data area ExifKey dataKey_; }; //! Function to create new LoaderExifDataJpeg Loader::AutoPtr createLoaderExifDataJpeg(PreviewId id, const Image &image, int parIdx); //! Loader for Tiff previews - it can get image data from ExifData or image_.io() as needed class LoaderTiff : public Loader { public: //! Constructor LoaderTiff(PreviewId id, const Image &image, int parIdx); //! Get properties of a preview image with given params virtual PreviewProperties getProperties() const; //! Get a buffer that contains the preview image virtual DataBuf getData() const; protected: //! Name of the group that contains the preview image const char *group_; //! Tag that contains image data. Possible values are "StripOffsets" or "TileOffsets" std::string offsetTag_; //! Tag that contains data sizes. Possible values are "StripByteCounts" or "TileByteCounts" std::string sizeTag_; //! Structure that lists preview groups struct Param { const char* group_; //!< Group name const char* checkTag_; //!< Tag to check or NULL const char* checkValue_; //!< The preview image is valid only if the checkTag_ has this value }; //! Table that holds all possible groups. parIdx is an index to this table. static const Param param_[]; }; //! Function to create new LoaderTiff Loader::AutoPtr createLoaderTiff(PreviewId id, const Image &image, int parIdx); //! Loader for JPEG previews stored in the XMP metadata class LoaderXmpJpeg : public Loader { public: //! Constructor LoaderXmpJpeg(PreviewId id, const Image &image, int parIdx); //! Get properties of a preview image with given params virtual PreviewProperties getProperties() const; //! Get a buffer that contains the preview image virtual DataBuf getData() const; //! Read preview image dimensions virtual bool readDimensions(); protected: //! Preview image data DataBuf preview_; }; //! Function to create new LoaderXmpJpeg Loader::AutoPtr createLoaderXmpJpeg(PreviewId id, const Image &image, int parIdx); // ***************************************************************************** // class member definitions const Loader::LoaderList Loader::loaderList_[] = { { 0, createLoaderNative, 0 }, { 0, createLoaderNative, 1 }, { 0, createLoaderNative, 2 }, { 0, createLoaderNative, 3 }, { 0, createLoaderExifDataJpeg, 0 }, { 0, createLoaderExifDataJpeg, 1 }, { 0, createLoaderExifDataJpeg, 2 }, { 0, createLoaderExifDataJpeg, 3 }, { 0, createLoaderExifDataJpeg, 4 }, { 0, createLoaderExifDataJpeg, 5 }, { 0, createLoaderExifDataJpeg, 6 }, { 0, createLoaderExifDataJpeg, 7 }, { 0, createLoaderExifDataJpeg, 8 }, { "image/x-panasonic-rw2", createLoaderExifDataJpeg, 9 }, { 0, createLoaderExifDataJpeg,10 }, { 0, createLoaderTiff, 0 }, { 0, createLoaderTiff, 1 }, { 0, createLoaderTiff, 2 }, { 0, createLoaderTiff, 3 }, { 0, createLoaderTiff, 4 }, { 0, createLoaderTiff, 5 }, { 0, createLoaderTiff, 6 }, { "image/x-canon-cr2", createLoaderTiff, 7 }, { 0, createLoaderExifJpeg, 0 }, { 0, createLoaderExifJpeg, 1 }, { 0, createLoaderExifJpeg, 2 }, { 0, createLoaderExifJpeg, 3 }, { 0, createLoaderExifJpeg, 4 }, { 0, createLoaderExifJpeg, 5 }, { 0, createLoaderExifJpeg, 6 }, { "image/x-canon-cr2", createLoaderExifJpeg, 7 }, { 0, createLoaderExifJpeg, 8 }, { 0, createLoaderXmpJpeg, 0 } }; const LoaderExifJpeg::Param LoaderExifJpeg::param_[] = { { "Exif.Image.JPEGInterchangeFormat", "Exif.Image.JPEGInterchangeFormatLength", 0 }, // 0 { "Exif.SubImage1.JPEGInterchangeFormat", "Exif.SubImage1.JPEGInterchangeFormatLength", 0 }, // 1 { "Exif.SubImage2.JPEGInterchangeFormat", "Exif.SubImage2.JPEGInterchangeFormatLength", 0 }, // 2 { "Exif.SubImage3.JPEGInterchangeFormat", "Exif.SubImage3.JPEGInterchangeFormatLength", 0 }, // 3 { "Exif.SubImage4.JPEGInterchangeFormat", "Exif.SubImage4.JPEGInterchangeFormatLength", 0 }, // 4 { "Exif.SubThumb1.JPEGInterchangeFormat", "Exif.SubThumb1.JPEGInterchangeFormatLength", 0 }, // 5 { "Exif.Image2.JPEGInterchangeFormat", "Exif.Image2.JPEGInterchangeFormatLength", 0 }, // 6 { "Exif.Image.StripOffsets", "Exif.Image.StripByteCounts", 0 }, // 7 { "Exif.OlympusCs.PreviewImageStart", "Exif.OlympusCs.PreviewImageLength", "Exif.MakerNote.Offset"} // 8 }; const LoaderExifDataJpeg::Param LoaderExifDataJpeg::param_[] = { { "Exif.Thumbnail.JPEGInterchangeFormat", "Exif.Thumbnail.JPEGInterchangeFormatLength" }, // 0 { "Exif.NikonPreview.JPEGInterchangeFormat", "Exif.NikonPreview.JPEGInterchangeFormatLength" }, // 1 { "Exif.Pentax.PreviewOffset", "Exif.Pentax.PreviewLength" }, // 2 { "Exif.PentaxDng.PreviewOffset", "Exif.PentaxDng.PreviewLength" }, // 3 { "Exif.Minolta.ThumbnailOffset", "Exif.Minolta.ThumbnailLength" }, // 4 { "Exif.SonyMinolta.ThumbnailOffset", "Exif.SonyMinolta.ThumbnailLength" }, // 5 { "Exif.Olympus.ThumbnailImage", 0 }, // 6 { "Exif.Olympus2.ThumbnailImage", 0 }, // 7 { "Exif.Minolta.Thumbnail", 0 }, // 8 { "Exif.PanasonicRaw.PreviewImage", 0 }, // 9 { "Exif.SamsungPreview.JPEGInterchangeFormat", "Exif.SamsungPreview.JPEGInterchangeFormatLength" } // 10 }; const LoaderTiff::Param LoaderTiff::param_[] = { { "Image", "Exif.Image.NewSubfileType", "1" }, // 0 { "SubImage1", "Exif.SubImage1.NewSubfileType", "1" }, // 1 { "SubImage2", "Exif.SubImage2.NewSubfileType", "1" }, // 2 { "SubImage3", "Exif.SubImage3.NewSubfileType", "1" }, // 3 { "SubImage4", "Exif.SubImage4.NewSubfileType", "1" }, // 4 { "SubThumb1", "Exif.SubThumb1.NewSubfileType", "1" }, // 5 { "Thumbnail", 0, 0 }, // 6 { "Image2", 0, 0 } // 7 }; Loader::AutoPtr Loader::create(PreviewId id, const Image &image) { if (id < 0 || id >= Loader::getNumLoaders()) return AutoPtr(); if (loaderList_[id].imageMimeType_ && std::string(loaderList_[id].imageMimeType_) != std::string(image.mimeType())) return AutoPtr(); AutoPtr loader = loaderList_[id].create_(id, image, loaderList_[id].parIdx_); if (loader.get() && !loader->valid()) loader.reset(); return loader; } Loader::Loader(PreviewId id, const Image &image) : id_(id), image_(image), width_(0), height_(0), size_(0), valid_(false) { } PreviewProperties Loader::getProperties() const { PreviewProperties prop; prop.id_ = id_; prop.size_ = size_; prop.width_ = width_; prop.height_ = height_; return prop; } PreviewId Loader::getNumLoaders() { return (PreviewId)EXV_COUNTOF(loaderList_); } LoaderNative::LoaderNative(PreviewId id, const Image &image, int parIdx) : Loader(id, image) { if (!(0 <= parIdx && static_cast(parIdx) < image.nativePreviews().size())) return; nativePreview_ = image.nativePreviews()[parIdx]; width_ = nativePreview_.width_; height_ = nativePreview_.height_; valid_ = true; if (nativePreview_.filter_ == "") { size_ = nativePreview_.size_; } else { size_ = getData().size_; } } Loader::AutoPtr createLoaderNative(PreviewId id, const Image &image, int parIdx) { return Loader::AutoPtr(new LoaderNative(id, image, parIdx)); } PreviewProperties LoaderNative::getProperties() const { PreviewProperties prop = Loader::getProperties(); prop.mimeType_ = nativePreview_.mimeType_; if (nativePreview_.mimeType_ == "image/jpeg") { prop.extension_ = ".jpg"; } else if (nativePreview_.mimeType_ == "image/tiff") { prop.extension_ = ".tif"; } else if (nativePreview_.mimeType_ == "image/x-wmf") { prop.extension_ = ".wmf"; } else if (nativePreview_.mimeType_ == "image/x-portable-anymap") { prop.extension_ = ".pnm"; } else { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Unknown native preview format: " << nativePreview_.mimeType_ << "\n"; #endif prop.extension_ = ".dat"; } #ifdef EXV_UNICODE_PATH prop.wextension_ = s2ws(prop.extension_); #endif return prop; } DataBuf LoaderNative::getData() const { if (!valid()) return DataBuf(); BasicIo &io = image_.io(); if (io.open() != 0) { throw Error(9, io.path(), strError()); } IoCloser closer(io); const byte* data = io.mmap(); if (io.size() < nativePreview_.position_ + static_cast(nativePreview_.size_)) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Invalid native preview position or size.\n"; #endif return DataBuf(); } if (nativePreview_.filter_ == "") { return DataBuf(data + nativePreview_.position_, static_cast(nativePreview_.size_)); } else if (nativePreview_.filter_ == "hex-ai7thumbnail-pnm") { const DataBuf ai7thumbnail = decodeHex(data + nativePreview_.position_, static_cast(nativePreview_.size_)); const DataBuf rgb = decodeAi7Thumbnail(ai7thumbnail); return makePnm(width_, height_, rgb); } else if (nativePreview_.filter_ == "hex-irb") { const DataBuf psData = decodeHex(data + nativePreview_.position_, static_cast(nativePreview_.size_)); const byte *record; uint32_t sizeHdr; uint32_t sizeData; if (Photoshop::locatePreviewIrb(psData.pData_, psData.size_, &record, &sizeHdr, &sizeData) != 0) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Missing preview IRB in Photoshop EPS preview.\n"; #endif return DataBuf(); } return DataBuf(record + sizeHdr + 28, sizeData - 28); } else { throw Error(1, "Invalid native preview filter: " + nativePreview_.filter_); } } bool LoaderNative::readDimensions() { if (!valid()) return false; if (width_ != 0 || height_ != 0) return true; const DataBuf data = getData(); if (data.size_ == 0) return false; try { Image::AutoPtr image = ImageFactory::open(data.pData_, data.size_); if (image.get() == 0) return false; image->readMetadata(); width_ = image->pixelWidth(); height_ = image->pixelHeight(); } catch (const AnyError& /* error */) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Invalid native preview image.\n"; #endif return false; } return true; } LoaderExifJpeg::LoaderExifJpeg(PreviewId id, const Image &image, int parIdx) : Loader(id, image) { offset_ = 0; ExifData::const_iterator pos = image_.exifData().findKey(ExifKey(param_[parIdx].offsetKey_)); if (pos != image_.exifData().end() && pos->count() > 0) { offset_ = pos->toLong(); } size_ = 0; pos = image_.exifData().findKey(ExifKey(param_[parIdx].sizeKey_)); if (pos != image_.exifData().end() && pos->count() > 0) { size_ = pos->toLong(); } if (offset_ == 0 || size_ == 0) return; if (param_[parIdx].baseOffsetKey_) { pos = image_.exifData().findKey(ExifKey(param_[parIdx].baseOffsetKey_)); if (pos != image_.exifData().end() && pos->count() > 0) { offset_ += pos->toLong(); } } if (offset_ + size_ > static_cast(image_.io().size())) return; valid_ = true; } Loader::AutoPtr createLoaderExifJpeg(PreviewId id, const Image &image, int parIdx) { return Loader::AutoPtr(new LoaderExifJpeg(id, image, parIdx)); } PreviewProperties LoaderExifJpeg::getProperties() const { PreviewProperties prop = Loader::getProperties(); prop.mimeType_ = "image/jpeg"; prop.extension_ = ".jpg"; #ifdef EXV_UNICODE_PATH prop.wextension_ = EXV_WIDEN(".jpg"); #endif return prop; } DataBuf LoaderExifJpeg::getData() const { if (!valid()) return DataBuf(); BasicIo &io = image_.io(); if (io.open() != 0) { throw Error(9, io.path(), strError()); } IoCloser closer(io); const Exiv2::byte* base = io.mmap(); return DataBuf(base + offset_, size_); } bool LoaderExifJpeg::readDimensions() { if (!valid()) return false; if (width_ || height_) return true; BasicIo &io = image_.io(); if (io.open() != 0) { throw Error(9, io.path(), strError()); } IoCloser closer(io); const Exiv2::byte* base = io.mmap(); try { Image::AutoPtr image = ImageFactory::open(base + offset_, size_); if (image.get() == 0) return false; image->readMetadata(); width_ = image->pixelWidth(); height_ = image->pixelHeight(); } catch (const AnyError& /* error */ ) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Invalid JPEG preview image.\n"; #endif return false; } return true; } LoaderExifDataJpeg::LoaderExifDataJpeg(PreviewId id, const Image &image, int parIdx) : Loader(id, image), dataKey_(param_[parIdx].dataKey_) { ExifData::const_iterator pos = image_.exifData().findKey(dataKey_); if (pos != image_.exifData().end()) { size_ = pos->sizeDataArea(); // indirect data if (size_ == 0 && pos->typeId() == undefined) size_ = pos->size(); // direct data } if (size_ == 0) return; valid_ = true; } Loader::AutoPtr createLoaderExifDataJpeg(PreviewId id, const Image &image, int parIdx) { return Loader::AutoPtr(new LoaderExifDataJpeg(id, image, parIdx)); } PreviewProperties LoaderExifDataJpeg::getProperties() const { PreviewProperties prop = Loader::getProperties(); prop.mimeType_ = "image/jpeg"; prop.extension_ = ".jpg"; #ifdef EXV_UNICODE_PATH prop.wextension_ = EXV_WIDEN(".jpg"); #endif return prop; } DataBuf LoaderExifDataJpeg::getData() const { if (!valid()) return DataBuf(); ExifData::const_iterator pos = image_.exifData().findKey(dataKey_); if (pos != image_.exifData().end()) { DataBuf buf = pos->dataArea(); // indirect data if (buf.size_ == 0) { // direct data buf = DataBuf(pos->size()); pos->copy(buf.pData_, invalidByteOrder); } buf.pData_[0] = 0xff; // fix Minolta thumbnails with invalid jpeg header return buf; } return DataBuf(); } bool LoaderExifDataJpeg::readDimensions() { if (!valid()) return false; DataBuf buf = getData(); if (buf.size_ == 0) return false; try { Image::AutoPtr image = ImageFactory::open(buf.pData_, buf.size_); if (image.get() == 0) return false; image->readMetadata(); width_ = image->pixelWidth(); height_ = image->pixelHeight(); } catch (const AnyError& /* error */ ) { return false; } return true; } LoaderTiff::LoaderTiff(PreviewId id, const Image &image, int parIdx) : Loader(id, image), group_(param_[parIdx].group_) { const ExifData &exifData = image_.exifData(); int offsetCount = 0; ExifData::const_iterator pos; // check if the group_ contains a preview image if (param_[parIdx].checkTag_) { pos = exifData.findKey(ExifKey(param_[parIdx].checkTag_)); if (pos == exifData.end()) return; if (param_[parIdx].checkValue_ && pos->toString() != param_[parIdx].checkValue_) return; } pos = exifData.findKey(ExifKey(std::string("Exif.") + group_ + ".StripOffsets")); if (pos != exifData.end()) { offsetTag_ = "StripOffsets"; sizeTag_ = "StripByteCounts"; offsetCount = pos->value().count(); } else { pos = exifData.findKey(ExifKey(std::string("Exif.") + group_ + ".TileOffsets")); if (pos == exifData.end()) return; offsetTag_ = "TileOffsets"; sizeTag_ = "TileByteCounts"; offsetCount = pos->value().count(); } pos = exifData.findKey(ExifKey(std::string("Exif.") + group_ + '.' + sizeTag_)); if (pos == exifData.end()) return; if (offsetCount != pos->value().count()) return; for (int i = 0; i < offsetCount; i++) { size_ += pos->toLong(i); } if (size_ == 0) return; pos = exifData.findKey(ExifKey(std::string("Exif.") + group_ + ".ImageWidth")); if (pos != exifData.end() && pos->count() > 0) { width_ = pos->toLong(); } pos = exifData.findKey(ExifKey(std::string("Exif.") + group_ + ".ImageLength")); if (pos != exifData.end() && pos->count() > 0) { height_ = pos->toLong(); } if (width_ == 0 || height_ == 0) return; valid_ = true; } Loader::AutoPtr createLoaderTiff(PreviewId id, const Image &image, int parIdx) { return Loader::AutoPtr(new LoaderTiff(id, image, parIdx)); } PreviewProperties LoaderTiff::getProperties() const { PreviewProperties prop = Loader::getProperties(); prop.mimeType_ = "image/tiff"; prop.extension_ = ".tif"; #ifdef EXV_UNICODE_PATH prop.wextension_ = EXV_WIDEN(".tif"); #endif return prop; } DataBuf LoaderTiff::getData() const { const ExifData &exifData = image_.exifData(); ExifData preview; // copy tags for (ExifData::const_iterator pos = exifData.begin(); pos != exifData.end(); ++pos) { if (pos->groupName() == group_) { /* Write only the neccessary TIFF image tags tags that especially could cause problems are: "NewSubfileType" - the result is no longer a thumbnail, it is a standalone image "Orientation" - this tag typically appears only in the "Image" group. Deleting it ensures consistent result for all previews, including JPEG */ uint16_t tag = pos->tag(); if (tag != 0x00fe && tag != 0x00ff && Internal::isTiffImageTag(tag, Internal::ifd0Id)) { preview.add(ExifKey(tag, "Image"), &pos->value()); } } } Value &dataValue = const_cast(preview["Exif.Image." + offsetTag_].value()); if (dataValue.sizeDataArea() == 0) { // image data are not available via exifData, read them from image_.io() BasicIo &io = image_.io(); if (io.open() != 0) { throw Error(9, io.path(), strError()); } IoCloser closer(io); const Exiv2::byte* base = io.mmap(); const Value &sizes = preview["Exif.Image." + sizeTag_].value(); if (sizes.count() == dataValue.count()) { if (sizes.count() == 1) { // this saves one copying of the buffer uint32_t offset = dataValue.toLong(0); uint32_t size = sizes.toLong(0); if (offset + size <= static_cast(io.size())) dataValue.setDataArea(base + offset, size); } else { // FIXME: the buffer is probably copied twice, it should be optimized DataBuf buf(size_); Exiv2::byte* pos = buf.pData_; for (int i = 0; i < sizes.count(); i++) { uint32_t offset = dataValue.toLong(i); uint32_t size = sizes.toLong(i); if (offset + size <= static_cast(io.size())) memcpy(pos, base + offset, size); pos += size; } dataValue.setDataArea(buf.pData_, buf.size_); } } } // Fix compression value in the CR2 IFD2 image if (0 == strcmp(group_, "Image2") && image_.mimeType() == "image/x-canon-cr2") { preview["Exif.Image.Compression"] = uint16_t(1); } // write new image MemIo mio; IptcData emptyIptc; XmpData emptyXmp; TiffParser::encode(mio, 0, 0, Exiv2::littleEndian, preview, emptyIptc, emptyXmp); return DataBuf(mio.mmap(), mio.size()); } LoaderXmpJpeg::LoaderXmpJpeg(PreviewId id, const Image &image, int parIdx) : Loader(id, image) { (void)parIdx; const XmpData &xmpData = image_.xmpData(); std::string prefix = "xmpGImg"; if (xmpData.findKey(XmpKey("Xmp.xmp.Thumbnails[1]/xapGImg:image")) != xmpData.end()) { prefix = "xapGImg"; } XmpData::const_iterator imageDatum = xmpData.findKey(XmpKey("Xmp.xmp.Thumbnails[1]/" + prefix + ":image")); if (imageDatum == xmpData.end()) return; XmpData::const_iterator formatDatum = xmpData.findKey(XmpKey("Xmp.xmp.Thumbnails[1]/" + prefix + ":format")); if (formatDatum == xmpData.end()) return; XmpData::const_iterator widthDatum = xmpData.findKey(XmpKey("Xmp.xmp.Thumbnails[1]/" + prefix + ":width")); if (widthDatum == xmpData.end()) return; XmpData::const_iterator heightDatum = xmpData.findKey(XmpKey("Xmp.xmp.Thumbnails[1]/" + prefix + ":height")); if (heightDatum == xmpData.end()) return; if (formatDatum->toString() != "JPEG") return; width_ = widthDatum->toLong(); height_ = heightDatum->toLong(); preview_ = decodeBase64(imageDatum->toString()); size_ = static_cast(preview_.size_); valid_ = true; } Loader::AutoPtr createLoaderXmpJpeg(PreviewId id, const Image &image, int parIdx) { return Loader::AutoPtr(new LoaderXmpJpeg(id, image, parIdx)); } PreviewProperties LoaderXmpJpeg::getProperties() const { PreviewProperties prop = Loader::getProperties(); prop.mimeType_ = "image/jpeg"; prop.extension_ = ".jpg"; #ifdef EXV_UNICODE_PATH prop.wextension_ = EXV_WIDEN(".jpg"); #endif return prop; } DataBuf LoaderXmpJpeg::getData() const { if (!valid()) return DataBuf(); return DataBuf(preview_.pData_, preview_.size_); } bool LoaderXmpJpeg::readDimensions() { return valid(); } DataBuf decodeHex(const byte *src, long srcSize) { // create decoding table byte invalid = 16; byte decodeHexTable[256]; for (long i = 0; i < 256; i++) decodeHexTable[i] = invalid; for (byte i = 0; i < 10; i++) decodeHexTable[static_cast('0') + i] = i; for (byte i = 0; i < 6; i++) decodeHexTable[static_cast('A') + i] = i + 10; for (byte i = 0; i < 6; i++) decodeHexTable[static_cast('a') + i] = i + 10; // calculate dest size long validSrcSize = 0; for (long srcPos = 0; srcPos < srcSize; srcPos++) { if (decodeHexTable[src[srcPos]] != invalid) validSrcSize++; } const long destSize = validSrcSize / 2; // allocate dest buffer DataBuf dest(destSize); // decode for (long srcPos = 0, destPos = 0; destPos < destSize; destPos++) { byte buffer = 0; for (int bufferPos = 1; bufferPos >= 0 && srcPos < srcSize; srcPos++) { byte srcValue = decodeHexTable[src[srcPos]]; if (srcValue == invalid) continue; buffer |= srcValue << (bufferPos * 4); bufferPos--; } dest.pData_[destPos] = buffer; } return dest; } static const char encodeBase64Table[64 + 1] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; DataBuf decodeBase64(const std::string& src) { const unsigned long srcSize = static_cast(src.size()); // create decoding table unsigned long invalid = 64; unsigned long decodeBase64Table[256]; for (unsigned long i = 0; i < 256; i++) decodeBase64Table[i] = invalid; for (unsigned long i = 0; i < 64; i++) decodeBase64Table[(unsigned char)encodeBase64Table[i]] = i; // calculate dest size unsigned long validSrcSize = 0; for (unsigned long srcPos = 0; srcPos < srcSize; srcPos++) { if (decodeBase64Table[(unsigned char)src[srcPos]] != invalid) validSrcSize++; } if (validSrcSize > ULONG_MAX / 3) return DataBuf(); // avoid integer overflow const unsigned long destSize = (validSrcSize * 3) / 4; // allocate dest buffer if (destSize > LONG_MAX) return DataBuf(); // avoid integer overflow DataBuf dest(static_cast(destSize)); // decode for (unsigned long srcPos = 0, destPos = 0; destPos < destSize;) { unsigned long buffer = 0; for (int bufferPos = 3; bufferPos >= 0 && srcPos < srcSize; srcPos++) { unsigned long srcValue = decodeBase64Table[(unsigned char)src[srcPos]]; if (srcValue == invalid) continue; buffer |= srcValue << (bufferPos * 6); bufferPos--; } for (int bufferPos = 2; bufferPos >= 0 && destPos < destSize; bufferPos--, destPos++) { dest.pData_[destPos] = static_cast((buffer >> (bufferPos * 8)) & 0xFF); } } return dest; } DataBuf decodeAi7Thumbnail(const DataBuf &src) { const byte *colorTable = src.pData_; const long colorTableSize = 256 * 3; if (src.size_ < colorTableSize) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Invalid size of AI7 thumbnail: " << src.size_ << "\n"; #endif return DataBuf(); } const byte *imageData = src.pData_ + colorTableSize; const long imageDataSize = src.size_ - colorTableSize; const bool rle = (imageDataSize >= 3 && imageData[0] == 'R' && imageData[1] == 'L' && imageData[2] == 'E'); std::string dest; for (long i = rle ? 3 : 0; i < imageDataSize;) { byte num = 1; byte value = imageData[i++]; if (rle && value == 0xFD) { if (i >= imageDataSize) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Unexpected end of image data at AI7 thumbnail.\n"; #endif return DataBuf(); } value = imageData[i++]; if (value != 0xFD) { if (i >= imageDataSize) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Unexpected end of image data at AI7 thumbnail.\n"; #endif return DataBuf(); } num = value; value = imageData[i++]; } } for (; num != 0; num--) { dest.append(reinterpret_cast(colorTable + (3*value)), 3); } } return DataBuf(reinterpret_cast(dest.data()), static_cast(dest.size())); } DataBuf makePnm(uint32_t width, uint32_t height, const DataBuf &rgb) { const long expectedSize = static_cast(width * height * 3); if (rgb.size_ != expectedSize) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Invalid size of preview data. Expected " << expectedSize << " bytes, got " << rgb.size_ << " bytes.\n"; #endif return DataBuf(); } const std::string header = "P6\n" + toString(width) + " " + toString(height) + "\n255\n"; const byte *headerBytes = reinterpret_cast(header.data()); DataBuf dest(static_cast(header.size() + rgb.size_)); std::copy(headerBytes, headerBytes + header.size(), dest.pData_); std::copy(rgb.pData_, rgb.pData_ + rgb.size_, dest.pData_ + header.size()); return dest; } } // namespace // ***************************************************************************** // class member definitions namespace Exiv2 { PreviewImage::PreviewImage(const PreviewProperties& properties, DataBuf data) : properties_(properties) { pData_ = data.pData_; size_ = data.size_; data.release(); } PreviewImage::~PreviewImage() { delete[] pData_; } PreviewImage::PreviewImage(const PreviewImage& rhs) { properties_ = rhs.properties_; pData_ = new byte[rhs.size_]; memcpy(pData_, rhs.pData_, rhs.size_); size_ = rhs.size_; } PreviewImage& PreviewImage::operator=(const PreviewImage& rhs) { if (this == &rhs) return *this; if (rhs.size_ > size_) { delete[] pData_; pData_ = new byte[rhs.size_]; } properties_ = rhs.properties_; memcpy(pData_, rhs.pData_, rhs.size_); size_ = rhs.size_; return *this; } long PreviewImage::writeFile(const std::string& path) const { std::string name = path + extension(); // Todo: Creating a DataBuf here unnecessarily copies the memory DataBuf buf(pData_, size_); return Exiv2::writeFile(buf, name); } #ifdef EXV_UNICODE_PATH long PreviewImage::writeFile(const std::wstring& wpath) const { std::wstring name = wpath + wextension(); // Todo: Creating a DataBuf here unnecessarily copies the memory DataBuf buf(pData_, size_); return Exiv2::writeFile(buf, name); } #endif DataBuf PreviewImage::copy() const { return DataBuf(pData_, size_); } const byte* PreviewImage::pData() const { return pData_; } uint32_t PreviewImage::size() const { return size_; } std::string PreviewImage::mimeType() const { return properties_.mimeType_; } std::string PreviewImage::extension() const { return properties_.extension_; } #ifdef EXV_UNICODE_PATH std::wstring PreviewImage::wextension() const { return properties_.wextension_; } #endif uint32_t PreviewImage::width() const { return properties_.width_; } uint32_t PreviewImage::height() const { return properties_.height_; } PreviewId PreviewImage::id() const { return properties_.id_; } PreviewManager::PreviewManager(const Image& image) : image_(image) { } PreviewPropertiesList PreviewManager::getPreviewProperties() const { PreviewPropertiesList list; // go through the loader table and store all successfully created loaders in the list for (PreviewId id = 0; id < Loader::getNumLoaders(); ++id) { Loader::AutoPtr loader = Loader::create(id, image_); if (loader.get() && loader->readDimensions()) { list.push_back(loader->getProperties()); } } std::sort(list.begin(), list.end(), cmpPreviewProperties); return list; } PreviewImage PreviewManager::getPreviewImage(const PreviewProperties &properties) const { Loader::AutoPtr loader = Loader::create(properties.id_, image_); DataBuf buf; if (loader.get()) { buf = loader->getData(); } return PreviewImage(properties, buf); } } // namespace Exiv2 exiv2-0.23/src/tgaimage.hpp0000644000175000017500000001165311732641407015400 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! @file tgaimage.hpp @brief Truevision TARGA v2 image, implemented using the following references: Truevision TGA page on Wikipedia
TGA(tm) File Format Specification @version $Rev: 2681 $ @author Marco Piovanelli, Ovolab (marco) marco.piovanelli@pobox.com @date 05-Mar-2007, marco: created */ #ifndef TGAIMAGE_HPP_ #define TGAIMAGE_HPP_ // ***************************************************************************** // included header files #include "exif.hpp" #include "iptc.hpp" #include "image.hpp" #include "types.hpp" // + standard includes #include // ***************************************************************************** // namespace extensions namespace Exiv2 { // ***************************************************************************** // class definitions // Add TARGA to the supported image formats namespace ImageType { const int tga = 13; //!< Truevision TARGA (tga) image type (see class TgaImage) } /*! @brief Class to access raw TARGA images. This is just a stub - we only read width and height. */ class EXIV2API TgaImage : public Image { //! @name NOT Implemented //@{ //! Copy constructor TgaImage(const TgaImage& rhs); //! Assignment operator TgaImage& operator=(const TgaImage& rhs); //@} public: //! @name Creators //@{ /*! @brief Constructor to open a Targa image. Since the constructor can not return a result, callers should check the good() method after object construction to determine success or failure. @param io An auto-pointer that owns a BasicIo instance used for reading and writing image metadata. \b Important: The constructor takes ownership of the passed in BasicIo instance through the auto-pointer. Callers should not continue to use the BasicIo instance after it is passed to this method. Use the Image::io() method to get a temporary reference. */ TgaImage(BasicIo::AutoPtr io); //@} //! @name Manipulators //@{ void readMetadata(); /*! @brief Todo: Write metadata back to the image. This method is not yet(?) implemented. Calling it will throw an Error(31). */ void writeMetadata(); /*! @brief Todo: Not supported yet(?). Calling this function will throw an instance of Error(32). */ void setExifData(const ExifData& exifData); /*! @brief Todo: Not supported yet(?). Calling this function will throw an instance of Error(32). */ void setIptcData(const IptcData& iptcData); /*! @brief Not supported. Calling this function will throw an instance of Error(32). */ void setComment(const std::string& comment); //@} //! @name Accessors //@{ std::string mimeType() const; //@} }; // class TgaImage // ***************************************************************************** // template, inline and free functions // These could be static private functions on Image subclasses but then // ImageFactory needs to be made a friend. /*! @brief Create a new TgaImage instance and return an auto-pointer to it. Caller owns the returned object and the auto-pointer ensures that it will be deleted. */ EXIV2API Image::AutoPtr newTgaInstance(BasicIo::AutoPtr io, bool create); //! Check if the file iIo is a Targa v2 image. EXIV2API bool isTgaType(BasicIo& iIo, bool advance); } // namespace Exiv2 #endif // #ifndef TGAIMAGE_HPP_ exiv2-0.23/src/jpgimage.cpp0000644000175000017500000011516411732641407015402 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /* File: jpgimage.cpp Version: $Rev: 2681 $ Author(s): Andreas Huggel (ahu) Brad Schick (brad) Volker Grabsch (vog) Michael Ulbrich (mul) History: 15-Jan-05, brad: split out from image.cpp */ // ***************************************************************************** #include "rcsid_int.hpp" EXIV2_RCSID("@(#) $Id: jpgimage.cpp 2681 2012-03-22 15:19:35Z ahuggel $") // ***************************************************************************** // included header files #ifdef _MSC_VER # include "exv_msvc.h" #else # include "exv_conf.h" #endif #include "jpgimage.hpp" #include "error.hpp" #include "futils.hpp" // + standard includes #include // for EOF #include #include // ***************************************************************************** // class member definitions namespace Exiv2 { const byte JpegBase::sos_ = 0xda; const byte JpegBase::eoi_ = 0xd9; const byte JpegBase::app0_ = 0xe0; const byte JpegBase::app1_ = 0xe1; const byte JpegBase::app13_ = 0xed; const byte JpegBase::com_ = 0xfe; // Start of Frame markers, nondifferential Huffman-coding frames const byte JpegBase::sof0_ = 0xc0; // start of frame 0, baseline DCT const byte JpegBase::sof1_ = 0xc1; // start of frame 1, extended sequential DCT, Huffman coding const byte JpegBase::sof2_ = 0xc2; // start of frame 2, progressive DCT, Huffman coding const byte JpegBase::sof3_ = 0xc3; // start of frame 3, lossless sequential, Huffman coding // Start of Frame markers, differential Huffman-coding frames const byte JpegBase::sof5_ = 0xc5; // start of frame 5, differential sequential DCT, Huffman coding const byte JpegBase::sof6_ = 0xc6; // start of frame 6, differential progressive DCT, Huffman coding const byte JpegBase::sof7_ = 0xc7; // start of frame 7, differential lossless, Huffman coding // Start of Frame markers, nondifferential arithmetic-coding frames const byte JpegBase::sof9_ = 0xc9; // start of frame 9, extended sequential DCT, arithmetic coding const byte JpegBase::sof10_ = 0xca; // start of frame 10, progressive DCT, arithmetic coding const byte JpegBase::sof11_ = 0xcb; // start of frame 11, lossless sequential, arithmetic coding // Start of Frame markers, differential arithmetic-coding frames const byte JpegBase::sof13_ = 0xcd; // start of frame 13, differential sequential DCT, arithmetic coding const byte JpegBase::sof14_ = 0xce; // start of frame 14, progressive DCT, arithmetic coding const byte JpegBase::sof15_ = 0xcf; // start of frame 15, differential lossless, arithmetic coding const char JpegBase::exifId_[] = "Exif\0\0"; const char JpegBase::jfifId_[] = "JFIF\0"; const char JpegBase::xmpId_[] = "http://ns.adobe.com/xap/1.0/\0"; const char Photoshop::ps3Id_[] = "Photoshop 3.0\0"; const char* Photoshop::irbId_[] = {"8BIM", "AgHg", "DCSR", "PHUT"}; const char Photoshop::bimId_[] = "8BIM"; // deprecated const uint16_t Photoshop::iptc_ = 0x0404; const uint16_t Photoshop::preview_ = 0x040c; bool Photoshop::isIrb(const byte* pPsData, long sizePsData) { if (sizePsData < 4) return false; for (size_t i = 0; i < (sizeof irbId_) / (sizeof *irbId_); i++) { assert(strlen(irbId_[i]) == 4); if (memcmp(pPsData, irbId_[i], 4) == 0) return true; } return false; } bool Photoshop::valid(const byte* pPsData, long sizePsData) { const byte *record = 0; uint32_t sizeIptc = 0; uint32_t sizeHdr = 0; const byte* pCur = pPsData; const byte* pEnd = pPsData + sizePsData; int ret = 0; while (pCur < pEnd && 0 == (ret = Photoshop::locateIptcIrb(pCur, static_cast(pEnd - pCur), &record, &sizeHdr, &sizeIptc))) { pCur = record + sizeHdr + sizeIptc + (sizeIptc & 1); } return ret >= 0; } // Todo: Generalised from JpegBase::locateIptcData without really understanding // the format (in particular the header). So it remains to be confirmed // if this also makes sense for psTag != Photoshop::iptc int Photoshop::locateIrb(const byte* pPsData, long sizePsData, uint16_t psTag, const byte** record, uint32_t *const sizeHdr, uint32_t *const sizeData) { assert(record); assert(sizeHdr); assert(sizeData); // Used for error checking long position = 0; #ifdef DEBUG std::cerr << "Photoshop::locateIrb: "; #endif // Data should follow Photoshop format, if not exit while (position <= sizePsData - 12 && isIrb(pPsData + position, 4)) { const byte *hrd = pPsData + position; position += 4; uint16_t type = getUShort(pPsData + position, bigEndian); position += 2; #ifdef DEBUG std::cerr << "0x" << std::hex << type << std::dec << " "; #endif // Pascal string is padded to have an even size (including size byte) byte psSize = pPsData[position] + 1; psSize += (psSize & 1); position += psSize; if (position + 4 > sizePsData) { #ifdef DEBUG std::cerr << "Warning: " << "Invalid or extended Photoshop IRB\n"; #endif return -2; } uint32_t dataSize = getULong(pPsData + position, bigEndian); position += 4; if (dataSize > static_cast(sizePsData - position)) { #ifdef DEBUG std::cerr << "Warning: " << "Invalid Photoshop IRB data size " << dataSize << " or extended Photoshop IRB\n"; #endif return -2; } #ifndef DEBUG if ( (dataSize & 1) && position + dataSize == static_cast(sizePsData)) { std::cerr << "Warning: " << "Photoshop IRB data is not padded to even size\n"; } #endif if (type == psTag) { #ifdef DEBUG std::cerr << "ok\n"; #endif *sizeData = dataSize; *sizeHdr = psSize + 10; *record = hrd; return 0; } // Data size is also padded to be even position += dataSize + (dataSize & 1); } #ifdef DEBUG std::cerr << "pPsData doesn't start with '8BIM'\n"; #endif if (position < sizePsData) { #ifdef DEBUG std::cerr << "Warning: " << "Invalid or extended Photoshop IRB\n"; #endif return -2; } return 3; } // Photoshop::locateIrb int Photoshop::locateIptcIrb(const byte* pPsData, long sizePsData, const byte** record, uint32_t *const sizeHdr, uint32_t *const sizeData) { return locateIrb(pPsData, sizePsData, iptc_, record, sizeHdr, sizeData); } int Photoshop::locatePreviewIrb(const byte* pPsData, long sizePsData, const byte** record, uint32_t *const sizeHdr, uint32_t *const sizeData) { return locateIrb(pPsData, sizePsData, preview_, record, sizeHdr, sizeData); } DataBuf Photoshop::setIptcIrb(const byte* pPsData, long sizePsData, const IptcData& iptcData) { if (sizePsData > 0) assert(pPsData); #ifdef DEBUG std::cerr << "IRB block at the beginning of Photoshop::setIptcIrb\n"; if (sizePsData == 0) std::cerr << " None.\n"; else hexdump(std::cerr, pPsData, sizePsData); #endif const byte* record = pPsData; uint32_t sizeIptc = 0; uint32_t sizeHdr = 0; DataBuf rc; // Safe to call with zero psData.size_ if (0 > Photoshop::locateIptcIrb(pPsData, sizePsData, &record, &sizeHdr, &sizeIptc)) { return rc; } Blob psBlob; const uint32_t sizeFront = static_cast(record - pPsData); // Write data before old record. if (sizePsData > 0 && sizeFront > 0) { append(psBlob, pPsData, sizeFront); } // Write new iptc record if we have it DataBuf rawIptc = IptcParser::encode(iptcData); if (rawIptc.size_ > 0) { byte tmpBuf[12]; std::memcpy(tmpBuf, Photoshop::irbId_[0], 4); us2Data(tmpBuf + 4, iptc_, bigEndian); tmpBuf[6] = 0; tmpBuf[7] = 0; ul2Data(tmpBuf + 8, rawIptc.size_, bigEndian); append(psBlob, tmpBuf, 12); append(psBlob, rawIptc.pData_, rawIptc.size_); // Data is padded to be even (but not included in size) if (rawIptc.size_ & 1) psBlob.push_back(0x00); } // Write existing stuff after record, // skip the current and all remaining IPTC blocks long pos = sizeFront; while (0 == Photoshop::locateIptcIrb(pPsData + pos, sizePsData - pos, &record, &sizeHdr, &sizeIptc)) { const long newPos = static_cast(record - pPsData); // Copy data up to the IPTC IRB if (newPos > pos) { append(psBlob, pPsData + pos, newPos - pos); } // Skip the IPTC IRB pos = newPos + sizeHdr + sizeIptc + (sizeIptc & 1); } if (pos < sizePsData) { append(psBlob, pPsData + pos, sizePsData - pos); } // Data is rounded to be even if (psBlob.size() > 0) rc = DataBuf(&psBlob[0], static_cast(psBlob.size())); #ifdef DEBUG std::cerr << "IRB block at the end of Photoshop::setIptcIrb\n"; if (rc.size_ == 0) std::cerr << " None.\n"; else hexdump(std::cerr, rc.pData_, rc.size_); #endif return rc; } // Photoshop::setIptcIrb JpegBase::JpegBase(int type, BasicIo::AutoPtr io, bool create, const byte initData[], long dataSize) : Image(type, mdExif | mdIptc | mdXmp | mdComment, io) { if (create) { initImage(initData, dataSize); } } int JpegBase::initImage(const byte initData[], long dataSize) { if (io_->open() != 0) { return 4; } IoCloser closer(*io_); if (io_->write(initData, dataSize) != dataSize) { return 4; } return 0; } int JpegBase::advanceToMarker() const { int c = -1; // Skips potential padding between markers while ((c=io_->getb()) != 0xff) { if (c == EOF) return -1; } // Markers can start with any number of 0xff while ((c=io_->getb()) == 0xff) { if (c == EOF) return -2; } return c; } void JpegBase::readMetadata() { int rc = 0; // Todo: this should be the return value if (io_->open() != 0) throw Error(9, io_->path(), strError()); IoCloser closer(*io_); // Ensure that this is the correct image type if (!isThisType(*io_, true)) { if (io_->error() || io_->eof()) throw Error(14); throw Error(15); } clearMetadata(); int search = 5; const long bufMinSize = 36; long bufRead = 0; DataBuf buf(bufMinSize); Blob psBlob; bool foundCompletePsData = false; bool foundExifData = false; bool foundXmpData = false; // Read section marker int marker = advanceToMarker(); if (marker < 0) throw Error(15); while (marker != sos_ && marker != eoi_ && search > 0) { // Read size and signature (ok if this hits EOF) std::memset(buf.pData_, 0x0, buf.size_); bufRead = io_->read(buf.pData_, bufMinSize); if (io_->error()) throw Error(14); if (bufRead < 2) throw Error(15); uint16_t size = getUShort(buf.pData_, bigEndian); if ( !foundExifData && marker == app1_ && memcmp(buf.pData_ + 2, exifId_, 6) == 0) { if (size < 8) { rc = 1; break; } // Seek to beginning and read the Exif data io_->seek(8 - bufRead, BasicIo::cur); DataBuf rawExif(size - 8); io_->read(rawExif.pData_, rawExif.size_); if (io_->error() || io_->eof()) throw Error(14); ByteOrder bo = ExifParser::decode(exifData_, rawExif.pData_, rawExif.size_); setByteOrder(bo); if (rawExif.size_ > 0 && byteOrder() == invalidByteOrder) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Failed to decode Exif metadata.\n"; #endif exifData_.clear(); } --search; foundExifData = true; } else if ( !foundXmpData && marker == app1_ && memcmp(buf.pData_ + 2, xmpId_, 29) == 0) { if (size < 31) { rc = 6; break; } // Seek to beginning and read the XMP packet io_->seek(31 - bufRead, BasicIo::cur); DataBuf xmpPacket(size - 31); io_->read(xmpPacket.pData_, xmpPacket.size_); if (io_->error() || io_->eof()) throw Error(14); xmpPacket_.assign(reinterpret_cast(xmpPacket.pData_), xmpPacket.size_); if (xmpPacket_.size() > 0 && XmpParser::decode(xmpData_, xmpPacket_)) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Failed to decode XMP metadata.\n"; #endif } --search; foundXmpData = true; } else if ( !foundCompletePsData && marker == app13_ && memcmp(buf.pData_ + 2, Photoshop::ps3Id_, 14) == 0) { if (size < 16) { rc = 2; break; } // Read the rest of the APP13 segment io_->seek(16 - bufRead, BasicIo::cur); DataBuf psData(size - 16); io_->read(psData.pData_, psData.size_); if (io_->error() || io_->eof()) throw Error(14); #ifdef DEBUG std::cerr << "Found app13 segment, size = " << size << "\n"; //hexdump(std::cerr, psData.pData_, psData.size_); #endif // Append to psBlob append(psBlob, psData.pData_, psData.size_); // Check whether psBlob is complete if (psBlob.size() > 0 && Photoshop::valid(&psBlob[0], (long) psBlob.size())) { --search; foundCompletePsData = true; } } else if (marker == com_ && comment_.empty()) { if (size < 2) { rc = 3; break; } // JPEGs can have multiple comments, but for now only read // the first one (most jpegs only have one anyway). Comments // are simple single byte ISO-8859-1 strings. io_->seek(2 - bufRead, BasicIo::cur); DataBuf comment(size - 2); io_->read(comment.pData_, comment.size_); if (io_->error() || io_->eof()) throw Error(14); comment_.assign(reinterpret_cast(comment.pData_), comment.size_); while ( comment_.length() && comment_.at(comment_.length()-1) == '\0') { comment_.erase(comment_.length()-1); } --search; } else if ( pixelHeight_ == 0 && ( marker == sof0_ || marker == sof1_ || marker == sof2_ || marker == sof3_ || marker == sof5_ || marker == sof6_ || marker == sof7_ || marker == sof9_ || marker == sof10_ || marker == sof11_ || marker == sof13_ || marker == sof14_ || marker == sof15_)) { // We hit a SOFn (start-of-frame) marker if (size < 8) { rc = 7; break; } pixelHeight_ = getUShort(buf.pData_ + 3, bigEndian); pixelWidth_ = getUShort(buf.pData_ + 5, bigEndian); if (pixelHeight_ != 0) --search; // Skip the remainder of the segment io_->seek(size-bufRead, BasicIo::cur); } else { if (size < 2) { rc = 4; break; } // Skip the remainder of the unknown segment if (io_->seek(size - bufRead, BasicIo::cur)) throw Error(14); } // Read the beginning of the next segment marker = advanceToMarker(); if (marker < 0) { rc = 5; break; } } // while there are segments to process if (psBlob.size() > 0) { // Find actual IPTC data within the psBlob Blob iptcBlob; const byte *record = 0; uint32_t sizeIptc = 0; uint32_t sizeHdr = 0; const byte* pCur = &psBlob[0]; const byte* pEnd = pCur + psBlob.size(); while ( pCur < pEnd && 0 == Photoshop::locateIptcIrb(pCur, static_cast(pEnd - pCur), &record, &sizeHdr, &sizeIptc)) { #ifdef DEBUG std::cerr << "Found IPTC IRB, size = " << sizeIptc << "\n"; #endif if (sizeIptc) { append(iptcBlob, record + sizeHdr, sizeIptc); } pCur = record + sizeHdr + sizeIptc + (sizeIptc & 1); } if ( iptcBlob.size() > 0 && IptcParser::decode(iptcData_, &iptcBlob[0], static_cast(iptcBlob.size()))) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Failed to decode IPTC metadata.\n"; #endif iptcData_.clear(); } } // psBlob.size() > 0 if (rc != 0) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "JPEG format error, rc = " << rc << "\n"; #endif } } // JpegBase::readMetadata void JpegBase::writeMetadata() { if (io_->open() != 0) { throw Error(9, io_->path(), strError()); } IoCloser closer(*io_); BasicIo::AutoPtr tempIo(io_->temporary()); // may throw assert (tempIo.get() != 0); doWriteMetadata(*tempIo); // may throw io_->close(); io_->transfer(*tempIo); // may throw } // JpegBase::writeMetadata void JpegBase::doWriteMetadata(BasicIo& outIo) { if (!io_->isopen()) throw Error(20); if (!outIo.isopen()) throw Error(21); // Ensure that this is the correct image type if (!isThisType(*io_, true)) { if (io_->error() || io_->eof()) throw Error(20); throw Error(22); } const long bufMinSize = 36; long bufRead = 0; DataBuf buf(bufMinSize); const long seek = io_->tell(); int count = 0; int search = 0; int insertPos = 0; int comPos = 0; int skipApp1Exif = -1; int skipApp1Xmp = -1; bool foundCompletePsData = false; std::vector skipApp13Ps3; int skipCom = -1; Blob psBlob; DataBuf rawExif; // Write image header if (writeHeader(outIo)) throw Error(21); // Read section marker int marker = advanceToMarker(); if (marker < 0) throw Error(22); // First find segments of interest. Normally app0 is first and we want // to insert after it. But if app0 comes after com, app1 and app13 then // don't bother. while (marker != sos_ && marker != eoi_ && search < 5) { // Read size and signature (ok if this hits EOF) bufRead = io_->read(buf.pData_, bufMinSize); if (io_->error()) throw Error(20); uint16_t size = getUShort(buf.pData_, bigEndian); if (marker == app0_) { if (size < 2) throw Error(22); insertPos = count + 1; if (io_->seek(size-bufRead, BasicIo::cur)) throw Error(22); } else if ( skipApp1Exif == -1 && marker == app1_ && memcmp(buf.pData_ + 2, exifId_, 6) == 0) { if (size < 8) throw Error(22); skipApp1Exif = count; ++search; // Seek to beginning and read the current Exif data io_->seek(8 - bufRead, BasicIo::cur); rawExif.alloc(size - 8); io_->read(rawExif.pData_, rawExif.size_); if (io_->error() || io_->eof()) throw Error(22); } else if ( skipApp1Xmp == -1 && marker == app1_ && memcmp(buf.pData_ + 2, xmpId_, 29) == 0) { if (size < 31) throw Error(22); skipApp1Xmp = count; ++search; if (io_->seek(size-bufRead, BasicIo::cur)) throw Error(22); } else if ( !foundCompletePsData && marker == app13_ && memcmp(buf.pData_ + 2, Photoshop::ps3Id_, 14) == 0) { #ifdef DEBUG std::cerr << "Found APP13 Photoshop PS3 segment\n"; #endif if (size < 16) throw Error(22); skipApp13Ps3.push_back(count); io_->seek(16 - bufRead, BasicIo::cur); // Load PS data now to allow reinsertion at any point DataBuf psData(size - 16); io_->read(psData.pData_, size - 16); if (io_->error() || io_->eof()) throw Error(20); // Append to psBlob append(psBlob, psData.pData_, psData.size_); // Check whether psBlob is complete if (psBlob.size() > 0 && Photoshop::valid(&psBlob[0],(long) psBlob.size())) { foundCompletePsData = true; } } else if (marker == com_ && skipCom == -1) { if (size < 2) throw Error(22); // Jpegs can have multiple comments, but for now only handle // the first one (most jpegs only have one anyway). skipCom = count; ++search; if (io_->seek(size-bufRead, BasicIo::cur)) throw Error(22); } else { if (size < 2) throw Error(22); if (io_->seek(size-bufRead, BasicIo::cur)) throw Error(22); } // As in jpeg-6b/wrjpgcom.c: // We will insert the new comment marker just before SOFn. // This (a) causes the new comment to appear after, rather than before, // existing comments; and (b) ensures that comments come after any JFIF // or JFXX markers, as required by the JFIF specification. if ( comPos == 0 && ( marker == sof0_ || marker == sof1_ || marker == sof2_ || marker == sof3_ || marker == sof5_ || marker == sof6_ || marker == sof7_ || marker == sof9_ || marker == sof10_ || marker == sof11_ || marker == sof13_ || marker == sof14_ || marker == sof15_)) { comPos = count; ++search; } marker = advanceToMarker(); if (marker < 0) throw Error(22); ++count; } if (!foundCompletePsData && psBlob.size() > 0) throw Error(22); search += (int) skipApp13Ps3.size(); if (comPos == 0) { if (marker == eoi_) comPos = count; else comPos = insertPos; ++search; } if (exifData_.count() > 0) ++search; if (writeXmpFromPacket() == false && xmpData_.count() > 0) ++search; if (writeXmpFromPacket() == true && xmpPacket_.size() > 0) ++search; if (foundCompletePsData || iptcData_.count() > 0) ++search; if (!comment_.empty()) ++search; io_->seek(seek, BasicIo::beg); count = 0; marker = advanceToMarker(); if (marker < 0) throw Error(22); // To simplify this a bit, new segments are inserts at either the start // or right after app0. This is standard in most jpegs, but has the // potential to change segment ordering (which is allowed). // Segments are erased if there is no assigned metadata. while (marker != sos_ && search > 0) { // Read size and signature (ok if this hits EOF) bufRead = io_->read(buf.pData_, bufMinSize); if (io_->error()) throw Error(20); // Careful, this can be a meaningless number for empty // images with only an eoi_ marker uint16_t size = getUShort(buf.pData_, bigEndian); if (insertPos == count) { byte tmpBuf[64]; // Write Exif data first so that - if there is no app0 - we // create "Exif images" according to the Exif standard. if (exifData_.count() > 0) { Blob blob; ByteOrder bo = byteOrder(); if (bo == invalidByteOrder) { bo = littleEndian; setByteOrder(bo); } WriteMethod wm = ExifParser::encode(blob, rawExif.pData_, rawExif.size_, bo, exifData_); const byte* pExifData = rawExif.pData_; uint32_t exifSize = rawExif.size_; if (wm == wmIntrusive) { pExifData = blob.size() > 0 ? &blob[0] : 0; exifSize = static_cast(blob.size()); } if (exifSize > 0) { // Write APP1 marker, size of APP1 field, Exif id and Exif data tmpBuf[0] = 0xff; tmpBuf[1] = app1_; if (exifSize + 8 > 0xffff) throw Error(37, "Exif"); us2Data(tmpBuf + 2, static_cast(exifSize + 8), bigEndian); std::memcpy(tmpBuf + 4, exifId_, 6); if (outIo.write(tmpBuf, 10) != 10) throw Error(21); // Write new Exif data buffer if ( outIo.write(pExifData, exifSize) != static_cast(exifSize)) throw Error(21); if (outIo.error()) throw Error(21); --search; } } if (writeXmpFromPacket() == false) { if (XmpParser::encode(xmpPacket_, xmpData_, XmpParser::useCompactFormat | XmpParser::omitAllFormatting) > 1) { #ifndef SUPPRESS_WARNINGS EXV_ERROR << "Failed to encode XMP metadata.\n"; #endif } } if (xmpPacket_.size() > 0) { // Write APP1 marker, size of APP1 field, XMP id and XMP packet tmpBuf[0] = 0xff; tmpBuf[1] = app1_; if (xmpPacket_.size() + 31 > 0xffff) throw Error(37, "XMP"); us2Data(tmpBuf + 2, static_cast(xmpPacket_.size() + 31), bigEndian); std::memcpy(tmpBuf + 4, xmpId_, 29); if (outIo.write(tmpBuf, 33) != 33) throw Error(21); // Write new XMP packet if ( outIo.write(reinterpret_cast(xmpPacket_.data()), static_cast(xmpPacket_.size())) != static_cast(xmpPacket_.size())) throw Error(21); if (outIo.error()) throw Error(21); --search; } if (foundCompletePsData || iptcData_.count() > 0) { // Set the new IPTC IRB, keeps existing IRBs but removes the // IPTC block if there is no new IPTC data to write DataBuf newPsData = Photoshop::setIptcIrb(psBlob.size() > 0 ? &psBlob[0] : 0, (long) psBlob.size(), iptcData_); const long maxChunkSize = 0xffff - 16; const byte* chunkStart = newPsData.pData_; const byte* chunkEnd = chunkStart + newPsData.size_; while (chunkStart < chunkEnd) { // Determine size of next chunk long chunkSize = static_cast(chunkEnd - chunkStart); if (chunkSize > maxChunkSize) { chunkSize = maxChunkSize; // Don't break at a valid IRB boundary const long writtenSize = static_cast(chunkStart - newPsData.pData_); if (Photoshop::valid(newPsData.pData_, writtenSize + chunkSize)) { // Since an IRB has minimum size 12, // (chunkSize - 8) can't be also a IRB boundary chunkSize -= 8; } } // Write APP13 marker, chunk size, and ps3Id tmpBuf[0] = 0xff; tmpBuf[1] = app13_; us2Data(tmpBuf + 2, static_cast(chunkSize + 16), bigEndian); std::memcpy(tmpBuf + 4, Photoshop::ps3Id_, 14); if (outIo.write(tmpBuf, 18) != 18) throw Error(21); if (outIo.error()) throw Error(21); // Write next chunk of the Photoshop IRB data buffer if (outIo.write(chunkStart, chunkSize) != chunkSize) throw Error(21); if (outIo.error()) throw Error(21); chunkStart += chunkSize; } --search; } } if (comPos == count) { if (!comment_.empty()) { byte tmpBuf[4]; // Write COM marker, size of comment, and string tmpBuf[0] = 0xff; tmpBuf[1] = com_; if (comment_.length() + 3 > 0xffff) throw Error(37, "JPEG comment"); us2Data(tmpBuf + 2, static_cast(comment_.length() + 3), bigEndian); if (outIo.write(tmpBuf, 4) != 4) throw Error(21); if (outIo.write((byte*)comment_.data(), (long)comment_.length()) != (long)comment_.length()) throw Error(21); if (outIo.putb(0)==EOF) throw Error(21); if (outIo.error()) throw Error(21); --search; } --search; } if (marker == eoi_) { break; } else if ( skipApp1Exif == count || skipApp1Xmp == count || std::find(skipApp13Ps3.begin(), skipApp13Ps3.end(), count) != skipApp13Ps3.end() || skipCom == count) { --search; io_->seek(size-bufRead, BasicIo::cur); } else { if (size < 2) throw Error(22); buf.alloc(size+2); io_->seek(-bufRead-2, BasicIo::cur); io_->read(buf.pData_, size+2); if (io_->error() || io_->eof()) throw Error(20); if (outIo.write(buf.pData_, size+2) != size+2) throw Error(21); if (outIo.error()) throw Error(21); } // Next marker marker = advanceToMarker(); if (marker < 0) throw Error(22); ++count; } // Copy rest of the Io io_->seek(-2, BasicIo::cur); buf.alloc(4096); long readSize = 0; while ((readSize=io_->read(buf.pData_, buf.size_))) { if (outIo.write(buf.pData_, readSize) != readSize) throw Error(21); } if (outIo.error()) throw Error(21); } // JpegBase::doWriteMetadata const byte JpegImage::soi_ = 0xd8; const byte JpegImage::blank_[] = { 0xFF,0xD8,0xFF,0xDB,0x00,0x84,0x00,0x10,0x0B,0x0B,0x0B,0x0C,0x0B,0x10,0x0C,0x0C, 0x10,0x17,0x0F,0x0D,0x0F,0x17,0x1B,0x14,0x10,0x10,0x14,0x1B,0x1F,0x17,0x17,0x17, 0x17,0x17,0x1F,0x1E,0x17,0x1A,0x1A,0x1A,0x1A,0x17,0x1E,0x1E,0x23,0x25,0x27,0x25, 0x23,0x1E,0x2F,0x2F,0x33,0x33,0x2F,0x2F,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x01,0x11,0x0F,0x0F,0x11,0x13,0x11,0x15,0x12, 0x12,0x15,0x14,0x11,0x14,0x11,0x14,0x1A,0x14,0x16,0x16,0x14,0x1A,0x26,0x1A,0x1A, 0x1C,0x1A,0x1A,0x26,0x30,0x23,0x1E,0x1E,0x1E,0x1E,0x23,0x30,0x2B,0x2E,0x27,0x27, 0x27,0x2E,0x2B,0x35,0x35,0x30,0x30,0x35,0x35,0x40,0x40,0x3F,0x40,0x40,0x40,0x40, 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0xFF,0xC0,0x00,0x11,0x08,0x00,0x01,0x00, 0x01,0x03,0x01,0x22,0x00,0x02,0x11,0x01,0x03,0x11,0x01,0xFF,0xC4,0x00,0x4B,0x00, 0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x07,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x10,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xDA,0x00,0x0C,0x03,0x01,0x00,0x02, 0x11,0x03,0x11,0x00,0x3F,0x00,0xA0,0x00,0x0F,0xFF,0xD9 }; JpegImage::JpegImage(BasicIo::AutoPtr io, bool create) : JpegBase(ImageType::jpeg, io, create, blank_, sizeof(blank_)) { } std::string JpegImage::mimeType() const { return "image/jpeg"; } int JpegImage::writeHeader(BasicIo& outIo) const { // Jpeg header byte tmpBuf[2]; tmpBuf[0] = 0xff; tmpBuf[1] = soi_; if (outIo.write(tmpBuf, 2) != 2) return 4; if (outIo.error()) return 4; return 0; } bool JpegImage::isThisType(BasicIo& iIo, bool advance) const { return isJpegType(iIo, advance); } Image::AutoPtr newJpegInstance(BasicIo::AutoPtr io, bool create) { Image::AutoPtr image(new JpegImage(io, create)); if (!image->good()) { image.reset(); } return image; } bool isJpegType(BasicIo& iIo, bool advance) { bool result = true; byte tmpBuf[2]; iIo.read(tmpBuf, 2); if (iIo.error() || iIo.eof()) return false; if (0xff != tmpBuf[0] || JpegImage::soi_ != tmpBuf[1]) { result = false; } if (!advance || !result ) iIo.seek(-2, BasicIo::cur); return result; } const char ExvImage::exiv2Id_[] = "Exiv2"; const byte ExvImage::blank_[] = { 0xff,0x01,'E','x','i','v','2',0xff,0xd9 }; ExvImage::ExvImage(BasicIo::AutoPtr io, bool create) : JpegBase(ImageType::exv, io, create, blank_, sizeof(blank_)) { } std::string ExvImage::mimeType() const { return "image/x-exv"; } int ExvImage::writeHeader(BasicIo& outIo) const { // Exv header byte tmpBuf[7]; tmpBuf[0] = 0xff; tmpBuf[1] = 0x01; std::memcpy(tmpBuf + 2, exiv2Id_, 5); if (outIo.write(tmpBuf, 7) != 7) return 4; if (outIo.error()) return 4; return 0; } bool ExvImage::isThisType(BasicIo& iIo, bool advance) const { return isExvType(iIo, advance); } Image::AutoPtr newExvInstance(BasicIo::AutoPtr io, bool create) { Image::AutoPtr image; image = Image::AutoPtr(new ExvImage(io, create)); if (!image->good()) image.reset(); return image; } bool isExvType(BasicIo& iIo, bool advance) { bool result = true; byte tmpBuf[7]; iIo.read(tmpBuf, 7); if (iIo.error() || iIo.eof()) return false; if ( 0xff != tmpBuf[0] || 0x01 != tmpBuf[1] || memcmp(tmpBuf + 2, ExvImage::exiv2Id_, 5) != 0) { result = false; } if (!advance || !result) iIo.seek(-7, BasicIo::cur); return result; } } // namespace Exiv2 exiv2-0.23/src/version.cpp0000644000175000017500000000413311732641407015275 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /* File: version.cpp Version: $Rev: 2681 $ Author(s): Andreas Huggel (ahu) History: 06-Mar-07, ahu: created */ // ***************************************************************************** #include "rcsid_int.hpp" EXIV2_RCSID("@(#) $Id: version.cpp 2681 2012-03-22 15:19:35Z ahuggel $") // ***************************************************************************** // included header files #ifdef _MSC_VER # include "exv_msvc.h" #else # include "exv_conf.h" #endif #include "version.hpp" // + standard includes #include #include namespace Exiv2 { int versionNumber() { return EXIV2_MAKE_VERSION(EXIV2_MAJOR_VERSION, EXIV2_MINOR_VERSION, EXIV2_PATCH_VERSION); } std::string versionNumberHexString() { std::ostringstream os; os << std::hex << std::setw(6) << std::setfill('0') << Exiv2::versionNumber(); return os.str(); } const char* version() { return EXV_PACKAGE_VERSION; } bool testVersion(int major, int minor, int patch) { return versionNumber() >= EXIV2_MAKE_VERSION(major,minor,patch); } } // namespace Exiv2 exiv2-0.23/src/nikonmn_int.hpp0000644000175000017500000003274211732641407016147 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! @file nikonmn_int.hpp @brief Nikon makernote tags.
References:
[1] MakerNote EXIF Tag of the Nikon 990 by Max Lyons
[2] Exif file format by TsuruZoh Tachibanaya
[3] "EXIFutils Field Reference Guide"
[3] Nikon Type 3 Makernote Tags Definition of the PHP JPEG Metadata Toolkit by Evan Hunter
[4] ExifTool by Phil Harvey
[5] Email communication with Robert Rottmerhusen
[6] Email communication with Roger Larsson
[7] Decoding raw digital photos in Linux by Dave Coffin
@version $Rev: 2681 $ @author Andreas Huggel (ahu) ahuggel@gmx.net @author Gilles Caulier (gc) caulier dot gilles at gmail dot com @author Jens Mueller (jm) tschensinger at web dot de @date 17-May-04, ahu: created
25-May-04, ahu: combined all Nikon formats in one component */ #ifndef NIKONMN_INT_HPP_ #define NIKONMN_INT_HPP_ // ***************************************************************************** // included header files #include "tags.hpp" #include "types.hpp" // + standard includes #include #include #include // ***************************************************************************** // namespace extensions namespace Exiv2 { namespace Internal { // ***************************************************************************** // class definitions //! A MakerNote format used by Nikon cameras, such as the E990 and D1. class Nikon1MakerNote { public: //! Return read-only list of built-in Nikon1 tags static const TagInfo* tagList(); //! @name Print functions for Nikon1 %MakerNote tags //@{ //! Print ISO setting static std::ostream& print0x0002(std::ostream& os, const Value& value, const ExifData*); //! Print autofocus mode static std::ostream& print0x0007(std::ostream& os, const Value& value, const ExifData*); //! Print manual focus distance static std::ostream& print0x0085(std::ostream& os, const Value& value, const ExifData*); //! Print digital zoom setting static std::ostream& print0x0086(std::ostream& os, const Value& value, const ExifData*); //! Print AF focus position static std::ostream& print0x0088(std::ostream& os, const Value& value, const ExifData*); //@} private: //! Tag information static const TagInfo tagInfo_[]; }; // class Nikon1MakerNote /*! @brief A second MakerNote format used by Nikon cameras, including the E700, E800, E900, E900S, E910, E950 */ class Nikon2MakerNote { public: //! Return read-only list of built-in Nikon2 tags static const TagInfo* tagList(); //! @name Print functions for Nikon2 %MakerNote tags //@{ //! Print digital zoom setting static std::ostream& print0x000a(std::ostream& os, const Value& value, const ExifData*); //@} private: //! Tag information static const TagInfo tagInfo_[]; }; // class Nikon2MakerNote //! A third MakerNote format used by Nikon cameras, e.g., E5400, SQ, D2H, D70 class Nikon3MakerNote { public: //! Return read-only list of built-in Nikon3 tags static const TagInfo* tagList(); //! Return read-only list of built-in Vibration Reduction tags static const TagInfo* tagListVr(); //! Return read-only list of built-in Picture Control tags static const TagInfo* tagListPc(); //! Return read-only list of built-in World time tags static const TagInfo* tagListWt(); //! Return read-only list of built-in ISO info tags static const TagInfo* tagListIi(); //! Return read-only list of built-in Auto Focus tags static const TagInfo* tagListAf(); //! Return read-only list of built-in Auto Focus 2 tags static const TagInfo* tagListAf2(); //! Return read-only list of built-in AF Fine Tune tags static const TagInfo* tagListAFT(); //! Return read-only list of built-in File Info tags static const TagInfo* tagListFi(); //! Return read-only list of built-in Multi Exposure tags static const TagInfo* tagListMe(); //! Return read-only list of built-in Flash Info 1 tags static const TagInfo* tagListFl1(); //! Return read-only list of built-in Flash Info 2 tags static const TagInfo* tagListFl2(); //! Return read-only list of built-in Flash Info 3 tags static const TagInfo* tagListFl3(); //! Return read-only list of built-in Shot Info D80 tags static const TagInfo* tagListSi1(); //! Return read-only list of built-in Shot Info D40 tags static const TagInfo* tagListSi2(); //! Return read-only list of built-in Shot Info D300 (a) tags static const TagInfo* tagListSi3(); //! Return read-only list of built-in Shot Info D300 (b) tags static const TagInfo* tagListSi4(); //! Return read-only list of built-in Shot Info tags static const TagInfo* tagListSi5(); //! Return read-only list of built-in Color Balance 1 tags static const TagInfo* tagListCb1(); //! Return read-only list of built-in Color Balance 2 tags static const TagInfo* tagListCb2(); //! Return read-only list of built-in Color Balance 2a tags static const TagInfo* tagListCb2a(); //! Return read-only list of built-in Color Balance 2b tags static const TagInfo* tagListCb2b(); //! Return read-only list of built-in Color Balance 3 tags static const TagInfo* tagListCb3(); //! Return read-only list of built-in Color Balance 4 tags static const TagInfo* tagListCb4(); //! Return read-only list of built-in Lens Data 1 tags static const TagInfo* tagListLd1(); //! Return read-only list of built-in Lens Data 2 tags static const TagInfo* tagListLd2(); //! Return read-only list of built-in Lens Data 3 tags static const TagInfo* tagListLd3(); //! @name Print functions for Nikon3 %MakerNote tags //@{ //! Print ISO setting static std::ostream& print0x0002(std::ostream& os, const Value& value, const ExifData*); //! Print autofocus mode static std::ostream& print0x0007(std::ostream& os, const Value& value, const ExifData*); //! Print lens type static std::ostream& print0x0083(std::ostream& os, const Value& value, const ExifData*); //! Print lens information static std::ostream& print0x0084(std::ostream& os, const Value& value, const ExifData*); //! Print manual focus distance static std::ostream& print0x0085(std::ostream& os, const Value& value, const ExifData*); //! Print digital zoom setting static std::ostream& print0x0086(std::ostream& os, const Value& value, const ExifData*); //! Print AF point static std::ostream& print0x0088(std::ostream& os, const Value& value, const ExifData*); //! Print shooting mode static std::ostream& print0x0089(std::ostream& os, const Value& value, const ExifData* metadata); //! Print number of lens stops static std::ostream& print0x008b(std::ostream& os, const Value& value, const ExifData*); //! Print AF Points In Focus static std::ostream& printAfPointsInFocus(std::ostream& os, const Value& value, const ExifData* metadata); //! Print lens name static std::ostream& printLensId(std::ostream& os, const Value& value, const ExifData* metadata, const std::string& group); static std::ostream& printLensId1(std::ostream& os, const Value& value, const ExifData* metadata); static std::ostream& printLensId2(std::ostream& os, const Value& value, const ExifData* metadata); static std::ostream& printLensId3(std::ostream& os, const Value& value, const ExifData* metadata); //! Print focus distance static std::ostream& printFocusDistance(std::ostream& os, const Value& value, const ExifData*); //! Print lens aperture value static std::ostream& printAperture(std::ostream& os, const Value& value, const ExifData*); //! Print lens focal length static std::ostream& printFocal(std::ostream& os, const Value& value, const ExifData*); //! Print lens f-stops static std::ostream& printFStops(std::ostream& os, const Value& value, const ExifData*); //! Print exit pupil position static std::ostream& printExitPupilPosition(std::ostream& os, const Value& value, const ExifData*); //! Print sensor pixel size static std::ostream& print0x009a(std::ostream& os, const Value& value, const ExifData*); //! Print retouch history static std::ostream& print0x009e(std::ostream& os, const Value& value, const ExifData*); //! Print Exif.NikonIi.ISO(2) static std::ostream& printIiIso(std::ostream& os, const Value& value, const ExifData*); //! Print flash focal length static std::ostream& printFlashFocalLength(std::ostream& os, const Value& value, const ExifData*); //! Print repeating flash rate static std::ostream& printRepeatingFlashRate(std::ostream& os, const Value& value, const ExifData*); //! Print repeating flash count static std::ostream& printRepeatingFlashCount(std::ostream& os, const Value& value, const ExifData*); //! Print time zone static std::ostream& printTimeZone(std::ostream& os, const Value& value, const ExifData*); //! Print picture control value static std::ostream& printPictureControl(std::ostream& os, const Value& value, const ExifData*); //@} private: //! Tag information static const TagInfo tagInfo_[]; //! Vibration Reduction tag information static const TagInfo tagInfoVr_[]; //! Picture Control tag information static const TagInfo tagInfoPc_[]; //! World Time tag information static const TagInfo tagInfoWt_[]; //! ISO info tag information static const TagInfo tagInfoIi_[]; //! Auto Focus tag information static const TagInfo tagInfoAf_[]; //! Auto Focus tag 2 information static const TagInfo tagInfoAf2_[]; //! AF Fine Tune tag information static const TagInfo tagInfoAFT_[]; //! File Info tag information static const TagInfo tagInfoFi_[]; //! Multi Exposure tag information static const TagInfo tagInfoMe_[]; //! Flash Info 1 tag information static const TagInfo tagInfoFl1_[]; //! Flash Info 2 tag information static const TagInfo tagInfoFl2_[]; //! Flash Info 3 tag information static const TagInfo tagInfoFl3_[]; //! Shot Info D80 tag information static const TagInfo tagInfoSi1_[]; //! Shot Info D40 tag information static const TagInfo tagInfoSi2_[]; //! Shot Info D300 (a) tag information static const TagInfo tagInfoSi3_[]; //! Shot Info D300 (b) tag information static const TagInfo tagInfoSi4_[]; //! Shot Info tag information static const TagInfo tagInfoSi5_[]; //! Color Balance 1 tag information static const TagInfo tagInfoCb1_[]; //! Color Balance 2 tag information static const TagInfo tagInfoCb2_[]; //! Color Balance 2a tag information static const TagInfo tagInfoCb2a_[]; //! Color Balance 2b tag information static const TagInfo tagInfoCb2b_[]; //! Color Balance 3 tag information static const TagInfo tagInfoCb3_[]; //! Color Balance 4 tag information static const TagInfo tagInfoCb4_[]; //! Lens Data 1 tag information static const TagInfo tagInfoLd1_[]; //! Lens Data 2 tag information static const TagInfo tagInfoLd2_[]; //! Lens Data 3 tag information static const TagInfo tagInfoLd3_[]; }; // class Nikon3MakerNote }} // namespace Internal, Exiv2 #endif // #ifndef NIKONMN_INT_HPP_ exiv2-0.23/src/fujimn.cpp0000644000175000017500000003101711732641407015101 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /* File: fujimn.cpp Version: $Rev: 2681 $ Author(s): Andreas Huggel (ahu) Gilles Caulier (gc) History: 18-Feb-04, ahu: created 07-Mar-04, ahu: isolated as a separate component Credits: See header file. */ // ***************************************************************************** #include "rcsid_int.hpp" EXIV2_RCSID("@(#) $Id: fujimn.cpp 2681 2012-03-22 15:19:35Z ahuggel $") // ***************************************************************************** // included header files #include "types.hpp" #include "fujimn_int.hpp" #include "tags_int.hpp" #include "value.hpp" #include "i18n.h" // NLS support. // + standard includes #include #include #include #include #include // ***************************************************************************** // class member definitions namespace Exiv2 { namespace Internal { //! OffOn, multiple tags extern const TagDetails fujiOffOn[] = { { 0, N_("Off") }, { 1, N_("On") } }; //! Sharpness, tag 0x1001 extern const TagDetails fujiSharpness[] = { { 1, N_("Soft mode 1") }, { 2, N_("Soft mode 2") }, { 3, N_("Normal") }, { 4, N_("Hard mode 1") }, { 5, N_("Hard mode 2") } }; //! WhiteBalance, tag 0x1002 extern const TagDetails fujiWhiteBalance[] = { { 0, N_("Auto") }, { 256, N_("Daylight") }, { 512, N_("Cloudy") }, { 768, N_("Fluorescent (daylight)") }, { 769, N_("Fluorescent (warm white)") }, { 770, N_("Fluorescent (cool white)") }, { 1024, N_("Incandescent") }, { 3480, N_("Custom") }, { 3480, N_("Custom") } // To silence compiler warning }; //! Color, tag 0x1003 extern const TagDetails fujiColor[] = { { 0, N_("Normal") }, { 256, N_("High") }, { 512, N_("Low") }, { 768, N_("None (black & white)") }, { 768, N_("None (black & white)") } // To silence compiler warning }; //! Tone, tag 0x1004 extern const TagDetails fujiTone[] = { { 0, N_("Normal") }, { 256, N_("High") }, { 512, N_("Low") } }; //! FlashMode, tag 0x1010 extern const TagDetails fujiFlashMode[] = { { 0, N_("Auto") }, { 1, N_("On") }, { 2, N_("Off") }, { 3, N_("Red-eye reduction") }, { 3, N_("Red-eye reduction") } // To silence compiler warning }; //! FocusMode, tag 0x1021 extern const TagDetails fujiFocusMode[] = { { 0, N_("Auto") }, { 1, N_("Manual") } }; //! PictureMode, tag 0x1031 extern const TagDetails fujiPictureMode[] = { { 0, N_("Auto") }, { 1, N_("Portrait") }, { 2, N_("Landscape") }, { 4, N_("Sports") }, { 5, N_("Night scene") }, { 6, N_("Program AE") }, { 7, N_("Natural light") }, { 8, N_("Anti-blur") }, { 10, N_("Sunset") }, { 11, N_("Museum") }, { 12, N_("Party") }, { 13, N_("Flower") }, { 14, N_("Text") }, { 15, N_("Natural light & flash") }, { 16, N_("Beach") }, { 17, N_("Snow") }, { 18, N_("Fireworks") }, { 19, N_("Underwater") }, { 256, N_("Aperture-priority AE") }, { 512, N_("Shutter speed priority AE") }, { 768, N_("Manual") } }; //! Continuous, tag 0x1100 extern const TagDetails fujiContinuous[] = { { 0, N_("Off") }, { 1, N_("On") }, { 2, N_("No flash & flash") } }; //! FinePixColor, tag 0x1210 extern const TagDetails fujiFinePixColor[] = { { 0, N_("Standard") }, { 16, N_("Chrome") }, { 48, N_("Black & white") } }; //! DynamicRange, tag 0x1400 extern const TagDetails fujiDynamicRange[] = { { 1, N_("Standard") }, { 3, N_("Wide") } }; //! FilmMode, tag 0x1401 extern const TagDetails fujiFilmMode[] = { { 0, N_("F0/Standard") }, { 256, N_("F1/Studio portrait") }, { 512, N_("F2/Fujichrome") }, { 768, N_("F3/Studio portrait Ex") }, { 1024, N_("F4/Velvia") } }; //! DynamicRange, tag 0x1402 extern const TagDetails fujiDynamicRangeSetting[] = { { 0, N_("Auto (100-400%)") }, { 1, N_("Raw") }, { 256, N_("Standard (100%)") }, { 512, N_("Wide mode 1 (230%)") }, { 513, N_("Wide mode 2 (400%)") }, { 32768, N_("Film simulation mode") } }; // Fujifilm MakerNote Tag Info const TagInfo FujiMakerNote::tagInfo_[] = { TagInfo(0x0000, "Version", N_("Version"), N_("Fujifilm Makernote version"), fujiId, makerTags, undefined, -1, printValue), TagInfo(0x0010, "SerialNumber", N_("Serial Number"), N_("This number is unique, and contains the date of manufacture, " "but is not the same as the number printed on the camera body."), fujiId, makerTags, asciiString, -1, printValue), TagInfo(0x1000, "Quality", N_("Quality"), N_("Image quality setting"), fujiId, makerTags, asciiString, -1, printValue), TagInfo(0x1001, N_("Sharpness"), N_("Sharpness"), N_("Sharpness setting"), fujiId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(fujiSharpness)), TagInfo(0x1002, "WhiteBalance", N_("White Balance"), N_("White balance setting"), fujiId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(fujiWhiteBalance)), TagInfo(0x1003, "Color", N_("Color"), N_("Chroma saturation setting"), fujiId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(fujiColor)), TagInfo(0x1004, "Tone", N_("Tone"), N_("Contrast setting"), fujiId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(fujiTone)), TagInfo(0x1010, "FlashMode", N_("Flash Mode"), N_("Flash firing mode setting"), fujiId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(fujiFlashMode)), TagInfo(0x1011, "FlashStrength", N_("Flash Strength"), N_("Flash firing strength compensation setting"), fujiId, makerTags, signedRational, -1, printValue), TagInfo(0x1020, "Macro", N_("Macro"), N_("Macro mode setting"), fujiId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(fujiOffOn)), TagInfo(0x1021, "FocusMode", N_("Focus Mode"), N_("Focusing mode setting"), fujiId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(fujiFocusMode)), TagInfo(0x1022, "0x1022", "0x1022", N_("Unknown"), fujiId, makerTags, unsignedShort, -1, printValue), TagInfo(0x1030, "SlowSync", N_("Slow Sync"), N_("Slow synchro mode setting"), fujiId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(fujiOffOn)), TagInfo(0x1031, "PictureMode", N_("Picture Mode"), N_("Picture mode setting"), fujiId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(fujiPictureMode)), TagInfo(0x1032, "0x1032", "0x1032", N_("Unknown"), fujiId, makerTags, unsignedShort, -1, printValue), TagInfo(0x1100, "Continuous", N_("Continuous"), N_("Continuous shooting or auto bracketing setting"), fujiId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(fujiContinuous)), TagInfo(0x1101, "SequenceNumber", N_("Sequence Number"), N_("Sequence number"), fujiId, makerTags, unsignedShort, -1, printValue), TagInfo(0x1200, "0x1200", "0x1200", N_("Unknown"), fujiId, makerTags, unsignedShort, -1, printValue), TagInfo(0x1210, "FinePixColor", N_("FinePix Color"), N_("Fuji FinePix color setting"), fujiId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(fujiFinePixColor)), TagInfo(0x1300, "BlurWarning", N_("Blur Warning"), N_("Blur warning status"), fujiId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(fujiOffOn)), TagInfo(0x1301, "FocusWarning", N_("Focus Warning"), N_("Auto Focus warning status"), fujiId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(fujiOffOn)), TagInfo(0x1302, "ExposureWarning", N_("Exposure Warning"), N_("Auto exposure warning status"), fujiId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(fujiOffOn)), TagInfo(0x1400, "DynamicRange", N_("Dynamic Range"), N_("Dynamic range"), fujiId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(fujiDynamicRange)), TagInfo(0x1401, "FilmMode", N_("Film Mode"), N_("Film mode"), fujiId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(fujiFilmMode)), TagInfo(0x1402, "DynamicRangeSetting", N_("Dynamic Range Setting"), N_("Dynamic range settings"), fujiId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(fujiDynamicRangeSetting)), TagInfo(0x1403, "DevelopmentDynamicRange", N_("Development Dynamic Range"), N_("Development dynamic range"), fujiId, makerTags, unsignedShort, -1, printValue), TagInfo(0x1404, "MinFocalLength", N_("Minimum Focal Length"), N_("Minimum focal length"), fujiId, makerTags, unsignedRational, -1, printValue), TagInfo(0x1405, "MaxFocalLength", N_("Maximum Focal Length"), N_("Maximum focal length"), fujiId, makerTags, unsignedRational, -1, printValue), TagInfo(0x1406, "MaxApertureAtMinFocal", N_("Maximum Aperture at Mininimum Focal"), N_("Maximum aperture at mininimum focal"), fujiId, makerTags, unsignedRational, -1, printValue), TagInfo(0x1407, "MaxApertureAtMaxFocal", N_("Maximum Aperture at Maxinimum Focal"), N_("Maximum aperture at maxinimum focal"), fujiId, makerTags, unsignedRational, -1, printValue), TagInfo(0x8000, "FileSource", N_("File Source"), N_("File source"), fujiId, makerTags, asciiString, -1, printValue), TagInfo(0x8002, "OrderNumber", N_("Order Number"), N_("Order number"), fujiId, makerTags, unsignedLong, -1, printValue), TagInfo(0x8003, "FrameNumber", N_("Frame Number"), N_("Frame number"), fujiId, makerTags, unsignedShort, -1, printValue), // End of list marker TagInfo(0xffff, "(UnknownFujiMakerNoteTag)", "(UnknownFujiMakerNoteTag)", N_("Unknown FujiMakerNote tag"), fujiId, makerTags, asciiString, -1, printValue) }; const TagInfo* FujiMakerNote::tagList() { return tagInfo_; } }} // namespace Internal, Exiv2 exiv2-0.23/src/cr2image.cpp0000644000175000017500000002302311732641407015300 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /* File: cr2image.cpp Version: $Rev: 2681 $ Author(s): Andreas Huggel (ahu) History: 22-Apr-06, ahu: created */ // ***************************************************************************** #include "rcsid_int.hpp" EXIV2_RCSID("@(#) $Id: cr2image.cpp 2681 2012-03-22 15:19:35Z ahuggel $") // ***************************************************************************** // included header files #ifdef _MSC_VER # include "exv_msvc.h" #else # include "exv_conf.h" #endif #include "cr2image.hpp" #include "cr2image_int.hpp" #include "tiffcomposite_int.hpp" #include "tiffimage_int.hpp" #include "image.hpp" #include "error.hpp" #include "futils.hpp" #include "i18n.h" // NLS support. // + standard includes #include #include #include #include // ***************************************************************************** // class member definitions namespace Exiv2 { using namespace Internal; Cr2Image::Cr2Image(BasicIo::AutoPtr io, bool /*create*/) : Image(ImageType::cr2, mdExif | mdIptc | mdXmp, io) { } // Cr2Image::Cr2Image std::string Cr2Image::mimeType() const { return "image/x-canon-cr2"; } int Cr2Image::pixelWidth() const { ExifData::const_iterator imageWidth = exifData_.findKey(Exiv2::ExifKey("Exif.Photo.PixelXDimension")); if (imageWidth != exifData_.end() && imageWidth->count() > 0) { return imageWidth->toLong(); } return 0; } int Cr2Image::pixelHeight() const { ExifData::const_iterator imageHeight = exifData_.findKey(Exiv2::ExifKey("Exif.Photo.PixelYDimension")); if (imageHeight != exifData_.end() && imageHeight->count() > 0) { return imageHeight->toLong(); } return 0; } void Cr2Image::setComment(const std::string& /*comment*/) { // not supported throw(Error(32, "Image comment", "CR2")); } void Cr2Image::readMetadata() { #ifdef DEBUG std::cerr << "Reading CR2 file " << io_->path() << "\n"; #endif if (io_->open() != 0) { throw Error(9, io_->path(), strError()); } IoCloser closer(*io_); // Ensure that this is the correct image type if (!isCr2Type(*io_, false)) { if (io_->error() || io_->eof()) throw Error(14); throw Error(3, "CR2"); } clearMetadata(); ByteOrder bo = Cr2Parser::decode(exifData_, iptcData_, xmpData_, io_->mmap(), io_->size()); setByteOrder(bo); } // Cr2Image::readMetadata void Cr2Image::writeMetadata() { #ifdef DEBUG std::cerr << "Writing CR2 file " << io_->path() << "\n"; #endif ByteOrder bo = byteOrder(); byte* pData = 0; long size = 0; IoCloser closer(*io_); if (io_->open() == 0) { // Ensure that this is the correct image type if (isCr2Type(*io_, false)) { pData = io_->mmap(true); size = io_->size(); Cr2Header cr2Header; if (0 == cr2Header.read(pData, 16)) { bo = cr2Header.byteOrder(); } } } if (bo == invalidByteOrder) { bo = littleEndian; } setByteOrder(bo); Cr2Parser::encode(*io_, pData, size, bo, exifData_, iptcData_, xmpData_); // may throw } // Cr2Image::writeMetadata ByteOrder Cr2Parser::decode( ExifData& exifData, IptcData& iptcData, XmpData& xmpData, const byte* pData, uint32_t size ) { Cr2Header cr2Header; return TiffParserWorker::decode(exifData, iptcData, xmpData, pData, size, Tag::root, TiffMapping::findDecoder, &cr2Header); } WriteMethod Cr2Parser::encode( BasicIo& io, const byte* pData, uint32_t size, ByteOrder byteOrder, const ExifData& exifData, const IptcData& iptcData, const XmpData& xmpData ) { // Copy to be able to modify the Exif data ExifData ed = exifData; // Delete IFDs which do not occur in TIFF images static const IfdId filteredIfds[] = { panaRawId }; for (unsigned int i = 0; i < EXV_COUNTOF(filteredIfds); ++i) { #ifdef DEBUG std::cerr << "Warning: Exif IFD " << filteredIfds[i] << " not encoded\n"; #endif ed.erase(std::remove_if(ed.begin(), ed.end(), FindExifdatum(filteredIfds[i])), ed.end()); } std::auto_ptr header(new Cr2Header(byteOrder)); OffsetWriter offsetWriter; offsetWriter.setOrigin(OffsetWriter::cr2RawIfdOffset, Cr2Header::offset2addr(), byteOrder); return TiffParserWorker::encode(io, pData, size, ed, iptcData, xmpData, Tag::root, TiffMapping::findEncoder, header.get(), &offsetWriter); } // ************************************************************************* // free functions Image::AutoPtr newCr2Instance(BasicIo::AutoPtr io, bool create) { Image::AutoPtr image(new Cr2Image(io, create)); if (!image->good()) { image.reset(); } return image; } bool isCr2Type(BasicIo& iIo, bool advance) { const int32_t len = 16; byte buf[len]; iIo.read(buf, len); if (iIo.error() || iIo.eof()) { return false; } Cr2Header header; bool rc = header.read(buf, len); if (!advance || !rc) { iIo.seek(-len, BasicIo::cur); } return rc; } } // namespace Exiv2 namespace Exiv2 { namespace Internal { const char* Cr2Header::cr2sig_ = "CR\2\0"; Cr2Header::Cr2Header(ByteOrder byteOrder) : TiffHeaderBase(42, 16, byteOrder, 0x00000010), offset2_(0x00000000) { } Cr2Header::~Cr2Header() { } bool Cr2Header::read(const byte* pData, uint32_t size) { if (size < 16) return false; if (pData[0] == 0x49 && pData[1] == 0x49) { setByteOrder(littleEndian); } else if (pData[0] == 0x4d && pData[1] == 0x4d) { setByteOrder(bigEndian); } else { return false; } if (tag() != getUShort(pData + 2, byteOrder())) return false; setOffset(getULong(pData + 4, byteOrder())); if (0 != memcmp(pData + 8, cr2sig_, 4)) return false; offset2_ = getULong(pData + 12, byteOrder()); return true; } // Cr2Header::read DataBuf Cr2Header::write() const { DataBuf buf(16); switch (byteOrder()) { case littleEndian: buf.pData_[0] = 0x49; buf.pData_[1] = 0x49; break; case bigEndian: buf.pData_[0] = 0x4d; buf.pData_[1] = 0x4d; break; case invalidByteOrder: assert(false); break; } us2Data(buf.pData_ + 2, tag(), byteOrder()); ul2Data(buf.pData_ + 4, 0x00000010, byteOrder()); memcpy(buf.pData_ + 8, cr2sig_, 4); // Write a dummy value for the RAW IFD offset. The offset-writer is used to set this offset in a second pass. ul2Data(buf.pData_ + 12, 0x00000000, byteOrder()); return buf; } // Cr2Header::write bool Cr2Header::isImageTag(uint16_t tag, IfdId group, const PrimaryGroups* /*pPrimaryGroups*/) const { // CR2 image tags are all IFD2 and IFD3 tags if (group == ifd2Id || group == ifd3Id) return true; // ...and any (IFD0) tag that is in the TIFF image tags list return isTiffImageTag(tag, group); } }} // namespace Internal, Exiv2 exiv2-0.23/src/tiffcomposite_int.hpp0000644000175000017500000020363111732641407017346 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! @file tiffcomposite_int.hpp @brief Internal classes used in a TIFF composite structure @version $Rev: 2681 $ @author Andreas Huggel (ahu) ahuggel@gmx.net @date 11-Apr-06, ahu: created */ #ifndef TIFFCOMPOSITE_INT_HPP_ #define TIFFCOMPOSITE_INT_HPP_ // ***************************************************************************** // included header files #include "value.hpp" #include "tifffwd_int.hpp" #include "types.hpp" // + standard includes #include #include #include #include // ***************************************************************************** // namespace extensions namespace Exiv2 { class BasicIo; namespace Internal { // ***************************************************************************** // class definitions //! TIFF value type. typedef uint16_t TiffType; const TiffType ttUnsignedByte = 1; //!< Exif BYTE type const TiffType ttAsciiString = 2; //!< Exif ASCII type const TiffType ttUnsignedShort = 3; //!< Exif SHORT type const TiffType ttUnsignedLong = 4; //!< Exif LONG type const TiffType ttUnsignedRational = 5; //!< Exif RATIONAL type const TiffType ttSignedByte = 6; //!< Exif SBYTE type const TiffType ttUndefined = 7; //!< Exif UNDEFINED type const TiffType ttSignedShort = 8; //!< Exif SSHORT type const TiffType ttSignedLong = 9; //!< Exif SLONG type const TiffType ttSignedRational =10; //!< Exif SRATIONAL type const TiffType ttTiffFloat =11; //!< TIFF FLOAT type const TiffType ttTiffDouble =12; //!< TIFF DOUBLE type const TiffType ttTiffIfd =13; //!< TIFF IFD type //! Convert the \em tiffType of a \em tag and \em group to an Exiv2 \em typeId. TypeId toTypeId(TiffType tiffType, uint16_t tag, IfdId group); //! Convert the %Exiv2 \em typeId to a TIFF value type. TiffType toTiffType(TypeId typeId); /*! Special TIFF tags for the use in TIFF structures only */ namespace Tag { const uint32_t none = 0x10000; //!< Dummy tag const uint32_t root = 0x20000; //!< Special tag: root IFD const uint32_t next = 0x30000; //!< Special tag: next IFD const uint32_t all = 0x40000; //!< Special tag: all tags in a group const uint32_t pana = 0x80000; //!< Special tag: root IFD of Panasonic RAW images } /*! @brief A tupel consisting of extended Tag and group used as an item in TIFF paths. */ class TiffPathItem { public: //! @name Creators //@{ //! Constructor TiffPathItem(uint32_t extendedTag, IfdId group) : extendedTag_(extendedTag), group_(group) {} //@} //! @name Accessors //@{ //! Return the tag corresponding to the extended tag uint16_t tag() const { return static_cast(extendedTag_ & 0xffff); } //! Return the extended tag (32 bit so that it can contain special tags) uint32_t extendedTag() const { return extendedTag_; } //! Return the group IfdId group() const { return group_; } //@} private: // DATA uint32_t extendedTag_; IfdId group_; }; // class TiffPathItem /*! @brief Simple IO wrapper to ensure that the header is only written if there is any other data at all. The wrapper is initialized with an IO reference and a pointer to a TIFF header. Subsequently the wrapper is used by all TIFF write methods. It takes care that the TIFF header is written to the IO first before any other output and only if there is any other data. */ class IoWrapper { public: //! @name Creators //@{ /*! brief Constructor. The IO wrapper owns none of the objects passed in so the caller is responsible to keep them alive. */ IoWrapper(BasicIo& io, const byte* pHeader, long size, OffsetWriter* pow); //@} //! @name Manipulators //@{ /*! @brief Wraps the corresponding BasicIo::write() method. Writes the TIFF header to the IO, if it hasn't been written yet, followed by the data passed in the arguments. */ long write(const byte* pData, long wcount); /*! @brief Wraps the corresponding BasicIo::putb() method. Writes the TIFF header to the IO, if it hasn't been written yet, followed by the data passed in the argument. */ int putb(byte data); //! Wrapper for OffsetWriter::setTarget(), using an int instead of the enum to reduce include deps void setTarget(int id, uint32_t target); //@} private: // DATA BasicIo& io_; //! Reference for the IO instance. const byte* pHeader_; //! Pointer to the header data. long size_; //! Size of the header data. bool wroteHeader_; //! Indicates if the header has been written. OffsetWriter* pow_; //! Pointer to an offset-writer, if any, or 0 }; // class IoWrapper /*! @brief Interface class for components of a TIFF directory hierarchy (Composite pattern). Both TIFF directories as well as entries implement this interface. A component can be uniquely identified by a tag, group tupel. This class is implemented as a NVI (Non-Virtual Interface) and it has an interface for visitors (Visitor pattern) to perform operations on all components. */ class TiffComponent { public: //! TiffComponent auto_ptr type typedef std::auto_ptr AutoPtr; //! Container type to hold all metadata typedef std::vector Components; //! @name Creators //@{ //! Constructor TiffComponent(uint16_t tag, IfdId group); //! Virtual destructor. virtual ~TiffComponent(); //@} //! @name Manipulators //@{ /*! @brief Add a TIFF entry \em tag to the component. Components on the path to the entry are added if they don't exist yet. @param tag The tag of the new entry @param tiffPath A path from the TIFF root element to a TIFF entry. @param pRoot Pointer to the root component of the TIFF composite. @param object TIFF component to add. If 0, the correct entry will be created. @return A pointer to the newly added TIFF entry. */ TiffComponent* addPath(uint16_t tag, TiffPath& tiffPath, TiffComponent* const pRoot, AutoPtr object =AutoPtr(0)); /*! @brief Add a child to the component. Default is to do nothing. @param tiffComponent Auto pointer to the component to add. @return Return a pointer to the newly added child element or 0. */ TiffComponent* addChild(AutoPtr tiffComponent); /*! @brief Add a "next" component to the component. Default is to do nothing. @param tiffComponent Auto pointer to the component to add. @return Return a pointer to the newly added "next" element or 0. */ TiffComponent* addNext(AutoPtr tiffComponent); /*! @brief Interface to accept visitors (Visitor pattern). Visitors can perform operations on all components of the composite. @param visitor The visitor. */ void accept(TiffVisitor& visitor); /*! @brief Set a pointer to the start of the binary representation of the component in a memory buffer. The buffer must be allocated and freed outside of this class. */ void setStart(const byte* pStart) { pStart_ = const_cast(pStart); } /*! @brief Write a TiffComponent to a binary image. @param ioWrapper IO wrapper to which the TiffComponent is written. @param byteOrder Applicable byte order (little or big endian). @param offset Offset from the start of the image (TIFF header) to the component. @param valueIdx Index of the component to be written relative to offset. @param dataIdx Index of the data area of the component relative to offset. @param imageIdx Index of the image data area relative to offset. @return Number of bytes written to the IO wrapper including all nested components. @throw Error If the component cannot be written. */ uint32_t write(IoWrapper& ioWrapper, ByteOrder byteOrder, int32_t offset, uint32_t valueIdx, uint32_t dataIdx, uint32_t& imageIdx); //@} //! @name Accessors //@{ //! Return the tag of this entry. uint16_t tag() const { return tag_; } //! Return the group id of this component IfdId group() const { return group_; } //! Return a pointer to the start of the binary representation of the component byte* start() const { return pStart_; } /*! @brief Return an auto-pointer to a copy of itself (deep copy, but without any children). The caller owns this copy and the auto-pointer ensures that it will be deleted. */ AutoPtr clone() const; /*! @brief Write the IFD data of this component to a binary image. Return the number of bytes written. Components derived from TiffEntryBase implement this method if needed. */ uint32_t writeData(IoWrapper& ioWrapper, ByteOrder byteOrder, int32_t offset, uint32_t dataIdx, uint32_t& imageIdx) const; /*! @brief Write the image data of this component to a binary image. Return the number of bytes written. TIFF components implement this method if needed. */ uint32_t writeImage(IoWrapper& ioWrapper, ByteOrder byteOrder) const; /*! @brief Return the size in bytes of the IFD value of this component when written to a binary image. */ uint32_t size() const; /*! @brief Return the number of components in this component. */ uint32_t count() const; /*! @brief Return the size in bytes of the IFD data of this component when written to a binary image. This is a support function for write(). Components derived from TiffEntryBase implement this method corresponding to their implementation of writeData(). */ uint32_t sizeData() const; /*! @brief Return the size in bytes of the image data of this component when written to a binary image. This is a support function for write(). TIFF components implement this method corresponding to their implementation of writeImage(). */ uint32_t sizeImage() const; /*! @brief Return the unique id of the entry in the image. */ // Todo: This is only implemented in TiffEntryBase. It is needed here so that // we can sort components by tag and idx. Something is not quite right. virtual int idx() const; //@} protected: //! @name Protected Manipulators //@{ //! Implements addPath(). The default implementation does nothing. virtual TiffComponent* doAddPath(uint16_t tag, TiffPath& tiffPath, TiffComponent* const pRoot, TiffComponent::AutoPtr object); //! Implements addChild(). The default implementation does nothing. virtual TiffComponent* doAddChild(AutoPtr tiffComponent); //! Implements addNext(). The default implementation does nothing. virtual TiffComponent* doAddNext(AutoPtr tiffComponent); //! Implements accept(). virtual void doAccept(TiffVisitor& visitor) =0; //! Implements write(). virtual uint32_t doWrite(IoWrapper& ioWrapper, ByteOrder byteOrder, int32_t offset, uint32_t valueIdx, uint32_t dataIdx, uint32_t& imageIdx) =0; //@} //! @name Protected Accessors //@{ //! Internal virtual copy constructor, implements clone(). virtual TiffComponent* doClone() const =0; //! Implements writeData(). virtual uint32_t doWriteData(IoWrapper& ioWrapper, ByteOrder byteOrder, int32_t offset, uint32_t dataIdx, uint32_t& imageIdx) const =0; //! Implements writeImage(). virtual uint32_t doWriteImage(IoWrapper& ioWrapper, ByteOrder byteOrder) const =0; //! Implements size(). virtual uint32_t doSize() const =0; //! Implements count(). virtual uint32_t doCount() const =0; //! Implements sizeData(). virtual uint32_t doSizeData() const =0; //! Implements sizeImage(). virtual uint32_t doSizeImage() const =0; //@} private: // DATA uint16_t tag_; //!< Tag that identifies the component IfdId group_; //!< Group id for this component /*! Pointer to the start of the binary representation of the component in a memory buffer. The buffer is allocated and freed outside of this class. */ byte* pStart_; }; // class TiffComponent //! TIFF mapping table for functions to decode special cases struct TiffMappingInfo { struct Key; /*! @brief Compare a TiffMappingInfo with a TiffMappingInfo::Key. The two are equal if TiffMappingInfo::make_ equals a substring of the key of the same size. E.g., mapping info = "OLYMPUS", key = "OLYMPUS OPTICAL CO.,LTD" (found in the image) match, the extendedTag is Tag::all or equal to the extended tag of the key, and the group is equal to that of the key. */ bool operator==(const Key& key) const; //! Return the tag corresponding to the extended tag uint16_t tag() const { return static_cast(extendedTag_ & 0xffff); } // DATA const char* make_; //!< Camera make for which these mapping functions apply uint32_t extendedTag_; //!< Tag (32 bit so that it can contain special tags) IfdId group_; //!< Group that contains the tag DecoderFct decoderFct_; //!< Decoder function for matching tags EncoderFct encoderFct_; //!< Encoder function for matching tags }; // struct TiffMappingInfo //! Search key for TIFF mapping structures. struct TiffMappingInfo::Key { //! Constructor Key(const std::string& m, uint32_t e, IfdId g) : m_(m), e_(e), g_(g) {} std::string m_; //!< Camera make uint32_t e_; //!< Extended tag IfdId g_; //!< %Group }; /*! @brief This abstract base class provides the common functionality of an IFD directory entry and defines an extended interface for derived concrete entries, which allows access to the attributes of the entry. */ class TiffEntryBase : public TiffComponent { friend class TiffReader; friend class TiffEncoder; friend int selectNikonLd(TiffBinaryArray* const, TiffComponent* const); public: //! @name Creators //@{ //! Default constructor. TiffEntryBase(uint16_t tag, IfdId group, TiffType tiffType =ttUndefined); //! Virtual destructor. virtual ~TiffEntryBase(); //@} //! @name Manipulators //@{ /*! @brief Encode a TIFF component from the metadatum provided and information from the \em encoder as needed. Implemented as double-dispatch calls back to one of the specific encoding functions at the \em encoder. */ void encode(TiffEncoder& encoder, const Exifdatum* datum); //! Set the offset void setOffset(int32_t offset) { offset_ = offset; } //! Set pointer and size of the entry's data (not taking ownership of the data). void setData(byte* pData, int32_t size); //! Set the entry's data buffer, taking ownership of the data buffer passed in. void setData(DataBuf buf); /*! @brief Update the value. Takes ownership of the pointer passed in. Update binary value data and call setValue(). */ void updateValue(Value::AutoPtr value, ByteOrder byteOrder); /*! @brief Set tag value. Takes ownership of the pointer passed in. Update type, count and the pointer to the value. */ void setValue(Value::AutoPtr value); //@} //! @name Accessors //@{ //! Return the TIFF type TiffType tiffType() const { return tiffType_; } /*! @brief Return the offset to the data area relative to the base for the component (usually the start of the TIFF header) */ int32_t offset() const { return offset_; } /*! @brief Return the unique id of the entry in the image */ virtual int idx() const; /*! @brief Return a pointer to the binary representation of the value of this component. */ const byte* pData() const { return pData_; } //! Return a const pointer to the converted value of this component const Value* pValue() const { return pValue_; } //@} protected: //! @name Protected Creators //@{ //! Copy constructor (used to implement clone()). TiffEntryBase(const TiffEntryBase& rhs); //@} //! @name Protected Manipulators //@{ //! Implements encode(). virtual void doEncode(TiffEncoder& encoder, const Exifdatum* datum) =0; //! Set the number of components in this entry void setCount(uint32_t count) { count_ = count; } //! Set the unique id of the entry in the image void setIdx(int idx) { idx_ = idx; } /*! @brief Implements write(). Write the value of a standard TIFF entry to the \em ioWrapper, return the number of bytes written. Only the \em ioWrapper and \em byteOrder arguments are used. */ virtual uint32_t doWrite(IoWrapper& ioWrapper, ByteOrder byteOrder, int32_t offset, uint32_t valueIdx, uint32_t dataIdx, uint32_t& imageIdx); //@} //! @name Protected Accessors //@{ //! Implements count(). virtual uint32_t doCount() const; /*! @brief Implements writeData(). Standard TIFF entries have no data: write nothing and return 0. */ virtual uint32_t doWriteData(IoWrapper& ioWrapper, ByteOrder byteOrder, int32_t offset, uint32_t dataIdx, uint32_t& imageIdx) const; /*! @brief Implements writeImage(). Standard TIFF entries have no image data: write nothing and return 0. */ virtual uint32_t doWriteImage(IoWrapper& ioWrapper, ByteOrder byteOrder) const; //! Implements size(). Return the size of a standard TIFF entry virtual uint32_t doSize() const; //! Implements sizeData(). Return 0. virtual uint32_t doSizeData() const; //! Implements sizeImage(). Return 0. virtual uint32_t doSizeImage() const; //@} //! Helper function to write an \em offset to a preallocated binary buffer static uint32_t writeOffset(byte* buf, int32_t offset, TiffType tiffType, ByteOrder byteOrder); private: //! @name NOT implemented //@{ //! Assignment operator. TiffEntryBase& operator=(const TiffEntryBase& rhs); //@} // DATA TiffType tiffType_; //!< Field TIFF type uint32_t count_; //!< The number of values of the indicated type int32_t offset_; //!< Offset to the data area /*! Size of the data buffer holding the value in bytes, there is no minimum size. */ uint32_t size_; byte* pData_; //!< Pointer to the data area bool isMalloced_; //!< True if this entry owns the value data int idx_; //!< Unique id of the entry in the image Value* pValue_; //!< Converted data value }; // class TiffEntryBase /*! @brief A standard TIFF IFD entry. */ class TiffEntry : public TiffEntryBase { public: //! @name Creators //@{ //! Constructor TiffEntry(uint16_t tag, IfdId group) : TiffEntryBase(tag, group) {} //! Virtual destructor. virtual ~TiffEntry(); //@} protected: //! @name Manipulators //@{ virtual void doAccept(TiffVisitor& visitor); virtual void doEncode(TiffEncoder& encoder, const Exifdatum* datum); //@} //! @name Protected Accessors //@{ virtual TiffEntry* doClone() const; //@} }; // class TiffEntry /*! @brief Interface for a standard TIFF IFD entry consisting of a value which is a set of offsets to a data area. The sizes of these "strips" are provided in a related TiffSizeEntry, tag and group of which are set in the constructor. The implementations of this interface differ in whether the data areas are extracted to the higher level metadata (TiffDataEntry) or not (TiffImageEntry). */ class TiffDataEntryBase : public TiffEntryBase { public: //! @name Creators //@{ //! Constructor TiffDataEntryBase(uint16_t tag, IfdId group, uint16_t szTag, IfdId szGroup) : TiffEntryBase(tag, group), szTag_(szTag), szGroup_(szGroup) {} //! Virtual destructor. virtual ~TiffDataEntryBase(); //@} //! @name Manipulators //@{ /*! @brief Set the data areas ("strips"). @param pSize Pointer to the Value holding the sizes corresponding to this data entry. @param pData Pointer to the data area. @param sizeData Size of the data area. @param baseOffset Base offset into the data area. */ virtual void setStrips(const Value* pSize, const byte* pData, uint32_t sizeData, uint32_t baseOffset) =0; //@} //! @name Accessors //@{ //! Return the group of the entry which has the size uint16_t szTag() const { return szTag_; } //! Return the group of the entry which has the size IfdId szGroup() const { return szGroup_; } //@} private: // DATA const uint16_t szTag_; //!< Tag of the entry with the size const IfdId szGroup_; //!< Group of the entry with the size }; // class TiffDataEntryBase /*! @brief A standard TIFF IFD entry consisting of a value which is an offset to a data area and the data area. The size of the data area is provided in a related TiffSizeEntry, tag and group of which are set in the constructor. This component extracts the data areas ("strips") and makes them available in the higher level metadata. It is used, e.g., for \em Exif.Thumbnail.JPEGInterchangeFormat for which the size is provided in \em Exif.Thumbnail.JPEGInterchangeFormatLength. */ class TiffDataEntry : public TiffDataEntryBase { friend class TiffEncoder; public: //! @name Creators //@{ //! Constructor TiffDataEntry(uint16_t tag, IfdId group, uint16_t szTag, IfdId szGroup) : TiffDataEntryBase(tag, group, szTag, szGroup), pDataArea_(0), sizeDataArea_(0) {} //! Virtual destructor. virtual ~TiffDataEntry(); //@} //! @name Manipulators //@{ virtual void setStrips(const Value* pSize, const byte* pData, uint32_t sizeData, uint32_t baseOffset); //@} protected: //! @name Protected Manipulators //@{ virtual void doAccept(TiffVisitor& visitor); virtual void doEncode(TiffEncoder& encoder, const Exifdatum* datum); /*! @brief Implements write(). Write pointers into the data area to the \em ioWrapper, relative to the offsets in the value. Return the number of bytes written. The \em valueIdx argument is not used. The number of components in the value determines how many offsets are written. Set the first value to 0, the second to the size of the first data area, etc. when creating a new data entry. Offsets will be adjusted on write. The type of the value can only be signed or unsigned short or long. */ virtual uint32_t doWrite(IoWrapper& ioWrapper, ByteOrder byteOrder, int32_t offset, uint32_t valueIdx, uint32_t dataIdx, uint32_t& imageIdx); //@} //! @name Protected Accessors //@{ virtual TiffDataEntry* doClone() const; /*! @brief Implements writeData(). Write the data area to the \em ioWrapper. Return the number of bytes written. */ virtual uint32_t doWriteData(IoWrapper& ioWrapper, ByteOrder byteOrder, int32_t offset, uint32_t dataIdx, uint32_t& imageIdx) const; // Using doWriteImage from base class // Using doSize() from base class //! Implements sizeData(). Return the size of the data area. virtual uint32_t doSizeData() const; // Using doSizeImage from base class //@} private: // DATA byte* pDataArea_; //!< Pointer to the data area (never alloc'd) uint32_t sizeDataArea_; //!< Size of the data area }; // class TiffDataEntry /*! @brief A standard TIFF IFD entry consisting of a value which is an array of offsets to image data areas. The sizes of the image data areas are provided in a related TiffSizeEntry, tag and group of which are set in the constructor. The data is not extracted into the higher level metadata tags, it is only copied to the target image when the image is written. This component is used, e.g., for \em Exif.Image.StripOffsets for which the sizes are provided in \em Exif.Image.StripByteCounts. */ class TiffImageEntry : public TiffDataEntryBase { friend class TiffEncoder; public: //! @name Creators //@{ //! Constructor TiffImageEntry(uint16_t tag, IfdId group, uint16_t szTag, IfdId szGroup) : TiffDataEntryBase(tag, group, szTag, szGroup) {} //! Virtual destructor. virtual ~TiffImageEntry(); //@} //! @name Manipulators //@{ virtual void setStrips(const Value* pSize, const byte* pData, uint32_t sizeData, uint32_t baseOffset); //@} protected: //! @name Protected Manipulators //@{ virtual void doAccept(TiffVisitor& visitor); virtual void doEncode(TiffEncoder& encoder, const Exifdatum* datum); /*! @brief Implements write(). Write pointers into the image data area to the \em ioWrapper. Return the number of bytes written. The \em valueIdx and \em dataIdx arguments are not used. */ virtual uint32_t doWrite(IoWrapper& ioWrapper, ByteOrder byteOrder, int32_t offset, uint32_t valueIdx, uint32_t dataIdx, uint32_t& imageIdx); //@} //! @name Protected Accessors //@{ virtual TiffImageEntry* doClone() const; /*! @brief Implements writeData(). Write the image data area to the \em ioWrapper. Return the number of bytes written. This function writes the image data to the data area of the current directory. It is used for TIFF image entries in the makernote (large preview images) so that the image data remains in the makernote IFD. */ virtual uint32_t doWriteData(IoWrapper& ioWrapper, ByteOrder byteOrder, int32_t offset, uint32_t dataIdx, uint32_t& imageIdx) const; /*! @brief Implements writeImage(). Write the image data area to the \em ioWrapper. Return the number of bytes written. */ virtual uint32_t doWriteImage(IoWrapper& ioWrapper, ByteOrder byteOrder) const; //! Implements size(). Return the size of the strip pointers. virtual uint32_t doSize() const; //! Implements sizeData(). Return the size of the image data area. virtual uint32_t doSizeData() const; //! Implements sizeImage(). Return the size of the image data area. virtual uint32_t doSizeImage() const; //@} private: //! Pointers to the image data (strips) and their sizes. typedef std::vector > Strips; // DATA Strips strips_; //!< Image strips data (never alloc'd) and sizes }; // class TiffImageEntry /*! @brief A TIFF IFD entry containing the size of a data area of a related TiffDataEntry. This component is used, e.g. for \em Exif.Thumbnail.JPEGInterchangeFormatLength, which contains the size of \em Exif.Thumbnail.JPEGInterchangeFormat. */ class TiffSizeEntry : public TiffEntryBase { public: //! @name Creators //@{ //! Constructor TiffSizeEntry(uint16_t tag, IfdId group, uint16_t dtTag, IfdId dtGroup) : TiffEntryBase(tag, group), dtTag_(dtTag), dtGroup_(dtGroup) {} //! Virtual destructor. virtual ~TiffSizeEntry(); //@} //! @name Accessors //@{ //! Return the group of the related entry which has the data area uint16_t dtTag() const { return dtTag_; } //! Return the group of the related entry which has the data area IfdId dtGroup() const { return dtGroup_; } //@} protected: //! @name Protected Manipulators //@{ virtual void doAccept(TiffVisitor& visitor); virtual void doEncode(TiffEncoder& encoder, const Exifdatum* datum); //@} //! @name Protected Accessors //@{ virtual TiffSizeEntry* doClone() const; //@} private: // DATA const uint16_t dtTag_; //!< Tag of the entry with the data area const IfdId dtGroup_; //!< Group of the entry with the data area }; // class TiffSizeEntry /*! @brief This class models a TIFF directory (%Ifd). It is a composite component of the TIFF tree. */ class TiffDirectory : public TiffComponent { friend class TiffEncoder; public: //! @name Creators //@{ //! Default constructor TiffDirectory(uint16_t tag, IfdId group, bool hasNext =true) : TiffComponent(tag, group), hasNext_(hasNext), pNext_(0) {} //! Virtual destructor virtual ~TiffDirectory(); //@} //! @name Accessors //@{ //! Return true if the directory has a next pointer bool hasNext() const { return hasNext_; } //@} protected: //! @name Protected Creators //@{ //! Copy constructor (used to implement clone()). TiffDirectory(const TiffDirectory& rhs); //@} //! @name Protected Manipulators //@{ virtual TiffComponent* doAddPath(uint16_t tag, TiffPath& tiffPath, TiffComponent* const pRoot, TiffComponent::AutoPtr object); virtual TiffComponent* doAddChild(TiffComponent::AutoPtr tiffComponent); virtual TiffComponent* doAddNext(TiffComponent::AutoPtr tiffComponent); virtual void doAccept(TiffVisitor& visitor); /*! @brief Implements write(). Write the TIFF directory, values and additional data, including the next-IFD, if any, to the \em ioWrapper, return the number of bytes written. */ virtual uint32_t doWrite(IoWrapper& ioWrapper, ByteOrder byteOrder, int32_t offset, uint32_t valueIdx, uint32_t dataIdx, uint32_t& imageIdx); //@} //! @name Protected Accessors //@{ virtual TiffDirectory* doClone() const; /*! @brief This class does not really implement writeData(), it only has write(). This method must not be called; it commits suicide. */ virtual uint32_t doWriteData(IoWrapper& ioWrapper, ByteOrder byteOrder, int32_t offset, uint32_t dataIdx, uint32_t& imageIdx) const; /*! @brief Implements writeImage(). Write the image data of the TIFF directory to the \em ioWrapper by forwarding the call to each component as well as the next-IFD, if there is any. Return the number of bytes written. */ virtual uint32_t doWriteImage(IoWrapper& ioWrapper, ByteOrder byteOrder) const; /*! @brief Implements size(). Return the size of the TIFF directory, values and additional data, including the next-IFD, if any. */ virtual uint32_t doSize() const; /*! @brief Implements count(). Return the number of entries in the TIFF directory. Does not count entries which are marked as deleted. */ virtual uint32_t doCount() const; /*! @brief This class does not really implement sizeData(), it only has size(). This method must not be called; it commits suicide. */ virtual uint32_t doSizeData() const; /*! @brief Implements sizeImage(). Return the sum of the image sizes of all components plus that of the next-IFD, if there is any. */ virtual uint32_t doSizeImage() const; //@} private: //! @name NOT implemented //@{ //! Assignment operator. TiffDirectory& operator=(const TiffDirectory& rhs); //@} //! @name Private Accessors //@{ //! Write a binary directory entry for a TIFF component. uint32_t writeDirEntry(IoWrapper& ioWrapper, ByteOrder byteOrder, int32_t offset, TiffComponent* pTiffComponent, uint32_t valueIdx, uint32_t dataIdx, uint32_t& imageIdx) const; //@} private: // DATA Components components_; //!< List of components in this directory const bool hasNext_; //!< True if the directory has a next pointer TiffComponent* pNext_; //!< Pointer to the next IFD }; // class TiffDirectory /*! @brief This class models a TIFF sub-directory (sub-IFD). A sub-IFD is an entry with one or more values that are pointers to IFD structures containing an IFD. The TIFF standard defines some important tags to be sub-IFDs, including the %Exif and GPS tags. */ class TiffSubIfd : public TiffEntryBase { friend class TiffReader; public: //! @name Creators //@{ //! Default constructor TiffSubIfd(uint16_t tag, IfdId group, IfdId newGroup); //! Virtual destructor virtual ~TiffSubIfd(); //@} protected: //! @name Protected Creators //@{ //! Copy constructor (used to implement clone()). TiffSubIfd(const TiffSubIfd& rhs); //@} //! @name Protected Manipulators //@{ virtual TiffComponent* doAddPath(uint16_t tag, TiffPath& tiffPath, TiffComponent* const pRoot, TiffComponent::AutoPtr object); virtual TiffComponent* doAddChild(TiffComponent::AutoPtr tiffComponent); virtual void doAccept(TiffVisitor& visitor); virtual void doEncode(TiffEncoder& encoder, const Exifdatum* datum); /*! @brief Implements write(). Write the sub-IFD pointers to the \em ioWrapper, return the number of bytes written. The \em valueIdx and \em imageIdx arguments are not used. */ virtual uint32_t doWrite(IoWrapper& ioWrapper, ByteOrder byteOrder, int32_t offset, uint32_t valueIdx, uint32_t dataIdx, uint32_t& imageIdx); //@} //! @name Protected Accessors //@{ virtual TiffSubIfd* doClone() const; /*! @brief Implements writeData(). Write the sub-IFDs to the \em ioWrapper. Return the number of bytes written. */ virtual uint32_t doWriteData(IoWrapper& ioWrapper, ByteOrder byteOrder, int32_t offset, uint32_t dataIdx, uint32_t& imageIdx) const; /*! @brief Implements writeImage(). Write the image data of each sub-IFD to the \em ioWrapper. Return the number of bytes written. */ virtual uint32_t doWriteImage(IoWrapper& ioWrapper, ByteOrder byteOrder) const; //! Implements size(). Return the size of the sub-Ifd pointers. uint32_t doSize() const; //! Implements sizeData(). Return the sum of the sizes of all sub-IFDs. virtual uint32_t doSizeData() const; //! Implements sizeImage(). Return the sum of the image sizes of all sub-IFDs. virtual uint32_t doSizeImage() const; //@} private: //! @name NOT implemented //@{ //! Assignment operator. TiffSubIfd& operator=(const TiffSubIfd& rhs); //@} //! A collection of TIFF directories (IFDs) typedef std::vector Ifds; // DATA IfdId newGroup_; //!< Start of the range of group numbers for the sub-IFDs Ifds ifds_; //!< The subdirectories }; // class TiffSubIfd /*! @brief This class is the basis for Makernote support in TIFF. It contains a pointer to a concrete Makernote. The TiffReader visitor has the responsibility to create the correct Make/Model specific Makernote for a particular TIFF file. Calls to child management methods are forwarded to the concrete Makernote, if there is one. */ class TiffMnEntry : public TiffEntryBase { friend class TiffReader; friend class TiffDecoder; friend class TiffEncoder; public: //! @name Creators //@{ //! Default constructor TiffMnEntry(uint16_t tag, IfdId group, IfdId mnGroup); //! Virtual destructor virtual ~TiffMnEntry(); //@} protected: //! @name Protected Manipulators //@{ virtual TiffComponent* doAddPath(uint16_t tag, TiffPath& tiffPath, TiffComponent* const pRoot, TiffComponent::AutoPtr object); virtual TiffComponent* doAddChild(TiffComponent::AutoPtr tiffComponent); virtual TiffComponent* doAddNext(TiffComponent::AutoPtr tiffComponent); virtual void doAccept(TiffVisitor& visitor); virtual void doEncode(TiffEncoder& encoder, const Exifdatum* datum); /*! @brief Implements write() by forwarding the call to the actual concrete Makernote, if there is one. */ virtual uint32_t doWrite(IoWrapper& ioWrapper, ByteOrder byteOrder, int32_t offset, uint32_t valueIdx, uint32_t dataIdx, uint32_t& imageIdx); //@} //! @name Protected Accessors //@{ virtual TiffMnEntry* doClone() const; //! Implements count(). Return number of components in the entry. virtual uint32_t doCount() const; // Using doWriteData from base class // Using doWriteImage from base class /*! @brief Implements size() by forwarding the call to the actual concrete Makernote, if there is one. */ virtual uint32_t doSize() const; // Using doSizeData from base class // Using doSizeImage from base class //@} private: //! @name NOT implemented //@{ //! Copy constructor. TiffMnEntry(const TiffMnEntry& rhs); //! Assignment operator. TiffMnEntry& operator=(const TiffMnEntry& rhs); //@} // DATA IfdId mnGroup_; //!< New group for concrete mn TiffComponent* mn_; //!< The Makernote }; // class TiffMnEntry /*! @brief Tiff IFD Makernote. This is a concrete class suitable for all IFD makernotes. Contains a makernote header (which can be 0) and an IFD and implements child mgmt functions to deal with the IFD entries. The various makernote weirdnesses are taken care of in the makernote header (and possibly in special purpose IFD entries). */ class TiffIfdMakernote : public TiffComponent { friend class TiffReader; public: //! @name Creators //@{ //! Default constructor TiffIfdMakernote(uint16_t tag, IfdId group, IfdId mnGroup, MnHeader* pHeader, bool hasNext =true); //! Virtual destructor virtual ~TiffIfdMakernote(); //@} //! @name Manipulators //@{ /*! @brief Read the header from a data buffer, return true if successful. The default implementation simply returns true. */ bool readHeader(const byte* pData, uint32_t size, ByteOrder byteOrder); /*! @brief Set the byte order for the makernote. */ void setByteOrder(ByteOrder byteOrder); /*! @brief Set the byte order used for the image. */ void setImageByteOrder(ByteOrder byteOrder) { imageByteOrder_ = byteOrder; } //@} //! @name Accessors //@{ //! Return the size of the header in bytes. uint32_t sizeHeader() const; //! Write the header to a data buffer, return the number of bytes written. uint32_t writeHeader(IoWrapper& ioWrapper, ByteOrder byteOrder) const; /*! @brief Return the offset to the makernote from the start of the TIFF header. */ uint32_t mnOffset() const; /*! @brief Return the offset to the start of the Makernote IFD from the start of the Makernote. Returns 0 if there is no header. */ uint32_t ifdOffset() const; /*! @brief Return the byte order for the makernote. Requires the image byte order to be set (setImageByteOrder()). Returns the byte order for the image if there is no header or the byte order for the header is \c invalidByteOrder. */ ByteOrder byteOrder() const; /*! @brief Return the byte order used for the image. */ ByteOrder imageByteOrder() const { return imageByteOrder_; } /*! @brief Return the base offset for use with the makernote IFD entries relative to the start of the TIFF header. Returns 0 if there is no header. */ uint32_t baseOffset() const; //@} protected: //! @name Protected Manipulators //@{ virtual TiffComponent* doAddPath(uint16_t tag, TiffPath& tiffPath, TiffComponent* const pRoot, TiffComponent::AutoPtr object); virtual TiffComponent* doAddChild(TiffComponent::AutoPtr tiffComponent); virtual TiffComponent* doAddNext(TiffComponent::AutoPtr tiffComponent); virtual void doAccept(TiffVisitor& visitor); /*! @brief Implements write(). Write the Makernote header, TIFF directory, values and additional data to the \em ioWrapper, return the number of bytes written. */ virtual uint32_t doWrite(IoWrapper& ioWrapper, ByteOrder byteOrder, int32_t offset, uint32_t valueIdx, uint32_t dataIdx, uint32_t& imageIdx); //@} //! @name Protected Accessors //@{ virtual TiffIfdMakernote* doClone() const; /*! @brief This class does not really implement writeData(), it only has write(). This method must not be called; it commits suicide. */ virtual uint32_t doWriteData(IoWrapper& ioWrapper, ByteOrder byteOrder, int32_t offset, uint32_t dataIdx, uint32_t& imageIdx) const; /*! @brief Implements writeImage(). Write the image data of the IFD of the Makernote. Return the number of bytes written. */ virtual uint32_t doWriteImage(IoWrapper& ioWrapper, ByteOrder byteOrder) const; /*! @brief Implements size(). Return the size of the Makernote header, TIFF directory, values and additional data. */ virtual uint32_t doSize() const; /*! @brief Implements count(). Return the number of entries in the IFD of the Makernote. Does not count entries which are marked as deleted. */ virtual uint32_t doCount() const; /*! @brief This class does not really implement sizeData(), it only has size(). This method must not be called; it commits suicide. */ virtual uint32_t doSizeData() const; /*! @brief Implements sizeImage(). Return the total image data size of the makernote IFD. */ virtual uint32_t doSizeImage() const; //@} private: /*! @name NOT implemented Implementing the copy constructor and assignment operator will require cloning the header, i.e., clone() functionality on the MnHeader hierarchy. */ //@{ //! Copy constructor. TiffIfdMakernote(const TiffIfdMakernote& rhs); //! Assignment operator. TiffIfdMakernote& operator=(const TiffIfdMakernote& rhs); //@} // DATA MnHeader* pHeader_; //!< Makernote header TiffDirectory ifd_; //!< Makernote IFD uint32_t mnOffset_; //!< Makernote offset ByteOrder imageByteOrder_; //!< Byte order for the image }; // class TiffIfdMakernote /*! @brief Function pointer type for a function to determine which cfg + def of a corresponding array set to use. */ typedef int (*CfgSelFct)(uint16_t, const byte*, uint32_t, TiffComponent* const); //! Function pointer type for a crypt function used for binary arrays. typedef DataBuf (*CryptFct)(uint16_t, const byte*, uint32_t, TiffComponent* const); //! Defines one tag in a binary array struct ArrayDef { //! Comparison with idx bool operator==(uint32_t idx) const { return idx_ == idx; } //! Get the size in bytes of a tag. uint32_t size(uint16_t tag, IfdId group) const; // DATA uint32_t idx_; //!< Index in bytes from the start TiffType tiffType_; //!< TIFF type of the element uint32_t count_; //!< Number of components }; //! Additional configuration for a binary array. struct ArrayCfg { /*! @brief Return the size of the default tag, which is used to calculate tag numbers as idx/tagStep */ uint32_t tagStep() const { return elDefaultDef_.size(0, group_); } //DATA IfdId group_; //!< Group for the elements ByteOrder byteOrder_; //!< Byte order, invalidByteOrder to inherit TiffType elTiffType_; //!< Type for the array entry and the size element, if any CryptFct cryptFct_; //!< Crypt function, 0 if not used bool hasSize_; //!< If true, first tag is the size element bool hasFillers_; //!< If true, write all defined tags bool concat_; //!< If true, concatenate gaps between defined tags to single tags ArrayDef elDefaultDef_; //!< Default element }; //! Combination of array configuration and definition for arrays struct ArraySet { const ArrayCfg cfg_; //!< Binary array configuration const ArrayDef* def_; //!< Binary array definition array const int defSize_; //!< Size of the array definition array }; /*! @brief Composite to model an array of different tags. The tag types as well as other aspects of the array are configurable. The elements of this component are of type TiffBinaryElement. */ class TiffBinaryArray : public TiffEntryBase { public: //! @name Creators //@{ //! Constructor TiffBinaryArray(uint16_t tag, IfdId group, const ArrayCfg* arrayCfg, const ArrayDef* arrayDef, int defSize); //! Constructor for a complex binary array TiffBinaryArray(uint16_t tag, IfdId group, const ArraySet* arraySet, int setSize, CfgSelFct cfgSelFct); //! Virtual destructor virtual ~TiffBinaryArray(); //@} //! @name Manipulators //@{ //! Add an element to the binary array, return the size of the element uint32_t addElement(uint32_t idx, const ArrayDef& def); /*! @brief Setup cfg and def for the component, in case of a complex binary array. Else do nothing. Return true if the initialization succeeded, else false. This version of initialize() is used during intrusive writing. It determines the correct settings based on the \em group passed in (which is the group of the first tag that is added to the array). It doesn't require cfgSelFct_. @param group Group to setup the binary array for. @return true if the initialization succeeded, else false. */ bool initialize(IfdId group); /*! @brief Setup cfg and def for the component, in case of a complex binary array. Else do nothing. Return true if the initialization succeeded, else false. This version of initialize() is used for reading and non-intrusive writing. It calls cfgSelFct_ to determine the correct settings. @param pRoot Pointer to the root component of the TIFF tree. @return true if the initialization succeeded, else false. */ bool initialize(TiffComponent* const pRoot); //! Initialize the original data buffer and its size from the base entry. void iniOrigDataBuf(); //! Update the original data buffer and its size, return true if successful. bool updOrigDataBuf(const byte* pData, uint32_t size); //! Set a flag to indicate if the array was decoded void setDecoded(bool decoded) { decoded_ = decoded; } //@} //! @name Accessors //@{ //! Return a pointer to the configuration const ArrayCfg* cfg() const { return arrayCfg_; } //! Return a pointer to the definition const ArrayDef* def() const { return arrayDef_; } //! Return the number of elements in the definition int defSize() const { return defSize_; } //! Return the flag which indicates if the array was decoded bool decoded() const { return decoded_; } //@} protected: //! @name Protected Creators //@{ //! Copy constructor (used to implement clone()). TiffBinaryArray(const TiffBinaryArray& rhs); //@} //! @name Protected Manipulators //@{ /*! @brief Implements addPath(). Todo: Document it! */ virtual TiffComponent* doAddPath(uint16_t tag, TiffPath& tiffPath, TiffComponent* const pRoot, TiffComponent::AutoPtr object); /*! @brief Implements addChild(). Todo: Document it! */ virtual TiffComponent* doAddChild(TiffComponent::AutoPtr tiffComponent); virtual void doAccept(TiffVisitor& visitor); virtual void doEncode(TiffEncoder& encoder, const Exifdatum* datum); /*! @brief Implements write(). Todo: Document it! */ virtual uint32_t doWrite(IoWrapper& ioWrapper, ByteOrder byteOrder, int32_t offset, uint32_t valueIdx, uint32_t dataIdx, uint32_t& imageIdx); //@} //! @name Protected Accessors //@{ virtual TiffBinaryArray* doClone() const; //! Implements count(). Todo: Document it! virtual uint32_t doCount() const; // Using doWriteData from base class // Using doWriteImage from base class /*! @brief Implements size(). Todo: Document it! */ virtual uint32_t doSize() const; // Using doSizeData from base class // Using doSizeImage from base class //@} private: //! @name NOT implemented //@{ //! Assignment operator. TiffBinaryArray& operator=(const TiffBinaryArray& rhs); //@} // DATA const CfgSelFct cfgSelFct_; //!< Pointer to a function to determine which cfg to use (may be 0) const ArraySet* arraySet_; //!< Pointer to the array set, if any (may be 0) const ArrayCfg* arrayCfg_; //!< Pointer to the array configuration (must not be 0, except for unrecognized complex binary arrays) const ArrayDef* arrayDef_; //!< Pointer to the array definition (may be 0) int defSize_; //!< Size of the array definition array (may be 0) int setSize_; //!< Size of the array set (may be 0) Components elements_; //!< List of elements in this composite byte* origData_; //!< Pointer to the original data buffer (unencrypted) uint32_t origSize_; //!< Size of the original data buffer TiffComponent* pRoot_; //!< Pointer to the root component of the TIFF tree. (Only used for intrusive writing.) bool decoded_; //!< Flag to indicate if the array was decoded }; // class TiffBinaryArray /*! @brief Element of a TiffBinaryArray. */ class TiffBinaryElement : public TiffEntryBase { public: //! @name Creators //@{ //! Constructor TiffBinaryElement(uint16_t tag, IfdId group); //! Virtual destructor. virtual ~TiffBinaryElement(); //@} //! @name Manipulators //@{ /*! @brief Set the array definition for this element. */ void setElDef(const ArrayDef& def) { elDef_ = def; } /*! @brief Set the byte order of this element. */ void setElByteOrder(ByteOrder byteOrder) { elByteOrder_ = byteOrder; } //@} //! @name Accessors //@{ /*! @brief Return the array definition of this element. */ const ArrayDef* elDef() const { return &elDef_; } /*! @brief Return the byte order of this element. */ ByteOrder elByteOrder() const { return elByteOrder_; } //@} protected: //! @name Protected Manipulators //@{ virtual void doAccept(TiffVisitor& visitor); virtual void doEncode(TiffEncoder& encoder, const Exifdatum* datum); /*! @brief Implements write(). Todo: Document it! */ virtual uint32_t doWrite(IoWrapper& ioWrapper, ByteOrder byteOrder, int32_t offset, uint32_t valueIdx, uint32_t dataIdx, uint32_t& imageIdx); //@} //! @name Protected Accessors //@{ virtual TiffBinaryElement* doClone() const; /*! @brief Implements count(). Returns the count from the element definition. */ virtual uint32_t doCount() const; // Using doWriteData from base class // Using doWriteImage from base class /*! @brief Implements size(). Returns count * type-size, both taken from the element definition. */ virtual uint32_t doSize() const; // Using doSizeData from base class // Using doSizeImage from base class //@} private: // DATA ArrayDef elDef_; //!< The array element definition ByteOrder elByteOrder_; //!< Byte order to read/write the element }; // class TiffBinaryElement // ***************************************************************************** // template, inline and free functions /*! @brief Compare two TIFF component pointers by tag. Return true if the tag of component lhs is less than that of rhs. */ bool cmpTagLt(TiffComponent const* lhs, TiffComponent const* rhs); /*! @brief Compare two TIFF component pointers by group. Return true if the group of component lhs is less than that of rhs. */ bool cmpGroupLt(TiffComponent const* lhs, TiffComponent const* rhs); //! Function to create and initialize a new TIFF entry TiffComponent::AutoPtr newTiffEntry(uint16_t tag, IfdId group); //! Function to create and initialize a new TIFF makernote entry TiffComponent::AutoPtr newTiffMnEntry(uint16_t tag, IfdId group); //! Function to create and initialize a new binary array element TiffComponent::AutoPtr newTiffBinaryElement(uint16_t tag, IfdId group); //! Function to create and initialize a new TIFF directory template TiffComponent::AutoPtr newTiffDirectory(uint16_t tag, IfdId /*group*/) { return TiffComponent::AutoPtr(new TiffDirectory(tag, newGroup)); } //! Function to create and initialize a new TIFF sub-directory template TiffComponent::AutoPtr newTiffSubIfd(uint16_t tag, IfdId group) { return TiffComponent::AutoPtr(new TiffSubIfd(tag, group, newGroup)); } //! Function to create and initialize a new binary array entry template TiffComponent::AutoPtr newTiffBinaryArray0(uint16_t tag, IfdId group) { // *& acrobatics is a workaround for a MSVC 7.1 bug return TiffComponent::AutoPtr( new TiffBinaryArray(tag, group, arrayCfg, *(&arrayDef), N)); } //! Function to create and initialize a new simple binary array entry template TiffComponent::AutoPtr newTiffBinaryArray1(uint16_t tag, IfdId group) { return TiffComponent::AutoPtr( new TiffBinaryArray(tag, group, arrayCfg, 0, 0)); } //! Function to create and initialize a new complex binary array entry template TiffComponent::AutoPtr newTiffBinaryArray2(uint16_t tag, IfdId group) { return TiffComponent::AutoPtr( new TiffBinaryArray(tag, group, arraySet, N, cfgSelFct)); } //! Function to create and initialize a new TIFF entry for a thumbnail (data) template TiffComponent::AutoPtr newTiffThumbData(uint16_t tag, IfdId group) { return TiffComponent::AutoPtr( new TiffDataEntry(tag, group, szTag, szGroup)); } //! Function to create and initialize a new TIFF entry for a thumbnail (size) template TiffComponent::AutoPtr newTiffThumbSize(uint16_t tag, IfdId group) { return TiffComponent::AutoPtr( new TiffSizeEntry(tag, group, dtTag, dtGroup)); } //! Function to create and initialize a new TIFF entry for image data template TiffComponent::AutoPtr newTiffImageData(uint16_t tag, IfdId group) { return TiffComponent::AutoPtr( new TiffImageEntry(tag, group, szTag, szGroup)); } //! Function to create and initialize a new TIFF entry for image data (size) template TiffComponent::AutoPtr newTiffImageSize(uint16_t tag, IfdId group) { // Todo: Same as newTiffThumbSize - consolidate (rename)? return TiffComponent::AutoPtr( new TiffSizeEntry(tag, group, dtTag, dtGroup)); } }} // namespace Internal, Exiv2 #endif // #ifndef TIFFCOMPOSITE_INT_HPP_ exiv2-0.23/src/pngimage.hpp0000644000175000017500000001160711732641407015410 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! @file pngimage.hpp @brief PNG image, implemented using the following references: PNG specification by W3C
PNG tags list by Phil Harvey
@version $Rev: 2681 $ @author Andreas Huggel (ahu) ahuggel@gmx.net @author Gilles Caulier (cgilles) caulier dot gilles at gmail dot com @date 12-Jun-06, gc: submitted */ #ifndef PNGIMAGE_HPP_ #define PNGIMAGE_HPP_ // ***************************************************************************** // included header files #include "image.hpp" #include "basicio.hpp" #include "types.hpp" // + standard includes #include // ***************************************************************************** // namespace extensions namespace Exiv2 { // ***************************************************************************** // class definitions // Add PNG to the supported image formats namespace ImageType { const int png = 6; //!< PNG image type (see class PngImage) } /*! @brief Class to access PNG images. Exif and IPTC metadata are supported directly. */ class EXIV2API PngImage : public Image { public: //! @name Creators //@{ /*! @brief Constructor that can either open an existing PNG image or create a new image from scratch. If a new image is to be created, any existing data is overwritten. Since the constructor can not return a result, callers should check the good() method after object construction to determine success or failure. @param io An auto-pointer that owns a BasicIo instance used for reading and writing image metadata. \b Important: The constructor takes ownership of the passed in BasicIo instance through the auto-pointer. Callers should not continue to use the BasicIo instance after it is passed to this method. Use the Image::io() method to get a temporary reference. @param create Specifies if an existing image should be read (false) or if a new file should be created (true). */ PngImage(BasicIo::AutoPtr io, bool create); //@} //! @name Manipulators //@{ void readMetadata(); void writeMetadata(); //@} //! @name Accessors //@{ std::string mimeType() const; //@} private: //! @name NOT implemented //@{ //! Copy constructor PngImage(const PngImage& rhs); //! Assignment operator PngImage& operator=(const PngImage& rhs); /*! @brief Provides the main implementation of writeMetadata() by writing all buffered metadata to the provided BasicIo. @param oIo BasicIo instance to write to (a temporary location). @return 4 if opening or writing to the associated BasicIo fails */ EXV_DLLLOCAL void doWriteMetadata(BasicIo& oIo); //@} }; // class PngImage // ***************************************************************************** // template, inline and free functions // These could be static private functions on Image subclasses but then // ImageFactory needs to be made a friend. /*! @brief Create a new PngImage instance and return an auto-pointer to it. Caller owns the returned object and the auto-pointer ensures that it will be deleted. */ EXIV2API Image::AutoPtr newPngInstance(BasicIo::AutoPtr io, bool create); //! Check if the file iIo is a PNG image. EXIV2API bool isPngType(BasicIo& iIo, bool advance); } // namespace Exiv2 #endif // #ifndef PNGIMAGE_HPP_ exiv2-0.23/src/exif.hpp0000644000175000017500000006076111732641407014561 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! @file exif.hpp @brief Encoding and decoding of Exif data @version $Rev: 2681 $ @author Andreas Huggel (ahu) ahuggel@gmx.net @date 09-Jan-04, ahu: created */ #ifndef EXIF_HPP_ #define EXIF_HPP_ // ***************************************************************************** // included header files #include "metadatum.hpp" #include "tags.hpp" #include "value.hpp" #include "types.hpp" // + standard includes #include #include #include // ***************************************************************************** // namespace extensions /*! @brief Provides classes and functions to encode and decode Exif and Iptc data. The libexiv2 API consists of the objects of this namespace. */ namespace Exiv2 { // ***************************************************************************** // class declarations class ExifData; // ***************************************************************************** // class definitions /*! @brief An Exif metadatum, consisting of an ExifKey and a Value and methods to manipulate these. */ class EXIV2API Exifdatum : public Metadatum { template friend Exifdatum& setValue(Exifdatum&, const T&); public: //! @name Creators //@{ /*! @brief Constructor for new tags created by an application. The %Exifdatum is created from a \em key / value pair. %Exifdatum copies (clones) the \em key and value if one is provided. Alternatively, a program can create an 'empty' %Exifdatum with only a key and set the value using setValue(). @param key %ExifKey. @param pValue Pointer to an %Exifdatum value. @throw Error if the key cannot be parsed and converted. */ explicit Exifdatum(const ExifKey& key, const Value* pValue =0); //! Copy constructor Exifdatum(const Exifdatum& rhs); //! Destructor virtual ~Exifdatum(); //@} //! @name Manipulators //@{ //! Assignment operator Exifdatum& operator=(const Exifdatum& rhs); /*! @brief Assign \em value to the %Exifdatum. The type of the new Value is set to UShortValue. */ Exifdatum& operator=(const uint16_t& value); /*! @brief Assign \em value to the %Exifdatum. The type of the new Value is set to ULongValue. */ Exifdatum& operator=(const uint32_t& value); /*! @brief Assign \em value to the %Exifdatum. The type of the new Value is set to URationalValue. */ Exifdatum& operator=(const URational& value); /*! @brief Assign \em value to the %Exifdatum. The type of the new Value is set to ShortValue. */ Exifdatum& operator=(const int16_t& value); /*! @brief Assign \em value to the %Exifdatum. The type of the new Value is set to LongValue. */ Exifdatum& operator=(const int32_t& value); /*! @brief Assign \em value to the %Exifdatum. The type of the new Value is set to RationalValue. */ Exifdatum& operator=(const Rational& value); /*! @brief Assign \em value to the %Exifdatum. Calls setValue(const std::string&). */ Exifdatum& operator=(const std::string& value); /*! @brief Assign \em value to the %Exifdatum. Calls setValue(const Value*). */ Exifdatum& operator=(const Value& value); void setValue(const Value* pValue); /*! @brief Set the value to the string \em value. Uses Value::read(const std::string&). If the %Exifdatum does not have a Value yet, then a %Value of the correct type for this %Exifdatum is created. An AsciiValue is created for unknown tags. Return 0 if the value was read successfully. */ int setValue(const std::string& value); /*! @brief Set the data area by copying (cloning) the buffer pointed to by \em buf. Values may have a data area, which can contain additional information besides the actual value. This method is used to set such a data area. @param buf Pointer to the source data area @param len Size of the data area @return Return -1 if the %Exifdatum does not have a value yet or the value has no data area, else 0. */ int setDataArea(const byte* buf, long len); //@} //! @name Accessors //@{ //! Return the key of the %Exifdatum. std::string key() const; const char* familyName() const; std::string groupName() const; std::string tagName() const; std::string tagLabel() const; uint16_t tag() const; //! Return the IFD id as an integer. (Do not use, this is meant for library internal use.) int ifdId() const; //! Return the name of the IFD const char* ifdName() const; //! Return the index (unique id of this key within the original IFD) int idx() const; /*! @brief Write value to a data buffer and return the number of bytes written. The user must ensure that the buffer has enough memory. Otherwise the call results in undefined behaviour. @param buf Data buffer to write to. @param byteOrder Applicable byte order (little or big endian). @return Number of characters written. */ long copy(byte* buf, ByteOrder byteOrder) const; std::ostream& write(std::ostream& os, const ExifData* pMetadata =0) const; //! Return the type id of the value TypeId typeId() const; //! Return the name of the type const char* typeName() const; //! Return the size in bytes of one component of this type long typeSize() const; //! Return the number of components in the value long count() const; //! Return the size of the value in bytes long size() const; //! Return the value as a string. std::string toString() const; std::string toString(long n) const; long toLong(long n =0) const; float toFloat(long n =0) const; Rational toRational(long n =0) const; Value::AutoPtr getValue() const; const Value& value() const; //! Return the size of the data area. long sizeDataArea() const; /*! @brief Return a copy of the data area of the value. The caller owns this copy and %DataBuf ensures that it will be deleted. Values may have a data area, which can contain additional information besides the actual value. This method is used to access such a data area. @return A %DataBuf containing a copy of the data area or an empty %DataBuf if the value does not have a data area assigned or the value is not set. */ DataBuf dataArea() const; //@} private: // DATA ExifKey::AutoPtr key_; //!< Key Value::AutoPtr value_; //!< Value }; // class Exifdatum /*! @brief Access to a Exif %thumbnail image. This class provides higher level accessors to the thumbnail image that is optionally embedded in IFD1 of the Exif data. These methods do not write to the Exif metadata. Manipulators are provided in subclass ExifThumb. @note Various other preview and thumbnail images may be contained in an image, depending on its format and the camera make and model. This class only provides access to the Exif thumbnail as specified in the Exif standard. */ class EXIV2API ExifThumbC { public: //! @name Creators //@{ //! Constructor. ExifThumbC(const ExifData& exifData); //@} //! @name Accessors //@{ /*! @brief Return the thumbnail image in a %DataBuf. The caller owns the data buffer and %DataBuf ensures that it will be deleted. */ DataBuf copy() const; /*! @brief Write the thumbnail image to a file. A filename extension is appended to \em path according to the image type of the thumbnail, so \em path should not include an extension. The function will overwrite an existing file of the same name. @param path File name of the thumbnail without extension. @return The number of bytes written. */ long writeFile(const std::string& path) const; #ifdef EXV_UNICODE_PATH /*! @brief Like writeFile() but accepts a unicode path in an std::wstring. @note This function is only available on Windows. */ long writeFile(const std::wstring& wpath) const; #endif /*! @brief Return the MIME type of the thumbnail, either \c "image/tiff" or \c "image/jpeg". */ const char* mimeType() const; /*! @brief Return the file extension for the format of the thumbnail (".tif" or ".jpg"). */ const char* extension() const; #ifdef EXV_UNICODE_PATH /*! @brief Like extension() but returns the extension in a wchar_t. @note This function is only available on Windows. */ const wchar_t* wextension() const; #endif //@} private: // DATA const ExifData& exifData_; //!< Const reference to the Exif metadata. }; // class ExifThumb /*! @brief Access and modify an Exif %thumbnail image. This class implements manipulators to set and erase the thumbnail image that is optionally embedded in IFD1 of the Exif data. Accessors are provided by the base class, ExifThumbC. @note Various other preview and thumbnail images may be contained in an image, depending on its format and the camera make and model. This class only provides access to the Exif thumbnail as specified in the Exif standard. */ class EXIV2API ExifThumb : public ExifThumbC { public: //! @name Creators //@{ //! Constructor. ExifThumb(ExifData& exifData); //@} //! @name Manipulators //@{ /*! @brief Set the Exif thumbnail to the JPEG image \em path. Set XResolution, YResolution and ResolutionUnit to \em xres, \em yres and \em unit, respectively. This results in the minimal thumbnail tags being set for a JPEG thumbnail, as mandated by the Exif standard. @throw Error if reading the file fails. @note No checks on the file format or size are performed. @note Additional existing Exif thumbnail tags are not modified. @note The JPEG image inserted as thumbnail image should not itself contain Exif data (or other metadata), as existing applications may have problems with that. (The preview application that comes with OS X for one.) - David Harvey. */ void setJpegThumbnail( const std::string& path, URational xres, URational yres, uint16_t unit ); #ifdef EXV_UNICODE_PATH /*! @brief Like setJpegThumbnail() but accepts a unicode path in an std::wstring. @note This function is only available on Windows. */ void setJpegThumbnail( const std::wstring& wpath, URational xres, URational yres, uint16_t unit ); #endif /*! @brief Set the Exif thumbnail to the JPEG image pointed to by \em buf, and size \em size. Set XResolution, YResolution and ResolutionUnit to \em xres, \em yres and \em unit, respectively. This results in the minimal thumbnail tags being set for a JPEG thumbnail, as mandated by the Exif standard. @throw Error if reading the file fails. @note No checks on the image format or size are performed. @note Additional existing Exif thumbnail tags are not modified. @note The JPEG image inserted as thumbnail image should not itself contain Exif data (or other metadata), as existing applications may have problems with that. (The preview application that comes with OS X for one.) - David Harvey. */ void setJpegThumbnail( const byte* buf, long size, URational xres, URational yres, uint16_t unit ); /*! @brief Set the Exif thumbnail to the JPEG image \em path. This sets only the Compression, JPEGInterchangeFormat and JPEGInterchangeFormatLength tags, which is not all the thumbnail Exif information mandatory according to the Exif standard. (But it's enough to work with the thumbnail.) @throw Error if reading the file fails. @note No checks on the file format or size are performed. @note Additional existing Exif thumbnail tags are not modified. */ void setJpegThumbnail(const std::string& path); #ifdef EXV_UNICODE_PATH /*! @brief Like setJpegThumbnail(const std::string& path) but accepts a unicode path in an std::wstring. @note This function is only available on Windows. */ void setJpegThumbnail(const std::wstring& wpath); #endif /*! @brief Set the Exif thumbnail to the JPEG image pointed to by \em buf, and size \em size. This sets only the Compression, JPEGInterchangeFormat and JPEGInterchangeFormatLength tags, which is not all the thumbnail Exif information mandatory according to the Exif standard. (But it's enough to work with the thumbnail.) @note No checks on the image format or size are performed. @note Additional existing Exif thumbnail tags are not modified. */ void setJpegThumbnail(const byte* buf, long size); /*! @brief Delete the thumbnail from the Exif data. Removes all Exif.%Thumbnail.*, i.e., Exif IFD1 tags. */ void erase(); //@} private: // DATA ExifData& exifData_; //!< Reference to the related Exif metadata. }; // class ExifThumb //! Container type to hold all metadata typedef std::list ExifMetadata; /*! @brief A container for Exif data. This is a top-level class of the %Exiv2 library. The container holds Exifdatum objects. Provide high-level access to the Exif data of an image: - read Exif information from JPEG files - access metadata through keys and standard C++ iterators - add, modify and delete metadata - write Exif data to JPEG files - extract Exif metadata to files, insert from these files - extract and delete Exif thumbnail (JPEG and TIFF thumbnails) */ class EXIV2API ExifData { public: //! ExifMetadata iterator type typedef ExifMetadata::iterator iterator; //! ExifMetadata const iterator type typedef ExifMetadata::const_iterator const_iterator; //! @name Manipulators //@{ /*! @brief Returns a reference to the %Exifdatum that is associated with a particular \em key. If %ExifData does not already contain such an %Exifdatum, operator[] adds object \em Exifdatum(key). @note Since operator[] might insert a new element, it can't be a const member function. */ Exifdatum& operator[](const std::string& key); /*! @brief Add an Exifdatum from the supplied key and value pair. This method copies (clones) key and value. No duplicate checks are performed, i.e., it is possible to add multiple metadata with the same key. */ void add(const ExifKey& key, const Value* pValue); /*! @brief Add a copy of the \em exifdatum to the Exif metadata. No duplicate checks are performed, i.e., it is possible to add multiple metadata with the same key. @throw Error if the makernote cannot be created */ void add(const Exifdatum& exifdatum); /*! @brief Delete the Exifdatum at iterator position \em pos, return the position of the next exifdatum. Note that iterators into the metadata, including \em pos, are potentially invalidated by this call. */ iterator erase(iterator pos); /*! @brief Remove all elements of the range \em beg, \em end, return the position of the next element. Note that iterators into the metadata are potentially invalidated by this call. */ iterator erase(iterator beg, iterator end); /*! @brief Delete all Exifdatum instances resulting in an empty container. Note that this also removes thumbnails. */ void clear(); //! Sort metadata by key void sortByKey(); //! Sort metadata by tag void sortByTag(); //! Begin of the metadata iterator begin() { return exifMetadata_.begin(); } //! End of the metadata iterator end() { return exifMetadata_.end(); } /*! @brief Find the first Exifdatum with the given \em key, return an iterator to it. */ iterator findKey(const ExifKey& key); //@} //! @name Accessors //@{ //! Begin of the metadata const_iterator begin() const { return exifMetadata_.begin(); } //! End of the metadata const_iterator end() const { return exifMetadata_.end(); } /*! @brief Find the first Exifdatum with the given \em key, return a const iterator to it. */ const_iterator findKey(const ExifKey& key) const; //! Return true if there is no Exif metadata bool empty() const { return count() == 0; } //! Get the number of metadata entries long count() const { return static_cast(exifMetadata_.size()); } //@} private: // DATA ExifMetadata exifMetadata_; }; // class ExifData /*! @brief Stateless parser class for Exif data. Images use this class to decode and encode binary Exif data. @note Encode is lossy and is not the inverse of decode. */ class EXIV2API ExifParser { public: /*! @brief Decode metadata from a buffer \em pData of length \em size with binary Exif data to the provided metadata container. The buffer must start with a TIFF header. Return byte order in which the data is encoded. @param exifData Exif metadata container. @param pData Pointer to the data buffer. Must point to data in binary Exif format; no checks are performed. @param size Length of the data buffer @return Byte order in which the data is encoded. */ static ByteOrder decode( ExifData& exifData, const byte* pData, uint32_t size ); /*! @brief Encode Exif metadata from the provided metadata to binary Exif format. The original binary Exif data in the memory block \em pData, \em size is parsed and updated in-place if possible ("non-intrusive" writing). If that is not possible (e.g., if new tags were added), the entire Exif structure is re-written to the \em blob ("intrusive" writing). The return value indicates which write method was used. If it is \c wmNonIntrusive, the original memory \em pData, \em size contains the result and \em blob is empty. If the return value is \c wmIntrusive, a new Exif structure was created and returned in \em blob. The memory block \em pData, \em size may be partly updated in this case and should not be used anymore. Encode is a lossy operation. It attempts to fit the Exif data into a binary block suitable as the payload of a JPEG APP1 Exif segment, which can be at most 65527 bytes large. Encode omits IFD0 tags that are "not recorded" in compressed images according to the Exif 2.2 specification. It also doesn't write tags in groups which do not occur in JPEG images. If the resulting binary block is larger than allowed, it further deletes specific large preview tags, unknown tags larger than 4kB and known tags larger than 40kB. The operation succeeds even if the end result is still larger than the allowed size. Application should therefore always check the size of the \em blob. @param blob Container for the binary Exif data if "intrusive" writing is necessary. Empty otherwise. @param pData Pointer to the binary Exif data buffer. Must point to data in Exif format; no checks are performed. Will be modified if "non-intrusive" writing is possible. @param size Length of the data buffer. @param byteOrder Byte order to use. @param exifData Exif metadata container. @return Write method used. */ static WriteMethod encode( Blob& blob, const byte* pData, uint32_t size, ByteOrder byteOrder, const ExifData& exifData ); /*! @brief Encode metadata from the provided metadata to Exif format. Encode Exif metadata from the \em ExifData container to binary Exif format in the \em blob, encoded in \em byteOrder. This simpler encode method uses "intrusive" writing, i.e., it builds the binary representation of the metadata from scratch. It does not attempt "non-intrusive", i.e., in-place updating. It's better to use the other encode() method, if the metadata is already available in binary format, in order to allow for "non-intrusive" updating of the existing binary representation. This is just an inline wrapper for ExifParser::encode(blob, 0, 0, byteOrder, exifData). @param blob Container for the binary Exif data. @param byteOrder Byte order to use. @param exifData Exif metadata container. */ static void encode( Blob& blob, ByteOrder byteOrder, const ExifData& exifData ) { encode(blob, 0, 0, byteOrder, exifData); } }; // class ExifParser } // namespace Exiv2 #endif // #ifndef EXIF_HPP_ exiv2-0.23/src/actions.cpp0000644000175000017500000021072111732641407015252 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /* File: actions.cpp Version: $Rev: 2681 $ Author(s): Andreas Huggel (ahu) History: 08-Dec-03, ahu: created 30-Apr-06, Roger Larsson: Print filename if processing multiple files */ // ***************************************************************************** #include "rcsid_int.hpp" EXIV2_RCSID("@(#) $Id: actions.cpp 2681 2012-03-22 15:19:35Z ahuggel $") // ***************************************************************************** // included header files #ifdef _MSC_VER # include "exv_msvc.h" #else # include "exv_conf.h" #endif #ifndef EXV_HAVE_TIMEGM # include "timegm.h" #endif #include "actions.hpp" #include "exiv2app.hpp" #include "image.hpp" #include "jpgimage.hpp" #include "xmpsidecar.hpp" #include "utils.hpp" #include "types.hpp" #include "exif.hpp" #include "easyaccess.hpp" #include "iptc.hpp" #include "xmp.hpp" #include "preview.hpp" #include "futils.hpp" #include "i18n.h" // NLS support. // + standard includes #include #include #include #include #include #include #include #include #include #include #include // for stat() #include // for stat() #ifdef EXV_HAVE_UNISTD_H # include // for stat() #endif #ifdef _MSC_VER # include #else # include #endif // ***************************************************************************** // local declarations namespace { //! Helper class to set the timestamp of a file to that of another file class Timestamp { public: //! C'tor Timestamp() : actime_(0), modtime_(0) {} //! Read the timestamp of a file int read(const std::string& path); //! Read the timestamp from a broken-down time in buffer \em tm. int read(struct tm* tm); //! Set the timestamp of a file int touch(const std::string& path); private: time_t actime_; time_t modtime_; }; /*! @brief Convert a string "YYYY:MM:DD HH:MI:SS" to a struct tm type, returns 0 if successful */ int str2Tm(const std::string& timeStr, struct tm* tm); //! Convert a localtime to a string "YYYY:MM:DD HH:MI:SS", "" on error std::string time2Str(time_t time); //! Convert a tm structure to a string "YYYY:MM:DD HH:MI:SS", "" on error std::string tm2Str(const struct tm* tm); /*! @brief Copy metadata from source to target according to Params::copyXyz @param source Source file path @param target Target file path. An *.exv file is created if target doesn't exist. @param targetType Image type for the target image in case it needs to be created. @param preserve Indicates if existing metadata in the target file should be kept. @return 0 if successful, else an error code */ int metacopy(const std::string& source, const std::string& target, int targetType, bool preserve); /*! @brief Rename a file according to a timestamp value. @param path The original file path. Contains the new path on exit. @param tm Pointer to a buffer with the broken-down time to rename the file to. @return 0 if successful, -1 if the file was skipped, 1 on error. */ int renameFile(std::string& path, const struct tm* tm); /*! @brief Make a file path from the current file path, destination directory (if any) and the filename extension passed in. @param path Path of the existing file @param ext New filename extension (incl. the dot '.' if required) @return 0 if successful, 1 if the new file exists and the user chose not to overwrite it. */ std::string newFilePath(const std::string& path, const std::string& ext); /*! @brief Check if file \em path exists and whether it should be overwritten. Ask user if necessary. Return 1 if the file exists and shouldn't be overwritten, else 0. */ int dontOverwrite(const std::string& path); } // ***************************************************************************** // class member definitions namespace Action { Task::~Task() { } Task::AutoPtr Task::clone() const { return AutoPtr(clone_()); } TaskFactory* TaskFactory::instance_ = 0; TaskFactory& TaskFactory::instance() { if (0 == instance_) { instance_ = new TaskFactory; } return *instance_; } // TaskFactory::instance void TaskFactory::cleanup() { if (instance_ != 0) { Registry::iterator e = registry_.end(); for (Registry::iterator i = registry_.begin(); i != e; ++i) { delete i->second; } delete instance_; instance_ = 0; } } //TaskFactory::cleanup void TaskFactory::registerTask(TaskType type, Task::AutoPtr task) { Registry::iterator i = registry_.find(type); if (i != registry_.end()) { delete i->second; } registry_[type] = task.release(); } // TaskFactory::registerTask TaskFactory::TaskFactory() { // Register a prototype of each known task registerTask(adjust, Task::AutoPtr(new Adjust)); registerTask(print, Task::AutoPtr(new Print)); registerTask(rename, Task::AutoPtr(new Rename)); registerTask(erase, Task::AutoPtr(new Erase)); registerTask(extract, Task::AutoPtr(new Extract)); registerTask(insert, Task::AutoPtr(new Insert)); registerTask(modify, Task::AutoPtr(new Modify)); registerTask(fixiso, Task::AutoPtr(new FixIso)); registerTask(fixcom, Task::AutoPtr(new FixCom)); } // TaskFactory c'tor Task::AutoPtr TaskFactory::create(TaskType type) { Registry::const_iterator i = registry_.find(type); if (i != registry_.end() && i->second != 0) { Task* t = i->second; return t->clone(); } return Task::AutoPtr(0); } // TaskFactory::create Print::~Print() { } int Print::run(const std::string& path) try { path_ = path; int rc = 0; switch (Params::instance().printMode_) { case Params::pmSummary: rc = printSummary(); break; case Params::pmList: rc = printList(); break; case Params::pmComment: rc = printComment(); break; case Params::pmPreview: rc = printPreviewList(); break; } return rc; } catch(const Exiv2::AnyError& e) { std::cerr << "Exiv2 exception in print action for file " << path << ":\n" << e << "\n"; return 1; } // Print::run int Print::printSummary() { if (!Exiv2::fileExists(path_, true)) { std::cerr << path_ << ": " << _("Failed to open the file\n"); return -1; } Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(path_); assert(image.get() != 0); image->readMetadata(); Exiv2::ExifData& exifData = image->exifData(); align_ = 16; // Filename printLabel(_("File name")); std::cout << path_ << std::endl; // Filesize struct stat buf; if (0 == stat(path_.c_str(), &buf)) { printLabel(_("File size")); std::cout << buf.st_size << " " << _("Bytes") << std::endl; } // MIME type printLabel(_("MIME type")); std::cout << image->mimeType() << std::endl; // Image size printLabel(_("Image size")); std::cout << image->pixelWidth() << " x " << image->pixelHeight() << std::endl; if (exifData.empty()) { std::cerr << path_ << ": " << _("No Exif data found in the file\n"); return -3; } // Camera make printTag(exifData, "Exif.Image.Make", _("Camera make")); // Camera model printTag(exifData, "Exif.Image.Model", _("Camera model")); // Image Timestamp printTag(exifData, "Exif.Photo.DateTimeOriginal", _("Image timestamp")); // Image number // Todo: Image number for cameras other than Canon printTag(exifData, "Exif.Canon.FileNumber", _("Image number")); // Exposure time // From ExposureTime, failing that, try ShutterSpeedValue bool done = false; printLabel(_("Exposure time")); if (!done) { done = 0 != printTag(exifData, "Exif.Photo.ExposureTime"); } if (!done) { done = 0 != printTag(exifData, "Exif.Photo.ShutterSpeedValue"); } std::cout << std::endl; // Aperture // Get if from FNumber and, failing that, try ApertureValue done = false; printLabel(_("Aperture")); if (!done) { done = 0 != printTag(exifData, "Exif.Photo.FNumber"); } if (!done) { done = 0 != printTag(exifData, "Exif.Photo.ApertureValue"); } std::cout << std::endl; // Exposure bias printTag(exifData, "Exif.Photo.ExposureBiasValue", _("Exposure bias")); // Flash printTag(exifData, "Exif.Photo.Flash", _("Flash")); // Flash bias printTag(exifData, Exiv2::flashBias, _("Flash bias")); // Actual focal length and 35 mm equivalent // Todo: Calculate 35 mm equivalent a la jhead Exiv2::ExifData::const_iterator md; printLabel(_("Focal length")); if (1 == printTag(exifData, "Exif.Photo.FocalLength")) { md = exifData.findKey( Exiv2::ExifKey("Exif.Photo.FocalLengthIn35mmFilm")); if (md != exifData.end()) { std::cout << " ("<< _("35 mm equivalent") << ": " << md->print(&exifData) << ")"; } } else { printTag(exifData, "Exif.Canon.FocalLength"); } std::cout << std::endl; // Subject distance printLabel(_("Subject distance")); done = false; if (!done) { done = 0 != printTag(exifData, "Exif.Photo.SubjectDistance"); } if (!done) { done = 0 != printTag(exifData, "Exif.CanonSi.SubjectDistance"); } std::cout << std::endl; // ISO speed printTag(exifData, Exiv2::isoSpeed, _("ISO speed")); // Exposure mode printTag(exifData, Exiv2::exposureMode, _("Exposure mode")); // Metering mode printTag(exifData, "Exif.Photo.MeteringMode", _("Metering mode")); // Macro mode printTag(exifData, Exiv2::macroMode, _("Macro mode")); // Image quality setting (compression) printTag(exifData, Exiv2::imageQuality, _("Image quality")); // Exif Resolution printLabel(_("Exif Resolution")); long xdim = 0; long ydim = 0; if (image->mimeType() == "image/tiff") { xdim = image->pixelWidth(); ydim = image->pixelHeight(); } else { md = exifData.findKey(Exiv2::ExifKey("Exif.Image.ImageWidth")); if (md == exifData.end()) { md = exifData.findKey(Exiv2::ExifKey("Exif.Photo.PixelXDimension")); } if (md != exifData.end() && md->count() > 0) { xdim = md->toLong(); } md = exifData.findKey(Exiv2::ExifKey("Exif.Image.ImageLength")); if (md == exifData.end()) { md = exifData.findKey(Exiv2::ExifKey("Exif.Photo.PixelYDimension")); } if (md != exifData.end() && md->count() > 0) { ydim = md->toLong(); } } if (xdim != 0 && ydim != 0) { std::cout << xdim << " x " << ydim; } std::cout << std::endl; // White balance printTag(exifData, Exiv2::whiteBalance, _("White balance")); // Thumbnail printLabel(_("Thumbnail")); Exiv2::ExifThumbC exifThumb(exifData); std::string thumbExt = exifThumb.extension(); if (thumbExt.empty()) { std::cout << _("None"); } else { Exiv2::DataBuf buf = exifThumb.copy(); if (buf.size_ == 0) { std::cout << _("None"); } else { std::cout << exifThumb.mimeType() << ", " << buf.size_ << " " << _("Bytes"); } } std::cout << std::endl; // Copyright printTag(exifData, "Exif.Image.Copyright", _("Copyright")); // Exif Comment printTag(exifData, "Exif.Photo.UserComment", _("Exif comment")); std::cout << std::endl; return 0; } // Print::printSummary void Print::printLabel(const std::string& label) const { std::cout << std::setfill(' ') << std::left; if (Params::instance().files_.size() > 1) { std::cout << std::setw(20) << path_ << " "; } std::cout << std::setw(align_) << label << ": "; } int Print::printTag(const Exiv2::ExifData& exifData, const std::string& key, const std::string& label) const { int rc = 0; if (!label.empty()) { printLabel(label); } Exiv2::ExifKey ek(key); Exiv2::ExifData::const_iterator md = exifData.findKey(ek); if (md != exifData.end()) { md->write(std::cout, &exifData); rc = 1; } if (!label.empty()) std::cout << std::endl; return rc; } // Print::printTag int Print::printTag(const Exiv2::ExifData& exifData, EasyAccessFct easyAccessFct, const std::string& label) const { int rc = 0; if (!label.empty()) { printLabel(label); } Exiv2::ExifData::const_iterator md = easyAccessFct(exifData); if (md != exifData.end()) { md->write(std::cout, &exifData); rc = 1; } if (!label.empty()) std::cout << std::endl; return rc; } // Print::printTag int Print::printList() { if (!Exiv2::fileExists(path_, true)) { std::cerr << path_ << ": " << _("Failed to open the file\n"); return -1; } Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(path_); assert(image.get() != 0); image->readMetadata(); // Set defaults for metadata types and data columns if (Params::instance().printTags_ == Exiv2::mdNone) { Params::instance().printTags_ = Exiv2::mdExif | Exiv2::mdIptc | Exiv2::mdXmp; } if (Params::instance().printItems_ == 0) { Params::instance().printItems_ = Params::prKey | Params::prType | Params::prCount | Params::prTrans; } return printMetadata(image.get()); } // Print::printList int Print::printMetadata(const Exiv2::Image* image) { int rc = 0; if (Params::instance().printTags_ & Exiv2::mdExif) { const Exiv2::ExifData& exifData = image->exifData(); for (Exiv2::ExifData::const_iterator md = exifData.begin(); md != exifData.end(); ++md) { printMetadatum(*md, image); } if (exifData.empty()) { if (Params::instance().verbose_) { std::cerr << path_ << ": " << _("No Exif data found in the file\n"); } rc = -3; } } if (Params::instance().printTags_ & Exiv2::mdIptc) { const Exiv2::IptcData& iptcData = image->iptcData(); for (Exiv2::IptcData::const_iterator md = iptcData.begin(); md != iptcData.end(); ++md) { printMetadatum(*md, image); } if (iptcData.empty()) { if (Params::instance().verbose_) { std::cerr << path_ << ": " << _("No IPTC data found in the file\n"); } rc = -3; } } if (Params::instance().printTags_ & Exiv2::mdXmp) { const Exiv2::XmpData& xmpData = image->xmpData(); for (Exiv2::XmpData::const_iterator md = xmpData.begin(); md != xmpData.end(); ++md) { printMetadatum(*md, image); } if (xmpData.empty()) { if (Params::instance().verbose_) { std::cerr << path_ << ": " << _("No XMP data found in the file\n"); } rc = -3; } } return rc; } // Print::printMetadata bool Print::grepTag(const std::string& key) { if (Params::instance().keys_.empty()) return true; for (Params::Keys::const_iterator k = Params::instance().keys_.begin(); k != Params::instance().keys_.end(); ++k) { if (*k == key) return true; } return false; } void Print::printMetadatum(const Exiv2::Metadatum& md, const Exiv2::Image* pImage) { if (!grepTag(md.key())) return; if ( Params::instance().unknown_ && md.tagName().substr(0, 2) == "0x") { return; } bool const manyFiles = Params::instance().files_.size() > 1; if (manyFiles) { std::cout << std::setfill(' ') << std::left << std::setw(20) << path_ << " "; } bool first = true; if (Params::instance().printItems_ & Params::prTag) { if (!first) std::cout << " "; first = false; std::cout << "0x" << std::setw(4) << std::setfill('0') << std::right << std::hex << md.tag(); } if (Params::instance().printItems_ & Params::prGroup) { if (!first) std::cout << " "; first = false; std::cout << std::setw(12) << std::setfill(' ') << std::left << md.groupName(); } if (Params::instance().printItems_ & Params::prKey) { if (!first) std::cout << " "; first = false; std::cout << std::setfill(' ') << std::left << std::setw(44) << md.key(); } if (Params::instance().printItems_ & Params::prName) { if (!first) std::cout << " "; first = false; std::cout << std::setw(27) << std::setfill(' ') << std::left << md.tagName(); } if (Params::instance().printItems_ & Params::prLabel) { if (!first) std::cout << " "; first = false; std::cout << std::setw(30) << std::setfill(' ') << std::left << md.tagLabel(); } if (Params::instance().printItems_ & Params::prType) { if (!first) std::cout << " "; first = false; std::cout << std::setw(9) << std::setfill(' ') << std::left; const char* tn = md.typeName(); if (tn) { std::cout << tn; } else { std::ostringstream os; os << "0x" << std::setw(4) << std::setfill('0') << std::hex << md.typeId(); std::cout << os.str(); } } if (Params::instance().printItems_ & Params::prCount) { if (!first) std::cout << " "; first = false; std::cout << std::dec << std::setw(3) << std::setfill(' ') << std::right << md.count(); } if (Params::instance().printItems_ & Params::prSize) { if (!first) std::cout << " "; first = false; std::cout << std::dec << std::setw(3) << std::setfill(' ') << std::right << md.size(); } if (Params::instance().printItems_ & Params::prValue) { if (!first) std::cout << " "; first = false; if ( Params::instance().binary_ && ( md.typeId() == Exiv2::undefined || md.typeId() == Exiv2::unsignedByte || md.typeId() == Exiv2::signedByte) && md.size() > 128) { std::cout << _("(Binary value suppressed)") << std::endl; return; } bool done = false; if (0 == strcmp(md.key().c_str(), "Exif.Photo.UserComment")) { const Exiv2::CommentValue* pcv = dynamic_cast(&md.value()); if (pcv) { Exiv2::CommentValue::CharsetId csId = pcv->charsetId(); if (csId != Exiv2::CommentValue::undefined) { std::cout << "charset=\"" << Exiv2::CommentValue::CharsetInfo::name(csId) << "\" "; } std::cout << pcv->comment(Params::instance().charset_.c_str()); done = true; } } if (!done) std::cout << std::dec << md.value(); } if (Params::instance().printItems_ & Params::prTrans) { if (!first) std::cout << " "; first = false; if ( Params::instance().binary_ && ( md.typeId() == Exiv2::undefined || md.typeId() == Exiv2::unsignedByte || md.typeId() == Exiv2::signedByte) && md.size() > 128) { std::cout << _("(Binary value suppressed)") << std::endl; return; } bool done = false; if (0 == strcmp(md.key().c_str(), "Exif.Photo.UserComment")) { const Exiv2::CommentValue* pcv = dynamic_cast(&md.value()); if (pcv) { std::cout << pcv->comment(Params::instance().charset_.c_str()); done = true; } } if (!done) std::cout << std::dec << md.print(&pImage->exifData()); } if (Params::instance().printItems_ & Params::prHex) { if (!first) std::cout << std::endl; first = false; if ( Params::instance().binary_ && ( md.typeId() == Exiv2::undefined || md.typeId() == Exiv2::unsignedByte || md.typeId() == Exiv2::signedByte) && md.size() > 128) { std::cout << _("(Binary value suppressed)") << std::endl; return; } Exiv2::DataBuf buf(md.size()); md.copy(buf.pData_, pImage->byteOrder()); Exiv2::hexdump(std::cout, buf.pData_, buf.size_); } std::cout << std::endl; } // Print::printMetadatum int Print::printComment() { if (!Exiv2::fileExists(path_, true)) { std::cerr << path_ << ": " << _("Failed to open the file\n"); return -1; } Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(path_); assert(image.get() != 0); image->readMetadata(); if (Params::instance().verbose_) { std::cout << _("JPEG comment") << ": "; } std::cout << image->comment() << std::endl; return 0; } // Print::printComment int Print::printPreviewList() { if (!Exiv2::fileExists(path_, true)) { std::cerr << path_ << ": " << _("Failed to open the file\n"); return -1; } Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(path_); assert(image.get() != 0); image->readMetadata(); bool const manyFiles = Params::instance().files_.size() > 1; int cnt = 0; Exiv2::PreviewManager pm(*image); Exiv2::PreviewPropertiesList list = pm.getPreviewProperties(); for (Exiv2::PreviewPropertiesList::const_iterator pos = list.begin(); pos != list.end(); ++pos) { if (manyFiles) { std::cout << std::setfill(' ') << std::left << std::setw(20) << path_ << " "; } std::cout << _("Preview") << " " << ++cnt << ": " << pos->mimeType_ << ", "; if (pos->width_ != 0 && pos->height_ != 0) { std::cout << pos->width_ << "x" << pos->height_ << " " << _("pixels") << ", "; } std::cout << pos->size_ << " " << _("bytes") << "\n"; } return 0; } // Print::printPreviewList Print::AutoPtr Print::clone() const { return AutoPtr(clone_()); } Print* Print::clone_() const { return new Print(*this); } Rename::~Rename() { } int Rename::run(const std::string& path) { try { if (!Exiv2::fileExists(path, true)) { std::cerr << path << ": " << _("Failed to open the file\n"); return -1; } Timestamp ts; if (Params::instance().preserve_) { ts.read(path); } Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(path); assert(image.get() != 0); image->readMetadata(); Exiv2::ExifData& exifData = image->exifData(); if (exifData.empty()) { std::cerr << path << ": " << _("No Exif data found in the file\n"); return -3; } Exiv2::ExifKey key("Exif.Photo.DateTimeOriginal"); Exiv2::ExifData::iterator md = exifData.findKey(key); if (md == exifData.end()) { key = Exiv2::ExifKey("Exif.Image.DateTime"); md = exifData.findKey(key); } if (md == exifData.end()) { std::cerr << _("Neither tag") << " `Exif.Photo.DateTimeOriginal' " << _("nor") << " `Exif.Image.DateTime' " << _("found in the file") << " " << path << "\n"; return 1; } std::string v = md->toString(); if (v.length() == 0 || v[0] == ' ') { std::cerr << _("Image file creation timestamp not set in the file") << " " << path << "\n"; return 1; } struct tm tm; if (str2Tm(v, &tm) != 0) { std::cerr << _("Failed to parse timestamp") << " `" << v << "' " << _("in the file") << " " << path << "\n"; return 1; } if ( Params::instance().timestamp_ || Params::instance().timestampOnly_) { ts.read(&tm); } int rc = 0; std::string newPath = path; if (Params::instance().timestampOnly_) { if (Params::instance().verbose_) { std::cout << _("Updating timestamp to") << " " << v << std::endl; } } else { rc = renameFile(newPath, &tm); if (rc == -1) return 0; // skip } if ( 0 == rc && ( Params::instance().preserve_ || Params::instance().timestamp_ || Params::instance().timestampOnly_)) { ts.touch(newPath); } return rc; } catch(const Exiv2::AnyError& e) { std::cerr << "Exiv2 exception in rename action for file " << path << ":\n" << e << "\n"; return 1; }} // Rename::run Rename::AutoPtr Rename::clone() const { return AutoPtr(clone_()); } Rename* Rename::clone_() const { return new Rename(*this); } Erase::~Erase() { } int Erase::run(const std::string& path) try { path_ = path; if (!Exiv2::fileExists(path_, true)) { std::cerr << path_ << ": " << _("Failed to open the file\n"); return -1; } Timestamp ts; if (Params::instance().preserve_) { ts.read(path); } Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(path_); assert(image.get() != 0); image->readMetadata(); // Thumbnail must be before Exif int rc = 0; if (Params::instance().target_ & Params::ctThumb) { rc = eraseThumbnail(image.get()); } if (0 == rc && Params::instance().target_ & Params::ctExif) { rc = eraseExifData(image.get()); } if (0 == rc && Params::instance().target_ & Params::ctIptc) { rc = eraseIptcData(image.get()); } if (0 == rc && Params::instance().target_ & Params::ctComment) { rc = eraseComment(image.get()); } if (0 == rc && Params::instance().target_ & Params::ctXmp) { rc = eraseXmpData(image.get()); } if (0 == rc) { image->writeMetadata(); } if (Params::instance().preserve_) { ts.touch(path); } return rc; } catch(const Exiv2::AnyError& e) { std::cerr << "Exiv2 exception in erase action for file " << path << ":\n" << e << "\n"; return 1; } // Erase::run int Erase::eraseThumbnail(Exiv2::Image* image) const { Exiv2::ExifThumb exifThumb(image->exifData()); std::string thumbExt = exifThumb.extension(); if (thumbExt.empty()) { return 0; } exifThumb.erase(); if (Params::instance().verbose_) { std::cout << _("Erasing thumbnail data") << std::endl; } return 0; } int Erase::eraseExifData(Exiv2::Image* image) const { if (Params::instance().verbose_ && image->exifData().count() > 0) { std::cout << _("Erasing Exif data from the file") << std::endl; } image->clearExifData(); return 0; } int Erase::eraseIptcData(Exiv2::Image* image) const { if (Params::instance().verbose_ && image->iptcData().count() > 0) { std::cout << _("Erasing IPTC data from the file") << std::endl; } image->clearIptcData(); return 0; } int Erase::eraseComment(Exiv2::Image* image) const { if (Params::instance().verbose_ && image->comment().size() > 0) { std::cout << _("Erasing JPEG comment from the file") << std::endl; } image->clearComment(); return 0; } int Erase::eraseXmpData(Exiv2::Image* image) const { if (Params::instance().verbose_ && image->xmpData().count() > 0) { std::cout << _("Erasing XMP data from the file") << std::endl; } image->clearXmpData(); // Quick fix for bug #612 image->clearXmpPacket(); return 0; } Erase::AutoPtr Erase::clone() const { return AutoPtr(clone_()); } Erase* Erase::clone_() const { return new Erase(*this); } Extract::~Extract() { } int Extract::run(const std::string& path) try { path_ = path; int rc = 0; if (Params::instance().target_ & Params::ctThumb) { rc = writeThumbnail(); } if (Params::instance().target_ & Params::ctXmpSidecar) { std::string xmpPath = newFilePath(path_, ".xmp"); if (dontOverwrite(xmpPath)) return 0; rc = metacopy(path_, xmpPath, Exiv2::ImageType::xmp, false); } if (Params::instance().target_ & Params::ctPreview) { rc = writePreviews(); } if ( !(Params::instance().target_ & Params::ctXmpSidecar) && !(Params::instance().target_ & Params::ctThumb) && !(Params::instance().target_ & Params::ctPreview)) { std::string exvPath = newFilePath(path_, ".exv"); if (dontOverwrite(exvPath)) return 0; rc = metacopy(path_, exvPath, Exiv2::ImageType::exv, false); } return rc; } catch(const Exiv2::AnyError& e) { std::cerr << "Exiv2 exception in extract action for file " << path << ":\n" << e << "\n"; return 1; } // Extract::run int Extract::writeThumbnail() const { if (!Exiv2::fileExists(path_, true)) { std::cerr << path_ << ": " << _("Failed to open the file\n"); return -1; } Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(path_); assert(image.get() != 0); image->readMetadata(); Exiv2::ExifData& exifData = image->exifData(); if (exifData.empty()) { std::cerr << path_ << ": " << _("No Exif data found in the file\n"); return -3; } int rc = 0; Exiv2::ExifThumb exifThumb(exifData); std::string thumbExt = exifThumb.extension(); if (thumbExt.empty()) { std::cerr << path_ << ": " << _("Image does not contain an Exif thumbnail\n"); } else { std::string thumb = newFilePath(path_, "-thumb"); std::string thumbPath = thumb + thumbExt; if (dontOverwrite(thumbPath)) return 0; if (Params::instance().verbose_) { Exiv2::DataBuf buf = exifThumb.copy(); if (buf.size_ != 0) { std::cout << _("Writing thumbnail") << " (" << exifThumb.mimeType() << ", " << buf.size_ << " " << _("Bytes") << ") " << _("to file") << " " << thumbPath << std::endl; } } rc = exifThumb.writeFile(thumb); if (rc == 0) { std::cerr << path_ << ": " << _("Exif data doesn't contain a thumbnail\n"); } } return rc; } // Extract::writeThumbnail int Extract::writePreviews() const { if (!Exiv2::fileExists(path_, true)) { std::cerr << path_ << ": " << _("Failed to open the file\n"); return -1; } Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(path_); assert(image.get() != 0); image->readMetadata(); Exiv2::PreviewManager pvMgr(*image); Exiv2::PreviewPropertiesList pvList = pvMgr.getPreviewProperties(); const Params::PreviewNumbers& numbers = Params::instance().previewNumbers_; for (Params::PreviewNumbers::const_iterator n = numbers.begin(); n != numbers.end(); ++n) { if (*n == 0) { // Write all previews for (int num = 0; num < static_cast(pvList.size()); ++num) { writePreviewFile(pvMgr.getPreviewImage(pvList[num]), num + 1); } break; } if (*n > static_cast(pvList.size())) { std::cerr << path_ << ": " << _("Image does not have preview") << " " << *n << "\n"; continue; } writePreviewFile(pvMgr.getPreviewImage(pvList[*n - 1]), *n); } return 0; } // Extract::writePreviews void Extract::writePreviewFile(const Exiv2::PreviewImage& pvImg, int num) const { std::string pvFile = newFilePath(path_, "-preview") + Exiv2::toString(num); std::string pvPath = pvFile + pvImg.extension(); if (dontOverwrite(pvPath)) return; if (Params::instance().verbose_) { std::cout << _("Writing preview") << " " << num << " (" << pvImg.mimeType() << ", "; if (pvImg.width() != 0 && pvImg.height() != 0) { std::cout << pvImg.width() << "x" << pvImg.height() << " " << _("pixels") << ", "; } std::cout << pvImg.size() << " " << _("bytes") << ") " << _("to file") << " " << pvPath << std::endl; } long rc = pvImg.writeFile(pvFile); if (rc == 0) { std::cerr << path_ << ": " << _("Image does not have preview") << " " << num << "\n"; } } // Extract::writePreviewFile Extract::AutoPtr Extract::clone() const { return AutoPtr(clone_()); } Extract* Extract::clone_() const { return new Extract(*this); } Insert::~Insert() { } int Insert::run(const std::string& path) try { if (!Exiv2::fileExists(path, true)) { std::cerr << path << ": " << _("Failed to open the file\n"); return -1; } int rc = 0; Timestamp ts; if (Params::instance().preserve_) { ts.read(path); } if (Params::instance().target_ & Params::ctThumb) { rc = insertThumbnail(path); } if ( rc == 0 && ( Params::instance().target_ & Params::ctExif || Params::instance().target_ & Params::ctIptc || Params::instance().target_ & Params::ctComment || Params::instance().target_ & Params::ctXmp)) { std::string suffix = Params::instance().suffix_; if (suffix.empty()) suffix = ".exv"; if (Params::instance().target_ & Params::ctXmpSidecar) suffix = ".xmp"; std::string exvPath = newFilePath(path, suffix); rc = metacopy(exvPath, path, Exiv2::ImageType::none, true); } if (0 == rc && Params::instance().target_ & Params::ctXmpSidecar) { rc = insertXmpPacket(path); } if (Params::instance().preserve_) { ts.touch(path); } return rc; } catch(const Exiv2::AnyError& e) { std::cerr << "Exiv2 exception in insert action for file " << path << ":\n" << e << "\n"; return 1; } // Insert::run int Insert::insertXmpPacket(const std::string& path) const { std::string xmpPath = newFilePath(path, ".xmp"); if (!Exiv2::fileExists(xmpPath, true)) { std::cerr << xmpPath << ": " << _("Failed to open the file\n"); return -1; } if (!Exiv2::fileExists(path, true)) { std::cerr << path << ": " << _("Failed to open the file\n"); return -1; } Exiv2::DataBuf buf = Exiv2::readFile(xmpPath); std::string xmpPacket; xmpPacket.assign(reinterpret_cast(buf.pData_), buf.size_); Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(path); assert(image.get() != 0); image->readMetadata(); image->setXmpPacket(xmpPacket); image->writeMetadata(); return 0; } int Insert::insertThumbnail(const std::string& path) const { std::string thumbPath = newFilePath(path, "-thumb.jpg"); if (!Exiv2::fileExists(thumbPath, true)) { std::cerr << thumbPath << ": " << _("Failed to open the file\n"); return -1; } if (!Exiv2::fileExists(path, true)) { std::cerr << path << ": " << _("Failed to open the file\n"); return -1; } Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(path); assert(image.get() != 0); image->readMetadata(); Exiv2::ExifThumb exifThumb(image->exifData()); exifThumb.setJpegThumbnail(thumbPath); image->writeMetadata(); return 0; } // Insert::insertThumbnail Insert::AutoPtr Insert::clone() const { return AutoPtr(clone_()); } Insert* Insert::clone_() const { return new Insert(*this); } Modify::~Modify() { } int Modify::run(const std::string& path) { try { if (!Exiv2::fileExists(path, true)) { std::cerr << path << ": " << _("Failed to open the file\n"); return -1; } Timestamp ts; if (Params::instance().preserve_) { ts.read(path); } Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(path); assert(image.get() != 0); image->readMetadata(); int rc = applyCommands(image.get()); // Save both exif and iptc metadata image->writeMetadata(); if (Params::instance().preserve_) { ts.touch(path); } return rc; } catch(const Exiv2::AnyError& e) { std::cerr << "Exiv2 exception in modify action for file " << path << ":\n" << e << "\n"; return 1; } } // Modify::run int Modify::applyCommands(Exiv2::Image* pImage) { if (!Params::instance().jpegComment_.empty()) { if (Params::instance().verbose_) { std::cout << _("Setting JPEG comment") << " '" << Params::instance().jpegComment_ << "'" << std::endl; } pImage->setComment(Params::instance().jpegComment_); } // loop through command table and apply each command ModifyCmds& modifyCmds = Params::instance().modifyCmds_; ModifyCmds::const_iterator i = modifyCmds.begin(); ModifyCmds::const_iterator end = modifyCmds.end(); int rc = 0; int ret = 0; for (; i != end; ++i) { switch (i->cmdId_) { case add: ret = addMetadatum(pImage, *i); if (rc == 0) rc = ret; break; case set: ret = setMetadatum(pImage, *i); if (rc == 0) rc = ret; break; case del: delMetadatum(pImage, *i); break; case reg: regNamespace(*i); break; case invalidCmdId: assert(invalidCmdId == i->cmdId_); break; } } return rc; } // Modify::applyCommands int Modify::addMetadatum(Exiv2::Image* pImage, const ModifyCmd& modifyCmd) { if (Params::instance().verbose_) { std::cout << _("Add") << " " << modifyCmd.key_ << " \"" << modifyCmd.value_ << "\" (" << Exiv2::TypeInfo::typeName(modifyCmd.typeId_) << ")" << std::endl; } Exiv2::ExifData& exifData = pImage->exifData(); Exiv2::IptcData& iptcData = pImage->iptcData(); Exiv2::XmpData& xmpData = pImage->xmpData(); Exiv2::Value::AutoPtr value = Exiv2::Value::create(modifyCmd.typeId_); int rc = value->read(modifyCmd.value_); if (0 == rc) { if (modifyCmd.metadataId_ == exif) { exifData.add(Exiv2::ExifKey(modifyCmd.key_), value.get()); } if (modifyCmd.metadataId_ == iptc) { iptcData.add(Exiv2::IptcKey(modifyCmd.key_), value.get()); } if (modifyCmd.metadataId_ == xmp) { xmpData.add(Exiv2::XmpKey(modifyCmd.key_), value.get()); } } else { std::cerr << _("Warning") << ": " << modifyCmd.key_ << ": " << _("Failed to read") << " " << Exiv2::TypeInfo::typeName(value->typeId()) << " " << _("value") << " \"" << modifyCmd.value_ << "\"\n"; } return rc; } // This function looks rather complex because we try to avoid adding an // empty metadatum if reading the value fails int Modify::setMetadatum(Exiv2::Image* pImage, const ModifyCmd& modifyCmd) { if (Params::instance().verbose_) { std::cout << _("Set") << " " << modifyCmd.key_ << " \"" << modifyCmd.value_ << "\" (" << Exiv2::TypeInfo::typeName(modifyCmd.typeId_) << ")" << std::endl; } Exiv2::ExifData& exifData = pImage->exifData(); Exiv2::IptcData& iptcData = pImage->iptcData(); Exiv2::XmpData& xmpData = pImage->xmpData(); Exiv2::Metadatum* metadatum = 0; if (modifyCmd.metadataId_ == exif) { Exiv2::ExifData::iterator pos = exifData.findKey(Exiv2::ExifKey(modifyCmd.key_)); if (pos != exifData.end()) { metadatum = &(*pos); } } if (modifyCmd.metadataId_ == iptc) { Exiv2::IptcData::iterator pos = iptcData.findKey(Exiv2::IptcKey(modifyCmd.key_)); if (pos != iptcData.end()) { metadatum = &(*pos); } } if (modifyCmd.metadataId_ == xmp) { Exiv2::XmpData::iterator pos = xmpData.findKey(Exiv2::XmpKey(modifyCmd.key_)); if (pos != xmpData.end()) { metadatum = &(*pos); } } // If a type was explicitly requested, use it; else // use the current type of the metadatum, if any; // or the default type Exiv2::Value::AutoPtr value; if (metadatum) { value = metadatum->getValue(); } if ( value.get() == 0 || ( modifyCmd.explicitType_ && modifyCmd.typeId_ != value->typeId())) { value = Exiv2::Value::create(modifyCmd.typeId_); } int rc = value->read(modifyCmd.value_); if (0 == rc) { if (metadatum) { metadatum->setValue(value.get()); } else { if (modifyCmd.metadataId_ == exif) { exifData.add(Exiv2::ExifKey(modifyCmd.key_), value.get()); } if (modifyCmd.metadataId_ == iptc) { iptcData.add(Exiv2::IptcKey(modifyCmd.key_), value.get()); } if (modifyCmd.metadataId_ == xmp) { xmpData.add(Exiv2::XmpKey(modifyCmd.key_), value.get()); } } } else { std::cerr << _("Warning") << ": " << modifyCmd.key_ << ": " << _("Failed to read") << " " << Exiv2::TypeInfo::typeName(value->typeId()) << " " << _("value") << " \"" << modifyCmd.value_ << "\"\n"; } return rc; } void Modify::delMetadatum(Exiv2::Image* pImage, const ModifyCmd& modifyCmd) { if (Params::instance().verbose_) { std::cout << _("Del") << " " << modifyCmd.key_ << std::endl; } Exiv2::ExifData& exifData = pImage->exifData(); Exiv2::IptcData& iptcData = pImage->iptcData(); Exiv2::XmpData& xmpData = pImage->xmpData(); if (modifyCmd.metadataId_ == exif) { Exiv2::ExifData::iterator pos; Exiv2::ExifKey exifKey = Exiv2::ExifKey(modifyCmd.key_); while((pos = exifData.findKey(exifKey)) != exifData.end()) { exifData.erase(pos); } } if (modifyCmd.metadataId_ == iptc) { Exiv2::IptcData::iterator pos; Exiv2::IptcKey iptcKey = Exiv2::IptcKey(modifyCmd.key_); while((pos = iptcData.findKey(iptcKey)) != iptcData.end()) { iptcData.erase(pos); } } if (modifyCmd.metadataId_ == xmp) { Exiv2::XmpData::iterator pos; Exiv2::XmpKey xmpKey = Exiv2::XmpKey(modifyCmd.key_); while((pos = xmpData.findKey(xmpKey)) != xmpData.end()) { xmpData.erase(pos); } } } void Modify::regNamespace(const ModifyCmd& modifyCmd) { if (Params::instance().verbose_) { std::cout << _("Reg ") << modifyCmd.key_ << "=\"" << modifyCmd.value_ << "\"" << std::endl; } Exiv2::XmpProperties::registerNs(modifyCmd.value_, modifyCmd.key_); } Modify::AutoPtr Modify::clone() const { return AutoPtr(clone_()); } Modify* Modify::clone_() const { return new Modify(*this); } Adjust::~Adjust() { } int Adjust::run(const std::string& path) try { adjustment_ = Params::instance().adjustment_; yearAdjustment_ = Params::instance().yodAdjust_[Params::yodYear].adjustment_; monthAdjustment_ = Params::instance().yodAdjust_[Params::yodMonth].adjustment_; dayAdjustment_ = Params::instance().yodAdjust_[Params::yodDay].adjustment_; if (!Exiv2::fileExists(path, true)) { std::cerr << path << ": " << _("Failed to open the file\n"); return -1; } Timestamp ts; if (Params::instance().preserve_) { ts.read(path); } Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(path); assert(image.get() != 0); image->readMetadata(); Exiv2::ExifData& exifData = image->exifData(); if (exifData.empty()) { std::cerr << path << ": " << _("No Exif data found in the file\n"); return -3; } int rc = adjustDateTime(exifData, "Exif.Image.DateTime", path); rc += adjustDateTime(exifData, "Exif.Photo.DateTimeOriginal", path); rc += adjustDateTime(exifData, "Exif.Photo.DateTimeDigitized", path); if (rc) return 1; image->writeMetadata(); if (Params::instance().preserve_) { ts.touch(path); } return rc; } catch(const Exiv2::AnyError& e) { std::cerr << "Exiv2 exception in adjust action for file " << path << ":\n" << e << "\n"; return 1; } // Adjust::run Adjust::AutoPtr Adjust::clone() const { return AutoPtr(clone_()); } Adjust* Adjust::clone_() const { return new Adjust(*this); } int Adjust::adjustDateTime(Exiv2::ExifData& exifData, const std::string& key, const std::string& path) const { Exiv2::ExifKey ek(key); Exiv2::ExifData::iterator md = exifData.findKey(ek); if (md == exifData.end()) { // Key not found. That's ok, we do nothing. return 0; } std::string timeStr = md->toString(); if (timeStr == "" || timeStr[0] == ' ') { std::cerr << path << ": " << _("Timestamp of metadatum with key") << " `" << ek << "' " << _("not set\n"); return 1; } if (Params::instance().verbose_) { bool comma = false; std::cout << _("Adjusting") << " `" << ek << "' " << _("by"); if (yearAdjustment_ != 0) { std::cout << (yearAdjustment_ < 0 ? " " : " +") << yearAdjustment_ << " "; if (yearAdjustment_ < -1 || yearAdjustment_ > 1) { std::cout << _("years"); } else { std::cout << _("year"); } comma = true; } if (monthAdjustment_ != 0) { if (comma) std::cout << ","; std::cout << (monthAdjustment_ < 0 ? " " : " +") << monthAdjustment_ << " "; if (monthAdjustment_ < -1 || monthAdjustment_ > 1) { std::cout << _("months"); } else { std::cout << _("month"); } comma = true; } if (dayAdjustment_ != 0) { if (comma) std::cout << ","; std::cout << (dayAdjustment_ < 0 ? " " : " +") << dayAdjustment_ << " "; if (dayAdjustment_ < -1 || dayAdjustment_ > 1) { std::cout << _("days"); } else { std::cout << _("day"); } comma = true; } if (adjustment_ != 0) { if (comma) std::cout << ","; std::cout << " " << adjustment_ << _("s"); } } struct tm tm; if (str2Tm(timeStr, &tm) != 0) { if (Params::instance().verbose_) std::cout << std::endl; std::cerr << path << ": " << _("Failed to parse timestamp") << " `" << timeStr << "'\n"; return 1; } const long monOverflow = (tm.tm_mon + monthAdjustment_) / 12; tm.tm_mon = (tm.tm_mon + monthAdjustment_) % 12; tm.tm_year += yearAdjustment_ + monOverflow; // Let's not create files with non-4-digit years, we can't read them. if (tm.tm_year > 9999 - 1900 || tm.tm_year < 1000 - 1900) { if (Params::instance().verbose_) std::cout << std::endl; std::cerr << path << ": " << _("Can't adjust timestamp by") << " " << yearAdjustment_ + monOverflow << " " << _("years") << "\n"; return 1; } time_t time = mktime(&tm); time += adjustment_ + dayAdjustment_ * 86400; timeStr = time2Str(time); if (Params::instance().verbose_) { std::cout << " " << _("to") << " " << timeStr << std::endl; } md->setValue(timeStr); return 0; } // Adjust::adjustDateTime FixIso::~FixIso() { } int FixIso::run(const std::string& path) { try { if (!Exiv2::fileExists(path, true)) { std::cerr << path << ": " <<_("Failed to open the file\n"); return -1; } Timestamp ts; if (Params::instance().preserve_) { ts.read(path); } Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(path); assert(image.get() != 0); image->readMetadata(); Exiv2::ExifData& exifData = image->exifData(); if (exifData.empty()) { std::cerr << path << ": " << _("No Exif data found in the file\n"); return -3; } Exiv2::ExifData::const_iterator md = Exiv2::isoSpeed(exifData); if (md != exifData.end()) { if (strcmp(md->key().c_str(), "Exif.Photo.ISOSpeedRatings") == 0) { if (Params::instance().verbose_) { std::cout << _("Standard Exif ISO tag exists; not modified\n"); } return 0; } // Copy the proprietary tag to the standard place std::ostringstream os; md->write(os, &exifData); if (Params::instance().verbose_) { std::cout << _("Setting Exif ISO value to") << " " << os.str() << "\n"; } exifData["Exif.Photo.ISOSpeedRatings"] = os.str(); } image->writeMetadata(); if (Params::instance().preserve_) { ts.touch(path); } return 0; } catch(const Exiv2::AnyError& e) { std::cerr << "Exiv2 exception in fixiso action for file " << path << ":\n" << e << "\n"; return 1; } } // FixIso::run FixIso::AutoPtr FixIso::clone() const { return AutoPtr(clone_()); } FixIso* FixIso::clone_() const { return new FixIso(*this); } FixCom::~FixCom() { } int FixCom::run(const std::string& path) { try { if (!Exiv2::fileExists(path, true)) { std::cerr << path << ": " <<_("Failed to open the file\n"); return -1; } Timestamp ts; if (Params::instance().preserve_) { ts.read(path); } Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(path); assert(image.get() != 0); image->readMetadata(); Exiv2::ExifData& exifData = image->exifData(); if (exifData.empty()) { std::cerr << path << ": " << _("No Exif data found in the file\n"); return -3; } Exiv2::ExifData::iterator pos = exifData.findKey(Exiv2::ExifKey("Exif.Photo.UserComment")); if (pos == exifData.end()) { if (Params::instance().verbose_) { std::cout << _("No Exif user comment found") << "\n"; } return 0; } Exiv2::Value::AutoPtr v = pos->getValue(); const Exiv2::CommentValue* pcv = dynamic_cast(v.get()); if (!pcv) { if (Params::instance().verbose_) { std::cout << _("Found Exif user comment with unexpected value type") << "\n"; } return 0; } Exiv2::CommentValue::CharsetId csId = pcv->charsetId(); if (csId != Exiv2::CommentValue::unicode) { if (Params::instance().verbose_) { std::cout << _("No Exif UNICODE user comment found") << "\n"; } return 0; } std::string comment = pcv->comment(Params::instance().charset_.c_str()); if (Params::instance().verbose_) { std::cout << _("Setting Exif UNICODE user comment to") << " \"" << comment << "\"\n"; } comment = std::string("charset=\"") + Exiv2::CommentValue::CharsetInfo::name(csId) + "\" " + comment; // Remove BOM and convert value from source charset to UCS-2, but keep byte order pos->setValue(comment); image->writeMetadata(); if (Params::instance().preserve_) { ts.touch(path); } return 0; } catch(const Exiv2::AnyError& e) { std::cerr << "Exiv2 exception in fixcom action for file " << path << ":\n" << e << "\n"; return 1; } } // FixCom::run FixCom::AutoPtr FixCom::clone() const { return AutoPtr(clone_()); } FixCom* FixCom::clone_() const { return new FixCom(*this); } } // namespace Action // ***************************************************************************** // local definitions namespace { //! @cond IGNORE int Timestamp::read(const std::string& path) { struct stat buf; int rc = stat(path.c_str(), &buf); if (0 == rc) { actime_ = buf.st_atime; modtime_ = buf.st_mtime; } return rc; } int Timestamp::read(struct tm* tm) { int rc = 1; time_t t = mktime(tm); // interpret tm according to current timezone settings if (t != (time_t)-1) { rc = 0; actime_ = t; modtime_ = t; } return rc; } int Timestamp::touch(const std::string& path) { if (0 == actime_) return 1; struct utimbuf buf; buf.actime = actime_; buf.modtime = modtime_; return utime(path.c_str(), &buf); } //! @endcond int str2Tm(const std::string& timeStr, struct tm* tm) { if (timeStr.length() == 0 || timeStr[0] == ' ') return 1; if (timeStr.length() < 19) return 2; if ( timeStr[4] != ':' || timeStr[7] != ':' || timeStr[10] != ' ' || timeStr[13] != ':' || timeStr[16] != ':') return 3; if (0 == tm) return 4; std::memset(tm, 0x0, sizeof(struct tm)); tm->tm_isdst = -1; long tmp; if (!Util::strtol(timeStr.substr(0,4).c_str(), tmp)) return 5; tm->tm_year = tmp - 1900; if (!Util::strtol(timeStr.substr(5,2).c_str(), tmp)) return 6; tm->tm_mon = tmp - 1; if (!Util::strtol(timeStr.substr(8,2).c_str(), tmp)) return 7; tm->tm_mday = tmp; if (!Util::strtol(timeStr.substr(11,2).c_str(), tmp)) return 8; tm->tm_hour = tmp; if (!Util::strtol(timeStr.substr(14,2).c_str(), tmp)) return 9; tm->tm_min = tmp; if (!Util::strtol(timeStr.substr(17,2).c_str(), tmp)) return 10; tm->tm_sec = tmp; // Conversions to set remaining fields of the tm structure if (mktime(tm) == (time_t)-1) return 11; return 0; } // str2Tm std::string time2Str(time_t time) { struct tm* tm = localtime(&time); return tm2Str(tm); } // time2Str std::string tm2Str(const struct tm* tm) { if (0 == tm) return ""; std::ostringstream os; os << std::setfill('0') << tm->tm_year + 1900 << ":" << std::setw(2) << tm->tm_mon + 1 << ":" << std::setw(2) << tm->tm_mday << " " << std::setw(2) << tm->tm_hour << ":" << std::setw(2) << tm->tm_min << ":" << std::setw(2) << tm->tm_sec; return os.str(); } // tm2Str int metacopy(const std::string& source, const std::string& target, int targetType, bool preserve) { if (!Exiv2::fileExists(source, true)) { std::cerr << source << ": " << _("Failed to open the file\n"); return -1; } Exiv2::Image::AutoPtr sourceImage = Exiv2::ImageFactory::open(source); assert(sourceImage.get() != 0); sourceImage->readMetadata(); // Apply any modification commands to the source image on-the-fly Action::Modify::applyCommands(sourceImage.get()); Exiv2::Image::AutoPtr targetImage; if (Exiv2::fileExists(target)) { targetImage = Exiv2::ImageFactory::open(target); assert(targetImage.get() != 0); if (preserve) targetImage->readMetadata(); } else { targetImage = Exiv2::ImageFactory::create(targetType, target); assert(targetImage.get() != 0); } if ( Params::instance().target_ & Params::ctExif && !sourceImage->exifData().empty()) { if (Params::instance().verbose_) { std::cout << _("Writing Exif data from") << " " << source << " " << _("to") << " " << target << std::endl; } targetImage->setExifData(sourceImage->exifData()); } if ( Params::instance().target_ & Params::ctIptc && !sourceImage->iptcData().empty()) { if (Params::instance().verbose_) { std::cout << _("Writing IPTC data from") << " " << source << " " << _("to") << " " << target << std::endl; } targetImage->setIptcData(sourceImage->iptcData()); } if ( Params::instance().target_ & Params::ctXmp && !sourceImage->xmpData().empty()) { if (Params::instance().verbose_) { std::cout << _("Writing XMP data from") << " " << source << " " << _("to") << " " << target << std::endl; } // Todo: Should use XMP packet if there are no XMP modification commands targetImage->setXmpData(sourceImage->xmpData()); } if ( Params::instance().target_ & Params::ctComment && !sourceImage->comment().empty()) { if (Params::instance().verbose_) { std::cout << _("Writing JPEG comment from") << " " << source << " " << _("to") << " " << target << std::endl; } targetImage->setComment(sourceImage->comment()); } try { targetImage->writeMetadata(); } catch (const Exiv2::AnyError& e) { std::cerr << target << ": " << _("Could not write metadata to file") << ": " << e << "\n"; return 1; } return 0; } // metacopy // Defined outside of the function so that Exiv2::find() can see it struct String { const char* s_; bool operator==(const char* s) const { return 0 == strcmp(s_, s); } }; int renameFile(std::string& newPath, const struct tm* tm) { std::string path = newPath; std::string format = Params::instance().format_; Util::replace(format, ":basename:", Util::basename(path, true)); Util::replace(format, ":dirname:", Util::basename(Util::dirname(path))); Util::replace(format, ":parentname:", Util::basename(Util::dirname(Util::dirname(path)))); const size_t max = 1024; char basename[max]; std::memset(basename, 0x0, max); if (strftime(basename, max, format.c_str(), tm) == 0) { std::cerr << _("Filename format yields empty filename for the file") << " " << path << "\n"; return 1; } newPath = Util::dirname(path) + EXV_SEPERATOR_STR + basename + Util::suffix(path); if ( Util::dirname(newPath) == Util::dirname(path) && Util::basename(newPath) == Util::basename(path)) { if (Params::instance().verbose_) { std::cout << _("This file already has the correct name") << std::endl; } return -1; } bool go = true; int seq = 1; std::string s; Params::FileExistsPolicy fileExistsPolicy = Params::instance().fileExistsPolicy_; while (go) { if (Exiv2::fileExists(newPath)) { switch (fileExistsPolicy) { case Params::overwritePolicy: go = false; break; case Params::renamePolicy: newPath = Util::dirname(path) + EXV_SEPERATOR_STR + basename + "_" + Exiv2::toString(seq++) + Util::suffix(path); break; case Params::askPolicy: std::cout << Params::instance().progname() << ": " << _("File") << " `" << newPath << "' " << _("exists. [O]verwrite, [r]ename or [s]kip?") << " "; std::cin >> s; switch (s[0]) { case 'o': case 'O': go = false; break; case 'r': case 'R': fileExistsPolicy = Params::renamePolicy; newPath = Util::dirname(path) + EXV_SEPERATOR_STR + basename + "_" + Exiv2::toString(seq++) + Util::suffix(path); break; default: // skip return -1; break; } } } else { go = false; } } if (Params::instance().verbose_) { std::cout << _("Renaming file to") << " " << newPath; if (Params::instance().timestamp_) { std::cout << ", " << _("updating timestamp"); } std::cout << std::endl; } // Workaround for MinGW rename which does not overwrite existing files remove(newPath.c_str()); if (std::rename(path.c_str(), newPath.c_str()) == -1) { std::cerr << Params::instance().progname() << ": " << _("Failed to rename") << " " << path << " " << _("to") << " " << newPath << ": " << Exiv2::strError() << "\n"; return 1; } return 0; } // renameFile std::string newFilePath(const std::string& path, const std::string& ext) { std::string directory = Params::instance().directory_; if (directory.empty()) directory = Util::dirname(path); std::string newPath = directory + EXV_SEPERATOR_STR + Util::basename(path, true) + ext; return newPath; } int dontOverwrite(const std::string& path) { if (!Params::instance().force_ && Exiv2::fileExists(path)) { std::cout << Params::instance().progname() << ": " << _("Overwrite") << " `" << path << "'? "; std::string s; std::cin >> s; if (s[0] != 'y' && s[0] != 'Y') return 1; } return 0; } } exiv2-0.23/src/crwedit.cpp0000644000175000017500000000716111045347530015252 0ustar andreasandreas// ***************************************************************** -*- C++ -*- // crwedit.cpp, $Rev: 1560 $ // Print the CIFF structure of a CRW file #include "crwimage.hpp" #include "crwimage_int.hpp" #include "futils.hpp" #include #include #include void remove(Exiv2::Internal::CiffHeader* pHead); void add(Exiv2::Internal::CiffHeader* pHead); void help(); void write(const std::string& filename, const Exiv2::Internal::CiffHeader* pHead); int main(int argc, char* const argv[]) try { if (argc != 2) { std::cout << "Usage: " << argv[0] << " file\n"; std::cout << "Edit the CIFF structure of a CRW file\n"; return 1; } std::string filename(argv[1]); Exiv2::FileIo io(filename); if(io.open() != 0) { throw Exiv2::Error(9, io.path(), Exiv2::strError()); } Exiv2::IoCloser closer(io); // Ensure that this is a CRW image if (!Exiv2::isCrwType(io, false)) { if (io.error() || io.eof()) throw Exiv2::Error(14); throw Exiv2::Error(33); } // Read the image into a memory buffer long len = io.size(); Exiv2::DataBuf buf(len); io.read(buf.pData_, len); if (io.error() || io.eof()) throw Exiv2::Error(14); // Parse the image, starting with a CIFF header component Exiv2::Internal::CiffHeader::AutoPtr parseTree(new Exiv2::Internal::CiffHeader); parseTree->read(buf.pData_, buf.size_); // Allow user to make changes bool go = true; while (go) { char cmd; std::cout << "command> "; std::cin >> cmd; switch (cmd) { case 'q': go = false; break; case 'p': parseTree->print(std::cout); break; case 'a': add(parseTree.get()); break; case 'd': remove(parseTree.get()); break; case 'w': write(filename, parseTree.get()); break; case 'h': help(); break; } } return 0; } catch (Exiv2::AnyError& e) { std::cerr << e << "\n"; return -1; } void write(const std::string& filename, const Exiv2::Internal::CiffHeader* pHead) { Exiv2::Blob blob; pHead->write(blob); Exiv2::FileIo io(filename); if(io.open("wb") != 0) { throw Exiv2::Error(9, io.path(), Exiv2::strError()); } Exiv2::IoCloser closer(io); long ret = io.write(&blob[0], blob.size()); if (static_cast(ret) != blob.size()) throw Exiv2::Error(21); io.close(); } void remove(Exiv2::Internal::CiffHeader* pHead) { uint16_t crwTag, crwDir; std::cout << "crwTag> 0x"; std::cin >> std::hex >> crwTag; std::cout << "crwDir> 0x"; std::cin >> std::hex >> crwDir; std::cout << "Deleting tag 0x" << std::hex << crwTag << " in dir 0x" << crwDir << ", ok? "; char cmd; std::cin >> cmd; if (cmd != 'n' && cmd != 'N') { pHead->remove(crwTag, crwDir); } else { std::cout << "Canceled.\n"; } } void add(Exiv2::Internal::CiffHeader* pHead) { uint16_t crwTag, crwDir; uint32_t size; std::cout << "crwTag> 0x"; std::cin >> std::hex >> crwTag; std::cout << "crwDir> 0x"; std::cin >> std::hex >> crwDir; std::cout << "size> "; std::cin >> std::dec >> size; std::cout << "Adding tag 0x" << std::hex << crwTag << " in dir 0x" << crwDir << ", " << size << " bytes, ok? "; char cmd; std::cin >> cmd; if (cmd != 'n' && cmd != 'N') { Exiv2::DataBuf buf(size); std::memset(buf.pData_, 0xaa, size); pHead->add(crwTag, crwDir, buf); } else { std::cout << "Canceled.\n"; } } void help() { std::cout << "a: add tag, d: delete tag, p: print tags, w: write file, q: quit\n"; } exiv2-0.23/src/exiv2app.hpp0000644000175000017500000002507211732641407015360 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! @file exiv2app.hpp @brief Defines class Params, used for the command line handling of exiv2 @version $Rev: 2681 $ @author Andreas Huggel (ahu) ahuggel@gmx.net @date 08-Dec-03, ahu: created */ #ifndef EXIV2APP_HPP_ #define EXIV2APP_HPP_ // ***************************************************************************** // included header files #include "utils.hpp" #include "types.hpp" // + standard includes #include #include #include #include // ***************************************************************************** // class definitions //! Command identifiers enum CmdId { invalidCmdId, add, set, del, reg }; //! Metadata identifiers enum MetadataId { invalidMetadataId, iptc, exif, xmp }; //! Structure for one parsed modification command struct ModifyCmd { //! C'tor ModifyCmd() : cmdId_(invalidCmdId), metadataId_(invalidMetadataId), typeId_(Exiv2::invalidTypeId), explicitType_(false) {} CmdId cmdId_; //!< Command identifier std::string key_; //!< Exiv2 key string MetadataId metadataId_; //!< Metadata identifier Exiv2::TypeId typeId_; //!< Exiv2 type identifier //! Flag to indicate if the type was explicitly specified (true) bool explicitType_; std::string value_; //!< Data }; //! Container for modification commands typedef std::vector ModifyCmds; //! Structure to link command identifiers to strings struct CmdIdAndString { CmdId cmdId_; //!< Commands identifier std::string cmdString_; //!< Command string }; /*! @brief Implements the command line handling for the program. Derives from Util::Getopt to use the command line argument parsing functionality provided there. This class is implemented as a singleton, i.e., there is only one global instance of it, which can be accessed from everywhere. Usage example:
@code #include "params.h" int main(int argc, char* const argv[]) { Params& params = Params::instance(); if (params.getopt(argc, argv)) { params.usage(); return 1; } if (params.help_) { params.help(); return 0; } if (params.version_) { params.version(); return 0; } // do something useful here... return 0; } @endcode */ class Params : public Util::Getopt { private: std::string optstring_; public: //! Container for command files typedef std::vector CmdFiles; //! Container for commands from the command line typedef std::vector CmdLines; //! Container to store filenames. typedef std::vector Files; //! Container for preview image numbers typedef std::set PreviewNumbers; //! Container for keys typedef std::vector Keys; /*! @brief Controls all access to the global Params instance. @return Reference to the global Params instance. */ static Params& instance(); //! Destructor void cleanup(); //! Enumerates print modes enum PrintMode { pmSummary, pmList, pmComment, pmPreview }; //! Individual items to print, bitmap enum PrintItem { prTag = 1, prGroup = 2, prKey = 4, prName = 8, prLabel = 16, prType = 32, prCount = 64, prSize = 128, prValue = 256, prTrans = 512, prHex = 1024 }; //! Enumerates common targets, bitmap enum CommonTarget { ctExif = 1, ctIptc = 2, ctComment = 4, ctThumb = 8, ctXmp = 16, ctXmpSidecar = 32, ctPreview = 64 }; //! Enumerates the policies to handle existing files in rename action enum FileExistsPolicy { overwritePolicy, renamePolicy, askPolicy }; //! Enumerates year, month and day adjustments. enum Yod { yodYear, yodMonth, yodDay }; //! Structure for year, month and day adjustment command line arguments. struct YodAdjust { bool flag_; //!< Adjustment flag. const char* option_; //!< Adjustment option string. long adjustment_; //!< Adjustment value. }; bool help_; //!< Help option flag. bool version_; //!< Version option flag. bool verbose_; //!< Verbose (talkative) option flag. bool force_; //!< Force overwrites flag. bool binary_; //!< Suppress long binary values. bool unknown_; //!< Suppress unknown tags. bool preserve_; //!< Preserve timestamps flag. bool timestamp_; //!< Rename also sets the file timestamp. bool timestampOnly_; //!< Rename only sets the file timestamp. FileExistsPolicy fileExistsPolicy_; //!< What to do if file to rename exists. bool adjust_; //!< Adjustment flag. PrintMode printMode_; //!< Print mode. unsigned long printItems_; //!< Print items. unsigned long printTags_; //!< Print tags (bitmap of MetadataId flags). //! %Action (integer rather than TaskType to avoid dependency). int action_; int target_; //!< What common target to process. long adjustment_; //!< Adjustment in seconds. YodAdjust yodAdjust_[3]; //!< Year, month and day adjustment info. std::string format_; //!< Filename format (-r option arg). bool formatSet_; //!< Whether the format is set with -r CmdFiles cmdFiles_; //!< Names of the modification command files CmdLines cmdLines_; //!< Commands from the command line ModifyCmds modifyCmds_; //!< Parsed modification commands std::string jpegComment_; //!< Jpeg comment to set in the image std::string directory_; //!< Location for files to extract/insert std::string suffix_; //!< File extension of the file to insert Files files_; //!< List of non-option arguments. PreviewNumbers previewNumbers_; //!< List of preview numbers Keys keys_; //!< List of keys to 'grep' from the metadata std::string charset_; //!< Charset to use for UNICODE Exif user comment private: //! Pointer to the global Params object. static Params* instance_; //! Initializer for year, month and day adjustment info. static const YodAdjust emptyYodAdjust_[]; bool first_; private: /*! @brief Default constructor. Note that optstring_ is initialized here. The c'tor is private to force instantiation through instance(). */ Params() : optstring_(":hVvqfbuktTFa:Y:O:D:r:p:P:d:e:i:c:m:M:l:S:g:n:Q:"), help_(false), version_(false), verbose_(false), force_(false), binary_(true), unknown_(true), preserve_(false), timestamp_(false), timestampOnly_(false), fileExistsPolicy_(askPolicy), adjust_(false), printMode_(pmSummary), printItems_(0), printTags_(Exiv2::mdNone), action_(0), target_(ctExif|ctIptc|ctComment|ctXmp), adjustment_(0), format_("%Y%m%d_%H%M%S"), formatSet_(false), first_(true) { yodAdjust_[yodYear] = emptyYodAdjust_[yodYear]; yodAdjust_[yodMonth] = emptyYodAdjust_[yodMonth]; yodAdjust_[yodDay] = emptyYodAdjust_[yodDay]; } //! Prevent copy-construction: not implemented. Params(const Params& rhs); //! @name Helpers //@{ int setLogLevel(const std::string& optarg); int evalRename(int opt, const std::string& optarg); int evalAdjust(const std::string& optarg); int evalYodAdjust(const Yod& yod, const std::string& optarg); int evalPrint(const std::string& optarg); int evalPrintFlags(const std::string& optarg); int evalDelete(const std::string& optarg); int evalExtract(const std::string& optarg); int evalInsert(const std::string& optarg); int evalModify(int opt, const std::string& optarg); //@} public: /*! @brief Call Getopt::getopt() with optstring, to inititate command line argument parsing, perform consistency checks after all command line arguments are parsed. @param argc Argument count as passed to main() on program invocation. @param argv Argument array as passed to main() on program invocation. @return 0 if successful, >0 in case of errors. */ int getopt(int argc, char* const argv[]); //! Handle options and their arguments. virtual int option(int opt, const std::string& optarg, int optopt); //! Handle non-option parameters. virtual int nonoption(const std::string& argv); //! Print a minimal usage note to an output stream. void usage(std::ostream& os =std::cout) const; //! Print further usage explanations to an output stream. void help(std::ostream& os =std::cout) const; //! Print version information to an output stream. void version(std::ostream& os =std::cout) const; }; // class Params #endif // #ifndef EXIV2APP_HPP_ exiv2-0.23/src/fujimn_int.hpp0000644000175000017500000000475011732641407015764 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! @file fujimn_int.hpp @brief Fujifilm MakerNote implemented according to the specification in Appendix 4: Makernote of Fujifilm of the document Exif file format by TsuruZoh Tachibanaya
Fuji Makernote list by Phil Harvey
@version $Rev: 2681 $ @author Andreas Huggel (ahu) ahuggel@gmx.net @author Gilles Caulier (gc) caulier dot gilles at gmail dot com @date 11-Feb-04, ahu: created */ #ifndef FUJIMN_INT_HPP_ #define FUJIMN_INT_HPP_ // ***************************************************************************** // included header files #include "tags.hpp" #include "types.hpp" // ***************************************************************************** // namespace extensions namespace Exiv2 { namespace Internal { // ***************************************************************************** // class definitions //! MakerNote for Fujifilm cameras class FujiMakerNote { public: //! Return read-only list of built-in Fujifilm tags static const TagInfo* tagList(); private: //! Tag information static const TagInfo tagInfo_[]; }; // class FujiMakerNote }} // namespace Internal, Exiv2 #endif // #ifndef FUJIMN_INT_HPP_ exiv2-0.23/src/samsungmn.cpp0000644000175000017500000002400111742031570015607 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /* File: samsungmn.cpp Version: $Rev: 2701 $ Author(s): Andreas Huggel (ahu) History: 27-Sep-10, ahu: created */ // ***************************************************************************** #include "rcsid_int.hpp" EXIV2_RCSID("@(#) $Id: samsungmn.cpp 2701 2012-04-13 14:08:56Z ahuggel $") // ***************************************************************************** // included header files #include "types.hpp" #include "samsungmn_int.hpp" #include "tags_int.hpp" #include "value.hpp" #include "i18n.h" // NLS support. // + standard includes #include #include #include #include #include // ***************************************************************************** // class member definitions namespace Exiv2 { namespace Internal { //! LensType, tag 0xa003 extern const TagDetails samsung2LensType[] = { { 0, N_("Built-in") }, { 1, N_("Samsung 30mm F2 Pancake") }, { 2, N_("Samsung Zoom 18-55mm F3.5-5.6 OIS") }, { 3, N_("Samsung Zoom 50-200mm F4-5.6 ED OIS") }, { 4, N_("Samsung 20-50mm F3.5-5.6 Compact Zoom") }, { 5, N_("Samsung 20mm F2.8 Pancake") }, { 7, N_("Samsung 60mm F2.8 Macro ED OIS SSA") }, { 8, N_("Samsung 16mm F2.4 Ultra Wide Pancake") } }; //! ColorSpace, tag 0xa011 extern const TagDetails samsung2ColorSpace[] = { { 0, N_("sRGB") }, { 1, N_("Adobe RGB") } }; //! SmartRange, tag 0xa012 extern const TagDetails samsung2SmartRange[] = { { 0, N_("Off") }, { 1, N_("On") } }; //! Print the camera temperature std::ostream& printCameraTemperature(std::ostream& os, const Value& value, const ExifData*) { if (value.count() != 1 || value.typeId() != signedRational) { return os << value; } return os << value.toFloat() << " C"; } //! Print the 35mm focal length std::ostream& printFocalLength35(std::ostream& os, const Value& value, const ExifData*) { if (value.count() != 1 || value.typeId() != unsignedLong) { return os << value; } long length = value.toLong(); if (length == 0) { os << _("Unknown"); } else { std::ostringstream oss; oss.copyfmt(os); os << std::fixed << std::setprecision(1) << length / 10.0 << " mm"; os.copyfmt(oss); } return os; } // Samsung MakerNote Tag Info const TagInfo Samsung2MakerNote::tagInfo_[] = { TagInfo(0x0001, "Version", N_("Version"), N_("Makernote version"), samsung2Id, makerTags, undefined, -1, printExifVersion), TagInfo(0x0021, "PictureWizard", N_("Picture Wizard"), N_("Picture wizard composite tag"), samsung2Id, makerTags, unsignedShort, -1, printValue), TagInfo(0x0030, "LocalLocationName", N_("Local Location Name"), N_("Local location name"), samsung2Id, makerTags, asciiString, -1, printValue), TagInfo(0x0031, "LocationName", N_("Location Name"), N_("Location name"), samsung2Id, makerTags, asciiString, -1, printValue), TagInfo(0x0035, "Preview", N_("Pointer to a preview image"), N_("Offset to an IFD containing a preview image"), samsung2Id, makerTags, unsignedLong, -1, printValue), TagInfo(0x0043, "CameraTemperature", N_("Camera Temperature"), N_("Camera temperature"), samsung2Id, makerTags, signedRational, -1, printCameraTemperature), TagInfo(0xa001, "FirmwareName", N_("Firmware Name"), N_("Firmware name"), samsung2Id, makerTags, asciiString, -1, printValue), TagInfo(0xa003, "LensType", N_("Lens Type"), N_("Lens type"), samsung2Id, makerTags, unsignedShort, -1, EXV_PRINT_TAG(samsung2LensType)), TagInfo(0xa004, "LensFirmware", N_("Lens Firmware"), N_("Lens firmware"), samsung2Id, makerTags, asciiString, -1, printValue), TagInfo(0xa010, "SensorAreas", N_("Sensor Areas"), N_("Sensor areas"), samsung2Id, makerTags, unsignedLong, -1, printValue), TagInfo(0xa011, "ColorSpace", N_("Color Space"), N_("Color space"), samsung2Id, makerTags, unsignedShort, -1, EXV_PRINT_TAG(samsung2ColorSpace)), TagInfo(0xa012, "SmartRange", N_("Smart Range"), N_("Smart range"), samsung2Id, makerTags, unsignedShort, -1, EXV_PRINT_TAG(samsung2SmartRange)), TagInfo(0xa013, "ExposureBiasValue", N_("Exposure Bias Value"), N_("Exposure bias value"), samsung2Id, makerTags, signedRational, -1, print0x9204), TagInfo(0xa014, "ISO", N_("ISO"), N_("ISO"), samsung2Id, makerTags, unsignedLong, -1, printValue), TagInfo(0xa018, "ExposureTime", N_("Exposure Time"), N_("Exposure time"), samsung2Id, makerTags, unsignedRational, -1, print0x829a), TagInfo(0xa019, "FNumber", N_("FNumber"), N_("The F number."), samsung2Id, makerTags, unsignedRational, -1, print0x829d), TagInfo(0xa01a, "FocalLengthIn35mmFormat", N_("Focal Length In 35mm Format"), N_("Focal length in 35mm format"), samsung2Id, makerTags, unsignedLong, -1, printFocalLength35), TagInfo(0xa020, "EncryptionKey", N_("Encryption Key"), N_("Encryption key"), samsung2Id, makerTags, unsignedLong, -1, printValue), TagInfo(0xa021, "WB_RGGBLevelsUncorrected", N_("WB RGGB Levels Uncorrected"), N_("WB RGGB levels not corrected for WB_RGGBLevelsBlack"), samsung2Id, makerTags, unsignedLong, -1, printValue), TagInfo(0xa022, "WB_RGGBLevelsAuto", N_("WB RGGB Levels Auto"), N_("WB RGGB levels auto"), samsung2Id, makerTags, unsignedLong, -1, printValue), TagInfo(0xa023, "WB_RGGBLevelsIlluminator1", N_("WB RGGB Levels Illuminator1"), N_("WB RGGB levels illuminator1"), samsung2Id, makerTags, unsignedLong, -1, printValue), TagInfo(0xa024, "WB_RGGBLevelsIlluminator2", N_("WB RGGB Levels Illuminator2"), N_("WB RGGB levels illuminator2"), samsung2Id, makerTags, unsignedLong, -1, printValue), TagInfo(0xa028, "WB_RGGBLevelsBlack", N_("WB RGGB Levels Black"), N_("WB RGGB levels black"), samsung2Id, makerTags, signedLong, -1, printValue), TagInfo(0xa030, "ColorMatrix", N_("Color Matrix"), N_("Color matrix"), samsung2Id, makerTags, signedLong, -1, printValue), TagInfo(0xa031, "ColorMatrixSRGB", N_("Color Matrix sRGB"), N_("Color matrix sRGB"), samsung2Id, makerTags, signedLong, -1, printValue), TagInfo(0xa032, "ColorMatrixAdobeRGB", N_("Color Matrix Adobe RGB"), N_("Color matrix Adobe RGB"), samsung2Id, makerTags, signedLong, -1, printValue), TagInfo(0xa040, "ToneCurve1", N_("Tone Curve 1"), N_("Tone curve 1"), samsung2Id, makerTags, unsignedLong, -1, printValue), TagInfo(0xa041, "ToneCurve2", N_("Tone Curve 2"), N_("Tone curve 2"), samsung2Id, makerTags, unsignedLong, -1, printValue), TagInfo(0xa042, "ToneCurve3", N_("Tone Curve 3"), N_("Tone curve 3"), samsung2Id, makerTags, unsignedLong, -1, printValue), TagInfo(0xa043, "ToneCurve4", N_("Tone Curve 4"), N_("Tone curve 4"), samsung2Id, makerTags, unsignedLong, -1, printValue), // End of list marker TagInfo(0xffff, "(UnknownSamsung2MakerNoteTag)", "(UnknownSamsung2MakerNoteTag)", N_("Unknown Samsung2MakerNote tag"), samsung2Id, makerTags, undefined, -1, printValue) }; const TagInfo* Samsung2MakerNote::tagList() { return tagInfo_; } //! PictureWizard Mode extern const TagDetails samsungPwMode[] = { { 0, N_("Standard") }, { 1, N_("Vivid") }, { 2, N_("Portrait") }, { 3, N_("Landscape") }, { 4, N_("Forest") }, { 5, N_("Retro") }, { 6, N_("Cool") }, { 7, N_("Calm") }, { 8, N_("Classic") }, { 9, N_("Custom1") }, { 10, N_("Custom2") }, { 11, N_("Custom3") } }; //! Print the tag value minus 4 std::ostream& printValueMinus4(std::ostream& os, const Value& value, const ExifData*) { if (value.count() != 1 || value.typeId() != unsignedShort) { return os << value; } return os << value.toLong(0) - 4; } // Samsung PictureWizard Tag Info const TagInfo Samsung2MakerNote::tagInfoPw_[] = { TagInfo(0x0000, "Mode", N_("Mode"), N_("Mode"), samsungPwId, makerTags, unsignedShort, 1, EXV_PRINT_TAG(samsungPwMode)), TagInfo(0x0001, "Color", N_("Color"), N_("Color"), samsungPwId, makerTags, unsignedShort, 1, printValue), TagInfo(0x0002, "Saturation", N_("Saturation"), N_("Saturation"), samsungPwId, makerTags, unsignedShort, 1, printValueMinus4), TagInfo(0x0003, "Sharpness", N_("Sharpness"), N_("Sharpness"), samsungPwId, makerTags, unsignedShort, 1, printValueMinus4), TagInfo(0x0004, "Contrast", N_("Contrast"), N_("Contrast"), samsungPwId, makerTags, unsignedShort, 1, printValueMinus4), // End of list marker TagInfo(0xffff, "(UnknownSamsungPictureWizardTag)", "(UnknownSamsungPictureWizardTag)", N_("Unknown SamsungPictureWizard tag"), samsungPwId, makerTags, unsignedShort, 1, printValue) }; const TagInfo* Samsung2MakerNote::tagListPw() { return tagInfoPw_; } }} // namespace Internal, Exiv2 exiv2-0.23/src/datasets.cpp0000644000175000017500000011455411732641407015431 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /* File: datasets.cpp Version: $Rev: 2681 $ Author(s): Brad Schick (brad) Gilles Caulier (gc) History: 24-Jul-04, brad: created */ // ***************************************************************************** #include "rcsid_int.hpp" EXIV2_RCSID("@(#) $Id: datasets.cpp 2681 2012-03-22 15:19:35Z ahuggel $") // ***************************************************************************** // included header files #include "datasets.hpp" #include "error.hpp" #include "types.hpp" #include "value.hpp" #include "metadatum.hpp" #include "i18n.h" // NLS support. #include #include #include // ***************************************************************************** // class member definitions namespace Exiv2 { DataSet::DataSet( uint16_t number, const char* name, const char* title, const char* desc, bool mandatory, bool repeatable, uint32_t minbytes, uint32_t maxbytes, TypeId type, uint16_t recordId, const char* photoshop ) : number_(number), name_(name), title_(title), desc_(desc), mandatory_(mandatory), repeatable_(repeatable), minbytes_(minbytes), maxbytes_(maxbytes), type_(type), recordId_(recordId), photoshop_(photoshop) { } RecordInfo::RecordInfo( uint16_t recordId, const char* name, const char* desc ) : recordId_(recordId), name_(name), desc_(desc) { } const RecordInfo IptcDataSets::recordInfo_[] = { RecordInfo(IptcDataSets::invalidRecord, "(invalid)", N_("(invalid)")), RecordInfo(IptcDataSets::envelope, "Envelope", N_("IIM envelope record")), RecordInfo(IptcDataSets::application2, "Application2", N_("IIM application record 2")), }; static const DataSet envelopeRecord[] = { DataSet(IptcDataSets::ModelVersion, "ModelVersion", N_("Model Version"), N_("A binary number identifying the version of the Information " "Interchange Model, Part I, utilised by the provider. Version " "numbers are assigned by IPTC and NAA organizations."), true, false, 2, 2, Exiv2::unsignedShort, IptcDataSets::envelope, ""), DataSet(IptcDataSets::Destination, "Destination", N_("Destination"), N_("This DataSet is to accommodate some providers who require " "routing information above the appropriate OSI layers."), false, true, 0, 1024, Exiv2::string, IptcDataSets::envelope, ""), DataSet(IptcDataSets::FileFormat, "FileFormat", N_("File Format"), N_("A binary number representing the file format. The file format " "must be registered with IPTC or NAA with a unique number " "assigned to it. The information is used to route " "the data to the appropriate system and to allow the receiving " "system to perform the appropriate actions there to."), true, false, 2, 2, Exiv2::unsignedShort, IptcDataSets::envelope, ""), DataSet(IptcDataSets::FileVersion, "FileVersion", N_("File Version"), N_("A binary number representing the particular version of the File " "Format specified by tag."), true, false, 2, 2, Exiv2::unsignedShort, IptcDataSets::envelope, ""), DataSet(IptcDataSets::ServiceId, "ServiceId", N_("Service Id"), N_("Identifies the provider and product"), true, false, 0, 10, Exiv2::string, IptcDataSets::envelope, ""), DataSet(IptcDataSets::EnvelopeNumber, "EnvelopeNumber", N_("Envelope Number"), N_("The characters form a number that will be unique for the date " "specified in tag and for the Service Identifier " "specified by tag. " "If identical envelope numbers appear with the same date and " "with the same Service Identifier, records 2-9 must be unchanged " "from the original. This is not intended to be a sequential serial " "number reception check."), true, false, 8, 8, Exiv2::string, IptcDataSets::envelope, ""), DataSet(IptcDataSets::ProductId, "ProductId", N_("Product Id"), N_("Allows a provider to identify subsets of its overall service. Used " "to provide receiving organisation data on which to select, route, " "or otherwise handle data."), false, true, 0, 32, Exiv2::string, IptcDataSets::envelope, ""), DataSet(IptcDataSets::EnvelopePriority, "EnvelopePriority", N_("Envelope Priority"), N_("Specifies the envelope handling priority and not the editorial " "urgency (see tag). \"1\" indicates the most urgent, \"5\" " "the normal urgency, and \"8\" the least urgent copy. The numeral " "\"9\" indicates a User Defined Priority. The numeral \"0\" is reserved " "for future use."), false, false, 1, 1, Exiv2::string, IptcDataSets::envelope, ""), DataSet(IptcDataSets::DateSent, "DateSent", N_("Date Sent"), N_("Uses the format CCYYMMDD (century, year, month, day) as de-fined " "in ISO 8601 to indicate year, month and day the service sent the material."), true, false, 8, 8, Exiv2::date, IptcDataSets::envelope, ""), DataSet(IptcDataSets::TimeSent, "TimeSent", N_("Time Sent"), N_("Uses the format HHMMSS:HHMM where HHMMSS refers to " "local hour, minute and seconds and HHMM refers to hours and " "minutes ahead (+) or behind (-) Universal Coordinated Time as " "described in ISO 8601. This is the time the service sent the material."), false, false, 11, 11, Exiv2::time, IptcDataSets::envelope, ""), DataSet(IptcDataSets::CharacterSet, "CharacterSet", N_("Character Set"), N_("This tag consisting of one or more control functions used for the announcement, " "invocation or designation of coded character sets. The control functions follow " "the ISO 2022 standard and may consist of the escape control " "character and one or more graphic characters."), false, false, 0, 32, Exiv2::string, IptcDataSets::envelope, ""), DataSet(IptcDataSets::UNO, "UNO", N_("Unique Name Object"), N_("This tag provide a globally unique " "identification for objects as specified in the IIM, independent of " "provider and for any media form. The provider must ensure the " "UNO is unique. Objects with the same UNO are identical."), false, false, 14, 80, Exiv2::string, IptcDataSets::envelope, ""), DataSet(IptcDataSets::ARMId, "ARMId", N_("ARM Identifier"), N_("The DataSet identifies the Abstract Relationship Method identifier (ARM) " "which is described in a document registered by the originator of " "the ARM with the IPTC and NAA organizations."), false, false, 2, 2, Exiv2::unsignedShort, IptcDataSets::envelope, ""), DataSet(IptcDataSets::ARMVersion, "ARMVersion", N_("ARM Version"), N_("This tag consisting of a binary number representing the particular " "version of the ARM specified by tag ."), false, false, 2, 2, Exiv2::unsignedShort, IptcDataSets::envelope, ""), DataSet(0xffff, "(Invalid)", "(Invalid)", "(Invalid)", false, false, 0, 0, Exiv2::unsignedShort, IptcDataSets::envelope, "") }; const DataSet* IptcDataSets::envelopeRecordList() { return envelopeRecord; } static const DataSet application2Record[] = { DataSet(IptcDataSets::RecordVersion, "RecordVersion", N_("Record Version"), N_("A binary number identifying the version of the Information " "Interchange Model, Part II, utilised by the provider. " "Version numbers are assigned by IPTC and NAA organizations."), true, false, 2, 2, Exiv2::unsignedShort, IptcDataSets::application2, ""), DataSet(IptcDataSets::ObjectType, "ObjectType", N_("Object Type"), N_("The Object Type is used to distinguish between different types " "of objects within the IIM. The first part is a number representing " "a language independent international reference to an Object Type " "followed by a colon separator. The second part, if used, is a text " "representation of the Object Type Number consisting of graphic " "characters plus spaces either in English or in the language of the " "service as indicated in tag "), false, false, 3, 67, Exiv2::string, IptcDataSets::application2, ""), DataSet(IptcDataSets::ObjectAttribute, "ObjectAttribute", N_("Object Attribute"), N_("The Object Attribute defines the nature of the object " "independent of the Subject. The first part is a number representing " "a language independent international reference to an Object Attribute " "followed by a colon separator. The second part, if used, is a text " "representation of the Object Attribute Number consisting of graphic " "characters plus spaces either in English, or in the language of the " "service as indicated in tag "), false, true, 4, 68, Exiv2::string, IptcDataSets::application2, ""), DataSet(IptcDataSets::ObjectName, "ObjectName", N_("Object Name"), N_("Used as a shorthand reference for the object. Changes to exist-ing " "data, such as updated stories or new crops on photos, should be " "identified in tag ."), false, false, 0, 64, Exiv2::string, IptcDataSets::application2, N_("Document Title")), DataSet(IptcDataSets::EditStatus, "EditStatus", N_("Edit Status"), N_("Status of the object data, according to the practice of the provider."), false, false, 0, 64, Exiv2::string, IptcDataSets::application2, ""), DataSet(IptcDataSets::EditorialUpdate, "EditorialUpdate", N_("Editorial Update"), N_("Indicates the type of update that this object provides to a " "previous object. The link to the previous object is made using " "the tags and , according to the practices of the provider."), false, false, 2, 2, Exiv2::string, IptcDataSets::application2, ""), DataSet(IptcDataSets::Urgency, "Urgency", N_("Urgency"), N_("Specifies the editorial urgency of content and not necessarily the " "envelope handling priority (see tag ). The \"1\" " "is most urgent, \"5\" normal and \"8\" denotes the least-urgent copy."), false, false, 1, 1, Exiv2::string, IptcDataSets::application2, N_("Urgency")), DataSet(IptcDataSets::Subject, "Subject", N_("Subject"), N_("The Subject Reference is a structured definition of the subject matter."), false, true, 13, 236, Exiv2::string, IptcDataSets::application2, ""), DataSet(IptcDataSets::Category, "Category", N_("Category"), N_("Identifies the subject of the object data in the opinion of the provider. " "A list of categories will be maintained by a regional registry, " "where available, otherwise by the provider."), false, false, 0, 3, Exiv2::string, IptcDataSets::application2, N_("Category")), DataSet(IptcDataSets::SuppCategory, "SuppCategory", N_("Supplemental Category"), N_("Supplemental categories further refine the subject of an " "object data. A supplemental category may include " "any of the recognised categories as used in tag . Otherwise, " "selection of supplemental categories are left to the provider."), false, true, 0, 32, Exiv2::string, IptcDataSets::application2, N_("Supplemental Categories")), DataSet(IptcDataSets::FixtureId, "FixtureId", N_("Fixture Id"), N_("Identifies object data that recurs often and predictably. Enables " "users to immediately find or recall such an object."), false, false, 0, 32, Exiv2::string, IptcDataSets::application2, ""), DataSet(IptcDataSets::Keywords, "Keywords", N_("Keywords"), N_("Used to indicate specific information retrieval words. " "It is expected that a provider of various types of data that are related " "in subject matter uses the same keyword, enabling the receiving system " "or subsystems to search across all types of data for related material."), false, true, 0, 64, Exiv2::string, IptcDataSets::application2, N_("Keywords")), DataSet(IptcDataSets::LocationCode, "LocationCode", N_("Location Code"), N_("Indicates the code of a country/geographical location referenced " "by the content of the object. Where ISO has established an appropriate " "country code under ISO 3166, that code will be used. When ISO 3166 does not " "adequately provide for identification of a location or a country, " "e.g. ships at sea, space, IPTC will assign an appropriate three-character " "code under the provisions of ISO 3166 to avoid conflicts."), false, true, 3, 3, Exiv2::string, IptcDataSets::application2, ""), DataSet(IptcDataSets::LocationName, "LocationName", N_("Location Name"), N_("Provides a full, publishable name of a country/geographical " "location referenced by the content of the object, according to " "guidelines of the provider."), false, true, 0, 64, Exiv2::string, IptcDataSets::application2, ""), DataSet(IptcDataSets::ReleaseDate, "ReleaseDate", N_("Release Date"), N_("Designates in the form CCYYMMDD the earliest date the " "provider intends the object to be used. Follows ISO 8601 standard."), false, false, 8, 8, Exiv2::date, IptcDataSets::application2, ""), DataSet(IptcDataSets::ReleaseTime, "ReleaseTime", N_("Release Time"), N_("Designates in the form HHMMSS:HHMM the earliest time the " "provider intends the object to be used. Follows ISO 8601 standard."), false, false, 11, 11, Exiv2::time, IptcDataSets::application2, ""), DataSet(IptcDataSets::ExpirationDate, "ExpirationDate", N_("Expiration Date"), N_("Designates in the form CCYYMMDD the latest date the provider " "or owner intends the object data to be used. Follows ISO 8601 standard."), false, false, 8, 8, Exiv2::date, IptcDataSets::application2, ""), DataSet(IptcDataSets::ExpirationTime, "ExpirationTime", N_("ExpirationTime"), N_("Designates in the form HHMMSS:HHMM the latest time the " "provider or owner intends the object data to be used. Follows ISO 8601 standard."), false, false, 11, 11, Exiv2::time, IptcDataSets::application2, ""), DataSet(IptcDataSets::SpecialInstructions, "SpecialInstructions", N_("Special Instructions"), N_("Other editorial instructions concerning the use of the object data, " "such as embargoes and warnings."), false, false, 0, 256, Exiv2::string, IptcDataSets::application2, N_("Instructions")), DataSet(IptcDataSets::ActionAdvised, "ActionAdvised", N_("Action Advised"), N_("Indicates the type of action that this object provides to a " "previous object. The link to the previous object is made using " "tags and , according to the practices of the provider."), false, false, 2, 2, Exiv2::string, IptcDataSets::application2, ""), DataSet(IptcDataSets::ReferenceService, "ReferenceService", N_("Reference Service"), N_("Identifies the Service Identifier of a prior envelope to which the " "current object refers."), false, true, 0, 10, Exiv2::string, IptcDataSets::application2, ""), DataSet(IptcDataSets::ReferenceDate, "ReferenceDate", N_("Reference Date"), N_("Identifies the date of a prior envelope to which the current object refers."), false, true, 8, 8, Exiv2::date, IptcDataSets::application2, ""), DataSet(IptcDataSets::ReferenceNumber, "ReferenceNumber", N_("Reference Number"), N_("Identifies the Envelope Number of a prior envelope to which the current object refers."), false, true, 8, 8, Exiv2::string, IptcDataSets::application2, ""), DataSet(IptcDataSets::DateCreated, "DateCreated", N_("Date Created"), N_("Represented in the form CCYYMMDD to designate the date the " "intellectual content of the object data was created rather than the " "date of the creation of the physical representation. Follows ISO 8601 standard."), false, false, 8, 8, Exiv2::date, IptcDataSets::application2, N_("Date Created")), DataSet(IptcDataSets::TimeCreated, "TimeCreated", N_("Time Created"), N_("Represented in the form HHMMSS:HHMM to designate the " "time the intellectual content of the object data current source " "material was created rather than the creation of the physical " "representation. Follows ISO 8601 standard."), false, false, 11, 11, Exiv2::time, IptcDataSets::application2, ""), DataSet(IptcDataSets::DigitizationDate, "DigitizationDate", N_("Digitization Date"), N_("Represented in the form CCYYMMDD to designate the date the " "digital representation of the object data was created. Follows ISO 8601 standard."), false, false, 8, 8, Exiv2::date, IptcDataSets::application2, ""), DataSet(IptcDataSets::DigitizationTime, "DigitizationTime", N_("Digitization Time"), N_("Represented in the form HHMMSS:HHMM to designate the " "time the digital representation of the object data was created. " "Follows ISO 8601 standard."), false, false, 11, 11, Exiv2::time, IptcDataSets::application2, ""), DataSet(IptcDataSets::Program, "Program", N_("Program"), N_("Identifies the type of program used to originate the object data."), false, false, 0, 32, Exiv2::string, IptcDataSets::application2, ""), DataSet(IptcDataSets::ProgramVersion, "ProgramVersion", N_("Program Version"), N_("Used to identify the version of the program mentioned in tag ."), false, false, 0, 10, Exiv2::string, IptcDataSets::application2, ""), DataSet(IptcDataSets::ObjectCycle, "ObjectCycle", N_("Object Cycle"), N_("Used to identify the editorial cycle of object data."), false, false, 1, 1, Exiv2::string, IptcDataSets::application2, ""), DataSet(IptcDataSets::Byline, "Byline", N_("By-line"), N_("Contains name of the creator of the object data, e.g. writer, photographer " "or graphic artist."), false, true, 0, 32, Exiv2::string, IptcDataSets::application2, N_("Author")), DataSet(IptcDataSets::BylineTitle, "BylineTitle", N_("By-line Title"), N_("A by-line title is the title of the creator or creators of an " "object data. Where used, a by-line title should follow the by-line it modifies."), false, true, 0, 32, Exiv2::string, IptcDataSets::application2, "Authors Position"), DataSet(IptcDataSets::City, "City", N_("City"), N_("Identifies city of object data origin according to guidelines established " "by the provider."), false, false, 0, 32, Exiv2::string, IptcDataSets::application2, N_("City")), DataSet(IptcDataSets::SubLocation, "SubLocation", N_("Sub Location"), N_("Identifies the location within a city from which the object data " "originates, according to guidelines established by the provider."), false, false, 0, 32, Exiv2::string, IptcDataSets::application2, ""), DataSet(IptcDataSets::ProvinceState, "ProvinceState", N_("Province State"), N_("Identifies Province/State of origin according to guidelines " "established by the provider."), false, false, 0, 32, Exiv2::string, IptcDataSets::application2, N_("State/Province")), DataSet(IptcDataSets::CountryCode, "CountryCode", N_("Country Code"), N_("Indicates the code of the country/primary location where the " "intellectual property of the object data was created, e.g. a photo " "was taken, an event occurred. Where ISO has established an appropriate " "country code under ISO 3166, that code will be used. When ISO 3166 does not " "adequately provide for identification of a location or a new " "country, e.g. ships at sea, space, IPTC will assign an " "appropriate three-character code under the provisions of " "ISO 3166 to avoid conflicts."), false, false, 3, 3, Exiv2::string, IptcDataSets::application2, ""), DataSet(IptcDataSets::CountryName, "CountryName", N_("Country Name"), N_("Provides full, publishable, name of the country/primary location " "where the intellectual property of the object data was created, " "according to guidelines of the provider."), false, false, 0, 64, Exiv2::string, IptcDataSets::application2, N_("Country")), DataSet(IptcDataSets::TransmissionReference, "TransmissionReference", N_("Transmission Reference"), N_("A code representing the location of original transmission according " "to practices of the provider."), false, false, 0, 32, Exiv2::string, IptcDataSets::application2, N_("Transmission Reference")), DataSet(IptcDataSets::Headline, "Headline", N_("Headline"), N_("A publishable entry providing a synopsis of the contents of the object data."), false, false, 0, 256, Exiv2::string, IptcDataSets::application2, N_("Headline")), DataSet(IptcDataSets::Credit, "Credit", N_("Credit"), N_("Identifies the provider of the object data, not necessarily the owner/creator."), false, false, 0, 32, Exiv2::string, IptcDataSets::application2, N_("Credit")), DataSet(IptcDataSets::Source, "Source", N_("Source"), N_("Identifies the original owner of the intellectual content of the " "object data. This could be an agency, a member of an agency or an individual."), false, false, 0, 32, Exiv2::string, IptcDataSets::application2, N_("Source")), DataSet(IptcDataSets::Copyright, "Copyright", N_("Copyright"), N_("Contains any necessary copyright notice."), false, false, 0, 128, Exiv2::string, IptcDataSets::application2, N_("Copyright Notice")), DataSet(IptcDataSets::Contact, "Contact", N_("Contact"), N_("Identifies the person or organisation which can provide further " "background information on the object data."), false, true, 0, 128, Exiv2::string, IptcDataSets::application2, ""), DataSet(IptcDataSets::Caption, "Caption", N_("Caption"), N_("A textual description of the object data."), false, false, 0, 2000, Exiv2::string, IptcDataSets::application2, N_("Description")), DataSet(IptcDataSets::Writer, "Writer", N_("Writer"), N_("Identification of the name of the person involved in the writing, " "editing or correcting the object data or caption/abstract."), false, true, 0, 32, Exiv2::string, IptcDataSets::application2, "Description writer"), DataSet(IptcDataSets::RasterizedCaption, "RasterizedCaption", N_("Rasterized Caption"), N_("Contains the rasterized object data description and is used " "where characters that have not been coded are required for the caption."), false, false, 7360, 7360, Exiv2::undefined, IptcDataSets::application2, ""), DataSet(IptcDataSets::ImageType, "ImageType", N_("Image Type"), N_("Indicates the color components of an image."), false, false, 2, 2, Exiv2::string, IptcDataSets::application2, ""), DataSet(IptcDataSets::ImageOrientation, "ImageOrientation", N_("Image Orientation"), N_("Indicates the layout of an image."), false, false, 1, 1, Exiv2::string, IptcDataSets::application2, ""), DataSet(IptcDataSets::Language, "Language", N_("Language"), N_("Describes the major national language of the object, according " "to the 2-letter codes of ISO 639:1988. Does not define or imply " "any coded character set, but is used for internal routing, e.g. to " "various editorial desks."), false, false, 2, 3, Exiv2::string, IptcDataSets::application2, ""), DataSet(IptcDataSets::AudioType, "AudioType", N_("Audio Type"), N_("Indicates the type of an audio content."), false, false, 2, 2, Exiv2::string, IptcDataSets::application2, ""), DataSet(IptcDataSets::AudioRate, "AudioRate", N_("Audio Rate"), N_("Indicates the sampling rate in Hertz of an audio content."), false, false, 6, 6, Exiv2::string, IptcDataSets::application2, ""), DataSet(IptcDataSets::AudioResolution, "AudioResolution", N_("Audio Resolution"), N_("Indicates the sampling resolution of an audio content."), false, false, 2, 2, Exiv2::string, IptcDataSets::application2, ""), DataSet(IptcDataSets::AudioDuration, "AudioDuration", N_("Audio Duration"), N_("Indicates the duration of an audio content."), false, false, 6, 6, Exiv2::string, IptcDataSets::application2, ""), DataSet(IptcDataSets::AudioOutcue, "AudioOutcue", N_("Audio Outcue"), N_("Identifies the content of the end of an audio object data, " "according to guidelines established by the provider."), false, false, 0, 64, Exiv2::string, IptcDataSets::application2, ""), DataSet(IptcDataSets::PreviewFormat, "PreviewFormat", N_("Preview Format"), N_("A binary number representing the file format of the object data " "preview. The file format must be registered with IPTC or NAA organizations " "with a unique number assigned to it."), false, false, 2, 2, Exiv2::unsignedShort, IptcDataSets::application2, ""), DataSet(IptcDataSets::PreviewVersion, "PreviewVersion", N_("Preview Version"), N_("A binary number representing the particular version of the " "object data preview file format specified in tag ."), false, false, 2, 2, Exiv2::unsignedShort, IptcDataSets::application2, ""), DataSet(IptcDataSets::Preview, "Preview", N_("Preview Data"), N_("Binary image preview data."), false, false, 0, 256000, Exiv2::undefined, IptcDataSets::application2, ""), DataSet(0xffff, "(Invalid)", N_("(Invalid)"), N_("(Invalid)"), false, false, 0, 0, Exiv2::unsignedShort, IptcDataSets::application2, "") }; const DataSet* IptcDataSets::application2RecordList() { return application2Record; } static const DataSet unknownDataSet(0xffff, "Unknown dataset", N_("Unknown dataset"), N_("Unknown dataset"), false, true, 0, 0xffffffff, Exiv2::string, IptcDataSets::invalidRecord, N_("Unknown dataset")); // Dataset lookup lists.This is an array with pointers to one list per IIM4 Record. // The record id is used as the index into the array. const DataSet* IptcDataSets::records_[] = { 0, envelopeRecord, application2Record, 0 }; int IptcDataSets::dataSetIdx(uint16_t number, uint16_t recordId) { if( recordId != envelope && recordId != application2 ) return -1; const DataSet* dataSet = records_[recordId]; if (dataSet == 0) return -1; int idx; for (idx = 0; dataSet[idx].number_ != number; ++idx) { if (dataSet[idx].number_ == 0xffff) return -1; } return idx; } int IptcDataSets::dataSetIdx(const std::string& dataSetName, uint16_t recordId) { if( recordId != envelope && recordId != application2 ) return -1; const DataSet* dataSet = records_[recordId]; if (dataSet == 0) return -1; int idx; for (idx = 0; dataSet[idx].name_ != dataSetName; ++idx) { if (dataSet[idx].number_ == 0xffff) return -1; } return idx; } TypeId IptcDataSets::dataSetType(uint16_t number, uint16_t recordId) { int idx = dataSetIdx(number, recordId); if (idx == -1) return unknownDataSet.type_; return records_[recordId][idx].type_; } std::string IptcDataSets::dataSetName(uint16_t number, uint16_t recordId) { int idx = dataSetIdx(number, recordId); if (idx != -1) return records_[recordId][idx].name_; std::ostringstream os; os << "0x" << std::setw(4) << std::setfill('0') << std::right << std::hex << number; return os.str(); } const char* IptcDataSets::dataSetTitle(uint16_t number, uint16_t recordId) { int idx = dataSetIdx(number, recordId); if (idx == -1) return unknownDataSet.title_; return records_[recordId][idx].title_; } const char* IptcDataSets::dataSetDesc(uint16_t number, uint16_t recordId) { int idx = dataSetIdx(number, recordId); if (idx == -1) return unknownDataSet.desc_; return records_[recordId][idx].desc_; } const char* IptcDataSets::dataSetPsName(uint16_t number, uint16_t recordId) { int idx = dataSetIdx(number, recordId); if (idx == -1) return unknownDataSet.photoshop_; return records_[recordId][idx].photoshop_; } bool IptcDataSets::dataSetRepeatable(uint16_t number, uint16_t recordId) { int idx = dataSetIdx(number, recordId); if (idx == -1) return unknownDataSet.repeatable_; return records_[recordId][idx].repeatable_; } uint16_t IptcDataSets::dataSet(const std::string& dataSetName, uint16_t recordId) { uint16_t dataSet; int idx = dataSetIdx(dataSetName, recordId); if (idx != -1) { // dataSetIdx checks the range of recordId dataSet = records_[recordId][idx].number_; } else { if (!isHex(dataSetName, 4, "0x")) throw Error(4, dataSetName); std::istringstream is(dataSetName); is >> std::hex >> dataSet; } return dataSet; } std::string IptcDataSets::recordName(uint16_t recordId) { if (recordId == envelope || recordId == application2) { return recordInfo_[recordId].name_; } std::ostringstream os; os << "0x" << std::setw(4) << std::setfill('0') << std::right << std::hex << recordId; return os.str(); } const char* IptcDataSets::recordDesc(uint16_t recordId) { if (recordId != envelope && recordId != application2) { return unknownDataSet.desc_; } return recordInfo_[recordId].desc_; } uint16_t IptcDataSets::recordId(const std::string& recordName) { uint16_t i; for (i = application2; i > 0; --i) { if (recordInfo_[i].name_ == recordName) break; } if (i == 0) { if (!isHex(recordName, 4, "0x")) throw Error(5, recordName); std::istringstream is(recordName); is >> std::hex >> i; } return i; } void IptcDataSets::dataSetList(std::ostream& os) { const int count = sizeof(records_)/sizeof(records_[0]); for (int i=0; i < count; ++i) { const DataSet *record = records_[i]; for (int j=0; record != 0 && record[j].number_ != 0xffff; ++j) { os << record[j] << "\n"; } } } // IptcDataSets::dataSetList const char* IptcKey::familyName_ = "Iptc"; IptcKey::IptcKey(const std::string& key) : key_(key) { decomposeKey(); } IptcKey::IptcKey(uint16_t tag, uint16_t record) : tag_(tag), record_(record) { makeKey(); } IptcKey::IptcKey(const IptcKey& rhs) : Key(rhs), tag_(rhs.tag_), record_(rhs.record_), key_(rhs.key_) { } IptcKey::~IptcKey() { } IptcKey& IptcKey::operator=(const IptcKey& rhs) { if (this == &rhs) return *this; Key::operator=(rhs); tag_ = rhs.tag_; record_ = rhs.record_; key_ = rhs.key_; return *this; } std::string IptcKey::key() const { return key_; } const char* IptcKey::familyName() const { return familyName_; } std::string IptcKey::groupName() const { return recordName(); } std::string IptcKey::tagName() const { return IptcDataSets::dataSetName(tag_, record_); } std::string IptcKey::tagLabel() const { return IptcDataSets::dataSetTitle(tag_, record_); } uint16_t IptcKey::tag() const { return tag_; } std::string IptcKey::recordName() const { return IptcDataSets::recordName(record_); } uint16_t IptcKey::record() const { return record_; } IptcKey::AutoPtr IptcKey::clone() const { return AutoPtr(clone_()); } IptcKey* IptcKey::clone_() const { return new IptcKey(*this); } void IptcKey::decomposeKey() { // Get the family name, record name and dataSet name parts of the key std::string::size_type pos1 = key_.find('.'); if (pos1 == std::string::npos) throw Error(6, key_); std::string familyName = key_.substr(0, pos1); if (0 != strcmp(familyName.c_str(), familyName_)) { throw Error(6, key_); } std::string::size_type pos0 = pos1 + 1; pos1 = key_.find('.', pos0); if (pos1 == std::string::npos) throw Error(6, key_); std::string recordName = key_.substr(pos0, pos1 - pos0); if (recordName == "") throw Error(6, key_); std::string dataSetName = key_.substr(pos1 + 1); if (dataSetName == "") throw Error(6, key_); // Use the parts of the key to find dataSet and recordId uint16_t recId = IptcDataSets::recordId(recordName); uint16_t dataSet = IptcDataSets::dataSet(dataSetName, recId); // Possibly translate hex name parts (0xabcd) to real names recordName = IptcDataSets::recordName(recId); dataSetName = IptcDataSets::dataSetName(dataSet, recId); tag_ = dataSet; record_ = recId; key_ = familyName + "." + recordName + "." + dataSetName; } // IptcKey::decomposeKey void IptcKey::makeKey() { key_ = std::string(familyName_) + "." + IptcDataSets::recordName(record_) + "." + IptcDataSets::dataSetName(tag_, record_); } // ************************************************************************* // free functions std::ostream& operator<<(std::ostream& os, const DataSet& dataSet) { IptcKey iptcKey(dataSet.number_, dataSet.recordId_); return os << dataSet.name_ << ", " << std::dec << dataSet.number_ << ", " << "0x" << std::setw(4) << std::setfill('0') << std::right << std::hex << dataSet.number_ << ", " << IptcDataSets::recordName(dataSet.recordId_) << ", " << std::boolalpha << dataSet.mandatory_ << ", " << dataSet.repeatable_ << ", " << std::dec << dataSet.minbytes_ << ", " << dataSet.maxbytes_ << ", " << iptcKey.key() << ", " << TypeInfo::typeName( IptcDataSets::dataSetType(dataSet.number_, dataSet.recordId_)) << ", " << dataSet.desc_; } } // namespace Exiv2 exiv2-0.23/src/types.hpp0000644000175000017500000005215011732641407014763 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! @file types.hpp @brief Type definitions for %Exiv2 and related functionality @version $Rev: 2681 $ @author Andreas Huggel (ahu) ahuggel@gmx.net @date 09-Jan-04, ahu: created
11-Feb-04, ahu: isolated as a component
31-Jul-04, brad: added Time, Data and String values */ #ifndef TYPES_HPP_ #define TYPES_HPP_ // ***************************************************************************** // included header files #ifdef _MSC_VER # include "exv_msvc.h" #else # include "exv_conf.h" #endif #include "version.hpp" // + standard includes #include #include #include #include #include #include #ifdef EXV_HAVE_STDINT_H # include #elif defined(_MSC_VER) // MSVC (before 2010) doesn't provide C99 types, but it has MS specific variants typedef unsigned __int8 uint8_t; typedef unsigned __int16 uint16_t; typedef unsigned __int32 uint32_t; typedef unsigned __int64 uint64_t; typedef __int8 int8_t; typedef __int16 int16_t; typedef __int32 int32_t; typedef __int64 int64_t; #endif // MSVC macro to convert a string to a wide string #ifdef EXV_UNICODE_PATH # define EXV_WIDEN(t) L ## t #endif /*! @brief Macro to make calls to member functions through a pointer more readable. See the C++ FAQ LITE, item [33.5] How can I avoid syntax errors when calling a member function using a pointer-to-member-function?. */ #define EXV_CALL_MEMBER_FN(object,ptrToMember) ((object).*(ptrToMember)) // Simple min and max macros //! Simple common min macro #define EXV_MIN(a,b) ((a) < (b) ? (a) : (b)) //! Simple common max macro #define EXV_MAX(a,b) ((a) > (b) ? (a) : (b)) // ***************************************************************************** // forward declarations struct tm; // ***************************************************************************** // namespace extensions namespace Exiv2 { // ***************************************************************************** // type definitions //! 1 byte unsigned integer type. typedef uint8_t byte; //! 8 byte unsigned rational type. typedef std::pair URational; //! 8 byte signed rational type. typedef std::pair Rational; //! Type to express the byte order (little or big endian) enum ByteOrder { invalidByteOrder, littleEndian, bigEndian }; //! Type to indicate write method used by TIFF parsers enum WriteMethod { wmIntrusive, wmNonIntrusive }; //! An identifier for each type of metadata enum MetadataId { mdNone=0, mdExif=1, mdIptc=2, mdComment=4, mdXmp=8 }; //! An identifier for each mode of metadata support enum AccessMode { amNone=0, amRead=1, amWrite=2, amReadWrite=3 }; /*! @brief %Exiv2 value type identifiers. Used primarily as identifiers when creating %Exiv2 Value instances. See Value::create. 0x0000 to 0xffff are reserved for TIFF (Exif) types. */ enum TypeId { unsignedByte = 1, //!< Exif BYTE type, 8-bit unsigned integer. asciiString = 2, //!< Exif ASCII type, 8-bit byte. unsignedShort = 3, //!< Exif SHORT type, 16-bit (2-byte) unsigned integer. unsignedLong = 4, //!< Exif LONG type, 32-bit (4-byte) unsigned integer. unsignedRational = 5, //!< Exif RATIONAL type, two LONGs: numerator and denumerator of a fraction. signedByte = 6, //!< Exif SBYTE type, an 8-bit signed (twos-complement) integer. undefined = 7, //!< Exif UNDEFINED type, an 8-bit byte that may contain anything. signedShort = 8, //!< Exif SSHORT type, a 16-bit (2-byte) signed (twos-complement) integer. signedLong = 9, //!< Exif SLONG type, a 32-bit (4-byte) signed (twos-complement) integer. signedRational =10, //!< Exif SRATIONAL type, two SLONGs: numerator and denumerator of a fraction. tiffFloat =11, //!< TIFF FLOAT type, single precision (4-byte) IEEE format. tiffDouble =12, //!< TIFF DOUBLE type, double precision (8-byte) IEEE format. tiffIfd =13, //!< TIFF IFD type, 32-bit (4-byte) unsigned integer. string =0x10000, //!< IPTC string type. date =0x10001, //!< IPTC date type. time =0x10002, //!< IPTC time type. comment =0x10003, //!< %Exiv2 type for the Exif user comment. directory =0x10004, //!< %Exiv2 type for a CIFF directory. xmpText =0x10005, //!< XMP text type. xmpAlt =0x10006, //!< XMP alternative type. xmpBag =0x10007, //!< XMP bag type. xmpSeq =0x10008, //!< XMP sequence type. langAlt =0x10009, //!< XMP language alternative type. invalidTypeId =0x1fffe, //!< Invalid type id. lastTypeId =0x1ffff //!< Last type id. }; //! Container for binary data typedef std::vector Blob; // ***************************************************************************** // class definitions //! Type information lookup functions. Implemented as a static class. class EXIV2API TypeInfo { //! Prevent construction: not implemented. TypeInfo(); //! Prevent copy-construction: not implemented. TypeInfo(const TypeInfo& rhs); //! Prevent assignment: not implemented. TypeInfo& operator=(const TypeInfo& rhs); public: //! Return the name of the type, 0 if unknown. static const char* typeName(TypeId typeId); //! Return the type id for a type name static TypeId typeId(const std::string& typeName); //! Return the size in bytes of one element of this type static long typeSize(TypeId typeId); }; /*! @brief Auxiliary type to enable copies and assignments, similar to std::auto_ptr_ref. See http://www.josuttis.com/libbook/auto_ptr.html for a discussion. */ struct EXIV2API DataBufRef { //! Constructor DataBufRef(std::pair rhs) : p(rhs) {} //! Pointer to a byte array and its size std::pair p; }; /*! @brief Utility class containing a character array. All it does is to take care of memory allocation and deletion. Its primary use is meant to be as a stack variable in functions that need a temporary data buffer. */ class EXIV2API DataBuf { public: //! @name Creators //@{ //! Default constructor DataBuf() : pData_(0), size_(0) {} //! Constructor with an initial buffer size explicit DataBuf(long size) : pData_(new byte[size]), size_(size) {} //! Constructor, copies an existing buffer DataBuf(const byte* pData, long size); /*! @brief Copy constructor. Transfers the buffer to the newly created object similar to std::auto_ptr, i.e., the original object is modified. */ DataBuf(DataBuf& rhs); //! Destructor, deletes the allocated buffer ~DataBuf() { delete[] pData_; } //@} //! @name Manipulators //@{ /*! @brief Assignment operator. Transfers the buffer and releases the buffer at the original object similar to std::auto_ptr, i.e., the original object is modified. */ DataBuf& operator=(DataBuf& rhs); /*! @brief Allocate a data buffer of at least the given size. Note that if the requested \em size is less than the current buffer size, no new memory is allocated and the buffer size doesn't change. */ void alloc(long size); /*! @brief Release ownership of the buffer to the caller. Returns the buffer as a data pointer and size pair, resets the internal buffer. */ std::pair release(); //! Reset value void reset(std::pair =std::make_pair((byte*)(0),long(0))); //@} /*! @name Conversions Special conversions with auxiliary type to enable copies and assignments, similar to those used for std::auto_ptr. See http://www.josuttis.com/libbook/auto_ptr.html for a discussion. */ //@{ DataBuf(DataBufRef rhs) : pData_(rhs.p.first), size_(rhs.p.second) {} DataBuf& operator=(DataBufRef rhs) { reset(rhs.p); return *this; } operator DataBufRef() { return DataBufRef(release()); } //@} // DATA //! Pointer to the buffer, 0 if none has been allocated byte* pData_; //! The current size of the buffer long size_; }; // class DataBuf // ***************************************************************************** // free functions //! Read a 2 byte unsigned short value from the data buffer EXIV2API uint16_t getUShort(const byte* buf, ByteOrder byteOrder); //! Read a 4 byte unsigned long value from the data buffer EXIV2API uint32_t getULong(const byte* buf, ByteOrder byteOrder); //! Read an 8 byte unsigned rational value from the data buffer EXIV2API URational getURational(const byte* buf, ByteOrder byteOrder); //! Read a 2 byte signed short value from the data buffer EXIV2API int16_t getShort(const byte* buf, ByteOrder byteOrder); //! Read a 4 byte signed long value from the data buffer EXIV2API int32_t getLong(const byte* buf, ByteOrder byteOrder); //! Read an 8 byte signed rational value from the data buffer EXIV2API Rational getRational(const byte* buf, ByteOrder byteOrder); //! Read a 4 byte single precision floating point value (IEEE 754 binary32) from the data buffer EXIV2API float getFloat(const byte* buf, ByteOrder byteOrder); //! Read an 8 byte double precision floating point value (IEEE 754 binary64) from the data buffer EXIV2API double getDouble(const byte* buf, ByteOrder byteOrder); //! Output operator for our fake rational EXIV2API std::ostream& operator<<(std::ostream& os, const Rational& r); //! Input operator for our fake rational EXIV2API std::istream& operator>>(std::istream& is, Rational& r); //! Output operator for our fake unsigned rational EXIV2API std::ostream& operator<<(std::ostream& os, const URational& r); //! Input operator for our fake unsigned rational EXIV2API std::istream& operator>>(std::istream& is, URational& r); /*! @brief Convert an unsigned short to data, write the data to the buffer, return number of bytes written. */ EXIV2API long us2Data(byte* buf, uint16_t s, ByteOrder byteOrder); /*! @brief Convert an unsigned long to data, write the data to the buffer, return number of bytes written. */ EXIV2API long ul2Data(byte* buf, uint32_t l, ByteOrder byteOrder); /*! @brief Convert an unsigned rational to data, write the data to the buffer, return number of bytes written. */ EXIV2API long ur2Data(byte* buf, URational l, ByteOrder byteOrder); /*! @brief Convert a signed short to data, write the data to the buffer, return number of bytes written. */ EXIV2API long s2Data(byte* buf, int16_t s, ByteOrder byteOrder); /*! @brief Convert a signed long to data, write the data to the buffer, return number of bytes written. */ EXIV2API long l2Data(byte* buf, int32_t l, ByteOrder byteOrder); /*! @brief Convert a signed rational to data, write the data to the buffer, return number of bytes written. */ EXIV2API long r2Data(byte* buf, Rational l, ByteOrder byteOrder); /*! @brief Convert a single precision floating point (IEEE 754 binary32) float to data, write the data to the buffer, return number of bytes written. */ EXIV2API long f2Data(byte* buf, float f, ByteOrder byteOrder); /*! @brief Convert a double precision floating point (IEEE 754 binary64) double to data, write the data to the buffer, return number of bytes written. */ EXIV2API long d2Data(byte* buf, double d, ByteOrder byteOrder); /*! @brief Print len bytes from buf in hex and ASCII format to the given stream, prefixed with the position in the buffer adjusted by offset. */ EXIV2API void hexdump(std::ostream& os, const byte* buf, long len, long offset =0); /*! @brief Return true if str is a hex number starting with prefix followed by size hex digits, false otherwise. If size is 0, any number of digits is allowed and all are checked. */ EXIV2API bool isHex(const std::string& str, size_t size =0, const std::string& prefix =""); /*! @brief Converts a string in the form "%Y:%m:%d %H:%M:%S", e.g., "2007:05:24 12:31:55" to broken down time format, returns 0 if successful, else 1. */ EXIV2API int exifTime(const char* buf, struct tm* tm); /*! @brief Translate a string using the gettext framework. This wrapper hides all the implementation details from the interface. */ EXIV2API const char* exvGettext(const char* str); #ifdef EXV_UNICODE_PATH //! Convert an std::string s to a unicode string returned as a std::wstring. EXIV2API std::wstring s2ws(const std::string& s); //! Convert a unicode std::wstring s to an std::string. EXIV2API std::string ws2s(const std::wstring& s); #endif /*! @brief Return a \em long set to the value represented by \em s. Besides strings that represent \em long values, the function also handles \em float, \em Rational and boolean (see also: stringTo(const std::string& s, bool& ok)). @param s String to parse @param ok Output variable indicating the success of the operation. @return Returns the \em long value represented by \em s and sets \em ok to \c true if the conversion was successful or \c false if not. */ EXIV2API long parseLong(const std::string& s, bool& ok); /*! @brief Return a \em float set to the value represented by \em s. Besides strings that represent \em float values, the function also handles \em long, \em Rational and boolean (see also: stringTo(const std::string& s, bool& ok)). @param s String to parse @param ok Output variable indicating the success of the operation. @return Returns the \em float value represented by \em s and sets \em ok to \c true if the conversion was successful or \c false if not. */ EXIV2API float parseFloat(const std::string& s, bool& ok); /*! @brief Return a \em Rational set to the value represented by \em s. Besides strings that represent \em Rational values, the function also handles \em long, \em float and boolean (see also: stringTo(const std::string& s, bool& ok)). Uses floatToRationalCast(float f) if the string can be parsed into a \em float. @param s String to parse @param ok Output variable indicating the success of the operation. @return Returns the \em Rational value represented by \em s and sets \em ok to \c true if the conversion was successful or \c false if not. */ EXIV2API Rational parseRational(const std::string& s, bool& ok); /*! @brief Very simple conversion of a \em float to a \em Rational. Test it with the values that you expect and check the implementation to see if this is really what you want! */ EXIV2API Rational floatToRationalCast(float f); // ***************************************************************************** // template and inline definitions /*! @brief Find an element that matches \em key in the array \em src. Designed to be used with lookup tables as shown in the example below. Requires a %Key structure (ideally in the array) and a comparison operator to compare a key with an array element. The size of the array is determined automagically. Thanks to Stephan Broennimann for this nifty implementation. @code struct Bar { int i; int k; const char* data; struct Key; bool operator==(const Bar::Key& rhs) const; }; struct Bar::Key { Key(int a, int b) : i(a), k(b) {} int i; int k; }; bool Bar::operator==(const Bar::Key& key) const // definition { return i == key.i && k == key.k; } const Bar bars[] = { { 1, 1, "bar data 1" }, { 1, 2, "bar data 2" }, { 1, 3, "bar data 3" } }; int main ( void ) { const Bar* bar = find(bars, Bar::Key(1, 3)); if (bar) std::cout << bar->data << "\n"; else std::cout << "Key not found.\n"; return 0; } @endcode */ template const T* find(T (&src)[N], const K& key) { const T* rc = std::find(src, src + N, key); return rc == src + N ? 0 : rc; } //! Template used in the COUNTOF macro to determine the size of an array template char (&sizer(T (&)[N]))[N]; //! Macro to determine the size of an array #define EXV_COUNTOF(a) (sizeof(Exiv2::sizer(a))) //! Utility function to convert the argument of any type to a string template std::string toString(const T& arg) { std::ostringstream os; os << arg; return os.str(); } /*! @brief Utility function to convert a string to a value of type \c T. The string representation of the value must match that recognized by the input operator for \c T for this function to succeed. @param s String to convert @param ok Output variable indicating the success of the operation. @return Returns the converted value and sets \em ok to \c true if the conversion was successful or \c false if not. */ template T stringTo(const std::string& s, bool& ok) { std::istringstream is(s); T tmp; ok = is >> tmp ? true : false; std::string rest; is >> std::skipws >> rest; if (!rest.empty()) ok = false; return tmp; } /*! @brief Specialization of stringTo(const std::string& s, bool& ok) for \em bool. Handles the same string values as the XMP SDK. Converts the string to lowercase and returns \c true if it is "true", "t" or "1", and \c false if it is "false", "f" or "0". */ template<> bool stringTo(const std::string& s, bool& ok); /*! @brief Return the greatest common denominator of n and m. (Implementation from Boost rational.hpp) @note We use n and m as temporaries in this function, so there is no value in using const IntType& as we would only need to make a copy anyway... */ template IntType gcd(IntType n, IntType m) { // Avoid repeated construction IntType zero(0); // This is abs() - given the existence of broken compilers with Koenig // lookup issues and other problems, I code this explicitly. (Remember, // IntType may be a user-defined type). #ifdef _MSC_VER #pragma warning( disable : 4146 ) #endif if (n < zero) n = -n; if (m < zero) m = -m; #ifdef _MSC_VER #pragma warning( default : 4146 ) #endif // As n and m are now positive, we can be sure that %= returns a // positive value (the standard guarantees this for built-in types, // and we require it of user-defined types). for(;;) { if(m == zero) return n; n %= m; if(n == zero) return m; m %= n; } } } // namespace Exiv2 #endif // #ifndef TYPES_HPP_ exiv2-0.23/src/rafimage.cpp0000644000175000017500000001226511732641407015370 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /* File: rafimage.cpp Version: $Rev: 2681 $ Author(s): Andreas Huggel (ahu) History: 05-Feb-07, ahu: created Credits: See header file */ // ***************************************************************************** #include "rcsid_int.hpp" EXIV2_RCSID("@(#) $Id: rafimage.cpp 2681 2012-03-22 15:19:35Z ahuggel $") // ***************************************************************************** // included header files #ifdef _MSC_VER # include "exv_msvc.h" #else # include "exv_conf.h" #endif #include "rafimage.hpp" #include "tiffimage.hpp" #include "image.hpp" #include "basicio.hpp" #include "error.hpp" #include "futils.hpp" // + standard includes #include #include #include #include // ***************************************************************************** // class member definitions namespace Exiv2 { RafImage::RafImage(BasicIo::AutoPtr io, bool /*create*/) : Image(ImageType::raf, mdExif | mdIptc | mdXmp, io) { } // RafImage::RafImage std::string RafImage::mimeType() const { return "image/x-fuji-raf"; } int RafImage::pixelWidth() const { Exiv2::ExifData::const_iterator widthIter = exifData_.findKey(Exiv2::ExifKey("Exif.Photo.PixelXDimension")); if (widthIter != exifData_.end() && widthIter->count() > 0) { return widthIter->toLong(); } return 0; } int RafImage::pixelHeight() const { Exiv2::ExifData::const_iterator heightIter = exifData_.findKey(Exiv2::ExifKey("Exif.Photo.PixelYDimension")); if (heightIter != exifData_.end() && heightIter->count() > 0) { return heightIter->toLong(); } return 0; } void RafImage::setExifData(const ExifData& /*exifData*/) { // Todo: implement me! throw(Error(32, "Exif metadata", "RAF")); } void RafImage::setIptcData(const IptcData& /*iptcData*/) { // Todo: implement me! throw(Error(32, "IPTC metadata", "RAF")); } void RafImage::setComment(const std::string& /*comment*/) { // not supported throw(Error(32, "Image comment", "RAF")); } void RafImage::readMetadata() { #ifdef DEBUG std::cerr << "Reading RAF file " << io_->path() << "\n"; #endif if (io_->open() != 0) throw Error(9, io_->path(), strError()); IoCloser closer(*io_); // Ensure that this is the correct image type if (!isRafType(*io_, false)) { if (io_->error() || io_->eof()) throw Error(14); throw Error(3, "RAF"); } byte const* pData = io_->mmap(); long size = io_->size(); if (size < 88 + 4) throw Error(14); // includes the test for -1 uint32_t const start = getULong(pData + 84, bigEndian) + 12; if (static_cast(size) < start) throw Error(14); clearMetadata(); ByteOrder bo = TiffParser::decode(exifData_, iptcData_, xmpData_, pData + start, size - start); exifData_["Exif.Image2.JPEGInterchangeFormat"] = getULong(pData + 84, bigEndian); exifData_["Exif.Image2.JPEGInterchangeFormatLength"] = getULong(pData + 88, bigEndian); setByteOrder(bo); } // RafImage::readMetadata void RafImage::writeMetadata() { //! Todo: implement me! throw(Error(31, "RAF")); } // RafImage::writeMetadata // ************************************************************************* // free functions Image::AutoPtr newRafInstance(BasicIo::AutoPtr io, bool create) { Image::AutoPtr image(new RafImage(io, create)); if (!image->good()) { image.reset(); } return image; } bool isRafType(BasicIo& iIo, bool advance) { const int32_t len = 8; byte buf[len]; iIo.read(buf, len); if (iIo.error() || iIo.eof()) { return false; } int rc = memcmp(buf, "FUJIFILM", 8); if (!advance || rc != 0) { iIo.seek(-len, BasicIo::cur); } return rc == 0; } } // namespace Exiv2 exiv2-0.23/src/basicio.hpp0000644000175000017500000007076411732641407015243 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! @file basicio.hpp @brief Simple binary IO abstraction @version $Rev: 2681 $ @author Brad Schick (brad) brad@robotbattle.com @date 04-Dec-04, brad: created */ #ifndef BASICIO_HPP_ #define BASICIO_HPP_ // ***************************************************************************** // included header files #include "types.hpp" // + standard includes #include #include // for std::auto_ptr // ***************************************************************************** // namespace extensions namespace Exiv2 { // ***************************************************************************** // class definitions /*! @brief An interface for simple binary IO. Designed to have semantics and names similar to those of C style FILE* operations. Subclasses should all behave the same so that they can be interchanged. */ class EXIV2API BasicIo { public: //! BasicIo auto_ptr type typedef std::auto_ptr AutoPtr; //! Seek starting positions enum Position { beg, cur, end }; //! @name Creators //@{ //! Destructor virtual ~BasicIo(); //@} //! @name Manipulators //@{ /*! @brief Open the IO source using the default access mode. The default mode should allow for reading and writing. This method can also be used to "reopen" an IO source which will flush any unwritten data and reset the IO position to the start. Subclasses may provide custom methods to allow for opening IO sources differently. @return 0 if successful;
Nonzero if failure. */ virtual int open() = 0; /*! @brief Close the IO source. After closing a BasicIo instance can not be read or written. Closing flushes any unwritten data. It is safe to call close on a closed instance. @return 0 if successful;
Nonzero if failure. */ virtual int close() = 0; /*! @brief Write data to the IO source. Current IO position is advanced by the number of bytes written. @param data Pointer to data. Data must be at least \em wcount bytes long @param wcount Number of bytes to be written. @return Number of bytes written to IO source successfully;
0 if failure; */ virtual long write(const byte* data, long wcount) = 0; /*! @brief Write data that is read from another BasicIo instance to the IO source. Current IO position is advanced by the number of bytes written. @param src Reference to another BasicIo instance. Reading start at the source's current IO position @return Number of bytes written to IO source successfully;
0 if failure; */ virtual long write(BasicIo& src) = 0; /*! @brief Write one byte to the IO source. Current IO position is advanced by one byte. @param data The single byte to be written. @return The value of the byte written if successful;
EOF if failure; */ virtual int putb(byte data) = 0; /*! @brief Read data from the IO source. Reading starts at the current IO position and the position is advanced by the number of bytes read. @param rcount Maximum number of bytes to read. Fewer bytes may be read if \em rcount bytes are not available. @return DataBuf instance containing the bytes read. Use the DataBuf::size_ member to find the number of bytes read. DataBuf::size_ will be 0 on failure. */ virtual DataBuf read(long rcount) = 0; /*! @brief Read data from the IO source. Reading starts at the current IO position and the position is advanced by the number of bytes read. @param buf Pointer to a block of memory into which the read data is stored. The memory block must be at least \em rcount bytes long. @param rcount Maximum number of bytes to read. Fewer bytes may be read if \em rcount bytes are not available. @return Number of bytes read from IO source successfully;
0 if failure; */ virtual long read(byte* buf, long rcount) = 0; /*! @brief Read one byte from the IO source. Current IO position is advanced by one byte. @return The byte read from the IO source if successful;
EOF if failure; */ virtual int getb() = 0; /*! @brief Remove all data from this object's IO source and then transfer data from the \em src BasicIo object into this object. The source object is invalidated by this operation and should not be used after this method returns. This method exists primarily to be used with the BasicIo::temporary() method. @param src Reference to another BasicIo instance. The entire contents of src are transferred to this object. The \em src object is invalidated by the method. @throw Error In case of failure */ virtual void transfer(BasicIo& src) = 0; /*! @brief Move the current IO position. @param offset Number of bytes to move the position relative to the starting position specified by \em pos @param pos Position from which the seek should start @return 0 if successful;
Nonzero if failure; */ virtual int seek(long offset, Position pos) = 0; /*! @brief Direct access to the IO data. For files, this is done by mapping the file into the process's address space; for memory blocks, this allows direct access to the memory block. @param isWriteable Set to true if the mapped area should be writeable (default is false). @return A pointer to the mapped area. @throw Error In case of failure. */ virtual byte* mmap(bool isWriteable =false) =0; /*! @brief Remove a mapping established with mmap(). If the mapped area is writeable, this ensures that changes are written back. @return 0 if successful;
Nonzero if failure; */ virtual int munmap() =0; //@} //! @name Accessors //@{ /*! @brief Get the current IO position. @return Offset from the start of IO if successful;
-1 if failure; */ virtual long tell() const = 0; /*! @brief Get the current size of the IO source in bytes. @return Size of the IO source in bytes;
-1 if failure; */ virtual long size() const = 0; //!Returns true if the IO source is open, otherwise false. virtual bool isopen() const = 0; //!Returns 0 if the IO source is in a valid state, otherwise nonzero. virtual int error() const = 0; //!Returns true if the IO position has reach the end, otherwise false. virtual bool eof() const = 0; /*! @brief Return the path to the IO resource. Often used to form comprehensive error messages where only a BasicIo instance is available. */ virtual std::string path() const =0; #ifdef EXV_UNICODE_PATH /*! @brief Like path() but returns a unicode path in an std::wstring. @note This function is only available on Windows. */ virtual std::wstring wpath() const =0; #endif /*! @brief Returns a temporary data storage location. This is often needed to rewrite an IO source. For example, data may be read from the original IO source, modified in some way, and then saved to the temporary instance. After the operation is complete, the BasicIo::transfer method can be used to replace the original IO source with the modified version. Subclasses are free to return any class that derives from BasicIo. @return An instance of BasicIo on success @throw Error In case of failure */ virtual BasicIo::AutoPtr temporary() const = 0; //@} protected: //! @name Creators //@{ //! Default Constructor BasicIo() {} //@} }; // class BasicIo /*! @brief Utility class that closes a BasicIo instance upon destruction. Meant to be used as a stack variable in functions that need to ensure BasicIo instances get closed. Useful when functions return errors from many locations. */ class EXIV2API IoCloser { public: //! @name Creators //@{ //! Constructor, takes a BasicIo reference IoCloser(BasicIo& bio) : bio_(bio) {} //! Destructor, closes the BasicIo reference ~IoCloser() { close(); } //@} //! @name Manipulators //@{ //! Close the BasicIo if it is open void close() { if (bio_.isopen()) bio_.close(); } //@} // DATA //! The BasicIo reference BasicIo& bio_; private: // Not implemented //! Copy constructor IoCloser(const IoCloser&); //! Assignment operator IoCloser& operator=(const IoCloser&); }; // class IoCloser /*! @brief Provides binary file IO by implementing the BasicIo interface. */ class EXIV2API FileIo : public BasicIo { public: //! @name Creators //@{ /*! @brief Constructor that accepts the file path on which IO will be performed. The constructor does not open the file, and therefore never failes. @param path The full path of a file */ FileIo(const std::string& path); #ifdef EXV_UNICODE_PATH /*! @brief Like FileIo(const std::string& path) but accepts a unicode path in an std::wstring. @note This constructor is only available on Windows. */ FileIo(const std::wstring& wpath); #endif //! Destructor. Flushes and closes an open file. virtual ~FileIo(); //@} //! @name Manipulators //@{ /*! @brief Open the file using using the specified mode. This method can also be used to "reopen" a file which will flush any unwritten data and reset the IO position to the start. Although files can be opened in binary or text mode, this class has only been tested carefully in binary mode. @param mode Specified that type of access allowed on the file. Valid values match those of the C fopen command exactly. @return 0 if successful;
Nonzero if failure. */ int open(const std::string& mode); /*! @brief Open the file using using the default access mode of "rb". This method can also be used to "reopen" a file which will flush any unwritten data and reset the IO position to the start. @return 0 if successful;
Nonzero if failure. */ virtual int open(); /*! @brief Flush and unwritten data and close the file . It is safe to call close on an already closed instance. @return 0 if successful;
Nonzero if failure; */ virtual int close(); /*! @brief Write data to the file. The file position is advanced by the number of bytes written. @param data Pointer to data. Data must be at least \em wcount bytes long @param wcount Number of bytes to be written. @return Number of bytes written to the file successfully;
0 if failure; */ virtual long write(const byte* data, long wcount); /*! @brief Write data that is read from another BasicIo instance to the file. The file position is advanced by the number of bytes written. @param src Reference to another BasicIo instance. Reading start at the source's current IO position @return Number of bytes written to the file successfully;
0 if failure; */ virtual long write(BasicIo& src); /*! @brief Write one byte to the file. The file position is advanced by one byte. @param data The single byte to be written. @return The value of the byte written if successful;
EOF if failure; */ virtual int putb(byte data); /*! @brief Read data from the file. Reading starts at the current file position and the position is advanced by the number of bytes read. @param rcount Maximum number of bytes to read. Fewer bytes may be read if \em rcount bytes are not available. @return DataBuf instance containing the bytes read. Use the DataBuf::size_ member to find the number of bytes read. DataBuf::size_ will be 0 on failure. */ virtual DataBuf read(long rcount); /*! @brief Read data from the file. Reading starts at the current file position and the position is advanced by the number of bytes read. @param buf Pointer to a block of memory into which the read data is stored. The memory block must be at least \em rcount bytes long. @param rcount Maximum number of bytes to read. Fewer bytes may be read if \em rcount bytes are not available. @return Number of bytes read from the file successfully;
0 if failure; */ virtual long read(byte* buf, long rcount); /*! @brief Read one byte from the file. The file position is advanced by one byte. @return The byte read from the file if successful;
EOF if failure; */ virtual int getb(); /*! @brief Remove the contents of the file and then transfer data from the \em src BasicIo object into the empty file. This method is optimized to simply rename the source file if the source object is another FileIo instance. The source BasicIo object is invalidated by this operation and should not be used after this method returns. This method exists primarily to be used with the BasicIo::temporary() method. @note If the caller doesn't have permissions to write to the file, an exception is raised and \em src is deleted. @param src Reference to another BasicIo instance. The entire contents of src are transferred to this object. The \em src object is invalidated by the method. @throw Error In case of failure */ virtual void transfer(BasicIo& src); /*! @brief Move the current file position. @param offset Number of bytes to move the file position relative to the starting position specified by \em pos @param pos Position from which the seek should start @return 0 if successful;
Nonzero if failure; */ virtual int seek(long offset, Position pos); /*! @brief Map the file into the process's address space. The file must be open before mmap() is called. If the mapped area is writeable, changes may not be written back to the underlying file until munmap() is called. The pointer is valid only as long as the FileIo object exists. @param isWriteable Set to true if the mapped area should be writeable (default is false). @return A pointer to the mapped area. @throw Error In case of failure. */ virtual byte* mmap(bool isWriteable =false); /*! @brief Remove a mapping established with mmap(). If the mapped area is writeable, this ensures that changes are written back to the underlying file. @return 0 if successful;
Nonzero if failure; */ virtual int munmap(); //@} //! @name Accessors //@{ /*! @brief Get the current file position. @return Offset from the start of the file if successful;
-1 if failure; */ virtual long tell() const; /*! @brief Flush any buffered writes and get the current file size in bytes. @return Size of the file in bytes;
-1 if failure; */ virtual long size() const; //! Returns true if the file is open, otherwise false. virtual bool isopen() const; //! Returns 0 if the file is in a valid state, otherwise nonzero. virtual int error() const; //! Returns true if the file position has reach the end, otherwise false. virtual bool eof() const; //! Returns the path of the file virtual std::string path() const; #ifdef EXV_UNICODE_PATH /* @brief Like path() but returns the unicode path of the file in an std::wstring. @note This function is only available on Windows. */ virtual std::wstring wpath() const; #endif /*! @brief Returns a temporary data storage location. The actual type returned depends upon the size of the file represented a FileIo object. For small files, a MemIo is returned while for large files a FileIo is returned. Callers should not rely on this behavior, however, since it may change. @return An instance of BasicIo on success @throw Error If opening the temporary file fails */ virtual BasicIo::AutoPtr temporary() const; //@} private: // NOT IMPLEMENTED //! Copy constructor FileIo(FileIo& rhs); //! Assignment operator FileIo& operator=(const FileIo& rhs); // Pimpl idiom class Impl; Impl* p_; }; // class FileIo /*! @brief Provides binary IO on blocks of memory by implementing the BasicIo interface. A copy-on-write implementation ensures that the data passed in is only copied when necessary, i.e., as soon as data is written to the MemIo. The original data is only used for reading. If writes are performed, the changed data can be retrieved using the read methods (since the data used in construction is never modified). @note If read only usage of this class is common, it might be worth creating a specialized readonly class or changing this one to have a readonly mode. */ class EXIV2API MemIo : public BasicIo { public: //! @name Creators //@{ //! Default constructor that results in an empty object MemIo(); /*! @brief Constructor that accepts a block of memory. A copy-on-write algorithm allows read operations directly from the original data and will create a copy of the buffer on the first write operation. @param data Pointer to data. Data must be at least \em size bytes long @param size Number of bytes to copy. */ MemIo(const byte* data, long size); //! Destructor. Releases all managed memory ~MemIo(); //@} //! @name Manipulators //@{ /*! @brief Memory IO is always open for reading and writing. This method therefore only resets the IO position to the start. @return 0 */ virtual int open(); /*! @brief Does nothing on MemIo objects. @return 0 */ virtual int close(); /*! @brief Write data to the memory block. If needed, the size of the internal memory block is expanded. The IO position is advanced by the number of bytes written. @param data Pointer to data. Data must be at least \em wcount bytes long @param wcount Number of bytes to be written. @return Number of bytes written to the memory block successfully;
0 if failure; */ virtual long write(const byte* data, long wcount); /*! @brief Write data that is read from another BasicIo instance to the memory block. If needed, the size of the internal memory block is expanded. The IO position is advanced by the number of bytes written. @param src Reference to another BasicIo instance. Reading start at the source's current IO position @return Number of bytes written to the memory block successfully;
0 if failure; */ virtual long write(BasicIo& src); /*! @brief Write one byte to the memory block. The IO position is advanced by one byte. @param data The single byte to be written. @return The value of the byte written if successful;
EOF if failure; */ virtual int putb(byte data); /*! @brief Read data from the memory block. Reading starts at the current IO position and the position is advanced by the number of bytes read. @param rcount Maximum number of bytes to read. Fewer bytes may be read if \em rcount bytes are not available. @return DataBuf instance containing the bytes read. Use the DataBuf::size_ member to find the number of bytes read. DataBuf::size_ will be 0 on failure. */ virtual DataBuf read(long rcount); /*! @brief Read data from the memory block. Reading starts at the current IO position and the position is advanced by the number of bytes read. @param buf Pointer to a block of memory into which the read data is stored. The memory block must be at least \em rcount bytes long. @param rcount Maximum number of bytes to read. Fewer bytes may be read if \em rcount bytes are not available. @return Number of bytes read from the memory block successfully;
0 if failure; */ virtual long read(byte* buf, long rcount); /*! @brief Read one byte from the memory block. The IO position is advanced by one byte. @return The byte read from the memory block if successful;
EOF if failure; */ virtual int getb(); /*! @brief Clear the memory block and then transfer data from the \em src BasicIo object into a new block of memory. This method is optimized to simply swap memory block if the source object is another MemIo instance. The source BasicIo instance is invalidated by this operation and should not be used after this method returns. This method exists primarily to be used with the BasicIo::temporary() method. @param src Reference to another BasicIo instance. The entire contents of src are transferred to this object. The \em src object is invalidated by the method. @throw Error In case of failure */ virtual void transfer(BasicIo& src); /*! @brief Move the current IO position. @param offset Number of bytes to move the IO position relative to the starting position specified by \em pos @param pos Position from which the seek should start @return 0 if successful;
Nonzero if failure; */ virtual int seek(long offset, Position pos); /*! @brief Allow direct access to the underlying data buffer. The buffer is not protected against write access in any way, the argument is ignored. @note The application must ensure that the memory pointed to by the returned pointer remains valid and allocated as long as the MemIo object exists. */ virtual byte* mmap(bool /*isWriteable*/ =false); virtual int munmap(); //@} //! @name Accessors //@{ /*! @brief Get the current IO position. @return Offset from the start of the memory block */ virtual long tell() const; /*! @brief Get the current memory buffer size in bytes. @return Size of the in memory data in bytes;
-1 if failure; */ virtual long size() const; //!Always returns true virtual bool isopen() const; //!Always returns 0 virtual int error() const; //!Returns true if the IO position has reach the end, otherwise false. virtual bool eof() const; //! Returns a dummy path, indicating that memory access is used virtual std::string path() const; #ifdef EXV_UNICODE_PATH /* @brief Like path() but returns a unicode dummy path in an std::wstring. @note This function is only available on Windows. */ virtual std::wstring wpath() const; #endif /*! @brief Returns a temporary data storage location. Currently returns an empty MemIo object, but callers should not rely on this behavior since it may change. @return An instance of BasicIo */ virtual BasicIo::AutoPtr temporary() const; //@} private: // NOT IMPLEMENTED //! Copy constructor MemIo(MemIo& rhs); //! Assignment operator MemIo& operator=(const MemIo& rhs); // Pimpl idiom class Impl; Impl* p_; }; // class MemIo // ***************************************************************************** // template, inline and free functions /*! @brief Read file \em path into a DataBuf, which is returned. @return Buffer containing the file. @throw Error In case of failure. */ EXIV2API DataBuf readFile(const std::string& path); #ifdef EXV_UNICODE_PATH /*! @brief Like readFile() but accepts a unicode path in an std::wstring. @note This function is only available on Windows. */ EXIV2API DataBuf readFile(const std::wstring& wpath); #endif /*! @brief Write DataBuf \em buf to file \em path. @return Return the number of bytes written. @throw Error In case of failure. */ EXIV2API long writeFile(const DataBuf& buf, const std::string& path); #ifdef EXV_UNICODE_PATH /*! @brief Like writeFile() but accepts a unicode path in an std::wstring. @note This function is only available on Windows. */ EXIV2API long writeFile(const DataBuf& buf, const std::wstring& wpath); #endif } // namespace Exiv2 #endif // #ifndef BASICIO_HPP_ exiv2-0.23/src/image.cpp0000644000175000017500000003636111732641407014702 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /* File: image.cpp Version: $Rev: 2681 $ Author(s): Andreas Huggel (ahu) Brad Schick (brad) History: 26-Jan-04, ahu: created 11-Feb-04, ahu: isolated as a component 19-Jul-04, brad: revamped to be more flexible and support Iptc 15-Jan-05, brad: inside-out design changes */ // ***************************************************************************** #include "rcsid_int.hpp" EXIV2_RCSID("@(#) $Id: image.cpp 2681 2012-03-22 15:19:35Z ahuggel $") // ***************************************************************************** // included header files #ifdef _MSC_VER # include "exv_msvc.h" #else # include "exv_conf.h" #endif #include "image.hpp" #include "error.hpp" #include "futils.hpp" #include "cr2image.hpp" #include "crwimage.hpp" #include "epsimage.hpp" #include "jpgimage.hpp" #include "mrwimage.hpp" #ifdef EXV_HAVE_LIBZ # include "pngimage.hpp" #endif // EXV_HAVE_LIBZ #include "rafimage.hpp" #include "tiffimage.hpp" #include "orfimage.hpp" #include "gifimage.hpp" #include "psdimage.hpp" #include "tgaimage.hpp" #include "bmpimage.hpp" #include "jp2image.hpp" #include "rw2image.hpp" #include "pgfimage.hpp" #include "xmpsidecar.hpp" // + standard includes #include #include #include #include #include #include #ifdef _MSC_VER # define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) #endif #ifdef EXV_HAVE_UNISTD_H # include // stat #endif // ***************************************************************************** namespace { using namespace Exiv2; //! Struct for storing image types and function pointers. struct Registry { //! Comparison operator to compare a Registry structure with an image type bool operator==(const int& imageType) const { return imageType == imageType_; } // DATA int imageType_; NewInstanceFct newInstance_; IsThisTypeFct isThisType_; AccessMode exifSupport_; AccessMode iptcSupport_; AccessMode xmpSupport_; AccessMode commentSupport_; }; const Registry registry[] = { //image type creation fct type check Exif mode IPTC mode XMP mode Comment mode //--------------- --------------- ---------- ----------- ----------- ----------- ------------ { ImageType::jpeg, newJpegInstance, isJpegType, amReadWrite, amReadWrite, amReadWrite, amReadWrite }, { ImageType::exv, newExvInstance, isExvType, amReadWrite, amReadWrite, amReadWrite, amReadWrite }, { ImageType::cr2, newCr2Instance, isCr2Type, amRead, amRead, amRead, amNone }, { ImageType::crw, newCrwInstance, isCrwType, amReadWrite, amNone, amNone, amReadWrite }, { ImageType::mrw, newMrwInstance, isMrwType, amRead, amRead, amRead, amNone }, { ImageType::tiff, newTiffInstance, isTiffType, amReadWrite, amReadWrite, amReadWrite, amNone }, { ImageType::dng, newTiffInstance, isTiffType, amReadWrite, amReadWrite, amReadWrite, amNone }, { ImageType::nef, newTiffInstance, isTiffType, amReadWrite, amReadWrite, amReadWrite, amNone }, { ImageType::pef, newTiffInstance, isTiffType, amReadWrite, amReadWrite, amReadWrite, amNone }, { ImageType::arw, newTiffInstance, isTiffType, amRead, amRead, amRead, amNone }, { ImageType::rw2, newRw2Instance, isRw2Type, amRead, amRead, amRead, amNone }, { ImageType::sr2, newTiffInstance, isTiffType, amRead, amRead, amRead, amNone }, { ImageType::srw, newTiffInstance, isTiffType, amReadWrite, amReadWrite, amReadWrite, amNone }, { ImageType::orf, newOrfInstance, isOrfType, amReadWrite, amReadWrite, amReadWrite, amNone }, #ifdef EXV_HAVE_LIBZ { ImageType::png, newPngInstance, isPngType, amReadWrite, amReadWrite, amReadWrite, amReadWrite }, #endif // EXV_HAVE_LIBZ { ImageType::pgf, newPgfInstance, isPgfType, amReadWrite, amReadWrite, amReadWrite, amReadWrite }, { ImageType::raf, newRafInstance, isRafType, amRead, amRead, amRead, amNone }, { ImageType::eps, newEpsInstance, isEpsType, amNone, amNone, amReadWrite, amNone }, { ImageType::xmp, newXmpInstance, isXmpType, amReadWrite, amReadWrite, amReadWrite, amNone }, { ImageType::gif, newGifInstance, isGifType, amNone, amNone, amNone, amNone }, { ImageType::psd, newPsdInstance, isPsdType, amRead, amRead, amRead, amNone }, { ImageType::tga, newTgaInstance, isTgaType, amNone, amNone, amNone, amNone }, { ImageType::bmp, newBmpInstance, isBmpType, amNone, amNone, amNone, amNone }, { ImageType::jp2, newJp2Instance, isJp2Type, amReadWrite, amReadWrite, amReadWrite, amNone }, // End of list marker { ImageType::none, 0, 0, amNone, amNone, amNone, amNone } }; } // ***************************************************************************** // class member definitions namespace Exiv2 { Image::Image(int imageType, uint16_t supportedMetadata, BasicIo::AutoPtr io) : io_(io), pixelWidth_(0), pixelHeight_(0), imageType_(imageType), supportedMetadata_(supportedMetadata), #ifdef EXV_HAVE_XMP_TOOLKIT writeXmpFromPacket_(false), #else writeXmpFromPacket_(true), #endif byteOrder_(invalidByteOrder) { } Image::~Image() { } void Image::clearMetadata() { clearExifData(); clearIptcData(); clearXmpPacket(); clearXmpData(); clearComment(); } ExifData& Image::exifData() { return exifData_; } IptcData& Image::iptcData() { return iptcData_; } XmpData& Image::xmpData() { return xmpData_; } std::string& Image::xmpPacket() { return xmpPacket_; } void Image::setMetadata(const Image& image) { if (checkMode(mdExif) & amWrite) { setExifData(image.exifData()); } if (checkMode(mdIptc) & amWrite) { setIptcData(image.iptcData()); } if (checkMode(mdXmp) & amWrite) { setXmpPacket(image.xmpPacket()); setXmpData(image.xmpData()); } if (checkMode(mdComment) & amWrite) { setComment(image.comment()); } } void Image::clearExifData() { exifData_.clear(); } void Image::setExifData(const ExifData& exifData) { exifData_ = exifData; } void Image::clearIptcData() { iptcData_.clear(); } void Image::setIptcData(const IptcData& iptcData) { iptcData_ = iptcData; } void Image::clearXmpPacket() { xmpPacket_.clear(); writeXmpFromPacket(true); } void Image::setXmpPacket(const std::string& xmpPacket) { xmpPacket_ = xmpPacket; writeXmpFromPacket(true); } void Image::clearXmpData() { xmpData_.clear(); writeXmpFromPacket(false); } void Image::setXmpData(const XmpData& xmpData) { xmpData_ = xmpData; writeXmpFromPacket(false); } void Image::writeXmpFromPacket(bool flag) { #ifdef EXV_HAVE_XMP_TOOLKIT writeXmpFromPacket_ = flag; #endif } void Image::clearComment() { comment_.erase(); } void Image::setComment(const std::string& comment) { comment_ = comment; } void Image::setByteOrder(ByteOrder byteOrder) { byteOrder_ = byteOrder; } ByteOrder Image::byteOrder() const { return byteOrder_; } int Image::pixelWidth() const { return pixelWidth_; } int Image::pixelHeight() const { return pixelHeight_; } const ExifData& Image::exifData() const { return exifData_; } const IptcData& Image::iptcData() const { return iptcData_; } const XmpData& Image::xmpData() const { return xmpData_; } std::string Image::comment() const { return comment_; } const std::string& Image::xmpPacket() const { return xmpPacket_; } BasicIo& Image::io() const { return *io_; } bool Image::writeXmpFromPacket() const { return writeXmpFromPacket_; } const NativePreviewList& Image::nativePreviews() const { return nativePreviews_; } bool Image::good() const { if (io_->open() != 0) return false; IoCloser closer(*io_); return ImageFactory::checkType(imageType_, *io_, false); } bool Image::supportsMetadata(MetadataId metadataId) const { return (supportedMetadata_ & metadataId) != 0; } AccessMode Image::checkMode(MetadataId metadataId) const { return ImageFactory::checkMode(imageType_, metadataId); } AccessMode ImageFactory::checkMode(int type, MetadataId metadataId) { const Registry* r = find(registry, type); if (!r) throw Error(13, type); AccessMode am = amNone; switch (metadataId) { case mdNone: break; case mdExif: am = r->exifSupport_; break; case mdIptc: am = r->iptcSupport_; break; case mdXmp: am = r->xmpSupport_; break; case mdComment: am = r->commentSupport_; break; // no default: let the compiler complain } return am; } bool ImageFactory::checkType(int type, BasicIo& io, bool advance) { const Registry* r = find(registry, type); if (0 != r) { return r->isThisType_(io, advance); } return false; } // ImageFactory::checkType int ImageFactory::getType(const std::string& path) { FileIo fileIo(path); return getType(fileIo); } #ifdef EXV_UNICODE_PATH int ImageFactory::getType(const std::wstring& wpath) { FileIo fileIo(wpath); return getType(fileIo); } #endif int ImageFactory::getType(const byte* data, long size) { MemIo memIo(data, size); return getType(memIo); } int ImageFactory::getType(BasicIo& io) { if (io.open() != 0) return ImageType::none; IoCloser closer(io); for (unsigned int i = 0; registry[i].imageType_ != ImageType::none; ++i) { if (registry[i].isThisType_(io, false)) { return registry[i].imageType_; } } return ImageType::none; } // ImageFactory::getType Image::AutoPtr ImageFactory::open(const std::string& path) { BasicIo::AutoPtr io(new FileIo(path)); Image::AutoPtr image = open(io); // may throw if (image.get() == 0) throw Error(11, path); return image; } #ifdef EXV_UNICODE_PATH Image::AutoPtr ImageFactory::open(const std::wstring& wpath) { BasicIo::AutoPtr io(new FileIo(wpath)); Image::AutoPtr image = open(io); // may throw if (image.get() == 0) throw WError(11, wpath); return image; } #endif Image::AutoPtr ImageFactory::open(const byte* data, long size) { BasicIo::AutoPtr io(new MemIo(data, size)); Image::AutoPtr image = open(io); // may throw if (image.get() == 0) throw Error(12); return image; } Image::AutoPtr ImageFactory::open(BasicIo::AutoPtr io) { if (io->open() != 0) { throw Error(9, io->path(), strError()); } for (unsigned int i = 0; registry[i].imageType_ != ImageType::none; ++i) { if (registry[i].isThisType_(*io, false)) { return registry[i].newInstance_(io, false); } } return Image::AutoPtr(); } // ImageFactory::open Image::AutoPtr ImageFactory::create(int type, const std::string& path) { std::auto_ptr fileIo(new FileIo(path)); // Create or overwrite the file, then close it if (fileIo->open("w+b") != 0) { throw Error(10, path, "w+b", strError()); } fileIo->close(); BasicIo::AutoPtr io(fileIo); Image::AutoPtr image = create(type, io); if (image.get() == 0) throw Error(13, type); return image; } #ifdef EXV_UNICODE_PATH Image::AutoPtr ImageFactory::create(int type, const std::wstring& wpath) { std::auto_ptr fileIo(new FileIo(wpath)); // Create or overwrite the file, then close it if (fileIo->open("w+b") != 0) { throw WError(10, wpath, "w+b", strError().c_str()); } fileIo->close(); BasicIo::AutoPtr io(fileIo); Image::AutoPtr image = create(type, io); if (image.get() == 0) throw Error(13, type); return image; } #endif Image::AutoPtr ImageFactory::create(int type) { BasicIo::AutoPtr io(new MemIo); Image::AutoPtr image = create(type, io); if (image.get() == 0) throw Error(13, type); return image; } Image::AutoPtr ImageFactory::create(int type, BasicIo::AutoPtr io) { // BasicIo instance does not need to be open const Registry* r = find(registry, type); if (0 != r) { return r->newInstance_(io, true); } return Image::AutoPtr(); } // ImageFactory::create // ***************************************************************************** // template, inline and free functions void append(Blob& blob, const byte* buf, uint32_t len) { if (len != 0) { assert(buf != 0); Blob::size_type size = blob.size(); if (blob.capacity() - size < len) { blob.reserve(size + 65536); } blob.resize(size + len); std::memcpy(&blob[size], buf, len); } } // append } // namespace Exiv2 exiv2-0.23/src/easyaccess.cpp0000644000175000017500000003725011744713412015740 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /* File: easyaccess.cpp Version: $Rev: 2711 $ Author(s): Carsten Pfeiffer Andreas Huggel (ahu) History: 28-Feb-09, gis: created */ // ***************************************************************************** #include "rcsid_int.hpp" EXIV2_RCSID("@(#) $Id: easyaccess.cpp 2711 2012-04-22 05:28:42Z ahuggel $") // ***************************************************************************** // included header files #include "easyaccess.hpp" // ***************************************************************************** namespace { using namespace Exiv2; /*! @brief Search \em ed for a Metadatum specified by the \em keys. The \em keys are searched in the order of their appearance, the first available Metadatum is returned. @param ed The %Exif metadata container to search @param keys Array of keys to look for @param count Number of elements in the array */ ExifData::const_iterator findMetadatum(const ExifData& ed, const char* keys[], int count) { for (int i = 0; i < count; ++i) { ExifData::const_iterator pos = ed.findKey(ExifKey(keys[i])); if (pos != ed.end()) return pos; } return ed.end(); } // findMetadatum } // anonymous namespace // ***************************************************************************** // class member definitions namespace Exiv2 { ExifData::const_iterator orientation(const ExifData& ed) { static const char* keys[] = { "Exif.Image.Orientation", "Exif.Panasonic.Rotation", "Exif.MinoltaCs5D.Rotation", "Exif.MinoltaCs5D.Rotation2", "Exif.MinoltaCs7D.Rotation", "Exif.Sony1MltCsA100.Rotation", "Exif.Sony1Cs.Rotation", "Exif.Sony2Cs.Rotation", "Exif.Sony1Cs2.Rotation", "Exif.Sony2Cs2.Rotation", "Exif.Sony1MltCsA100.Rotation" }; return findMetadatum(ed, keys, EXV_COUNTOF(keys)); } ExifData::const_iterator isoSpeed(const ExifData& ed) { static const char* keys[] = { "Exif.Photo.ISOSpeedRatings", "Exif.Image.ISOSpeedRatings", "Exif.CanonSi.ISOSpeed", "Exif.CanonCs.ISOSpeed", "Exif.Nikon1.ISOSpeed", "Exif.Nikon2.ISOSpeed", "Exif.Nikon3.ISOSpeed", "Exif.NikonIi.ISO", "Exif.NikonIi.ISO2", "Exif.MinoltaCsNew.ISOSetting", "Exif.MinoltaCsOld.ISOSetting", "Exif.MinoltaCs5D.ISOSpeed", "Exif.MinoltaCs7D.ISOSpeed", "Exif.Sony1Cs.ISOSetting", "Exif.Sony2Cs.ISOSetting", "Exif.Sony1Cs2.ISOSetting", "Exif.Sony2Cs2.ISOSetting", "Exif.Sony1MltCsA100.ISOSetting", "Exif.Pentax.ISO", "Exif.PentaxDng.ISO", "Exif.Olympus.ISOSpeed", "Exif.Samsung2.ISO" }; // Find the first ISO value which is not "0" const int cnt = EXV_COUNTOF(keys); ExifData::const_iterator md = ed.end(); for (int idx = 0; idx < cnt; ) { md = findMetadatum(ed, keys + idx, cnt - idx); if (md == ed.end()) break; std::ostringstream os; md->write(os, &ed); bool ok = false; long v = parseLong(os.str(), ok); if (ok && v != 0) break; while (strcmp(keys[idx++], md->key().c_str()) != 0 && idx < cnt) {} md = ed.end(); } return md; } ExifData::const_iterator flashBias(const ExifData& ed) { static const char* keys[] = { "Exif.CanonSi.FlashBias", "Exif.Panasonic.FlashBias", "Exif.Olympus.FlashBias", "Exif.OlympusCs.FlashExposureComp", "Exif.Minolta.FlashExposureComp", "Exif.SonyMinolta.FlashExposureComp", "Exif.Sony1.FlashExposureComp", "Exif.Sony2.FlashExposureComp" }; return findMetadatum(ed, keys, EXV_COUNTOF(keys)); } ExifData::const_iterator exposureMode(const ExifData& ed) { static const char* keys[] = { "Exif.Photo.ExposureProgram", "Exif.Image.ExposureProgram", "Exif.CanonCs.ExposureProgram", "Exif.MinoltaCs7D.ExposureMode", "Exif.MinoltaCs5D.ExposureMode", "Exif.MinoltaCsNew.ExposureMode", "Exif.MinoltaCsOld.ExposureMode", "Exif.Sony1MltCsA100.ExposureMode", "Exif.Sony1Cs.ExposureProgram", "Exif.Sony2Cs.ExposureProgram", "Exif.Sigma.ExposureMode" }; return findMetadatum(ed, keys, EXV_COUNTOF(keys)); } ExifData::const_iterator sceneMode(const ExifData& ed) { static const char* keys[] = { "Exif.CanonCs.EasyMode", "Exif.Fujifilm.PictureMode", "Exif.MinoltaCsNew.SubjectProgram", "Exif.MinoltaCsOld.SubjectProgram", "Exif.Minolta.SceneMode", "Exif.SonyMinolta.SceneMode", "Exif.Sony1.SceneMode", "Exif.Sony2.SceneMode", "Exif.OlympusCs.SceneMode", "Exif.Panasonic.ShootingMode", "Exif.Panasonic.SceneMode", "Exif.Pentax.PictureMode", "Exif.PentaxDng.PictureMode", "Exif.Photo.SceneCaptureType" }; return findMetadatum(ed, keys, EXV_COUNTOF(keys)); } ExifData::const_iterator macroMode(const ExifData& ed) { static const char* keys[] = { "Exif.CanonCs.Macro", "Exif.Fujifilm.Macro", "Exif.Olympus.Macro", "Exif.OlympusCs.MacroMode", "Exif.Panasonic.Macro", "Exif.MinoltaCsNew.MacroMode", "Exif.MinoltaCsOld.MacroMode", "Exif.Sony1.Macro", "Exif.Sony2.Macro" }; return findMetadatum(ed, keys, EXV_COUNTOF(keys)); } ExifData::const_iterator imageQuality(const ExifData& ed) { static const char* keys[] = { "Exif.CanonCs.Quality", "Exif.Fujifilm.Quality", "Exif.Sigma.Quality", "Exif.Nikon1.Quality", "Exif.Nikon2.Quality", "Exif.Nikon3.Quality", "Exif.Olympus.Quality", "Exif.OlympusCs.Quality", "Exif.Panasonic.Quality", "Exif.Minolta.Quality", "Exif.MinoltaCsNew.Quality", "Exif.MinoltaCsOld.Quality", "Exif.MinoltaCs5D.Quality", "Exif.MinoltaCs7D.Quality", "Exif.Sony1MltCsA100.Quality", "Exif.Sony1.JPEGQuality", "Exif.Sony1.Quality", "Exif.Sony1Cs.Quality", "Exif.Sony2.JPEGQuality", "Exif.Sony2.Quality", "Exif.Sony2Cs.Quality" }; return findMetadatum(ed, keys, EXV_COUNTOF(keys)); } ExifData::const_iterator whiteBalance(const ExifData& ed) { static const char* keys[] = { "Exif.CanonSi.WhiteBalance", "Exif.Fujifilm.WhiteBalance", "Exif.Sigma.WhiteBalance", "Exif.Nikon1.WhiteBalance", "Exif.Nikon2.WhiteBalance", "Exif.Nikon3.WhiteBalance", "Exif.Olympus.WhiteBalance", "Exif.OlympusCs.WhiteBalance", "Exif.Panasonic.WhiteBalance", "Exif.MinoltaCs5D.WhiteBalance", "Exif.MinoltaCs7D.WhiteBalance", "Exif.MinoltaCsNew.WhiteBalance", "Exif.MinoltaCsOld.WhiteBalance", "Exif.Minolta.WhiteBalance", "Exif.Sony1MltCsA100.WhiteBalance", "Exif.SonyMinolta.WhiteBalance", "Exif.Sony1.WhiteBalance", "Exif.Sony2.WhiteBalance", "Exif.Sony1.WhiteBalance2", "Exif.Sony2.WhiteBalance2", "Exif.Photo.WhiteBalance" }; return findMetadatum(ed, keys, EXV_COUNTOF(keys)); } ExifData::const_iterator lensName(const ExifData& ed) { static const char* keys[] = { "Exif.CanonCs.LensType", "Exif.NikonLd1.LensIDNumber", "Exif.NikonLd2.LensIDNumber", "Exif.NikonLd3.LensIDNumber", "Exif.Pentax.LensType", "Exif.PentaxDng.LensType", "Exif.Minolta.LensID", "Exif.SonyMinolta.LensID", "Exif.Sony1.LensID", "Exif.Sony2.LensID", "Exif.OlympusEq.LensModel", "Exif.Panasonic.LensType", "Exif.Samsung2.LensType" }; return findMetadatum(ed, keys, EXV_COUNTOF(keys)); } ExifData::const_iterator saturation(const ExifData& ed) { static const char* keys[] = { "Exif.Photo.Saturation", "Exif.CanonCs.Saturation", "Exif.MinoltaCsNew.Saturation", "Exif.MinoltaCsOld.Saturation", "Exif.MinoltaCs7D.Saturation", "Exif.MinoltaCs5D.Saturation", "Exif.Fujifilm.Color", "Exif.Nikon3.Saturation", "Exif.Panasonic.Saturation", "Exif.Pentax.Saturation", "Exif.PentaxDng.Saturation", "Exif.Sigma.Saturation" }; return findMetadatum(ed, keys, EXV_COUNTOF(keys)); } ExifData::const_iterator sharpness(const ExifData& ed) { static const char* keys[] = { "Exif.Photo.Sharpness", "Exif.CanonCs.Sharpness", "Exif.Fujifilm.Sharpness", "Exif.MinoltaCsNew.Sharpness", "Exif.MinoltaCsOld.Sharpness", "Exif.MinoltaCs7D.Sharpness", "Exif.MinoltaCs5D.Sharpness", "Exif.Olympus.SharpnessFactor", "Exif.Panasonic.Sharpness", "Exif.Pentax.Sharpness", "Exif.PentaxDng.Sharpness", "Exif.Sigma.Sharpness" }; return findMetadatum(ed, keys, EXV_COUNTOF(keys)); } ExifData::const_iterator contrast(const ExifData& ed) { static const char* keys[] = { "Exif.Photo.Contrast", "Exif.CanonCs.Contrast", "Exif.Fujifilm.Tone", "Exif.MinoltaCsNew.Contrast", "Exif.MinoltaCsOld.Contrast", "Exif.MinoltaCs7D.Contrast", "Exif.MinoltaCs5D.Contrast", "Exif.Olympus.Contrast", "Exif.Panasonic.Contrast", "Exif.Pentax.Contrast", "Exif.PentaxDng.Contrast", "Exif.Sigma.Contrast" }; return findMetadatum(ed, keys, EXV_COUNTOF(keys)); } ExifData::const_iterator sceneCaptureType(const ExifData& ed) { static const char* keys[] = { "Exif.Photo.SceneCaptureType", "Exif.Olympus.SpecialMode" }; return findMetadatum(ed, keys, EXV_COUNTOF(keys)); } ExifData::const_iterator meteringMode(const ExifData& ed) { static const char* keys[] = { "Exif.Photo.MeteringMode", "Exif.Image.MeteringMode", "Exif.CanonCs.MeteringMode", "Exif.Sony1MltCsA100.MeteringMode" }; return findMetadatum(ed, keys, EXV_COUNTOF(keys)); } ExifData::const_iterator make(const ExifData& ed) { static const char* keys[] = { "Exif.Image.Make" }; return findMetadatum(ed, keys, EXV_COUNTOF(keys)); } ExifData::const_iterator model(const ExifData& ed) { static const char* keys[] = { "Exif.Image.Model" }; return findMetadatum(ed, keys, EXV_COUNTOF(keys)); } ExifData::const_iterator exposureTime(const ExifData& ed) { static const char* keys[] = { "Exif.Photo.ExposureTime", "Exif.Image.ExposureTime", "Exif.Samsung2.ExposureTime" }; return findMetadatum(ed, keys, EXV_COUNTOF(keys)); } ExifData::const_iterator fNumber(const ExifData& ed) { static const char* keys[] = { "Exif.Photo.FNumber", "Exif.Image.FNumber", "Exif.Samsung2.FNumber" }; return findMetadatum(ed, keys, EXV_COUNTOF(keys)); } ExifData::const_iterator subjectDistance(const ExifData& ed) { static const char* keys[] = { "Exif.Photo.SubjectDistance", "Exif.Image.SubjectDistance", "Exif.CanonSi.SubjectDistance", "Exif.MinoltaCsNew.FocusDistance", "Exif.Nikon1.FocusDistance", "Exif.Nikon3.FocusDistance", "Exif.NikonLd2.FocusDistance", "Exif.NikonLd3.FocusDistance", "Exif.Olympus.FocusDistance", "Exif.OlympusFi.FocusDistance" }; return findMetadatum(ed, keys, EXV_COUNTOF(keys)); } ExifData::const_iterator serialNumber(const ExifData& ed) { static const char* keys[] = { "Exif.Image.CameraSerialNumber", "Exif.Canon.SerialNumber", "Exif.Nikon3.SerialNumber", "Exif.Nikon3.SerialNO", "Exif.Fujifilm.SerialNumber", "Exif.Olympus.SerialNumber2", "Exif.Sigma.SerialNumber" }; return findMetadatum(ed, keys, EXV_COUNTOF(keys)); } ExifData::const_iterator focalLength(const ExifData& ed) { static const char* keys[] = { "Exif.Photo.FocalLength", "Exif.Image.FocalLength", "Exif.Canon.FocalLength", "Exif.NikonLd2.FocalLength", "Exif.NikonLd3.FocalLength", "Exif.MinoltaCsNew.FocalLength", "Exif.Pentax.FocalLength", "Exif.PentaxDng.FocalLength" }; return findMetadatum(ed, keys, EXV_COUNTOF(keys)); } ExifData::const_iterator afPoint(const ExifData& ed) { static const char* keys[] = { "Exif.CanonPi.AFPointsUsed", "Exif.CanonPi.AFPointsUsed20D", "Exif.CanonSi.AFPointUsed", "Exif.CanonCs.AFPoint", "Exif.MinoltaCs7D.AFPoints", "Exif.Nikon1.AFFocusPos", "Exif.NikonAf.AFPoint", "Exif.NikonAf.AFPointsInFocus", "Exif.NikonAf2.AFPointsUsed", "Exif.NikonAf2.PrimaryAFPoint", "Exif.OlympusFi.AFPoint", "Exif.Pentax.AFPoint", "Exif.Pentax.AFPointInFocus", "Exif.PentaxDng.AFPoint", "Exif.PentaxDng.AFPointInFocus", "Exif.Sony1Cs.LocalAFAreaPoint", "Exif.Sony2Cs.LocalAFAreaPoint", "Exif.Sony1Cs2.LocalAFAreaPoint", "Exif.Sony2Cs2.LocalAFAreaPoint", "Exif.Sony1MltCsA100.LocalAFAreaPoint" }; return findMetadatum(ed, keys, EXV_COUNTOF(keys)); } } // namespace Exiv2 exiv2-0.23/src/pgfimage.hpp0000644000175000017500000001224311732641407015375 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! @file pgfimage.hpp @brief PGF image, implemented using the following references: PGF specification from libpgf web site
@version $Rev: 2681 $ @author Andreas Huggel (ahu) ahuggel@gmx.net @author Gilles Caulier (cgilles) caulier dot gilles at gmail dot com @date 16-Jun-09, gc: submitted */ #ifndef PGFIMAGE_HPP_ #define PGFIMAGE_HPP_ // ***************************************************************************** // included header files #include "image.hpp" #include "basicio.hpp" #include "types.hpp" // + standard includes #include // ***************************************************************************** // namespace extensions namespace Exiv2 { // ***************************************************************************** // class definitions // Add PGF to the supported image formats namespace ImageType { const int pgf = 17; //!< PGF image type (see class PgfImage) } /*! @brief Class to access PGF images. Exif and IPTC metadata are supported directly. */ class EXIV2API PgfImage : public Image { public: //! @name Creators //@{ /*! @brief Constructor that can either open an existing PGF image or create a new image from scratch. If a new image is to be created, any existing data is overwritten. Since the constructor can not return a result, callers should check the good() method after object construction to determine success or failure. @param io An auto-pointer that owns a BasicIo instance used for reading and writing image metadata. \b Important: The constructor takes ownership of the passed in BasicIo instance through the auto-pointer. Callers should not continue to use the BasicIo instance after it is passed to this method. Use the Image::io() method to get a temporary reference. @param create Specifies if an existing image should be read (false) or if a new file should be created (true). */ PgfImage(BasicIo::AutoPtr io, bool create); //@} //! @name Manipulators //@{ void readMetadata(); void writeMetadata(); //@} //! @name Accessors //@{ std::string mimeType() const { return "image/pgf"; } //@} private: //! @name NOT implemented //@{ //! Copy constructor PgfImage(const PgfImage& rhs); //! Assignment operator PgfImage& operator=(const PgfImage& rhs); /*! @brief Provides the main implementation of writeMetadata() by writing all buffered metadata to the provided BasicIo. @param oIo BasicIo instance to write to (a temporary location). @return 4 if opening or writing to the associated BasicIo fails */ EXV_DLLLOCAL void doWriteMetadata(BasicIo& oIo); //! Read Magick number. Only version >= 6 is supported. byte readPgfMagicNumber(BasicIo& iIo); //! Read PGF Header size encoded in 32 bits integer. uint32_t readPgfHeaderSize(BasicIo& iIo); //! Read header structure. DataBuf readPgfHeaderStructure(BasicIo& iIo, int* width, int* height); //@} }; // class PgfImage // ***************************************************************************** // template, inline and free functions // These could be static private functions on Image subclasses but then // ImageFactory needs to be made a friend. /*! @brief Create a new PgfImage instance and return an auto-pointer to it. Caller owns the returned object and the auto-pointer ensures that it will be deleted. */ EXIV2API Image::AutoPtr newPgfInstance(BasicIo::AutoPtr io, bool create); //! Check if the file iIo is a PGF image. EXIV2API bool isPgfType(BasicIo& iIo, bool advance); } // namespace Exiv2 #endif // #ifndef PGFIMAGE_HPP_ exiv2-0.23/src/metadatum.hpp0000644000175000017500000003037511732641407015605 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! @file metadatum.hpp @brief Provides abstract base classes Metadatum and Key @version $Rev: 2681 $ @author Andreas Huggel (ahu) ahuggel@gmx.net @author Brad Schick (brad) brad@robotbattle.com @date 09-Jan-04, ahu: created
31-Jul-04, brad: isolated as a component
23-Aug-04, ahu: added Key */ #ifndef METADATUM_HPP_ #define METADATUM_HPP_ // ***************************************************************************** // included header files #include "types.hpp" #include "value.hpp" // + standard includes #include #include // ***************************************************************************** // namespace extensions namespace Exiv2 { // ***************************************************************************** // class declarations class ExifData; // ***************************************************************************** // class definitions /*! @brief Abstract base class defining the %Key of a metadatum. Keys are used to identify and group metadata. */ class EXIV2API Key { public: //! Shortcut for a %Key auto pointer. typedef std::auto_ptr AutoPtr; //! @name Creators //@{ //! Destructor virtual ~Key(); //@} //! @name Accessors //@{ /*! @brief Return the key of the metadatum as a string. The key is of the form 'familyName.groupName.tagName'. Note however that the key is not necessarily unique, e.g., an ExifData may contain multiple metadata with the same key. */ virtual std::string key() const =0; //! Return an identifier for the type of metadata (the first part of the key) virtual const char* familyName() const =0; //! Return the name of the group (the second part of the key) virtual std::string groupName() const =0; //! Return the name of the tag (which is also the third part of the key) virtual std::string tagName() const =0; //! Return a label for the tag virtual std::string tagLabel() const =0; //! Return the tag number virtual uint16_t tag() const =0; /*! @brief Return an auto-pointer to a copy of itself (deep copy). The caller owns this copy and the auto-pointer ensures that it will be deleted. */ AutoPtr clone() const; /*! @brief Write the key to an output stream. You do not usually have to use this function; it is used for the implementation of the output operator for %Key, operator<<(std::ostream &os, const Key &key). */ std::ostream& write(std::ostream& os) const { return os << key(); } //@} protected: //! @name Manipulators //@{ /*! @brief Assignment operator. Protected so that it can only be used by subclasses but not directly. */ Key& operator=(const Key& rhs); //@} private: //! Internal virtual copy constructor. EXV_DLLLOCAL virtual Key* clone_() const =0; }; // class Key //! Output operator for Key types inline std::ostream& operator<<(std::ostream& os, const Key& key) { return key.write(os); } /*! @brief Abstract base class defining the interface to access information related to one metadata tag. */ class EXIV2API Metadatum { public: //! @name Creators //@{ //! Default Constructor Metadatum(); //! Copy constructor Metadatum(const Metadatum& rhs); //! Destructor virtual ~Metadatum(); //@} //! @name Manipulators //@{ /*! @brief Set the value. This method copies (clones) the value pointed to by pValue. */ virtual void setValue(const Value* pValue) =0; /*! @brief Set the value to the string buf. Uses Value::read(const std::string& buf). If the metadatum does not have a value yet, then one is created. See subclasses for more details. Return 0 if the value was read successfully. */ virtual int setValue(const std::string& buf) =0; //@} //! @name Accessors //@{ /*! @brief Write the interpreted value to a string. Implemented in terms of write(), see there. */ std::string print(const ExifData* pMetadata =0) const; /*! @brief Write value to a data buffer and return the number of bytes written. The user must ensure that the buffer has enough memory. Otherwise the call results in undefined behaviour. @param buf Data buffer to write to. @param byteOrder Applicable byte order (little or big endian). @return Number of characters written. */ virtual long copy(byte* buf, ByteOrder byteOrder) const =0; /*! @brief Write the interpreted value to an output stream, return the stream. The method takes an optional pointer to a metadata container. Pretty-print functions may use that to refer to other metadata as it is sometimes not sufficient to know only the value of the metadatum that should be interpreted. Thus, it is advisable to always call this method with a pointer to the metadata container if possible. This functionality is currently only implemented for Exif tags. The pointer is ignored when used to write IPTC datasets or XMP properties. Without the optional metadata pointer, you do not usually have to use this function; it is used for the implementation of the output operator for %Metadatum, operator<<(std::ostream &os, const Metadatum &md). See also print(), which prints the interpreted value to a string. */ virtual std::ostream& write( std::ostream& os, const ExifData* pMetadata =0 ) const =0; /*! @brief Return the key of the metadatum. The key is of the form 'familyName.groupName.tagName'. Note however that the key is not necessarily unique, e.g., an ExifData object may contain multiple metadata with the same key. */ virtual std::string key() const =0; //! Return the name of the metadata family (which is also the first part of the key) virtual const char* familyName() const =0; //! Return the name of the metadata group (which is also the second part of the key) virtual std::string groupName() const =0; //! Return the name of the tag (which is also the third part of the key) virtual std::string tagName() const =0; //! Return a label for the tag virtual std::string tagLabel() const =0; //! Return the tag virtual uint16_t tag() const =0; //! Return the type id of the value virtual TypeId typeId() const =0; //! Return the name of the type virtual const char* typeName() const =0; //! Return the size in bytes of one component of this type virtual long typeSize() const =0; //! Return the number of components in the value virtual long count() const =0; //! Return the size of the value in bytes virtual long size() const =0; //! Return the value as a string. virtual std::string toString() const =0; /*! @brief Return the n-th component of the value converted to a string. The behaviour of the method is undefined if there is no n-th component. */ virtual std::string toString(long n) const =0; /*! @brief Return the n-th component of the value converted to long. The return value is -1 if the value is not set and the behaviour of the method is undefined if there is no n-th component. */ virtual long toLong(long n =0) const =0; /*! @brief Return the n-th component of the value converted to float. The return value is -1 if the value is not set and the behaviour of the method is undefined if there is no n-th component. */ virtual float toFloat(long n =0) const =0; /*! @brief Return the n-th component of the value converted to Rational. The return value is -1/1 if the value is not set and the behaviour of the method is undefined if there is no n-th component. */ virtual Rational toRational(long n =0) const =0; /*! @brief Return an auto-pointer to a copy (clone) of the value. The caller owns this copy and the auto-poiner ensures that it will be deleted. This method is provided for users who need full control over the value. A caller may, e.g., downcast the pointer to the appropriate subclass of Value to make use of the interface of the subclass to set or modify its contents. @return An auto-pointer containing a pointer to a copy (clone) of the value, 0 if the value is not set. */ virtual Value::AutoPtr getValue() const =0; /*! @brief Return a constant reference to the value. This method is provided mostly for convenient and versatile output of the value which can (to some extent) be formatted through standard stream manipulators. Do not attempt to write to the value through this reference. An Error is thrown if the value is not set; as an alternative to catching it, one can use count() to check if there is any data before calling this method. @return A constant reference to the value. @throw Error if the value is not set. */ virtual const Value& value() const =0; //@} protected: //! @name Manipulators //@{ /*! @brief Assignment operator. Protected so that it can only be used by subclasses but not directly. */ Metadatum& operator=(const Metadatum& rhs); //@} }; // class Metadatum /*! @brief Output operator for Metadatum types, writing the interpreted tag value. */ inline std::ostream& operator<<(std::ostream& os, const Metadatum& md) { return md.write(os); } /*! @brief Compare two metadata by tag. Return true if the tag of metadatum lhs is less than that of rhs. */ EXIV2API bool cmpMetadataByTag(const Metadatum& lhs, const Metadatum& rhs); /*! @brief Compare two metadata by key. Return true if the key of metadatum lhs is less than that of rhs. */ EXIV2API bool cmpMetadataByKey(const Metadatum& lhs, const Metadatum& rhs); } // namespace Exiv2 #endif // #ifndef METADATUM_HPP_ exiv2-0.23/src/samsungmn_int.hpp0000644000175000017500000000456511732641407016510 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! @file samsungmn_int.hpp @brief Samsung makernote tags.
References:
[1] ExifTool by Phil Harvey @version $Rev: 2681 $ @author Andreas Huggel (ahu) ahuggel@gmx.net @date 27-Sep-10, ahu: created */ #ifndef SAMSUNGMN_INT_HPP_ #define SAMSUNGMN_INT_HPP_ // ***************************************************************************** // included header files #include "tags.hpp" #include "types.hpp" // + standard includes #include #include #include // ***************************************************************************** // namespace extensions namespace Exiv2 { namespace Internal { // ***************************************************************************** // class definitions //! MakerNote for Samsung cameras class Samsung2MakerNote { public: //! Return read-only list of built-in Samsung tags static const TagInfo* tagList(); //! Return read-only list of built-in PictureWizard tags static const TagInfo* tagListPw(); private: //! Tag information static const TagInfo tagInfo_[]; //! PictureWizard tag information static const TagInfo tagInfoPw_[]; }; // class Samsung2MakerNote }} // namespace Internal, Exiv2 #endif // #ifndef SAMSUNGMN_INT_HPP_ exiv2-0.23/src/xmpdump.cpp0000644000175000017500000000157711027153701015303 0ustar andreasandreas// ***************************************************************** -*- C++ -*- // xmpdump.cpp, $Rev: 1512 $ // Sample program to dump the XMP packet of an image #include "image.hpp" #include #include #include int main(int argc, char* const argv[]) try { if (argc != 2) { std::cout << "Usage: " << argv[0] << " file\n"; return 1; } Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(argv[1]); assert(image.get() != 0); image->readMetadata(); const std::string& xmpPacket = image->xmpPacket(); if (xmpPacket.empty()) { std::string error(argv[1]); error += ": No XMP packet found in the file"; throw Exiv2::Error(1, error); } std::cout << xmpPacket << "\n"; return 0; } catch (Exiv2::AnyError& e) { std::cout << "Caught Exiv2 exception '" << e << "'\n"; return -1; } exiv2-0.23/src/sigmamn.cpp0000644000175000017500000001671411732641407015253 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /* File: sigmamn.cpp Version: $Rev: 2681 $ Author(s): Andreas Huggel (ahu) History: 02-Apr-04, ahu: created Credits: Sigma and Foveon MakerNote implemented according to the specification in "SIGMA and FOVEON EXIF MakerNote Documentation" by Foveon. */ // ***************************************************************************** #include "rcsid_int.hpp" EXIV2_RCSID("@(#) $Id: sigmamn.cpp 2681 2012-03-22 15:19:35Z ahuggel $") // ***************************************************************************** // included header files #include "types.hpp" #include "sigmamn_int.hpp" #include "tags_int.hpp" #include "value.hpp" #include "i18n.h" // NLS support. // + standard includes #include #include #include #include #include // ***************************************************************************** // class member definitions namespace Exiv2 { namespace Internal { // Sigma (Foveon) MakerNote Tag Info const TagInfo SigmaMakerNote::tagInfo_[] = { TagInfo(0x0002, "SerialNumber", N_("Serial Number"), N_("Camera serial number"), sigmaId, makerTags, asciiString, -1, printValue), TagInfo(0x0003, "DriveMode", N_("Drive Mode"), N_("Drive mode"), sigmaId, makerTags, asciiString, -1, printValue), TagInfo(0x0004, "ResolutionMode", N_("Resolution Mode"), N_("Resolution mode"), sigmaId, makerTags, asciiString, -1, printValue), TagInfo(0x0005, "AutofocusMode", N_("Autofocus Mode"), N_("Autofocus mode"), sigmaId, makerTags, asciiString, -1, printValue), TagInfo(0x0006, "FocusSetting", N_("Focus Setting"), N_("Focus setting"), sigmaId, makerTags, asciiString, -1, printValue), TagInfo(0x0007, "WhiteBalance", N_("White Balance"), N_("White balance"), sigmaId, makerTags, asciiString, -1, printValue), TagInfo(0x0008, "ExposureMode", N_("Exposure Mode"), N_("Exposure mode"), sigmaId, makerTags, asciiString, -1, print0x0008), TagInfo(0x0009, "MeteringMode", N_("Metering Mode"), N_("Metering mode"), sigmaId, makerTags, asciiString, -1, print0x0009), TagInfo(0x000a, "LensRange", N_("Lens Range"), N_("Lens focal length range"), sigmaId, makerTags, asciiString, -1, printValue), TagInfo(0x000b, "ColorSpace", N_("Color Space"), N_("Color space"), sigmaId, makerTags, asciiString, -1, printValue), TagInfo(0x000c, "Exposure", N_("Exposure"), N_("Exposure"), sigmaId, makerTags, asciiString, -1, printStripLabel), TagInfo(0x000d, "Contrast", N_("Contrast"), N_("Contrast"), sigmaId, makerTags, asciiString, -1, printStripLabel), TagInfo(0x000e, "Shadow", N_("Shadow"), N_("Shadow"), sigmaId, makerTags, asciiString, -1, printStripLabel), TagInfo(0x000f, "Highlight", N_("Highlight"), N_("Highlight"), sigmaId, makerTags, asciiString, -1, printStripLabel), TagInfo(0x0010, "Saturation", N_("Saturation"), N_("Saturation"), sigmaId, makerTags, asciiString, -1, printStripLabel), TagInfo(0x0011, "Sharpness", N_("Sharpness"), N_("Sharpness"), sigmaId, makerTags, asciiString, -1, printStripLabel), TagInfo(0x0012, "FillLight", N_("Fill Light"), N_("X3 Fill light"), sigmaId, makerTags, asciiString, -1, printStripLabel), TagInfo(0x0014, "ColorAdjustment", N_("Color Adjustment"), N_("Color adjustment"), sigmaId, makerTags, asciiString, -1, printStripLabel), TagInfo(0x0015, "AdjustmentMode", N_("Adjustment Mode"), N_("Adjustment mode"), sigmaId, makerTags, asciiString, -1, printValue), TagInfo(0x0016, "Quality", N_("Quality"), N_("Quality"), sigmaId, makerTags, asciiString, -1, printStripLabel), TagInfo(0x0017, "Firmware", N_("Firmware"), N_("Firmware"), sigmaId, makerTags, asciiString, -1, printValue), TagInfo(0x0018, "Software", N_("Software"), N_("Software"), sigmaId, makerTags, asciiString, -1, printValue), TagInfo(0x0019, "AutoBracket", N_("Auto Bracket"), N_("Auto bracket"), sigmaId, makerTags, asciiString, -1, printValue), // End of list marker TagInfo(0xffff, "(UnknownSigmaMakerNoteTag)", "(UnknownSigmaMakerNoteTag)", N_("Unknown SigmaMakerNote tag"), sigmaId, makerTags, asciiString, -1, printValue) }; const TagInfo* SigmaMakerNote::tagList() { return tagInfo_; } std::ostream& SigmaMakerNote::printStripLabel(std::ostream& os, const Value& value, const ExifData*) { std::string v = value.toString(); std::string::size_type pos = v.find(':'); if (pos != std::string::npos) { if (v[pos + 1] == ' ') ++pos; v = v.substr(pos + 1); } return os << v; } std::ostream& SigmaMakerNote::print0x0008(std::ostream& os, const Value& value, const ExifData*) { switch (value.toString()[0]) { case 'P': os << _("Program"); break; case 'A': os << _("Aperture priority"); break; case 'S': os << _("Shutter priority"); break; case 'M': os << _("Manual"); break; default: os << "(" << value << ")"; break; } return os; } std::ostream& SigmaMakerNote::print0x0009(std::ostream& os, const Value& value, const ExifData*) { switch (value.toString()[0]) { case 'A': os << _("Average"); break; case 'C': os << _("Center"); break; case '8': os << _("8-Segment"); break; default: os << "(" << value << ")"; break; } return os; } }} // namespace Internal, Exiv2 exiv2-0.23/src/jp2image.cpp0000644000175000017500000006227211732641407015316 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /* File: jp2image.cpp Version: $Rev: 2681 $ Author(s): Marco Piovanelli, Ovolab (marco) Author(s): Gilles Caulier (cgilles) History: 12-Mar-2007, marco: created */ // ***************************************************************************** #include "rcsid_int.hpp" EXIV2_RCSID("@(#) $Id: jp2image.cpp 2681 2012-03-22 15:19:35Z ahuggel $") // ***************************************************************************** //#define DEBUG 1 // ***************************************************************************** // included header files #ifdef _MSC_VER # include "exv_msvc.h" #else # include "exv_conf.h" #endif #include "jp2image.hpp" #include "tiffimage.hpp" #include "image.hpp" #include "basicio.hpp" #include "error.hpp" #include "futils.hpp" // + standard includes #include #include #include #include // JPEG-2000 box types const uint32_t kJp2BoxTypeJp2Header = 0x6a703268; // 'jp2h' const uint32_t kJp2BoxTypeImageHeader = 0x69686472; // 'ihdr' const uint32_t kJp2BoxTypeUuid = 0x75756964; // 'uuid' // JPEG-2000 UUIDs for embedded metadata // // See http://www.jpeg.org/public/wg1n2600.doc for information about embedding IPTC-NAA data in JPEG-2000 files // See http://www.adobe.com/devnet/xmp/pdfs/xmp_specification.pdf for information about embedding XMP data in JPEG-2000 files const unsigned char kJp2UuidExif[] = "JpgTiffExif->JP2"; const unsigned char kJp2UuidIptc[] = "\x33\xc7\xa4\xd2\xb8\x1d\x47\x23\xa0\xba\xf1\xa3\xe0\x97\xad\x38"; const unsigned char kJp2UuidXmp[] = "\xbe\x7a\xcf\xcb\x97\xa9\x42\xe8\x9c\x71\x99\x94\x91\xe3\xaf\xac"; // See section B.1.1 (JPEG 2000 Signature box) of JPEG-2000 specification const unsigned char Jp2Signature[12] = { 0x00, 0x00, 0x00, 0x0c, 0x6a, 0x50, 0x20, 0x20, 0x0d, 0x0a, 0x87, 0x0a }; const unsigned char Jp2Blank[] = { 0x00,0x00,0x00,0x0c,0x6a,0x50,0x20,0x20,0x0d,0x0a,0x87,0x0a,0x00,0x00,0x00,0x14, 0x66,0x74,0x79,0x70,0x6a,0x70,0x32,0x20,0x00,0x00,0x00,0x00,0x6a,0x70,0x32,0x20, 0x00,0x00,0x00,0x2d,0x6a,0x70,0x32,0x68,0x00,0x00,0x00,0x16,0x69,0x68,0x64,0x72, 0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x01,0x07,0x07,0x00,0x00,0x00,0x00, 0x00,0x0f,0x63,0x6f,0x6c,0x72,0x01,0x00,0x00,0x00,0x00,0x00,0x11,0x00,0x00,0x00, 0x00,0x6a,0x70,0x32,0x63,0xff,0x4f,0xff,0x51,0x00,0x29,0x00,0x00,0x00,0x00,0x00, 0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x07, 0x01,0x01,0xff,0x64,0x00,0x23,0x00,0x01,0x43,0x72,0x65,0x61,0x74,0x6f,0x72,0x3a, 0x20,0x4a,0x61,0x73,0x50,0x65,0x72,0x20,0x56,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20, 0x31,0x2e,0x39,0x30,0x30,0x2e,0x31,0xff,0x52,0x00,0x0c,0x00,0x00,0x00,0x01,0x00, 0x05,0x04,0x04,0x00,0x01,0xff,0x5c,0x00,0x13,0x40,0x40,0x48,0x48,0x50,0x48,0x48, 0x50,0x48,0x48,0x50,0x48,0x48,0x50,0x48,0x48,0x50,0xff,0x90,0x00,0x0a,0x00,0x00, 0x00,0x00,0x00,0x2d,0x00,0x01,0xff,0x5d,0x00,0x14,0x00,0x40,0x40,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x93,0xcf,0xb4, 0x04,0x00,0x80,0x80,0x80,0x80,0x80,0xff,0xd9 }; //! @cond IGNORE struct Jp2BoxHeader { uint32_t boxLength; uint32_t boxType; }; struct Jp2ImageHeaderBox { uint32_t imageHeight; uint32_t imageWidth; uint16_t componentCount; uint8_t bitsPerComponent; uint8_t compressionType; uint8_t colorspaceIsUnknown; uint8_t intellectualPropertyFlag; uint16_t compressionTypeProfile; }; struct Jp2UuidBox { uint8_t uuid[16]; }; //! @endcond // ***************************************************************************** // class member definitions namespace Exiv2 { Jp2Image::Jp2Image(BasicIo::AutoPtr io, bool create) : Image(ImageType::jp2, mdExif | mdIptc | mdXmp, io) { if (create) { if (io_->open() == 0) { #ifdef DEBUG std::cerr << "Exiv2::Jp2Image:: Creating JPEG2000 image to memory\n"; #endif IoCloser closer(*io_); if (io_->write(Jp2Blank, sizeof(Jp2Blank)) != sizeof(Jp2Blank)) { #ifdef DEBUG std::cerr << "Exiv2::Jp2Image:: Failed to create JPEG2000 image on memory\n"; #endif } } } } // Jp2Image::Jp2Image std::string Jp2Image::mimeType() const { return "image/jp2"; } void Jp2Image::setComment(const std::string& /*comment*/) { // Todo: implement me! throw(Error(32, "Image comment", "JP2")); } // Jp2Image::setComment void Jp2Image::readMetadata() { #ifdef DEBUG std::cerr << "Exiv2::Jp2Image::readMetadata: Reading JPEG-2000 file " << io_->path() << "\n"; #endif if (io_->open() != 0) { throw Error(9, io_->path(), strError()); } IoCloser closer(*io_); // Ensure that this is the correct image type if (!isJp2Type(*io_, true)) { if (io_->error() || io_->eof()) throw Error(14); throw Error(3, "JPEG-2000"); } long position = 0; Jp2BoxHeader box = {0,0}; Jp2BoxHeader subBox = {0,0}; Jp2ImageHeaderBox ihdr = {0,0,0,0,0,0,0,0}; Jp2UuidBox uuid = {{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}; while (io_->read((byte*)&box, sizeof(box)) == sizeof(box)) { position = io_->tell(); box.boxLength = getLong((byte*)&box.boxLength, bigEndian); #ifdef DEBUG std::cout << "Exiv2::Jp2Image::readMetadata: Position: " << position << "\n"; std::cout << "Exiv2::Jp2Image::readMetadata: Find box type: " << std::string((const char*)&box.boxType) << " lenght: " << box.boxLength << "\n"; #endif box.boxType = getLong((byte*)&box.boxType, bigEndian); if (box.boxLength == 0) { #ifdef DEBUG std::cout << "Exiv2::Jp2Image::readMetadata: Null Box size has been found. " "This is the last box of file.\n"; #endif return; } if (box.boxLength == 1) { // FIXME. Special case. the real box size is given in another place. } switch(box.boxType) { case kJp2BoxTypeJp2Header: { #ifdef DEBUG std::cout << "Exiv2::Jp2Image::readMetadata: JP2Header box found\n"; #endif if (io_->read((byte*)&subBox, sizeof(subBox)) == sizeof(subBox)) { subBox.boxLength = getLong((byte*)&subBox.boxLength, bigEndian); subBox.boxType = getLong((byte*)&subBox.boxType, bigEndian); if((subBox.boxType == kJp2BoxTypeImageHeader) && (io_->read((byte*)&ihdr, sizeof(ihdr)) == sizeof(ihdr))) { #ifdef DEBUG std::cout << "Exiv2::Jp2Image::readMetadata: Ihdr data found\n"; #endif ihdr.imageHeight = getLong((byte*)&ihdr.imageHeight, bigEndian); ihdr.imageWidth = getLong((byte*)&ihdr.imageWidth, bigEndian); ihdr.componentCount = getShort((byte*)&ihdr.componentCount, bigEndian); ihdr.compressionTypeProfile = getShort((byte*)&ihdr.compressionTypeProfile, bigEndian); pixelWidth_ = ihdr.imageWidth; pixelHeight_ = ihdr.imageHeight; } } break; } case kJp2BoxTypeUuid: { #ifdef DEBUG std::cout << "Exiv2::Jp2Image::readMetadata: UUID box found\n"; #endif if (io_->read((byte*)&uuid, sizeof(uuid)) == sizeof(uuid)) { DataBuf rawData; long bufRead; if(memcmp(uuid.uuid, kJp2UuidExif, sizeof(uuid)) == 0) { #ifdef DEBUG std::cout << "Exiv2::Jp2Image::readMetadata: Exif data found\n"; #endif // we've hit an embedded Exif block rawData.alloc(box.boxLength - (sizeof(box) + sizeof(uuid))); bufRead = io_->read(rawData.pData_, rawData.size_); if (io_->error()) throw Error(14); if (bufRead != rawData.size_) throw Error(20); if (rawData.size_ > 0) { // Find the position of Exif header in bytes array. const byte exifHeader[] = { 0x45, 0x78, 0x69, 0x66, 0x00, 0x00 }; long pos = -1; for (long i=0 ; i < rawData.size_-(long)sizeof(exifHeader) ; i++) { if (memcmp(exifHeader, &rawData.pData_[i], sizeof(exifHeader)) == 0) { pos = i; break; } } // If found it, store only these data at from this place. if (pos !=-1) { #ifdef DEBUG std::cout << "Exiv2::Jp2Image::readMetadata: Exif header found at position " << pos << "\n"; #endif pos = pos + sizeof(exifHeader); ByteOrder bo = TiffParser::decode(exifData(), iptcData(), xmpData(), rawData.pData_ + pos, rawData.size_ - pos); setByteOrder(bo); } } else { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Failed to decode Exif metadata.\n"; #endif exifData_.clear(); } } else if(memcmp(uuid.uuid, kJp2UuidIptc, sizeof(uuid)) == 0) { // we've hit an embedded IPTC block #ifdef DEBUG std::cout << "Exiv2::Jp2Image::readMetadata: Iptc data found\n"; #endif rawData.alloc(box.boxLength - (sizeof(box) + sizeof(uuid))); bufRead = io_->read(rawData.pData_, rawData.size_); if (io_->error()) throw Error(14); if (bufRead != rawData.size_) throw Error(20); if (IptcParser::decode(iptcData_, rawData.pData_, rawData.size_)) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Failed to decode IPTC metadata.\n"; #endif iptcData_.clear(); } } else if(memcmp(uuid.uuid, kJp2UuidXmp, sizeof(uuid)) == 0) { // we've hit an embedded XMP block #ifdef DEBUG std::cout << "Exiv2::Jp2Image::readMetadata: Xmp data found\n"; #endif rawData.alloc(box.boxLength - (sizeof(box) + sizeof(uuid))); bufRead = io_->read(rawData.pData_, rawData.size_); if (io_->error()) throw Error(14); if (bufRead != rawData.size_) throw Error(20); xmpPacket_.assign(reinterpret_cast(rawData.pData_), rawData.size_); std::string::size_type idx = xmpPacket_.find_first_of('<'); if (idx != std::string::npos && idx > 0) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Removing " << static_cast(idx) << " characters from the beginning of the XMP packet\n"; #endif xmpPacket_ = xmpPacket_.substr(idx); } if (xmpPacket_.size() > 0 && XmpParser::decode(xmpData_, xmpPacket_)) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Failed to decode XMP metadata.\n"; #endif } } } break; } default: { break; } } // Move to the next box. io_->seek(position - sizeof(box) + box.boxLength, BasicIo::beg); if (io_->error() || io_->eof()) throw Error(14); } } // Jp2Image::readMetadata void Jp2Image::writeMetadata() { if (io_->open() != 0) { throw Error(9, io_->path(), strError()); } IoCloser closer(*io_); BasicIo::AutoPtr tempIo(io_->temporary()); // may throw assert (tempIo.get() != 0); doWriteMetadata(*tempIo); // may throw io_->close(); io_->transfer(*tempIo); // may throw } // Jp2Image::writeMetadata void Jp2Image::doWriteMetadata(BasicIo& outIo) { if (!io_->isopen()) throw Error(20); if (!outIo.isopen()) throw Error(21); #ifdef DEBUG std::cout << "Exiv2::Jp2Image::doWriteMetadata: Writing JPEG-2000 file " << io_->path() << "\n"; std::cout << "Exiv2::Jp2Image::doWriteMetadata: tmp file created " << outIo.path() << "\n"; #endif // Ensure that this is the correct image type if (!isJp2Type(*io_, true)) { if (io_->error() || io_->eof()) throw Error(20); throw Error(22); } // Write JPEG2000 Signature. if (outIo.write(Jp2Signature, 12) != 12) throw Error(21); Jp2BoxHeader box = {0,0}; byte boxDataSize[4]; byte boxUUIDtype[4]; DataBuf bheaderBuf(8); // Box header : 4 bytes (data size) + 4 bytes (box type). // FIXME: Andreas, why the loop do not stop when EOF is taken from _io. The loop go out by an exception // generated by a zero size data read. while(io_->tell() < io_->size()) { #ifdef DEBUG std::cout << "Exiv2::Jp2Image::doWriteMetadata: Position: " << io_->tell() << " / " << io_->size() << "\n"; #endif // Read chunk header. std::memset(bheaderBuf.pData_, 0x00, bheaderBuf.size_); long bufRead = io_->read(bheaderBuf.pData_, bheaderBuf.size_); if (io_->error()) throw Error(14); if (bufRead != bheaderBuf.size_) throw Error(20); // Decode box header. box.boxLength = getLong(bheaderBuf.pData_, bigEndian); box.boxType = getLong(bheaderBuf.pData_ + 4, bigEndian); #ifdef DEBUG std::cout << "Exiv2::Jp2Image::doWriteMetadata: Find box type: " << bheaderBuf.pData_ + 4 << " lenght: " << box.boxLength << "\n"; #endif if (box.boxLength == 0) { #ifdef DEBUG std::cout << "Exiv2::Jp2Image::doWriteMetadata: Null Box size has been found. " "This is the last box of file.\n"; #endif box.boxLength = io_->size() - io_->tell() + 8; } if (box.boxLength == 1) { // FIXME. Special case. the real box size is given in another place. } // Read whole box : Box header + Box data (not fixed size - can be null). DataBuf boxBuf(box.boxLength); // Box header (8 bytes) + box data. memcpy(boxBuf.pData_, bheaderBuf.pData_, 8); // Copy header. bufRead = io_->read(boxBuf.pData_ + 8, box.boxLength - 8); // Extract box data. if (io_->error()) { #ifdef DEBUG std::cout << "Exiv2::Jp2Image::doWriteMetadata: Error reading source file\n"; #endif throw Error(14); } if (bufRead != (long)(box.boxLength - 8)) { #ifdef DEBUG std::cout << "Exiv2::Jp2Image::doWriteMetadata: Cannot read source file data\n"; #endif throw Error(20); } switch(box.boxType) { case kJp2BoxTypeJp2Header: { #ifdef DEBUG std::cout << "Exiv2::Jp2Image::doWriteMetadata: Write JP2Header box (lenght: " << box.boxLength << ")\n"; #endif if (outIo.write(boxBuf.pData_, boxBuf.size_) != boxBuf.size_) throw Error(21); // Write all updated metadata here, just after JP2Header. if (exifData_.count() > 0) { // Update Exif data to a new UUID box Blob blob; ExifParser::encode(blob, littleEndian, exifData_); if (blob.size()) { const unsigned char ExifHeader[] = {0x45, 0x78, 0x69, 0x66, 0x00, 0x00}; DataBuf rawExif(static_cast(sizeof(ExifHeader) + blob.size())); memcpy(rawExif.pData_, ExifHeader, sizeof(ExifHeader)); memcpy(rawExif.pData_ + sizeof(ExifHeader), &blob[0], blob.size()); DataBuf boxData(8 + 16 + rawExif.size_); ul2Data(boxDataSize, boxData.size_, Exiv2::bigEndian); ul2Data(boxUUIDtype, kJp2BoxTypeUuid, Exiv2::bigEndian); memcpy(boxData.pData_, boxDataSize, 4); memcpy(boxData.pData_ + 4, boxUUIDtype, 4); memcpy(boxData.pData_ + 8, kJp2UuidExif, 16); memcpy(boxData.pData_ + 8 + 16, rawExif.pData_, rawExif.size_); #ifdef DEBUG std::cout << "Exiv2::Jp2Image::doWriteMetadata: Write box with Exif metadata (lenght: " << boxData.size_ << ")\n"; #endif if (outIo.write(boxData.pData_, boxData.size_) != boxData.size_) throw Error(21); } } if (iptcData_.count() > 0) { // Update Iptc data to a new UUID box DataBuf rawIptc = IptcParser::encode(iptcData_); if (rawIptc.size_ > 0) { DataBuf boxData(8 + 16 + rawIptc.size_); ul2Data(boxDataSize, boxData.size_, Exiv2::bigEndian); ul2Data(boxUUIDtype, kJp2BoxTypeUuid, Exiv2::bigEndian); memcpy(boxData.pData_, boxDataSize, 4); memcpy(boxData.pData_ + 4, boxUUIDtype, 4); memcpy(boxData.pData_ + 8, kJp2UuidIptc, 16); memcpy(boxData.pData_ + 8 + 16, rawIptc.pData_, rawIptc.size_); #ifdef DEBUG std::cout << "Exiv2::Jp2Image::doWriteMetadata: Write box with Iptc metadata (lenght: " << boxData.size_ << ")\n"; #endif if (outIo.write(boxData.pData_, boxData.size_) != boxData.size_) throw Error(21); } } if (writeXmpFromPacket() == false) { if (XmpParser::encode(xmpPacket_, xmpData_) > 1) { #ifndef SUPPRESS_WARNINGS EXV_ERROR << "Failed to encode XMP metadata.\n"; #endif } } if (xmpPacket_.size() > 0) { // Update Xmp data to a new UUID box DataBuf xmp(reinterpret_cast(xmpPacket_.data()), static_cast(xmpPacket_.size())); DataBuf boxData(8 + 16 + xmp.size_); ul2Data(boxDataSize, boxData.size_, Exiv2::bigEndian); ul2Data(boxUUIDtype, kJp2BoxTypeUuid, Exiv2::bigEndian); memcpy(boxData.pData_, boxDataSize, 4); memcpy(boxData.pData_ + 4, boxUUIDtype, 4); memcpy(boxData.pData_ + 8, kJp2UuidXmp, 16); memcpy(boxData.pData_ + 8 + 16, xmp.pData_, xmp.size_); #ifdef DEBUG std::cout << "Exiv2::Jp2Image::doWriteMetadata: Write box with XMP metadata (lenght: " << boxData.size_ << ")\n"; #endif if (outIo.write(boxData.pData_, boxData.size_) != boxData.size_) throw Error(21); } break; } case kJp2BoxTypeUuid: { if(memcmp(boxBuf.pData_ + 8, kJp2UuidExif, sizeof(16)) == 0) { #ifdef DEBUG std::cout << "Exiv2::Jp2Image::doWriteMetadata: strip Exif Uuid box\n"; #endif } else if(memcmp(boxBuf.pData_ + 8, kJp2UuidIptc, sizeof(16)) == 0) { #ifdef DEBUG std::cout << "Exiv2::Jp2Image::doWriteMetadata: strip Iptc Uuid box\n"; #endif } else if(memcmp(boxBuf.pData_ + 8, kJp2UuidXmp, sizeof(16)) == 0) { #ifdef DEBUG std::cout << "Exiv2::Jp2Image::doWriteMetadata: strip Xmp Uuid box\n"; #endif } else { #ifdef DEBUG std::cout << "Exiv2::Jp2Image::doWriteMetadata: write Uuid box (lenght: " << box.boxLength << ")\n"; #endif if (outIo.write(boxBuf.pData_, boxBuf.size_) != boxBuf.size_) throw Error(21); } break; } default: { #ifdef DEBUG std::cout << "Exiv2::Jp2Image::doWriteMetadata: write box (lenght: " << box.boxLength << ")\n"; #endif if (outIo.write(boxBuf.pData_, boxBuf.size_) != boxBuf.size_) throw Error(21); break; } } } #ifdef DEBUG std::cout << "Exiv2::Jp2Image::doWriteMetadata: EOF\n"; #endif } // Jp2Image::doWriteMetadata // ************************************************************************* // free functions Image::AutoPtr newJp2Instance(BasicIo::AutoPtr io, bool create) { Image::AutoPtr image(new Jp2Image(io, create)); if (!image->good()) { image.reset(); } return image; } bool isJp2Type(BasicIo& iIo, bool advance) { const int32_t len = 12; byte buf[len]; iIo.read(buf, len); if (iIo.error() || iIo.eof()) { return false; } bool matched = (memcmp(buf, Jp2Signature, len) == 0); if (!advance || !matched) { iIo.seek(-len, BasicIo::cur); } return matched; } } // namespace Exiv2 exiv2-0.23/src/error.hpp0000644000175000017500000003001211732641407014741 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! @file error.hpp @brief Error class for exceptions, log message class @version $Rev: 2681 $ @author Andreas Huggel (ahu) ahuggel@gmx.net @date 15-Jan-04, ahu: created
11-Feb-04, ahu: isolated as a component */ #ifndef ERROR_HPP_ #define ERROR_HPP_ // ***************************************************************************** // included header files #include "types.hpp" // + standard includes #include #include #include #include // ***************************************************************************** // namespace extensions namespace Exiv2 { // ***************************************************************************** // class definitions /*! @brief Class for a log message, used by the library. Applications can set the log level and provide a customer log message handler (callback function). This class is meant to be used as a temporary object with the related macro-magic like this: EXV_WARNING << "Warning! Something looks fishy.\n"; which translates to if (LogMsg::warn >= LogMsg::level() && LogMsg::handler()) LogMsg(LogMsg::warn).os() << "Warning! Something looks fishy.\n"; The macros EXV_DEBUG, EXV_INFO, EXV_WARNING and EXV_ERROR are shorthands and ensure efficient use of the logging facility: If a log message doesn't need to be generated because of the log level setting, the temp object is not even created. Caveat: The entire log message is not processed in this case. So don't make that call any logic that always needs to be executed. */ class EXIV2API LogMsg { //! Prevent copy-construction: not implemented. LogMsg(const LogMsg&); //! Prevent assignment: not implemented. LogMsg& operator=(const LogMsg&); public: /*! @brief Defined log levels. To suppress all log messages, either set the log level to \c mute or set the log message handler to 0. */ enum Level { debug = 0, info = 1, warn = 2, error = 3, mute = 4 }; /*! @brief Type for a log message handler function. The function receives the log level and message and can process it in an application specific way. The default handler sends the log message to standard error. */ typedef void (*Handler)(int, const char*); //! @name Creators //@{ //! Constructor, takes the log message type as an argument explicit LogMsg(Level msgType) : msgType_(msgType) {} //! Destructor, passes the log message to the message handler depending on the log level ~LogMsg() { if (msgType_ >= level_ && handler_) handler_(msgType_, os_.str().c_str()); } //@} //! @name Manipulators //@{ //! Return a reference to the ostringstream which holds the log message std::ostringstream& os() { return os_; } //@} /*! @brief Set the log level. Only log messages with a level greater or equal \em level are sent to the log message handler. Default log level is \c warn. To suppress all log messages, set the log level to \c mute (or set the log message handler to 0). */ static void setLevel(Level level) { level_ = level; } /*! @brief Set the log message handler. The default handler writes log messages to standard error. To suppress all log messages, set the log message handler to 0 (or set the log level to \c mute). */ static void setHandler(Handler handler) { handler_ = handler; } //! Return the current log level static Level level() { return level_; } //! Return the current log message handler static Handler handler() { return handler_; } //! The default log handler. Sends the log message to standard error. static void defaultHandler(int level, const char* s); private: // DATA // The output level. Only messages with type >= level_ will be written static Level level_; // The log handler in use static Handler handler_; // The type of this log message const Level msgType_; // Holds the log message until it is passed to the message handler std::ostringstream os_; }; // class LogMsg // Macros for simple access //! Shorthand to create a temp debug log message object and return its ostringstream #define EXV_DEBUG if (LogMsg::debug >= LogMsg::level() && LogMsg::handler()) LogMsg(LogMsg::debug).os() //! Shorthand for a temp info log message object and return its ostringstream #define EXV_INFO if (LogMsg::info >= LogMsg::level() && LogMsg::handler()) LogMsg(LogMsg::info).os() //! Shorthand for a temp warning log message object and return its ostringstream #define EXV_WARNING if (LogMsg::warn >= LogMsg::level() && LogMsg::handler()) LogMsg(LogMsg::warn).os() //! Shorthand for a temp error log message object and return its ostringstream #define EXV_ERROR if (LogMsg::error >= LogMsg::level() && LogMsg::handler()) LogMsg(LogMsg::error).os() #ifdef _MSC_VER // Disable MSVC warnings "non - DLL-interface classkey 'identifier' used as base // for DLL-interface classkey 'identifier'" # pragma warning( disable : 4275 ) #endif //! Generalised toString function template std::basic_string toBasicString(const T& arg) { std::basic_ostringstream os; os << arg; return os.str(); } /*! @brief Error class interface. Allows the definition and use of a hierarchy of error classes which can all be handled in one catch block. Inherits from the standard exception base-class, to make life easier for library users (they have the option of catching most things via std::exception). */ class EXIV2API AnyError : public std::exception { public: //! @name Creators //@{ //! Virtual destructor. virtual ~AnyError() throw(); //@} //! @name Accessors //@{ //! Return the error code. virtual int code() const throw() =0; //@} }; // AnyError //! %AnyError output operator inline std::ostream& operator<<(std::ostream& os, const AnyError& error) { return os << error.what(); } /*! @brief Simple error class used for exceptions. An output operator is provided to print errors to a stream. */ template class EXV_DLLPUBLIC BasicError : public AnyError { public: //! @name Creators //@{ //! Constructor taking only an error code EXV_DLLLOCAL explicit BasicError(int code); //! Constructor taking an error code and one argument template EXV_DLLLOCAL BasicError(int code, const A& arg1); //! Constructor taking an error code and two arguments template EXV_DLLLOCAL BasicError(int code, const A& arg1, const B& arg2); //! Constructor taking an error code and three arguments template EXV_DLLLOCAL BasicError(int code, const A& arg1, const B& arg2, const C& arg3); //! Virtual destructor. (Needed because of throw()) EXV_DLLLOCAL virtual ~BasicError() throw(); //@} //! @name Accessors //@{ EXV_DLLLOCAL virtual int code() const throw(); /*! @brief Return the error message as a C-string. The pointer returned by what() is valid only as long as the BasicError object exists. */ EXV_DLLLOCAL virtual const char* what() const throw(); #ifdef EXV_UNICODE_PATH /*! @brief Return the error message as a wchar_t-string. The pointer returned by wwhat() is valid only as long as the BasicError object exists. */ EXV_DLLLOCAL virtual const wchar_t* wwhat() const throw(); #endif //@} private: //! @name Manipulators //@{ //! Assemble the error message from the arguments EXIV2API void setMsg(); //@} // DATA int code_; //!< Error code int count_; //!< Number of arguments std::basic_string arg1_; //!< First argument std::basic_string arg2_; //!< Second argument std::basic_string arg3_; //!< Third argument std::string msg_; //!< Complete error message #ifdef EXV_UNICODE_PATH std::wstring wmsg_; //!< Complete error message as a wide string #endif }; // class BasicError //! Error class used for exceptions (std::string based) typedef BasicError Error; #ifdef EXV_UNICODE_PATH //! Error class used for exceptions (std::wstring based) typedef BasicError WError; #endif // ***************************************************************************** // free functions, template and inline definitions //! Return the error message for the error with code \em code. EXIV2API const char* errMsg(int code); template BasicError::BasicError(int code) : code_(code), count_(0) { setMsg(); } template template BasicError::BasicError(int code, const A& arg1) : code_(code), count_(1), arg1_(toBasicString(arg1)) { setMsg(); } template template BasicError::BasicError(int code, const A& arg1, const B& arg2) : code_(code), count_(2), arg1_(toBasicString(arg1)), arg2_(toBasicString(arg2)) { setMsg(); } template template BasicError::BasicError(int code, const A& arg1, const B& arg2, const C& arg3) : code_(code), count_(3), arg1_(toBasicString(arg1)), arg2_(toBasicString(arg2)), arg3_(toBasicString(arg3)) { setMsg(); } template BasicError::~BasicError() throw() { } template int BasicError::code() const throw() { return code_; } template const char* BasicError::what() const throw() { return msg_.c_str(); } #ifdef EXV_UNICODE_PATH template const wchar_t* BasicError::wwhat() const throw() { return wmsg_.c_str(); } #endif #ifdef _MSC_VER # pragma warning( default : 4275 ) #endif } // namespace Exiv2 #endif // #ifndef ERROR_HPP_ exiv2-0.23/src/crwimage.hpp0000644000175000017500000001501611732641407015415 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! @file crwimage.hpp @brief Class CrwImage to access Canon CRW images.
References:
The Canon RAW (CRW) File Format by Phil Harvey @version $Rev: 2681 $ @author Andreas Huggel (ahu) ahuggel@gmx.net @date 28-Aug-05, ahu: created */ #ifndef CRWIMAGE_HPP_ #define CRWIMAGE_HPP_ // ***************************************************************************** // included header files #include "types.hpp" #include "image.hpp" #include "basicio.hpp" // + standard includes #include #include // ***************************************************************************** // namespace extensions namespace Exiv2 { // ***************************************************************************** // class declarations class ExifData; class IptcData; // ***************************************************************************** // class definitions // Add CRW to the supported image formats namespace ImageType { const int crw = 3; //!< CRW image type (see class CrwImage) } /*! @brief Class to access raw Canon CRW images. Only Exif metadata and a comment are supported. CRW format does not contain IPTC metadata. */ class EXIV2API CrwImage : public Image { public: //! @name Creators //@{ /*! @brief Constructor that can either open an existing CRW image or create a new image from scratch. If a new image is to be created, any existing data is overwritten. Since the constructor can not return a result, callers should check the good() method after object construction to determine success or failure. @param io An auto-pointer that owns a BasicIo instance used for reading and writing image metadata. \b Important: The constructor takes ownership of the passed in BasicIo instance through the auto-pointer. Callers should not continue to use the BasicIo instance after it is passed to this method. Use the Image::io() method to get a temporary reference. @param create Specifies if an existing image should be read (false) or if a new file should be created (true). */ CrwImage(BasicIo::AutoPtr io, bool create); //@} //! @name Manipulators //@{ void readMetadata(); void writeMetadata(); /*! @brief Not supported. CRW format does not contain IPTC metadata. Calling this function will throw an Error(32). */ void setIptcData(const IptcData& iptcData); //@} //! @name Accessors //@{ std::string mimeType() const; int pixelWidth() const; int pixelHeight() const; //@} private: //! @name NOT Implemented //@{ //! Copy constructor CrwImage(const CrwImage& rhs); //! Assignment operator CrwImage& operator=(const CrwImage& rhs); //@} }; // class CrwImage /*! Stateless parser class for Canon CRW images (Ciff format). */ class EXIV2API CrwParser { public: /*! @brief Decode metadata from a Canon CRW image in data buffer \em pData of length \em size into \em crwImage. This is the entry point to access image data in Ciff format. The parser uses classes CiffHeader, CiffEntry, CiffDirectory. @param pCrwImage Pointer to the %Exiv2 CRW image to hold the metadata read from the buffer. @param pData Pointer to the data buffer. Must point to the data of a CRW image; no checks are performed. @param size Length of the data buffer. @throw Error If the data buffer cannot be parsed. */ static void decode(CrwImage* pCrwImage, const byte* pData, uint32_t size); /*! @brief Encode metadata from the CRW image into a data buffer (the binary CRW image). @param blob Data buffer for the binary image (target). @param pData Pointer to the binary image data buffer. Must point to data in CRW format; no checks are performed. @param size Length of the data buffer. @param pCrwImage Pointer to the %Exiv2 CRW image with the metadata to encode. @throw Error If the metadata from the CRW image cannot be encoded. */ static void encode( Blob& blob, const byte* pData, uint32_t size, const CrwImage* pCrwImage ); }; // class CrwParser // ***************************************************************************** // template, inline and free functions // These could be static private functions on Image subclasses but then // ImageFactory needs to be made a friend. /*! @brief Create a new CrwImage instance and return an auto-pointer to it. Caller owns the returned object and the auto-pointer ensures that it will be deleted. */ EXIV2API Image::AutoPtr newCrwInstance(BasicIo::AutoPtr io, bool create); //! Check if the file iIo is a CRW image. EXIV2API bool isCrwType(BasicIo& iIo, bool advance); } // namespace Exiv2 #endif // #ifndef CRWIMAGE_HPP_ exiv2-0.23/src/tags.hpp0000644000175000017500000002156511732641407014563 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! @file tags.hpp @brief Exif tag and type information @version $Rev: 2681 $ @author Andreas Huggel (ahu) ahuggel@gmx.net @date 15-Jan-04, ahu: created
11-Feb-04, ahu: isolated as a component */ #ifndef TAGS_HPP_ #define TAGS_HPP_ // ***************************************************************************** // included header files #include "metadatum.hpp" #include "types.hpp" // + standard includes #include #include #include // ***************************************************************************** // namespace extensions namespace Exiv2 { // ***************************************************************************** // class declarations class ExifData; class ExifKey; class Value; struct TagInfo; // ***************************************************************************** // type definitions //! Type for a function pointer for functions interpreting the tag value typedef std::ostream& (*PrintFct)(std::ostream&, const Value&, const ExifData* pExifData); //! A function returning a tag list. typedef const TagInfo* (*TagListFct)(); // ***************************************************************************** // class definitions //! The details of an Exif group. Groups include IFDs and binary arrays. struct EXIV2API GroupInfo { struct GroupName; bool operator==(int ifdId) const; //!< Comparison operator for IFD id bool operator==(const GroupName& groupName) const; //!< Comparison operator for group name int ifdId_; //!< IFD id const char* ifdName_; //!< IFD name const char* groupName_; //!< Group name, unique for each group. TagListFct tagList_; //!< Tag list }; //! Search key to find a GroupInfo by its group name. struct EXIV2API GroupInfo::GroupName { GroupName(const std::string& groupName); //!< Constructor std::string g_; //!< Group name }; //! Tag information struct EXIV2API TagInfo { //! Constructor TagInfo( uint16_t tag, const char* name, const char* title, const char* desc, int ifdId, int sectionId, TypeId typeId, int16_t count, PrintFct printFct ); uint16_t tag_; //!< Tag const char* name_; //!< One word tag label const char* title_; //!< Tag title const char* desc_; //!< Short tag description int ifdId_; //!< Link to the (preferred) IFD int sectionId_; //!< Section id TypeId typeId_; //!< Type id int16_t count_; //!< The number of values (not bytes!), 0=any, -1=count not known. PrintFct printFct_; //!< Pointer to tag print function }; // struct TagInfo //! Access to Exif group and tag lists and misc. tag reference methods, implemented as a static class. class EXIV2API ExifTags { //! Prevent construction: not implemented. ExifTags(); //! Prevent copy-construction: not implemented. ExifTags(const ExifTags& rhs); //! Prevent assignment: not implemented. ExifTags& operator=(const ExifTags& rhs); public: //! Return read-only list of built-in groups static const GroupInfo* groupList(); //! Return read-only list of built-in \em groupName tags. static const TagInfo* tagList(const std::string& groupName); //! Print a list of all standard Exif tags to output stream static void taglist(std::ostream& os); //! Print the list of tags for \em groupName static void taglist(std::ostream& os, const std::string& groupName); //! Return the name of the section for an Exif \em key. static const char* sectionName(const ExifKey& key); //! Return the default number of components (not bytes!) \em key has. (0=any, -1=count not known) static uint16_t defaultCount(const ExifKey& key); //! Return the name of the IFD for the group. static const char* ifdName(const std::string& groupName); /*! @brief Return true if \em groupName is a makernote group. */ static bool isMakerGroup(const std::string& groupName); /*! @brief Return true if \em groupName is a TIFF or Exif IFD, else false. This is used to differentiate between standard Exif IFDs and IFDs associated with the makernote. */ static bool isExifGroup(const std::string& groupName); }; // class ExifTags /*! @brief Concrete keys for Exif metadata and access to Exif tag reference data. */ class EXIV2API ExifKey : public Key { public: //! Shortcut for an %ExifKey auto pointer. typedef std::auto_ptr AutoPtr; //! @name Creators //@{ /*! @brief Constructor to create an Exif key from a key string. @param key The key string. @throw Error if the first part of the key is not 'Exif' or the remainin parts of the key cannot be parsed and converted to a group name and tag name. */ explicit ExifKey(const std::string& key); /*! @brief Constructor to create an Exif key from the tag number and group name. @param tag The tag value @param groupName The name of the group, i.e., the second part of the Exif key. @throw Error if the key cannot be constructed from the tag number and group name. */ ExifKey(uint16_t tag, const std::string& groupName); /*! @brief Constructor to create an Exif key from a TagInfo instance. @param ti The TagInfo instance @throw Error if the key cannot be constructed from the tag number and group name. */ ExifKey(const TagInfo& ti); //! Copy constructor ExifKey(const ExifKey& rhs); //! Destructor virtual ~ExifKey(); //@} //! @name Manipulators //@{ /*! @brief Assignment operator. */ ExifKey& operator=(const ExifKey& rhs); //! Set the index. void setIdx(int idx); //@} //! @name Accessors //@{ virtual std::string key() const; virtual const char* familyName() const; virtual std::string groupName() const; //! Return the IFD id as an integer. (Do not use, this is meant for library internal use.) int ifdId() const; virtual std::string tagName() const; virtual uint16_t tag() const; virtual std::string tagLabel() const; //! Return the tag description. std::string tagDesc() const; // Todo: should be in the base class //! Return the default type id for this tag. TypeId defaultTypeId() const; // Todo: should be in the base class AutoPtr clone() const; //! Return the index (unique id of this key within the original Exif data, 0 if not set) int idx() const; //@} private: //! Internal virtual copy constructor. EXV_DLLLOCAL virtual ExifKey* clone_() const; private: // Pimpl idiom struct Impl; Impl* p_; }; // class ExifKey // ***************************************************************************** // free functions //! Output operator for TagInfo EXIV2API std::ostream& operator<<(std::ostream& os, const TagInfo& ti); } // namespace Exiv2 #endif // #ifndef TAGS_HPP_ exiv2-0.23/src/xmpsidecar.hpp0000644000175000017500000001041311732641407015752 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! @file xmpsidecar.hpp @brief An Image subclass to support XMP sidecar files @version $Rev: 2681 $ @author Andreas Huggel ahuggel@gmx.net @date 07-Mar-08, ahu: created */ #ifndef XMPSIDECAR_HPP_ #define XMPSIDECAR_HPP_ // ***************************************************************************** // included header files #include "image.hpp" #include "basicio.hpp" #include "types.hpp" // + standard includes #include // ***************************************************************************** // namespace extensions namespace Exiv2 { // ***************************************************************************** // class definitions // Add XMP to the supported image formats namespace ImageType { const int xmp = 10; //!< XMP sidecar files (see class XmpSidecar) } /*! @brief Class to access XMP sidecar files. They contain only XMP metadata. */ class EXIV2API XmpSidecar : public Image { public: //! @name Creators //@{ /*! @brief Constructor for an XMP sidecar file. Since the constructor can not return a result, callers should check the good() method after object construction to determine success or failure. @param io An auto-pointer that owns a BasicIo instance used for reading and writing image metadata. \b Important: The constructor takes ownership of the passed in BasicIo instance through the auto-pointer. Callers should not continue to use the BasicIo instance after it is passed to this method. Use the Image::io() method to get a temporary reference. @param create Specifies if an existing image should be read (false) or if a new image should be created (true). */ XmpSidecar(BasicIo::AutoPtr io, bool create); //@} //! @name Manipulators //@{ void readMetadata(); void writeMetadata(); /*! @brief Not supported. XMP sidecar files do not contain a comment. Calling this function will throw an instance of Error(32). */ void setComment(const std::string& comment); //@} //! @name Accessors //@{ std::string mimeType() const; //@} private: //! @name NOT Implemented //@{ //! Copy constructor XmpSidecar(const XmpSidecar& rhs); //! Assignment operator XmpSidecar& operator=(const XmpSidecar& rhs); //@} }; // class XmpSidecar // ***************************************************************************** // template, inline and free functions // These could be static private functions on Image subclasses but then // ImageFactory needs to be made a friend. /*! @brief Create a new XmpSidecar instance and return an auto-pointer to it. Caller owns the returned object and the auto-pointer ensures that it will be deleted. */ EXIV2API Image::AutoPtr newXmpInstance(BasicIo::AutoPtr io, bool create); //! Check if the file iIo is an XMP sidecar file. EXIV2API bool isXmpType(BasicIo& iIo, bool advance); } // namespace Exiv2 #endif // #ifndef XMPSIDECAR_HPP_ exiv2-0.23/src/makernote_int.hpp0000644000175000017500000006437511742031570016465 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! @file makernote_int.hpp @brief Makernote factory and registry, IFD makernote header, and camera vendor specific makernote implementations.
References:
[1] ExifTool by Phil Harvey
[2] Decoding raw digital photos in Linux by Dave Coffin @version $Rev: 2701 $ @author Andreas Huggel (ahu) ahuggel@gmx.net @date 11-Apr-06, ahu: created */ #ifndef MAKERNOTE_INT_HPP_ #define MAKERNOTE_INT_HPP_ // ***************************************************************************** // included header files #include "tifffwd_int.hpp" #include "tags_int.hpp" #include "types.hpp" // + standard includes #include // ***************************************************************************** // namespace extensions namespace Exiv2 { namespace Internal { // ***************************************************************************** // class definitions //! Type for a pointer to a function creating a makernote (image) typedef TiffComponent* (*NewMnFct)(uint16_t tag, IfdId group, IfdId mnGroup, const byte* pData, uint32_t size, ByteOrder byteOrder); //! Type for a pointer to a function creating a makernote (group) typedef TiffComponent* (*NewMnFct2)(uint16_t tag, IfdId group, IfdId mnGroup); //! Makernote registry structure struct TiffMnRegistry { struct MakeKey; /*! @brief Compare a TiffMnRegistry structure with a key being the make string from the image. The two are equal if TiffMnRegistry::make_ equals a substring of the key of the same size. E.g., registry = "OLYMPUS", key = "OLYMPUS OPTICAL CO.,LTD" (found in the image) match. */ bool operator==(const std::string& key) const; //! Compare a TiffMnRegistry structure with a makernote group bool operator==(IfdId key) const; // DATA const char* make_; //!< Camera make IfdId mnGroup_; //!< Group identifier NewMnFct newMnFct_; //!< Makernote create function (image) NewMnFct2 newMnFct2_; //!< Makernote create function (group) }; /*! @brief TIFF makernote factory for concrete TIFF makernotes. */ class TiffMnCreator { public: /*! @brief Create the Makernote for camera \em make and details from the makernote entry itself if needed. Return a pointer to the newly created TIFF component. Set tag and group of the new component to \em tag and \em group. This method is used when a makernote is parsed from the Exif block. @note Ownership for the component is transferred to the caller, who is responsible to delete the component. No smart pointer is used to indicate this transfer here in order to reduce file dependencies. */ static TiffComponent* create(uint16_t tag, IfdId group, const std::string& make, const byte* pData, uint32_t size, ByteOrder byteOrder); /*! @brief Create the Makernote for a given group. This method is used when a makernote is written back from Exif tags. */ static TiffComponent* create(uint16_t tag, IfdId group, IfdId mnGroup); protected: //! Prevent destruction (needed if used as a policy class) ~TiffMnCreator() {} private: static const TiffMnRegistry registry_[]; // * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! @file canonmn_int.hpp @brief Canon makernote tags.
References:
[1] EXIF MakerNote of Canon by David Burren
[2] Canon makernote tags by Phil Harvey @version $Rev: 2681 $ @author Andreas Huggel (ahu)
David Cannings (dc) Andi Clemens (ac) @date 18-Feb-04, ahu: created
07-Mar-04, ahu: isolated as a separate component
12-Aug-06, dc: started updating all tags */ #ifndef CANONMN_INT_HPP_ #define CANONMN_INT_HPP_ // ***************************************************************************** // included header files #include "tags.hpp" #include "types.hpp" // + standard includes #include #include #include // ***************************************************************************** // namespace extensions namespace Exiv2 { class Value; namespace Internal { // ***************************************************************************** // class definitions //! MakerNote for Canon cameras class CanonMakerNote { public: //! Return read-only list of built-in Canon tags static const TagInfo* tagList(); //! Return read-only list of built-in Canon Camera Settings tags static const TagInfo* tagListCs(); //! Return read-only list of built-in Canon Shot Info tags static const TagInfo* tagListSi(); //! Return read-only list of built-in Canon Panorama tags static const TagInfo* tagListPa(); //! Return read-only list of built-in Canon Custom Function tags static const TagInfo* tagListCf(); //! Return read-only list of built-in Canon Picture Info tags static const TagInfo* tagListPi(); //! Return read-only list of built-in Canon File Info tags static const TagInfo* tagListFi(); //! Return read-only list of built-in Canon Processing Info tags static const TagInfo* tagListPr(); //! @name Print functions for Canon %MakerNote tags //@{ //! Print the FileInfo FileNumber static std::ostream& printFiFileNumber(std::ostream& os, const Value& value, const ExifData* metadata); //! Print the focal length static std::ostream& printFocalLength(std::ostream& os, const Value& value, const ExifData*); //! Print the image number static std::ostream& print0x0008(std::ostream& os, const Value& value, const ExifData*); //! Print the serial number of the camera static std::ostream& print0x000c(std::ostream& os, const Value& value, const ExifData*); //! Self timer static std::ostream& printCs0x0002(std::ostream& os, const Value& value, const ExifData*); //! Camera lens type. For some values, the exact type can only be determined if \em metadata is provided. static std::ostream& printCsLensType(std::ostream& os, const Value& value, const ExifData* metadata); //! Camera lens information static std::ostream& printCsLens(std::ostream& os, const Value& value, const ExifData*); //! ISO speed used static std::ostream& printSi0x0002(std::ostream& os, const Value& value, const ExifData*); //! MeasuredEV static std::ostream& printSi0x0003(std::ostream& os, const Value& value, const ExifData*); //! Sequence number static std::ostream& printSi0x0009(std::ostream& os, const Value& value, const ExifData*); //! AF point used static std::ostream& printSi0x000e(std::ostream& os, const Value& value, const ExifData* pExifData); //! Subject distance static std::ostream& printSi0x0013(std::ostream& os, const Value& value, const ExifData*); //! Aperture static std::ostream& printSi0x0015(std::ostream& os, const Value& value, const ExifData*); //! Shutter speed static std::ostream& printSi0x0016(std::ostream& os, const Value& value, const ExifData*); //! MeasuredEV2 static std::ostream& printSi0x0017(std::ostream& os, const Value& value, const ExifData*); //@} private: // DATA //! Tag information static const TagInfo tagInfo_[]; static const TagInfo tagInfoCs_[]; static const TagInfo tagInfoSi_[]; static const TagInfo tagInfoCf_[]; static const TagInfo tagInfoPi_[]; static const TagInfo tagInfoFi_[]; static const TagInfo tagInfoPa_[]; static const TagInfo tagInfoPr_[]; }; // class CanonMakerNote // ***************************************************************************** // template, inline and free functions /*! @brief Convert Canon hex-based EV (modulo 0x20) to real number Ported from Phil Harvey's Image::ExifTool::Canon::CanonEv by Will Stokes 0x00 -> 0 0x0c -> 0.33333 0x10 -> 0.5 0x14 -> 0.66666 0x20 -> 1 .. 160 -> 5 128 -> 4 143 -> 4.46875 */ float canonEv(long val); }} // namespace Internal, Exiv2 #endif // #ifndef CANONMN_INT_HPP_ exiv2-0.23/src/path-test.cpp0000644000175000017500000000166111121502305015505 0ustar andreasandreas// ***************************************************************** -*- C++ -*- // path-test.cpp, $Rev: 1703 $ #include "utils.hpp" #include #include #include #include int main(int argc, char* const argv[]) { if (argc != 2) { std::cout << "Usage: " << argv[0] << " file\n"; return 1; } std::ifstream file(argv[1]); if (!file) { std::cerr << *argv[1] << ": Failed to open file for reading\n"; return 1; } std::string line; while (std::getline(file, line)) { std::string path, dir, base; std::istringstream is(line); is >> path >> dir >> base; std::string d = Util::dirname(path); std::string b = Util::basename(path); if (d != dir || b != base) { std::cout << path << "\t'" << d << "'\t '" << b << "'\t ==> Testcase failed\n"; } } return 0; } exiv2-0.23/src/gifimage.hpp0000644000175000017500000001142211732641407015364 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! @file gifimage.hpp @brief GIF image, implemented using the following references: GIF89 specification by W3C
@version $Rev: 2681 $ @author Marco Piovanelli, Ovolab (marco) marco.piovanelli@pobox.com @date 26-Feb-2007, marco: created */ #ifndef GIFIMAGE_HPP_ #define GIFIMAGE_HPP_ // ***************************************************************************** // included header files #include "exif.hpp" #include "iptc.hpp" #include "image.hpp" #include "types.hpp" // + standard includes #include // ***************************************************************************** // namespace extensions namespace Exiv2 { // ***************************************************************************** // class definitions // Add GIF to the supported image formats namespace ImageType { const int gif = 11; //!< GIF image type (see class GifImage) } /*! @brief Class to access raw GIF images. Exif/IPTC metadata are supported directly. */ class EXIV2API GifImage : public Image { //! @name NOT Implemented //@{ //! Copy constructor GifImage(const GifImage& rhs); //! Assignment operator GifImage& operator=(const GifImage& rhs); //@} public: //! @name Creators //@{ /*! @brief Constructor to open a GIF image. Since the constructor can not return a result, callers should check the good() method after object construction to determine success or failure. @param io An auto-pointer that owns a BasicIo instance used for reading and writing image metadata. \b Important: The constructor takes ownership of the passed in BasicIo instance through the auto-pointer. Callers should not continue to use the BasicIo instance after it is passed to this method. Use the Image::io() method to get a temporary reference. */ GifImage(BasicIo::AutoPtr io); //@} //! @name Manipulators //@{ void readMetadata(); /*! @brief Todo: Write metadata back to the image. This method is not yet(?) implemented. Calling it will throw an Error(31). */ void writeMetadata(); /*! @brief Todo: Not supported yet(?). Calling this function will throw an instance of Error(32). */ void setExifData(const ExifData& exifData); /*! @brief Todo: Not supported yet(?). Calling this function will throw an instance of Error(32). */ void setIptcData(const IptcData& iptcData); /*! @brief Not supported. Calling this function will throw an instance of Error(32). */ void setComment(const std::string& comment); //@} //! @name Accessors //@{ std::string mimeType() const; //@} }; // class GifImage // ***************************************************************************** // template, inline and free functions // These could be static private functions on Image subclasses but then // ImageFactory needs to be made a friend. /*! @brief Create a new GifImage instance and return an auto-pointer to it. Caller owns the returned object and the auto-pointer ensures that it will be deleted. */ EXIV2API Image::AutoPtr newGifInstance(BasicIo::AutoPtr io, bool create); //! Check if the file iIo is a GIF image. EXIV2API bool isGifType(BasicIo& iIo, bool advance); } // namespace Exiv2 #endif // #ifndef GIFIMAGE_HPP_ exiv2-0.23/src/olympusmn_int.hpp0000644000175000017500000001407111732641407016534 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! @file olympusmn_int.hpp @brief Olympus makernote tags.
References:
[1] Exif file format, Appendix 1: MakerNote of Olympus Digicams by TsuruZoh Tachibanaya
[2] ExifTool by Phil Harvey
[3] Olympus Makernote Format Specification by Evan Hunter
[4] email communication with Will Stokes @version $Rev: 2681 $ @author Andreas Huggel (ahu) ahuggel@gmx.net @author Will Stokes (wuz) wstokes@gmail.com @author Gilles Caulier (gc) caulier dot gilles at gmail dot com @author Greg Mansfield G.Mansfield at computer dot org @date 10-Mar-05, wuz: created */ #ifndef OLYMPUSMN_INT_HPP_ #define OLYMPUSMN_INT_HPP_ // ***************************************************************************** // included header files #include "tags.hpp" #include "types.hpp" // + standard includes #include #include #include // ***************************************************************************** // namespace extensions namespace Exiv2 { namespace Internal { // ***************************************************************************** // class definitions //! MakerNote for Olympus cameras class OlympusMakerNote { public: //! Return read-only list of built-in Olympus tags static const TagInfo* tagList(); //! Return read-only list of built-in Olympus Camera Settings tags static const TagInfo* tagListCs(); //! Return read-only list of built-in Olympus Equipment tags static const TagInfo* tagListEq(); //! Return read-only list of built-in Olympus Raw Development tags static const TagInfo* tagListRd(); //! Return read-only list of built-in Olympus Raw Development 2 tags static const TagInfo* tagListRd2(); //! Return read-only list of built-in Olympus Image Processing tags static const TagInfo* tagListIp(); //! Return read-only list of built-in Olympus Focus Info tags static const TagInfo* tagListFi(); //! Return read-only list of built-in Olympus FE tags static const TagInfo* tagListFe(); //! Return read-only list of built-in Olympus Raw Info tags static const TagInfo* tagListRi(); //! @name Print functions for Olympus %MakerNote tags //@{ //! Print 'Special Mode' static std::ostream& print0x0200(std::ostream& os, const Value& value, const ExifData*); //! Print Digital Zoom Factor static std::ostream& print0x0204(std::ostream& os, const Value& value, const ExifData*); //! Print White Balance Mode static std::ostream& print0x1015(std::ostream& os, const Value& value, const ExifData*); //! Print Olympus equipment Lens type static std::ostream& print0x0201(std::ostream& os, const Value& value, const ExifData*); //! Print Olympus CamerID static std::ostream& print0x0209(std::ostream& os, const Value& value, const ExifData*); //! Print Olympus equipment Extender static std::ostream& printEq0x0301(std::ostream& os, const Value& value, const ExifData*); //! Print Olympus camera settings Focus Mode static std::ostream& printCs0x0301(std::ostream& os, const Value& value, const ExifData*); //! Print Olympus camera settings Gradation static std::ostream& print0x050f(std::ostream& os, const Value& value, const ExifData*); //! Print Olympus camera settings Noise Filter static std::ostream& print0x0527(std::ostream& os, const Value& value, const ExifData*); //! Print Olympus ArtFilter static std::ostream& print0x0529(std::ostream& os, const Value& value, const ExifData*); //! Print Olympus focus info ManualFlash static std::ostream& print0x1209(std::ostream& os, const Value& value, const ExifData*); //! Print Olympus focus info AF Point static std::ostream& print0x0308(std::ostream& os, const Value& value, const ExifData*); //! Print Olympus generic static std::ostream& printGeneric(std::ostream& os, const Value& value, const ExifData*); //@} private: //! Tag information static const TagInfo tagInfo_[]; static const TagInfo tagInfoCs_[]; static const TagInfo tagInfoEq_[]; static const TagInfo tagInfoRd_[]; static const TagInfo tagInfoRd2_[]; static const TagInfo tagInfoIp_[]; static const TagInfo tagInfoFi_[]; static const TagInfo tagInfoFe_[]; static const TagInfo tagInfoRi_[]; }; // class OlympusMakerNote }} // namespace Internal, Exiv2 #endif // #ifndef OLYMPUSMN_INT_HPP_ exiv2-0.23/src/rw2image.hpp0000644000175000017500000001300011732641407015323 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! @file rw2image.hpp @brief Class Rw2Image @version $Rev: 2681 $ @author Andreas Huggel (ahu) ahuggel@gmx.net @date 06-Jan-09, ahu: created */ #ifndef RW2IMAGE_HPP_ #define RW2IMAGE_HPP_ // ***************************************************************************** // included header files #include "image.hpp" #include "basicio.hpp" #include "types.hpp" // + standard includes #include // ***************************************************************************** // namespace extensions namespace Exiv2 { // ***************************************************************************** // class definitions // Add RW2 to the supported image formats namespace ImageType { const int rw2 = 16; //!< RW2 image type (see class Rw2Image) } /*! @brief Class to access raw Panasonic RW2 images. Exif metadata is supported directly, IPTC and XMP are read from the Exif data, if present. */ class EXIV2API Rw2Image : public Image { public: //! @name Creators //@{ /*! @brief Constructor to open an existing RW2 image. Since the constructor can not return a result, callers should check the good() method after object construction to determine success or failure. @param io An auto-pointer that owns a BasicIo instance used for reading and writing image metadata. \b Important: The constructor takes ownership of the passed in BasicIo instance through the auto-pointer. Callers should not continue to use the BasicIo instance after it is passed to this method. Use the Image::io() method to get a temporary reference. */ Rw2Image(BasicIo::AutoPtr io); //@} //! @name Manipulators //@{ void readMetadata(); /*! @brief Todo: Write metadata back to the image. This method is not yet implemented. Calling it will throw an Error(31). */ void writeMetadata(); /*! @brief Todo: Not supported yet, requires writeMetadata(). Calling this function will throw an Error(32). */ void setExifData(const ExifData& exifData); /*! @brief Todo: Not supported yet, requires writeMetadata(). Calling this function will throw an Error(32). */ void setIptcData(const IptcData& iptcData); /*! @brief Not supported. RW2 format does not contain a comment. Calling this function will throw an Error(32). */ void setComment(const std::string& comment); //@} //! @name Accessors //@{ std::string mimeType() const; int pixelWidth() const; int pixelHeight() const; //@} private: //! @name NOT implemented //@{ //! Copy constructor Rw2Image(const Rw2Image& rhs); //! Assignment operator Rw2Image& operator=(const Rw2Image& rhs); //@} }; // class Rw2Image /*! @brief Stateless parser class for data in RW2 format. Images use this class to decode and encode RW2 data. Only decoding is currently implemented. See class TiffParser for details. */ class EXIV2API Rw2Parser { public: /*! @brief Decode metadata from a buffer \em pData of length \em size with data in RW2 format to the provided metadata containers. See TiffParser::decode(). */ static ByteOrder decode( ExifData& exifData, IptcData& iptcData, XmpData& xmpData, const byte* pData, uint32_t size ); }; // class Rw2Parser // ***************************************************************************** // template, inline and free functions // These could be static private functions on Image subclasses but then // ImageFactory needs to be made a friend. /*! @brief Create a new Rw2Image instance and return an auto-pointer to it. Caller owns the returned object and the auto-pointer ensures that it will be deleted. */ EXIV2API Image::AutoPtr newRw2Instance(BasicIo::AutoPtr io, bool create); //! Check if the file iIo is a RW2 image. EXIV2API bool isRw2Type(BasicIo& iIo, bool advance); } // namespace Exiv2 #endif // #ifndef RW2IMAGE_HPP_ exiv2-0.23/src/sonymn.cpp0000644000175000017500000010250011732641407015130 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /* File: sonymn.cpp Version: $Rev: 2681 $ Author(s): Andreas Huggel (ahu) History: 18-Apr-05, ahu: created */ // ***************************************************************************** #include "rcsid_int.hpp" EXIV2_RCSID("@(#) $Id: sonymn.cpp 2681 2012-03-22 15:19:35Z ahuggel $") // ***************************************************************************** // included header files #include "types.hpp" #include "minoltamn_int.hpp" #include "sonymn_int.hpp" #include "tags_int.hpp" #include "value.hpp" #include "i18n.h" // NLS support. // + standard includes #include #include #include #include #include // ***************************************************************************** // class member definitions namespace Exiv2 { namespace Internal { // -- Standard Sony Makernotes tags --------------------------------------------------------------- //! Lookup table to translate Sony Auto HDR values to readable labels extern const TagDetails sonyHDRMode[] = { { 0x00000, N_("Off") }, { 0x10001, N_("Auto") }, { 0x10010, "1" }, { 0x10012, "2" }, { 0x10014, "3" }, { 0x10016, "4" }, { 0x10018, "5" } }; //! Lookup table to translate Sony model ID values to readable labels extern const TagDetails sonyModelId[] = { { 2, "DSC-R1" }, { 256, "DSLR-A100" }, { 257, "DSLR-A900" }, { 258, "DSLR-A700" }, { 259, "DSLR-A200" }, { 260, "DSLR-A350" }, { 261, "DSLR-A300" }, { 263, "DSLR-A380" }, { 264, "DSLR-A330" }, { 265, "DSLR-A230" }, { 269, "DSLR-A850" }, { 273, "DSLR-A550" }, { 274, "DSLR-A500" }, { 275, "DSLR-A450" }, { 278, "NEX-5" }, { 279, "NEX-3" } }; //! Lookup table to translate Sony dynamic range optimizer values to readable labels extern const TagDetails print0xb025[] = { { 0, N_("Off") }, { 1, N_("Standard ") }, { 2, N_("Advanced Auto") }, { 3, N_("Auto") }, { 8, N_("Advanced Lv1") }, { 9, N_("Advanced Lv2") }, { 10, N_("Advanced Lv3") }, { 11, N_("Advanced Lv4") }, { 12, N_("Advanced Lv5") }, { 16, "1" }, { 17, "2" }, { 18, "3" }, { 19, "4" }, { 20, "5" } }; //! Lookup table to translate Sony exposure mode values to readable labels extern const TagDetails sonyExposureMode[] = { { 0, N_("Auto") }, { 1, N_("Portrait") }, { 2, N_("Beach") }, { 4, N_("Snow") }, { 5, N_("Landscape ") }, { 6, N_("Program") }, { 7, N_("Aperture priority") }, { 8, N_("Shutter priority") }, { 9, N_("Night Scene / Twilight") }, { 10, N_("Hi-Speed Shutter") }, { 11, N_("Twilight Portrait") }, { 12, N_("Soft Snap") }, { 13, N_("Fireworks") }, { 14, N_("Smile Shutter") }, { 15, N_("Manual") }, { 18, N_("High Sensitivity") }, { 20, N_("Advanced Sports Shooting") }, { 29, N_("Underwater") }, { 33, N_("Gourmet") }, { 34, N_("Panorama") }, { 35, N_("Handheld Twilight") }, { 36, N_("Anti Motion Blur") }, { 37, N_("Pet") }, { 38, N_("Backlight Correction HDR") }, { 65535, N_("n/a") } }; //! Lookup table to translate Sony JPEG Quality values to readable labels extern const TagDetails sonyJPEGQuality[] = { { 0, N_("Normal") }, { 1, N_("Fine") }, { 65535, N_("n/a") } }; //! Lookup table to translate Sony anti-blur values to readable labels extern const TagDetails sonyAntiBlur[] = { { 0, N_("Off") }, { 1, N_("On (Continuous)") }, { 2, N_("On (Shooting)") }, { 65535, N_("n/a") } }; //! Lookup table to translate Sony dynamic range optimizer values to readable labels extern const TagDetails print0xb04f[] = { { 0, N_("Off") }, { 1, N_("Standard") }, { 2, N_("Plus") } }; //! Lookup table to translate Sony Intelligent Auto values to readable labels extern const TagDetails sonyIntelligentAuto[] = { { 0, N_("Off") }, { 1, N_("On") }, { 2, N_("Advanced") } }; //! Lookup table to translate Sony WB values to readable labels extern const TagDetails sonyWhiteBalance[] = { { 0, N_("Auto") }, { 4, N_("Manual") }, { 5, N_("Daylight") }, { 6, N_("Cloudy") }, { 7, N_("White Flourescent") }, { 8, N_("Cool White Flourescent") }, { 9, N_("Day White Flourescent") }, { 14, N_("Incandescent") }, { 15, N_("Flash") }, { 17, N_("Underwater 1 (Blue Water)") }, { 18, N_("Underwater 2 (Green Water)") } }; //! Lookup table to translate Sony AF mode values to readable labels extern const TagDetails sonyFocusMode[] = { { 1, "AF-S" }, { 2, "AF-C" }, { 4, N_("Permanent-AF") }, { 65535, N_("n/a") } }; //! Lookup table to translate Sony AF mode values to readable labels extern const TagDetails sonyAFMode[] = { { 0, N_("Default") }, { 1, N_("Multi AF") }, { 2, N_("Center AF") }, { 3, N_("Spot AF") }, { 4, N_("Flexible Spot AF") }, { 6, N_("Touch AF") }, { 14, N_("Manual Focus") }, { 15, N_("Face Detected") }, { 65535, N_("n/a") } }; //! Lookup table to translate Sony AF illuminator values to readable labels extern const TagDetails sonyAFIlluminator[] = { { 0, N_("Off") }, { 1, N_("Auto") }, { 65535, N_("n/a") } }; //! Lookup table to translate Sony macro mode values to readable labels extern const TagDetails sonyMacroMode[] = { { 0, N_("Off") }, { 1, N_("On") }, { 2, N_("Close Focus") }, { 65535, N_("n/a") } }; //! Lookup table to translate Sony flash level values to readable labels extern const TagDetails sonyFlashLevel[] = { { -32768, N_("Low") }, { -1, N_("n/a") }, { 0, N_("Normal") }, { 32767, N_("High") } }; //! Lookup table to translate Sony release mode values to readable labels extern const TagDetails sonyReleaseMode[] = { { 0, N_("Normal") }, { 2, N_("Burst") }, { 5, N_("Exposure Bracketing") }, { 6, N_("White Balance Bracketing") }, { 65535, N_("n/a") } }; //! Lookup table to translate Sony sequence number values to readable labels extern const TagDetails sonySequenceNumber[] = { { 0, N_("Single") }, { 65535, N_("n/a") } }; //! Lookup table to translate Sony long exposure noise reduction values to readable labels extern const TagDetails sonyLongExposureNoiseReduction[] = { { 0, N_("Off") }, { 1, N_("On") }, { 65535, N_("n/a") } }; std::ostream& SonyMakerNote::print0xb000(std::ostream& os, const Value& value, const ExifData*) { if (value.count() != 4) { os << "(" << value << ")"; } else { std::string val = value.toString(0) + value.toString(1) + value.toString(2) + value.toString(3); if (val == "0002") os << "JPEG"; else if (val == "1000") os << "SR2"; else if (val == "2000") os << "ARW 1.0"; else if (val == "3000") os << "ARW 2.0"; else if (val == "3100") os << "ARW 2.1"; else if (val == "3200") os << "ARW 2.2"; else os << "(" << value << ")"; } return os; } std::ostream& SonyMakerNote::printImageSize(std::ostream& os, const Value& value, const ExifData*) { if (value.count() == 2) os << value.toString(0) << " x " << value.toString(1); else os << "(" << value << ")"; return os; } // Sony MakerNote Tag Info const TagInfo SonyMakerNote::tagInfo_[] = { TagInfo(0x0102, "Quality", N_("Image Quality"), N_("Image quality"), sony1Id, makerTags, unsignedLong, -1, printMinoltaSonyImageQuality), TagInfo(0x0104, "FlashExposureComp", N_("Flash Exposure Compensation"), N_("Flash exposure compensation in EV"), sony1Id, makerTags, signedRational, -1, print0x9204), TagInfo(0x0105, "Teleconverter", N_("Teleconverter Model"), N_("Teleconverter Model"), sony1Id, makerTags, unsignedLong, -1, printMinoltaSonyTeleconverterModel), TagInfo(0x0112, "WhiteBalanceFineTune", N_("White Balance Fine Tune"), N_("White Balance Fine Tune Value"), sony1Id, makerTags, unsignedLong, -1, printValue), TagInfo(0x0114, "CameraSettings", N_("Camera Settings"), N_("Camera Settings"), sony1Id, makerTags, undefined, -1, printValue), TagInfo(0x0115, "WhiteBalance", N_("White Balance"), N_("White balance"), sony1Id, makerTags, unsignedLong, -1, printMinoltaSonyWhiteBalanceStd), TagInfo(0x0116, "0x0116", "0x0116", N_("Unknown"), sony1Id, makerTags, undefined, -1, printValue), TagInfo(0x0E00, "PrintIM", N_("Print IM"), N_("PrintIM information"), sony1Id, makerTags, undefined, -1, printValue), TagInfo(0x1000, "MultiBurstMode", N_("Multi Burst Mode"), N_("Multi Burst Mode"), sony1Id, makerTags, undefined, -1, printMinoltaSonyBoolValue), TagInfo(0x1001, "MultiBurstImageWidth", N_("Multi Burst Image Width"), N_("Multi Burst Image Width"), sony1Id, makerTags, unsignedShort, -1, printValue), TagInfo(0x1002, "MultiBurstImageHeight", N_("Multi Burst Image Height"), N_("Multi Burst Image Height"), sony1Id, makerTags, unsignedShort, -1, printValue), // TODO : Implement Panorama tags decoding. TagInfo(0x1003, "Panorama", N_("Panorama"), N_("Panorama"), sony1Id, makerTags, undefined, -1, printValue), TagInfo(0x2000, "0x2000", "0x2000", N_("Unknown"), sony1Id, makerTags, undefined, -1, printValue), TagInfo(0x2001, "PreviewImage", N_("Preview Image"), N_("JPEG preview image"), sony1Id, makerTags, undefined, -1, printValue), TagInfo(0x2002, "0x2002", "0x2002", N_("Unknown"), sony1Id, makerTags, unsignedLong, -1, printValue), TagInfo(0x2003, "0x2003", "0x2003", N_("Unknown"), sony1Id, makerTags, asciiString, -1, printValue), TagInfo(0x2004, "Contrast", "Contrast", N_("Contrast"), sony1Id, makerTags, signedLong, -1, printValue), TagInfo(0x2005, "Saturation", "Saturation", N_("Saturation"), sony1Id, makerTags, signedLong, -1, printValue), TagInfo(0x2006, "0x2006", "0x2006", N_("Unknown"), sony1Id, makerTags, signedLong, -1, printValue), TagInfo(0x2007, "0x2007", "0x2007", N_("Unknown"), sony1Id, makerTags, signedLong, -1, printValue), TagInfo(0x2008, "0x2008", "0x2008", N_("Unknown"), sony1Id, makerTags, signedLong, -1, printValue), TagInfo(0x2009, "0x2009", "0x2009", N_("Unknown"), sony1Id, makerTags, unsignedShort, -1, printValue), TagInfo(0x200A, "AutoHDR", N_("Auto HDR"), N_("High Definition Range Mode"), sony1Id, makerTags, unsignedLong, -1, EXV_PRINT_TAG(sonyHDRMode)), // TODO : Implement Shot Info tags decoding. TagInfo(0x3000, "ShotInfo", N_("Shot Info"), N_("Shot Information"), sony1Id, makerTags, undefined, -1, printValue), TagInfo(0xB000, "FileFormat", N_("File Format"), N_("File Format"), sony1Id, makerTags, unsignedByte, -1, print0xb000), TagInfo(0xB001, "SonyModelID", N_("Sony Model ID"), N_("Sony Model ID"), sony1Id, makerTags, unsignedShort, -1, EXV_PRINT_TAG(sonyModelId)), TagInfo(0xB020, "ColorReproduction", N_("Color Reproduction"), N_("Color Reproduction"), sony1Id, makerTags, asciiString, -1, printValue), TagInfo(0xb021, "ColorTemperature", N_("Color Temperature"), N_("Color Temperature"), sony1Id, makerTags, unsignedLong, -1, printValue), TagInfo(0xB022, "ColorCompensationFilter", N_("Color Compensation Filter"), N_("Color Compensation Filter: negative is green, positive is magenta"), sony1Id, makerTags, unsignedLong, -1, printValue), TagInfo(0xB023, "SceneMode", N_("Scene Mode"), N_("Scene Mode"), sony1Id, makerTags, unsignedLong, -1, printMinoltaSonySceneMode), TagInfo(0xB024, "ZoneMatching", N_("Zone Matching"), N_("Zone Matching"), sony1Id, makerTags, unsignedLong, -1, printMinoltaSonyZoneMatching), TagInfo(0xB025, "DynamicRangeOptimizer", N_("Dynamic Range Optimizer"), N_("Dynamic Range Optimizer"), sony1Id, makerTags, unsignedLong, -1, EXV_PRINT_TAG(print0xb025)), TagInfo(0xB026, "ImageStabilization", N_("Image Stabilization"), N_("Image stabilization"), sony1Id, makerTags, unsignedLong, -1, printMinoltaSonyBoolValue), TagInfo(0xB027, "LensID", N_("Lens ID"), N_("Lens identifier"), sony1Id, makerTags, unsignedLong, -1, printMinoltaSonyLensID), TagInfo(0xB028, "MinoltaMakerNote", N_("Minolta MakerNote"), N_("Minolta MakerNote"), sony1Id, makerTags, undefined, -1, printValue), TagInfo(0xB029, "ColorMode", N_("Color Mode"), N_("Color Mode"), sony1Id, makerTags, unsignedLong, -1, printMinoltaSonyColorMode), TagInfo(0xB02B, "FullImageSize", N_("Full Image Size"), N_("Full Image Size"), sony1Id, makerTags, unsignedLong, -1, printImageSize), TagInfo(0xB02C, "PreviewImageSize", N_("Preview Image Size"), N_("Preview image size"), sony1Id, makerTags, unsignedLong, -1, printImageSize), TagInfo(0xB040, "Macro", N_("Macro"), N_("Macro"), sony1Id, makerTags, unsignedShort, -1, EXV_PRINT_TAG(sonyMacroMode)), TagInfo(0xB041, "ExposureMode", N_("Exposure Mode"), N_("Exposure Mode"), sony1Id, makerTags, unsignedShort, -1, EXV_PRINT_TAG(sonyExposureMode)), TagInfo(0xB042, "FocusMode", N_("Focus Mode"), N_("Focus Mode"), sony1Id, makerTags, unsignedShort, -1, EXV_PRINT_TAG(sonyFocusMode)), TagInfo(0xB043, "AFMode", N_("AF Mode"), N_("AF Mode"), sony1Id, makerTags, unsignedShort, -1, EXV_PRINT_TAG(sonyAFMode)), TagInfo(0xB044, "AFIlluminator", N_("AF Illuminator"), N_("AF Illuminator"), sony1Id, makerTags, unsignedShort, -1, EXV_PRINT_TAG(sonyAFIlluminator)), TagInfo(0xB047, "JPEGQuality", N_("JPEG Quality"), N_("JPEG Quality"), sony1Id, makerTags, unsignedShort, -1, EXV_PRINT_TAG(sonyJPEGQuality)), TagInfo(0xB048, "FlashLevel", N_("Flash Level"), N_("Flash Level"), sony1Id, makerTags, signedShort, -1, EXV_PRINT_TAG(sonyFlashLevel)), TagInfo(0xB049, "ReleaseMode", N_("Release Mode"), N_("Release Mode"), sony1Id, makerTags, unsignedShort, -1, EXV_PRINT_TAG(sonyReleaseMode)), TagInfo(0xB04A, "SequenceNumber", N_("Sequence Number"), N_("Shot number in continous burst mode"), sony1Id, makerTags, unsignedShort, -1, EXV_PRINT_TAG(sonySequenceNumber)), TagInfo(0xB04B, "AntiBlur", N_("Anti-Blur"), N_("Anti-Blur"), sony1Id, makerTags, unsignedShort, -1, EXV_PRINT_TAG(sonyAntiBlur)), TagInfo(0xB04E, "LongExposureNoiseReduction", N_("Long Exposure Noise Reduction"), N_("Long Exposure Noise Reduction"), sony1Id, makerTags, unsignedShort, -1, EXV_PRINT_TAG(sonyLongExposureNoiseReduction)), TagInfo(0xB04F, "DynamicRangeOptimizer", N_("Dynamic Range Optimizer"), N_("Dynamic Range Optimizer"), sony1Id, makerTags, unsignedShort, -1, EXV_PRINT_TAG(print0xb04f)), TagInfo(0xB052, "IntelligentAuto", N_("Intelligent Auto"), N_("Intelligent Auto"), sony1Id, makerTags, unsignedShort, -1, EXV_PRINT_TAG(sonyIntelligentAuto)), TagInfo(0xB054, "WhiteBalance2", N_("White Balance 2"), N_("White balance 2"), sony1Id, makerTags, unsignedShort, -1, EXV_PRINT_TAG(sonyWhiteBalance)), // End of list marker TagInfo(0xffff, "(UnknownSony1MakerNoteTag)", "(UnknownSony1MakerNoteTag)", N_("Unknown Sony1MakerNote tag"), sony1Id, makerTags, asciiString, -1, printValue) }; const TagInfo* SonyMakerNote::tagList() { return tagInfo_; } // -- Sony camera settings --------------------------------------------------------------- //! Lookup table to translate Sony camera settings drive mode values to readable labels extern const TagDetails sonyDriveModeStd[] = { { 1, N_("Single Frame") }, { 2, N_("Continuous High") }, { 4, N_("Self-timer 10 sec") }, { 5, N_("Self-timer 2 sec") }, { 7, N_("Continuous Bracketing") }, { 12, N_("Continuous Low") }, { 18, N_("White Balance Bracketing Low") }, { 19, N_("D-Range Optimizer Bracketing Low") }, { 19, N_("D-Range Optimizer Bracketing Low") } // To silence compiler warning }; //! Lookup table to translate Sony camera settings focus mode values to readable labels extern const TagDetails sonyCSFocusMode[] = { { 0, N_("Manual") }, { 1, "AF-S" }, { 2, "AF-C" }, { 3, "AF-A" } }; //! Lookup table to translate Sony camera settings metering mode values to readable labels extern const TagDetails sonyMeteringMode[] = { { 1, N_("Multi-segment") }, { 2, N_("Center weighted average") }, { 4, N_("Spot") } }; //! Lookup table to translate Sony camera settings creative style values to readable labels extern const TagDetails sonyCreativeStyle[] = { { 1, N_("Standard") }, { 2, N_("Vivid") }, { 3, N_("Portrait") }, { 4, N_("Landscape") }, { 5, N_("Sunset") }, { 6, N_("Night View/Portrait") }, { 8, N_("Black & White") }, { 9, N_("Adobe RGB") }, { 11, N_("Neutral") }, { 12, N_("Clear") }, { 13, N_("Deep") }, { 14, N_("Light") }, { 15, N_("Autumn") }, { 16, N_("Sepia") } }; //! Lookup table to translate Sony camera settings flash mode values to readable labels extern const TagDetails sonyFlashMode[] = { { 0, N_("ADI") }, { 1, N_("TTL") }, }; //! Lookup table to translate Sony AF illuminator values to readable labels extern const TagDetails sonyAFIlluminatorCS[] = { { 0, N_("Auto") }, { 1, N_("Off") } }; //! Lookup table to translate Sony camera settings image style values to readable labels extern const TagDetails sonyImageStyle[] = { { 1, N_("Standard") }, { 2, N_("Vivid") }, { 9, N_("Adobe RGB") }, { 11, N_("Neutral") }, { 129, N_("StyleBox1") }, { 130, N_("StyleBox1") }, { 131, N_("StyleBox1") } }; //! Lookup table to translate Sony camera settings exposure program values to readable labels extern const TagDetails sonyExposureProgram[] = { { 0, N_("Auto") }, { 1, N_("Manual") }, { 2, N_("Program AE") }, { 3, N_("Aperture-priority AE") }, { 4, N_("Shutter speed priority AE") }, { 8, N_("Program Shift A") }, { 9, N_("Program Shift S") }, { 16, N_("Portrait") }, { 17, N_("Sports") }, { 18, N_("Sunset") }, { 19, N_("Night Portrait") }, { 20, N_("Landscape") }, { 21, N_("Macro") }, { 35, N_("Auto No Flash") } }; //! Lookup table to translate Sony camera settings image size values to readable labels extern const TagDetails sonyImageSize[] = { { 1, N_("Large") }, { 2, N_("Medium") }, { 3, N_("Small") } }; //! Lookup table to translate Sony aspect ratio values to readable labels extern const TagDetails sonyAspectRatio[] = { { 1, "3:2" }, { 2, "16:9" } }; //! Lookup table to translate Sony exposure level increments values to readable labels extern const TagDetails sonyExposureLevelIncrements[] = { { 33, "1/3 EV" }, { 50, "1/2 EV" } }; // Sony Camera Settings Tag Info // NOTE: all are for A200, A230, A300, A350, A700, A850 and A900 Sony model excepted // some entries which are only relevant with A700. // Warnings: Exiftool database give a list of tags shorted in decimal mode, not hexadecimal. const TagInfo SonyMakerNote::tagInfoCs_[] = { // NOTE: A700 only TagInfo(0x0004, "DriveMode", N_("Drive Mode"), N_("Drive Mode"), sony1CsId, makerTags, unsignedShort, 1, EXV_PRINT_TAG(sonyDriveModeStd)), // NOTE: A700 only TagInfo(0x0006, "WhiteBalanceFineTune", N_("White Balance Fine Tune"), N_("White Balance Fine Tune"), sony1CsId, makerTags, signedShort, 1, printValue), TagInfo(0x0010, "FocusMode", N_("Focus Mode"), N_("Focus Mode"), sony1CsId, makerTags, unsignedShort, 1, EXV_PRINT_TAG(sonyCSFocusMode)), TagInfo(0x0011, "AFAreaMode", N_("AF Area Mode"), N_("AF Area Mode"), sony1CsId, makerTags, unsignedShort, 1, printMinoltaSonyAFAreaMode), TagInfo(0x0012, "LocalAFAreaPoint", N_("Local AF Area Point"), N_("Local AF Area Point"), sony1CsId, makerTags, unsignedShort, 1, printMinoltaSonyLocalAFAreaPoint), TagInfo(0x0015, "MeteringMode", N_("Metering Mode"), N_("Metering Mode"), sony1CsId, makerTags, unsignedShort, 1, EXV_PRINT_TAG(sonyMeteringMode)), TagInfo(0x0016, "ISOSetting", N_("ISO Setting"), N_("ISO Setting"), sony1CsId, makerTags, unsignedShort, 1, printValue), TagInfo(0x0018, "DynamicRangeOptimizerMode", N_("Dynamic Range Optimizer Mode"), N_("Dynamic Range Optimizer Mode"), sony1CsId, makerTags, unsignedShort, 1, printMinoltaSonyDynamicRangeOptimizerMode), TagInfo(0x0019, "DynamicRangeOptimizerLevel", N_("Dynamic Range Optimizer Level"), N_("Dynamic Range Optimizer Level"), sony1CsId, makerTags, unsignedShort, 1, printValue), TagInfo(0x001A, "CreativeStyle", N_("Creative Style"), N_("Creative Style"), sony1CsId, makerTags, unsignedShort, 1, EXV_PRINT_TAG(sonyCreativeStyle)), TagInfo(0x001C, "Sharpness", N_("Sharpness"), N_("Sharpness"), sony1CsId, makerTags, unsignedShort, 1, printValue), TagInfo(0x001D, "Contrast", N_("Contrast"), N_("Contrast"), sony1CsId, makerTags, unsignedShort, 1, printValue), TagInfo(0x001E, "Saturation", N_("Saturation"), N_("Saturation"), sony1CsId, makerTags, unsignedShort, 1, printValue), TagInfo(0x001F, "ZoneMatchingValue", N_("Zone Matching Value"), N_("Zone Matching Value"), sony1CsId, makerTags, unsignedShort, 1, printValue), TagInfo(0x0022, "Brightness", N_("Brightness"), N_("Brightness"), sony1CsId, makerTags, unsignedShort, 1, printValue), TagInfo(0x0023, "FlashMode", N_("FlashMode"), N_("FlashMode"), sony1CsId, makerTags, unsignedShort, 1, EXV_PRINT_TAG(sonyFlashMode)), // NOTE: A700 only TagInfo(0x0028, "PrioritySetupShutterRelease", N_("Priority Setup Shutter Release"), N_("Priority Setup Shutter Release"), sony1CsId, makerTags, unsignedShort, 1, printMinoltaSonyPrioritySetupShutterRelease), // NOTE: A700 only TagInfo(0x0029, "AFIlluminator", N_("AF Illuminator"), N_("AF Illuminator"), sony1CsId, makerTags, unsignedShort, 1, EXV_PRINT_TAG(sonyAFIlluminatorCS)), // NOTE: A700 only TagInfo(0x002A, "AFWithShutter", N_("AF With Shutter"), N_("AF With Shutter"), sony1CsId, makerTags, unsignedShort, 1, printMinoltaSonyBoolInverseValue), // NOTE: A700 only TagInfo(0x002B, "LongExposureNoiseReduction", N_("Long Exposure Noise Reduction"), N_("Long Exposure Noise Reduction"), sony1CsId, makerTags, unsignedShort, 1, printMinoltaSonyBoolValue), // NOTE: A700 only TagInfo(0x002C, "HighISONoiseReduction", N_("High ISO NoiseReduction"), N_("High ISO NoiseReduction"), sony1CsId, makerTags, unsignedShort, 1, printValue), // NOTE: A700 only TagInfo(0x002D, "ImageStyle", N_("Image Style"), N_("Image Style"), sony1CsId, makerTags, unsignedShort, 1, EXV_PRINT_TAG(sonyImageStyle)), TagInfo(0x003C, "ExposureProgram", N_("Exposure Program"), N_("Exposure Program"), sony1CsId, makerTags, unsignedShort, 1, EXV_PRINT_TAG(sonyExposureProgram)), TagInfo(0x003D, "ImageStabilization", N_("Image Stabilization"), N_("Image Stabilization"), sony1CsId, makerTags, unsignedShort, 1, printMinoltaSonyBoolValue), TagInfo(0x003F, "Rotation", N_("Rotation"), N_("Rotation"), sony1CsId, makerTags, unsignedShort, 1, printMinoltaSonyRotation), TagInfo(0x0054, "SonyImageSize", N_("Sony Image Size"), N_("Sony Image Size"), sony1CsId, makerTags, unsignedShort, 1, EXV_PRINT_TAG(sonyImageSize)), TagInfo(0x0055, "AspectRatio", N_("Aspect Ratio"), N_("Aspect Ratio"), sony1CsId, makerTags, unsignedShort, 1, EXV_PRINT_TAG(sonyAspectRatio)), TagInfo(0x0056, "Quality", N_("Quality"), N_("Quality"), sony1CsId, makerTags, unsignedShort, 1, printMinoltaSonyQualityCs), TagInfo(0x0058, "ExposureLevelIncrements", N_("Exposure Level Increments"), N_("Exposure Level Increments"), sony1CsId, makerTags, unsignedShort, 1, EXV_PRINT_TAG(sonyExposureLevelIncrements)), // End of list marker TagInfo(0xffff, "(UnknownSony1CsTag)", "(UnknownSony1CsTag)", N_("Unknown Sony1 Camera Settings tag"), sony1CsId, makerTags, unsignedShort, 1, printValue) }; const TagInfo* SonyMakerNote::tagListCs() { return tagInfoCs_; } // -- Sony camera settings 2 --------------------------------------------------------------- // Sony Camera Settings Tag Version 2 Info // NOTE: for A330, A380, A450, A500, A550 Sony model // Warnings: Exiftool database give a list of tags shorted in decimal mode, not hexadecimal. const TagInfo SonyMakerNote::tagInfoCs2_[] = { TagInfo(0x0010, "FocusMode", N_("Focus Mode"), N_("Focus Mode"), sony1Cs2Id, makerTags, unsignedShort, 1, EXV_PRINT_TAG(sonyCSFocusMode)), TagInfo(0x0011, "AFAreaMode", N_("AF Area Mode"), N_("AF Area Mode"), sony1Cs2Id, makerTags, unsignedShort, 1, printMinoltaSonyAFAreaMode), TagInfo(0x0012, "LocalAFAreaPoint", N_("Local AF Area Point"), N_("Local AF Area Point"), sony1Cs2Id, makerTags, unsignedShort, 1, printMinoltaSonyLocalAFAreaPoint), TagInfo(0x0013, "MeteringMode", N_("Metering Mode"), N_("Metering Mode"), sony1Cs2Id, makerTags, unsignedShort, 1, EXV_PRINT_TAG(sonyMeteringMode)), TagInfo(0x0014, "ISOSetting", N_("ISO Setting"), N_("ISO Setting"), sony1Cs2Id, makerTags, unsignedShort, 1, printValue), TagInfo(0x0016, "DynamicRangeOptimizerMode", N_("Dynamic Range Optimizer Mode"), N_("Dynamic Range Optimizer Mode"), sony1Cs2Id, makerTags, unsignedShort, 1, printMinoltaSonyDynamicRangeOptimizerMode), TagInfo(0x0017, "DynamicRangeOptimizerLevel", N_("Dynamic Range Optimizer Level"), N_("Dynamic Range Optimizer Level"), sony1Cs2Id, makerTags, unsignedShort, 1, printValue), TagInfo(0x0018, "CreativeStyle", N_("Creative Style"), N_("Creative Style"), sony1Cs2Id, makerTags, unsignedShort, 1, EXV_PRINT_TAG(sonyCreativeStyle)), TagInfo(0x0019, "Sharpness", N_("Sharpness"), N_("Sharpness"), sony1Cs2Id, makerTags, unsignedShort, 1, printValue), TagInfo(0x001A, "Contrast", N_("Contrast"), N_("Contrast"), sony1Cs2Id, makerTags, unsignedShort, 1, printValue), TagInfo(0x001B, "Saturation", N_("Saturation"), N_("Saturation"), sony1Cs2Id, makerTags, unsignedShort, 1, printValue), TagInfo(0x0023, "FlashMode", N_("FlashMode"), N_("FlashMode"), sony1Cs2Id, makerTags, unsignedShort, 1, EXV_PRINT_TAG(sonyFlashMode)), TagInfo(0x003C, "ExposureProgram", N_("Exposure Program"), N_("Exposure Program"), sony1Cs2Id, makerTags, unsignedShort, 1, EXV_PRINT_TAG(sonyExposureProgram)), TagInfo(0x003F, "Rotation", N_("Rotation"), N_("Rotation"), sony1Cs2Id, makerTags, unsignedShort, 1, printMinoltaSonyRotation), TagInfo(0x0054, "SonyImageSize", N_("Sony Image Size"), N_("Sony Image Size"), sony1Cs2Id, makerTags, unsignedShort, 1, EXV_PRINT_TAG(sonyImageSize)), // End of list marker TagInfo(0xffff, "(UnknownSony1Cs2Tag)", "(UnknownSony1Cs2Tag)", N_("Unknown Sony1 Camera Settings 2 tag"), sony1Cs2Id, makerTags, unsignedShort, 1, printValue) }; const TagInfo* SonyMakerNote::tagListCs2() { return tagInfoCs2_; } }} // namespace Internal, Exiv2 exiv2-0.23/src/convert.hpp0000644000175000017500000001275211732641407015303 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! @file convert.hpp @brief Exif and IPTC conversions to and from XMP @version $Rev: 2681 $ @author Andreas Huggel (ahu) ahuggel@gmx.net
Vladimir Nadvornik (vn) nadvornik@suse.cz @date 17-Mar-08, ahu: created basic converter framework
20-May-08, vn: added actual conversion logic */ #ifndef CONVERT_HPP_ #define CONVERT_HPP_ // ***************************************************************************** // included header files #ifdef _MSC_VER # include "exv_msvc.h" #else # include "exv_conf.h" #endif // + standard includes #include // ***************************************************************************** // namespace extensions namespace Exiv2 { // ***************************************************************************** // class declarations class ExifData; class IptcData; class XmpData; // ***************************************************************************** // free functions, template and inline definitions //! Convert (copy) Exif tags to XMP properties. EXIV2API void copyExifToXmp(const ExifData& exifData, XmpData& xmpData); //! Convert (move) Exif tags to XMP properties, remove converted Exif tags. EXIV2API void moveExifToXmp(ExifData& exifData, XmpData& xmpData); //! Convert (copy) XMP properties to Exif tags. EXIV2API void copyXmpToExif(const XmpData& xmpData, ExifData& exifData); //! Convert (move) XMP properties to Exif tags, remove converted XMP properties. EXIV2API void moveXmpToExif(XmpData& xmpData, ExifData& exifData); //! Detect which metadata are newer and perform a copy in appropriate direction. EXIV2API void syncExifWithXmp(ExifData& exifData, XmpData& xmpData); //! Convert (copy) IPTC datasets to XMP properties. EXIV2API void copyIptcToXmp(const IptcData& iptcData, XmpData& xmpData, const char *iptcCharset = 0); //! Convert (move) IPTC datasets to XMP properties, remove converted IPTC datasets. EXIV2API void moveIptcToXmp(IptcData& iptcData, XmpData& xmpData, const char *iptcCharset = 0); //! Convert (copy) XMP properties to IPTC datasets. EXIV2API void copyXmpToIptc(const XmpData& xmpData, IptcData& iptcData); //! Convert (move) XMP properties to IPTC tags, remove converted XMP properties. EXIV2API void moveXmpToIptc(XmpData& xmpData, IptcData& iptcData); /*! @brief Convert character encoding of \em str from \em from to \em to. If the function succeeds, \em str contains the result string. This function uses the iconv library, if the %Exiv2 library was compiled with iconv support. Otherwise, on Windows, it uses Windows functions to support a limited number of conversions and fails with a warning if an unsupported conversion is attempted. If the function is called but %Exiv2 was not compiled with iconv support and can't use Windows functions, it fails with a warning. The conversions supported on Windows without iconv are:
fromto
UTF-8 UCS-2BE
UTF-8 UCS-2LE
UCS-2BE UTF-8
UCS-2BE UCS-2LE
UCS-2LE UTF-8
UCS-2LE UCS-2BE
ISO-8859-1UTF-8
ASCII UTF-8
@param str The string to convert. It is updated to the converted string, which may have a different size. If the function call fails, the string is not modified. @param from Charset in which the input string is encoded as a name understood by \c iconv_open(3). @param to Charset to convert the string to as a name understood by \c iconv_open(3). @return Return \c true if the conversion was successful, else \c false. */ EXIV2API bool convertStringCharset(std::string& str, const char* from, const char* to); } // namespace Exiv2 #endif // #ifndef CONVERT_HPP_ exiv2-0.23/src/preview.hpp0000644000175000017500000001476211732641407015307 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! @file preview.hpp @brief Classes to access all preview images embedded in an image. @version $Rev: 2681 $ @author Vladimir Nadvornik (vn) nadvornik@suse.cz @date 18-Sep-08, vn: created */ #ifndef PREVIEW_HPP_ #define PREVIEW_HPP_ // ***************************************************************************** // included header files #include "types.hpp" #include "image.hpp" #include "basicio.hpp" #include #include // ***************************************************************************** // namespace extensions namespace Exiv2 { // ***************************************************************************** // class definitions //! Type of preview image. typedef int PreviewId; /*! @brief Preview image properties. */ struct EXIV2API PreviewProperties { //! Preview image mime type. std::string mimeType_; //! Preview image extension. std::string extension_; #ifdef EXV_UNICODE_PATH //! Unicode preview image extension in an std::wstring std::wstring wextension_; #endif //! Preview image size in bytes. uint32_t size_; //! Preview image width in pixels or 0 for unknown width. uint32_t width_; //! Preview image height in pixels or 0 for unknown height. uint32_t height_; //! Identifies type of preview image. PreviewId id_; }; //! Container type to hold all preview images metadata. typedef std::vector PreviewPropertiesList; /*! @brief Class that holds preview image properties and data buffer. */ class EXIV2API PreviewImage { friend class PreviewManager; public: //! @name Constructors //@{ //! Copy constructor PreviewImage(const PreviewImage& rhs); //! Destructor. ~PreviewImage(); //@} //! @name Manipulators //@{ //! Assignment operator PreviewImage& operator=(const PreviewImage& rhs); //@} //! @name Accessors //@{ /*! @brief Return a copy of the preview image data. The caller owns this copy and %DataBuf ensures that it will be deleted. */ DataBuf copy() const; /*! @brief Return a pointer to the image data for read-only access. */ const byte* pData() const; /*! @brief Return the size of the preview image in bytes. */ uint32_t size() const; /*! @brief Write the thumbnail image to a file. A filename extension is appended to \em path according to the image type of the preview image, so \em path should not include an extension. The function will overwrite an existing file of the same name. @param path File name of the preview image without extension. @return The number of bytes written. */ long writeFile(const std::string& path) const; #ifdef EXV_UNICODE_PATH /*! @brief Like writeFile() but accepts a unicode path in an std::wstring. @note This function is only available on Windows. */ long writeFile(const std::wstring& wpath) const; #endif /*! @brief Return the MIME type of the preview image, usually either \c "image/tiff" or \c "image/jpeg". */ std::string mimeType() const; /*! @brief Return the file extension for the format of the preview image (".tif" or ".jpg"). */ std::string extension() const; #ifdef EXV_UNICODE_PATH /*! @brief Like extension() but returns the unicode encoded extension in an std::wstring. @note This function is only available on Windows. */ std::wstring wextension() const; #endif /*! @brief Return the width of the preview image in pixels. */ uint32_t width() const; /*! @brief Return the height of the preview image in pixels. */ uint32_t height() const; /*! @brief Return the preview image type identifier. */ PreviewId id() const; //@} private: //! Private constructor EXV_DLLLOCAL PreviewImage(const PreviewProperties& properties, DataBuf data); PreviewProperties properties_; //!< Preview image properties byte* pData_; //!< Pointer to the preview image data uint32_t size_; //!< Size of the preview image data }; // class PreviewImage /*! @brief Class for extracting preview images from image metadata. */ class EXIV2API PreviewManager { public: //! @name Constructors //@{ //! Constructor. PreviewManager(const Image& image); //@} //! @name Accessors //@{ /*! @brief Return the properties of all preview images in a list sorted by preview width * height, starting with the smallest preview image. */ PreviewPropertiesList getPreviewProperties() const; /*! @brief Return the preview image for the given preview properties. */ PreviewImage getPreviewImage(const PreviewProperties& properties) const; //@} private: const Image& image_; }; // class PreviewManager } // namespace Exiv2 #endif // #ifndef PREVIEW_HPP_ exiv2-0.23/src/timegm.h0000644000175000017500000000552711204426032014534 0ustar andreasandreas/*! @file timegm.h @brief Declaration of timegm(). The implementation is in localtime.c @version $Rev: 1800 $ */ #ifndef TIMEGM_H_ #define TIMEGM_H_ #include /* The following comments are copied from the Makefile of the tz distribution, available at ftp://elsie.nci.nih.gov/pub/: NIST-PCTS:151-2, Version 1.4, (1993-12-03) is a test suite put out by the National Institute of Standards and Technology which claims to test C and Posix conformance. If you want to pass PCTS, add -DPCTS to the end of the "CFLAGS=" line. If your system has a "zone abbreviation" field in its "struct tm"s (or if you decide to add such a field in your system's "time.h" file), add the name to a define such as -DTM_ZONE=tm_zone or -DTM_ZONE=_tm_zone to the end of the "CFLAGS=" line. If you want functions that were inspired by early versions of X3J11's work, add -DSTD_INSPIRED to the end of the "CFLAGS=" line. If you want to allocate state structures in localtime, add -DALL_STATE to the end of the "CFLAGS=" line. Storage is obtained by calling malloc. If you want Source Code Control System ID's left out of object modules, add -DNOID Add the following to the end of the "CFLAGS=" line as needed. -DTZDEFRULESTRING=\",date/time,date/time\" to default to the specified DST transitions if the time zone files cannot be accessed If you want to use System V compatibility code, add -DUSG_COMPAT to the end of the "CFLAGS=" line. This arrange for "timezone" and "daylight" variables to be kept up-to-date by the time conversion functions. Neither "timezone" nor "daylight" is described in X3J11's work. If you want an "altzone" variable (a la System V Release 3.1), add -DALTZONE to the end of the "CFLAGS=" line. This variable is not described in X3J11's work. If your system has a "GMT offset" field in its "struct tm"s (or if you decide to add such a field in your system's "time.h" file), add the name to a define such as -DTM_GMTOFF=tm_gmtoff or -DTM_GMTOFF=_tm_gmtoff to the end of the "CFLAGS=" line. Neither tm_gmtoff nor _tm_gmtoff is described in X3J11's work; in its work, use of "tm_gmtoff" is described as non-conforming. Both Linux and BSD have done the equivalent of defining TM_GMTOFF in their recent releases. If you want a "gtime" function (a la MACH), add -DCMUCS to the end of the "CFLAGS=" line This function is not described in X3J11's work. */ #define STD_INSPIRED #define NOID #ifdef __cplusplus extern "C" { #endif // The UTC version of mktime /* rmills - timegm is replaced with _mkgmtime on VC 2005 and up */ /* - see localtime.c */ #if !defined(_MSC_VER) || (_MSC_VER < 1400) time_t timegm(struct tm * const tmp); #else #define timegm _mkgmtime #endif #ifdef __cplusplus } #endif #endif // #ifndef TIMEGM_H_ exiv2-0.23/src/jpgimage.hpp0000644000175000017500000004351711732641407015411 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! @file jpgimage.hpp @brief Class JpegImage to access JPEG images @version $Rev: 2681 $ @author Andreas Huggel (ahu) ahuggel@gmx.net @author Brad Schick (brad) brad@robotbattle.com @author Volker Grabsch (vog) vog@notjusthosting.com @author Michael Ulbrich (mul) mul@rentapacs.de @date 15-Jan-05, brad: split out from image.cpp */ #ifndef JPGIMAGE_HPP_ #define JPGIMAGE_HPP_ // ***************************************************************************** // included header files #include "image.hpp" #include "basicio.hpp" #include "types.hpp" // + standard includes #include // ***************************************************************************** // namespace extensions namespace Exiv2 { // ***************************************************************************** // class definitions // Supported JPEG image formats namespace ImageType { const int jpeg = 1; //!< JPEG image type (see class JpegImage) const int exv = 2; //!< EXV image type (see class ExvImage) } /*! @brief Helper class, has methods to deal with %Photoshop "Information Resource Blocks" (IRBs). */ struct EXIV2API Photoshop { // Todo: Public for now static const char ps3Id_[]; //!< %Photoshop marker static const char* irbId_[]; //!< %Photoshop IRB markers static const char bimId_[]; //!< %Photoshop IRB marker (deprecated) static const uint16_t iptc_; //!< %Photoshop IPTC marker static const uint16_t preview_; //!< %Photoshop preview marker /*! @brief Checks an IRB @param pPsData Existing IRB buffer @param sizePsData Size of the IRB buffer @return true if the IRB marker is known and the buffer is big enough to check this;
false otherwise */ static bool isIrb(const byte* pPsData, long sizePsData); /*! @brief Validates all IRBs @param pPsData Existing IRB buffer @param sizePsData Size of the IRB buffer, may be 0 @return true if all IRBs are valid;
false otherwise */ static bool valid(const byte* pPsData, long sizePsData); /*! @brief Locates the data for a %Photoshop tag in a %Photoshop formated memory buffer. Operates on raw data to simplify reuse. @param pPsData Pointer to buffer containing entire payload of %Photoshop formated data, e.g., from APP13 Jpeg segment. @param sizePsData Size in bytes of pPsData. @param psTag %Tag number of the block to look for. @param record Output value that is set to the start of the data block within pPsData (may not be null). @param sizeHdr Output value that is set to the size of the header within the data block pointed to by record (may not be null). @param sizeData Output value that is set to the size of the actual data within the data block pointed to by record (may not be null). @return 0 if successful;
3 if no data for psTag was found in pPsData;
-2 if the pPsData buffer does not contain valid data. */ static int locateIrb(const byte *pPsData, long sizePsData, uint16_t psTag, const byte **record, uint32_t *const sizeHdr, uint32_t *const sizeData); /*! @brief Forwards to locateIrb() with \em psTag = \em iptc_ */ static int locateIptcIrb(const byte *pPsData, long sizePsData, const byte **record, uint32_t *const sizeHdr, uint32_t *const sizeData); /*! @brief Forwards to locatePreviewIrb() with \em psTag = \em preview_ */ static int locatePreviewIrb(const byte *pPsData, long sizePsData, const byte **record, uint32_t *const sizeHdr, uint32_t *const sizeData); /*! @brief Set the new IPTC IRB, keeps existing IRBs but removes the IPTC block if there is no new IPTC data to write. @param pPsData Existing IRB buffer @param sizePsData Size of the IRB buffer, may be 0 @param iptcData Iptc data to embed, may be empty @return A data buffer containing the new IRB buffer, may have 0 size */ static DataBuf setIptcIrb(const byte* pPsData, long sizePsData, const IptcData& iptcData); }; // class Photoshop /*! @brief Abstract helper base class to access JPEG images. */ class EXIV2API JpegBase : public Image { public: //! @name Manipulators //@{ void readMetadata(); void writeMetadata(); //@} protected: //! @name Creators //@{ /*! @brief Constructor that can either open an existing image or create a new image from scratch. If a new image is to be created, any existing data is overwritten. @param type Image type. @param io An auto-pointer that owns a BasicIo instance used for reading and writing image metadata. \b Important: The constructor takes ownership of the passed in BasicIo instance through the auto-pointer. Callers should not continue to use the BasicIo instance after it is passed to this method. Use the Image::io() method to get a temporary reference. @param create Specifies if an existing image should be read (false) or if a new image should be created (true). @param initData Data to initialize newly created images. Only used when \em create is true. Should contain data for the smallest valid image of the calling subclass. @param dataSize Size of initData in bytes. */ JpegBase(int type, BasicIo::AutoPtr io, bool create, const byte initData[], long dataSize); //@} //! @name Accessors //@{ /*! @brief Determine if the content of the BasicIo instance is of the type supported by this class. The advance flag determines if the read position in the stream is moved (see below). This applies only if the type matches and the function returns true. If the type does not match, the stream position is not changed. However, if reading from the stream fails, the stream position is undefined. Consult the stream state to obtain more information in this case. @param iIo BasicIo instance to read from. @param advance Flag indicating whether the position of the io should be advanced by the number of characters read to analyse the data (true) or left at its original position (false). This applies only if the type matches. @return true if the data matches the type of this class;
false if the data does not match */ virtual bool isThisType(BasicIo& iIo, bool advance) const =0; //@} //! @name Manipulators //@{ /*! @brief Writes the image header (aka signature) to the BasicIo instance. @param oIo BasicIo instance that the header is written to. @return 0 if successful;
4 if the output file can not be written to */ virtual int writeHeader(BasicIo& oIo) const =0; //@} // Constant Data static const byte sos_; //!< JPEG SOS marker static const byte eoi_; //!< JPEG EOI marker static const byte app0_; //!< JPEG APP0 marker static const byte app1_; //!< JPEG APP1 marker static const byte app13_; //!< JPEG APP13 marker static const byte com_; //!< JPEG Comment marker static const byte sof0_; //!< JPEG Start-Of-Frame marker static const byte sof1_; //!< JPEG Start-Of-Frame marker static const byte sof2_; //!< JPEG Start-Of-Frame marker static const byte sof3_; //!< JPEG Start-Of-Frame marker static const byte sof5_; //!< JPEG Start-Of-Frame marker static const byte sof6_; //!< JPEG Start-Of-Frame marker static const byte sof7_; //!< JPEG Start-Of-Frame marker static const byte sof9_; //!< JPEG Start-Of-Frame marker static const byte sof10_; //!< JPEG Start-Of-Frame marker static const byte sof11_; //!< JPEG Start-Of-Frame marker static const byte sof13_; //!< JPEG Start-Of-Frame marker static const byte sof14_; //!< JPEG Start-Of-Frame marker static const byte sof15_; //!< JPEG Start-Of-Frame marker static const char exifId_[]; //!< Exif identifier static const char jfifId_[]; //!< JFIF identifier static const char xmpId_[]; //!< XMP packet identifier private: //! @name NOT implemented //@{ //! Default constructor. JpegBase(); //! Copy constructor JpegBase(const JpegBase& rhs); //! Assignment operator JpegBase& operator=(const JpegBase& rhs); //@} //! @name Manipulators //@{ /*! @brief Initialize the image with the provided data. @param initData Data to be written to the associated BasicIo @param dataSize Size in bytes of data to be written @return 0 if successful;
4 if the image can not be written to. */ EXV_DLLLOCAL int initImage(const byte initData[], long dataSize); /*! @brief Provides the main implementation of writeMetadata() by writing all buffered metadata to the provided BasicIo. @param oIo BasicIo instance to write to (a temporary location). @return 4 if opening or writing to the associated BasicIo fails */ EXV_DLLLOCAL void doWriteMetadata(BasicIo& oIo); //@} //! @name Accessors //@{ /*! @brief Advances associated io instance to one byte past the next Jpeg marker and returns the marker. This method should be called when the BasicIo instance is positioned one byte past the end of a Jpeg segment. @return the next Jpeg segment marker if successful;
-1 if a maker was not found before EOF */ EXV_DLLLOCAL int advanceToMarker() const; //@} }; // class JpegBase /*! @brief Class to access JPEG images */ class EXIV2API JpegImage : public JpegBase { friend EXIV2API bool isJpegType(BasicIo& iIo, bool advance); public: //! @name Creators //@{ /*! @brief Constructor that can either open an existing Jpeg image or create a new image from scratch. If a new image is to be created, any existing data is overwritten. Since the constructor can not return a result, callers should check the good() method after object construction to determine success or failure. @param io An auto-pointer that owns a BasicIo instance used for reading and writing image metadata. \b Important: The constructor takes ownership of the passed in BasicIo instance through the auto-pointer. Callers should not continue to use the BasicIo instance after it is passed to this method. Use the Image::io() method to get a temporary reference. @param create Specifies if an existing image should be read (false) or if a new file should be created (true). */ JpegImage(BasicIo::AutoPtr io, bool create); //@} //! @name Accessors //@{ std::string mimeType() const; //@} protected: //! @name Accessors //@{ bool isThisType(BasicIo& iIo, bool advance) const; //@} //! @name Manipulators //@{ /*! @brief Writes a Jpeg header (aka signature) to the BasicIo instance. @param oIo BasicIo instance that the header is written to. @return 0 if successful;
2 if the input image is invalid or can not be read;
4 if the temporary image can not be written to;
-3 other temporary errors */ int writeHeader(BasicIo& oIo) const; //@} private: // Constant data static const byte soi_; // SOI marker static const byte blank_[]; // Minimal Jpeg image // NOT Implemented //! Default constructor JpegImage(); //! Copy constructor JpegImage(const JpegImage& rhs); //! Assignment operator JpegImage& operator=(const JpegImage& rhs); }; // class JpegImage //! Helper class to access %Exiv2 files class EXIV2API ExvImage : public JpegBase { friend EXIV2API bool isExvType(BasicIo& iIo, bool advance); public: //! @name Creators //@{ /*! @brief Constructor that can either open an existing EXV image or create a new image from scratch. If a new image is to be created, any existing data is overwritten. Since the constructor can not return a result, callers should check the good() method after object construction to determine success or failure. @param io An auto-pointer that owns a BasicIo instance used for reading and writing image metadata. \b Important: The constructor takes ownership of the passed in BasicIo instance through the auto-pointer. Callers should not continue to use the BasicIo instance after it is passed to this method. Use the Image::io() method to get a temporary reference. @param create Specifies if an existing image should be read (false) or if a new file should be created (true). */ ExvImage(BasicIo::AutoPtr io, bool create); //@} //! @name Accessors //@{ std::string mimeType() const; //@} protected: //! @name Accessors //@{ bool isThisType(BasicIo& iIo, bool advance) const; //@} //! @name Manipulators //@{ int writeHeader(BasicIo& oIo) const; //@} private: // Constant data static const char exiv2Id_[]; // EXV identifier static const byte blank_[]; // Minimal exiv2 file // NOT Implemented //! Default constructor ExvImage(); //! Copy constructor ExvImage(const ExvImage& rhs); //! Assignment operator ExvImage& operator=(const ExvImage& rhs); }; // class ExvImage // ***************************************************************************** // template, inline and free functions // These could be static private functions on Image subclasses but then // ImageFactory needs to be made a friend. /*! @brief Create a new JpegImage instance and return an auto-pointer to it. Caller owns the returned object and the auto-pointer ensures that it will be deleted. */ EXIV2API Image::AutoPtr newJpegInstance(BasicIo::AutoPtr io, bool create); //! Check if the file iIo is a JPEG image. EXIV2API bool isJpegType(BasicIo& iIo, bool advance); /*! @brief Create a new ExvImage instance and return an auto-pointer to it. Caller owns the returned object and the auto-pointer ensures that it will be deleted. */ EXIV2API Image::AutoPtr newExvInstance(BasicIo::AutoPtr io, bool create); //! Check if the file iIo is an EXV file EXIV2API bool isExvType(BasicIo& iIo, bool advance); } // namespace Exiv2 #endif // #ifndef JPGIMAGE_HPP_ exiv2-0.23/src/orfimage.cpp0000644000175000017500000002143711732641407015407 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /* File: orfimage.cpp Version: $Rev: 2681 $ Author(s): Andreas Huggel (ahu) History: 13-May-06, ahu: created Credits: See header file */ // ***************************************************************************** #include "rcsid_int.hpp" EXIV2_RCSID("@(#) $Id: orfimage.cpp 2681 2012-03-22 15:19:35Z ahuggel $") // ***************************************************************************** // included header files #ifdef _MSC_VER # include "exv_msvc.h" #else # include "exv_conf.h" #endif #include "orfimage.hpp" #include "orfimage_int.hpp" #include "tiffcomposite_int.hpp" #include "tiffimage_int.hpp" #include "image.hpp" #include "basicio.hpp" #include "error.hpp" #include "futils.hpp" // + standard includes #include #include #include #include // ***************************************************************************** // class member definitions namespace Exiv2 { using namespace Internal; OrfImage::OrfImage(BasicIo::AutoPtr io, bool /*create*/) : Image(ImageType::orf, mdExif | mdIptc | mdXmp, io) { } // OrfImage::OrfImage std::string OrfImage::mimeType() const { return "image/x-olympus-orf"; } int OrfImage::pixelWidth() const { ExifData::const_iterator imageWidth = exifData_.findKey(Exiv2::ExifKey("Exif.Image.ImageWidth")); if (imageWidth != exifData_.end() && imageWidth->count() > 0) { return imageWidth->toLong(); } return 0; } int OrfImage::pixelHeight() const { ExifData::const_iterator imageHeight = exifData_.findKey(Exiv2::ExifKey("Exif.Image.ImageLength")); if (imageHeight != exifData_.end() && imageHeight->count() > 0) { return imageHeight->toLong(); } return 0; } void OrfImage::setComment(const std::string& /*comment*/) { // not supported throw(Error(32, "Image comment", "ORF")); } void OrfImage::readMetadata() { #ifdef DEBUG std::cerr << "Reading ORF file " << io_->path() << "\n"; #endif if (io_->open() != 0) { throw Error(9, io_->path(), strError()); } IoCloser closer(*io_); // Ensure that this is the correct image type if (!isOrfType(*io_, false)) { if (io_->error() || io_->eof()) throw Error(14); throw Error(3, "ORF"); } clearMetadata(); ByteOrder bo = OrfParser::decode(exifData_, iptcData_, xmpData_, io_->mmap(), io_->size()); setByteOrder(bo); } // OrfImage::readMetadata void OrfImage::writeMetadata() { #ifdef DEBUG std::cerr << "Writing ORF file " << io_->path() << "\n"; #endif ByteOrder bo = byteOrder(); byte* pData = 0; long size = 0; IoCloser closer(*io_); if (io_->open() == 0) { // Ensure that this is the correct image type if (isOrfType(*io_, false)) { pData = io_->mmap(true); size = io_->size(); OrfHeader orfHeader; if (0 == orfHeader.read(pData, 8)) { bo = orfHeader.byteOrder(); } } } if (bo == invalidByteOrder) { bo = littleEndian; } setByteOrder(bo); OrfParser::encode(*io_, pData, size, bo, exifData_, iptcData_, xmpData_); // may throw } // OrfImage::writeMetadata ByteOrder OrfParser::decode( ExifData& exifData, IptcData& iptcData, XmpData& xmpData, const byte* pData, uint32_t size ) { OrfHeader orfHeader; return TiffParserWorker::decode(exifData, iptcData, xmpData, pData, size, Tag::root, TiffMapping::findDecoder, &orfHeader); } WriteMethod OrfParser::encode( BasicIo& io, const byte* pData, uint32_t size, ByteOrder byteOrder, const ExifData& exifData, const IptcData& iptcData, const XmpData& xmpData ) { // Copy to be able to modify the Exif data ExifData ed = exifData; // Delete IFDs which do not occur in TIFF images static const IfdId filteredIfds[] = { panaRawId }; for (unsigned int i = 0; i < EXV_COUNTOF(filteredIfds); ++i) { #ifdef DEBUG std::cerr << "Warning: Exif IFD " << filteredIfds[i] << " not encoded\n"; #endif ed.erase(std::remove_if(ed.begin(), ed.end(), FindExifdatum(filteredIfds[i])), ed.end()); } std::auto_ptr header(new OrfHeader(byteOrder)); return TiffParserWorker::encode(io, pData, size, ed, iptcData, xmpData, Tag::root, TiffMapping::findEncoder, header.get(), 0); } // ************************************************************************* // free functions Image::AutoPtr newOrfInstance(BasicIo::AutoPtr io, bool create) { Image::AutoPtr image(new OrfImage(io, create)); if (!image->good()) { image.reset(); } return image; } bool isOrfType(BasicIo& iIo, bool advance) { const int32_t len = 8; byte buf[len]; iIo.read(buf, len); if (iIo.error() || iIo.eof()) { return false; } OrfHeader orfHeader; bool rc = orfHeader.read(buf, len); if (!advance || !rc) { iIo.seek(-len, BasicIo::cur); } return rc; } } // namespace Exiv2 namespace Exiv2 { namespace Internal { OrfHeader::OrfHeader(ByteOrder byteOrder) : TiffHeaderBase(0x4f52, 8, byteOrder, 0x00000008), sig_(0x4f52) { } OrfHeader::~OrfHeader() { } bool OrfHeader::read(const byte* pData, uint32_t size) { if (size < 8) return false; if (pData[0] == 0x49 && pData[1] == 0x49) { setByteOrder(littleEndian); } else if (pData[0] == 0x4d && pData[1] == 0x4d) { setByteOrder(bigEndian); } else { return false; } uint16_t sig = getUShort(pData + 2, byteOrder()); if (tag() != sig && 0x5352 != sig) return false; // #658: Added 0x5352 for SP-560UZ sig_ = sig; setOffset(getULong(pData + 4, byteOrder())); if (offset() != 0x00000008) return false; return true; } // OrfHeader::read DataBuf OrfHeader::write() const { DataBuf buf(8); switch (byteOrder()) { case littleEndian: buf.pData_[0] = 0x49; buf.pData_[1] = 0x49; break; case bigEndian: buf.pData_[0] = 0x4d; buf.pData_[1] = 0x4d; break; case invalidByteOrder: assert(false); break; } us2Data(buf.pData_ + 2, sig_, byteOrder()); ul2Data(buf.pData_ + 4, 0x00000008, byteOrder()); return buf; } }} // namespace Internal, Exiv2 exiv2-0.23/src/version.hpp0000644000175000017500000001451711733051454015307 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! @file version.hpp @brief Precompiler define and a function to test the %Exiv2 version. References: Similar versioning defines are used in KDE, GTK and other libraries. See http://apr.apache.org/versioning.html for accompanying guidelines. @version $Rev: 2685 $ @author Andreas Huggel (ahu) ahuggel@gmx.net @date 31-May-06, ahu: created */ #ifndef VERSION_HPP_ #define VERSION_HPP_ // ***************************************************************************** // included header files // + standard includes #include /*! @brief %Exiv2 MAJOR version number of the library used at compile-time. */ #define EXIV2_MAJOR_VERSION (0) /*! @brief %Exiv2 MINOR version number of the library used at compile-time. */ #define EXIV2_MINOR_VERSION (23) /*! @brief %Exiv2 PATCH version number of the library used at compile-time. */ #define EXIV2_PATCH_VERSION (0) /*! @brief Make an integer version number for comparison from a major, minor and a patch version number. */ #define EXIV2_MAKE_VERSION(major,minor,patch) \ (((major) << 16) | ((minor) << 8) | (patch)) /*! @brief The %Exiv2 version number of the library used at compile-time as an integer number for easy comparison. */ #define EXIV2_VERSION \ EXIV2_MAKE_VERSION(EXIV2_MAJOR_VERSION,EXIV2_MINOR_VERSION,EXIV2_PATCH_VERSION) /*! @brief Deprecated version check macro. Do not use. This macro has flaws and only remains for backward compatibility. Use EXIV2_TEST_VERSION and testVersion() instead. */ #define EXIV2_CHECK_VERSION(major,minor,patch) \ ( Exiv2::versionNumber() >= EXIV2_MAKE_VERSION(major,minor,patch) ) /*! @brief Macro to test the version of the available %Exiv2 library at compile-time. Return true if it is the same as or newer than the passed-in version. Versions are denoted using a triplet of integers: \em MAJOR.MINOR.PATCH . @code // Don't include the file directly, it is included by // . Early Exiv2 versions didn't have version.hpp and the macros. #include // Make sure an EXIV2_TEST_VERSION macro exists: #ifdef EXIV2_VERSION # ifndef EXIV2_TEST_VERSION # define EXIV2_TEST_VERSION(major,minor,patch) \ ( EXIV2_VERSION >= EXIV2_MAKE_VERSION(major,minor,patch) ) # endif #else # define EXIV2_TEST_VERSION(major,minor,patch) (false) #endif std::cout << "Compiled with Exiv2 version " << EXV_PACKAGE_VERSION << "\n" << "Runtime Exiv2 version is " << Exiv2::version() << "\n"; // Test the Exiv2 version available at runtime but compile the if-clause only if // the compile-time version is at least 0.15. Earlier versions didn't have a // testVersion() function: #if EXIV2_TEST_VERSION(0,15,0) if (Exiv2::testVersion(0,13,0)) { std::cout << "Available Exiv2 version is equal to or greater than 0.13\n"; } else { std::cout << "Installed Exiv2 version is less than 0.13\n"; } #else std::cout << "Compile-time Exiv2 version doesn't have Exiv2::testVersion()\n"; #endif @endcode */ #define EXIV2_TEST_VERSION(major,minor,patch) \ ( EXIV2_VERSION >= EXIV2_MAKE_VERSION(major,minor,patch) ) // ***************************************************************************** // namespace extensions namespace Exiv2 { /*! @brief Return the version of %Exiv2 available at runtime as an integer. */ EXIV2API int versionNumber(); /*! @brief Return the version of %Exiv2 as hex string of fixed length 6. */ EXIV2API std::string versionNumberHexString(); /*! @brief Return the version of %Exiv2 available at runtime as a string. */ EXIV2API const char* version(); /*! @brief Test the version of the available %Exiv2 library at runtime. Return true if it is the same as or newer than the passed-in version. Versions are denoted using a triplet of integers: \em major.minor.patch . @code // Don't include the file directly, it is included by // . Early Exiv2 versions didn't have version.hpp and the macros. #include // Make sure an EXIV2_TEST_VERSION macro exists: #ifdef EXIV2_VERSION # ifndef EXIV2_TEST_VERSION # define EXIV2_TEST_VERSION(major,minor,patch) \ ( EXIV2_VERSION >= EXIV2_MAKE_VERSION(major,minor,patch) ) # endif #else # define EXIV2_TEST_VERSION(major,minor,patch) (false) #endif std::cout << "Compiled with Exiv2 version " << EXV_PACKAGE_VERSION << "\n" << "Runtime Exiv2 version is " << Exiv2::version() << "\n"; // Test the Exiv2 version available at runtime but compile the if-clause only if // the compile-time version is at least 0.15. Earlier versions didn't have a // testVersion() function: #if EXIV2_TEST_VERSION(0,15,0) if (Exiv2::testVersion(0,13,0)) { std::cout << "Available Exiv2 version is equal to or greater than 0.13\n"; } else { std::cout << "Installed Exiv2 version is less than 0.13\n"; } #else std::cout << "Compile-time Exiv2 version doesn't have Exiv2::testVersion()\n"; #endif @endcode */ EXIV2API bool testVersion(int major, int minor, int patch); } // namespace Exiv2 #endif // VERSION_HPP_ exiv2-0.23/src/Makefile0000644000175000017500000002366411732641407014556 0ustar andreasandreas# ************************************************************* -*- Makefile -*- # # Copyright (C) 2004-2012 Andreas Huggel # # This Makefile is part of the Exiv2 distribution. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # 3. The name of the author may not be used to endorse or promote # products derived from this software without specific prior # written permission. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER # IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN # IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # File: Makefile # Version: $Rev: 2681 $ # Author(s): Andreas Huggel (ahu) # History: 10-Dec-03, ahu: created # # Description: # Do NOT change this file! All system specific settings and configs # go into config.mk. # # This makefile contains (supposedly) generic build rules to build the # library and applications. It includes all system specific settings # from config.mk. The idea is that configuring and porting the # software to a new platform should only require changes in config.mk. # # Restrictions: # Requires GNU make. # # Default make target all: bin # Include system configuration top_srcdir = .. include $(top_srcdir)/config/config.mk # ****************************************************************************** # Source files # Add standalone C++ header files to this list CCHDR = exiv2.hpp \ exv_conf.h \ exv_msvc.h \ version.hpp # Add library C++ source files to this list CCSRC = basicio.cpp \ bmpimage.cpp \ canonmn.cpp \ convert.cpp \ cr2image.cpp \ crwimage.cpp \ datasets.cpp \ easyaccess.cpp \ epsimage.cpp \ error.cpp \ exif.cpp \ futils.cpp \ fujimn.cpp \ gifimage.cpp \ image.cpp \ iptc.cpp \ jp2image.cpp \ jpgimage.cpp \ makernote.cpp \ metadatum.cpp \ minoltamn.cpp \ mrwimage.cpp \ nikonmn.cpp \ olympusmn.cpp \ orfimage.cpp \ panasonicmn.cpp \ pgfimage.cpp ifdef HAVE_LIBZ CCSRC += pngimage.cpp \ pngchunk.cpp endif CCSRC += preview.cpp \ properties.cpp \ psdimage.cpp \ rafimage.cpp \ rw2image.cpp \ samsungmn.cpp \ sigmamn.cpp \ pentaxmn.cpp \ sonymn.cpp \ tags.cpp \ tgaimage.cpp \ tiffcomposite.cpp \ tiffimage.cpp \ tiffvisitor.cpp \ types.cpp \ value.cpp \ version.cpp \ xmp.cpp \ xmpsidecar.cpp # Add library C source files to this list ifndef HAVE_TIMEGM CSRC = localtime.c endif # Add source files of simple applications to this list # Todo: How can we still support crwedit.cpp, crwparse.cpp BINSRC = taglist.cpp # Source files for the Exiv2 application EXIV2MAIN = exiv2.cpp EXIV2SRC = actions.cpp \ utils.cpp # C source files for the Exiv2 application ifndef HAVE_TIMEGM EXIVCSRC = localtime.c endif # Source files for the metacopy sample application MCMAIN = metacopy.cpp MCSRC = utils.cpp # ****************************************************************************** # Library LIBRARY = libexiv2.la # ****************************************************************************** # Initialisations SHELL = /bin/sh .SUFFIXES: .SUFFIXES: .c .cpp .o .so .PRECIOUS: %.cpp CPPFLAGS += $(XMPSDK_CPPFLAGS) LDFLAGS += $(EXPAT_LDFLAGS) $(XMPSDK_LDFLAGS) LIBS += $(EXPAT_LIBS) $(XMPSDK_LIBS) # Generic variables CCHDR := $(CCHDR) $(CCSRC:.cpp=.hpp) CCOBJ = $(CCSRC:.cpp=.o) CCLOBJ = $(CCSRC:.cpp=.lo) COBJ = $(CSRC:.c=.o) CLOBJ = $(CSRC:.c=.lo) SRC = $(CCSRC) $(CSRC) HDR = $(CCHDR) OBJ = $(CCOBJ) $(COBJ) LOBJ = $(CCLOBJ) $(CLOBJ) BINOBJ = $(BINSRC:.cpp=.o) BINARY = $(BINSRC:.cpp=) EXECUTABLE = $(BINSRC:.cpp=$(EXEEXT)) EXIV2OBJ = $(EXIV2MAIN:.cpp=.o) $(EXIV2SRC:.cpp=.o) EXIV2COBJ = $(EXIVCSRC:.c=.o) EXIV2BIN = $(EXIV2MAIN:.cpp=) EXIV2EXE = $(EXIV2MAIN:.cpp=$(EXEEXT)) MCOBJ = $(MCMAIN:.cpp=.o) $(MCSRC:.cpp=.o) MCBIN = $(MCMAIN:.cpp=) MCEXE = $(MCMAIN:.cpp=$(EXEEXT)) ifdef DEP_TRACKING DEP = $(CCSRC:%.cpp=$(DEPDIR)/%.d) $(CSRC:%.c=$(DEPDIR)/%.d) \ $(BINSRC:%.cpp=$(DEPDIR)/%.d) \ $(EXIV2MAIN:%.cpp=$(DEPDIR)/%.d) $(EXIV2SRC:%.cpp=$(DEPDIR)/%.d) \ $(EXIVCSRC:%.c=$(DEPDIR)/%.d) $(MCMAIN:%.cpp=$(DEPDIR)/%.d) \ $(MCSRC:%.cpp=$(DEPDIR)/%.d) $(DEPDIR)/path-test.d endif # ****************************************************************************** # Rules $(CCOBJ): %.o: %.cpp @$(LIBTOOL) --mode=compile $(COMPILE.cc) -DEXV_BUILDING_LIB=1 -o $@ $< @$(MAKEDEPEND) @$(POSTDEPEND) $(COBJ): %.o: %.c @$(LIBTOOL) --mode=compile $(COMPILE.c) -DEXV_BUILDING_LIB=1 -o $@ $< @$(MAKEDEPEND) @$(POSTDEPEND) $(sort $(BINOBJ) $(EXIV2OBJ) $(MCOBJ) path-test.o): %.o: %.cpp $(COMPILE.cc) -o $@ $< @$(MAKEDEPEND) @$(POSTDEPEND) %.o: %.c $(COMPILE.c) -o $@ $< @$(MAKEDEPEND) @$(POSTDEPEND) %.ii: %.cpp set -e; \ $(CXXCPP) $(CPPFLAGS) -DEXV_BUILDING_LIB=1 $< | sed '/^[ ]*$$/d' > $@ # ****************************************************************************** # Targets .PHONY: all bin check ctags doc \ clean mostlyclean distclean maintainer-clean \ install install-header install-lib \ uninstall uninstall-header uninstall-lib ifdef DEP_TRACKING # Include targets from dependency files -include $(DEP) endif actions.cpp basicio.cpp exif.cpp exiv2.cpp futils.cpp image.cpp jpgimage.cpp utils.cpp: exv_conf.h exv_conf.h: $(top_srcdir)/config/config.h sed 's/#define \([A-Z]\)/#define EXV_\1/; s/#undef \([A-Z]\)/#undef EXV_\1/' < $< > $@ $(LIBTOOL): $(LIBTOOL_DEPS) $(SHELL) $(top_srcdir)/config.status --recheck bin: lib $(BINARY) $(EXIV2BIN) $(MCBIN) path-test lib: $(OBJ) $(LIBTOOL) --mode=link $(LINK.cc) -o $(LIBRARY) $(LOBJ) -rpath $(libdir) -version-info $(EXIV2_LTVERSION) $(LIBS) @touch lib path-test: path-test.o utils.o $(CXX) $(CXXFLAGS) path-test.o utils.o -o $@ $(BINARY): %: %.o lib @$(LIBTOOL) --mode=link $(LINK.cc) -o $@ $(LIBRARY) $@.o -rpath $(libdir) $(EXIV2BIN): lib $(EXIV2OBJ) $(EXIV2COBJ) @$(LIBTOOL) --mode=link $(LINK.cc) -o $@ $(LIBRARY) $(EXIV2OBJ) $(EXIV2COBJ) -rpath $(libdir) $(MCBIN): lib $(MCOBJ) @$(LIBTOOL) --mode=link $(LINK.cc) -o $@ $(LIBRARY) $(MCOBJ) -rpath $(libdir) install-header: $(INSTALL_DIRS) $(DESTDIR)$(incdir) @list='$(HDR)'; for p in $$list; do \ if test -f $$p; then \ echo "$(INSTALL_DATA) $$p $(DESTDIR)$(incdir)/$$p"; \ $(INSTALL_DATA) $$p $(DESTDIR)$(incdir)/$$p; \ else :; fi; \ done install-lib: lib install-header $(INSTALL_DIRS) $(DESTDIR)$(libdir) @$(LIBTOOL) --mode=install $(INSTALL_DATA) $(LIBRARY) $(DESTDIR)$(libdir)/$(LIBRARY) $(INSTALL_DIRS) $(DESTDIR)$(bindir) $(INSTALL_DIRS) $(DESTDIR)$(libdir)/pkgconfig $(INSTALL_DATA) $(top_srcdir)/config/exiv2.pc $(DESTDIR)$(libdir)/pkgconfig/exiv2.pc install: $(EXIV2BIN) install-lib $(INSTALL_DIRS) $(DESTDIR)$(bindir) @$(LIBTOOL) --mode=install $(INSTALL_PROGRAM) $(EXIV2EXE) $(DESTDIR)$(bindir)/$(EXIV2EXE) $(INSTALL_DIRS) $(DESTDIR)$(mandir) $(INSTALL_DIRS) $(DESTDIR)$(man1dir) $(INSTALL_DATA) exiv2.1 $(DESTDIR)$(man1dir)/exiv2.1 uninstall-header: @list='$(HDR)'; for p in $$list; do \ echo "$(RM) $(DESTDIR)$(incdir)/$$p"; \ $(RM) $(DESTDIR)$(incdir)/$$p; \ done -rmdir $(DESTDIR)$(incdir) uninstall-lib: uninstall-header $(RM) $(DESTDIR)$(libdir)/pkgconfig/exiv2.pc -rmdir $(DESTDIR)$(libdir)/pkgconfig @$(LIBTOOL) --mode=uninstall $(RM) $(DESTDIR)$(libdir)/$(LIBRARY) -rmdir $(DESTDIR)$(libdir) uninstall: uninstall-lib $(RM) $(DESTDIR)$(man1dir)/exiv2.1 -rmdir $(DESTDIR)$(man1dir) -rmdir $(DESTDIR)$(mandir) @$(LIBTOOL) --mode=uninstall $(RM) $(DESTDIR)$(bindir)/$(EXIV2EXE) -rmdir $(DESTDIR)$(bindir) ctags: ebrowse $(HDR) $(SRC) # ctags-exuberant --extra=+q -e * # ctags-exuberant --extra=+q * check: @echo "No checks available for this library." mostlyclean: $(RM) core $(RM) $(CCSRC:.cpp=.ii) $(RM) lib $(RM) path-test.o $(RM) $(CCSRC:%.cpp=.libs/%.d) $(CSRC:%.c=.libs/%.d) @$(LIBTOOL) --mode=clean $(RM) $(LOBJ) $(sort $(BINOBJ) $(EXIV2OBJ) $(EXIV2COBJ) $(MCOBJ)) clean: mostlyclean @$(LIBTOOL) --mode=clean $(RM) $(LIBRARY) @$(LIBTOOL) --mode=clean $(RM) $(EXECUTABLE) $(EXIV2EXE) $(MCEXE) @$(LIBTOOL) --mode=clean $(RM) path-test$(EXEEXT) # Run `make distclean' from the top source directory to also remove # files created by configuring the program. distclean: clean $(RM) exv_conf.h doxygen.hpp ifdef DEP_TRACKING $(RM) $(DEP) -rmdir $(DEPDIR) endif $(RM) tags TAGS $(RM) *~ *.bak *# # This command is intended for maintainers to use; it deletes files # that may need special tools to rebuild. maintainer-clean: uninstall distclean -$(RM) -r .deps -$(RM) -r .libs exiv2-0.23/src/cr2image.hpp0000644000175000017500000001311011732641407015301 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! @file cr2image.hpp @brief Class Cr2Image @version $Rev: 2681 $ @author Andreas Huggel (ahu) ahuggel@gmx.net @date 22-Apr-06, ahu: created */ #ifndef CR2IMAGE_HPP_ #define CR2IMAGE_HPP_ // ***************************************************************************** // included header files #include "image.hpp" #include "basicio.hpp" #include "types.hpp" // + standard includes #include // ***************************************************************************** // namespace extensions namespace Exiv2 { // ***************************************************************************** // class definitions // Add CR2 to the supported image formats namespace ImageType { const int cr2 = 7; //!< CR2 image type (see class Cr2Image) } /*! @brief Class to access raw Canon CR2 images. Exif metadata is supported directly, IPTC is read from the Exif data, if present. */ class EXIV2API Cr2Image : public Image { public: //! @name Creators //@{ /*! @brief Constructor that can either open an existing CR2 image or create a new image from scratch. If a new image is to be created, any existing data is overwritten. Since the constructor can not return a result, callers should check the good() method after object construction to determine success or failure. @param io An auto-pointer that owns a BasicIo instance used for reading and writing image metadata. \b Important: The constructor takes ownership of the passed in BasicIo instance through the auto-pointer. Callers should not continue to use the BasicIo instance after it is passed to this method. Use the Image::io() method to get a temporary reference. @param create Specifies if an existing image should be read (false) or if a new file should be created (true). */ Cr2Image(BasicIo::AutoPtr io, bool create); //@} //! @name Manipulators //@{ void readMetadata(); void writeMetadata(); /*! @brief Not supported. CR2 format does not contain a comment. Calling this function will throw an Error(32). */ void setComment(const std::string& comment); //@} //! @name Accessors //@{ std::string mimeType() const; int pixelWidth() const; int pixelHeight() const; //@} private: //! @name NOT implemented //@{ //! Copy constructor Cr2Image(const Cr2Image& rhs); //! Assignment operator Cr2Image& operator=(const Cr2Image& rhs); //@} }; // class Cr2Image /*! @brief Stateless parser class for data in CR2 format. Images use this class to decode and encode CR2 data. See class TiffParser for details. */ class EXIV2API Cr2Parser { public: /*! @brief Decode metadata from a buffer \em pData of length \em size with data in CR2 format to the provided metadata containers. See TiffParser::decode(). */ static ByteOrder decode( ExifData& exifData, IptcData& iptcData, XmpData& xmpData, const byte* pData, uint32_t size ); /*! @brief Encode metadata from the provided metadata to CR2 format. See TiffParser::encode(). */ static WriteMethod encode( BasicIo& io, const byte* pData, uint32_t size, ByteOrder byteOrder, const ExifData& exifData, const IptcData& iptcData, const XmpData& xmpData ); }; // class Cr2Parser // ***************************************************************************** // template, inline and free functions // These could be static private functions on Image subclasses but then // ImageFactory needs to be made a friend. /*! @brief Create a new Cr2Image instance and return an auto-pointer to it. Caller owns the returned object and the auto-pointer ensures that it will be deleted. */ EXIV2API Image::AutoPtr newCr2Instance(BasicIo::AutoPtr io, bool create); //! Check if the file iIo is a CR2 image. EXIV2API bool isCr2Type(BasicIo& iIo, bool advance); } // namespace Exiv2 #endif // #ifndef CR2IMAGE_HPP_ exiv2-0.23/src/actions.hpp0000644000175000017500000003337211732641407015264 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! @file actions.hpp @brief Implements base class Task, TaskFactory and the various supported actions (derived from Task). @version $Rev: 2681 $ @author Andreas Huggel (ahu) ahuggel@gmx.net @date 11-Dec-03, ahu: created */ #ifndef ACTIONS_HPP_ #define ACTIONS_HPP_ // ***************************************************************************** // included header files // + standard includes #include #include #include "exiv2app.hpp" #include "image.hpp" #include "exif.hpp" #include "iptc.hpp" // ***************************************************************************** // class declarations namespace Exiv2 { class ExifData; class Image; class Metadatum; class PreviewImage; } // ***************************************************************************** // namespace extensions /*! @brief Contains all action classes (task subclasses). */ namespace Action { //! Enumerates all tasks enum TaskType { none, adjust, print, rename, erase, extract, insert, modify, fixiso, fixcom }; // ***************************************************************************** // class definitions /*! @brief Abstract base class for all concrete actions. Task provides a simple interface that actions must implement and a few commonly used helpers. */ class Task { public: //! Shortcut for an auto pointer. typedef std::auto_ptr AutoPtr; //! Virtual destructor. virtual ~Task(); //! Virtual copy construction. AutoPtr clone() const; /*! @brief Application interface to perform a task. @param path Path of the file to process. @return 0 if successful. */ virtual int run(const std::string& path) =0; private: //! Internal virtual copy constructor. virtual Task* clone_() const =0; }; // class Task /*! @brief Task factory. Creates an instance of the task of the requested type. The factory is implemented as a singleton, which can be accessed only through the static member function instance(). */ class TaskFactory { public: /*! @brief Get access to the task factory. Clients access the task factory exclusively through this method. */ static TaskFactory& instance(); //! Destructor void cleanup(); /*! @brief Create a task. @param type Identifies the type of task to create. @return An auto pointer that owns a task of the requested type. If the task type is not supported, the pointer is 0. @remark The caller of the function should check the content of the returned auto pointer and take appropriate action (e.g., throw an exception) if it is 0. */ Task::AutoPtr create(TaskType type); /*! @brief Register a task prototype together with its type. The task factory creates new tasks of a given type by cloning its associated prototype. Additional tasks can be registered. If called for a type which already exists in the list, the corresponding prototype is replaced. @param type Task type. @param task Pointer to the prototype. Ownership is transfered to the task factory. That's what the auto pointer indicates. */ void registerTask(TaskType type, Task::AutoPtr task); private: //! Prevent construction other than through instance(). TaskFactory(); //! Prevent copy construction: not implemented. TaskFactory(const TaskFactory& rhs); //! Pointer to the one and only instance of this class. static TaskFactory* instance_; //! Type used to store Task prototype classes typedef std::map Registry; //! List of task types and corresponding prototypes. Registry registry_; }; // class TaskFactory //! %Print the Exif (or other metadata) of a file to stdout class Print : public Task { public: virtual ~Print(); virtual int run(const std::string& path); typedef std::auto_ptr AutoPtr; AutoPtr clone() const; //! Print the Jpeg comment int printComment(); //! Print list of available preview images int printPreviewList(); //! Print Exif summary information int printSummary(); //! Print Exif, IPTC and XMP metadata in user defined format int printList(); //! Return true if key should be printed, else false bool grepTag(const std::string& key); //! Print all metadata in a user defined format int printMetadata(const Exiv2::Image* image); //! Print a metadatum in a user defined format void printMetadatum(const Exiv2::Metadatum& md, const Exiv2::Image* image); //! Print the label for a summary line void printLabel(const std::string& label) const; /*! @brief Print one summary line with a label (if provided) and requested data. A line break is printed only if a label is provided. @return 1 if a line was written, 0 if the key was not found. */ int printTag(const Exiv2::ExifData& exifData, const std::string& key, const std::string& label ="") const; //! Type for an Exiv2 Easy access function typedef Exiv2::ExifData::const_iterator (*EasyAccessFct)(const Exiv2::ExifData& ed); /*! @brief Print one summary line with a label (if provided) and requested data. A line break is printed only if a label is provided. @return 1 if a line was written, 0 if the information was not found. */ int printTag(const Exiv2::ExifData& exifData, EasyAccessFct easyAccessFct, const std::string& label) const; private: virtual Print* clone_() const; std::string path_; int align_; // for the alignment of the summary output }; // class Print /*! @brief %Rename a file to its metadate creation timestamp, in the specified format. */ class Rename : public Task { public: virtual ~Rename(); virtual int run(const std::string& path); typedef std::auto_ptr AutoPtr; AutoPtr clone() const; private: virtual Rename* clone_() const; }; // class Rename //! %Adjust the Exif (or other metadata) timestamps class Adjust : public Task { public: virtual ~Adjust(); virtual int run(const std::string& path); typedef std::auto_ptr AutoPtr; AutoPtr clone() const; private: virtual Adjust* clone_() const; int adjustDateTime(Exiv2::ExifData& exifData, const std::string& key, const std::string& path) const; long adjustment_; long yearAdjustment_; long monthAdjustment_; long dayAdjustment_; }; // class Adjust /*! @brief %Erase the entire exif data or only the thumbnail section. */ class Erase : public Task { public: virtual ~Erase(); virtual int run(const std::string& path); typedef std::auto_ptr AutoPtr; AutoPtr clone() const; /*! @brief Delete the thumbnail image, incl IFD1 metadata from the file. */ int eraseThumbnail(Exiv2::Image* image) const; /*! @brief Erase the complete Exif data block from the file. */ int eraseExifData(Exiv2::Image* image) const; /*! @brief Erase all Iptc data from the file. */ int eraseIptcData(Exiv2::Image* image) const; /*! @brief Erase Jpeg comment from the file. */ int eraseComment(Exiv2::Image* image) const; /*! @brief Erase XMP packet from the file. */ int eraseXmpData(Exiv2::Image* image) const; private: virtual Erase* clone_() const; std::string path_; }; // class Erase /*! @brief %Extract the entire exif data or only the thumbnail section. */ class Extract : public Task { public: virtual ~Extract(); virtual int run(const std::string& path); typedef std::auto_ptr AutoPtr; AutoPtr clone() const; /*! @brief Write the thumbnail image to a file. The filename is composed by removing the suffix from the image filename and appending "-thumb" and the appropriate suffix (".jpg" or ".tif"), depending on the format of the Exif thumbnail image. */ int writeThumbnail() const; /*! @brief Write preview images to files. */ int writePreviews() const; /*! @brief Write one preview image to a file. The filename is composed by removing the suffix from the image filename and appending "-preview" and the appropriate suffix (".jpg" or ".tif"), depending on the format of the Exif thumbnail image. */ void writePreviewFile(const Exiv2::PreviewImage& pvImg, int num) const; private: virtual Extract* clone_() const; std::string path_; }; // class Extract /*! @brief %Insert the Exif data from corresponding *.exv files. */ class Insert : public Task { public: virtual ~Insert(); virtual int run(const std::string& path); typedef std::auto_ptr AutoPtr; AutoPtr clone() const; /*! @brief Insert a Jpeg thumbnail image from a file into file \em path. The filename of the thumbnail is expected to be the image filename (\em path) minus its suffix plus "-thumb.jpg". */ int insertThumbnail(const std::string& path) const; /*! @brief Insert an XMP packet from a file into file \em path. The filename of the XMP packet is expected to be the image filename (\em path) minus its suffix plus ".xmp". */ int insertXmpPacket(const std::string& path) const; private: virtual Insert* clone_() const; }; // class Insert /*! @brief %Modify the Exif data according to the commands in the modification table. */ class Modify : public Task { public: virtual ~Modify(); virtual int run(const std::string& path); typedef std::auto_ptr AutoPtr; AutoPtr clone() const; Modify() {} //! Apply modification commands to the \em pImage, return 0 if successful. static int applyCommands(Exiv2::Image* pImage); private: virtual Modify* clone_() const; //! Copy contructor needed because of AutoPtr member Modify(const Modify& /*src*/) : Task() {} //! Add a metadatum to \em pImage according to \em modifyCmd static int addMetadatum(Exiv2::Image* pImage, const ModifyCmd& modifyCmd); //! Set a metadatum in \em pImage according to \em modifyCmd static int setMetadatum(Exiv2::Image* pImage, const ModifyCmd& modifyCmd); //! Delete a metadatum from \em pImage according to \em modifyCmd static void delMetadatum(Exiv2::Image* pImage, const ModifyCmd& modifyCmd); //! Register an XMP namespace according to \em modifyCmd static void regNamespace(const ModifyCmd& modifyCmd); }; // class Modify /*! @brief %Copy ISO settings from any of the Nikon makernotes to the regular Exif tag, Exif.Photo.ISOSpeedRatings. */ class FixIso : public Task { public: virtual ~FixIso(); virtual int run(const std::string& path); typedef std::auto_ptr AutoPtr; AutoPtr clone() const; private: virtual FixIso* clone_() const; std::string path_; }; // class FixIso /*! @brief Fix the character encoding of Exif UNICODE user comments. Decodes the comment using the auto-detected or specified character encoding and writes it back in UCS-2. */ class FixCom : public Task { public: virtual ~FixCom(); virtual int run(const std::string& path); typedef std::auto_ptr AutoPtr; AutoPtr clone() const; private: virtual FixCom* clone_() const; std::string path_; }; // class FixCom } // namespace Action #endif // #ifndef ACTIONS_HPP_ exiv2-0.23/src/taglist.cpp0000644000175000017500000000343111436245701015255 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* Abstract: Print a simple comma separated list of tags defined in Exiv2 File: taglist.cpp Version: $Rev: 2331 $ Author(s): Andreas Huggel (ahu) History: 07-Jan-04, ahu: created */ // ***************************************************************************** #include "tags.hpp" #include "datasets.hpp" #include "properties.hpp" #include "error.hpp" #include #include using namespace Exiv2; int main(int argc, char* argv[]) try { int rc = 0; switch (argc) { case 2: { std::string item(argv[1]); if (item == "Exif") { ExifTags::taglist(std::cout); break; } if (item == "Iptc") { IptcDataSets::dataSetList(std::cout); break; } if (ExifTags::isExifGroup(item) || ExifTags::isMakerGroup(item)) { ExifTags::taglist(std::cout, item); break; } try { XmpProperties::printProperties(std::cout, item); } catch(const AnyError&) { rc = 2; } break; } case 1: ExifTags::taglist(std::cout); break; default: rc = 1; break; } if (rc) { std::cout << "Usage: " << argv[0] << " [Exif|Canon|CanonCs|CanonSi|CanonCf|Fujifilm|Minolta|Nikon1|Nikon2|Nikon3|Olympus|Panasonic|Pentax|Sigma|Sony|Iptc" << "|dc|xmp|xmpRights|xmpMM|xmpBJ|xmpTPg|xmpDM|pdf|photoshop|crs|tiff|exif|aux|iptc]\n" << "Print Exif tags, MakerNote tags, or Iptc datasets\n"; } return rc; } catch (AnyError& e) { std::cout << "Caught Exiv2 exception '" << e << "'\n"; return 1; } exiv2-0.23/src/datasets.hpp0000644000175000017500000003574611732641407015443 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! @file datasets.hpp @brief IPTC dataset and type information @version $Rev: 2681 $ @author Brad Schick (brad) @date 24-Jul-04, brad: created */ #ifndef DATASETS_HPP_ #define DATASETS_HPP_ // ***************************************************************************** // included header files #include "types.hpp" #include "metadatum.hpp" // + standard includes #include #include // for std::pair #include #include // ***************************************************************************** // namespace extensions namespace Exiv2 { // ***************************************************************************** // class definitions //! Details of an IPTC record. struct EXIV2API RecordInfo { //! Constructor RecordInfo(uint16_t recordId, const char* name, const char* desc); uint16_t recordId_; //!< Record id const char* name_; //!< Record name (one word) const char* desc_; //!< Record description }; //! Details of an IPTC dataset. struct EXIV2API DataSet { //! Constructor DataSet( uint16_t number, const char* name, const char* title, const char* desc, bool mandatory, bool repeatable, uint32_t minbytes, uint32_t maxbytes, TypeId type, uint16_t recordId, const char* photoshop ); uint16_t number_; //!< Dataset number const char* name_; //!< Dataset name const char* title_; //!< Dataset title or label const char* desc_; //!< Dataset description bool mandatory_; //!< True if dataset is mandatory bool repeatable_; //!< True if dataset is repeatable uint32_t minbytes_; //!< Minimum number of bytes uint32_t maxbytes_; //!< Maximum number of bytes TypeId type_; //!< Exiv2 default type uint16_t recordId_; //!< Record id const char* photoshop_; //!< Photoshop string }; // struct DataSet //! IPTC dataset reference, implemented as a static class. class EXIV2API IptcDataSets { public: /*! @name Record identifiers @brief Record identifiers to logically group dataSets. There are other possible record types, but they are not standardized by the IPTC IIM4 standard (and not commonly used in images). */ //@{ static const uint16_t invalidRecord = 0; static const uint16_t envelope = 1; static const uint16_t application2 = 2; //@} //! @name Dataset identifiers //@{ static const uint16_t ModelVersion = 0; static const uint16_t Destination = 5; static const uint16_t FileFormat = 20; static const uint16_t FileVersion = 22; static const uint16_t ServiceId = 30; static const uint16_t EnvelopeNumber = 40; static const uint16_t ProductId = 50; static const uint16_t EnvelopePriority = 60; static const uint16_t DateSent = 70; static const uint16_t TimeSent = 80; static const uint16_t CharacterSet = 90; static const uint16_t UNO = 100; static const uint16_t ARMId = 120; static const uint16_t ARMVersion = 122; static const uint16_t RecordVersion = 0; static const uint16_t ObjectType = 3; static const uint16_t ObjectAttribute = 4; static const uint16_t ObjectName = 5; static const uint16_t EditStatus = 7; static const uint16_t EditorialUpdate = 8; static const uint16_t Urgency = 10; static const uint16_t Subject = 12; static const uint16_t Category = 15; static const uint16_t SuppCategory = 20; static const uint16_t FixtureId = 22; static const uint16_t Keywords = 25; static const uint16_t LocationCode = 26; static const uint16_t LocationName = 27; static const uint16_t ReleaseDate = 30; static const uint16_t ReleaseTime = 35; static const uint16_t ExpirationDate = 37; static const uint16_t ExpirationTime = 38; static const uint16_t SpecialInstructions = 40; static const uint16_t ActionAdvised = 42; static const uint16_t ReferenceService = 45; static const uint16_t ReferenceDate = 47; static const uint16_t ReferenceNumber = 50; static const uint16_t DateCreated = 55; static const uint16_t TimeCreated = 60; static const uint16_t DigitizationDate = 62; static const uint16_t DigitizationTime = 63; static const uint16_t Program = 65; static const uint16_t ProgramVersion = 70; static const uint16_t ObjectCycle = 75; static const uint16_t Byline = 80; static const uint16_t BylineTitle = 85; static const uint16_t City = 90; static const uint16_t SubLocation = 92; static const uint16_t ProvinceState = 95; static const uint16_t CountryCode = 100; static const uint16_t CountryName = 101; static const uint16_t TransmissionReference = 103; static const uint16_t Headline = 105; static const uint16_t Credit = 110; static const uint16_t Source = 115; static const uint16_t Copyright = 116; static const uint16_t Contact = 118; static const uint16_t Caption = 120; static const uint16_t Writer = 122; static const uint16_t RasterizedCaption = 125; static const uint16_t ImageType = 130; static const uint16_t ImageOrientation = 131; static const uint16_t Language = 135; static const uint16_t AudioType = 150; static const uint16_t AudioRate = 151; static const uint16_t AudioResolution = 152; static const uint16_t AudioDuration = 153; static const uint16_t AudioOutcue = 154; static const uint16_t PreviewFormat = 200; static const uint16_t PreviewVersion = 201; static const uint16_t Preview = 202; //@} private: //! Prevent construction: not implemented. IptcDataSets() {} //! Prevent copy-construction: not implemented. IptcDataSets(const IptcDataSets& rhs); //! Prevent assignment: not implemented. IptcDataSets& operator=(const IptcDataSets& rhs); public: /*! @brief Return the name of the dataset. @param number The dataset number @param recordId The IPTC record Id @return The name of the dataset or a string containing the hexadecimal value of the dataset in the form "0x01ff", if this is an unknown dataset. */ static std::string dataSetName(uint16_t number, uint16_t recordId); /*! @brief Return the title (label) of the dataset. @param number The dataset number @param recordId The IPTC record Id @return The title (label) of the dataset */ static const char* dataSetTitle(uint16_t number, uint16_t recordId); /*! @brief Return the description of the dataset. @param number The dataset number @param recordId The IPTC record Id @return The description of the dataset */ static const char* dataSetDesc(uint16_t number, uint16_t recordId); /*! @brief Return the photohsop name of a given dataset. @param number The dataset number @param recordId The IPTC record Id @return The name used by photoshop for a dataset or an empty string if photoshop does not use the dataset. */ static const char* dataSetPsName(uint16_t number, uint16_t recordId); /*! @brief Check if a given dataset is repeatable @param number The dataset number @param recordId The IPTC record Id @return true if the given dataset is repeatable otherwise false */ static bool dataSetRepeatable(uint16_t number, uint16_t recordId); /*! @brief Return the dataSet number for dataset name and record id @param dataSetName dataSet name @param recordId recordId @return dataSet number @throw Error if the \em dataSetName or \em recordId are invalid */ static uint16_t dataSet(const std::string& dataSetName, uint16_t recordId); //! Return the type for dataSet number and Record id static TypeId dataSetType(uint16_t number, uint16_t recordId); /*! @brief Return the name of the Record @param recordId The record id @return The name of the record or a string containing the hexadecimal value of the record in the form "0x01ff", if this is an unknown record. */ static std::string recordName(uint16_t recordId); /*! @brief Return the description of a record @param recordId Record Id number @return the description of the Record */ static const char* recordDesc(uint16_t recordId); /*! @brief Return the Id number of a record @param recordName Name of a record type @return the Id number of a Record @throw Error if the record is not known; */ static uint16_t recordId(const std::string& recordName); //! Return read-only list of built-in Envelope Record datasets static const DataSet* envelopeRecordList(); //! Return read-only list of built-in Application2 Record datasets static const DataSet* application2RecordList(); //! Print a list of all dataSets to output stream static void dataSetList(std::ostream& os); private: static int dataSetIdx(uint16_t number, uint16_t recordId); static int dataSetIdx(const std::string& dataSetName, uint16_t recordId); static const DataSet* records_[]; static const RecordInfo recordInfo_[]; }; // class IptcDataSets /*! @brief Concrete keys for IPTC metadata. */ class EXIV2API IptcKey : public Key { public: //! Shortcut for an %IptcKey auto pointer. typedef std::auto_ptr AutoPtr; //! @name Creators //@{ /*! @brief Constructor to create an IPTC key from a key string. @param key The key string. @throw Error if the first part of the key is not 'Iptc' or the remaining parts of the key cannot be parsed and converted to a record name and a dataset name. */ explicit IptcKey(const std::string& key); /*! @brief Constructor to create an IPTC key from dataset and record ids. @param tag Dataset id @param record Record id */ IptcKey(uint16_t tag, uint16_t record); //! Copy constructor IptcKey(const IptcKey& rhs); //! Destructor virtual ~IptcKey(); //@} //! @name Manipulators //@{ /*! @brief Assignment operator. */ IptcKey& operator=(const IptcKey& rhs); //@} //! @name Accessors //@{ virtual std::string key() const; virtual const char* familyName() const; /*! @brief Return the name of the group (the second part of the key). For IPTC keys, the group name is the record name. */ virtual std::string groupName() const; virtual std::string tagName() const; virtual std::string tagLabel() const; virtual uint16_t tag() const; AutoPtr clone() const; //! Return the name of the record std::string recordName() const; //! Return the record id uint16_t record() const; //@} protected: //! @name Manipulators //@{ /*! @brief Set the key corresponding to the dataset and record id. The key is of the form 'Iptc.recordName.dataSetName'. */ void makeKey(); /*! @brief Parse and convert the key string into dataset and record id. Updates data members if the string can be decomposed, or throws \em Error. @throw Error if the key cannot be decomposed. */ void decomposeKey(); //@} private: //! Internal virtual copy constructor. EXV_DLLLOCAL virtual IptcKey* clone_() const; // DATA static const char* familyName_; uint16_t tag_; //!< Tag value uint16_t record_; //!< Record value std::string key_; //!< Key }; // class IptcKey // ***************************************************************************** // free functions //! Output operator for dataSet EXIV2API std::ostream& operator<<(std::ostream& os, const DataSet& dataSet); } // namespace Exiv2 #endif // #ifndef DATASETS_HPP_ exiv2-0.23/src/rafimage.hpp0000644000175000017500000001202711732641407015371 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! @file rafimage.hpp @brief Fujifilm RAW image @version $Rev: 2681 $ @author Andreas Huggel (ahu) ahuggel@gmx.net @date 05-Feb-07, ahu: created */ #ifndef RAFIMAGE_HPP_ #define RAFIMAGE_HPP_ // ***************************************************************************** // included header files #include "image.hpp" #include "basicio.hpp" #include "types.hpp" // + standard includes #include // ***************************************************************************** // namespace extensions namespace Exiv2 { // ***************************************************************************** // class definitions // Add RAF to the supported image formats namespace ImageType { const int raf = 8; //!< RAF image type (see class RafImage) } /*! @brief Class to access raw Fujifilm RAF images. Exif metadata is supported directly, IPTC is read from the Exif data, if present. */ class EXIV2API RafImage : public Image { public: //! @name Creators //@{ /*! @brief Constructor that can either open an existing RAF image or create a new image from scratch. If a new image is to be created, any existing data is overwritten. Since the constructor can not return a result, callers should check the good() method after object construction to determine success or failure. @param io An auto-pointer that owns a BasicIo instance used for reading and writing image metadata. \b Important: The constructor takes ownership of the passed in BasicIo instance through the auto-pointer. Callers should not continue to use the BasicIo instance after it is passed to this method. Use the Image::io() method to get a temporary reference. @param create Specifies if an existing image should be read (false) or if a new file should be created (true). */ RafImage(BasicIo::AutoPtr io, bool create); //@} //! @name Manipulators //@{ void readMetadata(); /*! @brief Todo: Write metadata back to the image. This method is not yet implemented. Calling it will throw an Error(31). */ void writeMetadata(); /*! @brief Todo: Not supported yet, requires writeMetadata(). Calling this function will throw an Error(32). */ void setExifData(const ExifData& exifData); /*! @brief Todo: Not supported yet, requires writeMetadata(). Calling this function will throw an Error(32). */ void setIptcData(const IptcData& iptcData); /*! @brief Not supported. RAF format does not contain a comment. Calling this function will throw an Error(32). */ void setComment(const std::string& comment); //@} //! @name Accessors //@{ std::string mimeType() const; int pixelWidth() const; int pixelHeight() const; //@} private: //! @name NOT implemented //@{ //! Copy constructor RafImage(const RafImage& rhs); //! Assignment operator RafImage& operator=(const RafImage& rhs); //@} }; // class RafImage // ***************************************************************************** // template, inline and free functions // These could be static private functions on Image subclasses but then // ImageFactory needs to be made a friend. /*! @brief Create a new RafImage instance and return an auto-pointer to it. Caller owns the returned object and the auto-pointer ensures that it will be deleted. */ EXIV2API Image::AutoPtr newRafInstance(BasicIo::AutoPtr io, bool create); //! Check if the file iIo is a RAF image. EXIV2API bool isRafType(BasicIo& iIo, bool advance); } // namespace Exiv2 #endif // #ifndef RAFIMAGE_HPP_ exiv2-0.23/src/bmpimage.cpp0000644000175000017500000001230711732641407015373 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /* File: bmpimage.cpp Version: $Rev: 2681 $ Author(s): Marco Piovanelli, Ovolab (marco) History: 05-Mar-2007, marco: created */ // ***************************************************************************** #include "rcsid_int.hpp" EXIV2_RCSID("@(#) $Id: bmpimage.cpp 2681 2012-03-22 15:19:35Z ahuggel $") //#define DEBUG 1 // ***************************************************************************** // included header files #ifdef _MSC_VER # include "exv_msvc.h" #else # include "exv_conf.h" #endif #include "bmpimage.hpp" #include "image.hpp" #include "basicio.hpp" #include "error.hpp" #include "futils.hpp" // + standard includes #include #include #include // ***************************************************************************** // class member definitions namespace Exiv2 { BmpImage::BmpImage(BasicIo::AutoPtr io) : Image(ImageType::bmp, mdNone, io) { } // BmpImage::BmpImage std::string BmpImage::mimeType() const { return "image/x-ms-bmp"; } void BmpImage::setExifData(const ExifData& /*exifData*/) { // Todo: implement me! throw(Error(32, "Exif metadata", "BMP")); } void BmpImage::setIptcData(const IptcData& /*iptcData*/) { // Todo: implement me! throw(Error(32, "IPTC metadata", "BMP")); } void BmpImage::setComment(const std::string& /*comment*/) { // not supported throw(Error(32, "Image comment", "BMP")); } void BmpImage::readMetadata() { #ifdef DEBUG std::cerr << "Exiv2::BmpImage::readMetadata: Reading Windows bitmap file " << io_->path() << "\n"; #endif if (io_->open() != 0) { throw Error(9, io_->path(), strError()); } IoCloser closer(*io_); // Ensure that this is the correct image type if (!isBmpType(*io_, false)) { if (io_->error() || io_->eof()) throw Error(14); throw Error(3, "BMP"); } clearMetadata(); /* The Windows bitmap header goes as follows -- all numbers are in little-endian byte order: offset length name description ====== ======= ===================== ======= 0 2 bytes signature always 'BM' 2 4 bytes bitmap size 6 4 bytes reserved 10 4 bytes bitmap offset 14 4 bytes header size 18 4 bytes bitmap width 22 4 bytes bitmap height 26 2 bytes plane count 28 2 bytes depth 30 4 bytes compression 0 = none; 1 = RLE, 8 bits/pixel; 2 = RLE, 4 bits/pixel; 3 = bitfield; 4 = JPEG; 5 = PNG 34 4 bytes image size size of the raw bitmap data, in bytes 38 4 bytes horizontal resolution (in pixels per meter) 42 4 bytes vertical resolution (in pixels per meter) 46 4 bytes color count 50 4 bytes important colors number of "important" colors */ byte buf[54]; if (io_->read(buf, sizeof(buf)) == sizeof(buf)) { pixelWidth_ = getLong(buf + 18, littleEndian); pixelHeight_ = getLong(buf + 22, littleEndian); } } // BmpImage::readMetadata void BmpImage::writeMetadata() { // Todo: implement me! throw(Error(31, "BMP")); } // BmpImage::writeMetadata // ************************************************************************* // free functions Image::AutoPtr newBmpInstance(BasicIo::AutoPtr io, bool /*create*/) { Image::AutoPtr image(new BmpImage(io)); if (!image->good()) { image.reset(); } return image; } bool isBmpType(BasicIo& iIo, bool advance) { const int32_t len = 2; const unsigned char BmpImageId[2] = { 'B', 'M' }; byte buf[len]; iIo.read(buf, len); if (iIo.error() || iIo.eof()) { return false; } bool matched = (memcmp(buf, BmpImageId, len) == 0); if (!advance || !matched) { iIo.seek(-len, BasicIo::cur); } return matched; } } // namespace Exiv2 exiv2-0.23/src/getopt_win32.c0000644000175000017500000003172110405550022015563 0ustar andreasandreas/* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */ /*- * Copyright (c) 2000 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Dieter Baron and Thomas Klausner. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the NetBSD * Foundation, Inc. and its contributors. * 4. Neither the name of The NetBSD Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #if _MSC_VER >= 1400 # pragma warning(disable : 4996) #endif // included header files #include #include #include #include #include "getopt_win32.h" #include #include #define REPLACE_GETOPT #define _DIAGASSERT(x) do {} while (0) #ifdef REPLACE_GETOPT #ifdef __weak_alias __weak_alias(getopt,_getopt) #endif int opterr = 1; /* if error message should be printed */ int optind = 1; /* index into parent argv vector */ int optopt = '?'; /* character checked for validity */ int optreset; /* reset getopt */ char *optarg; /* argument associated with option */ #endif #ifdef __weak_alias __weak_alias(getopt_long,_getopt_long) #endif #ifndef __CYGWIN__ #define __progname __argv[0] #else extern char __declspec(dllimport) *__progname; #endif #define IGNORE_FIRST (*options == '-' || *options == '+') #define PRINT_ERROR ((opterr) && ((*options != ':') \ || (IGNORE_FIRST && options[1] != ':'))) /* This differs from the cygwin implementation, which effectively defaults to PC, but is consistent with the NetBSD implementation and doc's. */ #ifndef IS_POSIXLY_CORRECT #define IS_POSIXLY_CORRECT (getenv("POSIXLY_CORRECT") != NULL) #endif #define PERMUTE (!IS_POSIXLY_CORRECT && !IGNORE_FIRST) /* XXX: GNU ignores PC if *options == '-' */ #define IN_ORDER (!IS_POSIXLY_CORRECT && *options == '-') /* return values */ #define BADCH (int)'?' #define BADARG ((IGNORE_FIRST && options[1] == ':') \ || (*options == ':') ? (int)':' : (int)'?') #define INORDER (int)1 static char EMSG[1]; static int getopt_internal (int, char * const *, const char *); static int gcd (int, int); static void permute_args (int, int, int, char * const *); static char *place = EMSG; /* option letter processing */ /* XXX: set optreset to 1 rather than these two */ static int nonopt_start = -1; /* first non option argument (for permute) */ static int nonopt_end = -1; /* first option after non options (for permute) */ /* Error messages */ static const char recargchar[] = "option requires an argument -- %c"; static const char recargstring[] = "option requires an argument -- %s"; static const char ambig[] = "ambiguous option -- %.*s"; static const char noarg[] = "option doesn't take an argument -- %.*s"; static const char illoptchar[] = "unknown option -- %c"; static const char illoptstring[] = "unknown option -- %s"; static void _vwarnx(const char *fmt, va_list ap) { (void)fprintf(stderr, "%s: ", __progname); if (fmt != NULL) (void)vfprintf(stderr, fmt, ap); (void)fprintf(stderr, "\n"); } static void warnx(const char *fmt, ...) { va_list ap; va_start(ap, fmt); _vwarnx(fmt, ap); va_end(ap); } /* * Compute the greatest common divisor of a and b. */ static int gcd(a, b) int a; int b; { int c; c = a % b; while (c != 0) { a = b; b = c; c = a % b; } return b; } /* * Exchange the block from nonopt_start to nonopt_end with the block * from nonopt_end to opt_end (keeping the same order of arguments * in each block). */ static void permute_args(panonopt_start, panonopt_end, opt_end, nargv) int panonopt_start; int panonopt_end; int opt_end; char * const *nargv; { int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos; char *swap; _DIAGASSERT(nargv != NULL); /* * compute lengths of blocks and number and size of cycles */ nnonopts = panonopt_end - panonopt_start; nopts = opt_end - panonopt_end; ncycle = gcd(nnonopts, nopts); cyclelen = (opt_end - panonopt_start) / ncycle; for (i = 0; i < ncycle; i++) { cstart = panonopt_end+i; pos = cstart; for (j = 0; j < cyclelen; j++) { if (pos >= panonopt_end) pos -= nnonopts; else pos += nopts; swap = nargv[pos]; /* LINTED const cast */ ((char **) nargv)[pos] = nargv[cstart]; /* LINTED const cast */ ((char **)nargv)[cstart] = swap; } } } /* * getopt_internal -- * Parse argc/argv argument vector. Called by user level routines. * Returns -2 if -- is found (can be long option or end of options marker). */ static int getopt_internal(nargc, nargv, options) int nargc; char * const *nargv; const char *options; { char *oli; /* option letter list index */ int optchar; _DIAGASSERT(nargv != NULL); _DIAGASSERT(options != NULL); optarg = NULL; /* * XXX Some programs (like rsyncd) expect to be able to * XXX re-initialize optind to 0 and have getopt_long(3) * XXX properly function again. Work around this braindamage. */ if (optind == 0) optind = 1; if (optreset) nonopt_start = nonopt_end = -1; start: if (optreset || !*place) { /* update scanning pointer */ optreset = 0; if (optind >= nargc) { /* end of argument vector */ place = EMSG; if (nonopt_end != -1) { /* do permutation, if we have to */ permute_args(nonopt_start, nonopt_end, optind, nargv); optind -= nonopt_end - nonopt_start; } else if (nonopt_start != -1) { /* * If we skipped non-options, set optind * to the first of them. */ optind = nonopt_start; } nonopt_start = nonopt_end = -1; return -1; } if ((*(place = nargv[optind]) != '-') || (place[1] == '\0')) { /* found non-option */ place = EMSG; if (IN_ORDER) { /* * GNU extension: * return non-option as argument to option 1 */ optarg = nargv[optind++]; return INORDER; } if (!PERMUTE) { /* * if no permutation wanted, stop parsing * at first non-option */ return -1; } /* do permutation */ if (nonopt_start == -1) nonopt_start = optind; else if (nonopt_end != -1) { permute_args(nonopt_start, nonopt_end, optind, nargv); nonopt_start = optind - (nonopt_end - nonopt_start); nonopt_end = -1; } optind++; /* process next argument */ goto start; } if (nonopt_start != -1 && nonopt_end == -1) nonopt_end = optind; if (place[1] && *++place == '-') { /* found "--" */ place++; return -2; } } if ((optchar = (int)*place++) == (int)':' || (oli = strchr(options + (IGNORE_FIRST ? 1 : 0), optchar)) == NULL) { /* option letter unknown or ':' */ if (!*place) ++optind; if (PRINT_ERROR) warnx(illoptchar, optchar); optopt = optchar; return BADCH; } if (optchar == 'W' && oli[1] == ';') { /* -W long-option */ /* XXX: what if no long options provided (called by getopt)? */ if (*place) return -2; if (++optind >= nargc) { /* no arg */ place = EMSG; if (PRINT_ERROR) warnx(recargchar, optchar); optopt = optchar; return BADARG; } else /* white space */ place = nargv[optind]; /* * Handle -W arg the same as --arg (which causes getopt to * stop parsing). */ return -2; } if (*++oli != ':') { /* doesn't take argument */ if (!*place) ++optind; } else { /* takes (optional) argument */ optarg = NULL; if (*place) /* no white space */ optarg = place; /* XXX: disable test for :: if PC? (GNU doesn't) */ else if (oli[1] != ':') { /* arg not optional */ if (++optind >= nargc) { /* no arg */ place = EMSG; if (PRINT_ERROR) warnx(recargchar, optchar); optopt = optchar; return BADARG; } else optarg = nargv[optind]; } place = EMSG; ++optind; } /* dump back option letter */ return optchar; } #ifdef REPLACE_GETOPT /* * getopt -- * Parse argc/argv argument vector. * * [eventually this will replace the real getopt] */ int getopt(nargc, nargv, options) int nargc; char * const *nargv; const char *options; { int retval; _DIAGASSERT(nargv != NULL); _DIAGASSERT(options != NULL); if ((retval = getopt_internal(nargc, nargv, options)) == -2) { ++optind; /* * We found an option (--), so if we skipped non-options, * we have to permute. */ if (nonopt_end != -1) { permute_args(nonopt_start, nonopt_end, optind, nargv); optind -= nonopt_end - nonopt_start; } nonopt_start = nonopt_end = -1; retval = -1; } return retval; } #endif /* * getopt_long -- * Parse argc/argv argument vector. */ int getopt_long(nargc, nargv, options, long_options, idx) int nargc; char * const *nargv; const char *options; const struct option *long_options; int *idx; { int retval; _DIAGASSERT(nargv != NULL); _DIAGASSERT(options != NULL); _DIAGASSERT(long_options != NULL); /* idx may be NULL */ if ((retval = getopt_internal(nargc, nargv, options)) == -2) { char *current_argv, *has_equal; size_t current_argv_len; int i, match; current_argv = place; match = -1; optind++; place = EMSG; if (*current_argv == '\0') { /* found "--" */ /* * We found an option (--), so if we skipped * non-options, we have to permute. */ if (nonopt_end != -1) { permute_args(nonopt_start, nonopt_end, optind, nargv); optind -= nonopt_end - nonopt_start; } nonopt_start = nonopt_end = -1; return -1; } if ((has_equal = strchr(current_argv, '=')) != NULL) { /* argument found (--option=arg) */ current_argv_len = has_equal - current_argv; has_equal++; } else current_argv_len = strlen(current_argv); for (i = 0; long_options[i].name; i++) { /* find matching long option */ if (strncmp(current_argv, long_options[i].name, current_argv_len)) continue; if (strlen(long_options[i].name) == (unsigned)current_argv_len) { /* exact match */ match = i; break; } if (match == -1) /* partial match */ match = i; else { /* ambiguous abbreviation */ if (PRINT_ERROR) warnx(ambig, (int)current_argv_len, current_argv); optopt = 0; return BADCH; } } if (match != -1) { /* option found */ if (long_options[match].has_arg == no_argument && has_equal) { if (PRINT_ERROR) warnx(noarg, (int)current_argv_len, current_argv); /* * XXX: GNU sets optopt to val regardless of * flag */ if (long_options[match].flag == NULL) optopt = long_options[match].val; else optopt = 0; return BADARG; } if (long_options[match].has_arg == required_argument || long_options[match].has_arg == optional_argument) { if (has_equal) optarg = has_equal; else if (long_options[match].has_arg == required_argument) { /* * optional argument doesn't use * next nargv */ optarg = nargv[optind++]; } } if ((long_options[match].has_arg == required_argument) && (optarg == NULL)) { /* * Missing argument; leading ':' * indicates no error should be generated */ if (PRINT_ERROR) warnx(recargstring, current_argv); /* * XXX: GNU sets optopt to val regardless * of flag */ if (long_options[match].flag == NULL) optopt = long_options[match].val; else optopt = 0; --optind; return BADARG; } } else { /* unknown option */ if (PRINT_ERROR) warnx(illoptstring, current_argv); optopt = 0; return BADCH; } if (long_options[match].flag) { *long_options[match].flag = long_options[match].val; retval = 0; } else retval = long_options[match].val; if (idx) *idx = match; } return retval; } exiv2-0.23/src/image.hpp0000644000175000017500000006515611742031570014706 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! @file image.hpp @brief Class Image, defining the interface for all Image subclasses. @version $Rev: 2701 $ @author Andreas Huggel (ahu) ahuggel@gmx.net @author Brad Schick (brad) brad@robotbattle.com @date 09-Jan-04, ahu: created
11-Feb-04, ahu: isolated as a component
19-Jul-04, brad: revamped to be more flexible and support IPTC
15-Jan-05, brad: inside-out design changes */ #ifndef IMAGE_HPP_ #define IMAGE_HPP_ // ***************************************************************************** // included header files #include "types.hpp" #include "basicio.hpp" #include "exif.hpp" #include "iptc.hpp" #include "xmp.hpp" // + standard includes #include #include // ***************************************************************************** // namespace extensions namespace Exiv2 { // ***************************************************************************** // class definitions //! Supported image formats namespace ImageType { const int none = 0; //!< Not an image } //! Native preview information. This is meant to be used only by the PreviewManager. struct NativePreview { long position_; //!< Position uint32_t size_; //!< Size uint32_t width_; //!< Width uint32_t height_; //!< Height std::string filter_; //!< Filter std::string mimeType_; //!< MIME type }; //! List of native previews. This is meant to be used only by the PreviewManager. typedef std::vector NativePreviewList; /*! @brief Abstract base class defining the interface for an image. This is the top-level interface to the Exiv2 library. Image has containers to store image metadata and subclasses implement read and save metadata from and to specific image formats.
Most client apps will obtain an Image instance by calling a static ImageFactory method. The Image class can then be used to to read, write, and save metadata. */ class EXIV2API Image { public: //! Image auto_ptr type typedef std::auto_ptr AutoPtr; //! @name Creators //@{ /*! @brief Constructor taking the image type, a bitmap of the supported metadata types and an auto-pointer that owns an IO instance. See subclass constructor doc. */ Image(int imageType, uint16_t supportedMetadata, BasicIo::AutoPtr io); //! Virtual Destructor virtual ~Image(); //@} //! @name Manipulators //@{ /*! @brief Read all metadata supported by a specific image format from the image. Before this method is called, the image metadata will be cleared. This method returns success even if no metadata is found in the image. Callers must therefore check the size of individual metadata types before accessing the data. @throw Error if opening or reading of the file fails or the image data is not valid (does not look like data of the specific image type). */ virtual void readMetadata() =0; /*! @brief Write metadata back to the image. All existing metadata sections in the image are either created, replaced, or erased. If values for a given metadata type have been assigned, a section for that metadata type will either be created or replaced. If no values have been assigned to a given metadata type, any exists section for that metadata type will be removed from the image. @throw Error if the operation fails */ virtual void writeMetadata() =0; /*! @brief Assign new Exif data. The new Exif data is not written to the image until the writeMetadata() method is called. @param exifData An ExifData instance holding Exif data to be copied */ virtual void setExifData(const ExifData& exifData); /*! @brief Erase any buffered Exif data. Exif data is not removed from the actual image until the writeMetadata() method is called. */ virtual void clearExifData(); /*! @brief Assign new IPTC data. The new IPTC data is not written to the image until the writeMetadata() method is called. @param iptcData An IptcData instance holding IPTC data to be copied */ virtual void setIptcData(const IptcData& iptcData); /*! @brief Erase any buffered IPTC data. IPTC data is not removed from the actual image until the writeMetadata() method is called. */ virtual void clearIptcData(); /*! @brief Assign a raw XMP packet. The new XMP packet is not written to the image until the writeMetadata() method is called. Subsequent calls to writeMetadata() write the XMP packet from the buffered raw XMP packet rather than from buffered parsed XMP data. In order to write from parsed XMP data again, use either writeXmpFromPacket(false) or setXmpData(). @param xmpPacket A string containing the raw XMP packet. */ virtual void setXmpPacket(const std::string& xmpPacket); /*! @brief Erase the buffered XMP packet. XMP data is not removed from the actual image until the writeMetadata() method is called. This has the same effect as clearXmpData() but operates on the buffered raw XMP packet only, not the parsed XMP data. Subsequent calls to writeMetadata() write the XMP packet from the buffered raw XMP packet rather than from buffered parsed XMP data. In order to write from parsed XMP data again, use either writeXmpFromPacket(false) or setXmpData(). */ virtual void clearXmpPacket(); /*! @brief Assign new XMP data. The new XMP data is not written to the image until the writeMetadata() method is called. Subsequent calls to writeMetadata() encode the XMP data to a raw XMP packet and write the newly encoded packet to the image. In the process, the buffered raw XMP packet is updated. In order to write directly from the raw XMP packet, use writeXmpFromPacket(true) or setXmpPacket(). @param xmpData An XmpData instance holding XMP data to be copied */ virtual void setXmpData(const XmpData& xmpData); /*! @brief Erase any buffered XMP data. XMP data is not removed from the actual image until the writeMetadata() method is called. This has the same effect as clearXmpPacket() but operates on the buffered parsed XMP data. Subsequent calls to writeMetadata() encode the XMP data to a raw XMP packet and write the newly encoded packet to the image. In the process, the buffered raw XMP packet is updated. In order to write directly from the raw XMP packet, use writeXmpFromPacket(true) or setXmpPacket(). */ virtual void clearXmpData(); /*! @brief Set the image comment. The new comment is not written to the image until the writeMetadata() method is called. @param comment String containing comment. */ virtual void setComment(const std::string& comment); /*! @brief Erase any buffered comment. Comment is not removed from the actual image until the writeMetadata() method is called. */ virtual void clearComment(); /*! @brief Copy all existing metadata from source Image. The data is copied into internal buffers and is not written to the image until the writeMetadata() method is called. @param image Metadata source. All metadata types are copied. */ virtual void setMetadata(const Image& image); /*! @brief Erase all buffered metadata. Metadata is not removed from the actual image until the writeMetadata() method is called. */ virtual void clearMetadata(); /*! @brief Returns an ExifData instance containing currently buffered Exif data. The contained Exif data may have been read from the image by a previous call to readMetadata() or added directly. The Exif data in the returned instance will be written to the image when writeMetadata() is called. @return modifiable ExifData instance containing Exif values */ virtual ExifData& exifData(); /*! @brief Returns an IptcData instance containing currently buffered IPTC data. The contained IPTC data may have been read from the image by a previous call to readMetadata() or added directly. The IPTC data in the returned instance will be written to the image when writeMetadata() is called. @return modifiable IptcData instance containing IPTC values */ virtual IptcData& iptcData(); /*! @brief Returns an XmpData instance containing currently buffered XMP data. The contained XMP data may have been read from the image by a previous call to readMetadata() or added directly. The XMP data in the returned instance will be written to the image when writeMetadata() is called. @return modifiable XmpData instance containing XMP values */ virtual XmpData& xmpData(); /*! @brief Return a modifiable reference to the raw XMP packet. */ virtual std::string& xmpPacket(); /*! @brief Determine the source when writing XMP. Depending on the setting of this flag, writeMetadata() writes XMP from the buffered raw XMP packet or from parsed XMP data. The default is to write from parsed XMP data. The switch is also set by all functions to set and clear the buffered raw XMP packet and parsed XMP data, so using this function should usually not be necessary. If %Exiv2 was compiled without XMP support, the default for this flag is true and it will never be changed in order to preserve access to the raw XMP packet. */ void writeXmpFromPacket(bool flag); /*! @brief Set the byte order to encode the Exif metadata in. The setting is only used when new Exif metadata is created and may not be applicable at all for some image formats. If the target image already contains Exif metadata, the byte order of the existing data is used. If byte order is not set when writeMetadata() is called, little-endian byte order (II) is used by default. */ void setByteOrder(ByteOrder byteOrder); //@} //! @name Accessors //@{ /*! @brief Return the byte order in which the Exif metadata of the image is encoded. Initially, it is not set (\em invalidByteOrder). */ ByteOrder byteOrder() const; /*! @brief Check if the Image instance is valid. Use after object construction. @return true if the Image is in a valid state. */ bool good() const; /*! @brief Return the MIME type of the image. @note For each supported image format, the library knows only one MIME type. This may not be the most specific MIME type for that format. In particular, several RAW formats are variants of the TIFF format with the same magic as TIFF itself. Class TiffImage handles most of them and thus they all have MIME type "image/tiff", although a more specific MIME type may exist (e.g., "image/x-nikon-nef"). */ virtual std::string mimeType() const =0; /*! @brief Return the pixel width of the image. */ virtual int pixelWidth() const; /*! @brief Return the pixel height of the image. */ virtual int pixelHeight() const; /*! @brief Returns an ExifData instance containing currently buffered Exif data. The Exif data may have been read from the image by a previous call to readMetadata() or added directly. The Exif data in the returned instance will be written to the image when writeMetadata() is called. @return read only ExifData instance containing Exif values */ virtual const ExifData& exifData() const; /*! @brief Returns an IptcData instance containing currently buffered IPTC data. The contained IPTC data may have been read from the image by a previous call to readMetadata() or added directly. The IPTC data in the returned instance will be written to the image when writeMetadata() is called. @return modifiable IptcData instance containing IPTC values */ virtual const IptcData& iptcData() const; /*! @brief Returns an XmpData instance containing currently buffered XMP data. The contained XMP data may have been read from the image by a previous call to readMetadata() or added directly. The XMP data in the returned instance will be written to the image when writeMetadata() is called. @return modifiable XmpData instance containing XMP values */ virtual const XmpData& xmpData() const; /*! @brief Return a copy of the image comment. May be an empty string. */ virtual std::string comment() const; /*! @brief Return the raw XMP packet as a string. */ virtual const std::string& xmpPacket() const; /*! @brief Return a reference to the BasicIo instance being used for Io. This refence is particularly useful to reading the results of operations on a MemIo instance. For example after metadata has been modified and the writeMetadata() method has been called, this method can be used to get access to the modified image. @return BasicIo instance that can be used to read or write image data directly. @note If the returned BasicIo is used to write to the image, the Image class will not see those changes until the readMetadata() method is called. */ virtual BasicIo& io() const; /*! @brief Returns the access mode, i.e., the metadata functions, which this image supports for the metadata type \em metadataId. @param metadataId The metadata identifier. @return Access mode for the requested image type and metadata identifier. */ AccessMode checkMode(MetadataId metadataId) const; /*! @brief Check if image supports a particular type of metadata. This method is deprecated. Use checkMode() instead. */ bool supportsMetadata(MetadataId metadataId) const; //! Return the flag indicating the source when writing XMP metadata. bool writeXmpFromPacket() const; //! Return list of native previews. This is meant to be used only by the PreviewManager. const NativePreviewList& nativePreviews() const; //@} protected: // DATA BasicIo::AutoPtr io_; //!< Image data IO pointer ExifData exifData_; //!< Exif data container IptcData iptcData_; //!< IPTC data container XmpData xmpData_; //!< XMP data container std::string comment_; //!< User comment std::string xmpPacket_; //!< XMP packet int pixelWidth_; //!< image pixel width int pixelHeight_; //!< image pixel height NativePreviewList nativePreviews_; //!< list of native previews private: //! @name NOT implemented //@{ //! Copy constructor Image(const Image& rhs); //! Assignment operator Image& operator=(const Image& rhs); //@} // DATA const int imageType_; //!< Image type const uint16_t supportedMetadata_; //!< Bitmap with all supported metadata types bool writeXmpFromPacket_;//!< Determines the source when writing XMP ByteOrder byteOrder_; //!< Byte order }; // class Image //! Type for function pointer that creates new Image instances typedef Image::AutoPtr (*NewInstanceFct)(BasicIo::AutoPtr io, bool create); //! Type for function pointer that checks image types typedef bool (*IsThisTypeFct)(BasicIo& iIo, bool advance); /*! @brief Returns an Image instance of the specified type. The factory is implemented as a static class. */ class EXIV2API ImageFactory { friend bool Image::good() const; public: /*! @brief Create an Image subclass of the appropriate type by reading the specified file. %Image type is derived from the file contents. @param path %Image file. The contents of the file are tested to determine the image type. File extension is ignored. @return An auto-pointer that owns an Image instance whose type matches that of the file. @throw Error If opening the file fails or it contains data of an unknown image type. */ static Image::AutoPtr open(const std::string& path); #ifdef EXV_UNICODE_PATH /*! @brief Like open() but accepts a unicode path in an std::wstring. @note This function is only available on Windows. */ static Image::AutoPtr open(const std::wstring& wpath); #endif /*! @brief Create an Image subclass of the appropriate type by reading the provided memory. %Image type is derived from the memory contents. @param data Pointer to a data buffer containing an image. The contents of the memory are tested to determine the image type. @param size Number of bytes pointed to by \em data. @return An auto-pointer that owns an Image instance whose type matches that of the data buffer. @throw Error If the memory contains data of an unknown image type. */ static Image::AutoPtr open(const byte* data, long size); /*! @brief Create an Image subclass of the appropriate type by reading the provided BasicIo instance. %Image type is derived from the data provided by \em io. The passed in \em io instance is (re)opened by this method. @param io An auto-pointer that owns a BasicIo instance that provides image data. The contents of the image data are tested to determine the type. @note This method takes ownership of the passed in BasicIo instance through the auto-pointer. Callers should not continue to use the BasicIo instance after it is passed to this method. Use the Image::io() method to get a temporary reference. @return An auto-pointer that owns an Image instance whose type matches that of the \em io data. If no image type could be determined, the pointer is 0. @throw Error If opening the BasicIo fails */ static Image::AutoPtr open(BasicIo::AutoPtr io); /*! @brief Create an Image subclass of the requested type by creating a new image file. If the file already exists, it will be overwritten. @param type Type of the image to be created. @param path %Image file to create. File extension is ignored. @return An auto-pointer that owns an Image instance of the requested type. @throw Error If the image type is not supported. */ static Image::AutoPtr create(int type, const std::string& path); #ifdef EXV_UNICODE_PATH /*! @brief Like create() but accepts a unicode path in an std::wstring. @note This function is only available on Windows. */ static Image::AutoPtr create(int type, const std::wstring& wpath); #endif /*! @brief Create an Image subclass of the requested type by creating a new image in memory. @param type Type of the image to be created. @return An auto-pointer that owns an Image instance of the requested type. @throw Error If the image type is not supported */ static Image::AutoPtr create(int type); /*! @brief Create an Image subclass of the requested type by writing a new image to a BasicIo instance. If the BasicIo instance already contains data, it will be overwritten. @param type Type of the image to be created. @param io An auto-pointer that owns a BasicIo instance that will be written to when creating a new image. @note This method takes ownership of the passed in BasicIo instance through the auto-pointer. Callers should not continue to use the BasicIo instance after it is passed to this method. Use the Image::io() method to get a temporary reference. @return An auto-pointer that owns an Image instance of the requested type. If the image type is not supported, the pointer is 0. */ static Image::AutoPtr create(int type, BasicIo::AutoPtr io); /*! @brief Returns the image type of the provided file. @param path %Image file. The contents of the file are tested to determine the image type. File extension is ignored. @return %Image type or Image::none if the type is not recognized. */ static int getType(const std::string& path); #ifdef EXV_UNICODE_PATH /*! @brief Like getType() but accepts a unicode path in an std::wstring. @note This function is only available on Windows. */ static int getType(const std::wstring& wpath); #endif /*! @brief Returns the image type of the provided data buffer. @param data Pointer to a data buffer containing an image. The contents of the memory are tested to determine the image type. @param size Number of bytes pointed to by \em data. @return %Image type or Image::none if the type is not recognized. */ static int getType(const byte* data, long size); /*! @brief Returns the image type of data provided by a BasicIo instance. The passed in \em io instance is (re)opened by this method. @param io A BasicIo instance that provides image data. The contents of the image data are tested to determine the type. @return %Image type or Image::none if the type is not recognized. */ static int getType(BasicIo& io); /*! @brief Returns the access mode or supported metadata functions for an image type and a metadata type. @param type The image type. @param metadataId The metadata identifier. @return Access mode for the requested image type and metadata identifier. @throw Error(13) if the image type is not supported. */ static AccessMode checkMode(int type, MetadataId metadataId); /*! @brief Determine if the content of \em io is an image of \em type. The \em advance flag determines if the read position in the stream is moved (see below). This applies only if the type matches and the function returns true. If the type does not match, the stream position is not changed. However, if reading from the stream fails, the stream position is undefined. Consult the stream state to obtain more information in this case. @param type Type of the image. @param io BasicIo instance to read from. @param advance Flag indicating whether the position of the io should be advanced by the number of characters read to analyse the data (true) or left at its original position (false). This applies only if the type matches. @return true if the data matches the type of this class;
false if the data does not match */ static bool checkType(int type, BasicIo& io, bool advance); private: //! @name Creators //@{ //! Prevent construction: not implemented. ImageFactory(); //! Prevent copy construction: not implemented. ImageFactory(const ImageFactory& rhs); //@} }; // class ImageFactory // ***************************************************************************** // template, inline and free functions //! Append \em len bytes pointed to by \em buf to \em blob. void append(Exiv2::Blob& blob, const byte* buf, uint32_t len); } // namespace Exiv2 #endif // #ifndef IMAGE_HPP_ exiv2-0.23/src/easyaccess.hpp0000644000175000017500000000742411732641407015746 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! @file easyaccess.hpp @brief Provides easy (high-level) access to some Exif meta data. @version $Rev: 2681 $ @author Carsten Pfeiffer @date 28-Feb-09, gis: created */ #ifndef EASYACCESS_HPP_ #define EASYACCESS_HPP_ // ***************************************************************************** // included header files #include "exif.hpp" namespace Exiv2 { // ***************************************************************************** // class declarations class ExifData; //! Return the orientation of the image EXIV2API ExifData::const_iterator orientation(const ExifData& ed); //! Return the ISO speed used to shoot the image EXIV2API ExifData::const_iterator isoSpeed(const ExifData& ed); //! Return the flash bias value EXIV2API ExifData::const_iterator flashBias(const ExifData& ed); //! Return the exposure mode setting EXIV2API ExifData::const_iterator exposureMode(const ExifData& ed); //! Return the scene mode setting EXIV2API ExifData::const_iterator sceneMode(const ExifData& ed); //! Return the macro mode setting EXIV2API ExifData::const_iterator macroMode(const ExifData& ed); //! Return the image quality setting EXIV2API ExifData::const_iterator imageQuality(const ExifData& ed); //! Return the white balance setting EXIV2API ExifData::const_iterator whiteBalance(const ExifData& ed); //! Return the name of the lens used EXIV2API ExifData::const_iterator lensName(const ExifData& ed); //! Return the saturation level EXIV2API ExifData::const_iterator saturation(const ExifData& ed); //! Return the sharpness level EXIV2API ExifData::const_iterator sharpness(const ExifData& ed); //! Return the contrast level EXIV2API ExifData::const_iterator contrast(const ExifData& ed); //! Return the scene capture type EXIV2API ExifData::const_iterator sceneCaptureType(const ExifData& ed); //! Return the metering mode setting EXIV2API ExifData::const_iterator meteringMode(const ExifData& ed); //! Return the camera make EXIV2API ExifData::const_iterator make(const ExifData& ed); //! Return the camera model EXIV2API ExifData::const_iterator model(const ExifData& ed); //! Return the exposure time EXIV2API ExifData::const_iterator exposureTime(const ExifData& ed); //! Return the F number EXIV2API ExifData::const_iterator fNumber(const ExifData& ed); //! Return the subject distance EXIV2API ExifData::const_iterator subjectDistance(const ExifData& ed); //! Return the camera serial number EXIV2API ExifData::const_iterator serialNumber(const ExifData& ed); //! Return the focal length setting EXIV2API ExifData::const_iterator focalLength(const ExifData& ed); //! Return the AF point EXIV2API ExifData::const_iterator afPoint(const ExifData& ed); } // namespace Exiv2 #endif // EASYACCESS_HPP_ exiv2-0.23/src/getopt_win32.h0000644000175000017500000000546410302102502015565 0ustar andreasandreas/* * Copyright (c) 1987, 1993, 1994, 1996 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef __GETOPT_H__ #define __GETOPT_H__ #ifdef __cplusplus extern "C" { #endif extern int opterr; /* if error message should be printed */ extern int optind; /* index into parent argv vector */ extern int optopt; /* character checked for validity */ extern int optreset; /* reset getopt */ extern char *optarg; /* argument associated with option */ int getopt (int, char * const *, const char *); #ifdef __cplusplus } #endif #endif /* __GETOPT_H__ */ #ifndef __UNISTD_GETOPT__ #ifndef __GETOPT_LONG_H__ #define __GETOPT_LONG_H__ #ifdef __cplusplus extern "C" { #endif struct option { const char *name; int has_arg; int *flag; int val; }; int getopt_long (int, char *const *, const char *, const struct option *, int *); #ifndef HAVE_DECL_GETOPT #define HAVE_DECL_GETOPT 1 #endif #define no_argument 0 #define required_argument 1 #define optional_argument 2 #ifdef __cplusplus } #endif #endif /* __GETOPT_LONG_H__ */ #endif /* __UNISTD_GETOPT__ */ exiv2-0.23/src/tiffimage.cpp0000644000175000017500000031260411742031570015543 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /* File: tiffimage.cpp Version: $Rev: 2701 $ Author(s): Andreas Huggel (ahu) History: 15-Mar-06, ahu: created */ // ***************************************************************************** #include "rcsid_int.hpp" EXIV2_RCSID("@(#) $Id: tiffimage.cpp 2701 2012-04-13 14:08:56Z ahuggel $") // ***************************************************************************** // included header files #ifdef _MSC_VER # include "exv_msvc.h" #else # include "exv_conf.h" #endif #include "tiffimage.hpp" #include "tiffimage_int.hpp" #include "tiffcomposite_int.hpp" #include "tiffvisitor_int.hpp" #include "makernote_int.hpp" #include "image.hpp" #include "error.hpp" #include "futils.hpp" #include "types.hpp" #include "i18n.h" // NLS support. // + standard includes #include #include #include #include #include /* -------------------------------------------------------------------------- Todo: + CR2 Makernotes don't seem to have a next pointer but Canon Jpeg Makernotes do. What a mess. (That'll become an issue when it comes to writing to CR2) + Sony makernotes in RAW files do not seem to have header like those in Jpegs. And maybe no next pointer either. in crwimage.* : + Fix CiffHeader according to TiffHeader + Combine Error(15) and Error(33), add format argument %1 + Search crwimage for todos, fix writeMetadata comment + rename loadStack to getPath for consistency -------------------------------------------------------------------------- */ // ***************************************************************************** // class member definitions namespace Exiv2 { using namespace Internal; TiffImage::TiffImage(BasicIo::AutoPtr io, bool /*create*/) : Image(ImageType::tiff, mdExif | mdIptc | mdXmp, io), pixelWidth_(0), pixelHeight_(0) { } // TiffImage::TiffImage //! Structure for TIFF compression to MIME type mappings struct MimeTypeList { //! Comparison operator for compression bool operator==(int compression) const { return compression_ == compression; } int compression_; //!< TIFF compression const char* mimeType_; //!< MIME type }; //! List of TIFF compression to MIME type mappings MimeTypeList mimeTypeList[] = { { 32770, "image/x-samsung-srw" }, { 34713, "image/x-nikon-nef" }, { 65535, "image/x-pentax-pef" } }; std::string TiffImage::mimeType() const { if (!mimeType_.empty()) return mimeType_; mimeType_ = std::string("image/tiff"); std::string key = "Exif." + primaryGroup() + ".Compression"; ExifData::const_iterator md = exifData_.findKey(ExifKey(key)); if (md != exifData_.end() && md->count() > 0) { const MimeTypeList* i = find(mimeTypeList, static_cast(md->toLong())); if (i) mimeType_ = std::string(i->mimeType_); } return mimeType_; } std::string TiffImage::primaryGroup() const { if (!primaryGroup_.empty()) return primaryGroup_; static const char* keys[] = { "Exif.Image.NewSubfileType", "Exif.SubImage1.NewSubfileType", "Exif.SubImage2.NewSubfileType", "Exif.SubImage3.NewSubfileType", "Exif.SubImage4.NewSubfileType", "Exif.SubImage5.NewSubfileType", "Exif.SubImage6.NewSubfileType", "Exif.SubImage7.NewSubfileType", "Exif.SubImage8.NewSubfileType", "Exif.SubImage9.NewSubfileType" }; // Find the group of the primary image, default to "Image" primaryGroup_ = std::string("Image"); for (unsigned int i = 0; i < EXV_COUNTOF(keys); ++i) { ExifData::const_iterator md = exifData_.findKey(ExifKey(keys[i])); // Is it the primary image? if (md != exifData_.end() && md->count() > 0 && md->toLong() == 0) { // Sometimes there is a JPEG primary image; that's not our first choice primaryGroup_ = md->groupName(); std::string key = "Exif." + primaryGroup_ + ".JPEGInterchangeFormat"; if (exifData_.findKey(ExifKey(key)) == exifData_.end()) break; } } return primaryGroup_; } int TiffImage::pixelWidth() const { if (pixelWidth_ != 0) return pixelWidth_; ExifKey key(std::string("Exif.") + primaryGroup() + std::string(".ImageWidth")); ExifData::const_iterator imageWidth = exifData_.findKey(key); if (imageWidth != exifData_.end() && imageWidth->count() > 0) { pixelWidth_ = static_cast(imageWidth->toLong()); } return pixelWidth_; } int TiffImage::pixelHeight() const { if (pixelHeight_ != 0) return pixelHeight_; ExifKey key(std::string("Exif.") + primaryGroup() + std::string(".ImageLength")); ExifData::const_iterator imageHeight = exifData_.findKey(key); if (imageHeight != exifData_.end() && imageHeight->count() > 0) { pixelHeight_ = imageHeight->toLong(); } return pixelHeight_; } void TiffImage::setComment(const std::string& /*comment*/) { // not supported throw(Error(32, "Image comment", "TIFF")); } void TiffImage::readMetadata() { #ifdef DEBUG std::cerr << "Reading TIFF file " << io_->path() << "\n"; #endif if (io_->open() != 0) throw Error(9, io_->path(), strError()); IoCloser closer(*io_); // Ensure that this is the correct image type if (!isTiffType(*io_, false)) { if (io_->error() || io_->eof()) throw Error(14); throw Error(3, "TIFF"); } clearMetadata(); ByteOrder bo = TiffParser::decode(exifData_, iptcData_, xmpData_, io_->mmap(), io_->size()); setByteOrder(bo); } // TiffImage::readMetadata void TiffImage::writeMetadata() { #ifdef DEBUG std::cerr << "Writing TIFF file " << io_->path() << "\n"; #endif ByteOrder bo = byteOrder(); byte* pData = 0; long size = 0; IoCloser closer(*io_); if (io_->open() == 0) { // Ensure that this is the correct image type if (isTiffType(*io_, false)) { pData = io_->mmap(true); size = io_->size(); TiffHeader tiffHeader; if (0 == tiffHeader.read(pData, 8)) { bo = tiffHeader.byteOrder(); } } } if (bo == invalidByteOrder) { bo = littleEndian; } setByteOrder(bo); TiffParser::encode(*io_, pData, size, bo, exifData_, iptcData_, xmpData_); // may throw } // TiffImage::writeMetadata ByteOrder TiffParser::decode( ExifData& exifData, IptcData& iptcData, XmpData& xmpData, const byte* pData, uint32_t size ) { return TiffParserWorker::decode(exifData, iptcData, xmpData, pData, size, Tag::root, TiffMapping::findDecoder); } // TiffParser::decode WriteMethod TiffParser::encode( BasicIo& io, const byte* pData, uint32_t size, ByteOrder byteOrder, const ExifData& exifData, const IptcData& iptcData, const XmpData& xmpData ) { // Copy to be able to modify the Exif data ExifData ed = exifData; // Delete IFDs which do not occur in TIFF images static const IfdId filteredIfds[] = { panaRawId }; for (unsigned int i = 0; i < EXV_COUNTOF(filteredIfds); ++i) { #ifdef DEBUG std::cerr << "Warning: Exif IFD " << filteredIfds[i] << " not encoded\n"; #endif ed.erase(std::remove_if(ed.begin(), ed.end(), FindExifdatum(filteredIfds[i])), ed.end()); } std::auto_ptr header(new TiffHeader(byteOrder)); return TiffParserWorker::encode(io, pData, size, ed, iptcData, xmpData, Tag::root, TiffMapping::findEncoder, header.get(), 0); } // TiffParser::encode // ************************************************************************* // free functions Image::AutoPtr newTiffInstance(BasicIo::AutoPtr io, bool create) { Image::AutoPtr image(new TiffImage(io, create)); if (!image->good()) { image.reset(); } return image; } bool isTiffType(BasicIo& iIo, bool advance) { const int32_t len = 8; byte buf[len]; iIo.read(buf, len); if (iIo.error() || iIo.eof()) { return false; } TiffHeader tiffHeader; bool rc = tiffHeader.read(buf, len); if (!advance || !rc) { iIo.seek(-len, BasicIo::cur); } return rc; } } // namespace Exiv2 // Shortcuts for the newTiffBinaryArray templates. #define EXV_BINARY_ARRAY(arrayCfg, arrayDef) (newTiffBinaryArray0<&arrayCfg, EXV_COUNTOF(arrayDef), arrayDef>) #define EXV_SIMPLE_BINARY_ARRAY(arrayCfg) (newTiffBinaryArray1<&arrayCfg>) #define EXV_COMPLEX_BINARY_ARRAY(arraySet, cfgSelFct) (newTiffBinaryArray2) namespace Exiv2 { namespace Internal { //! Constant for non-encrypted binary arrays const CryptFct notEncrypted = 0; //! Canon Camera Settings binary array - configuration extern const ArrayCfg canonCsCfg = { canonCsId, // Group for the elements invalidByteOrder, // Use byte order from parent ttUnsignedShort, // Type for array entry and size element notEncrypted, // Not encrypted true, // With size element false, // No fillers false, // Don't concatenate gaps { 0, ttUnsignedShort, 1 } }; //! Canon Camera Settings binary array - definition extern const ArrayDef canonCsDef[] = { { 46, ttUnsignedShort, 3 } // Exif.CanonCs.Lens }; //! Canon Shot Info binary array - configuration extern const ArrayCfg canonSiCfg = { canonSiId, // Group for the elements invalidByteOrder, // Use byte order from parent ttUnsignedShort, // Type for array entry and size element notEncrypted, // Not encrypted true, // With size element false, // No fillers false, // Don't concatenate gaps { 0, ttUnsignedShort, 1 } }; //! Canon Panorama binary array - configuration extern const ArrayCfg canonPaCfg = { canonPaId, // Group for the elements invalidByteOrder, // Use byte order from parent ttUnsignedShort, // Type for array entry and size element notEncrypted, // Not encrypted false, // No size element false, // No fillers false, // Don't concatenate gaps { 0, ttUnsignedShort, 1 } }; //! Canon Custom Function binary array - configuration extern const ArrayCfg canonCfCfg = { canonCfId, // Group for the elements invalidByteOrder, // Use byte order from parent ttUnsignedShort, // Type for array entry and size element notEncrypted, // Not encrypted true, // With size element false, // No fillers false, // Don't concatenate gaps { 0, ttUnsignedShort, 1 } }; //! Canon Picture Info binary array - configuration extern const ArrayCfg canonPiCfg = { canonPiId, // Group for the elements invalidByteOrder, // Use byte order from parent ttUnsignedShort, // Type for array entry and size element notEncrypted, // Not encrypted false, // No size element false, // No fillers false, // Don't concatenate gaps { 0, ttUnsignedShort, 1 } }; //! Canon File Info binary array - configuration extern const ArrayCfg canonFiCfg = { canonFiId, // Group for the elements invalidByteOrder, // Use byte order from parent ttUnsignedShort, // Type for array entry and size element notEncrypted, // Not encrypted true, // Has a size element false, // No fillers false, // Don't concatenate gaps { 0, ttSignedShort, 1 } }; //! Canon File Info binary array - definition extern const ArrayDef canonFiDef[] = { { 2, ttUnsignedLong, 1 } }; //! Canon Processing Info binary array - configuration extern const ArrayCfg canonPrCfg = { canonPrId, // Group for the elements invalidByteOrder, // Use byte order from parent ttUnsignedShort, // Type for array entry and size element notEncrypted, // Not encrypted true, // Has a size element false, // No fillers false, // Don't concatenate gaps { 0, ttSignedShort, 1 } }; //! Nikon Vibration Reduction binary array - configuration extern const ArrayCfg nikonVrCfg = { nikonVrId, // Group for the elements invalidByteOrder, // Use byte order from parent ttUndefined, // Type for array entry notEncrypted, // Not encrypted false, // No size element true, // Write all tags true, // Concatenate gaps { 0, ttUnsignedByte, 1 } }; //! Nikon Vibration Reduction binary array - definition extern const ArrayDef nikonVrDef[] = { { 0, ttUndefined, 4 }, // Version { 7, ttUnsignedByte, 1 } // The array contains 8 bytes }; //! Nikon Picture Control binary array - configuration extern const ArrayCfg nikonPcCfg = { nikonPcId, // Group for the elements invalidByteOrder, // Use byte order from parent ttUndefined, // Type for array entry notEncrypted, // Not encrypted false, // No size element true, // Write all tags true, // Concatenate gaps { 0, ttUnsignedByte, 1 } }; //! Nikon Picture Control binary array - definition extern const ArrayDef nikonPcDef[] = { { 0, ttUndefined, 4 }, // Version { 4, ttAsciiString, 20 }, { 24, ttAsciiString, 20 }, { 48, ttUnsignedByte, 1 }, { 49, ttUnsignedByte, 1 }, { 50, ttUnsignedByte, 1 }, { 51, ttUnsignedByte, 1 }, { 52, ttUnsignedByte, 1 }, { 53, ttUnsignedByte, 1 }, { 54, ttUnsignedByte, 1 }, { 55, ttUnsignedByte, 1 }, { 56, ttUnsignedByte, 1 }, { 57, ttUnsignedByte, 1 } // The array contains 58 bytes }; //! Nikon World Time binary array - configuration extern const ArrayCfg nikonWtCfg = { nikonWtId, // Group for the elements invalidByteOrder, // Use byte order from parent ttUndefined, // Type for array entry notEncrypted, // Not encrypted false, // No size element true, // Write all tags true, // Concatenate gaps { 0, ttUnsignedByte, 1 } }; //! Nikon World Time binary array - definition extern const ArrayDef nikonWtDef[] = { { 0, ttSignedShort, 1 }, { 2, ttUnsignedByte, 1 }, { 3, ttUnsignedByte, 1 } }; //! Nikon ISO info binary array - configuration extern const ArrayCfg nikonIiCfg = { nikonIiId, // Group for the elements bigEndian, // Byte order ttUndefined, // Type for array entry notEncrypted, // Not encrypted false, // No size element true, // Write all tags true, // Concatenate gaps { 0, ttUnsignedByte, 1 } }; //! Nikon ISO info binary array - definition extern const ArrayDef nikonIiDef[] = { { 0, ttUnsignedByte, 1 }, { 4, ttUnsignedShort, 1 }, { 6, ttUnsignedByte, 1 }, { 10, ttUnsignedShort, 1 }, { 13, ttUnsignedByte, 1 } // The array contains 14 bytes }; //! Nikon Auto Focus binary array - configuration extern const ArrayCfg nikonAfCfg = { nikonAfId, // Group for the elements littleEndian, // Byte order ttUndefined, // Type for array entry notEncrypted, // Not encrypted false, // No size element true, // Write all tags true, // Concatenate gaps { 0, ttUnsignedByte, 1 } }; //! Nikon Auto Focus binary array - definition extern const ArrayDef nikonAfDef[] = { { 0, ttUnsignedByte, 1 }, { 1, ttUnsignedByte, 1 }, { 2, ttUnsignedShort, 1 } // The array contains 4 bytes }; //! Nikon Auto Focus 2 binary array - configuration extern const ArrayCfg nikonAf2Cfg = { nikonAf2Id, // Group for the elements littleEndian, // Byte order ttUndefined, // Type for array entry notEncrypted, // Not encrypted false, // No size element true, // Write all tags true, // Concatenate gaps { 0, ttUnsignedByte, 1 } }; //! Nikon Auto Focus 2 binary array - definition extern const ArrayDef nikonAf2Def[] = { { 0, ttUndefined, 4 }, // Version { 4, ttUnsignedByte, 1 }, // ContrastDetectAF { 5, ttUnsignedByte, 1 }, // AFAreaMode { 6, ttUnsignedByte, 1 }, // PhaseDetectAF { 7, ttUnsignedByte, 1 }, // PrimaryAFPoint { 8, ttUnsignedByte, 7 }, // AFPointsUsed { 16, ttUnsignedShort, 1 }, // AFImageWidth { 18, ttUnsignedShort, 1 }, // AFImageHeight { 20, ttUnsignedShort, 1 }, // AFAreaXPosition { 22, ttUnsignedShort, 1 }, // AFAreaYPosition { 24, ttUnsignedShort, 1 }, // AFAreaWidth { 26, ttUnsignedShort, 1 }, // AFAreaHeight { 28, ttUnsignedShort, 1 }, // ContrastDetectAFInFocus }; //! Nikon AF Fine Tune binary array - configuration extern const ArrayCfg nikonAFTCfg = { nikonAFTId, // Group for the elements littleEndian, // Byte order ttUndefined, // Type for array entry notEncrypted, // Not encrypted false, // No size element true, // Write all tags true, // Concatenate gaps { 0, ttUnsignedByte, 1 } }; //! Nikon AF Fine Tune binary array - definition extern const ArrayDef nikonAFTDef[] = { { 0, ttUnsignedByte, 1 }, // AF Fine Tune on/off { 1, ttUnsignedByte, 1 }, // AF Fine Tune index { 2, ttUnsignedByte, 1 } // AF Fine Tune value }; //! Nikon File Info binary array - configuration extern const ArrayCfg nikonFiCfg = { nikonFiId, // Group for the elements littleEndian, // Byte order ttUndefined, // Type for array entry notEncrypted, // Not encrypted false, // No size element true, // Write all tags true, // Concatenate gaps { 0, ttUnsignedByte, 1 } }; //! Nikon File Info binary array - definition extern const ArrayDef nikonFiDef[] = { { 0, ttUndefined, 4 }, // Version { 6, ttUnsignedShort, 1 }, // Directory Number { 8, ttUnsignedShort, 1 } // File Number }; //! Nikon Multi Exposure binary array - configuration extern const ArrayCfg nikonMeCfg = { nikonMeId, // Group for the elements littleEndian, // Byte order ttUndefined, // Type for array entry notEncrypted, // Not encrypted false, // No size element true, // Write all tags true, // Concatenate gaps { 0, ttUnsignedByte, 1 } }; //! Nikon Multi Exposure binary array - definition extern const ArrayDef nikonMeDef[] = { { 0, ttUndefined, 4 }, // Version { 4, ttUnsignedLong, 1 }, // MultiExposureMode { 8, ttUnsignedLong, 1 }, // MultiExposureShots { 12, ttUnsignedLong, 1 } // MultiExposureAutoGain }; //! Nikon Flash Info binary array - configuration 1 extern const ArrayCfg nikonFl1Cfg = { nikonFl1Id, // Group for the elements littleEndian, // Byte order ttUndefined, // Type for array entry notEncrypted, // Not encrypted false, // No size element true, // Write all tags true, // Concatenate gaps { 0, ttUnsignedByte, 1 } }; //! Nikon Flash Info binary array - definition 1 extern const ArrayDef nikonFl1Def[] = { { 0, ttUndefined, 4 }, // Version { 4, ttUnsignedByte, 1 }, // FlashSource { 6, ttUnsignedShort, 1 }, // ExternalFlashFirmware { 8, ttUnsignedByte, 1 }, // ExternalFlashFlags { 11, ttUnsignedByte, 1 }, // FlashFocalLength { 12, ttUnsignedByte, 1 }, // RepeatingFlashRate { 13, ttUnsignedByte, 1 }, // RepeatingFlashCount { 14, ttUnsignedByte, 1 }, // FlashGNDistance { 15, ttUnsignedByte, 1 }, // FlashGroupAControlMode { 16, ttUnsignedByte, 1 } // FlashGroupBControlMode }; //! Nikon Flash Info binary array - configuration 2 extern const ArrayCfg nikonFl2Cfg = { nikonFl2Id, // Group for the elements littleEndian, // Byte order ttUndefined, // Type for array entry notEncrypted, // Not encrypted false, // No size element true, // Write all tags true, // Concatenate gaps { 0, ttUnsignedByte, 1 } }; //! Nikon Flash Info binary array - definition 2 extern const ArrayDef nikonFl2Def[] = { { 0, ttUndefined, 4 }, // Version { 4, ttUnsignedByte, 1 }, // FlashSource { 6, ttUnsignedShort, 1 }, // ExternalFlashFirmware { 8, ttUnsignedByte, 1 }, // ExternalFlashFlags { 12, ttUnsignedByte, 1 }, // FlashFocalLength { 13, ttUnsignedByte, 1 }, // RepeatingFlashRate { 14, ttUnsignedByte, 1 }, // RepeatingFlashCount { 15, ttUnsignedByte, 1 }, // FlashGNDistance }; //! Nikon Flash Info binary array - configuration 3 extern const ArrayCfg nikonFl3Cfg = { nikonFl3Id, // Group for the elements littleEndian, // Byte order ttUndefined, // Type for array entry notEncrypted, // Not encrypted false, // No size element true, // Write all tags true, // Concatenate gaps { 0, ttUnsignedByte, 1 } }; //! Nikon Flash Info binary array - definition extern const ArrayDef nikonFl3Def[] = { { 0, ttUndefined, 4 }, // Version { 4, ttUnsignedByte, 1 }, // FlashSource { 6, ttUnsignedShort, 1 }, // ExternalFlashFirmware { 8, ttUnsignedByte, 1 }, // ExternalFlashFlags { 12, ttUnsignedByte, 1 }, // FlashFocalLength { 13, ttUnsignedByte, 1 }, // RepeatingFlashRate { 14, ttUnsignedByte, 1 }, // RepeatingFlashCount { 15, ttUnsignedByte, 1 }, // FlashGNDistance { 16, ttUnsignedByte, 1 }, // FlashColorFilter }; //! Nikon Lens Data configurations and definitions extern const ArraySet nikonFlSet[] = { { nikonFl1Cfg, nikonFl1Def, EXV_COUNTOF(nikonFl1Def) }, { nikonFl2Cfg, nikonFl2Def, EXV_COUNTOF(nikonFl2Def) }, { nikonFl3Cfg, nikonFl3Def, EXV_COUNTOF(nikonFl3Def) } }; //! Nikon Shot Info binary array - configuration 1 (D80) extern const ArrayCfg nikonSi1Cfg = { nikonSi1Id, // Group for the elements bigEndian, // Use byte order from parent ttUndefined, // Type for array entry nikonCrypt, // Encryption function false, // No size element true, // Write all tags true, // Concatenate gaps { 0, ttUnsignedByte, 1 } }; //! Nikon Shot Info binary array - definition 1 (D80) extern const ArrayDef nikonSi1Def[] = { { 0, ttUndefined, 4 }, // Version { 586, ttUnsignedLong, 1 }, // ShutterCount { 1155, ttUnsignedByte, 1 } // The array contains 1156 bytes }; //! Nikon Shot Info binary array - configuration 2 (D40) extern const ArrayCfg nikonSi2Cfg = { nikonSi2Id, // Group for the elements bigEndian, // Use byte order from parent ttUndefined, // Type for array entry nikonCrypt, // Encryption function false, // No size element true, // Write all tags true, // Concatenate gaps { 0, ttUnsignedByte, 1 } }; //! Nikon Shot Info binary array - definition 2 (D40) extern const ArrayDef nikonSi2Def[] = { { 0, ttUndefined, 4 }, // Version { 582, ttUnsignedLong, 1 }, // ShutterCount { 738, ttUnsignedByte, 1 }, { 1112, ttUnsignedByte, 1 } // The array contains 1113 bytes }; //! Nikon Shot Info binary array - configuration 3 (D300a) extern const ArrayCfg nikonSi3Cfg = { nikonSi3Id, // Group for the elements bigEndian, // Use byte order from parent ttUndefined, // Type for array entry nikonCrypt, // Encryption function false, // No size element true, // Write all tags true, // Concatenate gaps { 0, ttUnsignedByte, 1 } }; //! Nikon Shot Info binary array - definition 3 (D300a) extern const ArrayDef nikonSi3Def[] = { { 0, ttUndefined, 4 }, // Version { 604, ttUnsignedByte, 1 }, // ISO { 633, ttUnsignedLong, 1 }, // ShutterCount { 721, ttUnsignedShort, 1 }, // AFFineTuneAdj { 814, ttUndefined, 4478 } // The array contains 5291 bytes }; //! Nikon Shot Info binary array - configuration 4 (D300b) extern const ArrayCfg nikonSi4Cfg = { nikonSi4Id, // Group for the elements bigEndian, // Use byte order from parent ttUndefined, // Type for array entry nikonCrypt, // Encryption function false, // No size element true, // Write all tags true, // Concatenate gaps { 0, ttUnsignedByte, 1 } }; //! Nikon Shot Info binary array - definition 4 (D300b) extern const ArrayDef nikonSi4Def[] = { { 0, ttUndefined, 4 }, // Version { 644, ttUnsignedLong, 1 }, // ShutterCount { 732, ttUnsignedShort, 1 }, // AFFineTuneAdj { 826, ttUndefined, 4478 } // The array contains 5303 bytes }; //! Nikon Shot Info binary array - configuration 5 (ver 02.xx) extern const ArrayCfg nikonSi5Cfg = { nikonSi5Id, // Group for the elements bigEndian, // Use byte order from parent ttUndefined, // Type for array entry nikonCrypt, // Encryption function false, // No size element false, // Write all tags (don't know how many) true, // Concatenate gaps { 0, ttUnsignedByte, 1 } }; //! Nikon Shot Info binary array - definition 5 (ver 01.xx and ver 02.xx) extern const ArrayDef nikonSi5Def[] = { { 0, ttUndefined, 4 }, // Version { 106, ttUnsignedLong, 1 }, // ShutterCount1 { 110, ttUnsignedLong, 1 }, // DeletedImageCount { 117, ttUnsignedByte, 1 }, // VibrationReduction { 130, ttUnsignedByte, 1 }, // VibrationReduction1 { 343, ttUndefined, 2 }, // ShutterCount { 430, ttUnsignedByte, 1 }, // VibrationReduction2 { 598, ttUnsignedByte, 1 }, // ISO { 630, ttUnsignedLong, 1 } // ShutterCount }; //! Nikon Shot Info binary array - configuration 6 (ver 01.xx) extern const ArrayCfg nikonSi6Cfg = { nikonSi6Id, // Group for the elements bigEndian, // Use byte order from parent ttUndefined, // Type for array entry notEncrypted, // Encryption function false, // No size element false, // Write all tags (don't know how many) true, // Concatenate gaps { 0, ttUnsignedByte, 1 } }; //! Nikon Lens Data configurations and definitions extern const ArraySet nikonSiSet[] = { { nikonSi1Cfg, nikonSi1Def, EXV_COUNTOF(nikonSi1Def) }, { nikonSi2Cfg, nikonSi2Def, EXV_COUNTOF(nikonSi2Def) }, { nikonSi3Cfg, nikonSi3Def, EXV_COUNTOF(nikonSi3Def) }, { nikonSi4Cfg, nikonSi4Def, EXV_COUNTOF(nikonSi4Def) }, { nikonSi5Cfg, nikonSi5Def, EXV_COUNTOF(nikonSi5Def) }, { nikonSi6Cfg, nikonSi5Def, EXV_COUNTOF(nikonSi5Def) } // uses nikonSi5Def }; //! Nikon Lens Data binary array - configuration 1 extern const ArrayCfg nikonLd1Cfg = { nikonLd1Id, // Group for the elements invalidByteOrder, // Use byte order from parent ttUndefined, // Type for array entry notEncrypted, // Encryption function false, // No size element true, // Write all tags false, // Concatenate gaps { 0, ttUnsignedByte, 1 } }; //! Nikon Lens Data binary array - configuration 2 extern const ArrayCfg nikonLd2Cfg = { nikonLd2Id, // Group for the elements invalidByteOrder, // Use byte order from parent ttUndefined, // Type for array entry nikonCrypt, // Encryption function false, // No size element true, // Write all tags false, // Concatenate gaps { 0, ttUnsignedByte, 1 } }; //! Nikon Lens Data binary array - configuration 3 extern const ArrayCfg nikonLd3Cfg = { nikonLd3Id, // Group for the elements invalidByteOrder, // Use byte order from parent ttUndefined, // Type for array entry nikonCrypt, // Encryption function false, // No size element true, // Write all tags false, // Don't concatenate gaps { 0, ttUnsignedByte, 1 } }; //! Nikon Lens Data binary array - definition extern const ArrayDef nikonLdDef[] = { { 0, ttUndefined, 4 } // Version }; //! Nikon Lens Data configurations and definitions extern const ArraySet nikonLdSet[] = { { nikonLd1Cfg, nikonLdDef, EXV_COUNTOF(nikonLdDef) }, { nikonLd2Cfg, nikonLdDef, EXV_COUNTOF(nikonLdDef) }, { nikonLd3Cfg, nikonLdDef, EXV_COUNTOF(nikonLdDef) } }; //! Nikon Color Balance binary array - configuration 1 extern const ArrayCfg nikonCb1Cfg = { nikonCb1Id, // Group for the elements invalidByteOrder, // Use byte order from parent ttUndefined, // Type for array entry notEncrypted, // Encryption function false, // No size element false, // Write all tags true, // Concatenate gaps { 0, ttUnsignedShort, 1 } }; //! Nikon Color Balance binary array - configuration 2 extern const ArrayCfg nikonCb2Cfg = { nikonCb2Id, // Group for the elements invalidByteOrder, // Use byte order from parent ttUndefined, // Type for array entry nikonCrypt, // Encryption function false, // No size element false, // Write all tags true, // Concatenate gaps { 0, ttUnsignedShort, 1 } }; //! Nikon Color Balance binary array - configuration 2a extern const ArrayCfg nikonCb2aCfg = { nikonCb2aId, // Group for the elements invalidByteOrder, // Use byte order from parent ttUndefined, // Type for array entry nikonCrypt, // Encryption function false, // No size element false, // Write all tags true, // Concatenate gaps { 0, ttUnsignedShort, 1 } }; //! Nikon Color Balance binary array - configuration 2b extern const ArrayCfg nikonCb2bCfg = { nikonCb2bId, // Group for the elements invalidByteOrder, // Use byte order from parent ttUndefined, // Type for array entry nikonCrypt, // Encryption function false, // No size element false, // Write all tags true, // Concatenate gaps { 0, ttUnsignedShort, 1 } }; //! Nikon Color Balance binary array - configuration 3 extern const ArrayCfg nikonCb3Cfg = { nikonCb3Id, // Group for the elements invalidByteOrder, // Use byte order from parent ttUndefined, // Type for array entry notEncrypted, // Encryption function false, // No size element false, // Write all tags true, // Concatenate gaps { 0, ttUnsignedShort, 1 } }; //! Nikon Color Balance binary array - configuration 4 extern const ArrayCfg nikonCb4Cfg = { nikonCb4Id, // Group for the elements invalidByteOrder, // Use byte order from parent ttUndefined, // Type for array entry nikonCrypt, // Encryption function false, // No size element false, // Write all tags true, // Concatenate gaps { 0, ttUnsignedShort, 1 } }; //! Nikon Color Balance binary array - definition 1 (D100) extern const ArrayDef nikonCb1Def[] = { { 0, ttUndefined, 4 }, // Version { 72, ttUnsignedShort, 4 } // Color balance levels }; //! Nikon Color Balance binary array - definition 2 (D2H) extern const ArrayDef nikonCb2Def[] = { { 0, ttUndefined, 4 }, // Version { 10, ttUnsignedShort, 4 } // Color balance levels }; //! Nikon Color Balance binary array - definition 2a (D50) extern const ArrayDef nikonCb2aDef[] = { { 0, ttUndefined, 4 }, // Version { 18, ttUnsignedShort, 4 } // Color balance levels }; //! Nikon Color Balance binary array - definition 2b (D2X=0204,D2Hs=0206,D200=0207,D40=0208) extern const ArrayDef nikonCb2bDef[] = { { 0, ttUndefined, 4 }, // Version { 4, ttUnsignedShort, 140 }, // Unknown {284, ttUnsignedShort, 3 }, // Unknown (encrypted) {290, ttUnsignedShort, 4 } // Color balance levels }; //! Nikon Color Balance binary array - definition 3 (D70) extern const ArrayDef nikonCb3Def[] = { { 0, ttUndefined, 4 }, // Version { 20, ttUnsignedShort, 4 } // Color balance levels }; //! Nikon Color Balance binary array - definition 4 (D3) extern const ArrayDef nikonCb4Def[] = { { 0, ttUndefined, 4 }, // Version { 4, ttUnsignedShort, 140 }, // Unknown {284, ttUnsignedShort, 5 }, // Unknown (encrypted) {294, ttUnsignedShort, 4 } // Color balance levels }; //! Nikon Color Balance configurations and definitions extern const ArraySet nikonCbSet[] = { { nikonCb1Cfg, nikonCb1Def, EXV_COUNTOF(nikonCb1Def) }, { nikonCb2Cfg, nikonCb2Def, EXV_COUNTOF(nikonCb2Def) }, { nikonCb2aCfg, nikonCb2aDef, EXV_COUNTOF(nikonCb2aDef) }, { nikonCb2bCfg, nikonCb2bDef, EXV_COUNTOF(nikonCb2bDef) }, { nikonCb3Cfg, nikonCb3Def, EXV_COUNTOF(nikonCb3Def) }, { nikonCb4Cfg, nikonCb4Def, EXV_COUNTOF(nikonCb4Def) } }; //! Minolta Camera Settings (old) binary array - configuration extern const ArrayCfg minoCsoCfg = { minoltaCsOldId, // Group for the elements bigEndian, // Big endian ttUndefined, // Type for array entry and size element notEncrypted, // Not encrypted false, // No size element false, // No fillers false, // Don't concatenate gaps { 0, ttUnsignedLong, 1 } }; //! Minolta Camera Settings (new) binary array - configuration extern const ArrayCfg minoCsnCfg = { minoltaCsNewId, // Group for the elements bigEndian, // Big endian ttUndefined, // Type for array entry and size element notEncrypted, // Not encrypted false, // No size element false, // No fillers false, // Don't concatenate gaps { 0, ttUnsignedLong, 1 } }; //! Minolta 7D Camera Settings binary array - configuration extern const ArrayCfg minoCs7Cfg = { minoltaCs7DId, // Group for the elements bigEndian, // Big endian ttUndefined, // Type for array entry and size element notEncrypted, // Not encrypted false, // No size element false, // No fillers false, // Don't concatenate gaps { 0, ttUnsignedShort, 1 } }; //! Minolta 7D Camera Settings binary array - definition extern const ArrayDef minoCs7Def[] = { { 60, ttSignedShort, 1 }, // Exif.MinoltaCs7D.ExposureCompensation { 126, ttSignedShort, 1 } // Exif.MinoltaCs7D.ColorTemperature }; //! Minolta 5D Camera Settings binary array - configuration extern const ArrayCfg minoCs5Cfg = { minoltaCs5DId, // Group for the elements bigEndian, // Big endian ttUndefined, // Type for array entry and size element notEncrypted, // Not encrypted false, // No size element false, // No fillers false, // Don't concatenate gaps { 0, ttUnsignedShort, 1 } }; //! Minolta 5D Camera Settings binary array - definition extern const ArrayDef minoCs5Def[] = { { 146, ttSignedShort, 1 } // Exif.MinoltaCs5D.ColorTemperature }; // Todo: Performance of the handling of Sony Camera Settings can be // improved by defining all known array elements in the definitions // sonyCsDef and sonyCs2Def below and enabling the 'concatenate gaps' // setting in all four configurations. //! Sony1 Camera Settings binary array - configuration extern const ArrayCfg sony1CsCfg = { sony1CsId, // Group for the elements bigEndian, // Big endian ttUndefined, // Type for array entry and size element notEncrypted, // Not encrypted false, // No size element false, // No fillers false, // Don't concatenate gaps { 0, ttUnsignedShort, 1 } }; //! Sony1 Camera Settings 2 binary array - configuration extern const ArrayCfg sony1Cs2Cfg = { sony1Cs2Id, // Group for the elements bigEndian, // Big endian ttUndefined, // Type for array entry and size element notEncrypted, // Not encrypted false, // No size element false, // No fillers false, // Don't concatenate gaps { 0, ttUnsignedShort, 1 } }; //! Sony[12] Camera Settings binary array - definition extern const ArrayDef sonyCsDef[] = { { 12, ttSignedShort, 1 } // Exif.Sony[12]Cs.WhiteBalanceFineTune }; //! Sony2 Camera Settings binary array - configuration extern const ArrayCfg sony2CsCfg = { sony2CsId, // Group for the elements bigEndian, // Big endian ttUndefined, // Type for array entry and size element notEncrypted, // Not encrypted false, // No size element false, // No fillers false, // Don't concatenate gaps { 0, ttUnsignedShort, 1 } }; //! Sony2 Camera Settings 2 binary array - configuration extern const ArrayCfg sony2Cs2Cfg = { sony2Cs2Id, // Group for the elements bigEndian, // Big endian ttUndefined, // Type for array entry and size element notEncrypted, // Not encrypted false, // No size element false, // No fillers false, // Don't concatenate gaps { 0, ttUnsignedShort, 1 } }; //! Sony[12] Camera Settings 2 binary array - definition extern const ArrayDef sonyCs2Def[] = { { 44, ttUnsignedShort, 1 } // Exif.Sony[12]Cs2.FocusMode }; //! Sony1 Camera Settings configurations and definitions extern const ArraySet sony1CsSet[] = { { sony1CsCfg, sonyCsDef, EXV_COUNTOF(sonyCsDef) }, { sony1Cs2Cfg, sonyCs2Def, EXV_COUNTOF(sonyCs2Def) } }; //! Sony2 Camera Settings configurations and definitions extern const ArraySet sony2CsSet[] = { { sony2CsCfg, sonyCsDef, EXV_COUNTOF(sonyCsDef) }, { sony2Cs2Cfg, sonyCs2Def, EXV_COUNTOF(sonyCs2Def) } }; //! Sony Minolta Camera Settings (old) binary array - configuration extern const ArrayCfg sony1MCsoCfg = { sony1MltCsOldId, // Group for the elements bigEndian, // Big endian ttUndefined, // Type for array entry and size element notEncrypted, // Not encrypted false, // No size element false, // No fillers false, // Don't concatenate gaps { 0, ttUnsignedLong, 1 } }; //! Sony Minolta Camera Settings (new) binary array - configuration extern const ArrayCfg sony1MCsnCfg = { sony1MltCsNewId, // Group for the elements bigEndian, // Big endian ttUndefined, // Type for array entry and size element notEncrypted, // Not encrypted false, // No size element false, // No fillers false, // Don't concatenate gaps { 0, ttUnsignedLong, 1 } }; //! Sony Minolta 7D Camera Settings binary array - configuration extern const ArrayCfg sony1MCs7Cfg = { sony1MltCs7DId, // Group for the elements bigEndian, // Big endian ttUndefined, // Type for array entry and size element notEncrypted, // Not encrypted false, // No size element false, // No fillers false, // Don't concatenate gaps { 0, ttUnsignedShort, 1 } }; //! Sony Minolta A100 Camera Settings binary array - configuration extern const ArrayCfg sony1MCsA100Cfg = { sony1MltCsA100Id, // Group for the elements bigEndian, // Big endian ttUndefined, // Type for array entry and size element notEncrypted, // Not encrypted false, // No size element false, // No fillers false, // Don't concatenate gaps { 0, ttUnsignedShort, 1 } }; //! Sony Minolta A100 Camera Settings binary array - definition extern const ArrayDef sony1MCsA100Def[] = { { 112, ttSignedShort, 1 }, // Exif.Sony1MltCsA100.WhiteBalanceFineTune { 116, ttSignedShort, 1 }, // Exif.Sony1MltCsA100.ColorCompensationFilter { 190, ttSignedShort, 1 } // Exif.Sony1MltCsA100.ColorCompensationFilter2 }; //! Samsung PictureWizard binary array - configuration extern const ArrayCfg samsungPwCfg = { samsungPwId, // Group for the elements invalidByteOrder, // Use byte order from parent ttUnsignedShort, // Type for array entry notEncrypted, // Not encrypted false, // No size element true, // Write all tags true, // Concatenate gaps { 0, ttUnsignedShort, 1 } }; //! Samsung PictureWizard binary array - definition extern const ArrayDef samsungPwDef[] = { { 0, ttUnsignedShort, 1 }, // Mode { 2, ttUnsignedShort, 1 }, // Color { 4, ttUnsignedShort, 1 }, // Saturation { 6, ttUnsignedShort, 1 }, // Sharpness { 8, ttUnsignedShort, 1 } // Contrast }; /* This table lists for each group in a tree, its parent group and tag. Root identifies the root of a TIFF tree, as there is a need for multiple trees. Groups are the nodes of a TIFF tree. A group is an IFD or any other composite component. With this table, it is possible, for a given group (and tag) to find a path, i.e., a list of groups and tags, from the root to that group (tag). */ const TiffTreeStruct TiffCreator::tiffTreeStruct_[] = { // root group parent group parent tag //--------- ----------------- ----------------- ---------- { Tag::root, ifdIdNotSet, ifdIdNotSet, Tag::root }, { Tag::root, ifd0Id, ifdIdNotSet, Tag::root }, { Tag::root, subImage1Id, ifd0Id, 0x014a }, { Tag::root, subImage2Id, ifd0Id, 0x014a }, { Tag::root, subImage3Id, ifd0Id, 0x014a }, { Tag::root, subImage4Id, ifd0Id, 0x014a }, { Tag::root, subImage5Id, ifd0Id, 0x014a }, { Tag::root, subImage6Id, ifd0Id, 0x014a }, { Tag::root, subImage7Id, ifd0Id, 0x014a }, { Tag::root, subImage8Id, ifd0Id, 0x014a }, { Tag::root, subImage9Id, ifd0Id, 0x014a }, { Tag::root, exifId, ifd0Id, 0x8769 }, { Tag::root, gpsId, ifd0Id, 0x8825 }, { Tag::root, iopId, exifId, 0xa005 }, { Tag::root, ifd1Id, ifd0Id, Tag::next }, { Tag::root, ifd2Id, ifd1Id, Tag::next }, { Tag::root, ifd3Id, ifd2Id, Tag::next }, { Tag::root, olympusId, exifId, 0x927c }, { Tag::root, olympus2Id, exifId, 0x927c }, { Tag::root, subThumb1Id, ifd1Id, 0x014a }, { Tag::root, olympusEqId, olympus2Id, 0x2010 }, { Tag::root, olympusCsId, olympus2Id, 0x2020 }, { Tag::root, olympusRdId, olympus2Id, 0x2030 }, { Tag::root, olympusRd2Id, olympus2Id, 0x2031 }, { Tag::root, olympusIpId, olympus2Id, 0x2040 }, { Tag::root, olympusFiId, olympus2Id, 0x2050 }, { Tag::root, olympusFe1Id, olympus2Id, 0x2100 }, { Tag::root, olympusFe2Id, olympus2Id, 0x2200 }, { Tag::root, olympusFe3Id, olympus2Id, 0x2300 }, { Tag::root, olympusFe4Id, olympus2Id, 0x2400 }, { Tag::root, olympusFe5Id, olympus2Id, 0x2500 }, { Tag::root, olympusFe6Id, olympus2Id, 0x2600 }, { Tag::root, olympusFe7Id, olympus2Id, 0x2700 }, { Tag::root, olympusFe8Id, olympus2Id, 0x2800 }, { Tag::root, olympusFe9Id, olympus2Id, 0x2900 }, { Tag::root, olympusRiId, olympus2Id, 0x3000 }, { Tag::root, fujiId, exifId, 0x927c }, { Tag::root, canonId, exifId, 0x927c }, { Tag::root, canonCsId, canonId, 0x0001 }, { Tag::root, canonSiId, canonId, 0x0004 }, { Tag::root, canonPaId, canonId, 0x0005 }, { Tag::root, canonCfId, canonId, 0x000f }, { Tag::root, canonPiId, canonId, 0x0012 }, { Tag::root, canonFiId, canonId, 0x0093 }, { Tag::root, canonPrId, canonId, 0x00a0 }, { Tag::root, nikon1Id, exifId, 0x927c }, { Tag::root, nikon2Id, exifId, 0x927c }, { Tag::root, nikon3Id, exifId, 0x927c }, { Tag::root, nikonPvId, nikon3Id, 0x0011 }, { Tag::root, nikonVrId, nikon3Id, 0x001f }, { Tag::root, nikonPcId, nikon3Id, 0x0023 }, { Tag::root, nikonWtId, nikon3Id, 0x0024 }, { Tag::root, nikonIiId, nikon3Id, 0x0025 }, { Tag::root, nikonAfId, nikon3Id, 0x0088 }, { Tag::root, nikonSi1Id, nikon3Id, 0x0091 }, { Tag::root, nikonSi2Id, nikon3Id, 0x0091 }, { Tag::root, nikonSi3Id, nikon3Id, 0x0091 }, { Tag::root, nikonSi4Id, nikon3Id, 0x0091 }, { Tag::root, nikonSi5Id, nikon3Id, 0x0091 }, { Tag::root, nikonSi6Id, nikon3Id, 0x0091 }, { Tag::root, nikonCb1Id, nikon3Id, 0x0097 }, { Tag::root, nikonCb2Id, nikon3Id, 0x0097 }, { Tag::root, nikonCb2aId, nikon3Id, 0x0097 }, { Tag::root, nikonCb2bId, nikon3Id, 0x0097 }, { Tag::root, nikonCb3Id, nikon3Id, 0x0097 }, { Tag::root, nikonCb4Id, nikon3Id, 0x0097 }, { Tag::root, nikonLd1Id, nikon3Id, 0x0098 }, { Tag::root, nikonLd2Id, nikon3Id, 0x0098 }, { Tag::root, nikonLd3Id, nikon3Id, 0x0098 }, { Tag::root, nikonMeId, nikon3Id, 0x00b0 }, { Tag::root, nikonAf2Id, nikon3Id, 0x00b7 }, { Tag::root, nikonFiId, nikon3Id, 0x00b8 }, { Tag::root, nikonAFTId, nikon3Id, 0x00b9 }, { Tag::root, nikonFl1Id, nikon3Id, 0x00a8 }, { Tag::root, nikonFl2Id, nikon3Id, 0x00a8 }, { Tag::root, nikonFl3Id, nikon3Id, 0x00a8 }, { Tag::root, panasonicId, exifId, 0x927c }, { Tag::root, pentaxId, exifId, 0x927c }, { Tag::root, pentaxDngId, ifd0Id, 0xc634 }, { Tag::root, samsung2Id, exifId, 0x927c }, { Tag::root, samsungPwId, samsung2Id, 0x0021 }, { Tag::root, samsungPvId, samsung2Id, 0x0035 }, { Tag::root, sigmaId, exifId, 0x927c }, { Tag::root, sony1Id, exifId, 0x927c }, { Tag::root, sony1CsId, sony1Id, 0x0114 }, { Tag::root, sony1Cs2Id, sony1Id, 0x0114 }, { Tag::root, sonyMltId, sony1Id, 0xb028 }, { Tag::root, sony1MltCsOldId, sonyMltId, 0x0001 }, { Tag::root, sony1MltCsNewId, sonyMltId, 0x0003 }, { Tag::root, sony1MltCs7DId, sonyMltId, 0x0004 }, { Tag::root, sony1MltCsA100Id, sonyMltId, 0x0114 }, { Tag::root, sony2Id, exifId, 0x927c }, { Tag::root, sony2CsId, sony2Id, 0x0114 }, { Tag::root, sony2Cs2Id, sony2Id, 0x0114 }, { Tag::root, minoltaId, exifId, 0x927c }, { Tag::root, minoltaCsOldId, minoltaId, 0x0001 }, { Tag::root, minoltaCsNewId, minoltaId, 0x0003 }, { Tag::root, minoltaCs7DId, minoltaId, 0x0004 }, { Tag::root, minoltaCs5DId, minoltaId, 0x0114 }, // --------------------------------------------------------- // Panasonic RW2 raw images { Tag::pana, ifdIdNotSet, ifdIdNotSet, Tag::pana }, { Tag::pana, panaRawId, ifdIdNotSet, Tag::pana }, { Tag::pana, exifId, panaRawId, 0x8769 }, { Tag::pana, gpsId, panaRawId, 0x8825 } }; /* This table describes the layout of each known TIFF group (including non-standard structures and IFDs only seen in RAW images). The key of the table consists of the first two attributes, (extended) tag and group. Tag is the TIFF tag or one of a few extended tags, group identifies the IFD or any other composite component. Each entry of the table defines for a particular tag and group combination the corresponding TIFF component create function. */ const TiffGroupStruct TiffCreator::tiffGroupStruct_[] = { // ext. tag group create function //--------- ----------------- ----------------------------------------- // Root directory { Tag::root, ifdIdNotSet, newTiffDirectory }, // IFD0 { 0x8769, ifd0Id, newTiffSubIfd }, { 0x8825, ifd0Id, newTiffSubIfd }, { 0x0111, ifd0Id, newTiffImageData<0x0117, ifd0Id> }, { 0x0117, ifd0Id, newTiffImageSize<0x0111, ifd0Id> }, { 0x0144, ifd0Id, newTiffImageData<0x0145, ifd0Id> }, { 0x0145, ifd0Id, newTiffImageSize<0x0144, ifd0Id> }, { 0x0201, ifd0Id, newTiffImageData<0x0202, ifd0Id> }, { 0x0202, ifd0Id, newTiffImageSize<0x0201, ifd0Id> }, { 0x014a, ifd0Id, newTiffSubIfd }, { 0xc634, ifd0Id, newTiffMnEntry }, { Tag::next, ifd0Id, newTiffDirectory }, { Tag::all, ifd0Id, newTiffEntry }, // Subdir subImage1 { 0x0111, subImage1Id, newTiffImageData<0x0117, subImage1Id> }, { 0x0117, subImage1Id, newTiffImageSize<0x0111, subImage1Id> }, { 0x0144, subImage1Id, newTiffImageData<0x0145, subImage1Id> }, { 0x0145, subImage1Id, newTiffImageSize<0x0144, subImage1Id> }, { 0x0201, subImage1Id, newTiffImageData<0x0202, subImage1Id> }, { 0x0202, subImage1Id, newTiffImageSize<0x0201, subImage1Id> }, { Tag::next, subImage1Id, newTiffDirectory }, { Tag::all, subImage1Id, newTiffEntry }, // Subdir subImage2 { 0x0111, subImage2Id, newTiffImageData<0x0117, subImage2Id> }, { 0x0117, subImage2Id, newTiffImageSize<0x0111, subImage2Id> }, { 0x0144, subImage2Id, newTiffImageData<0x0145, subImage2Id> }, { 0x0145, subImage2Id, newTiffImageSize<0x0144, subImage2Id> }, { 0x0201, subImage2Id, newTiffImageData<0x0202, subImage2Id> }, { 0x0202, subImage2Id, newTiffImageSize<0x0201, subImage2Id> }, { Tag::next, subImage2Id, newTiffDirectory }, { Tag::all, subImage2Id, newTiffEntry }, // Subdir subImage3 { 0x0111, subImage3Id, newTiffImageData<0x0117, subImage3Id> }, { 0x0117, subImage3Id, newTiffImageSize<0x0111, subImage3Id> }, { 0x0144, subImage3Id, newTiffImageData<0x0145, subImage3Id> }, { 0x0145, subImage3Id, newTiffImageSize<0x0144, subImage3Id> }, { 0x0201, subImage3Id, newTiffImageData<0x0202, subImage3Id> }, { 0x0202, subImage3Id, newTiffImageSize<0x0201, subImage3Id> }, { Tag::next, subImage3Id, newTiffDirectory }, { Tag::all, subImage3Id, newTiffEntry }, // Subdir subImage4 { 0x0111, subImage4Id, newTiffImageData<0x0117, subImage4Id> }, { 0x0117, subImage4Id, newTiffImageSize<0x0111, subImage4Id> }, { 0x0144, subImage4Id, newTiffImageData<0x0145, subImage4Id> }, { 0x0145, subImage4Id, newTiffImageSize<0x0144, subImage4Id> }, { 0x0201, subImage4Id, newTiffImageData<0x0202, subImage4Id> }, { 0x0202, subImage4Id, newTiffImageSize<0x0201, subImage4Id> }, { Tag::next, subImage4Id, newTiffDirectory }, { Tag::all, subImage4Id, newTiffEntry }, // Subdir subImage5 { 0x0111, subImage5Id, newTiffImageData<0x0117, subImage5Id> }, { 0x0117, subImage5Id, newTiffImageSize<0x0111, subImage5Id> }, { 0x0144, subImage5Id, newTiffImageData<0x0145, subImage5Id> }, { 0x0145, subImage5Id, newTiffImageSize<0x0144, subImage5Id> }, { 0x0201, subImage5Id, newTiffImageData<0x0202, subImage5Id> }, { 0x0202, subImage5Id, newTiffImageSize<0x0201, subImage5Id> }, { Tag::next, subImage5Id, newTiffDirectory }, { Tag::all, subImage5Id, newTiffEntry }, // Subdir subImage6 { 0x0111, subImage6Id, newTiffImageData<0x0117, subImage6Id> }, { 0x0117, subImage6Id, newTiffImageSize<0x0111, subImage6Id> }, { 0x0144, subImage6Id, newTiffImageData<0x0145, subImage6Id> }, { 0x0145, subImage6Id, newTiffImageSize<0x0144, subImage6Id> }, { 0x0201, subImage6Id, newTiffImageData<0x0202, subImage6Id> }, { 0x0202, subImage6Id, newTiffImageSize<0x0201, subImage6Id> }, { Tag::next, subImage6Id, newTiffDirectory }, { Tag::all, subImage6Id, newTiffEntry }, // Subdir subImage7 { 0x0111, subImage7Id, newTiffImageData<0x0117, subImage7Id> }, { 0x0117, subImage7Id, newTiffImageSize<0x0111, subImage7Id> }, { 0x0144, subImage7Id, newTiffImageData<0x0145, subImage7Id> }, { 0x0145, subImage7Id, newTiffImageSize<0x0144, subImage7Id> }, { 0x0201, subImage7Id, newTiffImageData<0x0202, subImage7Id> }, { 0x0202, subImage7Id, newTiffImageSize<0x0201, subImage7Id> }, { Tag::next, subImage7Id, newTiffDirectory }, { Tag::all, subImage7Id, newTiffEntry }, // Subdir subImage8 { 0x0111, subImage8Id, newTiffImageData<0x0117, subImage8Id> }, { 0x0117, subImage8Id, newTiffImageSize<0x0111, subImage8Id> }, { 0x0144, subImage8Id, newTiffImageData<0x0145, subImage8Id> }, { 0x0145, subImage8Id, newTiffImageSize<0x0144, subImage8Id> }, { 0x0201, subImage8Id, newTiffImageData<0x0202, subImage8Id> }, { 0x0202, subImage8Id, newTiffImageSize<0x0201, subImage8Id> }, { Tag::next, subImage8Id, newTiffDirectory }, { Tag::all, subImage8Id, newTiffEntry }, // Subdir subImage9 { 0x0111, subImage9Id, newTiffImageData<0x0117, subImage9Id> }, { 0x0117, subImage9Id, newTiffImageSize<0x0111, subImage9Id> }, { 0x0144, subImage9Id, newTiffImageData<0x0145, subImage9Id> }, { 0x0145, subImage9Id, newTiffImageSize<0x0144, subImage9Id> }, { 0x0201, subImage9Id, newTiffImageData<0x0202, subImage9Id> }, { 0x0202, subImage9Id, newTiffImageSize<0x0201, subImage9Id> }, { Tag::next, subImage9Id, newTiffDirectory }, { Tag::all, subImage9Id, newTiffEntry }, // Exif subdir { 0xa005, exifId, newTiffSubIfd }, { 0x927c, exifId, newTiffMnEntry }, { Tag::next, exifId, newTiffDirectory }, { Tag::all, exifId, newTiffEntry }, // GPS subdir { Tag::next, gpsId, newTiffDirectory }, { Tag::all, gpsId, newTiffEntry }, // IOP subdir { Tag::next, iopId, newTiffDirectory }, { Tag::all, iopId, newTiffEntry }, // IFD1 { 0x0111, ifd1Id, newTiffThumbData<0x0117, ifd1Id> }, { 0x0117, ifd1Id, newTiffThumbSize<0x0111, ifd1Id> }, { 0x0144, ifd1Id, newTiffImageData<0x0145, ifd1Id> }, { 0x0145, ifd1Id, newTiffImageSize<0x0144, ifd1Id> }, { 0x014a, ifd1Id, newTiffSubIfd }, { 0x0201, ifd1Id, newTiffThumbData<0x0202, ifd1Id> }, { 0x0202, ifd1Id, newTiffThumbSize<0x0201, ifd1Id> }, { Tag::next, ifd1Id, newTiffDirectory }, { Tag::all, ifd1Id, newTiffEntry }, // Subdir subThumb1 { 0x0111, subThumb1Id, newTiffImageData<0x0117, subThumb1Id> }, { 0x0117, subThumb1Id, newTiffImageSize<0x0111, subThumb1Id> }, { 0x0144, subThumb1Id, newTiffImageData<0x0145, subThumb1Id> }, { 0x0145, subThumb1Id, newTiffImageSize<0x0144, subThumb1Id> }, { 0x0201, subThumb1Id, newTiffImageData<0x0202, subThumb1Id> }, { 0x0202, subThumb1Id, newTiffImageSize<0x0201, subThumb1Id> }, { Tag::next, subThumb1Id, newTiffDirectory }, { Tag::all, subThumb1Id, newTiffEntry }, // IFD2 (eg, in Pentax PEF and Canon CR2 files) { 0x0111, ifd2Id, newTiffImageData<0x0117, ifd2Id> }, { 0x0117, ifd2Id, newTiffImageSize<0x0111, ifd2Id> }, { 0x0144, ifd1Id, newTiffImageData<0x0145, ifd2Id> }, { 0x0145, ifd1Id, newTiffImageSize<0x0144, ifd2Id> }, { 0x0201, ifd2Id, newTiffImageData<0x0202, ifd2Id> }, { 0x0202, ifd2Id, newTiffImageSize<0x0201, ifd2Id> }, { Tag::next, ifd2Id, newTiffDirectory }, { Tag::all, ifd2Id, newTiffEntry }, // IFD3 (eg, in Canon CR2 files) { 0x0111, ifd3Id, newTiffImageData<0x0117, ifd3Id> }, { 0x0117, ifd3Id, newTiffImageSize<0x0111, ifd3Id> }, { 0x0144, ifd1Id, newTiffImageData<0x0145, ifd3Id> }, { 0x0145, ifd1Id, newTiffImageSize<0x0144, ifd3Id> }, { 0x0201, ifd3Id, newTiffImageData<0x0202, ifd3Id> }, { 0x0202, ifd3Id, newTiffImageSize<0x0201, ifd3Id> }, { Tag::next, ifd3Id, newTiffDirectory }, { Tag::all, ifd3Id, newTiffEntry }, // Olympus makernote - some Olympus cameras use Minolta structures // Todo: Adding such tags will not work (maybe result in a Minolta makernote), need separate groups { 0x0001, olympusId, EXV_SIMPLE_BINARY_ARRAY(minoCsoCfg) }, { 0x0003, olympusId, EXV_SIMPLE_BINARY_ARRAY(minoCsnCfg) }, { Tag::next, olympusId, newTiffDirectory }, { Tag::all, olympusId, newTiffEntry }, // Olympus2 makernote { 0x0001, olympus2Id, EXV_SIMPLE_BINARY_ARRAY(minoCsoCfg) }, { 0x0003, olympus2Id, EXV_SIMPLE_BINARY_ARRAY(minoCsnCfg) }, { 0x2010, olympus2Id, newTiffSubIfd }, { 0x2020, olympus2Id, newTiffSubIfd }, { 0x2030, olympus2Id, newTiffSubIfd }, { 0x2031, olympus2Id, newTiffSubIfd }, { 0x2040, olympus2Id, newTiffSubIfd }, { 0x2050, olympus2Id, newTiffSubIfd }, { 0x2100, olympus2Id, newTiffSubIfd }, { 0x2200, olympus2Id, newTiffSubIfd }, { 0x2300, olympus2Id, newTiffSubIfd }, { 0x2400, olympus2Id, newTiffSubIfd }, { 0x2500, olympus2Id, newTiffSubIfd }, { 0x2600, olympus2Id, newTiffSubIfd }, { 0x2700, olympus2Id, newTiffSubIfd }, { 0x2800, olympus2Id, newTiffSubIfd }, { 0x2900, olympus2Id, newTiffSubIfd }, { 0x3000, olympus2Id, newTiffSubIfd }, { Tag::next, olympus2Id, newTiffDirectory }, { Tag::all, olympus2Id, newTiffEntry }, // Olympus2 equipment subdir { Tag::all, olympusEqId, newTiffEntry }, // Olympus2 camera settings subdir { 0x0101, olympusCsId, newTiffImageData<0x0102, olympusCsId> }, { 0x0102, olympusCsId, newTiffImageSize<0x0101, olympusCsId> }, { Tag::all, olympusCsId, newTiffEntry }, // Olympus2 raw development subdir { Tag::all, olympusRdId, newTiffEntry }, // Olympus2 raw development 2 subdir { Tag::all, olympusRd2Id, newTiffEntry }, // Olympus2 image processing subdir { Tag::all, olympusIpId, newTiffEntry }, // Olympus2 focus info subdir { Tag::all, olympusFiId, newTiffEntry }, // Olympus2 FE 1 subdir { Tag::all, olympusFe1Id, newTiffEntry }, // Olympus2 FE 2 subdir { Tag::all, olympusFe2Id, newTiffEntry }, // Olympus2 FE 3 subdir { Tag::all, olympusFe3Id, newTiffEntry }, // Olympus2 FE 4 subdir { Tag::all, olympusFe4Id, newTiffEntry }, // Olympus2 FE 5 subdir { Tag::all, olympusFe5Id, newTiffEntry }, // Olympus2 FE 6 subdir { Tag::all, olympusFe6Id, newTiffEntry }, // Olympus2 FE 7 subdir { Tag::all, olympusFe7Id, newTiffEntry }, // Olympus2 FE 8 subdir { Tag::all, olympusFe8Id, newTiffEntry }, // Olympus2 FE 9 subdir { Tag::all, olympusFe9Id, newTiffEntry }, // Olympus2 Raw Info subdir { Tag::all, olympusRiId, newTiffEntry }, // Fujifilm makernote { Tag::next, fujiId, newTiffDirectory }, { Tag::all, fujiId, newTiffEntry }, // Canon makernote { 0x0001, canonId, EXV_BINARY_ARRAY(canonCsCfg, canonCsDef) }, { 0x0004, canonId, EXV_SIMPLE_BINARY_ARRAY(canonSiCfg) }, { 0x0005, canonId, EXV_SIMPLE_BINARY_ARRAY(canonPaCfg) }, { 0x000f, canonId, EXV_SIMPLE_BINARY_ARRAY(canonCfCfg) }, { 0x0012, canonId, EXV_SIMPLE_BINARY_ARRAY(canonPiCfg) }, { 0x0093, canonId, EXV_BINARY_ARRAY(canonFiCfg, canonFiDef) }, { 0x00a0, canonId, EXV_SIMPLE_BINARY_ARRAY(canonPrCfg) }, { Tag::next, canonId, newTiffDirectory }, { Tag::all, canonId, newTiffEntry }, // Canon makernote composite tags { Tag::all, canonCsId, newTiffBinaryElement }, { Tag::all, canonSiId, newTiffBinaryElement }, { Tag::all, canonPaId, newTiffBinaryElement }, { Tag::all, canonCfId, newTiffBinaryElement }, { Tag::all, canonPiId, newTiffBinaryElement }, { Tag::all, canonFiId, newTiffBinaryElement }, { Tag::all, canonPrId, newTiffBinaryElement }, // Nikon1 makernote { Tag::next, nikon1Id, newTiffDirectory }, { Tag::all, nikon1Id, newTiffEntry }, // Nikon2 makernote { Tag::next, nikon2Id, newTiffDirectory }, { Tag::all, nikon2Id, newTiffEntry }, // Nikon3 makernote { Tag::next, nikon3Id, newTiffDirectory }, { 0x0011, nikon3Id, newTiffSubIfd }, { 0x001f, nikon3Id, EXV_BINARY_ARRAY(nikonVrCfg, nikonVrDef) }, { 0x0023, nikon3Id, EXV_BINARY_ARRAY(nikonPcCfg, nikonPcDef) }, { 0x0024, nikon3Id, EXV_BINARY_ARRAY(nikonWtCfg, nikonWtDef) }, { 0x0025, nikon3Id, EXV_BINARY_ARRAY(nikonIiCfg, nikonIiDef) }, { 0x0088, nikon3Id, EXV_BINARY_ARRAY(nikonAfCfg, nikonAfDef) }, { 0x0091, nikon3Id, EXV_COMPLEX_BINARY_ARRAY(nikonSiSet, nikonSelector) }, { 0x0097, nikon3Id, EXV_COMPLEX_BINARY_ARRAY(nikonCbSet, nikonSelector) }, { 0x0098, nikon3Id, EXV_COMPLEX_BINARY_ARRAY(nikonLdSet, nikonSelector) }, { 0x00a8, nikon3Id, EXV_COMPLEX_BINARY_ARRAY(nikonFlSet, nikonSelector) }, { 0x00b0, nikon3Id, EXV_BINARY_ARRAY(nikonMeCfg, nikonMeDef) }, { 0x00b7, nikon3Id, EXV_BINARY_ARRAY(nikonAf2Cfg, nikonAf2Def)}, { 0x00b8, nikon3Id, EXV_BINARY_ARRAY(nikonFiCfg, nikonFiDef) }, { 0x00b9, nikon3Id, EXV_BINARY_ARRAY(nikonAFTCfg, nikonAFTDef) }, { Tag::all, nikon3Id, newTiffEntry }, // Nikon3 makernote preview subdir { 0x0201, nikonPvId, newTiffThumbData<0x0202, nikonPvId> }, { 0x0202, nikonPvId, newTiffThumbSize<0x0201, nikonPvId> }, { Tag::next, nikonPvId, newTiffDirectory }, { Tag::all, nikonPvId, newTiffEntry }, // Nikon3 vibration reduction { Tag::all, nikonVrId, newTiffBinaryElement }, // Nikon3 picture control { Tag::all, nikonPcId, newTiffBinaryElement }, // Nikon3 world time { Tag::all, nikonWtId, newTiffBinaryElement }, // Nikon3 ISO info { Tag::all, nikonIiId, newTiffBinaryElement }, // Nikon3 auto focus { Tag::all, nikonAfId, newTiffBinaryElement }, // Nikon3 auto focus 2 { Tag::all, nikonAf2Id, newTiffBinaryElement }, // Nikon3 AF Fine Tune { Tag::all, nikonAFTId, newTiffBinaryElement }, // Nikon3 file info { Tag::all, nikonFiId, newTiffBinaryElement }, // Nikon3 multi exposure { Tag::all, nikonMeId, newTiffBinaryElement }, // Nikon3 flash info { Tag::all, nikonFl1Id, newTiffBinaryElement }, { Tag::all, nikonFl2Id, newTiffBinaryElement }, { Tag::all, nikonFl3Id, newTiffBinaryElement }, // Nikon3 shot info { Tag::all, nikonSi1Id, newTiffBinaryElement }, { Tag::all, nikonSi2Id, newTiffBinaryElement }, { Tag::all, nikonSi3Id, newTiffBinaryElement }, { Tag::all, nikonSi4Id, newTiffBinaryElement }, { Tag::all, nikonSi5Id, newTiffBinaryElement }, { Tag::all, nikonSi6Id, newTiffBinaryElement }, // Nikon3 color balance { Tag::all, nikonCb1Id, newTiffBinaryElement }, { Tag::all, nikonCb2Id, newTiffBinaryElement }, { Tag::all, nikonCb2aId, newTiffBinaryElement }, { Tag::all, nikonCb2bId, newTiffBinaryElement }, { Tag::all, nikonCb3Id, newTiffBinaryElement }, { Tag::all, nikonCb4Id, newTiffBinaryElement }, // Nikon3 lens data { Tag::all, nikonLd1Id, newTiffBinaryElement }, { Tag::all, nikonLd2Id, newTiffBinaryElement }, { Tag::all, nikonLd3Id, newTiffBinaryElement }, // Panasonic makernote { Tag::next, panasonicId, newTiffDirectory }, { Tag::all, panasonicId, newTiffEntry }, // Pentax DNG makernote { 0x0003, pentaxDngId, newTiffThumbSize<0x0004, pentaxDngId> }, { 0x0004, pentaxDngId, newTiffThumbData<0x0003, pentaxDngId> }, { Tag::next, pentaxDngId, newTiffDirectory }, { Tag::all, pentaxDngId, newTiffEntry }, // Pentax makernote { 0x0003, pentaxId, newTiffThumbSize<0x0004, pentaxId> }, { 0x0004, pentaxId, newTiffThumbData<0x0003, pentaxId> }, { Tag::next, pentaxId, newTiffDirectory }, { Tag::all, pentaxId, newTiffEntry }, // Samsung2 makernote { 0x0021, samsung2Id, EXV_BINARY_ARRAY(samsungPwCfg, samsungPwDef) }, { 0x0035, samsung2Id, newTiffSubIfd }, { Tag::next, samsung2Id, newTiffDirectory }, { Tag::all, samsung2Id, newTiffEntry }, // Samsung PictureWizard binary array { Tag::all, samsungPwId, newTiffBinaryElement }, // Samsung2 makernote preview subdir { 0x0201, samsungPvId, newTiffThumbData<0x0202, samsungPvId> }, { 0x0202, samsungPvId, newTiffThumbSize<0x0201, samsungPvId> }, { Tag::next, samsungPvId, newTiffDirectory }, { Tag::all, samsungPvId, newTiffEntry }, // Sigma/Foveon makernote { Tag::next, sigmaId, newTiffDirectory }, { Tag::all, sigmaId, newTiffEntry }, // Sony1 makernote { 0x0114, sony1Id, EXV_COMPLEX_BINARY_ARRAY(sony1CsSet, sonyCsSelector) }, { 0xb028, sony1Id, newTiffSubIfd }, { Tag::next, sony1Id, newTiffDirectory }, { Tag::all, sony1Id, newTiffEntry }, // Sony1 camera settings { Tag::all, sony1CsId, newTiffBinaryElement }, { Tag::all, sony1Cs2Id, newTiffBinaryElement }, // Sony2 makernote { 0x0114, sony2Id, EXV_COMPLEX_BINARY_ARRAY(sony2CsSet, sonyCsSelector) }, { Tag::next, sony2Id, newTiffDirectory }, { Tag::all, sony2Id, newTiffEntry }, // Sony2 camera settings { Tag::all, sony2CsId, newTiffBinaryElement }, { Tag::all, sony2Cs2Id, newTiffBinaryElement }, // Sony1 Minolta makernote { 0x0001, sonyMltId, EXV_SIMPLE_BINARY_ARRAY(sony1MCsoCfg) }, { 0x0003, sonyMltId, EXV_SIMPLE_BINARY_ARRAY(sony1MCsnCfg) }, { 0x0004, sonyMltId, EXV_BINARY_ARRAY(sony1MCs7Cfg, minoCs7Def)}, // minoCs7Def [sic] { 0x0088, sonyMltId, newTiffThumbData<0x0089, sonyMltId> }, { 0x0089, sonyMltId, newTiffThumbSize<0x0088, sonyMltId> }, { 0x0114, sonyMltId, EXV_BINARY_ARRAY(sony1MCsA100Cfg, sony1MCsA100Def)}, { Tag::next, sonyMltId, newTiffDirectory }, { Tag::all, sonyMltId, newTiffEntry }, // Sony1 Minolta makernote composite tags { Tag::all, sony1MltCsOldId, newTiffBinaryElement }, { Tag::all, sony1MltCsNewId, newTiffBinaryElement }, { Tag::all, sony1MltCs7DId, newTiffBinaryElement }, { Tag::all, sony1MltCsA100Id, newTiffBinaryElement }, // Minolta makernote { 0x0001, minoltaId, EXV_SIMPLE_BINARY_ARRAY(minoCsoCfg) }, { 0x0003, minoltaId, EXV_SIMPLE_BINARY_ARRAY(minoCsnCfg) }, { 0x0004, minoltaId, EXV_BINARY_ARRAY(minoCs7Cfg, minoCs7Def) }, { 0x0088, minoltaId, newTiffThumbData<0x0089, minoltaId> }, { 0x0089, minoltaId, newTiffThumbSize<0x0088, minoltaId> }, { 0x0114, minoltaId, EXV_BINARY_ARRAY(minoCs5Cfg, minoCs5Def) }, { Tag::next, minoltaId, newTiffDirectory }, { Tag::all, minoltaId, newTiffEntry }, // Minolta makernote composite tags { Tag::all, minoltaCsOldId, newTiffBinaryElement }, { Tag::all, minoltaCsNewId, newTiffBinaryElement }, { Tag::all, minoltaCs7DId, newTiffBinaryElement }, { Tag::all, minoltaCs5DId, newTiffBinaryElement }, // ----------------------------------------------------------------------- // Root directory of Panasonic RAW images { Tag::pana, ifdIdNotSet, newTiffDirectory }, // IFD0 of Panasonic RAW images { 0x8769, panaRawId, newTiffSubIfd }, { 0x8825, panaRawId, newTiffSubIfd }, // { 0x0111, panaRawId, newTiffImageData<0x0117, panaRawId> }, // { 0x0117, panaRawId, newTiffImageSize<0x0111, panaRawId> }, { Tag::next, panaRawId, newTiffDirectory }, { Tag::all, panaRawId, newTiffEntry }, // ----------------------------------------------------------------------- // Tags which are not de/encoded { Tag::next, ignoreId, newTiffDirectory }, { Tag::all, ignoreId, newTiffEntry } }; // TIFF mapping table for special decoding and encoding requirements const TiffMappingInfo TiffMapping::tiffMappingInfo_[] = { { "*", Tag::all, ignoreId, 0, 0 }, // Do not decode tags with group == ignoreId { "*", 0x02bc, ifd0Id, &TiffDecoder::decodeXmp, 0 /*done before the tree is traversed*/ }, { "*", 0x83bb, ifd0Id, &TiffDecoder::decodeIptc, 0 /*done before the tree is traversed*/ }, { "*", 0x8649, ifd0Id, &TiffDecoder::decodeIptc, 0 /*done before the tree is traversed*/ } }; DecoderFct TiffMapping::findDecoder(const std::string& make, uint32_t extendedTag, IfdId group) { DecoderFct decoderFct = &TiffDecoder::decodeStdTiffEntry; const TiffMappingInfo* td = find(tiffMappingInfo_, TiffMappingInfo::Key(make, extendedTag, group)); if (td) { // This may set decoderFct to 0, meaning that the tag should not be decoded decoderFct = td->decoderFct_; } return decoderFct; } EncoderFct TiffMapping::findEncoder( const std::string& make, uint32_t extendedTag, IfdId group ) { EncoderFct encoderFct = 0; const TiffMappingInfo* td = find(tiffMappingInfo_, TiffMappingInfo::Key(make, extendedTag, group)); if (td) { // Returns 0 if no special encoder function is found encoderFct = td->encoderFct_; } return encoderFct; } bool TiffTreeStruct::operator==(const TiffTreeStruct::Key& key) const { return key.r_ == root_ && key.g_ == group_; } TiffComponent::AutoPtr TiffCreator::create(uint32_t extendedTag, IfdId group) { TiffComponent::AutoPtr tc(0); uint16_t tag = static_cast(extendedTag & 0xffff); const TiffGroupStruct* ts = find(tiffGroupStruct_, TiffGroupStruct::Key(extendedTag, group)); if (ts && ts->newTiffCompFct_) { tc = ts->newTiffCompFct_(tag, group); } #ifdef DEBUG else { if (!ts) { std::cerr << "Warning: No TIFF structure entry found for "; } else { std::cerr << "Warning: No TIFF component creator found for "; } std::cerr << "extended tag 0x" << std::setw(4) << std::setfill('0') << std::hex << std::right << extendedTag << ", group " << groupName(group) << "\n"; } #endif return tc; } // TiffCreator::create void TiffCreator::getPath(TiffPath& tiffPath, uint32_t extendedTag, IfdId group, uint32_t root) { const TiffTreeStruct* ts = 0; do { tiffPath.push(TiffPathItem(extendedTag, group)); ts = find(tiffTreeStruct_, TiffTreeStruct::Key(root, group)); assert(ts != 0); extendedTag = ts->parentExtTag_; group = ts->parentGroup_; } while (!(ts->root_ == root && ts->group_ == ifdIdNotSet)); } // TiffCreator::getPath ByteOrder TiffParserWorker::decode( ExifData& exifData, IptcData& iptcData, XmpData& xmpData, const byte* pData, uint32_t size, uint32_t root, FindDecoderFct findDecoderFct, TiffHeaderBase* pHeader ) { // Create standard TIFF header if necessary std::auto_ptr ph; if (!pHeader) { ph = std::auto_ptr(new TiffHeader); pHeader = ph.get(); } TiffComponent::AutoPtr rootDir = parse(pData, size, root, pHeader); if (0 != rootDir.get()) { TiffDecoder decoder(exifData, iptcData, xmpData, rootDir.get(), findDecoderFct); rootDir->accept(decoder); } return pHeader->byteOrder(); } // TiffParserWorker::decode WriteMethod TiffParserWorker::encode( BasicIo& io, const byte* pData, uint32_t size, const ExifData& exifData, const IptcData& iptcData, const XmpData& xmpData, uint32_t root, FindEncoderFct findEncoderFct, TiffHeaderBase* pHeader, OffsetWriter* pOffsetWriter ) { /* 1) parse the binary image, if one is provided, and 2) attempt updating the parsed tree in-place ("non-intrusive writing") 3) else, create a new tree and write a new TIFF structure ("intrusive writing"). If there is a parsed tree, it is only used to access the image data in this case. */ assert(pHeader); assert(pHeader->byteOrder() != invalidByteOrder); WriteMethod writeMethod = wmIntrusive; TiffComponent::AutoPtr parsedTree = parse(pData, size, root, pHeader); PrimaryGroups primaryGroups; findPrimaryGroups(primaryGroups, parsedTree.get()); if (0 != parsedTree.get()) { // Attempt to update existing TIFF components based on metadata entries TiffEncoder encoder(exifData, iptcData, xmpData, parsedTree.get(), false, &primaryGroups, pHeader, findEncoderFct); parsedTree->accept(encoder); if (!encoder.dirty()) writeMethod = wmNonIntrusive; } if (writeMethod == wmIntrusive) { TiffComponent::AutoPtr createdTree = TiffCreator::create(root, ifdIdNotSet); if (0 != parsedTree.get()) { // Copy image tags from the original image to the composite TiffCopier copier(createdTree.get(), root, pHeader, &primaryGroups); parsedTree->accept(copier); } // Add entries from metadata to composite TiffEncoder encoder(exifData, iptcData, xmpData, createdTree.get(), parsedTree.get() == 0, &primaryGroups, pHeader, findEncoderFct); encoder.add(createdTree.get(), parsedTree.get(), root); // Write binary representation from the composite tree DataBuf header = pHeader->write(); BasicIo::AutoPtr tempIo(io.temporary()); // may throw assert(tempIo.get() != 0); IoWrapper ioWrapper(*tempIo, header.pData_, header.size_, pOffsetWriter); uint32_t imageIdx(uint32_t(-1)); createdTree->write(ioWrapper, pHeader->byteOrder(), header.size_, uint32_t(-1), uint32_t(-1), imageIdx); if (pOffsetWriter) pOffsetWriter->writeOffsets(*tempIo); io.transfer(*tempIo); // may throw #ifndef SUPPRESS_WARNINGS EXV_INFO << "Write strategy: Intrusive\n"; #endif } #ifndef SUPPRESS_WARNINGS else { EXV_INFO << "Write strategy: Non-intrusive\n"; } #endif return writeMethod; } // TiffParserWorker::encode TiffComponent::AutoPtr TiffParserWorker::parse( const byte* pData, uint32_t size, uint32_t root, TiffHeaderBase* pHeader ) { if (pData == 0 || size == 0) return TiffComponent::AutoPtr(0); if (!pHeader->read(pData, size) || pHeader->offset() >= size) { throw Error(3, "TIFF"); } TiffComponent::AutoPtr rootDir = TiffCreator::create(root, ifdIdNotSet); if (0 != rootDir.get()) { rootDir->setStart(pData + pHeader->offset()); TiffRwState::AutoPtr state( new TiffRwState(pHeader->byteOrder(), 0)); TiffReader reader(pData, size, rootDir.get(), state); rootDir->accept(reader); reader.postProcess(); } return rootDir; } // TiffParserWorker::parse void TiffParserWorker::findPrimaryGroups(PrimaryGroups& primaryGroups, TiffComponent* pSourceDir) { if (0 == pSourceDir) return; const IfdId imageGroups[] = { ifd0Id, ifd1Id, ifd2Id, ifd3Id, subImage1Id, subImage2Id, subImage3Id, subImage4Id, subImage5Id, subImage6Id, subImage7Id, subImage8Id, subImage9Id }; for (unsigned int i = 0; i < EXV_COUNTOF(imageGroups); ++i) { TiffFinder finder(0x00fe, imageGroups[i]); pSourceDir->accept(finder); TiffEntryBase* te = dynamic_cast(finder.result()); if ( te && te->pValue()->typeId() == unsignedLong && te->pValue()->count() == 1 && (te->pValue()->toLong() & 1) == 0) { primaryGroups.push_back(te->group()); } } } // TiffParserWorker::findPrimaryGroups TiffHeaderBase::TiffHeaderBase(uint16_t tag, uint32_t size, ByteOrder byteOrder, uint32_t offset) : tag_(tag), size_(size), byteOrder_(byteOrder), offset_(offset) { } TiffHeaderBase::~TiffHeaderBase() { } bool TiffHeaderBase::read(const byte* pData, uint32_t size) { if (!pData || size < 8) return false; if (pData[0] == 0x49 && pData[1] == 0x49) { byteOrder_ = littleEndian; } else if (pData[0] == 0x4d && pData[1] == 0x4d) { byteOrder_ = bigEndian; } else { return false; } if (tag_ != getUShort(pData + 2, byteOrder_)) return false; offset_ = getULong(pData + 4, byteOrder_); return true; } // TiffHeaderBase::read DataBuf TiffHeaderBase::write() const { DataBuf buf(8); switch (byteOrder_) { case littleEndian: buf.pData_[0] = 0x49; buf.pData_[1] = 0x49; break; case bigEndian: buf.pData_[0] = 0x4d; buf.pData_[1] = 0x4d; break; case invalidByteOrder: assert(false); break; } us2Data(buf.pData_ + 2, tag_, byteOrder_); ul2Data(buf.pData_ + 4, 0x00000008, byteOrder_); return buf; } void TiffHeaderBase::print(std::ostream& os, const std::string& prefix) const { os << prefix << _("TIFF header, offset") << " = 0x" << std::setw(8) << std::setfill('0') << std::hex << std::right << offset_; switch (byteOrder_) { case littleEndian: os << ", " << _("little endian encoded"); break; case bigEndian: os << ", " << _("big endian encoded"); break; case invalidByteOrder: break; } os << "\n"; } // TiffHeaderBase::print ByteOrder TiffHeaderBase::byteOrder() const { return byteOrder_; } void TiffHeaderBase::setByteOrder(ByteOrder byteOrder) { byteOrder_ = byteOrder; } uint32_t TiffHeaderBase::offset() const { return offset_; } void TiffHeaderBase::setOffset(uint32_t offset) { offset_ = offset; } uint32_t TiffHeaderBase::size() const { return size_; } uint16_t TiffHeaderBase::tag() const { return tag_; } bool TiffHeaderBase::isImageTag( uint16_t /*tag*/, IfdId /*group*/, const PrimaryGroups* /*primaryGroups*/) const { return false; } bool isTiffImageTag(uint16_t tag, IfdId group) { //! List of TIFF image tags static const TiffImgTagStruct tiffImageTags[] = { { 0x00fe, ifd0Id }, // Exif.Image.NewSubfileType { 0x00ff, ifd0Id }, // Exif.Image.SubfileType { 0x0100, ifd0Id }, // Exif.Image.ImageWidth { 0x0101, ifd0Id }, // Exif.Image.ImageLength { 0x0102, ifd0Id }, // Exif.Image.BitsPerSample { 0x0103, ifd0Id }, // Exif.Image.Compression { 0x0106, ifd0Id }, // Exif.Image.PhotometricInterpretation { 0x010a, ifd0Id }, // Exif.Image.FillOrder { 0x0111, ifd0Id }, // Exif.Image.StripOffsets { 0x0115, ifd0Id }, // Exif.Image.SamplesPerPixel { 0x0116, ifd0Id }, // Exif.Image.RowsPerStrip { 0x0117, ifd0Id }, // Exif.Image.StripByteCounts { 0x011a, ifd0Id }, // Exif.Image.XResolution { 0x011b, ifd0Id }, // Exif.Image.YResolution { 0x011c, ifd0Id }, // Exif.Image.PlanarConfiguration { 0x0122, ifd0Id }, // Exif.Image.GrayResponseUnit { 0x0123, ifd0Id }, // Exif.Image.GrayResponseCurve { 0x0124, ifd0Id }, // Exif.Image.T4Options { 0x0125, ifd0Id }, // Exif.Image.T6Options { 0x0128, ifd0Id }, // Exif.Image.ResolutionUnit { 0x012d, ifd0Id }, // Exif.Image.TransferFunction { 0x013d, ifd0Id }, // Exif.Image.Predictor { 0x013e, ifd0Id }, // Exif.Image.WhitePoint { 0x013f, ifd0Id }, // Exif.Image.PrimaryChromaticities { 0x0140, ifd0Id }, // Exif.Image.ColorMap { 0x0141, ifd0Id }, // Exif.Image.HalftoneHints { 0x0142, ifd0Id }, // Exif.Image.TileWidth { 0x0143, ifd0Id }, // Exif.Image.TileLength { 0x0144, ifd0Id }, // Exif.Image.TileOffsets { 0x0145, ifd0Id }, // Exif.Image.TileByteCounts { 0x014c, ifd0Id }, // Exif.Image.InkSet { 0x014d, ifd0Id }, // Exif.Image.InkNames { 0x014e, ifd0Id }, // Exif.Image.NumberOfInks { 0x0150, ifd0Id }, // Exif.Image.DotRange { 0x0151, ifd0Id }, // Exif.Image.TargetPrinter { 0x0152, ifd0Id }, // Exif.Image.ExtraSamples { 0x0153, ifd0Id }, // Exif.Image.SampleFormat { 0x0154, ifd0Id }, // Exif.Image.SMinSampleValue { 0x0155, ifd0Id }, // Exif.Image.SMaxSampleValue { 0x0156, ifd0Id }, // Exif.Image.TransferRange { 0x0157, ifd0Id }, // Exif.Image.ClipPath { 0x0158, ifd0Id }, // Exif.Image.XClipPathUnits { 0x0159, ifd0Id }, // Exif.Image.YClipPathUnits { 0x015a, ifd0Id }, // Exif.Image.Indexed { 0x015b, ifd0Id }, // Exif.Image.JPEGTables { 0x0200, ifd0Id }, // Exif.Image.JPEGProc { 0x0201, ifd0Id }, // Exif.Image.JPEGInterchangeFormat { 0x0202, ifd0Id }, // Exif.Image.JPEGInterchangeFormatLength { 0x0203, ifd0Id }, // Exif.Image.JPEGRestartInterval { 0x0205, ifd0Id }, // Exif.Image.JPEGLosslessPredictors { 0x0206, ifd0Id }, // Exif.Image.JPEGPointTransforms { 0x0207, ifd0Id }, // Exif.Image.JPEGQTables { 0x0208, ifd0Id }, // Exif.Image.JPEGDCTables { 0x0209, ifd0Id }, // Exif.Image.JPEGACTables { 0x0211, ifd0Id }, // Exif.Image.YCbCrCoefficients { 0x0212, ifd0Id }, // Exif.Image.YCbCrSubSampling { 0x0213, ifd0Id }, // Exif.Image.YCbCrPositioning { 0x0214, ifd0Id }, // Exif.Image.ReferenceBlackWhite { 0x828d, ifd0Id }, // Exif.Image.CFARepeatPatternDim { 0x828e, ifd0Id }, // Exif.Image.CFAPattern { 0x8773, ifd0Id }, // Exif.Image.InterColorProfile { 0x8824, ifd0Id }, // Exif.Image.SpectralSensitivity { 0x8828, ifd0Id }, // Exif.Image.OECF { 0x9102, ifd0Id }, // Exif.Image.CompressedBitsPerPixel { 0x9217, ifd0Id }, // Exif.Image.SensingMethod }; // If tag, group is one of the image tags listed above -> bingo! if (find(tiffImageTags, TiffImgTagStruct::Key(tag, group))) { #ifdef DEBUG ExifKey key(tag, groupName(group)); std::cerr << "Image tag: " << key << " (3)\n"; #endif return true; } #ifdef DEBUG std::cerr << "Not an image tag: " << key << " (4)\n"; #endif return false; } TiffHeader::TiffHeader(ByteOrder byteOrder, uint32_t offset, bool hasImageTags) : TiffHeaderBase(42, 8, byteOrder, offset), hasImageTags_(hasImageTags) { } TiffHeader::~TiffHeader() { } bool TiffHeader::isImageTag( uint16_t tag, IfdId group, const PrimaryGroups* pPrimaryGroups) const { if (!hasImageTags_) { #ifdef DEBUG std::cerr << "No image tags in this image\n"; #endif return false; } #ifdef DEBUG ExifKey key(tag, groupName(group)); #endif // If there are primary groups and none matches group, we're done if ( pPrimaryGroups != 0 && !pPrimaryGroups->empty() && std::find(pPrimaryGroups->begin(), pPrimaryGroups->end(), group) == pPrimaryGroups->end()) { #ifdef DEBUG std::cerr << "Not an image tag: " << key << " (1)\n"; #endif return false; } // All tags of marked primary groups other than IFD0 are considered // image tags. That should take care of NEFs until we know better. if ( pPrimaryGroups != 0 && !pPrimaryGroups->empty() && group != ifd0Id) { #ifdef DEBUG ExifKey key(tag, groupName(group)); std::cerr << "Image tag: " << key << " (2)\n"; #endif return true; } // Finally, if tag, group is one of the TIFF image tags -> bingo! return isTiffImageTag(tag, group); } // TiffHeader::isImageTag void OffsetWriter::setOrigin(OffsetId id, uint32_t origin, ByteOrder byteOrder) { offsetList_[id] = OffsetData(origin, byteOrder); } void OffsetWriter::setTarget(OffsetId id, uint32_t target) { OffsetList::iterator it = offsetList_.find(id); if (it != offsetList_.end()) it->second.target_ = target; } void OffsetWriter::writeOffsets(BasicIo& io) const { for (OffsetList::const_iterator it = offsetList_.begin(); it != offsetList_.end(); ++it) { io.seek(it->second.origin_, BasicIo::beg); byte buf[4] = { 0, 0, 0, 0 }; l2Data(buf, it->second.target_, it->second.byteOrder_); io.write(buf, 4); } } }} // namespace Internal, Exiv2 exiv2-0.23/src/pngchunk_int.hpp0000644000175000017500000002025711732641407016311 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! @file pngchunk_int.hpp @brief Class PngChunk to parse PNG chunk data implemented using the following references:
PNG iTXt chunk structure from PNG definitive guide,
PNG tTXt and zTXt chunks structures from PNG definitive guide,
PNG tags list by Phil Harvey
Email communication with caulier dot gilles at gmail dot com
@version $Rev: 2681 $ @author Andreas Huggel (ahu) ahuggel@gmx.net @author Gilles Caulier (cgilles) caulier dot gilles at gmail dot com @date 12-Jun-06, gc: submitted */ #ifndef PNGCHUNK_INT_HPP_ #define PNGCHUNK_INT_HPP_ // ***************************************************************************** // included header files #include "types.hpp" // + standard includes #include #include #include // ***************************************************************************** // namespace extensions namespace Exiv2 { // ***************************************************************************** // class declarations class Image; namespace Internal { // ***************************************************************************** // class definitions /*! @brief Stateless parser class for data in PNG chunk format. Images use this class to decode and encode PNG-based data. */ class PngChunk { public: /*! @brief Text Chunk types. */ enum TxtChunkType { tEXt_Chunk = 0, zTXt_Chunk = 1, iTXt_Chunk = 2 }; public: /*! @brief Decode PNG IHDR chunk data from a data buffer \em data and return image size to \em outWidth and \em outHeight. @param data PNG Chunk data buffer. @param outWidth Integer pointer to be set to the width of the image. @param outHeight Integer pointer to be set to the height of the image. */ static void decodeIHDRChunk(const DataBuf& data, int* outWidth, int* outHeight); /*! @brief Decode PNG tEXt, zTXt, or iTXt chunk data from \em pImage passed by data buffer \em data and extract Comment, Exif, Iptc, Xmp metadata accordingly. @param pImage Pointer to the image to hold the metadata @param data PNG Chunk data buffer. @param type PNG Chunk TXT type. */ static void decodeTXTChunk(Image* pImage, const DataBuf& data, TxtChunkType type); /*! @brief Return PNG TXT chunk key as data buffer. @param data PNG Chunk data buffer. @param stripHeader Set true if chunk data start with header bytes, else false (default). */ static DataBuf keyTXTChunk(const DataBuf& data, bool stripHeader=false); /*! @brief Return a complete PNG chunk data compressed or not as buffer. Data returned is formated accordingly with metadata \em type to host passed by \em metadata. @param metadata metadata buffer. @param type metadata type. */ static std::string makeMetadataChunk(const std::string& metadata, MetadataId type); private: /*! @brief Parse PNG Text chunk to determine type and extract content. Supported Chunk types are tTXt, zTXt, and iTXt. */ static DataBuf parseTXTChunk(const DataBuf& data, int keysize, TxtChunkType type); /*! @brief Parse PNG chunk contents to extract metadata container and assign it to image. Supported contents are: Exif raw text profile generated by ImageMagick ==> Image Exif metadata. Iptc raw text profile generated by ImageMagick ==> Image Iptc metadata. Xmp raw text profile generated by ImageMagick ==> Image Xmp metadata. Xmp packet generated by Adobe ==> Image Xmp metadata. Description string ==> Image Comments. */ static void parseChunkContent( Image* pImage, const byte* key, long keySize, const DataBuf arr); /*! @brief Return a compressed (zTXt) or uncompressed (tEXt) PNG ASCII text chunk (length + chunk type + chunk data + CRC) as a string. @param keyword Keyword for the PNG text chunk @param text Text to be recorded in the PNG chunk. @param compress Flag indicating whether to compress the PNG chunk data. @return String containing the PNG chunk */ static std::string makeAsciiTxtChunk(const std::string& keyword, const std::string& text, bool compress); /*! @brief Return a compressed or uncompressed (iTXt) PNG international text chunk (length + chunk type + chunk data + CRC) as a string. @param keyword Keyword for the PNG international text chunk @param text Text to be recorded in the PNG chunk. @param compress Flag indicating whether to compress the PNG chunk data. */ static std::string makeUtf8TxtChunk(const std::string& keyword, const std::string& text, bool compress); /*! @brief Wrapper around zlib to uncompress a PNG chunk content. */ static void zlibUncompress(const byte* compressedText, unsigned int compressedTextSize, DataBuf& arr); /*! @brief Wrapper around zlib to compress a PNG chunk content. */ static std::string zlibCompress(const std::string& text); /*! @brief Decode from ImageMagick raw text profile which host encoded Exif/Iptc/Xmp metadata byte array. */ static DataBuf readRawProfile(const DataBuf& text); /*! @brief Encode to ImageMagick raw text profile, which host encoded Exif/IPTC/XMP metadata byte arrays. */ static std::string writeRawProfile(const std::string& profileData, const char* profileType); }; // class PngChunk }} // namespace Internal, Exiv2 #endif // #ifndef PNGCHUNK_INT_HPP_ exiv2-0.23/src/jp2image.hpp0000644000175000017500000001161511732641407015316 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! @file jp2image.hpp @brief JPEG-2000 image, implemented using the following references: ISO/IEC JTC 1/SC 29/WG1 N2401: JPEG 2000 Part 6 FCD 15444-6
@version $Rev: 2681 $ @author Gilles Caulier (cgilles) caulier dot gilles at gmail dot com @author Marco Piovanelli, Ovolab (marco) marco.piovanelli@pobox.com @date 12-Mar-2007, marco: created */ #ifndef JP2IMAGE_HPP_ #define JP2IMAGE_HPP_ // ***************************************************************************** // included header files #include "exif.hpp" #include "iptc.hpp" #include "image.hpp" #include "types.hpp" // + standard includes #include // ***************************************************************************** // namespace extensions namespace Exiv2 { // ***************************************************************************** // class definitions // Add JPEG-2000 to the supported image formats namespace ImageType { const int jp2 = 15; //!< JPEG-2000 image type } /*! @brief Class to access JPEG-2000 images. */ class EXIV2API Jp2Image : public Image { public: //! @name Creators //@{ /*! @brief Constructor to open a JPEG-2000 image. Since the constructor can not return a result, callers should check the good() method after object construction to determine success or failure. @param io An auto-pointer that owns a BasicIo instance used for reading and writing image metadata. \b Important: The constructor takes ownership of the passed in BasicIo instance through the auto-pointer. Callers should not continue to use the BasicIo instance after it is passed to this method. Use the Image::io() method to get a temporary reference. @param create Specifies if an existing image should be read (false) or if a new file should be created (true). */ Jp2Image(BasicIo::AutoPtr io, bool create); //@} //! @name Manipulators //@{ void readMetadata(); void writeMetadata(); /*! @brief Todo: Not supported yet(?). Calling this function will throw an instance of Error(32). */ void setComment(const std::string& comment); //@} //! @name Accessors //@{ std::string mimeType() const; //@} private: //! @name NOT Implemented //@{ //! Copy constructor Jp2Image(const Jp2Image& rhs); //! Assignment operator Jp2Image& operator=(const Jp2Image& rhs); /*! @brief Provides the main implementation of writeMetadata() by writing all buffered metadata to the provided BasicIo. @param oIo BasicIo instance to write to (a temporary location). @return 4 if opening or writing to the associated BasicIo fails */ EXV_DLLLOCAL void doWriteMetadata(BasicIo& oIo); //@} }; // class Jp2Image // ***************************************************************************** // template, inline and free functions // These could be static private functions on Image subclasses but then // ImageFactory needs to be made a friend. /*! @brief Create a new Jp2Image instance and return an auto-pointer to it. Caller owns the returned object and the auto-pointer ensures that it will be deleted. */ EXIV2API Image::AutoPtr newJp2Instance(BasicIo::AutoPtr io, bool create); //! Check if the file iIo is a JPEG-2000 image. EXIV2API bool isJp2Type(BasicIo& iIo, bool advance); } // namespace Exiv2 #endif // #ifndef JP2IMAGE_HPP_ exiv2-0.23/src/tiff-test.cpp0000644000175000017500000000440411027153701015506 0ustar andreasandreas// ***************************************************************** -*- C++ -*- // tiff-test.cpp, $Rev: 1512 $ // TIFF writer tests. #include "tiffimage.hpp" #include "exif.hpp" #include "error.hpp" #include #include /* Tests: + All types of components + Makernotes + Data entries, thumbnails + Special use-cases + IFD1 + Multiple sub-IFDs + Comment + Other/unknown TIFF types */ using namespace Exiv2; void print(const ExifData& exifData); int main() try { BasicIo::AutoPtr io(new FileIo("image.tif")); TiffImage tiffImage(io, false); ExifData& exifData = tiffImage.exifData(); exifData["Exif.Image.ImageWidth"] = uint32_t(42); exifData["Exif.Image.ImageLength"] = 24; exifData["Exif.Image.Model"] = "Model"; exifData["Exif.Image.Make"] = "FujiFilm"; exifData["Exif.Photo.0x0001"] = "Just for fun"; exifData["Exif.Iop.RelatedImageFileFormat"] = "TIFF"; exifData["Exif.Photo.InteroperabilityTag"] = uint32_t(132); // for non-intrusive writing exifData["Exif.Image.ExifTag"] = uint32_t(89); // for non-intrusive writingti exifData.setJpegThumbnail("exiv2-empty.jpg"); // The setJpegThumbnail method sets this to 0. //exifData["Exif.Thumbnail.JPEGInterchangeFormat"] = uint32_t(197); print(exifData); tiffImage.writeMetadata(); return 0; } catch (const Error& e) { std::cerr << e << "\n"; return 1; } void print(const ExifData& exifData) { if (exifData.empty()) { std::string error("No Exif data found in the file"); throw Exiv2::Error(1, error); } Exiv2::ExifData::const_iterator end = exifData.end(); for (Exiv2::ExifData::const_iterator i = exifData.begin(); i != end; ++i) { std::cout << std::setw(44) << std::setfill(' ') << std::left << i->key() << " " << "0x" << std::setw(4) << std::setfill('0') << std::right << std::hex << i->tag() << " " << std::setw(9) << std::setfill(' ') << std::left << i->typeName() << " " << std::dec << std::setw(3) << std::setfill(' ') << std::right << i->count() << " " << std::dec << i->value() << "\n"; } } exiv2-0.23/src/nikonmn.cpp0000644000175000017500000044441711744713446015304 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * Lens database for the conversion of Nikon lens data to readable lens names * Copyright (C) 2005-2008 Robert Rottmerhusen * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /* File: nikonmn.cpp Version: $Rev: 2715 $ Author(s): Andreas Huggel (ahu) Gilles Caulier (gc) Jens Mueller (jm) History: 17-May-04, ahu: created 25-May-04, ahu: combined all Nikon formats in one component */ // ***************************************************************************** #include "rcsid_int.hpp" EXIV2_RCSID("@(#) $Id: nikonmn.cpp 2715 2012-04-22 05:29:10Z ahuggel $") // ***************************************************************************** // included header files #include "types.hpp" #include "nikonmn_int.hpp" #include "value.hpp" #include "image.hpp" #include "tags_int.hpp" #include "error.hpp" #include "i18n.h" // NLS support. // + standard includes #include #include #include #include #include #include //for log, pow, abs // ***************************************************************************** // class member definitions namespace Exiv2 { namespace Internal { //! OffOn, multiple tags extern const TagDetails nikonOffOn[] = { { 0, N_("Off") }, { 1, N_("On") } }; //! Off, Low, Normal, High, multiple tags extern const TagDetails nikonOlnh[] = { { 0, N_("Off") }, { 1, N_("Low") }, { 3, N_("Normal") }, { 5, N_("High") } }; //! Off, Low, Normal, High, multiple tags extern const TagDetails nikonActiveDLighning[] = { { 0, N_("Off") }, { 1, N_("Low") }, { 3, N_("Normal") }, { 5, N_("High") }, { 7, N_("Extra High") }, { 65535, N_("Auto") } }; //! Focus area for Nikon cameras. extern const char * const nikonFocusarea[] = { N_("Single area"), N_("Dynamic area"), N_("Dynamic area, closest subject"), N_("Group dynamic"), N_("Single area (wide)"), N_("Dynamic area (wide)") }; // Roger Larsson: My guess is that focuspoints will follow autofocus sensor // module. Note that relative size and position will vary depending on if // "wide" or not //! Focus points for Nikon cameras, used for Nikon 1 and Nikon 3 makernotes. extern const char * const nikonFocuspoints[] = { N_("Center"), N_("Top"), N_("Bottom"), N_("Left"), N_("Right"), N_("Upper-left"), N_("Upper-right"), N_("Lower-left"), N_("Lower-right"), N_("Left-most"), N_("Right-most") }; //! FlashComp, tag 0x0012 extern const TagDetails nikonFlashComp[] = { // From the PHP JPEG Metadata Toolkit { 0x06, "+1.0 EV" }, { 0x04, "+0.7 EV" }, { 0x03, "+0.5 EV" }, { 0x02, "+0.3 EV" }, { 0x00, "0.0 EV" }, { 0xfe, "-0.3 EV" }, { 0xfd, "-0.5 EV" }, { 0xfc, "-0.7 EV" }, { 0xfa, "-1.0 EV" }, { 0xf8, "-1.3 EV" }, { 0xf7, "-1.5 EV" }, { 0xf6, "-1.7 EV" }, { 0xf4, "-2.0 EV" }, { 0xf2, "-2.3 EV" }, { 0xf1, "-2.5 EV" }, { 0xf0, "-2.7 EV" }, { 0xee, "-3.0 EV" } }; //! ColorSpace, tag 0x001e extern const TagDetails nikonColorSpace[] = { { 1, N_("sRGB") }, { 2, N_("Adobe RGB") } }; //! FlashMode, tag 0x0087 extern const TagDetails nikonFlashMode[] = { { 0, N_("Did not fire") }, { 1, N_("Fire, manual") }, { 7, N_("Fire, external") }, { 8, N_("Fire, commander mode") }, { 9, N_("Fire, TTL mode") } }; //! ShootingMode, tag 0x0089 extern const TagDetailsBitmask nikonShootingMode[] = { { 0x0001, N_("Continuous") }, { 0x0002, N_("Delay") }, { 0x0004, N_("PC control") }, { 0x0010, N_("Exposure bracketing") }, { 0x0020, N_("Auto ISO") }, { 0x0040, N_("White balance bracketing") }, { 0x0080, N_("IR control") } }; //! ShootingMode D70, tag 0x0089 extern const TagDetailsBitmask nikonShootingModeD70[] = { { 0x0001, N_("Continuous") }, { 0x0002, N_("Delay") }, { 0x0004, N_("PC control") }, { 0x0010, N_("Exposure bracketing") }, { 0x0020, N_("Unused LE-NR slowdown") }, { 0x0040, N_("White balance bracketing") }, { 0x0080, N_("IR control") } }; //! AutoBracketRelease, tag 0x008a extern const TagDetails nikonAutoBracketRelease[] = { { 0, N_("None") }, { 1, N_("Auto release") }, { 2, N_("Manual release") } }; //! NEFCompression, tag 0x0093 extern const TagDetails nikonNefCompression[] = { { 1, N_("Lossy (type 1)") }, { 2, N_("Uncompressed") }, { 3, N_("Lossless") }, { 4, N_("Lossy (type 2)") } }; //! RetouchHistory, tag 0x009e extern const TagDetails nikonRetouchHistory[] = { { 0, N_("None") }, { 3, N_("B & W") }, { 4, N_("Sepia") }, { 5, N_("Trim") }, { 6, N_("Small picture") }, { 7, N_("D-Lighting") }, { 8, N_("Red eye") }, { 9, N_("Cyanotype") }, { 10, N_("Sky light") }, { 11, N_("Warm tone") }, { 12, N_("Color custom") }, { 13, N_("Image overlay") } }; //! HighISONoiseReduction, tag 0x00b1 extern const TagDetails nikonHighISONoiseReduction[] = { { 0, N_("Off") }, { 1, N_("Minimal") }, { 2, N_("Low") }, { 4, N_("Normal") }, { 6, N_("High") } }; // Nikon1 MakerNote Tag Info const TagInfo Nikon1MakerNote::tagInfo_[] = { TagInfo(0x0001, "Version", N_("Version"), N_("Nikon Makernote version"), nikon1Id, makerTags, undefined, -1, printValue), TagInfo(0x0002, "ISOSpeed", N_("ISO Speed"), N_("ISO speed setting"), nikon1Id, makerTags, unsignedShort, -1, print0x0002), TagInfo(0x0003, "ColorMode", N_("Color Mode"), N_("Color mode"), nikon1Id, makerTags, asciiString, -1, printValue), TagInfo(0x0004, "Quality", N_("Quality"), N_("Image quality setting"), nikon1Id, makerTags, asciiString, -1, printValue), TagInfo(0x0005, "WhiteBalance", N_("White Balance"), N_("White balance"), nikon1Id, makerTags, asciiString, -1, printValue), TagInfo(0x0006, "Sharpening", N_("Sharpening"), N_("Image sharpening setting"), nikon1Id, makerTags, asciiString, -1, printValue), TagInfo(0x0007, "Focus", N_("Focus"), N_("Focus mode"), nikon1Id, makerTags, asciiString, -1, print0x0007), TagInfo(0x0008, "FlashSetting", N_("Flash Setting"), N_("Flash setting"), nikon1Id, makerTags, asciiString, -1, printValue), TagInfo(0x000a, "0x000a", "0x000a", N_("Unknown"), nikon1Id, makerTags, unsignedRational, -1, printValue), TagInfo(0x000f, "ISOSelection", N_("ISO Selection"), N_("ISO selection"), nikon1Id, makerTags, asciiString, -1, printValue), TagInfo(0x0010, "DataDump", N_("Data Dump"), N_("Data dump"), nikon1Id, makerTags, undefined, -1, printValue), TagInfo(0x0080, "ImageAdjustment", N_("Image Adjustment"), N_("Image adjustment setting"), nikon1Id, makerTags, asciiString, -1, printValue), TagInfo(0x0082, "AuxiliaryLens", N_("Auxiliary Lens"), N_("Auxiliary lens (adapter)"), nikon1Id, makerTags, asciiString, -1, printValue), TagInfo(0x0085, "FocusDistance", N_("Focus Distance"), N_("Manual focus distance"), nikon1Id, makerTags, unsignedRational, -1, print0x0085), TagInfo(0x0086, "DigitalZoom", N_("Digital Zoom"), N_("Digital zoom setting"), nikon1Id, makerTags, unsignedRational, -1, print0x0086), TagInfo(0x0088, "AFFocusPos", N_("AF Focus Position"), N_("AF focus position information"), nikon1Id, makerTags, undefined, -1, print0x0088), // End of list marker TagInfo(0xffff, "(UnknownNikon1MnTag)", "(UnknownNikon1MnTag)", N_("Unknown Nikon1MakerNote tag"), nikon1Id, makerTags, asciiString, -1, printValue) }; const TagInfo* Nikon1MakerNote::tagList() { return tagInfo_; } std::ostream& Nikon1MakerNote::print0x0002(std::ostream& os, const Value& value, const ExifData*) { if (value.count() > 1) { os << value.toLong(1); } else { os << "(" << value << ")"; } return os; } std::ostream& Nikon1MakerNote::print0x0007(std::ostream& os, const Value& value, const ExifData*) { std::string focus = value.toString(); if (focus == "AF-C ") os << _("Continuous autofocus"); else if (focus == "AF-S ") os << _("Single autofocus"); else if (focus == "AF-A ") os << _("Automatic"); else os << "(" << value << ")"; return os; } std::ostream& Nikon1MakerNote::print0x0085(std::ostream& os, const Value& value, const ExifData*) { Rational distance = value.toRational(); if (distance.first == 0) { os << _("Unknown"); } else if (distance.second != 0) { std::ostringstream oss; oss.copyfmt(os); os << std::fixed << std::setprecision(2) << (float)distance.first / distance.second << " m"; os.copyfmt(oss); } else { os << "(" << value << ")"; } return os; } std::ostream& Nikon1MakerNote::print0x0086(std::ostream& os, const Value& value, const ExifData*) { Rational zoom = value.toRational(); if (zoom.first == 0) { os << _("Not used"); } else if (zoom.second != 0) { std::ostringstream oss; oss.copyfmt(os); os << std::fixed << std::setprecision(1) << (float)zoom.first / zoom.second << "x"; os.copyfmt(oss); } else { os << "(" << value << ")"; } return os; } std::ostream& Nikon1MakerNote::print0x0088(std::ostream& os, const Value& value, const ExifData*) { if (value.count() >= 1) { unsigned long focusArea = value.toLong(0); os << nikonFocusarea[focusArea] ; } if (value.count() >= 2) { os << "; "; unsigned long focusPoint = value.toLong(1); switch (focusPoint) { // Could use array nikonFokuspoints case 0: case 1: case 2: case 3: case 4: os << nikonFocuspoints[focusPoint]; break; default: os << value; if (focusPoint < sizeof(nikonFocuspoints)/sizeof(nikonFocuspoints[0])) os << " " << _("guess") << " " << nikonFocuspoints[focusPoint]; break; } } if (value.count() >= 3) { unsigned long focusPointsUsed1 = value.toLong(2); unsigned long focusPointsUsed2 = value.toLong(3); if (focusPointsUsed1 != 0 && focusPointsUsed2 != 0) { os << "; ["; if (focusPointsUsed1 & 1) os << nikonFocuspoints[0] << " "; if (focusPointsUsed1 & 2) os << nikonFocuspoints[1] << " "; if (focusPointsUsed1 & 4) os << nikonFocuspoints[2] << " "; if (focusPointsUsed1 & 8) os << nikonFocuspoints[3] << " "; if (focusPointsUsed1 & 16) os << nikonFocuspoints[4] << " "; if (focusPointsUsed1 & 32) os << nikonFocuspoints[5] << " "; if (focusPointsUsed1 & 64) os << nikonFocuspoints[6] << " "; if (focusPointsUsed1 & 128) os << nikonFocuspoints[7] << " "; if (focusPointsUsed2 & 1) os << nikonFocuspoints[8] << " "; if (focusPointsUsed2 & 2) os << nikonFocuspoints[9] << " "; if (focusPointsUsed2 & 4) os << nikonFocuspoints[10] << " "; os << "]"; } } else { os << "(" << value << ")"; } return os; } //! Quality, tag 0x0003 extern const TagDetails nikon2Quality[] = { { 1, N_("VGA Basic") }, { 2, N_("VGA Normal") }, { 3, N_("VGA Fine") }, { 4, N_("SXGA Basic") }, { 5, N_("SXGA Normal") }, { 6, N_("SXGA Fine") } }; //! ColorMode, tag 0x0004 extern const TagDetails nikon2ColorMode[] = { { 1, N_("Color") }, { 2, N_("Monochrome") } }; //! ImageAdjustment, tag 0x0005 extern const TagDetails nikon2ImageAdjustment[] = { { 0, N_("Normal") }, { 1, N_("Bright+") }, { 2, N_("Bright-") }, { 3, N_("Contrast+") }, { 4, N_("Contrast-") } }; //! ISOSpeed, tag 0x0006 extern const TagDetails nikon2IsoSpeed[] = { { 0, "80" }, { 2, "160" }, { 4, "320" }, { 5, "100" } }; //! WhiteBalance, tag 0x0007 extern const TagDetails nikon2WhiteBalance[] = { { 0, N_("Auto") }, { 1, N_("Preset") }, { 2, N_("Daylight") }, { 3, N_("Incandescent") }, { 4, N_("Fluorescent") }, { 5, N_("Cloudy") }, { 6, N_("Speedlight") } }; // Nikon2 MakerNote Tag Info const TagInfo Nikon2MakerNote::tagInfo_[] = { TagInfo(0x0002, "0x0002", "0x0002", N_("Unknown"), nikon2Id, makerTags, asciiString, -1, printValue), TagInfo(0x0003, "Quality", N_("Quality"), N_("Image quality setting"), nikon2Id, makerTags, unsignedShort, -1, EXV_PRINT_TAG(nikon2Quality)), TagInfo(0x0004, "ColorMode", N_("Color Mode"), N_("Color mode"), nikon2Id, makerTags, unsignedShort, -1, EXV_PRINT_TAG(nikon2ColorMode)), TagInfo(0x0005, "ImageAdjustment", N_("Image Adjustment"), N_("Image adjustment setting"), nikon2Id, makerTags, unsignedShort, -1, EXV_PRINT_TAG(nikon2ImageAdjustment)), TagInfo(0x0006, "ISOSpeed", N_("ISO Speed"), N_("ISO speed setting"), nikon2Id, makerTags, unsignedShort, -1, EXV_PRINT_TAG(nikon2IsoSpeed)), TagInfo(0x0007, "WhiteBalance", N_("White Balance"), N_("White balance"), nikon2Id, makerTags, unsignedShort, -1, EXV_PRINT_TAG(nikon2WhiteBalance)), TagInfo(0x0008, "Focus", N_("Focus Mode"), N_("Focus mode"), nikon2Id, makerTags, unsignedRational, -1, printValue), TagInfo(0x0009, "0x0009", "0x0009", N_("Unknown"), nikon2Id, makerTags, asciiString, -1, printValue), TagInfo(0x000a, "DigitalZoom", N_("Digital Zoom"), N_("Digital zoom setting"), nikon2Id, makerTags, unsignedRational, -1, print0x000a), TagInfo(0x000b, "AuxiliaryLens", N_("Auxiliary Lens"), N_("Auxiliary lens (adapter)"), nikon2Id, makerTags, unsignedShort, -1, printValue), TagInfo(0x0f00, "0x0f00", "0x0f00", N_("Unknown"), nikon2Id, makerTags, unsignedLong, -1, printValue), // End of list marker TagInfo(0xffff, "(UnknownNikon2MnTag)", "(UnknownNikon2MnTag)", N_("Unknown Nikon2MakerNote tag"), nikon2Id, makerTags, asciiString, -1, printValue) }; const TagInfo* Nikon2MakerNote::tagList() { return tagInfo_; } std::ostream& Nikon2MakerNote::print0x000a(std::ostream& os, const Value& value, const ExifData*) { Rational zoom = value.toRational(); if (zoom.first == 0) { os << _("Not used"); } else if (zoom.second != 0) { std::ostringstream oss; oss.copyfmt(os); os << std::fixed << std::setprecision(1) << (float)zoom.first / zoom.second << "x"; os.copyfmt(oss); } else { os << "(" << value << ")"; } return os; } // Nikon3 MakerNote Tag Info const TagInfo Nikon3MakerNote::tagInfo_[] = { TagInfo(0x0001, "Version", N_("Version"), N_("Nikon Makernote version"), nikon3Id, makerTags, undefined, -1, printExifVersion), TagInfo(0x0002, "ISOSpeed", N_("ISO Speed"), N_("ISO speed setting"), nikon3Id, makerTags, unsignedShort, -1, print0x0002), TagInfo(0x0003, "ColorMode", N_("Color Mode"), N_("Color mode"), nikon3Id, makerTags, asciiString, -1, printValue), TagInfo(0x0004, "Quality", N_("Quality"), N_("Image quality setting"), nikon3Id, makerTags, asciiString, -1, printValue), TagInfo(0x0005, "WhiteBalance", N_("White Balance"), N_("White balance"), nikon3Id, makerTags, asciiString, -1, printValue), TagInfo(0x0006, "Sharpening", N_("Sharpening"), N_("Image sharpening setting"), nikon3Id, makerTags, asciiString, -1, printValue), TagInfo(0x0007, "Focus", N_("Focus"), N_("Focus mode"), nikon3Id, makerTags, asciiString, -1, print0x0007), TagInfo(0x0008, "FlashSetting", N_("Flash Setting"), N_("Flash setting"), nikon3Id, makerTags, asciiString, -1, printValue), TagInfo(0x0009, "FlashDevice", N_("Flash Device"), N_("Flash device"), nikon3Id, makerTags, asciiString, -1, printValue), TagInfo(0x000a, "0x000a", "0x000a", N_("Unknown"), nikon3Id, makerTags, unsignedRational, -1, printValue), TagInfo(0x000b, "WhiteBalanceBias", N_("White Balance Bias"), N_("White balance bias"), nikon3Id, makerTags, signedShort, -1, printValue), TagInfo(0x000c, "WB_RBLevels", N_("WB RB Levels"), N_("WB RB levels"), nikon3Id, makerTags, unsignedRational, -1, printValue), TagInfo(0x000d, "ProgramShift", N_("Program Shift"), N_("Program shift"), nikon3Id, makerTags, undefined, -1, EXV_PRINT_TAG(nikonFlashComp)), TagInfo(0x000e, "ExposureDiff", N_("Exposure Difference"), N_("Exposure difference"), nikon3Id, makerTags, undefined, -1, EXV_PRINT_TAG(nikonFlashComp)), TagInfo(0x000f, "ISOSelection", N_("ISO Selection"), N_("ISO selection"), nikon3Id, makerTags, asciiString, -1, printValue), TagInfo(0x0010, "DataDump", N_("Data Dump"), N_("Data dump"), nikon3Id, makerTags, undefined, -1, printValue), TagInfo(0x0011, "Preview", N_("Pointer to a preview image"), N_("Offset to an IFD containing a preview image"), nikon3Id, makerTags, undefined, -1, printValue), TagInfo(0x0012, "FlashComp", N_("Flash Comp"), N_("Flash compensation setting"), nikon3Id, makerTags, undefined, -1, EXV_PRINT_TAG(nikonFlashComp)), TagInfo(0x0013, "ISOSettings", N_("ISO Settings"), N_("ISO setting"), nikon3Id, makerTags, unsignedShort, -1, print0x0002), // use 0x0002 print fct TagInfo(0x0016, "ImageBoundary", N_("Image Boundary"), N_("Image boundary"), nikon3Id, makerTags, unsignedShort, -1, printValue), TagInfo(0x0017, "FlashExposureComp", "Flash Exposure Comp", N_("Flash exposure comp"), nikon3Id, makerTags, undefined, -1, EXV_PRINT_TAG(nikonFlashComp)), TagInfo(0x0018, "FlashBracketComp", N_("Flash Bracket Comp"), N_("Flash bracket compensation applied"), nikon3Id, makerTags, undefined, -1, EXV_PRINT_TAG(nikonFlashComp)), // use 0x0012 print fct TagInfo(0x0019, "ExposureBracketComp", N_("Exposure Bracket Comp"), N_("AE bracket compensation applied"), nikon3Id, makerTags, signedRational, -1, printValue), TagInfo(0x001a, "ImageProcessing", N_("Image Processing"), N_("Image processing"), nikon3Id, makerTags, asciiString, -1, printValue), TagInfo(0x001b, "CropHiSpeed", N_("Crop High Speed"), N_("Crop high speed"), nikon3Id, makerTags, unsignedShort, -1, printValue), TagInfo(0x001c, "ExposureTuning", N_("Exposure Tuning"), N_("Exposure tuning"), nikon3Id, makerTags, unsignedShort, -1, printValue), TagInfo(0x001d, "SerialNumber", N_("Serial Number"), N_("Serial Number"), nikon3Id, makerTags, asciiString, -1, printValue), TagInfo(0x001e, "ColorSpace", N_("Color Space"), N_("Color space"), nikon3Id, makerTags, unsignedShort, -1, EXV_PRINT_TAG(nikonColorSpace)), TagInfo(0x001f, "VRInfo", N_("VR Info"), N_("VR info"), nikon3Id, makerTags, undefined, -1, printValue), TagInfo(0x0020, "ImageAuthentication", N_("Image Authentication"), N_("Image authentication"), nikon3Id, makerTags, unsignedByte, -1, EXV_PRINT_TAG(nikonOffOn)), TagInfo(0x0022, "ActiveDLighting", N_("ActiveD-Lighting"), N_("ActiveD-lighting"), nikon3Id, makerTags, unsignedShort, -1, EXV_PRINT_TAG(nikonActiveDLighning)), TagInfo(0x0023, "PictureControl", N_("Picture Control"), N_(" Picture control"), nikon3Id, makerTags, undefined, -1, printValue), TagInfo(0x0024, "WorldTime", N_("World Time"), N_("World time"), nikon3Id, makerTags, undefined, -1, printValue), TagInfo(0x0025, "ISOInfo", N_("ISO Info"), N_("ISO info"), nikon3Id, makerTags, undefined, -1, printValue), TagInfo(0x002a, "VignetteControl", N_("Vignette Control"), N_("Vignette control"), nikon3Id, makerTags, unsignedShort, -1, EXV_PRINT_TAG(nikonOlnh)), TagInfo(0x0080, "ImageAdjustment", N_("Image Adjustment"), N_("Image adjustment setting"), nikon3Id, makerTags, asciiString, -1, printValue), TagInfo(0x0081, "ToneComp", N_("Tone Compensation"), N_("Tone compensation"), nikon3Id, makerTags, asciiString, -1, printValue), TagInfo(0x0082, "AuxiliaryLens", N_("Auxiliary Lens"), N_("Auxiliary lens (adapter)"), nikon3Id, makerTags, asciiString, -1, printValue), TagInfo(0x0083, "LensType", N_("Lens Type"), N_("Lens type"), nikon3Id, makerTags, unsignedByte, -1, print0x0083), TagInfo(0x0084, "Lens", N_("Lens"), N_("Lens"), nikon3Id, makerTags, unsignedRational, -1, print0x0084), TagInfo(0x0085, "FocusDistance", N_("Focus Distance"), N_("Manual focus distance"), nikon3Id, makerTags, unsignedRational, -1, print0x0085), TagInfo(0x0086, "DigitalZoom", N_("Digital Zoom"), N_("Digital zoom setting"), nikon3Id, makerTags, unsignedRational, -1, print0x0086), TagInfo(0x0087, "FlashMode", N_("Flash Mode"), N_("Mode of flash used"), nikon3Id, makerTags, unsignedByte, -1, EXV_PRINT_TAG(nikonFlashMode)), TagInfo(0x0088, "AFInfo", N_("AF Info"), N_("AF info"), nikon3Id, makerTags, undefined, -1, printValue), TagInfo(0x0089, "ShootingMode", N_("Shooting Mode"), N_("Shooting mode"), nikon3Id, makerTags, unsignedShort, -1, print0x0089), TagInfo(0x008a, "AutoBracketRelease", N_("Auto Bracket Release"), N_("Auto bracket release"), nikon3Id, makerTags, unsignedShort, -1, EXV_PRINT_TAG(nikonAutoBracketRelease)), TagInfo(0x008b, "LensFStops", N_("Lens FStops"), N_("Lens FStops"), nikon3Id, makerTags, undefined, -1, print0x008b), TagInfo(0x008c, "ContrastCurve", N_("Contrast Curve"), N_("Contrast curve"), nikon3Id, makerTags, undefined, -1, printValue), TagInfo(0x008d, "ColorHue", N_("Color Hue"), N_("Color hue"), nikon3Id, makerTags, asciiString, -1, printValue), TagInfo(0x008f, "SceneMode", N_("Scene Mode"), N_("Scene mode"), nikon3Id, makerTags, asciiString, -1, printValue), TagInfo(0x0090, "LightSource", N_("Light Source"), N_("Light source"), nikon3Id, makerTags, asciiString, -1, printValue), TagInfo(0x0091, "ShotInfo", "Shot Info", N_("Shot info"), nikon3Id, makerTags, undefined, -1, printValue), TagInfo(0x0092, "HueAdjustment", N_("Hue Adjustment"), N_("Hue adjustment"), nikon3Id, makerTags, signedShort, -1, printValue), TagInfo(0x0093, "NEFCompression", N_("NEF Compression"), N_("NEF compression"), nikon3Id, makerTags, unsignedShort, -1, EXV_PRINT_TAG(nikonNefCompression)), TagInfo(0x0094, "Saturation", N_("Saturation"), N_("Saturation"), nikon3Id, makerTags, signedShort, -1, printValue), TagInfo(0x0095, "NoiseReduction", N_("Noise Reduction"), N_("Noise reduction"), nikon3Id, makerTags, asciiString, -1, printValue), TagInfo(0x0096, "LinearizationTable", N_("Linearization Table"), N_("Linearization table"), nikon3Id, makerTags, undefined, -1, printValue), TagInfo(0x0097, "ColorBalance", N_("Color Balance"), N_("Color balance"), nikon3Id, makerTags, undefined, -1, printValue), TagInfo(0x0098, "LensData", N_("Lens Data"), N_("Lens data settings"), nikon3Id, makerTags, undefined, -1, printValue), TagInfo(0x0099, "RawImageCenter", N_("Raw Image Center"), N_("Raw image center"), nikon3Id, makerTags, unsignedShort, -1, printValue), TagInfo(0x009a, "SensorPixelSize", N_("Sensor Pixel Size"), N_("Sensor pixel size"), nikon3Id, makerTags, unsignedRational, -1, print0x009a), TagInfo(0x009b, "0x009b", "0x009b", N_("Unknown"), nikon3Id, makerTags, unsignedShort, -1, printValue), TagInfo(0x009c, "SceneAssist", N_("Scene Assist"), N_("Scene assist"), nikon3Id, makerTags, asciiString, -1, printValue), TagInfo(0x009e, "RetouchHistory", N_("Retouch History"), N_("Retouch history"), nikon3Id, makerTags, unsignedShort, -1, print0x009e), TagInfo(0x009f, "0x009f", "0x009f", N_("Unknown"), nikon3Id, makerTags, signedShort, -1, printValue), TagInfo(0x00a0, "SerialNO", N_("Serial NO"), N_("Camera serial number, usually starts with \"NO= \""), nikon3Id, makerTags, asciiString, -1, printValue), TagInfo(0x00a2, "ImageDataSize", N_("Image Data Size"), N_("Image data size"), nikon3Id, makerTags, unsignedLong, -1, printValue), TagInfo(0x00a3, "0x00a3", "0x00a3", N_("Unknown"), nikon3Id, makerTags, unsignedByte, -1, printValue), TagInfo(0x00a5, "ImageCount", N_("Image Count"), N_("Image count"), nikon3Id, makerTags, unsignedLong, -1, printValue), TagInfo(0x00a6, "DeletedImageCount", N_("Deleted Image Count"), N_("Deleted image count"), nikon3Id, makerTags, unsignedLong, -1, printValue), TagInfo(0x00a7, "ShutterCount", N_("Shutter Count"), N_("Number of shots taken by camera"), nikon3Id, makerTags, unsignedLong, -1, printValue), TagInfo(0x00a8, "FlashInfo", "Flash Info", N_("Flash info"), nikon3Id, makerTags, undefined, -1, printValue), TagInfo(0x00a9, "ImageOptimization", N_("Image Optimization"), N_("Image optimization"), nikon3Id, makerTags, asciiString, -1, printValue), TagInfo(0x00aa, "Saturation", N_("Saturation"), N_("Saturation"), nikon3Id, makerTags, asciiString, -1, printValue), TagInfo(0x00ab, "VariProgram", N_("Program Variation"), N_("Program variation"), nikon3Id, makerTags, asciiString, -1, printValue), TagInfo(0x00ac, "ImageStabilization", N_("Image Stabilization"), N_("Image stabilization"), nikon3Id, makerTags, asciiString, -1, printValue), TagInfo(0x00ad, "AFResponse", N_("AF Response"), N_("AF response"), nikon3Id, makerTags, asciiString, -1, printValue), TagInfo(0x00b0, "MultiExposure", "Multi Exposure", N_("Multi exposure"), nikon3Id, makerTags, undefined, -1, printValue), TagInfo(0x00b1, "HighISONoiseReduction", N_("High ISO Noise Reduction"), N_("High ISO Noise Reduction"), nikon3Id, makerTags, unsignedShort, -1, EXV_PRINT_TAG(nikonHighISONoiseReduction)), TagInfo(0x00b3, "ToningEffect", "Toning Effect", N_("Toning effect"), nikon3Id, makerTags, asciiString, -1, printValue), TagInfo(0x00b7, "AFInfo2", "AF Info 2", N_("AF info 2"), nikon3Id, makerTags, undefined, -1, printValue), TagInfo(0x00b8, "FileInfo", "File Info", N_("File info"), nikon3Id, makerTags, undefined, -1, printValue), TagInfo(0x00b9, "AFTune", "AF Tune", N_("AF tune"), nikon3Id, makerTags, undefined, -1, printValue), TagInfo(0x0e00, "PrintIM", N_("Print IM"), N_("PrintIM information"), nikon3Id, makerTags, undefined, -1, printValue), // TODO: Add Capture Data decoding implementation. TagInfo(0x0e01, "CaptureData", N_("Capture Data"), N_("Capture data"), nikon3Id, makerTags, undefined, -1, printValue), TagInfo(0x0e09, "CaptureVersion", N_("Capture Version"), N_("Capture version"), nikon3Id, makerTags, asciiString, -1, printValue), // TODO: Add Capture Offsets decoding implementation. TagInfo(0x0e0e, "CaptureOffsets", N_("Capture Offsets"), N_("Capture offsets"), nikon3Id, makerTags, undefined, -1, printValue), TagInfo(0x0e10, "ScanIFD", "Scan IFD", N_("Scan IFD"), nikon3Id, makerTags, undefined, -1, printValue), TagInfo(0x0e1d, "ICCProfile", "ICC Profile", N_("ICC profile"), nikon3Id, makerTags, undefined, -1, printValue), TagInfo(0x0e1e, "CaptureOutput", "Capture Output", N_("Capture output"), nikon3Id, makerTags, undefined, -1, printValue), // End of list marker TagInfo(0xffff, "(UnknownNikon3MnTag)", "(UnknownNikon3MnTag)", N_("Unknown Nikon3MakerNote tag"), nikon3Id, makerTags, asciiString, -1, printValue) }; const TagInfo* Nikon3MakerNote::tagList() { return tagInfo_; } //! YesNo, used for DaylightSavings, tag index 2 extern const TagDetails nikonYesNo[] = { { 0, N_("No") }, { 1, N_("Yes") } }; //! DateDisplayFormat, tag index 3 extern const TagDetails nikonDateDisplayFormat[] = { { 0, N_("Y/M/D") }, { 1, N_("M/D/Y") }, { 2, N_("D/M/Y") } }; //! OnOff extern const TagDetails nikonOnOff[] = { { 1, N_("On") }, { 2, N_("Off") } }; // Nikon3 Vibration Reduction Tag Info const TagInfo Nikon3MakerNote::tagInfoVr_[] = { TagInfo(0, "Version", N_("Version"), N_("Version"), nikonVrId, makerTags, undefined, 4, printExifVersion), TagInfo(4, "VibrationReduction", N_("Vibration Reduction"), N_("Vibration reduction"), nikonVrId, makerTags, unsignedByte, 1, EXV_PRINT_TAG(nikonOnOff)), // End of list marker TagInfo(0xffff, "(UnknownNikonVrTag)", "(UnknownNikonVrTag)", N_("Unknown Nikon Vibration Reduction Tag"), nikonVrId, makerTags, unsignedByte, 1, printValue) }; const TagInfo* Nikon3MakerNote::tagListVr() { return tagInfoVr_; } //! Adjust extern const TagDetails nikonAdjust[] = { { 0, N_("Default Settings") }, { 1, N_("Quick Adjust") }, { 2, N_("Full Control") } }; //! FilterEffect extern const TagDetails nikonFilterEffect[] = { { 0x80, N_("Off") }, { 0x81, N_("Yellow") }, { 0x82, N_("Orange") }, { 0x83, N_("Red") }, { 0x84, N_("Green") }, { 0xff, N_("n/a") } }; //! ToningEffect extern const TagDetails nikonToningEffect[] = { { 0x80, N_("B&W") }, { 0x81, N_("Sepia") }, { 0x82, N_("Cyanotype") }, { 0x83, N_("Red") }, { 0x84, N_("Yellow") }, { 0x85, N_("Green") }, { 0x86, N_("Blue-green") }, { 0x87, N_("Blue") }, { 0x88, N_("Purple-blue") }, { 0x89, N_("Red-purple") }, { 0xff, N_("n/a") } }; // Nikon3 Picture Control Tag Info const TagInfo Nikon3MakerNote::tagInfoPc_[] = { TagInfo( 0, "Version", N_("Version"), N_("Version"), nikonPcId, makerTags, undefined, 4, printExifVersion), TagInfo( 4, "Name", N_("Name"), N_("Name"), nikonPcId, makerTags, asciiString, 20, printValue), TagInfo(24, "Base", N_("Base"), N_("Base"), nikonPcId, makerTags, asciiString, 20, printValue), TagInfo(48, "Adjust", N_("Adjust"), N_("Adjust"), nikonPcId, makerTags, unsignedByte, 1, EXV_PRINT_TAG(nikonAdjust)), TagInfo(49, "QuickAdjust", N_("Quick Adjust"), N_("Quick adjust"), nikonPcId, makerTags, unsignedByte, 1, printPictureControl), TagInfo(50, "Sharpness", N_("Sharpness"), N_("Sharpness"), nikonPcId, makerTags, unsignedByte, 1, printPictureControl), TagInfo(51, "Contrast", N_("Contrast"), N_("Contrast"), nikonPcId, makerTags, unsignedByte, 1, printPictureControl), TagInfo(52, "Brightness", N_("Brightness"), N_("Brightness"), nikonPcId, makerTags, unsignedByte, 1, printPictureControl), TagInfo(53, "Saturation", N_("Saturation"), N_("Saturation"), nikonPcId, makerTags, unsignedByte, 1, printPictureControl), TagInfo(54, "HueAdjustment", N_("Hue Adjustment"), N_("Hue adjustment"), nikonPcId, makerTags, unsignedByte, 1, printPictureControl), TagInfo(55, "FilterEffect", N_("Filter Effect"), N_("Filter effect"), nikonPcId, makerTags, unsignedByte, 1, EXV_PRINT_TAG(nikonFilterEffect)), TagInfo(56, "ToningEffect", N_("Toning Effect"), N_("Toning effect"), nikonPcId, makerTags, unsignedByte, 1, EXV_PRINT_TAG(nikonToningEffect)), TagInfo(57, "ToningSaturation", N_("Toning Saturation"), N_("Toning saturation"), nikonPcId, makerTags, unsignedByte, 1, printPictureControl), // End of list marker TagInfo(0xffff, "(UnknownNikonPcTag)", "(UnknownNikonPcTag)", N_("Unknown Nikon Picture Control Tag"), nikonPcId, makerTags, unsignedByte, 1, printValue) }; const TagInfo* Nikon3MakerNote::tagListPc() { return tagInfoPc_; } //! OnOff extern const TagDetails aftOnOff[] = { { 0, N_("Off") }, { 1, N_("On") }, { 2, N_("On") } }; // Nikon3 AF Fine Tune const TagInfo Nikon3MakerNote::tagInfoAFT_[] = { TagInfo(0, "AFFineTune", N_("AF Fine Tune"), N_("AF fine tune"), nikonAFTId, makerTags, unsignedByte, 1, EXV_PRINT_TAG(aftOnOff)), TagInfo(1, "AFFineTuneIndex", N_("AF Fine Tune Index"), N_("AF fine tune index"), nikonAFTId, makerTags, unsignedByte, 1, printValue), TagInfo(2, "AFFineTuneAdj", N_("AF Fine Tune Adjustment"), N_("AF fine tune adjustment"), nikonAFTId, makerTags, signedByte, 1, printValue), // End of list marker TagInfo(0xffff, "(UnknownNikonAFTTag)", "(UnknownNikonAFTTag)", N_("Unknown Nikon AF Fine Tune Tag"), nikonAFTId, makerTags, unsignedByte, 1, printValue) }; const TagInfo* Nikon3MakerNote::tagListAFT() { return tagInfoAFT_; } // Nikon3 World Time Tag Info const TagInfo Nikon3MakerNote::tagInfoWt_[] = { TagInfo(0, "Timezone", N_("Timezone"), N_("Timezone"), nikonWtId, makerTags, signedShort, 1, printTimeZone), TagInfo(2, "DaylightSavings", N_("Daylight Savings"), N_("Daylight savings"), nikonWtId, makerTags, unsignedByte, 1, EXV_PRINT_TAG(nikonYesNo)), TagInfo(3, "DateDisplayFormat", N_("Date Display Format"), N_("Date display format"), nikonWtId, makerTags, unsignedByte, 1, EXV_PRINT_TAG(nikonDateDisplayFormat)), // End of list marker TagInfo(0xffff, "(UnknownNikonWtTag)", "(UnknownNikonWtTag)", N_("Unknown Nikon World Time Tag"), nikonWtId, makerTags, unsignedByte, 1, printValue) }; const TagInfo* Nikon3MakerNote::tagListWt() { return tagInfoWt_; } //! ISOExpansion, tag index 4 and 10 extern const TagDetails nikonIsoExpansion[] = { { 0x000, N_("Off") }, { 0x101, N_("Hi 0.3") }, { 0x102, N_("Hi 0.5") }, { 0x103, N_("Hi 0.7") }, { 0x104, N_("Hi 1.0") }, { 0x105, N_("Hi 1.3") }, { 0x106, N_("Hi 1.5") }, { 0x107, N_("Hi 1.7") }, { 0x108, N_("Hi 2.0") }, { 0x201, N_("Lo 0.3") }, { 0x202, N_("Lo 0.5") }, { 0x203, N_("Lo 0.7") }, { 0x204, N_("Lo 1.0") } }; // Nikon3 ISO Info Tag Info const TagInfo Nikon3MakerNote::tagInfoIi_[] = { TagInfo( 0, "ISO", N_("ISO"), N_("ISO"), nikonIiId, makerTags, unsignedByte, 1, printIiIso), TagInfo( 4, "ISOExpansion", N_("ISO Expansion"), N_("ISO expansion"), nikonIiId, makerTags, unsignedShort, 1, EXV_PRINT_TAG(nikonIsoExpansion)), TagInfo( 6, "ISO2", N_("ISO 2"), N_("ISO 2"), nikonIiId, makerTags, unsignedByte, 1, printIiIso), TagInfo(10, "ISOExpansion2", N_("ISO Expansion 2"), N_("ISO expansion 2"), nikonIiId, makerTags, unsignedShort, 1, EXV_PRINT_TAG(nikonIsoExpansion)), // End of list marker TagInfo(0xffff, "(UnknownNikonIiTag)", "(UnknownNikonIiTag)", N_("Unknown Nikon Iso Info Tag"), nikonIiId, makerTags, unsignedByte, 1, printValue) }; const TagInfo* Nikon3MakerNote::tagListIi() { return tagInfoIi_; } //! AfAreaMode extern const TagDetails nikonAfAreaMode[] = { { 0, N_("Single Area") }, { 1, N_("Dynamic Area") }, { 2, N_("Dynamic Area, Closest Subject") }, { 3, N_("Group Dynamic") }, { 4, N_("Single Area (wide)") }, { 5, N_("Dynamic Area (wide)") } }; //! AfPoint extern const TagDetails nikonAfPoint[] = { { 0, N_("Center") }, { 1, N_("Top") }, { 2, N_("Bottom") }, { 3, N_("Mid-left") }, { 4, N_("Mid-right") }, { 5, N_("Upper-left") }, { 6, N_("Upper-right") }, { 7, N_("Lower-left") }, { 8, N_("Lower-right") }, { 9, N_("Far Left") }, { 10, N_("Far Right") } }; //! AfPointsInFocus extern const TagDetailsBitmask nikonAfPointsInFocus[] = { { 0x0001, N_("Center") }, { 0x0002, N_("Top") }, { 0x0004, N_("Bottom") }, { 0x0008, N_("Mid-left") }, { 0x0010, N_("Mid-right") }, { 0x0020, N_("Upper-left") }, { 0x0040, N_("Upper-right") }, { 0x0080, N_("Lower-left") }, { 0x0100, N_("Lower-right") }, { 0x0200, N_("Far Left") }, { 0x0400, N_("Far Right") } }; // Nikon3 Auto Focus Tag Info const TagInfo Nikon3MakerNote::tagInfoAf_[] = { TagInfo( 0, "AFAreaMode", N_("AF Area Mode"), N_("AF area mode"), nikonAfId, makerTags, unsignedByte, 1, EXV_PRINT_TAG(nikonAfAreaMode)), TagInfo( 1, "AFPoint", N_("AF Point"), N_("AF point"), nikonAfId, makerTags, unsignedByte, 1, EXV_PRINT_TAG(nikonAfPoint)), TagInfo( 2, "AFPointsInFocus", N_("AF Points In Focus"), N_("AF points in focus"), nikonAfId, makerTags, unsignedShort, 1, printAfPointsInFocus), // End of list marker TagInfo(0xffff, "(UnknownNikonAfTag)", "(UnknownNikonAfTag)", N_("Unknown Nikon Auto Focus Tag"), nikonAfId, makerTags, unsignedByte, 1, printValue) }; const TagInfo* Nikon3MakerNote::tagListAf() { return tagInfoAf_; } //! PhaseDetectAF extern const TagDetails nikonPhaseDetectAF[] = { { 0, N_("Off") }, { 1, N_("On (51-point)") }, { 2, N_("On (11-point)") } }; // Nikon3 Auto Focus Tag Info const TagInfo Nikon3MakerNote::tagInfoAf2_[] = { TagInfo( 0, "Version", N_("Version"), N_("Version"), nikonAf2Id, makerTags, undefined, 4, printExifVersion), TagInfo( 4, "ContrastDetectAF", N_("Contrast Detect AF"), N_("Contrast detect AF"), nikonAf2Id, makerTags, unsignedByte, 1, EXV_PRINT_TAG(nikonOffOn)), TagInfo( 5, "AFAreaMode", N_("AF Area Mode"), N_("AF area mode"), nikonAf2Id, makerTags, unsignedByte, 1, printValue), TagInfo( 6, "PhaseDetectAF", N_("Phase Detect AF"), N_("Phase detect AF"), nikonAf2Id, makerTags, unsignedByte, 1, EXV_PRINT_TAG(nikonPhaseDetectAF)), TagInfo( 7, "PrimaryAFPoint", N_("Primary AF Point"), N_("Primary AF point"), nikonAf2Id, makerTags, unsignedByte, 1, printValue), TagInfo( 8, "AFPointsUsed", N_("AF Points Used"), N_("AF points used"), nikonAf2Id, makerTags, unsignedByte, 7, printValue), TagInfo( 16, "AFImageWidth", N_("AF Image Width"), N_("AF image width"), nikonAf2Id, makerTags, unsignedShort, 1, printValue), TagInfo( 18, "AFImageHeight", N_("AF Image Height"), N_("AF image height"), nikonAf2Id, makerTags, unsignedShort, 1, printValue), TagInfo( 20, "AFAreaXPosition", N_("AF Area X Position"), N_("AF area x position"), nikonAf2Id, makerTags, unsignedShort, 1, printValue), TagInfo( 22, "AFAreaYPosition", N_("AF Area Y Position"), N_("AF area y position"), nikonAf2Id, makerTags, unsignedShort, 1, printValue), TagInfo( 24, "AFAreaWidth", N_("AF Area Width"), N_("AF area width"), nikonAf2Id, makerTags, unsignedShort, 1, printValue), TagInfo( 26, "AFAreaHeight", N_("AF Area Height"), N_("AF area height"), nikonAf2Id, makerTags, unsignedShort, 1, printValue), TagInfo( 28, "ContrastDetectAFInFocus", N_("Contrast Detect AF In Focus"), N_("Contrast detect AF in focus"), nikonAf2Id, makerTags, unsignedShort, 1, printValue), // End of list marker TagInfo(0xffff, "(UnknownNikonAf2Tag)", "(UnknownNikonAf2Tag)", N_("Unknown Nikon Auto Focus 2 Tag"), nikonAf2Id, makerTags, unsignedByte, 1, printValue) }; const TagInfo* Nikon3MakerNote::tagListAf2() { return tagInfoAf2_; } // Nikon3 File Info Tag Info const TagInfo Nikon3MakerNote::tagInfoFi_[] = { TagInfo( 0, "Version", N_("Version"), N_("Version"), nikonFiId, makerTags, undefined, 4, printExifVersion), TagInfo( 6, "DirectoryNumber", N_("Directory Number"), N_("Directory number"), nikonFiId, makerTags, unsignedShort, 1, printValue), TagInfo( 8, "FileNumber", N_("File Number"), N_("File number"), nikonFiId, makerTags, unsignedShort, 1, printValue), // End of list marker TagInfo(0xffff, "(UnknownNikonFiTag)", "(UnknownNikonFiTag)", N_("Unknown Nikon File Info Tag"), nikonFiId, makerTags, unsignedByte, 1, printValue) }; const TagInfo* Nikon3MakerNote::tagListFi() { return tagInfoFi_; } //! MultiExposureMode extern const TagDetails nikonMultiExposureMode[] = { { 0, N_("Off") }, { 1, N_("Multiple Exposure") }, { 2, N_("Image Overlay") } }; // Nikon3 Multi Exposure Tag Info const TagInfo Nikon3MakerNote::tagInfoMe_[] = { TagInfo( 0, "Version", N_("Version"), N_("Version"), nikonMeId, makerTags, undefined, 4, printExifVersion), TagInfo( 4, "MultiExposureMode", N_("Multi Exposure Mode"), N_("Multi exposure mode"), nikonMeId, makerTags, unsignedLong, 1, EXV_PRINT_TAG(nikonMultiExposureMode)), TagInfo( 8, "MultiExposureShots", N_("Multi Exposure Shots"), N_("Multi exposure shots"), nikonMeId, makerTags, unsignedLong, 1, printValue), TagInfo( 12, "MultiExposureAutoGain", N_("Multi Exposure Auto Gain"), N_("Multi exposure auto gain"), nikonMeId, makerTags, unsignedLong, 1, EXV_PRINT_TAG(nikonOffOn)), // End of list marker TagInfo(0xffff, "(UnknownNikonMeTag)", "(UnknownNikonMeTag)", N_("Unknown Nikon Multi Exposure Tag"), nikonMeId, makerTags, unsignedByte, 1, printValue) }; const TagInfo* Nikon3MakerNote::tagListMe() { return tagInfoMe_; } //! FlashSource extern const TagDetails nikonFlashSource[] = { { 0, N_("None") }, { 1, N_("External") }, { 2, N_("Internal") } }; //! FlashFirmware extern const TagDetails nikonFlashFirmware[] = { { 0x0000, N_("n/a") }, { 0x0101, N_("1.01 (SB-800 or Metz 58 AF-1)") }, { 0x0103, N_("1.03 (SB-800)") }, { 0x0201, N_("2.01 (SB-800)") }, { 0x0204, N_("2.04 (SB-600)") }, { 0x0205, N_("2.05 (SB-600)") }, { 0x0301, N_("3.01 (SU-800 Remote Commander)") }, { 0x0401, N_("4.01 (SB-400)") }, { 0x0402, N_("4.02 (SB-400)") }, { 0x0404, N_("4.04 (SB-400)") }, { 0x0501, N_("5.01 (SB-900)") }, { 0x0502, N_("5.02 (SB-900)") } }; //! FlashGNDistance extern const TagDetails nikonFlashGNDistance[] = { { 0, N_("None") }, { 1, N_("0.1 m") }, { 2, N_("0.2 m") }, { 3, N_("0.3 m") }, { 4, N_("0.4 m") }, { 5, N_("0.5 m") }, { 6, N_("0.6 m") }, { 7, N_("0.7 m") }, { 8, N_("0.8 m") }, { 9, N_("0.9 m") }, { 10, N_("1.0 m") }, { 11, N_("1.1 m") }, { 12, N_("1.3 m") }, { 13, N_("1.4 m") }, { 14, N_("1.6 m") }, { 15, N_("1.8 m") }, { 16, N_("2.0 m") }, { 17, N_("2.2 m") }, { 18, N_("2.5 m") }, { 19, N_("2.8 m") }, { 20, N_("3.2 m") }, { 21, N_("3.6 m") }, { 22, N_("4.0 m") }, { 23, N_("4.5 m") }, { 24, N_("5.0 m") }, { 25, N_("5.6 m") }, { 26, N_("6.3 m") }, { 27, N_("7.1 m") }, { 28, N_("8.0 m") }, { 29, N_("9.0 m") }, { 30, N_("10.0 m") }, { 31, N_("11.0 m") }, { 32, N_("13.0 m") }, { 33, N_("14.0 m") }, { 34, N_("16.0 m") }, { 35, N_("18.0 m") }, { 36, N_("20.0 m") }, { 255, N_("n/a") } }; //! FlashControlMode extern const TagDetails nikonFlashControlMode[] = { { 0, N_("Off") }, { 1, N_("iTTL-BL") }, { 2, N_("iTTL") }, { 3, N_("Auto Aperture") }, { 4, N_("Automatic") }, { 5, N_("GN (distance priority)") }, { 6, N_("Manual") }, { 7, N_("Repeating Flash") }, { 7, N_("Repeating Flash") } // To silence compiler warning }; //! ExternalFlashFlags extern const TagDetails nikonExternalFlashFlags[] = { { 0, N_("Fired") }, { 2, N_("Bounce Flash") }, { 4, N_("Wide Flash Adapter") } }; //! FlashColorFilter extern const TagDetails nikonFlashColorFilter[] = { { 0, N_("None") }, { 1, N_("FL-GL1") }, { 2, N_("FL-GL2") }, { 9, N_("TN-A1") }, { 10, N_("TN-A2") }, { 65, N_("Red") }, { 66, N_("Blue") }, { 67, N_("Yellow") }, { 68, N_("Amber") } }; // Nikon3 Flash Info 1 Tag Info const TagInfo Nikon3MakerNote::tagInfoFl1_[] = { TagInfo( 0, "Version", N_("Version"), N_("Version"), nikonFl1Id, makerTags, undefined, 4, printExifVersion), TagInfo( 4, "FlashSource", N_("Flash Source"), N_("Flash source"), nikonFl1Id, makerTags, unsignedByte, 1, EXV_PRINT_TAG(nikonFlashSource)), TagInfo( 5, "0x0005", N_("0x0005"), N_("Unknown"), nikonFl1Id, makerTags, unsignedByte, 1, printValue), TagInfo( 6, "ExternalFlashFirmware", N_("External Flash Firmware"), N_("External flash firmware"), nikonFl1Id, makerTags, unsignedShort, 1, EXV_PRINT_TAG(nikonFlashFirmware)), TagInfo( 8, "ExternalFlashFlags", N_("External Flash Flags"), N_("External flash flags"), nikonFl1Id, makerTags, unsignedByte, 1, EXV_PRINT_TAG(nikonExternalFlashFlags)), TagInfo( 11, "FlashFocalLength", N_("Flash Focal Length"), N_("Flash focal length"), nikonFl1Id, makerTags, unsignedByte, 1, printFlashFocalLength), TagInfo( 12, "RepeatingFlashRate", N_("Repeating Flash Rate"), N_("Repeating flash rate"), nikonFl1Id, makerTags, unsignedByte, 1, printRepeatingFlashRate), TagInfo( 13, "RepeatingFlashCount", N_("Repeating Flash Count"), N_("Repeating flash count"), nikonFl1Id, makerTags, unsignedByte, 1, printRepeatingFlashCount), TagInfo( 14, "FlashGNDistance", N_("Flash GN Distance"), N_("Flash GN distance"), nikonFl1Id, makerTags, unsignedByte, 1, EXV_PRINT_TAG(nikonFlashGNDistance)), TagInfo( 15, "FlashGroupAControlMode", N_("Flash Group A Control Mode"), N_("Flash group a control mode"), nikonFl1Id, makerTags, unsignedByte, 1, EXV_PRINT_TAG(nikonFlashControlMode)), TagInfo( 16, "FlashGroupBControlMode", N_("Flash Group B Control Mode"), N_("Flash group b control mode"), nikonFl1Id, makerTags, unsignedByte, 1, EXV_PRINT_TAG(nikonFlashControlMode)), // End of list marker TagInfo(0xffff, "(UnknownNikonMeTag)", "(UnknownNikonMeTag)", N_("Unknown Nikon Multi Exposure Tag"), nikonFl1Id, makerTags, unsignedByte, 1, printValue) }; const TagInfo* Nikon3MakerNote::tagListFl1() { return tagInfoFl1_; } // Nikon3 Flash Info 2 Tag Info const TagInfo Nikon3MakerNote::tagInfoFl2_[] = { TagInfo( 0, "Version", N_("Version"), N_("Version"), nikonFl2Id, makerTags, undefined, 4, printExifVersion), TagInfo( 4, "FlashSource", N_("Flash Source"), N_("Flash source"), nikonFl2Id, makerTags, unsignedByte, 1, EXV_PRINT_TAG(nikonFlashSource)), TagInfo( 5, "0x0005", N_("0x0005"), N_("Unknown"), nikonFl2Id, makerTags, unsignedByte, 1, printValue), TagInfo( 6, "ExternalFlashFirmware", N_("External Flash Firmware"), N_("External flash firmware"), nikonFl2Id, makerTags, unsignedShort, 1, EXV_PRINT_TAG(nikonFlashFirmware)), TagInfo( 8, "ExternalFlashFlags", N_("External Flash Flags"), N_("External flash flags"), nikonFl2Id, makerTags, unsignedByte, 1, EXV_PRINT_TAG(nikonExternalFlashFlags)), TagInfo( 12, "FlashFocalLength", N_("Flash Focal Length"), N_("Flash focal length"), nikonFl2Id, makerTags, unsignedByte, 1, printFlashFocalLength), TagInfo( 13, "RepeatingFlashRate", N_("Repeating Flash Rate"), N_("Repeating flash rate"), nikonFl2Id, makerTags, unsignedByte, 1, printRepeatingFlashRate), TagInfo( 14, "RepeatingFlashCount", N_("Repeating Flash Count"), N_("Repeating flash count"), nikonFl2Id, makerTags, unsignedByte, 1, printRepeatingFlashCount), TagInfo( 15, "FlashGNDistance", N_("Flash GN Distance"), N_("Flash GN distance"), nikonFl2Id, makerTags, unsignedByte, 1, EXV_PRINT_TAG(nikonFlashGNDistance)), // End of list marker TagInfo(0xffff, "(UnknownNikonMeTag)", "(UnknownNikonMeTag)", N_("Unknown Nikon Multi Exposure Tag"), nikonFl2Id, makerTags, unsignedByte, 1, printValue) }; const TagInfo* Nikon3MakerNote::tagListFl2() { return tagInfoFl2_; } // Nikon3 Flash Info 3 Tag Info const TagInfo Nikon3MakerNote::tagInfoFl3_[] = { TagInfo( 0, "Version", N_("Version"), N_("Version"), nikonFl3Id, makerTags, undefined, 4, printExifVersion), TagInfo( 4, "FlashSource", N_("Flash Source"), N_("Flash source"), nikonFl3Id, makerTags, unsignedByte, 1, EXV_PRINT_TAG(nikonFlashSource)), TagInfo( 6, "ExternalFlashFirmware", N_("External Flash Firmware"), N_("External flash firmware"), nikonFl3Id, makerTags, unsignedShort, 1, EXV_PRINT_TAG(nikonFlashFirmware)), TagInfo( 8, "ExternalFlashFlags", N_("External Flash Flags"), N_("External flash flags"), nikonFl3Id, makerTags, unsignedByte, 1, EXV_PRINT_TAG(nikonExternalFlashFlags)), TagInfo( 12, "FlashFocalLength", N_("Flash Focal Length"), N_("Flash focal length"), nikonFl3Id, makerTags, unsignedByte, 1, printFlashFocalLength), TagInfo( 13, "RepeatingFlashRate", N_("Repeating Flash Rate"), N_("Repeating flash rate"), nikonFl3Id, makerTags, unsignedByte, 1, printRepeatingFlashRate), TagInfo( 14, "RepeatingFlashCount", N_("Repeating Flash Count"), N_("Repeating flash count"), nikonFl3Id, makerTags, unsignedByte, 1, printRepeatingFlashCount), TagInfo( 15, "FlashGNDistance", N_("Flash GN Distance"), N_("Flash GN distance"), nikonFl3Id, makerTags, unsignedByte, 1, EXV_PRINT_TAG(nikonFlashGNDistance)), TagInfo( 16, "FlashColorFilter", N_("Flash Color Filter"), N_("Flash color filter"), nikonFl3Id, makerTags, unsignedByte, 1, EXV_PRINT_TAG(nikonFlashColorFilter)), // End of list marker TagInfo(0xffff, "(UnknownNikonMeTag)", "(UnknownNikonMeTag)", N_("Unknown Nikon Multi Exposure Tag"), nikonFl3Id, makerTags, unsignedByte, 1, printValue) }; const TagInfo* Nikon3MakerNote::tagListFl3() { return tagInfoFl3_; } // Nikon3 Shot Info D80 Tag Info const TagInfo Nikon3MakerNote::tagInfoSi1_[] = { TagInfo( 0, "Version", N_("Version"), N_("Version"), nikonSi1Id, makerTags, unsignedByte, 4, printExifVersion), TagInfo( 586, "ShutterCount", N_("Shutter Count"), N_("Shutter count"), nikonSi1Id, makerTags, unsignedLong, 1, printValue), // End of list marker TagInfo(0xffff, "(UnknownNikonSi1Tag)", "(UnknownNikonSi1Tag)", N_("Unknown Nikon Shot Info D80 Tag"), nikonSi1Id, makerTags, unsignedByte, 1, printValue) }; const TagInfo* Nikon3MakerNote::tagListSi1() { return tagInfoSi1_; } // Nikon3 Shot Info D40 Tag Info const TagInfo Nikon3MakerNote::tagInfoSi2_[] = { TagInfo( 0, "Version", N_("Version"), N_("Version"), nikonSi2Id, makerTags, unsignedByte, 4, printExifVersion), TagInfo( 582, "ShutterCount", N_("Shutter Count"), N_("Shutter count"), nikonSi2Id, makerTags, unsignedLong, 1, printValue), TagInfo( 738, "FlashLevel", N_("Flash Level"), N_("Flash level"), nikonSi2Id, makerTags, unsignedByte, 1, printValue), // End of list marker TagInfo(0xffff, "(UnknownNikonSi2Tag)", "(UnknownNikonSi2Tag)", N_("Unknown Nikon Shot Info D40 Tag"), nikonSi2Id, makerTags, unsignedByte, 1, printValue) }; const TagInfo* Nikon3MakerNote::tagListSi2() { return tagInfoSi2_; } //! AfFineTuneAdj D300 (a) extern const TagDetails nikonAfFineTuneAdj1[] = { { 0x0000, N_("0") }, { 0x003a, N_("+1") }, { 0x003b, N_("+2") }, { 0x003c, N_("+4") }, { 0x003d, N_("+8") }, { 0x003e, N_("+16") }, { 0x00c2, N_("-16") }, { 0x00c3, N_("-8") }, { 0x00c4, N_("-4") }, { 0x00c5, N_("-2") }, { 0x00c6, N_("-1") }, { 0x103e, N_("+17") }, { 0x10c2, N_("-17") }, { 0x203d, N_("+9") }, { 0x203e, N_("+18") }, { 0x20c2, N_("-18") }, { 0x20c3, N_("-9") }, { 0x303e, N_("+19") }, { 0x30c2, N_("-19") }, { 0x403c, N_("+5") }, { 0x403d, N_("+10") }, { 0x403e, N_("+20") }, { 0x40c2, N_("-20") }, { 0x40c3, N_("-10") }, { 0x40c4, N_("-5") }, { 0x603d, N_("+11") }, { 0x60c3, N_("-11") }, { 0x803b, N_("+3") }, { 0x803c, N_("+6") }, { 0x803d, N_("+12") }, { 0x80c3, N_("-12") }, { 0x80c4, N_("-6") }, { 0x80c5, N_("-3") }, { 0xa03d, N_("+13") }, { 0xa0c3, N_("-13") }, { 0xc03c, N_("+7") }, { 0xc03d, N_("+14") }, { 0xc0c3, N_("-14") }, { 0xc0c4, N_("-7") }, { 0xe03d, N_("+15") }, { 0xe0c3, N_("-15") } }; // Nikon3 Shot Info D300 (a) Tag Info const TagInfo Nikon3MakerNote::tagInfoSi3_[] = { TagInfo( 0, "Version", N_("Version"), N_("Version"), nikonSi3Id, makerTags, unsignedByte, 4, printExifVersion), TagInfo( 604, "ISO", N_("ISO"), N_("ISO"), nikonSi3Id, makerTags, unsignedByte, 1, printIiIso), TagInfo( 633, "ShutterCount", N_("Shutter Count"), N_("Shutter count"), nikonSi3Id, makerTags, unsignedLong, 1, printValue), TagInfo( 721, "AFFineTuneAdj", N_("AF Fine Tune Adj"), N_("AF fine tune adj"), nikonSi3Id, makerTags, unsignedShort, 1, EXV_PRINT_TAG(nikonAfFineTuneAdj1)), // End of list marker TagInfo(0xffff, "(UnknownNikonSi3Tag)", "(UnknownNikonSi3Tag)", N_("Unknown Nikon Shot Info D300 (a) Tag"), nikonSi3Id, makerTags, unsignedByte, 1, printValue) }; const TagInfo* Nikon3MakerNote::tagListSi3() { return tagInfoSi3_; } //! AfFineTuneAdj D300 (b) extern const TagDetails nikonAfFineTuneAdj2[] = { { 0x0000, N_("0") }, { 0x043e, N_("+13") }, { 0x04c2, N_("-13") }, { 0x183d, N_("+7") }, { 0x183e, N_("+14") }, { 0x18c2, N_("-14") }, { 0x18c3, N_("-7") }, { 0x2c3e, N_("+15") }, { 0x2cc2, N_("-15") }, { 0x403a, N_("+1") }, { 0x403b, N_("+2") }, { 0x403c, N_("+4") }, { 0x403d, N_("+8") }, { 0x403e, N_("+16") }, { 0x40c2, N_("-16") }, { 0x40c3, N_("-8") }, { 0x40c4, N_("-4") }, { 0x40c5, N_("-2") }, { 0x40c6, N_("-1") }, { 0x543e, N_("+17") }, { 0x54c2, N_("-17") }, { 0x683d, N_("+9") }, { 0x683e, N_("+18") }, { 0x68c2, N_("-18") }, { 0x68c3, N_("-9") }, { 0x7c3e, N_("+19") }, { 0x7cc2, N_("-19") }, { 0x903c, N_("+5") }, { 0x903d, N_("+10") }, { 0x903e, N_("+20") }, { 0x90c2, N_("-20") }, { 0x90c3, N_("-10") }, { 0x90c4, N_("-5") }, { 0xb83d, N_("+11") }, { 0xb8c3, N_("-11") }, { 0xe03b, N_("+3") }, { 0xe03c, N_("+6") }, { 0xe03d, N_("+12") }, { 0xe0c3, N_("-12") }, { 0xe0c4, N_("-6") }, { 0xe0c5, N_("-3") } }; // Nikon3 Shot Info D300 (b) Tag Info const TagInfo Nikon3MakerNote::tagInfoSi4_[] = { TagInfo( 0, "Version", N_("Version"), N_("Version"), nikonSi4Id, makerTags, unsignedByte, 4, printExifVersion), TagInfo( 613, "ISO", N_("ISO"), N_("ISO"), nikonSi4Id, makerTags, unsignedByte, 1, printIiIso), TagInfo( 644, "ShutterCount", N_("Shutter Count"), N_("Shutter count"), nikonSi4Id, makerTags, unsignedLong, 1, printValue), TagInfo( 732, "AFFineTuneAdj", N_("AF Fine Tune Adj"), N_("AF fine tune adj"), nikonSi4Id, makerTags, unsignedShort, 1, EXV_PRINT_TAG(nikonAfFineTuneAdj2)), // End of list marker TagInfo(0xffff, "(UnknownNikonSi4Tag)", "(UnknownNikonSi4Tag)", N_("Unknown Nikon Shot Info D300 (b) Tag"), nikonSi4Id, makerTags, unsignedByte, 1, printValue) }; const TagInfo* Nikon3MakerNote::tagListSi4() { return tagInfoSi4_; } //! VibrationReduction extern const TagDetails nikonOffOn2[] = { { 0, N_("Off") }, { 1, N_("On (1)") }, { 2, N_("On (2)") }, { 3, N_("On (3)") } }; //! VibrationReduction2 extern const TagDetails nikonOffOn3[] = { { 0x0, N_("n/a") }, { 0xc, N_("Off") }, { 0xf, N_("On") } }; // Nikon3 Shot Info Tag Info const TagInfo Nikon3MakerNote::tagInfoSi5_[] = { TagInfo( 0, "Version", N_("Version"), N_("Version"), nikonSi5Id, makerTags, unsignedByte, 4, printExifVersion), TagInfo( 106, "ShutterCount1", N_("Shutter Count 1"), N_("Shutter count 1"), nikonSi5Id, makerTags, unsignedLong, 1, printValue), TagInfo( 110, "DeletedImageCount", N_("Deleted Image Count"), N_("Deleted image count"), nikonSi5Id, makerTags, unsignedLong, 1, printValue), TagInfo( 117, "VibrationReduction", N_("Vibration Reduction"), N_("Vibration reduction"), nikonSi5Id, makerTags, unsignedByte, 1, EXV_PRINT_TAG(nikonOffOn2)), TagInfo( 130, "VibrationReduction1", N_("Vibration Reduction 1"), N_("Vibration reduction 1"), nikonSi5Id, makerTags, unsignedByte, 1, EXV_PRINT_TAG(nikonOffOn)), TagInfo( 343, "ShutterCount2", N_("Shutter Count 2"), N_("Shutter count 2"), nikonSi5Id, makerTags, undefined, 2, printValue), TagInfo( 430, "VibrationReduction2", N_("Vibration Reduction 2"), N_("Vibration reduction 2"), nikonSi5Id, makerTags, unsignedByte, 1, EXV_PRINT_TAG(nikonOffOn3)), TagInfo( 598, "ISO", N_("ISO"), N_("ISO"), nikonSi5Id, makerTags, unsignedByte, 1, printIiIso), TagInfo( 630, "ShutterCount", N_("Shutter Count"), N_("Shutter count"), nikonSi5Id, makerTags, unsignedLong, 1, printValue), // End of list marker TagInfo(0xffff, "(UnknownNikonSi5Tag)", "(UnknownNikonSi5Tag)", N_("Unknown Nikon Shot Info Tag"), nikonSi5Id, makerTags, unsignedByte, 1, printValue) }; const TagInfo* Nikon3MakerNote::tagListSi5() { return tagInfoSi5_; } // Nikon3 Color Balance 1 Tag Info const TagInfo Nikon3MakerNote::tagInfoCb1_[] = { TagInfo( 0, "Version", N_("Version"), N_("Version"), nikonCb1Id, makerTags, undefined, 4, printExifVersion), TagInfo(36, "WB_RBGGLevels", N_("WB RBGG Levels"), N_("WB RBGG levels"), nikonCb1Id, makerTags, unsignedShort, 4, printValue), // End of list marker TagInfo(0xffff, "(UnknownNikonCb1Tag)", "(UnknownNikonCb1Tag)", N_("Unknown Nikon Color Balance 1 Tag"), nikonCb1Id, makerTags, unsignedShort, 1, printValue) }; const TagInfo* Nikon3MakerNote::tagListCb1() { return tagInfoCb1_; } // Nikon3 Color Balance 2 Tag Info const TagInfo Nikon3MakerNote::tagInfoCb2_[] = { TagInfo( 0, "Version", N_("Version"), N_("Version"), nikonCb2Id, makerTags, undefined, 4, printExifVersion), TagInfo( 5, "WB_RGGBLevels", N_("WB RGGB Levels"), N_("WB RGGB levels"), nikonCb2Id, makerTags, unsignedShort, 4, printValue), // End of list marker TagInfo(0xffff, "(UnknownNikonCb2Tag)", "(UnknownNikonCb2Tag)", N_("Unknown Nikon Color Balance 2 Tag"), nikonCb2Id, makerTags, unsignedShort, 1, printValue) }; const TagInfo* Nikon3MakerNote::tagListCb2() { return tagInfoCb2_; } // Nikon3 Color Balance 2a Tag Info const TagInfo Nikon3MakerNote::tagInfoCb2a_[] = { TagInfo( 0, "Version", N_("Version"), N_("Version"), nikonCb2aId, makerTags, undefined, 4, printExifVersion), TagInfo( 9, "WB_RGGBLevels", N_("WB RGGB Levels"), N_("WB RGGB levels"), nikonCb2aId, makerTags, unsignedShort, 4, printValue), // End of list marker TagInfo(0xffff, "(UnknownNikonCb2aTag)", "(UnknownNikonCb2aTag)", N_("Unknown Nikon Color Balance 2a Tag"), nikonCb2aId, makerTags, unsignedShort, 1, printValue) }; const TagInfo* Nikon3MakerNote::tagListCb2a() { return tagInfoCb2a_; } // Nikon3 Color Balance 2b Tag Info const TagInfo Nikon3MakerNote::tagInfoCb2b_[] = { TagInfo( 0, "Version", N_("Version"), N_("Version"), nikonCb2bId, makerTags, undefined, 4, printExifVersion), TagInfo(145, "WB_RGGBLevels", N_("WB RGGB Levels"), N_("WB RGGB levels"), nikonCb2bId, makerTags, unsignedShort, 4, printValue), // End of list marker TagInfo(0xffff, "(UnknownNikonCb2bTag)", "(UnknownNikonCb2bTag)", N_("Unknown Nikon Color Balance 2b Tag"), nikonCb2bId, makerTags, unsignedShort, 1, printValue) }; const TagInfo* Nikon3MakerNote::tagListCb2b() { return tagInfoCb2b_; } // Nikon3 Color Balance 3 Tag Info const TagInfo Nikon3MakerNote::tagInfoCb3_[] = { TagInfo( 0, "Version", N_("Version"), N_("Version"), nikonCb3Id, makerTags, undefined, 4, printExifVersion), TagInfo(10, "WB_RGBGLevels", N_("WB RGBG Levels"), N_("WB RGBG levels"), nikonCb3Id, makerTags, unsignedShort, 4, printValue), // End of list marker TagInfo(0xffff, "(UnknownNikonCb3Tag)", "(UnknownNikonCb3Tag)", N_("Unknown Nikon Color Balance 3 Tag"), nikonCb3Id, makerTags, unsignedShort, 1, printValue) }; const TagInfo* Nikon3MakerNote::tagListCb3() { return tagInfoCb3_; } // Nikon3 Color Balance 4 Tag Info const TagInfo Nikon3MakerNote::tagInfoCb4_[] = { TagInfo( 0, "Version", N_("Version"), N_("Version"), nikonCb4Id, makerTags, undefined, 4, printExifVersion), TagInfo(147, "WB_GRBGLevels", N_("WB GRBG Levels"), N_("WB GRBG levels"), nikonCb4Id, makerTags, unsignedShort, 4, printValue), // End of list marker TagInfo(0xffff, "(UnknownNikonCb4Tag)", "(UnknownNikonCb4Tag)", N_("Unknown Nikon Color Balance 4 Tag"), nikonCb4Id, makerTags, unsignedShort, 1, printValue) }; const TagInfo* Nikon3MakerNote::tagListCb4() { return tagInfoCb4_; } // Nikon3 Lens Data 1 Tag Info const TagInfo Nikon3MakerNote::tagInfoLd1_[] = { TagInfo( 0, "Version", N_("Version"), N_("Version"), nikonLd1Id, makerTags, undefined, 4, printExifVersion), TagInfo( 6, "LensIDNumber", N_("Lens ID Number"), N_("Lens ID number"), nikonLd1Id, makerTags, unsignedByte, 1, printLensId1), TagInfo( 7, "LensFStops", N_("Lens F-Stops"), N_("Lens F-stops"), nikonLd1Id, makerTags, unsignedByte, 1, printFStops), TagInfo( 8, "MinFocalLength", N_("Min Focal Length"), N_("Min focal length"), nikonLd1Id, makerTags, unsignedByte, 1, printFocal), TagInfo( 9, "MaxFocalLength", N_("Max Focal Length"), N_("Max focal length"), nikonLd1Id, makerTags, unsignedByte, 1, printFocal), TagInfo(10, "MaxApertureAtMinFocal", N_("Max Aperture At Min Focal"), N_("Max aperture at min focal"), nikonLd1Id, makerTags, unsignedByte, 1, printAperture), TagInfo(11, "MaxApertureAtMaxFocal", N_("Max Aperture At Max Focal"), N_("Max aperture at max focal"), nikonLd1Id, makerTags, unsignedByte, 1, printAperture), TagInfo(12, "MCUVersion", N_("MCU Version"), N_("MCU version"), nikonLd1Id, makerTags, unsignedByte, 1, printValue), // End of list marker TagInfo(0xffff, "(UnknownNikonLd1Tag)", "(UnknownNikonLd1Tag)", N_("Unknown Nikon Lens Data 1 Tag"), nikonLd1Id, makerTags, unsignedByte, 1, printValue) }; const TagInfo* Nikon3MakerNote::tagListLd1() { return tagInfoLd1_; } // Nikon3 Lens Data 2 Tag Info const TagInfo Nikon3MakerNote::tagInfoLd2_[] = { TagInfo( 0, "Version", N_("Version"), N_("Version"), nikonLd2Id, makerTags, undefined, 4, printExifVersion), TagInfo( 4, "ExitPupilPosition", N_("Exit Pupil Position"), N_("Exit pupil position"), nikonLd2Id, makerTags, unsignedByte, 1, printExitPupilPosition), TagInfo( 5, "AFAperture", N_("AF Aperture"), N_("AF aperture"), nikonLd2Id, makerTags, unsignedByte, 1, printAperture), TagInfo( 8, "FocusPosition", N_("Focus Position"), N_("Focus position"), nikonLd2Id, makerTags, unsignedByte, 1, printValue), TagInfo( 9, "FocusDistance", N_("Focus Distance"), N_("Focus distance"), nikonLd2Id, makerTags, unsignedByte, 1, printFocusDistance), TagInfo(10, "FocalLength", N_("Focal Length"), N_("Focal length"), nikonLd2Id, makerTags, unsignedByte, 1, printFocal), TagInfo(11, "LensIDNumber", N_("Lens ID Number"), N_("Lens ID number"), nikonLd2Id, makerTags, unsignedByte, 1, printLensId2), TagInfo(12, "LensFStops", N_("Lens F-Stops"), N_("Lens F-stops"), nikonLd2Id, makerTags, unsignedByte, 1, printFStops), TagInfo(13, "MinFocalLength", N_("Min Focal Length"), N_("Min focal length"), nikonLd2Id, makerTags, unsignedByte, 1, printFocal), TagInfo(14, "MaxFocalLength", N_("Max Focal Length"), N_("Max focal length"), nikonLd2Id, makerTags, unsignedByte, 1, printFocal), TagInfo(15, "MaxApertureAtMinFocal", N_("Max Aperture At Min Focal"), N_("Max aperture at min focal"), nikonLd2Id, makerTags, unsignedByte, 1, printAperture), TagInfo(16, "MaxApertureAtMaxFocal", N_("Max Aperture At Max Focal"), N_("Max aperture at max focal"), nikonLd2Id, makerTags, unsignedByte, 1, printAperture), TagInfo(17, "MCUVersion", N_("MCU Version"), N_("MCU version"), nikonLd2Id, makerTags, unsignedByte, 1, printValue), TagInfo(18, "EffectiveMaxAperture", N_("Effective Max Aperture"), N_("Effective max aperture"), nikonLd2Id, makerTags, unsignedByte, 1, printAperture), // End of list marker TagInfo(0xffff, "(UnknownNikonLd2Tag)", "(UnknownNikonLd2Tag)", N_("Unknown Nikon Lens Data 2 Tag"), nikonLd2Id, makerTags, unsignedByte, 1, printValue) }; const TagInfo* Nikon3MakerNote::tagListLd2() { return tagInfoLd2_; } // Nikon3 Lens Data 3 Tag Info const TagInfo Nikon3MakerNote::tagInfoLd3_[] = { TagInfo( 0, "Version", N_("Version"), N_("Version"), nikonLd3Id, makerTags, undefined, 4, printExifVersion), TagInfo( 4, "ExitPupilPosition", N_("Exit Pupil Position"), N_("Exit pupil position"), nikonLd3Id, makerTags, unsignedByte, 1, printExitPupilPosition), TagInfo( 5, "AFAperture", N_("AF Aperture"), N_("AF aperture"), nikonLd3Id, makerTags, unsignedByte, 1, printAperture), TagInfo( 8, "FocusPosition", N_("Focus Position"), N_("Focus position"), nikonLd3Id, makerTags, unsignedByte, 1, printValue), TagInfo(10, "FocusDistance", N_("Focus Distance"), N_("Focus distance"), nikonLd3Id, makerTags, unsignedByte, 1, printFocusDistance), TagInfo(11, "FocalLength", N_("Focal Length"), N_("Focal length"), nikonLd3Id, makerTags, unsignedByte, 1, printFocal), TagInfo(12, "LensIDNumber", N_("Lens ID Number"), N_("Lens ID number"), nikonLd3Id, makerTags, unsignedByte, 1, printLensId3), TagInfo(13, "LensFStops", N_("Lens F-Stops"), N_("Lens F-stops"), nikonLd3Id, makerTags, unsignedByte, 1, printFStops), TagInfo(14, "MinFocalLength", N_("Min Focal Length"), N_("Min focal length"), nikonLd3Id, makerTags, unsignedByte, 1, printFocal), TagInfo(15, "MaxFocalLength", N_("Max Focal Length"), N_("Max focal length"), nikonLd3Id, makerTags, unsignedByte, 1, printFocal), TagInfo(16, "MaxApertureAtMinFocal", N_("Max Aperture At Min Focal"), N_("Max aperture at min focal length"), nikonLd3Id, makerTags, unsignedByte, 1, printAperture), TagInfo(17, "MaxApertureAtMaxFocal", N_("Max Aperture At Max Focal"), N_("Max aperture at max focal length"), nikonLd3Id, makerTags, unsignedByte, 1, printAperture), TagInfo(18, "MCUVersion", N_("MCU Version"), N_("MCU version"), nikonLd3Id, makerTags, unsignedByte, 1, printValue), TagInfo(19, "EffectiveMaxAperture", N_("Effective Max Aperture"), N_("Effective max aperture"), nikonLd3Id, makerTags, unsignedByte, 1, printAperture), // End of list marker TagInfo(0xffff, "(UnknownNikonLd3Tag)", "(UnknownNikonLd3Tag)", N_("Unknown Nikon Lens Data 3 Tag"), nikonLd3Id, makerTags, unsignedByte, 1, printValue) }; const TagInfo* Nikon3MakerNote::tagListLd3() { return tagInfoLd3_; } std::ostream& Nikon3MakerNote::printIiIso(std::ostream& os, const Value& value, const ExifData*) { double v = 100 * exp((value.toLong() / 12.0 - 5) * log(2.0)); return os << static_cast(v + 0.5); } std::ostream& Nikon3MakerNote::print0x0002(std::ostream& os, const Value& value, const ExifData*) { if (value.count() > 1) { os << value.toLong(1); } else { os << "(" << value << ")"; } return os; } std::ostream& Nikon3MakerNote::print0x0007(std::ostream& os, const Value& value, const ExifData*) { std::string focus = value.toString(); if (focus == "AF-C ") os << _("Continuous autofocus"); else if (focus == "AF-S ") os << _("Single autofocus"); else if (focus == "AF-A ") os << _("Automatic"); else os << "(" << value << ")"; return os; } std::ostream& Nikon3MakerNote::print0x0083(std::ostream& os, const Value& value, const ExifData*) { long lensType = value.toLong(); bool valid=false; if (lensType & 1) { os << "MF "; valid=true; } if (lensType & 2) { os << "D "; valid=true; } if (lensType & 4) { os << "G "; valid=true; } if (lensType & 8) { os << "VR"; valid=true; } if (!valid) os << "(" << lensType << ")"; return os; } std::ostream& Nikon3MakerNote::print0x0084(std::ostream& os, const Value& value, const ExifData*) { if ( value.count() != 4 || value.toRational(0).second == 0 || value.toRational(1).second == 0) { os << "(" << value << ")"; return os; } long len1 = value.toLong(0); long len2 = value.toLong(1); Rational fno1 = value.toRational(2); Rational fno2 = value.toRational(3); os << len1; if (len2 != len1) { os << "-" << len2; } os << "mm "; std::ostringstream oss; oss.copyfmt(os); os << "F" << std::setprecision(2) << static_cast(fno1.first) / fno1.second; if (fno2 != fno1) { os << "-" << std::setprecision(2) << static_cast(fno2.first) / fno2.second; } os.copyfmt(oss); return os; } std::ostream& Nikon3MakerNote::print0x0085(std::ostream& os, const Value& value, const ExifData*) { Rational distance = value.toRational(); if (distance.first == 0) { os << _("Unknown"); } else if (distance.second != 0) { std::ostringstream oss; oss.copyfmt(os); os << std::fixed << std::setprecision(2) << (float)distance.first / distance.second << " m"; os.copyfmt(oss); } else { os << "(" << value << ")"; } return os; } std::ostream& Nikon3MakerNote::print0x0086(std::ostream& os, const Value& value, const ExifData*) { Rational zoom = value.toRational(); if (zoom.first == 0) { os << _("Not used"); } else if (zoom.second != 0) { std::ostringstream oss; oss.copyfmt(os); os << std::fixed << std::setprecision(1) << (float)zoom.first / zoom.second << "x"; os.copyfmt(oss); } else { os << "(" << value << ")"; } return os; } std::ostream& Nikon3MakerNote::print0x0088(std::ostream& os, const Value& value, const ExifData*) { if (value.size() != 4) { // Size is 4 even for those who map this way... os << "(" << value << ")"; } else { // Mapping by Roger Larsson unsigned focusmetering = value.toLong(0); unsigned focuspoint = value.toLong(1); unsigned focusused = (value.toLong(2) << 8) + value.toLong(3); // TODO: enum {standard, wide} combination = standard; const unsigned focuspoints = sizeof(nikonFocuspoints) / sizeof(nikonFocuspoints[0]); if (focusmetering == 0 && focuspoint == 0 && focusused == 0) { // Special case, in Manual focus and with Nikon compacts // this indicates that the field has no meaning. // But when acually in "Single area, Center" this can mean // that focus was not found (try this in AF-C mode) // TODO: handle the meaningful case (interacts with other fields) os << "N/A"; return os; } switch (focusmetering) { case 0x00: os << _("Single area"); break; // D70, D200 case 0x01: os << _("Dynamic area"); break; // D70, D200 case 0x02: os << _("Closest subject"); break; // D70, D200 case 0x03: os << _("Group dynamic-AF"); break; // D200 case 0x04: os << _("Single area (wide)"); /* TODO: combination = wide; */ break; // D200 case 0x05: os << _("Dynamic area (wide)"); /* TODO: combination = wide; */ break; // D200 default: os << "(" << focusmetering << ")"; break; } char sep = ';'; if (focusmetering != 0x02) { // No user selected point for Closest subject os << sep << ' '; // What focuspoint did the user select? if (focuspoint < focuspoints) { os << nikonFocuspoints[focuspoint]; // TODO: os << position[fokuspoint][combination] } else os << "(" << focuspoint << ")"; sep = ','; } // What fokuspoints(!) did the camera use? add if differs if (focusused == 0) os << sep << " " << _("none"); else if (focusused != 1U<findKey(ExifKey("Exif.Image.Model")); if (pos != metadata->end() && pos->count() != 0) { std::string model = pos->toString(); if (model.find("NIKON D") != std::string::npos) { dModel = true; } } } uint16_t val = static_cast(value.toLong()); if (dModel) val = (val >> 8) | ((val & 0x00ff) << 8); if (val == 0x07ff) return os << _("All 11 Points"); UShortValue v; v.value_.push_back(val); return EXV_PRINT_TAG_BITMASK(nikonAfPointsInFocus)(os, v, 0); } std::ostream& Nikon3MakerNote::print0x0089(std::ostream& os, const Value& value, const ExifData* metadata) { if (value.count() != 1 || value.typeId() != unsignedShort) { return os << "(" << value << ")"; } long l = value.toLong(0); if (l == 0) return os << _("Single-frame"); if (!(l & 0x87)) os << _("Single-frame") << ", "; bool d70 = false; if (metadata) { ExifKey key("Exif.Image.Model"); ExifData::const_iterator pos = metadata->findKey(key); if (pos != metadata->end() && pos->count() != 0) { std::string model = pos->toString(); if (model.find("D70") != std::string::npos) { d70 = true; } } } if (d70) { EXV_PRINT_TAG_BITMASK(nikonShootingModeD70)(os, value, 0); } else { EXV_PRINT_TAG_BITMASK(nikonShootingMode)(os, value, 0); } return os; } std::ostream& Nikon3MakerNote::print0x008b(std::ostream& os, const Value& value, const ExifData*) { // Decoded by Robert Rottmerhusen if ( value.size() != 4 || value.typeId() != undefined) { return os << "(" << value << ")"; } float a = value.toFloat(0); long b = value.toLong(1); long c = value.toLong(2); if (c == 0) return os << "(" << value << ")"; return os << a * b / c; } std::ostream& Nikon3MakerNote::printLensId1(std::ostream& os, const Value& value, const ExifData* metadata) { return printLensId(os, value, metadata, "NikonLd1"); } std::ostream& Nikon3MakerNote::printLensId2(std::ostream& os, const Value& value, const ExifData* metadata) { return printLensId(os, value, metadata, "NikonLd2"); } std::ostream& Nikon3MakerNote::printLensId3(std::ostream& os, const Value& value, const ExifData* metadata) { return printLensId(os, value, metadata, "NikonLd3"); } std::ostream& Nikon3MakerNote::printLensId(std::ostream& os, const Value& value, const ExifData* metadata, const std::string& group) { #ifdef EXV_HAVE_LENSDATA // 8< - - - 8< do not remove this line >8 - - - >8 //------------------------------------------------------------------------------ #ifndef FMOUNTLH #define FMOUNTLH //------------------------------------------------------------------------------ // List of AF F-Mount lenses - Version 4.3.428.01 2012-03-26 //------------------------------------------------------------------------------ #define FMLVERSION "4.3.428.01" #define FMLDATE "2012-03-26" //------------------------------------------------------------------------------ // // // Created by Robert Rottmerhusen 2005 - 2012 // http://www.rottmerhusen.com (lens_id@rottmerhusen.com) // // For contributor info and more visit my online list: // http://www.rottmerhusen.com/objektives/lensid/thirdparty.html // // // Seven misidentified lenses due to double LensIDs: // // 2F 48 30 44 24 24 29 02.1: Nikon AF Zoom-Nikkor 20-35mm f/2.8D IF // 2F 48 30 44 24 24 29 02.2: Tokina AT-X 235 AF PRO (AF 20-35mm f/2.8) // // 32 54 6A 6A 24 24 35 02.1: Nikon AF Micro-Nikkor 105mm f/2.8D // 32 54 6A 6A 24 24 35 02.2: Sigma Macro 105mm F2.8 EX DG // // 7A 3C 1F 37 30 30 7E 06.1: Nikon AF-S DX Zoom-Nikkor 12-24mm f/4G IF-ED // 7A 3C 1F 37 30 30 7E 06.2: Tokina AT-X 124 AF PRO DX II (AF 12-24mm f/4) // // 8B 40 2D 80 2C 3C FD 0E.1: Nikon AF-S DX VR Zoom-Nikkor 18-200mm f/3.5-5.6G IF-ED // 8B 40 2D 80 2C 3C FD 0E.2: Nikon AF-S DX VR Zoom-Nikkor 18-200mm f/3.5-5.6G IF-ED II // // 32 53 64 64 24 24 35 02.1: Tamron SP AF 90mm F/2.8 Macro 1:1 (172E) // 32 53 64 64 24 24 35 02.2: Tamron SP AF 90mm F/2.8 Di Macro 1:1 (272E) // // 2F 40 30 44 2C 34 29 02.1: Tokina AF 235 II (AF 20-35mm f/3.5-4.5) // 2F 40 30 44 2C 34 29 02.2: Tokina AF 193 (AF 19-35mm f/3.5-4.5) // // 25 48 3C 5C 24 24 1B 02.1: Tokina AT-X 287 AF PRO SV (AF 28-70mm f/2.8) // 25 48 3C 5C 24 24 1B 02.2: Tokina AT-X 270 AF PRO II (AF 28-70mm f/2.6-2.8) // // // product number/order code not complete // // Free use in non-commercial, GPL or open source software only! // Please contact me for adding lenses or use in commercial software. // //"data from TAG 0x98" "ltyp" " "TC" "MID" "maker" "PN" "lens name from manuf"; // //------------------------------------------------------------------------------ // Nikkor lenses by their LensID //------------------------------------------------------------------------------ // static const struct {unsigned char lid,stps,focs,focl,aps,apl,lfw, ltype, tcinfo, dblid, mid; const char *manuf, *lnumber, *lensname;} fmountlens[] = { {0x01,0x58,0x50,0x50,0x14,0x14,0x02,0x00,0x00,0x00,0x00, "Nikon", "JAA00901", "AF Nikkor 50mm f/1.8"}, {0x02,0x42,0x44,0x5C,0x2A,0x34,0x02,0x00,0x00,0x00,0x00, "Nikon", "JAA72701", "AF Zoom-Nikkor 35-70mm f/3.3-4.5"}, {0x02,0x42,0x44,0x5C,0x2A,0x34,0x08,0x00,0x00,0x00,0x00, "Nikon", "JAA72701", "AF Zoom-Nikkor 35-70mm f/3.3-4.5"}, {0x03,0x48,0x5C,0x81,0x30,0x30,0x02,0x00,0x00,0x00,0x00, "Nikon", "JAA72801", "AF Zoom-Nikkor 70-210mm f/4"}, {0x04,0x48,0x3C,0x3C,0x24,0x24,0x03,0x00,0x00,0x00,0x00, "Nikon", "JAA12001", "AF Nikkor 28mm f/2.8"}, {0x05,0x54,0x50,0x50,0x0C,0x0C,0x04,0x00,0x00,0x00,0x00, "Nikon", "JAA01001", "AF Nikkor 50mm f/1.4"}, {0x06,0x54,0x53,0x53,0x24,0x24,0x06,0x00,0x40,0x00,0x00, "Nikon", "JAA62101", "AF Micro-Nikkor 55mm f/2.8"}, {0x07,0x40,0x3C,0x62,0x2C,0x34,0x03,0x00,0x00,0x00,0x00, "Nikon", "JAA72901", "AF Zoom-Nikkor 28-85mm f/3.5-4.5"}, {0x08,0x40,0x44,0x6A,0x2C,0x34,0x04,0x00,0x00,0x00,0x00, "Nikon", "JAA73001", "AF Zoom-Nikkor 35-105mm f/3.5-4.5"}, {0x09,0x48,0x37,0x37,0x24,0x24,0x04,0x00,0x00,0x00,0x00, "Nikon", "JAA12101", "AF Nikkor 24mm f/2.8"}, {0x0A,0x48,0x8E,0x8E,0x24,0x24,0x03,0x00,0x00,0x00,0x00, "Nikon", "JAA322AA", "AF Nikkor 300mm f/2.8 IF-ED"}, {0x0A,0x48,0x8E,0x8E,0x24,0x24,0x05,0x00,0x00,0x00,0x00, "Nikon", "JAA322AB", "AF Nikkor 300mm f/2.8 IF-ED N"}, {0x0B,0x48,0x7C,0x7C,0x24,0x24,0x05,0x00,0x00,0x00,0x00, "Nikon", "JAA32101", "AF Nikkor 180mm f/2.8 IF-ED"}, //0C {0x0D,0x40,0x44,0x72,0x2C,0x34,0x07,0x00,0x00,0x00,0x00, "Nikon", "JAA73101", "AF Zoom-Nikkor 35-135mm f/3.5-4.5"}, {0x0E,0x48,0x5C,0x81,0x30,0x30,0x05,0x00,0x00,0x00,0x00, "Nikon", "", "AF Zoom-Nikkor 70-210mm f/4"}, {0x0F,0x58,0x50,0x50,0x14,0x14,0x05,0x00,0x00,0x00,0x00, "Nikon", "JAA009AD", "AF Nikkor 50mm f/1.8 N"}, {0x10,0x48,0x8E,0x8E,0x30,0x30,0x08,0x00,0x00,0x00,0x00, "Nikon", "JAA32301", "AF Nikkor 300mm f/4 IF-ED"}, {0x11,0x48,0x44,0x5C,0x24,0x24,0x08,0x00,0x00,0x00,0x00, "Nikon", "JAA73301", "AF Zoom-Nikkor 35-70mm f/2.8"}, {0x12,0x48,0x5C,0x81,0x30,0x3C,0x09,0x00,0x00,0x00,0x00, "Nikon", "JAA73201", "AF Nikkor 70-210mm f/4-5.6"}, {0x13,0x42,0x37,0x50,0x2A,0x34,0x0B,0x00,0x00,0x00,0x00, "Nikon", "JAA73401", "AF Zoom-Nikkor 24-50mm f/3.3-4.5"}, {0x14,0x48,0x60,0x80,0x24,0x24,0x0B,0x00,0x00,0x00,0x00, "Nikon", "JAA73501", "AF Zoom-Nikkor 80-200mm f/2.8 ED"}, {0x15,0x4C,0x62,0x62,0x14,0x14,0x0C,0x00,0x00,0x00,0x00, "Nikon", "JAA32401", "AF Nikkor 85mm f/1.8"}, //16 {0x17,0x3C,0xA0,0xA0,0x30,0x30,0x0F,0x00,0x00,0x00,0x00, "Nikon", "JAA518AA", "Nikkor 500mm f/4 P ED IF"}, {0x17,0x3C,0xA0,0xA0,0x30,0x30,0x11,0x00,0x00,0x00,0x00, "Nikon", "JAA518AA", "Nikkor 500mm f/4 P ED IF"}, {0x18,0x40,0x44,0x72,0x2C,0x34,0x0E,0x00,0x00,0x00,0x00, "Nikon", "JAA736AA", "AF Zoom-Nikkor 35-135mm f/3.5-4.5 N"}, //19 {0x1A,0x54,0x44,0x44,0x18,0x18,0x11,0x00,0x00,0x00,0x00, "Nikon", "JAA12201", "AF Nikkor 35mm f/2"}, {0x1B,0x44,0x5E,0x8E,0x34,0x3C,0x10,0x00,0x00,0x00,0x00, "Nikon", "JAA738AA", "AF Zoom-Nikkor 75-300mm f/4.5-5.6"}, {0x1C,0x48,0x30,0x30,0x24,0x24,0x12,0x00,0x00,0x00,0x00, "Nikon", "JAA12301", "AF Nikkor 20mm f/2.8"}, {0x1D,0x42,0x44,0x5C,0x2A,0x34,0x12,0x00,0x00,0x00,0x00, "Nikon", "", "AF Zoom-Nikkor 35-70mm f/3.3-4.5 N"}, {0x1E,0x54,0x56,0x56,0x24,0x24,0x13,0x00,0x40,0x00,0x00, "Nikon", "JAA62201", "AF Micro-Nikkor 60mm f/2.8"}, {0x1F,0x54,0x6A,0x6A,0x24,0x24,0x14,0x00,0x40,0x00,0x00, "Nikon", "JAA62301", "AF Micro-Nikkor 105mm f/2.8"}, {0x20,0x48,0x60,0x80,0x24,0x24,0x15,0x00,0x00,0x00,0x00, "Nikon", "", "AF Zoom-Nikkor 80-200mm f/2.8 ED"}, {0x21,0x40,0x3C,0x5C,0x2C,0x34,0x16,0x00,0x00,0x00,0x00, "Nikon", "", "AF Zoom-Nikkor 28-70mm f/3.5-4.5"}, {0x22,0x48,0x72,0x72,0x18,0x18,0x16,0x00,0x00,0x00,0x00, "Nikon", "JAA32501", "AF DC-Nikkor 135mm f/2"}, {0x23,0x30,0xBE,0xCA,0x3C,0x48,0x17,0x00,0x00,0x00,0x00, "Nikon", "", "Zoom-Nikkor 1200-1700mm f/5.6-8 P ED IF"}, // - D - lenses from here {0x24,0x48,0x60,0x80,0x24,0x24,0x1A,0x02,0x00,0x00,0x00, "Nikon", "JAA742DA", "AF Zoom-Nikkor 80-200mm f/2.8D ED"}, {0x25,0x48,0x44,0x5c,0x24,0x24,0x1B,0x02,0x00,0x00,0x00, "Nikon", "JAA743DA", "AF Zoom-Nikkor 35-70mm f/2.8D"}, {0x25,0x48,0x44,0x5c,0x24,0x24,0x52,0x02,0x00,0x00,0x00, "Nikon", "JAA743DA", "AF Zoom-Nikkor 35-70mm f/2.8D"}, {0x26,0x40,0x3C,0x5C,0x2C,0x34,0x1C,0x02,0x00,0x00,0x00, "Nikon", "JAA744DA", "AF Zoom-Nikkor 28-70mm f/3.5-4.5D"}, // ^- not yet verified {0x27,0x48,0x8E,0x8E,0x24,0x24,0x1D,0x02,0x07,0x00,0x00, "Nikon", "JAA326DA", "AF-I Nikkor 300mm f/2.8D IF-ED"}, {0x27,0x48,0x8E,0x8E,0x24,0x24,0xF1,0x02,0x0F,0x00,0x00, "Nikon", "JAA326DA", "AF-I Nikkor 300mm f/2.8D IF-ED + TC-14E"}, {0x27,0x48,0x8E,0x8E,0x24,0x24,0xE1,0x02,0x0F,0x00,0x00, "Nikon", "JAA326DA", "AF-I Nikkor 300mm f/2.8D IF-ED + TC-17E"}, {0x27,0x48,0x8E,0x8E,0x24,0x24,0xF2,0x02,0x0F,0x00,0x00, "Nikon", "JAA326DA", "AF-I Nikkor 300mm f/2.8D IF-ED + TC-20E"}, {0x28,0x3C,0xA6,0xA6,0x30,0x30,0x1D,0x02,0x07,0x00,0x00, "Nikon", "JAA519DA", "AF-I Nikkor 600mm f/4D IF-ED"}, {0x28,0x3C,0xA6,0xA6,0x30,0x30,0xF1,0x02,0x0F,0x00,0x00, "Nikon", "JAA519DA", "AF-I Nikkor 600mm f/4D IF-ED + TC-14E"}, {0x28,0x3C,0xA6,0xA6,0x30,0x30,0xE1,0x02,0x0F,0x00,0x00, "Nikon", "JAA519DA", "AF-I Nikkor 600mm f/4D IF-ED + TC-17E"}, {0x28,0x3C,0xA6,0xA6,0x30,0x30,0xF2,0x02,0x0F,0x00,0x00, "Nikon", "JAA519DA", "AF-I Nikkor 600mm f/4D IF-ED + TC-20E"}, //29 {0x2A,0x54,0x3C,0x3C,0x0C,0x0C,0x26,0x02,0x00,0x00,0x00, "Nikon", "JAA124DA", "AF Nikkor 28mm f/1.4D"}, {0x2B,0x3C,0x44,0x60,0x30,0x3C,0x1F,0x02,0x00,0x00,0x00, "Nikon", "", "AF Zoom-Nikkor 35-80mm f/4-5.6D"}, {0x2C,0x48,0x6A,0x6A,0x18,0x18,0x27,0x02,0x00,0x00,0x00, "Nikon", "JAA327DA", "AF DC-Nikkor 105mm f/2D"}, {0x2D,0x48,0x80,0x80,0x30,0x30,0x21,0x02,0x40,0x00,0x00, "Nikon", "JAA624DA", "AF Micro-Nikkor 200mm f/4D IF-ED"}, {0x2E,0x48,0x5C,0x82,0x30,0x3C,0x22,0x02,0x00,0x00,0x00, "Nikon", "JAA747DA", "AF Nikkor 70-210mm f/4-5.6D"}, {0x2E,0x48,0x5C,0x82,0x30,0x3C,0x28,0x02,0x00,0x00,0x00, "Nikon", "JAA747DA", "AF Nikkor 70-210mm f/4-5.6D"}, {0x2F,0x48,0x30,0x44,0x24,0x24,0x29,0x02,0x00,0x01,0x00, "Nikon", "JAA746DA", "AF Zoom-Nikkor 20-35mm f/2.8D IF"}, {0x30,0x48,0x98,0x98,0x24,0x24,0x24,0x02,0x07,0x00,0x00, "Nikon", "JAA520DA", "AF-I Nikkor 400mm f/2.8D IF-ED"}, {0x30,0x48,0x98,0x98,0x24,0x24,0xF1,0x02,0x0F,0x00,0x00, "Nikon", "JAA520DA", "AF-I Nikkor 400mm f/2.8D IF-ED + TC-14E"}, {0x30,0x48,0x98,0x98,0x24,0x24,0xE1,0x02,0x0F,0x00,0x00, "Nikon", "JAA520DA", "AF-I Nikkor 400mm f/2.8D IF-ED + TC-17E"}, {0x30,0x48,0x98,0x98,0x24,0x24,0xF2,0x02,0x0F,0x00,0x00, "Nikon", "JAA520DA", "AF-I Nikkor 400mm f/2.8D IF-ED + TC-20E"}, {0x31,0x54,0x56,0x56,0x24,0x24,0x25,0x02,0x40,0x00,0x00, "Nikon", "JAA625DA", "AF Micro-Nikkor 60mm f/2.8D"}, {0x32,0x54,0x6A,0x6A,0x24,0x24,0x35,0x02,0x40,0x01,0x00, "Nikon", "JAA627DA", "AF Micro-Nikkor 105mm f/2.8D"}, {0x33,0x48,0x2D,0x2D,0x24,0x24,0x31,0x02,0x00,0x00,0x00, "Nikon", "JAA126DA", "AF Nikkor 18mm f/2.8D"}, {0x34,0x48,0x29,0x29,0x24,0x24,0x32,0x02,0x00,0x00,0x00, "Nikon", "JAA626DA", "AF Fisheye Nikkor 16mm f/2.8D"}, {0x35,0x3C,0xA0,0xA0,0x30,0x30,0x33,0x02,0x07,0x00,0x00, "Nikon", "JAA521DA", "AF-I Nikkor 500mm f/4D IF-ED"}, {0x35,0x3C,0xA0,0xA0,0x30,0x30,0xF1,0x02,0x0F,0x00,0x00, "Nikon", "JAA521DA", "AF-I Nikkor 500mm f/4D IF-ED + TC-14E"}, {0x35,0x3C,0xA0,0xA0,0x30,0x30,0xE1,0x02,0x0F,0x00,0x00, "Nikon", "JAA521DA", "AF-I Nikkor 500mm f/4D IF-ED + TC-17E"}, {0x35,0x3C,0xA0,0xA0,0x30,0x30,0xF2,0x02,0x0F,0x00,0x00, "Nikon", "JAA521DA", "AF-I Nikkor 500mm f/4D IF-ED + TC-20E"}, {0x36,0x48,0x37,0x37,0x24,0x24,0x34,0x02,0x00,0x00,0x00, "Nikon", "JAA125DA", "AF Nikkor 24mm f/2.8D"}, {0x37,0x48,0x30,0x30,0x24,0x24,0x36,0x02,0x00,0x00,0x00, "Nikon", "JAA127DA", "AF Nikkor 20mm f/2.8D"}, {0x38,0x4C,0x62,0x62,0x14,0x14,0x37,0x02,0x00,0x00,0x00, "Nikon", "JAA328DA", "AF Nikkor 85mm f/1.8D"}, //39 38 {0x3A,0x40,0x3C,0x5C,0x2C,0x34,0x39,0x02,0x00,0x00,0x00, "Nikon", "JAA744DA", "AF Zoom-Nikkor 28-70mm f/3.5-4.5D"}, {0x3B,0x48,0x44,0x5C,0x24,0x24,0x3A,0x02,0x00,0x00,0x00, "Nikon", "JAA743DA", "AF Zoom-Nikkor 35-70mm f/2.8D N"}, {0x3C,0x48,0x60,0x80,0x24,0x24,0x3B,0x02,0x00,0x00,0x00, "Nikon", "", "AF Zoom-Nikkor 80-200mm f/2.8D ED"}, {0x3D,0x3C,0x44,0x60,0x30,0x3C,0x3E,0x02,0x00,0x00,0x00, "Nikon", "", "AF Zoom-Nikkor 35-80mm f/4-5.6D"}, {0x3E,0x48,0x3C,0x3C,0x24,0x24,0x3D,0x02,0x00,0x00,0x00, "Nikon", "JAA128DA", "AF Nikkor 28mm f/2.8D"}, {0x3F,0x40,0x44,0x6A,0x2C,0x34,0x45,0x02,0x00,0x00,0x00, "Nikon", "JAA748DA", "AF Zoom-Nikkor 35-105mm f/3.5-4.5D"}, //40 {0x41,0x48,0x7c,0x7c,0x24,0x24,0x43,0x02,0x00,0x00,0x00, "Nikon", "JAA330DA", "AF Nikkor 180mm f/2.8D IF-ED"}, {0x42,0x54,0x44,0x44,0x18,0x18,0x44,0x02,0x00,0x00,0x00, "Nikon", "JAA129DA", "AF Nikkor 35mm f/2D"}, {0x43,0x54,0x50,0x50,0x0C,0x0C,0x46,0x02,0x00,0x00,0x00, "Nikon", "JAA011DB", "AF Nikkor 50mm f/1.4D"}, {0x44,0x44,0x60,0x80,0x34,0x3C,0x47,0x02,0x00,0x00,0x00, "Nikon", "JAA753DB", "AF Zoom-Nikkor 80-200mm f/4.5-5.6D"}, {0x45,0x40,0x3C,0x60,0x2C,0x3C,0x48,0x02,0x00,0x00,0x00, "Nikon", "JAA752DA", "AF Zoom-Nikkor 28-80mm f/3.5-5.6D"}, {0x46,0x3C,0x44,0x60,0x30,0x3C,0x49,0x02,0x00,0x00,0x00, "Nikon", "JAA754DA", "AF Zoom-Nikkor 35-80mm f/4-5.6D N"}, {0x47,0x42,0x37,0x50,0x2A,0x34,0x4A,0x02,0x00,0x00,0x00, "Nikon", "JAA756DA", "AF Zoom-Nikkor 24-50mm f/3.3-4.5D"}, {0x48,0x48,0x8E,0x8E,0x24,0x24,0x4B,0x02,0x07,0x00,0x00, "Nikon", "JAA333DA", "AF-S Nikkor 300mm f/2.8D IF-ED"}, {0x48,0x48,0x8E,0x8E,0x24,0x24,0xF1,0x02,0x0F,0x00,0x00, "Nikon", "JAA333DA", "AF-S Nikkor 300mm f/2.8D IF-ED + TC-14E"}, {0x48,0x48,0x8E,0x8E,0x24,0x24,0xE1,0x02,0x0F,0x00,0x00, "Nikon", "JAA333DA", "AF-S Nikkor 300mm f/2.8D IF-ED + TC-17E"}, {0x48,0x48,0x8E,0x8E,0x24,0x24,0xF2,0x02,0x0F,0x00,0x00, "Nikon", "JAA333DA", "AF-S Nikkor 300mm f/2.8D IF-ED + TC-20E"}, {0x49,0x3C,0xA6,0xA6,0x30,0x30,0x4C,0x02,0x07,0x00,0x00, "Nikon", "JAA522DA", "AF-S Nikkor 600mm f/4D IF-ED"}, {0x49,0x3C,0xA6,0xA6,0x30,0x30,0xF1,0x02,0x0F,0x00,0x00, "Nikon", "JAA522DA", "AF-S Nikkor 600mm f/4D IF-ED + TC-14E"}, {0x49,0x3C,0xA6,0xA6,0x30,0x30,0xE1,0x02,0x0F,0x00,0x00, "Nikon", "JAA522DA", "AF-S Nikkor 600mm f/4D IF-ED + TC-17E"}, {0x49,0x3C,0xA6,0xA6,0x30,0x30,0xF2,0x02,0x0F,0x00,0x00, "Nikon", "JAA522DA", "AF-S Nikkor 600mm f/4D IF-ED + TC-20E"}, {0x4A,0x54,0x62,0x62,0x0C,0x0C,0x4D,0x02,0x00,0x00,0x00, "Nikon", "JAA332DA", "AF Nikkor 85mm f/1.4D IF"}, {0x4B,0x3C,0xA0,0xA0,0x30,0x30,0x4E,0x02,0x07,0x00,0x00, "Nikon", "JAA523DA", "AF-S Nikkor 500mm f/4D IF-ED"}, {0x4B,0x3C,0xA0,0xA0,0x30,0x30,0xF1,0x02,0x0F,0x00,0x00, "Nikon", "JAA523DA", "AF-S Nikkor 500mm f/4D IF-ED + TC-14E"}, {0x4B,0x3C,0xA0,0xA0,0x30,0x30,0xE1,0x02,0x0F,0x00,0x00, "Nikon", "JAA523DA", "AF-S Nikkor 500mm f/4D IF-ED + TC-17E"}, {0x4B,0x3C,0xA0,0xA0,0x30,0x30,0xF2,0x02,0x0F,0x00,0x00, "Nikon", "JAA523DA", "AF-S Nikkor 500mm f/4D IF-ED + TC-20E"}, {0x4C,0x40,0x37,0x6E,0x2C,0x3C,0x4F,0x02,0x00,0x00,0x00, "Nikon", "JAA757DA", "AF Zoom-Nikkor 24-120mm f/3.5-5.6D IF"}, {0x4D,0x40,0x3C,0x80,0x2C,0x3C,0x62,0x02,0x00,0x00,0x00, "Nikon", "JAA758DA", "AF Zoom-Nikkor 28-200mm f/3.5-5.6D IF"}, {0x4E,0x48,0x72,0x72,0x18,0x18,0x51,0x02,0x00,0x00,0x00, "Nikon", "JAA329DA", "AF DC-Nikkor 135mm f/2D"}, {0x4F,0x40,0x37,0x5C,0x2C,0x3C,0x53,0x06,0x00,0x00,0x00, "Nikon", "JBA701AA", "IX-Nikkor 24-70mm f/3.5-5.6"}, {0x50,0x48,0x56,0x7C,0x30,0x3C,0x54,0x06,0x00,0x00,0x00, "Nikon", "JBA702AA", "IX-Nikkor 60-180mm f/4-5.6"}, // "JBA703AC" "IX-Nikkor 20-60 mm f/3.5-5.6"; //51 //52 {0x53,0x48,0x60,0x80,0x24,0x24,0x57,0x02,0x00,0x00,0x00, "Nikon", "JAA762DA", "AF Zoom-Nikkor 80-200mm f/2.8D ED"}, {0x53,0x48,0x60,0x80,0x24,0x24,0x60,0x02,0x00,0x00,0x00, "Nikon", "JAA762DA", "AF Zoom-Nikkor 80-200mm f/2.8D ED"}, {0x54,0x44,0x5C,0x7C,0x34,0x3C,0x58,0x02,0x00,0x00,0x00, "Nikon", "JAA763DA", "AF Zoom-Micro Nikkor 70-180mm f/4.5-5.6D ED"}, //55 {0x56,0x48,0x5C,0x8E,0x30,0x3C,0x5A,0x02,0x00,0x00,0x00, "Nikon", "JAA764DA", "AF Zoom-Nikkor 70-300mm f/4-5.6D ED"}, //57 //58 {0x59,0x48,0x98,0x98,0x24,0x24,0x5D,0x02,0x07,0x00,0x00, "Nikon", "JAA524DA", "AF-S Nikkor 400mm f/2.8D IF-ED"}, {0x59,0x48,0x98,0x98,0x24,0x24,0xF1,0x02,0x0F,0x00,0x00, "Nikon", "JAA524DA", "AF-S Nikkor 400mm f/2.8D IF-ED + TC-14E"}, {0x59,0x48,0x98,0x98,0x24,0x24,0xE1,0x02,0x0F,0x00,0x00, "Nikon", "JAA524DA", "AF-S Nikkor 400mm f/2.8D IF-ED + TC-17E"}, {0x59,0x48,0x98,0x98,0x24,0x24,0xF2,0x02,0x0F,0x00,0x00, "Nikon", "JAA524DA", "AF-S Nikkor 400mm f/2.8D IF-ED + TC-20E"}, {0x5A,0x3C,0x3E,0x56,0x30,0x3C,0x5E,0x06,0x00,0x00,0x00, "Nikon", "JBA704AA", "IX-Nikkor 30-60mm f/4-5.6"}, {0x5B,0x44,0x56,0x7C,0x34,0x3C,0x5F,0x06,0x00,0x00,0x00, "Nikon", "JBA705AA", "IX-Nikkor 60-180mm f/4.5-5.6"}, // "JBA706AC" "IX-Nikkor 20-60 mm f/3.5-5.6N"; //5C {0x5D,0x48,0x3C,0x5C,0x24,0x24,0x63,0x02,0x01,0x00,0x00, "Nikon", "JAA767DA", "AF-S Zoom-Nikkor 28-70mm f/2.8D IF-ED"}, {0x5E,0x48,0x60,0x80,0x24,0x24,0x64,0x02,0x03,0x00,0x00, "Nikon", "JAA765DA", "AF-S Zoom-Nikkor 80-200mm f/2.8D IF-ED"}, {0x5F,0x40,0x3C,0x6A,0x2C,0x34,0x65,0x02,0x00,0x00,0x00, "Nikon", "JAA766DA", "AF Zoom-Nikkor 28-105mm f/3.5-4.5D IF"}, {0x60,0x40,0x3C,0x60,0x2C,0x3C,0x66,0x02,0x00,0x00,0x00, "Nikon", "JAA769DA", "AF Zoom-Nikkor 28-80mm f/3.5-5.6D"}, {0x61,0x44,0x5E,0x86,0x34,0x3C,0x67,0x02,0x00,0x00,0x00, "Nikon", "JAA768DA", "AF Zoom-Nikkor 75-240mm f/4.5-5.6D"}, //62 69 {0x63,0x48,0x2B,0x44,0x24,0x24,0x68,0x02,0x01,0x00,0x00, "Nikon", "JAA770DA", "AF-S Nikkor 17-35mm f/2.8D IF-ED"}, {0x64,0x00,0x62,0x62,0x24,0x24,0x6A,0x02,0x40,0x00,0x00, "Nikon", "JAA628DA", "PC Micro-Nikkor 85mm f/2.8D"}, {0x65,0x44,0x60,0x98,0x34,0x3C,0x6B,0x0A,0x00,0x00,0x00, "Nikon", "JAA771DA", "AF VR Zoom-Nikkor 80-400mm f/4.5-5.6D ED"}, {0x66,0x40,0x2D,0x44,0x2C,0x34,0x6C,0x02,0x00,0x00,0x00, "Nikon", "JAA772DA", "AF Zoom-Nikkor 18-35mm f/3.5-4.5D IF-ED"}, {0x67,0x48,0x37,0x62,0x24,0x30,0x6D,0x02,0x00,0x00,0x00, "Nikon", "JAA774DA", "AF Zoom-Nikkor 24-85mm f/2.8-4D IF"}, {0x68,0x42,0x3C,0x60,0x2A,0x3C,0x6E,0x06,0x00,0x00,0x00, "Nikon", "JAA777DA", "AF Zoom-Nikkor 28-80mm f/3.3-5.6G"}, {0x69,0x48,0x5C,0x8E,0x30,0x3C,0x6F,0x06,0x00,0x00,0x00, "Nikon", "JAA776DA", "AF Zoom-Nikkor 70-300mm f/4-5.6G"}, {0x6A,0x48,0x8E,0x8E,0x30,0x30,0x70,0x02,0x03,0x00,0x00, "Nikon", "JAA334DA", "AF-S Nikkor 300mm f/4D IF-ED"}, {0x6B,0x48,0x24,0x24,0x24,0x24,0x71,0x02,0x00,0x00,0x00, "Nikon", "JAA130DA", "AF Nikkor ED 14mm f/2.8D"}, //6C 72 {0x6D,0x48,0x8E,0x8E,0x24,0x24,0x73,0x02,0x03,0x00,0x00, "Nikon", "JAA335DA", "AF-S Nikkor 300mm f/2.8D IF-ED II"}, {0x6E,0x48,0x98,0x98,0x24,0x24,0x74,0x02,0x03,0x00,0x00, "Nikon", "JAA525DA", "AF-S Nikkor 400mm f/2.8D IF-ED II"}, {0x6F,0x3C,0xA0,0xA0,0x30,0x30,0x75,0x02,0x03,0x00,0x00, "Nikon", "JAA526DA", "AF-S Nikkor 500mm f/4D IF-ED II"}, {0x70,0x3C,0xA6,0xA6,0x30,0x30,0x76,0x02,0x03,0x00,0x00, "Nikon", "JAA527DA", "AF-S Nikkor 600mm f/4D IF-ED II"}, //71 {0x72,0x48,0x4C,0x4C,0x24,0x24,0x77,0x00,0x00,0x00,0x00, "Nikon", "JAA012AA", "Nikkor 45mm f/2.8 P"}, //73 {0x74,0x40,0x37,0x62,0x2C,0x34,0x78,0x06,0x01,0x00,0x00, "Nikon", "JAA780DA", "AF-S Zoom-Nikkor 24-85mm f/3.5-4.5G IF-ED"}, {0x75,0x40,0x3C,0x68,0x2C,0x3C,0x79,0x06,0x00,0x00,0x00, "Nikon", "JAA778DA", "AF Zoom-Nikkor 28-100mm f/3.5-5.6G"}, {0x76,0x58,0x50,0x50,0x14,0x14,0x7A,0x02,0x00,0x00,0x00, "Nikon", "JAA013DA", "AF Nikkor 50mm f/1.8D"}, {0x77,0x48,0x5C,0x80,0x24,0x24,0x7B,0x0E,0x03,0x00,0x00, "Nikon", "JAA781DA", "AF-S VR Zoom-Nikkor 70-200mm f/2.8G IF-ED"}, {0x78,0x40,0x37,0x6E,0x2C,0x3C,0x7C,0x0E,0x01,0x00,0x00, "Nikon", "JAA782DA", "AF-S VR Zoom-Nikkor 24-120mm f/3.5-5.6G IF-ED"}, {0x79,0x40,0x3C,0x80,0x2C,0x3C,0x7F,0x06,0x00,0x00,0x00, "Nikon", "JAA783DA", "AF Zoom-Nikkor 28-200mm f/3.5-5.6G IF-ED"}, {0x7A,0x3C,0x1F,0x37,0x30,0x30,0x7E,0x06,0x01,0x01,0x00, "Nikon", "JAA784DA", "AF-S DX Zoom-Nikkor 12-24mm f/4G IF-ED"}, {0x7B,0x48,0x80,0x98,0x30,0x30,0x80,0x0E,0x03,0x00,0x00, "Nikon", "JAA787DA", "AF-S VR Zoom-Nikkor 200-400mm f/4G IF-ED"}, //7C 81 {0x7D,0x48,0x2B,0x53,0x24,0x24,0x82,0x06,0x01,0x00,0x00, "Nikon", "JAA788DA", "AF-S DX Zoom-Nikkor 17-55mm f/2.8G IF-ED"}, //7E 83 {0x7F,0x40,0x2D,0x5C,0x2C,0x34,0x84,0x06,0x11,0x00,0x00, "Nikon", "JAA790DA", "AF-S DX Zoom-Nikkor 18-70mm f/3.5-4.5G IF-ED"}, {0x80,0x48,0x1A,0x1A,0x24,0x24,0x85,0x06,0x00,0x00,0x00, "Nikon", "JAA629DA", "AF DX Fisheye-Nikkor 10.5mm f/2.8G ED"}, {0x81,0x54,0x80,0x80,0x18,0x18,0x86,0x0E,0x03,0x00,0x00, "Nikon", "JAA336DA", "AF-S VR Nikkor 200mm f/2G IF-ED"}, {0x82,0x48,0x8E,0x8E,0x24,0x24,0x87,0x0E,0x13,0x00,0x00, "Nikon", "JAA337DA", "AF-S VR Nikkor 300mm f/2.8G IF-ED"}, {0x83,0x00,0xB0,0xB0,0x5A,0x5A,0x88,0x04,0x00,0x00,0x00, "Nikon", "", "FSA-L2, EDG 65, 800mm F13 G"}, //84 //85 //86 //87 //88 {0x89,0x3C,0x53,0x80,0x30,0x3C,0x8B,0x06,0x01,0x00,0x00, "Nikon", "JAA793DA", "AF-S DX Zoom-Nikkor 55-200mm f/4-5.6G ED"}, {0x8A,0x54,0x6A,0x6A,0x24,0x24,0x8C,0x0E,0x53,0x00,0x00, "Nikon", "JAA630DA", "AF-S VR Micro-Nikkor 105mm f/2.8G IF-ED"}, {0x8B,0x40,0x2D,0x80,0x2C,0x3C,0x8D,0x0E,0x01,0x00,0x00, "Nikon", "JAA794DA", "AF-S DX VR Zoom-Nikkor 18-200mm f/3.5-5.6G IF-ED"}, {0x8B,0x40,0x2D,0x80,0x2C,0x3C,0xFD,0x0E,0x01,0x01,0x00, "Nikon", "JAA794DA", "AF-S DX VR Zoom-Nikkor 18-200mm f/3.5-5.6G IF-ED"}, {0x8B,0x40,0x2D,0x80,0x2C,0x3C,0xFD,0x0E,0x01,0x02,0x00, "Nikon", "JAA813DA", "AF-S DX VR Zoom-Nikkor 18-200mm f/3.5-5.6G IF-ED II"}, {0x8C,0x40,0x2D,0x53,0x2C,0x3C,0x8E,0x06,0x01,0x00,0x00, "Nikon", "JAA792DA", "AF-S DX Zoom-Nikkor 18-55mm f/3.5-5.6G ED"}, {0x8D,0x44,0x5C,0x8E,0x34,0x3C,0x8F,0x0E,0x31,0x00,0x00, "Nikon", "JAA795DA", "AF-S VR Zoom-Nikkor 70-300mm f/4.5-5.6G IF-ED"}, //8E 90 {0x8F,0x40,0x2D,0x72,0x2C,0x3C,0x91,0x06,0x01,0x00,0x00, "Nikon", "JAA796DA", "AF-S DX Zoom-Nikkor 18-135mm f/3.5-5.6G IF-ED"}, {0x90,0x3B,0x53,0x80,0x30,0x3C,0x92,0x0E,0x01,0x00,0x00, "Nikon", "JAA798DA", "AF-S DX VR Zoom-Nikkor 55-200mm f/4-5.6G IF-ED"}, //91 93 {0x92,0x48,0x24,0x37,0x24,0x24,0x94,0x06,0x01,0x00,0x00, "Nikon", "JAA801DA", "AF-S Zoom-Nikkor 14-24mm f/2.8G ED"}, {0x93,0x48,0x37,0x5C,0x24,0x24,0x95,0x06,0x01,0x00,0x00, "Nikon", "JAA802DA", "AF-S Zoom-Nikkor 24-70mm f/2.8G ED"}, {0x94,0x40,0x2D,0x53,0x2C,0x3C,0x96,0x06,0x01,0x00,0x00, "Nikon", "JAA797DA", "AF-S DX Zoom-Nikkor 18-55mm f/3.5-5.6G ED II"}, {0x95,0x4C,0x37,0x37,0x2C,0x2C,0x97,0x02,0x00,0x00,0x00, "Nikon", "JAA631DA", "PC-E Nikkor 24mm f/3.5D ED"}, {0x95,0x00,0x37,0x37,0x2C,0x2C,0x97,0x06,0x00,0x00,0x00, "Nikon", "JAA631DA", "PC-E Nikkor 24mm f/3.5D ED"}, {0x96,0x48,0x98,0x98,0x24,0x24,0x98,0x0E,0x13,0x00,0x00, "Nikon", "JAA528DA", "AF-S VR Nikkor 400mm f/2.8G ED"}, {0x97,0x3C,0xA0,0xA0,0x30,0x30,0x99,0x0E,0x13,0x00,0x00, "Nikon", "JAA529DA", "AF-S VR Nikkor 500mm f/4G ED"}, {0x98,0x3C,0xA6,0xA6,0x30,0x30,0x9A,0x0E,0x13,0x00,0x00, "Nikon", "JAA530DA", "AF-S VR Nikkor 600mm f/4G ED"}, {0x99,0x40,0x29,0x62,0x2C,0x3C,0x9B,0x0E,0x01,0x00,0x00, "Nikon", "JAA800DA", "AF-S DX VR Zoom-Nikkor 16-85mm f/3.5-5.6G ED"}, {0x9A,0x40,0x2D,0x53,0x2C,0x3C,0x9C,0x0E,0x01,0x00,0x00, "Nikon", "JAA803DA", "AF-S DX VR Zoom-Nikkor 18-55mm f/3.5-5.6G"}, {0x9B,0x54,0x4C,0x4C,0x24,0x24,0x9D,0x02,0x00,0x00,0x00, "Nikon", "JAA633DA", "PC-E Micro Nikkor 45mm f/2.8D ED"}, {0x9B,0x00,0x4C,0x4C,0x24,0x24,0x9D,0x06,0x00,0x00,0x00, "Nikon", "JAA633DA", "PC-E Micro Nikkor 45mm f/2.8D ED"}, {0x9C,0x54,0x56,0x56,0x24,0x24,0x9E,0x06,0x41,0x00,0x00, "Nikon", "JAA632DA", "AF-S Micro Nikkor 60mm f/2.8G ED"}, {0x9D,0x54,0x62,0x62,0x24,0x24,0x9F,0x02,0x40,0x00,0x00, "Nikon", "JAA634DA", "PC-E Micro Nikkor 85mm f/2.8D"}, {0x9D,0x00,0x62,0x62,0x24,0x24,0x9F,0x06,0x40,0x00,0x00, "Nikon", "JAA634DA", "PC-E Micro Nikkor 85mm f/2.8D"}, {0x9E,0x40,0x2D,0x6A,0x2C,0x3C,0xA0,0x0E,0x01,0x00,0x00, "Nikon", "JAA805DA", "AF-S DX VR Zoom-Nikkor 18-105mm f/3.5-5.6G ED"}, {0x9F,0x58,0x44,0x44,0x14,0x14,0xA1,0x06,0x01,0x00,0x00, "Nikon", "JAA132DA", "AF-S DX Nikkor 35mm f/1.8G"}, {0xA0,0x54,0x50,0x50,0x0C,0x0C,0xA2,0x06,0x01,0x00,0x00, "Nikon", "JAA014DA", "AF-S Nikkor 50mm f/1.4G"}, {0xA1,0x40,0x18,0x37,0x2C,0x34,0xA3,0x06,0x01,0x00,0x00, "Nikon", "JAA804DA", "AF-S DX Nikkor 10-24mm f/3.5-4.5G ED"}, {0xA2,0x48,0x5C,0x80,0x24,0x24,0xA4,0x0E,0x13,0x00,0x00, "Nikon", "JAA807DA", "AF-S Nikkor 70-200mm f/2.8G ED VR II"}, {0xA3,0x3C,0x29,0x44,0x30,0x30,0xA5,0x0E,0x01,0x00,0x00, "Nikon", "JAA806DA", "AF-S Nikkor 16-35mm f/4G ED VR"}, {0xA4,0x54,0x37,0x37,0x0C,0x0C,0xA6,0x06,0x01,0x00,0x00, "Nikon", "JAA131DA", "AF-S Nikkor 24mm f/1.4G ED"}, {0xA5,0x40,0x3C,0x8E,0x2C,0x3C,0xA7,0x0E,0x01,0x00,0x00, "Nikon", "JAA808DA", "AF-S Nikkor 28-300mm f/3.5-5.6G ED VR"}, {0xA6,0x48,0x8E,0x8E,0x24,0x24,0xA8,0x0E,0x13,0x00,0x00, "Nikon", "JAA339DA", "AF-S VR Nikkor 300mm f/2.8G IF-ED II"}, {0xA7,0x4B,0x62,0x62,0x2C,0x2C,0xA9,0x0E,0x41,0x00,0x00, "Nikon", "JAA637DA", "AF-S DX Micro Nikkor 85mm f/3.5G ED VR"}, {0xA8,0x48,0x80,0x98,0x30,0x30,0xAA,0x0E,0x03,0x00,0x00, "Nikon", "JAA809DA", "AF-S VR Zoom-Nikkor 200-400mm f/4G IF-ED II"}, {0xA9,0x54,0x80,0x80,0x18,0x18,0xAB,0x0E,0x13,0x00,0x00, "Nikon", "JAA340DA", "AF-S Nikkor 200mm f/2G ED VR II"}, {0xAA,0x3C,0x37,0x6E,0x30,0x30,0xAC,0x0E,0x01,0x00,0x00, "Nikon", "JAA811DA", "AF-S Nikkor 24-120mm f/4G ED VR"}, //AB AD {0xAC,0x38,0x53,0x8E,0x34,0x3C,0xAE,0x0E,0x01,0x00,0x00, "Nikon", "JAA814DA", "AF-S DX VR Nikkor 55-300mm 4.5-5.6G ED"}, //AD AF {0xAE,0x54,0x62,0x62,0x0C,0x0C,0xB0,0x06,0x01,0x00,0x00, "Nikon", "JAA338DA", "AF-S Nikkor 85mm f/1.4G"}, {0xAF,0x54,0x44,0x44,0x0C,0x0C,0xB1,0x06,0x01,0x00,0x00, "Nikon", "JAA134DA", "AF-S Nikkor 35mm f/1.4G"}, {0xB0,0x4C,0x50,0x50,0x14,0x14,0xB2,0x06,0x01,0x00,0x00, "Nikon", "JAA015DA", "AF-S Nikkor 50mm f/1.8G"}, {0xB1,0x48,0x48,0x48,0x24,0x24,0xB3,0x06,0x01,0x00,0x00, "Nikon", "JAA638DA", "AF-S DX Micro Nikkor 40mm f/2.8G"}, //B2 {0xB3,0x4C,0x62,0x62,0x14,0x14,0xB5,0x06,0x01,0x00,0x00, "Nikon", "JAA341DA", "AF-S Nikkor 85mm f/1.8G"}, // {0x01,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00, "Nikon", "JAA90701", "TC-16A"}, {0x01,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00, "Nikon", "JAA90701", "TC-16A"}, // //------------------------------------------------------------------------------ // Sigma lenses by focal length, first fixed then zoom lenses //------------------------------------------------------------------------------ // {0xFE,0x47,0x00,0x00,0x24,0x24,0x4B,0x06,0x01,0x00,0x05, "Sigma", "486556", "4.5mm F2.8 EX DC HSM Circular Fisheye"}, {0x26,0x48,0x11,0x11,0x30,0x30,0x1C,0x02,0x00,0x00,0x05, "Sigma", "483", "8mm F4 EX Circular Fisheye"}, {0x79,0x40,0x11,0x11,0x2C,0x2C,0x1C,0x06,0x00,0x00,0x05, "Sigma", "485597", "8mm F3.5 EX Circular Fisheye"}, {0xDC,0x48,0x19,0x19,0x24,0x24,0x4B,0x06,0x01,0x00,0x05, "Sigma", "477554", "10mm F2.8 EX DC HSM Fisheye"}, {0x02,0x3F,0x24,0x24,0x2C,0x2C,0x02,0x00,0x00,0x00,0x05, "Sigma", "468", "14mm F3.5"}, {0x48,0x48,0x24,0x24,0x24,0x24,0x4B,0x02,0x01,0x00,0x05, "Sigma", "", "14mm F2.8 EX Aspherical HSM"}, {0x26,0x48,0x27,0x27,0x24,0x24,0x1C,0x02,0x00,0x00,0x05, "Sigma", "476441", "15mm F2.8 EX Diagonal Fisheye"}, //M "Sigma" "410" "18mm F3.5"; {0x26,0x58,0x31,0x31,0x14,0x14,0x1C,0x02,0x00,0x00,0x05, "Sigma", "411442", "20mm F1.8 EX DG Aspherical RF"}, {0x26,0x58,0x37,0x37,0x14,0x14,0x1C,0x02,0x00,0x00,0x05, "Sigma", "432447", "24mm F1.8 EX DG Aspherical Macro"}, {0xE1,0x58,0x37,0x37,0x14,0x14,0x1C,0x02,0x00,0x00,0x05, "Sigma", "432447", "24mm F1.8 EX DG Aspherical Macro"}, {0x02,0x46,0x37,0x37,0x25,0x25,0x02,0x00,0x00,0x00,0x05, "Sigma", "438", "24mm F2.8 Super Wide II Macro"}, {0x26,0x58,0x3C,0x3C,0x14,0x14,0x1C,0x02,0x00,0x00,0x05, "Sigma", "440442", "28mm F1.8 EX DG Aspherical Macro"}, {0x48,0x54,0x3E,0x3E,0x0C,0x0C,0x4B,0x06,0x01,0x00,0x05, "Sigma", "477554", "30mm F1.4 EX DC HSM"}, {0xF8,0x54,0x3E,0x3E,0x0C,0x0C,0x4B,0x06,0x01,0x00,0x05, "Sigma", "477554", "30mm F1.4 EX DC HSM"}, {0xDE,0x54,0x50,0x50,0x0C,0x0C,0x4B,0x06,0x01,0x00,0x05, "Sigma", "310554", "50mm F1.4 EX DG HSM"}, {0x02,0x48,0x50,0x50,0x24,0x24,0x02,0x00,0x00,0x00,0x05, "Sigma", "", "Macro 50mm F2.8"}, {0x32,0x54,0x50,0x50,0x24,0x24,0x35,0x02,0x00,0x00,0x05, "Sigma", "346447", "Macro 50mm F2.8 EX DG"}, {0xE3,0x54,0x50,0x50,0x24,0x24,0x35,0x02,0x00,0x00,0x05, "Sigma", "", "Macro 50mm F2.8 EX DG"}, {0x79,0x48,0x5C,0x5C,0x24,0x24,0x1C,0x06,0x00,0x00,0x05, "Sigma", "270599", "Macro 70mm F2.8 EX DG"}, {0x9B,0x54,0x62,0x62,0x0C,0x0C,0x4B,0x06,0x00,0x00,0x05, "Sigma", "", "85mm F1.4 EX DG HSM"}, {0x02,0x48,0x65,0x65,0x24,0x24,0x02,0x00,0x00,0x00,0x05, "Sigma", "", "Macro 90mm F2.8"}, {0x32,0x54,0x6A,0x6A,0x24,0x24,0x35,0x02,0x00,0x02,0x05, "Sigma", "256", "Macro 105mm F2.8 EX DG"}, {0xE5,0x54,0x6A,0x6A,0x24,0x24,0x35,0x02,0x40,0x00,0x05, "Sigma", "257446", "Macro 105mm F2.8 EX DG"}, {0x48,0x48,0x76,0x76,0x24,0x24,0x4B,0x06,0x43,0x00,0x05, "Sigma", "104559", "APO Macro 150mm F2.8 EX DG HSM"}, {0xF5,0x48,0x76,0x76,0x24,0x24,0x4B,0x06,0x43,0x00,0x05, "Sigma", "104559", "APO Macro 150mm F2.8 EX DG HSM"}, {0x48,0x4C,0x7C,0x7C,0x2C,0x2C,0x4B,0x02,0x43,0x00,0x05, "Sigma", "", "APO Macro 180mm F3.5 EX DG HSM"}, {0x48,0x4C,0x7D,0x7D,0x2C,0x2C,0x4B,0x02,0x43,0x00,0x05, "Sigma", "105556", "APO Macro 180mm F3.5 EX DG HSM"}, //M "Sigma" "" "APO 300mm F2.8"; {0x48,0x54,0x8E,0x8E,0x24,0x24,0x4B,0x02,0x03,0x00,0x05, "Sigma", "", "APO 300mm F2.8 EX DG HSM"}, {0xFB,0x54,0x8E,0x8E,0x24,0x24,0x4B,0x02,0x13,0x00,0x05, "Sigma", "195557", "APO 300mm F2.8 EX DG HSM"}, {0x26,0x48,0x8E,0x8E,0x30,0x30,0x1C,0x02,0x00,0x00,0x05, "Sigma", "", "APO Tele Macro 300mm F4"}, {0x02,0x2F,0x98,0x98,0x3D,0x3D,0x02,0x00,0x00,0x00,0x05, "Sigma", "", "APO 400mm F5.6"}, {0x26,0x3C,0x98,0x98,0x3C,0x3C,0x1C,0x02,0x00,0x00,0x05, "Sigma", "", "APO Tele Macro 400mm F5.6"}, {0x02,0x37,0xA0,0xA0,0x34,0x34,0x02,0x00,0x00,0x00,0x05, "Sigma", "", "APO 500mm F4.5"}, {0x48,0x44,0xA0,0xA0,0x34,0x34,0x4B,0x02,0x03,0x00,0x05, "Sigma", "", "APO 500mm F4.5 EX HSM"}, {0xF1,0x44,0xA0,0xA0,0x34,0x34,0x4B,0x02,0x03,0x00,0x05, "Sigma", "184551", "APO 500mm F4.5 EX DG HSM"}, {0x02,0x34,0xA0,0xA0,0x44,0x44,0x02,0x00,0x00,0x00,0x05, "Sigma", "", "APO 500mm F7.2"}, {0x02,0x3C,0xB0,0xB0,0x3C,0x3C,0x02,0x00,0x00,0x00,0x05, "Sigma", "", "APO 800mm F5.6"}, {0x48,0x3C,0xB0,0xB0,0x3C,0x3C,0x4B,0x02,0x03,0x00,0x05, "Sigma", "", "APO 800mm F5.6 EX HSM"}, //M "Sigma" "152550" "APO 800mm F5.6 EX DG HSM"; //M2 B8 B8 49 49 02" "00" "00" "00" "05" "Sigma" "" "APO 1000mm F8.0"; // {0x9E,0x38,0x11,0x29,0x34,0x3C,0x4B,0x06,0x01,0x00,0x05, "Sigma", "", "8-16mm F4.5-5.6 DC HSM"}, {0xA1,0x41,0x19,0x31,0x2C,0x2C,0x4B,0x06,0x01,0x00,0x05, "Sigma", "", "10-20mm F3.5 EX DC HSM"}, {0x48,0x3C,0x19,0x31,0x30,0x3C,0x4B,0x06,0x01,0x00,0x05, "Sigma", "201555", "10-20mm F4-5.6 EX DC HSM"}, {0xF9,0x3C,0x19,0x31,0x30,0x3C,0x4B,0x06,0x01,0x00,0x05, "Sigma", "201555", "10-20mm F4-5.6 EX DC HSM"}, {0x48,0x38,0x1F,0x37,0x34,0x3C,0x4B,0x06,0x00,0x00,0x05, "Sigma", "200558", "12-24mm F4.5-5.6 EX DG Aspherical HSM"}, {0xF0,0x38,0x1F,0x37,0x34,0x3C,0x4B,0x06,0x00,0x00,0x05, "Sigma", "200558", "12-24mm F4.5-5.6 EX DG Aspherical HSM"}, {0x26,0x40,0x27,0x3F,0x2C,0x34,0x1C,0x02,0x00,0x00,0x05, "Sigma", "", "15-30mm F3.5-4.5 EX DG Aspherical DF"}, {0x48,0x48,0x2B,0x44,0x24,0x30,0x4B,0x06,0x00,0x00,0x05, "Sigma", "", "17-35mm F2.8-4 EX DG Aspherical HSM"}, {0x26,0x54,0x2B,0x44,0x24,0x30,0x1C,0x02,0x00,0x00,0x05, "Sigma", "", "17-35mm F2.8-4 EX Aspherical"}, {0x9D,0x48,0x2B,0x50,0x24,0x24,0x4B,0x0E,0x00,0x00,0x05, "Sigma", "", "17-50mm F2.8 EX DC OS HSM"}, {0x7A,0x47,0x2B,0x5C,0x24,0x34,0x4B,0x06,0x00,0x00,0x05, "Sigma", "689599", "17-70mm F2.8-4.5 DC Macro Asp. IF HSM"}, {0x7A,0x48,0x2B,0x5C,0x24,0x34,0x4B,0x06,0x00,0x00,0x05, "Sigma", "689599", "17-70mm F2.8-4.5 DC Macro Asp. IF HSM"}, {0x7F,0x48,0x2B,0x5C,0x24,0x34,0x1C,0x06,0x00,0x00,0x05, "Sigma", "", "17-70mm F2.8-4.5 DC Macro Asp. IF"}, {0x26,0x40,0x2D,0x44,0x2B,0x34,0x1C,0x02,0x00,0x00,0x05, "Sigma", "", "18-35 F3.5-4.5 Aspherical"}, {0x26,0x48,0x2D,0x50,0x24,0x24,0x1C,0x06,0x00,0x00,0x05, "Sigma", "", "18-50mm F2.8 EX DC"}, {0x7F,0x48,0x2D,0x50,0x24,0x24,0x1C,0x06,0x00,0x00,0x05, "Sigma", "", "18-50mm F2.8 EX DC Macro"}, {0x7A,0x48,0x2D,0x50,0x24,0x24,0x4B,0x06,0x01,0x00,0x05, "Sigma", "582593", "18-50mm F2.8 EX DC Macro"}, {0xF6,0x48,0x2D,0x50,0x24,0x24,0x4B,0x06,0x01,0x00,0x05, "Sigma", "582593", "18-50mm F2.8 EX DC Macro"}, {0xA4,0x47,0x2D,0x50,0x24,0x34,0x4B,0x0E,0x01,0x00,0x05, "Sigma", "", "18-50mm F2.8-4.5 DC OS HSM"}, {0x26,0x40,0x2D,0x50,0x2C,0x3C,0x1C,0x06,0x00,0x00,0x05, "Sigma", "", "18-50mm F3.5-5.6 DC"}, {0x7A,0x40,0x2D,0x50,0x2C,0x3C,0x4B,0x06,0x01,0x00,0x05, "Sigma", "551551", "18-50mm F3.5-5.6 DC HSM"}, {0x26,0x40,0x2D,0x70,0x2B,0x3C,0x1C,0x06,0x00,0x00,0x05, "Sigma", "", "18-125mm F3.5-5.6 DC"}, {0xCD,0x3D,0x2D,0x70,0x2E,0x3C,0x4B,0x0E,0x01,0x00,0x05, "Sigma", "853556", "18-125mm F3.8-5.6 DC OS HSM"}, {0x26,0x40,0x2D,0x80,0x2C,0x40,0x1C,0x06,0x00,0x00,0x05, "Sigma", "777555", "18-200mm F3.5-6.3 DC"}, {0x7A,0x40,0x2D,0x80,0x2C,0x40,0x4B,0x0E,0x01,0x00,0x05, "Sigma", "888558", "18-200mm F3.5-6.3 DC OS HSM"}, {0xED,0x40,0x2D,0x80,0x2C,0x40,0x4B,0x0E,0x01,0x00,0x05, "Sigma", "888558", "18-200mm F3.5-6.3 DC OS HSM"}, {0xA5,0x40,0x2D,0x88,0x2C,0x40,0x4B,0x0E,0x01,0x00,0x05, "Sigma", "", "18-250mm F3.5-6.3 DC OS HSM"}, {0x26,0x48,0x31,0x49,0x24,0x24,0x1C,0x02,0x00,0x00,0x05, "Sigma", "", "20-40mm F2.8"}, {0x26,0x48,0x37,0x56,0x24,0x24,0x1C,0x02,0x00,0x00,0x05, "Sigma", "547448", "24-60mm F2.8 EX DG"}, {0xB6,0x48,0x37,0x56,0x24,0x24,0x1C,0x02,0x00,0x00,0x05, "Sigma", "547448", "24-60mm F2.8 EX DG"}, {0xA6,0x48,0x37,0x5C,0x24,0x24,0x4B,0x06,0x01,0x00,0x05, "Sigma", "571559", "24-70mm F2.8 IF EX DG HSM"}, {0x26,0x54,0x37,0x5C,0x24,0x24,0x1C,0x02,0x00,0x00,0x05, "Sigma", "", "24-70mm F2.8 EX DG Macro"}, {0x67,0x54,0x37,0x5C,0x24,0x24,0x1C,0x02,0x00,0x00,0x05, "Sigma", "548445", "24-70mm F2.8 EX DG Macro"}, {0xE9,0x54,0x37,0x5C,0x24,0x24,0x1C,0x02,0x00,0x00,0x05, "Sigma", "548445", "24-70mm F2.8 EX DG Macro"}, {0x26,0x40,0x37,0x5C,0x2C,0x3C,0x1C,0x02,0x00,0x00,0x05, "Sigma", "", "24-70mm F3.5-5.6 Aspherical HF"}, {0x26,0x54,0x37,0x73,0x24,0x34,0x1C,0x02,0x00,0x00,0x05, "Sigma", "", "24-135mm F2.8-4.5"}, {0x02,0x46,0x3C,0x5C,0x25,0x25,0x02,0x00,0x00,0x00,0x05, "Sigma", "", "28-70mm F2.8"}, {0x26,0x54,0x3C,0x5C,0x24,0x24,0x1C,0x02,0x00,0x00,0x05, "Sigma", "", "28-70mm F2.8 EX"}, {0x26,0x48,0x3C,0x5C,0x24,0x24,0x1C,0x06,0x00,0x00,0x05, "Sigma", "549442", "28-70mm F2.8 EX DG"}, {0x26,0x48,0x3C,0x5C,0x24,0x30,0x1C,0x02,0x00,0x00,0x05, "Sigma", "634445", "28-70mm F2.8-4 DG"}, {0x02,0x3F,0x3C,0x5C,0x2D,0x35,0x02,0x00,0x00,0x00,0x05, "Sigma", "", "28-70mm F3.5-4.5 UC"}, {0x26,0x40,0x3C,0x60,0x2C,0x3C,0x1C,0x02,0x00,0x00,0x05, "Sigma", "", "28-80mm F3.5-5.6 Mini Zoom Macro II Aspherical"}, {0x26,0x40,0x3C,0x65,0x2C,0x3C,0x1C,0x02,0x00,0x00,0x05, "Sigma", "", "28-90mm F3.5-5.6 Macro"}, {0x26,0x48,0x3C,0x6A,0x24,0x30,0x1C,0x02,0x00,0x00,0x05, "Sigma", "", "28-105mm F2.8-4 Aspherical"}, {0x26,0x3E,0x3C,0x6A,0x2E,0x3C,0x1C,0x02,0x00,0x00,0x05, "Sigma", "", "28-105mm F3.8-5.6 UC-III Aspherical IF"}, {0x26,0x40,0x3C,0x80,0x2C,0x3C,0x1C,0x02,0x00,0x00,0x05, "Sigma", "", "28-200mm F3.5-5.6 Compact Aspherical Hyperzoom Macro"}, {0x26,0x40,0x3C,0x80,0x2B,0x3C,0x1C,0x02,0x00,0x00,0x05, "Sigma", "", "28-200mm F3.5-5.6 Compact Aspherical Hyperzoom Macro"}, {0x26,0x3D,0x3C,0x80,0x2F,0x3D,0x1C,0x02,0x00,0x00,0x05, "Sigma", "", "28-300mm F3.8-5.6 Aspherical"}, {0x26,0x41,0x3C,0x8E,0x2C,0x40,0x1C,0x02,0x00,0x00,0x05, "Sigma", "795443", "28-300mm F3.5-6.3 DG Macro"}, {0xE6,0x41,0x3C,0x8E,0x2C,0x40,0x1C,0x02,0x00,0x00,0x05, "Sigma", "", "28-300mm F3.5-6.3 DG Macro"}, {0x26,0x40,0x3C,0x8E,0x2C,0x40,0x1C,0x02,0x00,0x00,0x05, "Sigma", "", "28-300mm F3.5-6.3 Macro"}, {0x02,0x3B,0x44,0x61,0x30,0x3D,0x02,0x00,0x00,0x00,0x05, "Sigma", "", "35-80mm F4-5.6"}, {0x02,0x40,0x44,0x73,0x2B,0x36,0x02,0x00,0x00,0x00,0x05, "Sigma", "", "35-135mm F3.5-4.5 a"}, {0x7A,0x47,0x50,0x76,0x24,0x24,0x4B,0x06,0x03,0x00,0x05, "Sigma", "", "50-150mm F2.8 EX APO DC HSM"}, {0xFD,0x47,0x50,0x76,0x24,0x24,0x4B,0x06,0x03,0x00,0x05, "Sigma", "691554", "50-150mm F2.8 EX APO DC HSM II"}, {0x48,0x3C,0x50,0xA0,0x30,0x40,0x4B,0x02,0x03,0x00,0x05, "Sigma", "736552", "APO 50-500mm F4-6.3 EX HSM"}, {0x9F,0x37,0x50,0xA0,0x34,0x40,0x4B,0x0E,0x03,0x00,0x05, "Sigma", "", "50-500mm F4.5-6.3 APO DG OS HSM"}, //M "Sigma" "686550" "50-200mm F4-5.6 DC OS HSM"; {0x26,0x3C,0x54,0x80,0x30,0x3C,0x1C,0x06,0x00,0x00,0x05, "Sigma", "", "55-200mm F4-5.6 DC"}, {0x7A,0x3B,0x53,0x80,0x30,0x3C,0x4B,0x06,0x01,0x00,0x05, "Sigma", "", "55-200mm F4-5.6 DC HSM"}, {0x48,0x54,0x5C,0x80,0x24,0x24,0x4B,0x02,0x00,0x00,0x05, "Sigma", "", "70-200mm F2.8 EX APO IF HSM"}, {0x7A,0x48,0x5C,0x80,0x24,0x24,0x4B,0x06,0x03,0x00,0x05, "Sigma", "", "70-200mm F2.8 EX APO DG Macro HSM II"}, {0xEE,0x48,0x5C,0x80,0x24,0x24,0x4B,0x06,0x03,0x00,0x05, "Sigma", "579555", "70-200mm F2.8 EX APO DG Macro HSM II"}, {0x9C,0x48,0x5C,0x80,0x24,0x24,0x4B,0x0E,0x03,0x00,0x05, "Sigma", "", "70-200mm F2.8 EX DG OS HSM"}, {0x02,0x46,0x5C,0x82,0x25,0x25,0x02,0x00,0x00,0x00,0x05, "Sigma", "", "70-210mm F2.8 APO"}, {0x26,0x3C,0x5C,0x82,0x30,0x3C,0x1C,0x02,0x00,0x00,0x05, "Sigma", "", "70-210mm F4-5.6 UC-II"}, {0x26,0x3C,0x5C,0x8E,0x30,0x3C,0x1C,0x02,0x00,0x00,0x05, "Sigma", "", "70-300mm F4-5.6 DG Macro"}, {0x56,0x3C,0x5C,0x8E,0x30,0x3C,0x1C,0x02,0x00,0x00,0x05, "Sigma", "", "70-300mm F4-5.6 APO Macro Super II"}, {0xE0,0x3C,0x5C,0x8E,0x30,0x3C,0x4B,0x06,0x00,0x00,0x05, "Sigma", "508555", "APO 70-300mm F4-5.6 DG Macro"}, {0xA3,0x3C,0x5C,0x8E,0x30,0x3C,0x4B,0x0E,0x00,0x00,0x05, "Sigma", "572556", "70-300mm F4-5.6 DG OS"}, {0x02,0x37,0x5E,0x8E,0x35,0x3D,0x02,0x00,0x00,0x00,0x05, "Sigma", "", "75-300mm F4.5-5.6 APO"}, {0x02,0x3A,0x5E,0x8E,0x32,0x3D,0x02,0x00,0x00,0x00,0x05, "Sigma", "", "75-300mm F4.0-5.6"}, {0x77,0x44,0x61,0x98,0x34,0x3C,0x7B,0x0E,0x03,0x00,0x05, "Sigma", "", "80-400mm f4.5-5.6 EX OS"}, {0x48,0x48,0x68,0x8E,0x30,0x30,0x4B,0x02,0x03,0x00,0x05, "Sigma", "134556", "APO 100-300mm F4 EX IF HSM"}, {0xF3,0x48,0x68,0x8E,0x30,0x30,0x4B,0x02,0x13,0x00,0x05, "Sigma", "134556", "APO 100-300mm F4 EX IF HSM"}, {0x48,0x54,0x6F,0x8E,0x24,0x24,0x4B,0x02,0x03,0x00,0x05, "Sigma", "", "APO 120-300mm F2.8 EX DG HSM"}, {0x7A,0x54,0x6E,0x8E,0x24,0x24,0x4B,0x02,0x03,0x00,0x05, "Sigma", "135553", "APO 120-300mm F2.8 EX DG HSM"}, {0xFA,0x54,0x6E,0x8E,0x24,0x24,0x4B,0x02,0x03,0x00,0x05, "Sigma", "135553", "APO 120-300mm F2.8 EX DG HSM"}, {0xCF,0x38,0x6E,0x98,0x34,0x3C,0x4B,0x0E,0x03,0x00,0x05, "Sigma", "728557", "APO 120-400mm F4.5-5.6 DG OS HSM"}, {0x26,0x44,0x73,0x98,0x34,0x3C,0x1C,0x02,0x00,0x00,0x05, "Sigma", "", "135-400mm F4.5-5.6 APO Aspherical"}, {0xCE,0x34,0x76,0xA0,0x38,0x40,0x4B,0x0E,0x03,0x00,0x05, "Sigma", "737559", "APO 150-500mm F5-6.3 DG OS HSM"}, {0x26,0x40,0x7B,0xA0,0x34,0x40,0x1C,0x02,0x00,0x00,0x05, "Sigma", "", "APO 170-500mm F5-6.3 Aspherical RF"}, {0xA7,0x49,0x80,0xA0,0x24,0x24,0x4B,0x06,0x03,0x00,0x05, "Sigma", "", "APO 200-500mm F2.8 EX DG"}, {0x48,0x3C,0x8E,0xB0,0x3C,0x3C,0x4B,0x02,0x03,0x00,0x05, "Sigma", "595555", "APO 300-800mm F5.6 EX DG HSM"}, // //------------------------------------------------------------------------------ // Tamron lenses by focal length, first fixed then zoom lenses //------------------------------------------------------------------------------ // {0x00,0x47,0x25,0x25,0x24,0x24,0x00,0x02,0x00,0x00,0x02, "Tamron", "69E", "SP AF 14mm F/2.8 Aspherical (IF)"}, {0xF4,0x54,0x56,0x56,0x18,0x18,0x84,0x06,0x01,0x00,0x02, "Tamron", "G005", "SP AF 60mm F/2 Di II LD (IF) Macro 1:1"}, {0x1E,0x5D,0x64,0x64,0x20,0x20,0x13,0x00,0x40,0x00,0x02, "Tamron", "52E", "SP AF 90mm F/2.5"}, {0x20,0x5A,0x64,0x64,0x20,0x20,0x14,0x00,0x40,0x00,0x02, "Tamron", "152E", "SP AF 90mm F/2.5 Macro"}, {0x22,0x53,0x64,0x64,0x24,0x24,0xE0,0x02,0x40,0x00,0x02, "Tamron", "72E", "SP AF 90mm F/2.8 Macro 1:1"}, {0x32,0x53,0x64,0x64,0x24,0x24,0x35,0x02,0x40,0x01,0x02, "Tamron", "172E", "SP AF 90mm F/2.8 Macro 1:1"}, {0x32,0x53,0x64,0x64,0x24,0x24,0x35,0x02,0x40,0x02,0x02, "Tamron", "272E", "SP AF 90mm F/2.8 Di Macro 1:1"}, {0xF8,0x55,0x64,0x64,0x24,0x24,0x84,0x06,0x41,0x00,0x02, "Tamron", "272NII", "SP AF 90mm F/2.8 Di Macro 1:1"}, {0xF8,0x54,0x64,0x64,0x24,0x24,0xDF,0x06,0x41,0x00,0x02, "Tamron", "272NII", "SP AF 90mm F/2.8 Di Macro 1:1"}, {0x00,0x4C,0x7C,0x7C,0x2C,0x2C,0x00,0x02,0x00,0x00,0x02, "Tamron", "B01", "SP AF 180mm F/3.5 Di Model"}, {0x21,0x56,0x8E,0x8E,0x24,0x24,0x14,0x00,0x00,0x00,0x02, "Tamron", "60E", "SP AF 300mm F/2.8 LD-IF"}, {0x27,0x54,0x8E,0x8E,0x24,0x24,0x1D,0x02,0x00,0x00,0x02, "Tamron", "360E", "SP AF 300mm F/2.8 LD-IF"}, // {0xF6,0x3F,0x18,0x37,0x2C,0x34,0x84,0x06,0x01,0x00,0x02, "Tamron", "B001", "SP AF 10-24mm F/3.5-4.5 Di II LD Aspherical (IF)"}, {0x00,0x36,0x1C,0x2D,0x34,0x3C,0x00,0x06,0x00,0x00,0x02, "Tamron", "A13", "SP AF 11-18mm F/4.5-5.6 Di II LD Aspherical (IF)"}, {0x07,0x46,0x2B,0x44,0x24,0x30,0x03,0x02,0x00,0x00,0x02, "Tamron", "A05", "SP AF 17-35mm F/2.8-4 Di LD Aspherical (IF)"}, {0x00,0x53,0x2B,0x50,0x24,0x24,0x00,0x06,0x00,0x00,0x02, "Tamron", "A16", "SP AF 17-50mm F/2.8 XR Di II LD Aspherical (IF)"}, {0x00,0x54,0x2B,0x50,0x24,0x24,0x00,0x06,0x01,0x00,0x02, "Tamron", "A16NII", "SP AF 17-50mm F/2.8 XR Di II LD Aspherical (IF)"}, {0xFB,0x54,0x2B,0x50,0x24,0x24,0x84,0x06,0x01,0x00,0x02, "Tamron", "A16NII", "SP AF 17-50mm F/2.8 XR Di II LD Aspherical (IF)"}, {0xF3,0x54,0x2B,0x50,0x24,0x24,0x84,0x0E,0x01,0x00,0x02, "Tamron", "B005", "SP AF 17-50mm F/2.8 XR Di II VC LD Aspherical (IF)"}, {0x00,0x3F,0x2D,0x80,0x2B,0x40,0x00,0x06,0x00,0x00,0x02, "Tamron", "A14", "AF 18-200mm F/3.5-6.3 XR Di II LD Aspherical (IF)"}, {0x00,0x3F,0x2D,0x80,0x2C,0x40,0x00,0x06,0x00,0x00,0x02, "Tamron", "A14", "AF 18-200mm F/3.5-6.3 XR Di II LD Aspherical (IF) Macro"}, {0x00,0x40,0x2D,0x80,0x2C,0x40,0x00,0x06,0x01,0x00,0x02, "Tamron", "A14NII", "AF 18-200mm F/3.5-6.3 XR Di II LD Aspherical (IF) Macro"}, {0xFC,0x40,0x2D,0x80,0x2C,0x40,0xDF,0x06,0x01,0x00,0x02, "Tamron", "A14NII", "AF 18-200mm F/3.5-6.3 XR Di II LD Aspherical (IF) Macro"}, {0x00,0x40,0x2D,0x88,0x2C,0x40,0x62,0x06,0x00,0x00,0x02, "Tamron", "A18", "AF 18-250mm F/3.5-6.3 Di II LD Aspherical (IF) Macro"}, {0x00,0x40,0x2D,0x88,0x2C,0x40,0x00,0x06,0x01,0x00,0x02, "Tamron", "A18NII", "AF 18-250mm F/3.5-6.3 Di II LD Aspherical (IF) Macro "}, {0xF5,0x40,0x2C,0x8A,0x2C,0x40,0x40,0x0E,0x01,0x00,0x02, "Tamron", "B003", "AF 18-270mm F/3.5-6.3 Di II VC LD Aspherical (IF) Macro"}, {0xF0,0x3F,0x2D,0x8A,0x2C,0x40,0xDF,0x0E,0x01,0x00,0x02, "Tamron", "B008", "AF 18-270mm F/3.5-6.3 Di II VC PZD"}, {0x07,0x40,0x2F,0x44,0x2C,0x34,0x03,0x02,0x00,0x00,0x02, "Tamron", "A10", "AF 19-35mm F/3.5-4.5"}, {0x07,0x40,0x30,0x45,0x2D,0x35,0x03,0x02,0x00,0x00,0x02, "Tamron", "A10", "AF 19-35mm F/3.5-4.5"}, {0x00,0x49,0x30,0x48,0x22,0x2B,0x00,0x02,0x00,0x00,0x02, "Tamron", "166D", "SP AF 20-40mm F/2.7-3.5"}, {0x0E,0x4A,0x31,0x48,0x23,0x2D,0x0E,0x02,0x00,0x00,0x02, "Tamron", "166D", "SP AF 20-40mm F/2.7-3.5"}, //M "Tamron" "266D" "SP AF 20-40mm F/2.7-3.5 Aspherical-IF"; //M "Tamron" "73D" "AF 24-70mm F/3.3-5.6 Aspherical"; {0x45,0x41,0x37,0x72,0x2C,0x3C,0x48,0x02,0x00,0x00,0x02, "Tamron", "190D", "SP AF 24-135mm F/3.5-5.6 AD Aspherical (IF) Macro"}, //M "Tamron" "159D" "AF 28-70mm F/3.5-4.5"; //M "Tamron" "259D" "AF 28-70mm F/3.5-4.5"; {0x33,0x54,0x3C,0x5E,0x24,0x24,0x62,0x02,0x00,0x00,0x02, "Tamron", "A09", "SP AF 28-75mm F/2.8 XR Di LD Aspherical (IF) Macro"}, {0xFA,0x54,0x3C,0x5E,0x24,0x24,0x84,0x06,0x01,0x00,0x02, "Tamron", "A09NII", "SP AF 28-75mm F/2.8 XR Di LD Aspherical (IF) Macro"}, {0x10,0x3D,0x3C,0x60,0x2C,0x3C,0xD2,0x02,0x00,0x00,0x02, "Tamron", "177D", "AF 28-80mm F/3.5-5.6 Aspherical"}, {0x45,0x3D,0x3C,0x60,0x2C,0x3C,0x48,0x02,0x00,0x00,0x02, "Tamron", "177D", "AF 28-80mm F/3.5-5.6 Aspherical"}, {0x00,0x48,0x3C,0x6A,0x24,0x24,0x00,0x02,0x00,0x00,0x02, "Tamron", "176D", "SP AF 28-105mm F/2.8 LD Aspherical IF"}, //M "Tamron" "276D" "SP AF 28-105mm F/2.8 LD Aspherical IF"; //M "Tamron" "179D" "AF 28-105mm F4.0-5.6 IF"; //M "Tamron" "471D" "AF 28-200mm F/3.8-5.6 Aspherical IF Super2 Silver"; {0x0B,0x3E,0x3D,0x7F,0x2F,0x3D,0x0E,0x00,0x00,0x00,0x02, "Tamron", "71D", "AF 28-200mm F/3.8-5.6"}, {0x0B,0x3E,0x3D,0x7F,0x2F,0x3D,0x0E,0x02,0x00,0x00,0x02, "Tamron", "171D", "AF 28-200mm F/3.8-5.6D"}, {0x12,0x3D,0x3C,0x80,0x2E,0x3C,0xDF,0x02,0x00,0x00,0x02, "Tamron", "271D", "AF 28-200mm F/3.8-5.6 LD Aspherical (IF)"}, {0x4D,0x41,0x3C,0x8E,0x2B,0x40,0x62,0x02,0x00,0x00,0x02, "Tamron", "A061", "AF 28-300mm F/3.5-6.3 XR Di LD Aspherical (IF)"}, {0x4D,0x41,0x3C,0x8E,0x2C,0x40,0x62,0x02,0x00,0x00,0x02, "Tamron", "185D", "AF 28-300mm F/3.5-6.3 XR LD Aspherical (IF)"}, //M "Tamron" "285D" "AF 28-300mm F/3.8-6.3 LD Aspherical IF Silver"; {0xF9,0x40,0x3C,0x8E,0x2C,0x40,0x40,0x0E,0x01,0x00,0x02, "Tamron", "A20", "AF 28-300mm F/3.5-6.3 XR Di VC LD Aspherical (IF) Macro"}, //M "Tamron" "63D" "AF 35-90mm F/4-5.6"; //M "Tamron" "65D" "SP AF 35-105mm F/2.8 Aspherical"; //M "Tamron" "" "AF 35-135mm F/3.5-4.5"; {0x00,0x47,0x53,0x80,0x30,0x3C,0x00,0x06,0x00,0x00,0x02, "Tamron", "A15", "AF 55-200mm F/4-5.6 Di II LD"}, {0xF7,0x53,0x5C,0x80,0x24,0x24,0x84,0x06,0x01,0x00,0x02, "Tamron", "A001", "SP AF 70-200mm F/2.8 Di LD (IF) Macro"}, {0xFE,0x53,0x5C,0x80,0x24,0x24,0x84,0x06,0x01,0x00,0x02, "Tamron", "A001", "SP AF 70-200mm F/2.8 Di LD (IF) Macro"}, //M "Tamron" "67D" "SP AF 70-210mm f/2.8 LD"; //M "Tamron" "" "AF 70-210mm F/3.5-4.5"; //M "Tamron" "158D" "AF 70-210mm F/4-5.6"; //M "Tamron" "258D" "AF 70-210mm F/4-5.6"; //M "Tamron" "172D" "AF 70-300mm F/4-5.6"; //M "Tamron" "472D" "AF 70-300mm F/4-5.6 LD"; {0x69,0x48,0x5C,0x8E,0x30,0x3C,0x6F,0x02,0x00,0x00,0x02, "Tamron", "772D", "AF 70-300mm F/4-5.6 LD Macro 1:2"}, {0x69,0x47,0x5C,0x8E,0x30,0x3C,0x00,0x02,0x00,0x00,0x02, "Tamron", "A17N", "AF 70-300mm F/4-5.6 Di LD Macro 1:2"}, {0x00,0x48,0x5C,0x8E,0x30,0x3C,0x00,0x06,0x01,0x00,0x02, "Tamron", "A17NII", "AF 70-300mm F/4-5.6 Di LD Macro 1:2"}, {0xF1,0x47,0x5C,0x8E,0x30,0x3C,0xDF,0x0E,0x00,0x00,0x02, "Tamron", "A005", "SP 70-300mm F4-5.6 Di VC USD"}, //M "Tamron" "872D" "AF 75-300mm F/4-5.6 LD"; //M "Tamron" "278D" "AF 80-210mm F/4.5-5.6"; //M "Tamron" "62D" "AF 90-300mm F/4.5-5.6"; //M "Tamron" "186D" "AF 100-300mm F/5-6.3"; {0x20,0x3C,0x80,0x98,0x3D,0x3D,0x1E,0x02,0x00,0x00,0x02, "Tamron", "75D", "AF 200-400mm F/5.6 LD IF"}, {0x00,0x3E,0x80,0xA0,0x38,0x3F,0x00,0x02,0x00,0x00,0x02, "Tamron", "A08", "SP AF 200-500mm F/5-6.3 Di LD (IF)"}, {0x00,0x3F,0x80,0xA0,0x38,0x3F,0x00,0x02,0x00,0x00,0x02, "Tamron", "A08", "SP AF 200-500mm F/5-6.3 Di"}, // //------------------------------------------------------------------------------ // Tokina Lenses by focal length, first fixed then zoom lenses //------------------------------------------------------------------------------ // {0x00,0x40,0x2B,0x2B,0x2C,0x2C,0x00,0x02,0x00,0x00,0x03, "Tokina", "", "AT-X 17 AF PRO (AF 17mm f/3.5)"}, {0x00,0x47,0x44,0x44,0x24,0x24,0x00,0x06,0x40,0x00,0x03, "Tokina", "T303503", "AT-X M35 PRO DX (AF 35mm f/2.8 Macro)"}, {0x00,0x54,0x68,0x68,0x24,0x24,0x00,0x02,0x40,0x00,0x03, "Tokina", "T310003N", "AT-X M100 PRO D (AF 100mm f/2.8 Macro)"}, {0x27,0x48,0x8E,0x8E,0x30,0x30,0x1D,0x02,0x00,0x00,0x03, "Tokina", "", "AT-X 304 AF (AF 300mm f/4.0)"}, {0x00,0x54,0x8E,0x8E,0x24,0x24,0x00,0x02,0x00,0x00,0x03, "Tokina", "", "AT-X 300 AF PRO (AF 300mm f/2.8)"}, {0x12,0x3B,0x98,0x98,0x3D,0x3D,0x09,0x00,0x00,0x00,0x03, "Tokina", "", "AT-X 400 AF SD (AF 400mm f/5.6)"}, // {0x00,0x40,0x18,0x2B,0x2C,0x34,0x00,0x06,0x00,0x00,0x03, "Tokina", "T4101703", "AT-X 107 DX Fisheye (AF 10-17mm f/3.5-4.5)"}, {0x00,0x48,0x1C,0x29,0x24,0x24,0x00,0x06,0x00,0x00,0x03, "Tokina", "T4111603", "AT-X 116 PRO DX (AF 11-16mm f/2.8)"}, {0x00,0x3C,0x1F,0x37,0x30,0x30,0x00,0x06,0x00,0x00,0x03, "Tokina", "T4122403", "AT-X 124 AF PRO DX (AF 12-24mm f/4)"}, {0x7A,0x3C,0x1F,0x37,0x30,0x30,0x7E,0x06,0x01,0x02,0x03, "Tokina", "T4122423", "AT-X 124 AF PRO DX II (AF 12-24mm f/4)"}, {0x00,0x48,0x29,0x3C,0x24,0x24,0x00,0x06,0x00,0x00,0x03, "Tokina", "", "AT-X 16-28 AF PRO FX (AF 16-28mm f/2.8)"}, {0x00,0x48,0x29,0x50,0x24,0x24,0x00,0x06,0x00,0x00,0x03, "Tokina", "", "AT-X 165 PRO DX (AF 16-50mm f/2.8)"}, {0x00,0x40,0x2A,0x72,0x2C,0x3C,0x00,0x06,0x00,0x00,0x03, "Tokina", "", "AT-X 16.5-135 DX (AF 16.5-135mm F3.5-5.6)"}, {0x2F,0x40,0x30,0x44,0x2C,0x34,0x29,0x02,0x00,0x02,0x03, "Tokina", "", "AF 193 (AF 19-35mm f/3.5-4.5)"}, {0x2F,0x48,0x30,0x44,0x24,0x24,0x29,0x02,0x00,0x02,0x03, "Tokina", "", "AT-X 235 AF PRO (AF 20-35mm f/2.8)"}, //M "Tokina" "" "AF 235 (AF 20-35mm f/3.5-4.5)" {0x2F,0x40,0x30,0x44,0x2C,0x34,0x29,0x02,0x00,0x01,0x03, "Tokina", "", "AF 235 II (AF 20-35mm f/3.5-4.5)"}, //M "Tokina" "" "AT-X 240 AF (AF 24-40mm f/2.8)" {0x00,0x40,0x37,0x80,0x2C,0x3C,0x00,0x02,0x00,0x00,0x03, "Tokina", "", "AT-X 242 AF (AF 24-200mm f/3.5-5.6)"}, {0x25,0x48,0x3C,0x5C,0x24,0x24,0x1B,0x02,0x00,0x02,0x03, "Tokina", "", "AT-X 270 AF PRO II (AF 28-70mm f/2.6-2.8)"}, {0x25,0x48,0x3C,0x5C,0x24,0x24,0x1B,0x02,0x00,0x01,0x03, "Tokina", "", "AT-X 287 AF PRO SV (AF 28-70mm f/2.8)"}, {0x07,0x48,0x3C,0x5C,0x24,0x24,0x03,0x00,0x00,0x00,0x03, "Tokina", "", "AT-X 287 AF (AF 28-70mm f/2.8)"}, {0x07,0x47,0x3C,0x5C,0x25,0x35,0x03,0x00,0x00,0x00,0x03, "Tokina", "", "AF 287 SD (AF 28-70mm f/2.8-4.5)"}, {0x07,0x40,0x3C,0x5C,0x2C,0x35,0x03,0x00,0x00,0x00,0x03, "Tokina", "", "AF 270 II (AF 28-70mm f/3.5-4.5)"}, {0x00,0x48,0x3C,0x60,0x24,0x24,0x00,0x02,0x00,0x00,0x03, "Tokina", "", "AT-X 280 AF PRO (AF 28-80mm f/2.8)"}, //M "Tokina" "" "AF 280 II EMZ (AF 28-80mm f/3.5-5.6)" //M "Tokina" "" "AF 205 (AF 28-105mm f/3.5-4.5)" //M "Tokina" "" "AF 282 (AF 28-200mm 3.5-5.6)" //M "Tokina" "" "AF 282 EMZ II (AF 28-210mm f/4.2-6.5)" //M "Tokina" "" "AF 370 (AF 35-70mm f/3.5-4.6)" //M "Tokina" "" "AF 370 II (AF 35-70mm f/3.5-4.6)" {0x25,0x44,0x44,0x8E,0x34,0x42,0x1B,0x02,0x00,0x00,0x03, "Tokina", "", "AF 353 (AF 35-300mm f/4.5-6.7)"}, {0x00,0x48,0x50,0x72,0x24,0x24,0x00,0x06,0x00,0x00,0x03, "Tokina", "", "AT-X 535 PRO DX (AF 50-135mm f/2.8)"}, //M "Tokina" "" "AF 745 (AF 70-210mm f/4.5)" //M "Tokina" "" "AF 210 (AF 70-210mm f/4.0-5.6)" //M "Tokina" "" "AF 210 II SD (AF 70-210mm f/4.0-5.6)" {0x12,0x44,0x5E,0x8E,0x34,0x3C,0x09,0x00,0x00,0x00,0x03, "Tokina", "", "AF 730 (AF 75-300mm F4.5-5.6)"}, //M "Tokina" "" "AF 730 II (AF 75-300mm f/4.5-5.6)" {0x14,0x54,0x60,0x80,0x24,0x24,0x0B,0x00,0x00,0x00,0x03, "Tokina", "", "AT-X 828 AF (AF 80-200mm f/2.8)"}, {0x24,0x54,0x60,0x80,0x24,0x24,0x1A,0x02,0x00,0x00,0x03, "Tokina", "", "AT-X 828 AF PRO (AF 80-200mm f/2.8)"}, //M "Tokina" "" "AT-X 840 AF (AF 80-400mm f/4.5-5.6)" {0x24,0x44,0x60,0x98,0x34,0x3C,0x1A,0x02,0x00,0x00,0x03, "Tokina", "", "AT-X 840 AF-II (AF 80-400mm f/4.5-5.6)"}, {0x00,0x44,0x60,0x98,0x34,0x3C,0x00,0x02,0x00,0x00,0x03, "Tokina", "", "AT-X 840 D (AF 80-400mm f/4.5-5.6)"}, {0x14,0x48,0x68,0x8E,0x30,0x30,0x0B,0x00,0x00,0x00,0x03, "Tokina", "", "AT-X 340 AF (AF 100-300mm f/4)"}, //M "Tokina" "" "AT-X 340 AF-II (AF 100-300mm f/4)" //M "Tokina" "" "AF 130 EMZ II (AF 100-300mm f/5.6-6.7)" //M "Tokina" "" "AF 140 EMZ (AF 100-400mm f/4.5-6.3)" // //------------------------------------------------------------------------------ // Lenses from various other brands //------------------------------------------------------------------------------ // {0x06,0x3F,0x68,0x68,0x2C,0x2C,0x06,0x00,0x00,0x00,0x04, "Cosina", "", "AF 100mm F3.5 Macro"}, {0x07,0x36,0x3D,0x5F,0x2C,0x3C,0x03,0x00,0x00,0x00,0x04, "Cosina", "", "AF Zoom 28-80mm F3.5-5.6 MC Macro"}, {0x07,0x46,0x3D,0x6A,0x25,0x2F,0x03,0x00,0x00,0x00,0x04, "Cosina", "", "AF Zoom 28-105mm F2.8-3.8 MC"}, //M "Cosina" "" "AF Zoom 28-210mm F3.5-5.6"; //M "Cosina" "" "AF Zoom 28-210mm F4.2-6.5 Aspherical IF"; //M "Cosina" "" "AF Zoom 28-300mm F4.0-6.3"; //M "Cosina" "" "AF Zoom 70-210mm F2.8-4.0"; {0x12,0x36,0x5C,0x81,0x35,0x3D,0x09,0x00,0x00,0x00,0x04, "Cosina", "", "AF Zoom 70-210mm F4.5-5.6 MC Macro"}, {0x12,0x39,0x5C,0x8E,0x34,0x3D,0x08,0x02,0x00,0x00,0x04, "Cosina", "", "AF Zoom 70-300mm F4.5-5.6 MC Macro"}, {0x12,0x3B,0x68,0x8D,0x3D,0x43,0x09,0x02,0x00,0x00,0x04, "Cosina", "", "AF Zoom 100-300mm F5.6-6.7 MC Macro"}, //M "Cosina" "" "AF Zoom 100-400mm F5.6-6.7 MC"; // {0x00,0x40,0x31,0x31,0x2C,0x2C,0x00,0x00,0x00,0x00,0x34, "Voigtlander", "BA295AN", "Color Skopar 20mm F3.5 SLII Aspherical"}, {0x00,0x54,0x48,0x48,0x18,0x18,0x00,0x00,0x00,0x00,0x34, "Voigtlander", "BA229DN", "Ultron 40mm F2 SLII Aspherical"}, {0x00,0x54,0x55,0x55,0x0C,0x0C,0x00,0x00,0x00,0x00,0x34, "Voigtlander", "BA239BN", "Nokton 58mm F1.4 SLII"}, {0x00,0x40,0x64,0x64,0x2C,0x2C,0x00,0x00,0x00,0x00,0x34, "Voigtlander", "", "APO-Lanthar 90mm F3.5 SLII Close Focus"}, // {0x00,0x40,0x2D,0x2D,0x2C,0x2C,0x00,0x00,0x00,0x00,0x44, "Carl Zeiss", "", "Distagon T* 3,5/18 ZF.2"}, {0x00,0x48,0x32,0x32,0x24,0x24,0x00,0x00,0x00,0x00,0x44, "Carl Zeiss", "", "Distagon T* 2,8/21 ZF.2"}, {0x00,0x54,0x3C,0x3C,0x18,0x18,0x00,0x00,0x00,0x00,0x44, "Carl Zeiss", "", "Distagon T* 2/28 ZF.2"}, {0x00,0x54,0x44,0x44,0x18,0x18,0x00,0x00,0x00,0x00,0x44, "Carl Zeiss", "", "Distagon T* 2/35 ZF.2"}, {0x00,0x54,0x50,0x50,0x0C,0x0C,0x00,0x00,0x00,0x00,0x44, "Carl Zeiss", "", "Planar T* 1,4/50 ZF.2"}, {0x00,0x54,0x50,0x50,0x18,0x18,0x00,0x00,0x00,0x00,0x44, "Carl Zeiss", "", "Makro-Planar T* 2/50 ZF.2"}, {0x00,0x54,0x62,0x62,0x0C,0x0C,0x00,0x00,0x00,0x00,0x44, "Carl Zeiss", "", "Planar T* 1,4/85 ZF.2"}, {0x00,0x54,0x68,0x68,0x18,0x18,0x00,0x00,0x00,0x00,0x44, "Carl Zeiss", "", "Makro-Planar T* 2/100 ZF.2"}, // {0x00,0x54,0x56,0x56,0x30,0x30,0x00,0x00,0x00,0x00,0x0C, "Coastal Optical Systems", "", "60mm 1:4 UV-VIS-IR Macro Apo"}, // {0x4A,0x48,0x24,0x24,0x24,0x0C,0x4D,0x02,0x00,0x00,0x1D, "Samyang", "", "AE 14mm f/2.8 ED AS IF UMC"}, {0x4A,0x60,0x44,0x44,0x0C,0x0C,0x4D,0x02,0x00,0x00,0x1D, "Samyang", "", "35mm f/1.4 AS UMC"}, {0x4A,0x60,0x62,0x62,0x0C,0x0C,0x4D,0x02,0x00,0x00,0x1D, "Samyang", "", "AE 85mm f/1.4 AS IF UMC"}, // {0x02,0x40,0x44,0x5C,0x2C,0x34,0x02,0x00,0x00,0x00,0x15, "Exakta", "", "AF 35-70mm 1:3.5-4.5 MC"}, {0x07,0x3E,0x30,0x43,0x2D,0x35,0x03,0x00,0x00,0x00,0x14, "Soligor", "", "AF Zoom 19-35mm 1:3.5-4.5 MC"}, {0x03,0x43,0x5C,0x81,0x35,0x35,0x02,0x00,0x00,0x00,0x13, "Soligor", "", "AF C/D Zoom UMCS 70-210mm 1:4.5"}, {0x12,0x4A,0x5C,0x81,0x31,0x3D,0x09,0x00,0x00,0x00,0x13, "Soligor", "", "AF C/D Auto Zoom+Macro 70-210mm 1:4-5.6 UMCS"}, {0x12,0x36,0x69,0x97,0x35,0x42,0x09,0x00,0x00,0x00,0x14, "Soligor", "", "AF Zoom 100-400mm 1:4.5-6.7 MC"}, // {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, "Manual Lens", "", "No CPU"}, // //------------------------------------------------------------------------------ // // Lenses, that were upgraded with custom CPU // {0x00,0x47,0x10,0x10,0x24,0x24,0x00,0x00,0x00,0x00,0x00, "Nikon", "JAA604AC", "Fisheye Nikkor 8mm f/2.8 AiS"}, {0x00,0x54,0x44,0x44,0x0C,0x0C,0x00,0x00,0x00,0x00,0x00, "Nikon", "JAA115AD", "Nikkor 35mm f/1.4 AiS"}, {0x00,0x48,0x50,0x50,0x18,0x18,0x00,0x00,0x00,0x00,0x00, "Nikon", "", "Nikkor H 50mm f/2"}, {0x00,0x48,0x68,0x68,0x24,0x24,0x00,0x00,0x00,0x00,0x00, "Nikon", "JAA304AA", "Series E 100mm f/2.8"}, {0x00,0x4C,0x6A,0x6A,0x20,0x20,0x00,0x00,0x00,0x00,0x00, "Nikon", "JAA305AA", "Nikkor 105mm f/2.5 AiS"}, {0x00,0x48,0x80,0x80,0x30,0x30,0x00,0x00,0x00,0x00,0x00, "Nikon", "JAA313AA", "Nikkor 200mm f/4 AiS"}, {0x00,0x40,0x11,0x11,0x2C,0x2C,0x00,0x00,0x00,0x00,0x1D, "Samyang", "", "8mm f/3.5 Fish-Eye"}, {0x00,0x58,0x64,0x64,0x20,0x20,0x00,0x00,0x00,0x00,0x17, "Soligor", "", "C/D Macro MC 90mm f/2.5"}, // {0,0,0,0,0,0,0,0,0,0,0, NULL, NULL, NULL} }; //------------------------------------------------------------------------------ #endif // 8< - - - 8< do not remove this line >8 - - - >8 if (metadata == 0) return os << value; byte raw[] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; static const char* tags[] = { "LensIDNumber", "LensFStops", "MinFocalLength", "MaxFocalLength", "MaxApertureAtMinFocal", "MaxApertureAtMaxFocal", "MCUVersion" }; const std::string pre = std::string("Exif.") + group + std::string("."); for (unsigned int i = 0; i < 7; ++i) { ExifKey key(pre + std::string(tags[i])); ExifData::const_iterator md = metadata->findKey(key); if (md == metadata->end() || md->typeId() != unsignedByte || md->count() == 0) { return os << value; } raw[i] = static_cast(md->toLong()); } ExifData::const_iterator md = metadata->findKey(ExifKey("Exif.Nikon3.LensType")); if (md == metadata->end() || md->typeId() != unsignedByte || md->count() == 0) { return os << value; } raw[7] = static_cast(md->toLong()); for (int i = 0; fmountlens[i].lensname != NULL; ++i) { if ( raw[0] == fmountlens[i].lid && raw[1] == fmountlens[i].stps && raw[2] == fmountlens[i].focs && raw[3] == fmountlens[i].focl && raw[4] == fmountlens[i].aps && raw[5] == fmountlens[i].apl && raw[6] == fmountlens[i].lfw && raw[7] == fmountlens[i].ltype) { // Lens found in database return os << fmountlens[i].manuf << " " << fmountlens[i].lensname; } } // Lens not found in database return os << value; #else return os << value; #endif // EXV_HAVE_LENSDATA } std::ostream& Nikon3MakerNote::printFocusDistance(std::ostream& os, const Value& value, const ExifData*) { if (value.count() != 1 || value.typeId() != unsignedByte) { return os << "(" << value << ")"; } double dist = 0.01 * pow(10.0, value.toLong()/40.0); std::ostringstream oss; oss.copyfmt(os); os << std::fixed << std::setprecision(2) << dist << " m"; os.copyfmt(oss); return os; } std::ostream& Nikon3MakerNote::printAperture(std::ostream& os, const Value& value, const ExifData*) { if (value.count() != 1 || value.typeId() != unsignedByte) { return os << "(" << value << ")"; } double aperture = pow(2.0, value.toLong()/24.0); std::ostringstream oss; oss.copyfmt(os); os << std::fixed << std::setprecision(1) << "F" << aperture; os.copyfmt(oss); return os; } std::ostream& Nikon3MakerNote::printFocal(std::ostream& os, const Value& value, const ExifData*) { if (value.count() != 1 || value.typeId() != unsignedByte) { return os << "(" << value << ")"; } double focal = 5.0 * pow(2.0, value.toLong()/24.0); std::ostringstream oss; oss.copyfmt(os); os << std::fixed << std::setprecision(1) << focal << " mm"; os.copyfmt(oss); return os; } std::ostream& Nikon3MakerNote::printFStops(std::ostream& os, const Value& value, const ExifData*) { if (value.count() != 1 || value.typeId() != unsignedByte) { return os << "(" << value << ")"; } double fstops = value.toLong()/12.0; std::ostringstream oss; oss.copyfmt(os); os << std::fixed << std::setprecision(1) << "F" << fstops; os.copyfmt(oss); return os; } std::ostream& Nikon3MakerNote::printExitPupilPosition(std::ostream& os, const Value& value, const ExifData*) { if (value.count() != 1 || value.typeId() != unsignedByte || value.toLong() == 0) { return os << "(" << value << ")"; } double epp = 2048.0/value.toLong(); std::ostringstream oss; oss.copyfmt(os); os << std::fixed << std::setprecision(1) << epp << " mm"; os.copyfmt(oss); return os; } std::ostream& Nikon3MakerNote::printFlashFocalLength(std::ostream& os, const Value& value, const ExifData*) { if (value.count() != 1 || value.typeId() != unsignedByte || value.toLong() == 0 || value.toLong() == 255) { return os << "(" << value << ")"; } std::ostringstream oss; oss.copyfmt(os); os << std::fixed << std::setprecision(1) << value.toLong() << " mm"; os.copyfmt(oss); return os; } std::ostream& Nikon3MakerNote::printRepeatingFlashRate(std::ostream& os, const Value& value, const ExifData*) { if (value.count() != 1 || value.typeId() != unsignedByte || value.toLong() == 0 || value.toLong() == 255) { return os << "(" << value << ")"; } std::ostringstream oss; oss.copyfmt(os); os << std::fixed << std::setprecision(2) << value.toLong() << " Hz"; os.copyfmt(oss); return os; } std::ostream& Nikon3MakerNote::printRepeatingFlashCount(std::ostream& os, const Value& value, const ExifData*) { if (value.count() != 1 || value.typeId() != unsignedByte || value.toLong() == 0 || value.toLong() == 255) { return os << "(" << value << ")"; } std::ostringstream oss; oss.copyfmt(os); os << std::fixed << std::setprecision(2) << value.toLong(); os.copyfmt(oss); return os; } std::ostream& Nikon3MakerNote::printTimeZone(std::ostream& os, const Value& value, const ExifData*) { if (value.count() != 1 || value.typeId() != signedShort) { return os << "(" << value << ")"; } std::ostringstream oss; oss.copyfmt(os); char sign = value.toLong() < 0 ? '-' : '+'; long h = long(abs(value.toFloat())/60.0); long min = long(abs(value.toFloat()) - h*60); os << std::fixed << "UTC " << sign << std::setw(2) << std::setfill('0') << h << ":" << std::setw(2) << std::setfill('0') << min; os.copyfmt(oss); return os; } std::ostream& Nikon3MakerNote::printPictureControl(std::ostream& os, const Value& value, const ExifData*) { if (value.count() != 1 || value.typeId() != unsignedByte) { return os << "(" << value << ")"; } long pcval = value.toLong() - 0x80; std::ostringstream oss; oss.copyfmt(os); switch(pcval) { case 0: os << "Normal"; break; case 127: os << "n/a"; break; case -127: os << "User"; break; case -128: os << "Auto"; break; default: os << pcval; break; } os.copyfmt(oss); return os; } std::ostream& Nikon3MakerNote::print0x009a(std::ostream& os, const Value& value, const ExifData*) { if (value.count() != 2 || value.typeId() != unsignedRational) { return os << value; } float f1 = value.toFloat(0); float f2 = value.toFloat(1); return os << f1 << " x " << f2 << " um"; } std::ostream& Nikon3MakerNote::print0x009e(std::ostream& os, const Value& value, const ExifData*) { if (value.count() != 10 || value.typeId() != unsignedShort) { return os << value; } std::string s; bool trim = true; for (int i = 9; i >= 0; --i) { long l = value.toLong(i); if (i > 0 && l == 0 && trim) continue; if (l != 0) trim = false; std::string d = s.empty() ? "" : "; "; const TagDetails* td = find(nikonRetouchHistory, l); if (td) { s = std::string(exvGettext(td->label_)) + d + s; } else { s = std::string(_("Unknown")) + std::string(" (") + toString(l) + std::string(")") + d + s; } } return os << s; } }} // namespace Internal, Exiv2 exiv2-0.23/src/tiffcomposite.cpp0000644000175000017500000020265111741325454016471 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /* File: tiffcomposite.cpp Version: $Rev: 2699 $ Author(s): Andreas Huggel (ahu) History: 11-Apr-06, ahu: created */ // ***************************************************************************** #include "rcsid_int.hpp" EXIV2_RCSID("@(#) $Id: tiffcomposite.cpp 2699 2012-04-11 16:02:52Z ahuggel $") // ***************************************************************************** // included header files #ifdef _MSC_VER # include "exv_msvc.h" #else # include "exv_conf.h" #endif #include "tiffimage_int.hpp" #include "tiffcomposite_int.hpp" #include "tiffvisitor_int.hpp" #include "makernote_int.hpp" #include "value.hpp" #include "error.hpp" // + standard includes #include #include #include #include #include // ***************************************************************************** namespace { //! Add \em tobe - \em curr 0x00 filler bytes if necessary uint32_t fillGap(Exiv2::Internal::IoWrapper& ioWrapper, uint32_t curr, uint32_t tobe); } // ***************************************************************************** // class member definitions namespace Exiv2 { namespace Internal { bool TiffMappingInfo::operator==(const TiffMappingInfo::Key& key) const { return ( 0 == strcmp("*", make_) || 0 == strncmp(make_, key.m_.c_str(), strlen(make_))) && (Tag::all == extendedTag_ || key.e_ == extendedTag_) && key.g_ == group_; } IoWrapper::IoWrapper(BasicIo& io, const byte* pHeader, long size, OffsetWriter* pow) : io_(io), pHeader_(pHeader), size_(size), wroteHeader_(false), pow_(pow) { if (pHeader_ == 0 || size_ == 0) wroteHeader_ = true; } long IoWrapper::write(const byte* pData, long wcount) { if (!wroteHeader_ && wcount > 0) { io_.write(pHeader_, size_); wroteHeader_ = true; } return io_.write(pData, wcount); } int IoWrapper::putb(byte data) { if (!wroteHeader_) { io_.write(pHeader_, size_); wroteHeader_ = true; } return io_.putb(data); } void IoWrapper::setTarget(int id, uint32_t target) { if (pow_) pow_->setTarget(OffsetWriter::OffsetId(id), target); } TiffComponent::TiffComponent(uint16_t tag, IfdId group) : tag_(tag), group_(group), pStart_(0) { } TiffEntryBase::TiffEntryBase(uint16_t tag, IfdId group, TiffType tiffType) : TiffComponent(tag, group), tiffType_(tiffType), count_(0), offset_(0), size_(0), pData_(0), isMalloced_(false), idx_(0), pValue_(0) { } TiffSubIfd::TiffSubIfd(uint16_t tag, IfdId group, IfdId newGroup) : TiffEntryBase(tag, group, ttUnsignedLong), newGroup_(newGroup) { } TiffMnEntry::TiffMnEntry(uint16_t tag, IfdId group, IfdId mnGroup) : TiffEntryBase(tag, group, ttUndefined), mnGroup_(mnGroup), mn_(0) { } TiffIfdMakernote::TiffIfdMakernote(uint16_t tag, IfdId group, IfdId mnGroup, MnHeader* pHeader, bool hasNext) : TiffComponent(tag, group), pHeader_(pHeader), ifd_(tag, mnGroup, hasNext), mnOffset_(0), imageByteOrder_(invalidByteOrder) { } TiffBinaryArray::TiffBinaryArray(uint16_t tag, IfdId group, const ArrayCfg* arrayCfg, const ArrayDef* arrayDef, int defSize) : TiffEntryBase(tag, group, arrayCfg->elTiffType_), cfgSelFct_(0), arraySet_(0), arrayCfg_(arrayCfg), arrayDef_(arrayDef), defSize_(defSize), setSize_(0), origData_(0), origSize_(0), pRoot_(0), decoded_(false) { assert(arrayCfg != 0); } TiffBinaryArray::TiffBinaryArray(uint16_t tag, IfdId group, const ArraySet* arraySet, int setSize, CfgSelFct cfgSelFct) : TiffEntryBase(tag, group), // Todo: Does it make a difference that there is no type? cfgSelFct_(cfgSelFct), arraySet_(arraySet), arrayCfg_(0), arrayDef_(0), defSize_(0), setSize_(setSize), origData_(0), origSize_(0), pRoot_(0), decoded_(false) { // We'll figure out the correct cfg later assert(cfgSelFct != 0); assert(arraySet_ != 0); } TiffBinaryElement::TiffBinaryElement(uint16_t tag, IfdId group) : TiffEntryBase(tag, group) { } TiffComponent::~TiffComponent() { } TiffDirectory::~TiffDirectory() { for (Components::iterator i = components_.begin(); i != components_.end(); ++i) { delete *i; } delete pNext_; } TiffSubIfd::~TiffSubIfd() { for (Ifds::iterator i = ifds_.begin(); i != ifds_.end(); ++i) { delete *i; } } TiffEntryBase::~TiffEntryBase() { if (isMalloced_) { delete[] pData_; } delete pValue_; } TiffEntry::~TiffEntry() { } TiffDataEntryBase::~TiffDataEntryBase() { } TiffDataEntry::~TiffDataEntry() { } TiffImageEntry::~TiffImageEntry() { } TiffSizeEntry::~TiffSizeEntry() { } TiffMnEntry::~TiffMnEntry() { delete mn_; } TiffIfdMakernote::~TiffIfdMakernote() { delete pHeader_; } TiffBinaryArray::~TiffBinaryArray() { for (Components::iterator i = elements_.begin(); i != elements_.end(); ++i) { delete *i; } } TiffBinaryElement::~TiffBinaryElement() { } TiffEntryBase::TiffEntryBase(const TiffEntryBase& rhs) : TiffComponent(rhs), tiffType_(rhs.tiffType_), count_(rhs.count_), offset_(rhs.offset_), size_(rhs.size_), pData_(rhs.pData_), isMalloced_(rhs.isMalloced_), idx_(rhs.idx_), pValue_(rhs.pValue_ ? rhs.pValue_->clone().release() : 0) { if (rhs.isMalloced_) { pData_ = new byte[rhs.size_]; memcpy(pData_, rhs.pData_, rhs.size_); } } TiffDirectory::TiffDirectory(const TiffDirectory& rhs) : TiffComponent(rhs), hasNext_(rhs.hasNext_), pNext_(0) { } TiffSubIfd::TiffSubIfd(const TiffSubIfd& rhs) : TiffEntryBase(rhs), newGroup_(rhs.newGroup_) { } TiffBinaryArray::TiffBinaryArray(const TiffBinaryArray& rhs) : TiffEntryBase(rhs), cfgSelFct_(rhs.cfgSelFct_), arraySet_(rhs.arraySet_), arrayCfg_(rhs.arrayCfg_), arrayDef_(rhs.arrayDef_), defSize_(rhs.defSize_), setSize_(rhs.setSize_), origData_(rhs.origData_), origSize_(rhs.origSize_), pRoot_(rhs.pRoot_), decoded_(false) { } TiffComponent::AutoPtr TiffComponent::clone() const { return AutoPtr(doClone()); } TiffEntry* TiffEntry::doClone() const { return new TiffEntry(*this); } TiffDataEntry* TiffDataEntry::doClone() const { return new TiffDataEntry(*this); } TiffImageEntry* TiffImageEntry::doClone() const { return new TiffImageEntry(*this); } TiffSizeEntry* TiffSizeEntry::doClone() const { return new TiffSizeEntry(*this); } TiffDirectory* TiffDirectory::doClone() const { return new TiffDirectory(*this); } TiffSubIfd* TiffSubIfd::doClone() const { return new TiffSubIfd(*this); } TiffMnEntry* TiffMnEntry::doClone() const { assert(false); // Not implemented return 0; } TiffIfdMakernote* TiffIfdMakernote::doClone() const { assert(false); // Not implemented return 0; } TiffBinaryArray* TiffBinaryArray::doClone() const { return new TiffBinaryArray(*this); } TiffBinaryElement* TiffBinaryElement::doClone() const { return new TiffBinaryElement(*this); } int TiffComponent::idx() const { return 0; } int TiffEntryBase::idx() const { return idx_; } void TiffEntryBase::setData(DataBuf buf) { std::pair p = buf.release(); setData(p.first, p.second); isMalloced_ = true; } void TiffEntryBase::setData(byte* pData, int32_t size) { if (isMalloced_) { delete[] pData_; } pData_ = pData; size_ = size; if (pData_ == 0) size_ = 0; } void TiffEntryBase::updateValue(Value::AutoPtr value, ByteOrder byteOrder) { if (value.get() == 0) return; uint32_t newSize = value->size(); if (newSize > size_) { setData(DataBuf(newSize)); } memset(pData_, 0x0, size_); size_ = value->copy(pData_, byteOrder); assert(size_ == newSize); setValue(value); } // TiffEntryBase::updateValue void TiffEntryBase::setValue(Value::AutoPtr value) { if (value.get() == 0) return; tiffType_ = toTiffType(value->typeId()); count_ = value->count(); delete pValue_; pValue_ = value.release(); } // TiffEntryBase::setValue void TiffDataEntry::setStrips(const Value* pSize, const byte* pData, uint32_t sizeData, uint32_t baseOffset) { if (!pValue() || !pSize) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Directory " << groupName(group()) << ", entry 0x" << std::setw(4) << std::setfill('0') << std::hex << tag() << ": Size or data offset value not set, ignoring them.\n"; #endif return; } if (pValue()->count() == 0) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Directory " << groupName(group()) << ", entry 0x" << std::setw(4) << std::setfill('0') << std::hex << tag() << ": Data offset entry value is empty, ignoring it.\n"; #endif return; } if (pValue()->count() != pSize->count()) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Directory " << groupName(group()) << ", entry 0x" << std::setw(4) << std::setfill('0') << std::hex << tag() << ": Size and data offset entries have different" << " number of components, ignoring them.\n"; #endif return; } uint32_t size = 0; for (int i = 0; i < pSize->count(); ++i) { size += static_cast(pSize->toLong(i)); } uint32_t offset = static_cast(pValue()->toLong(0)); // Todo: Remove limitation of JPEG writer: strips must be contiguous // Until then we check: last offset + last size - first offset == size? if ( static_cast(pValue()->toLong(pValue()->count()-1)) + static_cast(pSize->toLong(pSize->count()-1)) - offset != size) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Directory " << groupName(group()) << ", entry 0x" << std::setw(4) << std::setfill('0') << std::hex << tag() << ": Data area is not contiguous, ignoring it.\n"; #endif return; } if ( offset > sizeData || size > sizeData || baseOffset + offset > sizeData - size) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Directory " << groupName(group()) << ", entry 0x" << std::setw(4) << std::setfill('0') << std::hex << tag() << ": Data area exceeds data buffer, ignoring it.\n"; #endif return; } pDataArea_ = const_cast(pData) + baseOffset + offset; sizeDataArea_ = size; const_cast(pValue())->setDataArea(pDataArea_, sizeDataArea_); } // TiffDataEntry::setStrips void TiffImageEntry::setStrips(const Value* pSize, const byte* pData, uint32_t sizeData, uint32_t baseOffset) { if (!pValue() || !pSize) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Directory " << groupName(group()) << ", entry 0x" << std::setw(4) << std::setfill('0') << std::hex << tag() << ": Size or data offset value not set, ignoring them.\n"; #endif return; } if (pValue()->count() != pSize->count()) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Directory " << groupName(group()) << ", entry 0x" << std::setw(4) << std::setfill('0') << std::hex << tag() << ": Size and data offset entries have different" << " number of components, ignoring them.\n"; #endif return; } for (int i = 0; i < pValue()->count(); ++i) { const uint32_t offset = static_cast(pValue()->toLong(i)); const byte* pStrip = pData + baseOffset + offset; const uint32_t size = static_cast(pSize->toLong(i)); if ( offset > sizeData || size > sizeData || baseOffset + offset > sizeData - size) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Directory " << groupName(group()) << ", entry 0x" << std::setw(4) << std::setfill('0') << std::hex << tag() << ": Strip " << std::dec << i << " is outside of the data area; ignored.\n"; #endif } else if (size != 0) { strips_.push_back(std::make_pair(pStrip, size)); } } } // TiffImageEntry::setStrips uint32_t TiffIfdMakernote::ifdOffset() const { if (!pHeader_) return 0; return pHeader_->ifdOffset(); } ByteOrder TiffIfdMakernote::byteOrder() const { assert(imageByteOrder_ != invalidByteOrder); if (!pHeader_ || pHeader_->byteOrder() == invalidByteOrder) { return imageByteOrder_; } return pHeader_->byteOrder(); } uint32_t TiffIfdMakernote::mnOffset() const { return mnOffset_; } uint32_t TiffIfdMakernote::baseOffset() const { if (!pHeader_) return 0; return pHeader_->baseOffset(mnOffset_); } bool TiffIfdMakernote::readHeader(const byte* pData, uint32_t size, ByteOrder byteOrder) { if (!pHeader_) return true; return pHeader_->read(pData, size, byteOrder); } void TiffIfdMakernote::setByteOrder(ByteOrder byteOrder) { if (pHeader_) pHeader_->setByteOrder(byteOrder); } uint32_t TiffIfdMakernote::sizeHeader() const { if (!pHeader_) return 0; return pHeader_->size(); } uint32_t TiffIfdMakernote::writeHeader(IoWrapper& ioWrapper, ByteOrder byteOrder) const { if (!pHeader_) return 0; return pHeader_->write(ioWrapper, byteOrder); } uint32_t ArrayDef::size(uint16_t tag, IfdId group) const { TypeId typeId = toTypeId(tiffType_, tag, group); return count_ * TypeInfo::typeSize(typeId); } bool TiffBinaryArray::initialize(IfdId group) { if (arrayCfg_ != 0) return true; // Not a complex array or already initialized for (int idx = 0; idx < setSize_; ++idx) { if (arraySet_[idx].cfg_.group_ == group) { arrayCfg_ = &arraySet_[idx].cfg_; arrayDef_ = arraySet_[idx].def_; defSize_ = arraySet_[idx].defSize_; return true; } } return false; } bool TiffBinaryArray::initialize(TiffComponent* const pRoot) { if (cfgSelFct_ == 0) return true; // Not a complex array int idx = cfgSelFct_(tag(), pData(), TiffEntryBase::doSize(), pRoot); if (idx > -1) { arrayCfg_ = &arraySet_[idx].cfg_; arrayDef_ = arraySet_[idx].def_; defSize_ = arraySet_[idx].defSize_; } return idx > -1; } void TiffBinaryArray::iniOrigDataBuf() { origData_ = const_cast(pData()); origSize_ = TiffEntryBase::doSize(); } bool TiffBinaryArray::updOrigDataBuf(const byte* pData, uint32_t size) { assert(pData != 0); if (origSize_ != size) return false; if (origData_ == pData) return true; memcpy(origData_, pData, origSize_); return true; } uint32_t TiffBinaryArray::addElement(uint32_t idx, const ArrayDef& def) { uint16_t tag = static_cast(idx / cfg()->tagStep()); int32_t sz = EXV_MIN(def.size(tag, cfg()->group_), TiffEntryBase::doSize() - idx); TiffComponent::AutoPtr tc = TiffCreator::create(tag, cfg()->group_); TiffBinaryElement* tp = dynamic_cast(tc.get()); // The assertion typically fails if a component is not configured in // the TIFF structure table (TiffCreator::tiffTreeStruct_) assert(tp); tp->setStart(pData() + idx); tp->setData(const_cast(pData() + idx), sz); tp->setElDef(def); tp->setElByteOrder(cfg()->byteOrder_); addChild(tc); return sz; } // TiffBinaryArray::addElement TiffComponent* TiffComponent::addPath(uint16_t tag, TiffPath& tiffPath, TiffComponent* const pRoot, TiffComponent::AutoPtr object) { return doAddPath(tag, tiffPath, pRoot, object); } // TiffComponent::addPath TiffComponent* TiffComponent::doAddPath(uint16_t /*tag*/, TiffPath& /*tiffPath*/, TiffComponent* const /*pRoot*/, TiffComponent::AutoPtr /*object*/) { return this; } // TiffComponent::doAddPath TiffComponent* TiffDirectory::doAddPath(uint16_t tag, TiffPath& tiffPath, TiffComponent* const pRoot, TiffComponent::AutoPtr object) { assert(tiffPath.size() > 1); tiffPath.pop(); const TiffPathItem tpi = tiffPath.top(); TiffComponent* tc = 0; // Try to use an existing component if there is still at least one // composite tag on the stack or the tag to add is the MakerNote tag. // This is used to prevent duplicate entries. Sub-IFDs also, but the > 1 // condition takes care of them, see below. if ( tiffPath.size() > 1 || (tpi.extendedTag() == 0x927c && tpi.group() == exifId)) { if (tpi.extendedTag() == Tag::next) { tc = pNext_; } else { for (Components::iterator i = components_.begin(); i != components_.end(); ++i) { if ((*i)->tag() == tpi.tag() && (*i)->group() == tpi.group()) { tc = *i; break; } } } } if (tc == 0) { TiffComponent::AutoPtr atc; if (tiffPath.size() == 1 && object.get() != 0) { atc = object; } else { atc = TiffCreator::create(tpi.extendedTag(), tpi.group()); } assert(atc.get() != 0); // Prevent dangling sub-IFD tags: Do not add a sub-IFD component without children. // Todo: How to check before creating the component? if (tiffPath.size() == 1 && dynamic_cast(atc.get()) != 0) return 0; if (tpi.extendedTag() == Tag::next) { tc = this->addNext(atc); } else { tc = this->addChild(atc); } } return tc->addPath(tag, tiffPath, pRoot, object); } // TiffDirectory::doAddPath TiffComponent* TiffSubIfd::doAddPath(uint16_t tag, TiffPath& tiffPath, TiffComponent* const pRoot, TiffComponent::AutoPtr object) { assert(!tiffPath.empty()); const TiffPathItem tpi1 = tiffPath.top(); tiffPath.pop(); if (tiffPath.empty()) { // If the last element in the path is the sub-IFD tag itself we're done. // But that shouldn't happen - see TiffDirectory::doAddPath return this; } const TiffPathItem tpi2 = tiffPath.top(); tiffPath.push(tpi1); TiffComponent* tc = 0; for (Ifds::iterator i = ifds_.begin(); i != ifds_.end(); ++i) { if ((*i)->group() == tpi2.group()) { tc = *i; break; } } if (tc == 0) { if (tiffPath.size() == 1 && object.get() != 0) { tc = addChild(object); } else { TiffComponent::AutoPtr atc(new TiffDirectory(tpi1.tag(), tpi2.group())); tc = addChild(atc); } setCount(static_cast(ifds_.size())); } return tc->addPath(tag, tiffPath, pRoot, object); } // TiffSubIfd::doAddPath TiffComponent* TiffMnEntry::doAddPath(uint16_t tag, TiffPath& tiffPath, TiffComponent* const pRoot, TiffComponent::AutoPtr object) { assert(!tiffPath.empty()); const TiffPathItem tpi1 = tiffPath.top(); tiffPath.pop(); if (tiffPath.empty()) { // If the last element in the path is the makernote tag itself we're done return this; } const TiffPathItem tpi2 = tiffPath.top(); tiffPath.push(tpi1); if (mn_ == 0) { mnGroup_ = tpi2.group(); mn_ = TiffMnCreator::create(tpi1.tag(), tpi1.group(), mnGroup_); assert(mn_); } return mn_->addPath(tag, tiffPath, pRoot, object); } // TiffMnEntry::doAddPath TiffComponent* TiffIfdMakernote::doAddPath(uint16_t tag, TiffPath& tiffPath, TiffComponent* const pRoot, TiffComponent::AutoPtr object) { return ifd_.addPath(tag, tiffPath, pRoot, object); } TiffComponent* TiffBinaryArray::doAddPath(uint16_t tag, TiffPath& tiffPath, TiffComponent* const pRoot, TiffComponent::AutoPtr object) { pRoot_ = pRoot; if (tiffPath.size() == 1) { // An unknown complex binary array has no children and acts like a standard TIFF entry return this; } tiffPath.pop(); const TiffPathItem tpi = tiffPath.top(); // Initialize the binary array (if it is a complex array) initialize(tpi.group()); TiffComponent* tc = 0; // Todo: Duplicates are not allowed! // To allow duplicate entries, we only check if the new component already // exists if there is still at least one composite tag on the stack if (tiffPath.size() > 1) { for (Components::iterator i = elements_.begin(); i != elements_.end(); ++i) { if ((*i)->tag() == tpi.tag() && (*i)->group() == tpi.group()) { tc = *i; break; } } } if (tc == 0) { TiffComponent::AutoPtr atc; if (tiffPath.size() == 1 && object.get() != 0) { atc = object; } else { atc = TiffCreator::create(tpi.extendedTag(), tpi.group()); } assert(atc.get() != 0); assert(tpi.extendedTag() != Tag::next); tc = addChild(atc); setCount(static_cast(elements_.size())); } return tc->addPath(tag, tiffPath, pRoot, object); } // TiffBinaryArray::doAddPath TiffComponent* TiffComponent::addChild(TiffComponent::AutoPtr tiffComponent) { return doAddChild(tiffComponent); } // TiffComponent::addChild TiffComponent* TiffComponent::doAddChild(AutoPtr /*tiffComponent*/) { return 0; } // TiffComponent::doAddChild TiffComponent* TiffDirectory::doAddChild(TiffComponent::AutoPtr tiffComponent) { TiffComponent* tc = tiffComponent.release(); components_.push_back(tc); return tc; } // TiffDirectory::doAddChild TiffComponent* TiffSubIfd::doAddChild(TiffComponent::AutoPtr tiffComponent) { TiffDirectory* d = dynamic_cast(tiffComponent.release()); assert(d); ifds_.push_back(d); return d; } // TiffSubIfd::doAddChild TiffComponent* TiffMnEntry::doAddChild(TiffComponent::AutoPtr tiffComponent) { TiffComponent* tc = 0; if (mn_) { tc = mn_->addChild(tiffComponent); } return tc; } // TiffMnEntry::doAddChild TiffComponent* TiffIfdMakernote::doAddChild(TiffComponent::AutoPtr tiffComponent) { return ifd_.addChild(tiffComponent); } TiffComponent* TiffBinaryArray::doAddChild(TiffComponent::AutoPtr tiffComponent) { TiffComponent* tc = tiffComponent.release(); elements_.push_back(tc); setDecoded(true); return tc; } // TiffBinaryArray::doAddChild TiffComponent* TiffComponent::addNext(TiffComponent::AutoPtr tiffComponent) { return doAddNext(tiffComponent); } // TiffComponent::addNext TiffComponent* TiffComponent::doAddNext(AutoPtr /*tiffComponent*/) { return 0; } // TiffComponent::doAddNext TiffComponent* TiffDirectory::doAddNext(TiffComponent::AutoPtr tiffComponent) { TiffComponent* tc = 0; if (hasNext_) { tc = tiffComponent.release(); pNext_ = tc; } return tc; } // TiffDirectory::doAddNext TiffComponent* TiffMnEntry::doAddNext(TiffComponent::AutoPtr tiffComponent) { TiffComponent* tc = 0; if (mn_) { tc = mn_->addNext(tiffComponent); } return tc; } // TiffMnEntry::doAddNext TiffComponent* TiffIfdMakernote::doAddNext(TiffComponent::AutoPtr tiffComponent) { return ifd_.addNext(tiffComponent); } void TiffComponent::accept(TiffVisitor& visitor) { if (visitor.go(TiffVisitor::geTraverse)) doAccept(visitor); // one for NVI :) } // TiffComponent::accept void TiffEntry::doAccept(TiffVisitor& visitor) { visitor.visitEntry(this); } // TiffEntry::doAccept void TiffDataEntry::doAccept(TiffVisitor& visitor) { visitor.visitDataEntry(this); } // TiffDataEntry::doAccept void TiffImageEntry::doAccept(TiffVisitor& visitor) { visitor.visitImageEntry(this); } // TiffImageEntry::doAccept void TiffSizeEntry::doAccept(TiffVisitor& visitor) { visitor.visitSizeEntry(this); } // TiffSizeEntry::doAccept void TiffDirectory::doAccept(TiffVisitor& visitor) { visitor.visitDirectory(this); for (Components::const_iterator i = components_.begin(); visitor.go(TiffVisitor::geTraverse) && i != components_.end(); ++i) { (*i)->accept(visitor); } if (visitor.go(TiffVisitor::geTraverse)) visitor.visitDirectoryNext(this); if (pNext_) pNext_->accept(visitor); if (visitor.go(TiffVisitor::geTraverse)) visitor.visitDirectoryEnd(this); } // TiffDirectory::doAccept void TiffSubIfd::doAccept(TiffVisitor& visitor) { visitor.visitSubIfd(this); for (Ifds::iterator i = ifds_.begin(); visitor.go(TiffVisitor::geTraverse) && i != ifds_.end(); ++i) { (*i)->accept(visitor); } } // TiffSubIfd::doAccept void TiffMnEntry::doAccept(TiffVisitor& visitor) { visitor.visitMnEntry(this); if (mn_) mn_->accept(visitor); if (!visitor.go(TiffVisitor::geKnownMakernote)) { delete mn_; mn_ = 0; } } // TiffMnEntry::doAccept void TiffIfdMakernote::doAccept(TiffVisitor& visitor) { if (visitor.go(TiffVisitor::geTraverse)) visitor.visitIfdMakernote(this); if (visitor.go(TiffVisitor::geKnownMakernote)) ifd_.accept(visitor); if ( visitor.go(TiffVisitor::geKnownMakernote) && visitor.go(TiffVisitor::geTraverse)) visitor.visitIfdMakernoteEnd(this); } void TiffBinaryArray::doAccept(TiffVisitor& visitor) { visitor.visitBinaryArray(this); for (Components::const_iterator i = elements_.begin(); visitor.go(TiffVisitor::geTraverse) && i != elements_.end(); ++i) { (*i)->accept(visitor); } if (visitor.go(TiffVisitor::geTraverse)) visitor.visitBinaryArrayEnd(this); } // TiffBinaryArray::doAccept void TiffBinaryElement::doAccept(TiffVisitor& visitor) { visitor.visitBinaryElement(this); } // TiffBinaryElement::doAccept void TiffEntryBase::encode(TiffEncoder& encoder, const Exifdatum* datum) { doEncode(encoder, datum); } // TiffComponent::encode void TiffBinaryElement::doEncode(TiffEncoder& encoder, const Exifdatum* datum) { encoder.encodeBinaryElement(this, datum); } // TiffBinaryElement::doEncode void TiffBinaryArray::doEncode(TiffEncoder& encoder, const Exifdatum* datum) { encoder.encodeBinaryArray(this, datum); } // TiffBinaryArray::doEncode void TiffDataEntry::doEncode(TiffEncoder& encoder, const Exifdatum* datum) { encoder.encodeDataEntry(this, datum); } // TiffDataEntry::doEncode void TiffEntry::doEncode(TiffEncoder& encoder, const Exifdatum* datum) { encoder.encodeTiffEntry(this, datum); } // TiffEntry::doEncode void TiffImageEntry::doEncode(TiffEncoder& encoder, const Exifdatum* datum) { encoder.encodeImageEntry(this, datum); } // TiffImageEntry::doEncode void TiffMnEntry::doEncode(TiffEncoder& encoder, const Exifdatum* datum) { encoder.encodeMnEntry(this, datum); } // TiffMnEntry::doEncode void TiffSizeEntry::doEncode(TiffEncoder& encoder, const Exifdatum* datum) { encoder.encodeSizeEntry(this, datum); } // TiffSizeEntry::doEncode void TiffSubIfd::doEncode(TiffEncoder& encoder, const Exifdatum* datum) { encoder.encodeSubIfd(this, datum); } // TiffSubIfd::doEncode uint32_t TiffComponent::count() const { return doCount(); } uint32_t TiffDirectory::doCount() const { return static_cast(components_.size()); } uint32_t TiffEntryBase::doCount() const { return count_; } uint32_t TiffMnEntry::doCount() const { if (!mn_) { return TiffEntryBase::doCount(); } // Count of IFD makernote in tag Exif.Photo.MakerNote is the size of the // Makernote in bytes assert(tiffType() == ttUndefined || tiffType() == ttUnsignedByte || tiffType() == ttSignedByte); return mn_->size(); } uint32_t TiffIfdMakernote::doCount() const { return ifd_.count(); } // TiffIfdMakernote::doCount uint32_t TiffBinaryArray::doCount() const { if (cfg() == 0 || !decoded()) return TiffEntryBase::doCount(); if (elements_.empty()) return 0; TypeId typeId = toTypeId(tiffType(), tag(), group()); long typeSize = TypeInfo::typeSize(typeId); if (0 == typeSize) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Directory " << groupName(group()) << ", entry 0x" << std::setw(4) << std::setfill('0') << std::hex << tag() << " has unknown Exif (TIFF) type " << std::dec << tiffType() << "; setting type size 1.\n"; #endif typeSize = 1; } return static_cast(static_cast(size()) / typeSize + 0.5); } uint32_t TiffBinaryElement::doCount() const { return elDef_.count_; } uint32_t TiffComponent::write(IoWrapper& ioWrapper, ByteOrder byteOrder, int32_t offset, uint32_t valueIdx, uint32_t dataIdx, uint32_t& imageIdx) { return doWrite(ioWrapper, byteOrder, offset, valueIdx, dataIdx, imageIdx); } // TiffComponent::write uint32_t TiffDirectory::doWrite(IoWrapper& ioWrapper, ByteOrder byteOrder, int32_t offset, uint32_t valueIdx, uint32_t dataIdx, uint32_t& imageIdx) { bool isRootDir = (imageIdx == uint32_t(-1)); // Number of components to write const uint32_t compCount = count(); if (compCount > 0xffff) throw Error(49, groupName(group())); // Size of next IFD, if any uint32_t sizeNext = 0; if (pNext_) sizeNext = pNext_->size(); // Nothing to do if there are no entries and the size of the next IFD is 0 if (compCount == 0 && sizeNext == 0) return 0; // Remember the offset of the CR2 RAW IFD if (group() == ifd3Id) { #ifdef DEBUG std::cerr << "Directory " << groupName(group()) << " offset is 0x" << std::setw(8) << std::setfill('0') << std::hex << offset << std::dec << "\n"; #endif ioWrapper.setTarget(OffsetWriter::cr2RawIfdOffset, offset); } // Size of all directory entries, without values and additional data const uint32_t sizeDir = 2 + 12 * compCount + (hasNext_ ? 4 : 0); // TIFF standard requires IFD entries to be sorted in ascending order by tag. // Not sorting makernote directories sometimes preserves them better. if (group() < mnId) { std::sort(components_.begin(), components_.end(), cmpTagLt); } // Size of IFD values and additional data uint32_t sizeValue = 0; uint32_t sizeData = 0; for (Components::const_iterator i = components_.begin(); i != components_.end(); ++i) { uint32_t sv = (*i)->size(); if (sv > 4) { sv += sv & 1; // Align value to word boundary sizeValue += sv; } // Also add the size of data, but only if needed if (isRootDir) { uint32_t sd = (*i)->sizeData(); sd += sd & 1; // Align data to word boundary sizeData += sd; } } uint32_t idx = 0; // Current IFD index / bytes written valueIdx = sizeDir; // Offset to the current IFD value dataIdx = sizeDir + sizeValue; // Offset to the entry's data area if (isRootDir) { // Absolute offset to the image data imageIdx = offset + dataIdx + sizeData + sizeNext; imageIdx += imageIdx & 1; // Align image data to word boundary } // 1st: Write the IFD, a) Number of directory entries byte buf[4]; us2Data(buf, static_cast(compCount), byteOrder); ioWrapper.write(buf, 2); idx += 2; // b) Directory entries - may contain pointers to the value or data for (Components::const_iterator i = components_.begin(); i != components_.end(); ++i) { idx += writeDirEntry(ioWrapper, byteOrder, offset, *i, valueIdx, dataIdx, imageIdx); uint32_t sv = (*i)->size(); if (sv > 4) { sv += sv & 1; // Align value to word boundary valueIdx += sv; } uint32_t sd = (*i)->sizeData(); sd += sd & 1; // Align data to word boundary dataIdx += sd; } // c) Pointer to the next IFD if (hasNext_) { memset(buf, 0x0, 4); if (pNext_ && sizeNext) { l2Data(buf, offset + dataIdx, byteOrder); } ioWrapper.write(buf, 4); idx += 4; } assert(idx == sizeDir); // 2nd: Write IFD values - may contain pointers to additional data valueIdx = sizeDir; dataIdx = sizeDir + sizeValue; for (Components::const_iterator i = components_.begin(); i != components_.end(); ++i) { uint32_t sv = (*i)->size(); if (sv > 4) { uint32_t d = (*i)->write(ioWrapper, byteOrder, offset, valueIdx, dataIdx, imageIdx); assert(sv == d); if ((sv & 1) == 1) { ioWrapper.putb(0x0); // Align value to word boundary sv += 1; } idx += sv; valueIdx += sv; } uint32_t sd = (*i)->sizeData(); sd += sd & 1; // Align data to word boundary dataIdx += sd; } assert(idx == sizeDir + sizeValue); // 3rd: Write data - may contain offsets too (eg sub-IFD) dataIdx = sizeDir + sizeValue; idx += writeData(ioWrapper, byteOrder, offset, dataIdx, imageIdx); // 4th: Write next-IFD if (pNext_ && sizeNext) { idx += pNext_->write(ioWrapper, byteOrder, offset + idx, uint32_t(-1), uint32_t(-1), imageIdx); } // 5th, at the root directory level only: write image data if (isRootDir) { idx += writeImage(ioWrapper, byteOrder); } return idx; } // TiffDirectory::doWrite uint32_t TiffDirectory::writeDirEntry(IoWrapper& ioWrapper, ByteOrder byteOrder, int32_t offset, TiffComponent* pTiffComponent, uint32_t valueIdx, uint32_t dataIdx, uint32_t& imageIdx) const { assert(pTiffComponent); TiffEntryBase* pDirEntry = dynamic_cast(pTiffComponent); assert(pDirEntry); byte buf[8]; us2Data(buf, pDirEntry->tag(), byteOrder); us2Data(buf + 2, pDirEntry->tiffType(), byteOrder); ul2Data(buf + 4, pDirEntry->count(), byteOrder); ioWrapper.write(buf, 8); if (pDirEntry->size() > 4) { pDirEntry->setOffset(offset + static_cast(valueIdx)); l2Data(buf, pDirEntry->offset(), byteOrder); ioWrapper.write(buf, 4); } else { const uint32_t len = pDirEntry->write(ioWrapper, byteOrder, offset, valueIdx, dataIdx, imageIdx); assert(len <= 4); if (len < 4) { memset(buf, 0x0, 4); ioWrapper.write(buf, 4 - len); } } return 12; } // TiffDirectory::writeDirEntry uint32_t TiffEntryBase::doWrite(IoWrapper& ioWrapper, ByteOrder byteOrder, int32_t /*offset*/, uint32_t /*valueIdx*/, uint32_t /*dataIdx*/, uint32_t& /*imageIdx*/) { if (!pValue_) return 0; DataBuf buf(pValue_->size()); pValue_->copy(buf.pData_, byteOrder); ioWrapper.write(buf.pData_, buf.size_); return buf.size_; } // TiffEntryBase::doWrite uint32_t TiffEntryBase::writeOffset(byte* buf, int32_t offset, TiffType tiffType, ByteOrder byteOrder) { uint32_t rc = 0; switch(tiffType) { case ttUnsignedShort: case ttSignedShort: if (static_cast(offset) > 0xffff) throw Error(26); rc = s2Data(buf, static_cast(offset), byteOrder); break; case ttUnsignedLong: case ttSignedLong: rc = l2Data(buf, static_cast(offset), byteOrder); break; default: throw Error(27); break; } return rc; } // TiffEntryBase::writeOffset uint32_t TiffDataEntry::doWrite(IoWrapper& ioWrapper, ByteOrder byteOrder, int32_t offset, uint32_t /*valueIdx*/, uint32_t dataIdx, uint32_t& /*imageIdx*/) { if (!pValue() || pValue()->count() == 0) return 0; DataBuf buf(pValue()->size()); uint32_t idx = 0; const long prevOffset = pValue()->toLong(0); for (uint32_t i = 0; i < count(); ++i) { const long newDataIdx = pValue()->toLong(i) - prevOffset + static_cast(dataIdx); idx += writeOffset(buf.pData_ + idx, offset + newDataIdx, tiffType(), byteOrder); } ioWrapper.write(buf.pData_, buf.size_); return buf.size_; } // TiffDataEntry::doWrite uint32_t TiffImageEntry::doWrite(IoWrapper& ioWrapper, ByteOrder byteOrder, int32_t offset, uint32_t /*valueIdx*/, uint32_t dataIdx, uint32_t& imageIdx) { uint32_t o2 = imageIdx; // For makernotes, write TIFF image data to the data area if (group() > mnId) o2 = offset + dataIdx; #ifdef DEBUG std::cerr << "TiffImageEntry, Directory " << groupName(group()) << ", entry 0x" << std::setw(4) << std::setfill('0') << std::hex << tag() << std::dec << ": Writing offset " << o2 << "\n"; #endif DataBuf buf(static_cast(strips_.size()) * 4); memset(buf.pData_, 0x0, buf.size_); uint32_t idx = 0; for (Strips::const_iterator i = strips_.begin(); i != strips_.end(); ++i) { idx += writeOffset(buf.pData_ + idx, o2, tiffType(), byteOrder); o2 += i->second; o2 += i->second & 1; // Align strip data to word boundary if (!(group() > mnId)) { // Todo: FIX THIS!! SHOULDN'T USE > imageIdx += i->second; imageIdx += i->second & 1; // Align strip data to word boundary } } ioWrapper.write(buf.pData_, buf.size_); return buf.size_; } // TiffImageEntry::doWrite uint32_t TiffSubIfd::doWrite(IoWrapper& ioWrapper, ByteOrder byteOrder, int32_t offset, uint32_t /*valueIdx*/, uint32_t dataIdx, uint32_t& /*imageIdx*/) { DataBuf buf(static_cast(ifds_.size()) * 4); uint32_t idx = 0; // Sort IFDs by group, needed if image data tags were copied first std::sort(ifds_.begin(), ifds_.end(), cmpGroupLt); for (Ifds::const_iterator i = ifds_.begin(); i != ifds_.end(); ++i) { idx += writeOffset(buf.pData_ + idx, offset + dataIdx, tiffType(), byteOrder); dataIdx += (*i)->size(); } ioWrapper.write(buf.pData_, buf.size_); return buf.size_; } // TiffSubIfd::doWrite uint32_t TiffMnEntry::doWrite(IoWrapper& ioWrapper, ByteOrder byteOrder, int32_t offset, uint32_t valueIdx, uint32_t dataIdx, uint32_t& imageIdx) { if (!mn_) { return TiffEntryBase::doWrite(ioWrapper, byteOrder, offset, valueIdx, dataIdx, imageIdx); } return mn_->write(ioWrapper, byteOrder, offset + valueIdx, uint32_t(-1), uint32_t(-1), imageIdx); } // TiffMnEntry::doWrite uint32_t TiffIfdMakernote::doWrite(IoWrapper& ioWrapper, ByteOrder byteOrder, int32_t offset, uint32_t /*valueIdx*/, uint32_t /*dataIdx*/, uint32_t& imageIdx) { mnOffset_ = offset; setImageByteOrder(byteOrder); uint32_t len = writeHeader(ioWrapper, this->byteOrder()); len += ifd_.write(ioWrapper, this->byteOrder(), offset - baseOffset() + len, uint32_t(-1), uint32_t(-1), imageIdx); return len; } // TiffIfdMakernote::doWrite uint32_t TiffBinaryArray::doWrite(IoWrapper& ioWrapper, ByteOrder byteOrder, int32_t offset, uint32_t valueIdx, uint32_t dataIdx, uint32_t& imageIdx) { if (cfg() == 0 || !decoded()) return TiffEntryBase::doWrite(ioWrapper, byteOrder, offset, valueIdx, dataIdx, imageIdx); if (cfg()->byteOrder_ != invalidByteOrder) byteOrder = cfg()->byteOrder_; // Tags must be sorted in ascending order std::sort(elements_.begin(), elements_.end(), cmpTagLt); uint32_t idx = 0; MemIo mio; IoWrapper mioWrapper(mio, 0, 0, 0); // Some array entries need to have the size in the first element if (cfg()->hasSize_) { byte buf[4]; long elSize = TypeInfo::typeSize(toTypeId(cfg()->elTiffType_, 0, cfg()->group_)); switch (elSize) { case 2: idx += us2Data(buf, size(), byteOrder); break; case 4: idx += ul2Data(buf, size(), byteOrder); break; default: assert(false); } mioWrapper.write(buf, elSize); } // write all tags of the array (Todo: assumes that there are no duplicates, need check) for (Components::const_iterator i = elements_.begin(); i != elements_.end(); ++i) { // Skip the manufactured tag, if it exists if (cfg()->hasSize_ && (*i)->tag() == 0) continue; uint32_t newIdx = (*i)->tag() * cfg()->tagStep(); idx += fillGap(mioWrapper, idx, newIdx); idx += (*i)->write(mioWrapper, byteOrder, offset + newIdx, valueIdx, dataIdx, imageIdx); } if (cfg()->hasFillers_ && def()) { const ArrayDef* lastDef = def() + defSize() - 1; uint16_t lastTag = static_cast(lastDef->idx_ / cfg()->tagStep()); idx += fillGap(mioWrapper, idx, lastDef->idx_ + lastDef->size(lastTag, cfg()->group_)); } DataBuf buf; if (cfg()->cryptFct_) { buf = cfg()->cryptFct_(tag(), mio.mmap(), static_cast(mio.size()), pRoot_); } if (buf.size_ > 0) { ioWrapper.write(buf.pData_, buf.size_); } else { ioWrapper.write(mio.mmap(), static_cast(mio.size())); } return idx; } // TiffBinaryArray::doWrite uint32_t TiffBinaryElement::doWrite(IoWrapper& ioWrapper, ByteOrder byteOrder, int32_t /*offset*/, uint32_t /*valueIdx*/, uint32_t /*dataIdx*/, uint32_t& /*imageIdx*/) { Value const* pv = pValue(); if (!pv || pv->count() == 0) return 0; DataBuf buf(pv->size()); pv->copy(buf.pData_, byteOrder); ioWrapper.write(buf.pData_, buf.size_); return buf.size_; } // TiffBinaryElement::doWrite uint32_t TiffComponent::writeData(IoWrapper& ioWrapper, ByteOrder byteOrder, int32_t offset, uint32_t dataIdx, uint32_t& imageIdx) const { return doWriteData(ioWrapper, byteOrder, offset, dataIdx, imageIdx); } // TiffComponent::writeData uint32_t TiffDirectory::doWriteData(IoWrapper& ioWrapper, ByteOrder byteOrder, int32_t offset, uint32_t dataIdx, uint32_t& imageIdx) const { uint32_t len = 0; for (Components::const_iterator i = components_.begin(); i != components_.end(); ++i) { len += (*i)->writeData(ioWrapper, byteOrder, offset, dataIdx + len, imageIdx); } return len; } // TiffDirectory::doWriteData uint32_t TiffEntryBase::doWriteData(IoWrapper&/*ioWrapper*/, ByteOrder /*byteOrder*/, int32_t /*offset*/, uint32_t /*dataIdx*/, uint32_t& /*imageIdx*/) const { return 0; } // TiffEntryBase::doWriteData uint32_t TiffImageEntry::doWriteData(IoWrapper& ioWrapper, ByteOrder byteOrder, int32_t /*offset*/, uint32_t /*dataIdx*/, uint32_t& /*imageIdx*/) const { uint32_t len = 0; // For makernotes, write TIFF image data to the data area if (group() > mnId) { // Todo: FIX THIS HACK!!! len = writeImage(ioWrapper, byteOrder); } return len; } // TiffImageEntry::doWriteData uint32_t TiffDataEntry::doWriteData(IoWrapper& ioWrapper, ByteOrder /*byteOrder*/, int32_t /*offset*/, uint32_t /*dataIdx*/, uint32_t& /*imageIdx*/) const { if (!pValue()) return 0; DataBuf buf = pValue()->dataArea(); ioWrapper.write(buf.pData_, buf.size_); // Align data to word boundary uint32_t align = (buf.size_ & 1); if (align) ioWrapper.putb(0x0); return buf.size_ + align; } // TiffDataEntry::doWriteData uint32_t TiffSubIfd::doWriteData(IoWrapper& ioWrapper, ByteOrder byteOrder, int32_t offset, uint32_t dataIdx, uint32_t& imageIdx) const { uint32_t len = 0; for (Ifds::const_iterator i = ifds_.begin(); i != ifds_.end(); ++i) { len += (*i)->write(ioWrapper, byteOrder, offset + dataIdx + len, uint32_t(-1), uint32_t(-1), imageIdx); } // Align data to word boundary uint32_t align = (len & 1); if (align) ioWrapper.putb(0x0); return len + align; } // TiffSubIfd::doWriteData uint32_t TiffIfdMakernote::doWriteData(IoWrapper&/*ioWrapper*/, ByteOrder /*byteOrder*/, int32_t /*offset*/, uint32_t /*dataIdx*/, uint32_t& /*imageIdx*/) const { assert(false); return 0; } // TiffIfdMakernote::doWriteData uint32_t TiffComponent::writeImage(IoWrapper& ioWrapper, ByteOrder byteOrder) const { return doWriteImage(ioWrapper, byteOrder); } // TiffComponent::writeImage uint32_t TiffDirectory::doWriteImage(IoWrapper& ioWrapper, ByteOrder byteOrder) const { uint32_t len = 0; TiffComponent* pSubIfd = 0; for (Components::const_iterator i = components_.begin(); i != components_.end(); ++i) { if ((*i)->tag() == 0x014a) { // Hack: delay writing of sub-IFD image data to get the order correct assert(pSubIfd == 0); pSubIfd = *i; continue; } len += (*i)->writeImage(ioWrapper, byteOrder); } if (pSubIfd) { len += pSubIfd->writeImage(ioWrapper, byteOrder); } if (pNext_) { len += pNext_->writeImage(ioWrapper, byteOrder); } return len; } // TiffDirectory::doWriteImage uint32_t TiffEntryBase::doWriteImage(IoWrapper&/*ioWrapper*/, ByteOrder /*byteOrder*/) const { return 0; } // TiffEntryBase::doWriteImage uint32_t TiffSubIfd::doWriteImage(IoWrapper& ioWrapper, ByteOrder byteOrder) const { uint32_t len = 0; for (Ifds::const_iterator i = ifds_.begin(); i != ifds_.end(); ++i) { len += (*i)->writeImage(ioWrapper, byteOrder); } return len; } // TiffSubIfd::doWriteImage uint32_t TiffIfdMakernote::doWriteImage(IoWrapper& ioWrapper, ByteOrder byteOrder) const { if (this->byteOrder() != invalidByteOrder) { byteOrder = this->byteOrder(); } uint32_t len = ifd_.writeImage(ioWrapper, byteOrder); return len; } // TiffIfdMakernote::doWriteImage uint32_t TiffImageEntry::doWriteImage(IoWrapper& ioWrapper, ByteOrder /*byteOrder*/) const { uint32_t len = pValue()->sizeDataArea(); if (len > 0) { #ifdef DEBUG std::cerr << "TiffImageEntry, Directory " << groupName(group()) << ", entry 0x" << std::setw(4) << std::setfill('0') << std::hex << tag() << std::dec << ": Writing data area, size = " << len; #endif DataBuf buf = pValue()->dataArea(); ioWrapper.write(buf.pData_, buf.size_); uint32_t align = len & 1; // Align image data to word boundary if (align) ioWrapper.putb(0x0); len += align; } else { #ifdef DEBUG std::cerr << "TiffImageEntry, Directory " << groupName(group()) << ", entry 0x" << std::setw(4) << std::setfill('0') << std::hex << tag() << std::dec << ": Writing " << strips_.size() << " strips"; #endif len = 0; for (Strips::const_iterator i = strips_.begin(); i != strips_.end(); ++i) { ioWrapper.write(i->first, i->second); len += i->second; uint32_t align = i->second & 1; // Align strip data to word boundary if (align) ioWrapper.putb(0x0); len += align; } } #ifdef DEBUG std::cerr << ", len = " << len << " bytes\n"; #endif return len; } // TiffImageEntry::doWriteImage uint32_t TiffComponent::size() const { return doSize(); } // TiffComponent::size uint32_t TiffDirectory::doSize() const { uint32_t compCount = count(); // Size of the directory, without values and additional data uint32_t len = 2 + 12 * compCount + (hasNext_ ? 4 : 0); // Size of IFD values and data for (Components::const_iterator i = components_.begin(); i != components_.end(); ++i) { uint32_t sv = (*i)->size(); if (sv > 4) { sv += sv & 1; // Align value to word boundary len += sv; } uint32_t sd = (*i)->sizeData(); sd += sd & 1; // Align data to word boundary len += sd; } // Size of next-IFD, if any uint32_t sizeNext = 0; if (pNext_) { sizeNext = pNext_->size(); len += sizeNext; } // Reset size of IFD if it has no entries and no or empty next IFD. if (compCount == 0 && sizeNext == 0) len = 0; return len; } // TiffDirectory::doSize uint32_t TiffEntryBase::doSize() const { return size_; } // TiffEntryBase::doSize uint32_t TiffImageEntry::doSize() const { return static_cast(strips_.size()) * 4; } // TiffImageEntry::doSize uint32_t TiffSubIfd::doSize() const { return static_cast(ifds_.size()) * 4; } // TiffSubIfd::doSize uint32_t TiffMnEntry::doSize() const { if (!mn_) { return TiffEntryBase::doSize(); } return mn_->size(); } // TiffMnEntry::doSize uint32_t TiffIfdMakernote::doSize() const { return sizeHeader() + ifd_.size(); } // TiffIfdMakernote::doSize uint32_t TiffBinaryArray::doSize() const { if (cfg() == 0 || !decoded()) return TiffEntryBase::doSize(); if (elements_.empty()) return 0; // Remaining assumptions: // - array elements don't "overlap" // - no duplicate tags in the array uint32_t idx = 0; uint32_t sz = cfg()->tagStep(); for (Components::const_iterator i = elements_.begin(); i != elements_.end(); ++i) { if ((*i)->tag() > idx) { idx = (*i)->tag(); sz = (*i)->size(); } } idx = idx * cfg()->tagStep() + sz; if (cfg()->hasFillers_ && def()) { const ArrayDef* lastDef = def() + defSize() - 1; uint16_t lastTag = static_cast(lastDef->idx_ / cfg()->tagStep()); idx = EXV_MAX(idx, lastDef->idx_ + lastDef->size(lastTag, cfg()->group_)); } return idx; } // TiffBinaryArray::doSize uint32_t TiffBinaryElement::doSize() const { if (!pValue()) return 0; return pValue()->size(); } // TiffBinaryElement::doSize uint32_t TiffComponent::sizeData() const { return doSizeData(); } // TiffComponent::sizeData uint32_t TiffDirectory::doSizeData() const { assert(false); return 0; } // TiffDirectory::doSizeData uint32_t TiffEntryBase::doSizeData() const { return 0; } // TiffEntryBase::doSizeData uint32_t TiffImageEntry::doSizeData() const { uint32_t len = 0; // For makernotes, TIFF image data is written to the data area if (group() > mnId) { // Todo: Fix this hack!! len = sizeImage(); } return len; } // TiffImageEntry::doSizeData uint32_t TiffDataEntry::doSizeData() const { if (!pValue()) return 0; return pValue()->sizeDataArea(); } // TiffDataEntry::doSizeData uint32_t TiffSubIfd::doSizeData() const { uint32_t len = 0; for (Ifds::const_iterator i = ifds_.begin(); i != ifds_.end(); ++i) { len += (*i)->size(); } return len; } // TiffSubIfd::doSizeData uint32_t TiffIfdMakernote::doSizeData() const { assert(false); return 0; } // TiffIfdMakernote::doSizeData uint32_t TiffComponent::sizeImage() const { return doSizeImage(); } // TiffComponent::sizeImage uint32_t TiffDirectory::doSizeImage() const { uint32_t len = 0; for (Components::const_iterator i = components_.begin(); i != components_.end(); ++i) { len += (*i)->sizeImage(); } if (pNext_) { len += pNext_->sizeImage(); } return len; } // TiffDirectory::doSizeImage uint32_t TiffSubIfd::doSizeImage() const { uint32_t len = 0; for (Ifds::const_iterator i = ifds_.begin(); i != ifds_.end(); ++i) { len += (*i)->sizeImage(); } return len; } // TiffSubIfd::doSizeImage uint32_t TiffIfdMakernote::doSizeImage() const { return ifd_.sizeImage(); } // TiffIfdMakernote::doSizeImage uint32_t TiffEntryBase::doSizeImage() const { return 0; } // TiffEntryBase::doSizeImage uint32_t TiffImageEntry::doSizeImage() const { if (!pValue()) return 0; uint32_t len = pValue()->sizeDataArea(); if (len == 0) { for (Strips::const_iterator i = strips_.begin(); i != strips_.end(); ++i) { len += i->second; } } return len; } // TiffImageEntry::doSizeImage // ************************************************************************* // free functions TypeId toTypeId(TiffType tiffType, uint16_t tag, IfdId group) { TypeId ti = TypeId(tiffType); // On the fly type conversion for Exif.Photo.UserComment if (tag == 0x9286 && group == exifId && ti == undefined) { ti = comment; } return ti; } TiffType toTiffType(TypeId typeId) { if (static_cast(typeId) > 0xffff) { #ifndef SUPPRESS_WARNINGS EXV_ERROR << "'" << TypeInfo::typeName(typeId) << "' is not a valid Exif (TIFF) type; using type '" << TypeInfo::typeName(undefined) << "'.\n"; #endif return undefined; } return static_cast(typeId); } bool cmpTagLt(TiffComponent const* lhs, TiffComponent const* rhs) { assert(lhs != 0); assert(rhs != 0); if (lhs->tag() != rhs->tag()) return lhs->tag() < rhs->tag(); return lhs->idx() < rhs->idx(); } bool cmpGroupLt(TiffComponent const* lhs, TiffComponent const* rhs) { assert(lhs != 0); assert(rhs != 0); return lhs->group() < rhs->group(); } TiffComponent::AutoPtr newTiffEntry(uint16_t tag, IfdId group) { return TiffComponent::AutoPtr(new TiffEntry(tag, group)); } TiffComponent::AutoPtr newTiffMnEntry(uint16_t tag, IfdId group) { return TiffComponent::AutoPtr(new TiffMnEntry(tag, group, mnId)); } TiffComponent::AutoPtr newTiffBinaryElement(uint16_t tag, IfdId group) { return TiffComponent::AutoPtr(new TiffBinaryElement(tag, group)); } }} // namespace Internal, Exiv2 // ***************************************************************************** // local definitions namespace { uint32_t fillGap(Exiv2::Internal::IoWrapper& ioWrapper, uint32_t curr, uint32_t tobe) { if (curr < tobe) { Exiv2::DataBuf buf(tobe - curr); memset(buf.pData_, 0x0, buf.size_); ioWrapper.write(buf.pData_, buf.size_); return tobe - curr; } return 0; } // fillGap } exiv2-0.23/src/private.h0000644000175000017500000001036110736464412014731 0ustar andreasandreas/*! @file private.h @brief This file is from the tz distribution at ftp://elsie.nci.nih.gov/pub/ @version $Rev: 1358 $ */ #ifndef PRIVATE_H #define PRIVATE_H /* ** This file is in the public domain, so clarified as of ** 1996-06-05 by Arthur David Olson (arthur_david_olson@nih.gov). */ /* ** This header is for use ONLY with the time conversion code. ** There is no guarantee that it will remain unchanged, ** or that it will remain at all. ** Do NOT copy it to any system include directory. ** Thank you! */ /* ** ID */ #ifndef lint #ifndef NOID static char privatehid[] = "@(#)private.h 7.53"; #endif /* !defined NOID */ #endif /* !defined lint */ /* ahu: moved required preprocessor symbols to config.h */ /* ahu: disable warnings */ #ifdef _MSC_VER // disable warning 'uses old-style declarator' C4131 #pragma warning (disable: 4131) #endif /* ** Nested includes */ #include "sys/types.h" /* for time_t */ #include "stdio.h" #include "errno.h" #include "string.h" #include "limits.h" /* for CHAR_BIT */ #include "time.h" #include "stdlib.h" /* ahu: added io.h for MSVC */ #ifdef _MSC_VER # include "io.h" #endif /* ahu: deleted include libintl.h */ /* ahu: deleted include sys/wait.h and WIFEXITED, WEXITSTATUS macros */ #if EXV_HAVE_UNISTD_H - 0 #include "unistd.h" /* for F_OK and R_OK */ #endif /* EXV_HAVE_UNISTD_H - 0 */ #if !(EXV_HAVE_UNISTD_H - 0) #ifndef F_OK #define F_OK 0 #endif /* !defined F_OK */ #ifndef R_OK #define R_OK 4 #endif /* !defined R_OK */ #endif /* !(EXV_HAVE_UNISTD_H - 0) */ /* Unlike 's isdigit, this also works if c < 0 | c > UCHAR_MAX. */ #define is_digit(c) ((unsigned)(c) - '0' <= 9) /* ** Workarounds for compilers/systems. */ /* ** SunOS 4.1.1 cc lacks prototypes. */ #ifndef P #ifdef __STDC__ #define P(x) x #endif /* defined __STDC__ */ #ifndef __STDC__ #define P(x) () #endif /* !defined __STDC__ */ #endif /* !defined P */ /* ** SunOS 4.1.1 headers lack EXIT_SUCCESS. */ #ifndef EXIT_SUCCESS #define EXIT_SUCCESS 0 #endif /* !defined EXIT_SUCCESS */ /* ** SunOS 4.1.1 headers lack EXIT_FAILURE. */ #ifndef EXIT_FAILURE #define EXIT_FAILURE 1 #endif /* !defined EXIT_FAILURE */ /* ** SunOS 4.1.1 headers lack FILENAME_MAX. */ #ifndef FILENAME_MAX #ifndef MAXPATHLEN #ifdef unix #include "sys/param.h" #endif /* defined unix */ #endif /* !defined MAXPATHLEN */ #ifdef MAXPATHLEN #define FILENAME_MAX MAXPATHLEN #endif /* defined MAXPATHLEN */ #ifndef MAXPATHLEN #define FILENAME_MAX 1024 /* Pure guesswork */ #endif /* !defined MAXPATHLEN */ #endif /* !defined FILENAME_MAX */ /* ahu: deleted unlink declaration and remove define */ /* ahu: deleted errno declaration */ /* ahu: deleted private function declarations */ /* ** Finally, some convenience items. */ #ifndef TRUE #define TRUE 1 #endif /* !defined TRUE */ #ifndef FALSE #define FALSE 0 #endif /* !defined FALSE */ #ifndef TYPE_BIT #define TYPE_BIT(type) (sizeof (type) * CHAR_BIT) #endif /* !defined TYPE_BIT */ #ifndef TYPE_SIGNED #define TYPE_SIGNED(type) (((type) -1) < 0) #endif /* !defined TYPE_SIGNED */ #ifndef INT_STRLEN_MAXIMUM /* ** 302 / 1000 is log10(2.0) rounded up. ** Subtract one for the sign bit if the type is signed; ** add one for integer division truncation; ** add one more for a minus sign if the type is signed. */ #define INT_STRLEN_MAXIMUM(type) \ ((TYPE_BIT(type) - TYPE_SIGNED(type)) * 302 / 1000 + 1 + TYPE_SIGNED(type)) #endif /* !defined INT_STRLEN_MAXIMUM */ /* ** INITIALIZE(x) */ #ifndef GNUC_or_lint #ifdef lint #define GNUC_or_lint #endif /* defined lint */ #ifndef lint #ifdef __GNUC__ #define GNUC_or_lint #endif /* defined __GNUC__ */ #endif /* !defined lint */ #endif /* !defined GNUC_or_lint */ #ifndef INITIALIZE #ifdef GNUC_or_lint #define INITIALIZE(x) ((x) = 0) #endif /* defined GNUC_or_lint */ #ifndef GNUC_or_lint #define INITIALIZE(x) #endif /* !defined GNUC_or_lint */ #endif /* !defined INITIALIZE */ /* ahu: deleted definition of _(msgid) macro */ #ifndef TZ_DOMAIN #define TZ_DOMAIN "tz" #endif /* !defined TZ_DOMAIN */ #if HAVE_INCOMPATIBLE_CTIME_R #undef asctime_r #undef ctime_r char *asctime_r P((struct tm const *, char *)); char *ctime_r P((time_t const *, char *)); #endif /* HAVE_INCOMPATIBLE_CTIME_R */ /* ** UNIX was a registered trademark of The Open Group in 2003. */ #endif /* !defined PRIVATE_H */ exiv2-0.23/src/metacopy.cpp0000644000175000017500000001314211732641407015431 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /* Abstract : Tester application for image file handling File : metacopy.cpp Version : $Rev: 2681 $ Author(s): Brad Schick (brad) History : 13-Jul-04, brad: created */ // ***************************************************************************** // included header files #include "image.hpp" #include "iptc.hpp" #include "exif.hpp" #include "types.hpp" #include "metacopy.hpp" #include #include #include // ***************************************************************************** // Main int main(int argc, char* const argv[]) { try { // Handle command line arguments Params params; if (params.getopt(argc, argv)) { params.usage(); return 1; } if (params.help_) { params.help(); return 2; } // Use MemIo to increase test coverage. Exiv2::BasicIo::AutoPtr fileIo(new Exiv2::FileIo(params.read_)); Exiv2::BasicIo::AutoPtr memIo(new Exiv2::MemIo); memIo->transfer(*fileIo); Exiv2::Image::AutoPtr readImg = Exiv2::ImageFactory::open(memIo); assert(readImg.get() != 0); readImg->readMetadata(); Exiv2::Image::AutoPtr writeImg = Exiv2::ImageFactory::open(params.write_); assert(writeImg.get() != 0); if (params.preserve_) writeImg->readMetadata(); if (params.iptc_) { writeImg->setIptcData(readImg->iptcData()); } if (params.exif_) { writeImg->setExifData(readImg->exifData()); } if (params.comment_) { writeImg->setComment(readImg->comment()); } if (params.xmp_) { writeImg->setXmpData(readImg->xmpData()); } try { writeImg->writeMetadata(); } catch (const Exiv2::AnyError&) { std::cerr << params.progname() << ": Could not write metadata to (" << params.write_ << ")\n"; return 8; } return 0; } catch (Exiv2::AnyError& e) { std::cerr << "Caught Exiv2 exception '" << e << "'\n"; return 10; } } int Params::option(int opt, const std::string& /*optarg*/, int optopt) { int rc = 0; switch (opt) { case 'h': help_ = true; break; case 'i': iptc_ = true; break; case 'e': exif_ = true; break; case 'c': comment_ = true; break; case 'x': xmp_ = true; break; case 'p': preserve_ = true; break; case 'a': iptc_ =true; exif_ =true; comment_ =true; xmp_ =true; break; case ':': std::cerr << progname() << ": Option -" << static_cast(optopt) << " requires an argument\n"; rc = 1; break; case '?': std::cerr << progname() << ": Unrecognized option -" << static_cast(optopt) << "\n"; rc = 1; break; default: std::cerr << progname() << ": getopt returned unexpected character code " << std::hex << opt << "\n"; rc = 1; break; } return rc; } int Params::nonoption(const std::string& argv) { if (!write_.empty()) { std::cerr << progname() << ": Unexpected extra argument (" << argv << ")\n"; return 1; } if (first_) read_ = argv; else write_ = argv; first_ = false; return 0; } int Params::getopt(int argc, char* const argv[]) { int rc = Util::Getopt::getopt(argc, argv, optstring_); // Further consistency checks if (help_==false) { if (rc==0 && read_.empty() ) { std::cerr << progname() << ": Read and write files must be specified\n"; rc = 1; } if (rc==0 && write_.empty() ) { std::cerr << progname() << ": Write file must be specified\n"; rc = 1; } if (preserve_ && iptc_ && exif_ && comment_ && xmp_ ) { std::cerr << progname() << ": Option -p has no effect when all metadata types are specified.\n"; rc = 1; } } return rc; } // Params::getopt void Params::usage(std::ostream& os) const { os << "\nReads and writes raw metadata. Use -h option for help.\n" << "Usage: " << progname() << " [-iecaph] readfile writefile\n"; } void Params::help(std::ostream& os) const { usage(os); os << "\nOptions:\n" << " -i Read Iptc data from readfile and write to writefile.\n" << " -e Read Exif data from readfile and write to writefile.\n" << " -c Read Jpeg comment from readfile and write to writefile.\n" << " -x Read XMP data from readfile and write to writefile.\n" << " -a Read all metadata from readfile and write to writefile.\n" << " -p Preserve existing metadata in writefile if not replaced.\n" << " -h Display this help and exit.\n\n"; } // Params::help exiv2-0.23/src/pentaxmn.cpp0000644000175000017500000013774211732641407015457 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /* File: pentaxmn.cpp Version: $Rev: 2681 $ Author(s): Michal Cihar Based on fujimn.cpp by: Andreas Huggel (ahu) Gilles Caulier (gc) History: 27-Sep-07 created Credits: See header file. */ // ***************************************************************************** #include "rcsid_int.hpp" EXIV2_RCSID("@(#) $Id: pentaxmn.cpp 2681 2012-03-22 15:19:35Z ahuggel $") // ***************************************************************************** // included header files #include "types.hpp" #include "pentaxmn_int.hpp" #include "value.hpp" #include "i18n.h" // NLS support. // + standard includes #include #include #include #include #include // ***************************************************************************** // class member definitions namespace Exiv2 { namespace Internal { //! ShootingMode, tag 0x0001 extern const TagDetails pentaxShootingMode[] = { { 0, N_("Auto") }, { 1, N_("Night-Scene") }, { 2, N_("Manual") }, }; //! CameraModel, tag 0x0005 extern const TagDetails pentaxModel[] = { { 0x0000d, N_("Optio 330/430") }, { 0x12926, N_("Optio 230") }, { 0x12958, N_("Optio 330GS") }, { 0x12962, N_("Optio 450/550") }, { 0x1296c, N_("Optio S") }, { 0x12994, N_("*ist D") }, { 0x129b2, N_("Optio 33L") }, { 0x129bc, N_("Optio 33LF") }, { 0x129c6, N_("Optio 33WR/43WR/555") }, { 0x129d5, N_("Optio S4") }, { 0x12a02, N_("Optio MX") }, { 0x12a0c, N_("Optio S40") }, { 0x12a16, N_("Optio S4i") }, { 0x12a34, N_("Optio 30") }, { 0x12a52, N_("Optio S30") }, { 0x12a66, N_("Optio 750Z") }, { 0x12a70, N_("Optio SV") }, { 0x12a75, N_("Optio SVi") }, { 0x12a7a, N_("Optio X") }, { 0x12a8e, N_("Optio S5i") }, { 0x12a98, N_("Optio S50") }, { 0x12aa2, N_("*ist DS") }, { 0x12ab6, N_("Optio MX4") }, { 0x12ac0, N_("Optio S5n") }, { 0x12aca, N_("Optio WP") }, { 0x12afc, N_("Optio S55") }, { 0x12b10, N_("Optio S5z") }, { 0x12b1a, N_("*ist DL") }, { 0x12b24, N_("Optio S60") }, { 0x12b2e, N_("Optio S45") }, { 0x12b38, N_("Optio S6") }, { 0x12b4c, N_("Optio WPi") }, { 0x12b56, N_("BenQ DC X600") }, { 0x12b60, N_("*ist DS2") }, { 0x12b62, N_("Samsung GX-1S") }, { 0x12b6a, N_("Optio A10") }, { 0x12b7e, N_("*ist DL2") }, { 0x12b80, N_("Samsung GX-1L") }, { 0x12b9c, N_("K100D") }, { 0x12b9d, N_("K110D") }, { 0x12ba2, N_("K100D Super") }, { 0x12bb0, N_("Optio T10/T20") }, { 0x12be2, N_("Optio W10") }, { 0x12bf6, N_("Optio M10") }, { 0x12c1e, N_("K10D") }, { 0x12c20, N_("Samsung GX10") }, { 0x12c28, N_("Optio S7") }, { 0x12c2d, N_("Optio L20") }, { 0x12c32, N_("Optio M20") }, { 0x12c3c, N_("Optio W20") }, { 0x12c46, N_("Optio A20") }, { 0x12c8c, N_("Optio M30") }, { 0x12c78, N_("Optio E30") }, { 0x12c7d, N_("Optio E35") }, { 0x12c82, N_("Optio T30") }, { 0x12c96, N_("Optio W30") }, { 0x12ca0, N_("Optio A30") }, { 0x12cb4, N_("Optio E40") }, { 0x12cbe, N_("Optio M40") }, { 0x12cc8, N_("Optio Z10") }, { 0x12cd2, N_("K20D") }, { 0x12cd4, N_("Samsung GX20") }, { 0x12cdc, N_("Optio S10") }, { 0x12ce6, N_("Optio A40") }, { 0x12cf0, N_("Optio V10") }, { 0x12cfa, N_("K200D") }, { 0x12d04, N_("Optio S12") }, { 0x12d0e, N_("Optio E50") }, { 0x12d18, N_("Optio M50") }, { 0x12d2c, N_("Optio V20") }, { 0x12d40, N_("Optio W60") }, { 0x12d4a, N_("Optio M60") }, { 0x12d68, N_("Optio E60") }, { 0x12d72, N_("K2000") }, { 0x12d73, N_("K-m") }, { 0x12d86, N_("Optio P70") }, { 0x12d9a, N_("Optio E70") }, { 0x12dae, N_("X70") }, { 0x12db8, N_("K-7") }, { 0x12dcc, N_("Optio W80") }, { 0x12dea, N_("Optio P80") }, { 0x12df4, N_("Optio WS80") }, { 0x12dfe, N_("K-x") }, { 0x12e08, N_("645D") }, { 0x12e3a, N_("Optio I-10") }, }; //! Quality, tag 0x0008 extern const TagDetails pentaxQuality[] = { { 0, N_("Good") }, { 1, N_("Better") }, { 2, N_("Best") }, { 3, N_("TIFF") }, { 4, N_("RAW") }, { 5, N_("Premium") }, }; //! Size, tag 0x0009 extern const TagDetails pentaxSize[] = { { 0, N_("640x480") }, { 1, N_("Full") }, { 2, N_("1024x768") }, { 3, N_("1280x960") }, { 4, N_("1600x1200") }, { 5, N_("2048x1536") }, { 8, N_("2560x1920 or 2304x1728") }, { 9, N_("3072x2304") }, { 10, N_("3264x2448") }, { 19, N_("320x240") }, { 20, N_("2288x1712") }, { 21, N_("2592x1944") }, { 22, N_("2304x1728 or 2592x1944") }, { 23, N_("3056x2296") }, { 25, N_("2816x2212 or 2816x2112") }, { 27, N_("3648x2736") }, }; //! Flash, tag 0x000c extern const TagDetails pentaxFlash[] = { { 0x000, N_("Auto, Did not fire") }, { 0x001, N_("Off") }, { 0x003, N_("Auto, Did not fire, Red-eye reduction") }, { 0x100, N_("Auto, Fired") }, { 0x102, N_("On") }, { 0x103, N_("Auto, Fired, Red-eye reduction") }, { 0x104, N_("On, Red-eye reduction") }, { 0x105, N_("On, Wireless") }, { 0x108, N_("On, Soft") }, { 0x109, N_("On, Slow-sync") }, { 0x10a, N_("On, Slow-sync, Red-eye reduction") }, { 0x10b, N_("On, Trailing-curtain Sync") }, }; //! Focus, tag 0x000d extern const TagDetails pentaxFocus[] = { { 0, N_("Normal") }, { 1, N_("Macro") }, { 2, N_("Infinity") }, { 3, N_("Manual") }, { 4, N_("Super Macro") }, { 5, N_("Pan Focus") }, { 16, N_("AF-S") }, { 17, N_("AF-C") }, { 18, N_("AF-A") }, }; //! AFPoint, tag 0x000e extern const TagDetails pentaxAFPoint[] = { { 0xffff, N_("Auto") }, { 0xfffe, N_("Fixed Center") }, { 0xfffd, N_("Automatic Tracking AF") }, { 0xfffc, N_("Face Recognition AF") }, { 1, N_("Upper-left") }, { 2, N_("Top") }, { 3, N_("Upper-right") }, { 4, N_("Left") }, { 5, N_("Mid-left") }, { 6, N_("Center") }, { 7, N_("Mid-right") }, { 8, N_("Right") }, { 9, N_("Lower-left") }, { 10, N_("Bottom") }, { 11, N_("Lower-right") }, }; //! AFPointInFocus, tag 0x000f extern const TagDetails pentaxAFPointFocus[] = { { 0xffff, N_("None") }, { 0, N_("Fixed Center or multiple") }, { 1, N_("Top-left") }, { 2, N_("Top-center") }, { 3, N_("Top-right") }, { 4, N_("Left") }, { 5, N_("Center") }, { 6, N_("Right") }, { 7, N_("Bottom-left") }, { 8, N_("Bottom-center") }, { 9, N_("Bottom-right") }, }; //! ISO, tag 0x0014 extern const TagDetails pentaxISO[] = { { 3, N_("50") }, { 4, N_("64") }, { 5, N_("80") }, { 6, N_("100") }, { 7, N_("125") }, { 8, N_("160") }, { 9, N_("200") }, { 10, N_("250") }, { 11, N_("320") }, { 12, N_("400") }, { 13, N_("500") }, { 14, N_("640") }, { 15, N_("800") }, { 16, N_("1000") }, { 17, N_("1250") }, { 18, N_("1600") }, { 19, N_("2000") }, { 20, N_("2500") }, { 21, N_("3200") }, { 22, N_("4000") }, { 23, N_("5000") }, { 24, N_("6400") }, { 50, N_("50") }, { 100, N_("100") }, { 200, N_("200") }, { 268, N_("200") }, { 400, N_("400") }, { 800, N_("800") }, { 1600, N_("1600") }, { 3200, N_("3200") }, { 258, N_("50") }, { 259, N_("70") }, { 260, N_("100") }, { 261, N_("140") }, { 262, N_("200") }, { 263, N_("280") }, { 264, N_("400") }, { 265, N_("560") }, { 266, N_("800") }, { 267, N_("1100") }, { 268, N_("1600") }, { 269, N_("2200") }, { 270, N_("3200") }, }; //! Generic for Off/On switches extern const TagDetails pentaxOffOn[] = { { 0, N_("Off") }, { 1, N_("On") }, }; //! Generic for Yes/No switches extern const TagDetails pentaxYesNo[] = { { 0, N_("No") }, { 1, N_("Yes") }, }; //! MeteringMode, tag 0x0017 extern const TagDetails pentaxMeteringMode[] = { { 0, N_("Multi Segment") }, { 1, N_("Center Weighted") }, { 2, N_("Spot") }, }; //! WhiteBallance, tag 0x0019 extern const TagDetails pentaxWhiteBallance[] = { { 0, N_("Auto") }, { 1, N_("Daylight") }, { 2, N_("Shade") }, { 3, N_("Fluorescent") }, { 4, N_("Tungsten") }, { 5, N_("Manual") }, { 6, N_("DaylightFluorescent") }, { 7, N_("DaywhiteFluorescent") }, { 8, N_("WhiteFluorescent") }, { 9, N_("Flash") }, { 10, N_("Cloudy") }, { 17, N_("Kelvin") }, { 65534, N_("Unknown") }, { 65535, N_("User Selected") }, }; //! WhiteBallance, tag 0x001a extern const TagDetails pentaxWhiteBallanceMode[] = { { 1, N_("Auto (Daylight)") }, { 2, N_("Auto (Shade)") }, { 3, N_("Auto (Flash)") }, { 4, N_("Auto (Tungsten)") }, { 7, N_("Auto (DaywhiteFluorescent)") }, { 8, N_("Auto (WhiteFluorescent)") }, { 10, N_("Auto (Cloudy)") }, { 0xffff, N_("User-Selected") }, { 0xfffe, N_("Preset (Fireworks?)") }, }; //! Saturation, tag 0x001f extern const TagDetails pentaxSaturation[] = { { 0, N_("Low") }, { 1, N_("Normal") }, { 2, N_("High") }, { 3, N_("Med Low") }, { 4, N_("Med High") }, { 5, N_("Very Low") }, { 6, N_("Very High") }, { 65535, N_("None") }, { 65535, N_("None") } // To silence compiler warning }; //! Contrast, tag 0x0020 extern const TagDetails pentaxContrast[] = { { 0, N_("Low") }, { 1, N_("Normal") }, { 2, N_("High") }, { 3, N_("Med Low") }, { 4, N_("Med High") }, { 5, N_("Very Low") }, { 6, N_("Very High") }, }; //! Sharpness, tag 0x0021 extern const TagDetails pentaxSharpness[] = { { 0, N_("Soft") }, { 1, N_("Normal") }, { 2, N_("Hard") }, { 3, N_("Med Soft") }, { 4, N_("Med Hard") }, { 5, N_("Very Soft") }, { 6, N_("Very Hard") }, }; //! Location, tag 0x0022 extern const TagDetails pentaxLocation[] = { { 0, N_("Home town") }, { 1, N_("Destination") }, }; //! City names, tags 0x0023 and 0x0024 extern const TagDetails pentaxCities[] = { { 0, N_("Pago Pago") }, { 1, N_("Honolulu") }, { 2, N_("Anchorage") }, { 3, N_("Vancouver") }, { 4, N_("San Fransisco") }, { 5, N_("Los Angeles") }, { 6, N_("Calgary") }, { 7, N_("Denver") }, { 8, N_("Mexico City") }, { 9, N_("Chicago") }, { 10, N_("Miami") }, { 11, N_("Toronto") }, { 12, N_("New York") }, { 13, N_("Santiago") }, { 14, N_("Caracus") }, { 15, N_("Halifax") }, { 16, N_("Buenos Aires") }, { 17, N_("Sao Paulo") }, { 18, N_("Rio de Janeiro") }, { 19, N_("Madrid") }, { 20, N_("London") }, { 21, N_("Paris") }, { 22, N_("Milan") }, { 23, N_("Rome") }, { 24, N_("Berlin") }, { 25, N_("Johannesburg") }, { 26, N_("Istanbul") }, { 27, N_("Cairo") }, { 28, N_("Jerusalem") }, { 29, N_("Moscow") }, { 30, N_("Jeddah") }, { 31, N_("Tehran") }, { 32, N_("Dubai") }, { 33, N_("Karachi") }, { 34, N_("Kabul") }, { 35, N_("Male") }, { 36, N_("Delhi") }, { 37, N_("Colombo") }, { 38, N_("Kathmandu") }, { 39, N_("Dacca") }, { 40, N_("Yangon") }, { 41, N_("Bangkok") }, { 42, N_("Kuala Lumpur") }, { 43, N_("Vientiane") }, { 44, N_("Singapore") }, { 45, N_("Phnom Penh") }, { 46, N_("Ho Chi Minh") }, { 47, N_("Jakarta") }, { 48, N_("Hong Kong") }, { 49, N_("Perth") }, { 50, N_("Beijing") }, { 51, N_("Shanghai") }, { 52, N_("Manila") }, { 53, N_("Taipei") }, { 54, N_("Seoul") }, { 55, N_("Adelaide") }, { 56, N_("Tokyo") }, { 57, N_("Guam") }, { 58, N_("Sydney") }, { 59, N_("Noumea") }, { 60, N_("Wellington") }, { 61, N_("Auckland") }, { 62, N_("Lima") }, { 63, N_("Dakar") }, { 64, N_("Algiers") }, { 65, N_("Helsinki") }, { 66, N_("Athens") }, { 67, N_("Nairobi") }, { 68, N_("Amsterdam") }, { 69, N_("Stockholm") }, { 70, N_("Lisbon") }, { 71, N_("Copenhagen") }, }; //! ImageProcessing, combi-tag 0x0032 (4 bytes) extern const TagDetails pentaxImageProcessing[] = { { 0x00000000, N_("Unprocessed") }, { 0x00000004, N_("Digital Filter") }, { 0x02000000, N_("Cropped") }, { 0x04000000, N_("Color Filter") }, { 0x10000000, N_("Frame Synthesis?") } }; //! PictureMode, combi-tag 0x0033 (3 bytes) extern const TagDetails pentaxPictureMode[] = { { 0x000000, N_("Program") }, { 0x000300, N_("MTF Program") }, { 0x000400, N_("Standard") }, { 0x000500, N_("Portrait") }, { 0x000600, N_("Landscape") }, { 0x000700, N_("Macro") }, { 0x000800, N_("Sport") }, { 0x000900, N_("Night Scene Portrait") }, { 0x000a00, N_("No Flash") }, /* SCN modes (menu-selected) */ { 0x000b00, N_("Night Scene") }, { 0x000c00, N_("Surf & Snow") }, { 0x000d00, N_("Text") }, { 0x000e00, N_("Sunset") }, { 0x000f00, N_("Kids") }, { 0x001000, N_("Pet") }, { 0x001100, N_("Candlelight") }, { 0x001200, N_("Museum") }, { 0x001300, N_("Food") }, { 0x001400, N_("Stage Lighting") }, { 0x001500, N_("Night Snap") }, /* AUTO PICT modes (auto-selected) */ { 0x010400, N_("Auto PICT (Standard)") }, { 0x010500, N_("Auto PICT (Portrait)") }, { 0x010600, N_("Auto PICT (Landscape)") }, { 0x010700, N_("Auto PICT (Macro)") }, { 0x010800, N_("Auto PICT (Sport)") }, /* Manual dial modes */ { 0x020000, N_("Program AE") }, { 0x030000, N_("Green Mode") }, { 0x040000, N_("Shutter Speed Priority") }, { 0x050000, N_("Aperture Priority") }, { 0x080000, N_("Manual") }, { 0x090000, N_("Bulb") }, /* *istD modes */ { 0x020001, N_("Program AE") }, { 0x020101, N_("Hi-speed Program") }, { 0x020201, N_("DOF Program") }, { 0x020301, N_("MTF Program") }, { 0x030001, N_("Green Mode") }, { 0x040001, N_("Shutter Speed Priority") }, { 0x050001, N_("Aperture Priority") }, { 0x060001, N_("Program Tv Shift") }, { 0x070001, N_("Program Av Shift") }, { 0x080001, N_("Manual") }, { 0x090001, N_("Bulb") }, { 0x0a0001, N_("Aperture Priority (Off-Auto-Aperture)") }, { 0x0b0001, N_("Manual (Off-Auto-Aperture)") }, { 0x0c0001, N_("Bulb (Off-Auto-Aperture)") }, /* K10D modes */ { 0x060000, N_("Shutter Priority") }, { 0x0d0000, N_("Shutter & Aperture Priority AE") }, { 0x0d0001, N_("Shutter & Aperture Priority AE (1)") }, { 0x0f0000, N_("Sensitivity Priority AE") }, { 0x0f0001, N_("Sensitivity Priority AE (1)") }, { 0x100000, N_("Flash X-Sync Speed AE") }, { 0x100001, N_("Flash X-Sync Speed AE (1)") }, /* other modes */ { 0x000001, N_("Program") }, { 0xfe0000, N_("Video (30 fps)") }, { 0xff0004, N_("Video (24 fps)") }, }; //! DriveMode, combi-tag 0x0034 (4 bytes) extern const TagDetails pentaxDriveMode[] = { { 0x00000000, N_("Single-frame") }, { 0x01000000, N_("Continuous") }, { 0x02000000, N_("Continuous (Hi)") }, { 0x03000000, N_("Burst") }, { 0x00100000, N_("Single-frame") }, /* on 645D */ { 0x00010000, N_("Self-timer (12 sec)") }, { 0x00020000, N_("Self-timer (2 sec)") }, { 0x00000100, N_("Remote Control (3 sec)") }, { 0x00000200, N_("Remote Control") }, { 0x00000001, N_("Multiple Exposure") }, { 0x000000ff, N_("Video") }, }; //! ColorSpace, tag 0x0037 extern const TagDetails pentaxColorSpace[] = { { 0, N_("sRGB") }, { 1, N_("Adobe RGB") }, }; //! LensType, combi-tag 0x003f (2 unsigned long) extern const TagDetails pentaxLensType[] = { { 0x0000, N_("M-42 or No Lens") }, { 0x0100, N_("K,M Lens") }, { 0x0200, N_("A Series Lens") }, { 0x0300, "SIGMA" }, { 0x0311, "smc PENTAX-FA SOFT 85mm F2.8" }, { 0x0312, "smc PENTAX-F 1.7X AF ADAPTER" }, { 0x0313, "smc PENTAX-F 24-50mm F4" }, { 0x0314, "smc PENTAX-F 35-80mm F4-5.6" }, { 0x0315, "smc PENTAX-F 80-200mm F4.7-5.6" }, { 0x0316, "smc PENTAX-F FISH-EYE 17-28mm F3.5-4.5" }, { 0x0317, "smc PENTAX-F 100-300mm F4.5-5.6" }, { 0x0318, "smc PENTAX-F 35-135mm F3.5-4.5" }, { 0x0319, "smc PENTAX-F 35-105mm F4-5.6 or SIGMA or Tokina" }, { 0x031a, "smc PENTAX-F* 250-600mm F5.6 ED[IF]" }, { 0x031b, "smc PENTAX-F 28-80mm F3.5-4.5" }, { 0x031c, "smc PENTAX-F 35-70mm F3.5-4.5" }, { 0x031d, "PENTAX-F 28-80mm F3.5-4.5 or SIGMA AF 18-125mm F3.5-5.6 DC" }, { 0x031e, "PENTAX-F 70-200mm F4-5.6" }, { 0x031f, "smc PENTAX-F 70-210mm F4-5.6" }, { 0x0320, "smc PENTAX-F 50mm F1.4" }, { 0x0321, "smc PENTAX-F 50mm F1.7" }, { 0x0322, "smc PENTAX-F 135mm F2.8 [IF]" }, { 0x0323, "smc PENTAX-F 28mm F2.8" }, { 0x0324, "SIGMA 20mm F1.8 EX DG ASPHERICAL RF" }, { 0x0326, "smc PENTAX-F* 300mm F4.5 ED[IF]" }, { 0x0327, "smc PENTAX-F* 600mm F4 ED[IF]" }, { 0x0328, "smc PENTAX-F MACRO 100mm F2.8" }, { 0x0329, "smc PENTAX-F MACRO 50mm F2.8 or Sigma 50mm F2,8 MACRO" }, { 0x032c, "Tamron 35-90mm F4 AF or various SIGMA models" }, { 0x032e, "SIGMA APO 70-200mm F2.8 EX" }, { 0x0332, "smc PENTAX-FA 28-70mm F4 AL" }, { 0x0333, "SIGMA 28mm F1.8 EX DG ASPHERICAL MACRO" }, { 0x0334, "smc PENTAX-FA 28-200mm F3.8-5.6 AL[IF]" }, { 0x0335, "smc PENTAX-FA 28-80mm F3.5-5.6 AL" }, { 0x03f7, "smc PENTAX-DA FISH-EYE 10-17mm F3.5-4.5 ED[IF]" }, { 0x03f8, "smc PENTAX-DA 12-24mm F4 ED AL[IF]" }, { 0x03fa, "smc PENTAX-DA 50-200mm F4-5.6 ED" }, { 0x03fb, "smc PENTAX-DA 40mm F2.8 Limited" }, { 0x03fc, "smc PENTAX-DA 18-55mm F3.5-5.6 AL" }, { 0x03fd, "smc PENTAX-DA 14mm F2.8 ED[IF]" }, { 0x03fe, "smc PENTAX-DA 16-45mm F4 ED AL" }, { 0x03ff, "SIGMA" }, { 0x0401, "smc PENTAX-FA SOFT 28mm F2.8" }, { 0x0402, "smc PENTAX-FA 80-320mm F4.5-5.6" }, { 0x0403, "smc PENTAX-FA 43mm F1.9 Limited" }, { 0x0406, "smc PENTAX-FA 35-80mm F4-5.6" }, { 0x040c, "smc PENTAX-FA 50mm F1.4" }, { 0x040f, "smc PENTAX-FA 28-105mm F4-5.6 [IF]" }, { 0x0410, "TAMRON AF 80-210mm F4-5.6 (178D)" }, { 0x0413, "TAMRON SP AF 90mm F2.8 (172E)" }, { 0x0414, "smc PENTAX-FA 28-80mm F3.5-5.6" }, { 0x0416, "TOKINA 28-80mm F3.5-5.6" }, { 0x0417, "smc PENTAX-FA 20-35mm F4 AL" }, { 0x0418, "smc PENTAX-FA 77mm F1.8 Limited" }, { 0x0419, "TAMRON SP AF 14mm F2.8" }, { 0x041a, "smc PENTAX-FA MACRO 100mm F3.5" }, { 0x041b, "TAMRON AF28-300mm F/3.5-6.3 LD Aspherical[IF] MACRO (285D)" }, { 0x041c, "smc PENTAX-FA 35mm F2 AL" }, { 0x041d, "TAMRON AF 28-200mm F/3.8-5.6 LD Super II MACRO (371D)" }, { 0x0422, "smc PENTAX-FA 24-90mm F3.5-4.5 AL[IF]" }, { 0x0423, "smc PENTAX-FA 100-300mm F4.7-5.8" }, { 0x0424, "TAMRON AF70-300mm F/4-5.6 LD MACRO" }, { 0x0425, "TAMRON SP AF 24-135mm F3.5-5.6 AD AL (190D)" }, { 0x0426, "smc PENTAX-FA 28-105mm F3.2-4.5 AL[IF]" }, { 0x0427, "smc PENTAX-FA 31mm F1.8AL Limited" }, { 0x0429, "TAMRON AF 28-200mm Super Zoom F3.8-5.6 Aspherical XR [IF] MACRO (A03)" }, { 0x042b, "smc PENTAX-FA 28-90mm F3.5-5.6" }, { 0x042c, "smc PENTAX-FA J 75-300mm F4.5-5.8 AL" }, { 0x042d, "TAMRON 28-300mm F3.5-6.3 Ultra zoom XR" }, { 0x042e, "smc PENTAX-FA J 28-80mm F3.5-5.6 AL" }, { 0x042f, "smc PENTAX-FA J 18-35mm F4-5.6 AL" }, { 0x0431, "TAMRON SP AF 28-75mm F2.8 XR Di (A09)" }, { 0x0433, "smc PENTAX-D FA 50mm F2.8 MACRO" }, { 0x0434, "smc PENTAX-D FA 100mm F2.8 MACRO" }, { 0x04f4, "smc PENTAX-DA 21mm F3.2 AL Limited" }, { 0x04f5, "Schneider D-XENON 50-200mm" }, { 0x04f6, "Schneider D-XENON 18-55mm" }, { 0x04f7, "smc PENTAX-DA 10-17mm F3.5-4.5 ED [IF] Fisheye zoom" }, { 0x04f8, "smc PENTAX-DA 12-24mm F4 ED AL [IF]" }, { 0x04f9, "TAMRON XR DiII 18-200mm F3.5-6.3 (A14)" }, { 0x04fa, "smc PENTAX-DA 50-200mm F4-5.6 ED" }, { 0x04fb, "smc PENTAX-DA 40mm F2.8 Limited" }, { 0x04fc, "smc PENTAX-DA 18-55mm F3.5-5.6 AL" }, { 0x04fd, "smc PENTAX-DA 14mm F2.8 ED[IF]" }, { 0x04fe, "smc PENTAX-DA 16-45mm F4 ED AL" }, { 0x0501, "smc PENTAX-FA* 24mm F2 AL[IF]" }, { 0x0502, "smc PENTAX-FA 28mm F2.8 AL" }, { 0x0503, "smc PENTAX-FA 50mm F1.7" }, { 0x0504, "smc PENTAX-FA 50mm F1.4" }, { 0x0505, "smc PENTAX-FA* 600mm F4 ED[IF]" }, { 0x0506, "smc PENTAX-FA* 300mm F4.5 ED[IF]" }, { 0x0507, "smc PENTAX-FA 135mm F2.8 [IF]" }, { 0x0508, "smc PENTAX-FA MACRO 50mm F2.8" }, { 0x0509, "smc PENTAX-FA MACRO 100mm F2.8" }, { 0x050a, "smc PENTAX-FA* 85mm F1.4 [IF]" }, { 0x050b, "smc PENTAX-FA* 200mm F2.8 ED[IF]" }, { 0x050c, "smc PENTAX-FA 28-80mm F3.5-4.7" }, { 0x050d, "smc PENTAX-FA 70-200mm F4-5.6" }, { 0x050e, "smc PENTAX-FA* 250-600mm F5.6 ED[IF]" }, { 0x050f, "smc PENTAX-FA 28-105mm F4-5.6" }, { 0x0510, "smc PENTAX-FA 100-300mm F4.5-5.6" }, { 0x0601, "smc PENTAX-FA* 85mm F1.4[IF]" }, { 0x0602, "smc PENTAX-FA* 200mm F2.8 ED[IF]" }, { 0x0603, "smc PENTAX-FA* 300mm F2.8 ED[IF]" }, { 0x0604, "smc PENTAX-FA* 28-70mm F2.8 AL" }, { 0x0605, "smc PENTAX-FA* 80-200mm F2.8 ED[IF]" }, { 0x0606, "smc PENTAX-FA* 28-70mm F2.8 AL" }, { 0x0607, "smc PENTAX-FA* 80-200mm F2.8 ED[IF]" }, { 0x0608, "smc PENTAX-FA 28-70mm F4AL" }, { 0x0609, "smc PENTAX-FA 20mm F2.8" }, { 0x060a, "smc PENTAX-FA* 400mm F5.6 ED[IF]" }, { 0x060d, "smc PENTAX-FA* 400mm F5.6 ED[IF]" }, { 0x060e, "smc PENTAX-FA* MACRO 200mm F4 ED[IF]" }, { 0x0700, "smc PENTAX-DA 21mm F3.2 AL Limited" }, { 0x074b, "Tamron SP AF 70-200mm F2.8 Di LD [IF] Macro (A001)" }, { 0x07d9, "smc PENTAX-DA 50-200mm F4-5.6 ED WR" }, { 0x07da, "smc PENTAX-DA 18-55mm F3.5-5.6 AL WR" }, { 0x07dc, "Tamron SP AF 10-24mm F3.5-4.5 Di II LD Aspherical [IF]" }, { 0x07de, "smc PENTAX-DA 18-55mm F3.5-5.6 AL II" }, { 0x07df, "Samsung D-XENON 18-55mm F3.5-5.6 II" }, { 0x07e0, "smc PENTAX-DA 15mm F4 ED AL Limited" }, { 0x07e1, "Samsung D-XENON 18-250mm F3.5-6.3" }, { 0x07e5, "smc PENTAX-DA 18-55mm F3.5-5.6 AL II" }, { 0x07e6, "Tamron AF 17-50mm F2.8 XR Di-II LD (Model A16)" }, { 0x07e7, "smc PENTAX-DA 18-250mm F3.5-6.3ED AL [IF]" }, { 0x07e9, "smc PENTAX-DA 35mm F2.8 Macro Limited" }, { 0x07ea, "smc PENTAX-DA* 300 mm F4ED [IF] SDM (SDM not used)" }, { 0x07eb, "smc PENTAX-DA* 200mm F2.8 ED [IF] SDM (SDM not used)" }, { 0x07ec, "smc PENTAX-DA 55-300mm F4-5.8 ED" }, { 0x07ee, "TAMRON AF 18-250mm F3.5-6.3 Di II LD Aspherical [IF] MACRO" }, { 0x07f1, "smc PENTAX-DA* 50-135mm F2.8 ED [IF] SDM (SDM not used)" }, { 0x07f2, "smc PENTAX-DA* 16-50mm F2.8 ED AL [IF] SDM (SDM not used)" }, { 0x07f3, "smc PENTAX-DA 70mm F2.4 Limited" }, { 0x07f4, "smc PENTAX-DA 21mm F3.2 AL Limited" }, { 0x08e2, "smc PENTAX-DA* 55mm F1.4 SDM" }, { 0x08e3, "smc PENTAX DA* 60-250mm F4 [IF] SDM"}, { 0x08e8, "smc PENTAX-DA 17-70mm F4 AL [IF] SDM" }, { 0x08ea, "smc PENTAX-DA* 300mm F4 ED [IF] SDM" }, { 0x08eb, "smc PENTAX-DA* 200mm F2.8 ED [IF] SDM" }, { 0x08f1, "smc PENTAX-DA* 50-135mm F2.8 ED [IF] SDM" }, { 0x08f2, "smc PENTAX-DA* 16-50mm F2.8 ED AL [IF] SDM" }, { 0x0b04, "smc PENTAX-FA645 Zoom 45mm-85mm F4.5" }, { 0x0b07, "smc PENTAX-FA645 Macro 120mm F4" }, { 0x0b11, "smc PENTAX-FA645 Zoom 150mm-300mm F5.6 ED [IF]" }, }; //! ImageTone, tag 0x004f extern const TagDetails pentaxImageTone[] = { { 0, N_("Natural") }, { 1, N_("Bright") }, { 2, N_("Portrait") }, { 3, N_("Landscape") }, { 4, N_("Vibrant") }, { 5, N_("Monochrome") }, { 7, N_("Reversal film") }, }; //! DynamicRangeExpansion, tag 0x0069 extern const TagDetails pentaxDynamicRangeExpansion[] = { { 0, N_("Off") }, { 0x1000000, N_("On") }, }; //! HighISONoiseReduction, tag 0x0071 extern const TagDetails pentaxHighISONoiseReduction[] = { { 0, N_("Off") }, { 1, N_("Weakest") }, { 2, N_("Weak") }, { 3, N_("Strong") }, { 4, N_("Custom") }, }; std::ostream& PentaxMakerNote::printPentaxVersion(std::ostream& os, const Value& value, const ExifData*) { std::string val = value.toString(); size_t i; while ((i = val.find(' ')) != std::string::npos && i != val.length() - 1) { val.replace(i, 1, "."); } os << val; return os; } std::ostream& PentaxMakerNote::printPentaxResolution(std::ostream& os, const Value& value, const ExifData*) { std::string val = value.toString(); size_t i; while ((i = val.find(' ')) != std::string::npos && i != val.length() - 1) { val.replace(i, 1, "x"); } os << val; return os; } std::ostream& PentaxMakerNote::printPentaxDate(std::ostream& os, const Value& value, const ExifData*) { /* I choose same format as is used inside EXIF itself */ os << ((value.toLong(0) << 8) + value.toLong(1)); os << ":"; os << std::setw(2) << std::setfill('0') << value.toLong(2); os << ":"; os << std::setw(2) << std::setfill('0') << value.toLong(3); return os; } std::ostream& PentaxMakerNote::printPentaxTime(std::ostream& os, const Value& value, const ExifData*) { os << std::setw(2) << std::setfill('0') << value.toLong(0); os << ":"; os << std::setw(2) << std::setfill('0') << value.toLong(1); os << ":"; os << std::setw(2) << std::setfill('0') << value.toLong(2); return os; } std::ostream& PentaxMakerNote::printPentaxExposure(std::ostream& os, const Value& value, const ExifData*) { os << static_cast(value.toLong()) / 100 << " ms"; return os; } std::ostream& PentaxMakerNote::printPentaxFValue(std::ostream& os, const Value& value, const ExifData*) { os << "F" << std::setprecision(2) << static_cast(value.toLong()) / 10; return os; } std::ostream& PentaxMakerNote::printPentaxFocalLength(std::ostream& os, const Value& value, const ExifData*) { os << std::fixed << std::setprecision(1) << static_cast(value.toLong()) / 100 << " mm"; return os; } std::ostream& PentaxMakerNote::printPentaxCompensation(std::ostream& os, const Value& value, const ExifData*) { os << std::setprecision(2) << (static_cast(value.toLong()) - 50) / 10 << " EV"; return os; } std::ostream& PentaxMakerNote::printPentaxTemperature(std::ostream& os, const Value& value, const ExifData*) { os << value.toLong() << " C"; return os; } std::ostream& PentaxMakerNote::printPentaxFlashCompensation(std::ostream& os, const Value& value, const ExifData*) { os << std::setprecision(2) << static_cast(value.toLong()) / 256 << " EV"; return os; } std::ostream& PentaxMakerNote::printPentaxBracketing(std::ostream& os, const Value& value, const ExifData*) { long l0 = value.toLong(0); if (l0 < 10) { os << std::setprecision(2) << static_cast(l0) / 3 << " EV"; } else { os << std::setprecision(2) << static_cast(l0) - 9.5 << " EV"; } if (value.count() == 2) { long l1 = value.toLong(1); long type; long range; os << " ("; if (l1 == 0) { os << _("No extended bracketing"); } else { type = l1 >> 8; range = l1 & 0xff; switch (type) { case 1: os << _("WB-BA"); break; case 2: os << _("WB-GM"); break; case 3: os << _("Saturation"); break; case 4: os << _("Sharpness"); break; case 5: os << _("Contrast"); break; default: os << _("Unknown ") << type; break; } os << " " << range; } os << ")"; } return os; } // Pentax MakerNote Tag Info const TagInfo PentaxMakerNote::tagInfo_[] = { TagInfo(0x0000, "Version", N_("Version"), N_("Pentax Makernote version"), pentaxId, makerTags, undefined, -1, printPentaxVersion), TagInfo(0x0001, "Mode", N_("Shooting mode"), N_("Camera shooting mode"), pentaxId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(pentaxShootingMode)), TagInfo(0x0002, "PreviewResolution", N_("Resolution of a preview image"), N_("Resolution of a preview image"), pentaxId, makerTags, undefined, -1, printPentaxResolution), TagInfo(0x0003, "PreviewLength", N_("Length of a preview image"), N_("Size of an IFD containing a preview image"), pentaxId, makerTags, undefined, -1, printValue), TagInfo(0x0004, "PreviewOffset", N_("Pointer to a preview image"), N_("Offset to an IFD containing a preview image"), pentaxId, makerTags, undefined, -1, printValue), TagInfo(0x0005, "ModelID", N_("Model identification"), N_("Pentax model idenfication"), pentaxId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(pentaxModel)), TagInfo(0x0006, "Date", N_("Date"), N_("Date"), pentaxId, makerTags, undefined, -1, printPentaxDate), TagInfo(0x0007, "Time", N_("Time"), N_("Time"), pentaxId, makerTags, undefined, -1, printPentaxTime), TagInfo(0x0008, "Quality", N_("Image quality"), N_("Image quality settings"), pentaxId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(pentaxQuality)), TagInfo(0x0009, "Size", N_("Image size"), N_("Image size settings"), pentaxId, makerTags, unsignedLong, -1, EXV_PRINT_TAG(pentaxSize)), /* Some missing ! */ TagInfo(0x000c, "Flash", N_("Flash mode"), N_("Flash mode settings"), pentaxId, makerTags, unsignedLong, -1, EXV_PRINT_TAG(pentaxFlash)), TagInfo(0x000d, "Focus", N_("Focus mode"), N_("Focus mode settings"), pentaxId, makerTags, unsignedLong, -1, EXV_PRINT_TAG(pentaxFocus)), TagInfo(0x000e, "AFPoint", N_("AF point"), N_("Selected AF point"), pentaxId, makerTags, unsignedLong, -1, EXV_PRINT_TAG(pentaxAFPoint)), TagInfo(0x000F, "AFPointInFocus", N_("AF point in focus"), N_("AF point in focus"), pentaxId, makerTags, unsignedLong, -1, EXV_PRINT_TAG(pentaxAFPointFocus)), /* Some missing ! */ TagInfo(0x0012, "ExposureTime", N_("Exposure time"), N_("Exposure time"), pentaxId, makerTags, unsignedLong, -1, printPentaxExposure), TagInfo(0x0013, "FNumber", N_("F-Number"), N_("F-Number"), pentaxId, makerTags, unsignedLong, -1, printPentaxFValue), TagInfo(0x0014, "ISO", N_("ISO sensitivity"), N_("ISO sensitivity settings"), pentaxId, makerTags, unsignedLong, -1, EXV_PRINT_TAG(pentaxISO)), /* Some missing ! */ TagInfo(0x0016, "ExposureCompensation", N_("Exposure compensation"), N_("Exposure compensation"), pentaxId, makerTags, unsignedLong, -1, printPentaxCompensation), /* Some missing ! */ TagInfo(0x0017, "MeteringMode", N_("MeteringMode"), N_("MeteringMode"), pentaxId, makerTags, undefined, -1, EXV_PRINT_TAG(pentaxMeteringMode)), TagInfo(0x0018, "AutoBracketing", N_("AutoBracketing"), N_("AutoBracketing"), pentaxId, makerTags, undefined, -1, printPentaxBracketing), TagInfo(0x0019, "WhiteBallance", N_("White ballance"), N_("White ballance"), pentaxId, makerTags, undefined, -1, EXV_PRINT_TAG(pentaxWhiteBallance)), TagInfo(0x001a, "WhiteBallanceMode", N_("White ballance mode"), N_("White ballance mode"), pentaxId, makerTags, undefined, -1, EXV_PRINT_TAG(pentaxWhiteBallanceMode)), TagInfo(0x001b, "BlueBalance", N_("Blue balance"), N_("Blue color balance"), pentaxId, makerTags, unsignedLong, -1, printValue), TagInfo(0x001c, "RedBalance", N_("Red balance"), N_("Red color balance"), pentaxId, makerTags, unsignedLong, -1, printValue), TagInfo(0x001d, "FocalLength", N_("FocalLength"), N_("FocalLength"), pentaxId, makerTags, undefined, -1, printPentaxFocalLength), TagInfo(0x001e, "DigitalZoom", N_("Digital zoom"), N_("Digital zoom"), pentaxId, makerTags, unsignedLong, -1, printValue), TagInfo(0x001f, "Saturation", N_("Saturation"), N_("Saturation"), pentaxId, makerTags, undefined, -1, EXV_PRINT_TAG(pentaxSaturation)), TagInfo(0x0020, "Contrast", N_("Contrast"), N_("Contrast"), pentaxId, makerTags, undefined, -1, EXV_PRINT_TAG(pentaxContrast)), TagInfo(0x0021, "Sharpness", N_("Sharpness"), N_("Sharpness"), pentaxId, makerTags, undefined, -1, EXV_PRINT_TAG(pentaxSharpness)), TagInfo(0x0022, "Location", N_("Location"), N_("Location"), pentaxId, makerTags, undefined, -1, EXV_PRINT_TAG(pentaxLocation)), TagInfo(0x0023, "Hometown", N_("Hometown"), N_("Home town"), pentaxId, makerTags, undefined, -1, EXV_PRINT_TAG(pentaxCities)), TagInfo(0x0024, "Destination", N_("Destination"), N_("Destination"), pentaxId, makerTags, undefined, -1, EXV_PRINT_TAG(pentaxCities)), TagInfo(0x0025, "HometownDST", N_("Hometown DST"), N_("Whether day saving time is active in home town"), pentaxId, makerTags, undefined, -1, EXV_PRINT_TAG(pentaxYesNo)), TagInfo(0x0026, "DestinationDST", N_("Destination DST"), N_("Whether day saving time is active in destination"), pentaxId, makerTags, undefined, -1, EXV_PRINT_TAG(pentaxYesNo)), TagInfo(0x0027, "DSPFirmwareVersion", N_("DSPFirmwareVersion"), N_("DSPFirmwareVersion"), pentaxId, makerTags, unsignedByte, -1, printValue), /* TODO: Decoding missing */ TagInfo(0x0028, "CPUFirmwareVersion", N_("CPUFirmwareVersion"), N_("CPUFirmwareVersion"), pentaxId, makerTags, unsignedByte, -1, printValue), /* TODO: Decoding missing */ TagInfo(0x0029, "FrameNumber", N_("Frame number"), N_("Frame number"), pentaxId, makerTags, undefined, -1, printValue), /* Some missing ! */ TagInfo(0x002d, "EffectiveLV", N_("Light value"), N_("Camera calculated light value, includes exposure compensation"), pentaxId, makerTags, unsignedShort, -1, printValue), /* Some missing ! */ TagInfo(0x0032, "ImageProcessing", N_("Image processing"), N_("Image processing"), pentaxId, makerTags, undefined, -1, EXV_PRINT_COMBITAG(pentaxImageProcessing, 4, 0)), TagInfo(0x0033, "PictureMode", N_("Picture mode"), N_("Picture mode"), pentaxId, makerTags, undefined, -1, EXV_PRINT_COMBITAG(pentaxPictureMode, 3, 0)), TagInfo(0x0034, "DriveMode", N_("Drive mode"), N_("Drive mode"), pentaxId, makerTags, undefined, -1, EXV_PRINT_COMBITAG(pentaxDriveMode, 4, 0)), /* Some missing ! */ TagInfo(0x0037, "ColorSpace", N_("Color space"), N_("Color space"), pentaxId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(pentaxColorSpace)), TagInfo(0x0038, "ImageAreaOffset", N_("Image area offset"), N_("Image area offset"), pentaxId, makerTags, unsignedLong, -1, printValue), TagInfo(0x0039, "RawImageSize", N_("Raw image size"), N_("Raw image size"), pentaxId, makerTags, unsignedLong, -1, printValue), /* Some missing ! */ TagInfo(0x003e, "PreviewImageBorders", N_("Preview image borders"), N_("Preview image borders"), pentaxId, makerTags, unsignedByte, -1, printValue), TagInfo(0x003f, "LensType", N_("Lens type"), N_("Lens type"), pentaxId, makerTags, unsignedByte, -1, EXV_PRINT_COMBITAG_MULTI(pentaxLensType, 2, 1, 2)), TagInfo(0x0040, "SensitivityAdjust", N_("Sensitivity adjust"), N_("Sensitivity adjust"), pentaxId, makerTags, unsignedLong, -1, printValue), TagInfo(0x0041, "DigitalFilter", N_("Digital filter"), N_("Digital filter"), pentaxId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(pentaxOffOn)), /* Some missing ! */ TagInfo(0x0047, "Temperature", N_("Temperature"), N_("Camera temperature"), pentaxId, makerTags, signedByte, -1, printPentaxTemperature), TagInfo(0x0048, "AELock", N_("AE lock"), N_("AE lock"), pentaxId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(pentaxOffOn)), TagInfo(0x0049, "NoiseReduction", N_("Noise reduction"), N_("Noise reduction"), pentaxId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(pentaxOffOn)), /* Some missing ! */ TagInfo(0x004d, "FlashExposureCompensation", N_("Flash exposure compensation"), N_("Flash exposure compensation"), pentaxId, makerTags, signedLong, -1, printPentaxFlashCompensation), /* Some missing ! */ TagInfo(0x004f, "ImageTone", N_("Image tone"), N_("Image tone"), pentaxId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(pentaxImageTone)), TagInfo(0x0050, "ColorTemperature", N_("Colort temperature"), N_("Colort temperature"), pentaxId, makerTags, unsignedShort, -1, printValue), /* Some missing ! */ TagInfo(0x005c, "ShakeReduction", N_("Shake reduction"), N_("Shake reduction information"), pentaxId, makerTags, undefined, -1, printValue), TagInfo(0x005d, "ShutterCount", N_("Shutter count"), N_("Shutter count"), pentaxId, makerTags, undefined, -1, printValue), /* TODO: This has some encryption by date (see exiftool) */ TagInfo(0x0069, "DynamicRangeExpansion", N_("Dynamic range expansion"), N_("Dynamic range expansion"), pentaxId, makerTags, undefined, -1, EXV_PRINT_COMBITAG(pentaxDynamicRangeExpansion, 4, 0)), TagInfo(0x0071, "HighISONoiseReduction", N_("High ISO noise reduction"), N_("High ISO noise reduction"), pentaxId, makerTags, unsignedByte, -1, EXV_PRINT_TAG(pentaxHighISONoiseReduction)), TagInfo(0x0072, "AFAdjustment", N_("AF Adjustment"), N_("AF Adjustment"), pentaxId, makerTags, undefined, -1, printValue), /* Many missing ! */ TagInfo(0x0200, "BlackPoint", N_("Black point"), N_("Black point"), pentaxId, makerTags, undefined, -1, printValue), TagInfo(0x0201, "WhitePoint", N_("White point"), N_("White point"), pentaxId, makerTags, undefined, -1, printValue), /* Some missing ! */ TagInfo(0x0205, "ShotInfo", N_("ShotInfo"), N_("ShotInfo"), pentaxId, makerTags, undefined, -1, printValue), /* TODO: Decoding missing */ TagInfo(0x0206, "AEInfo", N_("AEInfo"), N_("AEInfo"), pentaxId, makerTags, undefined, -1, printValue), /* TODO: Decoding missing */ TagInfo(0x0207, "LensInfo", N_("LensInfo"), N_("LensInfo"), pentaxId, makerTags, undefined, -1, printValue), /* TODO: Decoding missing */ TagInfo(0x0208, "FlashInfo", N_("FlashInfo"), N_("FlashInfo"), pentaxId, makerTags, undefined, -1, printValue), /* TODO: Decoding missing */ TagInfo(0x0209, "AEMeteringSegments", N_("AEMeteringSegments"), N_("AEMeteringSegments"), pentaxId, makerTags, undefined, -1, printValue), /* TODO: Decoding missing */ TagInfo(0x020a, "FlashADump", N_("FlashADump"), N_("FlashADump"), pentaxId, makerTags, undefined, -1, printValue), /* TODO: Decoding missing */ TagInfo(0x020b, "FlashBDump", N_("FlashBDump"), N_("FlashBDump"), pentaxId, makerTags, undefined, -1, printValue), /* TODO: Decoding missing */ /* Some missing ! */ TagInfo(0x020d, "WB_RGGBLevelsDaylight", N_("WB_RGGBLevelsDaylight"), N_("WB_RGGBLevelsDaylight"), pentaxId, makerTags, undefined, -1, printValue), /* TODO: Decoding missing */ TagInfo(0x020e, "WB_RGGBLevelsShade", N_("WB_RGGBLevelsShade"), N_("WB_RGGBLevelsShade"), pentaxId, makerTags, undefined, -1, printValue), /* TODO: Decoding missing */ TagInfo(0x020f, "WB_RGGBLevelsCloudy", N_("WB_RGGBLevelsCloudy"), N_("WB_RGGBLevelsCloudy"), pentaxId, makerTags, undefined, -1, printValue), /* TODO: Decoding missing */ TagInfo(0x0210, "WB_RGGBLevelsTungsten", N_("WB_RGGBLevelsTungsten"), N_("WB_RGGBLevelsTungsten"), pentaxId, makerTags, undefined, -1, printValue), /* TODO: Decoding missing */ TagInfo(0x0211, "WB_RGGBLevelsFluorescentD", N_("WB_RGGBLevelsFluorescentD"), N_("WB_RGGBLevelsFluorescentD"), pentaxId, makerTags, undefined, -1, printValue), /* TODO: Decoding missing */ TagInfo(0x0212, "WB_RGGBLevelsFluorescentN", N_("WB_RGGBLevelsFluorescentN"), N_("WB_RGGBLevelsFluorescentN"), pentaxId, makerTags, undefined, -1, printValue), /* TODO: Decoding missing */ TagInfo(0x0213, "WB_RGGBLevelsFluorescentW", N_("WB_RGGBLevelsFluorescentW"), N_("WB_RGGBLevelsFluorescentW"), pentaxId, makerTags, undefined, -1, printValue), /* TODO: Decoding missing */ TagInfo(0x0214, "WB_RGGBLevelsFlash", N_("WB_RGGBLevelsFlash"), N_("WB_RGGBLevelsFlash"), pentaxId, makerTags, undefined, -1, printValue), /* TODO: Decoding missing */ TagInfo(0x0215, "CameraInfo", N_("CameraInfo"), N_("CameraInfo"), pentaxId, makerTags, undefined, -1, printValue), /* TODO: Decoding missing */ TagInfo(0x0216, "BatteryInfo", N_("BatteryInfo"), N_("BatteryInfo"), pentaxId, makerTags, undefined, -1, printValue), /* TODO: Decoding missing */ TagInfo(0x021f, "AFInfo", N_("AFInfo"), N_("AFInfo"), pentaxId, makerTags, undefined, -1, printValue), /* TODO: Decoding missing */ TagInfo(0x0222, "ColorInfo", N_("ColorInfo"), N_("ColorInfo"), pentaxId, makerTags, undefined, -1, printValue), /* TODO: Decoding missing */ TagInfo(0x0229, "SerialNumber", N_("Serial Number"), N_("Serial Number"), pentaxId, makerTags, asciiString, -1, printValue), // End of list marker TagInfo(0xffff, "(UnknownPentaxMakerNoteTag)", "(UnknownPentaxMakerNoteTag)", N_("Unknown PentaxMakerNote tag"), pentaxId, makerTags, asciiString, -1, printValue) }; const TagInfo* PentaxMakerNote::tagList() { return tagInfo_; } }} // namespace Internal, Exiv2 exiv2-0.23/src/properties.cpp0000644000175000017500000042437011732641407016015 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /* File: properties.cpp Version: $Rev: 2681 $ Author(s): Andreas Huggel (ahu) Gilles Caulier (cgilles) History: 13-July-07, ahu: created */ // ***************************************************************************** #include "rcsid_int.hpp" EXIV2_RCSID("@(#) $Id: properties.cpp 2681 2012-03-22 15:19:35Z ahuggel $") // ***************************************************************************** // included header files #include "properties.hpp" #include "tags_int.hpp" #include "error.hpp" #include "types.hpp" #include "value.hpp" #include "metadatum.hpp" #include "i18n.h" // NLS support. #include "xmp.hpp" #include #include #include #include #include #include // ***************************************************************************** namespace { //! Struct used in the lookup table for pretty print functions struct XmpPrintInfo { //! Comparison operator for key bool operator==(const std::string& key) const { return 0 == strcmp(key_, key.c_str()); } const char* key_; //!< XMP key Exiv2::PrintFct printFct_; //!< Print function }; } // ***************************************************************************** // class member definitions namespace Exiv2 { using namespace Internal; //! @cond IGNORE extern const XmpPropertyInfo xmpDcInfo[]; extern const XmpPropertyInfo xmpDigikamInfo[]; extern const XmpPropertyInfo xmpKipiInfo[]; extern const XmpPropertyInfo xmpXmpInfo[]; extern const XmpPropertyInfo xmpXmpRightsInfo[]; extern const XmpPropertyInfo xmpXmpMMInfo[]; extern const XmpPropertyInfo xmpXmpBJInfo[]; extern const XmpPropertyInfo xmpXmpTPgInfo[]; extern const XmpPropertyInfo xmpXmpDMInfo[]; extern const XmpPropertyInfo xmpMicrosoftInfo[]; extern const XmpPropertyInfo xmpPdfInfo[]; extern const XmpPropertyInfo xmpPhotoshopInfo[]; extern const XmpPropertyInfo xmpCrsInfo[]; extern const XmpPropertyInfo xmpTiffInfo[]; extern const XmpPropertyInfo xmpExifInfo[]; extern const XmpPropertyInfo xmpAuxInfo[]; extern const XmpPropertyInfo xmpIptcInfo[]; extern const XmpPropertyInfo xmpIptcExtInfo[]; extern const XmpPropertyInfo xmpPlusInfo[]; extern const XmpPropertyInfo xmpMediaProInfo[]; extern const XmpPropertyInfo xmpExpressionMediaInfo[]; extern const XmpPropertyInfo xmpMicrosoftPhotoInfo[]; extern const XmpPropertyInfo xmpMicrosoftPhotoRegionInfoInfo[]; extern const XmpPropertyInfo xmpMicrosoftPhotoRegionInfo[]; extern const XmpPropertyInfo xmpMWGRegionsInfo[]; extern const XmpNsInfo xmpNsInfo[] = { // Schemas - NOTE: Schemas which the XMP-SDK doesn't know must be registered in XmpParser::initialize - Todo: Automate this { "http://purl.org/dc/elements/1.1/", "dc", xmpDcInfo, N_("Dublin Core schema") }, { "http://www.digikam.org/ns/1.0/", "digiKam", xmpDigikamInfo, N_("digiKam Photo Management schema") }, { "http://www.digikam.org/ns/kipi/1.0/", "kipi", xmpKipiInfo, N_("KDE Image Program Interface schema") }, { "http://ns.adobe.com/xap/1.0/", "xmp", xmpXmpInfo, N_("XMP Basic schema") }, { "http://ns.adobe.com/xap/1.0/rights/", "xmpRights", xmpXmpRightsInfo, N_("XMP Rights Management schema") }, { "http://ns.adobe.com/xap/1.0/mm/", "xmpMM", xmpXmpMMInfo, N_("XMP Media Management schema") }, { "http://ns.adobe.com/xap/1.0/bj/", "xmpBJ", xmpXmpBJInfo, N_("XMP Basic Job Ticket schema") }, { "http://ns.adobe.com/xap/1.0/t/pg/", "xmpTPg", xmpXmpTPgInfo, N_("XMP Paged-Text schema") }, { "http://ns.adobe.com/xmp/1.0/DynamicMedia/", "xmpDM", xmpXmpDMInfo, N_("XMP Dynamic Media schema") }, { "http://ns.microsoft.com/photo/1.0/", "MicrosoftPhoto", xmpMicrosoftInfo, N_("Microsoft Photo schema") }, { "http://ns.adobe.com/pdf/1.3/", "pdf", xmpPdfInfo, N_("Adobe PDF schema") }, { "http://ns.adobe.com/photoshop/1.0/", "photoshop", xmpPhotoshopInfo, N_("Adobe photoshop schema") }, { "http://ns.adobe.com/camera-raw-settings/1.0/", "crs", xmpCrsInfo, N_("Camera Raw schema") }, { "http://ns.adobe.com/tiff/1.0/", "tiff", xmpTiffInfo, N_("Exif Schema for TIFF Properties") }, { "http://ns.adobe.com/exif/1.0/", "exif", xmpExifInfo, N_("Exif schema for Exif-specific Properties") }, { "http://ns.adobe.com/exif/1.0/aux/", "aux", xmpAuxInfo, N_("Exif schema for Additional Exif Properties")}, { "http://iptc.org/std/Iptc4xmpCore/1.0/xmlns/", "iptc", xmpIptcInfo, N_("IPTC Core schema") }, // NOTE: 'Iptc4xmpCore' is just too long, so make 'iptc' { "http://iptc.org/std/Iptc4xmpCore/1.0/xmlns/", "Iptc4xmpCore", xmpIptcInfo, N_("IPTC Core schema") }, // the default prefix. But provide the official one too. { "http://iptc.org/std/Iptc4xmpExt/2008-02-29/", "iptcExt", xmpIptcExtInfo, N_("IPTC Extension schema") }, // NOTE: It really should be 'Iptc4xmpExt' but following { "http://iptc.org/std/Iptc4xmpExt/2008-02-29/", "Iptc4xmpExt", xmpIptcExtInfo, N_("IPTC Extension schema") }, // example above, 'iptcExt' is the default, Iptc4xmpExt works too. { "http://ns.useplus.org/ldf/xmp/1.0/", "plus", xmpPlusInfo, N_("PLUS License Data Format schema") }, { "http://ns.iview-multimedia.com/mediapro/1.0/", "mediapro", xmpMediaProInfo, N_("iView Media Pro schema") }, { "http://ns.microsoft.com/expressionmedia/1.0/", "expressionmedia",xmpExpressionMediaInfo, N_("Expression Media schema") }, { "http://ns.microsoft.com/photo/1.2/", "MP", xmpMicrosoftPhotoInfo, N_("Microsoft Photo 1.2 schema") }, { "http://ns.microsoft.com/photo/1.2/t/RegionInfo#", "MPRI", xmpMicrosoftPhotoRegionInfoInfo, N_("Microsoft Photo RegionInfo schema")}, { "http://ns.microsoft.com/photo/1.2/t/Region#", "MPReg", xmpMicrosoftPhotoRegionInfo, N_("Microsoft Photo Region schema") }, { "http://www.metadataworkinggroup.com/schemas/regions/", "mwg-rs", xmpMWGRegionsInfo,N_("Metadata Working Group Regions schema") }, // Structures { "http://ns.adobe.com/xap/1.0/g/", "xapG", 0, N_("Colorant structure") }, { "http://ns.adobe.com/xap/1.0/sType/Dimensions#", "stDim", 0, N_("Dimensions structure") }, { "http://ns.adobe.com/xap/1.0/sType/Font#", "stFnt", 0, N_("Font structure") }, { "http://ns.adobe.com/xap/1.0/g/img/", "xapGImg", 0, N_("Thumbnail structure") }, { "http://ns.adobe.com/xap/1.0/sType/ResourceEvent#", "stEvt", 0, N_("Resource Event structure") }, { "http://ns.adobe.com/xap/1.0/sType/ResourceRef#", "stRef", 0, N_("ResourceRef structure") }, { "http://ns.adobe.com/xap/1.0/sType/Version#", "stVer", 0, N_("Version structure") }, { "http://ns.adobe.com/xap/1.0/sType/Job#", "stJob", 0, N_("Basic Job/Workflow structure") }, { "http://ns.adobe.com/xmp/sType/Area#", "stArea", 0, N_("Area structure") }, // Qualifiers { "http://ns.adobe.com/xmp/Identifier/qual/1.0/", "xmpidq", 0, N_("Qualifier for xmp:Identifier") } }; extern const XmpPropertyInfo xmpDcInfo[] = { { "contributor", N_("Contributor"), "bag ProperName", xmpBag, xmpExternal, N_("Contributors to the resource (other than the authors).") }, { "coverage", N_("Coverage"), "Text", xmpText, xmpExternal, N_("The spatial or temporal topic of the resource, the spatial applicability of the " "resource, or the jurisdiction under which the resource is relevant.") }, { "creator", N_("Creator"), "seq ProperName", xmpSeq, xmpExternal, N_("The authors of the resource (listed in order of precedence, if significant).") }, { "date", N_("Date"), "seq Date", xmpSeq, xmpExternal, N_("Date(s) that something interesting happened to the resource.") }, { "description", N_("Description"), "Lang Alt", langAlt, xmpExternal, N_("A textual description of the content of the resource. Multiple values may be " "present for different languages.") }, { "format", N_("Format"), "MIMEType", xmpText, xmpInternal, N_("The file format used when saving the resource. Tools and applications should set " "this property to the save format of the data. It may include appropriate qualifiers.") }, { "identifier", N_("Identifier"), "Text", xmpText, xmpExternal, N_("Unique identifier of the resource. Recommended best practice is to identify the " "resource by means of a string conforming to a formal identification system.") }, { "language", N_("Language"), "bag Locale", xmpBag, xmpInternal, N_("An unordered array specifying the languages used in the resource.") }, { "publisher", N_("Publisher"), "bag ProperName", xmpBag, xmpExternal, N_("An entity responsible for making the resource available. Examples of a Publisher " "include a person, an organization, or a service. Typically, the name of a Publisher " "should be used to indicate the entity.") }, { "relation", N_("Relation"), "bag Text", xmpBag, xmpInternal, N_("Relationships to other documents. Recommended best practice is to identify the " "related resource by means of a string conforming to a formal identification system.") }, { "rights", N_("Rights"), "Lang Alt", langAlt, xmpExternal, N_("Informal rights statement, selected by language. Typically, rights information " "includes a statement about various property rights associated with the resource, " "including intellectual property rights.") }, { "source", N_("Source"), "Text", xmpText, xmpExternal, N_("Unique identifier of the work from which this resource was derived.") }, { "subject", N_("Subject"), "bag Text", xmpBag, xmpExternal, N_("An unordered array of descriptive phrases or keywords that specify the topic of the " "content of the resource.") }, { "title", N_("Title"), "Lang Alt", langAlt, xmpExternal, N_("The title of the document, or the name given to the resource. Typically, it will be " "a name by which the resource is formally known.") }, { "type", N_("Type"), "bag open Choice", xmpBag, xmpExternal, N_("A document type; for example, novel, poem, or working paper.") }, // End of list marker { 0, 0, 0, invalidTypeId, xmpInternal, 0 } }; extern const XmpPropertyInfo xmpDigikamInfo[] = { { "TagsList", N_("Tags List"), "seq Text", xmpSeq, xmpExternal, N_("The list of complete tags path as string. The path hierarchy is separated by '/' character (ex.: \"City/Paris/Monument/Eiffel Tower\".") }, { "CaptionsAuthorNames", N_("Captions Author Names"), "Lang Alt", langAlt, xmpExternal, N_("The list of all captions author names for each language alternative captions set in standard XMP tags.") }, { "CaptionsDateTimeStamps", N_("Captions Date Time Stamps"), "Lang Alt", langAlt, xmpExternal, N_("The list of all captions date time stamps for each language alternative captions set in standard XMP tags.") }, { "ImageHistory", N_("Image History"), "Text", xmpText, xmpExternal, N_("An XML based content to list all action processed on this image with image editor (as crop, rotate, color corrections, adjustements, etc.).") }, { "LensCorrectionSettings", N_("Lens Correction Settings"), "Text", xmpText, xmpExternal, N_("The list of Lens Correction tools settings used to fix lens distorsion. This include Batch Queue Manager and Image editor tools based on LensFun library.") }, { "ColorLabel", N_("Color Label"), "Text", xmpText, xmpExternal, N_("The color label assigned to this item. Possible values are \"0\": no label; \"1\": Red; \"2\": Orange; \"3\": Yellow; \"4\": Green; \"5\": Blue; \"6\": Magenta; \"7\": Gray; \"8\": Black; \"9\": White.") }, { "PickLabel", N_("Pick Label"), "Text", xmpText, xmpExternal, N_("The pick label assigned to this item. Possible values are \"0\": no label; \"1\": item rejected; \"2\": item in pending validation; \"3\": item accepted.") }, // End of list marker { 0, 0, 0, invalidTypeId, xmpInternal, 0 } }; extern const XmpPropertyInfo xmpKipiInfo[] = { { "EnfuseInputFiles", N_("Enfuse Input Files"), "Text", xmpText, xmpExternal, N_("The list of files processed with Enfuse program through ExpoBlending tool.") }, { "EnfuseSettings", N_("Enfuse Settings"), "Text", xmpText, xmpExternal, N_("The list of Enfuse settings used to blend image stack with ExpoBlending tool.") }, { "picasawebGPhotoId", N_("PicasaWeb Item ID"), "Text", xmpText, xmpExternal, N_("Item ID from PicasaWeb web service.") }, { "yandexGPhotoId", N_("Yandex Fotki Item ID"), "Text", xmpText, xmpExternal, N_("Item ID from Yandex Fotki web service.") }, // End of list marker { 0, 0, 0, invalidTypeId, xmpInternal, 0 } }; extern const XmpPropertyInfo xmpXmpInfo[] = { { "Advisory", N_("Advisory"), "bag XPath", xmpBag, xmpExternal, N_("An unordered array specifying properties that were edited outside the authoring " "application. Each item should contain a single namespace and XPath separated by " "one ASCII space (U+0020).") }, { "BaseURL", N_("Base URL"), "URL", xmpText, xmpInternal, N_("The base URL for relative URLs in the document content. If this document contains " "Internet links, and those links are relative, they are relative to this base URL. " "This property provides a standard way for embedded relative URLs to be interpreted " "by tools. Web authoring tools should set the value based on their notion of where " "URLs will be interpreted.") }, { "CreateDate", N_("Create Date"), "Date", xmpText, xmpInternal, N_("The date and time the resource was originally created.") }, { "CreatorTool", N_("Creator Tool"), "AgentName", xmpText, xmpInternal, N_("The name of the first known tool used to create the resource. If history is " "present in the metadata, this value should be equivalent to that of " "xmpMM:History's softwareAgent property.") }, { "Identifier", N_("Identifier"), "bag Text", xmpBag, xmpExternal, N_("An unordered array of text strings that unambiguously identify the resource within " "a given context. An array item may be qualified with xmpidq:Scheme to denote the " "formal identification system to which that identifier conforms. Note: The " "dc:identifier property is not used because it lacks a defined scheme qualifier and " "has been defined in the XMP Specification as a simple (single-valued) property.") }, { "Label", N_("Label"), "Text", xmpText, xmpExternal, N_("A word or short phrase that identifies a document as a member of a user-defined " "collection. Used to organize documents in a file browser.") }, { "MetadataDate", N_("Metadata Date"), "Date", xmpText, xmpInternal, N_("The date and time that any metadata for this resource was last changed. It should " "be the same as or more recent than xmp:ModifyDate.") }, { "ModifyDate", N_("Modify Date"), "Date", xmpText, xmpInternal, N_("The date and time the resource was last modified. Note: The value of this property " "is not necessarily the same as the file's system modification date because it is " "set before the file is saved.") }, { "Nickname", N_("Nickname"), "Text", xmpText, xmpExternal, N_("A short informal name for the resource.") }, { "Rating", N_("Rating"), "Closed Choice of Integer", xmpText, xmpExternal, N_("A number that indicates a document's status relative to other documents, " "used to organize documents in a file browser. Values are user-defined within an " "application-defined range.") }, { "Thumbnails", N_("Thumbnails"), "alt Thumbnail", xmpText, xmpInternal, N_("An alternative array of thumbnail images for a file, which can differ in " "characteristics such as size or image encoding.") }, // End of list marker { 0, 0, 0, invalidTypeId, xmpInternal, 0 } }; extern const XmpPropertyInfo xmpXmpRightsInfo[] = { { "Certificate", N_("Certificate"), "URL", xmpText, xmpExternal, N_("Online rights management certificate.") }, { "Marked", N_("Marked"), "Boolean", xmpText, xmpExternal, N_("Indicates that this is a rights-managed resource.") }, { "Owner", N_("Owner"), "bag ProperName", xmpBag, xmpExternal, N_("An unordered array specifying the legal owner(s) of a resource.") }, { "UsageTerms", N_("Usage Terms"), "Lang Alt", langAlt, xmpExternal, N_("Text instructions on how a resource can be legally used.") }, { "WebStatement", N_("Web Statement"), "URL", xmpText, xmpExternal, N_("The location of a web page describing the owner and/or rights statement for this resource.") }, // End of list marker { 0, 0, 0, invalidTypeId, xmpInternal, 0 } }; extern const XmpPropertyInfo xmpXmpMMInfo[] = { { "DerivedFrom", N_("Derived From"), "ResourceRef", xmpText, xmpInternal, N_("A reference to the original document from which this one is derived. It is a " "minimal reference; missing components can be assumed to be unchanged. For example, " "a new version might only need to specify the instance ID and version number of the " "previous version, or a rendition might only need to specify the instance ID and " "rendition class of the original.") }, { "DocumentID", N_("Document ID"), "URI", xmpText, xmpInternal, N_("The common identifier for all versions and renditions of a document. It should be " "based on a UUID; see Document and Instance IDs below.") }, { "History", N_("History"), "seq ResourceEvent", xmpText, xmpInternal, N_("An ordered array of high-level user actions that resulted in this resource. It is " "intended to give human readers a general indication of the steps taken to make the " "changes from the previous version to this one. The list should be at an abstract " "level; it is not intended to be an exhaustive keystroke or other detailed history.") }, { "InstanceID", N_("Instance ID"), "URI", xmpText, xmpInternal, N_("An identifier for a specific incarnation of a document, updated each time a file " "is saved. It should be based on a UUID; see Document and Instance IDs below.") }, { "ManagedFrom", N_("Managed From"), "ResourceRef", xmpText, xmpInternal, N_("A reference to the document as it was prior to becoming managed. It is set when a " "managed document is introduced to an asset management system that does not " "currently own it. It may or may not include references to different management systems.") }, { "Manager", N_("Manager"), "AgentName", xmpText, xmpInternal, N_("The name of the asset management system that manages this resource. Along with " "xmpMM: ManagerVariant, it tells applications which asset management system to " "contact concerning this document.") }, { "ManageTo", N_("Manage To"), "URI", xmpText, xmpInternal, N_("A URI identifying the managed resource to the asset management system; the presence " "of this property is the formal indication that this resource is managed. The form " "and content of this URI is private to the asset management system.") }, { "ManageUI", N_("Manage UI"), "URI", xmpText, xmpInternal, N_("A URI that can be used to access information about the managed resource through a " "web browser. It might require a custom browser plug-in.") }, { "ManagerVariant", N_("Manager Variant"), "Text", xmpText, xmpInternal, N_("Specifies a particular variant of the asset management system. The format of this " "property is private to the specific asset management system.") }, { "RenditionClass", N_("Rendition Class"), "RenditionClass", xmpText, xmpInternal, N_("The rendition class name for this resource. This property should be absent or set " "to default for a document version that is not a derived rendition.") }, { "RenditionParams", N_("Rendition Params"), "Text", xmpText, xmpInternal, N_("Can be used to provide additional rendition parameters that are too complex or " "verbose to encode in xmpMM: RenditionClass.") }, { "VersionID", N_("Version ID"), "Text", xmpText, xmpInternal, N_("The document version identifier for this resource. Each version of a document gets " "a new identifier, usually simply by incrementing integers 1, 2, 3 . . . and so on. " "Media management systems can have other conventions or support branching which " "requires a more complex scheme.") }, { "Versions", N_("Versions"), "seq Version", xmpText, xmpInternal, N_("The version history associated with this resource. Entry [1] is the oldest known " "version for this document, entry [last()] is the most recent version. Typically, a " "media management system would fill in the version information in the metadata on " "check-in. It is not guaranteed that a complete history versions from the first to " "this one will be present in the xmpMM:Versions property. Interior version information " "can be compressed or eliminated and the version history can be truncated at some point.") }, { "LastURL", N_("Last URL"), "URL", xmpText, xmpInternal, N_("Deprecated for privacy protection.") }, { "RenditionOf", N_("Rendition Of"), "ResourceRef", xmpText, xmpInternal, N_("Deprecated in favor of xmpMM:DerivedFrom. A reference to the document of which this is " "a rendition.") }, { "SaveID", N_("Save ID"), "Integer", xmpText, xmpInternal, N_("Deprecated. Previously used only to support the xmpMM:LastURL property.") }, // End of list marker { 0, 0, 0, invalidTypeId, xmpInternal, 0 } }; extern const XmpPropertyInfo xmpXmpBJInfo[] = { { "JobRef", N_("Job Reference"), "bag Job", xmpText, xmpExternal, N_("References an external job management file for a job process in which the document is being used. Use of job " "names is under user control. Typical use would be to identify all documents that are part of a particular job or contract. " "There are multiple values because there can be more than one job using a particular document at any time, and it can " "also be useful to keep historical information about what jobs a document was part of previously.") }, // End of list marker { 0, 0, 0, invalidTypeId, xmpInternal, 0 } }; extern const XmpPropertyInfo xmpXmpTPgInfo[] = { { "MaxPageSize", N_("Maximum Page Size"), "Dimensions", xmpText, xmpInternal, N_("The size of the largest page in the document (including any in contained documents).") }, { "NPages", N_("Number of Pages"), "Integer", xmpText, xmpInternal, N_("The number of pages in the document (including any in contained documents).") }, { "Fonts", N_("Fonts"), "bag Font", xmpText, xmpInternal, N_("An unordered array of fonts that are used in the document (including any in contained documents).") }, { "Colorants", N_("Colorants"), "seq Colorant", xmpText, xmpInternal, N_("An ordered array of colorants (swatches) that are used in the document (including any in contained documents).") }, { "PlateNames", N_("Plate Names"), "seq Text", xmpSeq, xmpInternal, N_("An ordered array of plate names that are needed to print the document (including any in contained documents).") }, // End of list marker { 0, 0, 0, invalidTypeId, xmpInternal, 0 } }; extern const XmpPropertyInfo xmpXmpDMInfo[] = { { "projectRef", N_("Project Reference"), "ProjectLink", xmpText, xmpInternal, N_("A reference to the project that created this file.") }, { "videoFrameRate", N_("Video Frame Rate"), "open Choice of Text", xmpText, xmpInternal, N_("The video frame rate. One of: 24, NTSC, PAL.") }, { "videoFrameSize", N_("Video Frame Size"), "Dimensions", xmpText, xmpInternal, N_("The frame size. For example: w:720, h: 480, unit:pixels") }, { "videoPixelAspectRatio", N_("Video Pixel Aspect Ratio"), "Rational", xmpText, xmpInternal, N_("The aspect ratio, expressed as ht/wd. For example: \"648/720\" = 0.9") }, { "videoPixelDepth", N_("Video Pixel Depth"), "closed Choice of Text", xmpText, xmpInternal, N_("The size in bits of each color component of a pixel. Standard Windows 32-bit " "pixels have 8 bits per component. One of: 8Int, 16Int, 32Int, 32Float.") }, { "videoColorSpace", N_("Video Color Space"), "closed Choice of Text", xmpText, xmpInternal, N_("The color space. One of: sRGB (used by Photoshop), CCIR-601 (used for NTSC), " "CCIR-709 (used for HD).") }, { "videoAlphaMode", N_("Video Alpha Mode"), "closed Choice of Text", xmpText, xmpExternal, N_("The alpha mode. One of: straight, pre-multiplied.") }, { "videoAlphaPremultipleColor", N_("Video Alpha Premultiple Color"), "Colorant", xmpText, xmpExternal, N_("A color in CMYK or RGB to be used as the pre-multiple color when " "alpha mode is pre-multiplied.") }, { "videoAlphaUnityIsTransparent", N_("Video Alpha Unity Is Transparent"), "Boolean", xmpText, xmpInternal, N_("When true, unity is clear, when false, it is opaque.") }, { "videoCompressor", N_("Video Compressor"), "Text", xmpText, xmpInternal, N_("Video compression used. For example, jpeg.") }, { "videoFieldOrder", N_("Video Field Order"), "closed Choice of Text", xmpText, xmpInternal, N_("The field order for video. One of: Upper, Lower, Progressive.") }, { "pullDown", N_("Pull Down"), "closed Choice of Text", xmpText, xmpInternal, N_("The sampling phase of film to be converted to video (pull-down). One of: " "WSSWW, SSWWW, SWWWS, WWWSS, WWSSW, WSSWW_24p, SSWWW_24p, SWWWS_24p, WWWSS_24p, WWSSW_24p.") }, { "audioSampleRate", N_("Audio Sample Rate"), "Integer", xmpText, xmpInternal, N_("The audio sample rate. Can be any value, but commonly 32000, 41100, or 48000.") }, { "audioSampleType", N_("Audio Sample Type"), "closed Choice of Text", xmpText, xmpInternal, N_("The audio sample type. One of: 8Int, 16Int, 32Int, 32Float.") }, { "audioChannelType", N_("Audio Channel Type"), "closed Choice of Text", xmpText, xmpInternal, N_("The audio channel type. One of: Mono, Stereo, 5.1, 7.1.") }, { "audioCompressor", N_("Audio Compressor"), "Text", xmpText, xmpInternal, N_("The audio compression used. For example, MP3.") }, { "speakerPlacement", N_("Speaker Placement"), "Text", xmpText, xmpExternal, N_("A description of the speaker angles from center front in degrees. For example: " "\"Left = -30, Right = 30, Center = 0, LFE = 45, Left Surround = -110, Right Surround = 110\"") }, { "fileDataRate", N_("File Data Rate"), "Rational", xmpText, xmpInternal, N_("The file data rate in megabytes per second. For example: \"36/10\" = 3.6 MB/sec") }, { "tapeName", N_("Tape Name"), "Text", xmpText, xmpExternal, N_("The name of the tape from which the clip was captured, as set during the capture process.") }, { "altTapeName", N_("Alternative Tape Name"), "Text", xmpText, xmpExternal, N_("An alternative tape name, set via the project window or timecode dialog in Premiere. " "If an alternative name has been set and has not been reverted, that name is displayed.") }, { "startTimecode", N_("Start Time Code"), "Timecode", xmpText, xmpInternal, N_("The timecode of the first frame of video in the file, as obtained from the device control.") }, { "altTimecode", N_("Alternative Time code"), "Timecode", xmpText, xmpExternal, N_("A timecode set by the user. When specified, it is used instead of the startTimecode.") }, { "duration", N_("Duration"), "Time", xmpText, xmpInternal, N_("The duration of the media file.") }, { "scene", N_("Scene"), "Text", xmpText, xmpExternal, N_("The name of the scene.") }, { "shotName", N_("Shot Name"), "Text", xmpText, xmpExternal, N_("The name of the shot or take.") }, { "shotDate", N_("Shot Date"), "Date", xmpText, xmpExternal, N_("The date and time when the video was shot.") }, { "shotLocation", N_("Shot Location"), "Text", xmpText, xmpExternal, N_("The name of the location where the video was shot. For example: \"Oktoberfest, Munich Germany\" " "For more accurate positioning, use the EXIF GPS values.") }, { "logComment", N_("Log Comment"), "Text", xmpText, xmpExternal, N_("User's log comments.") }, { "markers", N_("Markers"), "seq Marker", xmpText, xmpInternal, N_("An ordered list of markers") }, { "contributedMedia", N_("Contributed Media"), "bag Media", xmpText, xmpInternal, N_("An unordered list of all media used to create this media.") }, { "absPeakAudioFilePath", N_("Absolute Peak Audio File Path"), "URI", xmpText, xmpInternal, N_("The absolute path to the file's peak audio file. If empty, no peak file exists.") }, { "relativePeakAudioFilePath", N_("Relative Peak Audio File Path"), "URI", xmpText, xmpInternal, N_("The relative path to the file's peak audio file. If empty, no peak file exists.") }, { "videoModDate", N_("Video Modified Date"), "Date", xmpText, xmpInternal, N_("The date and time when the video was last modified.") }, { "audioModDate", N_("Audio Modified Date"), "Date", xmpText, xmpInternal, N_("The date and time when the audio was last modified.") }, { "metadataModDate", N_("Metadata Modified Date"), "Date", xmpText, xmpInternal, N_("The date and time when the metadata was last modified.") }, { "artist", N_("Artist"), "Text", xmpText, xmpExternal, N_("The name of the artist or artists.") }, { "album", N_("Album"), "Text", xmpText, xmpExternal, N_("The name of the album.") }, { "trackNumber", N_("Track Number"), "Integer", xmpText, xmpExternal, N_("A numeric value indicating the order of the audio file within its original recording.") }, { "genre", N_("Genre"), "Text", xmpText, xmpExternal, N_("The name of the genre.") }, { "copyright", N_("Copyright"), "Text", xmpText, xmpExternal, N_("The copyright information.") }, { "releaseDate", N_("Release Date"), "Date", xmpText, xmpExternal, N_("The date the title was released.") }, { "composer", N_("Composer"), "Text", xmpText, xmpExternal, N_("The composer's name.") }, { "engineer", N_("Engineer"), "Text", xmpText, xmpExternal, N_("The engineer's name.") }, { "tempo", N_("Tempo"), "Real", xmpText, xmpInternal, N_("The audio's tempo.") }, { "instrument", N_("Instrument"), "Text", xmpText, xmpExternal, N_("The musical instrument.") }, { "introTime", N_("Intro Time"), "Time", xmpText, xmpInternal, N_("The duration of lead time for queuing music.") }, { "outCue", N_("Out Cue"), "Time", xmpText, xmpInternal, N_("The time at which to fade out.") }, { "relativeTimestamp", N_("Relative Timestamp"), "Time", xmpText, xmpInternal, N_("The start time of the media inside the audio project.") }, { "loop", N_("Loop"), "Boolean", xmpText, xmpInternal, N_("When true, the clip can be looped seemlessly.") }, { "numberOfBeats", N_("Number Of Beats"), "Real", xmpText, xmpInternal, N_("The number of beats.") }, { "key", N_("Key"), "closed Choice of Text", xmpText, xmpInternal, N_("The audio's musical key. One of: C, C#, D, D#, E, F, F#, G, G#, A, A#, B.") }, { "stretchMode", N_("Stretch Mode"), "closed Choice of Text", xmpText, xmpInternal, N_("The audio stretch mode. One of: Fixed length, Time-Scale, Resample, Beat Splice, Hybrid.") }, { "timeScaleParams", N_("Time Scale Parameters"), "timeScaleStretch", xmpText, xmpInternal, N_("Additional parameters for Time-Scale stretch mode.") }, { "resampleParams", N_("Resample Parameters"), "resampleStretch", xmpText, xmpInternal, N_("Additional parameters for Resample stretch mode.") }, { "beatSpliceParams", N_("Beat Splice Parameters"), "beatSpliceStretch", xmpText, xmpInternal, N_("Additional parameters for Beat Splice stretch mode.") }, { "timeSignature", N_("Time Signature"), "closed Choice of Text", xmpText, xmpInternal, N_("The time signature of the music. One of: 2/4, 3/4, 4/4, 5/4, 7/4, 6/8, 9/8, 12/8, other.") }, { "scaleType", N_("Scale Type"), "closed Choice of Text", xmpText, xmpInternal, N_("The musical scale used in the music. One of: Major, Minor, Both, Neither. " "Neither is most often used for instruments with no associated scale, such as drums.") }, // End of list marker { 0, 0, 0, invalidTypeId, xmpInternal, 0 } }; extern const XmpPropertyInfo xmpMicrosoftInfo[] = { { "CameraSerialNumber", N_("Camera Serial Number"), "Text", xmpText, xmpExternal, N_("Camera Serial Number.") }, { "DateAcquired", N_("Date Acquired"), "Date", xmpText, xmpExternal, N_("Date Acquired.") }, { "FlashManufacturer", N_("Flash Manufacturer"), "Text", xmpText, xmpExternal, N_("Flash Manufacturer.") }, { "FlashModel", N_("Flash Model"), "Text", xmpText, xmpExternal, N_("Flash Model.") }, { "LastKeywordIPTC", N_("Last Keyword IPTC"), "bag Text", xmpBag, xmpExternal, N_("Last Keyword IPTC.") }, { "LastKeywordXMP", N_("Last Keyword XMP"), "bag Text", xmpBag, xmpExternal, N_("Last Keyword XMP.") }, { "LensManufacturer", N_("Lens Manufacturer"), "Text", xmpText, xmpExternal, N_("Lens Manufacturer.") }, { "LensModel", N_("Lens Model"), "Text", xmpText, xmpExternal, N_("Lens Model.") }, { "Rating", N_("Rating Percent"), "Text", xmpText, xmpExternal, N_("Rating Percent.") }, // End of list marker { 0, 0, 0, invalidTypeId, xmpInternal, 0 } }; extern const XmpPropertyInfo xmpPdfInfo[] = { { "Keywords", N_("Keywords"), "Text", xmpText, xmpExternal, N_("Keywords.") }, { "PDFVersion", N_("PDF Version"), "Text", xmpText, xmpInternal, N_("The PDF file version (for example: 1.0, 1.3, and so on).") }, { "Producer", N_("Producer"), "AgentName", xmpText, xmpInternal, N_("The name of the tool that created the PDF document.") }, // End of list marker { 0, 0, 0, invalidTypeId, xmpInternal, 0 } }; extern const XmpPropertyInfo xmpPhotoshopInfo[] = { { "AuthorsPosition", N_("Authors Position"), "Text", xmpText, xmpExternal, N_("By-line title.") }, { "CaptionWriter", N_("Caption Writer"), "ProperName", xmpText, xmpExternal, N_("Writer/editor.") }, { "Category", N_("Category"), "Text", xmpText, xmpExternal, N_("Category. Limited to 3 7-bit ASCII characters.") }, { "City", N_("City"), "Text", xmpText, xmpExternal, N_("City.") }, { "Country", N_("Country"), "Text", xmpText, xmpExternal, N_("Country/primary location.") }, { "Credit", N_("Credit"), "Text", xmpText, xmpExternal, N_("Credit.") }, { "DateCreated", N_("Date Created"), "Date", xmpText, xmpExternal, N_("The date the intellectual content of the document was created (rather than the creation " "date of the physical representation), following IIM conventions. For example, a photo " "taken during the American Civil War would have a creation date during that epoch " "(1861-1865) rather than the date the photo was digitized for archiving.") }, { "Headline", N_("Headline"), "Text", xmpText, xmpExternal, N_("Headline.") }, { "Instructions", N_("Instructions"), "Text", xmpText, xmpExternal, N_("Special instructions.") }, { "Source", N_("Source"), "Text", xmpText, xmpExternal, N_("Source.") }, { "State", N_("State"), "Text", xmpText, xmpExternal, N_("Province/state.") }, { "SupplementalCategories", N_("Supplemental Categories"), "bag Text", xmpBag, xmpExternal, N_("Supplemental category.") }, { "TransmissionReference", N_("Transmission Reference"), "Text", xmpText, xmpExternal, N_("Original transmission reference.") }, { "Urgency", N_("Urgency"), "Integer", xmpText, xmpExternal, N_("Urgency. Valid range is 1-8.") }, // End of list marker { 0, 0, 0, invalidTypeId, xmpInternal, 0 } }; //! XMP crs:CropUnits extern const TagDetails crsCropUnits[] = { { 0, N_("pixels") }, { 1, N_("inches") }, { 2, N_("cm") } }; extern const XmpPropertyInfo xmpCrsInfo[] = { { "AutoBrightness", N_("Auto Brightness"), "Boolean", xmpText, xmpExternal, N_("When true, \"Brightness\" is automatically adjusted.") }, { "AutoContrast", N_("Auto Contrast"), "Boolean", xmpText, xmpExternal, N_("When true, \"Contrast\" is automatically adjusted.") }, { "AutoExposure", N_("Auto Exposure"), "Boolean", xmpText, xmpExternal, N_("When true, \"Exposure\" is automatically adjusted.") }, { "AutoShadows", N_("Auto Shadows"), "Boolean", xmpText, xmpExternal, N_("When true,\"Shadows\" is automatically adjusted.") }, { "BlueHue", N_("Blue Hue"), "Integer", xmpText, xmpExternal, N_("\"Blue Hue\" setting. Range -100 to 100.") }, { "BlueSaturation", N_("Blue Saturation"), "Integer", xmpText, xmpExternal, N_("\"Blue Saturation\" setting. Range -100 to +100.") }, { "Brightness", N_("Brightness"), "Integer", xmpText, xmpExternal, N_("\"Brightness\" setting. Range 0 to +150.") }, { "CameraProfile", N_("Camera Profile"), "Text", xmpText, xmpExternal, N_("\"Camera Profile\" setting.") }, { "ChromaticAberrationB", N_("Chromatic Aberration Blue"), "Integer", xmpText, xmpExternal, N_("\"Chromatic Aberration, Fix Blue/Yellow Fringe\" setting. Range -100 to +100.") }, { "ChromaticAberrationR", N_("Chromatic Aberration Red"), "Integer", xmpText, xmpExternal, N_("\"Chromatic Aberration, Fix Red/Cyan Fringe\" setting. Range -100 to +100.") }, { "ColorNoiseReduction", N_("Color Noise Reduction"), "Integer", xmpText, xmpExternal, N_("\"Color Noise Reducton\" setting. Range 0 to +100.") }, { "Contrast", N_("Contrast"), "Integer", xmpText, xmpExternal, N_("\"Contrast\" setting. Range -50 to +100.") }, { "CropTop", N_("Crop Top"), "Real", xmpText, xmpExternal, N_("When \"Has Crop\" is true, top of crop rectangle") }, { "CropLeft", N_("Crop Left"), "Real", xmpText, xmpExternal, N_("When \"Has Crop\" is true, left of crop rectangle.") }, { "CropBottom", N_("Crop Bottom"), "Real", xmpText, xmpExternal, N_("When \"Has Crop\" is true, bottom of crop rectangle.") }, { "CropRight", N_("Crop Right"), "Real", xmpText, xmpExternal, N_("When \"Has Crop\" is true, right of crop rectangle.") }, { "CropAngle", N_("Crop Angle"), "Real", xmpText, xmpExternal, N_("When \"Has Crop\" is true, angle of crop rectangle.") }, { "CropWidth", N_("Crop Width"), "Real", xmpText, xmpExternal, N_("Width of resulting cropped image in CropUnits units.") }, { "CropHeight", N_("Crop Height"), "Real", xmpText, xmpExternal, N_("Height of resulting cropped image in CropUnits units.") }, { "CropUnits", N_("Crop Units"), "Integer", xmpText, xmpExternal, N_("Units for CropWidth and CropHeight. 0=pixels, 1=inches, 2=cm") }, { "Exposure", N_("Exposure"), "Real", xmpText, xmpExternal, N_("\"Exposure\" setting. Range -4.0 to +4.0.") }, { "GreenHue", N_("GreenHue"), "Integer", xmpText, xmpExternal, N_("\"Green Hue\" setting. Range -100 to +100.") }, { "GreenSaturation", N_("Green Saturation"), "Integer", xmpText, xmpExternal, N_("\"Green Saturation\" setting. Range -100 to +100.") }, { "HasCrop", N_("Has Crop"), "Boolean", xmpText, xmpExternal, N_("When true, image has a cropping rectangle.") }, { "HasSettings", N_("Has Settings"), "Boolean", xmpText, xmpExternal, N_("When true, non-default camera raw settings.") }, { "LuminanceSmoothing", N_("Luminance Smoothing"), "Integer", xmpText, xmpExternal, N_("\"Luminance Smoothing\" setting. Range 0 to +100.") }, { "RawFileName", N_("Raw File Name"), "Text", xmpText, xmpInternal, N_("File name of raw file (not a complete path).") }, { "RedHue", N_("Red Hue"), "Integer", xmpText, xmpExternal, N_("\"Red Hue\" setting. Range -100 to +100.") }, { "RedSaturation", N_("Red Saturation"), "Integer", xmpText, xmpExternal, N_("\"Red Saturation\" setting. Range -100 to +100.") }, { "Saturation", N_("Saturation"), "Integer", xmpText, xmpExternal, N_("\"Saturation\" setting. Range -100 to +100.") }, { "Shadows", N_("Shadows"), "Integer", xmpText, xmpExternal, N_("\"Shadows\" setting. Range 0 to +100.") }, { "ShadowTint", N_("Shadow Tint"), "Integer", xmpText, xmpExternal, N_("\"Shadow Tint\" setting. Range -100 to +100.") }, { "Sharpness", N_("Sharpness"), "Integer", xmpText, xmpExternal, N_("\"Sharpness\" setting. Range 0 to +100.") }, { "Temperature", N_("Temperature"), "Integer", xmpText, xmpExternal, N_("\"Temperature\" setting. Range 2000 to 50000.") }, { "Tint", N_("Tint"), "Integer", xmpText, xmpExternal, N_("\"Tint\" setting. Range -150 to +150.") }, { "ToneCurve", N_("Tone Curve"), "Seq of points (Integer, Integer)", xmpText, xmpExternal, N_("Array of points (Integer, Integer) defining a \"Tone Curve\".") }, { "ToneCurveName", N_("Tone Curve Name"), "Choice Text", xmpText, xmpInternal, N_("The name of the Tone Curve described by ToneCurve. One of: Linear, Medium Contrast, " "Strong Contrast, Custom or a user-defined preset name.") }, { "Version", N_("Version"), "Text", xmpText, xmpInternal, N_("Version of Camera Raw plugin.") }, { "VignetteAmount", N_("Vignette Amount"), "Integer", xmpText, xmpExternal, N_("\"Vignetting Amount\" setting. Range -100 to +100.") }, { "VignetteMidpoint", N_("Vignette Midpoint"), "Integer", xmpText, xmpExternal, N_("\"Vignetting Midpoint\" setting. Range 0 to +100.") }, { "WhiteBalance", N_("White Balance"), "Closed Choice Text", xmpText, xmpExternal, N_("\"White Balance\" setting. One of: As Shot, Auto, Daylight, Cloudy, Shade, Tungsten, " "Fluorescent, Flash, Custom") }, // End of list marker { 0, 0, 0, invalidTypeId, xmpInternal, 0 } }; extern const XmpPropertyInfo xmpTiffInfo[] = { { "ImageWidth", N_("Image Width"), "Integer", xmpText, xmpInternal, N_("TIFF tag 256, 0x100. Image width in pixels.") }, { "ImageLength", N_("Image Length"), "Integer", xmpText, xmpInternal, N_("TIFF tag 257, 0x101. Image height in pixels.") }, { "BitsPerSample", N_("Bits Per Sample"), "seq Integer", xmpSeq, xmpInternal, N_("TIFF tag 258, 0x102. Number of bits per component in each channel.") }, { "Compression", N_("Compression"), "Closed Choice of Integer", xmpText, xmpInternal, N_("TIFF tag 259, 0x103. Compression scheme: 1 = uncompressed; 6 = JPEG.") }, { "PhotometricInterpretation", N_("Photometric Interpretation"), "Closed Choice of Integer", xmpText, xmpInternal, N_("TIFF tag 262, 0x106. Pixel Composition: 2 = RGB; 6 = YCbCr.") }, { "Orientation", N_("Orientation"), "Closed Choice of Integer", xmpText, xmpInternal, N_("TIFF tag 274, 0x112. Orientation:" "1 = 0th row at top, 0th column at left " "2 = 0th row at top, 0th column at right " "3 = 0th row at bottom, 0th column at right " "4 = 0th row at bottom, 0th column at left " "5 = 0th row at left, 0th column at top " "6 = 0th row at right, 0th column at top " "7 = 0th row at right, 0th column at bottom " "8 = 0th row at left, 0th column at bottom") }, { "SamplesPerPixel", N_("Samples Per Pixel"), "Integer", xmpText, xmpInternal, N_("TIFF tag 277, 0x115. Number of components per pixel.") }, { "PlanarConfiguration", N_("Planar Configuration"), "Closed Choice of Integer", xmpText, xmpInternal, N_("TIFF tag 284, 0x11C. Data layout:1 = chunky; 2 = planar.") }, { "YCbCrSubSampling", N_("YCbCr Sub Sampling"), "Closed Choice of seq Integer", xmpSeq, xmpInternal, N_("TIFF tag 530, 0x212. Sampling ratio of chrominance " "components: [2, 1] = YCbCr4:2:2; [2, 2] = YCbCr4:2:0") }, { "YCbCrPositioning", N_("YCbCr Positioning"), "Closed Choice of Integer", xmpText, xmpInternal, N_("TIFF tag 531, 0x213. Position of chrominance vs. " "luminance components: 1 = centered; 2 = co-sited.") }, { "XResolution", N_("X Resolution"), "Rational", xmpText, xmpInternal, N_("TIFF tag 282, 0x11A. Horizontal resolution in pixels per unit.") }, { "YResolution", N_("Y Resolution"), "Rational", xmpText, xmpInternal, N_("TIFF tag 283, 0x11B. Vertical resolution in pixels per unit.") }, { "ResolutionUnit", N_("Resolution Unit"), "Closed Choice of Integer", xmpText, xmpInternal, N_("TIFF tag 296, 0x128. Unit used for XResolution and " "YResolution. Value is one of: 2 = inches; 3 = centimeters.") }, { "TransferFunction", N_("Transfer Function"), "seq Integer", xmpSeq, xmpInternal, N_("TIFF tag 301, 0x12D. Transfer function for image " "described in tabular style with 3 * 256 entries.") }, { "WhitePoint", N_("White Point"), "seq Rational", xmpSeq, xmpInternal, N_("TIFF tag 318, 0x13E. Chromaticity of white point.") }, { "PrimaryChromaticities", N_("Primary Chromaticities"), "seq Rational", xmpSeq, xmpInternal, N_("TIFF tag 319, 0x13F. Chromaticity of the three primary colors.") }, { "YCbCrCoefficients", N_("YCbCr Coefficients"), "seq Rational", xmpSeq, xmpInternal, N_("TIFF tag 529, 0x211. Matrix coefficients for RGB to YCbCr transformation.") }, { "ReferenceBlackWhite", N_("Reference Black White"), "seq Rational", xmpSeq, xmpInternal, N_("TIFF tag 532, 0x214. Reference black and white point values.") }, { "DateTime", N_("Date and Time"), "Date", xmpText, xmpInternal, N_("TIFF tag 306, 0x132 (primary) and EXIF tag 37520, " "0x9290 (subseconds). Date and time of image creation " "(no time zone in EXIF), stored in ISO 8601 format, not " "the original EXIF format. This property includes the " "value for the EXIF SubSecTime attribute. " "NOTE: This property is stored in XMP as xmp:ModifyDate.") }, { "ImageDescription", N_("Image Description"), "Lang Alt", langAlt, xmpExternal, N_("TIFF tag 270, 0x10E. Description of the image. Note: This property is stored in XMP as dc:description.") }, { "Make", N_("Make"), "ProperName", xmpText, xmpInternal, N_("TIFF tag 271, 0x10F. Manufacturer of recording equipment.") }, { "Model", N_("Model"), "ProperName", xmpText, xmpInternal, N_("TIFF tag 272, 0x110. Model name or number of equipment.") }, { "Software", N_("Software"), "AgentName", xmpText, xmpInternal, N_("TIFF tag 305, 0x131. Software or firmware used to generate image. " "Note: This property is stored in XMP as xmp:CreatorTool. ") }, { "Artist", N_("Artist"), "ProperName", xmpText, xmpExternal, N_("TIFF tag 315, 0x13B. Camera owner, photographer or image creator. " "Note: This property is stored in XMP as the first item in the dc:creator array.") }, { "Copyright", N_("Copyright"), "Lang Alt", langAlt, xmpExternal, N_("TIFF tag 33432, 0x8298. Copyright information. " "Note: This property is stored in XMP as dc:rights.") }, // End of list marker { 0, 0, 0, invalidTypeId, xmpInternal, 0 } }; extern const XmpPropertyInfo xmpExifInfo[] = { { "ExifVersion", N_("Exif Version"), "Closed Choice of Text", xmpText, xmpInternal, N_("EXIF tag 36864, 0x9000. EXIF version number.") }, { "FlashpixVersion", N_("Flashpix Version"), "Closed Choice of Text", xmpText, xmpInternal, N_("EXIF tag 40960, 0xA000. Version of FlashPix.") }, { "ColorSpace", N_("Color Space"), "Closed Choice of Integer", xmpText, xmpInternal, N_("EXIF tag 40961, 0xA001. Color space information") }, { "ComponentsConfiguration", N_("Components Configuration"), "Closed Choice of seq Integer", xmpSeq, xmpInternal, N_("EXIF tag 37121, 0x9101. Configuration of components in data: 4 5 6 0 (if RGB compressed data), " "1 2 3 0 (other cases).") }, { "CompressedBitsPerPixel", N_("Compressed Bits Per Pixel"), "Rational", xmpText, xmpInternal, N_("EXIF tag 37122, 0x9102. Compression mode used for a compressed image is indicated " "in unit bits per pixel.") }, { "PixelXDimension", N_("Pixel X Dimension"), "Integer", xmpText, xmpInternal, N_("EXIF tag 40962, 0xA002. Valid image width, in pixels.") }, { "PixelYDimension", N_("Pixel Y Dimension"), "Integer", xmpText, xmpInternal, N_("EXIF tag 40963, 0xA003. Valid image height, in pixels.") }, { "UserComment", N_("User Comment"), "Lang Alt", langAlt, xmpExternal, N_("EXIF tag 37510, 0x9286. Comments from user.") }, { "RelatedSoundFile", N_("Related Sound File"), "Text", xmpText, xmpInternal, N_("EXIF tag 40964, 0xA004. An \"8.3\" file name for the related sound file.") }, { "DateTimeOriginal", N_("Date and Time Original"), "Date", xmpText, xmpInternal, N_("EXIF tags 36867, 0x9003 (primary) and 37521, 0x9291 (subseconds). " "Date and time when original image was generated, in ISO 8601 format. " "Includes the EXIF SubSecTimeOriginal data.") }, { "DateTimeDigitized", N_("Date and Time Digitized"), "Date", xmpText, xmpInternal, N_("EXIF tag 36868, 0x9004 (primary) and 37522, 0x9292 (subseconds). Date and time when " "image was stored as digital data, can be the same as DateTimeOriginal if originally " "stored in digital form. Stored in ISO 8601 format. Includes the EXIF " "SubSecTimeDigitized data.") }, { "ExposureTime", N_("Exposure Time"), "Rational", xmpText, xmpInternal, N_("EXIF tag 33434, 0x829A. Exposure time in seconds.") }, { "FNumber", N_("F Number"), "Rational", xmpText, xmpInternal, N_("EXIF tag 33437, 0x829D. F number.") }, { "ExposureProgram", N_("Exposure Program"), "Closed Choice of Integer", xmpText, xmpInternal, N_("EXIF tag 34850, 0x8822. Class of program used for exposure.") }, { "SpectralSensitivity", N_("Spectral Sensitivity"), "Text", xmpText, xmpInternal, N_("EXIF tag 34852, 0x8824. Spectral sensitivity of each channel.") }, { "ISOSpeedRatings", N_("ISOSpeedRatings"), "seq Integer", xmpSeq, xmpInternal, N_("EXIF tag 34855, 0x8827. ISO Speed and ISO Latitude of the input device as " "specified in ISO 12232.") }, { "OECF", N_("OECF"), "OECF/SFR", xmpText, xmpInternal, N_("EXIF tag 34856, 0x8828. Opto-Electoric Conversion Function as specified in ISO 14524.") }, { "ShutterSpeedValue", N_("Shutter Speed Value"), "Rational", xmpText, xmpInternal, N_("EXIF tag 37377, 0x9201. Shutter speed, unit is APEX. See Annex C of the EXIF specification.") }, { "ApertureValue", N_("Aperture Value"), "Rational", xmpText, xmpInternal, N_("EXIF tag 37378, 0x9202. Lens aperture, unit is APEX.") }, { "BrightnessValue", N_("Brightness Value"), "Rational", xmpText, xmpInternal, N_("EXIF tag 37379, 0x9203. Brightness, unit is APEX.") }, { "ExposureBiasValue", N_("Exposure Bias Value"), "Rational", xmpText, xmpInternal, N_("EXIF tag 37380, 0x9204. Exposure bias, unit is APEX.") }, { "MaxApertureValue", N_("Maximum Aperture Value"), "Rational", xmpText, xmpInternal, N_("EXIF tag 37381, 0x9205. Smallest F number of lens, in APEX.") }, { "SubjectDistance", N_("Subject Distance"), "Rational", xmpText, xmpInternal, N_("EXIF tag 37382, 0x9206. Distance to subject, in meters.") }, { "MeteringMode", N_("Metering Mode"), "Closed Choice of Integer", xmpText, xmpInternal, N_("EXIF tag 37383, 0x9207. Metering mode.") }, { "LightSource", N_("Light Source"), "Closed Choice of Integer", xmpText, xmpInternal, N_("EXIF tag 37384, 0x9208. Light source.") }, { "Flash", N_("Flash"), "Flash", xmpText, xmpInternal, N_("EXIF tag 37385, 0x9209. Strobe light (flash) source data.") }, { "FocalLength", N_("Focal Length"), "Rational", xmpText, xmpInternal, N_("EXIF tag 37386, 0x920A. Focal length of the lens, in millimeters.") }, { "SubjectArea", N_("Subject Area"), "seq Integer", xmpSeq, xmpInternal, N_("EXIF tag 37396, 0x9214. The location and area of the main subject in the overall scene.") }, { "FlashEnergy", N_("Flash Energy"), "Rational", xmpText, xmpInternal, N_("EXIF tag 41483, 0xA20B. Strobe energy during image capture.") }, { "SpatialFrequencyResponse", N_("Spatial Frequency Response"), "OECF/SFR", xmpText, xmpInternal, N_("EXIF tag 41484, 0xA20C. Input device spatial frequency table and SFR values as " "specified in ISO 12233.") }, { "FocalPlaneXResolution", N_("Focal Plane X Resolution"), "Rational", xmpText, xmpInternal, N_("EXIF tag 41486, 0xA20E. Horizontal focal resolution, measured pixels per unit.") }, { "FocalPlaneYResolution", N_("Focal Plane Y Resolution"), "Rational", xmpText, xmpInternal, N_("EXIF tag 41487, 0xA20F. Vertical focal resolution, measured in pixels per unit.") }, { "FocalPlaneResolutionUnit", N_("Focal Plane Resolution Unit"), "Closed Choice of Integer", xmpText, xmpInternal, N_("EXIF tag 41488, 0xA210. Unit used for FocalPlaneXResolution and FocalPlaneYResolution.") }, { "SubjectLocation", N_("Subject Location"), "seq Integer", xmpSeq, xmpInternal, N_("EXIF tag 41492, 0xA214. Location of the main subject of the scene. The first value is the " "horizontal pixel and the second value is the vertical pixel at which the " "main subject appears.") }, { "ExposureIndex", N_("Exposure Index"), "Rational", xmpText, xmpInternal, N_("EXIF tag 41493, 0xA215. Exposure index of input device.") }, { "SensingMethod", N_("Sensing Method"), "Closed Choice of Integer", xmpText, xmpInternal, N_("EXIF tag 41495, 0xA217. Image sensor type on input device.") }, { "FileSource", N_("File Source"), "Closed Choice of Integer", xmpText, xmpInternal, N_("EXIF tag 41728, 0xA300. Indicates image source.") }, { "SceneType", N_("Scene Type"), "Closed Choice of Integer", xmpText, xmpInternal, N_("EXIF tag 41729, 0xA301. Indicates the type of scene.") }, { "CFAPattern", N_("CFA Pattern"), "CFAPattern", xmpText, xmpInternal, N_("EXIF tag 41730, 0xA302. Color filter array geometric pattern of the image sense.") }, { "CustomRendered", N_("Custom Rendered"), "Closed Choice of Integer", xmpText, xmpInternal, N_("EXIF tag 41985, 0xA401. Indicates the use of special processing on image data.") }, { "ExposureMode", N_("Exposure Mode"), "Closed Choice of Integer", xmpText, xmpInternal, N_("EXIF tag 41986, 0xA402. Indicates the exposure mode set when the image was shot.") }, { "WhiteBalance", N_("White Balance"), "Closed Choice of Integer", xmpText, xmpInternal, N_("EXIF tag 41987, 0xA403. Indicates the white balance mode set when the image was shot.") }, { "DigitalZoomRatio", N_("Digital Zoom Ratio"), "Rational", xmpText, xmpInternal, N_("EXIF tag 41988, 0xA404. Indicates the digital zoom ratio when the image was shot.") }, { "FocalLengthIn35mmFilm", N_("Focal Length In 35mm Film"), "Integer", xmpText, xmpInternal, N_("EXIF tag 41989, 0xA405. Indicates the equivalent focal length assuming a 35mm film " "camera, in mm. A value of 0 means the focal length is unknown. Note that this tag " "differs from the FocalLength tag.") }, { "SceneCaptureType", N_("Scene Capture Type"), "Closed Choice of Integer", xmpText, xmpInternal, N_("EXIF tag 41990, 0xA406. Indicates the type of scene that was shot.") }, { "GainControl", N_("Gain Control"), "Closed Choice of Integer", xmpText, xmpInternal, N_("EXIF tag 41991, 0xA407. Indicates the degree of overall image gain adjustment.") }, { "Contrast", N_("Contrast"), "Closed Choice of Integer", xmpText, xmpInternal, N_("EXIF tag 41992, 0xA408. Indicates the direction of contrast processing applied by the camera.") }, { "Saturation", N_("Saturation"), "Closed Choice of Integer", xmpText, xmpInternal, N_("EXIF tag 41993, 0xA409. Indicates the direction of saturation processing applied by the camera.") }, { "Sharpness", N_("Sharpness"), "Closed Choice of Integer", xmpText, xmpInternal, N_("EXIF tag 41994, 0xA40A. Indicates the direction of sharpness processing applied by the camera.") }, { "DeviceSettingDescription", N_("Device Setting Description"), "DeviceSettings", xmpText, xmpInternal, N_("EXIF tag 41995, 0xA40B. Indicates information on the picture-taking conditions of a particular camera model.") }, { "SubjectDistanceRange", N_("Subject Distance Range"), "Closed Choice of Integer", xmpText, xmpInternal, N_("EXIF tag 41996, 0xA40C. Indicates the distance to the subject.") }, { "ImageUniqueID", N_("Image Unique ID"), "Text", xmpText, xmpInternal, N_("EXIF tag 42016, 0xA420. An identifier assigned uniquely to each image. It is recorded as a 32 " "character ASCII string, equivalent to hexadecimal notation and 128-bit fixed length.") }, { "GPSVersionID", N_("GPS Version ID"), "Text", xmpText, xmpInternal, N_("GPS tag 0, 0x00. A decimal encoding of each of the four EXIF bytes with period separators. " "The current value is \"2.0.0.0\".") }, { "GPSLatitude", N_("GPS Latitude"), "GPSCoordinate", xmpText, xmpInternal, N_("GPS tag 2, 0x02 (position) and 1, 0x01 (North/South). Indicates latitude.") }, { "GPSLongitude", N_("GPS Longitude"), "GPSCoordinate", xmpText, xmpInternal, N_("GPS tag 4, 0x04 (position) and 3, 0x03 (East/West). Indicates longitude.") }, { "GPSAltitudeRef", N_("GPS Altitude Reference"), "Closed Choice of Integer", xmpText, xmpInternal, N_("GPS tag 5, 0x05. Indicates whether the altitude is above or below sea level.") }, { "GPSAltitude", N_("GPS Altitude"), "Rational", xmpText, xmpInternal, N_("GPS tag 6, 0x06. Indicates altitude in meters.") }, { "GPSTimeStamp", N_("GPS Time Stamp"), "Date", xmpText, xmpInternal, N_("GPS tag 29 (date), 0x1D, and, and GPS tag 7 (time), 0x07. Time stamp of GPS data, " "in Coordinated Universal Time. Note: The GPSDateStamp tag is new in EXIF 2.2. " "The GPS timestamp in EXIF 2.1 does not include a date. If not present, " "the date component for the XMP should be taken from exif:DateTimeOriginal, or if that is " "also lacking from exif:DateTimeDigitized. If no date is available, do not write " "exif:GPSTimeStamp to XMP.") }, { "GPSSatellites", N_("GPS Satellites"), "Text", xmpText, xmpInternal, N_("GPS tag 8, 0x08. Satellite information, format is unspecified.") }, { "GPSStatus", N_("GPS Status"), "Closed Choice of Text", xmpText, xmpInternal, N_("GPS tag 9, 0x09. Status of GPS receiver at image creation time.") }, { "GPSMeasureMode", N_("GPS Measure Mode"), "Text", xmpText, xmpInternal, N_("GPS tag 10, 0x0A. GPS measurement mode, Text type.") }, { "GPSDOP", N_("GPS DOP"), "Rational", xmpText, xmpInternal, N_("GPS tag 11, 0x0B. Degree of precision for GPS data.") }, { "GPSSpeedRef", N_("GPS Speed Reference"), "Closed Choice of Text", xmpText, xmpInternal, N_("GPS tag 12, 0x0C. Units used to speed measurement.") }, { "GPSSpeed", N_("GPS Speed"), "Rational", xmpText, xmpInternal, N_("GPS tag 13, 0x0D. Speed of GPS receiver movement.") }, { "GPSTrackRef", N_("GPS Track Reference"), "Closed Choice of Text", xmpText, xmpInternal, N_("GPS tag 14, 0x0E. Reference for movement direction.") }, { "GPSTrack", N_("GPS Track"), "Rational", xmpText, xmpInternal, N_("GPS tag 15, 0x0F. Direction of GPS movement, values range from 0 to 359.99.") }, { "GPSImgDirectionRef", N_("GPS Image Direction Reference"), "Closed Choice of Text", xmpText, xmpInternal, N_("GPS tag 16, 0x10. Reference for image direction.") }, { "GPSImgDirection", N_("GPS Image Direction"), "Rational", xmpText, xmpInternal, N_("GPS tag 17, 0x11. Direction of image when captured, values range from 0 to 359.99.") }, { "GPSMapDatum", N_("GPS Map Datum"), "Text", xmpText, xmpInternal, N_("GPS tag 18, 0x12. Geodetic survey data.") }, { "GPSDestLatitude", N_("GPS Destination Latitude"), "GPSCoordinate", xmpText, xmpInternal, N_("GPS tag 20, 0x14 (position) and 19, 0x13 (North/South). Indicates destination latitude.") }, { "GPSDestLongitude", N_("GPS Destination Longitude"), "GPSCoordinate", xmpText, xmpInternal, N_("GPS tag 22, 0x16 (position) and 21, 0x15 (East/West). Indicates destination longitude.") }, { "GPSDestBearingRef", N_("GPS Destination Bearing Reference"), "Closed Choice of Text", xmpText, xmpInternal, N_("GPS tag 23, 0x17. Reference for movement direction.") }, { "GPSDestBearing", N_("GPS Destination Bearing"), "Rational", xmpText, xmpInternal, N_("GPS tag 24, 0x18. Destination bearing, values from 0 to 359.99.") }, { "GPSDestDistanceRef", N_("GPS Destination Distance Refefrence"), "Closed Choice of Text", xmpText, xmpInternal, N_("GPS tag 25, 0x19. Units used for speed measurement.") }, { "GPSDestDistance", N_("GPS Destination Distance"), "Rational", xmpText, xmpInternal, N_("GPS tag 26, 0x1A. Distance to destination.") }, { "GPSProcessingMethod", N_("GPS Processing Method"), "Text", xmpText, xmpInternal, N_("GPS tag 27, 0x1B. A character string recording the name of the method used for location finding.") }, { "GPSAreaInformation", N_("GPS Area Information"), "Text", xmpText, xmpInternal, N_("GPS tag 28, 0x1C. A character string recording the name of the GPS area.") }, { "GPSDifferential", N_("GPS Differential"), "Closed Choice of Integer", xmpText, xmpInternal, N_("GPS tag 30, 0x1E. Indicates whether differential correction is applied to the GPS receiver.") }, // End of list marker { 0, 0, 0, invalidTypeId, xmpInternal, 0 } }; extern const XmpPropertyInfo xmpAuxInfo[] = { { "Lens", N_("Lens"), "Text", xmpText, xmpInternal, N_("A description of the lens used to take the photograph. For example, \"70-200 mm f/2.8-4.0\".") }, { "SerialNumber", N_("SerialNumber"), "Text", xmpText, xmpInternal, N_("The serial number of the camera or camera body used to take the photograph.") }, // End of list marker { 0, 0, 0, invalidTypeId, xmpInternal, 0 } }; extern const XmpPropertyInfo xmpIptcInfo[] = { { "CiAdrCity", N_("Contact Info-City"), "Text", xmpText, xmpExternal, N_("The contact information city part.") }, { "CiAdrCtry", N_("Contact Info-Country"), "Text", xmpText, xmpExternal, N_("The contact information country part.") }, { "CiAdrExtadr", N_("Contact Info-Address"), "Text", xmpText, xmpExternal, N_("The contact information address part. Comprises an optional company name and all required " "information to locate the building or postbox to which mail should be sent.") }, { "CiAdrPcode", N_("Contact Info-Postal Code"), "Text", xmpText, xmpExternal, N_("The contact information part denoting the local postal code.") }, { "CiAdrRegion", N_("Contact Info-State/Province"), "Text", xmpText, xmpExternal, N_("The contact information part denoting regional information like state or province.") }, { "CiEmailWork", N_("Contact Info-Email"), "Text", xmpText, xmpExternal, N_("The contact information email address part.") }, { "CiTelWork", N_("Contact Info-Phone"), "Text", xmpText, xmpExternal, N_("The contact information phone number part.") }, { "CiUrlWork", N_("Contact Info-Web URL"), "Text", xmpText, xmpExternal, N_("The contact information web address part.") }, { "CountryCode", N_("Country Code"), "closed Choice of Text", xmpText, xmpExternal, N_("Code of the country the content is focussing on -- either the country shown in visual " "media or referenced in text or audio media. This element is at the top/first level of " "a top-down geographical hierarchy. The code should be taken from ISO 3166 two or three " "letter code. The full name of a country should go to the \"Country\" element.") }, { "CreatorContactInfo", N_("Creator's Contact Info"), "ContactInfo", xmpText, xmpExternal, N_("The creator's contact information provides all necessary information to get in contact " "with the creator of this news object and comprises a set of sub-properties for proper addressing.") }, { "IntellectualGenre", N_("Intellectual Genre"), "Text", xmpText, xmpExternal, N_("Describes the nature, intellectual or journalistic characteristic of a news object, not " "specifically its content.") }, { "Location", N_("Location"), "Text", xmpText, xmpExternal, N_("Name of a location the content is focussing on -- either the location shown in visual " "media or referenced by text or audio media. This location name could either be the name " "of a sublocation to a city or the name of a well known location or (natural) monument " "outside a city. In the sense of a sublocation to a city this element is at the fourth " "level of a top-down geographical hierarchy.") }, { "Scene", N_("IPTC Scene"), "bag closed Choice of Text", xmpBag, xmpExternal, N_("Describes the scene of a photo content. Specifies one or more terms from the IPTC " "\"Scene-NewsCodes\". Each Scene is represented as a string of 6 digits in an unordered list.") }, { "SubjectCode", N_("IPTC Subject Code"), "bag closed Choice of Text", xmpBag, xmpExternal, N_("Specifies one or more Subjects from the IPTC \"Subject-NewsCodes\" taxonomy to " "categorize the content. Each Subject is represented as a string of 8 digits in an unordered list.") }, // End of list marker { 0, 0, 0, invalidTypeId, xmpInternal, 0 } }; extern const XmpPropertyInfo xmpIptcExtInfo[] = { { "AddlModelInfo", N_("Additional model info"), "Text", xmpText, xmpExternal, N_("Information about the ethnicity and other facts of the model(s) in a model-released image.") }, { "OrganisationInImageCode", N_("Code of featured Organisation"), "bag Text", xmpBag, xmpExternal, N_("Code from controlled vocabulary for identyfing the organisation or company which is featured in the image.") }, { "CVterm", N_("Controlled Vocabulary Term"), "bag URI", xmpBag, xmpExternal, N_("A term to describe the content of the image by a value from a Controlled Vocabulary.") }, { "ModelAge", N_("Model age"), "bag Integer", xmpBag, xmpExternal, N_("Age of the human model(s) at the time this image was taken in a model released image.") }, { "OrganisationInImageName", N_("Name of featured Organisation"), "bag Text", xmpBag, xmpExternal, N_("Name of the organisation or company which is featured in the image.") }, { "PersonInImage", N_("Person shown"), "bag Text", xmpBag, xmpExternal, N_("Name of a person shown in the image.") }, { "DigImageGUID", N_("Digital Image Identifier"), "Text", xmpText, xmpExternal, N_("Globally unique identifier for this digital image. It is created and applied by the creator of the digital image at the time of its creation. this value shall not be changed after that time.") }, { "DigitalSourcefileType", N_("Physical type of original photo"), "URI", xmpText, xmpExternal, N_("The type of the source digital file.") }, { "Event", N_("Event"), "Lang Alt", langAlt, xmpExternal, N_("Names or describes the specific event at which the photo was taken.") }, { "MaxAvailHeight", N_("Maximum available height"), "Integer", xmpText, xmpExternal, N_("The maximum available height in pixels of the original photo from which this photo has been derived by downsizing.") }, { "MaxAvailWidth", N_("Maximum available width"), "Integer", xmpText, xmpExternal, N_("The maximum available width in pixels of the original photo from which this photo has been derived by downsizing.") }, { "RegistryId", N_("Registry Entry"), "bag RegistryEntryDetails", xmpBag, xmpExternal, N_("Both a Registry Item Id and a Registry Organisation Id to record any registration of this digital image with a registry.") }, { "RegItemId", N_("Registry Entry-Item Identifier"), "Text", xmpText, xmpExternal, N_("A unique identifier created by a registry and applied by the creator of the digital image. This value shall not be changed after being applied. This identifier is linked to a corresponding Registry Organisation Identifier.") }, { "RegOrgId", N_("Registry Entry-Organisation Identifier"), "Text", xmpText, xmpExternal, N_("An identifier for the registry which issued the corresponding Registry Image Id.") }, { "IptcLastEdited", N_("IPTC Fields Last Edited"), "Date", xmpText, xmpExternal, N_("The date and optionally time when any of the IPTC photo metadata fields has been last edited.") }, { "LocationShown", N_("Location shown"), "bag LocationDetails", xmpBag, xmpExternal, N_("A location shown in the image.") }, { "LocationCreated", N_("Location Created"), "bag LocationDetails", xmpBag, xmpExternal, N_("The location the photo was taken.") }, { "City", N_("Location-City"), "Text", xmpText, xmpExternal, N_("Name of the city of a location.") }, { "CountryCode", N_("Location-Country ISO-Code"), "Text", xmpText, xmpExternal, N_("The ISO code of a country of a location.") }, { "CountryName", N_("Location-Country Name"), "Text", xmpText, xmpExternal, N_("The name of a country of a location.") }, { "ProvinceState", N_("Location-Province/State"), "Text", xmpText, xmpExternal, N_("The name of a subregion of a country - a province or state - of a location.") }, { "Sublocation", N_("Location-Sublocation"), "Text", xmpText, xmpExternal, N_("Name of a sublocation. This sublocation name could either be the name of a sublocation to a city or the name of a well known location or (natural) monument outside a city.") }, { "WorldRegion", N_("Location-World Region"), "Text", xmpText, xmpExternal, N_("The name of a world region of a location.") }, { "ArtworkOrObject", N_("Artwork or object in the image"), "bag ArtworkOrObjectDetails", xmpBag, xmpExternal, N_("A set of metadata about artwork or an object in the image.") }, { "AOCopyrightNotice", N_("Artwork or object-Copyright notice"), "Text", xmpText, xmpExternal, N_("Contains any necessary copyright notice for claiming the intellectual property for artwork or an object in the image and should identify the current owner of the copyright of this work with associated intellectual property rights.") }, { "AOCreator", N_("Artwork or object-Creator"), "seq ProperName", xmpSeq, xmpExternal, N_("Contains the name of the artist who has created artwork or an object in the image. In cases where the artist could or should not be identified the name of a company or organisation may be appropriate.") }, { "AODateCreated", N_("Artwork or object-Date Created"), "Date", xmpText, xmpExternal, N_("Designates the date and optionally the time the artwork or object in the image was created. This relates to artwork or objects with associated intellectual property rights.") }, { "AOSource", N_("Artwork or object-Source"), "Text", xmpText, xmpExternal, N_("The organisation or body holding and registering the artwork or object in the image for inventory purposes.") }, { "AOSourceInvNo", N_("Artwork or object-Source inventory number"), "Text", xmpText, xmpExternal, N_("The inventory number issued by the organisation or body holding and registering the artwork or object in the image.") }, { "AOTitle", N_("Artwork or object-Title"), "Lang Alt", langAlt, xmpExternal, N_("A reference for the artwork or object in the image.") }, // End of list marker { 0, 0, 0, invalidTypeId, xmpInternal, 0 } }; //! XMP iptcExt:DigitalSourcefileType extern const TagVocabulary iptcExtDigitalSourcefileType[] = { { "scanfilm", N_("Scan from film") }, { "scantransparency", N_("Scan from transparency (including slide)") }, { "scanprint", N_("Scan from print") }, { "cameraraw", N_("Camera RAW") }, { "cameratiff", N_("Camera TIFF") }, { "camerajpeg", N_("Camera JPEG") } }; extern const XmpPropertyInfo xmpPlusInfo[] = { // PLUS Version 1.2.0 { "Version", N_("PLUS Version"), "Text", xmpText, xmpExternal, N_("The version number of the PLUS standards in place at the time of the transaction.") }, { "Licensee", N_("Licensee"), "seq LicenseeDetail", xmpSeq, xmpExternal, N_("Party or parties to whom the license is granted by the Licensor/s under the license transaction.") }, { "LicenseeID", N_("Licensee ID"), "Text", xmpText, xmpExternal, N_("Optional PLUS-ID identifying each Licensee.") }, { "LicenseeName", N_("Licensee Name"), "ProperName", xmpText, xmpExternal, N_("Name of each Licensee.") }, { "EndUser", N_("End User"), "seq EndUserDetail", xmpSeq, xmpExternal, N_("Party or parties ultimately making use of the image under the license.") }, { "EndUserID", N_("End User ID"), "Text", xmpText, xmpExternal, N_("Optional PLUS-ID identifying each End User.") }, { "EndUserName", N_("End User Name"), "ProperName", xmpText, xmpExternal, N_("Name of each End User.") }, { "Licensor", N_("Licensor"), "seq LicensorDetail", xmpSeq, xmpExternal, N_("Party or parties granting the license to the Licensee.") }, { "LicensorID", N_("Licensor ID"), "Text", xmpText, xmpExternal, N_("Optional PLUS-ID identifying each Licensor.") }, { "LicensorName", N_("Licensor Name"), "ProperName", xmpText, xmpExternal, N_("Name of each Licensor.") }, { "LicensorStreetAddress", N_("Licensor Address"), "Text", xmpText, xmpExternal, N_("Licensor street address.") }, { "LicensorExtendedAddress", N_("Licensor Address Detail"), "Text", xmpText, xmpExternal, N_("Additional Licensor mailing address details.") }, { "LicensorCity", N_("Licensor City"), "Text", xmpText, xmpExternal, N_("Licensor City name.") }, { "LicensorRegion", N_("Licensor State or Province"), "Text", xmpText, xmpExternal, N_("Licensor State or Province name.") }, { "LicensorPostalCode", N_("Licensor Postal Code"), "Text", xmpText, xmpExternal, N_("Licensor Postal Code or Zip Code.") }, { "LicensorCountry", N_("Licensor Country"), "Text", xmpText, xmpExternal, N_("Licensor Country name.") }, { "LicensorTelephoneType1", N_("Licensor Telephone Type 1"), "URL", xmpText, xmpExternal, N_("Licensor Telephone Type 1.") }, { "LicensorTelephone1", N_("Licensor Telephone 1"), "Text", xmpText, xmpExternal, N_("Licensor Telephone number 1.") }, { "LicensorTelephoneType2", N_("Licensor Telephone Type 2"), "URL", xmpText, xmpExternal, N_("Licensor Telephone Type 2.") }, { "LicensorTelephone2", N_("Licensor Telephone 2"), "Text", xmpText, xmpExternal, N_("Licensor Telephone number 2.") }, { "LicensorEmail", N_("Licensor Email"), "Text", xmpText, xmpExternal, N_("Licensor Email address.") }, { "LicensorURL", N_("Licensor URL"), "URL", xmpText, xmpExternal, N_("Licensor world wide web address.") }, { "LicensorNotes", N_("Licensor Notes"), "Lang Alt", langAlt, xmpExternal, N_("Supplemental information for use in identifying and contacting the Licensor/s.") }, { "MediaSummaryCode", N_("PLUS Media Summary Code"), "Text", xmpText, xmpExternal, N_("A PLUS-standardized alphanumeric code string summarizing the media usages included in the license.") }, { "LicenseStartDate", N_("License Start Date"), "Date", xmpText, xmpExternal, N_("The date on which the license takes effect.") }, { "LicenseEndDate", N_("License End Date"), "Date", xmpText, xmpExternal, N_("The date on which the license expires.") }, { "MediaConstraints", N_("Media Constraints"), "Lang Alt", langAlt, xmpExternal, N_("Constraints limiting the scope of PLUS Media Usage/s included in the license to particular named media or to media not yet specifically defined in the PLUS Media Matrix.") }, { "RegionConstraints", N_("Region Constraints"), "Lang Alt", langAlt, xmpExternal, N_("Constraints limiting the scope of geographic distribution to specific cities, states, provinces or other areas to be included in or excluded from the PLUS Regions specified in the Media Usages specified in the license.") }, { "ProductOrServiceConstraints", N_("Product or Service Constraints"), "Lang Alt", langAlt, xmpExternal, N_("Constraints limiting usage of the image to promotion of/association with a named product or service.") }, { "ImageFileConstraints", N_("Image File Constraints"), "bag URL", xmpBag, xmpExternal, N_("Constraints on the changing of the image file name, metadata or file type.") }, { "ImageAlterationConstraints", N_("Image Alteration Constraints"), "bag URL", xmpBag, xmpExternal, N_("Constraints on alteration of the image by cropping, flipping, retouching, colorization, de-colorization or merging.") }, { "ImageDuplicationConstraints", N_("Image Duplication Constraints"), "URL", xmpText, xmpExternal, N_("Constraints on the creation of duplicates of the image.") }, { "ModelReleaseStatus", N_("Model Release Status"), "URL", xmpText, xmpExternal, N_("Summarizes the availability and scope of model releases authorizing usage of the likenesses of persons appearing in the photograph.") }, { "ModelReleaseID", N_("Model Release ID"), "bag Text", xmpBag, xmpExternal, N_("Optional identifier associated with each Model Release.") }, { "MinorModelAgeDisclosure", N_("Minor Model Age Disclosure"), "URL", xmpText, xmpExternal, N_("Age of the youngest model pictured in the image, at the time that the image was made.") }, { "PropertyReleaseStatus", N_("Property Release Status"), "URL", xmpText, xmpExternal, N_("Summarizes the availability and scope of property releases authorizing usage of the properties appearing in the photograph.") }, { "PropertyReleaseID", N_("Property Release ID"), "bag Text", xmpBag, xmpExternal, N_("Optional identifier associated with each Property Release.") }, { "OtherConstraints", N_("Other Constraints"), "Lang Alt", langAlt, xmpExternal, N_("Additional constraints on the license.") }, { "CreditLineRequired", N_("Credit Line Required"), "URL", xmpText, xmpExternal, N_("Attribution requirements, if any.") }, { "AdultContentWarning", N_("Adult Content Warning"), "URL", xmpText, xmpExternal, N_("Warning indicating the presence of content not suitable for minors.") }, { "OtherLicenseRequirements", N_("Other License Requirements"), "Lang Alt", langAlt, xmpExternal, N_("Additional license requirements.") }, { "TermsAndConditionsText", N_("Terms and Conditions Text"), "Lang Alt", langAlt, xmpExternal, N_("Terms and Conditions applying to the license.") }, { "TermsAndConditionsURL", N_("Terms and Conditions URL"), "URL", xmpText, xmpExternal, N_("URL for Terms and Conditions applying to the license.") }, { "OtherConditions", N_("Other License Conditions"), "Lang Alt", langAlt, xmpExternal, N_("Additional license conditions.") }, { "ImageType", N_("Image Type"), "URL", xmpText, xmpExternal, N_("Identifies the type of image delivered.") }, { "LicensorImageID", N_("Licensor Image ID"), "Text", xmpText, xmpExternal, N_("Optional identifier assigned by the Licensor to the image.") }, { "FileNameAsDelivered", N_("Image File Name As Delivered"), "Text", xmpText, xmpExternal, N_("Name of the image file delivered to the Licensee for use under the license.") }, { "ImageFileFormatAsDelivered", N_("Image File Format As Delivered"), "URL", xmpText, xmpExternal, N_("File format of the image file delivered to the Licensee for use under the license.") }, { "ImageFileSizeAsDelivered", N_("Image File Size As Delivered"), "URL", xmpText, xmpExternal, N_("Size of the image file delivered to the Licensee.") }, { "CopyrightStatus", N_("Copyright Status"), "URL", xmpText, xmpExternal, N_("Copyright status of the image.") }, { "CopyrightRegistrationNumber", N_("Copyright Registration Number"), "Text", xmpText, xmpExternal, N_("Copyright Registration Number, if any, applying to the licensed image.") }, { "FirstPublicationDate", N_("First Publication Date"), "Date", xmpText, xmpExternal, N_("The date on which the image was first published.") }, { "CopyrightOwner", N_("Copyright Owner"), "seq CopyrightOwnerDetail", xmpSeq, xmpExternal, N_("Owner or owners of the copyright in the licensed image.") }, { "CopyrightOwnerID", N_("Copyright Owner ID"), "Text", xmpText, xmpExternal, N_("Optional PLUS-ID identifying each Copyright Owner.") }, { "CopyrightOwnerName", N_("Copyright Owner Name"), "ProperName", xmpText, xmpExternal, N_("Name of Copyright Owner.") }, { "CopyrightOwnerImageID", N_("Copyright Owner Image ID"), "Text", xmpText, xmpExternal, N_("Optional identifier assigned by the Copyright Owner to the image.") }, { "ImageCreator", N_("Image Creator"), "seq ImageCreatorDetail", xmpSeq, xmpExternal, N_("Creator/s of the image.") }, { "ImageCreatorID", N_("Image Creator ID"), "Text", xmpText, xmpExternal, N_("Optional PLUS-ID identifying each Image Creator.") }, { "ImageCreatorName", N_("Image Creator Name"), "ProperName", xmpText, xmpExternal, N_("Name of Image Creator.") }, { "ImageCreatorImageID", N_("Image Creator Image ID"), "Text", xmpText, xmpExternal, N_("Optional identifier assigned by the Image Creator to the image.") }, { "ImageSupplierID", N_("Image Supplier ID"), "Text", xmpText, xmpExternal, N_("Optional PLUS-ID identifying the Image Supplier.") }, { "ImageSupplierName", N_("Image Supplier Name"), "ProperName", xmpText, xmpExternal, N_("Name of Image Supplier.") }, { "ImageSupplierImageID", N_("Image Supplier Image ID"), "Text", xmpText, xmpExternal, N_("Optional identifier assigned by the Image Supplier to the image.") }, { "LicenseeImageID", N_("Licensee Image ID"), "Text", xmpText, xmpExternal, N_("Optional identifier assigned by the Licensee to the image.") }, { "LicenseeImageNotes", N_("Licensee Image Notes"), "Lang Alt", langAlt, xmpExternal, N_("Notes added by Licensee.") }, { "OtherImageInfo", N_("Other Image Info"), "Lang Alt", langAlt, xmpExternal, N_("Additional image information.") }, { "LicenseID", N_("License ID"), "Text", xmpText, xmpExternal, N_("Optional PLUS-ID assigned by the Licensor to the License.") }, { "LicensorTransactionID", N_("Licensor Transaction ID"), "bag Text", xmpBag, xmpExternal, N_("Identifier assigned by Licensor for Licensor's reference and internal use.") }, { "LicenseeTransactionID", N_("Licensee Transaction ID"), "bag Text", xmpBag, xmpExternal, N_("Identifier assigned by Licensee for Licensee's reference and internal use.") }, { "LicenseeProjectReference", N_("Licensee Project Reference"), "bag Text", xmpBag, xmpExternal, N_("Project reference name or description assigned by Licensee.") }, { "LicenseTransactionDate", N_("License Transaction Date"), "Date", xmpText, xmpExternal, N_("The date of the License Transaction.") }, { "Reuse", N_("Reuse"), "URL", xmpText, xmpExternal, N_("Indicates whether a license is a repeat or an initial license. Reuse may require that licenses stored in files previously delivered to the customer be updated.") }, { "OtherLicenseDocuments", N_("Other License Documents"), "bag Text", xmpBag, xmpExternal, N_("Reference information for additional documents associated with the license.") }, { "OtherLicenseInfo", N_("Other License Info"), "Lang Alt", langAlt, xmpExternal, N_("Additional license information.") }, { "Custom1", N_("Custom 1"), "bag Lang Alt", xmpBag, xmpExternal, N_("Optional field for use at Licensor's discretion.") }, { "Custom2", N_("Custom 2"), "bag Lang Alt", xmpBag, xmpExternal, N_("Optional field for use at Licensor's discretion.") }, { "Custom3", N_("Custom 3"), "bag Lang Alt", xmpBag, xmpExternal, N_("Optional field for use at Licensor's discretion.") }, { "Custom4", N_("Custom 4"), "bag Lang Alt", xmpBag, xmpExternal, N_("Optional field for use at Licensor's discretion.") }, { "Custom5", N_("Custom 5"), "bag Lang Alt", xmpBag, xmpExternal, N_("Optional field for use at Licensor's discretion.") }, { "Custom6", N_("Custom 6"), "bag Lang Alt", xmpBag, xmpExternal, N_("Optional field for use at Licensee's discretion.") }, { "Custom7", N_("Custom 7"), "bag Lang Alt", xmpBag, xmpExternal, N_("Optional field for use at Licensee's discretion.") }, { "Custom8", N_("Custom 8"), "bag Lang Alt", xmpBag, xmpExternal, N_("Optional field for use at Licensee's discretion.") }, { "Custom9", N_("Custom 9"), "bag Lang Alt", xmpBag, xmpExternal, N_("Optional field for use at Licensee's discretion.") }, { "Custom10", N_("Custom 10"), "bag Lang Alt", xmpBag, xmpExternal, N_("Optional field for use at Licensee's discretion.") }, // End of list marker { 0, 0, 0, invalidTypeId, xmpInternal, 0 } }; //! XMP plus:AdultContentWarning extern const TagVocabulary plusAdultContentWarning[] = { { "CW-AWR", N_("Adult Content Warning Required") }, { "CW-NRQ", N_("Not Required") }, { "CW-UNK", N_("Unknown") } }; //! XMP plus:CopyrightStatus extern const TagVocabulary plusCopyrightStatus[] = { { "CS-PRO", N_("Protected") }, { "CS-PUB", N_("Public Domain") }, { "CS-UNK", N_("Unknown") } }; //! XMP plus:CreditLineRequired extern const TagVocabulary plusCreditLineRequired[] = { { "CR-CAI", N_("Credit Adjacent To Image") }, { "CR-CCA", N_("Credit in Credits Area") }, { "CR-COI", N_("Credit on Image") }, { "CR-NRQ", N_("Not Require") } }; //! XMP plus:ImageAlterationConstraints extern const TagVocabulary plusImageAlterationConstraints[] = { { "AL-CLR", N_("No Colorization") }, { "AL-CRP", N_("No Cropping") }, { "AL-DCL", N_("No De-Colorization") }, { "AL-FLP", N_("No Flipping") }, { "AL-MRG", N_("No Merging") }, { "AL-RET", N_("No Retouching") } }; //! XMP plus:ImageDuplicationConstraints extern const TagVocabulary plusImageDuplicationConstraints[] = { { "DP-LIC", N_("Duplication Only as Necessary Under License") }, { "DP-NDC", N_("No Duplication Constraints") }, { "DP-NOD", N_("No Duplication") } }; //! XMP plus:ImageFileConstraints extern const TagVocabulary plusImageFileConstraints[] = { { "IF-MFN", N_("Maintain File Name") }, { "IF-MFT", N_("Maintain File Type") }, { "IF-MID", N_("Maintain ID in File Name") }, { "IF-MMD", N_("Maintain Metadata") } }; //! XMP plus:ImageFileFormatAsDelivered extern const TagVocabulary plusImageFileFormatAsDelivered[] = { { "FF-BMP", N_("Windows Bitmap (BMP)") }, { "FF-DNG", N_("Digital Negative (DNG)") }, { "FF-EPS", N_("Encapsulated PostScript (EPS)") }, { "FF-GIF", N_("Graphics Interchange Format (GIF)") }, { "FF-JPG", N_("JPEG Interchange Formats (JPG, JIF, JFIF)") }, { "FF-OTR", N_("Other") }, { "FF-PIC", N_("Macintosh Picture (PICT)") }, { "FF-PNG", N_("Portable Network Graphics (PNG)") }, { "FF-PSD", N_("Photoshop Document (PSD)") }, { "FF-RAW", N_("Proprietary RAW Image Format") }, { "FF-TIF", N_("Tagged Image File Format (TIFF)") }, { "FF-WMP", N_("Windows Media Photo (HD Photo)") } }; //! XMP plus:ImageFileSizeAsDelivered extern const TagVocabulary plusImageFileSizeAsDelivered[] = { { "SZ-G50", N_("Greater than 50 MB") }, { "SZ-U01", N_("Up to 1 MB") }, { "SZ-U10", N_("Up to 10 MB") }, { "SZ-U30", N_("Up to 30 MB") }, { "SZ-U50", N_("Up to 50 MB") } }; //! XMP plus:ImageType extern const TagVocabulary plusImageType[] = { { "TY-ILL", N_("Illustrated Image") }, { "TY-MCI", N_("Multimedia or Composited Image") }, { "TY-OTR", N_("Other") }, { "TY-PHO", N_("Photographic Image") }, { "TY-VID", N_("Video") } }; //! XMP plus:LicensorTelephoneType extern const TagVocabulary plusLicensorTelephoneType[] = { { "cell", N_("Cell") }, { "fax", N_("FAX") }, { "home", N_("Home") }, { "pager", N_("Pager") }, { "work", N_("Work") } }; //! XMP plus:MinorModelAgeDisclosure extern const TagVocabulary plusMinorModelAgeDisclosure[] = { { "AG-UNK", N_("Age Unknown") }, { "AG-A25", N_("Age 25 or Over") }, { "AG-A24", N_("Age 24") }, { "AG-A23", N_("Age 23") }, { "AG-A22", N_("Age 22") }, { "AG-A21", N_("Age 21") }, { "AG-A20", N_("Age 20") }, { "AG-A19", N_("Age 19") }, { "AG-A18", N_("Age 18") }, { "AG-A17", N_("Age 17") }, { "AG-A16", N_("Age 16") }, { "AG-A15", N_("Age 15") }, { "AG-U14", N_("Age 14 or Under") } }; //! XMP plus:ModelReleaseStatus extern const TagVocabulary plusModelReleaseStatus[] = { { "MR-NON", N_("None") }, { "MR-NAP", N_("Not Applicable") }, { "MR-UMR", N_("Unlimited Model Releases") }, { "MR-LMR", N_("Limited or Incomplete Model Releases") } }; //! XMP plus:PropertyReleaseStatus extern const TagVocabulary plusPropertyReleaseStatus[] = { { "PR-NON", N_("None") }, { "PR-NAP", N_("Not Applicable") }, { "PR-UPR", N_("Unlimited Property Releases") }, { "PR-LPR", N_("Limited or Incomplete Property Releases") } }; //! XMP plus:Reuse extern const TagVocabulary plusReuse[] = { { "RE-NAP", N_("Not Applicable") }, { "RE-REU", N_("Repeat Use") } }; extern const XmpPropertyInfo xmpMediaProInfo[] = { { "Event", N_("Event"), "Text", xmpText, xmpExternal, N_("Fixture Identification") }, { "Status", N_("Status"), "Text", xmpText, xmpExternal, N_("A notation making the image unique") }, { "People", N_("People"), "bag Text", xmpBag, xmpExternal, N_("Contact") }, { "CatalogSets", N_("CatalogSets"), "bag Text", xmpBag, xmpExternal, N_("Descriptive markers of catalog items by content") }, // End of list marker { 0, 0, 0, invalidTypeId, xmpInternal, 0 } }; extern const XmpPropertyInfo xmpExpressionMediaInfo[] = { { "Event", N_("Event"), "Text", xmpText, xmpExternal, N_("Fixture Identification") }, { "Status", N_("Status"), "Text", xmpText, xmpExternal, N_("A notation making the image unique") }, { "People", N_("People"), "bag Text", xmpBag, xmpExternal, N_("Contact") }, { "CatalogSets", N_("CatalogSets"), "bag Text", xmpBag, xmpExternal, N_("Descriptive markers of catalog items by content") }, // End of list marker { 0, 0, 0, invalidTypeId, xmpInternal, 0 } }; extern const XmpPropertyInfo xmpMicrosoftPhotoInfo[] = { { "RegionInfo", N_("RegionInfo"), "RegionInfo", xmpText, xmpInternal, N_("Microsoft Photo people-tagging metadata root") }, // End of list marker { 0, 0, 0, invalidTypeId, xmpInternal, 0 } }; extern const XmpPropertyInfo xmpMicrosoftPhotoRegionInfoInfo[] = { { "DateRegionsValid", N_("DateRegionsValid"), "Date", xmpText, xmpExternal, N_("Date the last region was created") }, { "Regions", N_("Regions"), "bag Region", xmpBag, xmpExternal, N_("Contains Regions/person tags") }, // End of list marker { 0, 0, 0, invalidTypeId, xmpInternal, 0 } }; extern const XmpPropertyInfo xmpMicrosoftPhotoRegionInfo[] = { { "PersonDisplayName", N_("PersonDisplayName"), "Text", xmpText, xmpExternal, N_("Name of the person (in the given rectangle)") }, { "Rectangle", N_("Rectangle"), "Text", xmpText, xmpExternal, N_("Rectangle that identifies the person within the photo") }, { "PersonEmailDigest", N_("PersonEmailDigest"), "Text", xmpText, xmpExternal, N_("SHA-1 encrypted message hash of the person's Windows Live e-mail address"), }, { "PersonLiveCID", N_("PersonLiveCID"), "Text", xmpText, xmpExternal, N_("Signed decimal representation of the person's Windows Live CID") }, // End of list marker { 0, 0, 0, invalidTypeId, xmpInternal, 0 } }; extern const XmpPropertyInfo xmpMWGRegionsInfo[] = { { "Regions", N_("Regions"), "RegionInfo", xmpText, xmpInternal, N_("Main structure containing region based information") }, { "AppliedToDimensions", N_("AppliedToDimensions"), "Dimensions", xmpText, xmpExternal, N_("Width and height of image when storing region data") }, { "RegionList", N_("RegionList"), "bag RegionStruct", xmpBag, xmpExternal, N_("List of Region structures") }, { "Area", N_("Area"), "Area", xmpText, xmpExternal, N_("Descriptive markers of catalog items by content") }, { "Type", N_("Type"), "closed Choice of Text", xmpText, xmpExternal, N_("Type purpose of region (Face|Pet|Focus|BarCode)") }, { "Name", N_("Name"), "Text", xmpText, xmpExternal, N_("Name/ short description of content in image region") }, { "Description", N_("Description"), "Text", xmpText, xmpExternal, N_("Usage scenario for a given focus area (EvaluatedUsed|EvaluatedNotUsed|NotEvaluatedNotUsed)") }, { "FocusUsage", N_("FocusUsage"), "closed Choice of Text", xmpText, xmpExternal, N_("Descriptive markers of catalog items by content") }, { "BarCodeValue", N_("BarCodeValue"), "Text", xmpText, xmpExternal, N_("Decoded BarCode value string") }, { "Extensions", N_("Extensions"), "Text", xmpText, xmpInternal, N_("Any top level XMP property to describe the region content") }, // End of list marker { 0, 0, 0, invalidTypeId, xmpInternal, 0 } }; extern const XmpPrintInfo xmpPrintInfo[] = { {"Xmp.crs.CropUnits", EXV_PRINT_TAG(crsCropUnits) }, {"Xmp.exif.ApertureValue", print0x9202 }, {"Xmp.exif.BrightnessValue", printFloat }, {"Xmp.exif.ColorSpace", print0xa001 }, {"Xmp.exif.ComponentsConfiguration", print0x9101 }, {"Xmp.exif.Contrast", printNormalSoftHard }, {"Xmp.exif.CreateDate", printXmpDate }, {"Xmp.exif.CustomRendered", print0xa401 }, {"Xmp.exif.DateTimeOriginal", printXmpDate }, {"Xmp.exif.ExifVersion", printXmpVersion }, {"Xmp.exif.ExposureBiasValue", print0x9204 }, {"Xmp.exif.ExposureMode", print0xa402 }, {"Xmp.exif.ExposureProgram", print0x8822 }, {"Xmp.exif.FileSource", print0xa300 }, {"Xmp.exif.FlashpixVersion", printXmpVersion }, {"Xmp.exif.FNumber", print0x829d }, {"Xmp.exif.FocalLength", print0x920a }, {"Xmp.exif.FocalPlaneResolutionUnit", printExifUnit }, {"Xmp.exif.FocalPlaneXResolution", printFloat }, {"Xmp.exif.FocalPlaneYResolution", printFloat }, {"Xmp.exif.GainControl", print0xa407 }, {"Xmp.exif.GPSAltitudeRef", print0x0005 }, {"Xmp.exif.GPSDestBearingRef", printGPSDirRef }, {"Xmp.exif.GPSDestDistanceRef", print0x0019 }, {"Xmp.exif.GPSDifferential", print0x001e }, {"Xmp.exif.GPSImgDirectionRef", printGPSDirRef }, {"Xmp.exif.GPSMeasureMode", print0x000a }, {"Xmp.exif.GPSSpeedRef", print0x000c }, {"Xmp.exif.GPSStatus", print0x0009 }, {"Xmp.exif.GPSTimeStamp", printXmpDate }, {"Xmp.exif.GPSTrackRef", printGPSDirRef }, {"Xmp.exif.LightSource", print0x9208 }, {"Xmp.exif.MeteringMode", print0x9207 }, {"Xmp.exif.ModifyDate", printXmpDate }, {"Xmp.exif.Saturation", print0xa409 }, {"Xmp.exif.SceneCaptureType", print0xa406 }, {"Xmp.exif.SceneType", print0xa301 }, {"Xmp.exif.SensingMethod", print0xa217 }, {"Xmp.exif.Sharpness", printNormalSoftHard }, {"Xmp.exif.ShutterSpeedValue", print0x9201 }, {"Xmp.exif.SubjectDistanceRange", print0xa40c }, {"Xmp.exif.WhiteBalance", print0xa403 }, {"Xmp.tiff.Orientation", print0x0112 }, {"Xmp.tiff.ResolutionUnit", printExifUnit }, {"Xmp.tiff.XResolution", printLong }, {"Xmp.tiff.YCbCrPositioning", print0x0213 }, {"Xmp.tiff.YResolution", printLong }, {"Xmp.iptcExt.DigitalSourcefileType", EXV_PRINT_VOCABULARY(iptcExtDigitalSourcefileType) }, {"Xmp.plus.AdultContentWarning", EXV_PRINT_VOCABULARY(plusAdultContentWarning) }, {"Xmp.plus.CopyrightStatus", EXV_PRINT_VOCABULARY(plusCopyrightStatus) }, {"Xmp.plus.CreditLineRequired", EXV_PRINT_VOCABULARY(plusCreditLineRequired) }, {"Xmp.plus.ImageAlterationConstraints", EXV_PRINT_VOCABULARY(plusImageAlterationConstraints) }, {"Xmp.plus.ImageDuplicationConstraints", EXV_PRINT_VOCABULARY(plusImageDuplicationConstraints)}, {"Xmp.plus.ImageFileConstraints", EXV_PRINT_VOCABULARY(plusImageFileConstraints) }, {"Xmp.plus.ImageFileFormatAsDelivered", EXV_PRINT_VOCABULARY(plusImageFileFormatAsDelivered) }, {"Xmp.plus.ImageFileSizeAsDelivered", EXV_PRINT_VOCABULARY(plusImageFileSizeAsDelivered) }, {"Xmp.plus.ImageType", EXV_PRINT_VOCABULARY(plusImageType) }, {"Xmp.plus.LicensorTelephoneType1", EXV_PRINT_VOCABULARY(plusLicensorTelephoneType) }, {"Xmp.plus.LicensorTelephoneType2", EXV_PRINT_VOCABULARY(plusLicensorTelephoneType) }, {"Xmp.plus.MinorModelAgeDisclosure", EXV_PRINT_VOCABULARY(plusMinorModelAgeDisclosure) }, {"Xmp.plus.ModelReleaseStatus", EXV_PRINT_VOCABULARY(plusModelReleaseStatus) }, {"Xmp.plus.PropertyReleaseStatus", EXV_PRINT_VOCABULARY(plusPropertyReleaseStatus) }, {"Xmp.plus.Reuse", EXV_PRINT_VOCABULARY(plusReuse) } }; XmpNsInfo::Ns::Ns(const std::string& ns) : ns_(ns) { } XmpNsInfo::Prefix::Prefix(const std::string& prefix) : prefix_(prefix) { } bool XmpNsInfo::operator==(const XmpNsInfo::Ns& ns) const { std::string n(ns_); return n == ns.ns_; } bool XmpNsInfo::operator==(const XmpNsInfo::Prefix& prefix) const { std::string p(prefix_); return p == prefix.prefix_; } bool XmpPropertyInfo::operator==(const std::string& name) const { std::string n(name_); return n == name; } XmpProperties::NsRegistry XmpProperties::nsRegistry_; const XmpNsInfo* XmpProperties::lookupNsRegistry(const XmpNsInfo::Prefix& prefix) { for (NsRegistry::const_iterator i = nsRegistry_.begin(); i != nsRegistry_.end(); ++i) { if (i->second == prefix) return &(i->second); } return 0; } void XmpProperties::registerNs(const std::string& ns, const std::string& prefix) { std::string ns2 = ns; if ( ns2.substr(ns2.size() - 1, 1) != "/" && ns2.substr(ns2.size() - 1, 1) != "#") ns2 += "/"; // Check if there is already a registered namespace with this prefix const XmpNsInfo* xnp = lookupNsRegistry(XmpNsInfo::Prefix(prefix)); if (xnp) { #ifndef SUPPRESS_WARNINGS if (strcmp(xnp->ns_, ns2.c_str()) != 0) { EXV_WARNING << "Updating namespace URI for " << prefix << " from " << xnp->ns_ << " to " << ns2 << "\n"; } #endif unregisterNs(xnp->ns_); } // Allocated memory is freed when the namespace is unregistered. // Using malloc/free for better system compatibility in case // users don't unregister their namespaces explicitly. XmpNsInfo xn; char* c = static_cast(std::malloc(ns2.size() + 1)); std::strcpy(c, ns2.c_str()); xn.ns_ = c; c = static_cast(std::malloc(prefix.size() + 1)); std::strcpy(c, prefix.c_str()); xn.prefix_ = c; xn.xmpPropertyInfo_ = 0; xn.desc_ = ""; nsRegistry_[ns2] = xn; } void XmpProperties::unregisterNs(const std::string& ns) { NsRegistry::iterator i = nsRegistry_.find(ns); if (i != nsRegistry_.end()) { std::free(const_cast(i->second.prefix_)); std::free(const_cast(i->second.ns_)); nsRegistry_.erase(i); } } void XmpProperties::unregisterNs() { NsRegistry::iterator i = nsRegistry_.begin(); while (i != nsRegistry_.end()) { NsRegistry::iterator kill = i++; unregisterNs(kill->first); } } std::string XmpProperties::prefix(const std::string& ns) { std::string ns2 = ns; if ( ns2.substr(ns2.size() - 1, 1) != "/" && ns2.substr(ns2.size() - 1, 1) != "#") ns2 += "/"; NsRegistry::const_iterator i = nsRegistry_.find(ns2); std::string p; if (i != nsRegistry_.end()) { p = i->second.prefix_; } else { const XmpNsInfo* xn = find(xmpNsInfo, XmpNsInfo::Ns(ns2)); if (xn) p = std::string(xn->prefix_); } return p; } std::string XmpProperties::ns(const std::string& prefix) { const XmpNsInfo* xn = lookupNsRegistry(XmpNsInfo::Prefix(prefix)); if (xn != 0) return xn->ns_; return nsInfo(prefix)->ns_; } const char* XmpProperties::propertyTitle(const XmpKey& key) { const XmpPropertyInfo* pi = propertyInfo(key); return pi ? pi->title_ : 0; } const char* XmpProperties::propertyDesc(const XmpKey& key) { const XmpPropertyInfo* pi = propertyInfo(key); return pi ? pi->desc_ : 0; } TypeId XmpProperties::propertyType(const XmpKey& key) { const XmpPropertyInfo* pi = propertyInfo(key); return pi ? pi->typeId_ : xmpText; } const XmpPropertyInfo* XmpProperties::propertyInfo(const XmpKey& key) { std::string prefix = key.groupName(); std::string property = key.tagName(); // If property is a path for a nested property, determines the innermost element std::string::size_type i = property.find_last_of('/'); if (i != std::string::npos) { for (; i != std::string::npos && !isalpha(property[i]); ++i) {} property = property.substr(i); i = property.find_first_of(':'); if (i != std::string::npos) { prefix = property.substr(0, i); property = property.substr(i+1); } #ifdef DEBUG std::cout << "Nested key: " << key.key() << ", prefix: " << prefix << ", property: " << property << "\n"; #endif } const XmpPropertyInfo* pl = propertyList(prefix); if (!pl) return 0; const XmpPropertyInfo* pi = 0; for (int i = 0; pl[i].name_ != 0; ++i) { if (0 == strcmp(pl[i].name_, property.c_str())) { pi = pl + i; break; } } return pi; } const char* XmpProperties::nsDesc(const std::string& prefix) { return nsInfo(prefix)->desc_; } const XmpPropertyInfo* XmpProperties::propertyList(const std::string& prefix) { return nsInfo(prefix)->xmpPropertyInfo_; } const XmpNsInfo* XmpProperties::nsInfo(const std::string& prefix) { const XmpNsInfo::Prefix pf(prefix); const XmpNsInfo* xn = lookupNsRegistry(pf); if (!xn) xn = find(xmpNsInfo, pf); if (!xn) throw Error(35, prefix); return xn; } void XmpProperties::printProperties(std::ostream& os, const std::string& prefix) { const XmpPropertyInfo* pl = propertyList(prefix); if (pl) { for (int i = 0; pl[i].name_ != 0; ++i) { os << pl[i]; } } } // XmpProperties::printProperties std::ostream& XmpProperties::printProperty(std::ostream& os, const std::string& key, const Value& value) { PrintFct fct = printValue; if (value.count() != 0) { const XmpPrintInfo* info = find(xmpPrintInfo, key); if (info) fct = info->printFct_; } return fct(os, value, 0); } //! @cond IGNORE //! Internal Pimpl structure with private members and data of class XmpKey. struct XmpKey::Impl { Impl() {} //!< Default constructor Impl(const std::string& prefix, const std::string& property); //!< Constructor /*! @brief Parse and convert the \em key string into property and prefix. Updates data members if the string can be decomposed, or throws \em Error. @throw Error if the key cannot be decomposed. */ void decomposeKey(const std::string& key); // DATA static const char* familyName_; //!< "Xmp" std::string prefix_; //!< Prefix std::string property_; //!< Property name }; //! @endcond XmpKey::Impl::Impl(const std::string& prefix, const std::string& property) { // Validate prefix if (XmpProperties::ns(prefix).empty()) throw Error(46, prefix); property_ = property; prefix_ = prefix; } const char* XmpKey::Impl::familyName_ = "Xmp"; XmpKey::XmpKey(const std::string& key) : p_(new Impl) { p_->decomposeKey(key); } XmpKey::XmpKey(const std::string& prefix, const std::string& property) : p_(new Impl(prefix, property)) { } XmpKey::~XmpKey() { delete p_; } XmpKey::XmpKey(const XmpKey& rhs) : Key(rhs), p_(new Impl(*rhs.p_)) { } XmpKey& XmpKey::operator=(const XmpKey& rhs) { if (this == &rhs) return *this; Key::operator=(rhs); *p_ = *rhs.p_; return *this; } XmpKey::AutoPtr XmpKey::clone() const { return AutoPtr(clone_()); } XmpKey* XmpKey::clone_() const { return new XmpKey(*this); } std::string XmpKey::key() const { return std::string(p_->familyName_) + "." + p_->prefix_ + "." + p_->property_; } const char* XmpKey::familyName() const { return p_->familyName_; } std::string XmpKey::groupName() const { return p_->prefix_; } std::string XmpKey::tagName() const { return p_->property_; } std::string XmpKey::tagLabel() const { const char* pt = XmpProperties::propertyTitle(*this); if (!pt) return tagName(); return pt; } uint16_t XmpKey::tag() const { return 0; } std::string XmpKey::ns() const { return XmpProperties::ns(p_->prefix_); } void XmpKey::Impl::decomposeKey(const std::string& key) { // Get the family name, prefix and property name parts of the key std::string::size_type pos1 = key.find('.'); if (pos1 == std::string::npos) throw Error(6, key); std::string familyName = key.substr(0, pos1); if (0 != strcmp(familyName.c_str(), familyName_)) { throw Error(6, key); } std::string::size_type pos0 = pos1 + 1; pos1 = key.find('.', pos0); if (pos1 == std::string::npos) throw Error(6, key); std::string prefix = key.substr(pos0, pos1 - pos0); if (prefix == "") throw Error(6, key); std::string property = key.substr(pos1 + 1); if (property == "") throw Error(6, key); // Validate prefix if (XmpProperties::ns(prefix).empty()) throw Error(46, prefix); property_ = property; prefix_ = prefix; } // XmpKey::Impl::decomposeKey // ************************************************************************* // free functions std::ostream& operator<<(std::ostream& os, const XmpPropertyInfo& property) { return os << property.name_ << ",\t" << property.title_ << ",\t" << property.xmpValueType_ << ",\t" << TypeInfo::typeName(property.typeId_) << ",\t" << ( property.xmpCategory_ == xmpExternal ? "External" : "Internal" ) << ",\t" << property.desc_ << "\n"; } //! @endcond } // namespace Exiv2 exiv2-0.23/src/rw2image_int.hpp0000644000175000017500000000433611732641407016211 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! @file rw2image_int.hpp @brief Internal classes to support RW2 image format @version $Rev: 2681 $ @author Andreas Huggel (ahu) ahuggel@gmx.net @date 06-Jan-09, ahu: created */ #ifndef RW2IMAGE_INT_HPP_ #define RW2IMAGE_INT_HPP_ // ***************************************************************************** // included header files #include "tiffimage_int.hpp" #include "types.hpp" // + standard includes #include // ***************************************************************************** // namespace extensions namespace Exiv2 { namespace Internal { // ***************************************************************************** // class definitions /*! @brief Panasonic RW2 header structure. */ class Rw2Header : public TiffHeaderBase { public: //! @name Creators //@{ //! Default constructor Rw2Header(); //! Destructor. ~Rw2Header(); //@} //! @name Accessors //@{ //! Not yet implemented. Does nothing and returns an empty buffer. DataBuf write() const; //@} }; // class Rw2Header }} // namespace Internal, Exiv2 #endif // #ifndef RW2IMAGE_INT_HPP_ exiv2-0.23/src/exiv2.cpp0000644000175000017500000013367111732641407014657 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /* Abstract: Command line program to display and manipulate image metadata. File: exiv2.cpp Version: $Rev: 2681 $ Author(s): Andreas Huggel (ahu) History: 10-Dec-03, ahu: created */ // ***************************************************************************** #include "rcsid_int.hpp" EXIV2_RCSID("@(#) $Id: exiv2.cpp 2681 2012-03-22 15:19:35Z ahuggel $") // ***************************************************************************** // included header files #ifdef _MSC_VER # include "exv_msvc.h" #else # include "exv_conf.h" #endif #include "exiv2app.hpp" #include "actions.hpp" #include "utils.hpp" #include "convert.hpp" #include "i18n.h" // NLS support. #include "xmp.hpp" #include #include #include #include #include #include #include // ***************************************************************************** // local declarations namespace { //! List of all command identifiers and corresponding strings static const CmdIdAndString cmdIdAndString[] = { { add, "add" }, { set, "set" }, { del, "del" }, { reg, "reg" }, { invalidCmdId, "invalidCmd" } // End of list marker }; // Return a command Id for a command string CmdId commandId(const std::string& cmdString); // Evaluate [-]HH[:MM[:SS]], returns true and sets time to the value // in seconds if successful, else returns false. bool parseTime(const std::string& ts, long& time); /*! @brief Parse the oparg string into a bitmap of common targets. @param optarg Option arguments @param action Action being processed @return A bitmap of common targets or -1 in case of a parse error */ int parseCommonTargets(const std::string& optarg, const std::string& action); /*! @brief Parse numbers separated by commas into container @param previewNumbers Container for the numbers @param optarg Option arguments @param j Starting index into optarg @return Number of characters processed */ int parsePreviewNumbers(Params::PreviewNumbers& previewNumbers, const std::string& optarg, int j); /*! @brief Parse metadata modification commands from multiple files @param modifyCmds Reference to a structure to store the parsed commands @param cmdFiles Container with the file names */ bool parseCmdFiles(ModifyCmds& modifyCmds, const Params::CmdFiles& cmdFiles); /*! @brief Parse metadata modification commands from a container of commands @param modifyCmds Reference to a structure to store the parsed commands @param cmdLines Container with the commands */ bool parseCmdLines(ModifyCmds& modifyCmds, const Params::CmdLines& cmdLines); /*! @brief Parse one line of the command file @param modifyCmd Reference to a command structure to store the parsed command @param line Input line @param num Line number (used for error output) */ bool parseLine(ModifyCmd& modifyCmd, const std::string& line, int num); /*! @brief Parses a string containing backslash-escapes @param input Input string, assumed to be UTF-8 */ std::string parseEscapes(const std::string& input); } // ***************************************************************************** // Main int main(int argc, char* const argv[]) { #ifdef EXV_ENABLE_NLS setlocale(LC_ALL, ""); bindtextdomain(EXV_PACKAGE, EXV_LOCALEDIR); textdomain(EXV_PACKAGE); #endif // Handle command line arguments Params& params = Params::instance(); if (params.getopt(argc, argv)) { params.usage(); return 1; } if (params.help_) { params.help(); return 0; } if (params.version_) { params.version(); return 0; } // Create the required action class Action::TaskFactory& taskFactory = Action::TaskFactory::instance(); Action::Task::AutoPtr task = taskFactory.create(Action::TaskType(params.action_)); assert(task.get()); // Process all files int rc = 0; int n = 1; int s = static_cast(params.files_.size()); int w = s > 9 ? s > 99 ? 3 : 2 : 1; for (Params::Files::const_iterator i = params.files_.begin(); i != params.files_.end(); ++i) { if (params.verbose_) { std::cout << _("File") << " " << std::setw(w) << std::right << n++ << "/" << s << ": " << *i << std::endl; } int ret = task->run(*i); if (rc == 0) rc = ret; } taskFactory.cleanup(); params.cleanup(); Exiv2::XmpParser::terminate(); // Return a positive one byte code for better consistency across platforms return static_cast(rc) % 256; } // main // ***************************************************************************** // class Params Params* Params::instance_ = 0; const Params::YodAdjust Params::emptyYodAdjust_[] = { { false, "-Y", 0 }, { false, "-O", 0 }, { false, "-D", 0 }, }; Params& Params::instance() { if (0 == instance_) { instance_ = new Params; } return *instance_; } void Params::cleanup() { delete instance_; instance_ = 0; } void Params::version(std::ostream& os) const { bool b64 = sizeof(void*)==8; const char* sBuild = b64 ? "(64 bit build)" : "(32 bit build)" ; os << EXV_PACKAGE_STRING << " " << Exiv2::versionNumberHexString() << " " << sBuild << "\n" << _("Copyright (C) 2004-2012 Andreas Huggel.\n") << "\n" << _("This program is free software; you can redistribute it and/or\n" "modify it under the terms of the GNU General Public License\n" "as published by the Free Software Foundation; either version 2\n" "of the License, or (at your option) any later version.\n") << "\n" << _("This program is distributed in the hope that it will be useful,\n" "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" "GNU General Public License for more details.\n") << "\n" << _("You should have received a copy of the GNU General Public\n" "License along with this program; if not, write to the Free\n" "Software Foundation, Inc., 51 Franklin Street, Fifth Floor,\n" "Boston, MA 02110-1301 USA\n"); } void Params::usage(std::ostream& os) const { os << _("Usage:") << " " << progname() << " " << _("[ options ] [ action ] file ...\n\n") << _("Manipulate the Exif metadata of images.\n"); } void Params::help(std::ostream& os) const { usage(os); os << _("\nActions:\n") << _(" ad | adjust Adjust Exif timestamps by the given time. This action\n" " requires at least one of the -a, -Y, -O or -D options.\n") << _(" pr | print Print image metadata.\n") << _(" rm | delete Delete image metadata from the files.\n") << _(" in | insert Insert metadata from corresponding *.exv files.\n" " Use option -S to change the suffix of the input files.\n") << _(" ex | extract Extract metadata to *.exv, *.xmp and thumbnail image files.\n") << _(" mv | rename Rename files and/or set file timestamps according to the\n" " Exif create timestamp. The filename format can be set with\n" " -r format, timestamp options are controlled with -t and -T.\n") << _(" mo | modify Apply commands to modify (add, set, delete) the Exif and\n" " IPTC metadata of image files or set the JPEG comment.\n" " Requires option -c, -m or -M.\n") << _(" fi | fixiso Copy ISO setting from the Nikon Makernote to the regular\n" " Exif tag.\n") << _(" fc | fixcom Convert the UNICODE Exif user comment to UCS-2. Its current\n" " character encoding can be specified with the -n option.\n") << _("\nOptions:\n") << _(" -h Display this help and exit.\n") << _(" -V Show the program version and exit.\n") << _(" -v Be verbose during the program run.\n") << _(" -q Silence warnings and error messages during the program run (quiet).\n") << _(" -Q lvl Set log-level to d(ebug), i(nfo), w(arning), e(rror) or m(ute).\n") << _(" -b Show large binary values.\n") << _(" -u Show unknown tags.\n") << _(" -g key Only output info for this key (grep).\n") << _(" -n enc Charset to use to decode UNICODE Exif user comments.\n") << _(" -k Preserve file timestamps (keep).\n") << _(" -t Also set the file timestamp in 'rename' action (overrides -k).\n") << _(" -T Only set the file timestamp in 'rename' action, do not rename\n" " the file (overrides -k).\n") << _(" -f Do not prompt before overwriting existing files (force).\n") << _(" -F Do not prompt before renaming files (Force).\n") << _(" -a time Time adjustment in the format [-]HH[:MM[:SS]]. This option\n" " is only used with the 'adjust' action.\n") << _(" -Y yrs Year adjustment with the 'adjust' action.\n") << _(" -O mon Month adjustment with the 'adjust' action.\n") << _(" -D day Day adjustment with the 'adjust' action.\n") << _(" -p mode Print mode for the 'print' action. Possible modes are:\n") << _(" s : print a summary of the Exif metadata (the default)\n") << _(" a : print Exif, IPTC and XMP metadata (shortcut for -Pkyct)\n") << _(" t : interpreted (translated) Exif data (-PEkyct)\n") << _(" v : plain Exif data values (-PExgnycv)\n") << _(" h : hexdump of the Exif data (-PExgnycsh)\n") << _(" i : IPTC data values (-PIkyct)\n") << _(" x : XMP properties (-PXkyct)\n") << _(" c : JPEG comment\n") << _(" p : list available previews\n") << _(" -P flgs Print flags for fine control of tag lists ('print' action):\n") << _(" E : include Exif tags in the list\n") << _(" I : IPTC datasets\n") << _(" X : XMP properties\n") << _(" x : print a column with the tag number\n") << _(" g : group name\n") << _(" k : key\n") << _(" l : tag label\n") << _(" n : tag name\n") << _(" y : type\n") << _(" c : number of components (count)\n") << _(" s : size in bytes\n") << _(" v : plain data value\n") << _(" t : interpreted (translated) data\n") << _(" h : hexdump of the data\n") << _(" -d tgt Delete target(s) for the 'delete' action. Possible targets are:\n") << _(" a : all supported metadata (the default)\n") << _(" e : Exif section\n") << _(" t : Exif thumbnail only\n") << _(" i : IPTC data\n") << _(" x : XMP packet\n") << _(" c : JPEG comment\n") << _(" -i tgt Insert target(s) for the 'insert' action. Possible targets are\n" " the same as those for the -d option, plus a modifier:\n" " X : Insert metadata from an XMP sidecar file .xmp\n" " Only JPEG thumbnails can be inserted, they need to be named\n" " -thumb.jpg\n") << _(" -e tgt Extract target(s) for the 'extract' action. Possible targets\n" " are the same as those for the -d option, plus a target to extract\n" " preview images and a modifier to generate an XMP sidecar file:\n" " p[[, ...]] : Extract preview images.\n" " X : Extract metadata to an XMP sidecar file .xmp\n") << _(" -r fmt Filename format for the 'rename' action. The format string\n" " follows strftime(3). The following keywords are supported:\n") << _(" :basename: - original filename without extension\n") << _(" :dirname: - name of the directory holding the original file\n") << _(" :parentname: - name of parent directory\n") << _(" Default filename format is ") << format_ << ".\n" << _(" -c txt JPEG comment string to set in the image.\n") << _(" -m file Command file for the modify action. The format for commands is\n" " set|add|del [[] ].\n") << _(" -M cmd Command line for the modify action. The format for the\n" " commands is the same as that of the lines of a command file.\n") << _(" -l dir Location (directory) for files to be inserted from or extracted to.\n") << _(" -S .suf Use suffix .suf for source files for insert command.\n\n"); } // Params::help int Params::option(int opt, const std::string& optarg, int optopt) { int rc = 0; switch (opt) { case 'h': help_ = true; break; case 'V': version_ = true; break; case 'v': verbose_ = true; break; case 'q': Exiv2::LogMsg::setLevel(Exiv2::LogMsg::mute); break; case 'Q': rc = setLogLevel(optarg); break; case 'k': preserve_ = true; break; case 'b': binary_ = false; break; case 'u': unknown_ = false; break; case 'f': force_ = true; fileExistsPolicy_ = overwritePolicy; break; case 'F': force_ = true; fileExistsPolicy_ = renamePolicy; break; case 'g': keys_.push_back(optarg); printMode_ = pmList; break; case 'n': charset_ = optarg; break; case 'r': rc = evalRename(opt, optarg); break; case 't': rc = evalRename(opt, optarg); break; case 'T': rc = evalRename(opt, optarg); break; case 'a': rc = evalAdjust(optarg); break; case 'Y': rc = evalYodAdjust(yodYear, optarg); break; case 'O': rc = evalYodAdjust(yodMonth, optarg); break; case 'D': rc = evalYodAdjust(yodDay, optarg); break; case 'p': rc = evalPrint(optarg); break; case 'P': rc = evalPrintFlags(optarg); break; case 'd': rc = evalDelete(optarg); break; case 'e': rc = evalExtract(optarg); break; case 'i': rc = evalInsert(optarg); break; case 'c': rc = evalModify(opt, optarg); break; case 'm': rc = evalModify(opt, optarg); break; case 'M': rc = evalModify(opt, optarg); break; case 'l': directory_ = optarg; break; case 'S': suffix_ = optarg; break; case ':': std::cerr << progname() << ": " << _("Option") << " -" << static_cast(optopt) << " " << _("requires an argument\n"); rc = 1; break; case '?': std::cerr << progname() << ": " << _("Unrecognized option") << " -" << static_cast(optopt) << "\n"; rc = 1; break; default: std::cerr << progname() << ": " << _("getopt returned unexpected character code") << " " << std::hex << opt << "\n"; rc = 1; break; } return rc; } // Params::option int Params::setLogLevel(const std::string& optarg) { int rc = 0; const char logLevel = tolower(optarg[0]); switch (logLevel) { case 'd': Exiv2::LogMsg::setLevel(Exiv2::LogMsg::debug); break; case 'i': Exiv2::LogMsg::setLevel(Exiv2::LogMsg::info); break; case 'w': Exiv2::LogMsg::setLevel(Exiv2::LogMsg::warn); break; case 'e': Exiv2::LogMsg::setLevel(Exiv2::LogMsg::error); break; case 'm': Exiv2::LogMsg::setLevel(Exiv2::LogMsg::mute); break; default: std::cerr << progname() << ": " << _("Option") << " -Q: " << _("Invalid argument") << " \"" << optarg << "\"\n"; rc = 1; break; } return rc; } // Params::setLogLevel int Params::evalRename(int opt, const std::string& optarg) { int rc = 0; switch (action_) { case Action::none: action_ = Action::rename; switch (opt) { case 'r': format_ = optarg; formatSet_ = true; break; case 't': timestamp_ = true; break; case 'T': timestampOnly_ = true; break; } break; case Action::rename: if (opt == 'r' && (formatSet_ || timestampOnly_)) { std::cerr << progname() << ": " << _("Ignoring surplus option") << " -r \"" << optarg << "\"\n"; } else { format_ = optarg; formatSet_ = true; } break; default: std::cerr << progname() << ": " << _("Option") << " -" << (char)opt << " " << _("is not compatible with a previous option\n"); rc = 1; break; } return rc; } // Params::evalRename int Params::evalAdjust(const std::string& optarg) { int rc = 0; switch (action_) { case Action::none: case Action::adjust: if (adjust_) { std::cerr << progname() << ": " << _("Ignoring surplus option -a") << " " << optarg << "\n"; break; } action_ = Action::adjust; adjust_ = parseTime(optarg, adjustment_); if (!adjust_) { std::cerr << progname() << ": " << _("Error parsing -a option argument") << " `" << optarg << "'\n"; rc = 1; } break; default: std::cerr << progname() << ": " << _("Option -a is not compatible with a previous option\n"); rc = 1; break; } return rc; } // Params::evalAdjust int Params::evalYodAdjust(const Yod& yod, const std::string& optarg) { int rc = 0; switch (action_) { case Action::none: // fall-through case Action::adjust: if (yodAdjust_[yod].flag_) { std::cerr << progname() << ": " << _("Ignoring surplus option") << " " << yodAdjust_[yod].option_ << " " << optarg << "\n"; break; } action_ = Action::adjust; yodAdjust_[yod].flag_ = true; if (!Util::strtol(optarg.c_str(), yodAdjust_[yod].adjustment_)) { std::cerr << progname() << ": " << _("Error parsing") << " " << yodAdjust_[yod].option_ << " " << _("option argument") << " `" << optarg << "'\n"; rc = 1; } break; default: std::cerr << progname() << ": " << _("Option") << " " << yodAdjust_[yod].option_ << " " << _("is not compatible with a previous option\n"); rc = 1; break; } return rc; } // Params::evalYodAdjust int Params::evalPrint(const std::string& optarg) { int rc = 0; switch (action_) { case Action::none: switch (optarg[0]) { case 's': action_ = Action::print; printMode_ = pmSummary; break; case 'a': rc = evalPrintFlags("kyct"); break; case 't': rc = evalPrintFlags("Ekyct"); break; case 'v': rc = evalPrintFlags("Exgnycv"); break; case 'h': rc = evalPrintFlags("Exgnycsh"); break; case 'i': rc = evalPrintFlags("Ikyct"); break; case 'x': rc = evalPrintFlags("Xkyct"); break; case 'c': action_ = Action::print; printMode_ = pmComment; break; case 'p': action_ = Action::print; printMode_ = pmPreview; break; default: std::cerr << progname() << ": " << _("Unrecognized print mode") << " `" << optarg << "'\n"; rc = 1; break; } break; case Action::print: std::cerr << progname() << ": " << _("Ignoring surplus option -p") << optarg << "\n"; break; default: std::cerr << progname() << ": " << _("Option -p is not compatible with a previous option\n"); rc = 1; break; } return rc; } // Params::evalPrint int Params::evalPrintFlags(const std::string& optarg) { int rc = 0; switch (action_) { case Action::none: action_ = Action::print; printMode_ = pmList; for (std::size_t i = 0; i < optarg.length(); ++i) { switch (optarg[i]) { case 'E': printTags_ |= Exiv2::mdExif; break; case 'I': printTags_ |= Exiv2::mdIptc; break; case 'X': printTags_ |= Exiv2::mdXmp; break; case 'x': printItems_ |= prTag; break; case 'g': printItems_ |= prGroup; break; case 'k': printItems_ |= prKey; break; case 'l': printItems_ |= prLabel; break; case 'n': printItems_ |= prName; break; case 'y': printItems_ |= prType; break; case 'c': printItems_ |= prCount; break; case 's': printItems_ |= prSize; break; case 'v': printItems_ |= prValue; break; case 't': printItems_ |= prTrans; break; case 'h': printItems_ |= prHex; break; default: std::cerr << progname() << ": " << _("Unrecognized print item") << " `" << optarg[i] << "'\n"; rc = 1; break; } } break; case Action::print: std::cerr << progname() << ": " << _("Ignoring surplus option -P") << optarg << "\n"; break; default: std::cerr << progname() << ": " << _("Option -P is not compatible with a previous option\n"); rc = 1; break; } return rc; } // Params::evalPrintFlags int Params::evalDelete(const std::string& optarg) { int rc = 0; switch (action_) { case Action::none: action_ = Action::erase; target_ = 0; // fallthrough case Action::erase: rc = parseCommonTargets(optarg, "erase"); if (rc > 0) { target_ |= rc; rc = 0; } else { rc = 1; } break; default: std::cerr << progname() << ": " << _("Option -d is not compatible with a previous option\n"); rc = 1; break; } return rc; } // Params::evalDelete int Params::evalExtract(const std::string& optarg) { int rc = 0; switch (action_) { case Action::none: case Action::modify: action_ = Action::extract; target_ = 0; // fallthrough case Action::extract: rc = parseCommonTargets(optarg, "extract"); if (rc > 0) { target_ |= rc; rc = 0; } else { rc = 1; } break; default: std::cerr << progname() << ": " << _("Option -e is not compatible with a previous option\n"); rc = 1; break; } return rc; } // Params::evalExtract int Params::evalInsert(const std::string& optarg) { int rc = 0; switch (action_) { case Action::none: case Action::modify: action_ = Action::insert; target_ = 0; // fallthrough case Action::insert: rc = parseCommonTargets(optarg, "insert"); if (rc > 0) { target_ |= rc; rc = 0; } else { rc = 1; } break; default: std::cerr << progname() << ": " << _("Option -i is not compatible with a previous option\n"); rc = 1; break; } return rc; } // Params::evalInsert int Params::evalModify(int opt, const std::string& optarg) { int rc = 0; switch (action_) { case Action::none: action_ = Action::modify; // fallthrough case Action::modify: case Action::extract: case Action::insert: if (opt == 'c') jpegComment_ = parseEscapes(optarg); if (opt == 'm') cmdFiles_.push_back(optarg); // parse the files later if (opt == 'M') cmdLines_.push_back(optarg); // parse the commands later break; default: std::cerr << progname() << ": " << _("Option") << " -" << (char)opt << " " << _("is not compatible with a previous option\n"); rc = 1; break; } return rc; } // Params::evalModify int Params::nonoption(const std::string& argv) { int rc = 0; bool action = false; if (first_) { // The first non-option argument must be the action first_ = false; if (argv == "ad" || argv == "adjust") { if (action_ != Action::none && action_ != Action::adjust) { std::cerr << progname() << ": " << _("Action adjust is not compatible with the given options\n"); rc = 1; } action = true; action_ = Action::adjust; } if (argv == "pr" || argv == "print") { if (action_ != Action::none && action_ != Action::print) { std::cerr << progname() << ": " << _("Action print is not compatible with the given options\n"); rc = 1; } action = true; action_ = Action::print; } if (argv == "rm" || argv == "delete") { if (action_ != Action::none && action_ != Action::erase) { std::cerr << progname() << ": " << _("Action delete is not compatible with the given options\n"); rc = 1; } action = true; action_ = Action::erase; } if (argv == "ex" || argv == "extract") { if ( action_ != Action::none && action_ != Action::extract && action_ != Action::modify) { std::cerr << progname() << ": " << _("Action extract is not compatible with the given options\n"); rc = 1; } action = true; action_ = Action::extract; } if (argv == "in" || argv == "insert") { if ( action_ != Action::none && action_ != Action::insert && action_ != Action::modify) { std::cerr << progname() << ": " << _("Action insert is not compatible with the given options\n"); rc = 1; } action = true; action_ = Action::insert; } if (argv == "mv" || argv == "rename") { if (action_ != Action::none && action_ != Action::rename) { std::cerr << progname() << ": " << _("Action rename is not compatible with the given options\n"); rc = 1; } action = true; action_ = Action::rename; } if (argv == "mo" || argv == "modify") { if (action_ != Action::none && action_ != Action::modify) { std::cerr << progname() << ": " << _("Action modify is not compatible with the given options\n"); rc = 1; } action = true; action_ = Action::modify; } if (argv == "fi" || argv == "fixiso") { if (action_ != Action::none && action_ != Action::fixiso) { std::cerr << progname() << ": " << _("Action fixiso is not compatible with the given options\n"); rc = 1; } action = true; action_ = Action::fixiso; } if (argv == "fc" || argv == "fixcom" || argv == "fixcomment") { if (action_ != Action::none && action_ != Action::fixcom) { std::cerr << progname() << ": " << _("Action fixcom is not compatible with the given options\n"); rc = 1; } action = true; action_ = Action::fixcom; } if (action_ == Action::none) { // if everything else fails, assume print as the default action action_ = Action::print; } } if (!action) { files_.push_back(argv); } return rc; } // Params::nonoption int Params::getopt(int argc, char* const argv[]) { int rc = Util::Getopt::getopt(argc, argv, optstring_); // Further consistency checks if (help_ || version_) return 0; if (action_ == Action::none) { // This shouldn't happen since print is taken as default action std::cerr << progname() << ": " << _("An action must be specified\n"); rc = 1; } if ( action_ == Action::adjust && !adjust_ && !yodAdjust_[yodYear].flag_ && !yodAdjust_[yodMonth].flag_ && !yodAdjust_[yodDay].flag_) { std::cerr << progname() << ": " << _("Adjust action requires at least one -a, -Y, -O or -D option\n"); rc = 1; } if ( action_ == Action::modify && cmdFiles_.empty() && cmdLines_.empty() && jpegComment_.empty()) { std::cerr << progname() << ": " << _("Modify action requires at least one -c, -m or -M option\n"); rc = 1; } if (0 == files_.size()) { std::cerr << progname() << ": " << _("At least one file is required\n"); rc = 1; } if (rc == 0 && !cmdFiles_.empty()) { // Parse command files if (!parseCmdFiles(modifyCmds_, cmdFiles_)) { std::cerr << progname() << ": " << _("Error parsing -m option arguments\n"); rc = 1; } } if (rc == 0 && !cmdLines_.empty()) { // Parse command lines if (!parseCmdLines(modifyCmds_, cmdLines_)) { std::cerr << progname() << ": " << _("Error parsing -M option arguments\n"); rc = 1; } } if (rc == 0 && (!cmdFiles_.empty() || !cmdLines_.empty())) { // We'll set them again, after reading the file Exiv2::XmpProperties::unregisterNs(); } if ( !directory_.empty() && !(action_ == Action::insert || action_ == Action::extract)) { std::cerr << progname() << ": " << _("-l option can only be used with extract or insert actions\n"); rc = 1; } if (!suffix_.empty() && !(action_ == Action::insert)) { std::cerr << progname() << ": " << _("-S option can only be used with insert action\n"); rc = 1; } if (timestamp_ && !(action_ == Action::rename)) { std::cerr << progname() << ": " << _("-t option can only be used with rename action\n"); rc = 1; } if (timestampOnly_ && !(action_ == Action::rename)) { std::cerr << progname() << ": " << _("-T option can only be used with rename action\n"); rc = 1; } return rc; } // Params::getopt // ***************************************************************************** // local implementations namespace { bool parseTime(const std::string& ts, long& time) { std::string hstr, mstr, sstr; char *cts = new char[ts.length() + 1]; strcpy(cts, ts.c_str()); char *tmp = ::strtok(cts, ":"); if (tmp) hstr = tmp; tmp = ::strtok(0, ":"); if (tmp) mstr = tmp; tmp = ::strtok(0, ":"); if (tmp) sstr = tmp; delete[] cts; int sign = 1; long hh(0), mm(0), ss(0); // [-]HH part if (!Util::strtol(hstr.c_str(), hh)) return false; if (hh < 0) { sign = -1; hh *= -1; } // check for the -0 special case if (hh == 0 && hstr.find('-') != std::string::npos) sign = -1; // MM part, if there is one if (mstr != "") { if (!Util::strtol(mstr.c_str(), mm)) return false; if (mm > 59) return false; if (mm < 0) return false; } // SS part, if there is one if (sstr != "") { if (!Util::strtol(sstr.c_str(), ss)) return false; if (ss > 59) return false; if (ss < 0) return false; } time = sign * (hh * 3600 + mm * 60 + ss); return true; } // parseTime int parseCommonTargets(const std::string& optarg, const std::string& action) { int rc = 0; int target = 0; for (size_t i = 0; rc == 0 && i < optarg.size(); ++i) { switch (optarg[i]) { case 'e': target |= Params::ctExif; break; case 'i': target |= Params::ctIptc; break; case 'x': target |= Params::ctXmp; break; case 'c': target |= Params::ctComment; break; case 't': target |= Params::ctThumb; break; case 'a': target |= Params::ctExif | Params::ctIptc | Params::ctComment | Params::ctXmp; break; case 'X': target |= Params::ctXmpSidecar; if (optarg == "X") target |= Params::ctExif | Params::ctIptc | Params::ctXmp; break; case 'p': { if (strcmp(action.c_str(), "extract") == 0) { i += (size_t) parsePreviewNumbers(Params::instance().previewNumbers_, optarg, (int) i + 1); target |= Params::ctPreview; break; } // fallthrough } default: std::cerr << Params::instance().progname() << ": " << _("Unrecognized ") << action << " " << _("target") << " `" << optarg[i] << "'\n"; rc = -1; break; } } return rc ? rc : target; } // parseCommonTargets int parsePreviewNumbers(Params::PreviewNumbers& previewNumbers, const std::string& optarg, int j) { size_t k = j; for (size_t i = j; i < optarg.size(); ++i) { std::ostringstream os; for (k = i; k < optarg.size() && isdigit(optarg[k]); ++k) { os << optarg[k]; } if (k > i) { bool ok = false; int num = Exiv2::stringTo(os.str(), ok); if (ok && num >= 0) { previewNumbers.insert(num); } else { std::cerr << Params::instance().progname() << ": " << _("Invalid preview number") << ": " << num << "\n"; } i = k; } if (!(k < optarg.size() && optarg[i] == ',')) break; } int ret = static_cast(k - j); if (ret == 0) { previewNumbers.insert(0); } #ifdef DEBUG std::cout << "\nThe set now contains: "; for (Params::PreviewNumbers::const_iterator i = previewNumbers.begin(); i != previewNumbers.end(); ++i) { std::cout << *i << ", "; } std::cout << std::endl; #endif return (int) (k - j); } // parsePreviewNumbers bool parseCmdFiles(ModifyCmds& modifyCmds, const Params::CmdFiles& cmdFiles) { Params::CmdFiles::const_iterator end = cmdFiles.end(); Params::CmdFiles::const_iterator filename = cmdFiles.begin(); for ( ; filename != end; ++filename) { try { std::ifstream file(filename->c_str()); if (!file) { std::cerr << *filename << ": " << _("Failed to open command file for reading\n"); return false; } int num = 0; std::string line; while (std::getline(file, line)) { ModifyCmd modifyCmd; if (parseLine(modifyCmd, line, ++num)) { modifyCmds.push_back(modifyCmd); } } } catch (const Exiv2::AnyError& error) { std::cerr << *filename << ", " << _("line") << " " << error << "\n"; return false; } } return true; } // parseCmdFile bool parseCmdLines(ModifyCmds& modifyCmds, const Params::CmdLines& cmdLines) { try { int num = 0; Params::CmdLines::const_iterator end = cmdLines.end(); Params::CmdLines::const_iterator line = cmdLines.begin(); for ( ; line != end; ++line) { ModifyCmd modifyCmd; if (parseLine(modifyCmd, *line, ++num)) { modifyCmds.push_back(modifyCmd); } } return true; } catch (const Exiv2::AnyError& error) { std::cerr << _("-M option") << " " << error << "\n"; return false; } } // parseCmdLines bool parseLine(ModifyCmd& modifyCmd, const std::string& line, int num) { const std::string delim = " \t"; // Skip empty lines and comments std::string::size_type cmdStart = line.find_first_not_of(delim); if (cmdStart == std::string::npos || line[cmdStart] == '#') return false; // Get command and key std::string::size_type cmdEnd = line.find_first_of(delim, cmdStart+1); std::string::size_type keyStart = line.find_first_not_of(delim, cmdEnd+1); std::string::size_type keyEnd = line.find_first_of(delim, keyStart+1); if ( cmdStart == std::string::npos || cmdEnd == std::string::npos || keyStart == std::string::npos) { throw Exiv2::Error(1, Exiv2::toString(num) + ": " + _("Invalid command line")); } std::string cmd(line.substr(cmdStart, cmdEnd-cmdStart)); CmdId cmdId = commandId(cmd); if (cmdId == invalidCmdId) { throw Exiv2::Error(1, Exiv2::toString(num) + ": " + _("Invalid command") + " `" + cmd + "'"); } Exiv2::TypeId defaultType = Exiv2::invalidTypeId; std::string key(line.substr(keyStart, keyEnd-keyStart)); MetadataId metadataId = invalidMetadataId; if (cmdId != reg) { try { Exiv2::IptcKey iptcKey(key); metadataId = iptc; defaultType = Exiv2::IptcDataSets::dataSetType(iptcKey.tag(), iptcKey.record()); } catch (const Exiv2::AnyError&) {} if (metadataId == invalidMetadataId) { try { Exiv2::ExifKey exifKey(key); metadataId = exif; defaultType = exifKey.defaultTypeId(); } catch (const Exiv2::AnyError&) {} } if (metadataId == invalidMetadataId) { try { Exiv2::XmpKey xmpKey(key); metadataId = xmp; defaultType = Exiv2::XmpProperties::propertyType(xmpKey); } catch (const Exiv2::AnyError&) {} } if (metadataId == invalidMetadataId) { throw Exiv2::Error(1, Exiv2::toString(num) + ": " + _("Invalid key") + " `" + key + "'"); } } std::string value; Exiv2::TypeId type = defaultType; bool explicitType = false; if (cmdId != del) { // Get type and value std::string::size_type typeStart = std::string::npos; if (keyEnd != std::string::npos) typeStart = line.find_first_not_of(delim, keyEnd+1); std::string::size_type typeEnd = std::string::npos; if (typeStart != std::string::npos) typeEnd = line.find_first_of(delim, typeStart+1); std::string::size_type valStart = typeStart; std::string::size_type valEnd = std::string::npos; if (valStart != std::string::npos) valEnd = line.find_last_not_of(delim); if ( cmdId == reg && ( keyEnd == std::string::npos || valStart == std::string::npos)) { throw Exiv2::Error(1, Exiv2::toString(num) + ": " + _("Invalid command line") + " " ); } if ( cmdId != reg && typeStart != std::string::npos && typeEnd != std::string::npos) { std::string typeStr(line.substr(typeStart, typeEnd-typeStart)); Exiv2::TypeId tmpType = Exiv2::TypeInfo::typeId(typeStr); if (tmpType != Exiv2::invalidTypeId) { valStart = line.find_first_not_of(delim, typeEnd+1); if (valStart == std::string::npos) { throw Exiv2::Error(1, Exiv2::toString(num) + ": " + _("Invalid command line") + " " ); } type = tmpType; explicitType = true; } } if (valStart != std::string::npos) { value = parseEscapes(line.substr(valStart, valEnd+1-valStart)); std::string::size_type last = value.length()-1; if ( (value[0] == '"' && value[last] == '"') || (value[0] == '\'' && value[last] == '\'')) { value = value.substr(1, value.length()-2); } } } modifyCmd.cmdId_ = cmdId; modifyCmd.key_ = key; modifyCmd.metadataId_ = metadataId; modifyCmd.typeId_ = type; modifyCmd.explicitType_ = explicitType; modifyCmd.value_ = value; if (cmdId == reg) { // Registration needs to be done immediately as the new namespaces are // looked up during parsing of subsequent lines (to validate XMP keys). Exiv2::XmpProperties::registerNs(modifyCmd.value_, modifyCmd.key_); } return true; } // parseLine CmdId commandId(const std::string& cmdString) { int i = 0; for (; cmdIdAndString[i].cmdId_ != invalidCmdId && cmdIdAndString[i].cmdString_ != cmdString; ++i) {} return cmdIdAndString[i].cmdId_; } std::string parseEscapes(const std::string& input) { std::string result = ""; for (unsigned int i = 0; i < input.length(); ++i) { char ch = input[i]; if (ch != '\\') { result.push_back(ch); continue; } int escapeStart = i; if (!(input.length() - 1 > i)) { result.push_back(ch); continue; } ++i; ch = input[i]; switch (ch) { case '\\': // Escaping of backslash result.push_back('\\'); break; case 'r': // Escaping of carriage return result.push_back('\r'); break; case 'n': // Escaping of newline result.push_back('\n'); break; case 't': // Escaping of tab result.push_back('\t'); break; case 'u': // Escaping of unicode if (input.length() - 4 > i) { int acc = 0; for (int j = 0; j < 4; ++j) { ++i; acc <<= 4; if (input[i] >= '0' && input[i] <= '9') { acc |= input[i] - '0'; } else if (input[i] >= 'a' && input[i] <= 'f') { acc |= input[i] - 'a' + 10; } else if (input[i] >= 'A' && input[i] <= 'F') { acc |= input[i] - 'A' + 10; } else { acc = -1; break; } } if (acc == -1) { result.push_back('\\'); i = escapeStart; break; } std::string ucs2toUtf8 = ""; ucs2toUtf8.push_back((char) ((acc & 0xff00) >> 8)); ucs2toUtf8.push_back((char) (acc & 0x00ff)); if (Exiv2::convertStringCharset (ucs2toUtf8, "UCS-2BE", "UTF-8")) { result.append (ucs2toUtf8); } } else { result.push_back('\\'); result.push_back(ch); } break; default: result.push_back('\\'); result.push_back(ch); } } return result; } } exiv2-0.23/src/minoltamn.cpp0000644000175000017500000031264211732641407015615 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /* File: minoltamn.cpp Version: $Rev: 2681 $ Author(s): Gilles Caulier (cgilles) Andreas Huggel (ahu) History: 06-May-06, gc: submitted Credits: See header file. */ // ***************************************************************************** #include "rcsid_int.hpp" EXIV2_RCSID("@(#) $Id: minoltamn.cpp 2681 2012-03-22 15:19:35Z ahuggel $") // ***************************************************************************** // included header files #include "minoltamn_int.hpp" #include "tags_int.hpp" #include "value.hpp" #include "i18n.h" // NLS support. #include #include #include #include #include // ***************************************************************************** // class member definitions namespace Exiv2 { namespace Internal { // -- Standard Minolta Makernotes tags --------------------------------------------------------------- //! Lookup table to translate Minolta color mode values to readable labels extern const TagDetails minoltaColorMode[] = { { 0, N_("Natural Color") }, { 1, N_("Black & White") }, { 2, N_("Vivid Color") }, { 3, N_("Solarization") }, { 4, N_("AdobeRGB") }, { 5, N_("Sepia") }, { 9, N_("Natural") }, { 12, N_("Portrait") }, { 13, N_("Natural sRGB") }, { 14, N_("Natural+ sRGB") }, { 15, N_("Landscape") }, { 16, N_("Evening") }, { 17, N_("Night Scene") }, { 18, N_("Night Portrait") } }; //! Lookup table to translate Minolta image quality values to readable labels extern const TagDetails minoltaImageQuality[] = { { 0, N_("Raw") }, { 1, N_("Super Fine") }, { 2, N_("Fine") }, { 3, N_("Standard") }, { 4, N_("Economy") }, { 5, N_("Extra Fine") } }; //! Lookup table to translate Minolta image stabilization values extern const TagDetails minoltaImageStabilization[] = { { 1, N_("Off") }, { 5, N_("On") } }; // Minolta Tag Info const TagInfo MinoltaMakerNote::tagInfo_[] = { TagInfo(0x0000, "Version", N_("Makernote Version"), N_("String 'MLT0' (not null terminated)"), minoltaId, makerTags, undefined, -1, printValue), TagInfo(0x0001, "CameraSettingsStdOld", N_("Camera Settings (Std Old)"), N_("Standard Camera settings (Old Camera models like D5, D7, S304, and S404)"), minoltaId, makerTags, undefined, -1, printValue), TagInfo(0x0003, "CameraSettingsStdNew", N_("Camera Settings (Std New)"), N_("Standard Camera settings (New Camera Models like D7u, D7i, and D7hi)"), minoltaId, makerTags, undefined, -1, printValue), TagInfo(0x0004, "CameraSettings7D", N_("Camera Settings (7D)"), N_("Camera Settings (for Dynax 7D model)"), minoltaId, makerTags, undefined, -1, printValue), TagInfo(0x0018, "ImageStabilizationData", N_("Image Stabilization Data"), N_("Image stabilization data"), minoltaId, makerTags, undefined, -1, printValue), // TODO: Implement WB Info A100 tags decoding. TagInfo(0x0020, "WBInfoA100", N_("WB Info A100"), N_("White balance information for the Sony DSLR-A100"), minoltaId, makerTags, undefined, -1, printValue), TagInfo(0x0040, "CompressedImageSize", N_("Compressed Image Size"), N_("Compressed image size"), minoltaId, makerTags, unsignedLong, -1, printValue), TagInfo(0x0081, "Thumbnail", N_("Thumbnail"), N_("Jpeg thumbnail 640x480 pixels"), minoltaId, makerTags, undefined, -1, printValue), TagInfo(0x0088, "ThumbnailOffset", N_("Thumbnail Offset"), N_("Offset of the thumbnail"), minoltaId, makerTags, unsignedLong, -1, printValue), TagInfo(0x0089, "ThumbnailLength", N_("Thumbnail Length"), N_("Size of the thumbnail"), minoltaId, makerTags, unsignedLong, -1, printValue), TagInfo(0x0100, "SceneMode", N_("Scene Mode"), N_("Scene Mode"), minoltaId, makerTags, unsignedLong, -1, printMinoltaSonySceneMode), // TODO: for A100, use Sony table from printMinoltaSonyColorMode(). TagInfo(0x0101, "ColorMode", N_("Color Mode"), N_("Color mode"), minoltaId, makerTags, unsignedLong, -1, EXV_PRINT_TAG(minoltaColorMode)), TagInfo(0x0102, "Quality", N_("Image Quality"), N_("Image quality"), minoltaId, makerTags, unsignedLong, -1, printMinoltaSonyImageQuality), // TODO: Tag 0x0103 : quality or image size (see ExifTool doc). TagInfo(0x0103, "0x0103", N_("0x0103"), N_("0x0103"), minoltaId, makerTags, unsignedLong, -1, printValue), TagInfo(0x0104, "FlashExposureComp", N_("Flash Exposure Compensation"), N_("Flash exposure compensation in EV"), minoltaId, makerTags, signedRational, -1, print0x9204), TagInfo(0x0105, "Teleconverter", N_("Teleconverter Model"), N_("Teleconverter Model"), minoltaId, makerTags, unsignedLong, -1, printMinoltaSonyTeleconverterModel), TagInfo(0x0107, "ImageStabilization", N_("Image Stabilization"), N_("Image stabilization"), minoltaId, makerTags, unsignedLong, -1, EXV_PRINT_TAG(minoltaImageStabilization)), TagInfo(0x0109, "RawAndJpgRecording", N_("RAW+JPG Recording"), N_("RAW and JPG files recording"), minoltaId, makerTags, unsignedLong, -1, printMinoltaSonyBoolValue), TagInfo(0x010a, "ZoneMatching", N_("Zone Matching"), N_("Zone matching"), minoltaId, makerTags, unsignedLong, -1, printMinoltaSonyZoneMatching), TagInfo(0x010b, "ColorTemperature", N_("Color Temperature"), N_("Color temperature"), minoltaId, makerTags, unsignedLong, -1, printValue), TagInfo(0x010c, "LensID", N_("Lens ID"), N_("Lens identifier"), minoltaId, makerTags, unsignedLong, -1, printMinoltaSonyLensID), TagInfo(0x0111, "ColorCompensationFilter", N_("Color Compensation Filter"), N_("Color Compensation Filter: negative is green, positive is magenta"), minoltaId, makerTags, unsignedLong, -1, printValue), TagInfo(0x0112, "WhiteBalanceFineTune", N_("White Balance Fine Tune"), N_("White Balance Fine Tune Value"), minoltaId, makerTags, unsignedLong, -1, printValue), TagInfo(0x0113, "ImageStabilizationA100", N_("Image Stabilization A100"), N_("Image Stabilization for the Sony DSLR-A100"), minoltaId, makerTags, unsignedLong, -1, printMinoltaSonyBoolValue), // TODO: implement CameraSettingsA100 tags decoding. TagInfo(0x0114, "CameraSettings5D", N_("Camera Settings (5D)"), N_("Camera Settings (for Dynax 5D model)"), minoltaId, makerTags, undefined, -1, printValue), TagInfo(0x0115, "WhiteBalance", N_("White Balance"), N_("White balance"), minoltaId, makerTags, unsignedLong, -1, printMinoltaSonyWhiteBalanceStd), TagInfo(0x0e00, "PrintIM", N_("Print IM"), N_("PrintIM information"), minoltaId, makerTags, undefined, -1, printValue), TagInfo(0x0f00, "CameraSettingsZ1", N_("Camera Settings (Z1)"), N_("Camera Settings (for Z1, DImage X, and F100 models)"), minoltaId, makerTags, undefined, -1, printValue), // End of list marker TagInfo(0xffff, "(UnknownMinoltaMakerNoteTag)", "(UnknownMinoltaMakerNoteTag)", N_("Unknown Minolta MakerNote tag"), minoltaId, makerTags, asciiString, -1, printValue) }; const TagInfo* MinoltaMakerNote::tagList() { return tagInfo_; } // -- Standard Minolta camera settings --------------------------------------------------------------- //! Lookup table to translate Minolta Std camera settings exposure mode values to readable labels extern const TagDetails minoltaExposureModeStd[] = { { 0, N_("Program") }, { 1, N_("Aperture priority") }, { 2, N_("Shutter priority") }, { 3, N_("Manual") } }; //! Lookup table to translate Minolta Std camera settings flash mode values to readable labels extern const TagDetails minoltaFlashModeStd[] = { { 0, N_("Fill flash") }, { 1, N_("Red-eye reduction") }, { 2, N_("Rear flash sync") }, { 3, N_("Wireless") }, { 4, N_("Off") } }; //! Lookup table to translate Minolta Std camera settings white balance values to readable labels extern const TagDetails minoltaWhiteBalanceStd[] = { { 0, N_("Auto") }, { 1, N_("Daylight") }, { 2, N_("Cloudy") }, { 3, N_("Tungsten") }, { 5, N_("Custom") }, { 7, N_("Fluorescent") }, { 8, N_("Fluorescent 2") }, { 11, N_("Custom 2") }, { 12, N_("Custom 3") } }; //! Lookup table to translate Minolta Std camera settings image size values to readable labels extern const TagDetails minoltaImageSizeStd[] = { { 0, N_("Full size") }, { 1, "1600x1200" }, { 2, "1280x960" }, { 3, "640x480" }, { 6, "2080x1560" }, { 7, "2560x1920" }, { 8, "3264x2176" } }; //! Lookup table to translate Minolta Std camera settings image quality values to readable labels extern const TagDetails minoltaImageQualityStd[] = { { 0, N_("Raw") }, { 1, N_("Super fine") }, { 2, N_("Fine") }, { 3, N_("Standard") }, { 4, N_("Economy") }, { 5, N_("Extra fine") } }; //! Lookup table to translate Minolta Std camera settings drive mode values to readable labels extern const TagDetails minoltaDriveModeStd[] = { { 0, N_("Single Frame") }, { 1, N_("Continuous") }, { 2, N_("Self-timer") }, { 4, N_("Bracketing") }, { 5, N_("Interval") }, { 6, N_("UHS continuous") }, { 7, N_("HS continuous") } }; //! Lookup table to translate Minolta Std camera settings metering mode values to readable labels extern const TagDetails minoltaMeteringModeStd[] = { { 0, N_("Multi-segment") }, { 1, N_("Center weighted average") }, { 2, N_("Spot") } }; //! Lookup table to translate Minolta Std camera settings digital zoom values to readable labels extern const TagDetails minoltaDigitalZoomStd[] = { { 0, N_("Off") }, { 1, N_("Electronic magnification") }, { 2, "2x" } }; //! Lookup table to translate Minolta Std camera bracket step mode values to readable labels extern const TagDetails minoltaBracketStepStd[] = { { 0, "1/3 EV" }, { 1, "2/3 EV" }, { 2, "1 EV" } }; //! Lookup table to translate Minolta Std camera settings AF points values to readable labels extern const TagDetails minoltaAFPointsStd[] = { { 0, N_("Center") }, { 1, N_("Top") }, { 2, N_("Top-right") }, { 3, N_("Right") }, { 4, N_("Bottom-right") }, { 5, N_("Bottom") }, { 6, N_("Bottom-left") }, { 7, N_("Left") }, { 8, N_("Top-left") } }; //! Lookup table to translate Minolta Std camera settings flash fired values to readable labels extern const TagDetails minoltaFlashFired[] = { { 0, N_("Did not fire") }, { 1, N_("Fired") } }; //! Lookup table to translate Minolta Std camera settings sharpness values to readable labels extern const TagDetails minoltaSharpnessStd[] = { { 0, N_("Hard") }, { 1, N_("Normal") }, { 2, N_("Soft") } }; //! Lookup table to translate Minolta Std camera settings subject program values to readable labels extern const TagDetails minoltaSubjectProgramStd[] = { { 0, N_("None") }, { 1, N_("Portrait") }, { 2, N_("Text") }, { 3, N_("Night portrait") }, { 4, N_("Sunset") }, { 5, N_("Sports action") } }; //! Lookup table to translate Minolta Std camera settings ISO settings values to readable labels extern const TagDetails minoltaISOSettingStd[] = { { 0, "100" }, { 1, "200" }, { 2, "400" }, { 3, "800" }, { 4, N_("Auto") }, { 5, "64" } }; //! Lookup table to translate Minolta Std camera settings model values to readable labels extern const TagDetails minoltaModelStd[] = { { 0, "DiMAGE 7 | X1 | X21 | X31" }, { 1, "DiMAGE 5" }, { 2, "DiMAGE S304" }, { 3, "DiMAGE S404" }, { 4, "DiMAGE 7i" }, { 5, "DiMAGE 7Hi" }, { 6, "DiMAGE A1" }, { 7, "DiMAGE A2 | S414" }, { 7, "DiMAGE A2 | S414" } // To silence compiler warning }; //! Lookup table to translate Minolta Std camera settings interval mode values to readable labels extern const TagDetails minoltaIntervalModeStd[] = { { 0, N_("Still image") }, { 1, N_("Time-lapse movie") } }; //! Lookup table to translate Minolta Std camera settings folder name values to readable labels extern const TagDetails minoltaFolderNameStd[] = { { 0, N_("Standard form") }, { 1, N_("Data form") } }; //! Lookup table to translate Minolta Std camera settings color mode values to readable labels extern const TagDetails minoltaColorModeStd[] = { { 0, N_("Natural color") }, { 1, N_("Black and white") }, { 2, N_("Vivid color") }, { 3, N_("Solarization") }, { 4, N_("Adobe RGB") } }; //! Lookup table to translate Minolta Std camera settings wide focus zone values to readable labels extern const TagDetails minoltaWideFocusZoneStd[] = { { 0, N_("No zone") }, { 1, N_("Center zone (horizontal orientation)") }, { 1, N_("Center zone (vertical orientation)") }, { 1, N_("Left zone") }, { 4, N_("Right zone") } }; //! Lookup table to translate Minolta Std camera settings focus mode values to readable labels extern const TagDetails minoltaFocusModeStd[] = { { 0, N_("Auto focus") }, { 1, N_("Manual focus") } }; //! Lookup table to translate Minolta Std camera settings focus area values to readable labels extern const TagDetails minoltaFocusAreaStd[] = { { 0, N_("Wide focus (normal)") }, { 1, N_("Spot focus") } }; //! Lookup table to translate Minolta Std camera settings DEC switch position values to readable labels extern const TagDetails minoltaDECPositionStd[] = { { 0, N_("Exposure") }, { 1, N_("Contrast") }, { 2, N_("Saturation") }, { 3, N_("Filter") } }; //! Lookup table to translate Minolta Std camera settings color profile values to readable labels extern const TagDetails minoltaColorProfileStd[] = { { 0, N_("Not embedded") }, { 1, N_("Embedded") } }; //! Lookup table to translate Minolta Std camera settings data Imprint values to readable labels extern const TagDetails minoltaDataImprintStd[] = { { 0, N_("None") }, { 1, "YYYY/MM/DD" }, { 2, "MM/DD/HH:MM" }, { 3, N_("Text") }, { 4, N_("Text + ID#") } }; //! Lookup table to translate Minolta Std camera settings flash metering values to readable labels extern const TagDetails minoltaFlashMeteringStd[] = { { 0, N_("ADI (Advanced Distance Integration)") }, { 1, N_("Pre-flash TTl") }, { 2, N_("Manual flash control") } }; std::ostream& MinoltaMakerNote::printMinoltaExposureSpeedStd(std::ostream& os, const Value& value, const ExifData*) { // From the PHP JPEG Metadata Toolkit os << (value.toLong()/8)-1; return os; } std::ostream& MinoltaMakerNote::printMinoltaExposureTimeStd(std::ostream& os, const Value& value, const ExifData*) { // From the PHP JPEG Metadata Toolkit os << (value.toLong()/8)-6; return os; } std::ostream& MinoltaMakerNote::printMinoltaFNumberStd(std::ostream& os, const Value& value, const ExifData*) { // From the PHP JPEG Metadata Toolkit os << (value.toLong()/8)-1; return os; } std::ostream& MinoltaMakerNote::printMinoltaExposureCompensationStd(std::ostream& os, const Value& value, const ExifData*) { // From the PHP JPEG Metadata Toolkit os << value.toLong()/256; return os; } std::ostream& MinoltaMakerNote::printMinoltaFocalLengthStd(std::ostream& os, const Value& value, const ExifData*) { // From the PHP JPEG Metadata Toolkit os << (value.toLong()/3)-2; return os; } std::ostream& MinoltaMakerNote::printMinoltaDateStd(std::ostream& os, const Value& value, const ExifData*) { // From the PHP JPEG Metadata Toolkit os << value.toLong() / 65536 << ":" << std::right << std::setw(2) << std::setfill('0') << (value.toLong() - value.toLong() / 65536 * 65536) / 256 << ":" << std::right << std::setw(2) << std::setfill('0') << value.toLong() % 256; return os; } std::ostream& MinoltaMakerNote::printMinoltaTimeStd(std::ostream& os, const Value& value, const ExifData*) { // From the PHP JPEG Metadata Toolkit os << std::right << std::setw(2) << std::setfill('0') << value.toLong() / 65536 << ":" << std::right << std::setw(2) << std::setfill('0') << (value.toLong() - value.toLong() / 65536 * 65536) / 256 << ":" << std::right << std::setw(2) << std::setfill('0') << value.toLong() % 256; return os; } std::ostream& MinoltaMakerNote::printMinoltaFlashExposureCompStd(std::ostream& os, const Value& value, const ExifData*) { // From the PHP JPEG Metadata Toolkit os << (value.toLong()-6)/3; return os; } std::ostream& MinoltaMakerNote::printMinoltaWhiteBalanceStd(std::ostream& os, const Value& value, const ExifData*) { // From the PHP JPEG Metadata Toolkit os << value.toLong()/256; return os; } std::ostream& MinoltaMakerNote::printMinoltaBrightnessStd(std::ostream& os, const Value& value, const ExifData*) { // From the PHP JPEG Metadata Toolkit os << (value.toLong()/8)-6; return os; } // Minolta Standard Camera Settings Tag Info (Old and New) const TagInfo MinoltaMakerNote::tagInfoCsStd_[] = { TagInfo(0x0001, "ExposureMode", N_("Exposure Mode"), N_("Exposure mode"), minoltaCsNewId, makerTags, unsignedLong, 1, EXV_PRINT_TAG(minoltaExposureModeStd)), TagInfo(0x0002, "FlashMode", N_("Flash Mode"), N_("Flash mode"), minoltaCsNewId, makerTags, unsignedLong, 1, EXV_PRINT_TAG(minoltaFlashModeStd)), TagInfo(0x0003, "WhiteBalance", N_("White Balance"), N_("White balance"), minoltaCsNewId, makerTags, unsignedLong, 1, EXV_PRINT_TAG(minoltaWhiteBalanceStd)), TagInfo(0x0004, "ImageSize", N_("Image Size"), N_("Image size"), minoltaCsNewId, makerTags, unsignedLong, 1, EXV_PRINT_TAG(minoltaImageSizeStd)), TagInfo(0x0005, "Quality", N_("Image Quality"), N_("Image quality"), minoltaCsNewId, makerTags, unsignedLong, 1, EXV_PRINT_TAG(minoltaImageQualityStd)), TagInfo(0x0006, "DriveMode", N_("Drive Mode"), N_("Drive mode"), minoltaCsNewId, makerTags, unsignedLong, 1, EXV_PRINT_TAG(minoltaDriveModeStd)), TagInfo(0x0007, "MeteringMode", N_("Metering Mode"), N_("Metering mode"), minoltaCsNewId, makerTags, unsignedLong, 1, EXV_PRINT_TAG(minoltaMeteringModeStd)), TagInfo(0x0008, "ISO", N_("ISO"), N_("ISO Value"), minoltaCsNewId, makerTags, unsignedLong, 1, printMinoltaExposureSpeedStd), TagInfo(0x0009, "ExposureTime", N_("Exposure Time"), N_("Exposure time"), minoltaCsNewId, makerTags, unsignedLong, 1, printMinoltaExposureTimeStd), TagInfo(0x000A, "FNumber", N_("FNumber"), N_("The F-Number"), minoltaCsNewId, makerTags, unsignedLong, 1, printMinoltaFNumberStd), TagInfo(0x000B, "MacroMode", N_("Macro Mode"), N_("Macro mode"), minoltaCsNewId, makerTags, unsignedLong, 1, printMinoltaSonyBoolValue), TagInfo(0x000C, "DigitalZoom", N_("Digital Zoom"), N_("Digital zoom"), minoltaCsNewId, makerTags, unsignedLong, 1, EXV_PRINT_TAG(minoltaDigitalZoomStd)), TagInfo(0x000D, "ExposureCompensation", N_("Exposure Compensation"), N_("Exposure compensation"), minoltaCsNewId, makerTags, unsignedLong, 1, printMinoltaExposureCompensationStd), TagInfo(0x000E, "BracketStep", N_("Bracket Step"), N_("Bracket step"), minoltaCsNewId, makerTags, unsignedLong, 1, EXV_PRINT_TAG(minoltaBracketStepStd)), TagInfo(0x0010, "IntervalLength", N_("Interval Length"), N_("Interval length"), minoltaCsNewId, makerTags, unsignedLong, 1, printValue), TagInfo(0x0011, "IntervalNumber", N_("Interval Number"), N_("Interval number"), minoltaCsNewId, makerTags, unsignedLong, 1, printValue), TagInfo(0x0012, "FocalLength", N_("Focal Length"), N_("Focal length"), minoltaCsNewId, makerTags, unsignedLong, 1, printMinoltaFocalLengthStd), TagInfo(0x0013, "FocusDistance", N_("Focus Distance"), N_("Focus distance"), minoltaCsNewId, makerTags, unsignedLong, 1, printValue), TagInfo(0x0014, "FlashFired", N_("Flash Fired"), N_("Flash fired"), minoltaCsNewId, makerTags, unsignedLong, 1, EXV_PRINT_TAG(minoltaFlashFired)), TagInfo(0x0015, "MinoltaDate", N_("Minolta Date"), N_("Minolta date"), minoltaCsNewId, makerTags, unsignedLong, 1, printMinoltaDateStd), TagInfo(0x0016, "MinoltaTime", N_("Minolta Time"), N_("Minolta time"), minoltaCsNewId, makerTags, unsignedLong, 1, printMinoltaTimeStd), TagInfo(0x0017, "MaxAperture", N_("Max Aperture"), N_("Max aperture"), minoltaCsNewId, makerTags, unsignedLong, 1, printValue), TagInfo(0x001A, "FileNumberMemory", N_("File Number Memory"), N_("File number memory"), minoltaCsNewId, makerTags, unsignedLong, 1, printMinoltaSonyBoolValue), TagInfo(0x001B, "LastFileNumber", N_("Last Image Number"), N_("Last image number"), minoltaCsNewId, makerTags, unsignedLong, 1, printValue), TagInfo(0x001C, "ColorBalanceRed", N_("Color Balance Red"), N_("Color balance red"), minoltaCsNewId, makerTags, unsignedLong, 1, printMinoltaWhiteBalanceStd), TagInfo(0x001D, "ColorBalanceGreen", N_("Color Balance Green"), N_("Color balance green"), minoltaCsNewId, makerTags, unsignedLong, 1, printMinoltaWhiteBalanceStd), TagInfo(0x001E, "ColorBalanceBlue", N_("Color Balance Blue"), N_("Color balance blue"), minoltaCsNewId, makerTags, unsignedLong, 1, printMinoltaWhiteBalanceStd), TagInfo(0x001F, "Saturation", N_("Saturation"), N_("Saturation"), minoltaCsNewId, makerTags, unsignedLong, 1, printValue), TagInfo(0x0020, "Contrast", N_("Contrast"), N_("Contrast"), minoltaCsNewId, makerTags, unsignedLong, 1, printValue), TagInfo(0x0021, "Sharpness", N_("Sharpness"), N_("Sharpness"), minoltaCsNewId, makerTags, unsignedLong, 1, EXV_PRINT_TAG(minoltaSharpnessStd)), TagInfo(0x0022, "SubjectProgram", N_("Subject Program"), N_("Subject program"), minoltaCsNewId, makerTags, unsignedLong, 1, EXV_PRINT_TAG(minoltaSubjectProgramStd)), TagInfo(0x0023, "FlashExposureComp", N_("Flash Exposure Compensation"), N_("Flash exposure compensation in EV"), minoltaCsNewId, makerTags, unsignedLong, 1, printMinoltaFlashExposureCompStd), TagInfo(0x0024, "ISOSetting", N_("ISO Settings"), N_("ISO setting"), minoltaCsNewId, makerTags, unsignedLong, 1, EXV_PRINT_TAG(minoltaISOSettingStd)), TagInfo(0x0025, "MinoltaModel", N_("Minolta Model"), N_("Minolta model"), minoltaCsNewId, makerTags, unsignedLong, 1, EXV_PRINT_TAG(minoltaModelStd)), TagInfo(0x0026, "IntervalMode", N_("Interval Mode"), N_("Interval mode"), minoltaCsNewId, makerTags, unsignedLong, 1, EXV_PRINT_TAG(minoltaIntervalModeStd)), TagInfo(0x0027, "FolderName", N_("Folder Name"), N_("Folder name"), minoltaCsNewId, makerTags, unsignedLong, 1, EXV_PRINT_TAG(minoltaFolderNameStd)), TagInfo(0x0028, "ColorMode", N_("ColorMode"), N_("ColorMode"), minoltaCsNewId, makerTags, unsignedLong, 1, EXV_PRINT_TAG(minoltaColorModeStd)), TagInfo(0x0029, "ColorFilter", N_("Color Filter"), N_("Color filter"), minoltaCsNewId, makerTags, unsignedLong, 1, printValue), TagInfo(0x002A, "BWFilter", N_("Black and White Filter"), N_("Black and white filter"), minoltaCsNewId, makerTags, unsignedLong, 1, printValue), TagInfo(0x002B, "Internal Flash", N_("Internal Flash"), N_("Internal Flash"), minoltaCsNewId, makerTags, unsignedLong, 1, EXV_PRINT_TAG(minoltaFlashFired)), TagInfo(0x002C, "Brightness", N_("Brightness"), N_("Brightness"), minoltaCsNewId, makerTags, unsignedLong, 1, printMinoltaBrightnessStd), TagInfo(0x002D, "SpotFocusPointX", N_("Spot Focus Point X"), N_("Spot focus point X"), minoltaCsNewId, makerTags, unsignedLong, 1, printValue), TagInfo(0x002E, "SpotFocusPointY", N_("Spot Focus Point Y"), N_("Spot focus point Y"), minoltaCsNewId, makerTags, unsignedLong, 1, printValue), TagInfo(0x002F, "WideFocusZone", N_("Wide Focus Zone"), N_("Wide focus zone"), minoltaCsNewId, makerTags, unsignedLong, 1, EXV_PRINT_TAG(minoltaWideFocusZoneStd)), TagInfo(0x0030, "FocusMode", N_("Focus Mode"), N_("Focus mode"), minoltaCsNewId, makerTags, unsignedLong, 1, EXV_PRINT_TAG(minoltaFocusModeStd)), TagInfo(0x0031, "FocusArea", N_("Focus area"), N_("Focus area"), minoltaCsNewId, makerTags, unsignedLong, 1, EXV_PRINT_TAG(minoltaFocusAreaStd)), TagInfo(0x0032, "DECPosition", N_("DEC Switch Position"), N_("DEC switch position"), minoltaCsNewId, makerTags, unsignedLong, 1, EXV_PRINT_TAG(minoltaDECPositionStd)), TagInfo(0x0033, "ColorProfile", N_("Color Profile"), N_("Color profile"), minoltaCsNewId, makerTags, unsignedLong, 1, EXV_PRINT_TAG(minoltaColorProfileStd)), TagInfo(0x0034, "DataImprint", N_("Data Imprint"), N_("Data Imprint"), minoltaCsNewId, makerTags, unsignedLong, 1, EXV_PRINT_TAG(minoltaDataImprintStd)), TagInfo(0x003F, "FlashMetering", N_("Flash Metering"), N_("Flash metering"), minoltaCsNewId, makerTags, unsignedLong, 1, EXV_PRINT_TAG(minoltaFlashMeteringStd)), // End of list marker TagInfo(0xffff, "(UnknownMinoltaCsStdTag)", "(UnknownMinoltaCsStdTag)", N_("Unknown Minolta Camera Settings tag"), minoltaCsNewId, makerTags, unsignedLong, 1, printValue) }; const TagInfo* MinoltaMakerNote::tagListCsStd() { return tagInfoCsStd_; } // -- Minolta Dynax 7D camera settings --------------------------------------------------------------- //! Lookup table to translate Minolta Dynax 7D camera settings exposure mode values to readable labels extern const TagDetails minoltaExposureMode7D[] = { { 0, N_("Program") }, { 1, N_("Aperture priority") }, { 2, N_("Shutter priority") }, { 3, N_("Manual") }, { 4, N_("Auto") }, { 5, N_("Program-shift A") }, { 6, N_("Program-shift S") } }; //! Lookup table to translate Minolta Dynax 7D camera settings image size values to readable labels extern const TagDetails minoltaImageSize7D[] = { { 0, N_("Large") }, { 1, N_("Medium") }, { 2, N_("Small") } }; //! Lookup table to translate Minolta Dynax 7D camera settings image quality values to readable labels extern const TagDetails minoltaImageQuality7D[] = { { 0, N_("Raw") }, { 16, N_("Fine") }, { 32, N_("Normal") }, { 34, N_("Raw+Jpeg") }, { 48, N_("Economy") } }; //! Lookup table to translate Minolta Dynax 7D camera settings white balance values to readable labels extern const TagDetails minoltaWhiteBalance7D[] = { { 0, N_("Auto") }, { 1, N_("Daylight") }, { 2, N_("Shade") }, { 3, N_("Cloudy") }, { 4, N_("Tungsten") }, { 5, N_("Fluorescent") }, { 256, N_("Kelvin") }, { 512, N_("Manual") }, { 512, N_("Manual") } // To silence compiler warning }; //! Lookup table to translate Minolta Dynax 7D camera settings focus mode values to readable labels extern const TagDetails minoltaFocusMode7D[] = { { 0, N_("Single-shot AF") }, { 1, N_("Continuous AF") }, { 3, N_("Manual") }, { 4, N_("Automatic AF") } }; //! Lookup table to translate Minolta Dynax 7D camera settings AF points values to readable labels extern const TagDetails minoltaAFPoints7D[] = { { 1, N_("Center") }, { 2, N_("Top") }, { 4, N_("Top-right") }, { 8, N_("Right") }, { 16, N_("Bottom-right") }, { 32, N_("Bottom") }, { 64, N_("Bottom-left") }, { 128, N_("Left") }, { 256, N_("Top-left") } }; //! Lookup table to translate Minolta Dynax 7D camera settings ISO settings values to readable labels extern const TagDetails minoltaISOSetting7D[] = { { 0, N_("Auto") }, { 1, "100" }, { 3, "200" }, { 4, "400" }, { 5, "800" }, { 6, "1600" }, { 7, "3200" } }; //! Lookup table to translate Minolta Dynax 7D camera settings color space values to readable labels extern const TagDetails minoltaColorSpace7D[] = { { 0, N_("sRGB (Natural)") }, { 1, N_("sRGB (Natural+)") }, { 4, N_("Adobe RGB") } }; //! Lookup table to translate Minolta Dynax 7D camera settings rotation values to readable labels extern const TagDetails minoltaRotation7D[] = { { 72, N_("Horizontal (normal)") }, { 76, N_("Rotate 90 CW") }, { 82, N_("Rotate 270 CW") } }; // Minolta Dynax 7D Camera Settings Tag Info const TagInfo MinoltaMakerNote::tagInfoCs7D_[] = { TagInfo(0x0000, "ExposureMode", N_("Exposure Mode"), N_("Exposure mode"), minoltaCs7DId, makerTags, unsignedShort, 1, EXV_PRINT_TAG(minoltaExposureMode7D)), TagInfo(0x0002, "ImageSize", N_("Image Size"), N_("Image size"), minoltaCs7DId, makerTags, unsignedShort, 1, EXV_PRINT_TAG(minoltaImageSize7D)), TagInfo(0x0003, "Quality", N_("Image Quality"), N_("Image quality"), minoltaCs7DId, makerTags, unsignedShort, 1, EXV_PRINT_TAG(minoltaImageQuality7D)), TagInfo(0x0004, "WhiteBalance", N_("White Balance"), N_("White balance"), minoltaCs7DId, makerTags, unsignedShort, 1, EXV_PRINT_TAG(minoltaWhiteBalance7D)), TagInfo(0x000E, "FocusMode", N_("Focus Mode"), N_("Focus mode"), minoltaCs7DId, makerTags, unsignedShort, 1, EXV_PRINT_TAG(minoltaFocusMode7D)), TagInfo(0x0010, "AFPoints", N_("AF Points"), N_("AF points"), minoltaCs7DId, makerTags, unsignedShort, 1, EXV_PRINT_TAG(minoltaAFPoints7D)), TagInfo(0x0015, "FlashFired", N_("Flash Fired"), N_("Flash fired"), minoltaCs7DId, makerTags, unsignedLong, 1, EXV_PRINT_TAG(minoltaFlashFired)), TagInfo(0x0016, "FlashMode", N_("Flash Mode"), N_("Flash mode"), minoltaCs7DId, makerTags, unsignedShort, 1, printValue), TagInfo(0x001C, "ISOSpeed", N_("ISO Speed Mode"), N_("ISO speed setting"), minoltaCs7DId, makerTags, unsignedShort, 1, EXV_PRINT_TAG(minoltaISOSetting7D)), TagInfo(0x001E, "ExposureCompensation", N_("Exposure Compensation"), N_("Exposure compensation"), minoltaCs7DId, makerTags, signedShort, 1, printValue), TagInfo(0x0025, "ColorSpace", N_("Color Space"), N_("Color space"), minoltaCs7DId, makerTags, unsignedShort, 1, EXV_PRINT_TAG(minoltaColorSpace7D)), TagInfo(0x0026, "Sharpness", N_("Sharpness"), N_("Sharpness"), minoltaCs7DId, makerTags, unsignedShort, 1, printValue), TagInfo(0x0027, "Contrast", N_("Contrast"), N_("Contrast"), minoltaCs7DId, makerTags, unsignedShort, 1, printValue), TagInfo(0x0028, "Saturation", N_("Saturation"), N_("Saturation"), minoltaCs7DId, makerTags, unsignedShort, 1, printValue), TagInfo(0x002D, "FreeMemoryCardImages", N_("Free Memory Card Images"), N_("Free memory card images"), minoltaCs7DId, makerTags, unsignedShort, 1, printValue), TagInfo(0x003F, "ColorTemperature", N_("Color Temperature"), N_("Color temperature"), minoltaCs7DId, makerTags, signedShort, 1, printValue), TagInfo(0x0040, "Hue", N_("Hue"), N_("Hue"), minoltaCs7DId, makerTags, unsignedShort, 1, printValue), TagInfo(0x0046, "Rotation", N_("Rotation"), N_("Rotation"), minoltaCs7DId, makerTags, unsignedShort, 1, EXV_PRINT_TAG(minoltaRotation7D)), TagInfo(0x0047, "FNumber", N_("FNumber"), N_("The F-Number"), minoltaCs7DId, makerTags, unsignedShort, 1, printValue), TagInfo(0x0048, "ExposureTime", N_("Exposure Time"), N_("Exposure time"), minoltaCs7DId, makerTags, unsignedShort, 1, printValue), // 0x004A is a dupplicate than 0x002D. TagInfo(0x004A, "FreeMemoryCardImages", N_("Free Memory Card Images"), N_("Free memory card images"), minoltaCs7DId, makerTags, unsignedShort, 1, printValue), TagInfo(0x005E, "ImageNumber", N_("Image Number"), N_("Image number"), minoltaCs7DId, makerTags, unsignedShort, 1, printValue), TagInfo(0x0060, "NoiseReduction", N_("Noise Reduction"), N_("Noise reduction"), minoltaCs7DId, makerTags, unsignedShort, 1, printMinoltaSonyBoolValue), // 0x0062 is a dupplicate than 0x005E. TagInfo(0x0062, "ImageNumber", N_("Image Number"), N_("Image number"), minoltaCs7DId, makerTags, unsignedShort, 1, printValue), TagInfo(0x0071, "ImageStabilization", N_("Image Stabilization"), N_("Image stabilization"), minoltaCs7DId, makerTags, unsignedShort, 1, printMinoltaSonyBoolValue), TagInfo(0x0075, "ZoneMatchingOn", N_("Zone Matching On"), N_("Zone matching on"), minoltaCs7DId, makerTags, unsignedShort, 1, printMinoltaSonyBoolValue), // End of list marker TagInfo(0xffff, "(UnknownMinoltaCs7DTag)", "(UnknownMinoltaCs7DTag)", N_("Unknown Minolta Camera Settings 7D tag"), minoltaCs7DId, makerTags, unsignedShort, 1, printValue) }; const TagInfo* MinoltaMakerNote::tagListCs7D() { return tagInfoCs7D_; } // -- Minolta Dynax 5D camera settings --------------------------------------------------------------- //! Lookup table to translate Minolta Dynax 5D camera settings exposure mode values to readable labels extern const TagDetails minoltaExposureMode5D[] = { { 0, N_("Program") }, { 1, N_("Aperture priority") }, { 2, N_("Shutter priority") }, { 3, N_("Manual") }, { 4, N_("Auto") }, { 5, N_("Program Shift A") }, { 6, N_("Program Shift S") }, { 0x1013, N_("Portrait") }, { 0x1023, N_("Sports") }, { 0x1033, N_("Sunset") }, { 0x1043, N_("Night View/Portrait") }, { 0x1053, N_("Landscape") }, { 0x1083, N_("Macro") } }; //! Lookup table to translate Minolta Dynax 5D camera settings image size values to readable labels extern const TagDetails minoltaImageSize5D[] = { { 0, N_("Large") }, { 1, N_("Medium") }, { 2, N_("Small") } }; //! Lookup table to translate Minolta Dynax 5D camera settings image quality values to readable labels extern const TagDetails minoltaImageQuality5D[] = { { 0, N_("Raw") }, { 16, N_("Fine") }, { 32, N_("Normal") }, { 34, N_("Raw+Jpeg") }, { 48, N_("Economy") } }; //! Lookup table to translate Minolta Dynax 5D camera settings white balance values to readable labels extern const TagDetails minoltaWhiteBalance5D[] = { { 0, N_("Auto") }, { 1, N_("Daylight") }, { 2, N_("Cloudy") }, { 3, N_("Shade") }, { 4, N_("Tungsten") }, { 5, N_("Fluorescent") }, { 6, N_("Flash") }, { 256, N_("Kelvin") }, { 512, N_("Manual") } }; //! Lookup table to translate Minolta Dynax 5D camera settings metering mode values to readable labels extern const TagDetails minoltaMeteringMode5D[] = { { 0, N_("Multi-segment") }, { 1, N_("Center weighted") }, { 2, N_("Spot") } }; //! Lookup table to translate Minolta Dynax 5D camera settings ISO settings values to readable labels extern const TagDetails minoltaISOSetting5D[] = { { 0, N_("Auto") }, { 1, "100" }, { 3, "200" }, { 4, "400" }, { 5, "800" }, { 6, "1600" }, { 7, "3200" }, { 8, N_("200 (Zone Matching High)") }, { 10, N_("80 (Zone Matching Low)") } }; //! Lookup table to translate Minolta Dynax 5D camera settings color space values to readable labels extern const TagDetails minoltaColorSpace5D[] = { { 0, N_("sRGB (Natural)") }, { 1, N_("sRGB (Natural+)") }, { 2, N_("Monochrome") }, { 3, N_("Adobe RGB (ICC)") }, { 4, N_("Adobe RGB") } }; //! Lookup table to translate Minolta Dynax 5D camera settings rotation values to readable labels extern const TagDetails minoltaRotation5D[] = { { 72, N_("Horizontal (normal)") }, { 76, N_("Rotate 90 CW") }, { 82, N_("Rotate 270 CW") } }; //! Lookup table to translate Minolta Dynax 5D camera settings focus position values to readable labels extern const TagDetails minoltaFocusPosition5D[] = { { 0, N_("Wide") }, { 1, N_("Central") }, { 2, N_("Up") }, { 3, N_("Up right") }, { 4, N_("Right") }, { 5, N_("Down right") }, { 6, N_("Down") }, { 7, N_("Down left") }, { 8, N_("Left") }, { 9, N_("Up left") } }; //! Lookup table to translate Minolta Dynax 5D camera settings focus area values to readable labels extern const TagDetails minoltaFocusArea5D[] = { { 0, N_("Wide") }, { 1, N_("Selection") }, { 2, N_("Spot") } }; //! Lookup table to translate Minolta Dynax 5D camera settings focus mode values to readable labels extern const TagDetails minoltaAFMode5D[] = { { 0, "AF-A" }, { 1, "AF-S" }, { 2, "AF-D" }, { 3, "DMF" } }; //! Lookup table to translate Minolta Dynax 5D camera settings picture finish values to readable labels extern const TagDetails minoltaPictureFinish5D[] = { { 0, N_("Natural") }, { 1, N_("Natural+") }, { 2, N_("Portrait") }, { 3, N_("Wind Scene") }, { 4, N_("Evening Scene") }, { 5, N_("Night Scene") }, { 6, N_("Night Portrait") }, { 7, N_("Monochrome") }, { 8, N_("Adobe RGB") }, { 9, N_("Adobe RGB (ICC)") } }; //! Method to convert Minolta Dynax 5D exposure manual bias values. std::ostream& MinoltaMakerNote::printMinoltaExposureManualBias5D(std::ostream& os, const Value& value, const ExifData*) { // From Xavier Raynaud: the value is converted from 0:256 to -5.33:5.33 std::ostringstream oss; oss.copyfmt(os); os << std::fixed << std::setprecision(2) << (float (value.toLong()-128)/24); os.copyfmt(oss); return os; } //! Method to convert Minolta Dynax 5D exposure compensation values. std::ostream& MinoltaMakerNote::printMinoltaExposureCompensation5D(std::ostream& os, const Value& value, const ExifData*) { std::ostringstream oss; oss.copyfmt(os); os << std::fixed << std::setprecision(2) << (float (value.toLong()-300)/100); os.copyfmt(oss); return os; } // Minolta Dynax 5D Camera Settings Tag Info const TagInfo MinoltaMakerNote::tagInfoCs5D_[] = { TagInfo(0x000A, "ExposureMode", N_("Exposure Mode"), N_("Exposure mode"), minoltaCs5DId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(minoltaExposureMode5D)), TagInfo(0x000C, "ImageSize", N_("Image Size"), N_("Image size"), minoltaCs5DId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(minoltaImageSize5D)), TagInfo(0x000D, "Quality", N_("Image Quality"), N_("Image quality"), minoltaCs5DId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(minoltaImageQuality5D)), TagInfo(0x000E, "WhiteBalance", N_("White Balance"), N_("White balance"), minoltaCs5DId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(minoltaWhiteBalance5D)), TagInfo(0x001A, "FocusPosition", N_("Focus Position"), N_("Focus position"), minoltaCs5DId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(minoltaFocusPosition5D)), TagInfo(0x001B, "FocusArea", N_("Focus Area"), N_("Focus area"), minoltaCs5DId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(minoltaFocusArea5D)), TagInfo(0x001F, "FlashFired", N_("Flash Fired"), N_("Flash fired"), minoltaCs5DId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(minoltaFlashFired)), TagInfo(0x0025, "MeteringMode", N_("Metering Mode"), N_("Metering mode"), minoltaCs5DId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(minoltaMeteringMode5D)), TagInfo(0x0026, "ISOSpeed", N_("ISO Speed Mode"), N_("ISO speed setting"), minoltaCs5DId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(minoltaISOSetting5D)), TagInfo(0x002F, "ColorSpace", N_("Color Space"), N_("Color space"), minoltaCs5DId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(minoltaColorSpace5D)), TagInfo(0x0030, "Sharpness", N_("Sharpness"), N_("Sharpness"), minoltaCs5DId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0031, "Contrast", N_("Contrast"), N_("Contrast"), minoltaCs5DId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0032, "Saturation", N_("Saturation"), N_("Saturation"), minoltaCs5DId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0035, "ExposureTime", N_("Exposure Time"), N_("Exposure time"), minoltaCs5DId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0036, "FNumber", N_("FNumber"), N_("The F-Number"), minoltaCs5DId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0037, "FreeMemoryCardImages", N_("Free Memory Card Images"), N_("Free memory card images"), minoltaCs5DId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0038, "ExposureRevision", N_("Exposure Revision"), N_("Exposure revision"), minoltaCs5DId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0048, "FocusMode", N_("Focus Mode"), N_("Focus mode"), minoltaCs5DId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(minoltaFocusModeStd)), TagInfo(0x0049, "ColorTemperature", N_("Color Temperature"), N_("Color temperature"), minoltaCs5DId, makerTags, signedShort, -1, printValue), TagInfo(0x0050, "Rotation", N_("Rotation"), N_("Rotation"), minoltaCs5DId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(minoltaRotation5D)), TagInfo(0x0053, "ExposureCompensation", N_("Exposure Compensation"), N_("Exposure compensation"), minoltaCs5DId, makerTags, unsignedShort, -1, printMinoltaExposureCompensation5D), TagInfo(0x0054, "FreeMemoryCardImages", N_("Free Memory Card Images"), N_("Free memory card images"), minoltaCs5DId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0065, "Rotation2", N_("Rotation2"), N_("Rotation2"), minoltaCs5DId, makerTags, unsignedShort, -1, printMinoltaSonyRotation), TagInfo(0x006E, "Color Temperature", N_("Color Temperature"), N_("Color Temperature"), minoltaCs5DId, makerTags, signedShort, -1, printValue), TagInfo(0x0071, "PictureFinish", N_("Picture Finish"), N_("Picture Finish"), minoltaCs5DId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(minoltaPictureFinish5D)), TagInfo(0x0091, "ExposureManualBias", N_("Exposure Manual Bias"), N_("Exposure manual bias"), minoltaCs5DId, makerTags, unsignedShort, -1, printMinoltaExposureManualBias5D), TagInfo(0x009E, "AFMode", N_("AF Mode"), N_("AF mode"), minoltaCs5DId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(minoltaAFMode5D)), TagInfo(0x00AE, "ImageNumber", N_("Image Number"), N_("Image number"), minoltaCs5DId, makerTags, unsignedShort, -1, printValue), TagInfo(0x00B0, "NoiseReduction", N_("Noise Reduction"), N_("Noise reduction"), minoltaCs5DId, makerTags, unsignedShort, -1, printMinoltaSonyBoolValue), TagInfo(0x00BD, "ImageStabilization", N_("Image Stabilization"), N_("Image stabilization"), minoltaCs5DId, makerTags, unsignedShort, -1, printMinoltaSonyBoolValue), // From Xavier Raynaud: some notes on missing tags. // 0x0051 seems to be identical to FNumber (0x0036). An approx. relation between Tag value // and Fstop is exp(-0.335+value*0.043) // 0x0052 seems to be identical to ExposureTime (0x0035). An approx. relation between Tag // value and Exposure time is exp(-4+value*0.085) // End of list marker TagInfo(0xFFFF, "(UnknownMinoltaCs5DTag)", "(UnknownMinoltaCs5DTag)", N_("Unknown Minolta Camera Settings 5D tag"), minoltaCs5DId, makerTags, invalidTypeId, -1, printValue) }; const TagInfo* MinoltaMakerNote::tagListCs5D() { return tagInfoCs5D_; } // -- Sony A100 camera settings --------------------------------------------------------------- //! Lookup table to translate Sony A100 camera settings drive mode 2 values to readable labels extern const TagDetails sonyDriveMode2A100[] = { { 0, N_("Self-timer 10 sec") }, { 1, N_("Continuous") }, { 4, N_("Self-timer 2 sec") }, { 5, N_("Single Frame") }, { 8, N_("White Balance Bracketing Low") }, { 9, N_("White Balance Bracketing High") }, { 770, N_("Single-frame Bracketing Low") }, { 771, N_("Continuous Bracketing Low") }, { 1794, N_("Single-frame Bracketing High") }, { 1795, N_("Continuous Bracketing High") } }; //! Lookup table to translate Sony A100 camera settings focus mode values to readable labels extern const TagDetails sonyFocusModeA100[] = { { 0, "AF-S" }, { 1, "AF-C" }, { 4, "AF-A" }, { 5, "Manual" }, { 6, "DMF" } }; //! Lookup table to translate Sony A100 camera settings flash mode values to readable labels extern const TagDetails sonyFlashModeA100[] = { { 0, N_("Auto") }, { 2, N_("Rear flash sync") }, { 3, N_("Wireless") }, { 4, N_("Fill flash") } }; //! Lookup table to translate Sony A100 camera settings metering mode values to readable labels extern const TagDetails sonyMeteringModeA100[] = { { 0, N_("Multi-segment") }, { 1, N_("Center weighted average") }, { 2, N_("Spot") } }; //! Lookup table to translate Sony A100 camera settings zone matching mode values to readable labels extern const TagDetails sonyZoneMatchingModeA100[] = { { 0, N_("Off") }, { 1, N_("Standard") }, { 2, N_("Advanced") } }; //! Lookup table to translate Sony A100 camera settings color space values to readable labels extern const TagDetails sonyColorSpaceA100[] = { { 0, N_("sRGB") }, { 5, N_("Adobe RGB") } }; //! Lookup table to translate Sony A100 camera settings drive mode values to readable labels extern const TagDetails sonyDriveModeA100[] = { { 0, N_("Single Frame") }, { 1, N_("Continuous") }, { 2, N_("Self-timer") }, { 3, N_("Continuous Bracketing") }, { 4, N_("Single-Frame Bracketing") }, { 5, N_("White Balance Bracketing") } }; //! Lookup table to translate Sony A100 camera settings self timer time values to readable labels extern const TagDetails sonySelfTimerTimeA100[] = { { 0, "10s" }, { 4, "2s" } }; //! Lookup table to translate Sony A100 camera settings continuous bracketing values to readable labels extern const TagDetails sonyContinuousBracketingA100[] = { { 0x303, N_("Low") }, { 0x703, N_("High") } }; //! Lookup table to translate Sony A100 camera settings single frame bracketing values to readable labels extern const TagDetails sonySingleFrameBracketingA100[] = { { 0x302, N_("Low") }, { 0x702, N_("High") } }; //! Lookup table to translate Sony A100 camera settings white balance bracketing values to readable labels extern const TagDetails sonyWhiteBalanceBracketingA100[] = { { 0x8, N_("Low") }, { 0x9, N_("High") } }; //! Lookup table to translate Sony A100 camera settings white balance setting values to readable labels extern const TagDetails sonyWhiteBalanceSettingA100[] = { { 0x0000, N_("Auto") }, { 0x0001, N_("Preset") }, { 0x0002, N_("Custom") }, { 0x0003, N_("Color Temperature/Color Filter") }, { 0x8001, N_("Preset") }, { 0x8002, N_("Custom") }, { 0x8003, N_("Color Temperature/Color Filter") } }; //! Lookup table to translate Sony A100 camera settings preset white balance values to readable labels extern const TagDetails sonyPresetWhiteBalanceA100[] = { { 1, N_("Daylight") }, { 2, N_("Cloudy") }, { 3, N_("Shade") }, { 4, N_("Tungsten") }, { 5, N_("Fluorescent") }, { 6, N_("Flash") } }; //! Lookup table to translate Sony A100 camera settings color temperature setting values to readable labels extern const TagDetails sonyColorTemperatureSettingA100[] = { { 0, N_("Temperature") }, { 2, N_("Color Filter") } }; //! Lookup table to translate Sony A100 camera settings custom WB setting values to readable labels extern const TagDetails sonyCustomWBSettingA100[] = { { 0, N_("Setup") }, { 2, N_("Recall") } }; //! Lookup table to translate Sony A100 camera settings custom WB error values to readable labels extern const TagDetails sonyCustomWBErrorA100[] = { { 0, N_("Ok") }, { 2, N_("Error") } }; //! Lookup table to translate Sony A100 camera settings image size values to readable labels extern const TagDetails sonyImageSizeA100[] = { { 0, N_("Standard") }, { 1, N_("Medium") }, { 2, N_("Small") } }; //! Lookup table to translate Sony A100 camera settings instant playback setup values to readable labels extern const TagDetails sonyInstantPlaybackSetupA100[] = { { 0, N_("Image and Information") }, { 1, N_("Image Only") }, { 3, N_("Image and Histogram") } }; //! Lookup table to translate Sony A100 camera settings flash default setup values to readable labels extern const TagDetails sonyFlashDefaultA100[] = { { 0, N_("Auto") }, { 1, N_("Fill Flash") } }; //! Lookup table to translate Sony A100 camera settings auto bracket order values to readable labels extern const TagDetails sonyAutoBracketOrderA100[] = { { 0, "0-+" }, { 1, "-0+" } }; //! Lookup table to translate Sony A100 camera settings focus hold button values to readable labels extern const TagDetails sonyFocusHoldButtonA100[] = { { 0, N_("Focus Hold") }, { 1, N_("DOF Preview") } }; //! Lookup table to translate Sony A100 camera settings AEL button values to readable labels extern const TagDetails sonyAELButtonA100[] = { { 0, N_("Hold") }, { 1, N_("Toggle") }, { 2, N_("Spot Hold") }, { 3, N_("Spot Toggle") } }; //! Lookup table to translate Sony A100 camera settings control dial set values to readable labels extern const TagDetails sonyControlDialSetA100[] = { { 0, N_("Shutter Speed") }, { 1, N_("Aperture") } }; //! Lookup table to translate Sony A100 camera settings exposure compensation mode values to readable labels extern const TagDetails sonyExposureCompensationModeA100[] = { { 0, N_("Ambient and Flash") }, { 1, N_("Ambient Only") } }; //! Lookup table to translate Sony A100 camera settings sony AF area illumination values to readable labels extern const TagDetails sonyAFAreaIlluminationA100[] = { { 0, N_("0.3 seconds") }, { 1, N_("0.6 seconds") }, { 2, N_("Off") } }; //! Lookup table to translate Sony A100 camera settings monitor display off values to readable labels extern const TagDetails sonyMonitorDisplayOffA100[] = { { 0, N_("Automatic") }, { 1, N_("Manual") } }; //! Lookup table to translate Sony A100 camera settings record display values to readable labels extern const TagDetails sonyRecordDisplayA100[] = { { 0, N_("Auto-rotate") }, { 1, N_("Horizontal") } }; //! Lookup table to translate Sony A100 camera settings play display values to readable labels extern const TagDetails sonyPlayDisplayA100[] = { { 0, N_("Auto-rotate") }, { 1, N_("Manual Rotate") } }; //! Lookup table to translate Sony A100 camera settings metering off scale indicator values to readable labels extern const TagDetails sonyMeteringOffScaleIndicatorA100[] = { { 0, N_("Within Range") }, { 1, N_("Under/Over Range") }, { 255, N_("Out of Range") } }; //! Lookup table to translate Sony A100 camera settings exposure indicator values to readable labels extern const TagDetails sonyExposureIndicatorA100[] = { { 0, N_("Not Indicated") }, { 1, N_("Under Scale") }, { 119, N_("Bottom of Scale") }, { 120, "-2.0" }, { 121, "-1.7" }, { 122, "-1.5" }, { 123, "-1.3" }, { 124, "-1.0" }, { 125, "-0.7" }, { 126, "-0.5" }, { 127, "-0.3" }, { 128, "-0.0" }, { 129, "+0.3" }, { 130, "+0.5" }, { 131, "+0.7" }, { 132, "+1.0" }, { 133, "+1.3" }, { 134, "+1.5" }, { 135, "+1.7" }, { 136, "+2.0" }, { 253, N_("Top of Scale") }, { 254, N_("Over Scale") } }; //! Lookup table to translate Sony A100 camera settings focus mode switch values to readable labels extern const TagDetails sonyFocusModeSwitchA100[] = { { 0, N_("AM") }, { 1, N_("MF") } }; //! Lookup table to translate Sony A100 camera settings flash type switch values to readable labels extern const TagDetails sonyFlashTypeA100[] = { { 0, N_("Off") }, { 1, N_("Built-in") }, { 2, N_("External") } }; //! Lookup table to translate Sony A100 camera settings battery level switch values to readable labels extern const TagDetails sonyBatteryLevelA100[] = { { 3, N_("Very Low") }, { 4, N_("Low") }, { 5, N_("Half Full") }, { 6, N_("Sufficient Power Remaining") } }; // Sony A100 Camera Settings Tag Info const TagInfo MinoltaMakerNote::tagInfoCsA100_[] = { TagInfo(0x0000, "ExposureMode", N_("Exposure Mode"), N_("Exposure mode"), sony1MltCsA100Id, makerTags, unsignedShort, 1, EXV_PRINT_TAG(minoltaExposureMode5D)), TagInfo(0x0001, "ExposureCompensationSetting", N_("Exposure Compensation Setting"), N_("Exposure compensation setting"), sony1MltCsA100Id, makerTags, unsignedShort, 1, printValue), TagInfo(0x0005, "HighSpeedSync", N_("High Speed Sync"), N_("High speed sync"), sony1MltCsA100Id, makerTags, unsignedShort, 1, printMinoltaSonyBoolValue), TagInfo(0x0006, "ManualExposureTime", N_("Manual Exposure Time"), N_("Manual exposure time"), sony1MltCsA100Id, makerTags, unsignedShort, 1, printValue), TagInfo(0x0007, "ManualFNumber", N_("Manual FNumber"), N_("Manual FNumber"), sony1MltCsA100Id, makerTags, unsignedShort, 1, printValue), TagInfo(0x0008, "ExposureTime", N_("Exposure Time"), N_("Exposure time"), sony1MltCsA100Id, makerTags, unsignedShort, 1, printValue), TagInfo(0x0009, "FNumber", N_("FNumber"), N_("FNumber"), sony1MltCsA100Id, makerTags, unsignedShort, 1, printValue), TagInfo(0x000A, "DriveMode2", N_("Drive Mode 2"), N_("Drive mode 2"), sony1MltCsA100Id, makerTags, unsignedShort, 1, EXV_PRINT_TAG(sonyDriveMode2A100)), TagInfo(0x000B, "WhiteBalance", N_("White Balance"), N_("White balance"), sony1MltCsA100Id, makerTags, unsignedShort, 1, EXV_PRINT_TAG(minoltaWhiteBalance5D)), TagInfo(0x000C, "FocusMode", N_("Focus Mode"), N_("Focus mode"), sony1MltCsA100Id, makerTags, unsignedShort, 1, EXV_PRINT_TAG(sonyFocusModeA100)), TagInfo(0x000D, "LocalAFAreaPoint", N_("Local AF Area Point"), N_("Local AF Area Point"), sony1MltCsA100Id, makerTags, unsignedShort, 1, printMinoltaSonyLocalAFAreaPoint), TagInfo(0x000E, "AFAreaMode", N_("AF Area Mode"), N_("AF Area Mode"), sony1MltCsA100Id, makerTags, unsignedShort, 1, printMinoltaSonyAFAreaMode), TagInfo(0x000F, "FlashMode", N_("FlashMode"), N_("FlashMode"), sony1MltCsA100Id, makerTags, unsignedShort, 1, EXV_PRINT_TAG(sonyFlashModeA100)), TagInfo(0x0010, "FlashExposureCompSetting", N_("Flash Exposure Comp Setting"), N_("Flash exposure compensation setting"), sony1MltCsA100Id, makerTags, unsignedShort, 1, printValue), TagInfo(0x0012, "MeteringMode", N_("Metering Mode"), N_("Metering mode"), sony1MltCsA100Id, makerTags, unsignedShort, 1, EXV_PRINT_TAG(sonyMeteringModeA100)), TagInfo(0x0013, "ISOSetting", N_("ISO Setting"), N_("ISO setting"), sony1MltCsA100Id, makerTags, unsignedShort, 1, printValue), TagInfo(0x0014, "ZoneMatchingMode", N_("Zone Matching Mode"), N_("Zone Matching Mode"), sony1MltCsA100Id, makerTags, unsignedShort, 1, EXV_PRINT_TAG(sonyZoneMatchingModeA100)), TagInfo(0x0015, "DynamicRangeOptimizerMode", N_("Dynamic Range Optimizer Mode"), N_("Dynamic range optimizer mode"), sony1MltCsA100Id, makerTags, unsignedShort, 1, printMinoltaSonyDynamicRangeOptimizerMode), TagInfo(0x0016, "ColorMode", N_("Color Mode"), N_("Color mode"), sony1MltCsA100Id, makerTags, unsignedShort, 1, printMinoltaSonyColorMode), TagInfo(0x0017, "ColorSpace", N_("Color Space"), N_("Color space"), sony1MltCsA100Id, makerTags, unsignedShort, 1, EXV_PRINT_TAG(sonyColorSpaceA100)), TagInfo(0x0018, "Sharpness", N_("Sharpness"), N_("Sharpness"), sony1MltCsA100Id, makerTags, unsignedShort, 1, printValue), TagInfo(0x0019, "Contrast", N_("Contrast"), N_("Contrast"), sony1MltCsA100Id, makerTags, unsignedShort, 1, printValue), TagInfo(0x001A, "Saturation", N_("Saturation"), N_("Saturation"), sony1MltCsA100Id, makerTags, unsignedShort, 1, printValue), TagInfo(0x001C, "FlashMetering", N_("Flash Metering"), N_("Flash metering"), sony1MltCsA100Id, makerTags, unsignedShort, 1, EXV_PRINT_TAG(minoltaFlashMeteringStd)), TagInfo(0x001D, "PrioritySetupShutterRelease", N_("Priority Setup Shutter Release"), N_("Priority Setup Shutter Release"), sony1MltCsA100Id, makerTags, unsignedShort, 1, printMinoltaSonyPrioritySetupShutterRelease), TagInfo(0x001E, "DriveMode", N_("Drive Mode"), N_("Drive mode"), sony1MltCsA100Id, makerTags, unsignedShort, 1, EXV_PRINT_TAG(sonyDriveModeA100)), TagInfo(0x001F, "SelfTimerTime", N_("Self Timer Time"), N_("Self timer time"), sony1MltCsA100Id, makerTags, unsignedShort, 1, EXV_PRINT_TAG(sonySelfTimerTimeA100)), TagInfo(0x0020, "ContinuousBracketing", N_("Continuous Bracketing"), N_("Continuous bracketing"), sony1MltCsA100Id, makerTags, unsignedShort, 1, EXV_PRINT_TAG(sonyContinuousBracketingA100)), TagInfo(0x0021, "SingleFrameBracketing", N_("Single Frame Bracketing"), N_("Single frame bracketing"), sony1MltCsA100Id, makerTags, unsignedShort, 1, EXV_PRINT_TAG(sonySingleFrameBracketingA100)), TagInfo(0x0022, "WhiteBalanceBracketing", N_("White Balance Bracketing"), N_("White balance bracketing"), sony1MltCsA100Id, makerTags, unsignedShort, 1, EXV_PRINT_TAG(sonyWhiteBalanceBracketingA100)), TagInfo(0x0023, "WhiteBalanceSetting", N_("White Balance Setting"), N_("White balance setting"), sony1MltCsA100Id, makerTags, unsignedShort, 1, EXV_PRINT_TAG(sonyWhiteBalanceSettingA100)), TagInfo(0x0024, "PresetWhiteBalance", N_("Preset White Balance"), N_("Preset white balance"), sony1MltCsA100Id, makerTags, unsignedShort, 1, EXV_PRINT_TAG(sonyPresetWhiteBalanceA100)), TagInfo(0x0025, "ColorTemperatureSetting", N_("Color Temperature Setting"), N_("Color temperature setting"), sony1MltCsA100Id, makerTags, unsignedShort, 1, EXV_PRINT_TAG(sonyColorTemperatureSettingA100)), TagInfo(0x0026, "CustomWBSetting", N_("Custom WB Setting"), N_("Custom WB setting"), sony1MltCsA100Id, makerTags, unsignedShort, 1, EXV_PRINT_TAG(sonyCustomWBSettingA100)), TagInfo(0x0027, "DynamicRangeOptimizerSettings", N_("Dynamic Range Optimizer Settings"), N_("Dynamic Range Optimizer Settings"), sony1MltCsA100Id, makerTags, unsignedShort, 1, printMinoltaSonyDynamicRangeOptimizerMode), TagInfo(0x0032, "FreeMemoryCardImages", N_("Free Memory Card Images"), N_("Free memory card images"), sony1MltCsA100Id, makerTags, unsignedShort, 1, printValue), TagInfo(0x0034, "CustomWBRedLevel", N_("Custom WB Red Level"), N_("Custom WB red level"), sony1MltCsA100Id, makerTags, unsignedShort, 1, printValue), TagInfo(0x0035, "CustomWBGreenLevel", N_("Custom WB Green Level"), N_("Custom WB green level"), sony1MltCsA100Id, makerTags, unsignedShort, 1, printValue), TagInfo(0x0036, "CustomWBBlueLevel", N_("Custom WB Blue Level"), N_("CustomWB blue level"), sony1MltCsA100Id, makerTags, unsignedShort, 1, printValue), TagInfo(0x0037, "CustomWBError", N_("Custom WB Error"), N_("Custom WB Error"), sony1MltCsA100Id, makerTags, unsignedShort, 1, EXV_PRINT_TAG(sonyCustomWBErrorA100)), TagInfo(0x0038, "WhiteBalanceFineTune", N_("White Balance Fine Tune"), N_("White balance fine tune"), sony1MltCsA100Id, makerTags, signedShort, 1, printValue), TagInfo(0x0039, "ColorTemperature", N_("Color Temperature"), N_("Color temperature"), sony1MltCsA100Id, makerTags, unsignedShort, 1, printValue), TagInfo(0x003A, "ColorCompensationFilter", N_("Color Compensation Filter"), N_("Color compensation filter"), sony1MltCsA100Id, makerTags, signedShort, 1, printValue), TagInfo(0x003B, "SonyImageSize", N_("Sony Image Size"), N_("Sony Image Size"), sony1MltCsA100Id, makerTags, unsignedShort, 1, EXV_PRINT_TAG(sonyImageSizeA100)), TagInfo(0x003C, "Quality", N_("Quality"), N_("Quality"), sony1MltCsA100Id, makerTags, unsignedShort, 1, printMinoltaSonyQualityCs), TagInfo(0x003D, "InstantPlaybackTime", N_("Instant Playback Time"), N_("Instant playback time"), sony1MltCsA100Id, makerTags, unsignedShort, 1, printValue), TagInfo(0x003E, "InstantPlaybackSetup", N_("Instant Playback Setup"), N_("Instant playback setup"), sony1MltCsA100Id, makerTags, unsignedShort, 1, EXV_PRINT_TAG(sonyInstantPlaybackSetupA100)), TagInfo(0x003F, "NoiseReduction", N_("Noise Reduction"), N_("Noise reduction"), sony1MltCsA100Id, makerTags, unsignedShort, 1, printMinoltaSonyBoolValue), TagInfo(0x0040, "EyeStartAF", N_("Eye Start AF"), N_("Eye start AF"), sony1MltCsA100Id, makerTags, unsignedShort, 1, printMinoltaSonyBoolInverseValue), TagInfo(0x0041, "RedEyeReduction", N_("Red Eye Reduction"), N_("Red eye reduction"), sony1MltCsA100Id, makerTags, unsignedShort, 1, printMinoltaSonyBoolValue), TagInfo(0x0042, "FlashDefault", N_("Flash Default"), N_("Flash default"), sony1MltCsA100Id, makerTags, unsignedShort, 1, EXV_PRINT_TAG(sonyFlashDefaultA100)), TagInfo(0x0043, "AutoBracketOrder", N_("Auto Bracket Order"), N_("Auto bracket order"), sony1MltCsA100Id, makerTags, unsignedShort, 1, EXV_PRINT_TAG(sonyAutoBracketOrderA100)), TagInfo(0x0044, "FocusHoldButton", N_("Focus Hold Button"), N_("Focus hold button"), sony1MltCsA100Id, makerTags, unsignedShort, 1, EXV_PRINT_TAG(sonyFocusHoldButtonA100)), TagInfo(0x0045, "AELButton", N_("AEL Button"), N_("AEL button"), sony1MltCsA100Id, makerTags, unsignedShort, 1, EXV_PRINT_TAG(sonyAELButtonA100)), TagInfo(0x0046, "ControlDialSet", N_("Control Dial Set"), N_("Control dial set"), sony1MltCsA100Id, makerTags, unsignedShort, 1, EXV_PRINT_TAG(sonyControlDialSetA100)), TagInfo(0x0047, "ExposureCompensationMode", N_("Exposure Compensation Mode"), N_("Exposure compensation mode"), sony1MltCsA100Id, makerTags, unsignedShort, 1, EXV_PRINT_TAG(sonyExposureCompensationModeA100)), TagInfo(0x0048, "AFAssist", N_("AF Assist"), N_("AF assist"), sony1MltCsA100Id, makerTags, unsignedShort, 1, printMinoltaSonyBoolInverseValue), TagInfo(0x0049, "CardShutterLock", N_("Card Shutter Lock"), N_("Card shutter lock"), sony1MltCsA100Id, makerTags, unsignedShort, 1, printMinoltaSonyBoolInverseValue), TagInfo(0x004A, "LensShutterLock", N_("Lens Shutter Lock"), N_("Lens shutter lock"), sony1MltCsA100Id, makerTags, unsignedShort, 1, printMinoltaSonyBoolInverseValue), TagInfo(0x004B, "AFAreaIllumination", N_("AF Area Illumination"), N_("AF area illumination"), sony1MltCsA100Id, makerTags, unsignedShort, 1, EXV_PRINT_TAG(sonyAFAreaIlluminationA100)), TagInfo(0x004C, "MonitorDisplayOff", N_("Monitor Display Off"), N_("Monitor display off"), sony1MltCsA100Id, makerTags, unsignedShort, 1, EXV_PRINT_TAG(sonyMonitorDisplayOffA100)), TagInfo(0x004D, "RecordDisplay", N_("Record Display"), N_("Record display"), sony1MltCsA100Id, makerTags, unsignedShort, 1, EXV_PRINT_TAG(sonyRecordDisplayA100)), TagInfo(0x004E, "PlayDisplay", N_("Play Display"), N_("Play display"), sony1MltCsA100Id, makerTags, unsignedShort, 1, EXV_PRINT_TAG(sonyPlayDisplayA100)), TagInfo(0x0050, "ExposureIndicator", N_("Exposure Indicator"), N_("Exposure indicator"), sony1MltCsA100Id, makerTags, unsignedShort, 1, EXV_PRINT_TAG(sonyExposureIndicatorA100)), TagInfo(0x0051, "AELExposureIndicator", N_("AEL Exposure Indicator"), N_("AEL exposure indicator (also indicates exposure for next shot when bracketing)"), sony1MltCsA100Id, makerTags, unsignedShort, 1, EXV_PRINT_TAG(sonyExposureIndicatorA100)), TagInfo(0x0052, "ExposureBracketingIndicatorLast", N_("Exposure Bracketing Indicator Last"), N_("Exposure bracketing indicator last (indicator for last shot when bracketing)"), sony1MltCsA100Id, makerTags, unsignedShort, 1, EXV_PRINT_TAG(sonyExposureIndicatorA100)), TagInfo(0x0053, "MeteringOffScaleIndicator", N_("Metering Off Scale Indicator"), N_("Metering off scale indicator (two flashing triangles when under or over metering scale)"), sony1MltCsA100Id, makerTags, unsignedShort, 1, EXV_PRINT_TAG(sonyMeteringOffScaleIndicatorA100)), TagInfo(0x0054, "FlashExposureIndicator", N_("Flash Exposure Indicator"), N_("Flash exposure indicator"), sony1MltCsA100Id, makerTags, unsignedShort, 1, EXV_PRINT_TAG(sonyExposureIndicatorA100)), TagInfo(0x0055, "FlashExposureIndicatorNext", N_("Flash Exposure Indicator Next"), N_("Flash exposure indicator next (indicator for next shot when bracketing)"), sony1MltCsA100Id, makerTags, unsignedShort, 1, EXV_PRINT_TAG(sonyExposureIndicatorA100)), TagInfo(0x0056, "FlashExposureIndicatorLast", N_("Flash Exposure Indicator Last"), N_("Flash exposure indicator last (indicator for last shot when bracketing)"), sony1MltCsA100Id, makerTags, unsignedShort, 1, EXV_PRINT_TAG(sonyExposureIndicatorA100)), TagInfo(0x0057, "ImageStabilization", N_("Image Stabilization"), N_("Image stabilization"), sony1MltCsA100Id, makerTags, unsignedShort, 1, printMinoltaSonyBoolValue), TagInfo(0x0058, "FocusModeSwitch", N_("Focus Mode Switch"), N_("Focus mode switch"), sony1MltCsA100Id, makerTags, unsignedShort, 1, EXV_PRINT_TAG(sonyFocusModeSwitchA100)), TagInfo(0x0059, "FlashType", N_("Flash Type"), N_("Flash type"), sony1MltCsA100Id, makerTags, unsignedShort, 1, EXV_PRINT_TAG(sonyFlashTypeA100)), TagInfo(0x005A, "Rotation", N_("Rotation"), N_("Rotation"), sony1MltCsA100Id, makerTags, unsignedShort, 1, printMinoltaSonyRotation), TagInfo(0x004B, "AELock", N_("AE Lock"), N_("AE lock"), sony1MltCsA100Id, makerTags, unsignedShort, 1, printMinoltaSonyBoolValue), TagInfo(0x005E, "ColorTemperature", N_("Color Temperature"), N_("Color temperature"), sony1MltCsA100Id, makerTags, unsignedLong, 1, printValue), TagInfo(0x005F, "ColorCompensationFilter", N_("Color Compensation Filter"), N_("Color compensation filter: negative is green, positive is magenta"), sony1MltCsA100Id, makerTags, unsignedLong, 1, printValue), TagInfo(0x0060, "BatteryLevel", N_("Battery Level"), N_("Battery level"), sony1MltCsA100Id, makerTags, unsignedShort, 1, EXV_PRINT_TAG(sonyBatteryLevelA100)), // End of list marker TagInfo(0xffff, "(UnknownSonyCsA100Tag)", "(UnknownSonyCsA100Tag)", N_("Unknown Sony Camera Settings A100 tag"), sony1MltCsA100Id, makerTags, unsignedShort, 1, printValue) }; const TagInfo* MinoltaMakerNote::tagListCsA100() { return tagInfoCsA100_; } // TODO : Add camera settings tags info "New2"... // -- Minolta and Sony MakerNote Common Values --------------------------------------- //! Lookup table to translate Minolta/Sony Lens id values to readable labels /* NOTE: - duplicate tags value are: 0/25520, 4/25920, 13/25610, 19/25910, 22/26050/26070, 25500/25501/26130, 25540/25541/25850, 25580/25581, 2564025641, 25720/25721, 25790/25791, 25960/25961, 25980/25981, 26150/26151 - No need to i18n these string. */ extern TagDetails const minoltaSonyLensID[] = { { 0, "Minolta AF 28-85mm F3.5-4.5 New" }, { 1, "Minolta AF 80-200mm F2.8 HS-APO G" }, { 2, "Minolta AF 28-70mm F2.8 G" }, { 3, "Minolta AF 28-80mm F4-5.6" }, { 4, "Minolta AF 85mm F1.4G" }, { 5, "Minolta AF 35-70mm F3.5-4.5 [II]" }, { 6, "Minolta AF 24-85mm F3.5-4.5 [New]" }, { 7, "Minolta AF 100-300mm F4.5-5.6(D) APO [New] | " "Minolta AF 100-400mm F4.5-6.7(D) | " "Sigma AF 100-300mm F4 EX DG IF" }, { 8, "Minolta AF 70-210mm F4.5-5.6 [II]" }, { 9, "Minolta AF 50mm F3.5 Macro" }, { 10, "Minolta AF 28-105mm F3.5-4.5 [New]" }, { 11, "Minolta AF 300mm F4 HS-APO G" }, { 12, "Minolta AF 100mm F2.8 Soft Focus" }, { 13, "Minolta AF 75-300mm F4.5-5.6 (New or II)" }, { 14, "Minolta AF 100-400mm F4.5-6.7 APO" }, { 15, "Minolta AF 400mm F4.5 HS-APO G" }, { 16, "Minolta AF 17-35mm F3.5 G" }, { 17, "Minolta AF 20-35mm F3.5-4.5" }, { 18, "Minolta AF 28-80mm F3.5-5.6 II" }, { 19, "Minolta AF 35mm F1.4 G" }, { 20, "Minolta/Sony 135mm F2.8 [T4.5] STF" }, { 22, "Minolta AF 35-80mm F4-5.6 II" }, { 23, "Minolta AF 200mm F4 Macro APO G" }, { 24, "Minolta/Sony AF 24-105mm F3.5-4.5 (D) | " "Sigma 18-50mm F2.8 | " "Sigma 17-70mm F2.8-4.5 (D) | " "Sigma 20-40mm F2.8 EX DG Aspherical IF | " "Sigma 18-200mm F3.5-6.3 DC | " "Sigma 20-40mm F2.8 EX DG Aspherical IF | " "Sigma DC 18-125mm F4-5,6 D | " "Tamron SP AF 28-75mm F2.8 XR Di (IF) Macro" }, { 25, "Minolta AF 100-300mm F4.5-5.6 APO (D) | " "Sigma 100-300mm F4 EX (APO (D) or D IF) | " "Sigma 70mm F2.8 EX DG Macro | " "Sigma 20mm F1.8 EX DG Aspherical RF | " "Sigma 30mm F1.4 DG EX" }, { 27, "Minolta AF 85mm F1.4 G (D)" }, { 28, "Minolta/Sony AF 100mm F2.8 Macro (D) | " "Tamron SP AF 90mm F2.8 Di Macro" }, { 29, "Minolta/Sony AF 75-300mm F4.5-5.6 (D) " }, { 30, "Minolta AF 28-80mm F3.5-5.6 (D) | " "Sigma AF 10-20mm F4-5.6 EX DC | " "Sigma AF 12-24mm F4.5-5.6 EX DG | " "Sigma 28-70mm EX DG F2.8 | " "Sigma 55-200mm F4-5.6 DC" }, { 31, "Minolta AF 50mm F2.8 Macro(D) | " "Minolta AF 50mm F3.5 Macro" }, { 32, "Minolta AF 100-400mm F4.5-6.7(D) | " "Minolta AF 300mm F2.8G APO(D) SSM" }, { 33, "Minolta/Sony AF 70-200mm F2.8 G" }, { 35, "Minolta AF 85mm F1.4 G (D) Limited" }, { 36, "Minolta AF 28-100mm F3.5-5.6 (D)" }, { 38, "Minolta AF 17-35mm F2.8-4 (D)" }, { 39, "Minolta AF 28-75mm F2.8 (D)" }, { 40, "Minolta/Sony AF DT 18-70mm F3.5-5.6 (D) | " "Sony AF DT 18-200mm F3.5-6.3" }, { 41, "Minolta/Sony AF DT 11-18mm F4.5-5.6 (D) | " "Tamron SP AF 11-18mm F4.5-5.6 Di II LD Aspherical IF" }, { 42, "Minolta/Sony AF DT 18-200mm F3.5-6.3 (D)" }, { 43, "Sony 35mm F1.4 G (SAL-35F14G)" }, { 44, "Sony 50mm F1.4 (SAL-50F14)" }, { 45, "Carl Zeiss Planar T* 85mm F1.4 ZA" }, { 46, "Carl Zeiss Vario-Sonnar T* DT 16-80mm F3.5-4.5 ZA" }, { 47, "Carl Zeiss Sonnar T* 135mm F1.8 ZA" }, { 48, "Carl Zeiss Vario-Sonnar T* 24-70mm F2.8 ZA SSM (SAL-2470Z)" }, { 49, "Sony AF DT 55-200mm F4-5.6" }, { 50, "Sony AF DT 18-250mm F3.5-6.3" }, { 51, "Sony AF DT 16-105mm F3.5-5.6 | " "Sony AF DT 55-200mm F4-5.5" }, { 52, "Sony 70-300mm F4.5-5.6 G SSM" }, { 53, "Sony AF 70-400mm F4.5-5.6 G SSM (SAL-70400G)" }, { 54, "Carl Zeiss Vario-Sonnar T* 16-35mm F2.8 ZA SSM (SAL-1635Z)" }, { 55, "Sony DT 18-55mm F3.5-5.6 SAM (SAL-1855)" }, { 56, "Sony AF DT 55-200mm F4-5.6 SAM" }, { 57, "Sony AF DT 50mm F1.8 SAM" }, { 58, "Sony AF DT 30mm F2.8 SAM Macro" }, { 128, "Sigma 70-200mm F2.8 APO EX DG MACRO | " "Tamron 18-200mm F3.5-6.3 | " "Tamron 28-300mm F3.5-6.3 | " "Tamron 80-300mm F3.5-6.3 | " "Tamron AF 28-200mm F3.8-5.6 XR Di Aspherical [IF] MACRO | " "Tamron SP AF 17-35mm F2.8-4 Di LD Aspherical IF | " "Sigma AF 50-150mm F2.8 EX DC APO HSM II | " "Sigma 10-20mm F3.5 EX DC HSM | " "Sigma 70-200mm F2.8 II EX DG APO MACRO HSM" }, { 129, "Tamron 200-400mm F5.6 LD | " "Tamron 70-300mm F4-5.6 LD" }, { 131, "Tamron 20-40mm F2.7-3.5 SP Aspherical IF" }, { 135, "Vivitar 28-210mm F3.5-5.6" }, { 136, "Tokina EMZ M100 AF 100mm F3.5" }, { 137, "Cosina 70-210mm F2.8-4 AF" }, { 138, "Soligor 19-35mm F3.5-4.5" }, { 142, "Voigtlander 70-300mm F4.5-5.6" }, { 146, "Voigtlander Macro APO-Lanthar 125mm F2.5 SL" }, { 193, "Minolta AF 1.4x APO II" }, { 255, "Tamron SP AF 17-50mm F2.8 XR Di II LD Aspherical | " "Tamron AF 18-250mm F3.5-6.3 XR Di II LD | " "Tamron AF 55-200mm F4-5.6 Di II | " "Tamron AF 70-300mm F4-5.6 Di LD MACRO 1:2 | " "Tamron SP AF 200-500mm F5.0-6.3 Di LD IF | " "Tamron SP AF 10-24mm F3.5-4.5 Di II LD Aspherical IF | " "Tamron SP AF 70-200mm F2.8 Di LD IF Macro | " "Tamron SP AF 28-75mm F2.8 XR Di LD Aspherical IF" }, { 25500, "Minolta AF 50mm F1.7" }, { 25501, "Minolta AF 50mm F1.7" }, { 25510, "Minolta AF 35-70mm F1.4" }, { 25511, "Minolta AF 35-70mm F4 | " "Sigma UC AF 28-70mm F3.5-4.5 | " "Sigma AF 28-70mm F2.8 | " "Sigma M-AF 70-200mm F2.8 EX Aspherical | " "Quantaray M-AF 35-80mm F4-5.6 " }, { 25520, "Minolta AF 28-85mm F3.5-4.5" }, { 25521, "Minolta AF 28-85mm F3.5-4.5 | " "Tokina 19-35mm F3.5-4.5 | " "Tokina 28-70mm F2.8 AT-X | " "Tokina 80-400mm F4.5-5.6 AT-X AF II 840 | " "Tokina AF PRO 28-80mm F2.8 AT-X 280 | " "Tokina AT-X PRO II AF 28-70mm F2.6-2.8 270 | " "Tamron AF 19-35mm F3.5-4.5 | " "Angenieux AF 28-70mm F2.6" }, { 25530, "Minolta AF 28-135mm F4-4.5" }, { 25531, "Minolta AF 28-135mm F4-4.5 | " "Sigma ZOOM-alpha 35-135mm F3.5-4.5 | " "Sigma 28-105mm F2.8-4 Aspherical" }, { 25540, "Minolta AF 35-105mm F3.5-4.5" }, { 25541, "Minolta AF 35-105mm F3.5-4.5" }, { 25550, "Minolta AF 70-210mm F4" }, { 25551, "Minolta AF 70-210mm F4 Macro | " "Sigma 70-210mm F4-5.6 APO | " "Sigma M-AF 70-200mm F2.8 EX APO | " "Sigma 75-200mm F2.8-3.5" }, { 25560, "Minolta AF 135mm F2.8" }, { 25561, "Minolta AF 135mm F2.8" }, { 25570, "Minolta AF 28mm F2.8" }, { 25571, "Minolta/Sony AF 28mm F2.8" }, { 25580, "Minolta AF 24-50mm F4" }, { 25581, "Minolta AF 24-50mm F4" }, { 25600, "Minolta AF 100-200mm F4.5" }, { 25601, "Minolta AF 100-200mm F4.5" }, { 25610, "Minolta AF 75-300mm F4.5-5.6" }, { 25611, "Minolta AF 75-300mm F4.5-5.6 | " "Sigma 70-300mm F4-5.6 DL Macro | " "Sigma 300mm F4 APO Macro | " "Sigma AF 500mm F4.5 APO | " "Sigma AF 170-500mm F5-6.3 APO Aspherical | " "Tokina AT-X AF 300mm F4 | " "Tokina AT-X AF 400mm F5.6 SD | " "Tokina AF 730 II 75-300mm F4.5-5.6" }, { 25620, "Minolta AF 50mm F1.4" }, { 25621, "Minolta AF 50mm F1.4 [New]" }, { 25630, "Minolta AF 300mm F2.8G APO" }, { 25631, "Minolta AF 300mm F2.8 APO | " "Sigma AF 50-500mm F4-6.3 EX DG APO | " "Sigma AF 170-500mm F5-6.3 APO Aspherical | " "Sigma AF 500mm F4.5 EX DG APO | " "Sigma 400mm F5.6 APO" }, { 25640, "Minolta AF 50mm F2.8 Macro" }, { 25641, "Minolta AF 50mm F2.8 Macro | " "Sigma 50mm F2.8 EX Macro" }, { 25650, "Minolta AF 600mm F4 APO" }, { 25651, "Minolta AF 600mm F4 APO" }, { 25660, "Minolta AF 24mm F2.8" }, { 25661, "Minolta AF 24mm F2.8 | " "Sigma 17-35mm F2.8-4.0 EX-D" }, { 25720, "Minolta AF 500mm F8 Reflex" }, { 25721, "Minolta/Sony AF 500mm F8 Reflex" }, { 25780, "Minolta/Sony AF 16mm F2.8 Fisheye" }, { 25781, "Minolta/Sony AF 16mm F2.8 Fisheye | " "Sigma 8mm F4 EX [DG] Fisheye | " "Sigma 14mm F3.5 | " "Sigma 15mm F2.8 Fisheye" }, { 25790, "Minolta AF 20mm F2.8" }, { 25791, "Minolta/Sony AF 20mm F2.8" }, { 25810, "Minolta AF 100mm F2.8 Macro" }, { 25811, "Minolta AF 100mm F2.8 Macro [New] | " "Sigma AF 90mm F2.8 Macro | " "Sigma AF 105mm F2.8 EX [DG] Macro | " "Sigma 180mm F5.6 Macro | " "Tamron 90mm F2.8 Macro" }, { 25850, "Minolta AF 35-105mm F3.5-4.5" }, { 25851, "Beroflex 35-135mm F3.5-4.5" }, { 25858, "Minolta AF 35-105mm F3.5-4.5 New | " "Tamron 24-135mm F3.5-5.6" }, { 25880, "Minolta AF 70-210mm F3.5-4.5" }, { 25881, "Minolta AF 70-210mm F3.5-4.5" }, { 25890, "Minolta AF 80-200mm F2.8 APO" }, { 25891, "Minolta AF 80-200mm F2.8 APO | " "Tokina 80-200mm F2.8" }, { 25910, "Minolta AF 35mm F1.4G" }, { 25911, "Minolta AF 35mm F1.4" }, { 25920, "Minolta AF 85mm F1.4G" }, { 25921, "Minolta AF 85mm F1.4G(D)" }, { 25930, "Minolta AF 200mm F2.8 APO" }, { 25931, "Minolta AF 200mm F2.8 G APO" }, { 25940, "Minolta AF 3X-1X F1.7-2.8 Macro" }, { 25941, "Minolta AF 3x-1x F1.7-2.8 Macro" }, { 25960, "Minolta AF 28mm F2" }, { 25961, "Minolta AF 28mm F2" }, { 25970, "Minolta AF 35mm F2" }, { 25971, "Minolta AF 35mm F2 [New]" }, { 25980, "Minolta AF 100mm F2" }, { 25981, "Minolta AF 100mm F2" }, { 26040, "Minolta AF 80-200mm F4.5-5.6" }, { 26041, "Minolta AF 80-200mm F4.5-5.6" }, { 26050, "Minolta AF 35-80mm F4-5.6" }, { 26051, "Minolta AF 35-80mm F4-5.6" }, { 26060, "Minolta AF 100-300mm F4.5-5.6" }, { 26061, "Minolta AF 100-300mm F4.5-5.6(D) | " "Sigma 105mm F2.8 Macro EX-DG" }, { 26070, "Minolta AF 35-80mm F4-5.6" }, { 26071, "Minolta AF 35-80mm F4-5.6" }, { 26080, "Minolta AF 300mm F2.8G APO High Speed" }, { 26081, "Minolta AF 300mm F2.8G" }, { 26090, "Minolta AF 600mm F4G APO High Speed" }, { 26091, "Minolta AF 600mm F4 HS-APO G" }, { 26120, "Minolta AF 200mm F2.8G APO High Speed" }, { 26121, "Minolta AF 200mm F2.8G(D)" }, { 26130, "Minolta AF 50mm F1.7" }, { 26131, "Minolta AF 50mm F1.7 New" }, { 26150, "Minolta AF 28-105mm F3.5-4.5 Xi" }, { 26151, "Minolta AF 28-105mm F3.5-4.5 xi" }, { 26160, "Minolta AF 35-200mm F4.5-5.6 Xi" }, { 26161, "Minolta AF 35-200mm F4.5-5.6 Xi" }, { 26180, "Minolta AF 28-80mm F4-5.6 Xi" }, { 26181, "Minolta AF 28-80mm F4-5.6 xi" }, { 26190, "Minolta AF 80-200mm F4.5-5.6 Xi" }, { 26191, "Minolta AF 80-200mm F4.5-5.6 Xi" }, { 26201, "Minolta AF 28-70mm F2.8 G" }, { 26210, "Minolta AF 100-300mm F4.5-5.6 Xi" }, { 26211, "Minolta AF 100-300mm F4.5-5.6 xi" }, { 26240, "Minolta AF 35-80mm F4-5.6 Power" }, { 26241, "Minolta AF 35-80mm F4-5.6 Power Zoom" }, { 26281, "Minolta AF 80-200mm F2.8 G" }, { 26291, "Minolta AF 85mm F1.4 New" }, { 26311, "Minolta/Sony AF 100-300mm F4.5-5.6 APO" }, { 26321, "Minolta AF 24-50mm F4 New" }, { 26381, "Minolta AF 50mm F2.8 Macro New" }, { 26391, "Minolta AF 100mm F2.8 Macro" }, { 26411, "Minolta/Sony AF 20mm F2.8 New" }, { 26421, "Minolta AF 24mm F2.8 New" }, { 26441, "Minolta AF 100-400mm F4.5-6.7 APO" }, { 26621, "Minolta AF 50mm F1.4 New" }, { 26671, "Minolta AF 35mm F2 New" }, { 26681, "Minolta AF 28mm F2 New" }, { 26721, "Minolta AF 24-105mm F3.5-4.5 (D)" }, { 45671, "Tokina 70-210mm F4-5.6" }, { 45741, "Minolta AF200mm F2.8G x2 | " "Tokina 300mm F2.8 x2 | " "Tokina RF 500mm F8.0 x2 | " "Tamron SP AF 90mm F2.5"}, { 45751, "1.4x Teleconverter " }, { 45851, "Tamron SP AF 300mm F2.8 LD IF" }, { 65535, "T-Mount | " "Arax MC 35mm F2.8 Tilt+Shift | " "Arax MC 80mm F2.8 Tilt+Shift | " "Zenitar MF 16mm F2.8 Fisheye M42 | " "Samyang 500mm Mirror F8.0 | " "Pentacon Auto 135mm F2.8 | " "Pentacon Auto 29mm F2.8 | " "Helios 44-2 58mm F2.0 | " "No Lens" } }; std::ostream& printMinoltaSonyLensID(std::ostream& os, const Value& value, const ExifData* metadata) { return EXV_PRINT_TAG(minoltaSonyLensID)(os, value, metadata); } // ---------------------------------------------------------------------------------------------------- //! Lookup table to translate Minolta A100 and all other Sony Alpha camera color mode values to readable labels extern const TagDetails minoltaSonyColorMode[] = { { 0, N_("Standard") }, { 1, N_("Vivid Color") }, { 2, N_("Portrait") }, { 3, N_("Landscape") }, { 4, N_("Sunset") }, { 5, N_("Night View/Portrait") }, { 6, N_("Black & White") }, { 7, N_("AdobeRGB") }, { 12, N_("Neutral") }, { 100, N_("Neutral") }, { 101, N_("Clear") }, { 102, N_("Deep") }, { 103, N_("Light") }, { 104, N_("Night View") }, { 105, N_("Autumn Leaves") } }; std::ostream& printMinoltaSonyColorMode(std::ostream& os, const Value& value, const ExifData* metadata) { return EXV_PRINT_TAG(minoltaSonyColorMode)(os, value, metadata); } // ---------------------------------------------------------------------------------------------------- //! Lookup table to translate Minolta/Sony bool function values to readable labels extern const TagDetails minoltaSonyBoolFunction[] = { { 0, N_("Off") }, { 1, N_("On") } }; std::ostream& printMinoltaSonyBoolValue(std::ostream& os, const Value& value, const ExifData* metadata) { return EXV_PRINT_TAG(minoltaSonyBoolFunction)(os, value, metadata); } // ---------------------------------------------------------------------------------------------------- //! Lookup table to translate Minolta/Sony bool inverse function values to readable labels extern const TagDetails minoltaSonyBoolInverseFunction[] = { { 0, N_("On") }, { 1, N_("Off") } }; std::ostream& printMinoltaSonyBoolInverseValue(std::ostream& os, const Value& value, const ExifData* metadata) { return EXV_PRINT_TAG(minoltaSonyBoolInverseFunction)(os, value, metadata); } // ---------------------------------------------------------------------------------------------------- //! Lookup table to translate Sony camera settings focus mode values to readable labels extern const TagDetails minoltaSonyAFAreaMode[] = { { 0, N_("Wide") }, { 1, N_("Local") }, { 2, N_("Spot") } }; std::ostream& printMinoltaSonyAFAreaMode(std::ostream& os, const Value& value, const ExifData* metadata) { return EXV_PRINT_TAG(minoltaSonyAFAreaMode)(os, value, metadata); } // ---------------------------------------------------------------------------------------------------- //! Lookup table to translate Sony camera settings Local AF Area Point values to readable labels extern const TagDetails minoltaSonyLocalAFAreaPoint[] = { { 1, N_("Center") }, { 2, N_("Top") }, { 3, N_("Top-Right") }, { 4, N_("Right") }, { 5, N_("Bottom-Right") }, { 6, N_("Bottom") }, { 7, N_("Bottom-Left") }, { 8, N_("Left") }, { 9, N_("Top-Left") }, { 10, N_("Far-Right") }, { 11, N_("Far-Left") } }; std::ostream& printMinoltaSonyLocalAFAreaPoint(std::ostream& os, const Value& value, const ExifData* metadata) { return EXV_PRINT_TAG(minoltaSonyLocalAFAreaPoint)(os, value, metadata); } // ---------------------------------------------------------------------------------------------------- //! Lookup table to translate Sony camera settings dynamic range optimizer mode values to readable labels extern const TagDetails minoltaSonyDynamicRangeOptimizerMode[] = { { 0, N_("Off") }, { 1, N_("Standard") }, { 2, N_("Advanced Auto") }, { 3, N_("Advanced Level") }, { 4097, N_("Auto") } }; std::ostream& printMinoltaSonyDynamicRangeOptimizerMode(std::ostream& os, const Value& value, const ExifData* metadata) { return EXV_PRINT_TAG(minoltaSonyDynamicRangeOptimizerMode)(os, value, metadata); } // ---------------------------------------------------------------------------------------------------- //! Lookup table to translate Sony camera settings priority setup shutter release values to readable labels extern const TagDetails minoltaSonyPrioritySetupShutterRelease[] = { { 0, N_("AF") }, { 1, N_("Release") } }; std::ostream& printMinoltaSonyPrioritySetupShutterRelease(std::ostream& os, const Value& value, const ExifData* metadata) { return EXV_PRINT_TAG(minoltaSonyPrioritySetupShutterRelease)(os, value, metadata); } // ---------------------------------------------------------------------------------------------------- //! Lookup table to translate Sony camera settings quality values to readable labels extern const TagDetails minoltaSonyQualityCs[] = { { 0, N_("RAW ") }, { 2, N_("CRAW ") }, { 16, N_("Extra Fine") }, { 32, N_("Fine") }, { 34, N_("RAW+JPEG") }, { 35, N_("CRAW+JPEG") }, { 48, N_("Standard") } }; std::ostream& printMinoltaSonyQualityCs(std::ostream& os, const Value& value, const ExifData* metadata) { return EXV_PRINT_TAG(minoltaSonyQualityCs)(os, value, metadata); } // ---------------------------------------------------------------------------------------------------- //! Lookup table to translate Sony camera settings rotation values to readable labels extern const TagDetails minoltaSonyRotation[] = { { 0, N_("Horizontal (normal)") }, { 1, N_("Rotate 90 CW") }, { 2, N_("Rotate 270 CW") } }; std::ostream& printMinoltaSonyRotation(std::ostream& os, const Value& value, const ExifData* metadata) { return EXV_PRINT_TAG(minoltaSonyRotation)(os, value, metadata); } // ---------------------------------------------------------------------------------------------------- //! Lookup table to translate Minolta/Sony scene mode values to readable labels extern const TagDetails minoltaSonySceneMode[] = { { 0, N_("Standard") }, { 1, N_("Portrait") }, { 2, N_("Text") }, { 3, N_("Night Scene") }, { 4, N_("Sunset") }, { 5, N_("Sports") }, { 6, N_("Landscape") }, { 7, N_("Night Portrait") }, { 8, N_("Macro") }, { 9, N_("Super Macro") }, { 16, N_("Auto") }, { 17, N_("Night View/Portrait") } }; std::ostream& printMinoltaSonySceneMode(std::ostream& os, const Value& value, const ExifData* metadata) { return EXV_PRINT_TAG(minoltaSonySceneMode)(os, value, metadata); } // ---------------------------------------------------------------------------------------------------- //! Lookup table to translate Sony/Minolta image quality values to readable labels extern const TagDetails minoltaSonyImageQuality[] = { { 0, N_("Raw") }, { 1, N_("Super Fine") }, { 2, N_("Fine") }, { 3, N_("Standard") }, { 4, N_("Economy") }, { 5, N_("Extra Fine") }, { 6, N_("Raw + JPEG") }, { 7, N_("Compressed Raw") }, { 8, N_("Compressed Raw + JPEG") } }; std::ostream& printMinoltaSonyImageQuality(std::ostream& os, const Value& value, const ExifData* metadata) { return EXV_PRINT_TAG(minoltaSonyImageQuality)(os, value, metadata); } // ---------------------------------------------------------------------------------------------------- //! Lookup table to translate Sony/Minolta teleconverter model values to readable labels extern const TagDetails minoltaSonyTeleconverterModel[] = { { 0x00, N_("None") }, { 0x48, N_("Minolta AF 2x APO (D)") }, { 0x50, N_("Minolta AF 2x APO II") }, { 0x88, N_("Minolta AF 1.4x APO (D)") }, { 0x90, N_("Minolta AF 1.4x APO II") } }; std::ostream& printMinoltaSonyTeleconverterModel(std::ostream& os, const Value& value, const ExifData* metadata) { return EXV_PRINT_TAG(minoltaSonyTeleconverterModel)(os, value, metadata); } // ---------------------------------------------------------------------------------------------------- //! Lookup table to translate Sony/Minolta Std camera settings white balance values to readable labels extern const TagDetails minoltaSonyWhiteBalanceStd[] = { { 0x00, N_("Auto") }, { 0x01, N_("Color Temperature/Color Filter") }, { 0x10, N_("Daylight") }, { 0x20, N_("Cloudy") }, { 0x30, N_("Shade") }, { 0x40, N_("Tungsten") }, { 0x50, N_("Flash") }, { 0x60, N_("Fluorescent") }, { 0x70, N_("Custom") } }; std::ostream& printMinoltaSonyWhiteBalanceStd(std::ostream& os, const Value& value, const ExifData* metadata) { return EXV_PRINT_TAG(minoltaSonyWhiteBalanceStd)(os, value, metadata); } //! Lookup table to translate Sony/Minolta zone matching values to readable labels extern const TagDetails minoltaSonyZoneMatching[] = { { 0, N_("ISO Setting Used") }, { 1, N_("High Key") }, { 2, N_("Low Key") } }; std::ostream& printMinoltaSonyZoneMatching(std::ostream& os, const Value& value, const ExifData* metadata) { return EXV_PRINT_TAG(minoltaSonyZoneMatching)(os, value, metadata); } std::ostream& printMinoltaSonyFlashExposureComp(std::ostream& os, const Value& value, const ExifData*) { if (value.count() != 1 || value.typeId() != signedRational) { return os << "(" << value << ")"; } return os << std::fixed << std::setprecision(2) << value.toFloat(0) << " EV"; } }} // namespace Internal, Exiv2 exiv2-0.23/src/orfimage.hpp0000644000175000017500000001311711732641407015410 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! @file orfimage.hpp @brief Olympus RAW image @version $Rev: 2681 $ @author Jeff Costlow costlow@gmail.com @date 31-Jul-07, costlow: created */ #ifndef ORFIMAGE_HPP_ #define ORFIMAGE_HPP_ // ***************************************************************************** // included header files #include "image.hpp" #include "basicio.hpp" #include "types.hpp" // + standard includes #include // ***************************************************************************** // namespace extensions namespace Exiv2 { // ***************************************************************************** // class definitions // Add ORF to the supported image formats namespace ImageType { const int orf = 9; //!< ORF image type (see class OrfImage) } /*! @brief Class to access raw Olympus ORF images. Exif metadata is supported directly, IPTC is read from the Exif data, if present. */ class EXIV2API OrfImage : public Image { public: //! @name Creators //@{ /*! @brief Constructor that can either open an existing ORF image or create a new image from scratch. If a new image is to be created, any existing data is overwritten. Since the constructor can not return a result, callers should check the good() method after object construction to determine success or failure. @param io An auto-pointer that owns a BasicIo instance used for reading and writing image metadata. \b Important: The constructor takes ownership of the passed in BasicIo instance through the auto-pointer. Callers should not continue to use the BasicIo instance after it is passed to this method. Use the Image::io() method to get a temporary reference. @param create Specifies if an existing image should be read (false) or if a new file should be created (true). */ OrfImage(BasicIo::AutoPtr io, bool create); //@} //! @name Manipulators //@{ void readMetadata(); void writeMetadata(); /*! @brief Not supported. ORF format does not contain a comment. Calling this function will throw an Error(32). */ void setComment(const std::string& comment); //@} //! @name Accessors //@{ std::string mimeType() const; int pixelWidth() const; int pixelHeight() const; //@} private: //! @name NOT Implemented //@{ //! Copy constructor OrfImage(const OrfImage& rhs); //! Assignment operator OrfImage& operator=(const OrfImage& rhs); //@} }; // class OrfImage /*! @brief Stateless parser class for data in ORF format. Images use this class to decode and encode ORF data. See class TiffParser for details. */ class EXIV2API OrfParser { public: /*! @brief Decode metadata from a buffer \em pData of length \em size with data in ORF format to the provided metadata containers. See TiffParser::decode(). */ static ByteOrder decode( ExifData& exifData, IptcData& iptcData, XmpData& xmpData, const byte* pData, uint32_t size ); /*! @brief Encode metadata from the provided metadata to ORF format. See TiffParser::encode(). */ static WriteMethod encode( BasicIo& io, const byte* pData, uint32_t size, ByteOrder byteOrder, const ExifData& exifData, const IptcData& iptcData, const XmpData& xmpData ); }; // class OrfParser // ***************************************************************************** // template, inline and free functions // These could be static private functions on Image subclasses but then // ImageFactory needs to be made a friend. /*! @brief Create a new OrfImage instance and return an auto-pointer to it. Caller owns the returned object and the auto-pointer ensures that it will be deleted. */ EXIV2API Image::AutoPtr newOrfInstance(BasicIo::AutoPtr io, bool create); //! Check if the file iIo is an ORF image. EXIV2API bool isOrfType(BasicIo& iIo, bool advance); } // namespace Exiv2 #endif // #ifndef ORFIMAGE_HPP_ exiv2-0.23/src/tiffmn-test.cpp0000644000175000017500000001417611027153701016050 0ustar andreasandreas// ***************************************************************** -*- C++ -*- // tiffmn-test.cpp, $Rev: 1512 $ // Makernote TIFF writer tests. #include "tiffimage.hpp" #include "exif.hpp" #include "error.hpp" #include #include #include using namespace Exiv2; void canonmn(const std::string& path); void fujimn(const std::string& path); void minoltamn(const std::string& path); void nikon1mn(const std::string& path); void nikon2mn(const std::string& path); void nikon3mn(const std::string& path); void olympusmn(const std::string& path); void panasonicmn(const std::string& path); void sigmamn(const std::string& path); void sony1mn(const std::string& path); void sony2mn(const std::string& path); void print(const ExifData& exifData); int main() try { canonmn("exiv2-canonmn.tif"); fujimn("exiv2-fujimn.tif"); minoltamn("exiv2-minoltamn.tif"); nikon1mn("exiv2-nikon1mn.tif"); nikon2mn("exiv2-nikon2mn.tif"); nikon3mn("exiv2-nikon3mn.tif"); olympusmn("exiv2-olympusmn.tif"); panasonicmn("exiv2-panasonicmn.tif"); sigmamn("exiv2-sigmamn.tif"); sony1mn("exiv2-sony1mn.tif"); sony2mn("exiv2-sony2mn.tif"); return 0; } catch (const Error& e) { std::cout << e << "\n"; } void canonmn(const std::string& path) { TiffImage tiffImage(BasicIo::AutoPtr(new FileIo(path)), false); ExifData& exifData = tiffImage.exifData(); exifData["Exif.Image.Make"] = "Canon"; exifData["Exif.Photo.DateTimeOriginal"] = "Yesterday at noon"; exifData["Exif.Canon.OwnerName"] = "Camera Owner"; print(exifData); tiffImage.writeMetadata(); } void fujimn(const std::string& path) { TiffImage tiffImage(BasicIo::AutoPtr(new FileIo(path)), false); ExifData& exifData = tiffImage.exifData(); exifData["Exif.Image.Make"] = "FUJIFILM"; exifData["Exif.Photo.DateTimeOriginal"] = "Yesterday at noon"; exifData["Exif.Fujifilm.Quality"] = "Very good"; print(exifData); tiffImage.writeMetadata(); } void minoltamn(const std::string& path) { TiffImage tiffImage(BasicIo::AutoPtr(new FileIo(path)), false); ExifData& exifData = tiffImage.exifData(); exifData["Exif.Image.Make"] = "Minolta"; exifData["Exif.Photo.DateTimeOriginal"] = "Yesterday at noon"; exifData["Exif.Minolta.Quality"] = uint32_t(42); print(exifData); tiffImage.writeMetadata(); } void nikon1mn(const std::string& path) { TiffImage tiffImage(BasicIo::AutoPtr(new FileIo(path)), false); ExifData& exifData = tiffImage.exifData(); exifData["Exif.Image.Make"] = "NIKON"; exifData["Exif.Photo.DateTimeOriginal"] = "Yesterday at noon"; exifData["Exif.Nikon1.Quality"] = "Excellent"; print(exifData); tiffImage.writeMetadata(); } void nikon2mn(const std::string& path) { TiffImage tiffImage(BasicIo::AutoPtr(new FileIo(path)), false); ExifData& exifData = tiffImage.exifData(); exifData["Exif.Image.Make"] = "NIKON"; exifData["Exif.Photo.DateTimeOriginal"] = "Yesterday at noon"; exifData["Exif.Nikon2.Quality"] = uint16_t(42); print(exifData); tiffImage.writeMetadata(); } void nikon3mn(const std::string& path) { TiffImage tiffImage(BasicIo::AutoPtr(new FileIo(path)), false); ExifData& exifData = tiffImage.exifData(); exifData["Exif.Image.Make"] = "NIKON"; exifData["Exif.Photo.DateTimeOriginal"] = "Yesterday at noon"; exifData["Exif.Nikon3.Quality"] = "Nikon3 quality"; print(exifData); tiffImage.writeMetadata(); } void olympusmn(const std::string& path) { TiffImage tiffImage(BasicIo::AutoPtr(new FileIo(path)), false); ExifData& exifData = tiffImage.exifData(); exifData["Exif.Image.Make"] = "OLYMPUS"; exifData["Exif.Photo.DateTimeOriginal"] = "Yesterday at noon"; exifData["Exif.Olympus.Quality"] = uint16_t(42); print(exifData); tiffImage.writeMetadata(); } void panasonicmn(const std::string& path) { TiffImage tiffImage(BasicIo::AutoPtr(new FileIo(path)), false); ExifData& exifData = tiffImage.exifData(); exifData["Exif.Image.Make"] = "Panasonic"; exifData["Exif.Photo.DateTimeOriginal"] = "Yesterday at noon"; exifData["Exif.Panasonic.Quality"] = uint16_t(42); print(exifData); tiffImage.writeMetadata(); } void sigmamn(const std::string& path) { TiffImage tiffImage(BasicIo::AutoPtr(new FileIo(path)), false); ExifData& exifData = tiffImage.exifData(); exifData["Exif.Image.Make"] = "SIGMA"; exifData["Exif.Photo.DateTimeOriginal"] = "Yesterday at noon"; exifData["Exif.Sigma.Quality"] = "Sigma quality"; print(exifData); tiffImage.writeMetadata(); } void sony1mn(const std::string& path) { TiffImage tiffImage(BasicIo::AutoPtr(new FileIo(path)), false); ExifData& exifData = tiffImage.exifData(); exifData["Exif.Image.Make"] = "SONY"; exifData["Exif.Photo.DateTimeOriginal"] = "Yesterday at noon"; exifData["Exif.Sony.0x2000"] = uint16_t(42); print(exifData); tiffImage.writeMetadata(); } void sony2mn(const std::string& path) { TiffImage tiffImage(BasicIo::AutoPtr(new FileIo(path)), false); ExifData& exifData = tiffImage.exifData(); exifData["Exif.Image.Make"] = "SONY"; exifData["Exif.Photo.DateTimeOriginal"] = "Yesterday at noon"; exifData["Exif.Sony.0x2001"] = uint16_t(43); print(exifData); tiffImage.writeMetadata(); } void print(const ExifData& exifData) { if (exifData.empty()) { std::string error("No Exif data found in the file"); throw Exiv2::Error(1, error); } Exiv2::ExifData::const_iterator end = exifData.end(); for (Exiv2::ExifData::const_iterator i = exifData.begin(); i != end; ++i) { std::cout << std::setw(44) << std::setfill(' ') << std::left << i->key() << " " << "0x" << std::setw(4) << std::setfill('0') << std::right << std::hex << i->tag() << " " << std::setw(9) << std::setfill(' ') << std::left << i->typeName() << " " << std::dec << std::setw(3) << std::setfill(' ') << std::right << i->count() << " " << std::dec << i->value() << "\n"; } } exiv2-0.23/src/utils.cpp0000644000175000017500000001234011732641407014747 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /* File: utils.cpp Version: $Rev: 2681 $ Author(s): Andreas Huggel (ahu) History: 08-Dec-03, ahu: created */ // ***************************************************************************** #include "rcsid_int.hpp" EXIV2_RCSID("@(#) $Id: utils.cpp 2681 2012-03-22 15:19:35Z ahuggel $") // ***************************************************************************** // included header files #ifdef _MSC_VER # include "exv_msvc.h" #else # include "exv_conf.h" #endif #include "utils.hpp" // + standard includes #include #include #ifdef _MSC_VER # include "getopt_win32.h" # define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) #endif #ifdef EXV_HAVE_UNISTD_H # include // for getopt(), stat() #endif #include #include #include #include #include #include #include namespace Util { // ***************************************************************************** // class Getopt Getopt::Getopt() : errcnt_(0) { } Getopt::~Getopt() { } int Getopt::getopt(int argc, char* const argv[], const std::string& optstring) { progname_ = Util::basename(argv[0]); for (;;) { int c = ::getopt(argc, argv, optstring.c_str()); if (c == -1) break; errcnt_ += option(c, ::optarg == 0 ? "" : ::optarg, ::optopt); } for (int i = ::optind; i < argc; i++) { errcnt_ += nonoption(argv[i]); } return errcnt_; } int Getopt::nonoption(const std::string& /*argv*/) { return 0; } // ***************************************************************************** // free functions std::string dirname(const std::string& path) { if (path == "") return "."; // Strip trailing slashes or backslashes std::string p = path; while ( p.length() > 1 && (p[p.length()-1] == '\\' || p[p.length()-1] == '/')) { p = p.substr(0, p.length()-1); } if (p == "\\" || p == "/") return p; if (p.length() == 2 && p[1] == ':') return p; // For Windows paths std::string::size_type idx = p.find_last_of("\\/"); if (idx == std::string::npos) return "."; if (idx == 1 && p[0] == '\\' && p[1] == '\\') return p; // For Windows paths p = p.substr(0, idx == 0 ? 1 : idx); while ( p.length() > 1 && (p[p.length()-1] == '\\' || p[p.length()-1] == '/')) { p = p.substr(0, p.length()-1); } return p; } std::string basename(const std::string& path, bool delsuffix) { if (path == "") return "."; // Strip trailing slashes or backslashes std::string p = path; while ( p.length() > 1 && (p[p.length()-1] == '\\' || p[p.length()-1] == '/')) { p = p.substr(0, p.length()-1); } if (p.length() == 2 && p[1] == ':') return ""; // For Windows paths std::string::size_type idx = p.find_last_of("\\/"); if (idx == 1 && p[0] == '\\' && p[1] == '\\') return ""; // For Windows paths if (idx != std::string::npos) p = p.substr(idx+1); if (delsuffix) p = p.substr(0, p.length() - suffix(p).length()); return p; } std::string suffix(const std::string& path) { std::string b = basename(path); std::string::size_type idx = b.rfind('.'); if (idx == std::string::npos || idx == 0 || idx == b.length()-1) { return ""; } return b.substr(idx); } bool strtol(const char* nptr, long& n) { if (!nptr || *nptr == '\0') return false; char* endptr = 0; long tmp = std::strtol(nptr, &endptr, 10); if (*endptr != '\0') return false; if (tmp == LONG_MAX || tmp == LONG_MIN) return false; n = tmp; return true; } void replace(std::string& text, const std::string& searchText, const std::string& replaceText) { std::string::size_type index = 0; while ((index = text.find(searchText, index)) != std::string::npos) { text.replace(index, searchText.length(), replaceText.c_str(), replaceText.length()); index++; } } } // namespace Util exiv2-0.23/src/tzfile.h0000644000175000017500000001224210144213055014540 0ustar andreasandreas/*! @file tzfile.h @brief This file is from the tz distribution at ftp://elsie.nci.nih.gov/pub/ @version $Rev: 392 $ */ #ifndef TZFILE_H #define TZFILE_H /* ** This file is in the public domain, so clarified as of ** 1996-06-05 by Arthur David Olson (arthur_david_olson@nih.gov). */ /* ** This header is for use ONLY with the time conversion code. ** There is no guarantee that it will remain unchanged, ** or that it will remain at all. ** Do NOT copy it to any system include directory. ** Thank you! */ /* ** ID */ #ifndef lint #ifndef NOID static char tzfilehid[] = "@(#)tzfile.h 7.14"; #endif /* !defined NOID */ #endif /* !defined lint */ /* ** Information about time zone files. */ #ifndef TZDIR #define TZDIR "/usr/local/etc/zoneinfo" /* Time zone object file directory */ #endif /* !defined TZDIR */ #ifndef TZDEFAULT #define TZDEFAULT "localtime" #endif /* !defined TZDEFAULT */ #ifndef TZDEFRULES #define TZDEFRULES "posixrules" #endif /* !defined TZDEFRULES */ /* ** Each file begins with. . . */ #define TZ_MAGIC "TZif" struct tzhead { char tzh_magic[4]; /* TZ_MAGIC */ char tzh_reserved[16]; /* reserved for future use */ char tzh_ttisgmtcnt[4]; /* coded number of trans. time flags */ char tzh_ttisstdcnt[4]; /* coded number of trans. time flags */ char tzh_leapcnt[4]; /* coded number of leap seconds */ char tzh_timecnt[4]; /* coded number of transition times */ char tzh_typecnt[4]; /* coded number of local time types */ char tzh_charcnt[4]; /* coded number of abbr. chars */ }; /* ** . . .followed by. . . ** ** tzh_timecnt (char [4])s coded transition times a la time(2) ** tzh_timecnt (unsigned char)s types of local time starting at above ** tzh_typecnt repetitions of ** one (char [4]) coded UTC offset in seconds ** one (unsigned char) used to set tm_isdst ** one (unsigned char) that's an abbreviation list index ** tzh_charcnt (char)s '\0'-terminated zone abbreviations ** tzh_leapcnt repetitions of ** one (char [4]) coded leap second transition times ** one (char [4]) total correction after above ** tzh_ttisstdcnt (char)s indexed by type; if TRUE, transition ** time is standard time, if FALSE, ** transition time is wall clock time ** if absent, transition times are ** assumed to be wall clock time ** tzh_ttisgmtcnt (char)s indexed by type; if TRUE, transition ** time is UTC, if FALSE, ** transition time is local time ** if absent, transition times are ** assumed to be local time */ /* ** In the current implementation, "tzset()" refuses to deal with files that ** exceed any of the limits below. */ #ifndef TZ_MAX_TIMES /* ** The TZ_MAX_TIMES value below is enough to handle a bit more than a ** year's worth of solar time (corrected daily to the nearest second) or ** 138 years of Pacific Presidential Election time ** (where there are three time zone transitions every fourth year). */ #define TZ_MAX_TIMES 370 #endif /* !defined TZ_MAX_TIMES */ #ifndef TZ_MAX_TYPES #ifndef NOSOLAR #define TZ_MAX_TYPES 256 /* Limited by what (unsigned char)'s can hold */ #endif /* !defined NOSOLAR */ #ifdef NOSOLAR /* ** Must be at least 14 for Europe/Riga as of Jan 12 1995, ** as noted by Earl Chew . */ #define TZ_MAX_TYPES 20 /* Maximum number of local time types */ #endif /* !defined NOSOLAR */ #endif /* !defined TZ_MAX_TYPES */ #ifndef TZ_MAX_CHARS #define TZ_MAX_CHARS 50 /* Maximum number of abbreviation characters */ /* (limited by what unsigned chars can hold) */ #endif /* !defined TZ_MAX_CHARS */ #ifndef TZ_MAX_LEAPS #define TZ_MAX_LEAPS 50 /* Maximum number of leap second corrections */ #endif /* !defined TZ_MAX_LEAPS */ #define SECSPERMIN 60 #define MINSPERHOUR 60 #define HOURSPERDAY 24 #define DAYSPERWEEK 7 #define DAYSPERNYEAR 365 #define DAYSPERLYEAR 366 #define SECSPERHOUR (SECSPERMIN * MINSPERHOUR) #define SECSPERDAY ((long) SECSPERHOUR * HOURSPERDAY) #define MONSPERYEAR 12 #define TM_SUNDAY 0 #define TM_MONDAY 1 #define TM_TUESDAY 2 #define TM_WEDNESDAY 3 #define TM_THURSDAY 4 #define TM_FRIDAY 5 #define TM_SATURDAY 6 #define TM_JANUARY 0 #define TM_FEBRUARY 1 #define TM_MARCH 2 #define TM_APRIL 3 #define TM_MAY 4 #define TM_JUNE 5 #define TM_JULY 6 #define TM_AUGUST 7 #define TM_SEPTEMBER 8 #define TM_OCTOBER 9 #define TM_NOVEMBER 10 #define TM_DECEMBER 11 #define TM_YEAR_BASE 1900 #define EPOCH_YEAR 1970 #define EPOCH_WDAY TM_THURSDAY /* ** Accurate only for the past couple of centuries; ** that will probably do. */ #define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0)) #ifndef USG /* ** Use of the underscored variants may cause problems if you move your code to ** certain System-V-based systems; for maximum portability, use the ** underscore-free variants. The underscored variants are provided for ** backward compatibility only; they may disappear from future versions of ** this file. */ #define SECS_PER_MIN SECSPERMIN #define MINS_PER_HOUR MINSPERHOUR #define HOURS_PER_DAY HOURSPERDAY #define DAYS_PER_WEEK DAYSPERWEEK #define DAYS_PER_NYEAR DAYSPERNYEAR #define DAYS_PER_LYEAR DAYSPERLYEAR #define SECS_PER_HOUR SECSPERHOUR #define SECS_PER_DAY SECSPERDAY #define MONS_PER_YEAR MONSPERYEAR #endif /* !defined USG */ #endif /* !defined TZFILE_H */ exiv2-0.23/src/xmp.cpp0000644000175000017500000007266711732641407014435 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /* File: xmp.cpp Version: $Rev: 2681 $ Author(s): Andreas Huggel (ahu) History: 13-July-07, ahu: created */ // ***************************************************************************** #include "rcsid_int.hpp" EXIV2_RCSID("@(#) $Id: xmp.cpp 2681 2012-03-22 15:19:35Z ahuggel $") // ***************************************************************************** // included header files #include "xmp.hpp" #include "types.hpp" #include "error.hpp" #include "value.hpp" #include "properties.hpp" // + standard includes #include #include #include #include // Adobe XMP Toolkit #ifdef EXV_HAVE_XMP_TOOLKIT # define TXMP_STRING_TYPE std::string # include # include #endif // EXV_HAVE_XMP_TOOLKIT // ***************************************************************************** // local declarations namespace { //! Unary predicate that matches an Xmpdatum by key class FindXmpdatum { public: //! Constructor, initializes the object with key FindXmpdatum(const Exiv2::XmpKey& key) : key_(key.key()) {} /*! @brief Returns true if prefix and property of the argument Xmpdatum are equal to that of the object. */ bool operator()(const Exiv2::Xmpdatum& xmpdatum) const { return key_ == xmpdatum.key(); } private: std::string key_; }; // class FindXmpdatum #ifdef EXV_HAVE_XMP_TOOLKIT //! Convert XMP Toolkit struct option bit to Value::XmpStruct Exiv2::XmpValue::XmpStruct xmpStruct(const XMP_OptionBits& opt); //! Convert Value::XmpStruct to XMP Toolkit array option bits XMP_OptionBits xmpArrayOptionBits(Exiv2::XmpValue::XmpStruct xs); //! Convert XMP Toolkit array option bits to array TypeId Exiv2::TypeId arrayValueTypeId(const XMP_OptionBits& opt); //! Convert XMP Toolkit array option bits to Value::XmpArrayType Exiv2::XmpValue::XmpArrayType xmpArrayType(const XMP_OptionBits& opt); //! Convert Value::XmpArrayType to XMP Toolkit array option bits XMP_OptionBits xmpArrayOptionBits(Exiv2::XmpValue::XmpArrayType xat); //! Convert XmpFormatFlags to XMP Toolkit format option bits XMP_OptionBits xmpFormatOptionBits(Exiv2::XmpParser::XmpFormatFlags flags); # ifdef DEBUG //! Print information about a parsed XMP node void printNode(const std::string& schemaNs, const std::string& propPath, const std::string& propValue, const XMP_OptionBits& opt); # endif // DEBUG #endif // EXV_HAVE_XMP_TOOLKIT //! Make an XMP key from a schema namespace and property path Exiv2::XmpKey::AutoPtr makeXmpKey(const std::string& schemaNs, const std::string& propPath); //! Helper class used to serialize critical sections class AutoLock { public: AutoLock(Exiv2::XmpParser::XmpLockFct xmpLockFct, void* pLockData) : xmpLockFct_(xmpLockFct), pLockData_(pLockData) { if (xmpLockFct_) xmpLockFct_(pLockData_, true); } ~AutoLock() { if (xmpLockFct_) xmpLockFct_(pLockData_, false); } private: Exiv2::XmpParser::XmpLockFct xmpLockFct_; void* pLockData_; }; } // ***************************************************************************** // class member definitions namespace Exiv2 { //! Internal Pimpl structure of class Xmpdatum. struct Xmpdatum::Impl { Impl(const XmpKey& key, const Value* pValue); //!< Constructor Impl(const Impl& rhs); //!< Copy constructor Impl& operator=(const Impl& rhs); //!< Assignment // DATA XmpKey::AutoPtr key_; //!< Key Value::AutoPtr value_; //!< Value }; Xmpdatum::Impl::Impl(const XmpKey& key, const Value* pValue) : key_(key.clone()) { if (pValue) value_ = pValue->clone(); } Xmpdatum::Impl::Impl(const Impl& rhs) { if (rhs.key_.get() != 0) key_ = rhs.key_->clone(); // deep copy if (rhs.value_.get() != 0) value_ = rhs.value_->clone(); // deep copy } Xmpdatum::Impl& Xmpdatum::Impl::operator=(const Impl& rhs) { if (this == &rhs) return *this; key_.reset(); if (rhs.key_.get() != 0) key_ = rhs.key_->clone(); // deep copy value_.reset(); if (rhs.value_.get() != 0) value_ = rhs.value_->clone(); // deep copy return *this; } Xmpdatum::Xmpdatum(const XmpKey& key, const Value* pValue) : p_(new Impl(key, pValue)) { } Xmpdatum::Xmpdatum(const Xmpdatum& rhs) : Metadatum(rhs), p_(new Impl(*rhs.p_)) { } Xmpdatum& Xmpdatum::operator=(const Xmpdatum& rhs) { if (this == &rhs) return *this; Metadatum::operator=(rhs); *p_ = *rhs.p_; return *this; } Xmpdatum::~Xmpdatum() { delete p_; } std::string Xmpdatum::key() const { return p_->key_.get() == 0 ? "" : p_->key_->key(); } const char* Xmpdatum::familyName() const { return p_->key_.get() == 0 ? "" : p_->key_->familyName(); } std::string Xmpdatum::groupName() const { return p_->key_.get() == 0 ? "" : p_->key_->groupName(); } std::string Xmpdatum::tagName() const { return p_->key_.get() == 0 ? "" : p_->key_->tagName(); } std::string Xmpdatum::tagLabel() const { return p_->key_.get() == 0 ? "" : p_->key_->tagLabel(); } uint16_t Xmpdatum::tag() const { return p_->key_.get() == 0 ? 0 : p_->key_->tag(); } TypeId Xmpdatum::typeId() const { return p_->value_.get() == 0 ? invalidTypeId : p_->value_->typeId(); } const char* Xmpdatum::typeName() const { return TypeInfo::typeName(typeId()); } long Xmpdatum::typeSize() const { return 0; } long Xmpdatum::count() const { return p_->value_.get() == 0 ? 0 : p_->value_->count(); } long Xmpdatum::size() const { return p_->value_.get() == 0 ? 0 : p_->value_->size(); } std::string Xmpdatum::toString() const { return p_->value_.get() == 0 ? "" : p_->value_->toString(); } std::string Xmpdatum::toString(long n) const { return p_->value_.get() == 0 ? "" : p_->value_->toString(n); } long Xmpdatum::toLong(long n) const { return p_->value_.get() == 0 ? -1 : p_->value_->toLong(n); } float Xmpdatum::toFloat(long n) const { return p_->value_.get() == 0 ? -1 : p_->value_->toFloat(n); } Rational Xmpdatum::toRational(long n) const { return p_->value_.get() == 0 ? Rational(-1, 1) : p_->value_->toRational(n); } Value::AutoPtr Xmpdatum::getValue() const { return p_->value_.get() == 0 ? Value::AutoPtr(0) : p_->value_->clone(); } const Value& Xmpdatum::value() const { if (p_->value_.get() == 0) throw Error(8); return *p_->value_; } long Xmpdatum::copy(byte* /*buf*/, ByteOrder /*byteOrder*/) const { throw Error(34, "Xmpdatum::copy"); return 0; } std::ostream& Xmpdatum::write(std::ostream& os, const ExifData*) const { return XmpProperties::printProperty(os, key(), value()); } Xmpdatum& Xmpdatum::operator=(const std::string& value) { setValue(value); return *this; } Xmpdatum& Xmpdatum::operator=(const Value& value) { setValue(&value); return *this; } void Xmpdatum::setValue(const Value* pValue) { p_->value_.reset(); if (pValue) p_->value_ = pValue->clone(); } int Xmpdatum::setValue(const std::string& value) { if (p_->value_.get() == 0) { TypeId type = xmpText; if (0 != p_->key_.get()) { type = XmpProperties::propertyType(*p_->key_.get()); } p_->value_ = Value::create(type); } return p_->value_->read(value); } Xmpdatum& XmpData::operator[](const std::string& key) { XmpKey xmpKey(key); iterator pos = findKey(xmpKey); if (pos == end()) { add(Xmpdatum(xmpKey)); pos = findKey(xmpKey); } return *pos; } int XmpData::add(const XmpKey& key, const Value* value) { return add(Xmpdatum(key, value)); } int XmpData::add(const Xmpdatum& xmpDatum) { xmpMetadata_.push_back(xmpDatum); return 0; } XmpData::const_iterator XmpData::findKey(const XmpKey& key) const { return std::find_if(xmpMetadata_.begin(), xmpMetadata_.end(), FindXmpdatum(key)); } XmpData::iterator XmpData::findKey(const XmpKey& key) { return std::find_if(xmpMetadata_.begin(), xmpMetadata_.end(), FindXmpdatum(key)); } void XmpData::clear() { xmpMetadata_.clear(); } void XmpData::sortByKey() { std::sort(xmpMetadata_.begin(), xmpMetadata_.end(), cmpMetadataByKey); } XmpData::const_iterator XmpData::begin() const { return xmpMetadata_.begin(); } XmpData::const_iterator XmpData::end() const { return xmpMetadata_.end(); } bool XmpData::empty() const { return count() == 0; } long XmpData::count() const { return static_cast(xmpMetadata_.size()); } XmpData::iterator XmpData::begin() { return xmpMetadata_.begin(); } XmpData::iterator XmpData::end() { return xmpMetadata_.end(); } XmpData::iterator XmpData::erase(XmpData::iterator pos) { return xmpMetadata_.erase(pos); } bool XmpParser::initialized_ = false; XmpParser::XmpLockFct XmpParser::xmpLockFct_ = 0; void* XmpParser::pLockData_ = 0; bool XmpParser::initialize(XmpParser::XmpLockFct xmpLockFct, void* pLockData) { if (!initialized_) { #ifdef EXV_HAVE_XMP_TOOLKIT xmpLockFct_ = xmpLockFct; pLockData_ = pLockData; initialized_ = SXMPMeta::Initialize(); SXMPMeta::RegisterNamespace("http://www.digikam.org/ns/1.0/", "digiKam"); SXMPMeta::RegisterNamespace("http://www.digikam.org/ns/kipi/1.0/", "kipi"); SXMPMeta::RegisterNamespace("http://ns.microsoft.com/photo/1.0/", "MicrosoftPhoto"); SXMPMeta::RegisterNamespace("http://iptc.org/std/Iptc4xmpExt/2008-02-29/", "iptcExt"); SXMPMeta::RegisterNamespace("http://ns.useplus.org/ldf/xmp/1.0/", "plus"); SXMPMeta::RegisterNamespace("http://ns.iview-multimedia.com/mediapro/1.0/", "mediapro"); SXMPMeta::RegisterNamespace("http://ns.microsoft.com/expressionmedia/1.0/", "expressionmedia"); SXMPMeta::RegisterNamespace("http://ns.microsoft.com/photo/1.2/", "MP"); SXMPMeta::RegisterNamespace("http://ns.microsoft.com/photo/1.2/t/RegionInfo#", "MPRI"); SXMPMeta::RegisterNamespace("http://ns.microsoft.com/photo/1.2/t/Region#", "MPReg"); SXMPMeta::RegisterNamespace("http://www.metadataworkinggroup.com/schemas/regions/", "mwg-rs"); SXMPMeta::RegisterNamespace("http://ns.adobe.com/xmp/sType/Area#", "stArea"); #else initialized_ = true; #endif } return initialized_; } void XmpParser::terminate() { XmpProperties::unregisterNs(); if (initialized_) { #ifdef EXV_HAVE_XMP_TOOLKIT SXMPMeta::Terminate(); #endif xmpLockFct_ = 0; pLockData_ = 0; initialized_ = false; } } #ifdef EXV_HAVE_XMP_TOOLKIT void XmpParser::registerNs(const std::string& ns, const std::string& prefix) { try { initialize(); AutoLock autoLock(xmpLockFct_, pLockData_); SXMPMeta::DeleteNamespace(ns.c_str()); SXMPMeta::RegisterNamespace(ns.c_str(), prefix.c_str()); } catch (const XMP_Error& e) { throw Error(40, e.GetID(), e.GetErrMsg()); } } // XmpParser::registerNs #else void XmpParser::registerNs(const std::string& /*ns*/, const std::string& /*prefix*/) { initialize(); } // XmpParser::registerNs #endif void XmpParser::unregisterNs(const std::string& /*ns*/) { #ifdef EXV_HAVE_XMP_TOOLKIT try { // Throws XMP Toolkit error 8: Unimplemented method XMPMeta::DeleteNamespace // SXMPMeta::DeleteNamespace(ns.c_str()); } catch (const XMP_Error& e) { throw Error(40, e.GetID(), e.GetErrMsg()); } #endif } // XmpParser::unregisterNs #ifdef EXV_HAVE_XMP_TOOLKIT int XmpParser::decode( XmpData& xmpData, const std::string& xmpPacket) { try { xmpData.clear(); if (xmpPacket.empty()) return 0; if (!initialize()) { #ifndef SUPPRESS_WARNINGS EXV_ERROR << "XMP toolkit initialization failed.\n"; #endif return 2; } SXMPMeta meta(xmpPacket.data(), static_cast(xmpPacket.size())); SXMPIterator iter(meta); std::string schemaNs, propPath, propValue; XMP_OptionBits opt; while (iter.Next(&schemaNs, &propPath, &propValue, &opt)) { #ifdef DEBUG printNode(schemaNs, propPath, propValue, opt); #endif if (XMP_PropIsAlias(opt)) { throw Error(47, schemaNs, propPath, propValue); continue; } if (XMP_NodeIsSchema(opt)) { // Register unknown namespaces with Exiv2 // (Namespaces are automatically registered with the XMP Toolkit) if (XmpProperties::prefix(schemaNs).empty()) { std::string prefix; bool ret = meta.GetNamespacePrefix(schemaNs.c_str(), &prefix); if (!ret) throw Error(45, schemaNs); prefix = prefix.substr(0, prefix.size() - 1); XmpProperties::registerNs(schemaNs, prefix); } continue; } XmpKey::AutoPtr key = makeXmpKey(schemaNs, propPath); if (XMP_ArrayIsAltText(opt)) { // Read Lang Alt property LangAltValue::AutoPtr val(new LangAltValue); XMP_Index count = meta.CountArrayItems(schemaNs.c_str(), propPath.c_str()); while (count-- > 0) { // Get the text bool haveNext = iter.Next(&schemaNs, &propPath, &propValue, &opt); #ifdef DEBUG printNode(schemaNs, propPath, propValue, opt); #endif if ( !haveNext || !XMP_PropIsSimple(opt) || !XMP_PropHasLang(opt)) { throw Error(41, propPath, opt); } const std::string text = propValue; // Get the language qualifier haveNext = iter.Next(&schemaNs, &propPath, &propValue, &opt); #ifdef DEBUG printNode(schemaNs, propPath, propValue, opt); #endif if ( !haveNext || !XMP_PropIsSimple(opt) || !XMP_PropIsQualifier(opt) || propPath.substr(propPath.size() - 8, 8) != "xml:lang") { throw Error(42, propPath, opt); } val->value_[propValue] = text; } xmpData.add(*key.get(), val.get()); continue; } if ( XMP_PropIsArray(opt) && !XMP_PropHasQualifiers(opt) && !XMP_ArrayIsAltText(opt)) { // Check if all elements are simple bool simpleArray = true; SXMPIterator aIter(meta, schemaNs.c_str(), propPath.c_str()); std::string aSchemaNs, aPropPath, aPropValue; XMP_OptionBits aOpt; while (aIter.Next(&aSchemaNs, &aPropPath, &aPropValue, &aOpt)) { if (propPath == aPropPath) continue; if ( !XMP_PropIsSimple(aOpt) || XMP_PropHasQualifiers(aOpt) || XMP_PropIsQualifier(aOpt) || XMP_NodeIsSchema(aOpt) || XMP_PropIsAlias(aOpt)) { simpleArray = false; break; } } if (simpleArray) { // Read the array into an XmpArrayValue XmpArrayValue::AutoPtr val(new XmpArrayValue(arrayValueTypeId(opt))); XMP_Index count = meta.CountArrayItems(schemaNs.c_str(), propPath.c_str()); while (count-- > 0) { iter.Next(&schemaNs, &propPath, &propValue, &opt); #ifdef DEBUG printNode(schemaNs, propPath, propValue, opt); #endif val->read(propValue); } xmpData.add(*key.get(), val.get()); continue; } } XmpTextValue::AutoPtr val(new XmpTextValue); if ( XMP_PropIsStruct(opt) || XMP_PropIsArray(opt)) { // Create a metadatum with only XMP options val->setXmpArrayType(xmpArrayType(opt)); val->setXmpStruct(xmpStruct(opt)); xmpData.add(*key.get(), val.get()); continue; } if ( XMP_PropIsSimple(opt) || XMP_PropIsQualifier(opt)) { val->read(propValue); xmpData.add(*key.get(), val.get()); continue; } // Don't let any node go by unnoticed throw Error(39, key->key(), opt); } // iterate through all XMP nodes return 0; } #ifndef SUPPRESS_WARNINGS catch (const XMP_Error& e) { EXV_ERROR << Error(40, e.GetID(), e.GetErrMsg()) << "\n"; xmpData.clear(); return 3; } #else catch (const XMP_Error&) { xmpData.clear(); return 3; } #endif // SUPPRESS_WARNINGS } // XmpParser::decode #else int XmpParser::decode( XmpData& xmpData, const std::string& xmpPacket) { xmpData.clear(); if (!xmpPacket.empty()) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "XMP toolkit support not compiled in.\n"; #endif } return 1; } // XmpParser::decode #endif // !EXV_HAVE_XMP_TOOLKIT #ifdef EXV_HAVE_XMP_TOOLKIT int XmpParser::encode( std::string& xmpPacket, const XmpData& xmpData, uint16_t formatFlags, uint32_t padding) { try { if (xmpData.empty()) { xmpPacket.clear(); return 0; } if (!initialize()) { #ifndef SUPPRESS_WARNINGS EXV_ERROR << "XMP toolkit initialization failed.\n"; #endif return 2; } // Register custom namespaces with XMP-SDK for (XmpProperties::NsRegistry::iterator i = XmpProperties::nsRegistry_.begin(); i != XmpProperties::nsRegistry_.end(); ++i) { #ifdef DEBUG std::cerr << "Registering " << i->second.prefix_ << " : " << i->first << "\n"; #endif registerNs(i->first, i->second.prefix_); } SXMPMeta meta; for (XmpData::const_iterator i = xmpData.begin(); i != xmpData.end(); ++i) { const std::string ns = XmpProperties::ns(i->groupName()); XMP_OptionBits options = 0; if (i->typeId() == langAlt) { // Encode Lang Alt property const LangAltValue* la = dynamic_cast(&i->value()); if (la == 0) throw Error(43, i->key()); int idx = 1; // write the default first LangAltValue::ValueType::const_iterator k = la->value_.find("x-default"); if (k != la->value_.end()) { #ifdef DEBUG printNode(ns, i->tagName(), k->second, 0); #endif meta.AppendArrayItem(ns.c_str(), i->tagName().c_str(), kXMP_PropArrayIsAlternate, k->second.c_str()); const std::string item = i->tagName() + "[" + toString(idx++) + "]"; meta.SetQualifier(ns.c_str(), item.c_str(), kXMP_NS_XML, "lang", k->first.c_str()); } for (k = la->value_.begin(); k != la->value_.end(); ++k) { if (k->first == "x-default") continue; #ifdef DEBUG printNode(ns, i->tagName(), k->second, 0); #endif meta.AppendArrayItem(ns.c_str(), i->tagName().c_str(), kXMP_PropArrayIsAlternate, k->second.c_str()); const std::string item = i->tagName() + "[" + toString(idx++) + "]"; meta.SetQualifier(ns.c_str(), item.c_str(), kXMP_NS_XML, "lang", k->first.c_str()); } continue; } // Todo: Xmpdatum should have an XmpValue, not a Value const XmpValue* val = dynamic_cast(&i->value()); if (val == 0) throw Error(52, i->key(), i->typeName()); options = xmpArrayOptionBits(val->xmpArrayType()) | xmpArrayOptionBits(val->xmpStruct()); if ( i->typeId() == xmpBag || i->typeId() == xmpSeq || i->typeId() == xmpAlt) { #ifdef DEBUG printNode(ns, i->tagName(), "", options); #endif meta.SetProperty(ns.c_str(), i->tagName().c_str(), 0, options); for (int idx = 0; idx < i->count(); ++idx) { const std::string item = i->tagName() + "[" + toString(idx + 1) + "]"; #ifdef DEBUG printNode(ns, item, i->toString(idx), 0); #endif meta.SetProperty(ns.c_str(), item.c_str(), i->toString(idx).c_str()); } continue; } if (i->typeId() == xmpText) { if (i->count() == 0) { #ifdef DEBUG printNode(ns, i->tagName(), "", options); #endif meta.SetProperty(ns.c_str(), i->tagName().c_str(), 0, options); } else { #ifdef DEBUG printNode(ns, i->tagName(), i->toString(0), options); #endif meta.SetProperty(ns.c_str(), i->tagName().c_str(), i->toString(0).c_str(), options); } continue; } // Don't let any Xmpdatum go by unnoticed throw Error(38, i->tagName(), i->typeName()); } std::string tmpPacket; meta.SerializeToBuffer(&tmpPacket, xmpFormatOptionBits(static_cast(formatFlags)), padding); // throws xmpPacket = tmpPacket; return 0; } #ifndef SUPPRESS_WARNINGS catch (const XMP_Error& e) { EXV_ERROR << Error(40, e.GetID(), e.GetErrMsg()) << "\n"; return 3; } #else catch (const XMP_Error&) { return 3; } #endif // SUPPRESS_WARNINGS } // XmpParser::decode #else int XmpParser::encode( std::string& /*xmpPacket*/, const XmpData& xmpData, uint16_t /*formatFlags*/, uint32_t /*padding*/) { if (!xmpData.empty()) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "XMP toolkit support not compiled in.\n"; #endif } return 1; } // XmpParser::encode #endif // !EXV_HAVE_XMP_TOOLKIT } // namespace Exiv2 // ***************************************************************************** // local definitions namespace { #ifdef EXV_HAVE_XMP_TOOLKIT Exiv2::XmpValue::XmpStruct xmpStruct(const XMP_OptionBits& opt) { Exiv2::XmpValue::XmpStruct var(Exiv2::XmpValue::xsNone); if (XMP_PropIsStruct(opt)) { var = Exiv2::XmpValue::xsStruct; } return var; } XMP_OptionBits xmpArrayOptionBits(Exiv2::XmpValue::XmpStruct xs) { XMP_OptionBits var(0); switch (xs) { case Exiv2::XmpValue::xsNone: break; case Exiv2::XmpValue::xsStruct: XMP_SetOption(var, kXMP_PropValueIsStruct); break; } return var; } Exiv2::TypeId arrayValueTypeId(const XMP_OptionBits& opt) { Exiv2::TypeId typeId(Exiv2::invalidTypeId); if (XMP_PropIsArray(opt)) { if (XMP_ArrayIsAlternate(opt)) typeId = Exiv2::xmpAlt; else if (XMP_ArrayIsOrdered(opt)) typeId = Exiv2::xmpSeq; else if (XMP_ArrayIsUnordered(opt)) typeId = Exiv2::xmpBag; } return typeId; } Exiv2::XmpValue::XmpArrayType xmpArrayType(const XMP_OptionBits& opt) { return Exiv2::XmpValue::xmpArrayType(arrayValueTypeId(opt)); } XMP_OptionBits xmpArrayOptionBits(Exiv2::XmpValue::XmpArrayType xat) { XMP_OptionBits var(0); switch (xat) { case Exiv2::XmpValue::xaNone: break; case Exiv2::XmpValue::xaAlt: XMP_SetOption(var, kXMP_PropValueIsArray); XMP_SetOption(var, kXMP_PropArrayIsAlternate); break; case Exiv2::XmpValue::xaSeq: XMP_SetOption(var, kXMP_PropValueIsArray); XMP_SetOption(var, kXMP_PropArrayIsOrdered); break; case Exiv2::XmpValue::xaBag: XMP_SetOption(var, kXMP_PropValueIsArray); break; } return var; } XMP_OptionBits xmpFormatOptionBits(Exiv2::XmpParser::XmpFormatFlags flags) { XMP_OptionBits var(0); if (flags & Exiv2::XmpParser::omitPacketWrapper) var |= kXMP_OmitPacketWrapper; if (flags & Exiv2::XmpParser::readOnlyPacket) var |= kXMP_ReadOnlyPacket; if (flags & Exiv2::XmpParser::useCompactFormat) var |= kXMP_UseCompactFormat; if (flags & Exiv2::XmpParser::includeThumbnailPad) var |= kXMP_IncludeThumbnailPad; if (flags & Exiv2::XmpParser::exactPacketLength) var |= kXMP_ExactPacketLength; if (flags & Exiv2::XmpParser::writeAliasComments) var |= kXMP_WriteAliasComments; if (flags & Exiv2::XmpParser::omitAllFormatting) var |= kXMP_OmitAllFormatting; return var; } #ifdef DEBUG void printNode(const std::string& schemaNs, const std::string& propPath, const std::string& propValue, const XMP_OptionBits& opt) { static bool first = true; if (first) { first = false; std::cout << "ashisabsals\n" << "lcqqtrgqlai\n"; } enum { alia=0, sche, hasq, isqu, stru, arra, abag, aseq, aalt, lang, simp, len }; std::string opts(len, '.'); if (XMP_PropIsAlias(opt)) opts[alia] = 'X'; if (XMP_NodeIsSchema(opt)) opts[sche] = 'X'; if (XMP_PropHasQualifiers(opt)) opts[hasq] = 'X'; if (XMP_PropIsQualifier(opt)) opts[isqu] = 'X'; if (XMP_PropIsStruct(opt)) opts[stru] = 'X'; if (XMP_PropIsArray(opt)) opts[arra] = 'X'; if (XMP_ArrayIsUnordered(opt)) opts[abag] = 'X'; if (XMP_ArrayIsOrdered(opt)) opts[aseq] = 'X'; if (XMP_ArrayIsAlternate(opt)) opts[aalt] = 'X'; if (XMP_ArrayIsAltText(opt)) opts[lang] = 'X'; if (XMP_PropIsSimple(opt)) opts[simp] = 'X'; std::cout << opts << " "; if (opts[sche] == 'X') { std::cout << "ns=" << schemaNs; } else { std::cout << propPath << " = " << propValue; } std::cout << std::endl; } #endif // DEBUG #endif // EXV_HAVE_XMP_TOOLKIT Exiv2::XmpKey::AutoPtr makeXmpKey(const std::string& schemaNs, const std::string& propPath) { std::string property; std::string::size_type idx = propPath.find(':'); if (idx == std::string::npos) { throw Exiv2::Error(44, propPath, schemaNs); } // Don't worry about out_of_range, XMP parser takes care of this property = propPath.substr(idx + 1); std::string prefix = Exiv2::XmpProperties::prefix(schemaNs); if (prefix.empty()) { throw Exiv2::Error(36, propPath, schemaNs); } return Exiv2::XmpKey::AutoPtr(new Exiv2::XmpKey(prefix, property)); } // makeXmpKey } exiv2-0.23/src/panasonicmn.cpp0000644000175000017500000005167411732641407016132 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /* File: panasonicmn.cpp Version: $Rev: 2681 $ Author(s): Andreas Huggel (ahu) Gilles Caulier (gc) History: 11-Jun-04, ahu: created Credits: See header file */ // ***************************************************************************** #include "rcsid_int.hpp" EXIV2_RCSID("@(#) $Id: panasonicmn.cpp 2681 2012-03-22 15:19:35Z ahuggel $") // ***************************************************************************** // included header files #include "types.hpp" #include "panasonicmn_int.hpp" #include "tags_int.hpp" #include "value.hpp" #include "i18n.h" // NLS support. // + standard includes #include #include #include #include #include // ***************************************************************************** // class member definitions namespace Exiv2 { namespace Internal { //! Quality, tag 0x0001 extern const TagDetails panasonicQuality[] = { { 2, N_("High") }, { 3, N_("Normal") }, { 6, N_("Very High") }, { 7, N_("Raw") }, { 9, N_("Motion Picture") } }; //! WhiteBalance, tag 0x0003 extern const TagDetails panasonicWhiteBalance[] = { { 1, N_("Auto") }, { 2, N_("Daylight") }, { 3, N_("Cloudy") }, { 4, N_("Halogen") }, { 5, N_("Manual") }, { 8, N_("Flash") }, { 10, N_("Black and white") }, { 11, N_("Manual") }, { 11, N_("Manual") } // To silence compiler warning }; //! FocusMode, tag 0x0007 extern const TagDetails panasonicFocusMode[] = { { 1, N_("Auto") }, { 2, N_("Manual") }, { 4, N_("Auto, focus button") }, { 5, N_("Auto, continuous") }, { 5, N_("Auto, continuous") } // To silence compiler warning }; //! ImageStabilizer, tag 0x001a extern const TagDetails panasonicImageStabilizer[] = { { 2, N_("On, Mode 1") }, { 3, N_("Off") }, { 4, N_("On, Mode 2") } }; //! Macro, tag 0x001c extern const TagDetails panasonicMacro[] = { { 1, N_("On") }, { 2, N_("Off") }, { 257, N_("Tele-macro") } }; //! ShootingMode, tag 0x001f and SceneMode, tag 0x8001 extern const TagDetails panasonicShootingMode[] = { { 0, N_("Off") }, // only SceneMode { 1, N_("Normal") }, { 2, N_("Portrait") }, { 3, N_("Scenery") }, { 4, N_("Sports") }, { 5, N_("Night portrait") }, { 6, N_("Program") }, { 7, N_("Aperture priority") }, { 8, N_("Shutter-speed priority") }, { 9, N_("Macro") }, { 10, N_("Spot") }, { 11, N_("Manual") }, { 12, N_("Movie preview") }, { 13, N_("Panning") }, { 14, N_("Simple") }, { 15, N_("Color effects") }, { 18, N_("Fireworks") }, { 19, N_("Party") }, { 20, N_("Snow") }, { 21, N_("Night scenery") }, { 22, N_("Food") }, { 23, N_("Baby") }, { 24, N_("Soft skin") }, { 25, N_("Candlelight") }, { 26, N_("Starry night") }, { 27, N_("High sensitivity") }, { 28, N_("Panorama assist") }, { 29, N_("Underwater") }, { 30, N_("Beach") }, { 31, N_("Aerial photo") }, { 32, N_("Sunset") }, { 33, N_("Pet") }, { 34, N_("Intelligent ISO") }, { 36, N_("High speed continuous shooting") }, { 37, N_("Intelligent auto") }, }; //! Audio, tag 0x0020 extern const TagDetails panasonicAudio[] = { { 1, N_("Yes") }, { 2, N_("No") } }; //! ColorEffect, tag 0x0028 extern const TagDetails panasonicColorEffect[] = { { 1, N_("Off") }, { 2, N_("Warm") }, { 3, N_("Cool") }, { 4, N_("Black and white") }, { 5, N_("Sepia") } }; //! BustMode, tag 0x002a extern const TagDetails panasonicBurstMode[] = { { 0, N_("Off") }, { 1, N_("Low/High quality") }, { 2, N_("Infinite") } }; //! Contrast, tag 0x002c extern const TagDetails panasonicContrast[] = { { 0, N_("Normal") }, { 1, N_("Low") }, { 2, N_("High") }, { 6, N_("Medium low") }, { 7, N_("Medium high") }, { 256, N_("Low") }, { 272, N_("Standard") }, { 288, N_("High") }, { 288, N_("High") } // To silence compiler warning }; //! NoiseReduction, tag 0x002d extern const TagDetails panasonicNoiseReduction[] = { { 0, N_("Standard") }, { 1, N_("Low (-1)") }, { 2, N_("High (+1)") }, { 3, N_("Lowest (-2)") }, { 4, N_("Highest (+2)") } }; //! SelfTimer, tag 0x002e extern const TagDetails panasonicSelfTimer[] = { { 1, N_("Off") }, { 2, N_("10s") }, { 3, N_("2s") } }; //! Rotation, tag 0x0030 extern const TagDetails panasonicRotation[] = { { 1, N_("Horizontal (normal)") }, { 6, N_("Rotate 90 CW") }, { 8, N_("Rotate 270 CW") } }; //! ColorMode, tag 0x0032 extern const TagDetails panasonicColorMode[] = { { 0, N_("Normal") }, { 1, N_("Natural") }, { 2, N_("Vivid") } }; //! OpticalZoomMode, tag 0x0034 extern const TagDetails panasonicOpticalZoomMode[] = { { 1, N_("Standard") }, { 2, N_("EX optics") } }; //! ConversionLens, tag 0x0035 extern const TagDetails panasonicConversionLens[] = { { 1, N_("Off") }, { 2, N_("Wide") }, { 3, N_("Telephoto") }, { 4, N_("Macro") }, { 4, N_("Macro") } // To silence compiler warning }; //! WorldTimeLocation, tag 0x003a extern const TagDetails panasonicWorldTimeLocation[] = { { 1, N_("Home") }, { 2, N_("Destination") } }; //! FilmMode, tag 0x0042 extern const TagDetails panasonicFilmMode[] = { { 1, N_("Standard (color)") }, { 2, N_("Dynamic (color)") }, { 3, N_("Nature (color)") }, { 4, N_("Smooth (color)") }, { 5, N_("Standard (B&W)") }, { 6, N_("Dynamic (B&W)") }, { 7, N_("Smooth (B&W)") } }; // Panasonic MakerNote Tag Info const TagInfo PanasonicMakerNote::tagInfo_[] = { TagInfo(0x0001, "Quality", N_("Quality"), N_("Image Quality"), panasonicId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(panasonicQuality)), TagInfo(0x0002, "FirmwareVersion", N_("Firmware Version"), N_("Firmware version"), panasonicId, makerTags, undefined, -1, printValue), TagInfo(0x0003, "WhiteBalance", N_("White Balance"), N_("White balance setting"), panasonicId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(panasonicWhiteBalance)), TagInfo(0x0004, "0x0004", "0x0004", N_("Unknown"), panasonicId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0007, "FocusMode", N_("Focus Mode"), N_("Focus mode"), panasonicId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(panasonicFocusMode)), TagInfo(0x000f, "AFMode", N_("AF Mode"), N_("AF mode"), panasonicId, makerTags, unsignedByte, -1, print0x000f), TagInfo(0x001a, "ImageStabilization", N_("Image Stabilization"), N_("Image stabilization"), panasonicId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(panasonicImageStabilizer)), TagInfo(0x001c, "Macro", N_("Macro"), N_("Macro mode"), panasonicId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(panasonicMacro)), TagInfo(0x001f, "ShootingMode", N_("Shooting Mode"), N_("Shooting mode"), panasonicId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(panasonicShootingMode)), TagInfo(0x0020, "Audio", N_("Audio"), N_("Audio"), panasonicId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(panasonicAudio)), TagInfo(0x0021, "DataDump", N_("Data Dump"), N_("Data dump"), panasonicId, makerTags, undefined, -1, printValue), TagInfo(0x0022, "0x0022", "0x0022", N_("Unknown"), panasonicId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0023, "WhiteBalanceBias", N_("White Balance Bias"), N_("White balance adjustment"), panasonicId, makerTags, signedShort, -1, print0x0023), TagInfo(0x0024, "FlashBias", N_("FlashBias"), N_("Flash bias"), panasonicId, makerTags, signedShort, -1, printValue), TagInfo(0x0025, "InternalSerialNumber", N_("Internal Serial Number"), N_("This number is unique, and contains the date of manufacture, but is not the same as the number printed on the camera body."), panasonicId, makerTags, undefined, -1, printValue), TagInfo(0x0026, "ExifVersion", "Exif Version", N_("Exif version"), panasonicId, makerTags, undefined, -1, printExifVersion), TagInfo(0x0027, "0x0027", "0x0027", N_("Unknown"), panasonicId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0028, "ColorEffect", N_("Color Effect"), N_("Color effect"), panasonicId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(panasonicColorEffect)), TagInfo(0x0029, "TimeSincePowerOn", "Time since Power On", N_("Time in 1/100 s from when the camera was powered on to when the image is written to memory card"), panasonicId, makerTags, unsignedLong, -1, printValue), TagInfo(0x002a, "BurstMode", N_("Burst Mode"), N_("Burst mode"), panasonicId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(panasonicBurstMode)), TagInfo(0x002b, "SequenceNumber", N_("Sequence Number"), N_("Sequence number"), panasonicId, makerTags, unsignedLong, -1, printValue), TagInfo(0x002c, "Contrast", N_("Contrast"), N_("Contrast setting"), panasonicId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(panasonicContrast)), TagInfo(0x002d, "NoiseReduction", N_("NoiseReduction"), N_("Noise reduction"), panasonicId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(panasonicNoiseReduction)), TagInfo(0x002e, "SelfTimer", N_("Self Timer"), N_("Self timer"), panasonicId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(panasonicSelfTimer)), TagInfo(0x002f, "0x002f", "0x002f", N_("Unknown"), panasonicId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0030, "Rotation", N_("Rotation"), N_("Rotation"), panasonicId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(panasonicRotation)), TagInfo(0x0031, "0x0031", "0x0031", N_("Unknown"), panasonicId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0032, "ColorMode", N_("Color Mode"), N_("Color mode"), panasonicId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(panasonicColorMode)), TagInfo(0x0033, "BabyAge", N_("Baby Age"), N_("Baby (or pet) age"), panasonicId, makerTags, asciiString, -1, printValue), TagInfo(0x0034, "OpticalZoomMode", N_("Optical Zoom Mode"), N_("Optical zoom mode"), panasonicId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(panasonicOpticalZoomMode)), TagInfo(0x0035, "ConversionLens", N_("Conversion Lens"), N_("Conversion lens"), panasonicId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(panasonicConversionLens)), TagInfo(0x0036, "TravelDay", N_("Travel Day"), N_("Travel day"), panasonicId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0039, "Contrast", N_("Contrast"), N_("Contrast"), panasonicId, makerTags, unsignedShort, -1, printValue), TagInfo(0x003a, "WorldTimeLocation", N_("World Time Location"), N_("World time location"), panasonicId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(panasonicWorldTimeLocation)), TagInfo(0x003c, "ProgramISO", N_("Program ISO"), N_("Program ISO"), panasonicId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0040, "Saturation", N_("Saturation"), N_("Saturation"), panasonicId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0041, "Sharpness", N_("Sharpness"), N_("Sharpness"), panasonicId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0042, "FilmMode", N_("Film Mode"), N_("Film mode"), panasonicId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(panasonicFilmMode)), TagInfo(0x0046, "WBAdjustAB", N_("WB Adjust AB"), N_("WB adjust AB. Positive is a shift toward blue."), panasonicId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0047, "WBAdjustGM", N_("WB Adjust GM"), N_("WBAdjustGM. Positive is a shift toward green."), panasonicId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0051, "LensType", N_("Lens Type"), N_("Lens type"), panasonicId, makerTags, asciiString, -1, printValue), TagInfo(0x0052, "LensSerialNumber", N_("Lens Serial Number"), N_("Lens serial number"), panasonicId, makerTags, asciiString, -1, printValue), TagInfo(0x0053, "AccessoryType", N_("Accessory Type"), N_("Accessory type"), panasonicId, makerTags, asciiString, -1, printValue), TagInfo(0x0e00, "PrintIM", N_("Print IM"), N_("PrintIM information"), panasonicId, makerTags, undefined, -1, printValue), TagInfo(0x4449, "0x4449", "0x4449", N_("Unknown"), panasonicId, makerTags, undefined, -1, printValue), TagInfo(0x8000, "MakerNoteVersion", N_("MakerNote Version"), N_("MakerNote version"), panasonicId, makerTags, undefined, -1, printExifVersion), TagInfo(0x8001, "SceneMode", N_("Scene Mode"), N_("Scene mode"), panasonicId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(panasonicShootingMode)), TagInfo(0x8004, "WBRedLevel", N_("WB Red Level"), N_("WB red level"), panasonicId, makerTags, unsignedShort, -1, printValue), TagInfo(0x8005, "WBGreenLevel", N_("WB Green Level"), N_("WB green level"), panasonicId, makerTags, unsignedShort, -1, printValue), TagInfo(0x8006, "WBBlueLevel", N_("WB Blue Level"), N_("WB blue level"), panasonicId, makerTags, unsignedShort, -1, printValue), TagInfo(0x8010, "BabyAge", N_("Baby Age"), N_("Baby (or pet) age"), panasonicId, makerTags, asciiString, -1, printValue), // End of list marker TagInfo(0xffff, "(UnknownPanasonicMakerNoteTag)", "(UnknownPanasonicMakerNoteTag)", N_("Unknown PanasonicMakerNote tag"), panasonicId, makerTags, asciiString, -1, printValue) }; const TagInfo* PanasonicMakerNote::tagList() { return tagInfo_; } std::ostream& PanasonicMakerNote::print0x000f(std::ostream& os, const Value& value, const ExifData*) { if (value.count() < 2 || value.typeId() != unsignedByte) { return os << value; } long l0 = value.toLong(0); long l1 = value.toLong(1); if (l0 == 0 && l1 == 1) os << _("Spot mode on"); else if (l0 == 0 && l1 == 16) os << _("Spot mode off or 3-area (high speed)"); else if (l0 == 1 && l1 == 0) os << _("Spot focussing"); else if (l0 == 1 && l1 == 1) os << _("5-area"); else if (l0 == 16 && l1 == 0) os << _("1-area"); else if (l0 == 16 && l1 == 16) os << _("1-area (high speed)"); else if (l0 == 32 && l1 == 0) os << _("3-area (auto)"); else if (l0 == 32 && l1 == 1) os << _("3-area (left)"); else if (l0 == 32 && l1 == 2) os << _("3-area (center)"); else if (l0 == 32 && l1 == 3) os << _("3-area (right)"); else os << value; return os; } // PanasonicMakerNote::print0x000f std::ostream& PanasonicMakerNote::print0x0023(std::ostream& os, const Value& value, const ExifData*) { std::ostringstream oss; oss.copyfmt(os); os << std::fixed << std::setprecision(1) << value.toLong() / 3 << _(" EV"); os.copyfmt(oss); return os; } // PanasonicMakerNote::print0x0023 // Panasonic MakerNote Tag Info const TagInfo PanasonicMakerNote::tagInfoRaw_[] = { TagInfo(0x0001, "Version", N_("Version"), N_("Panasonic raw version"), panaRawId, panaRaw, undefined, -1, printExifVersion), TagInfo(0x0002, "SensorWidth", N_("Sensor Width"), N_("Sensor width"), panaRawId, panaRaw, unsignedShort, -1, printValue), TagInfo(0x0003, "SensorHeight", N_("Sensor Height"), N_("Sensor height"), panaRawId, panaRaw, unsignedShort, -1, printValue), TagInfo(0x0004, "SensorTopBorder", N_("Sensor Top Border"), N_("Sensor top border"), panaRawId, panaRaw, unsignedShort, -1, printValue), TagInfo(0x0005, "SensorLeftBorder", N_("Sensor Left Border"), N_("Sensor left border"), panaRawId, panaRaw, unsignedShort, -1, printValue), TagInfo(0x0006, "ImageHeight", N_("Image Height"), N_("Image height"), panaRawId, panaRaw, unsignedShort, -1, printValue), TagInfo(0x0007, "ImageWidth", N_("Image Width"), N_("Image width"), panaRawId, panaRaw, unsignedShort, -1, printValue), TagInfo(0x0011, "RedBalance", N_("Red Balance"), N_("Red balance (found in Digilux 2 RAW images)"), panaRawId, panaRaw, unsignedShort, -1, printValue), TagInfo(0x0012, "BlueBalance", N_("Blue Balance"), N_("Blue balance"), panaRawId, panaRaw, unsignedShort, -1, printValue), TagInfo(0x0017, "ISOSpeed", N_("ISO Speed"), N_("ISO speed setting"), panaRawId, panaRaw, unsignedShort, -1, printValue), TagInfo(0x0024, "WBRedLevel", N_("WB Red Level"), N_("WB red level"), panaRawId, panaRaw, unsignedShort, -1, printValue), TagInfo(0x0025, "WBGreenLevel", N_("WB Green Level"), N_("WB green level"), panaRawId, panaRaw, unsignedShort, -1, printValue), TagInfo(0x0026, "WBBlueLevel", N_("WB Blue Level"), N_("WB blue level"), panaRawId, panaRaw, unsignedShort, -1, printValue), TagInfo(0x002e, "PreviewImage", N_("Preview Image"), N_("Preview image"), panaRawId, panaRaw, undefined, -1, printValue), TagInfo(0x010f, "Make", N_("Manufacturer"), N_("The manufacturer of the recording equipment"), panaRawId, panaRaw, asciiString, -1, printValue), TagInfo(0x0110, "Model", N_("Model"), N_("The model name or model number of the equipment"), panaRawId, panaRaw, asciiString, -1, printValue), TagInfo(0x0111, "StripOffsets", N_("Strip Offsets"), N_("Strip offsets"), panaRawId, panaRaw, unsignedLong, -1, printValue), TagInfo(0x0112, "Orientation", N_("Orientation"), N_("Orientation"), panaRawId, panaRaw, unsignedShort, -1, print0x0112), TagInfo(0x0116, "RowsPerStrip", N_("Rows Per Strip"), N_("The number of rows per strip"), panaRawId, panaRaw, unsignedShort, -1, printValue), TagInfo(0x0117, "StripByteCounts", N_("Strip Byte Counts"), N_("Strip byte counts"), panaRawId, panaRaw, unsignedLong, -1, printValue), TagInfo(0x0118, "RawDataOffset", N_("Raw Data Offset"), N_("Raw data offset"), panaRawId, panaRaw, unsignedLong, -1, printValue), TagInfo(0x8769, "ExifTag", N_("Exif IFD Pointer"), N_("A pointer to the Exif IFD"), panaRawId, panaRaw, unsignedLong, -1, printValue), TagInfo(0x8825, "GPSTag", N_("GPS Info IFD Pointer"), N_("A pointer to the GPS Info IFD"), panaRawId, panaRaw, unsignedLong, -1, printValue), // End of list marker TagInfo(0xffff, "(UnknownPanasonicRawTag)", "(UnknownPanasonicRawTag)", N_("Unknown PanasonicRaw tag"), panaRawId, panaRaw, asciiString, -1, printValue) }; const TagInfo* PanasonicMakerNote::tagListRaw() { return tagInfoRaw_; } }} // namespace Internal, Exiv2 exiv2-0.23/src/cr2image_int.hpp0000644000175000017500000000537111732641407016165 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! @file cr2image_int.hpp @brief Internal classes to support CR2 image format @version $Rev: 2681 $ @author Andreas Huggel (ahu) ahuggel@gmx.net @date 23-Apr-08, ahu: created */ #ifndef CR2IMAGE_INT_HPP_ #define CR2IMAGE_INT_HPP_ // ***************************************************************************** // included header files #include "tiffimage_int.hpp" #include "types.hpp" // + standard includes #include // ***************************************************************************** // namespace extensions namespace Exiv2 { namespace Internal { // ***************************************************************************** // class definitions /*! @brief Canon CR2 header structure. */ class Cr2Header : public TiffHeaderBase { public: //! @name Creators //@{ //! Default constructor Cr2Header(ByteOrder byteOrder =littleEndian); //! Destructor. ~Cr2Header(); //@} //! @name Manipulators //@{ bool read(const byte* pData, uint32_t size); //@} //! @name Accessors //@{ DataBuf write() const; bool isImageTag( uint16_t tag, IfdId group, const PrimaryGroups* pPrimaryGroups) const; //@} //! Return the address of offset2 from the start of the header static uint32_t offset2addr() { return 12; } private: // DATA uint32_t offset2_; //!< Bytes 12-15 from the header static const char* cr2sig_; //!< Signature for CR2 type TIFF }; // class Cr2Header }} // namespace Internal, Exiv2 #endif // #ifndef CR2IMAGE_INT_HPP_ exiv2-0.23/src/tiffvisitor.cpp0000644000175000017500000015347711732641407016200 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /* File: tiffvisitor.cpp Version: $Rev: 2681 $ Author(s): Andreas Huggel (ahu) History: 11-Apr-06, ahu: created */ // ***************************************************************************** #include "rcsid_int.hpp" EXIV2_RCSID("@(#) $Id: tiffvisitor.cpp 2681 2012-03-22 15:19:35Z ahuggel $") // ***************************************************************************** // included header files #ifdef _MSC_VER # include "exv_msvc.h" #else # include "exv_conf.h" #endif #include "tiffcomposite_int.hpp" // Do not change the order of these 2 includes, #include "tiffvisitor_int.hpp" // see bug #487 #include "tiffimage_int.hpp" #include "makernote_int.hpp" #include "exif.hpp" #include "iptc.hpp" #include "value.hpp" #include "image.hpp" #include "jpgimage.hpp" #include "i18n.h" // NLS support. // + standard includes #include #include #include #include // ***************************************************************************** namespace { //! Unary predicate that matches an Exifdatum with a given group and index. class FindExifdatum2 { public: //! Constructor, initializes the object with the group and index to look for. FindExifdatum2(Exiv2::Internal::IfdId group, int idx) : groupName_(Exiv2::Internal::groupName(group)), idx_(idx) {} //! Returns true if group and index match. bool operator()(const Exiv2::Exifdatum& md) const { return idx_ == md.idx() && 0 == strcmp(md.groupName().c_str(), groupName_); } private: const char* groupName_; int idx_; }; // class FindExifdatum2 Exiv2::ByteOrder stringToByteOrder(const std::string& val) { Exiv2::ByteOrder bo = Exiv2::invalidByteOrder; if (0 == strcmp("II", val.c_str())) bo = Exiv2::littleEndian; else if (0 == strcmp("MM", val.c_str())) bo = Exiv2::bigEndian; return bo; } } // ***************************************************************************** // class member definitions namespace Exiv2 { namespace Internal { TiffVisitor::TiffVisitor() { for (int i = 0; i < events_; ++i) { go_[i] = true; } } TiffVisitor::~TiffVisitor() { } void TiffVisitor::setGo(GoEvent event, bool go) { assert(event >= 0 && event < events_); go_[event] = go; } bool TiffVisitor::go(GoEvent event) const { assert(event >= 0 && event < events_); return go_[event]; } void TiffVisitor::visitDirectoryNext(TiffDirectory* /*object*/) { } void TiffVisitor::visitDirectoryEnd(TiffDirectory* /*object*/) { } void TiffVisitor::visitIfdMakernoteEnd(TiffIfdMakernote* /*object*/) { } void TiffVisitor::visitBinaryArrayEnd(TiffBinaryArray* /*object*/) { } void TiffFinder::init(uint16_t tag, IfdId group) { tag_ = tag; group_ = group; tiffComponent_ = 0; setGo(geTraverse, true); } TiffFinder::~TiffFinder() { } void TiffFinder::findObject(TiffComponent* object) { if (object->tag() == tag_ && object->group() == group_) { tiffComponent_ = object; setGo(geTraverse, false); } } void TiffFinder::visitEntry(TiffEntry* object) { findObject(object); } void TiffFinder::visitDataEntry(TiffDataEntry* object) { findObject(object); } void TiffFinder::visitImageEntry(TiffImageEntry* object) { findObject(object); } void TiffFinder::visitSizeEntry(TiffSizeEntry* object) { findObject(object); } void TiffFinder::visitDirectory(TiffDirectory* object) { findObject(object); } void TiffFinder::visitSubIfd(TiffSubIfd* object) { findObject(object); } void TiffFinder::visitMnEntry(TiffMnEntry* object) { findObject(object); } void TiffFinder::visitIfdMakernote(TiffIfdMakernote* object) { findObject(object); } void TiffFinder::visitBinaryArray(TiffBinaryArray* object) { findObject(object); } void TiffFinder::visitBinaryElement(TiffBinaryElement* object) { findObject(object); } TiffCopier::TiffCopier( TiffComponent* pRoot, uint32_t root, const TiffHeaderBase* pHeader, const PrimaryGroups* pPrimaryGroups) : pRoot_(pRoot), root_(root), pHeader_(pHeader), pPrimaryGroups_(pPrimaryGroups) { assert(pRoot_ != 0); assert(pHeader_ != 0); assert(pPrimaryGroups_ != 0); } TiffCopier::~TiffCopier() { } void TiffCopier::copyObject(TiffComponent* object) { assert(object != 0); if (pHeader_->isImageTag(object->tag(), object->group(), pPrimaryGroups_)) { TiffComponent::AutoPtr clone = object->clone(); // Assumption is that the corresponding TIFF entry doesn't exist TiffPath tiffPath; TiffCreator::getPath(tiffPath, object->tag(), object->group(), root_); pRoot_->addPath(object->tag(), tiffPath, pRoot_, clone); #ifdef DEBUG ExifKey key(object->tag(), groupName(object->group())); std::cerr << "Copied " << key << "\n"; #endif } } void TiffCopier::visitEntry(TiffEntry* object) { copyObject(object); } void TiffCopier::visitDataEntry(TiffDataEntry* object) { copyObject(object); } void TiffCopier::visitImageEntry(TiffImageEntry* object) { copyObject(object); } void TiffCopier::visitSizeEntry(TiffSizeEntry* object) { copyObject(object); } void TiffCopier::visitDirectory(TiffDirectory* /*object*/) { // Do not copy directories (avoids problems with SubIfds) } void TiffCopier::visitSubIfd(TiffSubIfd* object) { copyObject(object); } void TiffCopier::visitMnEntry(TiffMnEntry* object) { copyObject(object); } void TiffCopier::visitIfdMakernote(TiffIfdMakernote* object) { copyObject(object); } void TiffCopier::visitBinaryArray(TiffBinaryArray* object) { copyObject(object); } void TiffCopier::visitBinaryElement(TiffBinaryElement* object) { copyObject(object); } TiffDecoder::TiffDecoder( ExifData& exifData, IptcData& iptcData, XmpData& xmpData, TiffComponent* const pRoot, FindDecoderFct findDecoderFct ) : exifData_(exifData), iptcData_(iptcData), xmpData_(xmpData), pRoot_(pRoot), findDecoderFct_(findDecoderFct), decodedIptc_(false) { assert(pRoot != 0); exifData_.clear(); iptcData_.clear(); xmpData_.clear(); // Find camera make TiffFinder finder(0x010f, ifd0Id); pRoot_->accept(finder); TiffEntryBase* te = dynamic_cast(finder.result()); if (te && te->pValue()) { make_ = te->pValue()->toString(); } } TiffDecoder::~TiffDecoder() { } void TiffDecoder::visitEntry(TiffEntry* object) { decodeTiffEntry(object); } void TiffDecoder::visitDataEntry(TiffDataEntry* object) { decodeTiffEntry(object); } void TiffDecoder::visitImageEntry(TiffImageEntry* object) { decodeTiffEntry(object); } void TiffDecoder::visitSizeEntry(TiffSizeEntry* object) { decodeTiffEntry(object); } void TiffDecoder::visitDirectory(TiffDirectory* /*object*/) { // Nothing to do } void TiffDecoder::visitSubIfd(TiffSubIfd* object) { decodeTiffEntry(object); } void TiffDecoder::visitMnEntry(TiffMnEntry* object) { // Always decode binary makernote tag decodeTiffEntry(object); } void TiffDecoder::visitIfdMakernote(TiffIfdMakernote* object) { assert(object != 0); exifData_["Exif.MakerNote.Offset"] = object->mnOffset(); switch (object->byteOrder()) { case littleEndian: exifData_["Exif.MakerNote.ByteOrder"] = "II"; break; case bigEndian: exifData_["Exif.MakerNote.ByteOrder"] = "MM"; break; case invalidByteOrder: assert(object->byteOrder() != invalidByteOrder); break; } } void TiffDecoder::getObjData(byte const*& pData, long& size, uint16_t tag, IfdId group, const TiffEntryBase* object) { if (object && object->tag() == tag && object->group() == group) { pData = object->pData(); size = object->size(); return; } TiffFinder finder(tag, group); pRoot_->accept(finder); TiffEntryBase const* te = dynamic_cast(finder.result()); if (te) { pData = te->pData(); size = te->size(); return; } } void TiffDecoder::decodeXmp(const TiffEntryBase* object) { // add Exif tag anyway decodeStdTiffEntry(object); byte const* pData = 0; long size = 0; getObjData(pData, size, 0x02bc, ifd0Id, object); if (pData) { std::string xmpPacket; xmpPacket.assign(reinterpret_cast(pData), size); std::string::size_type idx = xmpPacket.find_first_of('<'); if (idx != std::string::npos && idx > 0) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Removing " << static_cast(idx) << " characters from the beginning of the XMP packet\n"; #endif xmpPacket = xmpPacket.substr(idx); } if (XmpParser::decode(xmpData_, xmpPacket)) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Failed to decode XMP metadata.\n"; #endif } } } // TiffDecoder::decodeXmp void TiffDecoder::decodeIptc(const TiffEntryBase* object) { // add Exif tag anyway decodeStdTiffEntry(object); // All tags are read at this point, so the first time we come here, // find the relevant IPTC tag and decode IPTC if found if (decodedIptc_) { return; } decodedIptc_ = true; // 1st choice: IPTCNAA byte const* pData = 0; long size = 0; getObjData(pData, size, 0x83bb, ifd0Id, object); if (pData) { if (0 == IptcParser::decode(iptcData_, pData, size)) { return; } #ifndef SUPPRESS_WARNINGS else { EXV_WARNING << "Failed to decode IPTC block found in " << "Directory Image, entry 0x83bb\n"; } #endif } // 2nd choice if no IPTCNAA record found or failed to decode it: // ImageResources pData = 0; size = 0; getObjData(pData, size, 0x8649, ifd0Id, object); if (pData) { byte const* record = 0; uint32_t sizeHdr = 0; uint32_t sizeData = 0; if (0 != Photoshop::locateIptcIrb(pData, size, &record, &sizeHdr, &sizeData)) { return; } if (0 == IptcParser::decode(iptcData_, record + sizeHdr, sizeData)) { return; } #ifndef SUPPRESS_WARNINGS else { EXV_WARNING << "Failed to decode IPTC block found in " << "Directory Image, entry 0x8649\n"; } #endif } } // TiffMetadataDecoder::decodeIptc void TiffDecoder::decodeTiffEntry(const TiffEntryBase* object) { assert(object != 0); // Don't decode the entry if value is not set if (!object->pValue()) return; const DecoderFct decoderFct = findDecoderFct_(make_, object->tag(), object->group()); // skip decoding if decoderFct == 0 if (decoderFct) { EXV_CALL_MEMBER_FN(*this, decoderFct)(object); } } // TiffDecoder::decodeTiffEntry void TiffDecoder::decodeStdTiffEntry(const TiffEntryBase* object) { assert(object != 0); ExifKey key(object->tag(), groupName(object->group())); key.setIdx(object->idx()); exifData_.add(key, object->pValue()); } // TiffDecoder::decodeTiffEntry void TiffDecoder::visitBinaryArray(TiffBinaryArray* object) { if (object->cfg() == 0 || !object->decoded()) { decodeTiffEntry(object); } } void TiffDecoder::visitBinaryElement(TiffBinaryElement* object) { decodeTiffEntry(object); } TiffEncoder::TiffEncoder( const ExifData& exifData, const IptcData& iptcData, const XmpData& xmpData, TiffComponent* pRoot, const bool isNewImage, const PrimaryGroups* pPrimaryGroups, const TiffHeaderBase* pHeader, FindEncoderFct findEncoderFct ) : exifData_(exifData), iptcData_(iptcData), xmpData_(xmpData), del_(true), pHeader_(pHeader), pRoot_(pRoot), isNewImage_(isNewImage), pPrimaryGroups_(pPrimaryGroups), pSourceTree_(0), findEncoderFct_(findEncoderFct), dirty_(false), writeMethod_(wmNonIntrusive) { assert(pRoot != 0); assert(pPrimaryGroups != 0); assert(pHeader != 0); byteOrder_ = pHeader->byteOrder(); origByteOrder_ = byteOrder_; encodeIptc(); encodeXmp(); // Find camera make ExifKey key("Exif.Image.Make"); ExifData::const_iterator pos = exifData_.findKey(key); if (pos != exifData_.end()) { make_ = pos->toString(); } if (make_.empty() && pRoot_) { TiffFinder finder(0x010f, ifd0Id); pRoot_->accept(finder); TiffEntryBase* te = dynamic_cast(finder.result()); if (te && te->pValue()) { make_ = te->pValue()->toString(); } } } TiffEncoder::~TiffEncoder() { } void TiffEncoder::encodeIptc() { // Update IPTCNAA Exif tag, if it exists. Delete the tag if there // is no IPTC data anymore. // If there is new IPTC data and Exif.Image.ImageResources does // not exist, create a new IPTCNAA Exif tag. bool del = false; ExifKey iptcNaaKey("Exif.Image.IPTCNAA"); ExifData::iterator pos = exifData_.findKey(iptcNaaKey); if (pos != exifData_.end()) { iptcNaaKey.setIdx(pos->idx()); exifData_.erase(pos); del = true; } DataBuf rawIptc = IptcParser::encode(iptcData_); ExifKey irbKey("Exif.Image.ImageResources"); pos = exifData_.findKey(irbKey); if (pos != exifData_.end()) { irbKey.setIdx(pos->idx()); } if (rawIptc.size_ != 0 && (del || pos == exifData_.end())) { Value::AutoPtr value = Value::create(unsignedLong); DataBuf buf; if (rawIptc.size_ % 4 != 0) { // Pad the last unsignedLong value with 0s buf.alloc((rawIptc.size_ / 4) * 4 + 4); memset(buf.pData_, 0x0, buf.size_); memcpy(buf.pData_, rawIptc.pData_, rawIptc.size_); } else { buf = rawIptc; // Note: This resets rawIptc } value->read(buf.pData_, buf.size_, byteOrder_); Exifdatum iptcDatum(iptcNaaKey, value.get()); exifData_.add(iptcDatum); pos = exifData_.findKey(irbKey); // needed after add() } // Also update IPTC IRB in Exif.Image.ImageResources if it exists, // but don't create it if not. if (pos != exifData_.end()) { DataBuf irbBuf(pos->value().size()); pos->value().copy(irbBuf.pData_, invalidByteOrder); irbBuf = Photoshop::setIptcIrb(irbBuf.pData_, irbBuf.size_, iptcData_); exifData_.erase(pos); if (irbBuf.size_ != 0) { Value::AutoPtr value = Value::create(unsignedByte); value->read(irbBuf.pData_, irbBuf.size_, invalidByteOrder); Exifdatum iptcDatum(irbKey, value.get()); exifData_.add(iptcDatum); } } } // TiffEncoder::encodeIptc void TiffEncoder::encodeXmp() { ExifKey xmpKey("Exif.Image.XMLPacket"); // Remove any existing XMP Exif tag ExifData::iterator pos = exifData_.findKey(xmpKey); if (pos != exifData_.end()) { xmpKey.setIdx(pos->idx()); exifData_.erase(pos); } std::string xmpPacket; if (XmpParser::encode(xmpPacket, xmpData_) > 1) { #ifndef SUPPRESS_WARNINGS EXV_ERROR << "Failed to encode XMP metadata.\n"; #endif } if (!xmpPacket.empty()) { // Set the XMP Exif tag to the new value Value::AutoPtr value = Value::create(unsignedByte); value->read(reinterpret_cast(&xmpPacket[0]), static_cast(xmpPacket.size()), invalidByteOrder); Exifdatum xmpDatum(xmpKey, value.get()); exifData_.add(xmpDatum); } } // TiffEncoder::encodeXmp void TiffEncoder::setDirty(bool flag) { dirty_ = flag; setGo(geTraverse, !flag); } bool TiffEncoder::dirty() const { if (dirty_ || exifData_.count() > 0) return true; return false; } void TiffEncoder::visitEntry(TiffEntry* object) { encodeTiffComponent(object); } void TiffEncoder::visitDataEntry(TiffDataEntry* object) { encodeTiffComponent(object); } void TiffEncoder::visitImageEntry(TiffImageEntry* object) { encodeTiffComponent(object); } void TiffEncoder::visitSizeEntry(TiffSizeEntry* object) { encodeTiffComponent(object); } void TiffEncoder::visitDirectory(TiffDirectory* /*object*/) { // Nothing to do } void TiffEncoder::visitDirectoryNext(TiffDirectory* object) { // Update type and count in IFD entries, in case they changed assert(object != 0); byte* p = object->start() + 2; for (TiffDirectory::Components::iterator i = object->components_.begin(); i != object->components_.end(); ++i) { p += updateDirEntry(p, byteOrder(), *i); } } uint32_t TiffEncoder::updateDirEntry(byte* buf, ByteOrder byteOrder, TiffComponent* pTiffComponent) const { assert(buf); assert(pTiffComponent); TiffEntryBase* pTiffEntry = dynamic_cast(pTiffComponent); assert(pTiffEntry); us2Data(buf + 2, pTiffEntry->tiffType(), byteOrder); ul2Data(buf + 4, pTiffEntry->count(), byteOrder); // Move data to offset field, if it fits and is not yet there. if (pTiffEntry->size() <= 4 && buf + 8 != pTiffEntry->pData()) { #ifdef DEBUG std::cerr << "Copying data for tag " << pTiffEntry->tag() << " to offset area.\n"; #endif memset(buf + 8, 0x0, 4); memcpy(buf + 8, pTiffEntry->pData(), pTiffEntry->size()); memset(const_cast(pTiffEntry->pData()), 0x0, pTiffEntry->size()); } return 12; } void TiffEncoder::visitSubIfd(TiffSubIfd* object) { encodeTiffComponent(object); } void TiffEncoder::visitMnEntry(TiffMnEntry* object) { // Test is required here as well as in the callback encoder function if (!object->mn_) { encodeTiffComponent(object); } else if (del_) { // The makernote is made up of decoded tags, delete binary tag ExifKey key(object->tag(), groupName(object->group())); ExifData::iterator pos = exifData_.findKey(key); if (pos != exifData_.end()) exifData_.erase(pos); } } void TiffEncoder::visitIfdMakernote(TiffIfdMakernote* object) { assert(object != 0); ExifData::iterator pos = exifData_.findKey(ExifKey("Exif.MakerNote.ByteOrder")); if (pos != exifData_.end()) { // Set Makernote byte order ByteOrder bo = stringToByteOrder(pos->toString()); if (bo != invalidByteOrder && bo != object->byteOrder()) { object->setByteOrder(bo); setDirty(); } if (del_) exifData_.erase(pos); } if (del_) { // Remove remaining synthesized tags static const char* synthesizedTags[] = { "Exif.MakerNote.Offset", }; for (unsigned int i = 0; i < EXV_COUNTOF(synthesizedTags); ++i) { ExifData::iterator pos = exifData_.findKey(ExifKey(synthesizedTags[i])); if (pos != exifData_.end()) exifData_.erase(pos); } } // Modify encoder for Makernote peculiarities, byte order byteOrder_ = object->byteOrder(); } // TiffEncoder::visitIfdMakernote void TiffEncoder::visitIfdMakernoteEnd(TiffIfdMakernote* /*object*/) { // Reset byte order back to that from the c'tor byteOrder_ = origByteOrder_; } // TiffEncoder::visitIfdMakernoteEnd void TiffEncoder::visitBinaryArray(TiffBinaryArray* object) { if (object->cfg() == 0 || !object->decoded()) { encodeTiffComponent(object); } } void TiffEncoder::visitBinaryArrayEnd(TiffBinaryArray* object) { assert(object != 0); if (object->cfg() == 0 || !object->decoded()) return; int32_t size = object->TiffEntryBase::doSize(); if (size == 0) return; if (!object->initialize(pRoot_)) return; // Re-encrypt buffer if necessary const CryptFct cryptFct = object->cfg()->cryptFct_; if (cryptFct != 0) { const byte* pData = object->pData(); DataBuf buf = cryptFct(object->tag(), pData, size, pRoot_); if (buf.size_ > 0) { pData = buf.pData_; size = buf.size_; } if (!object->updOrigDataBuf(pData, size)) { setDirty(); } } } void TiffEncoder::visitBinaryElement(TiffBinaryElement* object) { // Temporarily overwrite byteorder according to that of the binary element ByteOrder boOrig = byteOrder_; if (object->elByteOrder() != invalidByteOrder) byteOrder_ = object->elByteOrder(); encodeTiffComponent(object); byteOrder_ = boOrig; } bool TiffEncoder::isImageTag(uint16_t tag, IfdId group) const { if (!isNewImage_ && pHeader_->isImageTag(tag, group, pPrimaryGroups_)) { return true; } return false; } void TiffEncoder::encodeTiffComponent( TiffEntryBase* object, const Exifdatum* datum ) { assert(object != 0); // Skip image tags of existing TIFF image - they were copied earlier - // but add and encode image tags of new images (creation) if (isImageTag(object->tag(), object->group())) return; ExifData::iterator pos = exifData_.end(); const Exifdatum* ed = datum; if (ed == 0) { // Non-intrusive writing: find matching tag ExifKey key(object->tag(), groupName(object->group())); pos = exifData_.findKey(key); if (pos != exifData_.end()) { ed = &(*pos); if (object->idx() != pos->idx()) { // Try to find exact match (in case of duplicate tags) ExifData::iterator pos2 = std::find_if(exifData_.begin(), exifData_.end(), FindExifdatum2(object->group(), object->idx())); if (pos2 != exifData_.end() && pos2->key() == key.key()) { ed = &(*pos2); pos = pos2; // make sure we delete the correct tag below } } } else { setDirty(); #ifdef DEBUG std::cerr << "DELETING " << key << ", idx = " << object->idx() << "\n"; #endif } } else { // For intrusive writing, the index is used to preserve the order of // duplicate tags object->idx_ = ed->idx(); } if (ed) { const EncoderFct fct = findEncoderFct_(make_, object->tag(), object->group()); if (fct) { // If an encoding function is registered for the tag, use it EXV_CALL_MEMBER_FN(*this, fct)(object, ed); } else { // Else use the encode function at the object (results in a double-dispatch // to the appropriate encoding function of the encoder. object->encode(*this, ed); } } if (del_ && pos != exifData_.end()) { exifData_.erase(pos); } #ifdef DEBUG std::cerr << "\n"; #endif } // TiffEncoder::encodeTiffComponent void TiffEncoder::encodeBinaryArray(TiffBinaryArray* object, const Exifdatum* datum) { encodeOffsetEntry(object, datum); } // TiffEncoder::encodeBinaryArray void TiffEncoder::encodeBinaryElement(TiffBinaryElement* object, const Exifdatum* datum) { encodeTiffEntryBase(object, datum); } // TiffEncoder::encodeArrayElement void TiffEncoder::encodeDataEntry(TiffDataEntry* object, const Exifdatum* datum) { encodeOffsetEntry(object, datum); if (!dirty_ && writeMethod() == wmNonIntrusive) { assert(object); assert(object->pValue()); if ( object->sizeDataArea_ < static_cast(object->pValue()->sizeDataArea())) { #ifdef DEBUG ExifKey key(object->tag(), groupName(object->group())); std::cerr << "DATAAREA GREW " << key << "\n"; #endif setDirty(); } else { // Write the new dataarea, fill with 0x0 #ifdef DEBUG ExifKey key(object->tag(), groupName(object->group())); std::cerr << "Writing data area for " << key << "\n"; #endif DataBuf buf = object->pValue()->dataArea(); memcpy(object->pDataArea_, buf.pData_, buf.size_); if (object->sizeDataArea_ - buf.size_ > 0) { memset(object->pDataArea_ + buf.size_, 0x0, object->sizeDataArea_ - buf.size_); } } } } // TiffEncoder::encodeDataEntry void TiffEncoder::encodeTiffEntry(TiffEntry* object, const Exifdatum* datum) { encodeTiffEntryBase(object, datum); } // TiffEncoder::encodeTiffEntry void TiffEncoder::encodeImageEntry(TiffImageEntry* object, const Exifdatum* datum) { encodeOffsetEntry(object, datum); uint32_t sizeDataArea = object->pValue()->sizeDataArea(); if (sizeDataArea > 0 && writeMethod() == wmNonIntrusive) { #ifdef DEBUG std::cerr << "\t DATAAREA IS SET (NON-INTRUSIVE WRITING)"; #endif setDirty(); } if (sizeDataArea > 0 && writeMethod() == wmIntrusive) { #ifdef DEBUG std::cerr << "\t DATAAREA IS SET (INTRUSIVE WRITING)"; #endif // Set pseudo strips (without a data pointer) from the size tag ExifKey key(object->szTag(), groupName(object->szGroup())); ExifData::const_iterator pos = exifData_.findKey(key); const byte* zero = 0; if (pos == exifData_.end()) { #ifndef SUPPRESS_WARNINGS EXV_ERROR << "Size tag " << key << " not found. Writing only one strip.\n"; #endif object->strips_.clear(); object->strips_.push_back(std::make_pair(zero, sizeDataArea)); } else { uint32_t sizeTotal = 0; object->strips_.clear(); for (long i = 0; i < pos->count(); ++i) { uint32_t len = pos->toLong(i); object->strips_.push_back(std::make_pair(zero, len)); sizeTotal += len; } if (sizeTotal != sizeDataArea) { #ifndef SUPPRESS_WARNINGS ExifKey key2(object->tag(), groupName(object->group())); EXV_ERROR << "Sum of all sizes of " << key << " != data size of " << key2 << ". " << "This results in an invalid image.\n"; #endif // Todo: How to fix? Write only one strip? } } } if (sizeDataArea == 0 && writeMethod() == wmIntrusive) { #ifdef DEBUG std::cerr << "\t USE STRIPS FROM SOURCE TREE IMAGE ENTRY"; #endif // Set strips from source tree if (pSourceTree_) { TiffFinder finder(object->tag(), object->group()); pSourceTree_->accept(finder); TiffImageEntry* ti = dynamic_cast(finder.result()); if (ti) { object->strips_ = ti->strips_; } } #ifndef SUPPRESS_WARNINGS else { ExifKey key2(object->tag(), groupName(object->group())); EXV_WARNING << "No image data to encode " << key2 << ".\n"; } #endif } } // TiffEncoder::encodeImageEntry void TiffEncoder::encodeMnEntry(TiffMnEntry* object, const Exifdatum* datum) { // Test is required here as well as in the visit function if (!object->mn_) encodeTiffEntryBase(object, datum); } // TiffEncoder::encodeMnEntry void TiffEncoder::encodeSizeEntry(TiffSizeEntry* object, const Exifdatum* datum) { encodeTiffEntryBase(object, datum); } // TiffEncoder::encodeSizeEntry void TiffEncoder::encodeSubIfd(TiffSubIfd* object, const Exifdatum* datum) { encodeOffsetEntry(object, datum); } // TiffEncoder::encodeSubIfd void TiffEncoder::encodeTiffEntryBase(TiffEntryBase* object, const Exifdatum* datum) { assert(object != 0); assert(datum != 0); #ifdef DEBUG bool tooLarge = false; #endif uint32_t newSize = datum->size(); if (newSize > object->size_) { // value doesn't fit, encode for intrusive writing setDirty(); #ifdef DEBUG tooLarge = true; #endif } object->updateValue(datum->getValue(), byteOrder()); // clones the value #ifdef DEBUG ExifKey key(object->tag(), groupName(object->group())); std::cerr << "UPDATING DATA " << key; if (tooLarge) { std::cerr << "\t\t\t ALLOCATED " << std::dec << object->size_ << " BYTES"; } #endif } // TiffEncoder::encodeTiffEntryBase void TiffEncoder::encodeOffsetEntry(TiffEntryBase* object, const Exifdatum* datum) { assert(object != 0); assert(datum != 0); uint32_t newSize = datum->size(); if (newSize > object->size_) { // value doesn't fit, encode for intrusive writing setDirty(); object->updateValue(datum->getValue(), byteOrder()); // clones the value #ifdef DEBUG ExifKey key(object->tag(), groupName(object->group())); std::cerr << "UPDATING DATA " << key; std::cerr << "\t\t\t ALLOCATED " << object->size() << " BYTES"; #endif } else { object->setValue(datum->getValue()); // clones the value #ifdef DEBUG ExifKey key(object->tag(), groupName(object->group())); std::cerr << "NOT UPDATING " << key; std::cerr << "\t\t\t PRESERVE VALUE DATA"; #endif } } // TiffEncoder::encodeOffsetEntry void TiffEncoder::add( TiffComponent* pRootDir, TiffComponent* pSourceDir, uint32_t root ) { assert(pRootDir != 0); writeMethod_ = wmIntrusive; pSourceTree_ = pSourceDir; // Ensure that the exifData_ entries are not deleted, to be able to // iterate over all remaining entries. del_ = false; ExifData::const_iterator posBo = exifData_.end(); for (ExifData::const_iterator i = exifData_.begin(); i != exifData_.end(); ++i) { IfdId group = groupId(i->groupName()); // Skip synthesized info tags if (group == mnId) { if (i->tag() == 0x0002) { posBo = i; } continue; } // Skip image tags of existing TIFF image - they were copied earlier - // but add and encode image tags of new images (creation) if (isImageTag(i->tag(), group)) continue; // Assumption is that the corresponding TIFF entry doesn't exist TiffPath tiffPath; TiffCreator::getPath(tiffPath, i->tag(), group, root); TiffComponent* tc = pRootDir->addPath(i->tag(), tiffPath, pRootDir); TiffEntryBase* object = dynamic_cast(tc); #ifdef DEBUG if (object == 0) { std::cerr << "Warning: addPath() didn't add an entry for " << i->groupName() << " tag 0x" << std::setw(4) << std::setfill('0') << std::hex << i->tag() << "\n"; } #endif if (object != 0) { encodeTiffComponent(object, &(*i)); } } /* What follows is a hack. I can't think of a better way to set the makernote byte order (and other properties maybe) in the makernote header during intrusive writing. The thing is that visit/encodeIfdMakernote is not called in this case and there can't be an Exif tag which corresponds to this component. */ if (posBo == exifData_.end()) return; TiffFinder finder(0x927c, exifId); pRootDir->accept(finder); TiffMnEntry* te = dynamic_cast(finder.result()); if (te) { TiffIfdMakernote* tim = dynamic_cast(te->mn_); if (tim) { // Set Makernote byte order ByteOrder bo = stringToByteOrder(posBo->toString()); if (bo != invalidByteOrder) tim->setByteOrder(bo); } } } // TiffEncoder::add TiffReader::TiffReader(const byte* pData, uint32_t size, TiffComponent* pRoot, TiffRwState::AutoPtr state) : pData_(pData), size_(size), pLast_(pData + size), pRoot_(pRoot), pState_(state.release()), pOrigState_(pState_), postProc_(false) { assert(pData_); assert(size_ > 0); } // TiffReader::TiffReader TiffReader::~TiffReader() { if (pOrigState_ != pState_) delete pOrigState_; delete pState_; } void TiffReader::resetState() { if (pOrigState_ != pState_) delete pState_; pState_ = pOrigState_; } void TiffReader::changeState(TiffRwState::AutoPtr state) { if (state.get() != 0) { if (pOrigState_ != pState_) delete pState_; // invalidByteOrder indicates 'no change' if (state->byteOrder_ == invalidByteOrder) state->byteOrder_ = pState_->byteOrder_; pState_ = state.release(); } } ByteOrder TiffReader::byteOrder() const { assert(pState_); return pState_->byteOrder_; } uint32_t TiffReader::baseOffset() const { assert(pState_); return pState_->baseOffset_; } void TiffReader::readDataEntryBase(TiffDataEntryBase* object) { assert(object != 0); readTiffEntry(object); TiffFinder finder(object->szTag(), object->szGroup()); pRoot_->accept(finder); TiffEntryBase* te = dynamic_cast(finder.result()); if (te && te->pValue()) { object->setStrips(te->pValue(), pData_, size_, baseOffset()); } } void TiffReader::visitEntry(TiffEntry* object) { readTiffEntry(object); } void TiffReader::visitDataEntry(TiffDataEntry* object) { readDataEntryBase(object); } void TiffReader::visitImageEntry(TiffImageEntry* object) { readDataEntryBase(object); } void TiffReader::visitSizeEntry(TiffSizeEntry* object) { assert(object != 0); readTiffEntry(object); TiffFinder finder(object->dtTag(), object->dtGroup()); pRoot_->accept(finder); TiffDataEntryBase* te = dynamic_cast(finder.result()); if (te && te->pValue()) { te->setStrips(object->pValue(), pData_, size_, baseOffset()); } } bool TiffReader::circularReference(const byte* start, IfdId group) { DirList::const_iterator pos = dirList_.find(start); if (pos != dirList_.end()) { #ifndef SUPPRESS_WARNINGS EXV_ERROR << groupName(group) << " pointer references previously read " << groupName(pos->second) << " directory. Ignored.\n"; #endif return true; } dirList_[start] = group; return false; } int TiffReader::nextIdx(IfdId group) { return ++idxSeq_[group]; } void TiffReader::postProcess() { postProc_ = true; for (PostList::const_iterator pos = postList_.begin(); pos != postList_.end(); ++pos) { (*pos)->accept(*this); } postProc_ = false; } void TiffReader::visitDirectory(TiffDirectory* object) { assert(object != 0); const byte* p = object->start(); assert(p >= pData_); if (circularReference(object->start(), object->group())) return; if (p + 2 > pLast_) { #ifndef SUPPRESS_WARNINGS EXV_ERROR << "Directory " << groupName(object->group()) << ": IFD exceeds data buffer, cannot read entry count.\n"; #endif return; } const uint16_t n = getUShort(p, byteOrder()); p += 2; // Sanity check with an "unreasonably" large number if (n > 256) { #ifndef SUPPRESS_WARNINGS EXV_ERROR << "Directory " << groupName(object->group()) << " with " << n << " entries considered invalid; not read.\n"; #endif return; } for (uint16_t i = 0; i < n; ++i) { if (p + 12 > pLast_) { #ifndef SUPPRESS_WARNINGS EXV_ERROR << "Directory " << groupName(object->group()) << ": IFD entry " << i << " lies outside of the data buffer.\n"; #endif return; } uint16_t tag = getUShort(p, byteOrder()); TiffComponent::AutoPtr tc = TiffCreator::create(tag, object->group()); // The assertion typically fails if a component is not configured in // the TIFF structure table assert(tc.get()); tc->setStart(p); object->addChild(tc); p += 12; } if (object->hasNext()) { if (p + 4 > pLast_) { #ifndef SUPPRESS_WARNINGS EXV_ERROR << "Directory " << groupName(object->group()) << ": IFD exceeds data buffer, cannot read next pointer.\n"; #endif return; } TiffComponent::AutoPtr tc(0); uint32_t next = getLong(p, byteOrder()); if (next) { tc = TiffCreator::create(Tag::next, object->group()); #ifndef SUPPRESS_WARNINGS if (tc.get() == 0) { EXV_WARNING << "Directory " << groupName(object->group()) << " has an unhandled next pointer.\n"; } #endif } if (tc.get()) { if (baseOffset() + next > size_) { #ifndef SUPPRESS_WARNINGS EXV_ERROR << "Directory " << groupName(object->group()) << ": Next pointer is out of bounds; ignored.\n"; #endif return; } tc->setStart(pData_ + baseOffset() + next); object->addNext(tc); } } // object->hasNext() } // TiffReader::visitDirectory void TiffReader::visitSubIfd(TiffSubIfd* object) { assert(object != 0); readTiffEntry(object); if ( (object->tiffType() == ttUnsignedLong || object->tiffType() == ttSignedLong || object->tiffType() == ttTiffIfd) && object->count() >= 1) { // Todo: Fix hack uint32_t maxi = 9; if (object->group() == ifd1Id) maxi = 1; for (uint32_t i = 0; i < object->count(); ++i) { int32_t offset = getLong(object->pData() + 4*i, byteOrder()); if ( baseOffset() + offset > size_ || static_cast(baseOffset()) + offset < 0) { #ifndef SUPPRESS_WARNINGS EXV_ERROR << "Directory " << groupName(object->group()) << ", entry 0x" << std::setw(4) << std::setfill('0') << std::hex << object->tag() << " Sub-IFD pointer " << i << " is out of bounds; ignoring it.\n"; #endif return; } if (i >= maxi) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Directory " << groupName(object->group()) << ", entry 0x" << std::setw(4) << std::setfill('0') << std::hex << object->tag() << ": Skipping sub-IFDs beyond the first " << i << ".\n"; #endif break; } // If there are multiple dirs, group is incremented for each TiffComponent::AutoPtr td(new TiffDirectory(object->tag(), static_cast(object->newGroup_ + i))); td->setStart(pData_ + baseOffset() + offset); object->addChild(td); } } #ifndef SUPPRESS_WARNINGS else { EXV_WARNING << "Directory " << groupName(object->group()) << ", entry 0x" << std::setw(4) << std::setfill('0') << std::hex << object->tag() << " doesn't look like a sub-IFD.\n"; } #endif } // TiffReader::visitSubIfd void TiffReader::visitMnEntry(TiffMnEntry* object) { assert(object != 0); readTiffEntry(object); // Find camera make TiffFinder finder(0x010f, ifd0Id); pRoot_->accept(finder); TiffEntryBase* te = dynamic_cast(finder.result()); std::string make; if (te && te->pValue()) { make = te->pValue()->toString(); // create concrete makernote, based on make and makernote contents object->mn_ = TiffMnCreator::create(object->tag(), object->mnGroup_, make, object->pData_, object->size_, byteOrder()); } if (object->mn_) object->mn_->setStart(object->pData()); } // TiffReader::visitMnEntry void TiffReader::visitIfdMakernote(TiffIfdMakernote* object) { assert(object != 0); object->setImageByteOrder(byteOrder()); // set the byte order for the image if (!object->readHeader(object->start(), static_cast(pLast_ - object->start()), byteOrder())) { #ifndef SUPPRESS_WARNINGS EXV_ERROR << "Failed to read " << groupName(object->ifd_.group()) << " IFD Makernote header.\n"; #ifdef DEBUG if (static_cast(pLast_ - object->start()) >= 16) { hexdump(std::cerr, object->start(), 16); } #endif // DEBUG #endif // SUPPRESS_WARNINGS setGo(geKnownMakernote, false); return; } object->ifd_.setStart(object->start() + object->ifdOffset()); // Modify reader for Makernote peculiarities, byte order and offset object->mnOffset_ = static_cast(object->start() - pData_); TiffRwState::AutoPtr state( new TiffRwState(object->byteOrder(), object->baseOffset()) ); changeState(state); } // TiffReader::visitIfdMakernote void TiffReader::visitIfdMakernoteEnd(TiffIfdMakernote* /*object*/) { // Reset state (byte order, create function, offset) back to that for the image resetState(); } // TiffReader::visitIfdMakernoteEnd void TiffReader::readTiffEntry(TiffEntryBase* object) { assert(object != 0); byte* p = object->start(); assert(p >= pData_); if (p + 12 > pLast_) { #ifndef SUPPRESS_WARNINGS EXV_ERROR << "Entry in directory " << groupName(object->group()) << "requests access to memory beyond the data buffer. " << "Skipping entry.\n"; #endif return; } // Component already has tag p += 2; TiffType tiffType = getUShort(p, byteOrder()); TypeId typeId = toTypeId(tiffType, object->tag(), object->group()); long typeSize = TypeInfo::typeSize(typeId); if (0 == typeSize) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Directory " << groupName(object->group()) << ", entry 0x" << std::setw(4) << std::setfill('0') << std::hex << object->tag() << " has unknown Exif (TIFF) type " << std::dec << tiffType << "; setting type size 1.\n"; #endif typeSize = 1; } p += 2; uint32_t count = getULong(p, byteOrder()); if (count >= 0x10000000) { #ifndef SUPPRESS_WARNINGS EXV_ERROR << "Directory " << groupName(object->group()) << ", entry 0x" << std::setw(4) << std::setfill('0') << std::hex << object->tag() << " has invalid size " << std::dec << count << "*" << typeSize << "; skipping entry.\n"; #endif return; } p += 4; uint32_t size = typeSize * count; int32_t offset = getLong(p, byteOrder()); byte* pData = p; if ( size > 4 && ( baseOffset() + offset >= size_ || static_cast(baseOffset()) + offset <= 0)) { #ifndef SUPPRESS_WARNINGS EXV_ERROR << "Offset of directory " << groupName(object->group()) << ", entry 0x" << std::setw(4) << std::setfill('0') << std::hex << object->tag() << " is out of bounds: " << "Offset = 0x" << std::setw(8) << std::setfill('0') << std::hex << offset << "; truncating the entry\n"; #endif size = 0; } if (size > 4) { pData = const_cast(pData_) + baseOffset() + offset; if (size > static_cast(pLast_ - pData)) { #ifndef SUPPRESS_WARNINGS EXV_ERROR << "Upper boundary of data for " << "directory " << groupName(object->group()) << ", entry 0x" << std::setw(4) << std::setfill('0') << std::hex << object->tag() << " is out of bounds: " << "Offset = 0x" << std::setw(8) << std::setfill('0') << std::hex << offset << ", size = " << std::dec << size << ", exceeds buffer size by " // cast to make MSVC happy << static_cast(pData + size - pLast_) << " Bytes; truncating the entry\n"; #endif size = 0; } } Value::AutoPtr v = Value::create(typeId); assert(v.get()); v->read(pData, size, byteOrder()); object->setValue(v); object->setData(pData, size); object->setOffset(offset); object->setIdx(nextIdx(object->group())); } // TiffReader::readTiffEntry void TiffReader::visitBinaryArray(TiffBinaryArray* object) { assert(object != 0); if (!postProc_) { // Defer reading children until after all other components are read, but // since state (offset) is not set during post-processing, read entry here readTiffEntry(object); object->iniOrigDataBuf(); postList_.push_back(object); return; } // Check duplicates TiffFinder finder(object->tag(), object->group()); pRoot_->accept(finder); TiffEntryBase* te = dynamic_cast(finder.result()); if (te && te->idx() != object->idx()) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Not decoding duplicate binary array tag 0x" << std::setw(4) << std::setfill('0') << std::hex << object->tag() << std::dec << ", group " << groupName(object->group()) << ", idx " << object->idx() << "\n"; #endif object->setDecoded(false); return; } if (object->TiffEntryBase::doSize() == 0) return; if (!object->initialize(pRoot_)) return; const ArrayCfg* cfg = object->cfg(); if (cfg == 0) return; const CryptFct cryptFct = cfg->cryptFct_; if (cryptFct != 0) { const byte* pData = object->pData(); int32_t size = object->TiffEntryBase::doSize(); DataBuf buf = cryptFct(object->tag(), pData, size, pRoot_); if (buf.size_ > 0) object->setData(buf); } const ArrayDef* defs = object->def(); const ArrayDef* defsEnd = defs + object->defSize(); const ArrayDef* def = &cfg->elDefaultDef_; ArrayDef gap = *def; for (uint32_t idx = 0; idx < object->TiffEntryBase::doSize(); ) { if (defs) { def = std::find(defs, defsEnd, idx); if (def == defsEnd) { if (cfg->concat_) { // Determine gap-size const ArrayDef* xdef = defs; for (; xdef != defsEnd && xdef->idx_ <= idx; ++xdef) {} uint32_t gapSize = 0; if (xdef != defsEnd && xdef->idx_ > idx) { gapSize = xdef->idx_ - idx; } else { gapSize = object->TiffEntryBase::doSize() - idx; } gap.idx_ = idx; gap.tiffType_ = cfg->elDefaultDef_.tiffType_; gap.count_ = gapSize / cfg->tagStep(); if (gap.count_ * cfg->tagStep() != gapSize) { gap.tiffType_ = ttUndefined; gap.count_ = gapSize; } def = ⪆ } else { def = &cfg->elDefaultDef_; } } } idx += object->addElement(idx, *def); // idx may be different from def->idx_ } } // TiffReader::visitBinaryArray void TiffReader::visitBinaryElement(TiffBinaryElement* object) { byte* pData = object->start(); uint32_t size = object->TiffEntryBase::doSize(); ByteOrder bo = object->elByteOrder(); if (bo == invalidByteOrder) bo = byteOrder(); TypeId typeId = toTypeId(object->elDef()->tiffType_, object->tag(), object->group()); Value::AutoPtr v = Value::create(typeId); assert(v.get()); v->read(pData, size, bo); object->setValue(v); object->setOffset(0); object->setIdx(nextIdx(object->group())); } // TiffReader::visitBinaryElement }} // namespace Internal, Exiv2 exiv2-0.23/src/localtime.c0000644000175000017500000010764711442760130015230 0ustar andreasandreas/*! @file localtime.c @brief This file is from the tz distribution at ftp://elsie.nci.nih.gov/pub/ @version $Rev: 2347 $ */ #ifdef _MSC_VER # include "exv_msvc.h" #else # include "exv_conf.h" #endif #include "timegm.h" /* ** This file is in the public domain, so clarified as of ** 1996-06-05 by Arthur David Olson (arthur_david_olson@nih.gov). */ #ifndef lint #ifndef NOID static char elsieid[] = "@(#)localtime.c 7.78"; #endif /* !defined NOID */ #endif /* !defined lint */ /* ** Leap second handling from Bradley White (bww@k.gp.cs.cmu.edu). ** POSIX-style TZ environment variable handling from Guy Harris ** (guy@auspex.com). */ /*LINTLIBRARY*/ #include "private.h" #include "tzfile.h" #include "fcntl.h" /* ** SunOS 4.1.1 headers lack O_BINARY. */ #ifdef O_BINARY #define OPEN_MODE (O_RDONLY | O_BINARY) #endif /* defined O_BINARY */ #ifndef O_BINARY #define OPEN_MODE O_RDONLY #endif /* !defined O_BINARY */ #ifndef WILDABBR /* ** Someone might make incorrect use of a time zone abbreviation: ** 1. They might reference tzname[0] before calling tzset (explicitly ** or implicitly). ** 2. They might reference tzname[1] before calling tzset (explicitly ** or implicitly). ** 3. They might reference tzname[1] after setting to a time zone ** in which Daylight Saving Time is never observed. ** 4. They might reference tzname[0] after setting to a time zone ** in which Standard Time is never observed. ** 5. They might reference tm.TM_ZONE after calling offtime. ** What's best to do in the above cases is open to debate; ** for now, we just set things up so that in any of the five cases ** WILDABBR is used. Another possibility: initialize tzname[0] to the ** string "tzname[0] used before set", and similarly for the other cases. ** And another: initialize tzname[0] to "ERA", with an explanation in the ** manual page of what this "time zone abbreviation" means (doing this so ** that tzname[0] has the "normal" length of three characters). */ #define WILDABBR " " #endif /* !defined WILDABBR */ /* ahu: added conditional */ #ifdef TM_ZONE static char wildabbr[] = "WILDABBR"; #endif /* TM_ZONE */ static const char gmt[] = "GMT"; /* ** The DST rules to use if TZ has no rules and we can't load TZDEFRULES. ** We default to US rules as of 1999-08-17. ** POSIX 1003.1 section 8.1.1 says that the default DST rules are ** implementation dependent; for historical reasons, US rules are a ** common default. */ #ifndef TZDEFRULESTRING #define TZDEFRULESTRING ",M4.1.0,M10.5.0" #endif /* !defined TZDEFDST */ struct ttinfo { /* time type information */ long tt_gmtoff; /* UTC offset in seconds */ int tt_isdst; /* used to set tm_isdst */ size_t tt_abbrind; /* abbreviation list index */ int tt_ttisstd; /* TRUE if transition is std time */ int tt_ttisgmt; /* TRUE if transition is UTC */ }; struct lsinfo { /* leap second information */ time_t ls_trans; /* transition time */ long ls_corr; /* correction to apply */ }; #define BIGGEST(a, b) (((a) > (b)) ? (a) : (b)) #ifdef TZNAME_MAX #define MY_TZNAME_MAX TZNAME_MAX #endif /* defined TZNAME_MAX */ #ifndef TZNAME_MAX #define MY_TZNAME_MAX 255 #endif /* !defined TZNAME_MAX */ struct state { int leapcnt; int timecnt; int typecnt; size_t charcnt; time_t ats[TZ_MAX_TIMES]; unsigned char types[TZ_MAX_TIMES]; struct ttinfo ttis[TZ_MAX_TYPES]; char chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, sizeof gmt), (2 * (MY_TZNAME_MAX + 1)))]; struct lsinfo lsis[TZ_MAX_LEAPS]; }; struct rule { int r_type; /* type of rule--see below */ int r_day; /* day number of rule */ int r_week; /* week number of rule */ int r_mon; /* month number of rule */ long r_time; /* transition time of rule */ }; #define JULIAN_DAY 0 /* Jn - Julian day */ #define DAY_OF_YEAR 1 /* n - day of year */ #define MONTH_NTH_DAY_OF_WEEK 2 /* Mm.n.d - month, week, day of week */ /* ** Prototypes for static functions. */ /* ahu: deleted declaration of detzcode */ static const char * getzname P((const char * strp)); static const char * getnum P((const char * strp, int * nump, int min, int max)); static const char * getsecs P((const char * strp, long * secsp)); static const char * getoffset P((const char * strp, long * offsetp)); static const char * getrule P((const char * strp, struct rule * rulep)); static void gmtload P((struct state * sp)); static void gmtsub P((const time_t * timep, long offset, struct tm * tmp)); static void localsub P((const time_t * timep, long offset, struct tm * tmp)); static int increment_overflow P((int * number, int delta)); static int normalize_overflow P((int * tensptr, int * unitsptr, int base)); /* ahu: deleted declaration of settzname */ static time_t time1 P((struct tm * tmp, void(*funcp) P((const time_t *, long, struct tm *)), long offset)); static time_t time2 P((struct tm *tmp, void(*funcp) P((const time_t *, long, struct tm*)), long offset, int * okayp)); static time_t time2sub P((struct tm *tmp, void(*funcp) P((const time_t *, long, struct tm*)), long offset, int * okayp, int do_norm_secs)); static void timesub P((const time_t * timep, long offset, const struct state * sp, struct tm * tmp)); static int tmcomp P((const struct tm * atmp, const struct tm * btmp)); static time_t transtime P((time_t janfirst, int year, const struct rule * rulep, long offset)); static int tzload P((const char * name, struct state * sp)); static int tzparse P((const char * name, struct state * sp, int lastditch)); #ifdef ALL_STATE static struct state * lclptr; static struct state * gmtptr; #endif /* defined ALL_STATE */ #ifndef ALL_STATE static struct state lclmem; static struct state gmtmem; #define lclptr (&lclmem) #define gmtptr (&gmtmem) #endif /* State Farm */ #ifndef TZ_STRLEN_MAX #define TZ_STRLEN_MAX 255 #endif /* !defined TZ_STRLEN_MAX */ /* ahu: deleted definition of lcl_TZname[] and lcl_is_set */ static int gmt_is_set; /* ahu: deleted definition of tzname[] */ /* ** Section 4.12.3 of X3.159-1989 requires that ** Except for the strftime function, these functions [asctime, ** ctime, gmtime, localtime] return values in one of two static ** objects: a broken-down time structure and an array of char. ** Thanks to Paul Eggert (eggert@twinsun.com) for noting this. */ /* deleted definition of tm */ #ifdef USG_COMPAT time_t timezone = 0; int daylight = 0; #endif /* defined USG_COMPAT */ #ifdef ALTZONE time_t altzone = 0; #endif /* defined ALTZONE */ static long detzcode(codep) const char * const codep; { register long result; register int i; result = (codep[0] & 0x80) ? ~0L : 0L; for (i = 0; i < 4; ++i) result = (result << 8) | (codep[i] & 0xff); return result; } /* ahu: deleted definition of settzname */ static int tzload(name, sp) register const char * name; register struct state * const sp; { register const char * p; register int i; register int fid; if (name == NULL && (name = TZDEFAULT) == NULL) return -1; { register int doaccess; /* ** Section 4.9.1 of the C standard says that ** "FILENAME_MAX expands to an integral constant expression ** that is the size needed for an array of char large enough ** to hold the longest file name string that the implementation ** guarantees can be opened." */ char fullname[FILENAME_MAX + 1]; if (name[0] == ':') ++name; doaccess = name[0] == '/'; if (!doaccess) { if ((p = TZDIR) == NULL) return -1; if ((strlen(p) + strlen(name) + 1) >= sizeof fullname) return -1; (void) strcpy(fullname, p); (void) strcat(fullname, "/"); (void) strcat(fullname, name); /* ** Set doaccess if '.' (as in "../") shows up in name. */ if (strchr(name, '.') != NULL) doaccess = TRUE; name = fullname; } if (doaccess && access(name, R_OK) != 0) return -1; if ((fid = open(name, OPEN_MODE)) == -1) return -1; } { struct tzhead * tzhp; union { struct tzhead tzhead; char buf[sizeof *sp + sizeof *tzhp]; } u; int ttisstdcnt; int ttisgmtcnt; i = read(fid, u.buf, sizeof u.buf); if (close(fid) != 0) return -1; ttisstdcnt = (int) detzcode(u.tzhead.tzh_ttisstdcnt); ttisgmtcnt = (int) detzcode(u.tzhead.tzh_ttisgmtcnt); sp->leapcnt = (int) detzcode(u.tzhead.tzh_leapcnt); sp->timecnt = (int) detzcode(u.tzhead.tzh_timecnt); sp->typecnt = (int) detzcode(u.tzhead.tzh_typecnt); sp->charcnt = detzcode(u.tzhead.tzh_charcnt); p = u.tzhead.tzh_charcnt + sizeof u.tzhead.tzh_charcnt; if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS || sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES || sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES || sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS || (ttisstdcnt != sp->typecnt && ttisstdcnt != 0) || (ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0)) return -1; if (i - (p - u.buf) < sp->timecnt * 4 + /* ats */ sp->timecnt + /* types */ sp->typecnt * (4 + 2) + /* ttinfos */ (int)sp->charcnt + /* chars */ sp->leapcnt * (4 + 4) + /* lsinfos */ ttisstdcnt + /* ttisstds */ ttisgmtcnt) /* ttisgmts */ return -1; for (i = 0; i < sp->timecnt; ++i) { sp->ats[i] = detzcode(p); p += 4; } for (i = 0; i < sp->timecnt; ++i) { sp->types[i] = (unsigned char) *p++; if (sp->types[i] >= sp->typecnt) return -1; } for (i = 0; i < sp->typecnt; ++i) { register struct ttinfo * ttisp; ttisp = &sp->ttis[i]; ttisp->tt_gmtoff = detzcode(p); p += 4; ttisp->tt_isdst = (unsigned char) *p++; if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1) return -1; ttisp->tt_abbrind = (unsigned char) *p++; if (ttisp->tt_abbrind < 0 || ttisp->tt_abbrind > sp->charcnt) return -1; } for (i = 0; i < (int)sp->charcnt; ++i) sp->chars[i] = *p++; sp->chars[i] = '\0'; /* ensure '\0' at end */ for (i = 0; i < sp->leapcnt; ++i) { register struct lsinfo * lsisp; lsisp = &sp->lsis[i]; lsisp->ls_trans = detzcode(p); p += 4; lsisp->ls_corr = detzcode(p); p += 4; } for (i = 0; i < sp->typecnt; ++i) { register struct ttinfo * ttisp; ttisp = &sp->ttis[i]; if (ttisstdcnt == 0) ttisp->tt_ttisstd = FALSE; else { ttisp->tt_ttisstd = *p++; if (ttisp->tt_ttisstd != TRUE && ttisp->tt_ttisstd != FALSE) return -1; } } for (i = 0; i < sp->typecnt; ++i) { register struct ttinfo * ttisp; ttisp = &sp->ttis[i]; if (ttisgmtcnt == 0) ttisp->tt_ttisgmt = FALSE; else { ttisp->tt_ttisgmt = *p++; if (ttisp->tt_ttisgmt != TRUE && ttisp->tt_ttisgmt != FALSE) return -1; } } } return 0; } static const int mon_lengths[2][MONSPERYEAR] = { { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } }; static const int year_lengths[2] = { DAYSPERNYEAR, DAYSPERLYEAR }; /* ** Given a pointer into a time zone string, scan until a character that is not ** a valid character in a zone name is found. Return a pointer to that ** character. */ static const char * getzname(strp) register const char * strp; { register char c; while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' && c != '+') ++strp; return strp; } /* ** Given a pointer into a time zone string, extract a number from that string. ** Check that the number is within a specified range; if it is not, return ** NULL. ** Otherwise, return a pointer to the first character not part of the number. */ static const char * getnum(strp, nump, min, max) register const char * strp; int * const nump; const int min; const int max; { register char c; register int num; if (strp == NULL || !is_digit(c = *strp)) return NULL; num = 0; do { num = num * 10 + (c - '0'); if (num > max) return NULL; /* illegal value */ c = *++strp; } while (is_digit(c)); if (num < min) return NULL; /* illegal value */ *nump = num; return strp; } /* ** Given a pointer into a time zone string, extract a number of seconds, ** in hh[:mm[:ss]] form, from the string. ** If any error occurs, return NULL. ** Otherwise, return a pointer to the first character not part of the number ** of seconds. */ static const char * getsecs(strp, secsp) register const char * strp; long * const secsp; { int num; /* ** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like ** "M10.4.6/26", which does not conform to Posix, ** but which specifies the equivalent of ** ``02:00 on the first Sunday on or after 23 Oct''. */ strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1); if (strp == NULL) return NULL; *secsp = num * (long) SECSPERHOUR; if (*strp == ':') { ++strp; strp = getnum(strp, &num, 0, MINSPERHOUR - 1); if (strp == NULL) return NULL; *secsp += num * SECSPERMIN; if (*strp == ':') { ++strp; /* `SECSPERMIN' allows for leap seconds. */ strp = getnum(strp, &num, 0, SECSPERMIN); if (strp == NULL) return NULL; *secsp += num; } } return strp; } /* ** Given a pointer into a time zone string, extract an offset, in ** [+-]hh[:mm[:ss]] form, from the string. ** If any error occurs, return NULL. ** Otherwise, return a pointer to the first character not part of the time. */ static const char * getoffset(strp, offsetp) register const char * strp; long * const offsetp; { register int neg = 0; if (*strp == '-') { neg = 1; ++strp; } else if (*strp == '+') ++strp; strp = getsecs(strp, offsetp); if (strp == NULL) return NULL; /* illegal time */ if (neg) *offsetp = -*offsetp; return strp; } /* ** Given a pointer into a time zone string, extract a rule in the form ** date[/time]. See POSIX section 8 for the format of "date" and "time". ** If a valid rule is not found, return NULL. ** Otherwise, return a pointer to the first character not part of the rule. */ static const char * getrule(strp, rulep) const char * strp; register struct rule * const rulep; { if (*strp == 'J') { /* ** Julian day. */ rulep->r_type = JULIAN_DAY; ++strp; strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR); } else if (*strp == 'M') { /* ** Month, week, day. */ rulep->r_type = MONTH_NTH_DAY_OF_WEEK; ++strp; strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR); if (strp == NULL) return NULL; if (*strp++ != '.') return NULL; strp = getnum(strp, &rulep->r_week, 1, 5); if (strp == NULL) return NULL; if (*strp++ != '.') return NULL; strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1); } else if (is_digit(*strp)) { /* ** Day of year. */ rulep->r_type = DAY_OF_YEAR; strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1); } else return NULL; /* invalid format */ if (strp == NULL) return NULL; if (*strp == '/') { /* ** Time specified. */ ++strp; strp = getsecs(strp, &rulep->r_time); } else rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */ return strp; } /* ** Given the Epoch-relative time of January 1, 00:00:00 UTC, in a year, the ** year, a rule, and the offset from UTC at the time that rule takes effect, ** calculate the Epoch-relative time that rule takes effect. */ static time_t transtime(janfirst, year, rulep, offset) const time_t janfirst; const int year; register const struct rule * const rulep; const long offset; { register int leapyear; register time_t value; register int i; int d, m1, yy0, yy1, yy2, dow; INITIALIZE(value); leapyear = isleap(year); switch (rulep->r_type) { case JULIAN_DAY: /* ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap ** years. ** In non-leap years, or if the day number is 59 or less, just ** add SECSPERDAY times the day number-1 to the time of ** January 1, midnight, to get the day. */ value = janfirst + (rulep->r_day - 1) * SECSPERDAY; if (leapyear && rulep->r_day >= 60) value += SECSPERDAY; break; case DAY_OF_YEAR: /* ** n - day of year. ** Just add SECSPERDAY times the day number to the time of ** January 1, midnight, to get the day. */ value = janfirst + rulep->r_day * SECSPERDAY; break; case MONTH_NTH_DAY_OF_WEEK: /* ** Mm.n.d - nth "dth day" of month m. */ value = janfirst; for (i = 0; i < rulep->r_mon - 1; ++i) value += mon_lengths[leapyear][i] * SECSPERDAY; /* ** Use Zeller's Congruence to get day-of-week of first day of ** month. */ m1 = (rulep->r_mon + 9) % 12 + 1; yy0 = (rulep->r_mon <= 2) ? (year - 1) : year; yy1 = yy0 / 100; yy2 = yy0 % 100; dow = ((26 * m1 - 2) / 10 + 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7; if (dow < 0) dow += DAYSPERWEEK; /* ** "dow" is the day-of-week of the first day of the month. Get ** the day-of-month (zero-origin) of the first "dow" day of the ** month. */ d = rulep->r_day - dow; if (d < 0) d += DAYSPERWEEK; for (i = 1; i < rulep->r_week; ++i) { if (d + DAYSPERWEEK >= mon_lengths[leapyear][rulep->r_mon - 1]) break; d += DAYSPERWEEK; } /* ** "d" is the day-of-month (zero-origin) of the day we want. */ value += d * SECSPERDAY; break; } /* ** "value" is the Epoch-relative time of 00:00:00 UTC on the day in ** question. To get the Epoch-relative time of the specified local ** time on that day, add the transition time and the current offset ** from UTC. */ return value + rulep->r_time + offset; } /* ** Given a POSIX section 8-style TZ string, fill in the rule tables as ** appropriate. */ static int tzparse(name, sp, lastditch) const char * name; register struct state * const sp; const int lastditch; { const char * stdname; const char * dstname; size_t stdlen; size_t dstlen; long stdoffset; long dstoffset; register time_t * atp; register unsigned char * typep; register char * cp; register int load_result; INITIALIZE(dstname); stdname = name; if (lastditch) { stdlen = strlen(name); /* length of standard zone name */ name += stdlen; if (stdlen >= sizeof sp->chars) stdlen = (sizeof sp->chars) - 1; stdoffset = 0; } else { name = getzname(name); stdlen = name - stdname; if (stdlen < 3) return -1; if (*name == '\0') return -1; name = getoffset(name, &stdoffset); if (name == NULL) return -1; } load_result = tzload(TZDEFRULES, sp); if (load_result != 0) sp->leapcnt = 0; /* so, we're off a little */ if (*name != '\0') { dstname = name; name = getzname(name); dstlen = name - dstname; /* length of DST zone name */ if (dstlen < 3) return -1; if (*name != '\0' && *name != ',' && *name != ';') { name = getoffset(name, &dstoffset); if (name == NULL) return -1; } else dstoffset = stdoffset - SECSPERHOUR; if (*name == '\0' && load_result != 0) name = TZDEFRULESTRING; if (*name == ',' || *name == ';') { struct rule start; struct rule end; register int year; register time_t janfirst; time_t starttime; time_t endtime; ++name; if ((name = getrule(name, &start)) == NULL) return -1; if (*name++ != ',') return -1; if ((name = getrule(name, &end)) == NULL) return -1; if (*name != '\0') return -1; sp->typecnt = 2; /* standard time and DST */ /* ** Two transitions per year, from EPOCH_YEAR to 2037. */ sp->timecnt = 2 * (2037 - EPOCH_YEAR + 1); if (sp->timecnt > TZ_MAX_TIMES) return -1; sp->ttis[0].tt_gmtoff = -dstoffset; sp->ttis[0].tt_isdst = 1; sp->ttis[0].tt_abbrind = stdlen + 1; sp->ttis[1].tt_gmtoff = -stdoffset; sp->ttis[1].tt_isdst = 0; sp->ttis[1].tt_abbrind = 0; atp = sp->ats; typep = sp->types; janfirst = 0; for (year = EPOCH_YEAR; year <= 2037; ++year) { starttime = transtime(janfirst, year, &start, stdoffset); endtime = transtime(janfirst, year, &end, dstoffset); if (starttime > endtime) { *atp++ = endtime; *typep++ = 1; /* DST ends */ *atp++ = starttime; *typep++ = 0; /* DST begins */ } else { *atp++ = starttime; *typep++ = 0; /* DST begins */ *atp++ = endtime; *typep++ = 1; /* DST ends */ } janfirst += year_lengths[isleap(year)] * SECSPERDAY; } } else { register long theirstdoffset; register long theirdstoffset; register long theiroffset; register int isdst; register int i; register int j; if (*name != '\0') return -1; /* ** Initial values of theirstdoffset and theirdstoffset. */ theirstdoffset = 0; for (i = 0; i < sp->timecnt; ++i) { j = sp->types[i]; if (!sp->ttis[j].tt_isdst) { theirstdoffset = -sp->ttis[j].tt_gmtoff; break; } } theirdstoffset = 0; for (i = 0; i < sp->timecnt; ++i) { j = sp->types[i]; if (sp->ttis[j].tt_isdst) { theirdstoffset = -sp->ttis[j].tt_gmtoff; break; } } /* ** Initially we're assumed to be in standard time. */ isdst = FALSE; theiroffset = theirstdoffset; /* ** Now juggle transition times and types ** tracking offsets as you do. */ for (i = 0; i < sp->timecnt; ++i) { j = sp->types[i]; sp->types[i] = sp->ttis[j].tt_isdst; if (sp->ttis[j].tt_ttisgmt) { /* No adjustment to transition time */ } else { /* ** If summer time is in effect, and the ** transition time was not specified as ** standard time, add the summer time ** offset to the transition time; ** otherwise, add the standard time ** offset to the transition time. */ /* ** Transitions from DST to DDST ** will effectively disappear since ** POSIX provides for only one DST ** offset. */ if (isdst && !sp->ttis[j].tt_ttisstd) { sp->ats[i] += dstoffset - theirdstoffset; } else { sp->ats[i] += stdoffset - theirstdoffset; } } theiroffset = -sp->ttis[j].tt_gmtoff; if (sp->ttis[j].tt_isdst) theirdstoffset = theiroffset; else theirstdoffset = theiroffset; } /* ** Finally, fill in ttis. ** ttisstd and ttisgmt need not be handled. */ sp->ttis[0].tt_gmtoff = -stdoffset; sp->ttis[0].tt_isdst = FALSE; sp->ttis[0].tt_abbrind = 0; sp->ttis[1].tt_gmtoff = -dstoffset; sp->ttis[1].tt_isdst = TRUE; sp->ttis[1].tt_abbrind = stdlen + 1; sp->typecnt = 2; } } else { dstlen = 0; sp->typecnt = 1; /* only standard time */ sp->timecnt = 0; sp->ttis[0].tt_gmtoff = -stdoffset; sp->ttis[0].tt_isdst = 0; sp->ttis[0].tt_abbrind = 0; } sp->charcnt = stdlen + 1; if (dstlen != 0) sp->charcnt += dstlen + 1; if ((size_t) sp->charcnt > sizeof sp->chars) return -1; cp = sp->chars; (void) strncpy(cp, stdname, stdlen); cp += stdlen; *cp++ = '\0'; if (dstlen != 0) { (void) strncpy(cp, dstname, dstlen); *(cp + dstlen) = '\0'; } return 0; } static void gmtload(sp) struct state * const sp; { if (tzload(gmt, sp) != 0) (void) tzparse(gmt, sp, TRUE); } /* ahu: deleted definition of tzsetwall */ /* ahu: deleted definition of tzset */ /* ** The easy way to behave "as if no library function calls" localtime ** is to not call it--so we drop its guts into "localsub", which can be ** freely called. (And no, the PANS doesn't require the above behavior-- ** but it *is* desirable.) ** ** The unused offset argument is for the benefit of mktime variants. */ /*ARGSUSED*/ static void localsub(timep, offset, tmp) const time_t * const timep; const long offset; struct tm * const tmp; { register struct state * sp; register const struct ttinfo * ttisp; register int i; const time_t t = *timep; sp = lclptr; #ifdef ALL_STATE if (sp == NULL) { gmtsub(timep, offset, tmp); return; } #endif /* defined ALL_STATE */ if (sp->timecnt == 0 || t < sp->ats[0]) { i = 0; while (sp->ttis[i].tt_isdst) if (++i >= sp->typecnt) { i = 0; break; } } else { for (i = 1; i < sp->timecnt; ++i) if (t < sp->ats[i]) break; i = sp->types[i - 1]; } ttisp = &sp->ttis[i]; /* ** To get (wrong) behavior that's compatible with System V Release 2.0 ** you'd replace the statement below with ** t += ttisp->tt_gmtoff; ** timesub(&t, 0L, sp, tmp); */ timesub(&t, ttisp->tt_gmtoff, sp, tmp); tmp->tm_isdst = ttisp->tt_isdst; tzname[tmp->tm_isdst] = &sp->chars[ttisp->tt_abbrind]; #ifdef TM_ZONE tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind]; #endif /* defined TM_ZONE */ } /* ahu: deleted definition of localtime */ /* ahu: deleted definition of localtime_r */ /* ** gmtsub is to gmtime as localsub is to localtime. */ static void gmtsub(timep, offset, tmp) const time_t * const timep; const long offset; struct tm * const tmp; { if (!gmt_is_set) { gmt_is_set = TRUE; #ifdef ALL_STATE gmtptr = (struct state *) malloc(sizeof *gmtptr); if (gmtptr != NULL) #endif /* defined ALL_STATE */ gmtload(gmtptr); } timesub(timep, offset, gmtptr, tmp); #ifdef TM_ZONE /* ** Could get fancy here and deliver something such as ** "UTC+xxxx" or "UTC-xxxx" if offset is non-zero, ** but this is no time for a treasure hunt. */ if (offset != 0) tmp->TM_ZONE = wildabbr; else { #ifdef ALL_STATE if (gmtptr == NULL) tmp->TM_ZONE = gmt; else tmp->TM_ZONE = gmtptr->chars; #endif /* defined ALL_STATE */ #ifndef ALL_STATE tmp->TM_ZONE = gmtptr->chars; #endif /* State Farm */ } #endif /* defined TM_ZONE */ } /* ahu: deleted definition of gmtime */ /* ahu: deleted definition of gmtime_r */ /* ahu: deleted definition of offtime */ static void timesub(timep, offset, sp, tmp) const time_t * const timep; const long offset; register const struct state * const sp; register struct tm * const tmp; { register const struct lsinfo * lp; register long days; register long rem; register int y; register int yleap; register const int * ip; register long corr; register int hit; register int i; corr = 0; hit = 0; #ifdef ALL_STATE i = (sp == NULL) ? 0 : sp->leapcnt; #endif /* defined ALL_STATE */ #ifndef ALL_STATE i = sp->leapcnt; #endif /* State Farm */ while (--i >= 0) { lp = &sp->lsis[i]; if (*timep >= lp->ls_trans) { if (*timep == lp->ls_trans) { hit = ((i == 0 && lp->ls_corr > 0) || lp->ls_corr > sp->lsis[i - 1].ls_corr); if (hit) while (i > 0 && sp->lsis[i].ls_trans == sp->lsis[i - 1].ls_trans + 1 && sp->lsis[i].ls_corr == sp->lsis[i - 1].ls_corr + 1) { ++hit; --i; } } corr = lp->ls_corr; break; } } days = (int)*timep / SECSPERDAY; rem = (int)*timep % SECSPERDAY; #ifdef mc68k if (*timep == 0x80000000) { /* ** A 3B1 muffs the division on the most negative number. */ days = -24855; rem = -11648; } #endif /* defined mc68k */ rem += (offset - corr); while (rem < 0) { rem += SECSPERDAY; --days; } while (rem >= SECSPERDAY) { rem -= SECSPERDAY; ++days; } tmp->tm_hour = (int) (rem / SECSPERHOUR); rem = rem % SECSPERHOUR; tmp->tm_min = (int) (rem / SECSPERMIN); /* ** A positive leap second requires a special ** representation. This uses "... ??:59:60" et seq. */ tmp->tm_sec = (int) (rem % SECSPERMIN) + hit; tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYSPERWEEK); if (tmp->tm_wday < 0) tmp->tm_wday += DAYSPERWEEK; y = EPOCH_YEAR; #define LEAPS_THRU_END_OF(y) ((y) / 4 - (y) / 100 + (y) / 400) while (days < 0 || days >= (long) year_lengths[yleap = isleap(y)]) { register int newy; newy = y + days / DAYSPERNYEAR; if (days < 0) --newy; days -= (newy - y) * DAYSPERNYEAR + LEAPS_THRU_END_OF(newy - 1) - LEAPS_THRU_END_OF(y - 1); y = newy; } tmp->tm_year = y - TM_YEAR_BASE; tmp->tm_yday = (int) days; ip = mon_lengths[yleap]; for (tmp->tm_mon = 0; days >= (long) ip[tmp->tm_mon]; ++(tmp->tm_mon)) days = days - (long) ip[tmp->tm_mon]; tmp->tm_mday = (int) (days + 1); tmp->tm_isdst = 0; #ifdef TM_GMTOFF tmp->TM_GMTOFF = offset; #endif /* defined TM_GMTOFF */ } /* ahu: deleted definition of ctime */ /* ahu: deleted definition of ctime_r */ /* ** Adapted from code provided by Robert Elz, who writes: ** The "best" way to do mktime I think is based on an idea of Bob ** Kridle's (so its said...) from a long time ago. ** [kridle@xinet.com as of 1996-01-16.] ** It does a binary search of the time_t space. Since time_t's are ** just 32 bits, its a max of 32 iterations (even at 64 bits it ** would still be very reasonable). */ #ifndef WRONG #define WRONG (-1) #endif /* !defined WRONG */ /* ** Simplified normalize logic courtesy Paul Eggert (eggert@twinsun.com). */ static int increment_overflow(number, delta) int * number; int delta; { int number0; number0 = *number; *number += delta; return (*number < number0) != (delta < 0); } static int normalize_overflow(tensptr, unitsptr, base) int * const tensptr; int * const unitsptr; const int base; { register int tensdelta; tensdelta = (*unitsptr >= 0) ? (*unitsptr / base) : (-1 - (-1 - *unitsptr) / base); *unitsptr -= tensdelta * base; return increment_overflow(tensptr, tensdelta); } static int tmcomp(atmp, btmp) register const struct tm * const atmp; register const struct tm * const btmp; { register int result; if ((result = (atmp->tm_year - btmp->tm_year)) == 0 && (result = (atmp->tm_mon - btmp->tm_mon)) == 0 && (result = (atmp->tm_mday - btmp->tm_mday)) == 0 && (result = (atmp->tm_hour - btmp->tm_hour)) == 0 && (result = (atmp->tm_min - btmp->tm_min)) == 0) result = atmp->tm_sec - btmp->tm_sec; return result; } static time_t time2sub(tmp, funcp, offset, okayp, do_norm_secs) struct tm * const tmp; void (* const funcp) P((const time_t*, long, struct tm*)); const long offset; int * const okayp; const int do_norm_secs; { register const struct state * sp; register int dir; register int bits; register int i, j ; register int saved_seconds; time_t newt; time_t t; struct tm yourtm, mytm; *okayp = FALSE; yourtm = *tmp; if (do_norm_secs) { if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec, SECSPERMIN)) return WRONG; } if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR)) return WRONG; if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY)) return WRONG; if (normalize_overflow(&yourtm.tm_year, &yourtm.tm_mon, MONSPERYEAR)) return WRONG; /* ** Turn yourtm.tm_year into an actual year number for now. ** It is converted back to an offset from TM_YEAR_BASE later. */ if (increment_overflow(&yourtm.tm_year, TM_YEAR_BASE)) return WRONG; while (yourtm.tm_mday <= 0) { if (increment_overflow(&yourtm.tm_year, -1)) return WRONG; i = yourtm.tm_year + (1 < yourtm.tm_mon); yourtm.tm_mday += year_lengths[isleap(i)]; } while (yourtm.tm_mday > DAYSPERLYEAR) { i = yourtm.tm_year + (1 < yourtm.tm_mon); yourtm.tm_mday -= year_lengths[isleap(i)]; if (increment_overflow(&yourtm.tm_year, 1)) return WRONG; } for ( ; ; ) { i = mon_lengths[isleap(yourtm.tm_year)][yourtm.tm_mon]; if (yourtm.tm_mday <= i) break; yourtm.tm_mday -= i; if (++yourtm.tm_mon >= MONSPERYEAR) { yourtm.tm_mon = 0; if (increment_overflow(&yourtm.tm_year, 1)) return WRONG; } } if (increment_overflow(&yourtm.tm_year, -TM_YEAR_BASE)) return WRONG; if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN) saved_seconds = 0; else if (yourtm.tm_year + TM_YEAR_BASE < EPOCH_YEAR) { /* ** We can't set tm_sec to 0, because that might push the ** time below the minimum representable time. ** Set tm_sec to 59 instead. ** This assumes that the minimum representable time is ** not in the same minute that a leap second was deleted from, ** which is a safer assumption than using 58 would be. */ if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN)) return WRONG; saved_seconds = yourtm.tm_sec; yourtm.tm_sec = SECSPERMIN - 1; } else { saved_seconds = yourtm.tm_sec; yourtm.tm_sec = 0; } /* ** Divide the search space in half ** (this works whether time_t is signed or unsigned). */ bits = TYPE_BIT(time_t) - 1; /* ** If time_t is signed, then 0 is just above the median, ** assuming two's complement arithmetic. ** If time_t is unsigned, then (1 << bits) is just above the median. */ t = TYPE_SIGNED(time_t) ? 0 : (((time_t) 1) << bits); for ( ; ; ) { (*funcp)(&t, offset, &mytm); dir = tmcomp(&mytm, &yourtm); if (dir != 0) { if (bits-- < 0) return WRONG; if (bits < 0) --t; /* may be needed if new t is minimal */ else if (dir > 0) t -= ((time_t) 1) << bits; else t += ((time_t) 1) << bits; continue; } if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst) break; /* ** Right time, wrong type. ** Hunt for right time, right type. ** It's okay to guess wrong since the guess ** gets checked. */ /* ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's. */ sp = (const struct state *) (((void *) funcp == (void *) localsub) ? lclptr : gmtptr); #ifdef ALL_STATE if (sp == NULL) return WRONG; #endif /* defined ALL_STATE */ for (i = sp->typecnt - 1; i >= 0; --i) { if (sp->ttis[i].tt_isdst != yourtm.tm_isdst) continue; for (j = sp->typecnt - 1; j >= 0; --j) { if (sp->ttis[j].tt_isdst == yourtm.tm_isdst) continue; newt = t + sp->ttis[j].tt_gmtoff - sp->ttis[i].tt_gmtoff; (*funcp)(&newt, offset, &mytm); if (tmcomp(&mytm, &yourtm) != 0) continue; if (mytm.tm_isdst != yourtm.tm_isdst) continue; /* ** We have a match. */ t = newt; goto label; } } return WRONG; } label: newt = t + saved_seconds; if ((newt < t) != (saved_seconds < 0)) return WRONG; t = newt; (*funcp)(&t, offset, tmp); *okayp = TRUE; return t; } static time_t time2(tmp, funcp, offset, okayp) struct tm * const tmp; void (* const funcp) P((const time_t*, long, struct tm*)); const long offset; int * const okayp; { time_t t; /* ** First try without normalization of seconds ** (in case tm_sec contains a value associated with a leap second). ** If that fails, try with normalization of seconds. */ t = time2sub(tmp, funcp, offset, okayp, FALSE); return *okayp ? t : time2sub(tmp, funcp, offset, okayp, TRUE); } static time_t time1(tmp, funcp, offset) struct tm * const tmp; void (* const funcp) P((const time_t *, long, struct tm *)); const long offset; { register time_t t; register const struct state * sp; register int samei, otheri; register int sameind, otherind; register int i; register int nseen; int seen[TZ_MAX_TYPES]; int types[TZ_MAX_TYPES]; int okay; if (tmp->tm_isdst > 1) tmp->tm_isdst = 1; t = time2(tmp, funcp, offset, &okay); #ifdef PCTS /* ** PCTS code courtesy Grant Sullivan (grant@osf.org). */ if (okay) return t; if (tmp->tm_isdst < 0) tmp->tm_isdst = 0; /* reset to std and try again */ #endif /* defined PCTS */ #ifndef PCTS if (okay || tmp->tm_isdst < 0) return t; #endif /* !defined PCTS */ /* ** We're supposed to assume that somebody took a time of one type ** and did some math on it that yielded a "struct tm" that's bad. ** We try to divine the type they started from and adjust to the ** type they need. */ /* ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's. */ sp = (const struct state *) (((void *) funcp == (void *) localsub) ? lclptr : gmtptr); #ifdef ALL_STATE if (sp == NULL) return WRONG; #endif /* defined ALL_STATE */ for (i = 0; i < sp->typecnt; ++i) seen[i] = FALSE; nseen = 0; for (i = sp->timecnt - 1; i >= 0; --i) if (!seen[sp->types[i]]) { seen[sp->types[i]] = TRUE; types[nseen++] = sp->types[i]; } for (sameind = 0; sameind < nseen; ++sameind) { samei = types[sameind]; if (sp->ttis[samei].tt_isdst != tmp->tm_isdst) continue; for (otherind = 0; otherind < nseen; ++otherind) { otheri = types[otherind]; if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst) continue; tmp->tm_sec += sp->ttis[otheri].tt_gmtoff - sp->ttis[samei].tt_gmtoff; tmp->tm_isdst = !tmp->tm_isdst; t = time2(tmp, funcp, offset, &okay); if (okay) return t; tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff - sp->ttis[samei].tt_gmtoff; tmp->tm_isdst = !tmp->tm_isdst; } } return WRONG; } /* ahu: deleted definition of mktime */ #ifdef STD_INSPIRED /* ahu: deleted definition of timelocal */ /* rmills - timegm is replaced with _mkgmtime on VC 2005 and up */ /* - see timegm.h */ #if !defined(_MSC_VER) || (_MSC_VER < 1400) time_t timegm(tmp) struct tm * const tmp; { tmp->tm_isdst = 0; return time1(tmp, gmtsub, 0L); } #endif /* ahu: deleted definition of timeoff */ #endif /* defined STD_INSPIRED */ /* ahu: deleted definition of gtime */ /* ahu: deleted definition of leapcorr */ /* ahu: deleted definition of time2posix */ /* ahu: deleted definition of posix2time */ exiv2-0.23/src/pentaxmn_int.hpp0000644000175000017500000001276511732641407016333 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! @file pentaxmn_int.hpp @brief Pentax MakerNote implemented according to the specification http://www.gvsoft.homedns.org/exif/makernote-pentax-type3.html and based on ExifTool implementation and Pentax Makernote list by Phil Harvey
@version $Rev: 2681 $ @author Michal Cihar michal@cihar.com @date 27-Sep-07 */ #ifndef PENTAXMN_INT_HPP_ #define PENTAXMN_INT_HPP_ // ***************************************************************************** // included header files #include "tags.hpp" #include "tags_int.hpp" #include "types.hpp" // + standard includes #include #include #include #include // ***************************************************************************** // namespace extensions namespace Exiv2 { namespace Internal { // ***************************************************************************** // class definitions //! MakerNote for Pentaxfilm cameras class PentaxMakerNote { public: //! Return read-only list of built-in Pentaxfilm tags static const TagInfo* tagList(); //! Print Pentax version static std::ostream& printPentaxVersion(std::ostream& os, const Value& value, const ExifData*); //! Print Pentax resolution static std::ostream& printPentaxResolution(std::ostream& os, const Value& value, const ExifData*); //! Print Pentax date static std::ostream& printPentaxDate(std::ostream& os, const Value& value, const ExifData*); //! Print Pentax time static std::ostream& printPentaxTime(std::ostream& os, const Value& value, const ExifData*); //! Print Pentax exposure static std::ostream& printPentaxExposure(std::ostream& os, const Value& value, const ExifData*); //! Print Pentax F value static std::ostream& printPentaxFValue(std::ostream& os, const Value& value, const ExifData*); //! Print Pentax focal length static std::ostream& printPentaxFocalLength(std::ostream& os, const Value& value, const ExifData*); //! Print Pentax compensation static std::ostream& printPentaxCompensation(std::ostream& os, const Value& value, const ExifData*); //! Print Pentax temperature static std::ostream& printPentaxTemperature(std::ostream& os, const Value& value, const ExifData*); //! Print Pentax flash compensation static std::ostream& printPentaxFlashCompensation(std::ostream& os, const Value& value, const ExifData*); //! Print Pentax bracketing static std::ostream& printPentaxBracketing(std::ostream& os, const Value& value, const ExifData*); private: //! Tag information static const TagInfo tagInfo_[]; }; // class PentaxMakerNote /*! @brief Print function to translate Pentax "combi-values" to a description by looking up a reference table. */ template std::ostream& printCombiTag(std::ostream& os, const Value& value, const ExifData* metadata) { if ((value.count() != count && (value.count() < (count + ignoredcount) || value.count() > (count + ignoredcountmax))) || count > 4) { return printValue(os, value, metadata); } unsigned long l = 0; for (int c = 0; c < count; ++c) { if (value.toLong(c) < 0 || value.toLong(c) > 255) { return printValue(os, value, metadata); } l += (value.toLong(c) << ((count - c - 1) * 8)); } const TagDetails* td = find(array, l); if (td) { os << exvGettext(td->label_); } else { os << exvGettext("Unknown") << " (0x" << std::setw(2 * count) << std::setfill('0') << std::hex << l << std::dec << ")"; } return os; } //! Shortcut for the printCombiTag template which requires typing the array name only once. #define EXV_PRINT_COMBITAG(array, count, ignoredcount) printCombiTag //! Shortcut for the printCombiTag template which requires typing the array name only once. #define EXV_PRINT_COMBITAG_MULTI(array, count, ignoredcount, ignoredcountmax) printCombiTag }} // namespace Internal, Exiv2 #endif // #ifndef PENTAXMN_INT_HPP_ exiv2-0.23/src/minoltamn_int.hpp0000644000175000017500000002140611742031570016462 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! @file minoltamn_int.hpp @brief Minolta MakerNote implemented using the following references:
Minolta Makernote Format Specification by Dalibor Jelinek,
Minolta Makernote list by Phil Harvey
Minolta Makernote list from PHP JPEG Metadata Toolkit
Email communication with caulier dot gilles at gmail dot com
Some Minolta camera settings have been decoded by Xavier Raynaud from digiKam project and added by Gilles Caulier. @version $Rev: 2701 $ @author Andreas Huggel (ahu) ahuggel@gmx.net @author Gilles Caulier (cgilles) caulier dot gilles at gmail dot com @date 06-May-06, gc: submitted */ #ifndef MINOLTAMN_INT_HPP_ #define MINOLTAMN_INT_HPP_ // ***************************************************************************** // included header files #include "tags.hpp" #include "types.hpp" // + standard includes #include // ***************************************************************************** // namespace extensions namespace Exiv2 { namespace Internal { // ***************************************************************************** // class definitions //! MakerNote for Minolta cameras class MinoltaMakerNote { public: //! Return read-only list of built-in Minolta tags static const TagInfo* tagList(); //! Return read-only list of built-in Minolta Standard Camera Settings tags static const TagInfo* tagListCsStd(); //! Return read-only list of built-in Minolta 7D Camera Settings tags static const TagInfo* tagListCs7D(); //! Return read-only list of built-in Minolta 5D Camera Settings tags static const TagInfo* tagListCs5D(); //! Return read-only list of built-in Sony A100 Camera Settings tags static const TagInfo* tagListCsA100(); //! @name Print functions for Minolta %MakerNote tags //@{ //! Print Exposure Speed setting from standard Minolta Camera Settings makernote static std::ostream& printMinoltaExposureSpeedStd(std::ostream& os, const Value& value, const ExifData*); //! Print Exposure Time setting from standard Minolta Camera Settings makernote static std::ostream& printMinoltaExposureTimeStd(std::ostream& os, const Value& value, const ExifData*); //! Print F Number setting from standard Minolta Camera Settings makernote static std::ostream& printMinoltaFNumberStd(std::ostream& os, const Value& value, const ExifData*); //! Print Exposure Compensation setting from standard Minolta Camera Settings makernote static std::ostream& printMinoltaExposureCompensationStd(std::ostream& os, const Value& value, const ExifData*); //! Print Focal Length setting from standard Minolta Camera Settings makernote static std::ostream& printMinoltaFocalLengthStd(std::ostream& os, const Value& value, const ExifData*); //! Print Minolta Date from standard Minolta Camera Settings makernote static std::ostream& printMinoltaDateStd(std::ostream& os, const Value& value, const ExifData*); //! Print Minolta Time from standard Minolta Camera Settings makernote static std::ostream& printMinoltaTimeStd(std::ostream& os, const Value& value, const ExifData*); //! Print Flash Exposure Compensation setting from standard Minolta Camera Settings makernote static std::ostream& printMinoltaFlashExposureCompStd(std::ostream& os, const Value& value, const ExifData*); //! Print White Balance setting from standard Minolta Camera Settings makernote static std::ostream& printMinoltaWhiteBalanceStd(std::ostream& os, const Value& value, const ExifData*); //! Print Brightness setting from standard Minolta Camera Settings makernote static std::ostream& printMinoltaBrightnessStd(std::ostream& os, const Value& value, const ExifData*); //! Print Exposure Manual Bias setting from 5D Minolta Camera Settings makernote static std::ostream& printMinoltaExposureManualBias5D(std::ostream& os, const Value& value, const ExifData*); //! Print Exposure Compensation setting from 5D Minolta Camera Settings makernote static std::ostream& printMinoltaExposureCompensation5D(std::ostream& os, const Value& value, const ExifData*); //@} private: //! Tag information static const TagInfo tagInfo_[]; static const TagInfo tagInfoCsA100_[]; static const TagInfo tagInfoCs5D_[]; static const TagInfo tagInfoCs7D_[]; static const TagInfo tagInfoCsStd_[]; }; // class MinoltaMakerNote // -- Minolta and Sony MakerNote Common Values --------------------------------------- //! Print Minolta/Sony Lens id values to readable labels. std::ostream& printMinoltaSonyLensID(std::ostream&, const Value&, const ExifData*); //! Print Minolta/Sony Color Mode values to readable labels. std::ostream& printMinoltaSonyColorMode(std::ostream&, const Value&, const ExifData*); //! Print Minolta/Sony bool function values to readable labels. std::ostream& printMinoltaSonyBoolValue(std::ostream&, const Value&, const ExifData*); //! Print Minolta/Sony bool inverse function values to readable labels. std::ostream& printMinoltaSonyBoolInverseValue(std::ostream&, const Value&, const ExifData*); //! Print Minolta/Sony AF Area Mode values to readable labels. std::ostream& printMinoltaSonyAFAreaMode(std::ostream&, const Value&, const ExifData*); //! Print Minolta/Sony Local AF Area Point values to readable labels. std::ostream& printMinoltaSonyLocalAFAreaPoint(std::ostream&, const Value&, const ExifData*); //! Print Minolta/Sony dynamic range optimizer mode values to readable labels. std::ostream& printMinoltaSonyDynamicRangeOptimizerMode(std::ostream&, const Value&, const ExifData*); //! Print Minolta/Sony priority setup shutter release values to readable labels. std::ostream& printMinoltaSonyPrioritySetupShutterRelease(std::ostream&, const Value&, const ExifData*); //! Print Minolta/Sony Quality values to readable labels. std::ostream& printMinoltaSonyQualityCs(std::ostream&, const Value&, const ExifData*); //! Print Minolta/Sony Rotation values to readable labels. std::ostream& printMinoltaSonyRotation(std::ostream&, const Value&, const ExifData*); //! Print Minolta/Sony Scene Mode values to readable labels. std::ostream& printMinoltaSonySceneMode(std::ostream&, const Value&, const ExifData*); //! Print Minolta/Sony Image Quality values to readable labels. std::ostream& printMinoltaSonyImageQuality(std::ostream&, const Value&, const ExifData*); //! Print Minolta/Sony Teleconverter Model values to readable labels. std::ostream& printMinoltaSonyTeleconverterModel(std::ostream&, const Value&, const ExifData*); //! Print Minolta/Sony White Balance Std values to readable labels. std::ostream& printMinoltaSonyWhiteBalanceStd(std::ostream&, const Value&, const ExifData*); //! Print Minolta/Sony ZoneMatching values to readable labels. std::ostream& printMinoltaSonyZoneMatching(std::ostream&, const Value&, const ExifData*); //! Print Minolta/Sony FlashExposureComp values to readable labels. std::ostream& printMinoltaSonyFlashExposureComp(std::ostream&, const Value&, const ExifData*); // TODO: Added shared methods here. }} // namespace Internal, Exiv2 #endif // #ifndef MINOLTAMN_INT_HPP_ exiv2-0.23/src/TODO0000644000175000017500000000347311363266605013605 0ustar andreasandreasLibrary Features: + rename erase* methods that access a file to remove* + add ExifData::erase(tag) + Thumbnail support: set (re-calculate) + operator>> for Value, since we already have read()? + Use size_t where appropriate + Support TIFF type ids + Support for broken IFD makernotes (which have corrupted IFD offsets) + Support non-intrusive deletion of entries from an IFD. + Write an example using low level IFD classes to print summary Exif info + Extended JPEG support (actual resolution of the image) + Implement proper error handling + Complete support to create Exif data from scratch: + set thumbnail, write thumbnail tags + Make it possible to force write from metadata (just an optional arg to write?) + Make Image::doWriteMetadata do its work in a single pass + Revise Image and IptcData+ExifData API (aka turn it inside out) + Add PSD images support (and TIFF, NEF, CRW...) + Add support for XML metadata files Exiv2 functionality + Add offset to value for hexdump (requires metadata to have an offset) Bugs: + Handle all Todo's + Cleanup and fix implementation of JpegImage (must be able to read any APP0/1), should be able to insert exv into extracted thumbs (usually w/o APP0/1) + Review Image interface. Is it really necessary to have so many functions there? + Review the handling of type ids? What if we encounter type 27 in an IFD? + Rational and other output operators (see Josuttis, p653) + Through ExifData::iterator and Metadatum::operator= it is possible to have multiple copies of one metadatum in the metadata container + Checks and non-intrusive updates must be atomic, i.e., not change anything if the metadata is not compatible + Review: Exception safety + Review: Ifd1 only at Thumbnail, do we really need Thumbnail::update() ? + Should JpegImage differ between NO Jpeg comment and an empty Jpeg comment?? exiv2-0.23/src/makernote.cpp0000644000175000017500000011656211741325444015607 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /* File: makernote.cpp Version: $Rev: 2698 $ Author(s): Andreas Huggel (ahu) History: 11-Apr-06, ahu: created */ // ***************************************************************************** #include "rcsid_int.hpp" EXIV2_RCSID("@(#) $Id: makernote.cpp 2698 2012-04-11 16:02:44Z ahuggel $") // ***************************************************************************** // included header files #ifdef _MSC_VER # include "exv_msvc.h" #else # include "exv_conf.h" #endif #include "makernote_int.hpp" #include "tiffcomposite_int.hpp" #include "tiffvisitor_int.hpp" #include "tiffimage.hpp" #include "tiffimage_int.hpp" // + standard includes #include #include // ***************************************************************************** namespace { // Todo: Can be generalized further - get any tag as a string/long/... //! Get the model name from tag Exif.Image.Model std::string getExifModel(Exiv2::Internal::TiffComponent* const pRoot); //! Nikon en/decryption function void ncrypt(Exiv2::byte* pData, uint32_t size, uint32_t count, uint32_t serial); } // ***************************************************************************** // class member definitions namespace Exiv2 { namespace Internal { const TiffMnRegistry TiffMnCreator::registry_[] = { { "Canon", canonId, newIfdMn, newIfdMn2 }, { "FOVEON", sigmaId, newSigmaMn, newSigmaMn2 }, { "FUJI", fujiId, newFujiMn, newFujiMn2 }, { "KONICA MINOLTA", minoltaId, newIfdMn, newIfdMn2 }, { "Minolta", minoltaId, newIfdMn, newIfdMn2 }, { "NIKON", ifdIdNotSet, newNikonMn, 0 }, // mnGroup_ is not used { "OLYMPUS", ifdIdNotSet, newOlympusMn, 0 }, // mnGroup_ is not used { "Panasonic", panasonicId, newPanasonicMn, newPanasonicMn2 }, { "PENTAX", ifdIdNotSet, newPentaxMn, 0 }, // mnGroup_ is not used { "SAMSUNG", samsung2Id, newSamsungMn, newSamsungMn2 }, { "SIGMA", sigmaId, newSigmaMn, newSigmaMn2 }, { "SONY", ifdIdNotSet, newSonyMn, 0 }, // mnGroup_ is not used // Entries below are only used for lookup by group { "-", nikon1Id, 0, newIfdMn2 }, { "-", nikon2Id, 0, newNikon2Mn2 }, { "-", nikon3Id, 0, newNikon3Mn2 }, { "-", sony1Id, 0, newSony1Mn2 }, { "-", sony2Id, 0, newSony2Mn2 }, { "-", olympusId, 0, newOlympusMn2 }, { "-", olympus2Id, 0, newOlympus2Mn2 }, { "-", pentaxId, 0, newPentaxMn2 }, { "-", pentaxDngId, 0, newPentaxDngMn2 } }; bool TiffMnRegistry::operator==(const std::string& key) const { std::string make(make_); if (key.size() > 0 && key[0] == '-') return false; return make == key.substr(0, make.length()); } bool TiffMnRegistry::operator==(IfdId key) const { return mnGroup_ == key; } TiffComponent* TiffMnCreator::create(uint16_t tag, IfdId group, const std::string& make, const byte* pData, uint32_t size, ByteOrder byteOrder) { TiffComponent* tc = 0; const TiffMnRegistry* tmr = find(registry_, make); if (tmr) { assert(tmr->newMnFct_); tc = tmr->newMnFct_(tag, group, tmr->mnGroup_, pData, size, byteOrder); } return tc; } // TiffMnCreator::create TiffComponent* TiffMnCreator::create(uint16_t tag, IfdId group, IfdId mnGroup) { TiffComponent* tc = 0; const TiffMnRegistry* tmr = find(registry_, mnGroup); if (tmr) { if (tmr->newMnFct2_ == 0) { std::cout << "mnGroup = " << mnGroup << "\n"; } assert(tmr->newMnFct2_); tc = tmr->newMnFct2_(tag, group, mnGroup); } return tc; } // TiffMnCreator::create MnHeader::~MnHeader() { } void MnHeader::setByteOrder(ByteOrder /*byteOrder*/) { } uint32_t MnHeader::ifdOffset() const { return 0; } ByteOrder MnHeader::byteOrder() const { return invalidByteOrder; } uint32_t MnHeader::baseOffset(uint32_t /*mnOffset*/) const { return 0; } const byte OlympusMnHeader::signature_[] = { 'O', 'L', 'Y', 'M', 'P', 0x00, 0x01, 0x00 }; uint32_t OlympusMnHeader::sizeOfSignature() { return sizeof(signature_); } OlympusMnHeader::OlympusMnHeader() { read(signature_, sizeOfSignature(), invalidByteOrder); } OlympusMnHeader::~OlympusMnHeader() { } uint32_t OlympusMnHeader::size() const { return header_.size_; } uint32_t OlympusMnHeader::ifdOffset() const { return sizeOfSignature(); } bool OlympusMnHeader::read(const byte* pData, uint32_t size, ByteOrder /*byteOrder*/) { if (!pData || size < sizeOfSignature()) return false; header_.alloc(sizeOfSignature()); std::memcpy(header_.pData_, pData, header_.size_); if ( static_cast(header_.size_) < sizeOfSignature() || 0 != memcmp(header_.pData_, signature_, 6)) { return false; } return true; } // OlympusMnHeader::read uint32_t OlympusMnHeader::write(IoWrapper& ioWrapper, ByteOrder /*byteOrder*/) const { ioWrapper.write(signature_, sizeOfSignature()); return sizeOfSignature(); } // OlympusMnHeader::write const byte Olympus2MnHeader::signature_[] = { 'O', 'L', 'Y', 'M', 'P', 'U', 'S', 0x00, 'I', 'I', 0x03, 0x00 }; uint32_t Olympus2MnHeader::sizeOfSignature() { return sizeof(signature_); } Olympus2MnHeader::Olympus2MnHeader() { read(signature_, sizeOfSignature(), invalidByteOrder); } Olympus2MnHeader::~Olympus2MnHeader() { } uint32_t Olympus2MnHeader::size() const { return header_.size_; } uint32_t Olympus2MnHeader::ifdOffset() const { return sizeOfSignature(); } uint32_t Olympus2MnHeader::baseOffset(uint32_t mnOffset) const { return mnOffset; } bool Olympus2MnHeader::read(const byte* pData, uint32_t size, ByteOrder /*byteOrder*/) { if (!pData || size < sizeOfSignature()) return false; header_.alloc(sizeOfSignature()); std::memcpy(header_.pData_, pData, header_.size_); if ( static_cast(header_.size_) < sizeOfSignature() || 0 != memcmp(header_.pData_, signature_, 10)) { return false; } return true; } // Olympus2MnHeader::read uint32_t Olympus2MnHeader::write(IoWrapper& ioWrapper, ByteOrder /*byteOrder*/) const { ioWrapper.write(signature_, sizeOfSignature()); return sizeOfSignature(); } // Olympus2MnHeader::write const byte FujiMnHeader::signature_[] = { 'F', 'U', 'J', 'I', 'F', 'I', 'L', 'M', 0x0c, 0x00, 0x00, 0x00 }; const ByteOrder FujiMnHeader::byteOrder_ = littleEndian; uint32_t FujiMnHeader::sizeOfSignature() { return sizeof(signature_); } FujiMnHeader::FujiMnHeader() { read(signature_, sizeOfSignature(), byteOrder_); } FujiMnHeader::~FujiMnHeader() { } uint32_t FujiMnHeader::size() const { return header_.size_; } uint32_t FujiMnHeader::ifdOffset() const { return start_; } ByteOrder FujiMnHeader::byteOrder() const { return byteOrder_; } uint32_t FujiMnHeader::baseOffset(uint32_t mnOffset) const { return mnOffset; } bool FujiMnHeader::read(const byte* pData, uint32_t size, ByteOrder /*byteOrder*/) { if (!pData || size < sizeOfSignature()) return false; header_.alloc(sizeOfSignature()); std::memcpy(header_.pData_, pData, header_.size_); // Read offset to the IFD relative to the start of the makernote // from the header. Note that we ignore the byteOrder argument start_ = getULong(header_.pData_ + 8, byteOrder_); if ( static_cast(header_.size_) < sizeOfSignature() || 0 != memcmp(header_.pData_, signature_, 8)) { return false; } return true; } // FujiMnHeader::read uint32_t FujiMnHeader::write(IoWrapper& ioWrapper, ByteOrder /*byteOrder*/) const { ioWrapper.write(signature_, sizeOfSignature()); return sizeOfSignature(); } // FujiMnHeader::write const byte Nikon2MnHeader::signature_[] = { 'N', 'i', 'k', 'o', 'n', '\0', 0x01, 0x00 }; uint32_t Nikon2MnHeader::sizeOfSignature() { return sizeof(signature_); } Nikon2MnHeader::Nikon2MnHeader() { read(signature_, sizeOfSignature(), invalidByteOrder); } Nikon2MnHeader::~Nikon2MnHeader() { } uint32_t Nikon2MnHeader::size() const { return sizeOfSignature(); } uint32_t Nikon2MnHeader::ifdOffset() const { return start_; } bool Nikon2MnHeader::read(const byte* pData, uint32_t size, ByteOrder /*byteOrder*/) { if (!pData || size < sizeOfSignature()) return false; if (0 != memcmp(pData, signature_, 6)) return false; buf_.alloc(sizeOfSignature()); std::memcpy(buf_.pData_, pData, buf_.size_); start_ = sizeOfSignature(); return true; } // Nikon2MnHeader::read uint32_t Nikon2MnHeader::write(IoWrapper& ioWrapper, ByteOrder /*byteOrder*/) const { ioWrapper.write(signature_, sizeOfSignature()); return sizeOfSignature(); } // Nikon2MnHeader::write const byte Nikon3MnHeader::signature_[] = { 'N', 'i', 'k', 'o', 'n', '\0', 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; uint32_t Nikon3MnHeader::sizeOfSignature() { return sizeof(signature_); } Nikon3MnHeader::Nikon3MnHeader() { buf_.alloc(sizeOfSignature()); std::memcpy(buf_.pData_, signature_, buf_.size_); byteOrder_ = invalidByteOrder; start_ = sizeOfSignature(); } Nikon3MnHeader::~Nikon3MnHeader() { } uint32_t Nikon3MnHeader::size() const { return sizeOfSignature(); } uint32_t Nikon3MnHeader::ifdOffset() const { return start_; } ByteOrder Nikon3MnHeader::byteOrder() const { return byteOrder_; } uint32_t Nikon3MnHeader::baseOffset(uint32_t mnOffset) const { return mnOffset + 10; } bool Nikon3MnHeader::read(const byte* pData, uint32_t size, ByteOrder /*byteOrder*/) { if (!pData || size < sizeOfSignature()) return false; if (0 != memcmp(pData, signature_, 6)) return false; buf_.alloc(sizeOfSignature()); std::memcpy(buf_.pData_, pData, buf_.size_); TiffHeader th; if (!th.read(buf_.pData_ + 10, 8)) return false; byteOrder_ = th.byteOrder(); start_ = 10 + th.offset(); return true; } // Nikon3MnHeader::read uint32_t Nikon3MnHeader::write(IoWrapper& ioWrapper, ByteOrder byteOrder) const { assert(buf_.size_ >= 10); ioWrapper.write(buf_.pData_, 10); // Todo: This removes any gap between the header and // makernote IFD. The gap should be copied too. TiffHeader th(byteOrder); DataBuf buf = th.write(); ioWrapper.write(buf.pData_, buf.size_); return 10 + buf.size_; } // Nikon3MnHeader::write void Nikon3MnHeader::setByteOrder(ByteOrder byteOrder) { byteOrder_ = byteOrder; } const byte PanasonicMnHeader::signature_[] = { 'P', 'a', 'n', 'a', 's', 'o', 'n', 'i', 'c', 0x00, 0x00, 0x00 }; uint32_t PanasonicMnHeader::sizeOfSignature() { return sizeof(signature_); } PanasonicMnHeader::PanasonicMnHeader() { read(signature_, sizeOfSignature(), invalidByteOrder); } PanasonicMnHeader::~PanasonicMnHeader() { } uint32_t PanasonicMnHeader::size() const { return sizeOfSignature(); } uint32_t PanasonicMnHeader::ifdOffset() const { return start_; } bool PanasonicMnHeader::read(const byte* pData, uint32_t size, ByteOrder /*byteOrder*/) { if (!pData || size < sizeOfSignature()) return false; if (0 != memcmp(pData, signature_, 9)) return false; buf_.alloc(sizeOfSignature()); std::memcpy(buf_.pData_, pData, buf_.size_); start_ = sizeOfSignature(); return true; } // PanasonicMnHeader::read uint32_t PanasonicMnHeader::write(IoWrapper& ioWrapper, ByteOrder /*byteOrder*/) const { ioWrapper.write(signature_, sizeOfSignature()); return sizeOfSignature(); } // PanasonicMnHeader::write const byte PentaxDngMnHeader::signature_[] = { 'P', 'E', 'N', 'T', 'A', 'X', ' ', 0x00, 'M', 'M' }; uint32_t PentaxDngMnHeader::sizeOfSignature() { return sizeof(signature_); } PentaxDngMnHeader::PentaxDngMnHeader() { read(signature_, sizeOfSignature(), invalidByteOrder); } PentaxDngMnHeader::~PentaxDngMnHeader() { } uint32_t PentaxDngMnHeader::size() const { return header_.size_; } uint32_t PentaxDngMnHeader::baseOffset(uint32_t mnOffset) const { return mnOffset; } uint32_t PentaxDngMnHeader::ifdOffset() const { return sizeOfSignature(); } bool PentaxDngMnHeader::read(const byte* pData, uint32_t size, ByteOrder /*byteOrder*/) { if (!pData || size < sizeOfSignature()) return false; header_.alloc(sizeOfSignature()); std::memcpy(header_.pData_, pData, header_.size_); if ( static_cast(header_.size_) < sizeOfSignature() || 0 != memcmp(header_.pData_, signature_, 7)) { return false; } return true; } // PentaxDngMnHeader::read uint32_t PentaxDngMnHeader::write(IoWrapper& ioWrapper, ByteOrder /*byteOrder*/) const { ioWrapper.write(signature_, sizeOfSignature()); return sizeOfSignature(); } // PentaxDngMnHeader::write const byte PentaxMnHeader::signature_[] = { 'A', 'O', 'C', 0x00, 'M', 'M' }; uint32_t PentaxMnHeader::sizeOfSignature() { return sizeof(signature_); } PentaxMnHeader::PentaxMnHeader() { read(signature_, sizeOfSignature(), invalidByteOrder); } PentaxMnHeader::~PentaxMnHeader() { } uint32_t PentaxMnHeader::size() const { return header_.size_; } uint32_t PentaxMnHeader::ifdOffset() const { return sizeOfSignature(); } bool PentaxMnHeader::read(const byte* pData, uint32_t size, ByteOrder /*byteOrder*/) { if (!pData || size < sizeOfSignature()) return false; header_.alloc(sizeOfSignature()); std::memcpy(header_.pData_, pData, header_.size_); if ( static_cast(header_.size_) < sizeOfSignature() || 0 != memcmp(header_.pData_, signature_, 3)) { return false; } return true; } // PentaxMnHeader::read uint32_t PentaxMnHeader::write(IoWrapper& ioWrapper, ByteOrder /*byteOrder*/) const { ioWrapper.write(signature_, sizeOfSignature()); return sizeOfSignature(); } // PentaxMnHeader::write SamsungMnHeader::SamsungMnHeader() { read(0, 0, invalidByteOrder); } uint32_t SamsungMnHeader::size() const { return 0; } uint32_t SamsungMnHeader::baseOffset(uint32_t mnOffset) const { return mnOffset; } bool SamsungMnHeader::read(const byte* /*pData*/, uint32_t /*size*/, ByteOrder /*byteOrder*/) { return true; } // SamsungMnHeader::read uint32_t SamsungMnHeader::write(IoWrapper& /*ioWrapper*/, ByteOrder /*byteOrder*/) const { return 0; } // SamsungMnHeader::write const byte SigmaMnHeader::signature1_[] = { 'S', 'I', 'G', 'M', 'A', '\0', '\0', '\0', 0x01, 0x00 }; const byte SigmaMnHeader::signature2_[] = { 'F', 'O', 'V', 'E', 'O', 'N', '\0', '\0', 0x01, 0x00 }; uint32_t SigmaMnHeader::sizeOfSignature() { assert(sizeof(signature1_) == sizeof(signature2_)); return sizeof(signature1_); } SigmaMnHeader::SigmaMnHeader() { read(signature1_, sizeOfSignature(), invalidByteOrder); } SigmaMnHeader::~SigmaMnHeader() { } uint32_t SigmaMnHeader::size() const { return sizeOfSignature(); } uint32_t SigmaMnHeader::ifdOffset() const { return start_; } bool SigmaMnHeader::read(const byte* pData, uint32_t size, ByteOrder /*byteOrder*/) { if (!pData || size < sizeOfSignature()) return false; if ( 0 != memcmp(pData, signature1_, 8) && 0 != memcmp(pData, signature2_, 8)) return false; buf_.alloc(sizeOfSignature()); std::memcpy(buf_.pData_, pData, buf_.size_); start_ = sizeOfSignature(); return true; } // SigmaMnHeader::read uint32_t SigmaMnHeader::write(IoWrapper& ioWrapper, ByteOrder /*byteOrder*/) const { ioWrapper.write(signature1_, sizeOfSignature()); return sizeOfSignature(); } // SigmaMnHeader::write const byte SonyMnHeader::signature_[] = { 'S', 'O', 'N', 'Y', ' ', 'D', 'S', 'C', ' ', '\0', '\0', '\0' }; uint32_t SonyMnHeader::sizeOfSignature() { return sizeof(signature_); } SonyMnHeader::SonyMnHeader() { read(signature_, sizeOfSignature(), invalidByteOrder); } SonyMnHeader::~SonyMnHeader() { } uint32_t SonyMnHeader::size() const { return sizeOfSignature(); } uint32_t SonyMnHeader::ifdOffset() const { return start_; } bool SonyMnHeader::read(const byte* pData, uint32_t size, ByteOrder /*byteOrder*/) { if (!pData || size < sizeOfSignature()) return false; if (0 != memcmp(pData, signature_, sizeOfSignature())) return false; buf_.alloc(sizeOfSignature()); std::memcpy(buf_.pData_, pData, buf_.size_); start_ = sizeOfSignature(); return true; } // SonyMnHeader::read uint32_t SonyMnHeader::write(IoWrapper& ioWrapper, ByteOrder /*byteOrder*/) const { ioWrapper.write(signature_, sizeOfSignature()); return sizeOfSignature(); } // SonyMnHeader::write // ************************************************************************* // free functions TiffComponent* newIfdMn(uint16_t tag, IfdId group, IfdId mnGroup, const byte* /*pData*/, uint32_t size, ByteOrder /*byteOrder*/) { // Require at least an IFD with 1 entry, but not necessarily a next pointer if (size < 14) return 0; return newIfdMn2(tag, group, mnGroup); } TiffComponent* newIfdMn2(uint16_t tag, IfdId group, IfdId mnGroup) { return new TiffIfdMakernote(tag, group, mnGroup, 0); } TiffComponent* newOlympusMn(uint16_t tag, IfdId group, IfdId /*mnGroup*/, const byte* pData, uint32_t size, ByteOrder /*byteOrder*/) { if (size < 10 || std::string(reinterpret_cast(pData), 10) != std::string("OLYMPUS\0II", 10)) { // Require at least the header and an IFD with 1 entry if (size < OlympusMnHeader::sizeOfSignature() + 18) return 0; return newOlympusMn2(tag, group, olympusId); } // Require at least the header and an IFD with 1 entry if (size < Olympus2MnHeader::sizeOfSignature() + 18) return 0; return newOlympus2Mn2(tag, group, olympus2Id); } TiffComponent* newOlympusMn2(uint16_t tag, IfdId group, IfdId mnGroup) { return new TiffIfdMakernote(tag, group, mnGroup, new OlympusMnHeader); } TiffComponent* newOlympus2Mn2(uint16_t tag, IfdId group, IfdId mnGroup) { return new TiffIfdMakernote(tag, group, mnGroup, new Olympus2MnHeader); } TiffComponent* newFujiMn(uint16_t tag, IfdId group, IfdId mnGroup, const byte* /*pData*/, uint32_t size, ByteOrder /*byteOrder*/) { // Require at least the header and an IFD with 1 entry if (size < FujiMnHeader::sizeOfSignature() + 18) return 0; return newFujiMn2(tag, group, mnGroup); } TiffComponent* newFujiMn2(uint16_t tag, IfdId group, IfdId mnGroup) { return new TiffIfdMakernote(tag, group, mnGroup, new FujiMnHeader); } TiffComponent* newNikonMn(uint16_t tag, IfdId group, IfdId /*mnGroup*/, const byte* pData, uint32_t size, ByteOrder /*byteOrder*/) { // If there is no "Nikon" string it must be Nikon1 format if (size < 6 || std::string(reinterpret_cast(pData), 6) != std::string("Nikon\0", 6)) { // Require at least an IFD with 1 entry if (size < 18) return 0; return newIfdMn2(tag, group, nikon1Id); } // If the "Nikon" string is not followed by a TIFF header, we assume // Nikon2 format TiffHeader tiffHeader; if ( size < 18 || !tiffHeader.read(pData + 10, size - 10) || tiffHeader.tag() != 0x002a) { // Require at least the header and an IFD with 1 entry if (size < Nikon2MnHeader::sizeOfSignature() + 18) return 0; return newNikon2Mn2(tag, group, nikon2Id); } // Else we have a Nikon3 makernote // Require at least the header and an IFD with 1 entry if (size < Nikon3MnHeader::sizeOfSignature() + 18) return 0; return newNikon3Mn2(tag, group, nikon3Id); } TiffComponent* newNikon2Mn2(uint16_t tag, IfdId group, IfdId mnGroup) { return new TiffIfdMakernote(tag, group, mnGroup, new Nikon2MnHeader); } TiffComponent* newNikon3Mn2(uint16_t tag, IfdId group, IfdId mnGroup) { return new TiffIfdMakernote(tag, group, mnGroup, new Nikon3MnHeader); } TiffComponent* newPanasonicMn(uint16_t tag, IfdId group, IfdId mnGroup, const byte* /*pData*/, uint32_t size, ByteOrder /*byteOrder*/) { // Require at least the header and an IFD with 1 entry, but without a next pointer if (size < PanasonicMnHeader::sizeOfSignature() + 14) return 0; return newPanasonicMn2(tag, group, mnGroup); } TiffComponent* newPanasonicMn2(uint16_t tag, IfdId group, IfdId mnGroup) { return new TiffIfdMakernote(tag, group, mnGroup, new PanasonicMnHeader, false); } TiffComponent* newPentaxMn(uint16_t tag, IfdId group, IfdId /*mnGroup*/, const byte* pData, uint32_t size, ByteOrder /*byteOrder*/) { if ( size > 8 && std::string(reinterpret_cast(pData), 8) == std::string("PENTAX \0", 8)) { // Require at least the header and an IFD with 1 entry if (size < PentaxDngMnHeader::sizeOfSignature() + 18) return 0; return newPentaxDngMn2(tag, group, pentaxDngId); } else if ( size > 4 && std::string(reinterpret_cast(pData), 4) == std::string("AOC\0", 4)) { // Require at least the header and an IFD with 1 entry if (size < PentaxMnHeader::sizeOfSignature() + 18) return 0; return newPentaxMn2(tag, group, pentaxId); } else return 0; } TiffComponent* newPentaxMn2(uint16_t tag, IfdId group, IfdId mnGroup) { return new TiffIfdMakernote(tag, group, mnGroup, new PentaxMnHeader); } TiffComponent* newPentaxDngMn2(uint16_t tag, IfdId group, IfdId mnGroup) { return new TiffIfdMakernote(tag, group, mnGroup, new PentaxDngMnHeader); } TiffComponent* newSamsungMn(uint16_t tag, IfdId group, IfdId mnGroup, const byte* /*pData*/, uint32_t size, ByteOrder /*byteOrder*/) { // Require at least an IFD with 1 entry if (size < 18) return 0; return newSamsungMn2(tag, group, mnGroup); } TiffComponent* newSamsungMn2(uint16_t tag, IfdId group, IfdId mnGroup) { return new TiffIfdMakernote(tag, group, mnGroup, new SamsungMnHeader); } TiffComponent* newSigmaMn(uint16_t tag, IfdId group, IfdId mnGroup, const byte* /*pData*/, uint32_t size, ByteOrder /*byteOrder*/) { // Require at least the header and an IFD with 1 entry if (size < SigmaMnHeader::sizeOfSignature() + 18) return 0; return newSigmaMn2(tag, group, mnGroup); } TiffComponent* newSigmaMn2(uint16_t tag, IfdId group, IfdId mnGroup) { return new TiffIfdMakernote(tag, group, mnGroup, new SigmaMnHeader); } TiffComponent* newSonyMn(uint16_t tag, IfdId group, IfdId /*mnGroup*/, const byte* pData, uint32_t size, ByteOrder /*byteOrder*/) { // If there is no "SONY DSC " string we assume it's a simple IFD Makernote if (size < 12 || std::string(reinterpret_cast(pData), 12) != std::string("SONY DSC \0\0\0", 12)) { // Require at least an IFD with 1 entry if (size < 18) return 0; return newSony2Mn2(tag, group, sony2Id); } // Require at least the header and an IFD with 1 entry, but without a next pointer if (size < SonyMnHeader::sizeOfSignature() + 14) return 0; return newSony1Mn2(tag, group, sony1Id); } TiffComponent* newSony1Mn2(uint16_t tag, IfdId group, IfdId mnGroup) { return new TiffIfdMakernote(tag, group, mnGroup, new SonyMnHeader, false); } TiffComponent* newSony2Mn2(uint16_t tag, IfdId group, IfdId mnGroup) { return new TiffIfdMakernote(tag, group, mnGroup, 0, true); } //! Structure for an index into the array set of complex binary arrays. struct NikonArrayIdx { //! Key for comparisons struct Key { //! Constructor Key(uint16_t tag, const char* ver, uint32_t size) : tag_(tag), ver_(ver), size_(size) {} uint16_t tag_; //!< Tag number const char* ver_; //!< Version string uint32_t size_; //!< Size of the data (not the version string) }; //! Comparison operator for a key bool operator==(const Key& key) const { return key.tag_ == tag_ && 0 == strncmp(key.ver_, ver_, strlen(ver_)) && (size_ == 0 || key.size_ == size_); } uint16_t tag_; //!< Tag number of the binary array const char* ver_; //!< Version string uint32_t size_; //!< Size of the data int idx_; //!< Index into the array set uint32_t start_; //!< Start of the encrypted data }; #define NA ((uint32_t)-1) //! Nikon binary array version lookup table extern const NikonArrayIdx nikonArrayIdx[] = { // NikonSi { 0x0091, "0208", 0, 0, 4 }, // D80 { 0x0091, "0209", 0, 1, 4 }, // D40 { 0x0091, "0210", 5291, 2, 4 }, // D300 { 0x0091, "0210", 5303, 3, 4 }, // D300, firmware version 1.10 { 0x0091, "02", 0, 4, 4 }, // Other v2.* (encrypted) { 0x0091, "01", 0, 5, NA }, // Other v1.* (not encrypted) // NikonCb { 0x0097, "0100", 0, 0, NA }, { 0x0097, "0102", 0, 1, NA }, { 0x0097, "0103", 0, 4, NA }, { 0x0097, "0204", 0, 3, 284 }, { 0x0097, "0205", 0, 2, 4 }, { 0x0097, "0206", 0, 3, 284 }, { 0x0097, "0207", 0, 3, 284 }, { 0x0097, "0208", 0, 3, 284 }, { 0x0097, "0209", 0, 5, 284 }, { 0x0097, "02", 0, 3, 284 }, // NikonLd { 0x0098, "0100", 0, 0, NA }, { 0x0098, "0101", 0, 1, NA }, { 0x0098, "0201", 0, 1, 4 }, { 0x0098, "0202", 0, 1, 4 }, { 0x0098, "0203", 0, 1, 4 }, { 0x0098, "0204", 0, 2, 4 }, // NikonFl { 0x00a8, "0100", 0, 0, NA }, { 0x00a8, "0101", 0, 0, NA }, { 0x00a8, "0102", 0, 1, NA }, { 0x00a8, "0103", 0, 2, NA }, }; int nikonSelector(uint16_t tag, const byte* pData, uint32_t size, TiffComponent* const /*pRoot*/) { if (size < 4) return -1; const NikonArrayIdx* aix = find(nikonArrayIdx, NikonArrayIdx::Key(tag, reinterpret_cast(pData), size)); return aix == 0 ? -1 : aix->idx_; } DataBuf nikonCrypt(uint16_t tag, const byte* pData, uint32_t size, TiffComponent* const pRoot) { DataBuf buf; if (size < 4) return buf; const NikonArrayIdx* nci = find(nikonArrayIdx, NikonArrayIdx::Key(tag, reinterpret_cast(pData), size)); if (nci == 0 || nci->start_ == NA || size <= nci->start_) return buf; // Find Exif.Nikon3.ShutterCount TiffFinder finder(0x00a7, nikon3Id); pRoot->accept(finder); TiffEntryBase* te = dynamic_cast(finder.result()); if (!te || !te->pValue() || te->pValue()->count() == 0) return buf; uint32_t count = static_cast(te->pValue()->toLong()); // Find Exif.Nikon3.SerialNumber finder.init(0x001d, nikon3Id); pRoot->accept(finder); te = dynamic_cast(finder.result()); if (!te || !te->pValue() || te->pValue()->count() == 0) return buf; bool ok(false); uint32_t serial = stringTo(te->pValue()->toString(), ok); if (!ok) { std::string model = getExifModel(pRoot); if (model.empty()) return buf; if (model.find("D50") != std::string::npos) { serial = 0x22; } else { serial = 0x60; } } buf.alloc(size); memcpy(buf.pData_, pData, buf.size_); ncrypt(buf.pData_ + nci->start_, buf.size_ - nci->start_, count, serial); return buf; } int sonyCsSelector(uint16_t /*tag*/, const byte* /*pData*/, uint32_t /*size*/, TiffComponent* const pRoot) { std::string model = getExifModel(pRoot); if (model.empty()) return -1; int idx = 0; if ( model.find("DSLR-A330") != std::string::npos || model.find("DSLR-A380") != std::string::npos) { idx = 1; } return idx; } }} // namespace Internal, Exiv2 // ***************************************************************************** // local definitions namespace { std::string getExifModel(Exiv2::Internal::TiffComponent* const pRoot) { Exiv2::Internal::TiffFinder finder(0x0110, Exiv2::Internal::ifd0Id); // Exif.Image.Model pRoot->accept(finder); Exiv2::Internal::TiffEntryBase* te = dynamic_cast(finder.result()); if (!te || !te->pValue() || te->pValue()->count() == 0) return std::string(); return te->pValue()->toString(); } void ncrypt(Exiv2::byte* pData, uint32_t size, uint32_t count, uint32_t serial) { static const Exiv2::byte xlat[2][256] = { { 0xc1,0xbf,0x6d,0x0d,0x59,0xc5,0x13,0x9d,0x83,0x61,0x6b,0x4f,0xc7,0x7f,0x3d,0x3d, 0x53,0x59,0xe3,0xc7,0xe9,0x2f,0x95,0xa7,0x95,0x1f,0xdf,0x7f,0x2b,0x29,0xc7,0x0d, 0xdf,0x07,0xef,0x71,0x89,0x3d,0x13,0x3d,0x3b,0x13,0xfb,0x0d,0x89,0xc1,0x65,0x1f, 0xb3,0x0d,0x6b,0x29,0xe3,0xfb,0xef,0xa3,0x6b,0x47,0x7f,0x95,0x35,0xa7,0x47,0x4f, 0xc7,0xf1,0x59,0x95,0x35,0x11,0x29,0x61,0xf1,0x3d,0xb3,0x2b,0x0d,0x43,0x89,0xc1, 0x9d,0x9d,0x89,0x65,0xf1,0xe9,0xdf,0xbf,0x3d,0x7f,0x53,0x97,0xe5,0xe9,0x95,0x17, 0x1d,0x3d,0x8b,0xfb,0xc7,0xe3,0x67,0xa7,0x07,0xf1,0x71,0xa7,0x53,0xb5,0x29,0x89, 0xe5,0x2b,0xa7,0x17,0x29,0xe9,0x4f,0xc5,0x65,0x6d,0x6b,0xef,0x0d,0x89,0x49,0x2f, 0xb3,0x43,0x53,0x65,0x1d,0x49,0xa3,0x13,0x89,0x59,0xef,0x6b,0xef,0x65,0x1d,0x0b, 0x59,0x13,0xe3,0x4f,0x9d,0xb3,0x29,0x43,0x2b,0x07,0x1d,0x95,0x59,0x59,0x47,0xfb, 0xe5,0xe9,0x61,0x47,0x2f,0x35,0x7f,0x17,0x7f,0xef,0x7f,0x95,0x95,0x71,0xd3,0xa3, 0x0b,0x71,0xa3,0xad,0x0b,0x3b,0xb5,0xfb,0xa3,0xbf,0x4f,0x83,0x1d,0xad,0xe9,0x2f, 0x71,0x65,0xa3,0xe5,0x07,0x35,0x3d,0x0d,0xb5,0xe9,0xe5,0x47,0x3b,0x9d,0xef,0x35, 0xa3,0xbf,0xb3,0xdf,0x53,0xd3,0x97,0x53,0x49,0x71,0x07,0x35,0x61,0x71,0x2f,0x43, 0x2f,0x11,0xdf,0x17,0x97,0xfb,0x95,0x3b,0x7f,0x6b,0xd3,0x25,0xbf,0xad,0xc7,0xc5, 0xc5,0xb5,0x8b,0xef,0x2f,0xd3,0x07,0x6b,0x25,0x49,0x95,0x25,0x49,0x6d,0x71,0xc7 }, { 0xa7,0xbc,0xc9,0xad,0x91,0xdf,0x85,0xe5,0xd4,0x78,0xd5,0x17,0x46,0x7c,0x29,0x4c, 0x4d,0x03,0xe9,0x25,0x68,0x11,0x86,0xb3,0xbd,0xf7,0x6f,0x61,0x22,0xa2,0x26,0x34, 0x2a,0xbe,0x1e,0x46,0x14,0x68,0x9d,0x44,0x18,0xc2,0x40,0xf4,0x7e,0x5f,0x1b,0xad, 0x0b,0x94,0xb6,0x67,0xb4,0x0b,0xe1,0xea,0x95,0x9c,0x66,0xdc,0xe7,0x5d,0x6c,0x05, 0xda,0xd5,0xdf,0x7a,0xef,0xf6,0xdb,0x1f,0x82,0x4c,0xc0,0x68,0x47,0xa1,0xbd,0xee, 0x39,0x50,0x56,0x4a,0xdd,0xdf,0xa5,0xf8,0xc6,0xda,0xca,0x90,0xca,0x01,0x42,0x9d, 0x8b,0x0c,0x73,0x43,0x75,0x05,0x94,0xde,0x24,0xb3,0x80,0x34,0xe5,0x2c,0xdc,0x9b, 0x3f,0xca,0x33,0x45,0xd0,0xdb,0x5f,0xf5,0x52,0xc3,0x21,0xda,0xe2,0x22,0x72,0x6b, 0x3e,0xd0,0x5b,0xa8,0x87,0x8c,0x06,0x5d,0x0f,0xdd,0x09,0x19,0x93,0xd0,0xb9,0xfc, 0x8b,0x0f,0x84,0x60,0x33,0x1c,0x9b,0x45,0xf1,0xf0,0xa3,0x94,0x3a,0x12,0x77,0x33, 0x4d,0x44,0x78,0x28,0x3c,0x9e,0xfd,0x65,0x57,0x16,0x94,0x6b,0xfb,0x59,0xd0,0xc8, 0x22,0x36,0xdb,0xd2,0x63,0x98,0x43,0xa1,0x04,0x87,0x86,0xf7,0xa6,0x26,0xbb,0xd6, 0x59,0x4d,0xbf,0x6a,0x2e,0xaa,0x2b,0xef,0xe6,0x78,0xb6,0x4e,0xe0,0x2f,0xdc,0x7c, 0xbe,0x57,0x19,0x32,0x7e,0x2a,0xd0,0xb8,0xba,0x29,0x00,0x3c,0x52,0x7d,0xa8,0x49, 0x3b,0x2d,0xeb,0x25,0x49,0xfa,0xa3,0xaa,0x39,0xa7,0xc5,0xa7,0x50,0x11,0x36,0xfb, 0xc6,0x67,0x4a,0xf5,0xa5,0x12,0x65,0x7e,0xb0,0xdf,0xaf,0x4e,0xb3,0x61,0x7f,0x2f } }; Exiv2::byte key = 0; for (int i = 0; i < 4; ++i) { key ^= (count >> (i*8)) & 0xff; } Exiv2::byte ci = xlat[0][serial & 0xff]; Exiv2::byte cj = xlat[1][key]; Exiv2::byte ck = 0x60; for (uint32_t i = 0; i < size; ++i) { cj += ci * ck++; pData[i] ^= cj; } } } exiv2-0.23/src/panasonicmn_int.hpp0000644000175000017500000000623611732641407017003 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! @file panasonicmn_int.hpp @brief Panasonic MakerNote implemented using the following references: Panasonic MakerNote Information by Tom Hughes, Panasonic.pm of ExifTool by Phil Harvey, Panasonic Makernote Format Specification by Evan Hunter. @version $Rev: 2681 $ @author Andreas Huggel (ahu) ahuggel@gmx.net @author Gilles Caulier (gc) caulier dot gilles at gmail dot com @date 11-Jun-05, ahu: created */ #ifndef PANASONICMN_INT_HPP_ #define PANASONICMN_INT_HPP_ // ***************************************************************************** // included header files #include "tags.hpp" #include "types.hpp" // + standard includes #include #include // ***************************************************************************** // namespace extensions namespace Exiv2 { namespace Internal { // ***************************************************************************** // class definitions //! MakerNote for Panasonic cameras class PanasonicMakerNote { public: //! Return read-only list of built-in Panasonic tags static const TagInfo* tagList(); //! Return read-only list of built-in Panasonic RAW image tags (IFD0) static const TagInfo* tagListRaw(); //! @name Print functions for Panasonic %MakerNote tags //@{ //! Print SpotMode static std::ostream& print0x000f(std::ostream& os, const Value& value, const ExifData*); //! Print WhiteBalanceBias static std::ostream& print0x0023(std::ostream& os, const Value& value, const ExifData*); //@} private: //! Makernote tag list static const TagInfo tagInfo_[]; //! Taglist for IFD0 of Panasonic RAW images static const TagInfo tagInfoRaw_[]; }; // class PanasonicMakerNote }} // namespace Internal, Exiv2 #endif // #ifndef PANASONICMN_INT_HPP_ exiv2-0.23/src/bmpimage.hpp0000644000175000017500000001130611732641407015376 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! @file bmpimage.hpp @brief Windows Bitmap (BMP) image @version $Rev: 2681 $ @author Marco Piovanelli, Ovolab (marco) marco.piovanelli@pobox.com @date 05-Mar-2007, marco: created */ #ifndef BMPIMAGE_HPP_ #define BMPIMAGE_HPP_ // ***************************************************************************** // included header files #include "exif.hpp" #include "iptc.hpp" #include "image.hpp" #include "types.hpp" // + standard includes #include // ***************************************************************************** // namespace extensions namespace Exiv2 { // ***************************************************************************** // class definitions // Add Windows Bitmap (BMP) to the supported image formats namespace ImageType { const int bmp = 14; //!< Windows bitmap (bmp) image type (see class BmpImage) } /*! @brief Class to access Windows bitmaps. This is just a stub - we only read width and height. */ class EXIV2API BmpImage : public Image { //! @name NOT Implemented //@{ //! Copy constructor BmpImage(const BmpImage& rhs); //! Assignment operator BmpImage& operator=(const BmpImage& rhs); //@} public: //! @name Creators //@{ /*! @brief Constructor to open a Windows bitmap image. Since the constructor can not return a result, callers should check the good() method after object construction to determine success or failure. @param io An auto-pointer that owns a BasicIo instance used for reading and writing image metadata. \b Important: The constructor takes ownership of the passed in BasicIo instance through the auto-pointer. Callers should not continue to use the BasicIo instance after it is passed to this method. Use the Image::io() method to get a temporary reference. */ BmpImage(BasicIo::AutoPtr io); //@} //! @name Manipulators //@{ void readMetadata(); /*! @brief Todo: Write metadata back to the image. This method is not yet(?) implemented. Calling it will throw an Error(31). */ void writeMetadata(); /*! @brief Todo: Not supported yet(?). Calling this function will throw an instance of Error(32). */ void setExifData(const ExifData& exifData); /*! @brief Todo: Not supported yet(?). Calling this function will throw an instance of Error(32). */ void setIptcData(const IptcData& iptcData); /*! @brief Not supported. Calling this function will throw an instance of Error(32). */ void setComment(const std::string& comment); //@} //! @name Accessors //@{ std::string mimeType() const; //@} }; // class BmpImage // ***************************************************************************** // template, inline and free functions // These could be static private functions on Image subclasses but then // ImageFactory needs to be made a friend. /*! @brief Create a new BmpImage instance and return an auto-pointer to it. Caller owns the returned object and the auto-pointer ensures that it will be deleted. */ EXIV2API Image::AutoPtr newBmpInstance(BasicIo::AutoPtr io, bool create); //! Check if the file iIo is a Windows Bitmap image. EXIV2API bool isBmpType(BasicIo& iIo, bool advance); } // namespace Exiv2 #endif // #ifndef BMPIMAGE_HPP_ exiv2-0.23/src/tiffvisitor_int.hpp0000644000175000017500000007515311732641407017051 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! @file tiffvisitor_int.hpp @brief Internal operations on a TIFF composite tree, implemented as visitor classes. @version $Rev: 2681 $ @author Andreas Huggel (ahu) ahuggel@gmx.net @date 11-Apr-06, ahu: created */ #ifndef TIFFVISITOR_INT_HPP_ #define TIFFVISITOR_INT_HPP_ // ***************************************************************************** // included header files #include "exif.hpp" #include "tifffwd_int.hpp" #include "types.hpp" // + standard includes #include #include #include #include #include #include #include // ***************************************************************************** // namespace extensions namespace Exiv2 { class IptcData; class XmpData; namespace Internal { // ***************************************************************************** // class definitions /*! @brief Abstract base class defining the interface for TIFF composite vistors (Visitor pattern) A concrete visitor class is used as shown in the example below. Accept() will invoke the member function corresponding to the concrete type of each component in the composite. @code void visitorExample(Exiv2::TiffComponent* tiffComponent, Exiv2::TiffVisitor& visitor) { tiffComponent->accept(visitor); } @endcode */ class TiffVisitor { public: //! Events for the stop/go flag. See setGo(). enum GoEvent { //! Signal to control traversing of the composite tree. geTraverse = 0, //! Signal used by TiffReader to signal an unknown makernote. geKnownMakernote = 1 // Note: If you add more events here, adjust the events_ constant too! }; private: static const int events_ = 2; //!< The number of stop/go flags. bool go_[events_]; //!< Array of stop/go flags. See setGo(). public: //! @name Creators //@{ //! Default constructor. Initialises all stop/go flags to true. TiffVisitor(); //! Virtual destructor virtual ~TiffVisitor(); //@} //! @name Manipulators //@{ /*! @brief Set the stop/go flag: true for go, false for stop. This mechanism is used by visitors and components to signal special events. Specifically, TiffFinder sets the geTraverse flag as soon as it finds the correct component to signal to components that the search should be aborted. TiffReader uses geKnownMakernote to signal problems reading a makernote to the TiffMnEntry component. There is an array of flags, one for each defined \em event, so different signals can be used independent of each other. */ void setGo(GoEvent event, bool go); //! Operation to perform for a TIFF entry virtual void visitEntry(TiffEntry* object) =0; //! Operation to perform for a TIFF data entry virtual void visitDataEntry(TiffDataEntry* object) =0; //! Operation to perform for a TIFF image entry virtual void visitImageEntry(TiffImageEntry* object) =0; //! Operation to perform for a TIFF size entry virtual void visitSizeEntry(TiffSizeEntry* object) =0; //! Operation to perform for a TIFF directory virtual void visitDirectory(TiffDirectory* object) =0; /*! @brief Operation to perform for a TIFF directory, after all components and before the next entry is processed. */ virtual void visitDirectoryNext(TiffDirectory* object); /*! @brief Operation to perform for a TIFF directory, at the end of the processing. */ virtual void visitDirectoryEnd(TiffDirectory* object); //! Operation to perform for a TIFF sub-IFD virtual void visitSubIfd(TiffSubIfd* object) =0; //! Operation to perform for the makernote component virtual void visitMnEntry(TiffMnEntry* object) =0; //! Operation to perform for an IFD makernote virtual void visitIfdMakernote(TiffIfdMakernote* object) =0; //! Operation to perform after processing an IFD makernote virtual void visitIfdMakernoteEnd(TiffIfdMakernote* object); //! Operation to perform for a binary array virtual void visitBinaryArray(TiffBinaryArray* object) =0; /*! @brief Operation to perform for a TIFF binary array, at the end of the processing. */ virtual void visitBinaryArrayEnd(TiffBinaryArray* object); //! Operation to perform for an element of a binary array virtual void visitBinaryElement(TiffBinaryElement* object) =0; //@} //! @name Accessors //@{ //! Check if stop flag for \em event is clear, return true if it's clear. bool go(GoEvent event) const; //@} }; // class TiffVisitor /*! @brief Search the composite for a component with \em tag and \em group. Return a pointer to the component or 0, if not found. The class is ready for a first search after construction and can be re-initialized with init(). */ class TiffFinder : public TiffVisitor { public: //! @name Creators //@{ //! Constructor, taking \em tag and \em group of the component to find. TiffFinder(uint16_t tag, IfdId group) : tag_(tag), group_(group), tiffComponent_(0) {} //! Virtual destructor virtual ~TiffFinder(); //@} //! @name Manipulators //@{ //! Find tag and group in a TIFF entry virtual void visitEntry(TiffEntry* object); //! Find tag and group in a TIFF data entry virtual void visitDataEntry(TiffDataEntry* object); //! Find tag and group in a TIFF image entry virtual void visitImageEntry(TiffImageEntry* object); //! Find tag and group in a TIFF size entry virtual void visitSizeEntry(TiffSizeEntry* object); //! Find tag and group in a TIFF directory virtual void visitDirectory(TiffDirectory* object); //! Find tag and group in a TIFF sub-IFD virtual void visitSubIfd(TiffSubIfd* object); //! Find tag and group in a TIFF makernote virtual void visitMnEntry(TiffMnEntry* object); //! Find tag and group in an IFD makernote virtual void visitIfdMakernote(TiffIfdMakernote* object); //! Find tag and group in a binary array virtual void visitBinaryArray(TiffBinaryArray* object); //! Find tag and group in an element of a binary array virtual void visitBinaryElement(TiffBinaryElement* object); //! Check if \em object matches \em tag and \em group void findObject(TiffComponent* object); //! Initialize the Finder for a new search. void init(uint16_t tag, IfdId group); //@} //! @name Accessors //@{ /*! @brief Return the search result. 0 if no TIFF component was found for the tag and group combination. */ TiffComponent* result() const { return tiffComponent_; } //@} private: uint16_t tag_; IfdId group_; TiffComponent* tiffComponent_; }; // class TiffFinder /*! @brief Copy all image tags from the source tree (the tree that is traversed) to a target tree, which is empty except for the root element provided in the constructor. */ class TiffCopier : public TiffVisitor { public: //! @name Creators //@{ /*! @brief Constructor @param pRoot Pointer to the root element of the (empty) target tree. @param root @param pHeader Pointer to the TIFF header of the source image. @param pPrimaryGroups Pointer to the list of primary groups. */ TiffCopier( TiffComponent* pRoot, uint32_t root, const TiffHeaderBase* pHeader, const PrimaryGroups* pPrimaryGroups); //! Virtual destructor virtual ~TiffCopier(); //@} //! @name Manipulators //@{ //! Copy a TIFF entry if it is an image tag virtual void visitEntry(TiffEntry* object); //! Copy a TIFF data entry if it is an image tag virtual void visitDataEntry(TiffDataEntry* object); //! Copy a TIFF image entry if it is an image tag virtual void visitImageEntry(TiffImageEntry* object); //! Copy a TIFF size entry if it is an image tag virtual void visitSizeEntry(TiffSizeEntry* object); //! Copy a TIFF directory if it is an image tag virtual void visitDirectory(TiffDirectory* object); //! Copy a TIFF sub-IFD if it is an image tag virtual void visitSubIfd(TiffSubIfd* object); //! Copy a TIFF makernote if it is an image tag virtual void visitMnEntry(TiffMnEntry* object); //! Copy an IFD makernote if it is an image tag virtual void visitIfdMakernote(TiffIfdMakernote* object); //! Copy a binary array if it is an image tag virtual void visitBinaryArray(TiffBinaryArray* object); //! Copy an element of a binary array if it is an image tag virtual void visitBinaryElement(TiffBinaryElement* object); //! Check if \em object is an image tag and if so, copy it to the target tree. void copyObject(TiffComponent* object); //@} private: TiffComponent* pRoot_; uint32_t root_; const TiffHeaderBase* pHeader_; const PrimaryGroups* pPrimaryGroups_; }; // class TiffCopier /*! @brief TIFF composite visitor to decode metadata from the TIFF tree and add it to an Image, which is supplied in the constructor (Visitor pattern). Used by TiffParser to decode the metadata from a TIFF composite. */ class TiffDecoder : public TiffVisitor { public: //! @name Creators //@{ /*! @brief Constructor, taking metadata containers to add the metadata to, the root element of the composite to decode and a FindDecoderFct function to get the decoder function for each tag. */ TiffDecoder( ExifData& exifData, IptcData& iptcData, XmpData& xmpData, TiffComponent* const pRoot, FindDecoderFct findDecoderFct ); //! Virtual destructor virtual ~TiffDecoder(); //@} //! @name Manipulators //@{ //! Decode a TIFF entry virtual void visitEntry(TiffEntry* object); //! Decode a TIFF data entry virtual void visitDataEntry(TiffDataEntry* object); //! Decode a TIFF image entry virtual void visitImageEntry(TiffImageEntry* object); //! Decode a TIFF size entry virtual void visitSizeEntry(TiffSizeEntry* object); //! Decode a TIFF directory virtual void visitDirectory(TiffDirectory* object); //! Decode a TIFF sub-IFD virtual void visitSubIfd(TiffSubIfd* object); //! Decode a TIFF makernote virtual void visitMnEntry(TiffMnEntry* object); //! Decode an IFD makernote virtual void visitIfdMakernote(TiffIfdMakernote* object); //! Decode a binary array virtual void visitBinaryArray(TiffBinaryArray* object); //! Decode an element of a binary array virtual void visitBinaryElement(TiffBinaryElement* object); //! Entry function, determines how to decode each tag void decodeTiffEntry(const TiffEntryBase* object); //! Decode a standard TIFF entry void decodeStdTiffEntry(const TiffEntryBase* object); //! Decode IPTC data from an IPTCNAA tag or Photoshop ImageResources void decodeIptc(const TiffEntryBase* object); //! Decode XMP packet from an XMLPacket tag void decodeXmp(const TiffEntryBase* object); //@} private: //! @name Manipulators //@{ /*! @brief Get the data for a \em tag and \em group, either from the \em object provided, if it matches or from the matching element in the hierarchy. Populates \em pData and \em size with the result. If no matching element is found the function leaves both of these parameters unchanged. */ void getObjData(byte const*& pData, long& size, uint16_t tag, IfdId group, const TiffEntryBase* object); //@} private: // DATA ExifData& exifData_; //!< Exif metadata container IptcData& iptcData_; //!< IPTC metadata container XmpData& xmpData_; //!< XMP metadata container TiffComponent* const pRoot_; //!< Root element of the composite const FindDecoderFct findDecoderFct_; //!< Ptr to the function to find special decoding functions std::string make_; //!< Camera make, determined from the tags to decode bool decodedIptc_; //!< Indicates if IPTC has been decoded yet }; // class TiffDecoder /*! @brief TIFF composite visitor to encode metadata from an image to the TIFF tree. The metadata containers and root element of the tree are supplied in the constructor. Used by TiffParserWorker to encode the metadata into a TIFF composite. For non-intrusive writing, the encoder is used as a visitor (by passing it to the accept() member of a TiffComponent). The composite tree is then traversed and metadata from the image is used to encode each existing component. For intrusive writing, add() is called, which loops through the metadata and creates and populates corresponding TiffComponents as needed. */ class TiffEncoder : public TiffVisitor { public: //! @name Creators //@{ /*! @brief Constructor, taking the root element of the composite to encode to, the image with the metadata to encode and a function to find special encoders. */ TiffEncoder( const ExifData& exifData, const IptcData& iptcData, const XmpData& xmpData, TiffComponent* pRoot, const bool isNewImage, const PrimaryGroups* pPrimaryGroups, const TiffHeaderBase* pHeader, FindEncoderFct findEncoderFct ); //! Virtual destructor virtual ~TiffEncoder(); //@} //! @name Manipulators //@{ //! Encode a TIFF entry virtual void visitEntry(TiffEntry* object); //! Encode a TIFF data entry virtual void visitDataEntry(TiffDataEntry* object); //! Encode a TIFF image entry virtual void visitImageEntry(TiffImageEntry* object); //! Encode a TIFF size entry virtual void visitSizeEntry(TiffSizeEntry* object); //! Encode a TIFF directory virtual void visitDirectory(TiffDirectory* object); //! Update directory entries virtual void visitDirectoryNext(TiffDirectory* object); //! Encode a TIFF sub-IFD virtual void visitSubIfd(TiffSubIfd* object); //! Encode a TIFF makernote virtual void visitMnEntry(TiffMnEntry* object); //! Encode an IFD makernote virtual void visitIfdMakernote(TiffIfdMakernote* object); //! Reset encoder to its original state, undo makernote specific settings virtual void visitIfdMakernoteEnd(TiffIfdMakernote* object); //! Encode a binary array virtual void visitBinaryArray(TiffBinaryArray* object); //! Re-encrypt binary array if necessary virtual void visitBinaryArrayEnd(TiffBinaryArray* object); //! Encode an element of a binary array virtual void visitBinaryElement(TiffBinaryElement* object); /*! @brief Top level encoder function. Determines how to encode each TIFF component. This function is called by the visit methods of the encoder as well as the add() method. If no \em datum is provided, search the metadata based on tag and group of the \em object. This is the case if the function is called from a visit method. Then check if a special encoder function is registered for the tag, and if so use it to encode the \em object. Else use the callback encoder function at the object (which results in a double-dispatch to the appropriate encoding function of the encoder. @param object Object in the TIFF component tree to encode. @param datum The corresponding metadatum with the updated value. @note Encoder functions may use metadata other than \em datum. */ void encodeTiffComponent( TiffEntryBase* object, const Exifdatum* datum =0 ); //! Callback encoder function for an element of a binary array. void encodeBinaryElement(TiffBinaryElement* object, const Exifdatum* datum); //! Callback encoder function for a binary array. void encodeBinaryArray(TiffBinaryArray* object, const Exifdatum* datum); //! Callback encoder function for a data entry. void encodeDataEntry(TiffDataEntry* object, const Exifdatum* datum); //! Callback encoder function for a standard TIFF entry void encodeTiffEntry(TiffEntry* object, const Exifdatum* datum); //! Callback encoder function for an image entry. void encodeImageEntry(TiffImageEntry* object, const Exifdatum* datum); //! Callback encoder function for a %Makernote entry. void encodeMnEntry(TiffMnEntry* object, const Exifdatum* datum); //! Callback encoder function for a size entry. void encodeSizeEntry(TiffSizeEntry* object, const Exifdatum* datum); //! Callback encoder function for a sub-IFD entry. void encodeSubIfd(TiffSubIfd* object, const Exifdatum* datum); //! Special encoder function for the base part of a TIFF entry. void encodeTiffEntryBase(TiffEntryBase* object, const Exifdatum* datum); //! Special encoder function for an offset entry. void encodeOffsetEntry(TiffEntryBase* object, const Exifdatum* datum); //! Special encoder function to encode SubIFD contents to Image group if it contains primary image data // Todo void encodeNikonSubIfd(TiffEntryBase* object, const Exifdatum* datum); //! Special encoder function to encode IPTC data to an IPTCNAA or Photoshop ImageResources tag. void encodeIptc(TiffEntryBase* object, const Exifdatum* datum); /*! @brief Add metadata from image to the TIFF composite. For each Exif metadatum, the corresponding TiffComponent is created if necessary and populated using encodeTiffComponent(). The add() function is used during intrusive writing, to create a new TIFF structure. @note For non-intrusive writing, the encoder is used as a visitor (by passing it to the accept() member of a TiffComponent). The composite tree is then traversed and metadata from the image is used to encode each existing component. */ void add( TiffComponent* pRootDir, TiffComponent* pSourceDir, uint32_t root ); //! Set the dirty flag and end of traversing signal. void setDirty(bool flag =true); //@} //! @name Accessors //@{ /*! @brief Return the applicable byte order. May be different for the Makernote and the rest of the TIFF entries. */ ByteOrder byteOrder() const { return byteOrder_; } /*! @brief True if any tag was deleted or allocated in the process of visiting a TIFF composite tree. */ bool dirty() const; //! Return the write method used. WriteMethod writeMethod() const { return writeMethod_; } //@} private: //! @name Manipulators //@{ /*! Encode IPTC data. Updates or adds tag Exif.Image.IPTCNAA, updates but never adds tag Exif.Image.ImageResources. This method is called from the constructor. */ void encodeIptc(); /*! Encode XMP data. Adds tag Exif.Image.XMLPacket with the XMP packet. This method is called from the constructor. */ void encodeXmp(); //@} //! @name Accessors //@{ /*! @brief Update a directory entry. This is called after all directory entries are encoded. It takes care of type and count changes and size shrinkage for non-intrusive writing. */ uint32_t updateDirEntry(byte* buf, ByteOrder byteOrder, TiffComponent* pTiffComponent) const; /*! @brief Check if the tag is an image tag of an existing image. Such tags are copied from the original image and can't be modifed. The condition is true if there is an existing image (as opposed to a newly created TIFF image) and \em tag, \em group is considered an image tag of this image - whether or not it's actually present in the existing image doesn't matter. */ bool isImageTag(uint16_t tag, IfdId group) const; //@} private: // DATA ExifData exifData_; //!< Copy of the Exif data to encode const IptcData& iptcData_; //!< IPTC data to encode, just a reference const XmpData& xmpData_; //!< XMP data to encode, just a reference bool del_; //!< Indicates if Exif data entries should be deleted after encoding const TiffHeaderBase* pHeader_; //!< TIFF image header TiffComponent* pRoot_; //!< Root element of the composite const bool isNewImage_; //!< True if the TIFF image is created from scratch const PrimaryGroups* pPrimaryGroups_; //!< List of primary image groups TiffComponent* pSourceTree_; //!< Parsed source tree for reference ByteOrder byteOrder_; //!< Byteorder for encoding ByteOrder origByteOrder_; //!< Byteorder as set in the c'tor const FindEncoderFct findEncoderFct_; //!< Ptr to the function to find special encoding functions std::string make_; //!< Camera make, determined from the tags to encode bool dirty_; //!< Signals if any tag is deleted or allocated WriteMethod writeMethod_; //!< Write method used. }; // class TiffEncoder /*! @brief Simple state class containing relevant state information for the TIFF reader. This is in a separate class so that the reader can change state if needed (e.g., to read certain complex makernotes). */ class TiffRwState { friend class TiffReader; public: //! TiffRWState auto_ptr type typedef std::auto_ptr AutoPtr; //! @name Creators //@{ //! Constructor. TiffRwState(ByteOrder byteOrder, uint32_t baseOffset) : byteOrder_(byteOrder), baseOffset_(baseOffset) {} //@} //! @name Accessors //@{ /*! @brief Return the applicable byte order. May be different for the Makernote and the rest of the TIFF entries. */ ByteOrder byteOrder() const { return byteOrder_; } /*! @brief Return the base offset. TIFF standard format uses byte offsets which are always relative to the start of the TIFF file, i.e., relative to the start of the TIFF image header. In this case, the base offset is 0. However, some camera vendors encode their makernotes in TIFF IFDs using offsets relative to (somewhere near) the start of the makernote data. In this case, base offset added to the start of the TIFF image header points to the basis for such makernote offsets. */ uint32_t baseOffset() const { return baseOffset_; } //@} private: ByteOrder byteOrder_; const uint32_t baseOffset_; }; // TiffRwState /*! @brief TIFF composite visitor to read the TIFF structure from a block of memory and build the composite from it (Visitor pattern). Used by TiffParser to read the TIFF data from a block of memory. */ class TiffReader : public TiffVisitor { public: //! @name Creators //@{ /*! @brief Constructor. The data buffer and table describing the TIFF structure of the data are set in the constructor. @param pData Pointer to the data buffer, starting with a TIFF header. @param size Number of bytes in the data buffer. @param pRoot Root element of the TIFF composite. @param state State object for creation function, byte order and base offset. */ TiffReader(const byte* pData, uint32_t size, TiffComponent* pRoot, TiffRwState::AutoPtr state); //! Virtual destructor virtual ~TiffReader(); //@} //! @name Manipulators //@{ //! Read a TIFF entry from the data buffer virtual void visitEntry(TiffEntry* object); //! Read a TIFF data entry from the data buffer virtual void visitDataEntry(TiffDataEntry* object); //! Read a TIFF image entry from the data buffer virtual void visitImageEntry(TiffImageEntry* object); //! Read a TIFF size entry from the data buffer virtual void visitSizeEntry(TiffSizeEntry* object); //! Read a TIFF directory from the data buffer virtual void visitDirectory(TiffDirectory* object); //! Read a TIFF sub-IFD from the data buffer virtual void visitSubIfd(TiffSubIfd* object); //! Read a TIFF makernote entry from the data buffer virtual void visitMnEntry(TiffMnEntry* object); //! Read an IFD makernote from the data buffer virtual void visitIfdMakernote(TiffIfdMakernote* object); //! Reset reader to its original state, undo makernote specific settings virtual void visitIfdMakernoteEnd(TiffIfdMakernote* object); //! Read a binary array from the data buffer virtual void visitBinaryArray(TiffBinaryArray* object); //! Read an element of a binary array from the data buffer virtual void visitBinaryElement(TiffBinaryElement* object); //! Read a standard TIFF entry from the data buffer void readTiffEntry(TiffEntryBase* object); //! Read a TiffDataEntryBase from the data buffer void readDataEntryBase(TiffDataEntryBase* object); //! Set the \em state class. Assumes ownership of the object passed in. void changeState(TiffRwState::AutoPtr state); //! Reset the state to the original state as set in the constructor. void resetState(); //! Check IFD directory pointer \em start for circular reference bool circularReference(const byte* start, IfdId group); //! Return the next idx sequence number for \em group int nextIdx(IfdId group); /*! @brief Read deferred components. This function is called after the TIFF composite is read by passing a TiffReader to the accept() function of the root component. It reads all components for which reading was deferred during that pass. This is usually done to make sure that all other components are accessible at the time the deferred components are processed. */ void postProcess(); //@} //! @name Accessors //@{ //! Return the byte order. ByteOrder byteOrder() const; //! Return the base offset. See class TiffRwState for details uint32_t baseOffset() const; //@} private: typedef std::map DirList; typedef std::map IdxSeq; typedef std::vector PostList; // DATA const byte* pData_; //!< Pointer to the memory buffer const uint32_t size_; //!< Size of the buffer const byte* pLast_; //!< Pointer to the last byte TiffComponent* const pRoot_; //!< Root element of the composite TiffRwState* pState_; //!< State class TiffRwState* pOrigState_; //!< State class as set in the c'tor DirList dirList_; //!< List of IFD pointers and their groups IdxSeq idxSeq_; //!< Sequences for group, used for the entry's idx PostList postList_; //!< List of components with deferred reading bool postProc_; //!< True in postProcessList() }; // class TiffReader }} // namespace Internal, Exiv2 #endif // #ifndef TIFFVISITOR_INT_HPP_ exiv2-0.23/src/doxygen.hpp.in0000644000175000017500000001374211732641407015705 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /*! @file doxygen.hpp @brief Additional documentation, this file contains no source code @version $Rev: 2681 $ @author Andreas Huggel (ahu) ahuggel@gmx.net @date 07-Feb-04, ahu: created */ // ***************************************************************************** // *** NOTE: doxygen.hpp is a generated file! Only edit doxygen.hpp.in *** // ***************************************************************************** /*! @mainpage Image metadata library and tools v@PACKAGE_VERSION@ @section overview Exiv2 Overview %Exiv2 comprises of a C++ library and a command line utility to access image metadata. %Exiv2 is free software. The homepage of %Exiv2 is at http://www.exiv2.org/. The %Exiv2 library provides - fast read and write access to the Exif, IPTC and XMP metadata of an image through %Exiv2 keys and standard C++ iterators - conversion of Exif and IPTC metadata to and from XMP - a smart IPTC implementation that does not affect data that programs like Photoshop store in the same image segment - Exif MakerNote support: - %MakerNote tags can be accessed just like any other Exif metadata - a sophisticated write algorithm avoids corrupting the %MakerNote - extract and delete methods for Exif thumbnails (both, JPEG and TIFF thumbnails) - set methods for Exif thumbnails (JPEG only, TIFF thumbnails can be set from individual tags) - an easy to use and well documented API @section getting-started Getting started A few pointers to get you started with the %Exiv2 library without delay. @section metadata Metadata reference tables Exif and MakerNote tags - Standard Exif tags - Canon MakerNote tags - Fujifilm MakerNote tags - Minolta MakerNote tags - Nikon MakerNote tags - Olympus MakerNote tags - Panasonic MakerNote tags - Pentax MakerNote tags - Samsung MakerNote tags - Sigma/Foveon MakerNote tags - Sony MakerNote tags IPTC datasets - IPTC datasets XMP properties - dc schema - xmp schema - xmpRights schema - xmpMM schema - xmpBJ schema - xmpTPg schema - xmpDM schema - pdf schema - photoshop schema - crs schema - tiff schema - exif schema - aux schema - Iptc4xmpCore schema - Iptc4xmpExt schema - PLUS schema - digiKam schema - KDE Image Program Interface schema - MicrosoftPhoto schema - iView Media Pro schema - Microsoft Expression Media schema - Microsoft Photo 1.2 schema - Microsoft Photo RegionInfo schema - Microsoft Photo Region schema - Metadata Working Group Regions schema @section formats File Formats

See the list of supported image formats in the Wiki and the Canon CRW mapping.

@section supp Support

All project resources are accessible from the project website.

Please send feedback or queries to the %Exiv2 forum. For new bug reports and feature requests, please open an issue.

@section license License

Copyright (C) 2004-2012 Andreas Huggel

%Exiv2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.

Alternatively, %Exiv2 is also available with a commercial license, which allows it to be used in closed-source projects. Contact me for more information.

%Exiv2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA.

*/ /*! @example addmoddel.cpp Sample usage of high-level metadata operations. */ /*! @example exifprint.cpp Sample program to print Exif data from an image. */ /*! @example exifcomment.cpp Sample program showing how to set the Exif comment of an image. */ /*! @example iptcprint.cpp Sample program to print the IPTC metadata of an image */ /*! @example iptceasy.cpp The quickest way to access, set or modify IPTC metadata */ /*! @example xmpsample.cpp Sample usage of high-level XMP classes. */ exiv2-0.23/src/psdimage.cpp0000644000175000017500000007570511732641407015416 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /* File: psdimage.cpp Version: $Rev: 2681 $ Author(s): Marco Piovanelli, Ovolab (marco) Michael Ulbrich (mul) History: 05-Mar-2007, marco: created */ // ***************************************************************************** #include "rcsid_int.hpp" EXIV2_RCSID("@(#) $Id: psdimage.cpp 2681 2012-03-22 15:19:35Z ahuggel $") //#define DEBUG 1 // ***************************************************************************** // included header files #ifdef _MSC_VER # include "exv_msvc.h" #else # include "exv_conf.h" #endif #include "psdimage.hpp" #include "jpgimage.hpp" #include "image.hpp" #include "basicio.hpp" #include "error.hpp" #include "futils.hpp" // + standard includes #include #include #include #include #include #include // Todo: Consolidate with existing code in struct Photoshop (jpgimage.hpp): // Extend this helper to a proper class with all required functionality, // then move it here or into a separate file? //! @cond IGNORE struct PhotoshopResourceBlock { uint32_t resourceType; // one of the markers in Photoshop::irbId_[] uint16_t resourceId; unsigned char resourceName[2]; // Pascal string (length byte + characters), padded to an even size -- this assumes the empty string uint32_t resourceDataSize; }; //! @endcond // Photoshop resource IDs (Cf. ) enum { kPhotoshopResourceID_Photoshop2Info = 0x03e8, // [obsolete -- Photoshop 2.0 only] General information -- contains five 2-byte values: number of channels, rows, columns, depth and mode kPhotoshopResourceID_MacintoshClassicPrintInfo = 0x03e9, // [optional] Macintosh classic print record (120 bytes) kPhotoshopResourceID_MacintoshCarbonPrintInfo = 0x03ea, // [optional] Macintosh carbon print info (variable-length XML format) kPhotoshopResourceID_Photoshop2ColorTable = 0x03eb, // [obsolete -- Photoshop 2.0 only] Indexed color table kPhotoshopResourceID_ResolutionInfo = 0x03ed, // PhotoshopResolutionInfo structure (see below) kPhotoshopResourceID_AlphaChannelsNames = 0x03ee, // as a series of Pstrings kPhotoshopResourceID_DisplayInfo = 0x03ef, // see appendix A in Photoshop SDK kPhotoshopResourceID_PStringCaption = 0x03f0, // [optional] the caption, as a Pstring kPhotoshopResourceID_BorderInformation = 0x03f1, // border width and units kPhotoshopResourceID_BackgroundColor = 0x03f2, // see additional Adobe information kPhotoshopResourceID_PrintFlags = 0x03f3, // labels, crop marks, colour bars, ecc... kPhotoshopResourceID_BWHalftoningInfo = 0x03f4, // Gray-scale and multich. half-toning info kPhotoshopResourceID_ColorHalftoningInfo = 0x03f5, // Colour half-toning information kPhotoshopResourceID_DuotoneHalftoningInfo = 0x03f6, // Duo-tone half-toning information kPhotoshopResourceID_BWTransferFunc = 0x03f7, // Gray-scale and multich. transfer function kPhotoshopResourceID_ColorTransferFuncs = 0x03f8, // Colour transfer function kPhotoshopResourceID_DuotoneTransferFuncs = 0x03f9, // Duo-tone transfer function kPhotoshopResourceID_DuotoneImageInfo = 0x03fa, // Duo-tone image information kPhotoshopResourceID_EffectiveBW = 0x03fb, // two bytes for the effective black and white values kPhotoshopResourceID_ObsoletePhotoshopTag1 = 0x03fc, // [obsolete] kPhotoshopResourceID_EPSOptions = 0x03fd, // Encapsulated Postscript options kPhotoshopResourceID_QuickMaskInfo = 0x03fe, // Quick Mask information. 2 bytes containing Quick Mask channel ID, 1 byte boolean indicating whether the mask was initially empty. kPhotoshopResourceID_ObsoletePhotoshopTag2 = 0x03ff, // [obsolete] kPhotoshopResourceID_LayerStateInfo = 0x0400, // index of target layer (0 means bottom) kPhotoshopResourceID_WorkingPathInfo = 0x0401, // should not be saved to the file kPhotoshopResourceID_LayersGroupInfo = 0x0402, // for grouping layers together kPhotoshopResourceID_ObsoletePhotoshopTag3 = 0x0403, // [obsolete] ?? kPhotoshopResourceID_IPTC_NAA = 0x0404, // IPTC/NAA data kPhotoshopResourceID_RawImageMode = 0x0405, // image mode for raw format files kPhotoshopResourceID_JPEGQuality = 0x0406, // [private] kPhotoshopResourceID_GridGuidesInfo = 0x0408, // see additional Adobe information kPhotoshopResourceID_ThumbnailResource = 0x0409, // see additional Adobe information kPhotoshopResourceID_CopyrightFlag = 0x040a, // true if image is copyrighted kPhotoshopResourceID_URL = 0x040b, // text string with a resource locator kPhotoshopResourceID_ThumbnailResource2 = 0x040c, // see additional Adobe information kPhotoshopResourceID_GlobalAngle = 0x040d, // global lighting angle for effects layer kPhotoshopResourceID_ColorSamplersResource = 0x040e, // see additional Adobe information kPhotoshopResourceID_ICCProfile = 0x040f, // see notes from Internat. Color Consortium kPhotoshopResourceID_Watermark = 0x0410, // one byte kPhotoshopResourceID_ICCUntagged = 0x0411, // 1 means intentionally untagged kPhotoshopResourceID_EffectsVisible = 0x0412, // 1 byte to show/hide all effects layers kPhotoshopResourceID_SpotHalftone = 0x0413, // version, length and data kPhotoshopResourceID_IDsBaseValue = 0x0414, // base value for new layers ID's kPhotoshopResourceID_UnicodeAlphaNames = 0x0415, // length plus Unicode string kPhotoshopResourceID_IndexedColourTableCount = 0x0416, // [Photoshop 6.0 and later] 2 bytes kPhotoshopResourceID_TransparentIndex = 0x0417, // [Photoshop 6.0 and later] 2 bytes kPhotoshopResourceID_GlobalAltitude = 0x0419, // [Photoshop 6.0 and later] 4 bytes kPhotoshopResourceID_Slices = 0x041a, // [Photoshop 6.0 and later] see additional Adobe info kPhotoshopResourceID_WorkflowURL = 0x041b, // [Photoshop 6.0 and later] 4 bytes length + Unicode string kPhotoshopResourceID_JumpToXPEP = 0x041c, // [Photoshop 6.0 and later] see additional Adobe info kPhotoshopResourceID_AlphaIdentifiers = 0x041d, // [Photoshop 6.0 and later] 4*(n+1) bytes kPhotoshopResourceID_URLList = 0x041e, // [Photoshop 6.0 and later] structured Unicode URL's kPhotoshopResourceID_VersionInfo = 0x0421, // [Photoshop 6.0 and later] see additional Adobe info kPhotoshopResourceID_ExifInfo = 0x0422, // [Photoshop 7.0?] Exif metadata kPhotoshopResourceID_XMPPacket = 0x0424, // [Photoshop 7.0?] XMP packet -- see http://www.adobe.com/devnet/xmp/pdfs/xmp_specification.pdf kPhotoshopResourceID_ClippingPathName = 0x0bb7, // [Photoshop 6.0 and later] name of clipping path kPhotoshopResourceID_MorePrintFlags = 0x2710 // [Photoshop 6.0 and later] Print flags information. 2 bytes version (=1), 1 byte center crop marks, 1 byte (=0), 4 bytes bleed width value, 2 bytes bleed width scale. }; // ***************************************************************************** // class member definitions namespace Exiv2 { PsdImage::PsdImage(BasicIo::AutoPtr io) : Image(ImageType::psd, mdExif | mdIptc | mdXmp, io) { } // PsdImage::PsdImage std::string PsdImage::mimeType() const { return "image/x-photoshop"; } void PsdImage::setComment(const std::string& /*comment*/) { // not supported throw(Error(32, "Image comment", "Photoshop")); } void PsdImage::readMetadata() { #ifdef DEBUG std::cerr << "Exiv2::PsdImage::readMetadata: Reading Photoshop file " << io_->path() << "\n"; #endif if (io_->open() != 0) { throw Error(9, io_->path(), strError()); } IoCloser closer(*io_); // Ensure that this is the correct image type if (!isPsdType(*io_, false)) { if (io_->error() || io_->eof()) throw Error(14); throw Error(3, "Photoshop"); } clearMetadata(); /* The Photoshop header goes as follows -- all numbers are in big-endian byte order: offset length name description ====== ======= ========= ========= 0 4 bytes signature always '8BPS' 4 2 bytes version always equal to 1 6 6 bytes reserved must be zero 12 2 bytes channels number of channels in the image, including alpha channels (1 to 24) 14 4 bytes rows the height of the image in pixels 18 4 bytes columns the width of the image in pixels 22 2 bytes depth the number of bits per channel 24 2 bytes mode the color mode of the file; Supported values are: Bitmap=0; Grayscale=1; Indexed=2; RGB=3; CMYK=4; Multichannel=7; Duotone=8; Lab=9 */ byte buf[26]; if (io_->read(buf, 26) != 26) { throw Error(3, "Photoshop"); } pixelWidth_ = getLong(buf + 18, bigEndian); pixelHeight_ = getLong(buf + 14, bigEndian); // immediately following the image header is the color mode data section, // the first four bytes of which specify the byte size of the whole section if (io_->read(buf, 4) != 4) { throw Error(3, "Photoshop"); } // skip it uint32_t colorDataLength = getULong(buf, bigEndian); if (io_->seek(colorDataLength, BasicIo::cur)) { throw Error(3, "Photoshop"); } // after the color data section, comes a list of resource blocks, preceeded by the total byte size if (io_->read(buf, 4) != 4) { throw Error(3, "Photoshop"); } uint32_t resourcesLength = getULong(buf, bigEndian); while (resourcesLength > 0) { if (io_->read(buf, 8) != 8) { throw Error(3, "Photoshop"); } if (!Photoshop::isIrb(buf, 4)) { break; // bad resource type } uint16_t resourceId = getUShort(buf + 4, bigEndian); uint32_t resourceNameLength = buf[6] & ~1; // skip the resource name, plus any padding io_->seek(resourceNameLength, BasicIo::cur); // read resource size if (io_->read(buf, 4) != 4) { throw Error(3, "Photoshop"); } uint32_t resourceSize = getULong(buf, bigEndian); uint32_t curOffset = io_->tell(); #ifdef DEBUG std::cerr << std::hex << "resourceId: " << resourceId << std::dec << " length: " << resourceSize << std::hex << "\n"; #endif readResourceBlock(resourceId, resourceSize); resourceSize = (resourceSize + 1) & ~1; // pad to even io_->seek(curOffset + resourceSize, BasicIo::beg); resourcesLength -= (12 + resourceNameLength + resourceSize); } } // PsdImage::readMetadata void PsdImage::readResourceBlock(uint16_t resourceId, uint32_t resourceSize) { switch(resourceId) { case kPhotoshopResourceID_IPTC_NAA: { DataBuf rawIPTC(resourceSize); io_->read(rawIPTC.pData_, rawIPTC.size_); if (io_->error() || io_->eof()) throw Error(14); if (IptcParser::decode(iptcData_, rawIPTC.pData_, rawIPTC.size_)) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Failed to decode IPTC metadata.\n"; #endif iptcData_.clear(); } break; } case kPhotoshopResourceID_ExifInfo: { DataBuf rawExif(resourceSize); io_->read(rawExif.pData_, rawExif.size_); if (io_->error() || io_->eof()) throw Error(14); ByteOrder bo = ExifParser::decode(exifData_, rawExif.pData_, rawExif.size_); setByteOrder(bo); if (rawExif.size_ > 0 && byteOrder() == invalidByteOrder) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Failed to decode Exif metadata.\n"; #endif exifData_.clear(); } break; } case kPhotoshopResourceID_XMPPacket: { DataBuf xmpPacket(resourceSize); io_->read(xmpPacket.pData_, xmpPacket.size_); if (io_->error() || io_->eof()) throw Error(14); xmpPacket_.assign(reinterpret_cast(xmpPacket.pData_), xmpPacket.size_); if (xmpPacket_.size() > 0 && XmpParser::decode(xmpData_, xmpPacket_)) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Failed to decode XMP metadata.\n"; #endif } break; } // - PS 4.0 preview data is fetched from ThumbnailResource // - PS >= 5.0 preview data is fetched from ThumbnailResource2 case kPhotoshopResourceID_ThumbnailResource: case kPhotoshopResourceID_ThumbnailResource2: { /* Photoshop thumbnail resource header offset length name description ====== ======== ==== =========== 0 4 bytes format = 1 (kJpegRGB). Also supports kRawRGB (0). 4 4 bytes width Width of thumbnail in pixels. 8 4 bytes height Height of thumbnail in pixels. 12 4 bytes widthbytes Padded row bytes as (width * bitspixel + 31) / 32 * 4. 16 4 bytes size Total size as widthbytes * height * planes 20 4 bytes compressedsize Size after compression. Used for consistentcy check. 24 2 bytes bitspixel = 24. Bits per pixel. 26 2 bytes planes = 1. Number of planes. 28 variable data JFIF data in RGB format. Note: For resource ID 1033 the data is in BGR format. */ byte buf[28]; if (io_->read(buf, 28) != 28) { throw Error(3, "Photoshop"); } NativePreview nativePreview; nativePreview.position_ = io_->tell(); nativePreview.size_ = getLong(buf + 20, bigEndian); // compressedsize nativePreview.width_ = getLong(buf + 4, bigEndian); nativePreview.height_ = getLong(buf + 8, bigEndian); const uint32_t format = getLong(buf + 0, bigEndian); if (nativePreview.size_ > 0 && nativePreview.position_ >= 0) { io_->seek(static_cast(nativePreview.size_), BasicIo::cur); if (io_->error() || io_->eof()) throw Error(14); if (format == 1) { nativePreview.filter_ = ""; nativePreview.mimeType_ = "image/jpeg"; nativePreviews_.push_back(nativePreview); } else { // unsupported format of native preview } } break; } default: { break; } } } // PsdImage::readResourceBlock void PsdImage::writeMetadata() { if (io_->open() != 0) { throw Error(9, io_->path(), strError()); } IoCloser closer(*io_); BasicIo::AutoPtr tempIo(io_->temporary()); // may throw assert (tempIo.get() != 0); doWriteMetadata(*tempIo); // may throw io_->close(); io_->transfer(*tempIo); // may throw } // PsdImage::writeMetadata void PsdImage::doWriteMetadata(BasicIo& outIo) { if (!io_->isopen()) throw Error(20); if (!outIo.isopen()) throw Error(21); #ifdef DEBUG std::cout << "Exiv2::PsdImage::doWriteMetadata: Writing PSD file " << io_->path() << "\n"; std::cout << "Exiv2::PsdImage::doWriteMetadata: tmp file created " << outIo.path() << "\n"; #endif // Ensure that this is the correct image type if (!isPsdType(*io_, true)) { if (io_->error() || io_->eof()) throw Error(20); throw Error(22); } io_->seek(0, BasicIo::beg); // rewind DataBuf lbuf(4096); byte buf[8]; // Get Photoshop header from original file byte psd_head[26]; if (io_->read(psd_head, 26) != 26) throw Error(3, "Photoshop"); // Write Photoshop header data out to new PSD file if (outIo.write(psd_head, 26) != 26) throw Error(21); // Read colorDataLength from original PSD if (io_->read(buf, 4) != 4) throw Error(3, "Photoshop"); uint32_t colorDataLength = getULong(buf, bigEndian); // Write colorDataLength ul2Data(buf, colorDataLength, bigEndian); if (outIo.write(buf, 4) != 4) throw Error(21); #ifdef DEBUG std::cerr << std::dec << "colorDataLength: " << colorDataLength << "\n"; #endif // Copy colorData uint32_t readTotal = 0; long toRead = 0; while (readTotal < colorDataLength) { toRead = static_cast(colorDataLength - readTotal) < lbuf.size_ ? static_cast(colorDataLength - readTotal) : lbuf.size_; if (io_->read(lbuf.pData_, toRead) != toRead) throw Error(3, "Photoshop"); readTotal += toRead; if (outIo.write(lbuf.pData_, toRead) != toRead) throw Error(21); } if (outIo.error()) throw Error(21); uint32_t resLenOffset = io_->tell(); // remember for later update // Read length of all resource blocks from original PSD if (io_->read(buf, 4) != 4) throw Error(3, "Photoshop"); uint32_t oldResLength = getULong(buf, bigEndian); uint32_t newResLength = 0; // Write oldResLength (will be updated later) ul2Data(buf, oldResLength, bigEndian); if (outIo.write(buf, 4) != 4) throw Error(21); #ifdef DEBUG std::cerr << std::dec << "oldResLength: " << oldResLength << "\n"; #endif // Iterate over original resource blocks. // Replace or insert IPTC, EXIF and XMP // Original resource blocks assumed to be sorted ASC bool iptcDone = false; bool exifDone = false; bool xmpDone = false; while (oldResLength > 0) { if (io_->read(buf, 8) != 8) throw Error(3, "Photoshop"); // read resource type and ID uint32_t resourceType = getULong(buf, bigEndian); if (!Photoshop::isIrb(buf, 4)) { throw Error(3, "Photoshop"); // bad resource type } uint16_t resourceId = getUShort(buf + 4, bigEndian); uint32_t resourceNameLength = buf[6]; uint32_t adjResourceNameLen = resourceNameLength & ~1; unsigned char resourceNameFirstChar = buf[7]; // read rest of resource name, plus any padding DataBuf resName(256); if ( io_->read(resName.pData_, adjResourceNameLen) != static_cast(adjResourceNameLen)) throw Error(3, "Photoshop"); // read resource size (actual length w/o padding!) if (io_->read(buf, 4) != 4) throw Error(3, "Photoshop"); uint32_t resourceSize = getULong(buf, bigEndian); uint32_t pResourceSize = (resourceSize + 1) & ~1; // padded resource size uint32_t curOffset = io_->tell(); // Write IPTC_NAA resource block if ((resourceId == kPhotoshopResourceID_IPTC_NAA || resourceId > kPhotoshopResourceID_IPTC_NAA) && iptcDone == false) { newResLength += writeIptcData(iptcData_, outIo); iptcDone = true; } // Write ExifInfo resource block else if ((resourceId == kPhotoshopResourceID_ExifInfo || resourceId > kPhotoshopResourceID_ExifInfo) && exifDone == false) { newResLength += writeExifData(exifData_, outIo); exifDone = true; } // Write XMPpacket resource block else if ((resourceId == kPhotoshopResourceID_XMPPacket || resourceId > kPhotoshopResourceID_XMPPacket) && xmpDone == false) { newResLength += writeXmpData(xmpData_, outIo); xmpDone = true; } // Copy all other resource blocks if ( resourceId != kPhotoshopResourceID_IPTC_NAA && resourceId != kPhotoshopResourceID_ExifInfo && resourceId != kPhotoshopResourceID_XMPPacket) { #ifdef DEBUG std::cerr << std::hex << "copy : resourceType: " << resourceType << "\n"; std::cerr << std::hex << "copy : resourceId: " << resourceId << "\n"; std::cerr << std::dec; #endif // Copy resource block to new PSD file ul2Data(buf, resourceType, bigEndian); if (outIo.write(buf, 4) != 4) throw Error(21); us2Data(buf, resourceId, bigEndian); if (outIo.write(buf, 2) != 2) throw Error(21); // Write resource name as Pascal string buf[0] = resourceNameLength & 0x00ff; if (outIo.write(buf, 1) != 1) throw Error(21); buf[0] = resourceNameFirstChar; if (outIo.write(buf, 1) != 1) throw Error(21); if ( outIo.write(resName.pData_, adjResourceNameLen) != static_cast(adjResourceNameLen)) throw Error(21); ul2Data(buf, resourceSize, bigEndian); if (outIo.write(buf, 4) != 4) throw Error(21); readTotal = 0; toRead = 0; while (readTotal < pResourceSize) { toRead = static_cast(pResourceSize - readTotal) < lbuf.size_ ? static_cast(pResourceSize - readTotal) : lbuf.size_; if (io_->read(lbuf.pData_, toRead) != toRead) { throw Error(3, "Photoshop"); } readTotal += toRead; if (outIo.write(lbuf.pData_, toRead) != toRead) throw Error(21); } if (outIo.error()) throw Error(21); newResLength += pResourceSize + adjResourceNameLen + 12; } io_->seek(curOffset + pResourceSize, BasicIo::beg); oldResLength -= (12 + adjResourceNameLen + pResourceSize); } // Append IPTC_NAA resource block, if not yet written if (iptcDone == false) { newResLength += writeIptcData(iptcData_, outIo); iptcDone = true; } // Append ExifInfo resource block, if not yet written if (exifDone == false) { newResLength += writeExifData(exifData_, outIo); exifDone = true; } // Append XmpPacket resource block, if not yet written if (xmpDone == false) { newResLength += writeXmpData(xmpData_, outIo); xmpDone = true; } // Copy remaining data long readSize = 0; while ((readSize=io_->read(lbuf.pData_, lbuf.size_))) { if (outIo.write(lbuf.pData_, readSize) != readSize) throw Error(21); } if (outIo.error()) throw Error(21); // Update length of resources #ifdef DEBUG std::cerr << "newResLength: " << newResLength << "\n"; #endif outIo.seek(resLenOffset, BasicIo::beg); ul2Data(buf, newResLength, bigEndian); if (outIo.write(buf, 4) != 4) throw Error(21); } // PsdImage::doWriteMetadata uint32_t PsdImage::writeIptcData(const IptcData& iptcData, BasicIo& out) const { uint32_t resLength = 0; byte buf[8]; if (iptcData.count() > 0) { DataBuf rawIptc = IptcParser::encode(iptcData); if (rawIptc.size_ > 0) { #ifdef DEBUG std::cerr << std::hex << "write: resourceId: " << kPhotoshopResourceID_IPTC_NAA << "\n"; std::cerr << std::dec << "Writing IPTC_NAA: size: " << rawIptc.size_ << "\n"; #endif if (out.write(reinterpret_cast(Photoshop::irbId_[0]), 4) != 4) throw Error(21); us2Data(buf, kPhotoshopResourceID_IPTC_NAA, bigEndian); if (out.write(buf, 2) != 2) throw Error(21); us2Data(buf, 0, bigEndian); // NULL resource name if (out.write(buf, 2) != 2) throw Error(21); ul2Data(buf, rawIptc.size_, bigEndian); if (out.write(buf, 4) != 4) throw Error(21); // Write encoded Iptc data if (out.write(rawIptc.pData_, rawIptc.size_) != rawIptc.size_) throw Error(21); resLength += rawIptc.size_ + 12; if (rawIptc.size_ & 1) // even padding { buf[0] = 0; if (out.write(buf, 1) != 1) throw Error(21); resLength++; } } } return resLength; } // PsdImage::writeIptcData uint32_t PsdImage::writeExifData(const ExifData& exifData, BasicIo& out) { uint32_t resLength = 0; byte buf[8]; if (exifData.count() > 0) { Blob blob; ByteOrder bo = byteOrder(); if (bo == invalidByteOrder) { bo = littleEndian; setByteOrder(bo); } ExifParser::encode(blob, bo, exifData); if (blob.size() > 0) { #ifdef DEBUG std::cerr << std::hex << "write: resourceId: " << kPhotoshopResourceID_ExifInfo << "\n"; std::cerr << std::dec << "Writing ExifInfo: size: " << blob.size() << "\n"; #endif if (out.write(reinterpret_cast(Photoshop::irbId_[0]), 4) != 4) throw Error(21); us2Data(buf, kPhotoshopResourceID_ExifInfo, bigEndian); if (out.write(buf, 2) != 2) throw Error(21); us2Data(buf, 0, bigEndian); // NULL resource name if (out.write(buf, 2) != 2) throw Error(21); ul2Data(buf, static_cast(blob.size()), bigEndian); if (out.write(buf, 4) != 4) throw Error(21); // Write encoded Exif data if (out.write(&blob[0], static_cast(blob.size())) != static_cast(blob.size())) throw Error(21); resLength += static_cast(blob.size()) + 12; if (blob.size() & 1) // even padding { buf[0] = 0; if (out.write(buf, 1) != 1) throw Error(21); resLength++; } } } return resLength; } // PsdImage::writeExifData uint32_t PsdImage::writeXmpData(const XmpData& xmpData, BasicIo& out) const { std::string xmpPacket; uint32_t resLength = 0; byte buf[8]; #ifdef DEBUG std::cerr << "writeXmpFromPacket(): " << writeXmpFromPacket() << "\n"; #endif // writeXmpFromPacket(true); if (writeXmpFromPacket() == false) { if (XmpParser::encode(xmpPacket, xmpData) > 1) { #ifndef SUPPRESS_WARNINGS EXV_ERROR << "Failed to encode XMP metadata.\n"; #endif } } if (xmpPacket.size() > 0) { #ifdef DEBUG std::cerr << std::hex << "write: resourceId: " << kPhotoshopResourceID_XMPPacket << "\n"; std::cerr << std::dec << "Writing XMPPacket: size: " << xmpPacket.size() << "\n"; #endif if (out.write(reinterpret_cast(Photoshop::irbId_[0]), 4) != 4) throw Error(21); us2Data(buf, kPhotoshopResourceID_XMPPacket, bigEndian); if (out.write(buf, 2) != 2) throw Error(21); us2Data(buf, 0, bigEndian); // NULL resource name if (out.write(buf, 2) != 2) throw Error(21); ul2Data(buf, static_cast(xmpPacket.size()), bigEndian); if (out.write(buf, 4) != 4) throw Error(21); // Write XMPPacket if (out.write(reinterpret_cast(xmpPacket.data()), static_cast(xmpPacket.size())) != static_cast(xmpPacket.size())) throw Error(21); if (out.error()) throw Error(21); resLength += static_cast(xmpPacket.size()) + 12; if (xmpPacket.size() & 1) // even padding { buf[0] = 0; if (out.write(buf, 1) != 1) throw Error(21); resLength++; } } return resLength; } // PsdImage::writeXmpData // ************************************************************************* // free functions Image::AutoPtr newPsdInstance(BasicIo::AutoPtr io, bool /*create*/) { Image::AutoPtr image(new PsdImage(io)); if (!image->good()) { image.reset(); } return image; } bool isPsdType(BasicIo& iIo, bool advance) { const int32_t len = 6; const unsigned char PsdHeader[6] = { '8', 'B', 'P', 'S', 0, 1 }; byte buf[len]; iIo.read(buf, len); if (iIo.error() || iIo.eof()) { return false; } bool matched = (memcmp(buf, PsdHeader, len) == 0); if (!advance || !matched) { iIo.seek(-len, BasicIo::cur); } return matched; } } // namespace Exiv2 exiv2-0.23/src/canonmn.cpp0000644000175000017500000023777611732641407015266 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /* File: canonmn.cpp Version: $Rev: 2681 $ Author(s): Andreas Huggel (ahu) David Cannings (dc) Andi Clemens (ac) */ // ***************************************************************************** #include "rcsid_int.hpp" EXIV2_RCSID("@(#) $Id: canonmn.cpp 2681 2012-03-22 15:19:35Z ahuggel $") // ***************************************************************************** // included header files #include "types.hpp" #include "canonmn_int.hpp" #include "tags_int.hpp" #include "value.hpp" #include "exif.hpp" #include "i18n.h" // NLS support. // + standard includes #include #include #include #include #include #include #include #include // ***************************************************************************** // class member definitions namespace Exiv2 { namespace Internal { //! OffOn, multiple tags extern const TagDetails canonOffOn[] = { { 0, N_("Off") }, { 1, N_("On") } }; //! Special treatment pretty-print function for non-unique lens ids. std::ostream& printCsLensByFocalLength(std::ostream& os, const Value& value, const ExifData* metadata); //! ModelId, tag 0x0010 extern const TagDetails canonModelId[] = { { 0x1010000, N_("PowerShot A30") }, { 0x1040000, N_("PowerShot S300 / Digital IXUS 300 / IXY Digital 300") }, { 0x1060000, N_("PowerShot A20") }, { 0x1080000, N_("PowerShot A10") }, { 0x1090000, N_("PowerShot S110 / Digital IXUS v / IXY Digital 200") }, { 0x1100000, N_("PowerShot G2") }, { 0x1110000, N_("PowerShot S40") }, { 0x1120000, N_("PowerShot S30") }, { 0x1130000, N_("PowerShot A40") }, { 0x1140000, N_("EOS D30") }, { 0x1150000, N_("PowerShot A100") }, { 0x1160000, N_("PowerShot S200 / Digital IXUS v2 / IXY Digital 200a") }, { 0x1170000, N_("PowerShot A200") }, { 0x1180000, N_("PowerShot S330 / Digital IXUS 330 / IXY Digital 300a") }, { 0x1190000, N_("PowerShot G3") }, { 0x1210000, N_("PowerShot S45") }, { 0x1230000, N_("PowerShot SD100 / Digital IXUS II / IXY Digital 30") }, { 0x1240000, N_("PowerShot S230 / Digital IXUS v3 / IXY Digital 320") }, { 0x1250000, N_("PowerShot A70") }, { 0x1260000, N_("PowerShot A60") }, { 0x1270000, N_("PowerShot S400 / Digital IXUS 400 / IXY Digital 400") }, { 0x1290000, N_("PowerShot G5") }, { 0x1300000, N_("PowerShot A300") }, { 0x1310000, N_("PowerShot S50") }, { 0x1340000, N_("PowerShot A80") }, { 0x1350000, N_("PowerShot SD10 / Digital IXUS i / IXY Digital L") }, { 0x1360000, N_("PowerShot S1 IS") }, { 0x1370000, N_("PowerShot Pro1") }, { 0x1380000, N_("PowerShot S70") }, { 0x1390000, N_("PowerShot S60") }, { 0x1400000, N_("PowerShot G6") }, { 0x1410000, N_("PowerShot S500 / Digital IXUS 500 / IXY Digital 500") }, { 0x1420000, N_("PowerShot A75") }, { 0x1440000, N_("PowerShot SD110 / Digital IXUS IIs / IXY Digital 30a") }, { 0x1450000, N_("PowerShot A400") }, { 0x1470000, N_("PowerShot A310") }, { 0x1490000, N_("PowerShot A85") }, { 0x1520000, N_("PowerShot S410 / Digital IXUS 430 / IXY Digital 450") }, { 0x1530000, N_("PowerShot A95") }, { 0x1540000, N_("PowerShot SD300 / Digital IXUS 40 / IXY Digital 50") }, { 0x1550000, N_("PowerShot SD200 / Digital IXUS 30 / IXY Digital 40") }, { 0x1560000, N_("PowerShot A520") }, { 0x1570000, N_("PowerShot A510") }, { 0x1590000, N_("PowerShot SD20 / Digital IXUS i5 / IXY Digital L2") }, { 0x1640000, N_("PowerShot S2 IS") }, { 0x1650000, N_("PowerShot SD430 / IXUS Wireless / IXY Wireless") }, { 0x1660000, N_("PowerShot SD500 / Digital IXUS 700 / IXY Digital 600") }, { 0x1668000, N_("EOS D60") }, { 0x1700000, N_("PowerShot SD30 / Digital IXUS i zoom / IXY Digital L3") }, { 0x1740000, N_("PowerShot A430") }, { 0x1750000, N_("PowerShot A410") }, { 0x1760000, N_("PowerShot S80") }, { 0x1780000, N_("PowerShot A620") }, { 0x1790000, N_("PowerShot A610") }, { 0x1800000, N_("PowerShot SD630 / Digital IXUS 65 / IXY Digital 80") }, { 0x1810000, N_("PowerShot SD450 / Digital IXUS 55 / IXY Digital 60") }, { 0x1820000, N_("PowerShot TX1") }, { 0x1870000, N_("PowerShot SD400 / Digital IXUS 50 / IXY Digital 55") }, { 0x1880000, N_("PowerShot A420") }, { 0x1890000, N_("PowerShot SD900 / Digital IXUS 900 Ti / IXY Digital 1000") }, { 0x1900000, N_("PowerShot SD550 / Digital IXUS 750 / IXY Digital 700") }, { 0x1920000, N_("PowerShot A700") }, { 0x1940000, N_("PowerShot SD700 IS / Digital IXUS 800 IS / IXY Digital 800 IS") }, { 0x1950000, N_("PowerShot S3 IS") }, { 0x1960000, N_("PowerShot A540") }, { 0x1970000, N_("PowerShot SD600 / Digital IXUS 60 / IXY Digital 70") }, { 0x1980000, N_("PowerShot G7") }, { 0x1990000, N_("PowerShot A530") }, { 0x2000000, N_("PowerShot SD800 IS / Digital IXUS 850 IS / IXY Digital 900 IS") }, { 0x2010000, N_("PowerShot SD40 / Digital IXUS i7 / IXY Digital L4") }, { 0x2020000, N_("PowerShot A710 IS") }, { 0x2030000, N_("PowerShot A640") }, { 0x2040000, N_("PowerShot A630") }, { 0x2090000, N_("PowerShot S5 IS") }, { 0x2100000, N_("PowerShot A460") }, { 0x2120000, N_("PowerShot SD850 IS / Digital IXUS 950 IS") }, { 0x2130000, N_("PowerShot A570 IS") }, { 0x2140000, N_("PowerShot A560") }, { 0x2150000, N_("PowerShot SD750 / Digital IXUS 75 / IXY Digital 90") }, { 0x2160000, N_("PowerShot SD1000 / Digital IXUS 70 / IXY Digital 10") }, { 0x2180000, N_("PowerShot A550") }, { 0x2190000, N_("PowerShot A450") }, { 0x3010000, N_("PowerShot Pro90 IS") }, { 0x4040000, N_("PowerShot G1") }, { 0x6040000, N_("PowerShot S100 / Digital IXUS / IXY Digital") }, { 0x4007d675, N_("HV10") }, { 0x4007d777, N_("iVIS DC50") }, { 0x4007d778, N_("iVIS HV20") }, { 0x80000001, N_("EOS-1D") }, { 0x80000167, N_("EOS-1DS") }, { 0x80000168, N_("EOS 10D") }, { 0x80000169, N_("EOS-1D Mark III") }, { 0x80000170, N_("EOS Digital Rebel / 300D / Kiss Digital") }, { 0x80000174, N_("EOS-1D Mark II") }, { 0x80000175, N_("EOS 20D") }, { 0x80000188, N_("EOS-1Ds Mark II") }, { 0x80000189, N_("EOS Digital Rebel XT / 350D / Kiss Digital N") }, { 0x80000213, N_("EOS 5D") }, { 0x80000232, N_("EOS-1D Mark II N") }, { 0x80000234, N_("EOS 30D") }, { 0x80000236, N_("EOS Digital Rebel XTi / 400D / Kiss Digital X") }, { 0x80000250, N_("EOS 7D") }, { 0x80000252, N_("EOS Rebel T1i / 500D / Kiss X3") }, { 0x80000254, N_("EOS Rebel XS / 1000D / Kiss F") }, { 0x80000261, N_("EOS 50D") }, { 0x80000270, N_("EOS Rebel T2i / 550D / Kiss X4") }, { 0x80000281, N_("EOS-1D Mark IV") }, }; //! SerialNumberFormat, tag 0x0015 extern const TagDetails canonSerialNumberFormat[] = { { 0x90000000, N_("Format 1") }, { 0xa0000000, N_("Format 2") }, }; //! SuperMacro, tag 0x001a extern const TagDetails canonSuperMacro[] = { { 0, N_("Off") }, { 1, N_("On (1)") }, { 2, N_("On (2)") } }; //! ColorSpace, tag 0x00b4 extern const TagDetails canonColorSpace[] = { { 1, N_("sRGB") }, { 2, N_("Adobe RGB") } }; // Canon MakerNote Tag Info const TagInfo CanonMakerNote::tagInfo_[] = { TagInfo(0x0000, "0x0000", "0x0000", N_("Unknown"), canonId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0001, "CameraSettings", N_("Camera Settings"), N_("Various camera settings"), canonId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0002, "FocalLength", N_("Focal Length"), N_("Focal length"), canonId, makerTags, unsignedShort, -1, printFocalLength), TagInfo(0x0003, "0x0003", "0x0003", N_("Unknown"), canonId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0004, "ShotInfo", N_("Shot Info"), N_("Shot information"), canonId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0005, "Panorama", N_("Panorama"), N_("Panorama"), canonId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0006, "ImageType", N_("Image Type"), N_("Image type"), canonId, makerTags, asciiString, -1, printValue), TagInfo(0x0007, "FirmwareVersion", N_("Firmware Version"), N_("Firmware version"), canonId, makerTags, asciiString, -1, printValue), TagInfo(0x0008, "FileNumber", N_("File Number"), N_("File number"), canonId, makerTags, unsignedLong, -1, print0x0008), TagInfo(0x0009, "OwnerName", N_("Owner Name"), N_("Owner Name"), canonId, makerTags, asciiString, -1, printValue), TagInfo(0x000c, "SerialNumber", N_("Serial Number"), N_("Camera serial number"), canonId, makerTags, unsignedLong, -1, print0x000c), TagInfo(0x000d, "CameraInfo", N_("Camera Info"), N_("Camera info"), canonId, makerTags, unsignedShort, -1, printValue), TagInfo(0x000f, "CustomFunctions", N_("Custom Functions"), N_("Custom Functions"), canonId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0010, "ModelID", N_("ModelID"), N_("Model ID"), canonId, makerTags, unsignedLong, -1, EXV_PRINT_TAG(canonModelId)), TagInfo(0x0012, "PictureInfo", N_("Picture Info"), N_("Picture info"), canonId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0013, "ThumbnailImageValidArea", N_("Thumbnail Image Valid Area"), N_("Thumbnail image valid area"), canonId, makerTags, signedShort, -1, printValue), TagInfo(0x0015, "SerialNumberFormat", N_("Serial Number Format"), N_("Serial number format"), canonId, makerTags, unsignedLong, -1, EXV_PRINT_TAG(canonSerialNumberFormat)), TagInfo(0x001a, "SuperMacro", N_("Super Macro"), N_("Super macro"), canonId, makerTags, signedShort, -1, EXV_PRINT_TAG(canonSuperMacro)), TagInfo(0x0026, "AFInfo", N_("AF Info"), N_("AF info"), canonId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0083, "OriginalDecisionDataOffset", N_("Original Decision Data Offset"), N_("Original decision data offset"), canonId, makerTags, signedLong, -1, printValue), TagInfo(0x00a4, "WhiteBalanceTable", N_("White Balance Table"), N_("White balance table"), canonId, makerTags, unsignedShort, -1, printValue), TagInfo(0x0095, "LensModel", N_("LensModel"), N_("LensModel"), canonId, makerTags, asciiString, -1, printValue), TagInfo(0x0096, "InternalSerialNumber", N_("Internal Serial Number"), N_("Internal serial number"), canonId, makerTags, asciiString, -1, printValue), TagInfo(0x0097, "DustRemovalData", N_("Dust Removal Data"), N_("Dust removal data"), canonId, makerTags, asciiString, -1, printValue), TagInfo(0x0099, "CustomFunctions", N_("Custom Functions"), N_("Custom functions"), canonId, makerTags, unsignedShort, -1, printValue), TagInfo(0x00a0, "ProcessingInfo", N_("Processing Info"), N_("Processing info"), canonId, makerTags, unsignedShort, -1, printValue), TagInfo(0x00aa, "MeasuredColor", N_("Measured Color"), N_("Measured color"), canonId, makerTags, unsignedShort, -1, printValue), TagInfo(0x00b4, "ColorSpace", N_("ColorSpace"), N_("ColorSpace"), canonId, makerTags, signedShort, -1, EXV_PRINT_TAG(canonColorSpace)), TagInfo(0x00b5, "0x00b5", "0x00b5", N_("Unknown"), canonId, makerTags, unsignedShort, -1, printValue), TagInfo(0x00c0, "0x00c0", "0x00c0", N_("Unknown"), canonId, makerTags, unsignedShort, -1, printValue), TagInfo(0x00c1, "0x00c1", "0x00c1", N_("Unknown"), canonId, makerTags, unsignedShort, -1, printValue), TagInfo(0x00d0, "VRDOffset", N_("VRD Offset"), N_("VRD offset"), canonId, makerTags, unsignedLong, -1, printValue), TagInfo(0x00e0, "SensorInfo", N_("Sensor Info"), N_("Sensor info"), canonId, makerTags, unsignedShort, -1, printValue), TagInfo(0x4001, "ColorData", N_("Color Data"), N_("Color data"), canonId, makerTags, unsignedShort, -1, printValue), // End of list marker TagInfo(0xffff, "(UnknownCanonMakerNoteTag)", "(UnknownCanonMakerNoteTag)", N_("Unknown CanonMakerNote tag"), canonId, makerTags, asciiString, -1, printValue) }; const TagInfo* CanonMakerNote::tagList() { return tagInfo_; } //! Macro, tag 0x0001 extern const TagDetails canonCsMacro[] = { { 1, N_("On") }, { 2, N_("Off") } }; //! Quality, tag 0x0003 extern const TagDetails canonCsQuality[] = { { 1, N_("Economy") }, { 2, N_("Normal") }, { 3, N_("Fine") }, { 4, N_("RAW") }, { 5, N_("Superfine") }, { 130, N_("Normal Movie") } }; //! FlashMode, tag 0x0004 extern const TagDetails canonCsFlashMode[] = { { 0, N_("Off") }, { 1, N_("Auto") }, { 2, N_("On") }, { 3, N_("Red-eye") }, { 4, N_("Slow sync") }, { 5, N_("Auto + red-eye") }, { 6, N_("On + red-eye") }, { 16, N_("External") }, { 16, N_("External") } // To silence compiler warning }; //! DriveMode, tag 0x0005 extern const TagDetails canonCsDriveMode[] = { { 0, N_("Single / timer") }, { 1, N_("Continuous") }, { 2, N_("Movie") }, { 3, N_("Continuous, speed priority") }, { 4, N_("Continuous, low") }, { 5, N_("Continuous, high") } }; //! FocusMode, tag 0x0007 extern const TagDetails canonCsFocusMode[] = { { 0, N_("One shot AF") }, { 1, N_("AI servo AF") }, { 2, N_("AI focus AF") }, { 3, N_("Manual focus") }, { 4, N_("Single") }, { 5, N_("Continuous") }, { 6, N_("Manual focus") }, { 16, N_("Pan focus") }, { 16, N_("Pan focus") } // To silence compiler warning }; //! ImageSize, tag 0x000a extern const TagDetails canonCsImageSize[] = { { 0, N_("Large") }, { 1, N_("Medium") }, { 2, N_("Small") }, { 5, N_("Medium 1") }, { 6, N_("Medium 2") }, { 7, N_("Medium 3") } }; //! EasyMode, tag 0x000b extern const TagDetails canonCsEasyMode[] = { { 0, N_("Full auto") }, { 1, N_("Manual") }, { 2, N_("Landscape") }, { 3, N_("Fast shutter") }, { 4, N_("Slow shutter") }, { 5, N_("Night Scene") }, { 6, N_("Gray scale") }, { 7, N_("Sepia") }, { 8, N_("Portrait") }, { 9, N_("Sports") }, { 10, N_("Macro / close-up") }, { 11, N_("Black & white") }, { 12, N_("Pan focus") }, { 13, N_("Vivid") }, { 14, N_("Neutral") }, { 15, N_("Flash off") }, { 16, N_("Long shutter") }, { 17, N_("Super macro") }, { 18, N_("Foliage") }, { 19, N_("Indoor") }, { 20, N_("Fireworks") }, { 21, N_("Beach") }, { 22, N_("Underwater") }, { 23, N_("Snow") }, { 24, N_("Kids & pets") }, { 25, N_("Night SnapShot") }, { 26, N_("Digital macro") }, { 27, N_("My Colors") }, { 28, N_("Still image") } }; //! DigitalZoom, tag 0x000c extern const TagDetails canonCsDigitalZoom[] = { { 0, N_("None") }, { 1, "2x" }, { 2, "4x" }, { 3, N_("Other") }, { 3, N_("Other") } // To silence compiler warning }; //! Contrast, Saturation Sharpness, tags 0x000d, 0x000e, 0x000f extern const TagDetails canonCsLnh[] = { { 0xffff, N_("Low") }, { 0x0000, N_("Normal") }, { 0x0001, N_("High") } }; //! ISOSpeeds, tag 0x0010 extern const TagDetails canonCsISOSpeed[] = { { 0, N_("n/a") }, { 14, N_("Auto High") }, { 15, N_("Auto") }, { 16, "50" }, { 17, "100" }, { 18, "200" }, { 19, "400" }, { 20, "800" }, { 16464, "80" }, { 16484, "100" }, { 16584, "200" }, { 16784, "400" }, { 17184, "800" }, { 17984, "1600" }, { 19584, "3200" } }; //! MeteringMode, tag 0x0011 extern const TagDetails canonCsMeteringMode[] = { { 0, N_("Default") }, { 1, N_("Spot") }, { 2, N_("Average") }, { 3, N_("Evaluative") }, { 4, N_("Partial") }, { 5, N_("Center weighted") } }; //! FocusType, tag 0x0012 extern const TagDetails canonCsFocusType[] = { { 0, N_("Manual") }, { 1, N_("Auto") }, { 2, N_("Not known") }, { 3, N_("Macro") }, { 4, N_("Very close") }, { 5, N_("Close") }, { 6, N_("Middle range") }, { 7, N_("Far range") }, { 8, N_("Pan focus") }, { 9, N_("Super macro") }, { 10, N_("Infinity") } }; //! AFPoint, tag 0x0013 extern const TagDetails canonCsAfPoint[] = { { 0x2005, N_("Manual AF point selection") }, { 0x3000, N_("None (MF)") }, { 0x3001, N_("Auto-selected") }, { 0x3002, N_("Right") }, { 0x3003, N_("Center") }, { 0x3004, N_("Left") }, { 0x4001, N_("Auto AF point selection") } }; //! ExposureProgram, tag 0x0014 extern const TagDetails canonCsExposureProgram[] = { { 0, N_("Easy shooting (Auto)") }, { 1, N_("Program (P)") }, { 2, N_("Shutter priority (Tv)") }, { 3, N_("Aperture priority (Av)") }, { 4, N_("Manual (M)") }, { 5, N_("A-DEP") }, { 6, N_("M-DEP") } }; //! LensType, tag 0x0016 extern const TagDetails canonCsLensType[] = { { 1, "Canon EF 50mm f/1.8" }, { 2, "Canon EF 28mm f/2.8" }, { 3, "Canon EF 135mm f/2.8 Soft" }, { 4, "Canon EF 35-105mm f/3.5-4.5 or Sigma Lens" }, // 0 { 4, "Sigma UC Zoom 35-135mm f/4-5.6" }, // 1 { 5, "Canon EF 35-70mm f/3.5-4.5" }, { 6, "Canon EF 28-70mm f/3.5-4.5 or Sigma or Tokina Lens" }, // 0 { 6, "Sigma 18-50mm f/3.5-5.6 DC" }, // 1 { 6, "Sigma 18-125mm f/3.5-5.6 DC IF ASP" }, // 2 { 6, "Tokina AF193-2 19-35mm f/3.5-4.5" }, // 3 { 6, "Sigma 28-80mm f/3.5-5.6 II Macro" }, // 4 { 7, "Canon EF 100-300mm f/5.6L" }, { 8, "Canon EF 100-300mm f/5.6" }, // 0 { 8, "Sigma 70-300mm f/4-5.6 DG Macro" }, // 1 { 8, "Tokina AT-X242AF 24-200mm f/3.5-5.6" }, // 2 { 9, "Canon EF 70-210mm f/4" }, // 0 { 9, "Sigma 55-200mm f/4-5.6 DC" }, // 1 { 10, "Canon EF 50mm f/2.5 Macro" }, // 0 { 10, "Sigma 50mm f/2.8 EX" }, // 1 { 10, "Sigma 28mm f/1.8" }, // 2 { 10, "Sigma 105mm f/2.8 Macro EX" }, // 3 { 10, "Sigma 70mm f/2.8 EX DG Macro EF" }, // 4 { 11, "Canon EF 35mm f/2" }, { 13, "Canon EF 15mm f/2.8 Fisheye" }, { 14, "Canon EF 50-200mm f/3.5-4.5L" }, { 15, "Canon EF 50-200mm f/3.5-4.5" }, { 16, "Canon EF 35-135mm f/3.5-4.5" }, { 17, "Canon EF 35-70mm f/3.5-4.5A" }, { 18, "Canon EF 28-70mm f/3.5-4.5" }, { 20, "Canon EF 100-200mm f/4.5A" }, { 21, "Canon EF 80-200mm f/2.8L" }, { 22, "Canon EF 20-35mm f/2.8L" }, // 0 { 22, "Tokina AT-X280AF PRO 28-80mm f/2.8 Aspherical" }, // 1 { 23, "Canon EF 35-105mm f/3.5-4.5" }, { 24, "Canon EF 35-80mm f/4-5.6 Power Zoom" }, { 25, "Canon EF 35-80mm f/4-5.6 Power Zoom" }, { 26, "Canon EF 100mm f/2.8 Macro or Cosina or Tamron Lens" }, // 0 { 26, "Cosina 100mm f/3.5 Macro AF" }, // 1 { 26, "Tamron SP AF 90mm f/2.8 Di Macro" }, // 2 { 26, "Tamron SP AF 180mm f/3.5 Di Macro" }, // 3 { 26, "Carl Zeiss Planar T* 50mm f/1.4" }, // 4 { 27, "Canon EF 35-80mm f/4-5.6" }, { 28, "Canon EF 80-200mm f/4.5-5.6" }, // 0 { 28, "Tamron SP AF 28-105mm f/2.8 LD Aspherical IF" }, // 1 { 28, "Tamron SP AF 28-75mm f/2.8 XR Di LD Aspherical [IF] Macro" }, // 2 { 28, "Tamron AF 70-300mm f/4.5-5.6 Di LD 1:2 Macro Zoom" }, // 3 { 28, "Tamron AF Aspherical 28-200mm f/3.8-5.6" }, // 4 { 29, "Canon EF 50mm f/1.8 MkII" }, { 30, "Canon EF 35-105mm f/4.5-5.6" }, { 31, "Canon EF 75-300mm f/4-5.6" }, // 0 { 31, "Tamron SP AF 300mm f/2.8 LD IF" }, // 1 { 32, "Canon EF 24mm f/2.8" }, // 0 { 32, "Sigma 15mm f/2.8 EX Fisheye" }, // 1 { 33, "Voigtlander or Zeiss Lens" }, // 0 { 33, "Voigtlander Ultron 40mm f/2 SLII Aspherical" }, // 1 { 33, "Zeiss Distagon 35mm T* f/2 ZE" }, // 2 { 35, "Canon EF 35-80mm f/4-5.6" }, { 36, "Canon EF 38-76mm f/4.5-5.6" }, { 37, "Canon EF 35-80mm f/4-5.6" }, // 0 { 37, "Tamron 70-200mm f/2.8 Di LD IF Macro" }, // 1 { 37, "Tamron AF 28-300mm f/3.5-6.3 XR Di VC LD Aspherical [IF] Macro Model A20" }, // 2 { 37, "Tamron SP AF 17-50mm f/2.8 XR Di II VC LD Aspherical [IF] " }, // 3 { 37, "Tamron AF 18-270mm f/3.5-6.3 Di II VC LD Aspherical [IF] Macro" }, // 4 { 38, "Canon EF 80-200mm f/4.5-5.6" }, { 39, "Canon EF 75-300mm f/4-5.6" }, { 40, "Canon EF 28-80mm f/3.5-5.6" }, { 41, "Canon EF 28-90mm f/4-5.6" }, { 42, "Canon EF 28-200mm f/3.5-5.6" }, // 0 { 42, "Tamron AF 28-300mm f/3.5-6.3 XR Di VC LD Aspherical [IF] Macro Model A20" }, // 1 { 43, "Canon EF 28-105mm f/4-5.6" }, { 44, "Canon EF 90-300mm f/4.5-5.6" }, { 45, "Canon EF-S 18-55mm f/3.5-5.6" }, { 46, "Canon EF 28-90mm f/4-5.6" }, { 48, "Canon EF-S 18-55mm f/3.5-5.6 IS" }, { 49, "Canon EF-S 55-250mm f/4-5.6 IS" }, { 50, "Canon EF-S 18-200mm f/3.5-5.6 IS" }, { 51, "Canon EF-S 18-135mm f/3.5-5.6 IS" }, { 52, "Canon EF-S 18-55mm f/3.5-5.6 IS II" }, { 53, "Canon EF-S 18-55mm f/3.5-5.6 III" }, { 94, "Canon TS-E 17mm f/4L" }, { 95, "Canon TS-E 24.0mm f/3.5 L II" }, { 124, "Canon MP-E 65mm f/2.8 1-5x Macro Photo" }, { 125, "Canon TS-E 24mm f/3.5L" }, { 126, "Canon TS-E 45mm f/2.8" }, { 127, "Canon TS-E 90mm f/2.8" }, { 129, "Canon EF 300mm f/2.8L" }, { 130, "Canon EF 50mm f/1.0L" }, { 131, "Canon EF 28-80mm f/2.8-4L" }, // 0 { 131, "Sigma 8mm f/3.5 EX DG Circular Fisheye" }, // 1 { 131, "Sigma 17-35mm f/2.8-4 EX DG Aspherical HSM" }, // 2 { 131, "Sigma 17-70mm f/2.8-4.5 DC Macro" }, // 3 { 131, "Sigma APO 50-150mm f/2.8 EX DC HSM" }, // 4 { 131, "Sigma APO 120-300mm f/2.8 EX DG HSM" }, // 5 { 131, "Sigma 4.5mm F2.8 EX DC HSM Circular Fisheye" }, // 6 { 132, "Canon EF 1200mm f/5.6L" }, { 134, "Canon EF 600mm f/4L IS" }, { 135, "Canon EF 200mm f/1.8L" }, { 136, "Canon EF 300mm f/2.8L" }, { 137, "Canon EF 85mm f/1.2L" }, // 0 { 137, "Sigma 18-50mm f/2.8-4.5 DC OS HSM" }, // 1 { 137, "Sigma 50-200mm f/4-5.6 DC OS HSM" }, // 2 { 137, "Sigma 18-250mm f/3.5-6.3 DC OS HSM" }, // 3 { 137, "Sigma 24-70mm f/2.8 IF EX DG HSM" }, // 4 { 137, "Sigma 18-125mm f/3.8-5.6 DC OS HSM" }, // 5 { 137, "Sigma 17-70mm f/2.8-4 DC Macro OS HSM" }, // 6 { 137, "Sigma 17-50mm f/2.8 OS HSM" }, // 7 { 137, "Sigma 18-200mm f/3.5-6.3 II DC OS HSM" }, // 8 { 137, "Tamron AF 18-270mm f/3.5-6.3 Di II VC PZD" }, // 9 { 138, "Canon EF 28-80mm f/2.8-4L" }, { 139, "Canon EF 400mm f/2.8L" }, { 140, "Canon EF 500mm f/4.5L" }, { 141, "Canon EF 500mm f/4.5L" }, { 142, "Canon EF 300mm f/2.8L IS" }, { 143, "Canon EF 500mm f/4L IS" }, { 144, "Canon EF 35-135mm f/4-5.6 USM" }, { 145, "Canon EF 100-300mm f/4.5-5.6 USM" }, { 146, "Canon EF 70-210mm f/3.5-4.5 USM" }, { 147, "Canon EF 35-135mm f/4-5.6 USM" }, { 148, "Canon EF 28-80mm f/3.5-5.6 USM" }, { 149, "Canon EF 100mm f/2 USM" }, { 150, "Canon EF 14mm f/2.8L" }, // 0 { 150, "Sigma 20mm EX f/1.8" }, // 1 { 150, "Sigma 30mm f/1.4 DC HSM" }, // 2 { 150, "Sigma 24mm f/1.8 DG Macro EX" }, // 3 { 151, "Canon EF 200mm f/2.8L" }, { 152, "Canon EF 300mm f/4L IS" }, // 0 { 152, "Sigma 12-24mm f/4.5-5.6 EX DG ASPHERICAL HSM" }, // 1 { 152, "Sigma 14mm f/2.8 EX Aspherical HSM" }, // 2 { 152, "Sigma 10-20mm f/4-5.6" }, // 3 { 152, "Sigma 100-300mm f/4" }, // 4 { 153, "Canon EF 35-350mm f/3.5-5.6L" }, // 0 { 153, "Sigma 50-500mm f/4-6.3 APO HSM EX" }, // 1 { 153, "Tamron AF 28-300mm f/3.5-6.3 XR LD Aspherical [IF] Macro" }, // 2 { 153, "Tamron AF 18-200mm f/3.5-6.3 XR Di II LD Aspherical [IF] Macro Model A14" }, // 3 { 153, "Tamron 18-250mm f/3.5-6.3 Di II LD Aspherical [IF] Macro" }, // 4 { 154, "Canon EF 20mm f/2.8 USM" }, { 155, "Canon EF 85mm f/1.8 USM" }, { 156, "Canon EF 28-105mm f/3.5-4.5 USM" }, // 0 { 156, "Tamron SP AF 70-300mm F4-5.6 Di VC USD" }, // 1 { 160, "Canon EF 20-35mm f/3.5-4.5 USM" }, // 0 { 160, "Tamron AF 19-35mm f/3.5-4.5" }, // 1 { 160, "Tokina AT-X 124 AF 12-24mm f/4 DX" }, // 2 { 160, "Tokina AT-X 107 AF DX Fish-eye 10-17mm f/3.5-4.5" }, // 3 { 160, "Tokina AT-X 116 PRO DX AF 11-16mm f/2.8" }, // 4 { 161, "Canon EF 28-70mm f/2.8L" }, // 0 { 161, "Sigma 24-70mm EX f/2.8" }, // 1 { 161, "Sigma 28-70mm f/2.8 EX" }, // 2 { 161, "Tamron AF 17-50mm f/2.8 Di-II LD Aspherical" }, // 3 { 161, "Tamron 90mm f/2.8" }, // 4 { 162, "Canon EF 200mm f/2.8L" }, { 163, "Canon EF 300mm f/4L" }, { 164, "Canon EF 400mm f/5.6L" }, { 165, "Canon EF 70-200mm f/2.8 L" }, { 166, "Canon EF 70-200mm f/2.8 L + 1.4x" }, { 167, "Canon EF 70-200mm f/2.8 L + 2x" }, { 168, "Canon EF 28mm f/1.8 USM" }, { 169, "Canon EF 17-35mm f/2.8L" }, // 0 { 169, "Sigma 18-200mm f/3.5-6.3 DC OS" }, // 1 { 169, "Sigma 15-30mm f/3.5-4.5 EX DG Aspherical" }, // 2 { 169, "Sigma 18-50mm f/2.8 Macro" }, // 3 { 169, "Sigma 50mm f/1.4 EX DG HSM" }, // 4 { 169, "Sigma 85mm f/1.4 EX DG HSM" }, // 5 { 169, "Sigma 30mm f/1.4 EX DC HSM" }, // 6 { 170, "Canon EF 200mm f/2.8L II" }, { 171, "Canon EF 300mm f/4L" }, { 172, "Canon EF 400mm f/5.6L" }, { 173, "Canon EF 180mm Macro f/3.5L or Sigma Lens" }, // 0 { 173, "Sigma 180mm EX HSM Macro f/3.5" }, // 1 { 173, "Sigma APO Macro 150mm f/3.5 EX DG IF HSM" }, // 2 { 174, "Canon EF 135mm f/2L" }, // 0 { 174, "Sigma 70-200mm f/2.8 EX DG APO OS HSM" }, // 1 { 175, "Canon EF 400mm f/2.8L" }, { 176, "Canon EF 24-85mm f/3.5-4.5 USM" }, { 177, "Canon EF 300mm f/4L IS" }, { 178, "Canon EF 28-135mm f/3.5-5.6 IS" }, { 179, "Canon EF 24mm f/1.4L" }, { 180, "Canon EF 35mm f/1.4L" }, { 181, "Canon EF 100-400mm f/4.5-5.6L IS + 1.4x" }, { 182, "Canon EF 100-400mm f/4.5-5.6L IS + 2x" }, { 183, "Canon EF 100-400mm f/4.5-5.6L IS" }, { 184, "Canon EF 400mm f/2.8L + 2x" }, { 185, "Canon EF 600mm f/4L IS" }, { 186, "Canon EF 70-200mm f/4L" }, { 187, "Canon EF 70-200mm f/4L + 1.4x" }, { 188, "Canon EF 70-200mm f/4L + 2x" }, { 189, "Canon EF 70-200mm f/4L + 2.8x" }, { 190, "Canon EF 100mm f/2.8 Macro" }, { 191, "Canon EF 400mm f/4 DO IS" }, { 193, "Canon EF 35-80mm f/4-5.6 USM" }, { 194, "Canon EF 80-200mm f/4.5-5.6 USM" }, { 195, "Canon EF 35-105mm f/4.5-5.6 USM" }, { 196, "Canon EF 75-300mm f/4-5.6 USM" }, { 197, "Canon EF 75-300mm f/4-5.6 IS USM" }, { 198, "Canon EF 50mm f/1.4 USM" }, { 199, "Canon EF 28-80mm f/3.5-5.6 USM" }, { 200, "Canon EF 75-300mm f/4-5.6 USM" }, { 201, "Canon EF 28-80mm f/3.5-5.6 USM" }, { 202, "Canon EF 28-80mm f/3.5-5.6 USM IV" }, { 208, "Canon EF 22-55mm f/4-5.6 USM" }, { 209, "Canon EF 55-200mm f/4.5-5.6" }, { 210, "Canon EF 28-90mm f/4-5.6 USM" }, { 211, "Canon EF 28-200mm f/3.5-5.6 USM" }, { 212, "Canon EF 28-105mm f/4-5.6 USM" }, { 213, "Canon EF 90-300mm f/4.5-5.6 USM" }, { 214, "Canon EF-S 18-55mm f/3.5-5.6 USM" }, { 215, "Canon EF 55-200mm f/4.5-5.6 II USM" }, { 224, "Canon EF 70-200mm f/2.8L IS" }, { 225, "Canon EF 70-200mm f/2.8L IS + 1.4x" }, { 226, "Canon EF 70-200mm f/2.8L IS + 2x" }, { 227, "Canon EF 70-200mm f/2.8L IS + 2.8x" }, { 228, "Canon EF 28-105mm f/3.5-4.5 USM" }, { 229, "Canon EF 16-35mm f/2.8L" }, { 230, "Canon EF 24-70mm f/2.8L" }, { 231, "Canon EF 17-40mm f/4L" }, { 232, "Canon EF 70-300mm f/4.5-5.6 DO IS USM" }, { 233, "Canon EF 28-300mm f/3.5-5.6L IS" }, { 234, "Canon EF-S 17-85mm f4-5.6 IS USM" }, { 235, "Canon EF-S 10-22mm f/3.5-4.5 USM" }, { 236, "Canon EF-S 60mm f/2.8 Macro USM" }, { 237, "Canon EF 24-105mm f/4L IS" }, { 238, "Canon EF 70-300mm f/4-5.6 IS USM" }, { 239, "Canon EF 85mm f/1.2L II" }, { 240, "Canon EF-S 17-55mm f/2.8 IS USM" }, { 241, "Canon EF 50mm f/1.2L" }, { 242, "Canon EF 70-200mm f/4L IS" }, { 243, "Canon EF 70-200mm f/4L IS + 1.4x" }, { 244, "Canon EF 70-200mm f/4L IS + 2x" }, { 245, "Canon EF 70-200mm f/4L IS + 2.8x" }, { 246, "Canon EF 16-35mm f/2.8L II" }, { 247, "Canon EF 14mm f/2.8L II USM" }, { 248, "Canon EF 200mm f/2L IS" }, { 249, "Canon EF 800mm f/5.6L IS" }, { 250, "Canon EF 24 f/1.4L II" }, { 251, "Canon EF 70-200mm f/2.8L IS II USM" }, { 254, "Canon EF 100mm f/2.8L Macro IS USM" }, { 488, "Canon EF-S 15-85mm f/3.5-5.6 IS USM" }, { 489, "Canon EF 70-300mm f/4-5.6L IS USM" }, { 490, "Canon EF 8-15mm f/4L USM" }, { 491, "Canon EF 300mm f/2.8L IS II USM" } }; //! A lens id and a pretty-print function for special treatment of the id. struct LensIdFct { long id_; //!< Lens id PrintFct fct_; //!< Pretty-print function //! Comparison operator for find template bool operator==(long id) const { return id_ == id; } }; //! List of lens ids which require special treatment with the medicine const LensIdFct lensIdFct[] = { { 4, 0 }, // no known medicine { 6, printCsLensByFocalLength }, { 8, printCsLensByFocalLength }, { 9, printCsLensByFocalLength }, { 10, printCsLensByFocalLength }, // works partly { 22, printCsLensByFocalLength }, { 26, printCsLensByFocalLength }, // works partly { 28, printCsLensByFocalLength }, { 31, printCsLensByFocalLength }, { 32, printCsLensByFocalLength }, { 33, printCsLensByFocalLength }, // not tested { 37, printCsLensByFocalLength }, { 42, printCsLensByFocalLength }, { 131, printCsLensByFocalLength }, { 137, printCsLensByFocalLength }, // not tested { 150, printCsLensByFocalLength }, { 152, printCsLensByFocalLength }, { 153, printCsLensByFocalLength }, { 156, printCsLensByFocalLength }, { 160, printCsLensByFocalLength }, { 161, printCsLensByFocalLength }, { 169, printCsLensByFocalLength }, { 173, printCsLensByFocalLength }, // works partly { 174, printCsLensByFocalLength } // not tested }; //! FlashActivity, tag 0x001c extern const TagDetails canonCsFlashActivity[] = { { 0, N_("Did not fire") }, { 1, N_("Fired") } }; //! FlashDetails, tag 0x001d extern const TagDetailsBitmask canonCsFlashDetails[] = { { 0x4000, N_("External flash") }, { 0x2000, N_("Internal flash") }, { 0x0001, N_("Manual") }, { 0x0002, N_("TTL") }, { 0x0004, N_("A-TTL") }, { 0x0008, N_("E-TTL") }, { 0x0010, N_("FP sync enabled") }, { 0x0080, N_("2nd-curtain sync used") }, { 0x0800, N_("FP sync used") } }; //! FocusContinuous, tag 0x0020 extern const TagDetails canonCsFocusContinuous[] = { { 0, N_("Single") }, { 1, N_("Continuous") } }; //! AESetting, tag 0x0021 extern const TagDetails canonCsAESetting[] = { { 0, N_("Normal AE") }, { 1, N_("Exposure compensation") }, { 2, N_("AE lock") }, { 3, N_("AE lock + exposure compensation") }, { 4, N_("No AE") } }; //! ImageStabilization, tag 0x0022 extern const TagDetails canonCsImageStabilization[] = { { 0, N_("Off") }, { 1, N_("On") }, { 2, N_("On, shot only") } }; //! SpotMeteringMode, tag 0x0027 extern const TagDetails canonCsSpotMeteringMode[] = { { 0, N_("Center") }, { 1, N_("AF Point") } }; //! PhotoEffect, tag 0x0028 extern const TagDetails canonCsPhotoEffect[] = { { 0, N_("Off") }, { 1, N_("Vivid") }, { 2, N_("Neutral") }, { 3, N_("Smooth") }, { 4, N_("Sepia") }, { 5, N_("B&W") }, { 6, N_("Custom") }, { 100, N_("My color data") }, { 100, N_("My color data") } // To silence compiler warning }; //! ManualFlashOutput, tag 0x0029 extern const TagDetails canonCsManualFlashOutput[] = { { 0x0000, N_("n/a") }, { 0x0500, N_("Full") }, { 0x0502, N_("Medium") }, { 0x0504, N_("Low") }, { 0x7fff, N_("n/a") } }; //! SRAWQuality, tag 0x002e extern const TagDetails canonCsSRAWQuality[] = { { 0, N_("n/a") }, { 1, N_("sRAW1 (mRAW)") }, { 2, N_("sRAW2 (sRAW)") } }; // Canon Camera Settings Tag Info const TagInfo CanonMakerNote::tagInfoCs_[] = { TagInfo(0x0001, "Macro", N_("Macro"), N_("Macro mode"), canonCsId, makerTags, signedShort, 1, EXV_PRINT_TAG(canonCsMacro)), TagInfo(0x0002, "Selftimer", N_("Selftimer"), N_("Self timer"), canonCsId, makerTags, signedShort, 1, printCs0x0002), TagInfo(0x0003, "Quality", N_("Quality"), N_("Quality"), canonCsId, makerTags, signedShort, 1, EXV_PRINT_TAG(canonCsQuality)), TagInfo(0x0004, "FlashMode", N_("Flash Mode"), N_("Flash mode setting"), canonCsId, makerTags, signedShort, 1, EXV_PRINT_TAG(canonCsFlashMode)), TagInfo(0x0005, "DriveMode", N_("Drive Mode"), N_("Drive mode setting"), canonCsId, makerTags, signedShort, 1, EXV_PRINT_TAG(canonCsDriveMode)), TagInfo(0x0006, "0x0006", "0x0006", N_("Unknown"), canonCsId, makerTags, unsignedShort, 1, printValue), TagInfo(0x0007, "FocusMode", N_("Focus Mode"), N_("Focus mode setting"), canonCsId, makerTags, signedShort, 1, EXV_PRINT_TAG(canonCsFocusMode)), TagInfo(0x0008, "0x0008", "0x0008", N_("Unknown"), canonCsId, makerTags, signedShort, 1, printValue), TagInfo(0x0009, "0x0009", "0x0009", N_("Unknown"), canonCsId, makerTags, signedShort, 1, printValue), TagInfo(0x000a, "ImageSize", N_("Image Size"), N_("Image size"), canonCsId, makerTags, signedShort, 1, EXV_PRINT_TAG(canonCsImageSize)), TagInfo(0x000b, "EasyMode", N_("Easy Mode"), N_("Easy shooting mode"), canonCsId, makerTags, signedShort, 1, EXV_PRINT_TAG(canonCsEasyMode)), TagInfo(0x000c, "DigitalZoom", N_("Digital Zoom"), N_("Digital zoom"), canonCsId, makerTags, signedShort, 1, EXV_PRINT_TAG(canonCsDigitalZoom)), TagInfo(0x000d, "Contrast", N_("Contrast"), N_("Contrast setting"), canonCsId, makerTags, signedShort, 1, EXV_PRINT_TAG(canonCsLnh)), TagInfo(0x000e, "Saturation", N_("Saturation"), N_("Saturation setting"), canonCsId, makerTags, signedShort, 1, EXV_PRINT_TAG(canonCsLnh)), TagInfo(0x000f, "Sharpness", N_("Sharpness"), N_("Sharpness setting"), canonCsId, makerTags, signedShort, 1, EXV_PRINT_TAG(canonCsLnh)), TagInfo(0x0010, "ISOSpeed", N_("ISO Speed Mode"), N_("ISO speed setting"), canonCsId, makerTags, signedShort, 1, EXV_PRINT_TAG(canonCsISOSpeed)), TagInfo(0x0011, "MeteringMode", N_("Metering Mode"), N_("Metering mode setting"), canonCsId, makerTags, signedShort, 1, EXV_PRINT_TAG(canonCsMeteringMode)), TagInfo(0x0012, "FocusType", N_("Focus Type"), N_("Focus type setting"), canonCsId, makerTags, signedShort, 1, EXV_PRINT_TAG(canonCsFocusType)), TagInfo(0x0013, "AFPoint", N_("AF Point"), N_("AF point selected"), canonCsId, makerTags, signedShort, 1, EXV_PRINT_TAG(canonCsAfPoint)), TagInfo(0x0014, "ExposureProgram", N_("Exposure Program"), N_("Exposure mode setting"), canonCsId, makerTags, signedShort, 1, EXV_PRINT_TAG(canonCsExposureProgram)), TagInfo(0x0015, "0x0015", "0x0015", N_("Unknown"), canonCsId, makerTags, signedShort, 1, printValue), TagInfo(0x0016, "LensType", N_("Lens Type"), N_("Lens type"), canonCsId, makerTags, signedShort, 1, printCsLensType), TagInfo(0x0017, "Lens", N_("Lens"), N_("'long' and 'short' focal length of lens (in 'focal units') and 'focal units' per mm"), canonCsId, makerTags, unsignedShort, 3, printCsLens), TagInfo(0x0018, "ShortFocal", N_("Short Focal"), N_("Short focal"), canonCsId, makerTags, unsignedShort, 1, printValue), TagInfo(0x0019, "FocalUnits", N_("Focal Units"), N_("Focal units"), canonCsId, makerTags, signedShort, 1, printValue), TagInfo(0x001a, "MaxAperture", N_("Max Aperture"), N_("Max aperture"), canonCsId, makerTags, signedShort, 1, printSi0x0015), TagInfo(0x001b, "MinAperture", N_("Min Aperture"), N_("Min aperture"), canonCsId, makerTags, signedShort, 1, printSi0x0015), TagInfo(0x001c, "FlashActivity", N_("Flash Activity"), N_("Flash activity"), canonCsId, makerTags, signedShort, 1, EXV_PRINT_TAG(canonCsFlashActivity)), TagInfo(0x001d, "FlashDetails", N_("Flash Details"), N_("Flash details"), canonCsId, makerTags, signedShort, 1, EXV_PRINT_TAG_BITMASK(canonCsFlashDetails)), TagInfo(0x001e, "0x001e", "0x001e", N_("Unknown"), canonCsId, makerTags, signedShort, 1, printValue), TagInfo(0x001f, "0x001f", "0x001f", N_("Unknown"), canonCsId, makerTags, signedShort, 1, printValue), TagInfo(0x0020, "FocusContinuous", N_("Focus Continuous"), N_("Focus continuous setting"), canonCsId, makerTags, signedShort, 1, EXV_PRINT_TAG(canonCsFocusContinuous)), TagInfo(0x0021, "AESetting", N_("AESetting"), N_("AE setting"), canonCsId, makerTags, signedShort, 1, EXV_PRINT_TAG(canonCsAESetting)), TagInfo(0x0022, "ImageStabilization", N_("Image Stabilization"), N_("Image stabilization"), canonCsId, makerTags, signedShort, 1, EXV_PRINT_TAG(canonCsImageStabilization)), TagInfo(0x0023, "DisplayAperture", N_("Display Aperture"), N_("Display aperture"), canonCsId, makerTags, signedShort, 1, printValue), TagInfo(0x0024, "ZoomSourceWidth", N_("Zoom Source Width"), N_("Zoom source width"), canonCsId, makerTags, signedShort, 1, printValue), TagInfo(0x0025, "ZoomTargetWidth", N_("Zoom Target Width"), N_("Zoom target width"), canonCsId, makerTags, signedShort, 1, printValue), TagInfo(0x0026, "0x0026", "0x0026", N_("Unknown"), canonCsId, makerTags, signedShort, 1, printValue), TagInfo(0x0027, "SpotMeteringMode", N_("Spot Metering Mode"), N_("Spot metering mode"), canonCsId, makerTags, signedShort, 1, EXV_PRINT_TAG(canonCsSpotMeteringMode)), TagInfo(0x0028, "PhotoEffect", N_("Photo Effect"), N_("Photo effect"), canonCsId, makerTags, signedShort, 1, EXV_PRINT_TAG(canonCsPhotoEffect)), TagInfo(0x0029, "ManualFlashOutput", N_("Manual Flash Output"), N_("Manual flash output"), canonCsId, makerTags, signedShort, 1, EXV_PRINT_TAG(canonCsSRAWQuality)), TagInfo(0x002a, "ColorTone", N_("Color Tone"), N_("Color tone"), canonCsId, makerTags, signedShort, 1, printValue), TagInfo(0x002e, "SRAWQuality", N_("SRAW Quality Tone"), N_("SRAW quality"), canonCsId, makerTags, signedShort, 1, EXV_PRINT_TAG(canonCsSRAWQuality)), // End of list marker TagInfo(0xffff, "(UnknownCanonCsTag)", "(UnknownCanonCsTag)", N_("Unknown Canon Camera Settings 1 tag"), canonCsId, makerTags, unsignedShort, 1, printValue) }; const TagInfo* CanonMakerNote::tagListCs() { return tagInfoCs_; } //! WhiteBalance, multiple tags extern const TagDetails canonSiWhiteBalance[] = { { 0, N_("Auto") }, { 1, N_("Sunny") }, { 2, N_("Cloudy") }, { 3, N_("Tungsten") }, { 4, N_("Fluorescent") }, { 5, N_("Flash") }, { 6, N_("Custom") }, { 7, N_("Black & White") }, { 8, N_("Shade") }, { 9, N_("Manual Temperature (Kelvin)") }, { 10, N_("PC Set 1") }, { 11, N_("PC Set 2") }, { 12, N_("PC Set 3") }, { 14, N_("Daylight Fluorescent") }, { 15, N_("Custom 1") }, { 16, N_("Custom 2") }, { 17, N_("Underwater") }, { 18, N_("Custom 3") }, { 19, N_("Custom 3") }, { 20, N_("PC Set 4") }, { 21, N_("PC Set 5") } }; //! AFPointUsed, tag 0x000e extern const TagDetailsBitmask canonSiAFPointUsed[] = { { 0x0004, N_("left") }, { 0x0002, N_("center") }, { 0x0001, N_("right") } }; //! FlashBias, tag 0x000f extern const TagDetails canonSiFlashBias[] = { { 0xffc0, "-2 EV" }, { 0xffcc, "-1.67 EV" }, { 0xffd0, "-1.50 EV" }, { 0xffd4, "-1.33 EV" }, { 0xffe0, "-1 EV" }, { 0xffec, "-0.67 EV" }, { 0xfff0, "-0.50 EV" }, { 0xfff4, "-0.33 EV" }, { 0x0000, "0 EV" }, { 0x000c, "0.33 EV" }, { 0x0010, "0.50 EV" }, { 0x0014, "0.67 EV" }, { 0x0020, "1 EV" }, { 0x002c, "1.33 EV" }, { 0x0030, "1.50 EV" }, { 0x0034, "1.67 EV" }, { 0x0040, "2 EV" } }; // Canon Shot Info Tag const TagInfo CanonMakerNote::tagInfoSi_[] = { TagInfo(0x0001, "0x0001", "0x0001", N_("Unknown"), canonSiId, makerTags, unsignedShort, 1, printValue), TagInfo(0x0002, "ISOSpeed", N_("ISO Speed Used"), N_("ISO speed used"), canonSiId, makerTags, unsignedShort, 1, printSi0x0002), TagInfo(0x0003, "MeasuredEV", N_("Measured EV"), N_("Measured EV"), canonSiId, makerTags, unsignedShort, 1, printSi0x0003), TagInfo(0x0004, "TargetAperture", N_("Target Aperture"), N_("Target Aperture"), canonSiId, makerTags, unsignedShort, 1, printSi0x0015), TagInfo(0x0005, "TargetShutterSpeed", N_("Target Shutter Speed"), N_("Target shutter speed"), canonSiId, makerTags, unsignedShort, 1, printSi0x0016), TagInfo(0x0006, "0x0006", "0x0006", N_("Unknown"), canonSiId, makerTags, unsignedShort, 1, printValue), TagInfo(0x0007, "WhiteBalance", N_("White Balance"), N_("White balance setting"), canonSiId, makerTags, unsignedShort, 1, EXV_PRINT_TAG(canonSiWhiteBalance)), TagInfo(0x0008, "0x0008", "0x0008", N_("Unknown"), canonSiId, makerTags, unsignedShort, 1, printValue), TagInfo(0x0009, "Sequence", N_("Sequence"), N_("Sequence number (if in a continuous burst)"), canonSiId, makerTags, unsignedShort, 1, printSi0x0009), TagInfo(0x000a, "0x000a", "0x000a", N_("Unknown"), canonSiId, makerTags, unsignedShort, 1, printValue), TagInfo(0x000b, "0x000b", "0x000b", N_("Unknown"), canonSiId, makerTags, unsignedShort, 1, printValue), TagInfo(0x000c, "0x000c", "0x000c", N_("Unknown"), canonSiId, makerTags, unsignedShort, 1, printValue), TagInfo(0x000d, "0x000d", "0x000d", N_("Unknown"), canonSiId, makerTags, unsignedShort, 1, printValue), TagInfo(0x000e, "AFPointUsed", N_("AF Point Used"), N_("AF point used"), canonSiId, makerTags, unsignedShort, 1, printSi0x000e), TagInfo(0x000f, "FlashBias", N_("Flash Bias"), N_("Flash bias"), canonSiId, makerTags, unsignedShort, 1, EXV_PRINT_TAG(canonSiFlashBias)), TagInfo(0x0010, "0x0010", "0x0010", N_("Unknown"), canonSiId, makerTags, unsignedShort, 1, printValue), TagInfo(0x0011, "0x0011", "0x0011", N_("Unknown"), canonSiId, makerTags, unsignedShort, 1, printValue), TagInfo(0x0012, "0x0012", "0x0012", N_("Unknown"), canonSiId, makerTags, unsignedShort, 1, printValue), TagInfo(0x0013, "SubjectDistance", N_("Subject Distance"), N_("Subject distance (units are not clear)"), canonSiId, makerTags, unsignedShort, 1, printSi0x0013), TagInfo(0x0014, "0x0014", "0x0014", N_("Unknown"), canonSiId, makerTags, unsignedShort, 1, printValue), TagInfo(0x0015, "ApertureValue", N_("Aperture Value"), N_("Aperture"), canonSiId, makerTags, unsignedShort, 1, printSi0x0015), TagInfo(0x0016, "ShutterSpeedValue", N_("Shutter Speed Value"), N_("Shutter speed"), canonSiId, makerTags, unsignedShort, 1, printSi0x0016), TagInfo(0x0017, "MeasuredEV2", N_("Measured EV 2"), N_("Measured EV 2"), canonSiId, makerTags, unsignedShort, 1, printSi0x0017), TagInfo(0x0018, "0x0018", "0x0018", N_("Unknown"), canonSiId, makerTags, unsignedShort, 1, printValue), TagInfo(0x0019, "0x0019", "0x0019", N_("Unknown"), canonSiId, makerTags, unsignedShort, 1, printValue), TagInfo(0x001a, "0x001a", "0x001a", N_("Unknown"), canonSiId, makerTags, unsignedShort, 1, printValue), // End of list marker TagInfo(0xffff, "(UnknownCanonSiTag)", "(UnknownCanonSiTag)", N_("Unknown Canon Camera Settings 2 tag"), canonSiId, makerTags, unsignedShort, 1, printValue) }; const TagInfo* CanonMakerNote::tagListSi() { return tagInfoSi_; } //! PanoramaDirection, tag 0x0005 extern const TagDetails canonPaDirection[] = { { 0, N_("Left to right") }, { 1, N_("Right to left") }, { 2, N_("Bottom to top") }, { 3, N_("Top to bottom") }, { 4, N_("2x2 matrix (Clockwise)") } }; // Canon Panorama Info const TagInfo CanonMakerNote::tagInfoPa_[] = { TagInfo(0x0002, "PanoramaFrame", N_("Panorama Frame"), N_("Panorama frame number"), canonPaId, makerTags, unsignedShort, 1, printValue), TagInfo(0x0005, "PanoramaDirection", N_("Panorama Direction"), N_("Panorama direction"), canonPaId, makerTags, unsignedShort, 1, EXV_PRINT_TAG(canonPaDirection)), // End of list marker TagInfo(0xffff, "(UnknownCanonCs2Tag)", "(UnknownCanonCs2Tag)", N_("Unknown Canon Panorama tag"), canonPaId, makerTags, unsignedShort, 1, printValue) }; const TagInfo* CanonMakerNote::tagListPa() { return tagInfoPa_; } // Canon Custom Function Tag Info const TagInfo CanonMakerNote::tagInfoCf_[] = { TagInfo(0x0001, "NoiseReduction", N_("Noise Reduction"), N_("Long exposure noise reduction"), canonCfId, makerTags, unsignedShort, 1, printValue), TagInfo(0x0002, "ShutterAeLock", N_("Shutter Ae Lock"), N_("Shutter/AE lock buttons"), canonCfId, makerTags, unsignedShort, 1, printValue), TagInfo(0x0003, "MirrorLockup", N_("Mirror Lockup"), N_("Mirror lockup"), canonCfId, makerTags, unsignedShort, 1, printValue), TagInfo(0x0004, "ExposureLevelIncrements", N_("Exposure Level Increments"), N_("Tv/Av and exposure level"), canonCfId, makerTags, unsignedShort, 1, printValue), TagInfo(0x0005, "AFAssist", N_("AF Assist"), N_("AF assist light"), canonCfId, makerTags, unsignedShort, 1, printValue), TagInfo(0x0006, "FlashSyncSpeedAv", N_("Flash Sync Speed Av"), N_("Shutter speed in Av mode"), canonCfId, makerTags, unsignedShort, 1, printValue), TagInfo(0x0007, "AEBSequence", N_("AEB Sequence"), N_("AEB sequence/auto cancellation"), canonCfId, makerTags, unsignedShort, 1, printValue), TagInfo(0x0008, "ShutterCurtainSync", N_("Shutter Curtain Sync"), N_("Shutter curtain sync"), canonCfId, makerTags, unsignedShort, 1, printValue), TagInfo(0x0009, "LensAFStopButton", N_("Lens AF Stop Button"), N_("Lens AF stop button Fn. Switch"), canonCfId, makerTags, unsignedShort, 1, printValue), TagInfo(0x000a, "FillFlashAutoReduction", N_("Fill Flash Auto Reduction"), N_("Auto reduction of fill flash"), canonCfId, makerTags, unsignedShort, 1, printValue), TagInfo(0x000b, "MenuButtonReturn", N_("Menu Button Return"), N_("Menu button return position"), canonCfId, makerTags, unsignedShort, 1, printValue), TagInfo(0x000c, "SetButtonFunction", N_("Set Button Function"), N_("SET button func. when shooting"), canonCfId, makerTags, unsignedShort, 1, printValue), TagInfo(0x000d, "SensorCleaning", N_("Sensor Cleaning"), N_("Sensor cleaning"), canonCfId, makerTags, unsignedShort, 1, printValue), TagInfo(0x000e, "SuperimposedDisplay", N_("Superimposed Display"), N_("Superimposed display"), canonCfId, makerTags, unsignedShort, 1, printValue), TagInfo(0x000f, "ShutterReleaseNoCFCard", N_("Shutter Release No CF Card"), N_("Shutter Release W/O CF Card"), canonCfId, makerTags, unsignedShort, 1, printValue), // End of list marker TagInfo(0xffff, "(UnknownCanonCfTag)", "(UnknownCanonCfTag)", N_("Unknown Canon Custom Function tag"), canonCfId, makerTags, unsignedShort, 1, printValue) }; const TagInfo* CanonMakerNote::tagListCf() { return tagInfoCf_; } //! AFPointsUsed, tag 0x0016 extern const TagDetailsBitmask canonPiAFPointsUsed[] = { { 0x01, N_("right") }, { 0x02, N_("mid-right") }, { 0x04, N_("bottom") }, { 0x08, N_("center") }, { 0x10, N_("top") }, { 0x20, N_("mid-left") }, { 0x40, N_("left") } }; //! AFPointsUsed20D, tag 0x001a extern const TagDetailsBitmask canonPiAFPointsUsed20D[] = { { 0x001, N_("top") }, { 0x002, N_("upper-left") }, { 0x004, N_("upper-right") }, { 0x008, N_("left") }, { 0x010, N_("center") }, { 0x020, N_("right") }, { 0x040, N_("lower-left") }, { 0x080, N_("lower-right") }, { 0x100, N_("bottom") } }; // Canon Picture Info Tag const TagInfo CanonMakerNote::tagInfoPi_[] = { TagInfo(0x0002, "ImageWidth", N_("Image Width"), N_("Image width"), canonPiId, makerTags, unsignedShort, 1, printValue), TagInfo(0x0003, "ImageHeight", N_("Image Height"), N_("Image height"), canonPiId, makerTags, unsignedShort, 1, printValue), TagInfo(0x0004, "ImageWidthAsShot", N_("Image Width As Shot"), N_("Image width (as shot)"), canonPiId, makerTags, unsignedShort, 1, printValue), TagInfo(0x0005, "ImageHeightAsShot", N_("Image Height As Shot"), N_("Image height (as shot)"), canonPiId, makerTags, unsignedShort, 1, printValue), TagInfo(0x0016, "AFPointsUsed", N_("AF Points Used"), N_("AF points used"), canonPiId, makerTags, unsignedShort, 1, EXV_PRINT_TAG_BITMASK(canonPiAFPointsUsed)), TagInfo(0x001a, "AFPointsUsed20D", N_("AF Points Used 20D"), N_("AF points used (20D)"), canonPiId, makerTags, unsignedShort, 1, EXV_PRINT_TAG_BITMASK(canonPiAFPointsUsed20D)), // End of list marker TagInfo(0xffff, "(UnknownCanonPiTag)", "(UnknownCanonPiTag)", N_("Unknown Canon Picture Info tag"), canonPiId, makerTags, unsignedShort, 1, printValue) }; const TagInfo* CanonMakerNote::tagListPi() { return tagInfoPi_; } //! BracketMode, tag 0x0003 extern const TagDetails canonBracketMode[] = { { 0, N_("Off") }, { 1, N_("AEB") }, { 2, N_("FEB") }, { 3, N_("ISO") }, { 4, N_("WB") } }; //! RawJpgSize, tag 0x0007 extern const TagDetails canonRawJpgSize[] = { { 0, N_("Large") }, { 1, N_("Medium") }, { 2, N_("Small") }, { 5, N_("Medium 1") }, { 6, N_("Medium 2") }, { 7, N_("Medium 3") }, { 8, N_("Postcard") }, { 9, N_("Widescreen") }, { 129, N_("Medium Movie") }, { 130, N_("Small Movie") } }; //! NoiseReduction, tag 0x0008 extern const TagDetails canonNoiseReduction[] = { { 0, N_("Off") }, { 1, N_("On 1") }, { 2, N_("On 2") }, { 3, N_("On") }, { 4, N_("Auto") } }; //! WBBracketMode, tag 0x0009 extern const TagDetails canonWBBracketMode[] = { { 0, N_("Off") }, { 1, N_("On (shift AB)") }, { 2, N_("On (shift GM)") } }; //! FilterEffect, tag 0x000e extern const TagDetails canonFilterEffect[] = { { 0, N_("None") }, { 1, N_("Yellow") }, { 2, N_("Orange") }, { 3, N_("Red") }, { 4, N_("Green") } }; //! ToningEffect, tag 0x000e extern const TagDetails canonToningEffect[] = { { 0, N_("None") }, { 1, N_("Sepia") }, { 2, N_("Blue") }, { 3, N_("Purple") }, { 4, N_("Green") } }; // Canon File Info Tag const TagInfo CanonMakerNote::tagInfoFi_[] = { TagInfo(0x0001, "FileNumber", N_("File Number"), N_("File Number"), canonFiId, makerTags, unsignedLong, 1, printFiFileNumber), TagInfo(0x0003, "BracketMode", N_("Bracket Mode"), N_("Bracket Mode"), canonFiId, makerTags, signedShort, 1, EXV_PRINT_TAG(canonBracketMode)), TagInfo(0x0004, "BracketValue", N_("Bracket Value"), N_("Bracket Value"), canonFiId, makerTags, signedShort, 1, printValue), TagInfo(0x0005, "BracketShotNumber", N_("Bracket Shot Number"), N_("Bracket Shot Number"), canonFiId, makerTags, signedShort, 1, printValue), TagInfo(0x0006, "RawJpgQuality", N_("Raw Jpg Quality"), N_("Raw Jpg Quality"), canonFiId, makerTags, signedShort, 1, EXV_PRINT_TAG(canonCsQuality)), TagInfo(0x0007, "RawJpgSize", N_("Raw Jpg Size"), N_("Raw Jpg Size"), canonFiId, makerTags, signedShort, 1, EXV_PRINT_TAG(canonRawJpgSize)), TagInfo(0x0008, "NoiseReduction", N_("Noise Reduction"), N_("Noise Reduction"), canonFiId, makerTags, signedShort, 1, EXV_PRINT_TAG(canonNoiseReduction)), TagInfo(0x0009, "WBBracketMode", N_("WB Bracket Mode"), N_("WB Bracket Mode"), canonFiId, makerTags, signedShort, 1, EXV_PRINT_TAG(canonWBBracketMode)), TagInfo(0x000c, "WBBracketValueAB", N_("WB Bracket Value AB"), N_("WB Bracket Value AB"), canonFiId, makerTags, signedShort, 1, printValue), TagInfo(0x000d, "WBBracketValueGM", N_("WB Bracket Value GM"), N_("WB Bracket Value GM"), canonFiId, makerTags, signedShort, 1, printValue), TagInfo(0x000e, "FilterEffect", N_("Filter Effect"), N_("Filter Effect"), canonFiId, makerTags, signedShort, 1, EXV_PRINT_TAG(canonFilterEffect)), TagInfo(0x000f, "ToningEffect", N_("Toning Effect"), N_("Toning Effect"), canonFiId, makerTags, signedShort, 1, EXV_PRINT_TAG(canonToningEffect)), TagInfo(0x0010, "MacroMagnification", N_("Macro Magnification"), N_("Macro magnification"), canonFiId, makerTags, signedShort, 1, printValue), TagInfo(0x0013, "LiveViewShooting", N_("Live View Shooting"), N_("Live view shooting"), canonFiId, makerTags, signedShort, 1, EXV_PRINT_TAG(canonOffOn)), TagInfo(0x0019, "FlashExposureLock", N_("Flash Exposure Lock"), N_("Flash exposure lock"), canonFiId, makerTags, signedShort, 1, EXV_PRINT_TAG(canonOffOn)), // End of list marker TagInfo(0xffff, "(UnknownCanonFiTag)", "(UnknownCanonFiTag)", N_("Unknown Canon File Info tag"), canonFiId, makerTags, signedShort, 1, printValue) }; const TagInfo* CanonMakerNote::tagListFi() { return tagInfoFi_; } //! Tone Curve Values extern const TagDetails canonToneCurve[] = { { 0, N_("Standard") }, { 1, N_("Manual") }, { 2, N_("Custom") } }; //! Sharpness Frequency Values extern const TagDetails canonSharpnessFrequency[] = { { 0, N_("n/a") }, { 1, N_("Lowest") }, { 2, N_("Low") }, { 3, N_("Standard") }, { 4, N_("High") }, { 5, N_("Highest") } }; //! PictureStyle Values extern const TagDetails canonPictureStyle[] = { { 0x00, N_("None") }, { 0x01, N_("Standard") }, { 0x02, N_("Portrait") }, { 0x03, N_("High Saturation") }, { 0x04, N_("Adobe RGB") }, { 0x05, N_("Low Saturation") }, { 0x06, N_("CM Set 1") }, { 0x07, N_("CM Set 2") }, { 0x21, N_("User Def. 1") }, { 0x22, N_("User Def. 2") }, { 0x23, N_("User Def. 3") }, { 0x41, N_("PC 1") }, { 0x42, N_("PC 2") }, { 0x43, N_("PC 3") }, { 0x81, N_("Standard") }, { 0x82, N_("Portrait") }, { 0x83, N_("Landscape") }, { 0x84, N_("Neutral") }, { 0x85, N_("Faithful") }, { 0x86, N_("Monochrome") }, }; // Canon Processing Info Tag const TagInfo CanonMakerNote::tagInfoPr_[] = { TagInfo(0x0001, "ToneCurve", N_("ToneCurve"), N_("Tone curve"), canonPrId, makerTags, signedShort, 1, EXV_PRINT_TAG(canonToneCurve)), TagInfo(0x0002, "Sharpness", N_("Sharpness"), N_("Sharpness"), canonPrId, makerTags, signedShort, 1, printValue), TagInfo(0x0003, "SharpnessFrequency", N_("SharpnessFrequency"), N_("Sharpness frequency"), canonPrId, makerTags, signedShort, 1, EXV_PRINT_TAG(canonSharpnessFrequency)), TagInfo(0x0004, "SensorRedLevel", N_("SensorRedLevel"), N_("Sensor red level"), canonPrId, makerTags, signedShort, 1, printValue), TagInfo(0x0005, "SensorBlueLevel", N_("SensorBlueLevel"), N_("Sensor blue level"), canonPrId, makerTags, signedShort, 1, printValue), TagInfo(0x0006, "WhiteBalanceRed", N_("WhiteBalanceRed"), N_("White balance red"), canonPrId, makerTags, signedShort, 1, printValue), TagInfo(0x0007, "WhiteBalanceBlue", N_("WhiteBalanceBlue"), N_("White balance blue"), canonPrId, makerTags, signedShort, 1, printValue), TagInfo(0x0008, "WhiteBalance", N_("WhiteBalance"), N_("White balance"), canonPrId, makerTags, signedShort, 1, EXV_PRINT_TAG(canonSiWhiteBalance)), TagInfo(0x0009, "ColorTemperature", N_("ColorTemperature"), N_("Color Temperature"), canonPrId, makerTags, signedShort, 1, printValue), TagInfo(0x000a, "PictureStyle", N_("PictureStyle"), N_("Picture style"), canonPrId, makerTags, signedShort, 1, EXV_PRINT_TAG(canonPictureStyle)), TagInfo(0x000b, "DigitalGain", N_("DigitalGain"), N_("Digital gain"), canonPrId, makerTags, signedShort, 1, printValue), TagInfo(0x000c, "WBShiftAB", N_("WBShiftAB"), N_("WBShift AB"), canonPrId, makerTags, signedShort, 1, printValue), TagInfo(0x000d, "WBShiftGM", N_("WBShiftGM"), N_("WB Shift GM"), canonPrId, makerTags, signedShort, 1, printValue), TagInfo(0xffff, "(UnknownCanonPrTag)", "(UnknownCanonPrTag)", N_("Unknown Canon Processing Info tag"), canonPrId, makerTags, signedShort, 1, printValue) }; const TagInfo* CanonMakerNote::tagListPr() { return tagInfoPr_; } std::ostream& CanonMakerNote::printFiFileNumber(std::ostream& os, const Value& value, const ExifData* metadata) { if ( !metadata || value.typeId() != unsignedLong || value.count() == 0) return os << "(" << value << ")"; ExifData::const_iterator pos = metadata->findKey(ExifKey("Exif.Image.Model")); if (pos == metadata->end()) return os << "(" << value << ")"; // Ported from Exiftool std::string model = pos->toString(); if ( model.find("20D") != std::string::npos || model.find("350D") != std::string::npos || model.substr(model.size() - 8, 8) == "REBEL XT" || model.find("Kiss Digital N") != std::string::npos) { uint32_t val = value.toLong(); uint32_t dn = (val & 0xffc0) >> 6; uint32_t fn = ((val >> 16) & 0xff) + ((val & 0x3f) << 8); return os << std::dec << dn << "-" << std::setw(4) << std::setfill('0') << fn; } if ( model.find("30D") != std::string::npos || model.find("400D") != std::string::npos || model.find("REBEL XTi") != std::string::npos || model.find("Kiss Digital X") != std::string::npos || model.find("K236") != std::string::npos) { uint32_t val = value.toLong(); uint32_t dn = (val & 0xffc00) >> 10; while (dn < 100) dn += 0x40; uint32_t fn = ((val & 0x3ff) << 4) + ((val >> 20) & 0x0f); return os << std::dec << dn << "-" << std::setw(4) << std::setfill('0') << fn; } return os << "(" << value << ")"; } std::ostream& CanonMakerNote::printFocalLength(std::ostream& os, const Value& value, const ExifData* metadata) { if ( !metadata || value.count() < 4 || value.typeId() != unsignedShort) { return os << value; } ExifKey key("Exif.CanonCs.Lens"); ExifData::const_iterator pos = metadata->findKey(key); if ( pos != metadata->end() && pos->value().count() >= 3 && pos->value().typeId() == unsignedShort) { float fu = pos->value().toFloat(2); if (fu != 0.0) { float fl = value.toFloat(1) / fu; std::ostringstream oss; oss.copyfmt(os); os << std::fixed << std::setprecision(1); os << fl << " mm"; os.copyfmt(oss); return os; } } return os << value; } std::ostream& CanonMakerNote::print0x0008(std::ostream& os, const Value& value, const ExifData*) { std::string n = value.toString(); if (n.length() < 4) return os << "(" << n << ")"; return os << n.substr(0, n.length() - 4) << "-" << n.substr(n.length() - 4); } std::ostream& CanonMakerNote::print0x000c(std::ostream& os, const Value& value, const ExifData*) { std::istringstream is(value.toString()); uint32_t l; is >> l; return os << std::setw(4) << std::setfill('0') << std::hex << ((l & 0xffff0000) >> 16) << std::setw(5) << std::setfill('0') << std::dec << (l & 0x0000ffff); } std::ostream& CanonMakerNote::printCs0x0002(std::ostream& os, const Value& value, const ExifData*) { if ( value.typeId() != unsignedShort || value.count() == 0) return os << value; long l = value.toLong(); if (l == 0) { os << "Off"; } else { os << l / 10.0 << " s"; } return os; } //! Helper structure struct LensTypeAndFocalLength { long lensType_; //!< Lens type std::string focalLength_; //!< Focal length }; //! Compare tag details with a lens entry bool operator==(const TagDetails& td, const LensTypeAndFocalLength& ltfl) { return ( td.val_ == ltfl.lensType_ && std::string(td.label_).find(ltfl.focalLength_) != std::string::npos); } std::ostream& printCsLensByFocalLength(std::ostream& os, const Value& value, const ExifData* metadata) { if ( !metadata || value.typeId() != unsignedShort || value.count() == 0) return os << value; LensTypeAndFocalLength ltfl; ltfl.lensType_ = value.toLong(); ExifKey key("Exif.CanonCs.Lens"); ExifData::const_iterator pos = metadata->findKey(key); if ( pos != metadata->end() && pos->value().count() >= 3 && pos->value().typeId() == unsignedShort) { float fu = pos->value().toFloat(2); if (fu != 0.0) { float len1 = pos->value().toLong(0) / fu; float len2 = pos->value().toLong(1) / fu; std::ostringstream oss; oss << std::fixed << std::setprecision(0); if (len1 == len2) { oss << len1 << "mm"; } else { oss << len2 << "-" << len1 << "mm"; } ltfl.focalLength_ = oss.str(); } } if (ltfl.focalLength_.empty()) return os << value; const TagDetails* td = find(canonCsLensType, ltfl); if (!td) return os << value; return os << td->label_; } std::ostream& CanonMakerNote::printCsLensType(std::ostream& os, const Value& value, const ExifData* metadata) { if ( value.typeId() != unsignedShort || value.count() == 0) return os << "(" << value << ")"; const LensIdFct* lif = find(lensIdFct, value.toLong()); if (!lif) { return EXV_PRINT_TAG(canonCsLensType)(os, value, metadata); } if (metadata && lif->fct_) { return lif->fct_(os, value, metadata); } return os << value; } std::ostream& CanonMakerNote::printCsLens(std::ostream& os, const Value& value, const ExifData*) { if ( value.count() < 3 || value.typeId() != unsignedShort) { return os << "(" << value << ")"; } float fu = value.toFloat(2); if (fu == 0.0) return os << value; float len1 = value.toLong(0) / fu; float len2 = value.toLong(1) / fu; std::ostringstream oss; oss.copyfmt(os); os << std::fixed << std::setprecision(1); if (len1 == len2) { os << len1 << " mm"; } else { os << len2 << " - " << len1 << " mm"; } os.copyfmt(oss); return os; } std::ostream& CanonMakerNote::printSi0x0002(std::ostream& os, const Value& value, const ExifData*) { if ( value.typeId() == unsignedShort && value.count() > 0) { // Ported from Exiftool by Will Stokes os << exp(canonEv(value.toLong()) * log(2.0)) * 100.0 / 32.0; } return os; } std::ostream& CanonMakerNote::printSi0x0003(std::ostream& os, const Value& value, const ExifData*) { if ( value.typeId() == unsignedShort && value.count() > 0) { // The offset of '5' seems to be ok for most Canons (see Exiftool) // It might be explained by the fakt, that most Canons have a longest // exposure of 30s which is 5 EV below 1s // see also printSi0x0017 std::ostringstream oss; oss.copyfmt(os); int res = static_cast(100.0 * (value.toLong() / 32.0 + 5.0) + 0.5); os << std::fixed << std::setprecision(2) << res / 100.0; os.copyfmt(oss); } return os; } std::ostream& CanonMakerNote::printSi0x0009(std::ostream& os, const Value& value, const ExifData*) { if ( value.typeId() != unsignedShort || value.count() == 0) return os << value; long l = value.toLong(); os << l << ""; // Todo: determine unit return os; } std::ostream& CanonMakerNote::printSi0x000e(std::ostream& os, const Value& value, const ExifData* pExifData) { if ( value.typeId() != unsignedShort || value.count() == 0) return os << value; long l = value.toLong(); long num = (l & 0xf000) >> 12; os << num << " focus points; "; long used = l & 0x0fff; if (used == 0) { os << "none"; } else { EXV_PRINT_TAG_BITMASK(canonSiAFPointUsed)(os, value, pExifData); } os << " used"; return os; } std::ostream& CanonMakerNote::printSi0x0013(std::ostream& os, const Value& value, const ExifData*) { if ( value.typeId() != unsignedShort || value.count() == 0) return os << value; long l = value.toLong(); if (l == 0xffff) { os << "Infinite"; } else { os << l << ""; } return os; } std::ostream& CanonMakerNote::printSi0x0015(std::ostream& os, const Value& value, const ExifData*) { if ( value.typeId() != unsignedShort || value.count() == 0) return os << value; std::ostringstream oss; oss.copyfmt(os); long val = static_cast(value.toLong()); if (val < 0) return os << value; os << std::setprecision(2) << "F" << fnumber(canonEv(val)); os.copyfmt(oss); return os; } std::ostream& CanonMakerNote::printSi0x0016(std::ostream& os, const Value& value, const ExifData*) { if ( value.typeId() != unsignedShort || value.count() == 0) return os << value; URational ur = exposureTime(canonEv(value.toLong())); os << ur.first; if (ur.second > 1) { os << "/" << ur.second; } return os << " s"; } std::ostream& CanonMakerNote::printSi0x0017(std::ostream& os, const Value& value, const ExifData*) { if ( value.typeId() != unsignedShort || value.count() == 0) return os << value; std::ostringstream oss; oss.copyfmt(os); os << std::fixed << std::setprecision(2) << value.toLong() / 8.0 - 6.0; os.copyfmt(oss); return os; } // ***************************************************************************** // free functions float canonEv(long val) { // temporarily remove sign int sign = 1; if (val < 0) { sign = -1; val = -val; } // remove fraction float frac = static_cast(val & 0x1f); val -= long(frac); // convert 1/3 (0x0c) and 2/3 (0x14) codes if (frac == 0x0c) { frac = 32.0f / 3; } else if (frac == 0x14) { frac = 64.0f / 3; } return sign * (val + frac) / 32.0f; } }} // namespace Internal, Exiv2 exiv2-0.23/AUTHORS0000644000175000017500000000010711364504654013365 0ustar andreasandreasSee doc/ChangeLog. Authors and other contributors are mentioned there. exiv2-0.23/contrib/0000755000175000017500000000000011745263371013760 5ustar andreasandreasexiv2-0.23/contrib/organize/0000755000175000017500000000000011745263371015576 5ustar andreasandreasexiv2-0.23/contrib/organize/organize.cpp0000644000175000017500000007226611154700466020130 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2009 Brad Schick * * This file is part of the organize tool. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /* File: organize.cpp Version: $Rev: 1762 $ Author(s): Brad Schick (brad) History: 19-Jan-09, brad: created */ // ***************************************************************************** #include #include #include #include #include #include #include #include #include #include #include #include #include "MD5.h" #include "helpers.hpp" typedef Exiv2::byte md5digest[16]; namespace po = boost::program_options; bool g_verbose = false; bool g_neednewline = false; // Array size should match number of SLOTs boost::array g_run_order = {{-1, -1, -1, -1}}; const int EXIF_SLOT = 0; const int IPTC_SLOT = 1; const int XMP_SLOT = 2; const int FILE_SLOT = 3; const unsigned DOT_EVERY = 55; struct Pattern { std::string pat; std::string desc; pfunc funcs[4]; // order should always be exif, iptc, xmp, file }; struct PathPart { std::string pre; const Pattern *pat; std::string post; PathPart(std::string pre_, const Pattern *pat_, std::string post_) : pre(pre_), pat(pat_), post(post_) {} }; std::vector g_path_parts; // Instead of making these all global struct ProcessParams { const fs::path &dest_dir; const bool dry_run; const bool ignore_dups; const bool ignore_unsorted; const bool force; const bool rename; const bool symlink; const bool verify; const bool move; const long limit_depth; const fs::path &dups_dir; const fs::path &unsorted_dir; const std::vector &excludes; unsigned dups_count; unsigned unsorted_count; unsigned dir_err_count; unsigned file_err_count; unsigned ok_count; unsigned dups_ignored_count; unsigned unsorted_ignored_count; unsigned dir_ex_count; unsigned file_ex_count; }; void process_directory(const fs::path &directory, const long depth, ProcessParams ¶ms); const Pattern g_patterns[] = { {"@date", "date captured (2009-01-19)", {exif_date, iptc_date, NULL, file_date} }, {"@year", "year captured (2009)", {exif_year, iptc_year, NULL, file_year} }, {"@month", "month captured (01)", {exif_month, iptc_month, NULL, file_month} }, {"@day", "day captured (19)", {exif_day, iptc_day, NULL, file_day} }, {"@time", "time captured (14-35-27)", {exif_time, iptc_time, NULL, file_time} }, {"@hour", "hour captured (14)", {exif_hour, iptc_hour, NULL, file_hour} }, {"@min", "minute captured (35)", {exif_minute, iptc_minute, NULL, file_minute} }, {"@sec", "second captured (27)", {exif_second, iptc_second, NULL, file_second} }, {"@dim", "pixel dimension (2272-1704)", {exif_dimension, NULL, NULL, file_dimension} }, {"@x", "pixel width (2272)", {exif_width, NULL, NULL, file_width} }, {"@y", "pixel height (1704)", {exif_height, NULL, NULL, file_height} }, {"@make", "device make (Canon)", {exif_make, NULL, NULL, NULL} }, {"@model", "device model (Canon PowerShot S40)", {exif_model, NULL, NULL, NULL} }, {"@speed", "shutter speed (1-60)", {exif_speed, NULL, NULL, NULL} }, {"@aper", "aperture (F3.2)", {exif_aperture, NULL, NULL, NULL} }, {"@iso", "iso speed (400)", {exif_iso, NULL, NULL, NULL} }, {"@focal", "focal length (8.6 mm)", {exif_focal, NULL, NULL, NULL} }, {"@dist", "subject distance (1.03 m)", {exif_distance, NULL, NULL, NULL} }, {"@meter", "meter mode (multi-segment)", {exif_meter, NULL, NULL, NULL} }, {"@macro", "macro mode (Off)", {exif_macro, NULL, NULL, NULL} }, {"@orient", "orientation (top_left)", {exif_orientation, NULL, NULL, NULL} }, {"@lens", "lens name (Tamron 90mm f-2.8)", {exif_lens, NULL, NULL, NULL} }, {"@key", "first keyword (Family)", {exif_keyword, iptc_keyword, NULL, NULL} }, {"", "", {NULL, NULL, NULL, NULL} } }; // Check that 'opt1' and 'opt2' are not specified at the same time. void conflicting(const po::variables_map& vm, const char* opt1, const char* opt2) { if (vm.count(opt1) && !vm[opt1].defaulted() && vm.count(opt2) && !vm[opt2].defaulted()) { throw std::logic_error(std::string("conflicting options '") + opt1 + "' and '" + opt2 + "'"); } } // Check that 'required' is present void required(const po::variables_map& vm, const char* required) { if (!vm.count(required) || vm[required].defaulted()) { throw std::logic_error(std::string("required parameter '") + required + "' is missing"); } } void info(const std::string &msg) { if(g_verbose) { std::cout << msg << "\n"; g_neednewline = false; } } void error(const std::exception &e, const std::string &msg) { if(g_neednewline) { std::cout << "\n"; g_neednewline = false; } std::cerr << e.what() << "\n"; std::cerr << msg << std::endl; } void usage_header(const char* exname) { std::cout << "Usage: " << exname << " [options] source-dir dest-dir pattern\n"; } void usage_full(const po::options_description &options, const char* exname) { usage_header(exname); std::cout << "\n Creates groups of files in new directories defined by a metadata 'pattern'.\n" << " Files are copied, moved, or linked from 'source-dir' to 'dest-dir'.\n" << " The destination directory should not be within the source directory.\n\n"; std::cout << options; std::cout << "\nPattern values:\n"; for( const Pattern *pattern = g_patterns; pattern->pat.length(); ++pattern) { std::cout << " " << std::setw(8) << std::left << pattern->pat; std::cout << pattern->desc << "\n"; } std::cout << "\nExamples:\n"; std::cout << " `" << exname << " -m mess clean @year-@month'\n"; std::cout << " Moves files from 'mess' into directories of 'clean' according to\n" << " year-month the file was captured (clean/2006-11/...)\n\n"; std::cout << " `" << exname << " -o ie source find width-@x/height-@y'\n"; std::cout << " Copies files into directories according first to pixel width then pixel\n" << " height. Check iptc then exif metadata (find/width-2272/height-1704/...)\n\n"; std::cout << " `" << exname << " -lf source find @aper/@hour'\n"; std::cout << " Force create symlinks in directories according first to aperture then\n" << " hour captured (find/F3.2/15/...)\n"; std::cout << std::endl; } void version() { std::cout << "organized 0.1\n" << "Copyright (C) 2009 Brad Schick. \n\n" << "This program is free software; you can redistribute it and/or\n" "modify it under the terms of the GNU General Public License\n" "as published by the Free Software Foundation; either version 2\n" "of the License, or (at your option) any later version.\n" "\n" "This program is distributed in the hope that it will be useful,\n" "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" "GNU General Public License for more details.\n" "\n" "You should have received a copy of the GNU General Public\n" "License along with this program; if not, write to the Free\n" "Software Foundation, Inc., 51 Franklin Street, Fifth Floor,\n" "Boston, MA 02110-1301 USA" << std::endl; } // Returns empty string if the destination subdirectory could not be determined // for the supplied source file. std::string build_dest(const fs::path &source_file) { std::string dest; Exiv2::Image::AutoPtr image; try { image = Exiv2::ImageFactory::open(source_file.string()); image->readMetadata(); } catch(const Exiv2::AnyError&) { // No metadata, let things continue to try file info } std::vector::iterator iter = g_path_parts.begin(); std::vector::iterator end = g_path_parts.end(); for( ; iter != end; ++iter) { dest += iter->pre; std::string result; const Pattern *pat = iter->pat; for(unsigned fx = 0; fx < g_run_order.size(); ++fx) { if(g_run_order[fx] != -1 && pat->funcs[g_run_order[fx]]) { if(g_run_order[fx] == FILE_SLOT) { // Always run file operations result = pat->funcs[g_run_order[fx]](image.get(), source_file); } else if(image.get()) { // No point in running metadata operations without an image result = pat->funcs[g_run_order[fx]](image.get(), source_file); } if(result.length()) break; } } // If we found no data, even for part of pattern, give up and // return no destination if(!result.length()) return result; dest += (result + iter->post); } return dest; } bool md5sum(const fs::path &path, md5digest &digest) { try { Exiv2::FileIo io(path.file_string()); if (io.open() != 0) return false; Exiv2::IoCloser closer(io); Exiv2::byte buff[4096]; MD5_CTX context; MD5Init(&context); long read_count = io.read(buff, 4096); while(read_count) { MD5Update(&context, buff, read_count); read_count = io.read(buff, 4096); } MD5Final(digest, &context); return true; } catch (std::exception& ) { return false; } } int main(int argc, char* argv[]) { po::options_description options("Options"); // Don't use default values because the help print it ugly and too wide options.add_options() ("move,m", "move files rather than copy") ("symlink,s", "symlink files rather than copy (posix only)") ("order,o", po::value(), "order and types of metadata to read\ne=exif, i=iptc, f=file (default: eif)") ("unsorted,u", po::value(), "special directory to store unsorted files (default: unsorted)") ("dups,d", po::value(), "special directory to store files with duplicate names (default: duplicates)") ("force,f", "overwrite duplicate files instead of using special directory") ("rename,r", "rename duplicate files instead of using special directory") ("ignore,i", "ignore both unsorted and duplicate files instead of using special directories") ("ignore-unsorted", "ignore unsorted files instead of using special directory") ("ignore-dups", "ignore duplicate files instead of using special directory") ("verify", "verify copied or moved files and exit if incorrect") ("exclude,x", po::value< std::vector >(), "exclude directories and files that contain arg (case sensitive on all platforms)") ("limit-depth,l", po::value(), "limit recursion to specified depth (0 disables recursion)") ("verbose,v", "prints operations as they happen") ("dry-run,n", "do not make actual changes (implies verbose)") ("help,h", "show this help message then exit") ("version,V", "show program version then exit") ; po::options_description hidden("Hidden Options"); hidden.add_options() ("source-dir", po::value< std::string >(), "directory of files to organize, may end in file wildcard") ("dest-dir", po::value< std::string >(), "desination directory for files, may not be within source-dir") ("pattern", po::value< std::string >(), "subdirectory pattern for grouping files within dest-dir") ; po::options_description cmdline; cmdline.add(options).add(hidden); po::positional_options_description positional; positional.add("source-dir", 1); positional.add("dest-dir", 1); positional.add("pattern", 1); try { po::variables_map vm; po::store(po::command_line_parser(argc, argv). options(cmdline).positional(positional).run(), vm); po::notify(vm); if (vm.count("help")) { usage_full(options, argv[0]); return 0; } if (vm.count("version")) { version(); return 0; } conflicting(vm, "verify", "symlink"); conflicting(vm, "move", "symlink"); conflicting(vm, "unsorted", "ignore"); conflicting(vm, "unsorted", "ignore-unsorted"); conflicting(vm, "dups", "ignore"); conflicting(vm, "dups", "ignore-dups"); conflicting(vm, "force", "ignore"); conflicting(vm, "force", "ignore-dups"); conflicting(vm, "force", "rename"); conflicting(vm, "rename", "ignore"); conflicting(vm, "rename", "ignore-dups"); required(vm, "source-dir"); required(vm, "dest-dir"); required(vm, "pattern"); const bool dry_run = vm.count("dry-run") != 0; g_verbose = (vm.count("verbose") != 0 || dry_run); std::string order = "eif"; if(vm.count("order")) { order = vm["order"].as(); boost::to_lower(order); if(order.length() > 3) { throw std::logic_error(std::string("order is longer than 4 characters")); } } unsigned i = 0; std::string::iterator end = order.end(); for(std::string::iterator iter = order.begin(); iter != end && i < 4; ++iter, ++i) { switch(*iter) { case 'e': g_run_order[i] = EXIF_SLOT; break; case 'i': g_run_order[i] = IPTC_SLOT; break; case 'x': throw std::logic_error(std::string("xmp not implemented yet '") + *iter + "'"); break; case 'f': g_run_order[i] = FILE_SLOT; break; default: throw std::logic_error(std::string("unknown order character '") + *iter + "'"); } } const fs::path source_dir( vm["source-dir"].as() ); if( !exists(source_dir) || !is_directory(source_dir) ) { throw std::logic_error(std::string("source '") + source_dir.string() + "' must exist and be a directory"); } const fs::path dest_dir( vm["dest-dir"].as() ); if( exists(dest_dir) && !is_directory(dest_dir) ) { throw std::logic_error(std::string("destination '") + dest_dir.string() + "' must be a directory"); } // Boost doesn't seem to have a way to get a canonical path, so this // simple test is easy to confuse with some ../../'s in the paths. Oh // well, this is good enough for now. fs::path test_dest(dest_dir); for(; !test_dest.empty(); test_dest = test_dest.parent_path()) { if(fs::equivalent(source_dir, test_dest)) { throw std::logic_error(std::string("dest-dir must not be within source-dir")); } } // Disect the pattern std::string pattern = vm["pattern"].as(); boost::regex regex( "([^@]*)(@[[:alpha:]]+)([^@]*)"); boost::sregex_iterator m_iter = make_regex_iterator(pattern, regex); boost::sregex_iterator m_end; for( ; m_iter != m_end; ++m_iter) { const boost::smatch &match = *m_iter; const std::string &pre = match[1]; const std::string &pat = match[2]; const std::string &post = match[3]; // Should put this in a map, but there aren't that many options now bool found = false; for( const Pattern *pattern = g_patterns; pattern->pat.length(); ++pattern) { if(pattern->pat == pat) { PathPart part(pre, pattern, post); g_path_parts.push_back(part); found = true; break; } } if(!found) { throw std::logic_error(std::string("unknown pattern '") + pat + "'"); } } // Assign defaults to params that need them const bool ignore = vm.count("ignore") != 0; std::vector excludes; if(vm.count("exclude")) excludes = vm["exclude"].as< std::vector >(); long limit_depth = LONG_MAX; if(vm.count("limit-depth")) { limit_depth = vm["limit-depth"].as(); // Boost program_options doesn't work with unsigned, so do it manually if( limit_depth < 0 ) throw std::logic_error(std::string("recursion depth limit must be positive")); } std::string dups = "duplicates"; if(vm.count("dups")) dups = vm["dups"].as(); const fs::path dups_dir = dest_dir / dups; std::string unsorted = "unsorted"; if(vm.count("unsorted")) unsorted = vm["unsorted"].as(); const fs::path unsorted_dir = dest_dir / unsorted; ProcessParams params = { dest_dir, dry_run, (vm.count("ignore-dups") != 0 || ignore), (vm.count("ignore-unsorted") != 0 || ignore), vm.count("force") != 0, vm.count("rename") != 0, vm.count("symlink") != 0, vm.count("verify") != 0, vm.count("move") != 0, limit_depth, dups_dir, unsorted_dir, excludes, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; process_directory(source_dir, 0, params); std::string op = "copied"; if(params.symlink) op = "linked"; else if(params.move) op = "moved"; if(dry_run) op = std::string("would be ") + op; if(g_neednewline) std::cout << "\n"; std::cout << "\n" << params.ok_count << " files " << op << "\n"; std::cout << " " << params.dups_count << " duplicates\n"; std::cout << " " << params.unsorted_count << " unsorted\n"; if(params.dups_ignored_count) std::cout << params.dups_ignored_count << " duplicates ignored\n"; if(params.unsorted_ignored_count) std::cout << params.unsorted_ignored_count << " unsorted ignored\n"; if(params.dir_ex_count) std::cout << params.dir_ex_count << " directories excluded\n"; if(params.file_ex_count) std::cout << params.file_ex_count << " files excluded\n"; if(params.dir_err_count) std::cout << params.dir_err_count << " directory errors\n"; if(params.file_err_count) std::cout << params.file_err_count << " file errors\n"; return 0; } catch (Exiv2::AnyError& e) { error(e, std::string("Aborting")); return -1; } catch(std::logic_error& e) { error(e, ""); usage_header(argv[0]); std::cout << argv[0] << " -h for more help" << std::endl; return -2; } catch(std::exception& e) { error(e, "Aborting"); return -3; } } boost::regex uregex("(.*?)\\(([[:digit:]]{1,2})\\)$"); fs::path uniquify(const fs::path &dest) { std::string ext = dest.extension(); std::string fname = dest.stem(); fs::path parent = dest.parent_path(); unsigned number = 1; std::string newfname; fs::path newdest; boost::smatch match; if(boost::regex_search(fname, match, uregex)) { // Matches are indexes into fname, so don't change it while reading values newfname = match[1]; number = boost::lexical_cast(match[2]); fname = newfname; } do { newfname = fname + "(" + boost::lexical_cast(++number) + ")" + ext; newdest = parent / newfname; } while(fs::exists(newdest)); return newdest; } void process_directory(const fs::path &directory, const long depth, ProcessParams ¶ms) { // Exclude entire directories bool exclude = false; std::vector::const_iterator x_iter = params.excludes.begin(); std::vector::const_iterator x_end = params.excludes.end(); for( ; x_iter != x_end; ++x_iter ) { if(boost::contains(directory.file_string(), *x_iter)) { exclude = true; break; } } if(exclude) { info(std::string("excluding directory: ") + directory.file_string() + " matched: " + *x_iter); ++params.dir_ex_count; return; } try { fs::directory_iterator p_iter(directory), p_end; for( ; p_iter != p_end; ++p_iter) { if( is_directory(*p_iter) ) { // recurse if we haven't hit the limit if(depth < params.limit_depth) process_directory(p_iter->path(), depth + 1, params); else { info(std::string("depth reached, skipping: ") + p_iter->path().file_string()); } } else if( is_regular_file(*p_iter) ) { // Check again for excluding file names exclude = false; x_iter = params.excludes.begin(); for( ; x_iter != x_end; ++x_iter ) { if(boost::contains(p_iter->path().file_string(), *x_iter)) { exclude = true; break; } } if(exclude) { info(std::string("excluding file: ") + p_iter->path().file_string() + " matched: " + *x_iter); ++params.file_ex_count; continue; } try { const fs::path dest_subdir = build_dest(*p_iter); fs::path dest_file; if(!dest_subdir.empty()) dest_file = params.dest_dir / dest_subdir; else if(params.ignore_unsorted) { info(std::string("ignoring unsorted: ") + p_iter->path().file_string()); ++params.unsorted_ignored_count; continue; } else { info(std::string("unsorted file (missing metadata): ") + p_iter->path().file_string()); dest_file = params.unsorted_dir; ++params.unsorted_count; } dest_file /= p_iter->filename(); if(fs::exists(dest_file)) { if(params.ignore_dups) { info(std::string("ignoring: ") + p_iter->path().file_string() + " duplicates: " + dest_file.file_string()); ++params.dups_ignored_count; continue; } else { if(params.force) { info(std::string("force removing: ") + dest_file.file_string() + " for: " + p_iter->path().file_string()); if(!params.dry_run) fs::remove(dest_file); } else if(params.rename) { info(std::string("renaming: ") + p_iter->path().file_string() + " duplicates: " + dest_file.file_string()); dest_file = uniquify(dest_file); } else { info(std::string("duplicate file: ") + p_iter->path().file_string() + " of: " + dest_file.file_string()); dest_file = params.dups_dir / dest_subdir / p_iter->filename(); // Ugh, more dup possibilities if(fs::exists(dest_file)) { info(std::string("renaming: ") + p_iter->path().file_string() + " duplicates: " + dest_file.file_string()); dest_file = uniquify(dest_file); } } ++params.dups_count; } } if(!params.dry_run) fs::create_directories(dest_file.parent_path()); if(params.symlink) { info(std::string("linking from: ") + p_iter->path().file_string() + " to: " + dest_file.file_string()); if(!params.dry_run) { // The target of a symlink must be either absolute (aka complete) or // relative to the location of the link. Easiest solution is to make // a complete path. fs::path target; if(p_iter->path().is_complete()) target = p_iter->path(); else target = fs::initial_path() / p_iter->path(); fs::create_symlink(target, dest_file); } } else { info(std::string("copying from: ") + p_iter->path().file_string() + " to: " + dest_file.file_string()); if(!params.dry_run) { // Copy the file and restore its write time (needed for posix) std::time_t time = fs::last_write_time(*p_iter); fs::copy_file(*p_iter, dest_file); fs::last_write_time(dest_file, time); if(params.verify) { md5digest src_digest, dst_digest; bool ok = md5sum(p_iter->path(), src_digest); if(ok) ok = md5sum(dest_file, dst_digest); if(ok) ok = (memcmp(src_digest,dst_digest, sizeof(md5digest))==0); if(!ok) { // Should probably find a more appropriate exception for this throw std::runtime_error(std::string("File verification failed: '") + p_iter->path().file_string() + "' differs from '" + dest_file.file_string() + "'"); } else { info(std::string("verification passed")); } } } } if(params.move) { info(std::string("removing: ") + p_iter->path().file_string()); if(!params.dry_run) fs::remove(*p_iter); } if(!g_verbose && (params.ok_count % DOT_EVERY)==0) { std::cout << "." << std::flush; g_neednewline = true; } ++params.ok_count; } catch(fs::filesystem_error& e) { error(e, std::string("skipping file: " + p_iter->path().file_string())); ++params.file_err_count; } } } } catch(fs::filesystem_error& e) { error(e, std::string("skipping directory: " + directory.file_string())); ++params.dir_err_count; } } exiv2-0.23/contrib/organize/helpers.cpp0000644000175000017500000004023611154700466017744 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2009 Brad Schick * * This file is part of the organize tool. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /* File: helpers.cpp Version: $Rev: 1762 $ Author(s): Brad Schick (brad) History: 19-Jan-09, brad: created */ // ***************************************************************************** #include #include #include #include #include #include #include #include #include //#include #include #include #include #include "helpers.hpp" #define BOOST_FILESYSTEM_NO_DEPRECATED namespace fs = boost::filesystem; typedef Exiv2::ExifData::const_iterator (*EasyAccessFct)(const Exiv2::ExifData& ed); std::string scrub(const std::string &dirty, bool strip_space = false) { std::string scrub = boost::trim_copy(dirty); if(strip_space) { boost::regex space("\\s"); scrub = boost::regex_replace(scrub, space, ""); } boost::regex dash("[:/\\\\|<>]"); boost::regex under("[\"'\\[\\]\\{\\}#=%\\$\\?,\\+\\*]"); scrub = boost::regex_replace(scrub, dash, "-"); return boost::regex_replace(scrub, under, "_"); } bool exif_data(const Exiv2::Image *image, const char *key, Exiv2::ExifData::const_iterator &md) { assert(image && key); bool ok = false; try { const Exiv2::ExifData &exifData = image->exifData(); Exiv2::ExifKey exifKey(key); md = exifData.findKey(exifKey); if(md != exifData.end() && md->typeId() != Exiv2::undefined) ok = true; } catch(const Exiv2::AnyError&) { } return ok; } bool exif_data_easy(const Exiv2::Image *image, EasyAccessFct easy, Exiv2::ExifData::const_iterator &md) { assert(image && easy); bool ok = false; try { const Exiv2::ExifData &exifData = image->exifData(); md = easy(exifData); if(md != exifData.end() && md->typeId() != Exiv2::undefined) ok = true; } catch(const Exiv2::AnyError&) { } return ok; } bool iptc_data(const Exiv2::Image *image, const char *key, Exiv2::IptcData::const_iterator &md) { bool ok = false; assert(image && key); try { const Exiv2::IptcData &iptcData = image->iptcData(); Exiv2::IptcKey iptcKey(key); md = iptcData.findKey(iptcKey); if(md != iptcData.end() && md->typeId() != Exiv2::undefined) ok = true; } catch(const Exiv2::AnyError&) { } return ok; } std::string exif_date(const Exiv2::Image *image, const fs::path &) { Exiv2::ExifData::const_iterator md; bool done = exif_data(image, "Exif.Photo.DateTimeDigitized", md); if(!done) done = exif_data(image, "Exif.Photo.DateTimeOriginal", md); if(!done) return ""; std::string date = scrub(md->print().substr(0,10)); // Some files have zeros for dates, just fail in that case if(boost::lexical_cast(date.substr(0,4))==0) return ""; return date; } std::string exif_year(const Exiv2::Image *image, const fs::path &path) { std::string date = exif_date(image, path); if(date.length()) return date.substr(0,4); else return date; } std::string exif_month(const Exiv2::Image *image, const fs::path &path) { std::string date = exif_date(image, path); if(date.length()) return date.substr(5,2); else return date; } std::string exif_day(const Exiv2::Image *image, const fs::path &path) { std::string date = exif_date(image, path); if(date.length()) return date.substr(8,2); else return date; } bool iptc_get_date(const Exiv2::Image *image, Exiv2::DateValue::Date &date) { Exiv2::IptcData::const_iterator md; bool done = iptc_data(image, "Iptc.Application2.DigitizationDate", md); if(!done) done = iptc_data(image, "Iptc.Application2.DateCreated", md); if(!done) return false; date = ((Exiv2::DateValue*)md->getValue().get())->getDate(); return date.year > 0; } std::string iptc_date(const Exiv2::Image *image, const fs::path &) { Exiv2::DateValue::Date date; if(iptc_get_date(image, date)) return str(boost::format("%4d-%02d-%02d") % date.year % date.month % date.day); else return ""; } std::string iptc_year(const Exiv2::Image *image, const fs::path &) { Exiv2::DateValue::Date date; if(iptc_get_date(image, date)) return str(boost::format("%4d") % date.year); else return ""; } std::string iptc_month(const Exiv2::Image *image, const fs::path &) { Exiv2::DateValue::Date date; if(iptc_get_date(image, date)) return str(boost::format("%02d") % date.month); else return ""; } std::string iptc_day(const Exiv2::Image *image, const fs::path &) { Exiv2::DateValue::Date date; if(iptc_get_date(image, date)) return str(boost::format("%02d") % date.day); else return ""; } bool file_get_tm(const fs::path &path, std::tm &tm) { std::time_t timer = fs::last_write_time(path); if(time > 0) { tm = *localtime(&timer); return true; } else { return false; } } std::string file_date(const Exiv2::Image *, const fs::path &path) { std::tm tm; if(file_get_tm(path, tm)) return str(boost::format("%4d-%02d-%02d") % (tm.tm_year + 1900) % (tm.tm_mon + 1) % tm.tm_mday); else return ""; } std::string file_year(const Exiv2::Image *, const fs::path &path) { std::tm tm; if(file_get_tm(path, tm)) return str(boost::format("%4d") % (tm.tm_year + 1900)); else return ""; } std::string file_month(const Exiv2::Image *, const fs::path &path) { std::tm tm; if(file_get_tm(path, tm)) return str(boost::format("%02d") % (tm.tm_mon + 1)); else return ""; } std::string file_day(const Exiv2::Image *, const fs::path &path) { std::tm tm; if(file_get_tm(path, tm)) return str(boost::format("%02d") % tm.tm_mday); else return ""; } /* std::string xmp_date(const Exiv2::Image *image, const fs::path &) { return ""; } std::string xmp_year(const Exiv2::Image *image, const fs::path &) { return ""; } std::string xmp_month(const Exiv2::Image *image, const fs::path &) { return ""; } std::string xmp_day(const Exiv2::Image *image, const fs::path &) { return ""; }*/ std::string exif_time(const Exiv2::Image *image, const fs::path &) { Exiv2::ExifData::const_iterator md; bool done = exif_data(image, "Exif.Photo.DateTimeDigitized", md); if(!done) done = exif_data(image, "Exif.Photo.DateTimeOriginal", md); if(!done) return ""; std::string datetime = md->print(); // Some files have zeros for dates, just fail in that case if(boost::lexical_cast(datetime.substr(0,4)) == 0) return ""; return scrub(datetime.substr(11)); } std::string exif_hour(const Exiv2::Image *image, const fs::path &path) { std::string time = exif_time(image, path); if(time.length()) return time.substr(0,2); else return time; } std::string exif_minute(const Exiv2::Image *image, const fs::path &path) { std::string time = exif_time(image, path); if(time.length()) return time.substr(3,2); else return time; } std::string exif_second(const Exiv2::Image *image, const fs::path &path) { std::string time = exif_time(image, path); if(time.length()) return time.substr(6,2); else return time; } bool iptc_get_time(const Exiv2::Image *image, Exiv2::TimeValue::Time &time) { Exiv2::IptcData::const_iterator md; bool done = iptc_data(image, "Iptc.Application2.DigitizationTime", md); if(!done) done = iptc_data(image, "Iptc.Application2.TimeCreated", md); if(!done) return false; time = ((Exiv2::TimeValue*)md->getValue().get())->getTime(); // Zero is a valid time, so this one is hard to check. return true; } std::string iptc_time(const Exiv2::Image *image, const fs::path &) { Exiv2::TimeValue::Time time; if(iptc_get_time(image, time)) return str(boost::format("%02d-%02d-%02d") % time.hour % time.minute % time.second); else return ""; } std::string iptc_hour(const Exiv2::Image *image, const fs::path &) { Exiv2::TimeValue::Time time; if(iptc_get_time(image, time)) return str(boost::format("%02d") % time.hour); else return ""; } std::string iptc_minute(const Exiv2::Image *image, const fs::path &) { Exiv2::TimeValue::Time time; if(iptc_get_time(image, time)) return str(boost::format("%02d") % time.minute); else return ""; } std::string iptc_second(const Exiv2::Image *image, const fs::path &) { Exiv2::TimeValue::Time time; if(iptc_get_time(image, time)) return str(boost::format("%02d") % time.second); else return ""; } std::string file_time(const Exiv2::Image *, const fs::path &path) { std::tm tm; if(file_get_tm(path, tm)) return str(boost::format("%02d-%02d-%02d") % tm.tm_hour % tm.tm_min % tm.tm_sec); else return ""; } std::string file_hour(const Exiv2::Image *, const fs::path &path) { std::tm tm; if(file_get_tm(path, tm)) return str(boost::format("%02d") % tm.tm_hour); else return ""; } std::string file_minute(const Exiv2::Image *, const fs::path &path) { std::tm tm; if(file_get_tm(path, tm)) return str(boost::format("%02d") % tm.tm_min); else return ""; } std::string file_second(const Exiv2::Image *, const fs::path &path) { std::tm tm; if(file_get_tm(path, tm)) return str(boost::format("%02d") % tm.tm_sec); else return ""; } /*std::string xmp_time(const Exiv2::Image *image, const fs::path &) { return ""; } std::string xmp_hour(const Exiv2::Image *image, const fs::path &) { return ""; } std::string xmp_minute(const Exiv2::Image *image, const fs::path &) { return ""; } std::string xmp_second(const Exiv2::Image *image, const fs::path &) { return ""; }*/ std::string exif_dimension(const Exiv2::Image *image, const fs::path &path) { return exif_width(image, path) + "-" + exif_height(image, path); } std::string exif_width(const Exiv2::Image *image, const fs::path &) { Exiv2::ExifData::const_iterator md; bool done = exif_data(image, "Exif.Photo.PixelXDimension", md); if(!done) return ""; return scrub(md->print()); } std::string exif_height(const Exiv2::Image *image, const fs::path &) { Exiv2::ExifData::const_iterator md; bool done = exif_data(image, "Exif.Photo.PixelYDimension", md); if(!done) return ""; return scrub(md->print()); } std::string file_dimension(const Exiv2::Image *image, const fs::path &path) { if(image) return file_width(image, path) + "-" + file_height(image, path); else return ""; } std::string file_width(const Exiv2::Image *image, const fs::path &) { if(image) return str(boost::format("%02d") % image->pixelWidth()); else return ""; } std::string file_height(const Exiv2::Image *image, const fs::path &) { if(image) return str(boost::format("%02d") % image->pixelHeight()); else return ""; } /* std::string xmp_dimension(const Exiv2::Image *image, const fs::path &) { return "" } std::string xmp_width(const Exiv2::Image *image, const fs::path &) { return ""; } std::string xmp_height(const Exiv2::Image *image, const fs::path &) { return ""; }*/ std::string exif_model(const Exiv2::Image *image, const fs::path &) { Exiv2::ExifData::const_iterator md; bool done = exif_data(image, "Exif.Image.Model", md); if(!done) return ""; return scrub(md->print()); } std::string exif_make(const Exiv2::Image *image, const fs::path &) { Exiv2::ExifData::const_iterator md; bool done = exif_data(image, "Exif.Image.Make", md); if(!done) return ""; return scrub(md->print()); } /*std::string xmp_model(const Exiv2::Image *image, const fs::path &) { return ""; }*/ std::string exif_speed(const Exiv2::Image *image, const fs::path &) { Exiv2::ExifData::const_iterator md; bool done = exif_data(image, "Exif.Photo.ShutterSpeedValue", md); if(!done) done = exif_data(image, "Exif.Photo.ExposureTime", md); if(!done) return ""; return scrub(md->print()); } /*std::string xmp_speed(const Exiv2::Image *image, const fs::path &) { return ""; }*/ std::string exif_aperture(const Exiv2::Image *image, const fs::path &) { Exiv2::ExifData::const_iterator md; bool done = exif_data(image, "Exif.Photo.ApertureValue", md); if(!done) done = exif_data(image, "Exif.Photo.FNumber", md); if(!done) return ""; return scrub(md->print()); } /*std::string xmp_aperture(const Exiv2::Image *image, const fs::path &) { return ""; }*/ std::string exif_focal(const Exiv2::Image *image, const fs::path &) { Exiv2::ExifData::const_iterator md; bool done = exif_data(image, "Exif.Photo.FocalLength", md); if(!done) return ""; return scrub(md->print()); } /*std::string xmp_focal(const Exiv2::Image *image, const fs::path &) { return ""; }*/ std::string exif_distance(const Exiv2::Image *image, const fs::path &) { Exiv2::ExifData::const_iterator md; bool done = exif_data(image, "Exif.Photo.SubjectDistance", md); if(!done) return ""; return scrub(md->print()); } /*std::string xmp_distance(const Exiv2::Image *image, const fs::path &) { return ""; }*/ std::string exif_meter(const Exiv2::Image *image, const fs::path &) { Exiv2::ExifData::const_iterator md; bool done = exif_data(image, "Exif.Photo.MeteringMode", md); if(!done) return ""; return scrub(md->print()); } std::string exif_macro(const Exiv2::Image *image, const fs::path &) { Exiv2::ExifData::const_iterator md; bool done = exif_data_easy(image, Exiv2::macroMode, md); if(!done) return ""; return scrub(md->print()); } std::string exif_orientation(const Exiv2::Image *image, const fs::path &) { Exiv2::ExifData::const_iterator md; bool done = exif_data_easy(image, Exiv2::orientation, md); if(!done) return ""; return scrub(md->print(), true); } std::string exif_lens(const Exiv2::Image *image, const fs::path &) { Exiv2::ExifData::const_iterator md; bool done = exif_data_easy(image, Exiv2::lensName, md); if(!done) return ""; return scrub(md->print()); } std::string exif_iso(const Exiv2::Image *image, const fs::path &) { Exiv2::ExifData::const_iterator md; bool done = exif_data_easy(image, Exiv2::isoSpeed, md); if(!done) return ""; return scrub(md->print()); } /*std::string xmp_meter(const Exiv2::Image *image, const fs::path &) { return ""; }*/ std::string exif_keyword(const Exiv2::Image *image, const fs::path &) { Exiv2::ExifData::const_iterator md; bool done = exif_data(image, "Exif.Photo.UserComment", md); if(!done) return ""; return scrub(md->print()); } std::string iptc_keyword(const Exiv2::Image *image, const fs::path &) { Exiv2::IptcData::const_iterator md; bool done = iptc_data(image, "Iptc.Application2.Keywords", md); if(!done) return ""; return scrub(md->print()); } /*std::string xmp_keyword(const Exiv2::Image *image, const fs::path &) { return ""; }*/ exiv2-0.23/contrib/organize/MD5.cpp0000644000175000017500000001651111141017140016650 0ustar andreasandreas/* * This code implements the MD5 message-digest algorithm. * The algorithm is due to Ron Rivest. This code was * written by Colin Plumb in 1993, no copyright is claimed. * This code is in the public domain; do with it what you wish. * * Equivalent code is available from RSA Data Security, Inc. * This code has been tested against that, and is equivalent, * except that you don't need to include two pages of legalese * with every copy. * * To compute the message digest of a chunk of bytes, declare an * MD5_CTX structure, pass it to MD5Init, call MD5Update as * needed on buffers full of bytes, and then call MD5Final, which * will fill a supplied 16-byte array with the digest. * * Changed so as no longer to depend on Colin Plumb's `usual.h' header * definitions; now uses stuff from dpkg's config.h. * - Ian Jackson . * Still in the public domain. */ #include #include "MD5.h" using namespace std; static void byteSwap(UWORD32 *buf, unsigned words) { const uint32_t byteOrderTest = 0x1; if (((char *)&byteOrderTest)[0] == 0) { md5byte *p = (md5byte *)buf; do { *buf++ = (UWORD32)((unsigned)p[3] << 8 | p[2]) << 16 | ((unsigned)p[1] << 8 | p[0]); p += 4; } while (--words); } } /* * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious * initialization constants. */ void MD5Init(struct MD5_CTX *ctx) { ctx->buf[0] = 0x67452301; ctx->buf[1] = 0xefcdab89; ctx->buf[2] = 0x98badcfe; ctx->buf[3] = 0x10325476; ctx->bytes[0] = 0; ctx->bytes[1] = 0; } /* * Update context to reflect the concatenation of another buffer full * of bytes. */ void MD5Update(struct MD5_CTX *ctx, md5byte const *buf, unsigned len) { UWORD32 t; /* Update byte count */ t = ctx->bytes[0]; if ((ctx->bytes[0] = t + len) < t) ctx->bytes[1]++; /* Carry from low to high */ t = 64 - (t & 0x3f); /* Space available in ctx->in (at least 1) */ if (t > len) { memcpy((md5byte *)ctx->in + 64 - t, buf, len); return; } /* First chunk is an odd size */ memcpy((md5byte *)ctx->in + 64 - t, buf, t); byteSwap(ctx->in, 16); MD5Transform(ctx->buf, ctx->in); buf += t; len -= t; /* Process data in 64-byte chunks */ while (len >= 64) { memcpy(ctx->in, buf, 64); byteSwap(ctx->in, 16); MD5Transform(ctx->buf, ctx->in); buf += 64; len -= 64; } /* Handle any remaining bytes of data. */ memcpy(ctx->in, buf, len); } /* * Final wrapup - pad to 64-byte boundary with the bit pattern * 1 0* (64-bit count of bits processed, MSB-first) */ void MD5Final(md5byte digest[16], struct MD5_CTX *ctx) { int count = ctx->bytes[0] & 0x3f; /* Number of bytes in ctx->in */ md5byte *p = (md5byte *)ctx->in + count; /* Set the first char of padding to 0x80. There is always room. */ *p++ = 0x80; /* Bytes of padding needed to make 56 bytes (-8..55) */ count = 56 - 1 - count; if (count < 0) { /* Padding forces an extra block */ memset(p, 0, count + 8); byteSwap(ctx->in, 16); MD5Transform(ctx->buf, ctx->in); p = (md5byte *)ctx->in; count = 56; } memset(p, 0, count); byteSwap(ctx->in, 14); /* Append length in bits and transform */ ctx->in[14] = ctx->bytes[0] << 3; ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29; MD5Transform(ctx->buf, ctx->in); byteSwap(ctx->buf, 4); memcpy(digest, ctx->buf, 16); memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */ } /* The four core functions - F1 is optimized somewhat */ /* #define F1(x, y, z) (x & y | ~x & z) */ #define F1(x, y, z) (z ^ (x & (y ^ z))) #define F2(x, y, z) F1(z, x, y) #define F3(x, y, z) (x ^ y ^ z) #define F4(x, y, z) (y ^ (x | ~z)) /* This is the central step in the MD5 algorithm. */ #define MD5STEP(f,w,x,y,z,in,s) \ (w += f(x,y,z) + in, w = (w<>(32-s)) + x) /* * The core of the MD5 algorithm, this alters an existing MD5 hash to * reflect the addition of 16 longwords of new data. MD5Update blocks * the data and converts bytes into longwords for this routine. */ void MD5Transform(UWORD32 buf[4], UWORD32 const in[16]) { register UWORD32 a, b, c, d; a = buf[0]; b = buf[1]; c = buf[2]; d = buf[3]; MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); buf[0] += a; buf[1] += b; buf[2] += c; buf[3] += d; } exiv2-0.23/contrib/organize/helpers.hpp0000644000175000017500000001360211154700466017746 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2009 Brad Schick * * This file is part of the organize tool. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /* File: helpers.hpp Version: $Rev: 1762 $ Author(s): Brad Schick (brad) History: 19-Jan-09, brad: created */ // ***************************************************************************** #ifndef HELPERS_HPP_ #define HELPERS_HPP_ #include #define BOOST_FILESYSTEM_NO_DEPRECATED namespace fs = boost::filesystem; typedef std::string (*pfunc)(const Exiv2::Image *image, const fs::path &path); // This would be a lot smaller if Exiv2 had support // for unified metadata std::string exif_date(const Exiv2::Image *image, const fs::path &path); std::string exif_year(const Exiv2::Image *image, const fs::path &path); std::string exif_month(const Exiv2::Image *image, const fs::path &path); std::string exif_day(const Exiv2::Image *image, const fs::path &path); std::string iptc_date(const Exiv2::Image *image, const fs::path &path); std::string iptc_year(const Exiv2::Image *image, const fs::path &path); std::string iptc_month(const Exiv2::Image *image, const fs::path &path); std::string iptc_day(const Exiv2::Image *image, const fs::path &path); std::string file_date(const Exiv2::Image *image, const fs::path &path); std::string file_year(const Exiv2::Image *image, const fs::path &path); std::string file_month(const Exiv2::Image *image, const fs::path &path); std::string file_day(const Exiv2::Image *image, const fs::path &path); /*std::string xmp_date(const Exiv2::Image *image, const fs::path &path); std::string xmp_year(const Exiv2::Image *image, const fs::path &path); std::string xmp_month(const Exiv2::Image *image, const fs::path &path); std::string xmp_day(const Exiv2::Image *image, const fs::path &path);*/ std::string exif_time(const Exiv2::Image *image, const fs::path &path); std::string exif_hour(const Exiv2::Image *image, const fs::path &path); std::string exif_minute(const Exiv2::Image *image, const fs::path &path); std::string exif_second(const Exiv2::Image *image, const fs::path &path); std::string iptc_time(const Exiv2::Image *image, const fs::path &path); std::string iptc_hour(const Exiv2::Image *image, const fs::path &path); std::string iptc_minute(const Exiv2::Image *image, const fs::path &path); std::string iptc_second(const Exiv2::Image *image, const fs::path &path); std::string file_time(const Exiv2::Image *image, const fs::path &path); std::string file_hour(const Exiv2::Image *image, const fs::path &path); std::string file_minute(const Exiv2::Image *image, const fs::path &path); std::string file_second(const Exiv2::Image *image, const fs::path &path); /*std::string xmp_time(const Exiv2::Image *image, const fs::path &path); std::string xmp_hour(const Exiv2::Image *image, const fs::path &path); std::string xmp_minute(const Exiv2::Image *image, const fs::path &path); std::string xmp_second(const Exiv2::Image *image, const fs::path &path);*/ std::string exif_dimension(const Exiv2::Image *image, const fs::path &path); std::string exif_width(const Exiv2::Image *image, const fs::path &path); std::string exif_height(const Exiv2::Image *image, const fs::path &path); std::string file_dimension(const Exiv2::Image *image, const fs::path &path); std::string file_width(const Exiv2::Image *image, const fs::path &path); std::string file_height(const Exiv2::Image *image, const fs::path &path); /*std::string xmp_dimension(const Exiv2::Image *image, const fs::path &path); std::string xmp_width(const Exiv2::Image *image, const fs::path &path); std::string xmp_height(const Exiv2::Image *image, const fs::path &path);*/ std::string exif_model(const Exiv2::Image *image, const fs::path &path); std::string exif_make(const Exiv2::Image *image, const fs::path &path); /*std::string xmp_model(const Exiv2::Image *image, const fs::path &path); std::string xmp_make(const Exiv2::Image *image, const fs::path &path);*/ std::string exif_speed(const Exiv2::Image *image, const fs::path &path); //std::string xmp_speed(const Exiv2::Image *image, const fs::path &path); std::string exif_aperture(const Exiv2::Image *image, const fs::path &path); //std::string xmp_aperture(const Exiv2::Image *image, const fs::path &path); std::string exif_focal(const Exiv2::Image *image, const fs::path &path); //std::string xmp_focal(const Exiv2::Image *image, const fs::path &path); std::string exif_distance(const Exiv2::Image *image, const fs::path &path); //std::string xmp_distance(const Exiv2::Image *image, const fs::path &path); std::string exif_meter(const Exiv2::Image *image, const fs::path &path); //std::string xmp_meter(const Exiv2::Image *image, const fs::path &path); std::string exif_macro(const Exiv2::Image *image, const fs::path &path); std::string exif_orientation(const Exiv2::Image *image, const fs::path &path); std::string exif_lens(const Exiv2::Image *image, const fs::path &path); std::string exif_keyword(const Exiv2::Image *image, const fs::path &path); std::string iptc_keyword(const Exiv2::Image *image, const fs::path &path); //std::string xmp_keyword(const Exiv2::Image *image, const fs::path &path); std::string exif_iso(const Exiv2::Image *image, const fs::path &path); #endif //HELPERS_HPP_ exiv2-0.23/contrib/organize/MD5.h0000644000175000017500000000303211141017140016307 0ustar andreasandreas#ifndef __MD5_h__ #define __MD5_h__ /* * This is the header file for the MD5 message-digest algorithm. * The algorithm is due to Ron Rivest. This code was * written by Colin Plumb in 1993, no copyright is claimed. * This code is in the public domain; do with it what you wish. * * Equivalent code is available from RSA Data Security, Inc. * This code has been tested against that, and is equivalent, * except that you don't need to include two pages of legalese * with every copy. * * To compute the message digest of a chunk of bytes, declare an * MD5_CTX structure, pass it to MD5Init, call MD5Update as * needed on buffers full of bytes, and then call MD5Final, which * will fill a supplied 16-byte array with the digest. * * Changed so as no longer to depend on Colin Plumb's `usual.h' * header definitions; now uses stuff from dpkg's config.h * - Ian Jackson . * Still in the public domain. */ #include #ifdef EXV_HAVE_STDINT_H # include #endif /* MSVC doesn't provide C99 types, but it has MS specific variants */ #ifdef _MSC_VER typedef unsigned __int32 uint32_t; #endif typedef unsigned char md5byte; typedef uint32_t UWORD32; struct MD5_CTX { UWORD32 buf[4]; UWORD32 bytes[2]; UWORD32 in[16]; }; extern void MD5Init(struct MD5_CTX *context); extern void MD5Update(struct MD5_CTX *context, md5byte const *buf, unsigned len); extern void MD5Final(unsigned char digest[16], struct MD5_CTX *context); extern void MD5Transform(UWORD32 buf[4], UWORD32 const in[16]); #endif exiv2-0.23/contrib/organize/boost.mk0000644000175000017500000000052111141017140017230 0ustar andreasandreas# Boost configuration for organize - change paths and library names as needed BOOST_INC_DIR = /usr/local/include/boost-1_37 BOOST_LIBS = /usr/local/lib/libboost_system-gcc43-mt-1_37.a /usr/local/lib/libboost_filesystem-gcc43-mt-1_37.a /usr/local/lib/libboost_regex-gcc43-mt-1_37.a /usr/local/lib/libboost_program_options-gcc43-mt-1_37.a exiv2-0.23/contrib/organize/Makefile0000644000175000017500000001042611732641407017235 0ustar andreasandreas# ************************************************************* -*- Makefile -*- # # Copyright (C) 2004-2012 Andreas Huggel # # This Makefile is part of the Exiv2 distribution. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # 3. The name of the author may not be used to endorse or promote # products derived from this software without specific prior # written permission. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER # IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN # IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # File: Makefile # Version: $Rev: 2681 $ # Author(s): Andreas Huggel (ahu) # History: 31-Jan-09, ahu: created # # Description: # Simple Makefile to build the organize application. Requires installed # exiv2 library and headers. Adapted from samples/Makefile. # # Restrictions: # Requires GNU make. # # ****************************************************************************** # Default make target all: ozbin # Include system configuration top_srcdir = ../.. include $(top_srcdir)/config/config.mk include boost.mk # ****************************************************************************** # Source files # Source files for the organize application OZMAIN = organize.cpp OZSRC = helpers.cpp MD5.cpp # ****************************************************************************** # Initialisations SHELL = /bin/sh .SUFFIXES: .SUFFIXES: .c .cpp .o .so .PRECIOUS: %.cpp CPPFLAGS := -I$(BOOST_INC_DIR) `pkg-config exiv2 --cflags` ifdef HAVE_STDINT CPPFLAGS += -DEXV_HAVE_STDINT_H=1 endif LDFLAGS := $(BOOST_LIBS) `pkg-config exiv2 --libs` OZOBJ = $(OZSRC:.cpp=.o) $(OZMAIN:.cpp=.o) OZBIN = $(OZMAIN:.cpp=) OZEXE = $(OZMAIN:.cpp=$(EXEEXT)) ifdef DEP_TRACKING DEP = $(OZMAIN:%.cpp=$(DEPDIR)/%.d) $(OZSRC:%.cpp=$(DEPDIR)/%.d) endif # ****************************************************************************** # Rules ozbin: $(OZBIN) $(OZOBJ): %.o: %.cpp $(COMPILE.cc) -o $@ $< @$(MAKEDEPEND) @$(POSTDEPEND) %.ii: %.cpp set -e; \ $(CXXCPP) -E $(CPPFLAGS) $< | sed '/^[ ]*$$/d' > $@ # ****************************************************************************** # Targets .PHONY: all ozbin relink binclean install uninstall mostlyclean clean distclean maintainer-clean ifdef DEP_TRACKING # Include targets from dependency files -include $(DEP) endif $(OZBIN): $(OZOBJ) $(LIBTOOL) --mode=link $(LINK.cc) -o $@ $(OZOBJ) relink: binclean organize install: $(INSTALL_DIRS) $(DESTDIR)$(bindir) @$(LIBTOOL) --mode=install $(INSTALL_PROGRAM) $(OZEXE) $(DESTDIR)$(bindir)/$(OZEXE) uninstall: @$(LIBTOOL) --mode=uninstall $(RM) $(DESTDIR)$(bindir)/$(OZEXE) -rmdir $(DESTDIR)$(bindir) # Remove binaries, e.g., to relink them binclean: $(RM) $(OZEXE) mostlyclean: $(RM) core $(RM) $(OZMAIN:.cpp=.ii) $(OZSRC:.cpp=.ii) $(RM) $(OZMAIN:%.cpp=.libs/%.d) $(OZSRC:%.cpp=.libs/%.d) -rmdir .libs $(RM) $(OZOBJ) clean: binclean mostlyclean # Run `make distclean' from the top source directory to also remove # files created by configuring the program. distclean: clean ifdef DEP_TRACKING $(RM) $(DEP) -rmdir $(DEPDIR) endif $(RM) *~ *.bak *# # This command is intended for maintainers to use; it deletes files # that may need special tools to rebuild. maintainer-clean: uninstall distclean exiv2-0.23/contrib/organize/README0000644000175000017500000000024711141017140016436 0ustar andreasandreasorganize uses the Boost library (http://www.boost.org). Configuration settings for Boost are in the file boost.mk in this directory and should be changed as required. exiv2-0.23/contrib/diffeps0000755000175000017500000000056611613276470015333 0ustar andreasandreas#!/bin/sh if [ "$#" -ne 2 ] ; then echo "Usage: $0 file1.eps file2.eps" exit 1 fi suffix='0a8baf61-6321-4899-86e8-8bf9ebd002b3' sed 's/\r$//; s/$//; s/\r/\n/g' < "$1" > "$1.$suffix" sed 's/\r$//; s/$//; s/\r/\n/g' < "$2" > "$2.$suffix" diff -a -u "$1.$suffix" "$2.$suffix" exitcode="$?" rm -f "$1.$suffix" "$2.$suffix" exit "$exitcode" exiv2-0.23/contrib/makeUniversal0000755000175000017500000000152511744161045016511 0ustar andreasandreas#!/bin/bash ## # makeUniversal - combine .i386 and .x86_64 build results into .libs # this script is called by buildForMac ## ## # search for directories called .x86_64 # run every file and lipo .x86_64/file .x86_64/file -> .libs/file for D in $(find . -name ".x86_64"); do for F in $(find $(dirname $D)/.x86_64 -type f); do f=$(echo $F | sed -E -e "s/.x86_64/.i386/") U=$(echo $F | sed -E -e "s/.x86_64/.libs/") if [[ -e $f && -e $F ]]; then # echo $F $f -> $U lipo -arch i386 $f -arch x86_64 $F -create -output $U if [ $? != '0' ]; then echo FAILED lipo -arch i386 $f -arch x86_64 $F -create -output $U else eval $(stat -s $U) s=$(printf "%10s" ${st_size}) echo $(lipo -info $U|sed -E -e "s/Architectures in the fat file://" -e "s/ are://" -e "s#$U##" ) "$s" $U fi fi done done # That's all Folks! ## exiv2-0.23/contrib/buildForMac0000755000175000017500000000276111744124202016067 0ustar andreasandreas#!/bin/bash ## # buildForMac # example: contrib/buildForMac --[dis|en]able-shared # ## ## # test OS level (L=9 SL==10 Lion = 11, ML=12) LION="" let os=$(uname -a | cut -d' ' -f 3 | cut -d'.' -f 1) if [ $(( os >= 11 )) ]; then LION="--with-zlib=/usr/lib" fi if [ ! -d contrib ]; then echo "you are in the wrong directory - please run $0 in the main directory (which includes contrib and src)" exit 1 fi if [ ! -e configure ]; then make config ; fi if [ -z $TARGET ]; then export TARGET="MACOSX_DEPLOYMENT_TARGET=10.5" ; fi # version=$(grep EXIV2_LTVERSION config/config.mk | cut "-d " -f 3 | cut -d: -f 1) # lib=libexiv2.$version.dylib build() { make clean ./configure CFLAGS="$arch" CXXFLAGS="$arch" LDFLAGS="$arch -L${PWD}/xmpsdk/src" OBJCFLAGS="$arch" OBJCXXFLAGS="$arch" $TARGET $LION "$@" make CFLAGS="$arch" CXXFLAGS="$arch" LDFLAGS="$arch -L${PWD}/xmpsdk/src" OBJCFLAGS="$arch" OBJCXXFLAGS="$arch" $TARGET all # make CFLAGS="$arch" CXXFLAGS="$arch" LDFLAGS="$arch -L${PWD}/xmpsdk/src" OBJCFLAGS="$arch" OBJCXXFLAGS="$arch" $TARGET samples if [ "$?" != "0" ]; then echo build failed exit fi } ## # build one architecture at a time for arch in '-arch i386' '-arch x86_64' ; do echo arch = $arch a=${arch:6:100} build "$@" ## # copy .libs to .arch for d in $(find . -name ".libs" -type d); do D=$(dirname $d)/.$a ditto $d $D done done ## # combine the builds into a universal $(dirname $0)/makeUniversal # That's all Folks! ## exiv2-0.23/contrib/createEpsTestfiles0000755000175000017500000000122611625345747017512 0ustar andreasandreas#!/bin/sh set -eu if [ "$#" -ne 1 ]; then echo "Usage: $0 BASENAME" exit 1 fi set -x bin=../../../src $bin/exiv2 -V exiv2version="`$bin/exiv2 -V | sed -n '1 s,^exiv2 [^ ]* \([^ ]*\).*,\1,p'`" rm -f $1.xmp $bin/exiv2 -f -eX $1.eps cp $1.eps $1.eps.delxmp if $bin/exiv2 -dx $1.eps.delxmp; then sed -i "s,%Exiv2Version: $exiv2version,%Exiv2Version: _Exiv2Version_," $1.eps.delxmp else rm -f $1.eps.delxmp fi cp $1.eps $1.eps.newxmp cp eps-test-newxmp.exv $1.eps.exv if $bin/exiv2 -ix $1.eps.newxmp; then sed -i "s,%Exiv2Version: $exiv2version,%Exiv2Version: _Exiv2Version_," $1.eps.newxmp else rm -f $1.eps.newxmp fi rm -f $1.eps.exv exiv2-0.23/samples/0000755000175000017500000000000011745263717013770 5ustar andreasandreasexiv2-0.23/samples/xmpparser-test.cpp0000644000175000017500000000461411411621067017461 0ustar andreasandreas// ***************************************************************** -*- C++ -*- // xmpparser-test.cpp, $Rev: 2286 $ // Read an XMP packet from a file, parse and re-serialize it. #include #include #include #include int main(int argc, char* const argv[]) try { if (argc != 2) { std::cout << "Usage: " << argv[0] << " file\n"; return 1; } std::string filename(argv[1]); Exiv2::DataBuf buf = Exiv2::readFile(filename); std::string xmpPacket; xmpPacket.assign(reinterpret_cast(buf.pData_), buf.size_); std::cerr << "-----> Decoding XMP data read from " << filename << " <-----\n"; Exiv2::XmpData xmpData; if (0 != Exiv2::XmpParser::decode(xmpData, xmpPacket)) { std::string error(argv[1]); error += ": Failed to parse file contents (XMP packet)"; throw Exiv2::Error(1, error); } if (xmpData.empty()) { std::string error(argv[1]); error += ": No XMP properties found in the XMP packet"; throw Exiv2::Error(1, error); } for (Exiv2::XmpData::const_iterator md = xmpData.begin(); md != xmpData.end(); ++md) { std::cout << std::setfill(' ') << std::left << std::setw(44) << md->key() << " " << std::setw(9) << std::setfill(' ') << std::left << md->typeName() << " " << std::dec << std::setw(3) << std::setfill(' ') << std::right << md->count() << " " << std::dec << md->value() << std::endl; } filename += "-new"; std::cerr << "-----> Encoding XMP data to write to " << filename << " <-----\n"; if (0 != Exiv2::XmpParser::encode(xmpPacket, xmpData)) { std::string error(argv[1]); error += ": Failed to encode the XMP data"; throw Exiv2::Error(1, error); } Exiv2::FileIo file(filename); if (file.open("wb") != 0) { throw Exiv2::Error(10, filename, "wb", Exiv2::strError()); } if (file.write(reinterpret_cast(xmpPacket.data()), static_cast(xmpPacket.size())) == 0) { throw Exiv2::Error(2, filename, Exiv2::strError(), "FileIo::write"); } Exiv2::XmpParser::terminate(); return 0; } catch (Exiv2::AnyError& e) { std::cout << "Caught Exiv2 exception '" << e << "'\n"; return -1; } exiv2-0.23/samples/xmpparse.cpp0000644000175000017500000000323311411621067016316 0ustar andreasandreas// ***************************************************************** -*- C++ -*- // xmpparse.cpp, $Rev: 2286 $ // Read an XMP packet from a file, parse it and print all (known) properties. #include #include #include #include int main(int argc, char* const argv[]) try { if (argc != 2) { std::cout << "Usage: " << argv[0] << " file\n"; return 1; } Exiv2::DataBuf buf = Exiv2::readFile(argv[1]); std::string xmpPacket; xmpPacket.assign(reinterpret_cast(buf.pData_), buf.size_); Exiv2::XmpData xmpData; if (0 != Exiv2::XmpParser::decode(xmpData, xmpPacket)) { std::string error(argv[1]); error += ": Failed to parse file contents (XMP packet)"; throw Exiv2::Error(1, error); } if (xmpData.empty()) { std::string error(argv[1]); error += ": No XMP properties found in the XMP packet"; throw Exiv2::Error(1, error); } for (Exiv2::XmpData::const_iterator md = xmpData.begin(); md != xmpData.end(); ++md) { std::cout << std::setfill(' ') << std::left << std::setw(44) << md->key() << " " << std::setw(9) << std::setfill(' ') << std::left << md->typeName() << " " << std::dec << std::setw(3) << std::setfill(' ') << std::right << md->count() << " " << std::dec << md->value() << std::endl; } Exiv2::XmpParser::terminate(); return 0; } catch (Exiv2::AnyError& e) { std::cout << "Caught Exiv2 exception '" << e << "'\n"; return -1; } exiv2-0.23/samples/iptctest.cpp0000644000175000017500000001245311411621067016322 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* Abstract : Sample program test the Iptc reading and writing. This is not designed to be a robust application. File : iptctest.cpp Version : $Rev: 2286 $ Author(s): Brad Schick (brad) History : 01-Aug-04, brad: created */ // ***************************************************************************** // included header files #include #include #include #include using namespace Exiv2; bool processLine(const std::string& line, int num, IptcData &iptcData); void processAdd(const std::string& line, int num, IptcData &iptcData); void processRemove(const std::string& line, int num, IptcData &iptcData); void processModify(const std::string& line, int num, IptcData &iptcData); // ***************************************************************************** // Main int main(int argc, char* const argv[]) { try { if (argc != 2) { std::cout << "Usage: " << argv[0] << " image\n"; std::cout << "Commands read from stdin.\n"; return 1; } Image::AutoPtr image = ImageFactory::open(argv[1]); assert (image.get() != 0); image->readMetadata(); // Process commands std::string line; int num = 0; std::getline(std::cin, line); while (line.length() && processLine(line, ++num, image->iptcData())) { std::getline(std::cin, line); } // Save any changes image->writeMetadata(); return 0; } catch (AnyError& e) { std::cout << "Caught Exiv2 exception '" << e << "'\n"; return -1; } } bool processLine(const std::string& line, int num, IptcData &iptcData) { switch (line.at(0)) { case 'a': case 'A': processAdd(line, num, iptcData); break; case 'r': case 'R': processRemove(line, num, iptcData); break; case 'm': case 'M': processModify(line, num, iptcData); break; case 'q': case 'Q': return false; default: std::ostringstream os; os << "Unknown command (" << line.at(0) << ") at line " << num; throw Error(1, os.str()); } return true; } void processAdd(const std::string& line, int num, IptcData &iptcData) { std::string::size_type keyStart = line.find_first_not_of(" \t", 1); std::string::size_type keyEnd = line.find_first_of(" \t", keyStart+1); std::string::size_type dataStart = line.find_first_not_of(" \t", keyEnd+1); if (keyStart == std::string::npos || keyEnd == std::string::npos || dataStart == std::string::npos) { std::ostringstream os; os << "Invalid \'a\' command at line " << num; throw Error(1, os.str()); } std::string key(line.substr(keyStart, keyEnd-keyStart)); IptcKey iptcKey(key); std::string data(line.substr(dataStart)); // if data starts and ends with quotes, remove them if (data.at(0) == '\"' && data.at(data.size()-1) == '\"') { data = data.substr(1, data.size()-2); } TypeId type = IptcDataSets::dataSetType(iptcKey.tag(), iptcKey.record()); Value::AutoPtr value = Value::create(type); value->read(data); int rc = iptcData.add(iptcKey, value.get()); if (rc) { throw Error(1, "Iptc dataset already exists and is not repeatable"); } } void processRemove(const std::string& line, int num, IptcData &iptcData) { std::string::size_type keyStart = line.find_first_not_of(" \t", 1); if (keyStart == std::string::npos) { std::ostringstream os; os << "Invalid \'r\' command at line " << num; throw Error(1, os.str()); } const std::string key( line.substr(keyStart) ); IptcKey iptcKey(key); IptcData::iterator iter = iptcData.findKey(iptcKey); if (iter != iptcData.end()) { iptcData.erase(iter); } } void processModify(const std::string& line, int num, IptcData &iptcData) { std::string::size_type keyStart = line.find_first_not_of(" \t", 1); std::string::size_type keyEnd = line.find_first_of(" \t", keyStart+1); std::string::size_type dataStart = line.find_first_not_of(" \t", keyEnd+1); if (keyStart == std::string::npos || keyEnd == std::string::npos || dataStart == std::string::npos) { std::ostringstream os; os << "Invalid \'m\' command at line " << num; throw Error(1, os.str()); } std::string key(line.substr(keyStart, keyEnd-keyStart)); IptcKey iptcKey(key); std::string data(line.substr(dataStart)); // if data starts and ends with quotes, remove them if (data.at(0) == '\"' && data.at(data.size()-1) == '\"') { data = data.substr(1, data.size()-2); } TypeId type = IptcDataSets::dataSetType(iptcKey.tag(), iptcKey.record()); Value::AutoPtr value = Value::create(type); value->read(data); IptcData::iterator iter = iptcData.findKey(iptcKey); if (iter != iptcData.end()) { iter->setValue(value.get()); } else { int rc = iptcData.add(iptcKey, value.get()); if (rc) { throw Error(1, "Iptc dataset already exists and is not repeatable"); } } } exiv2-0.23/samples/easyaccess-test.cpp0000644000175000017500000000514611472501061017562 0ustar andreasandreas// ***************************************************************** -*- C++ -*- // easyaccess-test.cpp, $Rev: 2380 $ // Sample program using high-level metadata access functions // included header files #include #include #include #include typedef Exiv2::ExifData::const_iterator (*EasyAccessFct)(const Exiv2::ExifData& ed); struct EasyAccess { const char* label_; EasyAccessFct findFct_; }; static const EasyAccess easyAccess[] = { { "Orientation", Exiv2::orientation }, { "ISO speed", Exiv2::isoSpeed }, { "Flash bias", Exiv2::flashBias }, { "Exposure mode", Exiv2::exposureMode }, { "Scene mode", Exiv2::sceneMode }, { "Macro mode", Exiv2::macroMode }, { "Image quality", Exiv2::imageQuality }, { "White balance", Exiv2::whiteBalance }, { "Lens name", Exiv2::lensName }, { "Saturation", Exiv2::saturation }, { "Sharpness", Exiv2::sharpness }, { "Contrast", Exiv2::contrast }, { "Scene capture type", Exiv2::sceneCaptureType }, { "Metering mode", Exiv2::meteringMode }, { "Camera make", Exiv2::make }, { "Camera model", Exiv2::model }, { "Exposure time", Exiv2::exposureTime }, { "FNumber", Exiv2::fNumber }, { "Subject distance", Exiv2::subjectDistance }, { "Camera serial number", Exiv2::serialNumber }, { "Focal length", Exiv2::focalLength }, { "AF point", Exiv2::afPoint } }; int main(int argc, char **argv) try { if (argc != 2) { std::cout << "Usage: " << argv[0] << " file\n"; return 1; } Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(argv[1]); assert (image.get() != 0); image->readMetadata(); Exiv2::ExifData& ed = image->exifData(); for (unsigned int i = 0; i < EXV_COUNTOF(easyAccess); ++i) { Exiv2::ExifData::const_iterator pos = easyAccess[i].findFct_(ed); std::cout << std::setw(20) << std::left << easyAccess[i].label_; if (pos != ed.end()) { std::cout << " (" << std::setw(35) << pos->key() << ") : " << pos->print(&ed) << "\n"; } else { std::cout << " (" << std::setw(35) << " " << ") : \n"; } } return 0; } catch (Exiv2::AnyError& e) { std::cout << "Caught Exiv2 exception '" << e << "'\n"; return -1; } exiv2-0.23/samples/exifdata-test.cpp0000644000175000017500000001130111411621067017214 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* Abstract : ExifData assignment and copy construction unit tests File : exifdata-test.cpp Version : $Rev: 2286 $ Author(s): Andreas Huggel (ahu) History : 20-Feb-05, ahu: created */ // ***************************************************************************** // included header files #include #include #include #include #include void write(const std::string& file, Exiv2::ExifData& ed); void print(const std::string& file); // ***************************************************************************** // Main int main(int argc, char* const argv[]) { try { if (argc != 2) { std::cout << "Usage: " << argv[0] << " file\n"; return 1; } std::string file(argv[1]); Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(file); assert (image.get() != 0); image->readMetadata(); Exiv2::ExifData &ed = image->exifData(); if (ed.empty()) { std::string error = file + ": No Exif data found in the file"; throw Exiv2::Error(1, error); } std::cout << "Copy construction, non-intrusive changes\n"; Exiv2::ExifData ed1(ed); ed1["Exif.Image.DateTime"] = "Sunday, 11am"; ed1["Exif.Image.Orientation"] = uint16_t(2); ed1["Exif.Photo.DateTimeOriginal"] = "Sunday, 11am"; ed1["Exif.Photo.MeteringMode"] = uint16_t(1); ed1["Exif.Iop.InteroperabilityIndex"] = "123"; // ed1["Exif.Thumbnail.Orientation"] = uint16_t(2); write(file, ed1); print(file); std::cout << "----------------------------------------------\n"; std::cout << "Copy construction, intrusive changes\n"; Exiv2::ExifData ed2(ed); ed2["Exif.Image.DateTime"] = "Sunday, 11am and ten minutes"; ed2["Exif.Image.Orientation"] = "2 3 4 5"; ed2["Exif.Photo.DateTimeOriginal"] = "Sunday, 11am and ten minutes"; ed2["Exif.Photo.MeteringMode"] = "1 2 3 4 5 6"; ed2["Exif.Iop.InteroperabilityIndex"] = "1234"; ed2["Exif.Thumbnail.Orientation"] = "2 3 4 5 6"; write(file, ed2); print(file); std::cout << "----------------------------------------------\n"; std::cout << "Assignment, non-intrusive changes\n"; Exiv2::ExifData ed3; ed3["Exif.Iop.InteroperabilityVersion"] = "Test 6 Iop tag"; ed3["Exif.Thumbnail.Artist"] = "Test 6 Ifd1 tag"; ed3 = ed; ed3["Exif.Image.DateTime"] = "Sunday, 11am"; ed3["Exif.Image.Orientation"] = uint16_t(2); ed3["Exif.Photo.DateTimeOriginal"] = "Sunday, 11am"; ed3["Exif.Photo.MeteringMode"] = uint16_t(1); ed3["Exif.Iop.InteroperabilityIndex"] = "123"; ed3["Exif.Thumbnail.Orientation"] = uint16_t(2); write(file, ed3); print(file); std::cout << "----------------------------------------------\n"; std::cout << "Assignment, intrusive changes\n"; Exiv2::ExifData ed4; ed4["Exif.Iop.InteroperabilityVersion"] = "Test 6 Iop tag"; ed4["Exif.Thumbnail.Artist"] = "Test 6 Ifd1 tag"; ed4 = ed; ed4["Exif.Image.DateTime"] = "Sunday, 11am and ten minutes"; ed4["Exif.Image.Orientation"] = "2 3 4 5"; ed4["Exif.Photo.DateTimeOriginal"] = "Sunday, 11am and ten minutes"; ed4["Exif.Photo.MeteringMode"] = uint16_t(1); ed4["Exif.Iop.InteroperabilityIndex"] = "123"; ed4["Exif.Thumbnail.Orientation"] = uint16_t(2); write(file, ed4); print(file); return 0; } catch (Exiv2::AnyError& e) { std::cout << "Caught Exiv2 exception '" << e << "'\n"; return -1; } } void write(const std::string& file, Exiv2::ExifData& ed) { Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(file); assert (image.get() != 0); image->setExifData(ed); image->writeMetadata(); } void print(const std::string& file) { Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(file); assert (image.get() != 0); image->readMetadata(); Exiv2::ExifData &ed = image->exifData(); Exiv2::ExifData::const_iterator end = ed.end(); for (Exiv2::ExifData::const_iterator i = ed.begin(); i != end; ++i) { std::cout << std::setw(45) << std::setfill(' ') << std::left << i->key() << " " << "0x" << std::setw(4) << std::setfill('0') << std::right << std::hex << i->tag() << " " << std::setw(12) << std::setfill(' ') << std::left << i->ifdName() << " " << std::setw(9) << std::setfill(' ') << std::left << i->typeName() << " " << std::dec << std::setw(3) << std::setfill(' ') << std::right << i->count() << " " << std::dec << i->value() << "\n"; } } exiv2-0.23/samples/tiff-test.cpp0000644000175000017500000000632411411621067016370 0ustar andreasandreas// ***************************************************************** -*- C++ -*- // tiff-test.cpp, $Rev: 2286 $ // First and very simple TIFF write test. #include #include #include #include #include using namespace Exiv2; void print(const ExifData& exifData); void mini1(const char* path); void mini9(const char* path); int main(int argc, char* const argv[]) try { if (argc != 2) { std::cout << "Usage: " << argv[0] << " file\n"; return 1; } const char* path = argv[1]; mini1(path); mini9(path); return 0; } catch (const AnyError& e) { std::cout << e << "\n"; } void mini1(const char* path) { ExifData exifData; Blob blob; WriteMethod wm; // Write nothing to a new structure, without a previous binary image wm = ExifParser::encode(blob, 0, 0, bigEndian, exifData); assert(wm == wmIntrusive); assert(blob.size() == 0); std::cout << "Test 1: Writing empty Exif data without original binary data: ok.\n"; // Write nothing, this time with a previous binary image DataBuf buf = readFile(path); wm = ExifParser::encode(blob, buf.pData_, buf.size_, bigEndian, exifData); assert(wm == wmIntrusive); assert(blob.size() == 0); std::cout << "Test 2: Writing empty Exif data with original binary data: ok.\n"; // Write something to a new structure, without a previous binary image exifData["Exif.Photo.DateTimeOriginal"] = "Yesterday at noon"; wm = ExifParser::encode(blob, 0, 0, bigEndian, exifData); assert(wm == wmIntrusive); std::cout << "Test 3: Wrote non-empty Exif data without original binary data:\n"; exifData.clear(); ByteOrder bo = ExifParser::decode(exifData, &blob[0], blob.size()); assert(bo == bigEndian); print(exifData); } void mini9(const char* path) { TiffImage tiffImage(BasicIo::AutoPtr(new FileIo(path)), false); tiffImage.readMetadata(); std::cout << "MIME type: " << tiffImage.mimeType() << "\n"; std::cout << "Image size: " << tiffImage.pixelWidth() << " x " << tiffImage.pixelHeight() << "\n"; ExifData& exifData = tiffImage.exifData(); std::cout << "Before\n"; print(exifData); std::cout << "======\n"; exifData["Exif.Photo.DateTimeOriginal"] = "Yesterday at noon"; std::cout << "After\n"; print(exifData); tiffImage.writeMetadata(); } void print(const ExifData& exifData) { if (exifData.empty()) { std::string error("No Exif data found in the file"); throw Exiv2::Error(1, error); } Exiv2::ExifData::const_iterator end = exifData.end(); for (Exiv2::ExifData::const_iterator i = exifData.begin(); i != end; ++i) { std::cout << std::setw(44) << std::setfill(' ') << std::left << i->key() << " " << "0x" << std::setw(4) << std::setfill('0') << std::right << std::hex << i->tag() << " " << std::setw(9) << std::setfill(' ') << std::left << i->typeName() << " " << std::dec << std::setw(3) << std::setfill(' ') << std::right << i->count() << " " << std::dec << i->value() << "\n"; } } exiv2-0.23/samples/key-test.cpp0000644000175000017500000001156511445366253016245 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* Abstract : Key unit tests File : key-test.cpp Version : $Rev: 2348 $ Author(s): Andreas Huggel (ahu) History : 24-Aug-04, ahu: created */ // ***************************************************************************** // included header files #include #include #include #include using namespace Exiv2; int main() { int tc = 0; int rc = 0; std::string key("Exif.Iop.InteroperabilityVersion"); ExifKey ek(key); // operator<< tc += 1; std::ostringstream os; os << ek; if (os.str() != key) { std::cout << "Testcase failed (operator<<)" << std::endl; rc += 1; } // familyName tc += 1; if (std::string(ek.familyName()) != "Exif") { std::cout << "Testcase failed (familyName)" << std::endl; rc += 1; } // groupName tc += 1; if (ek.groupName() != "Iop") { std::cout << "Testcase failed (groupName)" << std::endl; rc += 1; } // tagName tc += 1; if (ek.tagName() != "InteroperabilityVersion") { std::cout << "Testcase failed (tagName)" << std::endl; rc += 1; } // tagName tc += 1; if (ek.tag() != 0x0002) { std::cout << "Testcase failed (tag)" << std::endl; rc += 1; } // ifdName tc += 1; if (std::string(ExifTags::ifdName(ek.groupName())) != "Iop") { std::cout << "Testcase failed (ifdName: " << std::endl; rc += 1; } // sectionName tc += 1; if (strcmp(ExifTags::sectionName(ek), "Interoperability") != 0) { std::cout << "Testcase failed (sectionName)" << std::endl; rc += 1; } // ----- // Copy constructor ExifKey ek2(ek); // operator<< tc += 1; std::ostringstream os2; os2 << ek2; if (os2.str() != key) { std::cout << "Testcase failed (operator<<)" << std::endl; rc += 1; } // familyName tc += 1; if (std::string(ek2.familyName()) != "Exif") { std::cout << "Testcase failed (familyName)" << std::endl; rc += 1; } // groupName tc += 1; if (ek2.groupName() != "Iop") { std::cout << "Testcase failed (groupName)" << std::endl; rc += 1; } // tagName tc += 1; if (ek2.tagName() != "InteroperabilityVersion") { std::cout << "Testcase failed (tagName)" << std::endl; rc += 1; } // tagName tc += 1; if (ek2.tag() != 0x0002) { std::cout << "Testcase failed (tag)" << std::endl; rc += 1; } // ifdName tc += 1; if (std::string(ExifTags::ifdName(ek2.groupName())) != "Iop") { std::cout << "Testcase failed (ifdName: " << std::endl; rc += 1; } // sectionName tc += 1; if (strcmp(ExifTags::sectionName(ek2), "Interoperability") != 0) { std::cout << "Testcase failed (sectionName)" << std::endl; rc += 1; } // ----- ExifKey ek4("Exif.Image.0x0110"); tc += 1; if (ek4.key() != "Exif.Image.Model") { std::cout << "Testcase failed (converted key)" << std::endl; rc += 1; } tc += 1; if (ek4.tagName() != "Model") { std::cout << "Testcase failed (converted tagName)" << std::endl; rc += 1; } // ----- ExifKey ek5("Exif.Nikon3.0x0007"); tc += 1; if (ek5.key() != "Exif.Nikon3.Focus") { std::cout << "Testcase failed (converted key)" << std::endl; rc += 1; } tc += 1; if (ek5.tagName() != "Focus") { std::cout << "Testcase failed (converted tagName)" << std::endl; rc += 1; } // ----- IptcKey ik1("Iptc.Envelope.0x0005"); tc += 1; if (ik1.key() != "Iptc.Envelope.Destination") { std::cout << "Testcase failed (converted Iptc key)" << std::endl; rc += 1; } tc += 1; if (ik1.tagName() != "Destination") { std::cout << "Testcase failed (converted tagName)" << std::endl; rc += 1; } tc += 1; if (ik1.recordName() != "Envelope") { std::cout << "Testcase failed (converted recordName)" << std::endl; rc += 1; } // ----- IptcKey ik2(0xabcd, 0x1234); tc += 1; if (ik2.key() != "Iptc.0x1234.0xabcd") { std::cout << "Testcase failed (unknown Iptc key)" << std::endl; rc += 1; } tc += 1; if (ik2.tagName() != "0xabcd") { std::cout << "Testcase failed (converted tagName)" << std::endl; rc += 1; } tc += 1; if (ik2.recordName() != "0x1234") { std::cout << "Testcase failed (converted recordName)" << std::endl; rc += 1; } // ----- if (rc == 0) { std::cout << "All " << tc << " testcases passed." << std::endl; } else { std::cout << rc << " of " << tc << " testcases failed." << std::endl; } } exiv2-0.23/samples/xmpsample.cpp0000644000175000017500000002123411664576615016510 0ustar andreasandreas// ***************************************************************** -*- C++ -*- // xmpsample.cpp, $Rev: 2639 $ // Sample/test for high level XMP classes. See also addmoddel.cpp #include #include #include #include #include #include bool isEqual(float a, float b) { double d = std::fabs(a - b); return d < 0.00001; } int main() try { // The XMP property container Exiv2::XmpData xmpData; // ------------------------------------------------------------------------- // Teaser: Setting XMP properties doesn't get much easier than this: xmpData["Xmp.dc.source"] = "xmpsample.cpp"; // a simple text value xmpData["Xmp.dc.subject"] = "Palmtree"; // an array item xmpData["Xmp.dc.subject"] = "Rubbertree"; // add a 2nd array item // a language alternative with two entries and without default xmpData["Xmp.dc.title"] = "lang=de-DE Sonnenuntergang am Strand"; xmpData["Xmp.dc.title"] = "lang=en-US Sunset on the beach"; // ------------------------------------------------------------------------- // Any properties can be set provided the namespace is known. Values of any // type can be assigned to an Xmpdatum, if they have an output operator. The // default XMP value type for unknown properties is a simple text value. xmpData["Xmp.dc.one"] = -1; xmpData["Xmp.dc.two"] = 3.1415; xmpData["Xmp.dc.three"] = Exiv2::Rational(5, 7); xmpData["Xmp.dc.four"] = uint16_t(255); xmpData["Xmp.dc.five"] = int32_t(256); xmpData["Xmp.dc.six"] = false; // In addition, there is a dedicated assignment operator for Exiv2::Value Exiv2::XmpTextValue val("Seven"); xmpData["Xmp.dc.seven"] = val; xmpData["Xmp.dc.eight"] = true; // Extracting values assert(xmpData["Xmp.dc.one"].toLong() == -1); assert(xmpData["Xmp.dc.one"].value().ok()); const Exiv2::Value &getv1 = xmpData["Xmp.dc.one"].value(); assert(isEqual(getv1.toFloat(), -1)); assert(getv1.ok()); assert(getv1.toRational() == Exiv2::Rational(-1, 1)); assert(getv1.ok()); const Exiv2::Value &getv2 = xmpData["Xmp.dc.two"].value(); assert(isEqual(getv2.toFloat(), 3.1415f)); assert(getv2.ok()); assert(getv2.toLong() == 3); assert(getv2.ok()); Exiv2::Rational R = getv2.toRational(); assert(getv2.ok()); assert(isEqual(static_cast(R.first) / R.second, 3.1415f )); const Exiv2::Value &getv3 = xmpData["Xmp.dc.three"].value(); assert(isEqual(getv3.toFloat(), 5.0f/7.0f)); assert(getv3.ok()); assert(getv3.toLong() == 0); // long(5.0 / 7.0) assert(getv3.ok()); assert(getv3.toRational() == Exiv2::Rational(5, 7)); assert(getv3.ok()); const Exiv2::Value &getv6 = xmpData["Xmp.dc.six"].value(); assert(getv6.toLong() == 0); assert(getv6.ok()); assert(getv6.toFloat() == 0.0); assert(getv6.ok()); assert(getv6.toRational() == Exiv2::Rational(0, 1)); assert(getv6.ok()); const Exiv2::Value &getv7 = xmpData["Xmp.dc.seven"].value(); getv7.toLong(); // this should fail assert(!getv7.ok()); const Exiv2::Value &getv8 = xmpData["Xmp.dc.eight"].value(); assert(getv8.toLong() == 1); assert(getv8.ok()); assert(getv8.toFloat() == 1.0); assert(getv8.ok()); assert(getv8.toRational() == Exiv2::Rational(1, 1)); assert(getv8.ok()); // Deleting an XMP property Exiv2::XmpData::iterator pos = xmpData.findKey(Exiv2::XmpKey("Xmp.dc.eight")); if (pos == xmpData.end()) throw Exiv2::Error(1, "Key not found"); xmpData.erase(pos); // ------------------------------------------------------------------------- // Exiv2 has specialized values for simple XMP properties, arrays of simple // properties and language alternatives. // Add a simple XMP property in a known namespace Exiv2::Value::AutoPtr v = Exiv2::Value::create(Exiv2::xmpText); v->read("image/jpeg"); xmpData.add(Exiv2::XmpKey("Xmp.dc.format"), v.get()); // Add an ordered array of text values. v = Exiv2::Value::create(Exiv2::xmpSeq); // or xmpBag or xmpAlt. v->read("1) The first creator"); // The sequence in which the array v->read("2) The second creator"); // elements are added is their v->read("3) And another one"); // order in the array. xmpData.add(Exiv2::XmpKey("Xmp.dc.creator"), v.get()); // Add a language alternative property v = Exiv2::Value::create(Exiv2::langAlt); v->read("lang=de-DE Hallo, Welt"); // The default doesn't need a v->read("Hello, World"); // qualifier xmpData.add(Exiv2::XmpKey("Xmp.dc.description"), v.get()); // According to the XMP specification, Xmp.tiff.ImageDescription is an // alias for Xmp.dc.description. Exiv2 treats an alias just like any // other property and leaves it to the application to implement specific // behaviour if desired. xmpData["Xmp.tiff.ImageDescription"] = "TIFF image description"; xmpData["Xmp.tiff.ImageDescription"] = "lang=de-DE TIFF Bildbeschreibung"; // ------------------------------------------------------------------------- // Register a namespace which Exiv2 doesn't know yet. This is only needed // when properties are added manually. If the XMP metadata is read from an // image, namespaces are decoded and registered at the same time. Exiv2::XmpProperties::registerNs("myNamespace/", "ns"); // ------------------------------------------------------------------------- // Add a property in the new custom namespace. xmpData["Xmp.ns.myProperty"] = "myValue"; // ------------------------------------------------------------------------- // There are no specialized values for structures, qualifiers and nested // types. However, these can be added by using an XmpTextValue and a path as // the key. // Add a structure Exiv2::XmpTextValue tv("16"); xmpData.add(Exiv2::XmpKey("Xmp.xmpDM.videoFrameSize/stDim:w"), &tv); tv.read("9"); xmpData.add(Exiv2::XmpKey("Xmp.xmpDM.videoFrameSize/stDim:h"), &tv); tv.read("inch"); xmpData.add(Exiv2::XmpKey("Xmp.xmpDM.videoFrameSize/stDim:unit"), &tv); // Add an element with a qualifier (using the namespace registered above) xmpData["Xmp.dc.publisher"] = "James Bond"; // creates an unordered array xmpData["Xmp.dc.publisher[1]/?ns:role"] = "secret agent"; // Add a qualifer to an array element of Xmp.dc.creator (added above) tv.read("programmer"); xmpData.add(Exiv2::XmpKey("Xmp.dc.creator[2]/?ns:role"), &tv); // Add an array of structures tv.read(""); // Clear the value tv.setXmpArrayType(Exiv2::XmpValue::xaBag); xmpData.add(Exiv2::XmpKey("Xmp.xmpBJ.JobRef"), &tv); // Set the array type. tv.setXmpArrayType(Exiv2::XmpValue::xaNone); tv.read("Birthday party"); xmpData.add(Exiv2::XmpKey("Xmp.xmpBJ.JobRef[1]/stJob:name"), &tv); tv.read("Photographer"); xmpData.add(Exiv2::XmpKey("Xmp.xmpBJ.JobRef[1]/stJob:role"), &tv); tv.read("Wedding ceremony"); xmpData.add(Exiv2::XmpKey("Xmp.xmpBJ.JobRef[2]/stJob:name"), &tv); tv.read("Best man"); xmpData.add(Exiv2::XmpKey("Xmp.xmpBJ.JobRef[2]/stJob:role"), &tv); // Add a creator contact info structure xmpData["Xmp.iptc.CreatorContactInfo/Iptc4xmpCore:CiAdrCity"] = "Kuala Lumpur"; xmpData["Xmp.iptc.CreatorContactInfo/Iptc4xmpCore:CiAdrCtry"] = "Malaysia"; xmpData["Xmp.iptc.CreatorContactInfo/Iptc4xmpCore:CiUrlWork"] = "http://www.exiv2.org"; // ------------------------------------------------------------------------- // Output XMP properties for (Exiv2::XmpData::const_iterator md = xmpData.begin(); md != xmpData.end(); ++md) { std::cout << std::setfill(' ') << std::left << std::setw(44) << md->key() << " " << std::setw(9) << std::setfill(' ') << std::left << md->typeName() << " " << std::dec << std::setw(3) << std::setfill(' ') << std::right << md->count() << " " << std::dec << md->value() << std::endl; } // ------------------------------------------------------------------------- // Serialize the XMP data and output the XMP packet std::string xmpPacket; if (0 != Exiv2::XmpParser::encode(xmpPacket, xmpData)) { throw Exiv2::Error(1, "Failed to serialize XMP data"); } std::cout << xmpPacket << "\n"; // Cleanup Exiv2::XmpParser::terminate(); return 0; } catch (Exiv2::AnyError& e) { std::cout << "Caught Exiv2 exception '" << e << "'\n"; return -1; } exiv2-0.23/samples/write-test.cpp0000644000175000017500000001562411411621067016575 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* Abstract : ExifData write unit tests Author(s): Andreas Huggel (ahu) Version : $Rev: 2286 $ Test procedure: $ rm -f test.jpg thumb.jpg iii ttt; $ ./exifprint ../test/img_1771.jpg > iii; $ cp ../test/img_1771.jpg ./test.jpg; $ ./makernote-test2 ../test/img_1771.jpg > ttt; $ diff iii ttt */ // ***************************************************************************** // included header files #include #include #include #include #include #include #include // ***************************************************************************** // local declarations using namespace Exiv2; void testCase(const std::string& file1, const std::string& file2, const std::string& thumb, const std::string& key, const std::string& value); void exifPrint(const ExifData& exifData); // ***************************************************************************** // Main int main(int argc, char* const argv[]) { try { if (argc != 3) { std::cout << "Usage: write-test file case\n\n" << "where case is an integer between 1 and 11\n"; return 1; } std::string testFile = argv[1]; std::istringstream iss(argv[2]); int testNo; iss >> testNo; int rc = 0; switch (testNo) { case 1: std::cerr << "Case 1: "; std::cerr << "Non-intrusive change to the standard Exif metadata\n"; testCase(testFile, "test1.jpg", "thumb1", "Exif.Photo.DateTimeOriginal", "1999:11:22 00:11:22"); break; case 2: std::cerr << "Case 2: "; std::cerr << "Non-intrusive change to the makernote metadata\n"; testCase(testFile, "test2.jpg", "thumb2", "Exif.Canon.OwnerName", "Chan YeeSend"); break; case 3: std::cerr << "Case 3: "; std::cerr << "Non-intrusive change to the Exif metadata (w/o makernote)\n"; testCase(testFile, "test3.jpg", "thumb3", "Exif.Photo.DateTimeOriginal", "1999:11:22 00:11:22"); break; case 4: std::cerr << "Case 4: "; std::cerr << "Intrusive change to the standard Exif metadata\n"; testCase(testFile, "test4.jpg", "thumb4", "Exif.Photo.DateTimeOriginal", "1999:11:22 00:11:22 and twenty seconds"); break; case 5: std::cerr << "Case 5: "; std::cerr << "Intrusive change to the Canon makernote metadata\n"; testCase(testFile, "test5.jpg", "thumb5", "Exif.Canon.OwnerName", "Frau Chan YeeSend und Herr Andreas Huggel"); break; case 6: std::cerr << "Case 6: "; std::cerr << "Intrusive change to the Exif metadata (w/o makernote)\n"; testCase(testFile, "test6.jpg", "thumb6", "Exif.Photo.DateTimeOriginal", "1999:11:22 00:11:22 and twenty seconds"); break; case 7: std::cerr << "Case 7: "; std::cerr << "Intrusive change to the Fujifilm makernote metadata\n"; testCase(testFile, "test7.jpg", "thumb7", "Exif.Fujifilm.Quality", "Typical Fujifilm Quality"); break; case 8: std::cerr << "Case 8: "; std::cerr << "Intrusive change to the Sigma makernote metadata\n"; testCase(testFile, "test8.jpg", "thumb8", "Exif.Sigma.ResolutionMode", "Sigma HI resolution"); break; case 9: std::cerr << "Case 9: "; std::cerr << "Intrusive change to the Nikon1 makernote metadata\n"; testCase(testFile, "test9.jpg", "thumb9", "Exif.Nikon1.Quality", "Typical Nikon1 Quality"); break; case 10: std::cerr << "Case 10: "; std::cerr << "Intrusive change to the Nikon2 makernote metadata\n"; testCase(testFile, "test10.jpg", "thumb10", "Exif.Nikon2.0x0002", "Nikon2 Version 2"); break; case 11: std::cerr << "Case 11: "; std::cerr << "Intrusive change to the Nikon3 makernote metadata\n"; testCase(testFile, "test11.jpg", "thumb11", "Exif.Nikon3.Quality", "Typical Nikon3 Quality"); break; // ToDo: Erase Sigma thumbnail // ToDo: Write to a broken (truncated) IFD entry default: std::cout << "Usage: exiftest file case\n\n" << "where case is an integer between 1 and 11\n"; rc = 1; break; } return rc; } catch (AnyError& e) { std::cerr << "Caught Exiv2 exception '" << e << "'\n"; return 1; } } // ***************************************************************************** void testCase(const std::string& file1, const std::string& file2, const std::string& thumb, const std::string& key, const std::string& value) { ExifKey ek(key); //Open first image Image::AutoPtr image1 = ImageFactory::open(file1); assert(image1.get() != 0); // Load existing metadata std::cerr << "---> Reading file " << file1 << "\n"; image1->readMetadata(); Exiv2::ExifData &ed1 = image1->exifData(); std::cerr << "---> Modifying Exif data\n"; Exiv2::ExifData::iterator pos = ed1.findKey(ek); if (pos == ed1.end()) { throw Error(1, "Metadatum with key = " + ek.key() + " not found"); } pos->setValue(value); // Open second image Image::AutoPtr image2 = ImageFactory::open(file2); assert(image2.get() != 0); image2->setExifData(image1->exifData()); std::cerr << "---> Writing Exif data to file " << file2 << "\n"; image2->writeMetadata(); std::cerr << "---> Reading file " << file2 << "\n"; image2->readMetadata(); Exiv2::ExifData &ed2 = image2->exifData(); exifPrint(ed2); std::cerr << "---> Writing Exif thumbnail to file " << thumb << ".*\n"; ExifThumbC et2(ed2); et2.writeFile(thumb); } // ***************************************************************************** void exifPrint(const ExifData& exifData) { ExifData::const_iterator i = exifData.begin(); for (; i != exifData.end(); ++i) { std::cout << std::setw(44) << std::setfill(' ') << std::left << i->key() << " " << "0x" << std::setw(4) << std::setfill('0') << std::right << std::hex << i->tag() << " " << std::setw(9) << std::setfill(' ') << std::left << i->typeName() << " " << std::dec << std::setw(3) << std::setfill(' ') << std::right << i->count() << " " << std::dec << i->value() << "\n"; } } exiv2-0.23/samples/iotest.cpp0000644000175000017500000001410011732641407015767 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /* Abstract : Tester application for BasicIo functions. Tests MemIo primarily since FileIo just sits atop of FILE* streams. File : iotest.cpp Version : $Rev: 2681 $ Author(s): Brad Schick (brad) History : 04-Dec-04, brad: created */ // ***************************************************************************** // included header files #include #include // for EOF #include #include using Exiv2::byte; using Exiv2::BasicIo; using Exiv2::MemIo; using Exiv2::FileIo; using Exiv2::IoCloser; using Exiv2::Error; using Exiv2::strError; int WriteReadSeek(BasicIo &io); // ***************************************************************************** // Main int main(int argc, char* const argv[]) { try { if (argc != 4) { std::cout << "Usage: " << argv[0] << " filein fileout1 fileout2\n"; std::cout << "fileouts are overwritten and should match filein exactly\n"; return 1; } FileIo fileIn(argv[1]); if (fileIn.open() != 0) { throw Error(9, fileIn.path(), strError()); } FileIo fileOut1(argv[2]); if (fileOut1.open("w+b") != 0) { throw Error(10, argv[2], "w+b", strError()); } MemIo memIo1; // Copy to output file through memIo memIo1.write(fileIn); memIo1.seek(0, BasicIo::beg); fileOut1.write(memIo1); // Make sure they are all the same size if(fileIn.size() != memIo1.size() || memIo1.size() != fileOut1.size()) { std::cerr << argv[0] << ": Sizes do not match\n"; return 1; } // Read writereadseek test on MemIo MemIo memIo2; int rc = WriteReadSeek(memIo2); if (rc != 0) return rc; // Read writereadseek test on FileIo // Create or overwrite the file, then close it FileIo fileTest("iotest.txt"); if (fileTest.open("w+b") != 0) { throw Error(10, "iotest.txt", "w+b", strError()); } fileTest.close(); rc = WriteReadSeek(fileTest); if (rc != 0) return rc; // Another test of reading and writing fileOut1.seek(0, BasicIo::beg); memIo2.seek(0, BasicIo::beg); FileIo fileOut2(argv[3]); if (fileOut2.open("w+b") != 0) { throw Error(10, argv[3], "w+b", strError()); } long readCount = 0; byte buf[32]; while ((readCount=fileOut1.read(buf, sizeof(buf)))) { if (memIo2.write(buf, readCount) != readCount) { std::cerr << argv[0] << ": MemIo bad write 2\n"; return 13; } if (fileOut2.write(buf, readCount) != readCount) { std::cerr << argv[0] << ": FileIo bad write 2\n"; return 14; } } return 0; } catch (Exiv2::AnyError& e) { std::cerr << "Caught Exiv2 exception '" << e << "'\n"; return 20; } } int WriteReadSeek(BasicIo &io) { byte buf[4096]; const char tester1[] = "this is a little test of MemIo"; const char tester2[] = "Appending this on the end"; const char expect[] = "this is a little teAppending this on the end"; const long insert = 19; const long len1 = (long)std::strlen(tester1) + 1; const long len2 = (long)std::strlen(tester2) + 1; if (io.open() != 0) { throw Error(9, io.path(), strError()); } IoCloser closer(io); if (io.write((byte*)tester1, len1) != len1) { std::cerr << ": WRS initial write failed\n"; return 2; } if (io.size() != len1) { std::cerr << ": WRS size is not " << len1 << "\n"; return 2; } io.seek(-len1, BasicIo::cur); int c = EOF; std::memset(buf, -1, sizeof(buf)); for (int i = 0; (c=io.getb()) != EOF; ++i) { buf[i] = (byte)c; } // Make sure we got the null back if(buf[len1-1] != 0) { std::cerr << ": WRS missing null terminator 1\n"; return 3; } if (strcmp(tester1, (char*)buf) != 0 ) { std::cerr << ": WRS strings don't match 1\n"; return 4; } io.seek(-2, BasicIo::end); if (io.getb() != 'o') { std::cerr << ": WRS bad getb o\n"; return 5; } io.seek(-2, BasicIo::cur); if (io.getb() != 'I') { std::cerr << ": WRS bad getb I\n"; return 6; } if (io.putb('O') != 'O') { std::cerr << ": WRS bad putb\n"; return 7; } io.seek(-1, BasicIo::cur); if (io.getb() != 'O') { std::cerr << ": WRS bad getb O\n"; return 8; } io.seek(insert, BasicIo::beg); if(io.write((byte*)tester2, len2) != len2) { std::cerr << ": WRS bad write 1\n"; return 9; } // open should seek to beginning if (io.open() != 0) { throw Error(9, io.path(), strError()); } std::memset(buf, -1, sizeof(buf)); if (io.read(buf, sizeof(buf)) != insert + len2) { std::cerr << ": WRS something went wrong\n"; return 10; } // Make sure we got the null back if(buf[insert + len2 - 1] != 0) { std::cerr << ": WRS missing null terminator 2\n"; return 11; } if (std::strcmp(expect, (char*)buf) != 0 ) { std::cerr << ": WRS strings don't match 2\n"; return 12; } return 0; } exiv2-0.23/samples/mmap-test.cpp0000644000175000017500000000177111411621067016373 0ustar andreasandreas// ***************************************************************** -*- C++ -*- // mmap-test.cpp, $Rev: 2286 $ // Simple mmap tests #include #include #include using namespace Exiv2; int main(int argc, char* const argv[]) try { if (argc != 2) { std::cout << "Usage: " << argv[0] << " file\n"; return 1; } const char* path = argv[1]; FileIo file(path); // Open the file in read mode if (file.open("rb") != 0) { throw Error(10, path, "rb", strError()); } // Map it to memory const Exiv2::byte* pData = file.mmap(); long size = file.size(); DataBuf buf(size); // Read from the memory mapped region memcpy(buf.pData_, pData, buf.size_); // Reopen file in write mode and write to it file.write(buf.pData_, buf.size_); // Read from the mapped region again memcpy(buf.pData_, pData, buf.size_); file.close(); return 0; } catch (const AnyError& e) { std::cout << e << "\n"; } exiv2-0.23/samples/exifprint.cpp0000644000175000017500000000321411411621067016466 0ustar andreasandreas// ***************************************************************** -*- C++ -*- // exifprint.cpp, $Rev: 2286 $ // Sample program to print the Exif metadata of an image #include #include #include #include int main(int argc, char* const argv[]) try { if (argc != 2) { std::cout << "Usage: " << argv[0] << " file\n"; return 1; } Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(argv[1]); assert(image.get() != 0); image->readMetadata(); Exiv2::ExifData &exifData = image->exifData(); if (exifData.empty()) { std::string error(argv[1]); error += ": No Exif data found in the file"; throw Exiv2::Error(1, error); } Exiv2::ExifData::const_iterator end = exifData.end(); for (Exiv2::ExifData::const_iterator i = exifData.begin(); i != end; ++i) { const char* tn = i->typeName(); std::cout << std::setw(44) << std::setfill(' ') << std::left << i->key() << " " << "0x" << std::setw(4) << std::setfill('0') << std::right << std::hex << i->tag() << " " << std::setw(9) << std::setfill(' ') << std::left << (tn ? tn : "Unknown") << " " << std::dec << std::setw(3) << std::setfill(' ') << std::right << i->count() << " " << std::dec << i->value() << "\n"; } return 0; } //catch (std::exception& e) { //catch (Exiv2::AnyError& e) { catch (Exiv2::Error& e) { std::cout << "Caught Exiv2 exception '" << e.what() << "'\n"; return -1; } exiv2-0.23/samples/iptcprint.cpp0000644000175000017500000000303611411621067016474 0ustar andreasandreas// ***************************************************************** -*- C++ -*- // iptcprint.cpp, $Rev: 2286 $ // Sample program to print the IPTC metadata of an image #include #include #include #include int main(int argc, char* const argv[]) try { if (argc != 2) { std::cout << "Usage: " << argv[0] << " file\n"; return 1; } Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(argv[1]); assert (image.get() != 0); image->readMetadata(); Exiv2::IptcData &iptcData = image->iptcData(); if (iptcData.empty()) { std::string error(argv[1]); error += ": No IPTC data found in the file"; throw Exiv2::Error(1, error); } Exiv2::IptcData::iterator end = iptcData.end(); for (Exiv2::IptcData::iterator md = iptcData.begin(); md != end; ++md) { std::cout << std::setw(44) << std::setfill(' ') << std::left << md->key() << " " << "0x" << std::setw(4) << std::setfill('0') << std::right << std::hex << md->tag() << " " << std::setw(9) << std::setfill(' ') << std::left << md->typeName() << " " << std::dec << std::setw(3) << std::setfill(' ') << std::right << md->count() << " " << std::dec << md->value() << std::endl; } return 0; } catch (Exiv2::AnyError& e) { std::cout << "Caught Exiv2 exception '" << e << "'\n"; return -1; } exiv2-0.23/samples/prevtest.cpp0000644000175000017500000000257411411621067016342 0ustar andreasandreas// ***************************************************************** -*- C++ -*- // prevtest.cpp, $Rev: 2286 $ // Test access to preview images #include #include #include #include int main(int argc, char* const argv[]) try { if (argc != 2) { std::cout << "Usage: " << argv[0] << " file\n"; return 1; } std::string filename(argv[1]); Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(filename); assert(image.get() != 0); image->readMetadata(); Exiv2::PreviewManager loader(*image); Exiv2::PreviewPropertiesList list = loader.getPreviewProperties(); for (Exiv2::PreviewPropertiesList::iterator pos = list.begin(); pos != list.end(); pos++) { std::cout << pos->mimeType_ << " preview, type " << pos->id_ << ", " << pos->size_ << " bytes, " << pos->width_ << 'x' << pos->height_ << " pixels" << "\n"; Exiv2::PreviewImage preview = loader.getPreviewImage(*pos); preview.writeFile(filename + "_" + Exiv2::toString(pos->width_) + "x" + Exiv2::toString(pos->height_)); } // Cleanup Exiv2::XmpParser::terminate(); return 0; } catch (Exiv2::AnyError& e) { std::cout << "Caught Exiv2 exception '" << e << "'\n"; return -1; } exiv2-0.23/samples/addmoddel.cpp0000644000175000017500000001077211411621067016402 0ustar andreasandreas// ***************************************************************** -*- C++ -*- // addmoddel.cpp, $Rev: 2286 $ // Sample program showing how to add, modify and delete Exif metadata. #include #include #include #include int main(int argc, char* const argv[]) try { if (argc != 2) { std::cout << "Usage: " << argv[0] << " file\n"; return 1; } std::string file(argv[1]); // Container for exif metadata. This is an example of creating // exif metadata from scratch. If you want to add, modify, delete // metadata that exists in an image, start with ImageFactory::open Exiv2::ExifData exifData; // ************************************************************************* // Add to the Exif data // This is the quickest way to add (simple) Exif data. If a metadatum for // a given key already exists, its value is overwritten. Otherwise a new // tag is added. exifData["Exif.Image.Model"] = "Test 1"; // AsciiValue exifData["Exif.Image.SamplesPerPixel"] = uint16_t(162); // UShortValue exifData["Exif.Image.XResolution"] = int32_t(-2); // LongValue exifData["Exif.Image.YResolution"] = Exiv2::Rational(-2, 3); // RationalValue std::cout << "Added a few tags the quick way.\n"; // Create a ASCII string value (note the use of create) Exiv2::Value::AutoPtr v = Exiv2::Value::create(Exiv2::asciiString); // Set the value to a string v->read("1999:12:31 23:59:59"); // Add the value together with its key to the Exif data container Exiv2::ExifKey key("Exif.Photo.DateTimeOriginal"); exifData.add(key, v.get()); std::cout << "Added key \"" << key << "\", value \"" << *v << "\"\n"; // Now create a more interesting value (without using the create method) Exiv2::URationalValue::AutoPtr rv(new Exiv2::URationalValue); // Set two rational components from a string rv->read("1/2 1/3"); // Add more elements through the extended interface of rational value rv->value_.push_back(std::make_pair(2,3)); rv->value_.push_back(std::make_pair(3,4)); // Add the key and value pair to the Exif data key = Exiv2::ExifKey("Exif.Image.PrimaryChromaticities"); exifData.add(key, rv.get()); std::cout << "Added key \"" << key << "\", value \"" << *rv << "\"\n"; // ************************************************************************* // Modify Exif data // Since we know that the metadatum exists (or we don't mind creating a new // tag if it doesn't), we can simply do this: Exiv2::Exifdatum& tag = exifData["Exif.Photo.DateTimeOriginal"]; std::string date = tag.toString(); date.replace(0, 4, "2000"); tag.setValue(date); std::cout << "Modified key \"" << key << "\", new value \"" << tag.value() << "\"\n"; // Alternatively, we can use findKey() key = Exiv2::ExifKey("Exif.Image.PrimaryChromaticities"); Exiv2::ExifData::iterator pos = exifData.findKey(key); if (pos == exifData.end()) throw Exiv2::Error(1, "Key not found"); // Get a pointer to a copy of the value v = pos->getValue(); // Downcast the Value pointer to its actual type Exiv2::URationalValue* prv = dynamic_cast(v.release()); if (prv == 0) throw Exiv2::Error(1, "Downcast failed"); rv = Exiv2::URationalValue::AutoPtr(prv); // Modify the value directly through the interface of URationalValue rv->value_[2] = std::make_pair(88,77); // Copy the modified value back to the metadatum pos->setValue(rv.get()); std::cout << "Modified key \"" << key << "\", new value \"" << pos->value() << "\"\n"; // ************************************************************************* // Delete metadata from the Exif data container // Delete the metadatum at iterator position pos key = Exiv2::ExifKey("Exif.Image.PrimaryChromaticities"); pos = exifData.findKey(key); if (pos == exifData.end()) throw Exiv2::Error(1, "Key not found"); exifData.erase(pos); std::cout << "Deleted key \"" << key << "\"\n"; // ************************************************************************* // Finally, write the remaining Exif data to the image file Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(file); assert(image.get() != 0); image->setExifData(exifData); image->writeMetadata(); return 0; } catch (Exiv2::AnyError& e) { std::cout << "Caught Exiv2 exception '" << e << "'\n"; return -1; } exiv2-0.23/samples/exifcomment.cpp0000644000175000017500000000416611411621067017003 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* Abstract : Sample program showing how to set the Exif comment of an image, Exif.Photo.UserComment File: exifcomment.cpp Version : $Rev: 2286 $ Author(s): Andreas Huggel (ahu) History : 10-May-04, ahu: created 16-Jan-05, ahu: updated using CommentValue and operator trickery */ // ***************************************************************************** // included header files #include #include #include // ***************************************************************************** // Main int main(int argc, char* const argv[]) try { if (argc != 2) { std::cout << "Usage: " << argv[0] << " file\n"; return 1; } Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(argv[1]); assert (image.get() != 0); image->readMetadata(); Exiv2::ExifData &exifData = image->exifData(); /* Exiv2 uses a CommentValue for Exif user comments. The format of the comment string includes an optional charset specification at the beginning: [charset=["]Ascii|Jis|Unicode|Undefined["] ]comment Undefined is used as a default if the comment doesn't start with a charset definition. Following are a few examples of valid comments. The last one is written to the file. */ exifData["Exif.Photo.UserComment"] = "charset=\"Unicode\" An Unicode Exif comment added with Exiv2"; exifData["Exif.Photo.UserComment"] = "charset=\"Undefined\" An undefined Exif comment added with Exiv2"; exifData["Exif.Photo.UserComment"] = "Another undefined Exif comment added with Exiv2"; exifData["Exif.Photo.UserComment"] = "charset=Ascii An ASCII Exif comment added with Exiv2"; std::cout << "Writing user comment '" << exifData["Exif.Photo.UserComment"] << "' back to the image\n"; image->writeMetadata(); return 0; } catch (Exiv2::AnyError& e) { std::cout << "Caught Exiv2 exception '" << e << "'\n"; return -1; } exiv2-0.23/samples/iptceasy.cpp0000644000175000017500000000273111411621067016302 0ustar andreasandreas// ***************************************************************** -*- C++ -*- // iptceasy.cpp, $Rev: 2286 $ // The quickest way to access, set or modify IPTC metadata. #include #include #include #include int main(int argc, char* const argv[]) try { if (argc != 2) { std::cout << "Usage: " << argv[0] << " file\n"; return 1; } std::string file(argv[1]); Exiv2::IptcData iptcData; iptcData["Iptc.Application2.Headline"] = "The headline I am"; iptcData["Iptc.Application2.Keywords"] = "Yet another keyword"; iptcData["Iptc.Application2.DateCreated"] = "2004-8-3"; iptcData["Iptc.Application2.Urgency"] = uint16_t(1); iptcData["Iptc.Envelope.ModelVersion"] = 42; iptcData["Iptc.Envelope.TimeSent"] = "14:41:0-05:00"; iptcData["Iptc.Application2.RasterizedCaption"] = "230 42 34 2 90 84 23 146"; iptcData["Iptc.0x0009.0x0001"] = "Who am I?"; Exiv2::StringValue value; value.read("very!"); iptcData["Iptc.Application2.Urgency"] = value; std::cout << "Time sent: " << iptcData["Iptc.Envelope.TimeSent"] << "\n"; // Open image file Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(file); assert (image.get() != 0); // Set IPTC data and write it to the file image->setIptcData(iptcData); image->writeMetadata(); return 0; } catch (Exiv2::AnyError& e) { std::cout << "Caught Exiv2 exception '" << e << "'\n"; return -1; } exiv2-0.23/samples/stringto-test.cpp0000644000175000017500000000326611411621067017313 0ustar andreasandreas// ***************************************************************** -*- C++ -*- // stringto-test.cpp, $Rev: 2286 $ // Test conversions from string to long, float and Rational types. #include #include #include const char* testcases[] = { // bool "True", "False", "t", "f", // long "-1", "0", "1", // float "0.0", "0.1", "0.01", "0.001", "-1.49999", "-1.5", "1.49999", "1.5", // Rational "0/1", "1/1", "1/3", "-1/3", "4/3", "-4/3", "0/0", // nok "text" }; int main() { std::cout << std::setfill(' '); std::cout << std::setw(12) << std::left << "string"; std::cout << std::setw(12) << std::left << "long"; std::cout << std::setw(12) << std::left << "float"; std::cout << std::setw(12) << std::left << "Rational"; std::cout << std::endl; for (unsigned int i = 0; i < EXV_COUNTOF(testcases); ++i) try { std::string s(testcases[i]); std::cout << std::setw(12) << std::left << s; bool ok; long l = Exiv2::parseLong(s, ok); std::cout << std::setw(12) << std::left; if (ok) std::cout << l; else std::cout << "nok"; float f = Exiv2::parseFloat(s, ok); std::cout << std::setw(12) << std::left; if (ok) std::cout << f; else std::cout << "nok"; Exiv2::Rational r = Exiv2::parseRational(s, ok); if (ok) std::cout << r.first << "/" << r.second; else std::cout << "nok"; std::cout << std::endl; } catch (Exiv2::AnyError& e) { std::cout << "Caught Exiv2 exception '" << e << "'\n"; return -1; } return 0; } exiv2-0.23/samples/largeiptc-test.cpp0000644000175000017500000000426711411621067017416 0ustar andreasandreas// ***************************************************************** -*- C++ -*- // Test for large (>65535 bytes) IPTC buffer #include #include #include int main(int argc, char* const argv[]) try { if (argc != 3) { std::cout << "Usage: " << argv[0] << " image datafile\n"; return 1; } std::string file(argv[1]); std::string data(argv[2]); // Read data file into data buffer Exiv2::FileIo io(data); if (io.open() != 0) { throw Exiv2::Error(9, io.path(), Exiv2::strError()); } Exiv2::DataBuf buf(io.size()); std::cout << "Reading " << buf.size_ << " bytes from " << data << "\n"; io.read(buf.pData_, buf.size_); if (io.error() || io.eof()) throw Exiv2::Error(14); // Read metadata from file Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(file); assert(image.get() != 0); image->readMetadata(); // Set Preview field to the content of the data file Exiv2::DataValue value; value.read(buf.pData_, buf.size_); Exiv2::IptcData& iptcData = image->iptcData(); std::cout << "IPTC fields: " << iptcData.size() << "\n"; iptcData["Iptc.Application2.Preview"] = value; std::cout << "IPTC fields: " << iptcData.size() << "\n"; // Set IRB, compare with IPTC raw data Exiv2::DataBuf irb = Exiv2::Photoshop::setIptcIrb(0, 0, iptcData); std::cout << "IRB buffer : " << irb.size_ << "\n"; const Exiv2::byte* record; uint32_t sizeHdr; uint32_t sizeData; Exiv2::Photoshop::locateIptcIrb(irb.pData_, irb.size_, &record, &sizeHdr, &sizeData); Exiv2::DataBuf rawIptc = Exiv2::IptcParser::encode(iptcData); std::cout << "Comparing IPTC and IRB size... "; if (static_cast(rawIptc.size_) != sizeData) { std::cout << "not "; } std::cout << "ok\n"; std::cout << "Comparing IPTC and IRB data... "; if (0 != memcmp(rawIptc.pData_, record + sizeHdr, sizeData)) { std::cout << "not "; } std::cout << "ok\n"; // Set Iptc data and write it to the file image->writeMetadata(); return 0; } catch (Exiv2::AnyError& e) { std::cout << "Caught Exiv2 exception '" << e << "'\n"; return -1; } exiv2-0.23/samples/write2-test.cpp0000644000175000017500000001753211411621067016657 0ustar andreasandreas// ***************************************************************** -*- C++ -*- /* Abstract : ExifData write unit tests for Exif data created from scratch File : write2-test.cpp Version : $Rev: 2286 $ Author(s): Andreas Huggel (ahu) History : 26-Jun-04, ahu: created */ // ***************************************************************************** // included header files #include #include #include #include #include void write(const std::string& file, Exiv2::ExifData& ed); void print(const std::string& file); // ***************************************************************************** // Main int main(int argc, char* const argv[]) { try { if (argc != 2) { std::cout << "Usage: " << argv[0] << " file\n"; return 1; } std::string file(argv[1]); std::cout <<"----- Some IFD0 tags\n"; Exiv2::ExifData ed1; ed1["Exif.Image.Model"] = "Test 1"; Exiv2::Value::AutoPtr v1 = Exiv2::Value::create(Exiv2::unsignedShort); v1->read("160 161 162 163"); ed1.add(Exiv2::ExifKey("Exif.Image.SamplesPerPixel"), v1.get()); Exiv2::Value::AutoPtr v2 = Exiv2::Value::create(Exiv2::signedLong); v2->read("-2 -1 0 1"); ed1.add(Exiv2::ExifKey("Exif.Image.XResolution"), v2.get()); Exiv2::Value::AutoPtr v3 = Exiv2::Value::create(Exiv2::signedRational); v3->read("-2/3 -1/3 0/3 1/3"); ed1.add(Exiv2::ExifKey("Exif.Image.YResolution"), v3.get()); Exiv2::Value::AutoPtr v4 = Exiv2::Value::create(Exiv2::undefined); v4->read("255 254 253 252"); ed1.add(Exiv2::ExifKey("Exif.Image.WhitePoint"), v4.get()); write(file, ed1); print(file); std::cout <<"\n----- One Exif tag\n"; Exiv2::ExifData ed2; ed2["Exif.Photo.DateTimeOriginal"] = "Test 2"; write(file, ed2); print(file); std::cout <<"\n----- Canon MakerNote tags\n"; Exiv2::ExifData edMn1; edMn1["Exif.Image.Make"] = "Canon"; edMn1["Exif.Image.Model"] = "Canon PowerShot S40"; edMn1["Exif.Canon.0xabcd"] = "A Canon makernote tag"; edMn1["Exif.CanonCs.0x0002"] = uint16_t(41); edMn1["Exif.CanonSi.0x0005"] = uint16_t(42); edMn1["Exif.CanonCf.0x0001"] = uint16_t(43); edMn1["Exif.CanonPi.0x0001"] = uint16_t(44); edMn1["Exif.CanonPa.0x0001"] = uint16_t(45); write(file, edMn1); print(file); std::cout <<"\n----- Non-intrusive writing of special Canon MakerNote tags\n"; Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(file); assert(image.get() != 0); image->readMetadata(); Exiv2::ExifData& rEd = image->exifData(); rEd["Exif.CanonCs.0x0001"] = uint16_t(88); rEd["Exif.CanonSi.0x0004"] = uint16_t(99); image->writeMetadata(); print(file); std::cout <<"\n----- One Fujifilm MakerNote tag\n"; Exiv2::ExifData edMn2; edMn2["Exif.Image.Make"] = "FUJIFILM"; edMn2["Exif.Image.Model"] = "FinePixS2Pro"; edMn2["Exif.Fujifilm.0x1000"] = "A Fujifilm QUALITY tag"; write(file, edMn2); print(file); std::cout <<"\n----- One Sigma/Foveon MakerNote tag\n"; Exiv2::ExifData edMn3; edMn3["Exif.Image.Make"] = "SIGMA"; edMn3["Exif.Image.Model"] = "SIGMA SD10"; edMn3["Exif.Sigma.0x0018"] = "Software? Exiv2!"; write(file, edMn3); print(file); std::cout <<"\n----- One Nikon1 MakerNote tag\n"; Exiv2::ExifData edMn4; edMn4["Exif.Image.Make"] = "NIKON"; edMn4["Exif.Image.Model"] = "E990"; edMn4["Exif.Nikon1.0x0080"] = "ImageAdjustment by Exiv2"; write(file, edMn4); print(file); std::cout <<"\n----- One Nikon2 MakerNote tag\n"; Exiv2::ExifData edMn5; edMn5["Exif.Image.Make"] = "NIKON"; edMn5["Exif.Image.Model"] = "E950"; edMn5["Exif.Nikon2.0xffff"] = "An obscure Nikon2 tag"; write(file, edMn5); print(file); std::cout <<"\n----- One Nikon3 MakerNote tag\n"; Exiv2::ExifData edMn6; edMn6["Exif.Image.Make"] = "NIKON CORPORATION"; edMn6["Exif.Image.Model"] = "NIKON D70"; edMn6["Exif.Nikon3.0x0004"] = "A boring Nikon3 Quality tag"; write(file, edMn6); print(file); std::cout <<"\n----- One Olympus MakerNote tag\n"; Exiv2::ExifData edMn7; edMn7["Exif.Image.Make"] = "OLYMPUS CORPORATION"; edMn7["Exif.Image.Model"] = "C8080WZ"; edMn7["Exif.Olympus.0x0201"] = uint16_t(1); write(file, edMn7); print(file); std::cout <<"\n----- One Panasonic MakerNote tag\n"; Exiv2::ExifData edMn8; edMn8["Exif.Image.Make"] = "Panasonic"; edMn8["Exif.Image.Model"] = "DMC-FZ5"; edMn8["Exif.Panasonic.0x0001"] = uint16_t(1); write(file, edMn8); print(file); std::cout <<"\n----- One Sony1 MakerNote tag\n"; Exiv2::ExifData edMn9; edMn9["Exif.Image.Make"] = "SONY"; edMn9["Exif.Image.Model"] = "DSC-W7"; edMn9["Exif.Sony1.0x2000"] = "0 1 2 3 4 5"; write(file, edMn9); print(file); std::cout <<"\n----- Minolta MakerNote tags\n"; Exiv2::ExifData edMn10; edMn10["Exif.Image.Make"] = "Minolta"; edMn10["Exif.Image.Model"] = "A fancy Minolta camera"; edMn10["Exif.Minolta.ColorMode"] = uint32_t(1); edMn10["Exif.MinoltaCsNew.WhiteBalance"] = uint32_t(2); edMn10["Exif.MinoltaCs5D.WhiteBalance"] = uint16_t(3); edMn10["Exif.MinoltaCs5D.ColorTemperature"] = int16_t(-1); edMn10["Exif.MinoltaCs7D.WhiteBalance"] = uint16_t(4); edMn10["Exif.MinoltaCs7D.ExposureCompensation"] = int16_t(-2); edMn10["Exif.MinoltaCs7D.ColorTemperature"] = int16_t(-3); write(file, edMn10); print(file); std::cout <<"\n----- One IOP tag\n"; Exiv2::ExifData ed3; ed3["Exif.Iop.InteroperabilityIndex"] = "Test 3"; write(file, ed3); print(file); std::cout <<"\n----- One GPS tag\n"; Exiv2::ExifData ed4; ed4["Exif.GPSInfo.GPSVersionID"] = "19 20"; write(file, ed4); print(file); std::cout <<"\n----- One IFD1 tag\n"; Exiv2::ExifData ed5; ed5["Exif.Thumbnail.Artist"] = "Test 5"; write(file, ed5); print(file); std::cout <<"\n----- One IOP and one IFD1 tag\n"; Exiv2::ExifData ed6; ed6["Exif.Iop.InteroperabilityIndex"] = "Test 6 Iop tag"; ed6["Exif.Thumbnail.Artist"] = "Test 6 Ifd1 tag"; write(file, ed6); print(file); std::cout <<"\n----- One IFD0 and one IFD1 tag\n"; Exiv2::ExifData ed7; ed7["Exif.Thumbnail.Artist"] = "Test 7"; Exiv2::Value::AutoPtr v5 = Exiv2::Value::create(Exiv2::unsignedShort); v5->read("160 161 162 163"); ed7.add(Exiv2::ExifKey("Exif.Image.SamplesPerPixel"), v5.get()); write(file, ed7); print(file); return 0; } catch (Exiv2::AnyError& e) { std::cout << "Caught Exiv2 exception '" << e << "'\n"; return -1; } } void write(const std::string& file, Exiv2::ExifData& ed) { Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(file); assert(image.get() != 0); image->setExifData(ed); image->writeMetadata(); } void print(const std::string& file) { Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(file); assert(image.get() != 0); image->readMetadata(); Exiv2::ExifData &ed = image->exifData(); Exiv2::ExifData::const_iterator end = ed.end(); for (Exiv2::ExifData::const_iterator i = ed.begin(); i != end; ++i) { std::cout << std::setw(45) << std::setfill(' ') << std::left << i->key() << " " << "0x" << std::setw(4) << std::setfill('0') << std::right << std::hex << i->tag() << " " << std::setw(12) << std::setfill(' ') << std::left << i->ifdName() << " " << std::setw(9) << std::setfill(' ') << std::left << i->typeName() << " " << std::dec << std::setw(3) << std::setfill(' ') << std::right << i->count() << " " << std::dec << i->value() << "\n"; } } exiv2-0.23/samples/tiffaddpath-test.cpp0000644000175000017500000000725011027153701017713 0ustar andreasandreas// ***************************************************************** -*- C++ -*- // tiffaddpath-test.cpp, $Rev: 1512 $ // Test driver to test adding new tags to a TIFF composite structure #include "tiffcomposite_int.hpp" #include "makernote2_int.hpp" #include "tiffimage_int.hpp" #include #include #include #include using namespace Exiv2; void addPath(TiffComponent* pRootDir, uint16_t tag, TiffPath& tiffPath); void printPath(TiffPath tiffPath, uint32_t tag, uint16_t grp); struct TiffTagInfo { bool operator==(const uint32_t& tag) const; uint32_t tag_; const char* name_; }; extern const TiffTagInfo tiffTagInfo[] = { { 0x10000, "none" }, { 0x20000, "root" }, { 0x30000, "next" }, { 0x40000, "all" } }; bool TiffTagInfo::operator==(const uint32_t& tag) const { return tag_ == tag; } std::string tiffTagName(uint32_t tag) { const TiffTagInfo* gi = find(tiffTagInfo, tag); std::string name; if (gi != 0) { name = gi->name_; } else { std::ostringstream os; os << "0x" << std::hex << std::setw(4) << std::setfill('0') << std::right << tag; name = os.str(); } return name; } // ----------------------------------------------------------------------------- // Main program int main(int argc, char* const argv[]) { if (argc != 3) { std::cout << "Usage: " << argv[0] << " tag group\n" << "Print the TIFF path for a tag and group (decimal numbers)\n"; return 1; } uint32_t tag = atol(argv[1]); uint16_t grp = atol(argv[2]); TiffComponent* pRootDir = new TiffDirectory(0, 1); TiffPath tiffPath1; TiffCreator::getPath(tiffPath1, tag, grp); printPath(tiffPath1, tag, grp); addPath(pRootDir, tag, tiffPath1); ++tag; TiffPath tiffPath2; TiffCreator::getPath(tiffPath2, tag, grp); printPath(tiffPath2, tag, grp); addPath(pRootDir, tag, tiffPath2); return 0; } // ----------------------------------------------------------------------------- void addPath(TiffComponent* pRootDir, uint16_t tag, TiffPath& tiffPath) { TiffComponent* tc = pRootDir->addPath(tag, tiffPath); TiffPrinter tiffPrinter(std::cout); pRootDir->accept(tiffPrinter); std::cout << std::endl; if (tc) { std::cout << "Added tag " << tiffTagName(tc->tag()) << ", group " << tiffGroupName(tc->group()) << "\n"; } else { std::cout << "No tag added\n"; } std::cout << std::endl; } // ----------------------------------------------------------------------------- void printPath(TiffPath tiffPath, uint32_t tag, uint16_t grp) { std::cout << "\nTiff path for tag " << std::setw(6) << std::setfill(' ') << std::left << tiffTagName(tag) << ", group " << tiffGroupName(grp) << " (id = " << std::dec << grp << "):\n\n" << "ext. tag group new group \n" << "-------- ------------ ------------\n"; while (!tiffPath.empty()) { const TiffStructure* ts = tiffPath.top(); tiffPath.pop(); std::cout << std::setw(8) << std::setfill(' ') << std::left << tiffTagName(ts->extendedTag_) << " " << std::setw(12) << std::setfill(' ') << std::left << tiffGroupName(ts->group_) << " " << std::setw(12) << std::setfill(' ') << std::left << tiffGroupName(ts->newGroup_) << "\n"; } std::cout << std::endl; } exiv2-0.23/samples/Makefile0000644000175000017500000001063211732641407015422 0ustar andreasandreas# ************************************************************* -*- Makefile -*- # # Copyright (C) 2004-2012 Andreas Huggel # # This Makefile is part of the Exiv2 distribution. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # 3. The name of the author may not be used to endorse or promote # products derived from this software without specific prior # written permission. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER # IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN # IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # File: Makefile # Version: $Rev: 2681 $ # Author(s): Andreas Huggel (ahu) # History: 08-Oct-07, ahu: created # # Description: # Simple Makefile to build sample programs. Requires installed exiv2 library # and headers. Adapted from the main Exiv2 src/Makefile. # # Restrictions: # Requires GNU make. # # Default make target all: samples # Include system configuration top_srcdir = .. include $(top_srcdir)/config/config.mk # ****************************************************************************** # Source files # Add source files of sample programs to this list BINSRC = addmoddel.cpp \ convert-test.cpp \ easyaccess-test.cpp \ exifcomment.cpp \ exifdata-test.cpp \ exifprint.cpp \ iotest.cpp \ iptceasy.cpp \ iptcprint.cpp \ iptctest.cpp \ key-test.cpp \ largeiptc-test.cpp \ mmap-test.cpp \ prevtest.cpp \ stringto-test.cpp \ tiff-test.cpp \ werror-test.cpp \ write-test.cpp \ write2-test.cpp \ xmpparse.cpp \ xmpparser-test.cpp \ xmpsample.cpp # ****************************************************************************** # Initialisations SHELL = /bin/sh .SUFFIXES: .SUFFIXES: .c .cpp .o .so .PRECIOUS: %.cpp CPPFLAGS := `pkg-config exiv2 --cflags` LDFLAGS := `pkg-config exiv2 --libs` BINOBJ = $(BINSRC:.cpp=.o) BINARY = $(BINSRC:.cpp=) EXECUTABLE = $(BINSRC:.cpp=$(EXEEXT)) ifdef DEP_TRACKING DEP = $(BINSRC:%.cpp=$(DEPDIR)/%.d) endif # ****************************************************************************** # Rules samples: $(BINARY) $(BINOBJ): %.o: %.cpp $(COMPILE.cc) -o $@ $< @$(MAKEDEPEND) @$(POSTDEPEND) $(BINARY): %: %.o $(LIBTOOL) --mode=link $(LINK.cc) -o $@ $@.o %.ii: %.cpp set -e; \ $(CXXCPP) -E $(CPPFLAGS) $< | sed '/^[ ]*$$/d' > $@ # ****************************************************************************** # Targets .PHONY: all relink binclean mostlyclean clean distclean maintainer-clean ifdef DEP_TRACKING # Include targets from dependency files -include $(DEP) endif relink: binclean samples # Remove binaries, e.g., to relink them binclean: $(RM) $(EXECUTABLE) mostlyclean: $(RM) core $(RM) $(CCSRC:.cpp=.ii) $(RM) $(CCSRC:%.cpp=.libs/%.d) $(CSRC:%.c=.libs/%.d) -rmdir .libs $(RM) $(BINOBJ) clean: binclean mostlyclean # Run `make distclean' from the top source directory to also remove # files created by configuring the program. distclean: clean ifdef DEP_TRACKING $(RM) $(DEP) -rmdir $(DEPDIR) endif $(RM) *~ *.bak *# # This command is intended for maintainers to use; it deletes files # that may need special tools to rebuild. maintainer-clean: distclean exiv2-0.23/samples/convert-test.cpp0000644000175000017500000000165111411621067017116 0ustar andreasandreas// ***************************************************************** -*- C++ -*- // convert-test.cpp, $Rev: 2286 $ // Conversion test driver - make sure you have a copy of the input file around! #include #include #include #include int main(int argc, char* const argv[]) try { if (argc != 2) { std::cout << "Usage: " << argv[0] << " file\n"; return 1; } Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(argv[1]); assert(image.get() != 0); image->readMetadata(); Exiv2::XmpData xmpData; Exiv2::copyExifToXmp(image->exifData(), xmpData); Exiv2::ExifData exifData; Exiv2::copyXmpToExif(xmpData, exifData); image->setXmpData(xmpData); image->setExifData(exifData); image->writeMetadata(); return 0; } catch (Exiv2::AnyError& e) { std::cout << "Caught Exiv2 exception '" << e << "'\n"; return -1; } exiv2-0.23/samples/werror-test.cpp0000644000175000017500000000132211411621067016751 0ustar andreasandreas// ***************************************************************** -*- C++ -*- // werror-test.cpp, $Rev: 2286 $ // Simple tests for the wide-string error class WError #include #include int main() { try { throw Exiv2::Error(-1, "ARG1", "ARG2", "ARG3"); } catch (const Exiv2::Error& e) { std::cout << "Caught Error '" << e.what() << "'\n"; } #ifdef EXV_UNICODE_PATH try { throw Exiv2::WError(-1, L"WARG1", L"WARG2", L"WARG3"); } catch (const Exiv2::WError& e) { std::wstring wmsg = e.wwhat(); std::string msg(wmsg.begin(), wmsg.end()); std::cout << "Caught WError '" << msg << "'\n"; } #endif return 0; } exiv2-0.23/README0000644000175000017500000001416611732641407013204 0ustar andreasandreasExiv2 ***** Welcome to Exiv2, a C++ library and a command line utility to read and write Exif, IPTC and XMP image metadata. The homepage of Exiv2 is: http://www.exiv2.org/ See doc/ChangeLog for a list of recent changes to Exiv2. Exiv2 API and tag reference documentation is at http://www.exiv2.org/doc or you can build it and point your browser to doc/index.html. For more information on XMP support in Exiv2, see doc/README-XMP. Building and Installing ======================= You can build the libraries in the following ways: 1 UNIX-like systems (including GNU/Linux, Mac OS X, Cygwin, MinGW) - general notes follow - FAQ concerning Cygwin/MSYS and Mac OS X: http://dev.exiv2.org/projects/exiv2/wiki/FAQ 2 Microsoft Visual C++ - see msvc/README-MSVC.txt (32bit build VC7.1/2003 and up) - see msvc64/ReadMe.txt (32bit and 64bit build VC8/2005 and up) 3 CMake (experimental support for cmake on all platforms) - see README-CMAKE for more information To build a commercial version of the Exiv2 library, see also section "Commercial version" at the end of this file. On UNIX-like systems, use the GNU configure script. Run the following commands from the top directory (containing this file) to configure, build and install the library and utility: $ ./configure $ make $ sudo make install If you downloaded the source code from the subversion repository, you won't have a configure script. Run 'make config' to generate it and see the section "Hacking" below. The default install locations are /usr/local/lib for the library, /usr/local/bin for the exiv2 utility and /usr/local/include/exiv2 for the header files. Use the --prefix=directory option of the configure script to change the default. Run './configure --help' to see a list of all options. To uninstall Exiv2 from a UNIX-like system, run: $ make uninstall Dependencies ============ The following libexiv2 features are enabled by default and may*) require external libraries. They can be controlled through configure options. See also './configure --help'. Feature Package Configure options -------------------------- -------- ---------------------------- PNG image support zlib --without-zlib --with-zlib=DIR Native language support gettext --disable-nls Characterset conversions libiconv --without-libiconv-prefix --with-libiconv-prefix[=DIR] XMP support expat --disable-xmp --with-expat=DIR zlib http://zlib.net/ gettext *) http://www.gnu.org/software/gettext/ libiconv *) http://www.gnu.org/software/libiconv/ expat http://expat.sourceforge.net/ *) Some systems have gettext and iconv in libc. The configure script should detect this. On Linux, it is usually best to install the dependencies through the package management system of the distribution together with the corresponding development packages (for the header files and static libraries). To build the sample programs in the samples/ directory ('make samples'), you also need to have the pkg-config program. To generate the documentation ('make doc'), you will further need doxygen, graphviz, python and xsltproc. pkg-config http://pkg-config.freedesktop.org/wiki/ doxygen http://www.doxygen.org/ graphviz http://www.graphviz.org/ python http://www.python.org/ xsltproc http://xmlsoft.org/XSLT/ Troubleshooting =============== If you have problems building Exiv2 on UNIX-like systems, check the generated config/config.mk and config/config.h files. You should *not* need to modify any Makefile directly, in particular not src/Makefile! Support ======= All project resources are accessible from the project website at http://dev.exiv2.org/wiki/exiv2 Please send feedback or queries to the Exiv2 forum. For new bug reports and feature requests, please open an issue. Hacking ======= A pkg-config .pc file is installed together with the library. Application developers can use pkg-config(1) to obtain correct compile and link time flags for the Exiv2 library. See samples/Makefile for an example. If you downloaded Exiv2 directly from the subversion repository, and you want to build it using the GNU configure script, then you need to have GNU Autoconf installed on your system and create the configure script as the first step: $ make config Then run the usual './configure; make; make install' commands. Exiv2 uses GNU Libtool in order to build shared libraries on a variety of systems. While this is very nice for making usable binaries, it can be a pain when trying to debug a program. For that reason, compilation of shared libraries can be turned off by specifying the --disable-shared option to the configure script. License ======= Copyright (C) 2004-2012 Andreas Huggel Exiv2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Alternatively, Exiv2 is also available with a commercial license, which allows it to be used in closed-source projects. Contact me for more information. Exiv2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. Commercial version ================== If you have a commercial license, you must disable NLS support and the conversion of Nikon lens data to readable lens names to build a commercial version of the Exiv2 library. To do this on Windows, compile the library with the preprocessor symbol EXV_COMMERCIAL_VERSION defined in msvc\include\exv_msvc.h or msvc64\include\exv_msvc.h. On UNIX-like systems, run the configure script with the options --enable-commercial --disable-nls --disable-lensdata. exiv2-0.23/config/0000755000175000017500000000000011745263717013571 5ustar andreasandreasexiv2-0.23/config/mkinstalldirs0000755000175000017500000000653511512651243016373 0ustar andreasandreas#! /bin/sh # mkinstalldirs --- make directory hierarchy scriptversion=2004-02-15.20 # Original author: Noah Friedman # Created: 1993-05-16 # Public domain. # # This file is maintained in Automake, please report # bugs to or send patches to # . errstatus=0 dirmode="" usage="\ Usage: mkinstalldirs [-h] [--help] [--version] [-m MODE] DIR ... Create each directory DIR (with mode MODE, if specified), including all leading file name components. Report bugs to ." # process command line arguments while test $# -gt 0 ; do case $1 in -h | --help | --h*) # -h for help echo "$usage" exit 0 ;; -m) # -m PERM arg shift test $# -eq 0 && { echo "$usage" 1>&2; exit 1; } dirmode=$1 shift ;; --version) echo "$0 $scriptversion" exit 0 ;; --) # stop option processing shift break ;; -*) # unknown option echo "$usage" 1>&2 exit 1 ;; *) # first non-opt arg break ;; esac done for file do if test -d "$file"; then shift else break fi done case $# in 0) exit 0 ;; esac # Solaris 8's mkdir -p isn't thread-safe. If you mkdir -p a/b and # mkdir -p a/c at the same time, both will detect that a is missing, # one will create a, then the other will try to create a and die with # a "File exists" error. This is a problem when calling mkinstalldirs # from a parallel make. We use --version in the probe to restrict # ourselves to GNU mkdir, which is thread-safe. case $dirmode in '') if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then echo "mkdir -p -- $*" exec mkdir -p -- "$@" else # On NextStep and OpenStep, the `mkdir' command does not # recognize any option. It will interpret all options as # directories to create, and then abort because `.' already # exists. test -d ./-p && rmdir ./-p test -d ./--version && rmdir ./--version fi ;; *) if mkdir -m "$dirmode" -p --version . >/dev/null 2>&1 && test ! -d ./--version; then echo "mkdir -m $dirmode -p -- $*" exec mkdir -m "$dirmode" -p -- "$@" else # Clean up after NextStep and OpenStep mkdir. for d in ./-m ./-p ./--version "./$dirmode"; do test -d $d && rmdir $d done fi ;; esac for file do set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'` shift pathcomp= for d do pathcomp="$pathcomp$d" case $pathcomp in -*) pathcomp=./$pathcomp ;; esac if test ! -d "$pathcomp"; then echo "mkdir $pathcomp" mkdir "$pathcomp" || lasterr=$? if test ! -d "$pathcomp"; then errstatus=$lasterr else if test ! -z "$dirmode"; then echo "chmod $dirmode $pathcomp" lasterr="" chmod "$dirmode" "$pathcomp" || lasterr=$? if test ! -z "$lasterr"; then errstatus=$lasterr fi fi fi fi pathcomp="$pathcomp/" done done exit $errstatus # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-end: "$" # End: exiv2-0.23/config/config.mk.in0000644000175000017500000001404711732641407015772 0ustar andreasandreas# ***************************************************** -*- Makefile -*- # # Copyright (C) 2004-2012 Andreas Huggel # # This Makefile is part of the Exiv2 distribution. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # 3. The name of the author may not be used to endorse or promote # products derived from this software without specific prior # written permission. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER # IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN # IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # File: config.mk.in # Version: $Rev: 2681 $ # Author(s): Andreas Huggel (ahu) # History: 10-Dec-03, ahu: created # # Description: # Exiv2 system configuration file. # # ********************************************************************** # Exiv2 version for use with libtool (-version-info argument) EXIV2_LTVERSION = @EXIV2_LTVERSION@ # Compile for use with a commercial license COMMERCIAL_VERSION = @COMMERCIAL_VERSION@ # ********************************************************************** # Libtool LIBTOOL = $(top_srcdir)/libtool LIBTOOL_DEPS = $(top_srcdir)/@LIBTOOL_DEPS@ # ********************************************************************** # C++ Compiler and precompiler CXX = @CXX@ GXX = @GXX@ # Common compiler flags (warnings, symbols [-ggdb], optimization [-O2], etc) CXXFLAGS = @CXXFLAGS@ ifeq ($(GXX),yes) CXXFLAGS += -Wall -Wcast-align -Wpointer-arith -Wformat-security -Wmissing-format-attribute -Woverloaded-virtual -W endif # Command to run only the preprocessor CXXCPP = @CXXCPP@ # Preprocessor flags CPPFLAGS = -I. @CPPFLAGS@ -DEXV_LOCALEDIR=\"$(localedir)\" ifeq ($(COMMERCIAL_VERSION),yes) CPPFLAGS += -DEXV_COMMERCIAL_VERSION=1 endif # Linker flags and libraries LDFLAGS = @LDFLAGS@ LIBS = @LTLIBINTL@ @LTLIBICONV@ @LIBS@ # Suffix of executables EXEEXT := @EXEEXT@ # ********************************************************************** # C Compiler CC = @CC@ GCC = @GCC@ CFLAGS = @CFLAGS@ ifeq ($(GCC),yes) CFLAGS += -Wall endif # ********************************************************************** # XMP support ENABLE_XMP = @ENABLE_XMP@ ifdef ENABLE_XMP XMPSDK_LIBRARY = xmpsdk XMPSDK_DIR = $(top_srcdir)/xmpsdk XMPSDK_CPPFLAGS = -I$(XMPSDK_DIR)/include XMPSDK_LDFLAGS = -L$(XMPSDK_DIR)/src XMPSDK_LIBS = -l$(XMPSDK_LIBRARY) else # Enable additional warnings. XMP Toolkit doesn't compile # with these. ifeq ($(GXX),yes) CXXFLAGS += -Wundef -pedantic endif endif # Expat library needed to compile the XMP Toolkit EXPAT_LDFLAGS = @EXPAT_LDFLAGS@ EXPAT_CPPFLAGS = @EXPAT_CPPFLAGS@ EXPAT_LIBS = @EXPAT_LIBS@ # ********************************************************************** # Libraries, include files, functions HAVE_LIBZ = @HAVE_LIBZ@ HAVE_STDINT = @HAVE_STDINT@ HAVE_TIMEGM = @HAVE_TIMEGM@ # ********************************************************************** # Advanced auto-dependency generation # http://make.paulandlesley.org/autodep.html DEP_TRACKING = @DEP_TRACKING@ ifdef DEP_TRACKING # Directory for dependency files DEPDIR = .deps # Command to run the compiler or preprocessor to produce # dependencies. If you're not using gcc, you may need to change # this to something suitable for your compiler or simply unset # the variable. See the link above for suggestions. MAKEDEPEND = $(CXX) -MM $(CPPFLAGS) -o $*.d $< # Dependency files post-process commands POSTDEPEND = if test ! -d $(DEPDIR); then mkdir $(DEPDIR); fi; \ if test -e $*.d; then cp $*.d $(DEPDIR)/$*.d; \ sed -e 's/^\#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \ -e '/^$$/ d' -e 's/$$/ :/' < $*.d >> $(DEPDIR)/$*.d; \ $(RM) $*.d; fi # Compiler flags to generate dependency files at the same time # as object files (for gcc) ifeq ($(GXX),yes) CXXFLAGS += -MMD CFLAGS += -MMD MAKEDEPEND = endif endif # ********************************************************************** # Compilation shortcuts COMPILE.cc = $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c COMPILE.c = $(CC) $(CFLAGS) $(CPPFLAGS) -c # LINK.cc does not need $(LIBS), libtool's dark magic takes care of that # when linking a binary with a libtool library. LINK.cc = $(CXX) $(LDFLAGS) # ********************************************************************** # Installation programs INSTALL_EXE = @INSTALL@ INSTALL_PROGRAM = $(INSTALL_EXE) INSTALL_DATA = $(INSTALL_EXE) -m 644 INSTALL_DIRS = $(top_srcdir)/config/mkinstalldirs # ********************************************************************** # Other programs RM = rm -f # ********************************************************************** # Directories prefix = @prefix@ exec_prefix = @exec_prefix@ # Source directory srcdir = @srcdir@ # Installation directories bindir = @bindir@ datarootdir = @datarootdir@ datadir = @datadir@ localedir = $(datadir)/locale incdir = @includedir@/exiv2 libdir = @libdir@ mandir = @mandir@ man1dir = $(mandir)/man1 exiv2-0.23/config/config.make0000644000175000017500000000431411732641407015667 0ustar andreasandreas# ***************************************************** -*- Makefile -*- # # Copyright (C) 2004-2012 Andreas Huggel # # This Makefile is part of the Exiv2 distribution. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # 3. The name of the author may not be used to endorse or promote # products derived from this software without specific prior # written permission. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER # IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN # IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # File: config.make # Version: $Rev: 2681 $ # Author(s): Andreas Huggel (ahu) # History: 26-Feb-05, ahu: created # # Description: # Simple makefile to automate config tasks # # Restrictions: # Requires GNU make. # # Default make target all: config .PHONY: all config mostlyclean clean distclean maintainer-clean config: autoconf -o ../configure mostlyclean clean: rm -f configure.scan autoscan.log rm -rf autom4te.cache/ rm -f *~ *.bak *# distclean: clean rm -f config.h ../src/exv_conf.h config.mk exiv2.pc # This removes almost everything, including the configure script! maintainer-clean: distclean exiv2-0.23/config/Makefile.in0000644000175000017500000000704011732641407015627 0ustar andreasandreas# ***************************************************** -*- Makefile -*- # # Copyright (C) 2004-2012 Andreas Huggel # # This Makefile is part of the Exiv2 distribution. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # 3. The name of the author may not be used to endorse or promote # products derived from this software without specific prior # written permission. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER # IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN # IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # File: Makefile.in # Version: $Rev: 2681 $ # Author(s): Andreas Huggel (ahu) # History: 15-Jan-04, ahu: created # # Description: # Simple top-level makefile that mainly forwards to makefiles in # subdirectories. # # Restrictions: # Requires GNU make. # ######################################################################## # Makefile is a generated file. Do NOT change any settings in this file. # Run ./configure with the appropriate options to regenerate the file # and possibly others. ######################################################################## SHELL = /bin/sh ENABLE_XMP = @ENABLE_XMP@ .PHONY: all doc config samples xmpsdk \ mostlyclean clean distclean maintainer-clean \ install uninstall all install: config/config.mk xmpsdk cd src && $(MAKE) $(MAKECMDGOALS) cd po && $(MAKE) $(MAKECMDGOALS) uninstall: config/config.mk cd src && $(MAKE) $(MAKECMDGOALS) cd po && $(MAKE) $(MAKECMDGOALS) doc: config/config.mk cd doc && $(MAKE) $(MAKECMDGOALS) samples: config/config.mk cd samples && $(MAKE) $(MAKECMDGOALS) config: cd config && $(MAKE) -f config.make $(MAKECMDGOALS) xmpsdk: config/config.mk if test "x$(ENABLE_XMP)" = "x1"; then cd xmpsdk/src && $(MAKE) $@; fi; mostlyclean clean: config/config.mk cd src && $(MAKE) $(MAKECMDGOALS) cd doc && $(MAKE) $(MAKECMDGOALS) cd samples && $(MAKE) $(MAKECMDGOALS) cd xmpsdk/src && $(MAKE) $(MAKECMDGOALS) cd config && $(MAKE) -f config.make $(MAKECMDGOALS) cd po && $(MAKE) $(MAKECMDGOALS) # `make distclean' also removes files created by configuring # the program. Running `make all distclean' prepares the project # for packaging. distclean: clean rm -f config.log config.status libtool rm -f *~ *.bak *# # This removes almost everything, including the configure script! maintainer-clean: distclean rm -f configure -cd test && $(MAKE) $(MAKECMDGOALS) config/config.mk: $(error File config/config.mk does not exist. Did you run ./configure?) exiv2-0.23/config/config.rpath0000755000175000017500000004364711512651243016102 0ustar andreasandreas#! /bin/sh # Output a system dependent set of variables, describing how to set the # run time search path of shared libraries in an executable. # # Copyright 1996-2007 Free Software Foundation, Inc. # Taken from GNU libtool, 2001 # Originally by Gordon Matzigkeit , 1996 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # # The first argument passed to this file is the canonical host specification, # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # The environment variables CC, GCC, LDFLAGS, LD, with_gnu_ld # should be set by the caller. # # The set of defined variables is at the end of this script. # Known limitations: # - On IRIX 6.5 with CC="cc", the run time search patch must not be longer # than 256 bytes, otherwise the compiler driver will dump core. The only # known workaround is to choose shorter directory names for the build # directory and/or the installation directory. # All known linkers require a `.a' archive for static linking (except MSVC, # which needs '.lib'). libext=a shrext=.so host="$1" host_cpu=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` host_vendor=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` host_os=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` # Code taken from libtool.m4's _LT_CC_BASENAME. for cc_temp in $CC""; do case $cc_temp in compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; \-*) ;; *) break;; esac done cc_basename=`echo "$cc_temp" | sed -e 's%^.*/%%'` # Code taken from libtool.m4's AC_LIBTOOL_PROG_COMPILER_PIC. wl= if test "$GCC" = yes; then wl='-Wl,' else case "$host_os" in aix*) wl='-Wl,' ;; darwin*) case $cc_basename in xlc*) wl='-Wl,' ;; esac ;; mingw* | cygwin* | pw32* | os2*) ;; hpux9* | hpux10* | hpux11*) wl='-Wl,' ;; irix5* | irix6* | nonstopux*) wl='-Wl,' ;; newsos6) ;; linux* | k*bsd*-gnu) case $cc_basename in icc* | ecc*) wl='-Wl,' ;; pgcc | pgf77 | pgf90) wl='-Wl,' ;; ccc*) wl='-Wl,' ;; como) wl='-lopt=' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) wl='-Wl,' ;; esac ;; esac ;; osf3* | osf4* | osf5*) wl='-Wl,' ;; rdos*) ;; solaris*) wl='-Wl,' ;; sunos4*) wl='-Qoption ld ' ;; sysv4 | sysv4.2uw2* | sysv4.3*) wl='-Wl,' ;; sysv4*MP*) ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) wl='-Wl,' ;; unicos*) wl='-Wl,' ;; uts4*) ;; esac fi # Code taken from libtool.m4's AC_LIBTOOL_PROG_LD_SHLIBS. hardcode_libdir_flag_spec= hardcode_libdir_separator= hardcode_direct=no hardcode_minus_L=no case "$host_os" in cygwin* | mingw* | pw32*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. if test "$GCC" != yes; then with_gnu_ld=no fi ;; interix*) # we just hope/assume this is gcc and not c89 (= MSVC++) with_gnu_ld=yes ;; openbsd*) with_gnu_ld=no ;; esac ld_shlibs=yes if test "$with_gnu_ld" = yes; then # Set some defaults for GNU ld with shared library support. These # are reset later if shared libraries are not supported. Putting them # here allows them to be overridden if necessary. # Unlike libtool, we use -rpath here, not --rpath, since the documented # option of GNU ld is called -rpath, not --rpath. hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' case "$host_os" in aix3* | aix4* | aix5*) # On AIX/PPC, the GNU linker is very broken if test "$host_cpu" != ia64; then ld_shlibs=no fi ;; amigaos*) hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes # Samuel A. Falvo II reports # that the semantics of dynamic libraries on AmigaOS, at least up # to version 4, is to share data among multiple programs linked # with the same dynamic library. Since this doesn't match the # behavior of shared libraries on other platforms, we cannot use # them. ld_shlibs=no ;; beos*) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then : else ld_shlibs=no fi ;; cygwin* | mingw* | pw32*) # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. hardcode_libdir_flag_spec='-L$libdir' if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then : else ld_shlibs=no fi ;; interix[3-9]*) hardcode_direct=no hardcode_libdir_flag_spec='${wl}-rpath,$libdir' ;; gnu* | linux* | k*bsd*-gnu) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then : else ld_shlibs=no fi ;; netbsd*) ;; solaris*) if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then ld_shlibs=no elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then : else ld_shlibs=no fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) case `$LD -v 2>&1` in *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) ld_shlibs=no ;; *) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`' else ld_shlibs=no fi ;; esac ;; sunos4*) hardcode_direct=yes ;; *) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then : else ld_shlibs=no fi ;; esac if test "$ld_shlibs" = no; then hardcode_libdir_flag_spec= fi else case "$host_os" in aix3*) # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. hardcode_minus_L=yes if test "$GCC" = yes; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. hardcode_direct=unsupported fi ;; aix4* | aix5*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no else aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[23]|aix4.[23].*|aix5*) for ld_flag in $LDFLAGS; do if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then aix_use_runtimelinking=yes break fi done ;; esac fi hardcode_direct=yes hardcode_libdir_separator=':' if test "$GCC" = yes; then case $host_os in aix4.[012]|aix4.[012].*) collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && \ strings "$collect2name" | grep resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 hardcode_direct=unsupported hardcode_minus_L=yes hardcode_libdir_flag_spec='-L$libdir' hardcode_libdir_separator= fi ;; esac fi # Begin _LT_AC_SYS_LIBPATH_AIX. echo 'int main () { return 0; }' > conftest.c ${CC} ${LDFLAGS} conftest.c -o conftest aix_libpath=`dump -H conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'` if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'` fi if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib" fi rm -f conftest.c conftest # End _LT_AC_SYS_LIBPATH_AIX. if test "$aix_use_runtimelinking" = yes; then hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" else if test "$host_cpu" = ia64; then hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' else hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" fi fi ;; amigaos*) hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes # see comment about different semantics on the GNU ld section ld_shlibs=no ;; bsdi[45]*) ;; cygwin* | mingw* | pw32*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. hardcode_libdir_flag_spec=' ' libext=lib ;; darwin* | rhapsody*) hardcode_direct=no if test "$GCC" = yes ; then : else case $cc_basename in xlc*) ;; *) ld_shlibs=no ;; esac fi ;; dgux*) hardcode_libdir_flag_spec='-L$libdir' ;; freebsd1*) ld_shlibs=no ;; freebsd2.2*) hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes ;; freebsd2*) hardcode_direct=yes hardcode_minus_L=yes ;; freebsd* | dragonfly*) hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes ;; hpux9*) hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: hardcode_direct=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes ;; hpux10*) if test "$with_gnu_ld" = no; then hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: hardcode_direct=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes fi ;; hpux11*) if test "$with_gnu_ld" = no; then hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: case $host_cpu in hppa*64*|ia64*) hardcode_direct=no ;; *) hardcode_direct=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes ;; esac fi ;; irix5* | irix6* | nonstopux*) hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: ;; netbsd*) hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes ;; newsos6) hardcode_direct=yes hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: ;; openbsd*) if test -f /usr/libexec/ld.so; then hardcode_direct=yes if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then hardcode_libdir_flag_spec='${wl}-rpath,$libdir' else case "$host_os" in openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) hardcode_libdir_flag_spec='-R$libdir' ;; *) hardcode_libdir_flag_spec='${wl}-rpath,$libdir' ;; esac fi else ld_shlibs=no fi ;; os2*) hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes ;; osf3*) hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: ;; osf4* | osf5*) if test "$GCC" = yes; then hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' else # Both cc and cxx compiler support -rpath directly hardcode_libdir_flag_spec='-rpath $libdir' fi hardcode_libdir_separator=: ;; solaris*) hardcode_libdir_flag_spec='-R$libdir' ;; sunos4*) hardcode_libdir_flag_spec='-L$libdir' hardcode_direct=yes hardcode_minus_L=yes ;; sysv4) case $host_vendor in sni) hardcode_direct=yes # is this really true??? ;; siemens) hardcode_direct=no ;; motorola) hardcode_direct=no #Motorola manual says yes, but my tests say they lie ;; esac ;; sysv4.3*) ;; sysv4*MP*) if test -d /usr/nec; then ld_shlibs=yes fi ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) ;; sysv5* | sco3.2v5* | sco5v6*) hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`' hardcode_libdir_separator=':' ;; uts4*) hardcode_libdir_flag_spec='-L$libdir' ;; *) ld_shlibs=no ;; esac fi # Check dynamic linker characteristics # Code taken from libtool.m4's AC_LIBTOOL_SYS_DYNAMIC_LINKER. # Unlike libtool.m4, here we don't care about _all_ names of the library, but # only about the one the linker finds when passed -lNAME. This is the last # element of library_names_spec in libtool.m4, or possibly two of them if the # linker has special search rules. library_names_spec= # the last element of library_names_spec in libtool.m4 libname_spec='lib$name' case "$host_os" in aix3*) library_names_spec='$libname.a' ;; aix4* | aix5*) library_names_spec='$libname$shrext' ;; amigaos*) library_names_spec='$libname.a' ;; beos*) library_names_spec='$libname$shrext' ;; bsdi[45]*) library_names_spec='$libname$shrext' ;; cygwin* | mingw* | pw32*) shrext=.dll library_names_spec='$libname.dll.a $libname.lib' ;; darwin* | rhapsody*) shrext=.dylib library_names_spec='$libname$shrext' ;; dgux*) library_names_spec='$libname$shrext' ;; freebsd1*) ;; freebsd* | dragonfly*) case "$host_os" in freebsd[123]*) library_names_spec='$libname$shrext$versuffix' ;; *) library_names_spec='$libname$shrext' ;; esac ;; gnu*) library_names_spec='$libname$shrext' ;; hpux9* | hpux10* | hpux11*) case $host_cpu in ia64*) shrext=.so ;; hppa*64*) shrext=.sl ;; *) shrext=.sl ;; esac library_names_spec='$libname$shrext' ;; interix[3-9]*) library_names_spec='$libname$shrext' ;; irix5* | irix6* | nonstopux*) library_names_spec='$libname$shrext' case "$host_os" in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= ;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 ;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 ;; *) libsuff= shlibsuff= ;; esac ;; esac ;; linux*oldld* | linux*aout* | linux*coff*) ;; linux* | k*bsd*-gnu) library_names_spec='$libname$shrext' ;; knetbsd*-gnu) library_names_spec='$libname$shrext' ;; netbsd*) library_names_spec='$libname$shrext' ;; newsos6) library_names_spec='$libname$shrext' ;; nto-qnx*) library_names_spec='$libname$shrext' ;; openbsd*) library_names_spec='$libname$shrext$versuffix' ;; os2*) libname_spec='$name' shrext=.dll library_names_spec='$libname.a' ;; osf3* | osf4* | osf5*) library_names_spec='$libname$shrext' ;; rdos*) ;; solaris*) library_names_spec='$libname$shrext' ;; sunos4*) library_names_spec='$libname$shrext$versuffix' ;; sysv4 | sysv4.3*) library_names_spec='$libname$shrext' ;; sysv4*MP*) library_names_spec='$libname$shrext' ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) library_names_spec='$libname$shrext' ;; uts4*) library_names_spec='$libname$shrext' ;; esac sed_quote_subst='s/\(["`$\\]\)/\\\1/g' escaped_wl=`echo "X$wl" | sed -e 's/^X//' -e "$sed_quote_subst"` shlibext=`echo "$shrext" | sed -e 's,^\.,,'` escaped_libname_spec=`echo "X$libname_spec" | sed -e 's/^X//' -e "$sed_quote_subst"` escaped_library_names_spec=`echo "X$library_names_spec" | sed -e 's/^X//' -e "$sed_quote_subst"` escaped_hardcode_libdir_flag_spec=`echo "X$hardcode_libdir_flag_spec" | sed -e 's/^X//' -e "$sed_quote_subst"` LC_ALL=C sed -e 's/^\([a-zA-Z0-9_]*\)=/acl_cv_\1=/' <