Annotate debug_exception() with source file, line, and function.
[geeqie.git] / src / exiv2.cc
index f870cae..455c8d3 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Geeqie
- * Copyright (C) 2008 - 2009 The Geeqie Team
+ * Copyright (C) 2008 - 2012 The Geeqie Team
  *
  * Author: Vladimir Nadvornik
  *
@@ -76,12 +76,42 @@ struct _AltKey
 
 /* this is a list of keys that should be converted, even with the older Exiv2 which does not support it directly */
 static const AltKey alt_keys[] = {
-       {"Xmp.tiff.Orientation", "Exif.Image.Orientation", NULL},
-       {"Xmp.dc.subject", NULL, "Iptc.Application2.Keywords"},
-       {"Xmp.dc.description", NULL, "Iptc.Application2.Caption"},
+       {"Xmp.tiff.Orientation",                "Exif.Image.Orientation",       NULL},
+       {"Xmp.dc.title",                        NULL,                           "Iptc.Application2.ObjectName"          },
+       {"Xmp.photoshop.Urgency",               NULL,                           "Iptc.Application2.Urgency"             },
+       {"Xmp.photoshop.Category",              NULL,                           "Iptc.Application2.Category"            },
+       {"Xmp.photoshop.SupplementalCategory",  NULL,                           "Iptc.Application2.SuppCategory"        },
+       {"Xmp.dc.subject",                      NULL,                           "Iptc.Application2.Keywords"            },
+       {"Xmp.iptc.Location",                   NULL,                           "Iptc.Application2.LocationName"        },
+       {"Xmp.photoshop.Instruction",           NULL,                           "Iptc.Application2.SpecialInstructions" },
+       {"Xmp.photoshop.DateCreated",           NULL,                           "Iptc.Application2.DateCreated"         },
+       {"Xmp.dc.creator",                      NULL,                           "Iptc.Application2.Byline"              },
+       {"Xmp.photoshop.AuthorsPosition",       NULL,                           "Iptc.Application2.BylineTitle"         },
+       {"Xmp.photoshop.City",                  NULL,                           "Iptc.Application2.City"                },
+       {"Xmp.photoshop.State",                 NULL,                           "Iptc.Application2.ProvinceState"       },
+       {"Xmp.iptc.CountryCode",                NULL,                           "Iptc.Application2.CountryCode"         },
+       {"Xmp.photoshop.Country",               NULL,                           "Iptc.Application2.CountryName"         },
+       {"Xmp.photoshop.TransmissionReference", NULL,                           "Iptc.Application2.TransmissionReference"},
+       {"Xmp.photoshop.Headline",              NULL,                           "Iptc.Application2.Headline"            },
+       {"Xmp.photoshop.Credit",                NULL,                           "Iptc.Application2.Credit"              },
+       {"Xmp.photoshop.Source",                NULL,                           "Iptc.Application2.Source"              },
+       {"Xmp.dc.rights",                       NULL,                           "Iptc.Application2.Copyright"           },
+       {"Xmp.dc.description",                  NULL,                           "Iptc.Application2.Caption"             },
+       {"Xmp.photoshop.CaptionWriter",         NULL,                           "Iptc.Application2.Writer"              },
        {NULL, NULL, NULL}
        };
 
