From c6a7fb1bc05ad40385ac49256ccb8004076ba383 Mon Sep 17 00:00:00 2001 From: Robert Clifton Date: Thu, 10 Jun 2021 12:02:01 -0700 Subject: [PATCH] Added function to create xmp namespace, added error handling when reading metadata to capture stderr and return if outputs --- ext/exiv2/exiv2.cpp | 93 +++++++++++++++++++++++++++++---------------- spec/exiv2_spec.rb | 24 ++++++++++++ 2 files changed, 85 insertions(+), 32 deletions(-) diff --git a/ext/exiv2/exiv2.cpp b/ext/exiv2/exiv2.cpp index 0ca0b73..a48da77 100644 --- a/ext/exiv2/exiv2.cpp +++ b/ext/exiv2/exiv2.cpp @@ -66,6 +66,7 @@ static VALUE xmp_data_class; static VALUE xmp_data_each(VALUE self); static VALUE xmp_data_add(VALUE self, VALUE key, VALUE value); static VALUE xmp_data_delete(VALUE self, VALUE key); +static VALUE xmp_register_ns(VALUE self, VALUE uri, VALUE ns); extern "C" void Init_exiv2() { VALUE enumerable_module = rb_const_get(rb_cObject, rb_intern("Enumerable")); @@ -101,6 +102,7 @@ extern "C" void Init_exiv2() { rb_define_method(xmp_data_class, "each", (Method)xmp_data_each, 0); rb_define_method(xmp_data_class, "add", (Method)xmp_data_add, 2); rb_define_method(xmp_data_class, "delete", (Method)xmp_data_delete, 1); + rb_define_method(xmp_data_class, "register", (Method)xmp_register_ns, 2); } @@ -111,17 +113,22 @@ static void image_free(Exiv2::Image* image) { } static VALUE image_read_metadata(VALUE self) { + VALUE result = Qnil; Exiv2::Image* image; Data_Get_Struct(self, Exiv2::Image, image); try { + char buf[BUFSIZ]; + setbuf(stderr, buf); image->readMetadata(); + if (buf[1]) { + result = rb_sprintf("%s", buf); // If stderr outputs, we direct that into a string and return as result + } } catch (Exiv2::BasicError error) { rb_raise(basic_error_class, "%s", error.what()); } - - return Qnil; + return result; } static VALUE image_write_metadata(VALUE self) { @@ -195,18 +202,23 @@ static VALUE exif_data_add(VALUE self, VALUE key, VALUE value) { Exiv2::ExifData* data; Data_Get_Struct(self, Exiv2::ExifData, data); - Exiv2::ExifKey exifKey = Exiv2::ExifKey(to_std_string(key)); - -#if EXIV2_MAJOR_VERSION <= 0 && EXIV2_MINOR_VERSION <= 20 - Exiv2::TypeId typeId = Exiv2::ExifTags::tagType(exifKey.tag(), exifKey.ifdId()); -#else - Exiv2::TypeId typeId = exifKey.defaultTypeId(); -#endif - - Exiv2::Value::AutoPtr v = Exiv2::Value::create(typeId); - v->read(to_std_string(value)); - - data->add(exifKey, v.get()); + try { + Exiv2::ExifKey exifKey = Exiv2::ExifKey(to_std_string(key)); + + #if EXIV2_MAJOR_VERSION <= 0 && EXIV2_MINOR_VERSION <= 20 + Exiv2::TypeId typeId = Exiv2::ExifTags::tagType(exifKey.tag(), exifKey.ifdId()); + #else + Exiv2::TypeId typeId = exifKey.defaultTypeId(); + #endif + + Exiv2::Value::AutoPtr v = Exiv2::Value::create(typeId); + v->read(to_std_string(value)); + + data->add(exifKey, v.get()); + } + catch (Exiv2::BasicError error) { + rb_raise(basic_error_class, "%s", error.what()); + } return Qtrue; } @@ -232,15 +244,19 @@ static VALUE iptc_data_each(VALUE self) { static VALUE iptc_data_add(VALUE self, VALUE key, VALUE value) { Exiv2::IptcData* data; Data_Get_Struct(self, Exiv2::IptcData, data); - - Exiv2::IptcKey iptcKey = Exiv2::IptcKey(to_std_string(key)); - Exiv2::TypeId typeId = Exiv2::IptcDataSets::dataSetType(iptcKey.tag(), iptcKey.record()); - - Exiv2::Value::AutoPtr v = Exiv2::Value::create(typeId); - v->read(to_std_string(value)); - - if(data->add(iptcKey, v.get())) { - return Qfalse; + try { + Exiv2::IptcKey iptcKey = Exiv2::IptcKey(to_std_string(key)); + Exiv2::TypeId typeId = Exiv2::IptcDataSets::dataSetType(iptcKey.tag(), iptcKey.record()); + + Exiv2::Value::AutoPtr v = Exiv2::Value::create(typeId); + v->read(to_std_string(value)); + + if(data->add(iptcKey, v.get())) { + return Qfalse; + } + } + catch (Exiv2::BasicError error) { + rb_raise(basic_error_class, "%s", error.what()); } return Qtrue; } @@ -266,15 +282,18 @@ static VALUE xmp_data_each(VALUE self) { static VALUE xmp_data_add(VALUE self, VALUE key, VALUE value) { Exiv2::XmpData* data; Data_Get_Struct(self, Exiv2::XmpData, data); - - Exiv2::XmpKey xmpKey = Exiv2::XmpKey(to_std_string(key)); - Exiv2::TypeId typeId = Exiv2::XmpProperties::propertyType(xmpKey); - - Exiv2::Value::AutoPtr v = Exiv2::Value::create(typeId); - v->read(to_std_string(value)); - - if(data->add(xmpKey, v.get())) { - return Qfalse; + try { + Exiv2::XmpKey xmpKey = Exiv2::XmpKey(to_std_string(key)); + Exiv2::TypeId typeId = Exiv2::XmpProperties::propertyType(xmpKey); + + Exiv2::Value::AutoPtr v = Exiv2::Value::create(typeId); + v->read(to_std_string(value)); + if(data->add(xmpKey, v.get())) { + return Qfalse; + } + } + catch (Exiv2::BasicError error) { + rb_raise(basic_error_class, "%s", error.what()); } return Qtrue; } @@ -290,3 +309,13 @@ static VALUE xmp_data_delete(VALUE self, VALUE key) { return Qtrue; } + +static VALUE xmp_register_ns(VALUE self, VALUE uri, VALUE ns) { + try { + Exiv2::XmpProperties::registerNs(to_std_string(uri), to_std_string(ns)); + } + catch (Exiv2::BasicError error) { + rb_raise(basic_error_class, "%s", error.what()); + } + return Qtrue; +} diff --git a/spec/exiv2_spec.rb b/spec/exiv2_spec.rb index 11d2af4..29b5409 100644 --- a/spec/exiv2_spec.rb +++ b/spec/exiv2_spec.rb @@ -111,6 +111,12 @@ @iptc_data.delete_all("Iptc.Application2.Keywords") expect(@iptc_data.to_hash["Iptc.Application2.Keywords"]).to eq(nil) end + + it "should throw error because the IPTC namespace does not exist" do + expect { + @iptc_data.add("Iptc.DoesNotExist.New", "ruby-exiv2") + }.to raise_error(Exiv2::BasicError) + end end context "XMP data" do @@ -161,6 +167,18 @@ @xmp_data.delete_all("Xmp.dc.title") expect(@xmp_data.to_hash["Xmp.dc.title"]).to eq(nil) end + + it "should throw error because the XMP namespace does not exist" do + expect { + @xmp_data.add("Xmp.DoesNotExist.New", "ruby-exiv2") + }.to raise_error(Exiv2::BasicError) + end + + it "should add XMP namespace to file" do + @xmp_data.register("http://newnamespace.com/new.namespace/", "ShouldNowExist") + @xmp_data.add("Xmp.ShouldNowExist.New", "ruby-exiv2") + expect(@xmp_data.to_hash["Xmp.ShouldNowExist.New"]).to eq("ruby-exiv2") + end end context "EXIF data" do @@ -223,5 +241,11 @@ @exif_data.delete_all("Exif.Image.Software") expect(@exif_data.to_hash["Exif.Image.Software"]).to eq(nil) end + + it "should throw error because the Exif namespace does not exist" do + expect { + @exif_data.add("Exif.DoesNotExist.New", "ruby-exiv2") + }.to raise_error(Exiv2::BasicError) + end end end