+static void _debug_exception(const char* file,
+                             int line,
+                             const char* func,
+                             Exiv2::AnyError& e)
+{
+       gchar *str = g_locale_from_utf8(e.what(), -1, NULL, NULL, NULL);
+       DEBUG_1("%s:%d:%s:Exiv2: %s", file, line, func, str);
+       g_free(str);
+}
+
+#define debug_exception(e) _debug_exception(__FILE__, __LINE__, __func__, e)
 
 struct _ExifData
 {
@@ -129,6 +159,13 @@ protected:
        /* the icc profile in jpeg is not technically exif - store it here */
        unsigned char *cp_data_;
        guint cp_length_;
+       gboolean valid_;
+
+       Exiv2::ExifData emptyExifData_;
+       Exiv2::IptcData emptyIptcData_;
+#if EXIV2_TEST_VERSION(0,16,0)
+       Exiv2::XmpData emptyXmpData_;
+#endif
 
 public:
        _ExifDataOriginal(Exiv2::Image::AutoPtr image)
@@ -136,43 +173,53 @@ public:
                cp_data_ = NULL;
                cp_length_ = 0;
                image_ = image;
+               valid_ = TRUE;
        }
 
        _ExifDataOriginal(gchar *path)
        {
                cp_data_ = NULL;
                cp_length_ = 0;
+               valid_ = TRUE;
+               
                gchar *pathl = path_from_utf8(path);
-               image_ = Exiv2::ImageFactory::open(pathl);
-               g_free(pathl);
-//             g_assert (image.get() != 0);
-               image_->readMetadata();
+               try 
+                       {
+                       image_ = Exiv2::ImageFactory::open(pathl);
+//                     g_assert (image.get() != 0);
+                       image_->readMetadata();
 
 #if EXIV2_TEST_VERSION(0,16,0)
-               if (image_->mimeType() == "application/rdf+xml")
-                       {
-                       //Exiv2 sidecar converts xmp to exif and iptc, we don't want it.
-                       image_->clearExifData();
-                       image_->clearIptcData();
-                       }
+                       if (image_->mimeType() == "application/rdf+xml")
+                               {
+                               //Exiv2 sidecar converts xmp to exif and iptc, we don't want it.
+                               image_->clearExifData();
+                               image_->clearIptcData();
+                               }
 #endif
 
 #if EXIV2_TEST_VERSION(0,14,0)
-               if (image_->mimeType() == "image/jpeg")
-                       {
-                       /* try to get jpeg color profile */
-                       Exiv2::BasicIo &io = image_->io();
-                       gint open = io.isopen();
-                       if (!open) io.open();
-                       if (io.isopen())
+                       if (image_->mimeType() == "image/jpeg")
                                {
-                               unsigned char *mapped = (unsigned char*)io.mmap();
-                               if (mapped) exif_jpeg_parse_color(this, mapped, io.size());
-                               io.munmap();
+                               /* try to get jpeg color profile */
+                               Exiv2::BasicIo &io = image_->io();
+                               gint open = io.isopen();
+                               if (!open) io.open();
+                               if (io.isopen())
+                                       {
+                                       unsigned char *mapped = (unsigned char*)io.mmap();
+                                       if (mapped) exif_jpeg_parse_color(this, mapped, io.size());
+                                       io.munmap();
+                                       }
+                               if (!open) io.close();
                                }
-                       if (!open) io.close();
-                       }
 #endif
+                       }
+               catch (Exiv2::AnyError& e) 
+                       {
+                       valid_ = FALSE;
+                       }
+               g_free(pathl);
        }
        
        virtual ~_ExifDataOriginal()
@@ -182,22 +229,26 @@ public:
        
        virtual Exiv2::Image *image()
        {
+               if (!valid_) return NULL;
                return image_.get();
        }
        
        virtual Exiv2::ExifData &exifData ()
        {
+               if (!valid_) return emptyExifData_;
                return image_->exifData();
        }
 
        virtual Exiv2::IptcData &iptcData ()
        {
+               if (!valid_) return emptyIptcData_;
                return image_->iptcData();
        }
 
 #if EXIV2_TEST_VERSION(0,16,0)
        virtual Exiv2::XmpData &xmpData ()
        {
+               if (!valid_) return emptyXmpData_;
                return image_->xmpData();
        }
 #endif
@@ -257,7 +308,14 @@ public:
                exifData_ = imageData_->exifData();
                iptcData_ = imageData_->iptcData();
 #if EXIV2_TEST_VERSION(0,17,0)
-               syncExifWithXmp(exifData_, xmpData_);
+               try
+                       {
+                       syncExifWithXmp(exifData_, xmpData_);
+                       }
+               catch (...)
+                       {
+                       DEBUG_1("Exiv2: Catching bug\n");
+                       }
 #endif
                if (modified_xmp)
                        {
@@ -288,12 +346,15 @@ public:
 
                        copyXmpToExif(xmpData_, exifData_);
 #endif
-                       imageData_->image()->setExifData(exifData_);
-                       imageData_->image()->setIptcData(iptcData_);
+                       Exiv2::Image *image = imageData_->image();
+                       
+                       if (!image) Exiv2::Error(21);
+                       image->setExifData(exifData_);
+                       image->setIptcData(iptcData_);
 #if EXIV2_TEST_VERSION(0,16,0)
-                       imageData_->image()->setXmpData(xmpData_);
+                       image->setXmpData(xmpData_);
 #endif
-                       imageData_->image()->writeMetadata();
+                       image->writeMetadata();
                        } 
                else
                        {
@@ -372,7 +433,7 @@ ExifData *exif_read(gchar *path, gchar *sidecar_path, GHashTable *modified_xmp)
                return new _ExifDataProcessed(path, sidecar_path, modified_xmp);
        }
        catch (Exiv2::AnyError& e) {
-               std::cout << "Caught Exiv2 exception '" << e << "'\n";
+               debug_exception(e);
                return NULL;
        }
        
@@ -385,7 +446,7 @@ gboolean exif_write(ExifData *exif)
                return TRUE;
        }
        catch (Exiv2::AnyError& e) {
-               std::cout << "Caught Exiv2 exception '" << e << "'\n";
+               debug_exception(e);
                return FALSE;
        }
 }
@@ -397,7 +458,7 @@ gboolean exif_write_sidecar(ExifData *exif, gchar *path)
                return TRUE;
        }
        catch (Exiv2::AnyError& e) {
-               std::cout << "Caught Exiv2 exception '" << e << "'\n";
+               debug_exception(e);
                return FALSE;
        }
        
@@ -446,7 +507,7 @@ ExifItem *exif_get_item(ExifData *exif, const gchar *key)
                return (ExifItem *)item;
        }
        catch (Exiv2::AnyError& e) {
-               std::cout << "Caught Exiv2 exception '" << e << "'\n";
+               debug_exception(e);
                return NULL;
        }
 }
@@ -483,7 +544,7 @@ ExifItem *exif_add_item(ExifData *exif, const gchar *key)
                return (ExifItem *)item;
        }
        catch (Exiv2::AnyError& e) {
-               std::cout << "Caught Exiv2 exception '" << e << "'\n";
+               debug_exception(e);
                return NULL;
        }
 }
@@ -521,7 +582,7 @@ ExifItem *exif_get_first_item(ExifData *exif)
                        
        }
        catch (Exiv2::AnyError& e) {
-               std::cout << "Caught Exiv2 exception '" << e << "'\n";
+               debug_exception(e);
                return NULL;
        }
 }
@@ -552,7 +613,7 @@ ExifItem *exif_get_next_item(ExifData *exif)
                return NULL;
        }
        catch (Exiv2::AnyError& e) {
-               std::cout << "Caught Exiv2 exception '" << e << "'\n";
+               debug_exception(e);
                return NULL;
        }
 }
@@ -564,7 +625,7 @@ char *exif_item_get_tag_name(ExifItem *item)
                return g_strdup(((Exiv2::Metadatum *)item)->key().c_str());
        }
        catch (Exiv2::AnyError& e) {
-               std::cout << "Caught Exiv2 exception '" << e << "'\n";
+               debug_exception(e);
                return NULL;
        }
 }
@@ -576,7 +637,7 @@ guint exif_item_get_tag_id(ExifItem *item)
                return ((Exiv2::Metadatum *)item)->tag();
        }
        catch (Exiv2::AnyError& e) {
-               std::cout << "Caught Exiv2 exception '" << e << "'\n";
+               debug_exception(e);
                return 0;
        }
 }
@@ -588,7 +649,7 @@ guint exif_item_get_elements(ExifItem *item)
                return ((Exiv2::Metadatum *)item)->count();
        }
        catch (Exiv2::AnyError& e) {
-               std::cout << "Caught Exiv2 exception '" << e << "'\n";
+               debug_exception(e);
                return 0;
        }
 }
@@ -605,7 +666,7 @@ char *exif_item_get_data(ExifItem *item, guint *data_len)
                return data;
        }
        catch (Exiv2::AnyError& e) {
-               std::cout << "Caught Exiv2 exception '" << e << "'\n";
+               debug_exception(e);
                return NULL;
        }
 }
@@ -617,7 +678,7 @@ char *exif_item_get_description(ExifItem *item)
                return utf8_validate_or_convert(((Exiv2::Metadatum *)item)->tagLabel().c_str());
        }
        catch (std::exception& e) {
-//             std::cout << "Caught Exiv2 exception '" << e << "'\n";
+//             debug_exception(e);
                return NULL;
        }
 }
@@ -664,7 +725,7 @@ guint exif_item_get_format_id(ExifItem *item)
                return format_id_trans_tbl[id];
        }
        catch (Exiv2::AnyError& e) {
-               std::cout << "Caught Exiv2 exception '" << e << "'\n";
+               debug_exception(e);
                return EXIF_FORMAT_UNKNOWN;
        }
 }
@@ -676,7 +737,7 @@ const char *exif_item_get_format_name(ExifItem *item, gboolean brief)
                return ((Exiv2::Metadatum *)item)->typeName();
        }
        catch (Exiv2::AnyError& e) {
-               std::cout << "Caught Exiv2 exception '" << e << "'\n";
+               debug_exception(e);
                return NULL;
        }
 }
@@ -741,12 +802,12 @@ gchar *exif_item_get_string(ExifItem *item, int idx)
 gint exif_item_get_integer(ExifItem *item, gint *value)
 {
        try {
-               if (!item) return 0;
+               if (!item || exif_item_get_elements(item) == 0) return 0;
                *value = ((Exiv2::Metadatum *)item)->toLong();
                return 1;
        }
        catch (Exiv2::AnyError& e) {
-               std::cout << "Caught Exiv2 exception '" << e << "'\n";
+               debug_exception(e);
                return 0;
        }
 }
@@ -764,7 +825,7 @@ ExifRational *exif_item_get_rational(ExifItem *item, gint *sign, guint n)
                return &ret;
        }
        catch (Exiv2::AnyError& e) {
-               std::cout << "Caught Exiv2 exception '" << e << "'\n";
+               debug_exception(e);
                return NULL;
        }
 }
@@ -773,12 +834,27 @@ gchar *exif_get_tag_description_by_key(const gchar *key)
 {
        try {
                Exiv2::ExifKey ekey(key);
-               return utf8_validate_or_convert(Exiv2::ExifTags::tagLabel(ekey.tag(), ekey.ifdId ()));
+               return utf8_validate_or_convert(ekey.tagLabel().c_str());
        }
        catch (Exiv2::AnyError& e) {
-               std::cout << "Caught Exiv2 exception '" << e << "'\n";
-               return NULL;
+               try {
+                       Exiv2::IptcKey ikey(key);
+                       return utf8_validate_or_convert(ikey.tagLabel().c_str());
+               }
+               catch (Exiv2::AnyError& e) {
+                       try {
+#if EXIV2_TEST_VERSION(0,16,0)
+                               Exiv2::XmpKey xkey(key);
+                               return utf8_validate_or_convert(xkey.tagLabel().c_str());
+#endif
+                       }
+                       catch (Exiv2::AnyError& e) {
+                               debug_exception(e);
+                               return NULL;
+                       }
+               }
        }
+       return NULL;
 }
 
 static const AltKey *find_alt_key(const gchar *xmp_key)
@@ -854,7 +930,7 @@ static gint exif_update_metadata_simple(ExifData *exif, const gchar *key, const
                return 1;
        }
        catch (Exiv2::AnyError& e) {
-               std::cout << "Caught Exiv2 exception '" << e << "'\n";
+               debug_exception(e);
                return 0;
        }
 }
@@ -918,12 +994,12 @@ static GList *exif_add_value_to_glist(GList *list, Exiv2::Metadatum &item, Metad
 #if EXIV2_TEST_VERSION(0,16,0)
                        Exiv2::Xmpdatum *xmpdatum;
 #endif
-                       if ((exifdatum = dynamic_cast<Exiv2::Exifdatum *>(metadatum)))
+                       if ((exifdatum = dynamic_cast<Exiv2::Exifdatum *>(&item)))
                                stream << *exifdatum;
-                       else if ((iptcdatum = dynamic_cast<Exiv2::Iptcdatum *>(metadatum)))
+                       else if ((iptcdatum = dynamic_cast<Exiv2::Iptcdatum *>(&item)))
                                stream << *iptcdatum;
 #if EXIV2_TEST_VERSION(0,16,0)
-                       else if ((xmpdatum = dynamic_cast<Exiv2::Xmpdatum *>(metadatum)))
+                       else if ((xmpdatum = dynamic_cast<Exiv2::Xmpdatum *>(&item)))
                                stream << *xmpdatum;
 #endif
                        str = stream.str();
@@ -938,11 +1014,11 @@ static GList *exif_add_value_to_glist(GList *list, Exiv2::Metadatum &item, Metad
                else
                        {
                        str = item.toString();
-                       if (str.length() > 5 && str.substr(0, 5) == "lang=")
-                               {
-                               std::string::size_type pos = str.find_first_of(' ');
-                               if (pos != std::string::npos) str = str.substr(pos+1);
-                               }
+                       }
+               if (str.length() > 5 && str.substr(0, 5) == "lang=")
+                       {
+                       std::string::size_type pos = str.find_first_of(' ');
+                       if (pos != std::string::npos) str = str.substr(pos+1);
                        }
                list = g_list_append(list, utf8_validate_or_convert(str.c_str())); 
 #if EXIV2_TEST_VERSION(0,16,0)
@@ -992,7 +1068,7 @@ static GList *exif_get_metadata_simple(ExifData *exif, const gchar *key, Metadat
                }
        }
        catch (Exiv2::AnyError& e) {
-               std::cout << "Caught Exiv2 exception '" << e << "'\n";
+               debug_exception(e);
        }
        return list;
 }
@@ -1052,6 +1128,8 @@ guchar *exif_get_preview(ExifData *exif, guint *data_len, gint requested_width,
 {
        if (!exif) return NULL;
 
+       if (!exif->image()) return NULL;
+       
        const char* path = exif->image()->io().path().c_str();
        /* given image pathname, first do simple (and fast) file extension test */
        gboolean is_raw = filter_file_class(path, FORMAT_CLASS_RAWIMAGE);
@@ -1101,7 +1179,7 @@ guchar *exif_get_preview(ExifData *exif, guint *data_len, gint requested_width,
                return NULL;
        }
        catch (Exiv2::AnyError& e) {
-               std::cout << "Caught Exiv2 exception '" << e << "'\n";
+               debug_exception(e);
                return NULL;
        }
 }
@@ -1152,6 +1230,8 @@ extern "C" guchar *exif_get_preview(ExifData *exif, guint *data_len, gint reques
        unsigned long offset;
 
        if (!exif) return NULL;
+       if (!exif->image()) return NULL;
+
        const char* path = exif->image()->io().path().c_str();
 
        /* given image pathname, first do simple (and fast) file extension test */
@@ -1197,7 +1277,7 @@ extern "C" guchar *exif_get_preview(ExifData *exif, guint *data_len, gint reques
                
        }
        catch (Exiv2::AnyError& e) {
-               std::cout << "Caught Exiv2 exception '" << e << "'\n";
+               debug_exception(e);
        }
        return NULL;