From 0d55992e2f5db3683e96dc3a2dcb430d29004cef Mon Sep 17 00:00:00 2001 From: Andreas Huggel Date: Sat, 21 Jun 2008 10:28:17 +0000 Subject: [PATCH] Merged unstable branch to trunk. --- samples/Makefile | 5 +- samples/exifdata-test.cpp | 2 +- samples/ifd-test.cpp | 209 --- samples/key-test.cpp | 80 -- samples/largeiptc-test.cpp | 2 +- samples/makernote-test.cpp | 49 - samples/tiff-test.cpp | 108 ++ samples/tiffaddpath-test.cpp | 136 ++ samples/write-test.cpp | 4 +- src/Makefile | 4 - src/actions.cpp | 51 +- src/canonmn.cpp | 350 +---- src/canonmn.hpp | 127 +- src/convert.cpp | 2 +- src/cr2image.cpp | 205 ++- src/cr2image.hpp | 82 +- src/cr2image_int.hpp | 122 ++ src/crwimage.cpp | 9 +- src/error.cpp | 5 +- src/exif.cpp | 1284 ++++-------------- src/exif.hpp | 649 +++------ src/fujimn.cpp | 87 -- src/fujimn.hpp | 86 +- src/ifd.cpp | 788 ----------- src/ifd.hpp | 616 --------- src/image.cpp | 51 +- src/image.hpp | 76 +- src/iptc.cpp | 253 ++-- src/iptc.hpp | 67 +- src/jp2image.cpp | 6 +- src/jpgimage.cpp | 45 +- src/makernote.cpp | 459 ------- src/makernote.hpp | 519 ------- src/makernote2.cpp | 323 ++++- src/{makernote2.hpp => makernote2_int.hpp} | 225 ++- src/minoltamn.cpp | 327 +---- src/minoltamn.hpp | 132 +- src/mrwimage.cpp | 10 +- src/mrwthumb.cpp | 49 + src/nikonmn.cpp | 260 +--- src/nikonmn.hpp | 194 +-- src/olympusmn.cpp | 85 +- src/olympusmn.hpp | 86 +- src/orfimage.cpp | 120 +- src/orfimage.hpp | 52 +- src/orfimage_int.hpp | 72 + src/panasonicmn.cpp | 90 +- src/panasonicmn.hpp | 85 +- src/pentaxmn.cpp | 105 +- src/pentaxmn.hpp | 109 +- src/pngchunk.cpp | 12 +- src/properties.cpp | 2 +- src/psdimage.cpp | 6 +- src/rafimage.cpp | 10 +- src/sigmamn.cpp | 99 +- src/sigmamn.hpp | 86 +- src/sonymn.cpp | 83 -- src/sonymn.hpp | 81 +- src/taglist.cpp | 1 - src/tags.cpp | 207 ++- src/tags.hpp | 126 +- src/tiff-test.cpp | 76 ++ src/tiffcomposite.cpp | 1059 ++++++++++++++- src/tiffcomposite.hpp | 641 --------- src/tiffcomposite_int.hpp | 1261 +++++++++++++++++ src/{tifffwd.hpp => tifffwd_int.hpp} | 56 +- src/tiffimage.cpp | 579 +++++++- src/tiffimage.hpp | 159 +-- src/tiffimage_int.hpp | 287 ++++ src/tiffmn-test.cpp | 212 +++ {samples => src}/tiffparse.cpp | 0 src/tiffparser.cpp | 214 --- src/tiffparser.hpp | 132 -- src/tiffvisitor.cpp | 859 +++++++++--- src/{tiffvisitor.hpp => tiffvisitor_int.hpp} | 300 +++- src/types.hpp | 7 + src/value.cpp | 5 +- src/value.hpp | 4 + src/xmpdump.cpp | 35 + test/Makefile | 20 +- test/data/addmoddel.out | 2 +- test/data/conversions.out | 4 +- test/data/exifdata-test.out | 478 +++---- test/data/mini9.tif | Bin 0 -> 526 bytes test/data/modify-test.out | 8 +- test/data/smiley2.jpg.c1gd | Bin 3315 -> 3309 bytes test/data/smiley2.jpg.c2gd | Bin 3315 -> 3309 bytes test/data/tiff-test.out | 138 ++ test/data/write2-test.out | 4 +- test/ifd-test.sh | 24 - test/makernote-test.sh | 24 - test/tiff-test.sh | 35 + 92 files changed, 7161 insertions(+), 9037 deletions(-) delete mode 100644 samples/ifd-test.cpp delete mode 100644 samples/makernote-test.cpp create mode 100644 samples/tiff-test.cpp create mode 100644 samples/tiffaddpath-test.cpp create mode 100644 src/cr2image_int.hpp delete mode 100644 src/ifd.cpp delete mode 100644 src/ifd.hpp delete mode 100644 src/makernote.cpp delete mode 100644 src/makernote.hpp rename src/{makernote2.hpp => makernote2_int.hpp} (70%) create mode 100644 src/mrwthumb.cpp create mode 100644 src/orfimage_int.hpp create mode 100644 src/tiff-test.cpp delete mode 100644 src/tiffcomposite.hpp create mode 100644 src/tiffcomposite_int.hpp rename src/{tifffwd.hpp => tifffwd_int.hpp} (67%) create mode 100644 src/tiffimage_int.hpp create mode 100644 src/tiffmn-test.cpp rename {samples => src}/tiffparse.cpp (100%) delete mode 100644 src/tiffparser.cpp delete mode 100644 src/tiffparser.hpp rename src/{tiffvisitor.hpp => tiffvisitor_int.hpp} (59%) create mode 100644 src/xmpdump.cpp create mode 100644 test/data/mini9.tif create mode 100644 test/data/tiff-test.out delete mode 100755 test/ifd-test.sh delete mode 100755 test/makernote-test.sh create mode 100644 test/tiff-test.sh diff --git a/samples/Makefile b/samples/Makefile index 58c6a495..a346b90b 100644 --- a/samples/Makefile +++ b/samples/Makefile @@ -58,22 +58,19 @@ BINSRC = addmoddel.cpp \ convert-test.cpp \ crwedit.cpp \ crwparse.cpp \ - dataarea-test.cpp \ exifcomment.cpp \ exifdata-test.cpp \ exifprint.cpp \ - ifd-test.cpp \ iotest.cpp \ iptceasy.cpp \ iptcprint.cpp \ iptctest.cpp \ key-test.cpp \ largeiptc-test.cpp \ - makernote-test.cpp \ stringto-test.cpp \ + tiff-test.cpp \ write-test.cpp \ write2-test.cpp \ - tiffparse.cpp \ xmpparse.cpp \ xmpparser-test.cpp \ xmpsample.cpp diff --git a/samples/exifdata-test.cpp b/samples/exifdata-test.cpp index abb5ec6e..39cb8bd7 100644 --- a/samples/exifdata-test.cpp +++ b/samples/exifdata-test.cpp @@ -75,7 +75,7 @@ try { 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); + ed3["Exif.Thumbnail.Orientation"] = uint16_t(2); write(file, ed3); print(file); std::cout << "----------------------------------------------\n"; diff --git a/samples/ifd-test.cpp b/samples/ifd-test.cpp deleted file mode 100644 index 05070032..00000000 --- a/samples/ifd-test.cpp +++ /dev/null @@ -1,209 +0,0 @@ -// ***************************************************************** -*- C++ -*- -/* - Abstract : Simple test program to test class Ifd. - - File : ifd-test.cpp - Version : $Rev$ - Author(s): Andreas Huggel (ahu) - History : 15-Feb-05, ahu - */ -// ***************************************************************************** -// included header files -#include -#include - -#include -#include -#include - -int main() -try { - // ------------------------------------------------------------------------- - std::cout << "Read standard Ifd from data buffer\n"; - - const long len = 77; - Exiv2::byte buf[] - = { 0xff, // Filler - // No - 0x00,0x04, - // Tag Type Components Offset/Data - 0x00,0x01, 0x00,0x02, 0x00,0x00,0x00,0x04, 'T', 'h', 'e', '\0', - 0x00,0x02, 0x00,0x02, 0x00,0x00,0x00,0x06, 0x00,0x00,0x00,0x37, - 0x00,0x03, 0x00,0x02, 0x00,0x00,0x00,0x07, 0x00,0x00,0x00,0x3d, - 0x00,0x04, 0x00,0x02, 0x00,0x00,0x00,0x09, 0x00,0x00,0x00,0x44, - // Next - 0x00,0x00,0x00,0x00, - // Data - 'K', 'u', 'a', 'l', 'a', '\0', - 'L', 'u', 'm', 'p', 'u', 'r', '\0', - 'M', 'a', 'l', 'a', 'y', 's', 'i', 'a', '\0' - }; - - Exiv2::Ifd ifd(Exiv2::ifd0Id, 0, false); - int rc = ifd.read(buf, len, 1, Exiv2::bigEndian); - if (rc) { - std::cout << "Ifd::read (1) failed, rc = " << rc << "\n"; - return rc; - } - ifd.print(std::cout); - - Exiv2::Ifd::iterator pos = ifd.findTag(0x0004); - if (pos == ifd.end()) { - std::cout << "Tag not found!\n"; - return 1; - } - Exiv2::byte data[] = { 'T', 'H', 'R', 'E', 'E', '\0' }; - - std::cout << "Setting value of entry 3...\n"; - pos->setValue(2, 6, data, 6); - - Exiv2::DataBuf db(1024); - rc = ifd.copy(db.pData_ + 1, Exiv2::bigEndian); - std::cout << "Wrote " << rc << " characters to data buffer\n"; - rc = ifd.read(db.pData_, len, 1, Exiv2::bigEndian); - if (rc) { - std::cout << "Ifd::read (1a) failed, rc = " << rc << "\n"; - return rc; - } - ifd.print(std::cout); - - // ------------------------------------------------------------------------- - std::cout << "\nRead non-standard Ifd from data buffer\n"; - - const long len2 = 76; - Exiv2::byte buf2[] - = { // Data - 'K', 'u', 'a', 'l', 'a', '\0', - 'L', 'u', 'm', 'p', 'u', 'r', '\0', - 'M', 'a', 'l', 'a', 'y', 's', 'i', 'a', '\0', - // No - 0x00,0x04, - // Tag Type Components Offset/Data - 0x00,0x01, 0x00,0x02, 0x00,0x00,0x00,0x04, 'T', 'h', 'e', '\0', - 0x00,0x02, 0x00,0x02, 0x00,0x00,0x00,0x06, 0x00,0x00,0x00,0x00, - 0x00,0x03, 0x00,0x02, 0x00,0x00,0x00,0x07, 0x00,0x00,0x00,0x06, - 0x00,0x04, 0x00,0x02, 0x00,0x00,0x00,0x09, 0x00,0x00,0x00,0x0d, - // Next - 0x00,0x00,0x00,0x00 - }; - - Exiv2::Ifd ifd2(Exiv2::ifd0Id, 0, false); - rc = ifd2.read(buf2, len2, 22, Exiv2::bigEndian); - if (rc) { - std::cout << "Ifd::read (2) failed, rc = " << rc << "\n"; - return rc; - } - ifd2.print(std::cout); - - pos = ifd2.findTag(0x0004); - if (pos == ifd2.end()) { - std::cout << "Tag not found!\n"; - return 1; - } - Exiv2::byte data2[] = { 'T', 'H', 'R', 'E', 'E', '\0' }; - - std::cout << "Setting value of entry 3...\n"; - pos->setValue(2, 6, data2, 6); - - ifd2.print(std::cout); - - // ------------------------------------------------------------------------- - std::cout << "\nTest boundary checks, the following reads should generate warnings or errors\n"; - - std::cout << "--- read (3)" << std::endl; - rc = ifd.read(buf, len-1, 1, Exiv2::bigEndian); - if (rc) { - std::cout << "Ifd::read (3) failed, rc = " << rc << "\n"; - } - - std::cout << "--- read (4)" << std::endl; - rc = ifd.read(buf, len-17, 1, Exiv2::bigEndian); - if (rc) { - std::cout << "Ifd::read (4) failed, rc = " << rc << "\n"; - } - - std::cout << "--- read (5)" << std::endl; - rc = ifd.read(buf, len-16, 1, Exiv2::bigEndian); - if (rc) { - std::cout << "Ifd::read (5) failed, rc = " << rc << "\n"; - } - - std::cout << "--- read (6)" << std::endl; - rc = ifd.read(buf, len-23, 1, Exiv2::bigEndian); - if (rc) { - std::cout << "Ifd::read (6) failed, rc = " << rc << "\n"; - } - - std::cout << "--- read (7)" << std::endl; - rc = ifd2.read(buf2, len2-1, 22, Exiv2::bigEndian); - if (rc) { - std::cout << "Ifd::read (7) failed, rc = " << rc << "\n"; - } - - // ------------------------------------------------------------------------- - std::cout << "\nCreate Ifd from scratch\n"; - - Exiv2::Ifd ifd3(Exiv2::ifd0Id); - Exiv2::Entry e; - e.setIfdId(Exiv2::ifd0Id); - e.setIdx(0); - - e.setTag(0x0001); - e.setOffset(0); // will be calculated when the IFD is written - Exiv2::byte data0x01[] = { 'T', 'h', 'e', '\0' }; - e.setValue(2, 4, data0x01, 4); - ifd3.add(e); - - e.setTag(0x0002); - e.setOffset(0); // will be calculated when the IFD is written - Exiv2::byte data0x02[] = { 'K', 'u', 'a', 'l', 'a', '\0' }; - e.setValue(2, 6, data0x02, 6); - ifd3.add(e); - - e.setTag(0x0003); - e.setOffset(0); // will be calculated when the IFD is written - Exiv2::byte data0x03[] = { 'L', 'u', 'm', 'p', 'u', 'r', '\0' }; - e.setValue(2, 7, data0x03, 7); - ifd3.add(e); - - e.setTag(0x0004); - e.setOffset(0); // will be calculated when the IFD is written - Exiv2::byte data0x04[] = { 'M', 'a', 'l', 'a', 'y', 's', 'i', 'a', '\0' }; - e.setValue(2, 9, data0x04, 9); - ifd3.add(e); - - Exiv2::DataBuf ibuf(256); - long len3 = ifd3.copy(ibuf.pData_, Exiv2::bigEndian); - - Exiv2::Ifd ifd4(Exiv2::ifd0Id, 0, false); - rc = ifd4.read(ibuf.pData_, len3, 0, Exiv2::bigEndian); - if (rc) { - std::cout << "Ifd::read (8) failed, rc = " << rc << "\n"; - } - ifd4.print(std::cout); - - // ------------------------------------------------------------------------- - std::cout << "\nMove data buffer\n"; - - Exiv2::Ifd ifd5(Exiv2::ifd0Id, 0, false); - rc = ifd5.read(buf, len, 1, Exiv2::bigEndian); - if (rc) { - std::cout << "Ifd::read (1) failed, rc = " << rc << "\n"; - return rc; - } - ifd5.print(std::cout); - - Exiv2::byte* newBuf = new Exiv2::byte[len]; - std::memset(newBuf, 0x00, len); - std::memcpy(newBuf, buf, len); - std::memset(buf, 0x0, len); - ifd5.updateBase(newBuf); - ifd5.print(std::cout); - delete[] newBuf; - - return 0; -} -catch (const Exiv2::AnyError& e) { - std::cout << "Caught Exiv2 exception '" << e << "'\n"; - return 1; -} diff --git a/samples/key-test.cpp b/samples/key-test.cpp index 74800e35..60ea35dd 100644 --- a/samples/key-test.cpp +++ b/samples/key-test.cpp @@ -122,86 +122,6 @@ int main() // ----- - long len = 76; - byte buf[] - = { // No - 0x00,0x04, - // Tag Type Components Offset/Data - 0x00,0x01, 0x00,0x02, 0x00,0x00,0x00,0x04, 'T', 'h', 'e', '\0', - 0x00,0x02, 0x00,0x02, 0x00,0x00,0x00,0x06, 0x00,0x00,0x00,0x37, - 0x00,0x03, 0x00,0x02, 0x00,0x00,0x00,0x07, 0x00,0x00,0x00,0x3d, - 0x00,0x04, 0x00,0x02, 0x00,0x00,0x00,0x09, 0x00,0x00,0x00,0x44, - // Next - 0x00,0x00,0x00,0x00, - // Data - 'K', 'u', 'a', 'l', 'a', '\0', - 'L', 'u', 'm', 'p', 'u', 'r', '\0', - 'M', 'a', 'l', 'a', 'y', 's', 'i', 'a', '\0' - }; - - Ifd ifd(Exiv2::iopIfdId, 0, false); - int ret = ifd.read(buf, len, 0, bigEndian, 1); - if (ret) { - std::cout << "Ifd::read failed, ret = " << ret << "\n"; - return ret; - } - - Ifd::const_iterator i = ifd.findTag(0x0002); - if (i == ifd.end()) { - std::cout << "Ifd::findTag failed" << "\n"; - } - else { - ExifKey ek3(*i); - - // operator<< - tc += 1; - std::ostringstream os2; - os2 << ek3; - if (os2.str() != key) { - std::cout << "Testcase failed (operator<<)" << std::endl; - rc += 1; - } - // familyName - tc += 1; - if (std::string(ek3.familyName()) != "Exif") { - std::cout << "Testcase failed (familyName)" << std::endl; - rc += 1; - } - // groupName - tc += 1; - if (ek3.groupName() != "Iop") { - std::cout << "Testcase failed (groupName)" << std::endl; - rc += 1; - } - // tagName - tc += 1; - if (ek3.tagName() != "InteroperabilityVersion") { - std::cout << "Testcase failed (tagName)" << std::endl; - rc += 1; - } - // tagName - tc += 1; - if (ek3.tag() != 0x0002) { - std::cout << "Testcase failed (tag)" << std::endl; - rc += 1; - } - // ifdName - tc += 1; - if (std::string(ek3.ifdName()) != "Iop") { - std::cout << "Testcase failed (ifdName: " << std::endl; - rc += 1; - } - // sectionName - tc += 1; - if (ek3.sectionName() != "Interoperability") { - std::cout << "Testcase failed (sectionName)" << std::endl; - rc += 1; - } - - } - - // ----- - ExifKey ek4("Exif.Image.0x0110"); tc += 1; if (ek4.key() != "Exif.Image.Model") { diff --git a/samples/largeiptc-test.cpp b/samples/largeiptc-test.cpp index 1774d814..079c83ae 100644 --- a/samples/largeiptc-test.cpp +++ b/samples/largeiptc-test.cpp @@ -47,7 +47,7 @@ try { uint32_t sizeHdr; uint32_t sizeData; Exiv2::Photoshop::locateIptcIrb(irb.pData_, irb.size_, &record, &sizeHdr, &sizeData); - Exiv2::DataBuf rawIptc = iptcData.copy(); + Exiv2::DataBuf rawIptc = Exiv2::IptcParser::encode(iptcData); std::cout << "Comparing IPTC and IRB size... "; if (static_cast(rawIptc.size_) != sizeData) { std::cout << "not "; diff --git a/samples/makernote-test.cpp b/samples/makernote-test.cpp deleted file mode 100644 index 9c2184db..00000000 --- a/samples/makernote-test.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include - -#include -#include -#include - -void testMatch(const std::string& reg, const std::string& key); - -int main() -{ - testMatch("Canon", "Canon"); - testMatch("Canon*", "Canon"); - testMatch("Canon*", "Canon Corp."); - testMatch("PENTAX*", "PENTAX Corporation"); - testMatch("*foo*bar*", "foobar"); - testMatch("*foo*bar*", "barfoofoobarbar"); - testMatch("foo*bar", "foo"); - testMatch("foo*bar", "bar"); - testMatch("foo*bar", "foobar"); - testMatch("foo*bar", "fooYAHOObar"); - testMatch("foo*bar", "Thefoobar"); - testMatch("foo*bar", "foobarTrick"); - testMatch("foo*bar", "ThefoobarTrick"); - testMatch("foo*bar", "ThefooYAHOObarTrick"); - - testMatch("*", "anything"); - testMatch("**", "anything times two"); - - testMatch("*bar", "bar"); - testMatch("b*bar", "bar"); - testMatch("b*bar", "bbar"); - testMatch("*foobar", "bar"); - testMatch("*bar", "foobar"); - - return 0; -} - -void testMatch(const std::string& reg, const std::string& key) -{ - int rc = Exiv2::MakerNoteFactory::match(reg, key); - - if (rc) { - std::cout << "Key '" << key << "' matches '" << reg << "' " - << "with a score of " << rc << ".\n"; - } - else { - std::cout << "Key '" << key << "' does not match '" << reg << "'.\n"; - } -} diff --git a/samples/tiff-test.cpp b/samples/tiff-test.cpp new file mode 100644 index 00000000..b1a2a727 --- /dev/null +++ b/samples/tiff-test.cpp @@ -0,0 +1,108 @@ +// ***************************************************************** -*- C++ -*- +// tiff-test.cpp, $Rev$ +// First and very simple TIFF write test. + +#include +#include +#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"; + } +} diff --git a/samples/tiffaddpath-test.cpp b/samples/tiffaddpath-test.cpp new file mode 100644 index 00000000..548af041 --- /dev/null +++ b/samples/tiffaddpath-test.cpp @@ -0,0 +1,136 @@ +// ***************************************************************** -*- C++ -*- +// tiffaddpath-test.cpp, $Rev$ +// 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; +} diff --git a/samples/write-test.cpp b/samples/write-test.cpp index 7ed219f0..1d944c2f 100644 --- a/samples/write-test.cpp +++ b/samples/write-test.cpp @@ -17,7 +17,6 @@ // included header files #include #include -#include #include #include @@ -195,7 +194,8 @@ void testCase(const std::string& file1, exifPrint(ed2); std::cerr << "---> Writing Exif thumbnail to file " << thumb << ".*\n"; - ed2.writeThumbnail(thumb); + ExifThumbC et2(ed2); + et2.writeFile(thumb); } // ***************************************************************************** diff --git a/src/Makefile b/src/Makefile index 2caa7f5c..6e681113 100644 --- a/src/Makefile +++ b/src/Makefile @@ -63,7 +63,6 @@ CCHDR = exv_conf.h \ exv_msvc.h \ mn.hpp \ rcsid.hpp \ - tifffwd.hpp \ version.hpp # Add library C++ source files to this list @@ -79,12 +78,10 @@ CCSRC = basicio.cpp \ futils.cpp \ fujimn.cpp \ gifimage.cpp \ - ifd.cpp \ image.cpp \ iptc.cpp \ jp2image.cpp \ jpgimage.cpp \ - makernote.cpp \ makernote2.cpp \ metadatum.cpp \ minoltamn.cpp \ @@ -106,7 +103,6 @@ CCSRC += psdimage.cpp \ tgaimage.cpp \ tiffcomposite.cpp \ tiffimage.cpp \ - tiffparser.cpp \ tiffvisitor.cpp \ types.cpp \ value.cpp \ diff --git a/src/actions.cpp b/src/actions.cpp index 75a0a845..54a90bd6 100644 --- a/src/actions.cpp +++ b/src/actions.cpp @@ -97,14 +97,16 @@ namespace { time_t modtime_; }; - // Convert a string "YYYY:MM:DD HH:MI:SS" to a struct tm type, - // returns 0 if successful + /*! + @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 UTC time to a string "YYYY:MM:DD HH:MI:SS", "" on error + //! Convert a UTC time 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 + //! Convert a tm structure to a string "YYYY:MM:DD HH:MI:SS", "" on error std::string tm2Str(struct tm* tm); /*! @@ -137,8 +139,9 @@ namespace { /*! @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) + @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. */ @@ -146,7 +149,7 @@ namespace { /*! @brief Check if file \em path exists and whether it should be - overwritten. Ask user if necessary. Return 1 if the file + overwritten. Ask user if necessary. Return 1 if the file exists and shouldn't be overwritten, else 0. */ int dontOverwrite(const std::string& path); @@ -550,13 +553,14 @@ namespace Action { // Thumbnail printLabel(_("Thumbnail")); - std::string thumbExt = exifData.thumbnailExtension(); + Exiv2::ExifThumbC exifThumb(exifData); + std::string thumbExt = exifThumb.extension(); if (thumbExt.empty()) { std::cout << _("None"); } else { - Exiv2::DataBuf buf = exifData.copyThumbnail(); - std::cout << exifData.thumbnailFormat() << ", " + Exiv2::DataBuf buf = exifThumb.copy(); + std::cout << exifThumb.mimeType() << ", " << buf.size_ << " " << _("Bytes"); } std::cout << std::endl; @@ -710,7 +714,7 @@ namespace Action { continue; } Exiv2::DataBuf buf(md->size()); - md->copy(buf.pData_, exifData.byteOrder()); + md->copy(buf.pData_, image->byteOrder()); Exiv2::hexdump(std::cout, buf.pData_, buf.size_); } std::cout << std::endl; @@ -958,15 +962,14 @@ namespace Action { int Erase::eraseThumbnail(Exiv2::Image* image) const { - Exiv2::ExifData& exifData = image->exifData(); - std::string thumbExt = exifData.thumbnailExtension(); + Exiv2::ExifThumb exifThumb(image->exifData()); + std::string thumbExt = exifThumb.extension(); if (thumbExt.empty()) { return 0; } - long delta = exifData.eraseThumbnail(); + exifThumb.erase(); if (Params::instance().verbose_) { - std::cout << _("Erasing") << " " << delta - << " " << _("Bytes of thumbnail data") << std::endl; + std::cout << _("Erasing thumbnail data") << std::endl; } return 0; } @@ -1061,7 +1064,8 @@ namespace Action { return -3; } int rc = 0; - std::string thumbExt = exifData.thumbnailExtension(); + Exiv2::ExifThumb exifThumb(exifData); + std::string thumbExt = exifThumb.extension(); if (thumbExt.empty()) { std::cerr << path_ << ": " << _("Image does not contain an Exif thumbnail\n"); } @@ -1070,14 +1074,13 @@ namespace Action { std::string thumbPath = thumb + thumbExt; if (dontOverwrite(thumbPath)) return 0; if (Params::instance().verbose_) { - Exiv2::DataBuf buf = exifData.copyThumbnail(); - std::cout << _("Writing") << " " - << exifData.thumbnailFormat() << " " << _("thumbnail") << " (" + Exiv2::DataBuf buf = exifThumb.copy(); + std::cout << _("Writing thumbnail") << " (" << exifThumb.mimeType() << ", " << buf.size_ << " " << _("Bytes") << ") " << _("to file") << " " << thumbPath << std::endl; } - rc = exifData.writeThumbnail(thumb); - if (rc) { + rc = exifThumb.writeFile(thumb); + if (rc == 0) { std::cerr << path_ << ": " << _("Exif data doesn't contain a thumbnail\n"); } } @@ -1176,8 +1179,8 @@ namespace Action { Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(path); assert(image.get() != 0); image->readMetadata(); - Exiv2::ExifData& exifData = image->exifData(); - exifData.setJpegThumbnail(thumbPath); + Exiv2::ExifThumb exifThumb(image->exifData()); + exifThumb.setJpegThumbnail(thumbPath); image->writeMetadata(); return 0; @@ -1637,6 +1640,7 @@ namespace Action { // local definitions namespace { + //! @cond IGNORE int Timestamp::read(const std::string& path) { struct stat buf; @@ -1668,6 +1672,7 @@ namespace { buf.modtime = modtime_; return utime(path.c_str(), &buf); } + //! @endcond int str2Tm(const std::string& timeStr, struct tm* tm) { diff --git a/src/canonmn.cpp b/src/canonmn.cpp index 02c00cdc..41a09dfe 100644 --- a/src/canonmn.cpp +++ b/src/canonmn.cpp @@ -34,9 +34,7 @@ EXIV2_RCSID("@(#) $Id$") // included header files #include "types.hpp" #include "canonmn.hpp" -#include "makernote.hpp" #include "value.hpp" -#include "ifd.hpp" #include "i18n.h" // NLS support. // + standard includes @@ -52,26 +50,6 @@ EXIV2_RCSID("@(#) $Id$") // class member definitions namespace Exiv2 { - //! @cond IGNORE - CanonMakerNote::RegisterMn::RegisterMn() - { - MakerNoteFactory::registerMakerNote("Canon", "*", createCanonMakerNote); - - MakerNoteFactory::registerMakerNote( - canonIfdId, MakerNote::AutoPtr(new CanonMakerNote)); - MakerNoteFactory::registerMakerNote( - canonCsIfdId, MakerNote::AutoPtr(new CanonMakerNote)); - MakerNoteFactory::registerMakerNote( - canonSiIfdId, MakerNote::AutoPtr(new CanonMakerNote)); - MakerNoteFactory::registerMakerNote( - canonPaIfdId, MakerNote::AutoPtr(new CanonMakerNote)); - MakerNoteFactory::registerMakerNote( - canonCfIfdId, MakerNote::AutoPtr(new CanonMakerNote)); - MakerNoteFactory::registerMakerNote( - canonPiIfdId, MakerNote::AutoPtr(new CanonMakerNote)); - } - //! @endcond - //! ModelId, tag 0x0010 extern const TagDetails canonModelId[] = { { 0x1010000, N_("PowerShot A30") }, @@ -265,7 +243,7 @@ namespace Exiv2 { { 6, N_("Medium 2") }, { 7, N_("Medium 3") } }; - + //! EasyMode, tag 0x000b extern const TagDetails canonCsEasyMode[] = { { 0, N_("Full auto") }, @@ -661,293 +639,9 @@ namespace Exiv2 { return tagInfoPi_; } - int CanonMakerNote::read(const byte* buf, - long len, - long start, - ByteOrder byteOrder, - long shift) - { - int rc = IfdMakerNote::read(buf, len, start, byteOrder, shift); - if (rc) return rc; - - // Decode camera settings 1 and add settings as additional entries - Entries::iterator cs = ifd_.findTag(0x0001); - if (cs != ifd_.end() && cs->type() == unsignedShort) { - for (uint16_t c = 1; cs->count() > c; ++c) { - if (c == 23 && cs->count() > 25) { - // Pack related lens info into one tag - addCsEntry(canonCsIfdId, c, cs->offset() + c*2, - cs->data() + c*2, 3); - c += 2; - } - else { - addCsEntry(canonCsIfdId, c, cs->offset() + c*2, - cs->data() + c*2, 1); - } - } - // Discard the original entry - ifd_.erase(cs); - } - - // Decode camera settings 2 and add settings as additional entries - cs = ifd_.findTag(0x0004); - if (cs != ifd_.end() && cs->type() == unsignedShort) { - for (uint16_t c = 1; cs->count() > c; ++c) { - addCsEntry(canonSiIfdId, c, cs->offset() + c*2, - cs->data() + c*2, 1); - } - // Discard the original entry - ifd_.erase(cs); - } - - // Decode panorama information and add each as an additional entry - cs = ifd_.findTag(0x0005); - if (cs != ifd_.end() && cs->type() == unsignedShort) { - for (uint16_t c = 1; cs->count() > c; ++c) { - addCsEntry(canonPaIfdId, c, cs->offset() + c*2, - cs->data() + c*2, 1); - } - // Discard the original entry - ifd_.erase(cs); - } - - // Decode custom functions and add each as an additional entry - cs = ifd_.findTag(0x000f); - if (cs != ifd_.end() && cs->type() == unsignedShort) { - for (uint16_t c = 1; cs->count() > c; ++c) { - addCsEntry(canonCfIfdId, c, cs->offset() + c*2, - cs->data() + c*2, 1); - } - // Discard the original entry - ifd_.erase(cs); - } - - // Decode picture info and add each as an additional entry - cs = ifd_.findTag(0x0012); - if (cs != ifd_.end() && cs->type() == unsignedShort) { - for (uint16_t c = 1; cs->count() > c; ++c) { - addCsEntry(canonPiIfdId, c, cs->offset() + c*2, - cs->data() + c*2, 1); - } - // Discard the original entry - ifd_.erase(cs); - } - - // Copy remaining ifd entries - entries_.insert(entries_.begin(), ifd_.begin(), ifd_.end()); - - // Set idx - int idx = 0; - Entries::iterator e = entries_.end(); - for (Entries::iterator i = entries_.begin(); i != e; ++i) { - i->setIdx(++idx); - } - - return 0; - } - - void CanonMakerNote::addCsEntry(IfdId ifdId, - uint16_t tag, - long offset, - const byte* data, - int count) - { - Entry e(false); - e.setIfdId(ifdId); - e.setTag(tag); - e.setOffset(offset); - e.setValue(unsignedShort, count, data, 2*count); - add(e); - } - - void CanonMakerNote::add(const Entry& entry) - { - assert(alloc_ == entry.alloc()); - assert( entry.ifdId() == canonIfdId - || entry.ifdId() == canonCsIfdId - || entry.ifdId() == canonSiIfdId - || entry.ifdId() == canonPaIfdId - || entry.ifdId() == canonCfIfdId - || entry.ifdId() == canonPiIfdId); - // allow duplicates - entries_.push_back(entry); - } - - long CanonMakerNote::copy(byte* buf, ByteOrder byteOrder, long offset) - { - if (byteOrder_ == invalidByteOrder) byteOrder_ = byteOrder; - - assert(ifd_.alloc()); - ifd_.clear(); - - // Add all standard Canon entries to the IFD - Entries::const_iterator end = entries_.end(); - for (Entries::const_iterator i = entries_.begin(); i != end; ++i) { - if (i->ifdId() == canonIfdId) { - ifd_.add(*i); - } - } - // Collect camera settings entries and add the original Canon tag - Entry cs; - if (assemble(cs, canonCsIfdId, 0x0001, byteOrder_)) { - ifd_.erase(0x0001); - ifd_.add(cs); - } - // Collect shot info entries and add the original Canon tag - Entry si; - if (assemble(si, canonSiIfdId, 0x0004, byteOrder_)) { - ifd_.erase(0x0004); - ifd_.add(si); - } - // Collect panorama entries and add the original Canon tag - Entry pa; - if (assemble(pa, canonPaIfdId, 0x0005, byteOrder_)) { - ifd_.erase(0x0005); - ifd_.add(pa); - } - // Collect custom function entries and add the original Canon tag - Entry cf; - if (assemble(cf, canonCfIfdId, 0x000f, byteOrder_)) { - ifd_.erase(0x000f); - ifd_.add(cf); - } - // Collect picture info entries and add the original Canon tag - Entry pi; - if (assemble(pi, canonPiIfdId, 0x0012, byteOrder_)) { - ifd_.erase(0x0012); - ifd_.add(pi); - } - - return IfdMakerNote::copy(buf, byteOrder_, offset); - } // CanonMakerNote::copy - - void CanonMakerNote::updateBase(byte* pNewBase) - { - byte* pBase = ifd_.updateBase(pNewBase); - if (absShift_ && !alloc_) { - Entries::iterator end = entries_.end(); - for (Entries::iterator pos = entries_.begin(); pos != end; ++pos) { - pos->updateBase(pBase, pNewBase); - } - } - } // CanonMakerNote::updateBase - - long CanonMakerNote::size() const - { - Ifd ifd(canonIfdId, 0, alloc_); // offset doesn't matter - - // Add all standard Canon entries to the IFD - Entries::const_iterator end = entries_.end(); - for (Entries::const_iterator i = entries_.begin(); i != end; ++i) { - if (i->ifdId() == canonIfdId) { - ifd.add(*i); - } - } - // Collect camera settings entries and add the original Canon tag - Entry cs(alloc_); - if (assemble(cs, canonCsIfdId, 0x0001, littleEndian)) { - ifd.erase(0x0001); - ifd.add(cs); - } - // Collect shot info entries and add the original Canon tag - Entry si(alloc_); - if (assemble(si, canonSiIfdId, 0x0004, littleEndian)) { - ifd.erase(0x0004); - ifd.add(si); - } - // Collect panorama entries and add the original Canon tag - Entry pa(alloc_); - if (assemble(pa, canonPaIfdId, 0x0005, littleEndian)) { - ifd.erase(0x0005); - ifd.add(pa); - } - // Collect custom function entries and add the original Canon tag - Entry cf(alloc_); - if (assemble(cf, canonCfIfdId, 0x000f, littleEndian)) { - ifd.erase(0x000f); - ifd.add(cf); - } - // Collect picture info entries and add the original Canon tag - Entry pi(alloc_); - if (assemble(pi, canonPiIfdId, 0x0012, littleEndian)) { - ifd.erase(0x0012); - ifd.add(pi); - } - - return headerSize() + ifd.size() + ifd.dataSize(); - } // CanonMakerNote::size - - long CanonMakerNote::assemble(Entry& e, - IfdId ifdId, - uint16_t tag, - ByteOrder byteOrder) const - { - DataBuf buf(1024); - std::memset(buf.pData_, 0x0, 1024); - uint16_t len = 0; - Entries::const_iterator end = entries_.end(); - for (Entries::const_iterator i = entries_.begin(); i != end; ++i) { - if (i->ifdId() == ifdId) { - uint16_t pos = i->tag() * 2; - uint16_t size = pos + static_cast(i->size()); - assert(size <= 1024); - std::memcpy(buf.pData_ + pos, i->data(), i->size()); - if (len < size) len = size; - } - } - if (len > 0) { - // Number of shorts in the buffer (rounded up) - uint16_t s = (len+1) / 2; - us2Data(buf.pData_, s*2, byteOrder); - - e.setIfdId(canonIfdId); - e.setIdx(0); // don't care - e.setTag(tag); - e.setOffset(0); // will be calculated when the IFD is written - e.setValue(unsignedShort, s, buf.pData_, s*2); - } - return len; - } // CanonMakerNote::assemble - - Entries::const_iterator CanonMakerNote::findIdx(int idx) const - { - return std::find_if(entries_.begin(), entries_.end(), - FindEntryByIdx(idx)); - } - - CanonMakerNote::CanonMakerNote(bool alloc) - : IfdMakerNote(canonIfdId, alloc) - { - } - - CanonMakerNote::CanonMakerNote(const CanonMakerNote& rhs) - : IfdMakerNote(rhs) - { - entries_ = rhs.entries_; - } - - CanonMakerNote::AutoPtr CanonMakerNote::create(bool alloc) const - { - return AutoPtr(create_(alloc)); - } - - CanonMakerNote* CanonMakerNote::create_(bool alloc) const - { - return new CanonMakerNote(alloc); - } - - CanonMakerNote::AutoPtr CanonMakerNote::clone() const - { - return AutoPtr(clone_()); - } - - CanonMakerNote* CanonMakerNote::clone_() const - { - return new CanonMakerNote(*this); - } - std::ostream& CanonMakerNote::print0x0008(std::ostream& os, - const Value& value) + const Value& value, + const ExifData*) { std::string n = value.toString(); if (n.length() < 4) return os << "(" << n << ")"; @@ -956,7 +650,8 @@ namespace Exiv2 { } std::ostream& CanonMakerNote::print0x000c(std::ostream& os, - const Value& value) + const Value& value, + const ExifData*) { std::istringstream is(value.toString()); uint32_t l; @@ -968,7 +663,8 @@ namespace Exiv2 { } std::ostream& CanonMakerNote::printCs0x0002(std::ostream& os, - const Value& value) + const Value& value, + const ExifData*) { if (value.typeId() != unsignedShort) return os << value; long l = value.toLong(); @@ -982,7 +678,8 @@ namespace Exiv2 { } std::ostream& CanonMakerNote::printCsLens(std::ostream& os, - const Value& value) + const Value& value, + const ExifData*) { if ( value.count() < 3 || value.typeId() != unsignedShort) { @@ -1006,14 +703,16 @@ namespace Exiv2 { } std::ostream& CanonMakerNote::printSi0x0002(std::ostream& os, - const Value& value) + const Value& value, + const ExifData*) { // Ported from Exiftool by Will Stokes return os << exp(canonEv(value.toLong()) * log(2.0)) * 100.0 / 32.0; } std::ostream& CanonMakerNote::printSi0x0009(std::ostream& os, - const Value& value) + const Value& value, + const ExifData*) { if (value.typeId() != unsignedShort) return os << value; long l = value.toLong(); @@ -1023,7 +722,8 @@ namespace Exiv2 { } std::ostream& CanonMakerNote::printSi0x000e(std::ostream& os, - const Value& value) + const Value& value, + const ExifData* pExifData) { if (value.typeId() != unsignedShort) return os << value; long l = value.toLong(); @@ -1034,14 +734,15 @@ namespace Exiv2 { os << "none"; } else { - EXV_PRINT_TAG_BITMASK(canonSiAFPointUsed)(os, value); + EXV_PRINT_TAG_BITMASK(canonSiAFPointUsed)(os, value, pExifData); } os << " used"; return os; } std::ostream& CanonMakerNote::printSi0x0013(std::ostream& os, - const Value& value) + const Value& value, + const ExifData*) { if (value.typeId() != unsignedShort) return os << value; long l = value.toLong(); @@ -1055,7 +756,8 @@ namespace Exiv2 { } std::ostream& CanonMakerNote::printSi0x0015(std::ostream& os, - const Value& value) + const Value& value, + const ExifData*) { if (value.typeId() != unsignedShort) return os << value; @@ -1069,7 +771,8 @@ namespace Exiv2 { } std::ostream& CanonMakerNote::printSi0x0016(std::ostream& os, - const Value& value) + const Value& value, + const ExifData*) { if (value.typeId() != unsignedShort) return os << value; @@ -1084,15 +787,6 @@ namespace Exiv2 { // ***************************************************************************** // free functions - MakerNote::AutoPtr createCanonMakerNote( bool alloc, - const byte* /*buf*/, - long /*len*/, - ByteOrder /*byteOrder*/, - long /*offset*/) - { - return MakerNote::AutoPtr(new CanonMakerNote(alloc)); - } - float canonEv(long val) { // temporarily remove sign diff --git a/src/canonmn.hpp b/src/canonmn.hpp index a9e732be..0a01aa78 100644 --- a/src/canonmn.hpp +++ b/src/canonmn.hpp @@ -36,7 +36,6 @@ // ***************************************************************************** // included header files #include "types.hpp" -#include "makernote.hpp" #include "tags.hpp" // + standard includes @@ -52,81 +51,12 @@ namespace Exiv2 { // class declarations class Value; -// ***************************************************************************** -// free functions - - /*! - @brief Return an auto-pointer to a newly created empty MakerNote - initialized to operate in the memory management model indicated. - The caller owns this copy and the auto-pointer ensures that it - will be deleted. - - @param alloc Memory management model for the new MakerNote. Determines if - memory required to store data should be allocated and deallocated - (true) or not (false). If false, only pointers to the buffer - provided to read() will be kept. See Ifd for more background on - this concept. - @param buf Pointer to the makernote character buffer (not used). - @param len Length of the makernote character buffer (not used). - @param byteOrder Byte order in which the Exif data (and possibly the - makernote) is encoded (not used). - @param offset Offset from the start of the TIFF header of the makernote - buffer (not used). - - @return An auto-pointer to a newly created empty MakerNote. The caller - owns this copy and the auto-pointer ensures that it will be - deleted. - */ - MakerNote::AutoPtr createCanonMakerNote(bool alloc, - const byte* buf, - long len, - ByteOrder byteOrder, - long offset); - // ***************************************************************************** // class definitions //! MakerNote for Canon cameras - class CanonMakerNote : public IfdMakerNote { + class CanonMakerNote { public: - //! Shortcut for a %CanonMakerNote auto pointer. - typedef std::auto_ptr AutoPtr; - - //! @name Creators - //@{ - /*! - @brief Constructor. Allows to choose whether or not memory management - is required for the makernote entries. - */ - CanonMakerNote(bool alloc =true); - //! Copy constructor - CanonMakerNote(const CanonMakerNote& rhs); - //! Virtual destructor - virtual ~CanonMakerNote() {} - //@} - - //! @name Manipulators - //@{ - int read(const byte* buf, - long len, - long start, - ByteOrder byteOrder, - long shift); - long copy(byte* buf, ByteOrder byteOrder, long offset); - void add(const Entry& entry); - Entries::iterator begin() { return entries_.begin(); } - Entries::iterator end() { return entries_.end(); } - void updateBase(byte* pNewBase); - //@} - - //! @name Accessors - //@{ - Entries::const_iterator begin() const { return entries_.begin(); } - Entries::const_iterator end() const { return entries_.end(); } - Entries::const_iterator findIdx(int idx) const; - long size() const; - AutoPtr create(bool alloc =true) const; - AutoPtr clone() const; //! Return read-only list of built-in Canon tags static const TagInfo* tagList(); //! Return read-only list of built-in Canon Camera Settings tags @@ -139,66 +69,33 @@ namespace Exiv2 { static const TagInfo* tagListCf(); //! Return read-only list of built-in Canon Picture Info tags static const TagInfo* tagListPi(); - //@} //! @name Print functions for Canon %MakerNote tags //@{ //! Print the image number - static std::ostream& print0x0008(std::ostream& os, const Value& value); + 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); + static std::ostream& print0x000c(std::ostream& os, const Value& value, const ExifData*); //! Self timer - static std::ostream& printCs0x0002(std::ostream& os, const Value& value); + static std::ostream& printCs0x0002(std::ostream& os, const Value& value, const ExifData*); //! Camera lens information - static std::ostream& printCsLens(std::ostream& os, const Value& value); + 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); + static std::ostream& printSi0x0002(std::ostream& os, const Value& value, const ExifData*); //! Sequence number - static std::ostream& printSi0x0009(std::ostream& os, const Value& value); + 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); + 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); + static std::ostream& printSi0x0013(std::ostream& os, const Value& value, const ExifData*); //! Aperture - static std::ostream& printSi0x0015(std::ostream& os, const Value& value); + static std::ostream& printSi0x0015(std::ostream& os, const Value& value, const ExifData*); //! Shutter speed - static std::ostream& printSi0x0016(std::ostream& os, const Value& value); + static std::ostream& printSi0x0016(std::ostream& os, const Value& value, const ExifData*); //@} - //! @cond IGNORE - // Public only so that we can create a static instance - struct RegisterMn { - RegisterMn(); - }; - //! @endcond - private: - //! @name Manipulators - //@{ - //! Add a camera settings entry to the makernote entries - void addCsEntry(IfdId ifdId, - uint16_t tag, - long offset, - const byte* data, - int count); - //@} - - //! @name Accessors - //@{ - //! Assemble special Canon entries into an entry with the original tag - long assemble(Entry& e, - IfdId ifdId, - uint16_t tag, - ByteOrder byteOrder) const; - //! Internal virtual create function. - CanonMakerNote* create_(bool alloc =true) const; - //! Internal virtual copy constructor. - CanonMakerNote* clone_() const; - //@} - // DATA - //! Container to store Makernote entries (instead of Ifd) - Entries entries_; //! Tag information static const TagInfo tagInfo_[]; @@ -210,8 +107,6 @@ namespace Exiv2 { }; // class CanonMakerNote - static CanonMakerNote::RegisterMn registerCanonMakerNote; - // ***************************************************************************** // template, inline and free functions diff --git a/src/convert.cpp b/src/convert.cpp index a2a441e7..8a011ec5 100644 --- a/src/convert.cpp +++ b/src/convert.cpp @@ -1191,7 +1191,7 @@ namespace Exiv2 { MD5Init(&context); - DataBuf data = iptcData_->copy(); + 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; diff --git a/src/cr2image.cpp b/src/cr2image.cpp index 40e34b3e..b04e2e74 100644 --- a/src/cr2image.cpp +++ b/src/cr2image.cpp @@ -38,9 +38,10 @@ EXIV2_RCSID("@(#) $Id$") #endif #include "cr2image.hpp" -#include "tiffcomposite.hpp" -#include "tiffparser.hpp" -#include "tiffvisitor.hpp" +#include "cr2image_int.hpp" +#include "tiffcomposite_int.hpp" +#include "tiffimage_int.hpp" +#include "tiffvisitor_int.hpp" #include "image.hpp" #include "error.hpp" #include "futils.hpp" @@ -56,37 +57,7 @@ EXIV2_RCSID("@(#) $Id$") // class member definitions namespace Exiv2 { - // CR2 decoder table for special CR2 decoding requirements - const TiffDecoderInfo Cr2Decoder::cr2DecoderInfo_[] = { - { "*", Tag::all, Group::ignr, 0 }, // Do not decode tags with group == Group::ignr - { "*", 0x014a, Group::ifd0, 0 }, // Todo: Controversial, causes problems with Exiftool - { "*", 0x0100, Group::ifd0, 0 }, // CR2 IFD0 refers to a preview image, ignore these tags - { "*", 0x0101, Group::ifd0, 0 }, - { "*", 0x0102, Group::ifd0, 0 }, - { "*", 0x0103, Group::ifd0, 0 }, - { "*", 0x0111, Group::ifd0, 0 }, - { "*", 0x0117, Group::ifd0, 0 }, - { "*", 0x011a, Group::ifd0, 0 }, - { "*", 0x011b, Group::ifd0, 0 }, - { "*", 0x0128, Group::ifd0, 0 }, - { "*", 0x02bc, Group::ifd0, &TiffMetadataDecoder::decodeXmp }, - { "*", 0x83bb, Group::ifd0, &TiffMetadataDecoder::decodeIptc }, - { "*", 0x8649, Group::ifd0, &TiffMetadataDecoder::decodeIptc } - }; - - DecoderFct Cr2Decoder::findDecoder(const std::string& make, - uint32_t extendedTag, - uint16_t group) - { - DecoderFct decoderFct = &TiffMetadataDecoder::decodeStdTiffEntry; - const TiffDecoderInfo* td = find(cr2DecoderInfo_, - TiffDecoderInfo::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; - } + using namespace Internal; Cr2Image::Cr2Image(BasicIo::AutoPtr io, bool /*create*/) : Image(ImageType::cr2, mdExif | mdIptc, io) @@ -138,19 +109,141 @@ namespace Exiv2 { throw Error(3, "CR2"); } clearMetadata(); - Cr2Header cr2Header; - TiffParser::decode(this, io_->mmap(), io_->size(), - TiffCreator::create, Cr2Decoder::findDecoder, - &cr2Header); - + ByteOrder bo = Cr2Parser::decode(exifData_, + iptcData_, + xmpData_, + io_->mmap(), + io_->size()); + setByteOrder(bo); } // Cr2Image::readMetadata void Cr2Image::writeMetadata() { - //! Todo: implement me! + // Todo: implement me! throw(Error(31, "CR2")); } // 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, + TiffCreator::create, + Cr2Mapping::findDecoder, + &cr2Header); + } + + WriteMethod Cr2Parser::encode( + Blob& blob, + const byte* pData, + uint32_t size, + const ExifData& exifData, + const IptcData& iptcData, + const XmpData& xmpData + ) + { + /* Todo: Implement me! + + TiffParserWorker::encode(blob, + pData, + size, + exifData, + iptcData, + xmpData, + TiffCreator::create, + TiffMapping::findEncoder); + */ + blob.clear(); + return wmIntrusive; + } + + // ************************************************************************* + // 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 { + + // CR2 mapping table for special CR2 decoding requirements + const TiffMappingInfo Cr2Mapping::cr2MappingInfo_[] = { + { "*", Tag::all, Group::ignr, 0, 0 }, // Do not decode tags with group == Group::ignr + { "*", 0x014a, Group::ifd0, 0, 0 }, // Todo: Controversial, causes problems with Exiftool + { "*", 0x0100, Group::ifd0, 0, 0 }, // CR2 IFD0 refers to a preview image, ignore these tags + { "*", 0x0101, Group::ifd0, 0, 0 }, + { "*", 0x0102, Group::ifd0, 0, 0 }, + { "*", 0x0103, Group::ifd0, 0, 0 }, + { "*", 0x0111, Group::ifd0, 0, 0 }, + { "*", 0x0117, Group::ifd0, 0, 0 }, + { "*", 0x011a, Group::ifd0, 0, 0 }, + { "*", 0x011b, Group::ifd0, 0, 0 }, + { "*", 0x0128, Group::ifd0, 0, 0 }, + { "*", 0x02bc, Group::ifd0, &TiffDecoder::decodeXmp, &TiffEncoder::encodeXmp }, + { "*", 0x83bb, Group::ifd0, &TiffDecoder::decodeIptc, &TiffEncoder::encodeIptc }, + { "*", 0x8649, Group::ifd0, &TiffDecoder::decodeIptc, &TiffEncoder::encodeIptc } + }; + + DecoderFct Cr2Mapping::findDecoder(const std::string& make, + uint32_t extendedTag, + uint16_t group) + { + DecoderFct decoderFct = &TiffDecoder::decodeStdTiffEntry; + const TiffMappingInfo* td = find(cr2MappingInfo_, + 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 Cr2Mapping::findEncoder(const std::string& make, + uint32_t extendedTag, + uint16_t group) + { + EncoderFct encoderFct = 0; + const TiffMappingInfo* td = find(cr2MappingInfo_, + TiffMappingInfo::Key(make, extendedTag, group)); + if (td) { + // Returns 0 if no special encoder function is found + encoderFct = td->encoderFct_; + } + return encoderFct; + } + const char* Cr2Header::cr2sig_ = "CR\2\0"; Cr2Header::Cr2Header() @@ -184,36 +277,10 @@ namespace Exiv2 { return true; } // Cr2Header::read - void Cr2Header::write(Blob& blob) const + uint32_t Cr2Header::write(Blob& blob) const { // Todo: Implement me! + return 0; } - // ************************************************************************* - // 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 Internal, Exiv2 diff --git a/src/cr2image.hpp b/src/cr2image.hpp index e22d88d8..2aa4f223 100644 --- a/src/cr2image.hpp +++ b/src/cr2image.hpp @@ -33,9 +33,7 @@ // included header files #include "image.hpp" #include "basicio.hpp" -#include "tifffwd.hpp" #include "types.hpp" -#include "tiffimage.hpp" // + standard includes #include @@ -122,60 +120,38 @@ namespace Exiv2 { }; // class Cr2Image /*! - @brief Table of Cr2 decoding functions and find function. See - TiffDecoder for details. + @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 Cr2Decoder { + class Cr2Parser { 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, - uint16_t group); - - private: - static const TiffDecoderInfo cr2DecoderInfo_[]; // + * + * 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$ + @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 Table of CR2 decoding functions and find function. See + TiffMapping for details. + */ + class Cr2Mapping { + 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, + uint16_t group); + + /*! + @brief Find the encoder function for a key. + + If the returned pointer is 0, the tag should not be encoded, + 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, + uint16_t group); + + private: + static const TiffMappingInfo cr2MappingInfo_[]; //add(pCrwMapping->crwTagId_, pCrwMapping->crwDir_, buf); } @@ -1355,6 +1356,7 @@ namespace Exiv2 { // ***************************************************************************** // local definitions namespace { + //! @cond IGNORE const RotationMap::OmList RotationMap::omList_[] = { { 1, 0 }, { 3, 180 }, @@ -1390,4 +1392,5 @@ namespace { } return d; } + //! @endcond } diff --git a/src/error.cpp b/src/error.cpp index 7a25727d..21786062 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -65,7 +65,7 @@ namespace Exiv2 { ErrMsg( 20, N_("Failed to read input data")), ErrMsg( 21, N_("Failed to write image")), ErrMsg( 22, N_("Input data does not contain a valid image")), - ErrMsg( 23, N_("Failed to create Makernote for ifdId %1")), // %1=ifdId + ErrMsg( 23, N_("Invalid ifdId %1")), // %1=ifdId ErrMsg( 24, N_("Entry::setValue: Value too large (tag=%1, size=%2, requested=%3)")), // %1=tag, %2=dataSize, %3=required size ErrMsg( 25, N_("Entry::setDataArea: Value too large (tag=%1, size=%2, requested=%3)")), // %1=tag, %2=dataAreaSize, %3=required size ErrMsg( 26, N_("Offset out of range")), @@ -91,6 +91,9 @@ namespace Exiv2 { ErrMsg( 46, N_("No namespace registered for prefix `%1'")), // %1=prefix ErrMsg( 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 ErrMsg( 48, N_("Invalid XmpText type `%1'")), // %1=type + ErrMsg( 49, N_("TIFF directory %1 has too many entries")), // %1=TIFF directory name + ErrMsg( 50, N_("Multiple TIFF array element tags %1 in one directory")), // %1=tag number + ErrMsg( 51, N_("TIFF array element tag %1 has wrong type or more than one component")), // %1=tag number // Last error message (message is not used) ErrMsg( -2, N_("(Unknown Error)")) diff --git a/src/exif.cpp b/src/exif.cpp index 00332bf9..163ae124 100644 --- a/src/exif.cpp +++ b/src/exif.cpp @@ -29,10 +29,6 @@ #include "rcsid.hpp" EXIV2_RCSID("@(#) $Id$") -// Define DEBUG_MAKERNOTE to output debug information to std::cerr, e.g, by -// calling make like this: make DEFS=-DDEBUG_MAKERNOTE exif.o -//#define DEBUG_MAKERNOTE - // ***************************************************************************** // included header files #ifdef _MSC_VER @@ -42,45 +38,108 @@ EXIV2_RCSID("@(#) $Id$") #endif #include "exif.hpp" +#include "metadatum.hpp" +#include "tags.hpp" +#include "value.hpp" #include "types.hpp" -#include "basicio.hpp" #include "error.hpp" -#include "value.hpp" -#include "ifd.hpp" -#include "tags.hpp" -#include "image.hpp" -#include "makernote.hpp" -#include "futils.hpp" +#include "basicio.hpp" +#include "tiffimage.hpp" // + standard includes #include #include #include #include -#include #include #include #include -#include // for stat() -#include // for stat() -#ifdef EXV_HAVE_UNISTD_H -# include // for stat() -#endif // ***************************************************************************** -// local declarations namespace { - - /* - Set the data of the entry identified by tag in ifd to an unsigned long - with the value of offset. If no entry with this tag exists in ifd, an - entry of type unsigned long with one component is created. + /*! + @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. */ - void setOffsetTag(Exiv2::Ifd& ifd, - int idx, - uint16_t tag, - uint32_t offset, - Exiv2::ByteOrder byteOrder); + 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; + //@} + + }; // 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; + //@} + + }; // 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; + //@} + + }; // class JpegThumbnail } @@ -88,10 +147,22 @@ namespace { // class member definitions namespace Exiv2 { - Exifdatum::Exifdatum(const Entry& e, ByteOrder byteOrder) - : key_(ExifKey::AutoPtr(new ExifKey(e))) + /*! + @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) { - setValue(e, e.byteOrder() == invalidByteOrder ? byteOrder : e.byteOrder()); + 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) @@ -184,18 +255,6 @@ namespace Exiv2 { if (pValue) value_ = pValue->clone(); } - void Exifdatum::setValue(const Entry& e, ByteOrder byteOrder) - { - TypeId t = TypeId(e.type()); - // Hack: On the fly type conversion for Exif.Photo.UserComment - if (e.tag() == 0x9286 && e.ifdId() == exifIfdId && e.type() == undefined) { - t = comment; - } - value_ = Value::create(t); - value_->read(e.data(), e.count() * e.typeSize(), byteOrder); - value_->setDataArea(e.dataArea(), e.sizeDataArea()); - } - void Exifdatum::setValue(const std::string& value) { if (value_.get() == 0) { @@ -205,260 +264,99 @@ namespace Exiv2 { value_->read(value); } - TiffThumbnail& TiffThumbnail::operator=(const TiffThumbnail& /*rhs*/) - { - return *this; - } - - int TiffThumbnail::setDataArea(ExifData& exifData, Ifd* pIfd1, - const byte* buf, long len) const + ExifThumbC::ExifThumbC(const ExifData& exifData) + : exifData_(exifData) { - // Create a DataBuf that can hold all strips - ExifData::const_iterator sizes; - ExifKey key("Exif.Thumbnail.StripByteCounts"); - sizes = exifData.findKey(key); - if (sizes == exifData.end()) return 1; - - uint32_t totalSize = 0; - for (long i = 0; i < sizes->count(); ++i) { - uint32_t size = sizes->toLong(i); - if (size > 0xffffffff - totalSize) return 1; - totalSize += size; - } - DataBuf stripsBuf(totalSize); - - // Copy all strips into the data buffer. For each strip remember its - // offset from the start of the data buffer - ExifData::iterator stripOffsets; - key = ExifKey("Exif.Thumbnail.StripOffsets"); - stripOffsets = exifData.findKey(key); - if (stripOffsets == exifData.end()) return 1; - if (stripOffsets->count() != sizes->count()) return 1; - - std::ostringstream os; // for the strip offsets - uint32_t currentOffset = 0; - uint32_t firstOffset = stripOffsets->toLong(0); - uint32_t lastOffset = 0; - uint32_t lastSize = 0; - for (long i = 0; i < stripOffsets->count(); ++i) { - uint32_t offset = stripOffsets->toLong(i); - lastOffset = offset; - uint32_t size = sizes->toLong(i); - lastSize = size; - if ( size > 0xffffffff - offset - || static_cast(len) < offset + size) { - return 2; - } - std::memcpy(stripsBuf.pData_ + currentOffset, buf + offset, size); - os << currentOffset << " "; - currentOffset += size; - } - - // Set StripOffsets data area and relative offsets - stripOffsets->setDataArea(stripsBuf.pData_, stripsBuf.size_); - stripOffsets->setValue(os.str()); - - // Set corresponding data area at IFD1, if it is a contiguous area - if (pIfd1 && firstOffset + totalSize == lastOffset + lastSize) { - Ifd::iterator pos = pIfd1->findTag(0x0111); - assert(pos != pIfd1->end()); - pos->setDataArea(buf + firstOffset, totalSize); - } - - return 0; - } // TiffThumbnail::setDataArea - - const char* TiffThumbnail::format() const - { - return "TIFF"; } - const char* TiffThumbnail::extension() const + DataBuf ExifThumbC::copy() const { - return ".tif"; + Thumbnail::AutoPtr thumbnail = Thumbnail::create(exifData_); + if (thumbnail.get() == 0) return DataBuf(); + return thumbnail->copy(exifData_); } - DataBuf TiffThumbnail::copy(const ExifData& exifData) const + long ExifThumbC::writeFile(const std::string& path) const { - // Create a TIFF header and IFD1 - TiffHeader tiffHeader(exifData.byteOrder()); - Ifd ifd1(ifd1Id); - - // Populate IFD (without Exif and GPS tags) from metadata - addToIfd(ifd1, exifData.begin(), exifData.end(), exifData.byteOrder()); - ifd1.erase(0x8769); - ifd1.erase(0x8825); - ifd1.sortByTag(); - - long size = tiffHeader.size() + ifd1.size() + ifd1.dataSize(); - DataBuf buf(size); - long len = tiffHeader.copy(buf.pData_); - len += ifd1.copy(buf.pData_ + len, exifData.byteOrder(), len); - assert(len == size); - return buf; + Thumbnail::AutoPtr thumbnail = Thumbnail::create(exifData_); + if (thumbnail.get() == 0) return 0; + std::string name = path + thumbnail->extension(); + DataBuf buf(thumbnail->copy(exifData_)); + return Exiv2::writeFile(buf, name); } - JpegThumbnail& JpegThumbnail::operator=(const JpegThumbnail& /*rhs*/) + const char* ExifThumbC::mimeType() const { - return *this; + Thumbnail::AutoPtr thumbnail = Thumbnail::create(exifData_); + if (thumbnail.get() == 0) return ""; + return thumbnail->mimeType(); } - int JpegThumbnail::setDataArea(ExifData& exifData, Ifd* pIfd1, - const byte* buf, long len) const - { - ExifKey key("Exif.Thumbnail.JPEGInterchangeFormat"); - ExifData::iterator format = exifData.findKey(key); - if (format == exifData.end()) return 1; - uint32_t offset = format->toLong(); - key = ExifKey("Exif.Thumbnail.JPEGInterchangeFormatLength"); - ExifData::const_iterator length = exifData.findKey(key); - if (length == exifData.end()) return 1; - uint32_t size = length->toLong(); - if ( size > 0xffffffff - offset - || static_cast(len) < offset + size) { - return 2; - } - format->setDataArea(buf + offset, size); - format->setValue("0"); - if (pIfd1) { - Ifd::iterator pos = pIfd1->findTag(0x0201); - assert(pos != pIfd1->end()); - pos->setDataArea(buf + offset, size); - } - return 0; - } // JpegThumbnail::setDataArea - - const char* JpegThumbnail::format() const + const char* ExifThumbC::extension() const { - return "JPEG"; + Thumbnail::AutoPtr thumbnail = Thumbnail::create(exifData_); + if (thumbnail.get() == 0) return ""; + return thumbnail->extension(); } - const char* JpegThumbnail::extension() const + ExifThumb::ExifThumb(ExifData& exifData) + : ExifThumbC(exifData), exifData_(exifData) { - return ".jpg"; } - DataBuf JpegThumbnail::copy(const ExifData& exifData) const + void ExifThumb::setJpegThumbnail( + const std::string& path, + URational xres, + URational yres, + uint16_t unit + ) { - ExifKey key("Exif.Thumbnail.JPEGInterchangeFormat"); - ExifData::const_iterator format = exifData.findKey(key); - if (format == exifData.end()) return DataBuf(); - return format->dataArea(); + DataBuf thumb = readFile(path); // may throw + setJpegThumbnail(thumb.pData_, thumb.size_, xres, yres, unit); } - ExifData::ExifData() - : pTiffHeader_(0), - pIfd0_(0), pExifIfd_(0), pIopIfd_(0), pGpsIfd_(0), pIfd1_(0), - pMakerNote_(0), size_(0), pData_(0), compatible_(true) + 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; } - ExifData::ExifData(const ExifData& rhs) - : exifMetadata_(rhs.exifMetadata_), pTiffHeader_(0), - pIfd0_(0), pExifIfd_(0), pIopIfd_(0), pGpsIfd_(0), pIfd1_(0), - pMakerNote_(0), size_(0), pData_(0), compatible_(rhs.compatible_) + void ExifThumb::setJpegThumbnail(const std::string& path) { - pData_ = new byte[rhs.size_]; - size_ = rhs.size_; - std::memcpy(pData_, rhs.pData_, rhs.size_); - - if (rhs.pTiffHeader_) { - pTiffHeader_ = new TiffHeader(*rhs.pTiffHeader_); - } - if (rhs.pIfd0_) { - pIfd0_ = new Ifd(*rhs.pIfd0_); - pIfd0_->updateBase(pData_); - } - if (rhs.pExifIfd_) { - pExifIfd_ = new Ifd(*rhs.pExifIfd_); - pExifIfd_->updateBase(pData_); - } - if (rhs.pIopIfd_) { - pIopIfd_ = new Ifd(*rhs.pIopIfd_); - pIopIfd_->updateBase(pData_); - } - if (rhs.pGpsIfd_) { - pGpsIfd_ = new Ifd(*rhs.pGpsIfd_); - pGpsIfd_->updateBase(pData_); - } - if (rhs.pIfd1_) { - pIfd1_ = new Ifd(*rhs.pIfd1_); - pIfd1_->updateBase(pData_); - } - if (rhs.pMakerNote_) { - pMakerNote_ = rhs.pMakerNote_->clone().release(); - pMakerNote_->updateBase(pData_); - } + DataBuf thumb = readFile(path); // may throw + setJpegThumbnail(thumb.pData_, thumb.size_); } - ExifData::~ExifData() + void ExifThumb::setJpegThumbnail(const byte* buf, long size) { - delete pTiffHeader_; - delete pIfd0_; - delete pExifIfd_; - delete pIopIfd_; - delete pGpsIfd_; - delete pIfd1_; - delete pMakerNote_; - delete[] pData_; + 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); } - ExifData& ExifData::operator=(const ExifData& rhs) + void ExifThumb::erase() { - if (this == &rhs) return *this; - - exifMetadata_ = rhs.exifMetadata_; - - size_ = 0; - delete[] pData_; - pData_ = new byte[rhs.size_]; - size_ = rhs.size_; - std::memcpy(pData_, rhs.pData_, rhs.size_); - - delete pTiffHeader_; - pTiffHeader_ = 0; - if (rhs.pTiffHeader_) { - pTiffHeader_ = new TiffHeader(*rhs.pTiffHeader_); - } - delete pIfd0_; - pIfd0_ = 0; - if (rhs.pIfd0_) { - pIfd0_ = new Ifd(*rhs.pIfd0_); - pIfd0_->updateBase(pData_); - } - delete pExifIfd_; - pExifIfd_ = 0; - if (rhs.pExifIfd_) { - pExifIfd_ = new Ifd(*rhs.pExifIfd_); - pExifIfd_->updateBase(pData_); - } - delete pIopIfd_; - pIopIfd_ = 0; - if (rhs.pIopIfd_) { - pIopIfd_ = new Ifd(*rhs.pIopIfd_); - pIopIfd_->updateBase(pData_); - } - delete pGpsIfd_; - pGpsIfd_ = 0; - if (rhs.pGpsIfd_) { - pGpsIfd_ = new Ifd(*rhs.pGpsIfd_); - pGpsIfd_->updateBase(pData_); - } - delete pIfd1_; - pIfd1_ = 0; - if (rhs.pIfd1_) { - pIfd1_ = new Ifd(*rhs.pIfd1_); - pIfd1_->updateBase(pData_); - } - delete pMakerNote_; - pMakerNote_ = 0; - if (rhs.pMakerNote_) { - pMakerNote_ = rhs.pMakerNote_->clone().release(); - pMakerNote_->updateBase(pData_); + // Delete all Exif.Thumbnail.* (IFD1) metadata + // Todo: Do it the C++ way(TM) + ExifMetadata::iterator i = exifData_.begin(); + while (i != exifData_.end()) { + if (i->ifdId() == ifd1Id) { + i = exifData_.erase(i); + } + else { + ++i; + } } - - compatible_ = rhs.compatible_; - return *this; } Exifdatum& ExifData::operator[](const std::string& key) @@ -472,317 +370,6 @@ namespace Exiv2 { return *pos; } - int ExifData::load(const byte* buf, long len) - { - if (!buf || len == 0) return -1; - - // Copy the data buffer - DataBuf tmpData(len); - std::memcpy(tmpData.pData_, buf, len); - - // Read the TIFF header - std::auto_ptr tmpTiffHeader(new TiffHeader); - assert(tmpTiffHeader.get() != 0); - if (tmpData.size_ < tmpTiffHeader->size()) return 1; - int rc = tmpTiffHeader->read(tmpData.pData_); - if (rc) return rc; - - // Read IFD0 - std::auto_ptr tmpIfd0(new Ifd(ifd0Id, 0, false)); - assert(tmpIfd0.get() != 0); - rc = tmpIfd0->read(tmpData.pData_, - tmpData.size_, - tmpTiffHeader->offset(), - tmpTiffHeader->byteOrder()); - if (rc) return rc; // no point to continue if there is no IFD0 - - // We have at least a valid IFD0, so replace old metadata with new now - // After this point we only return 0 (success), although parts of the - // Exif data may be missing due to problems reading specific IFDs. - - this->clear(); // Deletes existing pointers - pData_ = tmpData.pData_; - size_ = tmpData.size_; - tmpData.release(); - pTiffHeader_ = tmpTiffHeader.release(); - pIfd0_ = tmpIfd0.release(); - - std::auto_ptr tmpExif(new Ifd(exifIfdId, 0, false)); - assert(tmpExif.get() != 0); - // Find and read ExifIFD sub-IFD of IFD0 - rc = pIfd0_->readSubIfd(*tmpExif, pData_, size_, byteOrder(), 0x8769); - if (0 == rc) { - pExifIfd_ = tmpExif.release(); - } - - if (pExifIfd_) { - // Find MakerNote in ExifIFD, create a MakerNote class - Ifd::iterator pos = pExifIfd_->findTag(0x927c); - Ifd::iterator make = pIfd0_->findTag(0x010f); - Ifd::iterator model = pIfd0_->findTag(0x0110); - MakerNote::AutoPtr tmpMakerNote; - if ( pos != pExifIfd_->end() - && make != pIfd0_->end() && model != pIfd0_->end()) { - // Todo: The conversion to string assumes that there is a \0 at the end - // Todo: How to avoid the cast (is that a MSVC thing?) - tmpMakerNote = MakerNoteFactory::create( - reinterpret_cast(make->data()), - reinterpret_cast(model->data()), - false, - pos->data(), - pos->size(), - byteOrder(), - pExifIfd_->offset() + pos->offset()); - } - // Read the MakerNote - if (tmpMakerNote.get() != 0) { - rc = tmpMakerNote->read(pData_, size_, - pExifIfd_->offset() + pos->offset(), - byteOrder()); - if (0 == rc) { - pMakerNote_ = tmpMakerNote.release(); - } - else { -#ifndef SUPPRESS_WARNINGS - std::cerr << "Warning: Failed to read Makernote, rc = " - << rc << "\n"; -#endif - } - } - // If we successfully parsed the MakerNote, delete the raw MakerNote, - // the parsed MakerNote is the primary MakerNote from now on - if (pMakerNote_) { - pExifIfd_->erase(pos); - } - - std::auto_ptr tmpIop(new Ifd(iopIfdId, 0, false)); - assert(tmpIop.get() != 0); - // Find and read Interoperability IFD in ExifIFD - rc = pExifIfd_->readSubIfd(*tmpIop, pData_, size_, byteOrder(), 0xa005); - if (0 == rc) { - pIopIfd_ = tmpIop.release(); - } - } // if (pExifIfd_) - - std::auto_ptr tmpGps(new Ifd(gpsIfdId, 0, false)); - assert(tmpGps.get() != 0); - // Find and read GPSInfo sub-IFD in IFD0 - rc = pIfd0_->readSubIfd(*tmpGps, pData_, size_, byteOrder(), 0x8825); - if (0 == rc) { - pGpsIfd_ = tmpGps.release(); - } - - std::auto_ptr tmpIfd1(new Ifd(ifd1Id, 0, false)); - assert(tmpIfd1.get() != 0); - // Read IFD1 - if (pIfd0_->next()) { - rc = tmpIfd1->read(pData_, size_, pIfd0_->next(), byteOrder()); - if (0 == rc) { - pIfd1_ = tmpIfd1.release(); - } - } - if (pIfd1_) { - // Find and delete ExifIFD sub-IFD of IFD1 - Ifd::iterator pos = pIfd1_->findTag(0x8769); - if (pos != pIfd1_->end()) { - pIfd1_->erase(pos); - } - // Find and delete GPSInfo sub-IFD in IFD1 - pos = pIfd1_->findTag(0x8825); - if (pos != pIfd1_->end()) { - pIfd1_->erase(pos); - } - } - // Copy all entries from the IFDs and the MakerNote to the metadata - add(pIfd0_->begin(), pIfd0_->end(), byteOrder()); - if (pExifIfd_) add(pExifIfd_->begin(), pExifIfd_->end(), byteOrder()); - if (pMakerNote_) { - add(pMakerNote_->begin(), pMakerNote_->end(), - (pMakerNote_->byteOrder() == invalidByteOrder ? - byteOrder() : pMakerNote_->byteOrder())); - } - if (pIopIfd_) add(pIopIfd_->begin(), pIopIfd_->end(), byteOrder()); - if (pGpsIfd_) add(pGpsIfd_->begin(), pGpsIfd_->end(), byteOrder()); - if (pIfd1_) add(pIfd1_->begin(), pIfd1_->end(), byteOrder()); - // Finally, read the thumbnail - rc = readThumbnail(); - if (0 < rc) { -#ifndef SUPPRESS_WARNINGS - std::cerr << "Warning: Failed to read thumbnail, rc = " - << rc << "\n"; -#endif - } - - return 0; - } // ExifData::load - - DataBuf ExifData::copy() - { - DataBuf buf; - // If we can update the internal IFDs and the underlying data buffer - // from the metadata without changing the data size, then it is enough - // to copy the data buffer. - if (compatible_ && updateEntries()) { -#ifdef DEBUG_MAKERNOTE - std::cerr << "->>>>>> using non-intrusive writing <<<<<<-\n"; -#endif - buf.alloc(size_); - std::memcpy(buf.pData_, pData_, size_); - } - // Else we have to do it the hard way... - else { -#ifdef DEBUG_MAKERNOTE - std::cerr << "->>>>>> writing from metadata <<<<<<-\n"; -#endif - buf = copyFromMetadata(); - } - return buf; - } - - DataBuf ExifData::copyFromMetadata() - { - // Build IFD0 - Ifd ifd0(ifd0Id); - addToIfd(ifd0, begin(), end(), byteOrder()); - - // Build Exif IFD from metadata - Ifd exifIfd(exifIfdId); - addToIfd(exifIfd, begin(), end(), byteOrder()); - MakerNote::AutoPtr makerNote; - if (pMakerNote_) { - // Build MakerNote from metadata - makerNote = pMakerNote_->create(); - addToMakerNote(makerNote.get(), - begin(), end(), - (pMakerNote_->byteOrder() == invalidByteOrder ? - byteOrder() : pMakerNote_->byteOrder())); - // Create a placeholder MakerNote entry of the correct size and - // add it to the Exif IFD (because we don't know the offset yet) - Entry e; - e.setIfdId(exifIfd.ifdId()); - e.setTag(0x927c); - DataBuf tmpBuf(makerNote->size()); - std::memset(tmpBuf.pData_, 0x0, tmpBuf.size_); - e.setValue(undefined, tmpBuf.size_, tmpBuf.pData_, tmpBuf.size_); - exifIfd.erase(0x927c); - exifIfd.add(e); - } - - // Build Interoperability IFD from metadata - Ifd iopIfd(iopIfdId); - addToIfd(iopIfd, begin(), end(), byteOrder()); - - // Build GPSInfo IFD from metadata - Ifd gpsIfd(gpsIfdId); - addToIfd(gpsIfd, begin(), end(), byteOrder()); - - // build IFD1 from metadata - Ifd ifd1(ifd1Id); - addToIfd(ifd1, begin(), end(), byteOrder()); - // Set a temporary dummy offset in IFD0 - if (ifd1.size() > 0) { - ifd0.setNext(1, byteOrder()); - } - - // Compute the new IFD offsets - int exifIdx = ifd0.erase(0x8769); - int gpsIdx = ifd0.erase(0x8825); - int iopIdx = exifIfd.erase(0xa005); - - TiffHeader tiffHeader(byteOrder()); - long ifd0Offset = tiffHeader.size(); - bool addOffsetTag = false; - long exifIfdOffset = ifd0Offset + ifd0.size() + ifd0.dataSize(); - if (exifIfd.size() > 0 || iopIfd.size() > 0) { - exifIfdOffset += 12; - addOffsetTag = true; - } - if (gpsIfd.size() > 0) { - exifIfdOffset += 12; - addOffsetTag = true; - } - if (ifd0.size() == 0 && addOffsetTag) { - exifIfdOffset += 6; - } - addOffsetTag = false; - long iopIfdOffset = exifIfdOffset + exifIfd.size() + exifIfd.dataSize(); - if (iopIfd.size() > 0) { - iopIfdOffset += 12; - addOffsetTag = true; - } - if (exifIfd.size() == 0 && addOffsetTag) { - iopIfdOffset += 6; - } - long gpsIfdOffset = iopIfdOffset + iopIfd.size() + iopIfd.dataSize(); - long ifd1Offset = gpsIfdOffset + gpsIfd.size() + gpsIfd.dataSize(); - - // Set the offset to IFD1 in IFD0 - if (ifd1.size() > 0) { - ifd0.setNext(ifd1Offset, byteOrder()); - } - - // Set the offset to the Exif IFD in IFD0 - if (exifIfd.size() > 0 || iopIfd.size() > 0) { - setOffsetTag(ifd0, exifIdx, 0x8769, exifIfdOffset, byteOrder()); - } - // Set the offset to the GPSInfo IFD in IFD0 - if (gpsIfd.size() > 0) { - setOffsetTag(ifd0, gpsIdx, 0x8825, gpsIfdOffset, byteOrder()); - } - // Set the offset to the Interoperability IFD in Exif IFD - if (iopIfd.size() > 0) { - setOffsetTag(exifIfd, iopIdx, 0xa005, iopIfdOffset, byteOrder()); - } - - // Allocate a data buffer big enough for all metadata - long size = ifd0.size() + ifd0.dataSize(); - size += exifIfd.size() + exifIfd.dataSize(); - size += iopIfd.size() + iopIfd.dataSize(); - size += gpsIfd.size() + gpsIfd.dataSize(); - size += ifd1.size() + ifd1.dataSize(); - - // Return an empty buffer without TIFF header if there is nothing to write - if (size == 0) return DataBuf(0); - - size += tiffHeader.size(); - DataBuf buf(size); - - // Copy the TIFF header, all IFDs, MakerNote and thumbnail to the buffer - size = tiffHeader.copy(buf.pData_); - ifd0.sortByTag(); - size += ifd0.copy(buf.pData_ + ifd0Offset, byteOrder(), ifd0Offset); - exifIfd.sortByTag(); - size += exifIfd.copy(buf.pData_ + exifIfdOffset, byteOrder(), exifIfdOffset); - if (makerNote.get() != 0) { - // Copy the MakerNote over the placeholder data - Entries::iterator mn = exifIfd.findTag(0x927c); - // Do _not_ sort the makernote; vendors (at least Canon), don't seem - // to bother about this TIFF standard requirement, so writing the - // makernote as is might result in fewer deviations from the original - makerNote->copy(buf.pData_ + exifIfdOffset + mn->offset(), - byteOrder(), - exifIfdOffset + mn->offset()); - } - iopIfd.sortByTag(); - size += iopIfd.copy(buf.pData_ + iopIfdOffset, byteOrder(), iopIfdOffset); - gpsIfd.sortByTag(); - size += gpsIfd.copy(buf.pData_ + gpsIfdOffset, byteOrder(), gpsIfdOffset); - ifd1.sortByTag(); - size += ifd1.copy(buf.pData_ + ifd1Offset, byteOrder(), ifd1Offset); - assert(size == buf.size_); - return buf; - } // ExifData::copyFromMetadata - - void ExifData::add(Entries::const_iterator begin, - Entries::const_iterator end, - ByteOrder byteOrder) - { - Entries::const_iterator i = begin; - for (; i != end; ++i) { - add(Exifdatum(*i, byteOrder)); - } - } - void ExifData::add(const ExifKey& key, const Value* pValue) { add(Exifdatum(key, pValue)); @@ -790,12 +377,6 @@ namespace Exiv2 { void ExifData::add(const Exifdatum& exifdatum) { - if (ExifTags::isMakerIfd(exifdatum.ifdId())) { - if (pMakerNote_ == 0) { - pMakerNote_ = MakerNoteFactory::create(exifdatum.ifdId()).release(); - } - if (pMakerNote_ == 0) throw Error(23, exifdatum.ifdId()); - } // allow duplicates exifMetadata_.push_back(exifdatum); } @@ -812,48 +393,9 @@ namespace Exiv2 { FindMetadatumByKey(key.key())); } - ExifData::const_iterator ExifData::findIfdIdIdx(IfdId ifdId, int idx) const - { - return std::find_if(exifMetadata_.begin(), exifMetadata_.end(), - FindMetadatumByIfdIdIdx(ifdId, idx)); - } - - ExifData::iterator ExifData::findIfdIdIdx(IfdId ifdId, int idx) - { - return std::find_if(exifMetadata_.begin(), exifMetadata_.end(), - FindMetadatumByIfdIdIdx(ifdId, idx)); - } - void ExifData::clear() { - eraseThumbnail(); exifMetadata_.clear(); - delete pTiffHeader_; - pTiffHeader_ = 0; - delete pIfd0_; - pIfd0_ = 0; - delete pExifIfd_; - pExifIfd_ = 0; - delete pIopIfd_; - pIopIfd_ = 0; - delete pGpsIfd_; - pGpsIfd_ = 0; - delete pIfd1_; - pIfd1_ = 0; - delete pMakerNote_; - pMakerNote_ = 0; - delete[] pData_; - pData_ = 0; - } - - void ExifData::sortByKey() - { - std::sort(exifMetadata_.begin(), exifMetadata_.end(), cmpMetadataByKey); - } - - void ExifData::sortByTag() - { - std::sort(exifMetadata_.begin(), exifMetadata_.end(), cmpMetadataByTag); } ExifData::iterator ExifData::erase(ExifData::iterator pos) @@ -861,165 +403,62 @@ namespace Exiv2 { return exifMetadata_.erase(pos); } - void ExifData::setJpegThumbnail(const byte* buf, long size) - { - (*this)["Exif.Thumbnail.Compression"] = uint16_t(6); - Exifdatum& format = (*this)["Exif.Thumbnail.JPEGInterchangeFormat"]; - format = uint32_t(0); - format.setDataArea(buf, size); - (*this)["Exif.Thumbnail.JPEGInterchangeFormatLength"] = uint32_t(size); - } - - void ExifData::setJpegThumbnail(const byte* buf, long size, - URational xres, URational yres, uint16_t unit) - { - setJpegThumbnail(buf, size); - (*this)["Exif.Thumbnail.XResolution"] = xres; - (*this)["Exif.Thumbnail.YResolution"] = yres; - (*this)["Exif.Thumbnail.ResolutionUnit"] = unit; - } - - void ExifData::setJpegThumbnail(const std::string& path) - { - DataBuf thumb = readFile(path); // may throw - setJpegThumbnail(thumb.pData_, thumb.size_); - } - - void ExifData::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); - } - - long ExifData::eraseThumbnail() - { - // First, determine if the thumbnail is at the end of the Exif data - bool stp = stdThumbPosition(); - // Delete all Exif.Thumbnail.* (IFD1) metadata - ExifMetadata::iterator i = begin(); - while (i != end()) { - if (i->ifdId() == ifd1Id) { - i = erase(i); - } - else { - ++i; - } - } - long delta = 0; - if (stp) { - delta = size_; - if (size_ > 0 && pIfd0_ && pIfd0_->next() > 0) { - // Truncate IFD1 and thumbnail data from the data buffer - size_ = pIfd0_->next(); - pIfd0_->setNext(0, byteOrder()); - if (pIfd1_) pIfd1_->clear(); - } - delta -= size_; - } - else { - // We will have to write the hard way and re-arrange the data - compatible_ = false; - if (pIfd1_) delta = pIfd1_->size() + pIfd1_->dataSize(); - } - return delta; - } // ExifData::eraseThumbnail - - bool ExifData::stdThumbPosition() const - { - if (pIfd1_ == 0) return true; - - // Todo: There is still an invalid assumption here: The data of an IFD - // can be stored in multiple non-contiguous blocks. In this case, - // dataOffset + dataSize does not point to the end of the IFD data. - // in particular, this is potentially the case for the remaining Exif - // data in the presence of a known Makernote. - bool rc = true; - Thumbnail::AutoPtr thumbnail = getThumbnail(); - if (thumbnail.get()) { - long maxOffset; - maxOffset = std::max(pIfd0_->offset(), pIfd0_->dataOffset()); - if (pExifIfd_) { - maxOffset = std::max(maxOffset, pExifIfd_->offset()); - maxOffset = std::max(maxOffset, pExifIfd_->dataOffset() - + pExifIfd_->dataSize()); - } - if (pMakerNote_) { - maxOffset = std::max(maxOffset, pMakerNote_->offset() - + pMakerNote_->size()); - } - if (pIopIfd_) { - maxOffset = std::max(maxOffset, pIopIfd_->offset()); - maxOffset = std::max(maxOffset, pIopIfd_->dataOffset() - + pIopIfd_->dataSize()); - } - if (pGpsIfd_) { - maxOffset = std::max(maxOffset, pGpsIfd_->offset()); - maxOffset = std::max(maxOffset, pGpsIfd_->dataOffset() - + pGpsIfd_->dataSize()); - } - if ( maxOffset > pIfd1_->offset() - || (maxOffset > pIfd1_->dataOffset() && pIfd1_->dataOffset() > 0)) - rc = false; - /* - Todo: Removed condition from the above if(). Should be re-added... - || maxOffset > pThumbnail_->offset() - */ - } - return rc; - } // ExifData::stdThumbPosition - - ByteOrder ExifData::byteOrder() const - { - if (pTiffHeader_) return pTiffHeader_->byteOrder(); - return littleEndian; - } - - int ExifData::writeThumbnail(const std::string& path) const + ByteOrder ExifParser::decode( + ExifData& exifData, + const byte* pData, + uint32_t size + ) { - Thumbnail::AutoPtr thumbnail = getThumbnail(); - if (thumbnail.get() == 0) return 8; - - std::string name = path + thumbnail->extension(); - FileIo file(name); - if (file.open("wb") != 0) { - throw Error(10, name, "wb", strError()); + IptcData iptcData; + XmpData xmpData; + ByteOrder bo = TiffParser::decode(exifData, + iptcData, + xmpData, + pData, + size); +#ifndef SUPPRESS_WARNINGS + if (!iptcData.empty()) { + std::cerr << "Warning: Ignoring IPTC information encoded in the Exif data.\n"; } - - DataBuf buf(thumbnail->copy(*this)); - if (file.write(buf.pData_, buf.size_) != buf.size_) { - throw Error(2, name, strError(), "FileIo::write"); + if (!xmpData.empty()) { + std::cerr << "Warning: Ignoring XMP information encoded in the Exif data.\n"; } +#endif + return bo; + } // ExifParser::decode + + WriteMethod ExifParser::encode( + Blob& blob, + const byte* pData, + uint32_t size, + ByteOrder byteOrder, + const ExifData& exifData + ) + { + const IptcData iptcData; + const XmpData xmpData; + return TiffParser::encode(blob, + pData, + size, + byteOrder, + exifData, + iptcData, + xmpData); + } // ExifParser::encode - return 0; - } // ExifData::writeThumbnail - - DataBuf ExifData::copyThumbnail() const - { - Thumbnail::AutoPtr thumbnail = getThumbnail(); - if (thumbnail.get() == 0) return DataBuf(); - return thumbnail->copy(*this); - } - - const char* ExifData::thumbnailFormat() const - { - Thumbnail::AutoPtr thumbnail = getThumbnail(); - if (thumbnail.get() == 0) return ""; - return thumbnail->format(); - } +} // namespace Exiv2 - const char* ExifData::thumbnailExtension() const - { - Thumbnail::AutoPtr thumbnail = getThumbnail(); - if (thumbnail.get() == 0) return ""; - return thumbnail->extension(); - } +// ***************************************************************************** +// local definitions +namespace { - Thumbnail::AutoPtr ExifData::getThumbnail() const + //! @cond IGNORE + Thumbnail::AutoPtr Thumbnail::create(const Exiv2::ExifData& exifData) { Thumbnail::AutoPtr thumbnail; - const_iterator pos = findKey(ExifKey("Exif.Thumbnail.Compression")); - if (pos != end()) { + const Exiv2::ExifKey k1("Exif.Thumbnail.Compression"); + Exiv2::ExifData::const_iterator pos = exifData.findKey(k1); + if (pos != exifData.end()) { long compression = pos->toLong(); if (compression == 6) { thumbnail = Thumbnail::AutoPtr(new JpegThumbnail); @@ -1029,286 +468,59 @@ namespace Exiv2 { } } else { - pos = findKey(ExifKey("Exif.Thumbnail.JPEGInterchangeFormat")); - if (pos != end()) thumbnail = Thumbnail::AutoPtr(new JpegThumbnail); - } - return thumbnail; - - } // ExifData::getThumbnail - - int ExifData::readThumbnail() - { - int rc = -1; - Thumbnail::AutoPtr thumbnail = getThumbnail(); - if (thumbnail.get() != 0) { - rc = thumbnail->setDataArea(*this, pIfd1_, pData_, size_); - } - return rc; - - } // ExifData::readThumbnail - - bool ExifData::updateEntries() - { - if (pIfd0_ == 0 || pExifIfd_ == 0 || pIopIfd_ == 0 || pGpsIfd_ == 0) { - return false; - } - if (!this->compatible()) return false; - - bool compatible = true; - compatible &= updateRange(pIfd0_->begin(), pIfd0_->end(), byteOrder()); - compatible &= updateRange(pExifIfd_->begin(), pExifIfd_->end(), byteOrder()); - if (pMakerNote_) { - compatible &= updateRange(pMakerNote_->begin(), - pMakerNote_->end(), - (pMakerNote_->byteOrder() == invalidByteOrder ? - byteOrder() : pMakerNote_->byteOrder())); - } - compatible &= updateRange(pIopIfd_->begin(), pIopIfd_->end(), byteOrder()); - compatible &= updateRange(pGpsIfd_->begin(), pGpsIfd_->end(), byteOrder()); - if (pIfd1_) { - compatible &= updateRange(pIfd1_->begin(), pIfd1_->end(), byteOrder()); - } - return compatible; - } // ExifData::updateEntries - - bool ExifData::updateRange(const Entries::iterator& begin, - const Entries::iterator& end, - ByteOrder byteOrder) - { - bool compatible = true; - for (Entries::iterator entry = begin; entry != end; ++entry) { - // find the corresponding Exifdatum - const_iterator md = findIfdIdIdx(entry->ifdId(), entry->idx()); - if (md == this->end()) { - // corresponding Exifdatum was deleted: this is not (yet) a - // supported non-intrusive write operation. - compatible = false; - continue; - } - if (entry->count() == 0 && md->count() == 0) { - // Special case: don't do anything if both the entry and - // Exifdatum have no data. This is to preserve the original - // data in the offset field of an IFD entry with count 0, - // if the Exifdatum was not changed. - } - else if ( entry->size() < md->size() - || entry->sizeDataArea() < md->sizeDataArea()) { - compatible = false; - continue; - } - else { - // Hack: Set the entry's value only if there is no data area. - // This ensures that the original offsets are not overwritten - // with relative offsets from the Exifdatum (which require - // conversion to offsets relative to the start of the TIFF - // header and that is currently only done in intrusive write - // mode). On the other hand, it is thus now not possible to - // change the offsets of an entry with a data area in - // non-intrusive mode. This can be considered a bug. - // Todo: Fix me! - if (md->sizeDataArea() == 0) { - DataBuf buf(md->size()); - // Hack: Use byte order from the entry if there is one - md->copy(buf.pData_, entry->byteOrder() == invalidByteOrder - ? byteOrder : entry->byteOrder()); - entry->setValue(static_cast(md->typeId()), - md->count(), - buf.pData_, md->size()); - } - // Always set the data area - DataBuf dataArea(md->dataArea()); - entry->setDataArea(dataArea.pData_, dataArea.size_); - } - } - return compatible; - } // ExifData::updateRange - - bool ExifData::compatible() const - { - bool compatible = true; - // For each Exifdatum, check if it is compatible with the corresponding - // IFD or MakerNote entry - for (const_iterator md = begin(); md != this->end(); ++md) { - std::pair rc; - rc = findEntry(md->ifdId(), md->idx()); - // Make sure that we have an entry - if (!rc.first) { - compatible = false; - break; - } - // Make sure that the size of the Exifdatum fits the available size - // of the entry and the types are the same - if ( md->size() > rc.second->size() - || md->sizeDataArea() > rc.second->sizeDataArea() - || md->typeId() != rc.second->type()) { - compatible = false; - break; - } - } - return compatible; - } // ExifData::compatible - - std::pair - ExifData::findEntry(IfdId ifdId, int idx) const - { - Entries::const_iterator entry; - std::pair rc(false, entry); - - if (ExifTags::isMakerIfd(ifdId) && pMakerNote_) { - entry = pMakerNote_->findIdx(idx); - if (entry != pMakerNote_->end()) { - rc.first = true; - rc.second = entry; - } - return rc; - } - const Ifd* ifd = getIfd(ifdId); - if (ifd && isExifIfd(ifdId)) { - entry = ifd->findIdx(idx); - if (entry != ifd->end()) { - rc.first = true; - rc.second = entry; + const Exiv2::ExifKey k2("Exif.Thumbnail.JPEGInterchangeFormat"); + pos = exifData.findKey(k2); + if (pos != exifData.end()) { + thumbnail = Thumbnail::AutoPtr(new JpegThumbnail); } } - return rc; - } // ExifData::findEntry + return thumbnail; + } - const Ifd* ExifData::getIfd(IfdId ifdId) const + const char* TiffThumbnail::mimeType() const { - const Ifd* ifd = 0; - switch (ifdId) { - case ifd0Id: - ifd = pIfd0_; - break; - case exifIfdId: - ifd = pExifIfd_; - break; - case iopIfdId: - ifd = pIopIfd_; - break; - case gpsIfdId: - ifd = pGpsIfd_; - break; - case ifd1Id: - ifd = pIfd1_; - break; - default: - ifd = 0; - break; - } - return ifd; - } // ExifData::getIfd - - // ************************************************************************* - // free functions + return "image/tiff"; + } - IfdId hasMakerNote(const ExifData& exifData) + const char* TiffThumbnail::extension() const { - ExifData::const_iterator e = exifData.end(); - for (ExifData::const_iterator md = exifData.begin(); md != e; ++md) { - if (ExifTags::isMakerIfd(md->ifdId())) return md->ifdId(); - } - return ifdIdNotSet; - } // hasMakerNote + return ".tif"; + } - void addToIfd(Ifd& ifd, - ExifMetadata::const_iterator begin, - ExifMetadata::const_iterator end, - ByteOrder byteOrder) + Exiv2::DataBuf TiffThumbnail::copy(const Exiv2::ExifData& exifData) const { - for (ExifMetadata::const_iterator i = begin; i != end; ++i) { - // add only metadata with matching IFD id - if (i->ifdId() == ifd.ifdId()) { - addToIfd(ifd, *i, byteOrder); + 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()); } } - } // addToIfd - - void addToIfd(Ifd& ifd, const Exifdatum& md, ByteOrder byteOrder) - { - assert(ifd.alloc()); - - Entry e; - e.setIfdId(md.ifdId()); - e.setIdx(md.idx()); - e.setTag(md.tag()); - e.setOffset(0); // will be calculated when the IFD is written - DataBuf buf(md.size()); - md.copy(buf.pData_, byteOrder); - e.setValue(static_cast(md.typeId()), md.count(), - buf.pData_, buf.size_); - - DataBuf dataArea(md.dataArea()); - e.setDataArea(dataArea.pData_, dataArea.size_); - - ifd.add(e); - } // addToIfd + Exiv2::Blob blob; + const Exiv2::IptcData emptyIptc; + const Exiv2::XmpData emptyXmp; + Exiv2::TiffParser::encode(blob, 0, 0, Exiv2::littleEndian, thumb, emptyIptc, emptyXmp); + return Exiv2::DataBuf(&blob[0], static_cast(blob.size())); + } - void addToMakerNote(MakerNote* makerNote, - ExifMetadata::const_iterator begin, - ExifMetadata::const_iterator end, - ByteOrder byteOrder) + const char* JpegThumbnail::mimeType() const { - for (ExifMetadata::const_iterator i = begin; i != end; ++i) { - if (ExifTags::isMakerIfd(i->ifdId())) { - // Wild Hack... very ugly - ByteOrder bo = byteOrder; - if ( i->ifdId() == minoltaCs5DIfdId - || i->ifdId() == minoltaCs7DIfdId - || i->ifdId() == minoltaCsOldIfdId - || i->ifdId() == minoltaCsNewIfdId) { - bo = bigEndian; - } - addToMakerNote(makerNote, *i, bo); - } - } - } // addToMakerNote + return "image/jpeg"; + } - void addToMakerNote(MakerNote* makerNote, - const Exifdatum& md, - ByteOrder byteOrder) + const char* JpegThumbnail::extension() const { - Entry e; - e.setIfdId(md.ifdId()); - e.setIdx(md.idx()); - e.setTag(md.tag()); - e.setOffset(0); // will be calculated when the makernote is written - - DataBuf buf(md.size()); - md.copy(buf.pData_, byteOrder); - e.setValue(static_cast(md.typeId()), md.count(), - buf.pData_, md.size()); - - DataBuf dataArea(md.dataArea()); - e.setDataArea(dataArea.pData_, dataArea.size_); - - makerNote->add(e); - } // addToMakerNote - -} // namespace Exiv2 - -// ***************************************************************************** -// local definitions -namespace { + return ".jpg"; + } - void setOffsetTag(Exiv2::Ifd& ifd, - int idx, - uint16_t tag, - uint32_t offset, - Exiv2::ByteOrder byteOrder) + Exiv2::DataBuf JpegThumbnail::copy(const Exiv2::ExifData& exifData) const { - Exiv2::Ifd::iterator pos = ifd.findTag(tag); - if (pos == ifd.end()) { - Exiv2::Entry e(ifd.alloc()); - e.setIfdId(ifd.ifdId()); - e.setIdx(idx); - e.setTag(tag); - e.setOffset(0); // will be calculated when the IFD is written - ifd.add(e); - pos = ifd.findTag(tag); - } - pos->setValue(offset, byteOrder); + Exiv2::ExifKey key("Exif.Thumbnail.JPEGInterchangeFormat"); + Exiv2::ExifData::const_iterator format = exifData.findKey(key); + if (format == exifData.end()) return Exiv2::DataBuf(); + return format->dataArea(); } - + //! @endcond } diff --git a/src/exif.hpp b/src/exif.hpp index dee57ab9..9f71c93d 100644 --- a/src/exif.hpp +++ b/src/exif.hpp @@ -32,11 +32,9 @@ // ***************************************************************************** // included header files #include "metadatum.hpp" -#include "types.hpp" -#include "error.hpp" -#include "value.hpp" -#include "ifd.hpp" #include "tags.hpp" +#include "value.hpp" +#include "types.hpp" // + standard includes #include @@ -47,16 +45,13 @@ // namespace extensions /*! @brief Provides classes and functions to encode and decode Exif and Iptc data. - This namespace corresponds to the libexiv2 library. - + The libexiv2 API consists of the objects of this namespace. */ namespace Exiv2 { // ***************************************************************************** // class declarations class ExifData; - class MakerNote; - class TiffHeader; // ***************************************************************************** // class definitions @@ -82,8 +77,6 @@ namespace Exiv2 { @throw Error if the key cannot be parsed and converted. */ explicit Exifdatum(const ExifKey& key, const Value* pValue =0); - //! Constructor to build an %Exifdatum from an IFD entry. - Exifdatum(const Entry& e, ByteOrder byteOrder); //! Copy constructor Exifdatum(const Exifdatum& rhs); //! Destructor @@ -142,10 +135,6 @@ namespace Exiv2 { created. An AsciiValue is created for unknown tags. */ void setValue(const std::string& value); - /*! - @brief Set the value from an IFD entry. - */ - void setValue(const Entry& e, ByteOrder byteOrder); /*! @brief Set the data area by copying (cloning) the buffer pointed to by \em buf. @@ -258,154 +247,168 @@ namespace Exiv2 { }; // class Exifdatum /*! - @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 - Exifdatum& setValue(Exifdatum& exifDatum, const T& value); - - /*! - @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. + @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 Thumbnail { + class ExifThumbC { public: - //! Shortcut for a %Thumbnail auto pointer. - typedef std::auto_ptr AutoPtr; - //! @name Creators //@{ - //! Virtual destructor - virtual ~Thumbnail() {} + //! Constructor. + ExifThumbC(const ExifData& exifData); //@} //! @name Accessors //@{ - /*! - @brief Set the image data as data area of the appropriate Exif - metadatum. Read the thumbnail image data from data buffer - \em buf. Return 0 if successful. - - @param exifData Exif data corresponding to the data buffer. - @param pIfd1 Corresponding raw IFD1. - @param buf Data buffer containing the thumbnail data. The buffer must - start with the TIFF header. - @param len Number of bytes in the data buffer. - @return 0 if successful;
- 1 in case of inconsistent thumbnail Exif data; or
- 2 if the data area is outside of the data buffer - */ - virtual int setDataArea(ExifData& exifData, - Ifd* pIfd1, - const byte* buf, - long len) const =0; /*! @brief Return the thumbnail image in a %DataBuf. The caller owns the data buffer and %DataBuf ensures that it will be deleted. */ - virtual DataBuf copy(const ExifData& exifData) const =0; + DataBuf copy() const; /*! - @brief Return a short string for the format of the thumbnail - ("TIFF", "JPEG"). + @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; + /*! + @brief Return the MIME type of the thumbnail, either \c "image/tiff" + or \c "image/jpeg". */ - virtual const char* format() const =0; + const char* mimeType() const; /*! @brief Return the file extension for the format of the thumbnail - (".tif", ".jpg"). + (".tif" or ".jpg"). */ - virtual const char* extension() const =0; + const char* extension() const; //@} - protected: - //! @name Manipulators - //@{ - /*! - @brief Assignment operator. Protected so that it can only be used - by subclasses but not directly. - */ - Thumbnail& operator=(const Thumbnail& rhs); - //@} + private: + const ExifData& exifData_; //!< Const reference to the Exif metadata. - }; // class Thumbnail + }; // class ExifThumb - //! Exif thumbnail image in TIFF format - class TiffThumbnail : public Thumbnail { + /*! + @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 ExifThumb : public ExifThumbC { public: - //! Shortcut for a %TiffThumbnail auto pointer. - typedef std::auto_ptr AutoPtr; - - //! @name Manipulators + //! @name Creators //@{ - //! Assignment operator. - TiffThumbnail& operator=(const TiffThumbnail& rhs); + //! Constructor. + ExifThumb(ExifData& exifData); //@} - //! @name Accessors + //! @name Manipulators //@{ - int setDataArea(ExifData& exifData, - Ifd* pIfd1, - const byte* buf, - long len) const; - DataBuf copy(const ExifData& exifData) const; - const char* format() const; - const char* extension() const; - //@} + /*! + @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. - }; // class TiffThumbnail + This results in the minimal thumbnail tags being set for a JPEG + thumbnail, as mandated by the Exif standard. - //! Exif thumbnail image in JPEG format - class JpegThumbnail : public Thumbnail { - public: - //! Shortcut for a %JpegThumbnail auto pointer. - typedef std::auto_ptr AutoPtr; + @throw Error if reading the file fails. - //! @name Manipulators - //@{ - //! Assignment operator. - JpegThumbnail& operator=(const JpegThumbnail& rhs); - //@} + @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 + ); + /*! + @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. - //! @name Accessors - //@{ - int setDataArea(ExifData& exifData, - Ifd* pIfd1, - const byte* buf, - long len) const; - DataBuf copy(const ExifData& exifData) const; - const char* format() const; - const char* extension() const; - //@} + This results in the minimal thumbnail tags being set for a JPEG + thumbnail, as mandated by the Exif standard. - }; // class JpegThumbnail + @throw Error if reading the file fails. - //! Container type to hold all metadata - typedef std::vector ExifMetadata; + @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. - //! Unary predicate that matches a Exifdatum with a given ifd id and idx - class FindMetadatumByIfdIdIdx { - public: - //! Constructor, initializes the object with the ifd id and idx to look for - FindMetadatumByIfdIdIdx(IfdId ifdId, int idx) - : ifdId_(ifdId), idx_(idx) {} + 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); /*! - @brief Returns true if the ifd id and idx of the argument - \em exifdatum is equal to that of the object. - */ - bool operator()(const Exifdatum& exifdatum) const - { return ifdId_ == exifdatum.ifdId() && idx_ == exifdatum.idx(); } + @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: - IfdId ifdId_; - int idx_; + ExifData& exifData_; //!< Reference to the related Exif metadata. + + }; // class ExifThumb - }; // class FindMetadatumByIfdIdIdx + //! Container type to hold all metadata + typedef std::vector ExifMetadata; /*! @brief A container for Exif data. This is a top-level class of the %Exiv2 @@ -426,53 +429,8 @@ namespace Exiv2 { //! ExifMetadata const iterator type typedef ExifMetadata::const_iterator const_iterator; - //! @name Creators - //@{ - //! Default constructor - ExifData(); - //! Copy constructor (Todo: copy image data also) - ExifData(const ExifData& rhs); - //! Destructor - ~ExifData(); - //@} - //! @name Manipulators //@{ - //! Assignment operator (Todo: assign image data also) - ExifData& operator=(const ExifData& rhs); - /*! - @brief Load the Exif data from a byte buffer. The data buffer - must start with the TIFF header. This method is deprecated. - Use ImageFactory::open() instead. - @param buf Pointer to the data buffer to read from - @param len Number of bytes in the data buffer - @return 0 if successful. - */ - int load(const byte* buf, long len); - /*! - @brief Write the Exif data to a data buffer, which is returned. The - caller owns this copy and %DataBuf ensures that it will be - deleted. The copied data starts with the TIFF header. - - Tries to update the original data buffer and write it back with - minimal changes, in a 'non-intrusive' fashion, if possible. In this - case, tag data that ExifData does not understand stand a good chance - to remain valid. (In particular, if the Exif data contains a - Makernote in IFD format, the offsets in its IFD will remain valid.) -
- If 'non-intrusive' writing is not possible, the Exif data will be - re-built from scratch, in which case the absolute position of the - metadata entries within the data buffer may (and in most cases will) - be different from their original position. Furthermore, in this case, - the Exif data is updated with the metadata from the actual thumbnail - image (overriding existing metadata). - - @note If there is no Exif data to write, the buffer is empty, i.e., - no TIFF header is written in this case. - - @return A %DataBuf containing the Exif data. - */ - DataBuf copy(); /*! @brief Returns a reference to the %Exifdatum that is associated with a particular \em key. If %ExifData does not already contain such @@ -482,15 +440,6 @@ namespace Exiv2 { member function. */ Exifdatum& operator[](const std::string& key); - /*! - @brief Add all (IFD) entries in the range from iterator position begin - to iterator position end to the Exif metadata. No duplicate - checks are performed, i.e., it is possible to add multiple - metadata with the same key. - */ - void add(Entries::const_iterator begin, - Entries::const_iterator end, - ByteOrder byteOrder); /*! @brief Add an Exifdatum from the supplied key and value pair. This method copies (clones) key and value. No duplicate checks are @@ -520,8 +469,6 @@ namespace Exiv2 { 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 @@ -531,98 +478,6 @@ namespace Exiv2 { iterator to it. */ iterator findKey(const ExifKey& key); - /*! - @brief Find the first Exifdatum with the given \em ifdId and \em idx, - return an iterator to it. - - This method can be used to uniquely identify an exifdatum that was - created from an IFD or from the makernote (with idx greater than - 0). Metadata created by an application (not read from an IFD or a - makernote) all have their idx field set to 0, i.e., they cannot be - uniquely identified with this method. - */ - iterator findIfdIdIdx(IfdId ifdId, int idx); - /*! - @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); - /*! - @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); - /*! - @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., IFD1 metadata. - - @return The number of bytes of thumbnail data erased from the original - Exif data. Note that the original image size may differ from - the size of the image after deleting the thumbnail by more - than this number. This is the case if the Exif data contains - extra bytes (often at the end of the Exif block) or gaps and - the thumbnail is not located at the end of the Exif block so - that non-intrusive writing of a truncated Exif block is not - possible. Instead it is in this case necessary to write the - Exif data, without the thumbnail, from the metadata and all - extra bytes and gaps are lost, resulting in a smaller image. - */ - long eraseThumbnail(); //@} //! @name Accessors @@ -636,215 +491,73 @@ namespace Exiv2 { iterator to it. */ const_iterator findKey(const ExifKey& key) const; - /*! - @brief Find the first Exifdatum with the given \em ifdId and \em idx, - return an iterator to it. - - This method can be used to uniquely identify a Exifdatum that was - created from an IFD or from the makernote (with idx greater than - 0). Metadata created by an application (not read from an IFD or a - makernote) all have their idx field set to 0, i.e., they cannot be - uniquely identified with this method. - */ - const_iterator findIfdIdIdx(IfdId ifdId, int idx) 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()); } - /*! - @brief Returns the byte order. Default is little endian. - */ - ByteOrder byteOrder() 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. - This will overwrite an existing file of the same name. - - @param path Path of the filename without image type extension - - @throw Error if writing to the file fails. - - @return 0 if successful;
- 8 if the Exif data does not contain a thumbnail. - */ - int writeThumbnail(const std::string& path) const; - /*! - @brief Return the thumbnail image in a %DataBuf. The caller owns the - data buffer and %DataBuf ensures that it will be deleted. - */ - DataBuf copyThumbnail() const; - /*! - @brief Return a short string describing the format of the Exif - thumbnail ("TIFF", "JPEG"). - */ - const char* thumbnailFormat() const; - /*! - @brief Return the file extension for the Exif thumbnail depending - on the format (".tif", ".jpg"). - */ - const char* thumbnailExtension() const; - /*! - @brief Return a thumbnail object of the correct type, corresponding to - the current Exif data. Caller owns this object and the auto - pointer ensures that it will be deleted. - */ - Thumbnail::AutoPtr getThumbnail() const; //@} private: - //! @name Manipulators - //@{ - /*! - @brief Read the thumbnail from the data buffer. Assigns the thumbnail - data area with the appropriate Exif tags. Return 0 if successful, - i.e., if there is a thumbnail. - */ - int readThumbnail(); - /*! - @brief Check if the metadata changed and update the internal IFDs and - the MakerNote if the changes are compatible with the existing - data (non-intrusive write support). - - @return True if only compatible changes were detected in the metadata - and the internal IFDs and MakerNote (and thus the data buffer) - were updated successfully. Return false, if non-intrusive - writing is not possible. The internal IFDs and the MakerNote - (and thus the data buffer) may or may not be modified in this - case. - */ - bool updateEntries(); - /*! - @brief Update the metadata for a range of entries. Called by - updateEntries() for each of the internal IFDs and the MakerNote - (if any). - */ - bool updateRange(const Entries::iterator& begin, - const Entries::iterator& end, - ByteOrder byteOrder); - /*! - @brief Write the Exif data to a data buffer the hard way, return the - data buffer. The caller owns this data buffer and %DataBuf - ensures that it will be deleted. - - Rebuilds the Exif data from scratch, using the TIFF header, metadata - container and thumbnail. In particular, the internal IFDs and the - original data buffer are not used. Furthermore, this method updates - the Exif data with the metadata from the actual thumbnail image - (overriding existing metadata). - - @return A %DataBuf containing the Exif data. - */ - DataBuf copyFromMetadata(); - //@} - - //! @name Accessors - //@{ - /*! - @brief Check if the metadata is compatible with the internal IFDs for - non-intrusive writing. Return true if compatible, false if not. - - @note This function does not detect deleted metadata as incompatible, - although the deletion of metadata is not (yet) a supported - non-intrusive write operation. - */ - bool compatible() const; - /*! - @brief Find the IFD or makernote entry corresponding to ifd id and idx. - - @return A pair of which the first part determines if a match was found - and, if true, the second contains an iterator to the entry. - */ - std::pair - findEntry(IfdId ifdId, int idx) const; - //! Return a pointer to the internal IFD identified by its IFD id - const Ifd* getIfd(IfdId ifdId) const; - /*! - @brief Check if IFD1, the IFD1 data and thumbnail data are located at - the end of the Exif data. Return true, if they are or if there - is no thumbnail at all, else return false. - */ - bool stdThumbPosition() const; - //@} - // DATA ExifMetadata exifMetadata_; - // The pointers below are used only if Exif data is read from a - // raw data buffer - TiffHeader* pTiffHeader_; //! Pointer to the TIFF header - Ifd* pIfd0_; //! Pointer to Ifd0 - Ifd* pExifIfd_; //! Pointer to ExifIfd - Ifd* pIopIfd_; //! Pointer to IopIfd - Ifd* pGpsIfd_; //! Pointer to GpsIfd - Ifd* pIfd1_; //! Pointer to Ifd1 - MakerNote* pMakerNote_; //! Pointer to the MakerNote, if any - - long size_; //!< Size of the Exif raw data in bytes - byte* pData_; //!< Exif raw data buffer - - /*! - Can be set to false to indicate that non-intrusive writing is not - possible. If it is true (the default), then the compatibility checks - will be performed to determine which writing method to use. - */ - bool compatible_; - }; // class ExifData -// ***************************************************************************** -// template, inline and free functions - - template - Exifdatum& setValue(Exifdatum& exifDatum, const T& value) - { - std::auto_ptr > v - = std::auto_ptr >(new ValueType); - v->value_.push_back(value); - exifDatum.value_ = v; - return exifDatum; - } - /*! - @brief Returns the IfdId of the first Exif makernote tag it finds in the - Exif metadata or ifdIdNotSet if there is no Exif makernote tag. - */ - IfdId hasMakerNote(const ExifData& exifData); - /*! - @brief Add all metadata in the range from iterator position begin to - iterator position end, which have an IFD id matching that of the - IFD to the list of directory entries of ifd. No duplicate checks - are performed, i.e., it is possible to add multiple metadata with - the same key to an IFD. - */ - void addToIfd(Ifd& ifd, - ExifMetadata::const_iterator begin, - ExifMetadata::const_iterator end, - ByteOrder byteOrder); - /*! - @brief Add the Exifdatum to the IFD. No duplicate checks are performed, - i.e., it is possible to add multiple metadata with the same key to - an IFD. - */ - void addToIfd(Ifd& ifd, const Exifdatum& exifdatum, ByteOrder byteOrder); /*! - @brief Add all metadata in the range from iterator position begin to - iterator position end with IFD id 'makerIfd' to the list of - makernote entries of the object pointed to be makerNote. No - duplicate checks are performed, i.e., it is possible to add - multiple metadata with the same key to a makernote. + @brief Stateless parser class for Exif data. Images use this class to + decode and encode binary Exif data. See class TiffParser for details. */ - void addToMakerNote(MakerNote* makerNote, - ExifMetadata::const_iterator begin, - ExifMetadata::const_iterator end, - ByteOrder byteOrder); - /*! - @brief Add the Exifdatum to makerNote, encoded in byte order byteOrder. - No duplicate checks are performed, i.e., it is possible to add - multiple metadata with the same key to a makernote. - */ - void addToMakerNote(MakerNote* makerNote, - const Exifdatum& exifdatum, - ByteOrder byteOrder); + class ExifParser { + public: + /*! + @brief Decode metadata from a buffer \em pData of length \em size + with binary Exif data to the provided metadata container. + Return byte order in which the data is encoded. + See TiffParser::decode(). + */ + static ByteOrder decode( + ExifData& exifData, + const byte* pData, + uint32_t size + ); + /*! + @brief Encode metadata from the provided metadata to Exif format. + See TiffParser::encode(). + */ + 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. + See TiffParser::encode(). + + Encode Exif metadata from the \em ExifData container to binary 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). + */ + static void encode( + Blob& blob, + ByteOrder byteOrder, + const ExifData& exifData + ) + { + encode(blob, 0, 0, byteOrder, exifData); + } + + }; // class ExifParser } // namespace Exiv2 diff --git a/src/fujimn.cpp b/src/fujimn.cpp index 2c22d879..9883a10f 100644 --- a/src/fujimn.cpp +++ b/src/fujimn.cpp @@ -35,7 +35,6 @@ EXIV2_RCSID("@(#) $Id$") // included header files #include "types.hpp" #include "fujimn.hpp" -#include "makernote.hpp" #include "value.hpp" #include "i18n.h" // NLS support. @@ -50,15 +49,6 @@ EXIV2_RCSID("@(#) $Id$") // class member definitions namespace Exiv2 { - //! @cond IGNORE - FujiMakerNote::RegisterMn::RegisterMn() - { - MakerNoteFactory::registerMakerNote("FUJIFILM", "*", createFujiMakerNote); - MakerNoteFactory::registerMakerNote( - fujiIfdId, MakerNote::AutoPtr(new FujiMakerNote)); - } - //! @endcond - //! OffOn, multiple tags extern const TagDetails fujiOffOn[] = { { 0, N_("Off") }, @@ -293,81 +283,4 @@ namespace Exiv2 { return tagInfo_; } - FujiMakerNote::FujiMakerNote(bool alloc) - : IfdMakerNote(fujiIfdId, alloc) - { - byteOrder_ = littleEndian; - absShift_ = false; - byte buf[] = { - 'F', 'U', 'J', 'I', 'F', 'I', 'L', 'M', 0x0c, 0x00, 0x00, 0x00 - }; - readHeader(buf, 12, byteOrder_); - } - - FujiMakerNote::FujiMakerNote(const FujiMakerNote& rhs) - : IfdMakerNote(rhs) - { - } - - int FujiMakerNote::readHeader(const byte* buf, - long len, - ByteOrder /*byteOrder*/) - { - if (len < 12) return 1; - - header_.alloc(12); - std::memcpy(header_.pData_, buf, header_.size_); - // Read offset to the IFD relative to the start of the makernote - // from the header. Note that we ignore the byteOrder paramter - start_ = getUShort(header_.pData_ + 8, byteOrder_); - return 0; - } - - int FujiMakerNote::checkHeader() const - { - int rc = 0; - // Check the FUJIFILM prefix - if ( header_.size_ < 12 - || std::string(reinterpret_cast(header_.pData_), 8) - != std::string("FUJIFILM", 8)) { - rc = 2; - } - return rc; - } - - FujiMakerNote::AutoPtr FujiMakerNote::create(bool alloc) const - { - return AutoPtr(create_(alloc)); - } - - FujiMakerNote* FujiMakerNote::create_(bool alloc) const - { - AutoPtr makerNote(new FujiMakerNote(alloc)); - assert(makerNote.get() != 0); - makerNote->readHeader(header_.pData_, header_.size_, byteOrder_); - return makerNote.release(); - } - - FujiMakerNote::AutoPtr FujiMakerNote::clone() const - { - return AutoPtr(clone_()); - } - - FujiMakerNote* FujiMakerNote::clone_() const - { - return new FujiMakerNote(*this); - } - -// ***************************************************************************** -// free functions - - MakerNote::AutoPtr createFujiMakerNote(bool alloc, - const byte* /*buf*/, - long /*len*/, - ByteOrder /*byteOrder*/, - long /*offset*/) - { - return MakerNote::AutoPtr(new FujiMakerNote(alloc)); - } - } // namespace Exiv2 diff --git a/src/fujimn.hpp b/src/fujimn.hpp index 6cfc7ced..1823e6d7 100644 --- a/src/fujimn.hpp +++ b/src/fujimn.hpp @@ -37,111 +37,27 @@ // ***************************************************************************** // included header files -#include "types.hpp" -#include "makernote.hpp" #include "tags.hpp" -// + standard includes -#include -#include -#include - // ***************************************************************************** // namespace extensions namespace Exiv2 { -// ***************************************************************************** -// class declarations - class Value; - -// ***************************************************************************** -// free functions - - /*! - @brief Return an auto-pointer to a newly created empty MakerNote - initialized to operate in the memory management model indicated. - The caller owns this copy and the auto-pointer ensures that it - will be deleted. - - @param alloc Memory management model for the new MakerNote. Determines if - memory required to store data should be allocated and deallocated - (true) or not (false). If false, only pointers to the buffer - provided to read() will be kept. See Ifd for more background on - this concept. - @param buf Pointer to the makernote character buffer (not used). - @param len Length of the makernote character buffer (not used). - @param byteOrder Byte order in which the Exif data (and possibly the - makernote) is encoded (not used). - @param offset Offset from the start of the TIFF header of the makernote - buffer (not used). - - @return An auto-pointer to a newly created empty MakerNote. The caller - owns this copy and the auto-pointer ensures that it will be - deleted. - */ - MakerNote::AutoPtr createFujiMakerNote(bool alloc, - const byte* buf, - long len, - ByteOrder byteOrder, - long offset); - // ***************************************************************************** // class definitions //! MakerNote for Fujifilm cameras - class FujiMakerNote : public IfdMakerNote { + class FujiMakerNote { public: - //! Shortcut for a %FujiMakerNote auto pointer. - typedef std::auto_ptr AutoPtr; - - //! @name Creators - //@{ - /*! - @brief Constructor. Allows to choose whether or not memory management - is required for the makernote entries. - */ - FujiMakerNote(bool alloc =true); - //! Copy constructor - FujiMakerNote(const FujiMakerNote& rhs); - //! Virtual destructor - virtual ~FujiMakerNote() {} - //@} - - //! @name Manipulators - //@{ - int readHeader(const byte* buf, - long len, - ByteOrder byteOrder); - //@} - - //! @name Accessors - //@{ - int checkHeader() const; - AutoPtr create(bool alloc =true) const; - AutoPtr clone() const; //! Return read-only list of built-in Fujifilm tags static const TagInfo* tagList(); - //@} - - //! @cond IGNORE - // Public only so that we can create a static instance - struct RegisterMn { - RegisterMn(); - }; - //! @endcond private: - //! Internal virtual create function. - FujiMakerNote* create_(bool alloc =true) const; - //! Internal virtual copy constructor. - FujiMakerNote* clone_() const; - //! Tag information static const TagInfo tagInfo_[]; }; // class FujiMakerNote - static FujiMakerNote::RegisterMn registerFujiMakerNote; } // namespace Exiv2 #endif // #ifndef FUJIMN_HPP_ diff --git a/src/ifd.cpp b/src/ifd.cpp deleted file mode 100644 index 8e33d501..00000000 --- a/src/ifd.cpp +++ /dev/null @@ -1,788 +0,0 @@ -// ***************************************************************** -*- C++ -*- -/* - * Copyright (C) 2004-2008 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: ifd.cpp - Version: $Rev$ - Author(s): Andreas Huggel (ahu) - History: 26-Jan-04, ahu: created - 11-Feb-04, ahu: isolated as a component - */ -// ***************************************************************************** -#include "rcsid.hpp" -EXIV2_RCSID("@(#) $Id$") - -// ***************************************************************************** -// included header files -#include "ifd.hpp" -#include "types.hpp" -#include "error.hpp" -#include "tags.hpp" // for ExifTags::ifdName -#include "i18n.h" // NLS support. - -// + standard includes -#include -#include -#include -#include -#include -#include -#include - -// ***************************************************************************** -// class member definitions -namespace Exiv2 { - - Entry::Entry(bool alloc) - : alloc_(alloc), ifdId_(ifdIdNotSet), idx_(0), - tag_(0), type_(0), count_(0), offset_(0), size_(0), pData_(0), - sizeDataArea_(0), pDataArea_(0), byteOrder_(invalidByteOrder) - { - } - - Entry::~Entry() - { - if (alloc_) { - delete[] pData_; - delete[] pDataArea_; - } - } - - Entry::Entry(const Entry& rhs) - : alloc_(rhs.alloc_), ifdId_(rhs.ifdId_), idx_(rhs.idx_), - tag_(rhs.tag_), type_(rhs.type_), - count_(rhs.count_), offset_(rhs.offset_), size_(rhs.size_), pData_(0), - sizeDataArea_(rhs.sizeDataArea_), pDataArea_(0), byteOrder_(rhs.byteOrder_) - { - if (alloc_) { - if (rhs.pData_) { - pData_ = new byte[rhs.size()]; - std::memcpy(pData_, rhs.pData_, rhs.size()); - } - if (rhs.pDataArea_) { - pDataArea_ = new byte[rhs.sizeDataArea()]; - std::memcpy(pDataArea_, rhs.pDataArea_, rhs.sizeDataArea()); - } - } - else { - pData_ = rhs.pData_; - pDataArea_ = rhs.pDataArea_; - } - } - - Entry& Entry::operator=(const Entry& rhs) - { - if (this == &rhs) return *this; - alloc_ = rhs.alloc_; - ifdId_ = rhs.ifdId_; - idx_ = rhs.idx_; - tag_ = rhs.tag_; - type_ = rhs.type_; - count_ = rhs.count_; - offset_ = rhs.offset_; - size_ = rhs.size_; - sizeDataArea_ = rhs.sizeDataArea_; - byteOrder_ = rhs.byteOrder_; - if (alloc_) { - delete[] pData_; - pData_ = 0; - if (rhs.pData_) { - pData_ = new byte[rhs.size()]; - std::memcpy(pData_, rhs.pData_, rhs.size()); - } - delete[] pDataArea_; - pDataArea_ = 0; - if (rhs.pDataArea_) { - pDataArea_ = new byte[rhs.sizeDataArea()]; - std::memcpy(pDataArea_, rhs.pDataArea_, rhs.sizeDataArea()); - } - } - else { - pData_ = rhs.pData_; - pDataArea_ = rhs.pDataArea_; - } - return *this; - } // Entry::operator= - - void Entry::setValue(uint32_t data, ByteOrder byteOrder) - { - if (pData_ == 0 || size_ < 4) { - assert(alloc_); - size_ = 4; - delete[] pData_; - pData_ = new byte[size_]; - } - ul2Data(pData_, data, byteOrder); - // do not change size_ - type_ = unsignedLong; - count_ = 1; - } - - void Entry::setValue(uint16_t type, uint32_t count, const byte* buf, long len, ByteOrder byteOrder) - { - byteOrder_ = byteOrder; - long dataSize = count * TypeInfo::typeSize(TypeId(type)); - // No minimum size requirement, but make sure the buffer can hold the data - if (len < dataSize) throw Error(24, tag(), dataSize, len); - if (alloc_) { - delete[] pData_; - pData_ = new byte[len]; - std::memset(pData_, 0x0, len); - std::memcpy(pData_, buf, dataSize); - size_ = len; - } - else { - if (size_ == 0) { - // Set the data pointer of a virgin entry - pData_ = const_cast(buf); - size_ = len; - } - else { - // Overwrite existing data if it fits into the buffer - if (size_ < dataSize) throw Error(24, tag(), dataSize, size_); - std::memset(pData_, 0x0, size_); - std::memcpy(pData_, buf, dataSize); - // do not change size_ - } - } - type_ = type; - count_ = count; - } // Entry::setValue - - void Entry::setDataArea(const byte* buf, long len) - { - if (alloc_) { - delete[] pDataArea_; - pDataArea_ = new byte[len]; - std::memcpy(pDataArea_, buf, len); - sizeDataArea_ = len; - } - else { - if (sizeDataArea_ == 0) { - // Set the data area pointer of a virgin entry - pDataArea_ = const_cast(buf); - sizeDataArea_ = len; - } - else { - // Overwrite existing data if it fits into the buffer - if (sizeDataArea_ < len) { - throw Error(25, tag(), sizeDataArea_, len); - } - std::memset(pDataArea_, 0x0, sizeDataArea_); - std::memcpy(pDataArea_, buf, len); - // do not change sizeDataArea_ - } - } - } // Entry::setDataArea - - void Entry::setDataAreaOffsets(uint32_t offset, ByteOrder byteOrder) - { - // Hack: Do not require offsets to start from 0, except for rationals - uint16_t fusOffset = 0; - uint32_t fulOffset = 0; - int16_t fsOffset = 0; - int32_t flOffset = 0; - - for (uint32_t i = 0; i < count(); ++i) { - byte* buf = pData_ + i * typeSize(); - switch(TypeId(type())) { - case unsignedShort: { - if (i == 0) fusOffset = getUShort(buf, byteOrder); - uint16_t d = getUShort(buf, byteOrder) - fusOffset; - if (d + offset > 0xffff) throw Error(26); - us2Data(buf, d + static_cast(offset), byteOrder); - break; - } - case unsignedLong: { - if (i == 0) fulOffset = getULong(buf, byteOrder); - ul2Data(buf, getULong(buf, byteOrder) - fulOffset + offset, byteOrder); - break; - } - case unsignedRational: { - URational d = getURational(buf, byteOrder); - d.first = d.first + offset * d.second; - ur2Data(buf, d, byteOrder); - break; - } - case signedShort: { - if (i == 0) fsOffset = getShort(buf, byteOrder); - int16_t d = getShort(buf, byteOrder) - fsOffset; - if (d + static_cast(offset) > 0xffff) throw Error(26); - s2Data(buf, d + static_cast(offset), byteOrder); - break; - } - case signedLong: { - if (i == 0) flOffset = getLong(buf, byteOrder); - int32_t d = getLong(buf, byteOrder) - flOffset; - l2Data(buf, d + static_cast(offset), byteOrder); - break; - } - case signedRational: { - Rational d = getRational(buf, byteOrder); - d.first = d.first + static_cast(offset) * d.second; - r2Data(buf, d, byteOrder); - break; - } - default: - throw Error(27); - break; - } - } - } // Entry::setDataAreaOffsets - - void Entry::updateBase(byte* pOldBase, byte* pNewBase) - { - if (!alloc_) { - if (pDataArea_) { - pDataArea_ = pDataArea_ - pOldBase + pNewBase; - } - if (pData_) { - pData_ = pData_ - pOldBase + pNewBase; - } - } - } // Entry::updateBase - - const byte* Entry::component(uint32_t n) const - { - if (n >= count()) return 0; - return data() + n * typeSize(); - } // Entry::component - - Ifd::Ifd(IfdId ifdId) - : alloc_(true), ifdId_(ifdId), pBase_(0), offset_(0), - dataOffset_(0), hasNext_(true), pNext_(0), next_(0) - { - pNext_ = new byte[4]; - std::memset(pNext_, 0x0, 4); - } - - Ifd::Ifd(IfdId ifdId, long offset) - : alloc_(true), ifdId_(ifdId), pBase_(0), offset_(offset), - dataOffset_(0), hasNext_(true), pNext_(0), next_(0) - { - pNext_ = new byte[4]; - std::memset(pNext_, 0x0, 4); - } - - Ifd::Ifd(IfdId ifdId, long offset, bool alloc, bool hasNext) - : alloc_(alloc), ifdId_(ifdId), pBase_(0), offset_(offset), - dataOffset_(0), hasNext_(hasNext), pNext_(0), next_(0) - { - if (alloc_ && hasNext_) { - pNext_ = new byte[4]; - std::memset(pNext_, 0x0, 4); - } - } - - Ifd::~Ifd() - { - // do not delete pBase_ - if (alloc_ && hasNext_) delete[] pNext_; - } - - Ifd::Ifd(const Ifd& rhs) - : alloc_(rhs.alloc_), entries_(rhs.entries_), ifdId_(rhs.ifdId_), - pBase_(rhs.pBase_), offset_(rhs.offset_), dataOffset_(rhs.dataOffset_), - hasNext_(rhs.hasNext_), pNext_(rhs.pNext_), next_(rhs.next_) - { - if (alloc_ && hasNext_) { - pNext_ = new byte[4]; - std::memset(pNext_, 0x0, 4); - if (rhs.pNext_) std::memcpy(pNext_, rhs.pNext_, 4); - } - } - - int Ifd::read(const byte* buf, - long len, - long start, - ByteOrder byteOrder, - long shift) - { - int rc = 0; - long o = start; - Ifd::PreEntries preEntries; - - if (o < 0 || len < o + 2) { -#ifndef SUPPRESS_WARNINGS - std::cerr << "Error: " << ExifTags::ifdName(ifdId_) - << " lies outside of the IFD memory buffer.\n"; -#endif - rc = 6; - } - int n = 0; - if (rc == 0) { - offset_ = start - shift; - n = getUShort(buf + o, byteOrder); - o += 2; - // Sanity check with an "unreasonably" large number - if (n > 256) { -#ifndef SUPPRESS_WARNINGS - std::cerr << "Error: " - << "Directory " << ExifTags::ifdName(ifdId_) << " with " - << n << " entries considered invalid; not read.\n"; -#endif - rc = 6; - } - } - if (rc == 0) { - for (int i = 0; i < n; ++i) { - if (len < o + 12) { -#ifndef SUPPRESS_WARNINGS - std::cerr << "Error: " << ExifTags::ifdName(ifdId_) - << " entry " << i - << " lies outside of the IFD memory buffer.\n"; -#endif - rc = 6; - break; - } - Ifd::PreEntry pe; - pe.tag_ = getUShort(buf + o, byteOrder); - pe.type_ = getUShort(buf + o + 2, byteOrder); - pe.count_ = getULong(buf + o + 4, byteOrder); - uint32_t ts = TypeInfo::typeSize(TypeId(pe.type_)); - if (pe.count_ >= 0x10000000) { -#ifndef SUPPRESS_WARNINGS - std::cerr << "Warning: " - << ExifTags::ifdName(ifdId_) << " tag 0x" - << std::setw(4) << std::setfill('0') << std::hex - << pe.tag_ << " has invalid size " - << std::dec << pe.count_ << "*" << ts - << "; truncating the data.\n"; -#endif - pe.count_ = 0; - } - pe.size_ = pe.count_ * ts; - pe.offsetLoc_ = o + 8 - shift; - pe.offset_ = pe.size_ > 4 ? getLong(buf + o + 8, byteOrder) : 0; - preEntries.push_back(pe); - o += 12; - } - } - if (rc == 0 && hasNext_) { - if (len < o + 4) { -#ifndef SUPPRESS_WARNINGS - std::cerr << "Error: " << ExifTags::ifdName(ifdId_) - << " memory of the pointer to the next IFD" - << " lies outside of the IFD memory buffer.\n"; -#endif - rc = 6; - } - else { - if (alloc_) { - std::memcpy(pNext_, buf + o, 4); - } - else { - pNext_ = const_cast(buf + o); - } - next_ = getULong(buf + o, byteOrder); - if ( static_cast(next_) + shift < 0 - || static_cast(next_) + shift >= len) { -#ifndef SUPPRESS_WARNINGS - std::cerr << "Warning: " << ExifTags::ifdName(ifdId_) - << ": Pointer to next IFD is out of bounds; ignored.\n"; -#endif - next_ = 0; - } - } - } - // Set the offset of the first data entry outside of the IFD. - if (rc == 0 && preEntries.size() > 0) { - // Find the entry with the smallest offset - Ifd::PreEntries::const_iterator i = std::min_element( - preEntries.begin(), preEntries.end(), cmpPreEntriesByOffset); - // Only do something if there is at least one entry with data - // outside the IFD directory itself. - if (i->size_ > 4) { - // Set the offset of the first data entry outside of the IFD - if (i->offset_ + shift < 0) { -#ifndef SUPPRESS_WARNINGS - std::cerr << "Error: Offset of the 1st data entry of " - << ExifTags::ifdName(ifdId_) - << " is out of bounds:\n" - << " Offset = 0x" << std::setw(8) - << std::setfill('0') << std::hex - << i->offset_ - offset_ // relative to start of IFD - << ", is before start of buffer by " - << std::dec << -1 * (i->offset_ + shift) - << " Bytes\n"; -#endif - rc = 6; - } - else if (i->offset_ + shift + i->size_ > len) { -#ifndef SUPPRESS_WARNINGS - std::cerr << "Error: Upper boundary of the 1st data entry of " - << ExifTags::ifdName(ifdId_) - << " is out of bounds:\n" - << " Offset = 0x" << std::setw(8) - << std::setfill('0') << std::hex - << i->offset_ - offset_ // relative to start of IFD - << ", exceeds buffer size by " - << std::dec << i->offset_ + shift + i->size_ - len - << " Bytes\n"; -#endif - rc = 6; - } - else { - dataOffset_ = i->offset_; - } - } - } - // Convert the pre-IFD entries to the actual entries, assign the data - // to each IFD entry and calculate relative offsets, relative to the - // start of the IFD - if (rc == 0) { - entries_.clear(); - int idx = 0; - const Ifd::PreEntries::iterator begin = preEntries.begin(); - const Ifd::PreEntries::iterator end = preEntries.end(); - for (Ifd::PreEntries::iterator i = begin; i != end; ++i) { - Entry e(alloc_); - e.setIfdId(ifdId_); - e.setIdx(++idx); - e.setTag(i->tag_); - long tmpOffset = // still from the start of the TIFF header - i->size_ > 4 ? i->offset_ : i->offsetLoc_; - if (tmpOffset + shift + i->size_ > len) { -#ifndef SUPPRESS_WARNINGS - std::cerr << "Warning: Upper boundary of data for " - << ExifTags::ifdName(ifdId_) - << " entry " << static_cast(i - begin) - << " is out of bounds:\n" - << " Offset = 0x" << std::setw(8) - << std::setfill('0') << std::hex - << tmpOffset - offset_ // relative to start of IFD - << ", size = " << std::dec << i->size_ - << ", exceeds buffer size by " - << tmpOffset + shift + i->size_ - len - << " Bytes; Truncating the data.\n"; -#endif - // Truncate the entry - i->size_ = 0; - i->count_ = 0; - tmpOffset = i->offsetLoc_; - } - // Set the offset to the data, relative to start of IFD - e.setOffset(tmpOffset - offset_); - // Set the size to at least for bytes to accomodate offset-data -#ifndef SUPPRESS_WARNINGS - if (i->type_ < 1 || i->type_ > 10) { - std::cerr << "Warning: " - << ExifTags::ifdName(ifdId_) << " tag 0x" - << std::setw(4) << std::setfill('0') << std::hex - << i->tag_ << " has invalid Exif type " - << std::dec << i->type_ - << "; using 7 (undefined).\n"; - } -#endif - e.setValue(i->type_, i->count_, buf + start + e.offset(), - std::max(long(4), i->size_)); - this->add(e); - } - } - if (!alloc_) pBase_ = const_cast(buf); - if (rc) this->clear(); - - return rc; - } // Ifd::read - - Ifd::const_iterator Ifd::findIdx(int idx) const - { - return std::find_if(entries_.begin(), entries_.end(), - FindEntryByIdx(idx)); - } - - Ifd::iterator Ifd::findIdx(int idx) - { - return std::find_if(entries_.begin(), entries_.end(), - FindEntryByIdx(idx)); - } - - Ifd::const_iterator Ifd::findTag(uint16_t tag) const - { - return std::find_if(entries_.begin(), entries_.end(), - FindEntryByTag(tag)); - } - - Ifd::iterator Ifd::findTag(uint16_t tag) - { - return std::find_if(entries_.begin(), entries_.end(), - FindEntryByTag(tag)); - } - - void Ifd::sortByTag() - { - std::sort(entries_.begin(), entries_.end(), cmpEntriesByTag); - } - - int Ifd::readSubIfd( - Ifd& dest, const byte* buf, long len, ByteOrder byteOrder, uint16_t tag - ) const - { - int rc = 0; - const_iterator pos = findTag(tag); - if (pos != entries_.end()) { - long offset = getULong(pos->data(), byteOrder); - if (len < offset) { - rc = 6; - } - else { - rc = dest.read(buf, len, offset, byteOrder); - } - } - return rc; - } // Ifd::readSubIfd - - long Ifd::copy(byte* buf, ByteOrder byteOrder, long offset) - { - if (entries_.size() == 0 && next_ == 0) return 0; - if (offset != 0) offset_ = offset; - - // Add the number of entries to the data buffer - us2Data(buf, static_cast(entries_.size()), byteOrder); - long o = 2; - - // Add all directory entries to the data buffer - long dataSize = 0; - long dataAreaSize = 0; - long totalDataSize = 0; - const iterator b = entries_.begin(); - const iterator e = entries_.end(); - iterator i; - for (i = b; i != e; ++i) { - if (i->size() > 4) { - totalDataSize += i->size(); - } - } - for (i = b; i != e; ++i) { - us2Data(buf + o, i->tag(), byteOrder); - us2Data(buf + o + 2, i->type(), byteOrder); - ul2Data(buf + o + 4, i->count(), byteOrder); - if (i->sizeDataArea() > 0) { - long dataAreaOffset = offset_+size()+totalDataSize+dataAreaSize; - i->setDataAreaOffsets(dataAreaOffset, byteOrder); - dataAreaSize += i->sizeDataArea(); - } - if (i->size() > 4) { - // Set the offset of the entry, data immediately follows the IFD - i->setOffset(size() + dataSize); - l2Data(buf + o + 8, offset_ + i->offset(), byteOrder); - dataSize += i->size(); - } - else { - // Copy data into the offset field - std::memset(buf + o + 8, 0x0, 4); - std::memcpy(buf + o + 8, i->data(), i->size()); - } - o += 12; - } - - if (hasNext_) { - // Add the offset to the next IFD to the data buffer - if (pNext_) { - std::memcpy(buf + o, pNext_, 4); - } - else { - std::memset(buf + o, 0x0, 4); - } - o += 4; - } - - // Add the data of all IFD entries to the data buffer - for (i = b; i != e; ++i) { - if (i->size() > 4) { - std::memcpy(buf + o, i->data(), i->size()); - o += i->size(); - } - } - - // Add all data areas to the data buffer - for (i = b; i != e; ++i) { - if (i->sizeDataArea() > 0) { - std::memcpy(buf + o, i->dataArea(), i->sizeDataArea()); - o += i->sizeDataArea(); - } - } - - return o; - } // Ifd::copy - - void Ifd::clear() - { - entries_.clear(); - offset_ = 0; - dataOffset_ = 0; - if (hasNext_) { - if (alloc_) { - std::memset(pNext_, 0x0, 4); - } - else { - pBase_ = 0; - pNext_ = 0; - } - next_ = 0; - } - } // Ifd::clear - - void Ifd::setNext(uint32_t next, ByteOrder byteOrder) - { - if (hasNext_) { - assert(pNext_); - ul2Data(pNext_, next, byteOrder); - next_ = next; - } - } - - void Ifd::add(const Entry& entry) - { - assert(alloc_ == entry.alloc()); - assert(ifdId_ == entry.ifdId()); - // allow duplicates - entries_.push_back(entry); - } - - int Ifd::erase(uint16_t tag) - { - int idx = 0; - iterator pos = findTag(tag); - if (pos != end()) { - idx = pos->idx(); - erase(pos); - } - return idx; - } - - Ifd::iterator Ifd::erase(iterator pos) - { - return entries_.erase(pos); - } - - byte* Ifd::updateBase(byte* pNewBase) - { - byte *pOld = 0; - if (!alloc_) { - iterator end = this->end(); - for (iterator pos = begin(); pos != end; ++pos) { - pos->updateBase(pBase_, pNewBase); - } - if (hasNext_) { - pNext_ = pNext_ - pBase_ + pNewBase; - } - pOld = pBase_; - pBase_ = pNewBase; - } - return pOld; - } - - long Ifd::size() const - { - if (entries_.size() == 0 && next_ == 0) return 0; - return static_cast(2 + 12 * entries_.size() + (hasNext_ ? 4 : 0)); - } - - long Ifd::dataSize() const - { - long dataSize = 0; - const_iterator end = this->end(); - for (const_iterator i = begin(); i != end; ++i) { - if (i->size() > 4) dataSize += i->size(); - dataSize += i->sizeDataArea(); - } - return dataSize; - } - - void Ifd::print(std::ostream& os, const std::string& prefix) const - { - if (entries_.size() == 0) return; - // Print a header - os << prefix << _("IFD Offset") << ": 0x" - << std::setw(8) << std::setfill('0') << std::hex << std::right - << offset_ - << ", " << _("IFD Entries") << ": " - << std::setfill(' ') << std::dec << std::right - << static_cast(entries_.size()) << "\n" - << prefix << _("Entry Tag Format (Bytes each) Number Offset\n") - << prefix << "----- ------ --------------------- ------ -----------\n"; - // Print IFD entries - const const_iterator b = entries_.begin(); - const const_iterator e = entries_.end(); - const_iterator i = b; - for (; i != e; ++i) { - std::ostringstream offset; - if (i->size() > 4) { - offset << " 0x" << std::setw(8) << std::setfill('0') - << std::hex << std::right << static_cast(i->offset()); - } - else { - const byte* data = i->data(); - for (int k = 0; k < i->size(); ++k) { - offset << std::setw(2) << std::setfill('0') << std::hex - << (int)data[k] << " "; - } - } - os << prefix << std::setw(5) << std::setfill(' ') << std::dec - << std::right << static_cast(i - b) - << " 0x" << std::setw(4) << std::setfill('0') << std::hex - << std::right << i->tag() - << " " << std::setw(17) << std::setfill(' ') - << std::left << i->typeName() - << " (" << std::dec << i->typeSize() << ")" - << " " << std::setw(6) << std::setfill(' ') << std::dec - << std::right << i->count() - << " " << offset.str() - << "\n"; - } - if (hasNext_) { - os << prefix << _("Next IFD") << ": 0x" - << std::setw(8) << std::setfill('0') << std::hex - << std::right << next() << "\n"; - } - // Print data of IFD entries - for (i = b; i != e; ++i) { - if (i->size() > 4) { - os << _("Data of entry") << " " << static_cast(i - b) << ":\n"; - hexdump(os, i->data(), i->size(), offset_ + i->offset()); - } - } - - } // Ifd::print - - // ************************************************************************* - // free functions - - bool cmpEntriesByTag(const Entry& lhs, const Entry& rhs) - { - return lhs.tag() < rhs.tag(); - } - - bool cmpPreEntriesByOffset(const Ifd::PreEntry& lhs, const Ifd::PreEntry& rhs) - { - // We need to ignore entries with size <= 4, so by definition, - // entries with size <= 4 are greater than those with size > 4 - // when compared by their offset. - if (lhs.size_ <= 4) { - return false; // lhs is greater by definition, or they are equal - } - if (rhs.size_ <= 4) { - return true; // rhs is greater by definition (they cannot be equal) - } - return lhs.offset_ < rhs.offset_; - } // cmpPreEntriesByOffset - -} // namespace Exiv2 diff --git a/src/ifd.hpp b/src/ifd.hpp deleted file mode 100644 index ed415d2a..00000000 --- a/src/ifd.hpp +++ /dev/null @@ -1,616 +0,0 @@ -// ***************************************************************** -*- C++ -*- -/* - * Copyright (C) 2004-2008 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 ifd.hpp - @brief Encoding and decoding of IFD (%Image File Directory) data - @version $Rev$ - @author Andreas Huggel (ahu) - ahuggel@gmx.net - @date 09-Jan-04, ahu: created
- 11-Feb-04, ahu: isolated as a component - */ -#ifndef IFD_HPP_ -#define IFD_HPP_ - -// ***************************************************************************** -// included header files -#include "types.hpp" - -// + standard includes -#include -#include -#include - -// ***************************************************************************** -// namespace extensions -namespace Exiv2 { - -// ***************************************************************************** -// class declarations - class Ifd; - -// ***************************************************************************** -// class definitions - - /*! - @brief Data structure for one IFD directory entry. See the description of - class Ifd for an explanation of the supported modes for memory - allocation. - */ - class Entry { - public: - //! @name Creators - //@{ - /*! - @brief Default constructor. The entry allocates memory for its - data if alloc is true (the default), otherwise it remembers - just the pointers into a read and writeable data buffer which - it doesn't allocate or delete. - */ - explicit Entry(bool alloc =true); - //! Destructor - ~Entry(); - //! Copy constructor - Entry(const Entry& rhs); - //@} - - //! @name Manipulators - //@{ - //! Assignment operator - Entry& operator=(const Entry& rhs); - //! Set the tag - void setTag(uint16_t tag) { tag_ = tag; } - //! Set the IFD id - void setIfdId(IfdId ifdId) { ifdId_ = ifdId; } - //! Set the index (unique id of an entry within one IFD) - void setIdx(int idx) { idx_ = idx; } - //! Set the offset. The offset is relative to the start of the IFD. - void setOffset(long offset) { offset_ = offset; } - /*! - @brief Set the value of the entry to a single unsigned long component, - i.e., set the type of the entry to unsigned long, number of - components to one and the value according to the data provided. - - The size of the data buffer is set to at least four bytes, but is left - unchanged if it can accomodate the pointer. This method can be used - to set the value of a tag which contains a pointer (offset) to a - location in the Exif data (like e.g., ExifTag, 0x8769 in IFD0, which - contains a pointer to the Exif IFD). -
This method cannot be used to set the value of a newly created - %Entry in non-alloc mode. - - @note This method is now deprecated, use data area related methods - instead. - */ - void setValue(uint32_t data, ByteOrder byteOrder); - /*! - @brief Set type, count, the data buffer and its size. - - Copies the provided buffer when called in memory allocation mode. -
In non-alloc mode, use this method to initialise the data of a - newly created %Entry. In this case, only the pointer to the buffer is - copied, i.e., the buffer must remain valid throughout the life of the - %Entry. Subsequent calls in non-alloc mode will overwrite the data - pointed to by this pointer with the data provided, i.e., the buffer - provided in subsequent calls can be deleted after the call. -
In either memory allocation mode, the data buffer provided must be - large enough to hold count components of type. The size of the buffer - will be as indicated in the size argument. I.e., it is possible to - allocate (set) a data buffer larger than required to hold count - components of the given type. - - @param type The type of the data. - @param count Number of components in the buffer. - @param data Pointer to the data buffer. - @param size Size of the desired data buffer in bytes. - @param byteOrder Optional byte order. - @throw Error if no memory allocation is allowed - and the size of the data buffer is larger than the existing - data buffer of the entry or if size is not large enough to hold - count components of the given type. - */ - void setValue(uint16_t type, uint32_t count, const byte* data, long size, ByteOrder byteOrder =invalidByteOrder); - /*! - @brief Set the data area. Memory management as for - setValue(uint16_t, uint32_t, const byte*, long) - - For certain tags the regular value of an IFD entry is an offset to a - data area outside of the IFD. Examples are Exif tag 0x8769 in IFD0 - (Exif.Image.ExifTag) or tag 0x0201 in IFD1 - (Exif.Thumbnail.JPEGInterchangeFormat). The offset of ExifTag points - to a data area containing the Exif IFD. That of JPEGInterchangeFormat - contains the JPEG thumbnail image. - This method sets the data area of a tag in accordance with the memory - allocation mode. - - @param buf Pointer to the data area. - @param len Size of the data area. - - @throw Error in non-alloc mode, if there already is a dataarea but the - size of the existing dataarea is not large enough for the - new buffer. - */ - void setDataArea(const byte* buf, long len); - /*! - @brief Set the offset(s) to the data area of an entry. - - Add @em offset to each data component of the entry. This is used by - Ifd::copy to convert the data components of an entry containing - offsets relative to the data area to become offsets from the start of - the TIFF header. Usually, entries with a data area have exactly one - unsigned long data component, which is 0. - - @param offset Offset - @param byteOrder Byte order - - @throw Error if the offset is out of range for the data type of the - tag or the data type is not supported. - */ - void setDataAreaOffsets(uint32_t offset, ByteOrder byteOrder); - /*! - @brief Update the base pointer of the Entry from \em pOldBase - to \em pNewBase. - - Allows to re-locate the underlying data buffer to a new location - \em pNewBase. This method only has an effect in non-alloc mode. - - @param pOldBase Base pointer of the old data buffer - @param pNewBase Base pointer of the new data buffer - */ - void updateBase(byte* pOldBase, byte* pNewBase); - //@} - - //! @name Accessors - //@{ - //! Return the tag - uint16_t tag() const { return tag_; } - //! Return the type id. - uint16_t type() const { return type_; } - //! Return the name of the type - const char* typeName() const - { return TypeInfo::typeName(TypeId(type_)); } - //! Return the size in bytes of one element of this type - long typeSize() const - { return TypeInfo::typeSize(TypeId(type_)); } - //! Return the IFD id - IfdId ifdId() const { return ifdId_; } - //! Return the index (unique id >0 of an entry within an IFD, 0 if not set) - int idx() const { return idx_; } - //! Return the number of components in the value - uint32_t count() const { return count_; } - /*! - @brief Return the size of the data buffer in bytes. - @note There is no minimum size for the data buffer, except that it - must be large enough to hold the data. - */ - long size() const { return size_; } - //! Return the offset from the start of the IFD to the data of the entry - long offset() const { return offset_; } - /*! - @brief Return a pointer to the data buffer. Do not attempt to write - to this pointer. - */ - const byte* data() const { return pData_; } - /*! - @brief Return a pointer to the n-th component, 0 if there is no - n-th component. Do not attempt to write to this pointer. - */ - const byte* component(uint32_t n) const; - //! Get the memory allocation mode - bool alloc() const { return alloc_; } - //! Return the size of the data area. - long sizeDataArea() const { return sizeDataArea_; } - /*! - @brief Return a pointer to the data area. Do not attempt to write to - this pointer. - - For certain tags the regular value of an IFD entry is an offset to a - data area outside of the IFD. Examples are Exif tag 0x8769 in IFD0 - (Exif.Image.ExifTag) or tag 0x0201 in IFD1 - (Exif.Thumbnail.JPEGInterchangeFormat). The offset of ExifTag points - to a data area containing the Exif IFD. That of JPEGInterchangeFormat - contains the JPEG thumbnail image. - Use this method to access (read-only) the data area of a tag. Use - setDataArea() to write to the data area. - - @return Return a pointer to the data area. - */ - const byte* dataArea() const { return pDataArea_; } - /*! - @brief Return the byte order of the entry. There should generally - not be a need for this, it is only used in special cases - (Minolta Makernote CameraSettings tags). - */ - ByteOrder byteOrder() const { return byteOrder_; } - - //@} - - private: - // DATA - /*! - True: Requires memory allocation and deallocation,
- False: No memory management needed. - */ - bool alloc_; - //! Redundant IFD id (it is also at the IFD) - IfdId ifdId_; - //! Unique id of an entry within an IFD (0 if not set) - int idx_; - //! Tag - uint16_t tag_; - //! Type - uint16_t type_; - //! Number of components - uint32_t count_; - //! Offset from the start of the IFD to the data - long offset_; - /*! - Size of the data buffer holding the value in bytes, there is - no minimum size. - */ - long size_; - //! Pointer to the data buffer - byte* pData_; - //! Size of the data area - long sizeDataArea_; - //! Pointer to the data area - byte* pDataArea_; - //! Byte order (optional, only used for special cases) - ByteOrder byteOrder_; - - }; // class Entry - - //! Container type to hold all IFD directory entries - typedef std::vector Entries; - - //! Unary predicate that matches an Entry with a given index - class FindEntryByIdx { - public: - //! Constructor, initializes the object with the index to look for - FindEntryByIdx(int idx) : idx_(idx) {} - /*! - @brief Returns true if the idx of the argument entry is equal - to that of the object. - */ - bool operator()(const Entry& entry) const - { return idx_ == entry.idx(); } - - private: - int idx_; - - }; // class FindEntryByIdx - - //! Unary predicate that matches an Entry with a given tag - class FindEntryByTag { - public: - //! Constructor, initializes the object with the tag to look for - FindEntryByTag(uint16_t tag) : tag_(tag) {} - /*! - @brief Returns true if the tag of the argument entry is equal - to that of the object. - */ - bool operator()(const Entry& entry) const - { return tag_ == entry.tag(); } - - private: - uint16_t tag_; - - }; // class FindEntryByTag - - /*! - @brief Models an IFD (%Image File Directory) - - This class models an IFD as described in the TIFF 6.0 specification. - - An instance of class %Ifd can operate in two modes, one that allocates and - deallocates the memory required to store data, and one that doesn't - perform such memory management. -
An external data buffer (not managed by %Ifd) is needed for an instance - of %Ifd which operates in no memory management mode. The %Ifd will - maintain only pointers into this buffer. -
The mode without memory management is used to make "non-intrusive - write support" possible. This allows writing to Exif data of an image - without changing the data layout of the Exif data, to maximize chances - that tag data, which the Exif reader may not understand (e.g., the - Makernote) remains valid. A "non-intrusive write operation" is the - modification of tag data without increasing the data size. - - @note Use the mode with memory management (the default) if you are unsure - or if these memory management considerations are of no concern to you. - - @note The two different modes imply completely different copy and - assignment behaviours, with the first resulting in entirely separate - classes and the second mode resulting in multiple classes using one - and the same data buffer. - */ - class Ifd { - //! @name Not implemented - //@{ - //! Assignment not allowed (memory management mode alloc_ is const) - Ifd& operator=(const Ifd& rhs); - //@} - - public: - //! %Entries const iterator type - typedef Entries::const_iterator const_iterator; - //! %Entries iterator type - typedef Entries::iterator iterator; - - //! @name Creators - //@{ - /*! - @brief Constructor. Allows to set the IFD identifier. Memory management - is enabled, offset is set to 0. Serves as default constructor. - */ - explicit Ifd(IfdId ifdId =ifdIdNotSet); - /*! - @brief Constructor. Allows to set the IFD identifier and the offset of - the IFD from the start of TIFF header. Memory management is - enabled. - */ - Ifd(IfdId ifdId, long offset); - /*! - @brief Constructor. Allows to set the IFD identifier, offset of the - IFD from the start of TIFF header, choose whether or not - memory management is required for the Entries, and decide - whether this IFD has a next pointer. - */ - Ifd(IfdId ifdId, long offset, bool alloc, bool hasNext =true); - //! Copy constructor - Ifd(const Ifd& rhs); - //! Destructor - ~Ifd(); - //@} - - //! @name Manipulators - //@{ - /*! - @brief Read a complete IFD and its data from a data buffer - - @param buf Pointer to the Exif data buffer that contains the IFD to - decode. Usually, the buffer will contain all Exif data - starting from the TIFF header. - @param len Number of bytes in the Exif data buffer. - @param start IFD starts at buf + start. - @param byteOrder Applicable byte order (little or big endian). - @param shift IFD offsets are relative to buf + shift. - - @return 0 if successful;
- 6 if the data buffer is too small, e.g., if an offset points - beyond the provided buffer. The IFD is cleared in this - case. - */ - int read(const byte* buf, - long len, - long start, - ByteOrder byteOrder, - long shift =0); - /*! - @brief Copy the IFD to a data array, update the offsets of the IFD and - all its entries, return the number of bytes written. - - First the number of IFD entries is written (2 bytes), followed - by all directory entries: tag (2), type (2), number of data - components (4) and offset to the data or the data, if it - occupies not more than four bytes (4). The directory entries - are followed by the offset of the next IFD (4). All these - fields are encoded according to the byte order argument. Data - that doesn't fit into the offset fields follows immediately - after the IFD entries. The offsets in the IFD are set to - correctly point to the data fields, using the offset parameter - or the offset of the IFD. - - @param buf Pointer to the data buffer. The user must ensure that the - buffer has enough memory. Otherwise the call results in - undefined behaviour. - @param byteOrder Applicable byte order (little or big endian). - @param offset Target offset from the start of the TIFF header of the - data array. The IFD offsets will be adjusted as necessary. If - not given, then it is assumed that the IFD will remain at its - original position, i.e., the offset of the IFD will be used. - @return Returns the number of characters written. - */ - long copy(byte* buf, ByteOrder byteOrder, long offset =0); - /*! - @brief Reset the IFD. Delete all IFD entries from the class and put - the object in a state where it can accept completely new - entries. - */ - void clear(); - /*! - @brief Set the offset of the next IFD. Byte order is needed to update - the underlying data buffer in non-alloc mode. This method only - has an effect if the IFD was instantiated with hasNext = true. - */ - void setNext(uint32_t next, ByteOrder byteOrder); - /*! - @brief Add the entry to the IFD. No duplicate-check is performed, - i.e., it is possible to add multiple entries with the same tag. - The memory allocation mode of the entry to be added must match - that of the IFD and the IFD ids of the IFD and entry must - match. - */ - void add(const Entry& entry); - /*! - @brief Delete the directory entry with the given tag. Return the index - of the deleted entry or 0 if no entry with tag was found. - */ - int erase(uint16_t tag); - /*! - @brief Delete the directory entry at iterator position pos, return the - position of the next entry. Note that iterators into the - directory, including pos, are potentially invalidated by this - call. - */ - iterator erase(iterator pos); - //! Sort the IFD entries by tag - void sortByTag(); - //! The first entry - iterator begin() { return entries_.begin(); } - //! End of the entries - iterator end() { return entries_.end(); } - //! Find an IFD entry by idx, return an iterator into the entries list - iterator findIdx(int idx); - //! Find an IFD entry by tag, return an iterator into the entries list - iterator findTag(uint16_t tag); - /*! - @brief Update the base pointer of the Ifd and all entries to \em pNewBase. - - Allows to re-locate the underlying data buffer to a new location - \em pNewBase. This method only has an effect in non-alloc mode. - - @param pNewBase Pointer to the new data buffer - - @return Old base pointer or 0 if called in alloc mode - */ - byte* updateBase(byte* pNewBase); - //@} - - //! @name Accessors - //@{ - /*! - @brief Read a sub-IFD from the location pointed to by the directory entry - with the given tag. - - @param dest References the destination IFD. - @param buf The data buffer to read from. The buffer must contain all Exif - data starting from the TIFF header. - @param len Number of bytes in the data buffer - @param byteOrder Applicable byte order (little or big endian). - @param tag Tag to look for. - - @return 0 if successful;
- 6 if reading the sub-IFD failed (see read() above) or - the location pointed to by the directory entry with the - given tag is outside of the data buffer. - - @note It is not considered an error if the tag cannot be found in the - IFD. 0 is returned and no action is taken in this case. - */ - int readSubIfd( - Ifd& dest, const byte* buf, long len, ByteOrder byteOrder, uint16_t tag - ) const; - //! Get the memory allocation mode, see the Ifd class description for details - bool alloc() const { return alloc_; } - //! The first entry - const_iterator begin() const { return entries_.begin(); } - //! End of the entries - const_iterator end() const { return entries_.end(); } - //! Find an IFD entry by idx, return a const iterator into the entries list - const_iterator findIdx(int idx) const; - //! Find an IFD entry by tag, return a const iterator into the entries list - const_iterator findTag(uint16_t tag) const; - //! Get the IfdId of the IFD - IfdId ifdId() const { return ifdId_; } - //! Get the offset of the IFD from the start of the TIFF header - long offset() const { return offset_; } - /*! - @brief Get the offset of the first data entry outside of the IFD from - the start of the TIFF header, return 0 if there is none. The - data offset is determined when the IFD is read. - */ - long dataOffset() const { return dataOffset_; } - //! Get the offset to the next IFD from the start of the TIFF header - uint32_t next() const { return next_; } - //! Get the number of directory entries in the IFD - long count() const { return static_cast(entries_.size()); } - //! Get the size of this IFD in bytes (IFD only, without data) - long size() const; - /*! - @brief Return the total size of the data of this IFD in bytes; sums - the size of all directory entries where size is greater than - four plus the size of all data areas, i.e., all data that - requires memory outside the IFD directory entries is counted. - */ - long dataSize() const; - /*! - @brief Print the IFD in human readable format to the given stream; - begin each line with prefix. - */ - void print(std::ostream& os, const std::string& prefix ="") const; - //@} - - private: - //! Helper structure to build IFD entries - struct PreEntry { - uint16_t tag_; - uint16_t type_; - uint32_t count_; - long size_; - long offsetLoc_; - long offset_; - }; - - //! cmpPreEntriesByOffset needs to know about PreEntry, that's all. - friend bool cmpPreEntriesByOffset(const PreEntry&, const PreEntry&); - - //! Container for 'pre-entries' - typedef std::vector PreEntries; - - // DATA - /*! - True: requires memory allocation and deallocation, - False: no memory management needed. - */ - const bool alloc_; - //! IFD entries - Entries entries_; - //! IFD Id - IfdId ifdId_; - //! Pointer to IFD - byte* pBase_; - //! Offset of the IFD from the start of the TIFF header - long offset_; - //! Offset of the first data entry outside of the IFD directory - long dataOffset_; - //! Indicates whether the IFD has a next pointer - bool hasNext_; - //! Pointer to the offset of next IFD - byte* pNext_; - /*! - The offset of the next IFD from the start of the TIFF header as data - value (always in sync with *pNext_) - */ - uint32_t next_; - - }; // class Ifd - -// ***************************************************************************** -// free functions - - /*! - @brief Compare two IFD entries by tag. Return true if the tag of entry - lhs is less than that of rhs. - */ - bool cmpEntriesByTag(const Entry& lhs, const Entry& rhs); - - /*! - @brief Compare two 'pre-IFD entries' by offset, taking care of special - cases where one or both of the entries don't have an offset. - Return true if the offset of entry lhs is less than that of rhs, - else false. By definition, entries without an offset are greater - than those with an offset. - */ - bool cmpPreEntriesByOffset(const Ifd::PreEntry& lhs, const Ifd::PreEntry& rhs); - -} // namespace Exiv2 - -#endif // #ifndef IFD_HPP_ diff --git a/src/image.cpp b/src/image.cpp index 03748bdd..3e05a65a 100644 --- a/src/image.cpp +++ b/src/image.cpp @@ -117,10 +117,11 @@ namespace Exiv2 { imageType_(imageType), supportedMetadata_(supportedMetadata), #ifdef EXV_HAVE_XMP_TOOLKIT - writeXmpFromPacket_(false) + writeXmpFromPacket_(false), #else - writeXmpFromPacket_(true) + writeXmpFromPacket_(true), #endif + byteOrder_(invalidByteOrder) { } @@ -203,6 +204,11 @@ namespace Exiv2 { comment_ = comment; } + void Image::setByteOrder(ByteOrder byteOrder) + { + byteOrder_ = byteOrder; + } + bool Image::good() const { if (io_->open() != 0) return false; @@ -341,47 +347,6 @@ namespace Exiv2 { return Image::AutoPtr(); } // ImageFactory::create - TiffHeader::TiffHeader(ByteOrder byteOrder) - : byteOrder_(byteOrder), tag_(0x002a), offset_(0x00000008) - { - } - - int TiffHeader::read(const byte* buf) - { - if (buf[0] == 0x49 && buf[1] == 0x49) { - byteOrder_ = littleEndian; - } - else if (buf[0] == 0x4d && buf[1] == 0x4d) { - byteOrder_ = bigEndian; - } - else { - return 1; - } - tag_ = getUShort(buf+2, byteOrder_); - offset_ = getULong(buf+4, byteOrder_); - return 0; - } - - long TiffHeader::copy(byte* buf) const - { - switch (byteOrder_) { - case littleEndian: - buf[0] = 0x49; - buf[1] = 0x49; - break; - case bigEndian: - buf[0] = 0x4d; - buf[1] = 0x4d; - break; - case invalidByteOrder: - // do nothing - break; - } - us2Data(buf+2, 0x002a, byteOrder_); - ul2Data(buf+4, 0x00000008, byteOrder_); - return size(); - } // TiffHeader::copy - // ***************************************************************************** // template, inline and free functions diff --git a/src/image.hpp b/src/image.hpp index aad28085..5766003a 100644 --- a/src/image.hpp +++ b/src/image.hpp @@ -50,12 +50,6 @@ // namespace extensions namespace Exiv2 { -// ***************************************************************************** -// type definitions - - //! Container for binary image - typedef std::vector Blob; - // ***************************************************************************** // class definitions @@ -274,10 +268,25 @@ namespace Exiv2 { 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 { return byteOrder_; } /*! @brief Check if the Image instance is valid. Use after object construction. @@ -402,6 +411,7 @@ namespace Exiv2 { 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 @@ -577,60 +587,6 @@ namespace Exiv2 { static const Registry registry_[]; }; // class ImageFactory - //! Helper class modelling the TIFF header structure. - class TiffHeader { - public: - //! @name Creators - //@{ - /*! - @brief Default constructor. Optionally sets the byte order - (default: little endian). - */ - explicit TiffHeader(ByteOrder byteOrder =littleEndian); - //@} - - //! @name Manipulators - //@{ - //! Read the TIFF header from a data buffer. Returns 0 if successful. - int read(const byte* buf); - //@} - - //! @name Accessors - //@{ - /*! - @brief Write a standard TIFF header into buf as a data string, return - number of bytes copied. - - Only the byte order of the TIFF header varies, the values written for - offset and tag are constant, i.e., independent of the values possibly - read before a call to this function. The value 0x00000008 is written - for the offset, tag is set to 0x002a. - - @param buf The data buffer to write to. - @return The number of bytes written. - */ - long copy(byte* buf) const; - //! Return the size of the TIFF header in bytes. - long size() const { return 8; } - //! Return the byte order (little or big endian). - ByteOrder byteOrder() const { return byteOrder_; } - //! Return the tag value. - uint16_t tag() const { return tag_; } - /*! - @brief Return the offset to IFD0 from the start of the TIFF header. - The offset is 0x00000008 if IFD0 begins immediately after the - TIFF header. - */ - uint32_t offset() const { return offset_; } - //@} - - private: - ByteOrder byteOrder_; - uint16_t tag_; - uint32_t offset_; - - }; // class TiffHeader - // ***************************************************************************** // template, inline and free functions diff --git a/src/iptc.cpp b/src/iptc.cpp index 3d880cb2..4d50a348 100644 --- a/src/iptc.cpp +++ b/src/iptc.cpp @@ -41,6 +41,27 @@ EXIV2_RCSID("@(#) $Id$") #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 + ); +} + // ***************************************************************************** // class member definitions namespace Exiv2 { @@ -123,8 +144,6 @@ namespace Exiv2 { value_->read(value); } - const byte IptcData::marker_ = 0x1C; // Dataset marker - Iptcdatum& IptcData::operator[](const std::string& key) { IptcKey iptcKey(key); @@ -136,20 +155,100 @@ namespace Exiv2 { return *pos; } - int IptcData::load(const byte* buf, long len) + 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(), + FindMetadatumById(key.tag(), key.record())); + } + + IptcData::iterator IptcData::findKey(const IptcKey& key) + { + return std::find_if(iptcMetadata_.begin(), iptcMetadata_.end(), + FindMetadatumById(key.tag(), key.record())); + } + + IptcData::const_iterator IptcData::findId(uint16_t dataset, uint16_t record) const + { + return std::find_if(iptcMetadata_.begin(), iptcMetadata_.end(), + FindMetadatumById(dataset, record)); + } + + IptcData::iterator IptcData::findId(uint16_t dataset, uint16_t record) + { + return std::find_if(iptcMetadata_.begin(), iptcMetadata_.end(), + FindMetadatumById(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 byte IptcParser::marker_ = 0x1C; // Dataset marker + + int IptcParser::decode( + IptcData& iptcData, + const byte* pData, + uint32_t size + ) { #ifdef DEBUG - std::cerr << "IptcData::load, len = " << len << "\n"; + std::cerr << "IptcParser::decode, size = " << size << "\n"; #endif - const byte* pRead = buf; - iptcMetadata_.clear(); + const byte* pRead = pData; + iptcData.clear(); uint16_t record = 0; uint16_t dataSet = 0; uint32_t sizeData = 0; byte extTest = 0; - while (pRead + 3 < buf + len) { + 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. @@ -173,9 +272,9 @@ namespace Exiv2 { sizeData = getUShort(pRead, bigEndian); pRead += 2; } - if (pRead + sizeData <= buf + len) { + if (pRead + sizeData <= pData + size) { int rc = 0; - if ((rc = readData(dataSet, record, pRead, sizeData)) != 0) { + if ((rc = readData(iptcData, dataSet, record, pRead, sizeData)) != 0) { #ifndef SUPPRESS_WARNINGS std::cerr << "Warning: " << "Failed to read IPTC dataset " @@ -195,38 +294,15 @@ namespace Exiv2 { } return 0; - } // IptcData::load + } // IptcParser::decode - int IptcData::readData(uint16_t dataSet, uint16_t record, - const byte* data, uint32_t sizeData) + DataBuf IptcParser::encode(const IptcData& iptcData) { - Value::AutoPtr value; - TypeId type = IptcDataSets::dataSetType(dataSet, record); - value = Value::create(type); - int rc = value->read(data, sizeData, bigEndian); - if (0 == rc) { - IptcKey key(dataSet, record); - add(key, value.get()); - } - else if (1 == rc) { - // If the first attempt failed, try with a string value - value = Value::create(string); - rc = value->read(data, sizeData, bigEndian); - if (0 == rc) { - IptcKey key(dataSet, record); - add(key, value.get()); - } - } - return rc; - } - - DataBuf IptcData::copy() const - { - DataBuf buf(size()); + DataBuf buf(iptcData.size()); byte *pWrite = buf.pData_; - const_iterator iter = iptcMetadata_.begin(); - const_iterator end = iptcMetadata_.end(); + IptcData::const_iterator iter = iptcData.begin(); + IptcData::const_iterator end = iptcData.end(); for ( ; iter != end; ++iter) { // marker, record Id, dataset num *pWrite++ = marker_; @@ -247,85 +323,44 @@ namespace Exiv2 { us2Data(pWrite, static_cast(dataSize), bigEndian); pWrite += 2; } - pWrite += iter->value().copy(pWrite, bigEndian); } return buf; - } // IptcData::copy + } // IptcParser::encode - 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)); - } +} // namespace Exiv2 - int IptcData::add(const Iptcdatum& iptcDatum) +// ***************************************************************************** +// local definitions +namespace { + + int readData( + Exiv2::IptcData& iptcData, + uint16_t dataSet, + uint16_t record, + const Exiv2::byte* data, + uint32_t sizeData + ) { - if (!IptcDataSets::dataSetRepeatable( - iptcDatum.tag(), iptcDatum.record()) && - findId(iptcDatum.tag(), iptcDatum.record()) != end()) { - return 6; + 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()); } - // 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(), - FindMetadatumById(key.tag(), key.record())); - } - - IptcData::iterator IptcData::findKey(const IptcKey& key) - { - return std::find_if(iptcMetadata_.begin(), iptcMetadata_.end(), - FindMetadatumById(key.tag(), key.record())); - } - - IptcData::const_iterator IptcData::findId(uint16_t dataset, uint16_t record) const - { - return std::find_if(iptcMetadata_.begin(), iptcMetadata_.end(), - FindMetadatumById(dataset, record)); - } - - IptcData::iterator IptcData::findId(uint16_t dataset, uint16_t record) - { - return std::find_if(iptcMetadata_.begin(), iptcMetadata_.end(), - FindMetadatumById(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); + 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; } -} // namespace Exiv2 +} diff --git a/src/iptc.hpp b/src/iptc.hpp index 35ea2de8..95012102 100644 --- a/src/iptc.hpp +++ b/src/iptc.hpp @@ -214,15 +214,6 @@ namespace Exiv2 { //! @name Manipulators //@{ - /*! - @brief Load the IPTC data from a byte buffer. The format must follow - the IPTC IIM4 standard. - @param buf Pointer to the data buffer to read from - @param len Number of bytes in the data buffer - @return 0 if successful;
- 5 if IPTC data is invalid or corrupt;
- */ - int load(const byte* buf, long len); /*! @brief Returns a reference to the %Iptcdatum that is associated with a particular \em key. If %IptcData does not already contain such @@ -285,13 +276,6 @@ namespace Exiv2 { const_iterator begin() const { return iptcMetadata_.begin(); } //! End of the metadata const_iterator end() const { return iptcMetadata_.end(); } - /*! - @brief Write the IPTC data to a data buffer and return the data buffer. - Caller owns this buffer. The copied data follows the IPTC IIM4 - standard. - @return Data buffer containing the IPTC data. - */ - DataBuf copy() const; /*! @brief Find the first Iptcdatum with the given key, return a const iterator to it. @@ -314,23 +298,50 @@ namespace Exiv2 { //@} 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 IptcParser { + public: /*! - @brief Read a single dataset payload and create a new metadata entry - @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. + @brief Decode 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 data 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 metadata from the provided metadata to IPTC IIM4 format. + + Write the IPTC data to a data buffer and return the data buffer. + Caller owns this buffer. The copied data follows the IPTC IIM4 + standard. + + @return Data buffer containing the IPTC data. */ - int readData(uint16_t dataSet, uint16_t record, - const byte* data, uint32_t sizeData); + static DataBuf encode( + const IptcData& iptcData + ); + private: // Constant data - static const byte marker_; // Dataset marker + static const byte marker_; // Dataset marker - // DATA - IptcMetadata iptcMetadata_; - }; // class IptcData + }; // class IptcParser } // namespace Exiv2 diff --git a/src/jp2image.cpp b/src/jp2image.cpp index 152b42b1..638c1c95 100644 --- a/src/jp2image.cpp +++ b/src/jp2image.cpp @@ -176,7 +176,9 @@ namespace Exiv2 { DataBuf rawExif(box.boxLength - (sizeof(box) + sizeof(uuid))); io_->read(rawExif.pData_, rawExif.size_); if (io_->error() || io_->eof()) throw Error(14); - if (exifData_.load(rawExif.pData_, rawExif.size_)) { + ByteOrder bo = ExifParser::decode(exifData_, rawExif.pData_, rawExif.size_); + setByteOrder(bo); + if (rawExif.size_ > 0 && byteOrder() == invalidByteOrder) { #ifndef SUPPRESS_WARNINGS std::cerr << "Warning: Failed to decode Exif metadata.\n"; #endif @@ -189,7 +191,7 @@ namespace Exiv2 { DataBuf rawIPTC(box.boxLength - (sizeof(box) + sizeof(uuid))); io_->read(rawIPTC.pData_, rawIPTC.size_); if (io_->error() || io_->eof()) throw Error(14); - if (iptcData_.load(rawIPTC.pData_, rawIPTC.size_)) { + if (IptcParser::decode(iptcData_, rawIPTC.pData_, rawIPTC.size_)) { #ifndef SUPPRESS_WARNINGS std::cerr << "Warning: Failed to decode IPTC metadata.\n"; #endif diff --git a/src/jpgimage.cpp b/src/jpgimage.cpp index fa429ce4..af2463c5 100644 --- a/src/jpgimage.cpp +++ b/src/jpgimage.cpp @@ -197,7 +197,7 @@ namespace Exiv2 { append(psBlob, pPsData, sizeFront); } // Write new iptc record if we have it - DataBuf rawIptc(iptcData.copy()); + DataBuf rawIptc = IptcParser::encode(iptcData); if (rawIptc.size_ > 0) { byte tmpBuf[12]; std::memcpy(tmpBuf, Photoshop::bimId_, 4); @@ -315,7 +315,9 @@ namespace Exiv2 { DataBuf rawExif(size - 8); io_->read(rawExif.pData_, rawExif.size_); if (io_->error() || io_->eof()) throw Error(14); - if (exifData_.load(rawExif.pData_, rawExif.size_)) { + ByteOrder bo = ExifParser::decode(exifData_, rawExif.pData_, rawExif.size_); + setByteOrder(bo); + if (rawExif.size_ > 0 && byteOrder() == invalidByteOrder) { #ifndef SUPPRESS_WARNINGS std::cerr << "Warning: Failed to decode Exif metadata.\n"; #endif @@ -422,7 +424,7 @@ namespace Exiv2 { break; } // Skip the remainder of the unknown segment - if (io_->seek(size-bufRead, BasicIo::cur)) throw Error(14); + if (io_->seek(size - bufRead, BasicIo::cur)) throw Error(14); } // Read the beginning of the next segment marker = advanceToMarker(); @@ -433,7 +435,7 @@ namespace Exiv2 { } // while there are segments to process if ( iptcBlob.size() > 0 - && iptcData_.load(&iptcBlob[0], static_cast(iptcBlob.size()))) { + && IptcParser::decode(iptcData_, &iptcBlob[0], iptcBlob.size())) { #ifndef SUPPRESS_WARNINGS std::cerr << "Warning: Failed to decode IPTC metadata.\n"; #endif @@ -484,6 +486,7 @@ namespace Exiv2 { int skipApp13Ps3 = -1; int skipCom = -1; DataBuf psData; + DataBuf rawExif; // Write image header if (writeHeader(outIo)) throw Error(21); @@ -510,7 +513,11 @@ namespace Exiv2 { if (size < 8) throw Error(22); skipApp1Exif = count; ++search; - if (io_->seek(size-bufRead, BasicIo::cur)) throw Error(22); + // 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 (marker == app1_ && memcmp(buf.pData_ + 2, xmpId_, 29) == 0) { if (size < 31) throw Error(22); @@ -589,20 +596,36 @@ namespace Exiv2 { --search; } if (exifData_.count() > 0) { - DataBuf rawExif = exifData_.copy(); - if (rawExif.size_ > 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[0]; + exifSize = blob.size(); + } + if (exifSize > 0) { // Write APP1 marker, size of APP1 field, Exif id and Exif data tmpBuf[0] = 0xff; tmpBuf[1] = app1_; - if (rawExif.size_ + 8 > 0xffff) throw Error(37, "Exif"); - us2Data(tmpBuf + 2, static_cast(rawExif.size_ + 8), bigEndian); + 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(rawExif.pData_, rawExif.size_) - != rawExif.size_) throw Error(21); + if ( outIo.write(pExifData, exifSize) + != static_cast(exifSize)) throw Error(21); if (outIo.error()) throw Error(21); --search; } diff --git a/src/makernote.cpp b/src/makernote.cpp deleted file mode 100644 index 8317f814..00000000 --- a/src/makernote.cpp +++ /dev/null @@ -1,459 +0,0 @@ -// ***************************************************************** -*- C++ -*- -/* - * Copyright (C) 2004-2008 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$ - Author(s): Andreas Huggel (ahu) - History: 18-Feb-04, ahu: created - */ -// ***************************************************************************** -#include "rcsid.hpp" -EXIV2_RCSID("@(#) $Id$") - -// Define DEBUG_* to output debug information to std::cerr, e.g, by calling -// make like this: make DEFS=-DDEBUG_MAKERNOTE makernote.o -//#define DEBUG_MAKERNOTE -//#define DEBUG_REGISTRY - -// ***************************************************************************** -// included header files -#include "makernote.hpp" -#include "error.hpp" - -// + standard includes -#include -#include -#include -#include -#include -#include - -// ***************************************************************************** -// class member definitions -namespace Exiv2 { - - MakerNote::MakerNote(bool alloc) - : alloc_(alloc), offset_(0), byteOrder_(invalidByteOrder) - { - } - - MakerNote::AutoPtr MakerNote::create(bool alloc) const - { - return AutoPtr(create_(alloc)); - } - - MakerNote::AutoPtr MakerNote::clone() const - { - return AutoPtr(clone_()); - } - - IfdMakerNote::IfdMakerNote(IfdId ifdId, bool alloc, bool hasNext) - : MakerNote(alloc), - absShift_(true), shift_(0), start_(0), ifd_(ifdId, 0, alloc, hasNext) - { - } - - IfdMakerNote::IfdMakerNote(const IfdMakerNote& rhs) - : MakerNote(rhs), absShift_(rhs.absShift_), shift_(rhs.shift_), - start_(rhs.start_), header_(rhs.header_.size_), ifd_(rhs.ifd_) - { - std::memcpy(header_.pData_, rhs.header_.pData_, header_.size_); - } - - int IfdMakerNote::read(const byte* buf, - long len, - long start, - ByteOrder byteOrder, - long shift) - { - // Remember the offset - offset_ = start - shift; - // Set byte order if none is set yet - if (byteOrder_ == invalidByteOrder) byteOrder_ = byteOrder; - // Read and check the header (and set offset adjustment) - int rc = readHeader(buf + start, len - start, byteOrder); - if (rc == 0) { - rc = checkHeader(); - } - // Adjust shift - long newShift = absShift_ ? shift + shift_ : start + shift_; - // Read the makernote IFD - if (rc == 0) { - rc = ifd_.read(buf, len, start + start_, byteOrder_, newShift); - } - if (rc == 0) { - // IfdMakerNote currently does not support multiple IFDs - if (ifd_.next() != 0) { -#ifndef SUPPRESS_WARNINGS - std::cerr << "Warning: Makernote IFD has a next pointer != 0 (" - << ifd_.next() - << "). Ignored.\n"; -#endif - } - } -#ifdef DEBUG_MAKERNOTE - hexdump(std::cerr, buf + start, len - start); - if (rc == 0) ifd_.print(std::cerr); -#endif - - return rc; - } // IfdMakerNote::read - - long IfdMakerNote::copy(byte* buf, ByteOrder byteOrder, long offset) - { - // Remember the new offset - offset_ = offset; - // Set byte order if none is set yet - if (byteOrder_ == invalidByteOrder) byteOrder_ = byteOrder; - // Adjust the offset - offset = absShift_ ? offset + start_ - shift_ : start_ - shift_; - - long len = 0; - len += copyHeader(buf); - len += ifd_.copy(buf + len, byteOrder_, offset); - - return len; - } // IfdMakerNote::copy - - int IfdMakerNote::readHeader(const byte* /*buf*/, - long /*len*/, - ByteOrder /*byteOrder*/) - { - // Default implementation does nothing, assuming there is no header - return 0; - } - - void IfdMakerNote::updateBase(byte* pNewBase) - { - ifd_.updateBase(pNewBase); - } - - int IfdMakerNote::checkHeader() const - { - // Default implementation does nothing, assuming there is no header - return 0; - } - - long IfdMakerNote::copyHeader(byte* buf) const - { - if (header_.size_ != 0) std::memcpy(buf, header_.pData_, header_.size_); - return header_.size_; - } - - long IfdMakerNote::headerSize() const - { - return header_.size_; - } - - Entries::const_iterator IfdMakerNote::findIdx(int idx) const - { - return ifd_.findIdx(idx); - } - - long IfdMakerNote::size() const - { - return headerSize() + ifd_.size() + ifd_.dataSize(); - } - - IfdMakerNote::AutoPtr IfdMakerNote::create(bool alloc) const - { - return AutoPtr(create_(alloc)); - } - - IfdMakerNote::AutoPtr IfdMakerNote::clone() const - { - return AutoPtr(clone_()); - } - - int MakerNoteFactory::Init::count = 0; - - MakerNoteFactory::Init::Init() - { - ++count; - } - - MakerNoteFactory::Init::~Init() - { - if (--count == 0) { - Exiv2::MakerNoteFactory::cleanup(); - } - } - - MakerNoteFactory::Registry* MakerNoteFactory::pRegistry_ = 0; - MakerNoteFactory::IfdIdRegistry* MakerNoteFactory::pIfdIdRegistry_ = 0; - - void MakerNoteFactory::cleanup() - { - if (pRegistry_ != 0) { - Registry::iterator e = pRegistry_->end(); - for (Registry::iterator i = pRegistry_->begin(); i != e; ++i) { - delete i->second; - } - delete pRegistry_; - } - - if (pIfdIdRegistry_ != 0) { - IfdIdRegistry::iterator e = pIfdIdRegistry_->end(); - for (IfdIdRegistry::iterator i = pIfdIdRegistry_->begin(); i != e; ++i) { - delete i->second; - } - delete pIfdIdRegistry_; - } - } - - void MakerNoteFactory::init() - { - if (0 == pRegistry_) { - pRegistry_ = new Registry; - } - if (0 == pIfdIdRegistry_) { - pIfdIdRegistry_ = new IfdIdRegistry; - } - } // MakerNoteFactory::init - - void MakerNoteFactory::registerMakerNote(IfdId ifdId, - MakerNote::AutoPtr makerNote) - { - init(); - MakerNote* pMakerNote = makerNote.release(); - assert(pMakerNote); - IfdIdRegistry::iterator pos = pIfdIdRegistry_->find(ifdId); - if (pos != pIfdIdRegistry_->end()) { - delete pos->second; - pos->second = 0; - } - (*pIfdIdRegistry_)[ifdId] = pMakerNote; - } // MakerNoteFactory::registerMakerNote - - MakerNote::AutoPtr MakerNoteFactory::create(IfdId ifdId, bool alloc) - { - assert(pIfdIdRegistry_ != 0); - IfdIdRegistry::const_iterator i = pIfdIdRegistry_->find(ifdId); - if (i == pIfdIdRegistry_->end()) return MakerNote::AutoPtr(0); - assert(i->second); - return i->second->create(alloc); - } // MakerNoteFactory::create - - void MakerNoteFactory::registerMakerNote(const std::string& make, - const std::string& model, - CreateFct createMakerNote) - { -#ifdef DEBUG_REGISTRY - std::cerr << "Registering MakerNote create function for \"" - << make << "\" and \"" << model << "\".\n"; -#endif - init(); - // Todo: use case insensitive make and model comparisons - - // Find or create a registry entry for make - ModelRegistry* pModelRegistry = 0; - assert(pRegistry_ != 0); - Registry::const_iterator end1 = pRegistry_->end(); - Registry::const_iterator pos1; - for (pos1 = pRegistry_->begin(); pos1 != end1; ++pos1) { - if (pos1->first == make) break; - } - if (pos1 != end1) { - pModelRegistry = pos1->second; - } - else { - pModelRegistry = new ModelRegistry; - pRegistry_->push_back(std::make_pair(make, pModelRegistry)); - } - // Find or create a registry entry for model - ModelRegistry::iterator end2 = pModelRegistry->end(); - ModelRegistry::iterator pos2; - for (pos2 = pModelRegistry->begin(); pos2 != end2; ++pos2) { - if (pos2->first == model) break; - } - if (pos2 != end2) { - pos2->second = createMakerNote; - } - else { - pModelRegistry->push_back(std::make_pair(model, createMakerNote)); - } - } // MakerNoteFactory::registerMakerNote - - MakerNote::AutoPtr MakerNoteFactory::create(const std::string& make, - const std::string& model, - bool alloc, - const byte* buf, - long len, - ByteOrder byteOrder, - long offset) - { -#ifdef DEBUG_REGISTRY - std::cerr << "Entering MakerNoteFactory::create(\"" - << make << "\", \"" << model << "\", " - << (alloc == true ? "true" : "false") << ")\n"; -#endif - // loop through each make of the registry to find the best matching make - int score = 0; - ModelRegistry* pModelRegistry = 0; -#ifdef DEBUG_REGISTRY - std::string makeMatch; - std::cerr << "Searching make registry...\n"; -#endif - assert(pRegistry_ != 0); - Registry::const_iterator end1 = pRegistry_->end(); - Registry::const_iterator pos1; - for (pos1 = pRegistry_->begin(); pos1 != end1; ++pos1) { - int rc = match(pos1->first, make); - if (rc > score) { - score = rc; -#ifdef DEBUG_REGISTRY - makeMatch = pos1->first; -#endif - pModelRegistry = pos1->second; - } - } - if (pModelRegistry == 0) return MakerNote::AutoPtr(0); -#ifdef DEBUG_REGISTRY - std::cerr << "Best match is \"" << makeMatch << "\".\n"; -#endif - - // loop through each model of the model registry to find the best match - score = 0; - CreateFct createMakerNote = 0; -#ifdef DEBUG_REGISTRY - std::string modelMatch; - std::cerr << "Searching model registry...\n"; -#endif - ModelRegistry::const_iterator end2 = pModelRegistry->end(); - ModelRegistry::const_iterator pos2; - for (pos2 = pModelRegistry->begin(); pos2 != end2; ++pos2) { - int rc = match(pos2->first, model); - if (rc > score) { - score = rc; -#ifdef DEBUG_REGISTRY - modelMatch = pos2->first; -#endif - createMakerNote = pos2->second; - } - } - if (createMakerNote == 0) return MakerNote::AutoPtr(0); -#ifdef DEBUG_REGISTRY - std::cerr << "Best match is \"" << modelMatch << "\".\n"; -#endif - - return createMakerNote(alloc, buf, len, byteOrder, offset); - } // MakerNoteFactory::create - - int MakerNoteFactory::match(const std::string& regEntry, - const std::string& key) - { -#ifdef DEBUG_REGISTRY - std::cerr << " Matching registry entry \"" << regEntry << "\" (" - << (int)regEntry.size() << ") with key \"" << key << "\" (" - << (int)key.size() << "): "; -#endif - // Todo: make the comparisons case insensitive - - // Handle exact match (this is only necessary because of the different - // return value - the following algorithm also finds exact matches) - if (regEntry == key) { -#ifdef DEBUG_REGISTRY - std::cerr << "Exact match (score: " << (int)key.size() + 2 << ")\n"; -#endif - return static_cast(key.size()) + 2; - } - std::string uKey = key; - std::string uReg = regEntry; - - int count = 0; // number of matching characters - std::string::size_type ei = 0; // index in the registry entry - std::string::size_type ki = 0; // index in the key - - while (ei != std::string::npos) { - - std::string::size_type pos = uReg.find('*', ei); - if (pos != ei) { - std::string ss = pos == std::string::npos ? - uReg.substr(ei) : uReg.substr(ei, pos - ei); - - if (ki == std::string::npos) { -#ifdef DEBUG_REGISTRY - std::cerr << "Not a match.\n"; -#endif - return 0; - } - - bool found = false; - // Find the substr ss in the key starting from index ki. - // Take care of the special cases - // + where the substr must match the key from beg to end, - // + from beg, - // + to end - // + and where it can be anywhere in the key. - // If found, ki is adjusted to the position in the key after ss. - if (ei == 0 && pos == std::string::npos) { // ei == 0 => ki == 0 - if (0 == uKey.compare(ss)) { - found = true; - ki = std::string::npos; - } - } - else if (ei == 0) { // ei == 0 => ki == 0 - if (0 == uKey.compare(0, ss.size(), ss)) { - found = true; - ki = ss.size(); - } - } - else if (pos == std::string::npos) { - if ( ss.size() <= uKey.size() - && ki <= uKey.size() - ss.size()) { - if (0 == uKey.compare( - uKey.size() - ss.size(), ss.size(), ss)) { - found = true; - ki = std::string::npos; - } - } - } - else { - std::string::size_type idx = uKey.find(ss, ki); - if (idx != std::string::npos) { - found = true; - ki = idx + ss.size(); - } - } - - if (found) { - count += static_cast(ss.size()); - } - else { -#ifdef DEBUG_REGISTRY - std::cerr << "Not a match.\n"; -#endif - return 0; - } - } // if the substr is not empty - - ei = pos == std::string::npos ? std::string::npos : pos + 1; - - } // while ei doesn't point to the end of the registry entry - -#ifdef DEBUG_REGISTRY - std::cerr << "Match (score: " << count + 1 << ")\n"; -#endif - return count + 1; - - } // MakerNoteFactory::match - -} // namespace Exiv2 diff --git a/src/makernote.hpp b/src/makernote.hpp deleted file mode 100644 index 6cbc3c05..00000000 --- a/src/makernote.hpp +++ /dev/null @@ -1,519 +0,0 @@ -// ***************************************************************** -*- C++ -*- -/* - * Copyright (C) 2004-2008 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.hpp - @brief Contains the Exif %MakerNote interface, IFD %MakerNote and a - MakerNote factory - @version $Rev$ - @author Andreas Huggel (ahu) - ahuggel@gmx.net - @date 18-Feb-04, ahu: created - */ -#ifndef MAKERNOTE_HPP_ -#define MAKERNOTE_HPP_ - -// ***************************************************************************** -// included header files -#include "types.hpp" -#include "ifd.hpp" - -// + standard includes -#include -#include -#include -#include -#include -#include - -// ***************************************************************************** -// namespace extensions -namespace Exiv2 { - -// ***************************************************************************** -// class declarations - class Value; - -// ***************************************************************************** -// class definitions - - /*! - @brief Exif makernote interface - - %MakerNote is a low-level container for makernote entries. The ExifData - container uses makernote entries just like the other Exif metadata. Thus, - clients can access Exif and makernote tags and their values uniformly - through the ExifData interface. The role of %MakerNote is very similar to - that of class Ifd (but makernotes do not need to be in IFD format, see - below). In addition, it provides %MakerNote specific tag descriptions and - print functions to interpret the makernote values. - - MakerNote holds methods and functionality to - - read the makernote from a character buffer - - copy the makernote to a character buffer - - maintain a list of makernote entries (similar to IFD entries) - - interpret (print) the values of makernote tags - - Makernotes can be added to the system by subclassing %MakerNote and - registering a create function for the new subclass together with the - camera make and model (which may contain wildcards) in the - MakerNoteFactory. Since the majority of makernotes are in IFD format, - subclass IfdMakerNote is provided. It contains an IFD container and - implements all interface methods related to the makernote entries.
- - To implement a new IFD makernote, all that you need to do is - - subclass %IfdMakerNote, - - implement methods to read and check the header (if any) as well as - clone and create functions, - - add a list of tag descriptions and appropriate print functions and - - register the camera make/model and create function in the makernote factory. - . - See existing makernote implementations for examples, e.g., CanonMakerNote - or FujiMakerNote. - - Finally, the header file which defines the static variable - \em register*MakerNote needs to be included from mn.hpp, to ensure that - the makernote is automatically registered in the factory. - */ - class MakerNote { - //! @name Not implemented - //@{ - //! Assignment not allowed (memory management mode alloc_ is const) - MakerNote& operator=(const MakerNote& rhs); - //@} - - public: - //! Shortcut for a %MakerNote auto pointer. - typedef std::auto_ptr AutoPtr; - - //! @name Creators - //@{ - /*! - @brief Constructor. Allows to choose whether or not memory management - is required for the Entries. - */ - explicit MakerNote(bool alloc =true); - //! Virtual destructor. - virtual ~MakerNote() {} - //@} - - //! @name Manipulators - //@{ - /*! - @brief Read the makernote, including the makernote header, from the - Exif data buffer. - - @param buf Pointer to the Exif data buffer that contains the - MakerNote to decode. The buffer should contain all Exif - data starting from the TIFF header. - @param len Number of bytes in the Exif data buffer - @param start MakerNote starts at buf + start. - @param byteOrder Applicable byte order (little or big endian). - @param shift IFD offsets are relative to buf + shift. - - @return 0 if successful. - */ - virtual int read(const byte* buf, - long len, - long start, - ByteOrder byteOrder, - long shift =0) =0; - /*! - @brief Copy (write) the makerNote to the character buffer buf at - position offset (from the start of the TIFF header), encoded - in byte order byteOrder. Update internal offsets if necessary. - Return the number of bytes written. - */ - virtual long copy(byte* buf, ByteOrder byteOrder, long offset) =0; - /*! - @brief Add the entry to the makernote. No duplicate-check is performed, - i.e., it is possible to add multiple entries with the same tag. - The memory allocation mode of the entry to be added must be the - same as that of the makernote and the IFD id of the entry must - be set to 'makerIfd'. - */ - virtual void add(const Entry& entry) =0; - //! The first makernote entry - virtual Entries::iterator begin() =0; - //! End of the makernote entries - virtual Entries::iterator end() =0; - /*! - @brief Update the base pointer of the %MakerNote and all its entries - to \em pNewBase. - - Allows to re-locate the underlying data buffer to a new location - \em pNewBase. This method only has an effect in non-alloc mode. - */ - virtual void updateBase(byte* pNewBase) =0; - //@} - - //! @name Accessors - //@{ - //! Return the byte order (little or big endian). - ByteOrder byteOrder() const { return byteOrder_; } - //! Return the offset of the makernote from the start of the TIFF header - long offset() const { return offset_; } - /*! - @brief Return an auto-pointer to an newly created, empty instance of - the same type as this. The makernote entries are not - copied. The caller owns the new object and the auto-pointer - ensures that it will be deleted. - - @param alloc Memory management model for the newly created object. - Indicates if memory required to store data should be allocated - and deallocated (true) or not (false). If false, only pointers - to the buffer provided to read() will be kept. See Ifd for more - background on this concept. - */ - AutoPtr create(bool alloc =true) const; - /*! - @brief Return an auto-pointer to a clone of this object. The caller - owns the new object and the auto-pointer ensures that it will - be deleted. - - @note In non-alloc mode the clone potentially contains pointers to - the same data buffer as the original. - Use updateBase(byte* pNewBase) to adjust them. - */ - AutoPtr clone() const; - //! The first makernote entry - virtual Entries::const_iterator begin() const =0; - //! End of the makernote entries - virtual Entries::const_iterator end() const =0; - //! Find an entry by idx, return a const iterator to the record - virtual Entries::const_iterator findIdx(int idx) const =0; - //! Return the size of the makernote in bytes - virtual long size() const =0; - //@} - - protected: - // DATA - /*! - @brief Flag to control the memory management:
- True: requires memory allocation and deallocation,
- False: no memory management needed. - */ - const bool alloc_; - /*! - @brief Offset of the makernote from the start of the TIFF header - (for offset()). - */ - long offset_; - /*! - @brief Alternative byte order to use, invalid if the byte order of the - Exif block can be used - */ - ByteOrder byteOrder_; - - private: - //! Internal virtual create function. - virtual MakerNote* create_(bool alloc =true) const =0; - //! Internal virtual copy constructor. - virtual MakerNote* clone_() const =0; - - }; // class MakerNote - - //! Type for a pointer to a function creating a makernote - typedef MakerNote::AutoPtr (*CreateFct)(bool, const byte*, long, ByteOrder, long); - - /*! - @brief Interface for MakerNotes in IFD format. See MakerNote. - */ - class IfdMakerNote : public MakerNote { - //! @name Not implemented - //@{ - //! Assignment not allowed (Ifd does not have an assignment operator) - IfdMakerNote& operator=(const IfdMakerNote& rhs); - //@} - - public: - //! Shortcut for an %IfdMakerNote auto pointer. - typedef std::auto_ptr AutoPtr; - - //! @name Creators - //@{ - /*! - @brief Constructor. Requires an %Ifd id and allows to choose whether - or not memory management is needed for the Entries and whether - the IFD has a next pointer. - */ - explicit IfdMakerNote(IfdId ifdId, bool alloc =true, bool hasNext =true); - //! Copy constructor - IfdMakerNote(const IfdMakerNote& rhs); - //! Virtual destructor - virtual ~IfdMakerNote() {} - //@} - - //! @name Manipulators - //@{ - virtual int read(const byte* buf, - long len, - long start, - ByteOrder byteOrder, - long shift); - /*! - @brief Read the makernote header from the makernote databuffer. This - method must set the offset to the start of the IFD (start_), if - needed (assuming that the required information is in the header). - Return 0 if successful. - @note The default implementation does nothing, assuming there is no - header - */ - virtual int readHeader(const byte* buf, - long len, - ByteOrder byteOrder); - virtual long copy(byte* buf, ByteOrder byteOrder, long offset); - virtual void add(const Entry& entry) { ifd_.add(entry); } - virtual Entries::iterator begin() { return ifd_.begin(); } - virtual Entries::iterator end() { return ifd_.end(); } - virtual void updateBase(byte* pNewBase); - //@} - - //! @name Accessors - //@{ - virtual Entries::const_iterator begin() const { return ifd_.begin(); } - virtual Entries::const_iterator end() const { return ifd_.end(); } - virtual Entries::const_iterator findIdx(int idx) const; - virtual long size() const; - AutoPtr create(bool alloc =true) const; - AutoPtr clone() const; - /*! - @brief Check the makernote header. This will typically check if a - required prefix string is present in the header. Return 0 if - successful. - @note The default implementation does nothing, assuming there is no - header - */ - virtual int checkHeader() const; - /*! - @brief Write the makernote header to a character buffer, return the - number of characters written. - @note The default implementation copies the header_ buffer. - */ - virtual long copyHeader(byte* buf) const; - /*! - @brief Return the size of the makernote header in bytes. - @note The default implementation returns the size of the header_ - buffer. - */ - virtual long headerSize() const; - //@} - - protected: - // DATA - /*! - @brief True: IFD offsets are relative to the start of the TIFF - header (i.e., the start of the Exif data section) - + shift_ - False: IFD offsets are relative to the start of the - makernote + shift_ - */ - bool absShift_; - /*! - @brief Adjustment for IFD offsets, see absShift_. - */ - long shift_; - /*! - @brief Start of the makernote IFD relative to the start of the - makernote. - */ - long start_; - //! Data buffer for the makernote header - DataBuf header_; - //! The makernote IFD - Ifd ifd_; - - private: - virtual IfdMakerNote* create_(bool alloc =true) const =0; - virtual IfdMakerNote* clone_() const =0; - - }; // class IfdMakerNote - - /*! - @brief Factory for MakerNote objects. - - Maintains an associative list (tree) of camera makes/models and - corresponding %MakerNote create functions. Creates an instance of the - %MakerNote for one camera make/model. The factory is implemented as a - static class. - */ - class MakerNoteFactory { - public: - //! Destructor. - static void cleanup(); - /*! - @brief Register a %MakerNote create function for a camera make and - model. - - Registers a create function for a %MakerNote for a given make and - model combination with the factory. Both the make and model strings - may contain wildcards ('*', e.g., "Canon*"). If the make already - exists in the registry, then a new branch for the model is added. If - the model also already exists, then the new create function replaces - the old one. - - @param make Camera manufacturer. (Typically the string from the Exif - make tag.) - @param model Camera model. (Typically the string from the Exif - model tag.) - @param createMakerNote Pointer to a function to create a new - %MakerNote of a particular type. - */ - static void registerMakerNote(const std::string& make, - const std::string& model, - CreateFct createMakerNote); - - //! Register a %MakerNote prototype in the IFD id registry. - static void registerMakerNote(IfdId ifdId, MakerNote::AutoPtr makerNote); - - /*! - @brief Create the appropriate %MakerNote based on camera make and - model and possibly the contents of the makernote itself, return - an auto-pointer to the newly created MakerNote instance. Return - 0 if no %MakerNote is defined for the camera model. - - The method searches the make-model tree for a make and model - combination in the registry that matches the search key. The search is - case insensitive (Todo: implement case-insensitive comparisons) and - wildcards in the registry entries are supported. First the best - matching make is searched, then the best matching model for this make - is searched. If there is no matching make or no matching model within - the models registered for the best matching make, then no makernote - is created and the function returns 0. If a match is found, the - function invokes the registered create function and returns an - auto-pointer to the newly created MakerNote. The makernote pointed to - is owned by the caller of the function and the auto-pointer ensures - that it is deleted. The best match is an exact match, then a match is - rated according to the number of matching characters. The makernote - buffer is passed on to the create function, which can based on its - content, automatically determine the correct version or flavour of the - makernote required. This is used, e.g., to determine which of the - three Nikon makernotes to create. - - @param make Camera manufacturer. (Typically the string from the Exif - make tag.) - @param model Camera model. (Typically the string from the Exif - model tag.) - @param alloc Memory management model for the new MakerNote. Determines - if memory required to store data should be allocated and - deallocated (true) or not (false). If false, only pointers to - the buffer provided to read() will be kept. See Ifd for more - background on this concept. - @param buf Pointer to the makernote character buffer. - @param len Length of the makernote character buffer. - @param byteOrder Byte order in which the Exif data (and possibly the - makernote) is encoded. - @param offset Offset from the start of the TIFF header of the makernote - buffer. - - @return An auto-pointer that owns a %MakerNote for the camera model. - If the camera is not supported, the pointer is 0. - */ - static MakerNote::AutoPtr create(const std::string& make, - const std::string& model, - bool alloc, - const byte* buf, - long len, - ByteOrder byteOrder, - long offset); - - //! Create a %MakerNote for an IFD id. - static MakerNote::AutoPtr create(IfdId ifdId, bool alloc =true); - - /*! - @brief Match a registry entry with a key (used for make and model). - - The matching algorithm is case insensitive and wildcards ('*') in the - registry entry are supported. The best match is an exact match, then - a match is rated according to the number of matching characters. - - @return A score value indicating how good the key and registry entry - match. 0 means no match, values greater than 0 indicate a - match, larger values are better matches:
- 0: key and registry entry do not match
- 1: a pure wildcard match, i.e., the registry entry is just - a wildcard.
- Score values greater than 1 are computed by adding 1 to the - number of matching characters, except for an exact match, - which scores 2 plus the number of matching characters. - */ - static int match(const std::string& regEntry, const std::string& key); - - /*! - @brief Class Init is used to execute initialisation and termination - code exactly once, at the begin and end of the program. - - See Bjarne Stroustrup, 'The C++ Programming Language 3rd - Edition', section 21.5.2 for details about this pattern. - */ - class Init { - static int count; //!< Counts calls to constructor - public: - //! @name Creators - //@{ - //! Perform one-time initialisations. - Init(); - //! Perform one-time cleanup operations. - ~Init(); - //@} - }; - - private: - //! @name Creators - //@{ - //! Prevent construction: not implemented. - MakerNoteFactory() {} - //! Prevent copy construction: not implemented. - MakerNoteFactory(const MakerNoteFactory& rhs); - //@} - - //! Creates the private static instance - static void init(); - - //! Type used to store model labels and %MakerNote create functions - typedef std::vector > ModelRegistry; - //! Type used to store a list of make labels and model registries - typedef std::vector > Registry; - //! Type used to store a list of IFD ids and %MakerNote prototypes - typedef std::map IfdIdRegistry; - - // DATA - //! List of makernote types and corresponding makernote create functions. - static Registry* pRegistry_; - //! List of makernote IFD ids and corresponding create functions. - static IfdIdRegistry* pIfdIdRegistry_; - - }; // class MakerNoteFactory - -} // namespace Exiv2 - -namespace { - /*! - Each translation unit that includes makernote.hpp declares its own - Init object. The destructor ensures that the factory is properly - freed exactly once. - - See Bjarne Stroustrup, 'The C++ Programming Language 3rd - Edition', section 21.5.2 for details about this pattern. - */ - Exiv2::MakerNoteFactory::Init makerNoteFactoryInit; -} - -#endif // #ifndef MAKERNOTE_HPP_ diff --git a/src/makernote2.cpp b/src/makernote2.cpp index da15562e..6be8fee4 100644 --- a/src/makernote2.cpp +++ b/src/makernote2.cpp @@ -36,10 +36,11 @@ EXIV2_RCSID("@(#) $Id$") # include "exv_conf.h" #endif -#include "makernote2.hpp" -#include "tiffcomposite.hpp" -#include "tiffvisitor.hpp" +#include "makernote2_int.hpp" +#include "tiffcomposite_int.hpp" +#include "tiffvisitor_int.hpp" #include "tiffimage.hpp" +#include "tiffimage_int.hpp" // + standard includes #include @@ -48,25 +49,37 @@ EXIV2_RCSID("@(#) $Id$") // ***************************************************************************** // class member definitions namespace Exiv2 { + namespace Internal { const TiffMnRegistry TiffMnCreator::registry_[] = { - { "Canon", newCanonMn, Group::canonmn }, - { "FOVEON", newSigmaMn, Group::sigmamn }, - { "FUJIFILM", newFujiMn, Group::fujimn }, - { "KONICA MINOLTA", newMinoltaMn, Group::minoltamn }, - { "Minolta", newMinoltaMn, Group::minoltamn }, - { "NIKON", newNikonMn, Group::nikonmn }, - { "OLYMPUS", newOlympusMn, Group::olympmn }, - { "Panasonic", newPanasonicMn, Group::panamn }, - { "PENTAX", newPentaxMn, Group::pentaxmn }, - { "SIGMA", newSigmaMn, Group::sigmamn }, - { "SONY", newSonyMn, Group::sonymn } + { "Canon", Group::canonmn, newIfdMn, newIfdMn2 }, + { "FOVEON", Group::sigmamn, newSigmaMn, newSigmaMn2 }, + { "FUJIFILM", Group::fujimn, newFujiMn, newFujiMn2 }, + { "KONICA MINOLTA", Group::minoltamn, newIfdMn, newIfdMn2 }, + { "Minolta", Group::minoltamn, newIfdMn, newIfdMn2 }, + { "NIKON", Group::nikonmn, newNikonMn, 0 }, + { "OLYMPUS", Group::olympmn, newOlympusMn, newOlympusMn2 }, + { "Panasonic", Group::panamn, newPanasonicMn, newPanasonicMn2 }, + { "PENTAX", Group::pentaxmn, newPentaxMn, newPentaxMn2 }, + { "SIGMA", Group::sigmamn, newSigmaMn, newSigmaMn2 }, + { "SONY", Group::sonymn, newSonyMn, 0 }, + // Entries below are only used for lookup by group + { "-", Group::nikon1mn, 0, newIfdMn2 }, + { "-", Group::nikon2mn, 0, newNikon2Mn2 }, + { "-", Group::nikon3mn, 0, newNikon3Mn2 }, + { "-", Group::sony1mn, 0, newSony1Mn2 }, + { "-", Group::sony2mn, 0, newSony2Mn2 } }; - bool TiffMnRegistry::operator==(const TiffMnRegistry::Key& key) const + bool TiffMnRegistry::operator==(const std::string& key) const { std::string make(make_); - return make == key.make_.substr(0, make.length()); + return make == key.substr(0, make.length()); + } + + bool TiffMnRegistry::operator==(const uint16_t& key) const + { + return mnGroup_ == key; } TiffComponent* TiffMnCreator::create(uint16_t tag, @@ -77,13 +90,29 @@ namespace Exiv2 { ByteOrder byteOrder) { TiffComponent* tc = 0; - const TiffMnRegistry* tmr = find(registry_, TiffMnRegistry::Key(make)); - if (tmr) tc = tmr->newMnFct_(tag, - group, - tmr->mnGroup_, - pData, - size, - byteOrder); + 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, + uint16_t group, + uint16_t mnGroup) + { + TiffComponent* tc = 0; + const TiffMnRegistry* tmr = find(registry_, mnGroup); + if (tmr) { + assert(tmr->newMnFct2_); + tc = tmr->newMnFct2_(tag, group, mnGroup); + } return tc; } // TiffMnCreator::create @@ -118,23 +147,99 @@ namespace Exiv2 { return pHeader_->read(pData, size, byteOrder); } - void TiffIfdMakernote::doAddChild(TiffComponent::AutoPtr tiffComponent) + uint32_t TiffIfdMakernote::sizeHeader() const { - ifd_.addChild(tiffComponent); + if (!pHeader_) return 0; + return pHeader_->size(); + } + + uint32_t TiffIfdMakernote::writeHeader(Blob& blob, ByteOrder byteOrder) const + { + if (!pHeader_) return 0; + return pHeader_->write(blob, byteOrder); + } + + TiffComponent* TiffIfdMakernote::doAddPath(uint16_t tag, TiffPath& tiffPath) + { + return ifd_.addPath(tag, tiffPath); + } + + TiffComponent* TiffIfdMakernote::doAddChild(TiffComponent::AutoPtr tiffComponent) + { + return ifd_.addChild(tiffComponent); } - void TiffIfdMakernote::doAddNext(TiffComponent::AutoPtr tiffComponent) + TiffComponent* TiffIfdMakernote::doAddNext(TiffComponent::AutoPtr tiffComponent) { - ifd_.addNext(tiffComponent); + return ifd_.addNext(tiffComponent); } void TiffIfdMakernote::doAccept(TiffVisitor& visitor) { - if (visitor.go()) visitor.visitIfdMakernote(this); + if (visitor.go(TiffVisitor::geTraverse)) visitor.visitIfdMakernote(this); ifd_.accept(visitor); - if (visitor.go()) visitor.visitIfdMakernoteEnd(this); + if (visitor.go(TiffVisitor::geTraverse)) visitor.visitIfdMakernoteEnd(this); } + uint32_t TiffIfdMakernote::doWrite(Blob& blob, + ByteOrder byteOrder, + int32_t offset, + uint32_t /*valueIdx*/, + uint32_t /*dataIdx*/, + uint32_t imageIdx) + { + if (this->byteOrder() != invalidByteOrder) { + byteOrder = this->byteOrder(); + } + uint32_t len = writeHeader(blob, byteOrder); + len += ifd_.write(blob, byteOrder, + offset - baseOffset(offset) + len, + uint32_t(-1), uint32_t(-1), + imageIdx); + return len; + } // TiffIfdMakernote::doWrite + + uint32_t TiffIfdMakernote::doWriteData(Blob& /*blob*/, + ByteOrder /*byteOrder*/, + int32_t /*offset*/, + uint32_t /*dataIdx*/, + uint32_t /*imageIdx*/) const + { + assert(false); + return 0; + } // TiffIfdMakernote::doWriteData + + uint32_t TiffIfdMakernote::doWriteImage(Blob& /*blob*/, + ByteOrder /*byteOrder*/, + int32_t /*offset*/, + uint32_t /*imageIdx*/) const + { + assert(false); + return 0; + } // TiffIfdMakernote::doWriteImage + + uint32_t TiffIfdMakernote::doSize() const + { + return sizeHeader() + ifd_.size(); + } // TiffIfdMakernote::doSize + + uint32_t TiffIfdMakernote::doCount() const + { + return ifd_.count(); + } // TiffIfdMakernote::doCount + + uint32_t TiffIfdMakernote::doSizeData() const + { + assert(false); + return 0; + } // TiffIfdMakernote::doSizeData + + uint32_t TiffIfdMakernote::doSizeImage() const + { + assert(false); + return 0; + } // TiffIfdMakernote::doSizeImage + const byte OlympusMnHeader::signature_[] = { 'O', 'L', 'Y', 'M', 'P', 0x00, 0x01, 0x00 }; @@ -162,6 +267,13 @@ namespace Exiv2 { return true; } // OlympusMnHeader::read + uint32_t OlympusMnHeader::write(Blob& blob, + ByteOrder /*byteOrder*/) const + { + append(blob, signature_, size_); + return size_; + } // OlympusMnHeader::write + const byte FujiMnHeader::signature_[] = { 'F', 'U', 'J', 'I', 'F', 'I', 'L', 'M', 0x0c, 0x00, 0x00, 0x00 }; @@ -195,9 +307,15 @@ namespace Exiv2 { return true; } // FujiMnHeader::read + uint32_t FujiMnHeader::write(Blob& blob, + ByteOrder /*byteOrder*/) const + { + append(blob, signature_, size_); + return size_; + } // FujiMnHeader::write const byte Nikon2MnHeader::signature_[] = { - 'N', 'i', 'k', 'o', 'n', '\0', 0x00, 0x01 + 'N', 'i', 'k', 'o', 'n', '\0', 0x01, 0x00 }; const uint32_t Nikon2MnHeader::size_ = 8; @@ -221,6 +339,13 @@ namespace Exiv2 { } // Nikon2MnHeader::read + uint32_t Nikon2MnHeader::write(Blob& blob, + ByteOrder /*byteOrder*/) const + { + append(blob, signature_, size_); + return size_; + } // Nikon2MnHeader::write + const byte Nikon3MnHeader::signature_[] = { 'N', 'i', 'k', 'o', 'n', '\0', 0x02, 0x10, 0x00, 0x00, 0x4d, 0x4d, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x08 @@ -250,6 +375,13 @@ namespace Exiv2 { } // Nikon3MnHeader::read + uint32_t Nikon3MnHeader::write(Blob& blob, + ByteOrder /*byteOrder*/) const + { + append(blob, signature_, size_); + return size_; + } // Nikon3MnHeader::write + const byte PanasonicMnHeader::signature_[] = { 'P', 'a', 'n', 'a', 's', 'o', 'n', 'i', 'c', 0x00, 0x00, 0x00 }; @@ -261,8 +393,8 @@ namespace Exiv2 { } bool PanasonicMnHeader::read(const byte* pData, - uint32_t size, - ByteOrder /*byteOrder*/) + uint32_t size, + ByteOrder /*byteOrder*/) { assert (pData != 0); @@ -275,6 +407,13 @@ namespace Exiv2 { } // PanasonicMnHeader::read + uint32_t PanasonicMnHeader::write(Blob& blob, + ByteOrder /*byteOrder*/) const + { + append(blob, signature_, size_); + return size_; + } // PanasonicMnHeader::write + const byte PentaxMnHeader::signature_[] = { 'A', 'O', 'C', 0x00, 'M', 'M' }; @@ -292,7 +431,6 @@ namespace Exiv2 { assert (pData != 0); if (size < size_) return false; - header_.alloc(size_); std::memcpy(header_.pData_, pData, header_.size_); if ( static_cast(header_.size_) < size_ @@ -302,6 +440,13 @@ namespace Exiv2 { return true; } // PentaxMnHeader::read + uint32_t PentaxMnHeader::write(Blob& blob, + ByteOrder /*byteOrder*/) const + { + append(blob, signature_, size_); + return size_; + } // PentaxMnHeader::write + const byte SigmaMnHeader::signature1_[] = { 'S', 'I', 'G', 'M', 'A', '\0', '\0', '\0', 0x01, 0x00 }; @@ -331,6 +476,13 @@ namespace Exiv2 { } // SigmaMnHeader::read + uint32_t SigmaMnHeader::write(Blob& blob, + ByteOrder /*byteOrder*/) const + { + append(blob, signature1_, size_); + return size_; + } // SigmaMnHeader::write + const byte SonyMnHeader::signature_[] = { 'S', 'O', 'N', 'Y', ' ', 'D', 'S', 'C', ' ', '\0', '\0', '\0' }; @@ -356,25 +508,29 @@ namespace Exiv2 { } // SonyMnHeader::read + uint32_t SonyMnHeader::write(Blob& blob, + ByteOrder /*byteOrder*/) const + { + append(blob, signature_, size_); + return size_; + } // SonyMnHeader::write + // ************************************************************************* // free functions - TiffComponent* newCanonMn(uint16_t tag, - uint16_t group, - uint16_t mnGroup, - const byte* /*pData*/, - uint32_t /*size*/, - ByteOrder /*byteOrder*/) + TiffComponent* newIfdMn(uint16_t tag, + uint16_t group, + uint16_t mnGroup, + const byte* /*pData*/, + uint32_t /*size*/, + ByteOrder /*byteOrder*/) { - return new TiffIfdMakernote(tag, group, mnGroup, 0); + return newIfdMn2(tag, group, mnGroup); } - TiffComponent* newMinoltaMn(uint16_t tag, - uint16_t group, - uint16_t mnGroup, - const byte* /*pData*/, - uint32_t /*size*/, - ByteOrder /*byteOrder*/) + TiffComponent* newIfdMn2(uint16_t tag, + uint16_t group, + uint16_t mnGroup) { return new TiffIfdMakernote(tag, group, mnGroup, 0); } @@ -385,6 +541,13 @@ namespace Exiv2 { const byte* /*pData*/, uint32_t /*size*/, ByteOrder /*byteOrder*/) + { + return newOlympusMn2(tag, group, mnGroup); + } + + TiffComponent* newOlympusMn2(uint16_t tag, + uint16_t group, + uint16_t mnGroup) { return new TiffIfdMakernote(tag, group, mnGroup, new OlympusMnHeader); } @@ -395,6 +558,13 @@ namespace Exiv2 { const byte* /*pData*/, uint32_t /*size*/, ByteOrder /*byteOrder*/) + { + return newFujiMn2(tag, group, mnGroup); + } + + TiffComponent* newFujiMn2(uint16_t tag, + uint16_t group, + uint16_t mnGroup) { return new TiffIfdMakernote(tag, group, mnGroup, new FujiMnHeader); } @@ -409,7 +579,7 @@ namespace Exiv2 { // 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)) { - return new TiffIfdMakernote(tag, group, Group::nikon1mn, 0); + return newIfdMn2(tag, group, Group::nikon1mn); } // If the "Nikon" string is not followed by a TIFF header, we assume // Nikon2 format @@ -417,10 +587,24 @@ namespace Exiv2 { if ( size < 18 || !tiffHeader.read(pData + 10, size - 10) || tiffHeader.tag() != 0x002a) { - return new TiffIfdMakernote(tag, group, Group::nikon2mn, new Nikon2MnHeader); + return newNikon2Mn2(tag, group, Group::nikon2mn); } // Else we have a Nikon3 makernote - return new TiffIfdMakernote(tag, group, Group::nikon3mn, new Nikon3MnHeader); + return newNikon3Mn2(tag, group, Group::nikon3mn); + } + + TiffComponent* newNikon2Mn2(uint16_t tag, + uint16_t group, + uint16_t mnGroup) + { + return new TiffIfdMakernote(tag, group, mnGroup, new Nikon2MnHeader); + } + + TiffComponent* newNikon3Mn2(uint16_t tag, + uint16_t group, + uint16_t mnGroup) + { + return new TiffIfdMakernote(tag, group, mnGroup, new Nikon3MnHeader); } TiffComponent* newPanasonicMn(uint16_t tag, @@ -429,6 +613,13 @@ namespace Exiv2 { const byte* /*pData*/, uint32_t /*size*/, ByteOrder /*byteOrder*/) + { + return newPanasonicMn2(tag, group, mnGroup); + } + + TiffComponent* newPanasonicMn2(uint16_t tag, + uint16_t group, + uint16_t mnGroup) { return new TiffIfdMakernote(tag, group, mnGroup, new PanasonicMnHeader, false); } @@ -439,6 +630,13 @@ namespace Exiv2 { const byte* /*pData*/, uint32_t /*size*/, ByteOrder /*byteOrder*/) + { + return newPentaxMn2(tag, group, mnGroup); + } + + TiffComponent* newPentaxMn2(uint16_t tag, + uint16_t group, + uint16_t mnGroup) { return new TiffIfdMakernote(tag, group, mnGroup, new PentaxMnHeader); } @@ -449,6 +647,13 @@ namespace Exiv2 { const byte* /*pData*/, uint32_t /*size*/, ByteOrder /*byteOrder*/) + { + return newSigmaMn2(tag, group, mnGroup); + } + + TiffComponent* newSigmaMn2(uint16_t tag, + uint16_t group, + uint16_t mnGroup) { return new TiffIfdMakernote(tag, group, mnGroup, new SigmaMnHeader); } @@ -463,9 +668,23 @@ namespace Exiv2 { // 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)) { - return new TiffIfdMakernote(tag, group, Group::sony2mn, 0, true); + return newSony2Mn2(tag, group, Group::sony2mn); } - return new TiffIfdMakernote(tag, group, Group::sony1mn, new SonyMnHeader, false); + return newSony1Mn2(tag, group, Group::sony1mn); + } + + TiffComponent* newSony1Mn2(uint16_t tag, + uint16_t group, + uint16_t mnGroup) + { + return new TiffIfdMakernote(tag, group, mnGroup, new SonyMnHeader, false); + } + + TiffComponent* newSony2Mn2(uint16_t tag, + uint16_t group, + uint16_t mnGroup) + { + return new TiffIfdMakernote(tag, group, mnGroup, 0, true); } -} // namespace Exiv2 +}} // namespace Internal, Exiv2 diff --git a/src/makernote2.hpp b/src/makernote2_int.hpp similarity index 70% rename from src/makernote2.hpp rename to src/makernote2_int.hpp index 6cdccae4..9ff57045 100644 --- a/src/makernote2.hpp +++ b/src/makernote2_int.hpp @@ -19,21 +19,20 @@ * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! - @file makernote2.hpp - @brief Makernote TIFF composite class TiffIfdMakernote and classes for - various makernote headers. + @file makernote2_int.hpp + @brief Internal Makernote TIFF composite class TiffIfdMakernote and classes + for various makernote headers. @version $Rev$ @author Andreas Huggel (ahu) ahuggel@gmx.net @date 11-Apr-06, ahu: created */ -#ifndef MAKERNOTE2_HPP_ -#define MAKERNOTE2_HPP_ +#ifndef MAKERNOTE2_INT_HPP_ +#define MAKERNOTE2_INT_HPP_ // ***************************************************************************** // included header files -#include "tiffcomposite.hpp" -#include "tiffvisitor.hpp" +#include "tiffcomposite_int.hpp" #include "types.hpp" // + standard includes @@ -42,6 +41,7 @@ // ***************************************************************************** // namespace extensions namespace Exiv2 { + namespace Internal { namespace Group { const uint16_t olympmn = 257; //!< Olympus makernote @@ -72,7 +72,7 @@ namespace Exiv2 { // ***************************************************************************** // class definitions - //! Type for a pointer to a function creating a makernote + //! Type for a pointer to a function creating a makernote (image) typedef TiffComponent* (*NewMnFct)(uint16_t tag, uint16_t group, uint16_t mnGroup, @@ -80,28 +80,31 @@ namespace Exiv2 { uint32_t size, ByteOrder byteOrder); + //! Type for a pointer to a function creating a makernote (group) + typedef TiffComponent* (*NewMnFct2)(uint16_t tag, + uint16_t group, + uint16_t mnGroup); + //! Makernote registry structure struct TiffMnRegistry { - struct Key; + struct MakeKey; /*! - @brief Compare a TiffMnRegistry structure with a TiffMnRegistry::Key - The two are equal if TiffMnRegistry::make_ equals a substring - of the key of the same size. E.g., registry = "OLYMPUS", + @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 Key& key) const; + bool operator==(const std::string& key) const; + + //! Compare a TiffMnRegistry structure with a makernote group + bool operator==(const uint16_t& key) const; // DATA const char* make_; //!< Camera make - NewMnFct newMnFct_; //!< Makernote create function uint16_t mnGroup_; //!< Group identifier - }; - - //! Search key for Makernote registry structure. - struct TiffMnRegistry::Key { - //! Constructor - Key(const std::string& make) : make_(make) {} - std::string make_; //!< Camera make + NewMnFct newMnFct_; //!< Makernote create function (image) + NewMnFct2 newMnFct2_; //!< Makernote create function (group) }; /*! @@ -113,7 +116,8 @@ namespace Exiv2 { @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. + 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 @@ -125,6 +129,14 @@ namespace Exiv2 { 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, + uint16_t group, + uint16_t mnGroup); + protected: //! Prevent destruction (needed if used as a policy class) ~TiffMnCreator() {} @@ -151,12 +163,15 @@ namespace Exiv2 { //@{ //! Return the size of the header (in bytes). virtual uint32_t size() const =0; + //! Write the header to a data buffer, return the number of bytes written. + virtual uint32_t write(Blob& blob, + ByteOrder byteOrder) const =0; /*! @brief Return the offset to the start of the Makernote IFD from the start of the Makernote (= the start of the header). */ virtual uint32_t ifdOffset() const { return 0; } - /*! + /*! @brief Return the byte order for the makernote. If the return value is invalidByteOrder, this means that the byte order of the the image should be used for the makernote. @@ -179,7 +194,7 @@ namespace Exiv2 { 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. + header (and possibly in special purpose IFD entries). */ class TiffIfdMakernote : public TiffComponent { friend class TiffReader; @@ -211,12 +226,17 @@ namespace Exiv2 { //! @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(Blob& blob, ByteOrder byteOrder) const; + //@} /*! @brief Return the offset to the start of the Makernote IFD from the start of the Makernote. */ uint32_t ifdOffset() const; - /*! + /*! @brief Return the byte order for the makernote. Default (if there is no header) is invalidByteOrder. This means that the byte order of the the image should be used for the makernote. @@ -236,11 +256,68 @@ namespace Exiv2 { protected: //! @name Manipulators //@{ - virtual void doAddChild(TiffComponent::AutoPtr tiffComponent); - virtual void doAddNext(TiffComponent::AutoPtr tiffComponent); + virtual TiffComponent* doAddPath(uint16_t tag, TiffPath& tiffPath); + virtual TiffComponent* doAddChild(TiffComponent::AutoPtr tiffComponent); + virtual TiffComponent* doAddNext(TiffComponent::AutoPtr tiffComponent); virtual void doAccept(TiffVisitor& visitor); //@} + //! @name Write support (Manipulators) + //@{ + /*! + @brief Implements write(). Write the Makernote header, TIFF directory, + values and additional data to the blob, return the number of + bytes written. + */ + virtual uint32_t doWrite(Blob& blob, + ByteOrder byteOrder, + int32_t offset, + uint32_t valueIdx, + uint32_t dataIdx, + uint32_t imageIdx); + //@} + //! @name Write support (Accessors) + //@{ + /*! + @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(Blob& blob, + ByteOrder byteOrder, + int32_t offset, + uint32_t dataIdx, + uint32_t imageIdx) const; + /*! + @brief This class does not really implement writeImage(), it only has + write(). This method must not be called; it commits suicide. + */ + virtual uint32_t doWriteImage(Blob& blob, + ByteOrder byteOrder, + int32_t offset, + uint32_t imageIdx) 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 This class does not really implement sizeData(), it only has + size(). This method must not be called; it commits suicide. + */ + virtual uint32_t doSizeImage() const; + //@} + private: // DATA MnHeader* pHeader_; //!< Makernote header @@ -267,6 +344,7 @@ namespace Exiv2 { //! @name Accessors //@{ virtual uint32_t size() const { return header_.size_; } + virtual uint32_t write(Blob& blob, ByteOrder byteOrder) const; virtual uint32_t ifdOffset() const { return size_; } //@} @@ -296,9 +374,10 @@ namespace Exiv2 { //! @name Accessors //@{ virtual uint32_t size() const { return header_.size_; } + virtual uint32_t write(Blob& blob, ByteOrder byteOrder) const; virtual uint32_t ifdOffset() const { return start_; } virtual ByteOrder byteOrder() const { return byteOrder_; } - virtual uint32_t baseOffset(uint32_t mnOffset) const { return mnOffset; } + virtual uint32_t baseOffset(uint32_t mnOffset) const { return mnOffset; } //@} private: @@ -329,6 +408,7 @@ namespace Exiv2 { //! @name Accessors //@{ virtual uint32_t size() const { return size_; } + virtual uint32_t write(Blob& blob, ByteOrder byteOrder) const; virtual uint32_t ifdOffset() const { return start_; } //@} @@ -359,6 +439,7 @@ namespace Exiv2 { //! @name Accessors //@{ virtual uint32_t size() const { return size_; } + virtual uint32_t write(Blob& blob, ByteOrder byteOrder) const; virtual uint32_t ifdOffset() const { return start_; } virtual ByteOrder byteOrder() const { return byteOrder_; } virtual uint32_t baseOffset(uint32_t mnOffset) const { return mnOffset + 10; } @@ -392,6 +473,7 @@ namespace Exiv2 { //! @name Accessors //@{ virtual uint32_t size() const { return size_; } + virtual uint32_t write(Blob& blob, ByteOrder byteOrder) const; virtual uint32_t ifdOffset() const { return start_; } //@} @@ -422,6 +504,7 @@ namespace Exiv2 { //! @name Accessors //@{ virtual uint32_t size() const { return header_.size_; } + virtual uint32_t write(Blob& blob, ByteOrder byteOrder) const; virtual uint32_t ifdOffset() const { return size_; } //@} @@ -451,6 +534,7 @@ namespace Exiv2 { //! @name Accessors //@{ virtual uint32_t size() const { return size_; } + virtual uint32_t write(Blob& blob, ByteOrder byteOrder) const; virtual uint32_t ifdOffset() const { return start_; } //@} @@ -482,6 +566,7 @@ namespace Exiv2 { //! @name Accessors //@{ virtual uint32_t size() const { return size_; } + virtual uint32_t write(Blob& blob, ByteOrder byteOrder) const; virtual uint32_t ifdOffset() const { return start_; } //@} @@ -496,21 +581,18 @@ namespace Exiv2 { // ***************************************************************************** // template, inline and free functions - //! Function to create a Canon makernote - TiffComponent* newCanonMn(uint16_t tag, - uint16_t group, - uint16_t mnGroup, - const byte* pData, - uint32_t size, - ByteOrder byteOrder); + //! Function to create a simple IFD makernote (Canon, Minolta, Nikon1) + TiffComponent* newIfdMn(uint16_t tag, + uint16_t group, + uint16_t mnGroup, + const byte* pData, + uint32_t size, + ByteOrder byteOrder); - //! Function to create a Minolta makernote - TiffComponent* newMinoltaMn(uint16_t tag, - uint16_t group, - uint16_t mnGroup, - const byte* pData, - uint32_t size, - ByteOrder byteOrder); + //! Function to create a simple IFD makernote (Canon, Minolta, Nikon1) + TiffComponent* newIfdMn2(uint16_t tag, + uint16_t group, + uint16_t mnGroup); //! Function to create an Olympus makernote TiffComponent* newOlympusMn(uint16_t tag, @@ -520,6 +602,11 @@ namespace Exiv2 { uint32_t size, ByteOrder byteOrder); + //! Function to create an Olympus makernote + TiffComponent* newOlympusMn2(uint16_t tag, + uint16_t group, + uint16_t mnGroup); + //! Function to create a Fujifilm makernote TiffComponent* newFujiMn(uint16_t tag, uint16_t group, @@ -528,6 +615,11 @@ namespace Exiv2 { uint32_t size, ByteOrder byteOrder); + //! Function to create a Fujifilm makernote + TiffComponent* newFujiMn2(uint16_t tag, + uint16_t group, + uint16_t mnGroup); + /*! @brief Function to create a Nikon makernote. This will create the appropriate Nikon 1, 2 or 3 makernote, based on the arguments. @@ -539,6 +631,16 @@ namespace Exiv2 { uint32_t size, ByteOrder byteOrder); + //! Function to create a Nikon2 makernote + TiffComponent* newNikon2Mn2(uint16_t tag, + uint16_t group, + uint16_t mnGroup); + + //! Function to create a Nikon3 makernote + TiffComponent* newNikon3Mn2(uint16_t tag, + uint16_t group, + uint16_t mnGroup); + //! Function to create a Panasonic makernote TiffComponent* newPanasonicMn(uint16_t tag, uint16_t group, @@ -547,13 +649,23 @@ namespace Exiv2 { uint32_t size, ByteOrder byteOrder); + //! Function to create a Panasonic makernote + TiffComponent* newPanasonicMn2(uint16_t tag, + uint16_t group, + uint16_t mnGroup); + //! Function to create an Pentax makernote TiffComponent* newPentaxMn(uint16_t tag, - uint16_t group, - uint16_t mnGroup, - const byte* pData, - uint32_t size, - ByteOrder byteOrder); + uint16_t group, + uint16_t mnGroup, + const byte* pData, + uint32_t size, + ByteOrder byteOrder); + + //! Function to create an Pentax makernote + TiffComponent* newPentaxMn2(uint16_t tag, + uint16_t group, + uint16_t mnGroup); //! Function to create a Sigma makernote TiffComponent* newSigmaMn(uint16_t tag, @@ -563,6 +675,11 @@ namespace Exiv2 { uint32_t size, ByteOrder byteOrder); + //! Function to create a Sigma makernote + TiffComponent* newSigmaMn2(uint16_t tag, + uint16_t group, + uint16_t mnGroup); + //! Function to create a Sony makernote TiffComponent* newSonyMn(uint16_t tag, uint16_t group, @@ -571,6 +688,16 @@ namespace Exiv2 { uint32_t size, ByteOrder byteOrder); -} // namespace Exiv2 + //! Function to create a Sony1 makernote + TiffComponent* newSony1Mn2(uint16_t tag, + uint16_t group, + uint16_t mnGroup); + + //! Function to create a Sony2 makernote + TiffComponent* newSony2Mn2(uint16_t tag, + uint16_t group, + uint16_t mnGroup); + +}} // namespace Internal, Exiv2 -#endif // #ifndef MAKERNOTE2_HPP_ +#endif // #ifndef MAKERNOTE2_INT_HPP_ diff --git a/src/minoltamn.cpp b/src/minoltamn.cpp index 6663c082..3be8d28a 100644 --- a/src/minoltamn.cpp +++ b/src/minoltamn.cpp @@ -35,7 +35,6 @@ EXIV2_RCSID("@(#) $Id$") // included header files #include "types.hpp" #include "minoltamn.hpp" -#include "makernote.hpp" #include "value.hpp" #include "tags.hpp" #include "i18n.h" // NLS support. @@ -531,42 +530,42 @@ namespace Exiv2 { { 2, N_("Manual flash control") } }; - std::ostream& MinoltaMakerNote::printMinoltaExposureSpeedStd(std::ostream& os, const Value& value) + 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) + 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) + 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) + 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) + 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) + 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') @@ -575,7 +574,7 @@ namespace Exiv2 { return os; } - std::ostream& MinoltaMakerNote::printMinoltaTimeStd(std::ostream& os, const Value& value) + 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 @@ -585,21 +584,21 @@ namespace Exiv2 { return os; } - std::ostream& MinoltaMakerNote::printMinoltaFlashExposureCompStd(std::ostream& os, const Value& value) + 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) + 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) + std::ostream& MinoltaMakerNote::printMinoltaBrightnessStd(std::ostream& os, const Value& value, const ExifData*) { // From the PHP JPEG Metadata Toolkit os << (value.toLong()/8)-6; @@ -1096,7 +1095,7 @@ namespace Exiv2 { }; //! Method to convert Minolta Dynax 5D exposure manual bias values. - std::ostream& MinoltaMakerNote::printMinoltaExposureManualBias5D(std::ostream& os, const Value& value) + 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 @@ -1109,7 +1108,7 @@ namespace Exiv2 { } //! Method to convert Minolta Dynax 5D exposure compensation values. - std::ostream& MinoltaMakerNote::printMinoltaExposureCompensation5D(std::ostream& os, const Value& value) + std::ostream& MinoltaMakerNote::printMinoltaExposureCompensation5D(std::ostream& os, const Value& value, const ExifData*) { std::ostringstream oss; oss.copyfmt(os); @@ -1219,306 +1218,4 @@ namespace Exiv2 { // TODO : Add camera settings tags info "New2"... - //! @cond IGNORE - MinoltaMakerNote::RegisterMn::RegisterMn() - { - MakerNoteFactory::registerMakerNote("KONICA MINOLTA*", "*", createMinoltaMakerNote); - MakerNoteFactory::registerMakerNote("Minolta*", "*", createMinoltaMakerNote); - - MakerNoteFactory::registerMakerNote(minoltaIfdId, MakerNote::AutoPtr(new MinoltaMakerNote)); - MakerNoteFactory::registerMakerNote(minoltaCs5DIfdId, MakerNote::AutoPtr(new MinoltaMakerNote)); - MakerNoteFactory::registerMakerNote(minoltaCs7DIfdId, MakerNote::AutoPtr(new MinoltaMakerNote)); - MakerNoteFactory::registerMakerNote(minoltaCsOldIfdId, MakerNote::AutoPtr(new MinoltaMakerNote)); - MakerNoteFactory::registerMakerNote(minoltaCsNewIfdId, MakerNote::AutoPtr(new MinoltaMakerNote)); - } - //! @endcond - - int MinoltaMakerNote::read(const byte* buf, long len, long start, ByteOrder byteOrder, long shift) - { - int rc = IfdMakerNote::read(buf, len, start, byteOrder, shift); - if (rc) return rc; - - // Decode Dynax 5D camera settings and add settings as additional entries - Entries::iterator cs5D = ifd_.findTag(0x0114); - - if (cs5D != ifd_.end() && cs5D->type() == undefined) { - for (uint16_t c = 0; cs5D->count()/2 > c; ++c) { - addCsEntry(minoltaCs5DIfdId, c, cs5D->offset() + c*2, cs5D->data() + c*2, 1); - } - // Discard the original entry - ifd_.erase(cs5D); - } - - // Decode Dynax 7D camera settings and add settings as additional entries - Entries::iterator cs7D = ifd_.findTag(0x0004); - - if (cs7D != ifd_.end() && cs7D->type() == undefined) { - for (uint16_t c = 0; cs7D->count()/2 > c; ++c) { - addCsEntry(minoltaCs7DIfdId, c, cs7D->offset() + c*2, cs7D->data() + c*2, 1); - } - // Discard the original entry - ifd_.erase(cs7D); - } - - // Decode Old Std camera settings and add settings as additional entries - Entries::iterator csOldStd = ifd_.findTag(0x0001); - - if (csOldStd != ifd_.end() && csOldStd->type() == undefined) { - for (uint16_t c = 0; csOldStd->count()/4 > c; ++c) { - addCsStdEntry(minoltaCsOldIfdId, c, csOldStd->offset() + c*4, csOldStd->data() + c*4, 1); - } - // Discard the original entry - ifd_.erase(csOldStd); - } - - // Decode New Std camera settings and add settings as additional entries - Entries::iterator csNewStd = ifd_.findTag(0x0003); - - if (csNewStd != ifd_.end() && csNewStd->type() == undefined) { - for (uint16_t c = 0; csNewStd->count()/4 > c; ++c) { - addCsStdEntry(minoltaCsNewIfdId, c, csNewStd->offset() + c*4, csNewStd->data() + c*4, 1); - } - // Discard the original entry - ifd_.erase(csNewStd); - } - - // Copy remaining ifd entries - entries_.insert(entries_.begin(), ifd_.begin(), ifd_.end()); - - // Set idx - int idx = 0; - Entries::iterator e = entries_.end(); - for (Entries::iterator i = entries_.begin(); i != e; ++i) { - i->setIdx(++idx); - } - - return 0; - } - - void MinoltaMakerNote::addCsEntry(IfdId ifdId, uint16_t tag, long offset, const byte* data, int count) - { - Entry e(false); - e.setIfdId(ifdId); - e.setTag(tag); - e.setOffset(offset); - e.setValue(unsignedShort, count, data, 2*count, bigEndian); - add(e); - } - - void MinoltaMakerNote::addCsStdEntry(IfdId ifdId, uint32_t tag, long offset, const byte* data, int count) - { - Entry e(false); - e.setIfdId(ifdId); - e.setTag(tag); - e.setOffset(offset); - e.setValue(unsignedLong, count, data, 4*count, bigEndian); - add(e); - } - - void MinoltaMakerNote::add(const Entry& entry) - { - assert(alloc_ == entry.alloc()); - assert( entry.ifdId() == minoltaIfdId - || entry.ifdId() == minoltaCs5DIfdId - || entry.ifdId() == minoltaCs7DIfdId - || entry.ifdId() == minoltaCsOldIfdId - || entry.ifdId() == minoltaCsNewIfdId); - // allow duplicates - entries_.push_back(entry); - } - - long MinoltaMakerNote::copy(byte* buf, ByteOrder byteOrder, long offset) - { - if (byteOrder_ == invalidByteOrder) byteOrder_ = byteOrder; - - assert(ifd_.alloc()); - ifd_.clear(); - - // Add all standard Minolta entries to the IFD - Entries::const_iterator end = entries_.end(); - for (Entries::const_iterator i = entries_.begin(); i != end; ++i) { - if (i->ifdId() == minoltaIfdId) { - ifd_.add(*i); - } - } - - // Collect Dynax 5D camera settings entries and add the original Minolta tag - Entry cs5D; - if (assemble(cs5D, minoltaCs5DIfdId, 0x0114, bigEndian)) { - ifd_.erase(0x0114); - ifd_.add(cs5D); - } - - // Collect Dynax 7D camera settings entries and add the original Minolta tag - Entry cs7D; - if (assemble(cs7D, minoltaCs7DIfdId, 0x0004, bigEndian)) { - ifd_.erase(0x0004); - ifd_.add(cs7D); - } - - // Collect Old Std camera settings entries and add the original Minolta tag - Entry csOldStd; - if (assembleStd(csOldStd, minoltaCsOldIfdId, 0x0001, bigEndian)) { - ifd_.erase(0x0001); - ifd_.add(csOldStd); - } - - // Collect New Std camera settings entries and add the original Minolta tag - Entry csNewStd; - if (assembleStd(csNewStd, minoltaCsNewIfdId, 0x0003, bigEndian)) { - ifd_.erase(0x0003); - ifd_.add(csNewStd); - } - - return IfdMakerNote::copy(buf, byteOrder_, offset); - } // MinoltaMakerNote::copy - - void MinoltaMakerNote::updateBase(byte* pNewBase) - { - byte* pBase = ifd_.updateBase(pNewBase); - if (absShift_ && !alloc_) { - Entries::iterator end = entries_.end(); - for (Entries::iterator pos = entries_.begin(); pos != end; ++pos) { - pos->updateBase(pBase, pNewBase); - } - } - } // MinoltaMakerNote::updateBase - - long MinoltaMakerNote::size() const - { - Ifd ifd(minoltaIfdId, 0, alloc_); // offset doesn't matter - - // Add all standard Minolta entries to the IFD - Entries::const_iterator end = entries_.end(); - for (Entries::const_iterator i = entries_.begin(); i != end; ++i) { - if (i->ifdId() == minoltaIfdId) { - ifd.add(*i); - } - } - // Collect Dynax 5D camera settings entries and add the original Minolta tag - Entry cs5D(alloc_); - if (assemble(cs5D, minoltaCs5DIfdId, 0x0114, bigEndian)) { - ifd.erase(0x0114); - ifd.add(cs5D); - } - - // Collect Dynax 7D camera settings entries and add the original Minolta tag - Entry cs7D(alloc_); - if (assemble(cs7D, minoltaCs7DIfdId, 0x0004, bigEndian)) { - ifd.erase(0x0004); - ifd.add(cs7D); - } - - // Collect Old Std camera settings entries and add the original Minolta tag - Entry csOldStd(alloc_); - if (assembleStd(csOldStd, minoltaCsOldIfdId, 0x0001, bigEndian)) { - ifd.erase(0x0001); - ifd.add(csOldStd); - } - - // Collect New Std camera settings entries and add the original Minolta tag - Entry csNewStd(alloc_); - if (assembleStd(csNewStd, minoltaCsNewIfdId, 0x0003, bigEndian)) { - ifd.erase(0x0003); - ifd.add(csNewStd); - } - - return headerSize() + ifd.size() + ifd.dataSize(); - } // MinoltaMakerNote::size - - long MinoltaMakerNote::assemble(Entry& e, IfdId ifdId, uint16_t tag, ByteOrder /*byteOrder*/) const - { - DataBuf buf(1024); - std::memset(buf.pData_, 0x0, 1024); - uint16_t len = 0; - Entries::const_iterator end = entries_.end(); - for (Entries::const_iterator i = entries_.begin(); i != end; ++i) { - if (i->ifdId() == ifdId) { - uint16_t pos = i->tag() * 2; - uint16_t size = pos + static_cast(i->size()); - assert(size <= 1024); - std::memcpy(buf.pData_ + pos, i->data(), i->size()); - if (len < size) len = size; - } - } - if (len > 0) { - e.setIfdId(minoltaIfdId); - e.setIdx(0); // don't care - e.setTag(tag); - e.setOffset(0); // will be calculated when the IFD is written - e.setValue(undefined, len, buf.pData_, len * 2); - } - return len; - } // MinoltaMakerNote::assemble - - long MinoltaMakerNote::assembleStd(Entry& e, IfdId ifdId, uint32_t tag, ByteOrder /*byteOrder*/) const - { - DataBuf buf(1024); - std::memset(buf.pData_, 0x0, 1024); - uint32_t len = 0; - Entries::const_iterator end = entries_.end(); - for (Entries::const_iterator i = entries_.begin(); i != end; ++i) { - if (i->ifdId() == ifdId) { - uint32_t pos = i->tag() * 4; - uint32_t size = pos + static_cast(i->size()); - assert(size <= 1024); - std::memcpy(buf.pData_ + pos, i->data(), i->size()); - if (len < size) len = size; - } - } - if (len > 0) { - e.setIfdId(minoltaIfdId); - e.setIdx(0); // don't care - e.setTag(tag); - e.setOffset(0); // will be calculated when the IFD is written - e.setValue(undefined, len, buf.pData_, len * 4); - } - return len; - } // MinoltaMakerNote::assembleStd - - Entries::const_iterator MinoltaMakerNote::findIdx(int idx) const - { - return std::find_if(entries_.begin(), entries_.end(), FindEntryByIdx(idx)); - } - - MinoltaMakerNote::MinoltaMakerNote(bool alloc) - : IfdMakerNote(minoltaIfdId, alloc) - { - } - - MinoltaMakerNote::MinoltaMakerNote(const MinoltaMakerNote& rhs) - : IfdMakerNote(rhs) - { - entries_ = rhs.entries_; - } - - MinoltaMakerNote::AutoPtr MinoltaMakerNote::create(bool alloc) const - { - return AutoPtr(create_(alloc)); - } - - MinoltaMakerNote* MinoltaMakerNote::create_(bool alloc) const - { - return new MinoltaMakerNote(alloc); - } - - MinoltaMakerNote::AutoPtr MinoltaMakerNote::clone() const - { - return AutoPtr(clone_()); - } - - MinoltaMakerNote* MinoltaMakerNote::clone_() const - { - return new MinoltaMakerNote(*this); - } - -// ***************************************************************************** -// free functions - - MakerNote::AutoPtr createMinoltaMakerNote(bool alloc, const byte* /*buf*/, long /*len*/, - ByteOrder /*byteOrder*/, long /*offset*/) - { - return MakerNote::AutoPtr(new MinoltaMakerNote(alloc)); - } - } // namespace Exiv2 diff --git a/src/minoltamn.hpp b/src/minoltamn.hpp index 8275d6f8..d53bf2ca 100644 --- a/src/minoltamn.hpp +++ b/src/minoltamn.hpp @@ -38,94 +38,21 @@ // ***************************************************************************** // included header files -#include "types.hpp" -#include "makernote.hpp" #include "tags.hpp" // + standard includes -#include #include -#include // ***************************************************************************** // namespace extensions namespace Exiv2 { -// ***************************************************************************** -// class declarations - class Value; - -// ***************************************************************************** -// free functions - - /*! - @brief Return an auto-pointer to a newly created empty MakerNote - initialized to operate in the memory management model indicated. - The caller owns this copy and the auto-pointer ensures that it - will be deleted. - - @param alloc Memory management model for the new MakerNote. Determines if - memory required to store data should be allocated and deallocated - (true) or not (false). If false, only pointers to the buffer - provided to read() will be kept. See Ifd for more background on - this concept. - @param buf Pointer to the makernote character buffer (not used). - @param len Length of the makernote character buffer (not used). - @param byteOrder Byte order in which the Exif data (and possibly the - makernote) is encoded (not used). - @param offset Offset from the start of the TIFF header of the makernote - buffer (not used). - - @return An auto-pointer to a newly created empty MakerNote. The caller - owns this copy and the auto-pointer ensures that it will be - deleted. - */ - MakerNote::AutoPtr createMinoltaMakerNote(bool alloc, - const byte* buf, - long len, - ByteOrder byteOrder, - long offset); - // ***************************************************************************** // class definitions //! MakerNote for Minolta cameras - class MinoltaMakerNote : public IfdMakerNote { + class MinoltaMakerNote { public: - //! Shortcut for a %MinoltaMakerNote auto pointer. - typedef std::auto_ptr AutoPtr; - - //! @name Creators - //@{ - /*! - @brief Constructor. Allows to choose whether or not memory management - is required for the makernote entries. - */ - MinoltaMakerNote(bool alloc =true); - //! Copy constructor - MinoltaMakerNote(const MinoltaMakerNote& rhs); - //! Virtual destructor - virtual ~MinoltaMakerNote() {} - //@} - - //! @name Manipulators - //@{ - int read(const byte* buf, long len, long start, ByteOrder byteOrder, long shift); - long copy(byte* buf, ByteOrder byteOrder, long offset); - void add(const Entry& entry); - Entries::iterator begin() { return entries_.begin(); } - Entries::iterator end() { return entries_.end(); } - void updateBase(byte* pNewBase); - //@} - - //! @name Accessors - //@{ - Entries::const_iterator begin() const { return entries_.begin(); } - Entries::const_iterator end() const { return entries_.end(); } - Entries::const_iterator findIdx(int idx) const; - long size() const; - AutoPtr create(bool alloc =true) const; - AutoPtr clone() const; //! 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 @@ -134,69 +61,37 @@ namespace Exiv2 { static const TagInfo* tagListCs7D(); //! Return read-only list of built-in Minolta 5D Camera Settings tags static const TagInfo* tagListCs5D(); - //@} //! @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); + 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); + 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); + 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); + 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); + 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); + 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); + 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); + 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); + 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); + 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); + 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); + static std::ostream& printMinoltaExposureCompensation5D(std::ostream& os, const Value& value, const ExifData*); //@} - //! @cond IGNORE - // Public only so that we can create a static instance - struct RegisterMn { - RegisterMn(); - }; - //! @endcond - private: - //! @name Manipulators - //@{ - //! Add a Dynax 5D and 7D camera settings entry to the makernote entries - void addCsEntry(IfdId ifdId, uint16_t tag, long offset, const byte* data, int count); - //! Add a standard camera settings entry to the makernote entries - void addCsStdEntry(IfdId ifdId, uint32_t tag, long offset, const byte* data, int count); - //@} - - //! @name Accessors - //@{ - //! Assemble special Dynax 5D or 7D Minolta entries into an entry with the original tag - long assemble(Entry& e, IfdId ifdId, uint16_t tag, ByteOrder byteOrder) const; - //! Assemble special standard Minolta entries into an entry with the original tag - long assembleStd(Entry& e, IfdId ifdId, uint32_t tag, ByteOrder byteOrder) const; - //! Internal virtual create function. - MinoltaMakerNote* create_(bool alloc =true) const; - //! Internal virtual copy constructor. - MinoltaMakerNote* clone_() const; - //@} - - // DATA - //! Container to store Makernote entries (instead of Ifd) - Entries entries_; - //! Tag information static const TagInfo tagInfo_[]; static const TagInfo tagInfoCs5D_[]; @@ -205,7 +100,6 @@ namespace Exiv2 { }; // class MinoltaMakerNote - static MinoltaMakerNote::RegisterMn registerMinoltaMakerNote; } // namespace Exiv2 #endif // #ifndef MINOLTAMN_HPP_ diff --git a/src/mrwimage.cpp b/src/mrwimage.cpp index 29549b23..b78859c2 100644 --- a/src/mrwimage.cpp +++ b/src/mrwimage.cpp @@ -38,7 +38,7 @@ EXIV2_RCSID("@(#) $Id$") #endif #include "mrwimage.hpp" -#include "tiffparser.hpp" +#include "tiffimage.hpp" #include "image.hpp" #include "basicio.hpp" #include "error.hpp" @@ -142,8 +142,12 @@ namespace Exiv2 { io_->read(buf.pData_, buf.size_); if (io_->error() || io_->eof()) throw Error(14); - TiffParser::decode(this, buf.pData_, buf.size_, - TiffCreator::create, TiffDecoder::findDecoder); + ByteOrder bo = TiffParser::decode(exifData_, + iptcData_, + xmpData_, + buf.pData_, + buf.size_); + setByteOrder(bo); } // MrwImage::readMetadata void MrwImage::writeMetadata() diff --git a/src/mrwthumb.cpp b/src/mrwthumb.cpp new file mode 100644 index 00000000..5068da83 --- /dev/null +++ b/src/mrwthumb.cpp @@ -0,0 +1,49 @@ +// ***************************************************************** -*- C++ -*- +// mrwthumb.cpp, $Rev$ +// 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; +} diff --git a/src/nikonmn.cpp b/src/nikonmn.cpp index d64ce6f2..33fcf93a 100644 --- a/src/nikonmn.cpp +++ b/src/nikonmn.cpp @@ -37,7 +37,6 @@ EXIV2_RCSID("@(#) $Id$") // included header files #include "types.hpp" #include "nikonmn.hpp" -#include "makernote.hpp" #include "value.hpp" #include "image.hpp" #include "tags.hpp" @@ -147,15 +146,6 @@ namespace Exiv2 { { 6, N_("Strong") } }; - //! @cond IGNORE - Nikon1MakerNote::RegisterMn::RegisterMn() - { - MakerNoteFactory::registerMakerNote("NIKON*", "*", createNikonMakerNote); - MakerNoteFactory::registerMakerNote( - nikon1IfdId, MakerNote::AutoPtr(new Nikon1MakerNote)); - } - //! @endcond - // Nikon1 MakerNote Tag Info const TagInfo Nikon1MakerNote::tagInfo_[] = { TagInfo(0x0001, "Version", N_("Version"), @@ -218,38 +208,9 @@ namespace Exiv2 { return tagInfo_; } - Nikon1MakerNote::Nikon1MakerNote(bool alloc) - : IfdMakerNote(nikon1IfdId, alloc) - { - } - - Nikon1MakerNote::Nikon1MakerNote(const Nikon1MakerNote& rhs) - : IfdMakerNote(rhs) - { - } - - Nikon1MakerNote::AutoPtr Nikon1MakerNote::create(bool alloc) const - { - return AutoPtr(create_(alloc)); - } - - Nikon1MakerNote* Nikon1MakerNote::create_(bool alloc) const - { - return new Nikon1MakerNote(alloc); - } - - Nikon1MakerNote::AutoPtr Nikon1MakerNote::clone() const - { - return AutoPtr(clone_()); - } - - Nikon1MakerNote* Nikon1MakerNote::clone_() const - { - return new Nikon1MakerNote(*this); - } - std::ostream& Nikon1MakerNote::print0x0002(std::ostream& os, - const Value& value) + const Value& value, + const ExifData*) { if (value.count() > 1) { os << value.toLong(1); @@ -261,7 +222,8 @@ namespace Exiv2 { } std::ostream& Nikon1MakerNote::print0x0007(std::ostream& os, - const Value& value) + const Value& value, + const ExifData*) { std::string focus = value.toString(); if (focus == "AF-C ") os << _("Continuous autofocus"); @@ -271,7 +233,8 @@ namespace Exiv2 { } std::ostream& Nikon1MakerNote::print0x0085(std::ostream& os, - const Value& value) + const Value& value, + const ExifData*) { Rational distance = value.toRational(); if (distance.first == 0) { @@ -292,7 +255,8 @@ namespace Exiv2 { } std::ostream& Nikon1MakerNote::print0x0086(std::ostream& os, - const Value& value) + const Value& value, + const ExifData*) { Rational zoom = value.toRational(); if (zoom.first == 0) { @@ -313,7 +277,8 @@ namespace Exiv2 { } std::ostream& Nikon1MakerNote::print0x0088(std::ostream& os, - const Value& value) + const Value& value, + const ExifData*) { if (value.count() >= 1) { unsigned long focusArea = value.toLong(0); @@ -380,14 +345,6 @@ namespace Exiv2 { return os; } - //! @cond IGNORE - Nikon2MakerNote::RegisterMn::RegisterMn() - { - MakerNoteFactory::registerMakerNote( - nikon2IfdId, MakerNote::AutoPtr(new Nikon2MakerNote)); - } - //! @endcond - //! Quality, tag 0x0003 extern const TagDetails nikon2Quality[] = { { 1, N_("VGA Basic") }, @@ -478,69 +435,9 @@ namespace Exiv2 { return tagInfo_; } - Nikon2MakerNote::Nikon2MakerNote(bool alloc) - : IfdMakerNote(nikon2IfdId, alloc) - { - byte buf[] = { - 'N', 'i', 'k', 'o', 'n', '\0', 0x00, 0x01 - }; - readHeader(buf, 8, byteOrder_); - } - - Nikon2MakerNote::Nikon2MakerNote(const Nikon2MakerNote& rhs) - : IfdMakerNote(rhs) - { - } - - int Nikon2MakerNote::readHeader(const byte* buf, - long len, - ByteOrder /*byteOrder*/) - { - if (len < 8) return 1; - - header_.alloc(8); - std::memcpy(header_.pData_, buf, header_.size_); - start_ = 8; - return 0; - } - - int Nikon2MakerNote::checkHeader() const - { - int rc = 0; - // Check the Nikon prefix - if ( header_.size_ < 8 - || std::string(reinterpret_cast(header_.pData_), 6) - != std::string("Nikon\0", 6)) { - rc = 2; - } - return rc; - } - - Nikon2MakerNote::AutoPtr Nikon2MakerNote::create(bool alloc) const - { - return AutoPtr(create_(alloc)); - } - - Nikon2MakerNote* Nikon2MakerNote::create_(bool alloc) const - { - AutoPtr makerNote(new Nikon2MakerNote(alloc)); - assert(makerNote.get() != 0); - makerNote->readHeader(header_.pData_, header_.size_, byteOrder_); - return makerNote.release(); - } - - Nikon2MakerNote::AutoPtr Nikon2MakerNote::clone() const - { - return AutoPtr(clone_()); - } - - Nikon2MakerNote* Nikon2MakerNote::clone_() const - { - return new Nikon2MakerNote(*this); - } - std::ostream& Nikon2MakerNote::print0x000a(std::ostream& os, - const Value& value) + const Value& value, + const ExifData*) { Rational zoom = value.toRational(); if (zoom.first == 0) { @@ -560,14 +457,6 @@ namespace Exiv2 { return os; } - //! @cond IGNORE - Nikon3MakerNote::RegisterMn::RegisterMn() - { - MakerNoteFactory::registerMakerNote( - nikon3IfdId, MakerNote::AutoPtr(new Nikon3MakerNote)); - } - //! @endcond - // Nikon3 MakerNote Tag Info const TagInfo Nikon3MakerNote::tagInfo_[] = { TagInfo(0x0001, "Version", N_("Version"), @@ -800,75 +689,9 @@ namespace Exiv2 { return tagInfo_; } - Nikon3MakerNote::Nikon3MakerNote(bool alloc) - : IfdMakerNote(nikon3IfdId, alloc) - { - absShift_ = false; - byte buf[] = { - 'N', 'i', 'k', 'o', 'n', '\0', - 0x02, 0x10, 0x00, 0x00, 0x4d, 0x4d, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x08 - }; - readHeader(buf, 18, byteOrder_); - } - - Nikon3MakerNote::Nikon3MakerNote(const Nikon3MakerNote& rhs) - : IfdMakerNote(rhs) - { - } - - int Nikon3MakerNote::readHeader(const byte* buf, - long len, - ByteOrder /*byteOrder*/) - { - if (len < 18) return 1; - - header_.alloc(18); - std::memcpy(header_.pData_, buf, header_.size_); - TiffHeader tiffHeader; - tiffHeader.read(header_.pData_ + 10); - byteOrder_ = tiffHeader.byteOrder(); - start_ = 10 + tiffHeader.offset(); - shift_ = 10; - return 0; - } - - int Nikon3MakerNote::checkHeader() const - { - int rc = 0; - // Check the Nikon prefix - if ( header_.size_ < 18 - || std::string(reinterpret_cast(header_.pData_), 6) - != std::string("Nikon\0", 6)) { - rc = 2; - } - return rc; - } - - Nikon3MakerNote::AutoPtr Nikon3MakerNote::create(bool alloc) const - { - return AutoPtr(create_(alloc)); - } - - Nikon3MakerNote* Nikon3MakerNote::create_(bool alloc) const - { - AutoPtr makerNote(new Nikon3MakerNote(alloc)); - assert(makerNote.get() != 0); - makerNote->readHeader(header_.pData_, header_.size_, byteOrder_); - return makerNote.release(); - } - - Nikon3MakerNote::AutoPtr Nikon3MakerNote::clone() const - { - return AutoPtr(clone_()); - } - - Nikon3MakerNote* Nikon3MakerNote::clone_() const - { - return new Nikon3MakerNote(*this); - } - std::ostream& Nikon3MakerNote::print0x0002(std::ostream& os, - const Value& value) + const Value& value, + const ExifData*) { if (value.count() > 1) { os << value.toLong(1); @@ -880,7 +703,8 @@ namespace Exiv2 { } std::ostream& Nikon3MakerNote::print0x0007(std::ostream& os, - const Value& value) + const Value& value, + const ExifData*) { std::string focus = value.toString(); if (focus == "AF-C ") os << _("Continuous autofocus"); @@ -890,7 +714,8 @@ namespace Exiv2 { } std::ostream& Nikon3MakerNote::print0x0083(std::ostream& os, - const Value& value) + const Value& value, + const ExifData*) { long lensType = value.toLong(); @@ -923,7 +748,8 @@ namespace Exiv2 { } std::ostream& Nikon3MakerNote::print0x0084(std::ostream& os, - const Value& value) + const Value& value, + const ExifData*) { if ( value.count() != 4 || value.toRational(0).second == 0 @@ -954,7 +780,8 @@ namespace Exiv2 { } std::ostream& Nikon3MakerNote::print0x0085(std::ostream& os, - const Value& value) + const Value& value, + const ExifData*) { Rational distance = value.toRational(); if (distance.first == 0) { @@ -975,7 +802,8 @@ namespace Exiv2 { } std::ostream& Nikon3MakerNote::print0x0086(std::ostream& os, - const Value& value) + const Value& value, + const ExifData*) { Rational zoom = value.toRational(); if (zoom.first == 0) { @@ -996,7 +824,8 @@ namespace Exiv2 { } std::ostream& Nikon3MakerNote::print0x0088(std::ostream& os, - const Value& value) + const Value& value, + const ExifData*) { if (value.size() != 4) { // Size is 4 even for those who map this way... os << "(" << value << ")"; @@ -1064,7 +893,8 @@ namespace Exiv2 { } std::ostream& Nikon3MakerNote::print0x008b(std::ostream& os, - const Value& value) + const Value& value, + const ExifData*) { // Decoded by Robert Rottmerhusen if ( value.size() != 4 @@ -1079,7 +909,8 @@ namespace Exiv2 { } std::ostream& Nikon3MakerNote::print0x0098(std::ostream& os, - const Value& value) + const Value& value, + const ExifData*) { #ifdef EXV_HAVE_LENSDATA //#----------------------------------------- @@ -1448,9 +1279,9 @@ namespace Exiv2 { idx = 11; } else if (0 == memcmp(lens.pData_, "0201", 4)) { - // Here we should decrypt(lens.pData_ + 4, lens.size_ - 4); - // however, the decrypt algorithm requires access to serial number - // and shutter count tags but print functions are static... + // Todo: decrypt(lens.pData_ + 4, lens.size_ - 4); + // The decrypt algorithm requires access to serial number + // and shutter count tags idx = 11; } if (idx == 0 || lens.size_ < idx + 7) { @@ -1476,29 +1307,4 @@ namespace Exiv2 { #endif // EXV_HAVE_LENSDATA } -// ***************************************************************************** -// free functions - - MakerNote::AutoPtr createNikonMakerNote(bool alloc, - const byte* buf, - long len, - ByteOrder /*byteOrder*/, - long /*offset*/) - { - // If there is no "Nikon" string it must be Nikon1 format - if (len < 6 || std::string(reinterpret_cast(buf), 6) - != std::string("Nikon\0", 6)) { - return MakerNote::AutoPtr(new Nikon1MakerNote(alloc)); - } - // If the "Nikon" string is not followed by a TIFF header, we assume - // Nikon2 format - TiffHeader tiffHeader; - if ( len < 18 - || tiffHeader.read(buf + 10) != 0 || tiffHeader.tag() != 0x002a) { - return MakerNote::AutoPtr(new Nikon2MakerNote(alloc)); - } - // Else we have a Nikon3 makernote - return MakerNote::AutoPtr(new Nikon3MakerNote(alloc)); - } - } // namespace Exiv2 diff --git a/src/nikonmn.hpp b/src/nikonmn.hpp index 515ce82a..918d7991 100644 --- a/src/nikonmn.hpp +++ b/src/nikonmn.hpp @@ -42,8 +42,6 @@ // ***************************************************************************** // included header files -#include "types.hpp" -#include "makernote.hpp" #include "tags.hpp" // + standard includes @@ -55,246 +53,90 @@ // namespace extensions namespace Exiv2 { -// ***************************************************************************** -// class declarations - class Value; - -// ***************************************************************************** -// free functions - - /*! - @brief Return an auto-pointer to a newly created empty MakerNote - initialized to operate in the memory management model indicated. - The caller owns this copy and the auto-pointer ensures that it - will be deleted. - - @param alloc Memory management model for the new MakerNote. Determines if - memory required to store data should be allocated and deallocated - (true) or not (false). If false, only pointers to the buffer - provided to read() will be kept. See Ifd for more background on - this concept. - @param buf Pointer to the makernote character buffer (not used). - @param len Length of the makernote character buffer (not used). - @param byteOrder Byte order in which the Exif data (and possibly the - makernote) is encoded (not used). - @param offset Offset from the start of the TIFF header of the makernote - buffer (not used). - - @return An auto-pointer to a newly created empty MakerNote. The caller - owns this copy and the auto-pointer ensures that it will be - deleted. - */ - MakerNote::AutoPtr createNikonMakerNote(bool alloc, - const byte* buf, - long len, - ByteOrder byteOrder, - long offset); - // ***************************************************************************** // class definitions //! A MakerNote format used by Nikon cameras, such as the E990 and D1. - class Nikon1MakerNote : public IfdMakerNote { + class Nikon1MakerNote { public: - //! Shortcut for a %Nikon1MakerNote auto pointer. - typedef std::auto_ptr AutoPtr; - - //! @name Creators - //@{ - /*! - @brief Constructor. Allows to choose whether or not memory management - is required for the makernote entries. - */ - Nikon1MakerNote(bool alloc =true); - //! Copy constructor - Nikon1MakerNote(const Nikon1MakerNote& rhs); - //! Virtual destructor - virtual ~Nikon1MakerNote() {} - //@} - - //! @name Accessors - //@{ - AutoPtr create(bool alloc =true) const; - AutoPtr clone() const; //! 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); + 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); + 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); + 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); + 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); + static std::ostream& print0x0088(std::ostream& os, const Value& value, const ExifData*); //@} - //! @cond IGNORE - // Public only so that we can create a static instance - struct RegisterMn { - RegisterMn(); - }; - //! @endcond - private: - //! Internal virtual create function. - Nikon1MakerNote* create_(bool alloc =true) const; - //! Internal virtual copy constructor. - Nikon1MakerNote* clone_() const; - //! Tag information static const TagInfo tagInfo_[]; }; // class Nikon1MakerNote - static Nikon1MakerNote::RegisterMn registerNikon1MakerNote; - /*! @brief A second MakerNote format used by Nikon cameras, including the E700, E800, E900, E900S, E910, E950 */ - class Nikon2MakerNote : public IfdMakerNote { + class Nikon2MakerNote { public: - //! Shortcut for a %Nikon2MakerNote auto pointer. - typedef std::auto_ptr AutoPtr; - - //! @name Creators - //@{ - /*! - @brief Constructor. Allows to choose whether or not memory management - is required for the makernote entries. - */ - Nikon2MakerNote(bool alloc =true); - //! Copy constructor - Nikon2MakerNote(const Nikon2MakerNote& rhs); - //! Virtual destructor - virtual ~Nikon2MakerNote() {} - //@} - - //! @name Manipulators - //@{ - int readHeader(const byte* buf, - long len, - ByteOrder byteOrder); - //@} - - //! @name Accessors - //@{ - int checkHeader() const; - AutoPtr create(bool alloc =true) const; - AutoPtr clone() const; //! 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); + static std::ostream& print0x000a(std::ostream& os, const Value& value, const ExifData*); //@} - //! @cond IGNORE - // Public only so that we can create a static instance - struct RegisterMn { - RegisterMn(); - }; - //! @endcond - private: - //! Internal virtual create function. - Nikon2MakerNote* create_(bool alloc =true) const; - //! Internal virtual copy constructor. - Nikon2MakerNote* clone_() const; - //! Tag information static const TagInfo tagInfo_[]; }; // class Nikon2MakerNote - static Nikon2MakerNote::RegisterMn registerNikon2MakerNote; - //! A third MakerNote format used by Nikon cameras, e.g., E5400, SQ, D2H, D70 - class Nikon3MakerNote : public IfdMakerNote { + class Nikon3MakerNote { public: - //! Shortcut for a %Nikon3MakerNote auto pointer. - typedef std::auto_ptr AutoPtr; - - //! @name Creators - //@{ - /*! - @brief Constructor. Allows to choose whether or not memory management - is required for the makernote entries. - */ - Nikon3MakerNote(bool alloc =true); - //! Copy constructor - Nikon3MakerNote(const Nikon3MakerNote& rhs); - //! Virtual destructor - virtual ~Nikon3MakerNote() {} - //@} - - //! @name Manipulators - //@{ - int readHeader(const byte* buf, - long len, - ByteOrder byteOrder); - //@} - - //! @name Accessors - //@{ - int checkHeader() const; - AutoPtr create(bool alloc =true) const; - AutoPtr clone() const; //! Return read-only list of built-in Nikon3 tags static const TagInfo* tagList(); - //@} //! @name Print functions for Nikon3 %MakerNote tags //@{ //! Print ISO setting - static std::ostream& print0x0002(std::ostream& os, const Value& value); + 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); + 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); + 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); + 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); + 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); + 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); + static std::ostream& print0x0088(std::ostream& os, const Value& value, const ExifData*); //! Print number of lens stops - static std::ostream& print0x008b(std::ostream& os, const Value& value); + static std::ostream& print0x008b(std::ostream& os, const Value& value, const ExifData*); //! Print number of lens data - static std::ostream& print0x0098(std::ostream& os, const Value& value); + static std::ostream& print0x0098(std::ostream& os, const Value& value, const ExifData*); //@} - //! @cond IGNORE - // Public only so that we can create a static instance - struct RegisterMn { - RegisterMn(); - }; - //! @endcond - private: - //! Internal virtual create function. - Nikon3MakerNote* create_(bool alloc =true) const; - //! Internal virtual copy constructor. - Nikon3MakerNote* clone_() const; - //! Tag information static const TagInfo tagInfo_[]; }; // class Nikon3MakerNote - static Nikon3MakerNote::RegisterMn registerNikon3MakerNote; - } // namespace Exiv2 #endif // #ifndef NIKONMN_HPP_ diff --git a/src/olympusmn.cpp b/src/olympusmn.cpp index cf9074c1..dedb1635 100644 --- a/src/olympusmn.cpp +++ b/src/olympusmn.cpp @@ -36,7 +36,6 @@ EXIV2_RCSID("@(#) $Id$") // included header files #include "types.hpp" #include "olympusmn.hpp" -#include "makernote.hpp" #include "value.hpp" #include "i18n.h" // NLS support. @@ -404,76 +403,7 @@ namespace Exiv2 { return tagInfo_; } - //! @cond IGNORE - OlympusMakerNote::RegisterMn::RegisterMn() - { - MakerNoteFactory::registerMakerNote("OLYMPUS*", "*", createOlympusMakerNote); - MakerNoteFactory::registerMakerNote(olympusIfdId, MakerNote::AutoPtr(new OlympusMakerNote)); - } - //! @endcond - - OlympusMakerNote::OlympusMakerNote(bool alloc) - : IfdMakerNote(olympusIfdId, alloc) - { - byte buf[] = { - 'O', 'L', 'Y', 'M', 'P', 0x00, 0x01, 0x00 - }; - readHeader(buf, 8, byteOrder_); - } - - OlympusMakerNote::OlympusMakerNote(const OlympusMakerNote& rhs) - : IfdMakerNote(rhs) - { - } - - int OlympusMakerNote::readHeader(const byte* buf, long len, ByteOrder /*byteOrder*/) - { - if (len < 8) return 1; - - // Copy the header - header_.alloc(8); - std::memcpy(header_.pData_, buf, header_.size_); - // Adjust the offset of the IFD for the prefix - start_ = 8; - return 0; - } - - int OlympusMakerNote::checkHeader() const - { - int rc = 0; - // Check the OLYMPUS prefix - if ( header_.size_ < 8 - || std::string(reinterpret_cast(header_.pData_), 5) - != std::string("OLYMP", 5)) { - rc = 2; - } - return rc; - } - - OlympusMakerNote::AutoPtr OlympusMakerNote::create(bool alloc) const - { - return AutoPtr(create_(alloc)); - } - - OlympusMakerNote* OlympusMakerNote::create_(bool alloc) const - { - AutoPtr makerNote(new OlympusMakerNote(alloc)); - assert(makerNote.get() != 0); - makerNote->readHeader(header_.pData_, header_.size_, byteOrder_); - return makerNote.release(); - } - - OlympusMakerNote::AutoPtr OlympusMakerNote::clone() const - { - return AutoPtr(clone_()); - } - - OlympusMakerNote* OlympusMakerNote::clone_() const - { - return new OlympusMakerNote(*this); - } - - std::ostream& OlympusMakerNote::print0x0200(std::ostream& os, const Value& value) + std::ostream& OlympusMakerNote::print0x0200(std::ostream& os, const Value& value, const ExifData*) { if (value.count() != 3 || value.typeId() != unsignedLong) { return os << value; @@ -504,7 +434,7 @@ namespace Exiv2 { return os; } // OlympusMakerNote::print0x0200 - std::ostream& OlympusMakerNote::print0x0204(std::ostream& os, const Value& value) + std::ostream& OlympusMakerNote::print0x0204(std::ostream& os, const Value& value, const ExifData*) { if ( value.count() == 0 || value.toRational().second == 0) { @@ -519,7 +449,7 @@ namespace Exiv2 { return os; } // OlympusMakerNote::print0x0204 - std::ostream& OlympusMakerNote::print0x1015(std::ostream& os, const Value& value) + std::ostream& OlympusMakerNote::print0x1015(std::ostream& os, const Value& value, const ExifData*) { if (value.count() != 2 || value.typeId() != unsignedShort) { return os << value; @@ -561,13 +491,4 @@ namespace Exiv2 { return os; } // OlympusMakerNote::print0x1015 -// ***************************************************************************** -// free functions - - MakerNote::AutoPtr createOlympusMakerNote(bool alloc, const byte* /*buf*/, long /*len*/, - ByteOrder /*byteOrder*/, long /*offset*/) - { - return MakerNote::AutoPtr(new OlympusMakerNote(alloc)); - } - } // namespace Exiv2 diff --git a/src/olympusmn.hpp b/src/olympusmn.hpp index e84d853c..0abf074c 100644 --- a/src/olympusmn.hpp +++ b/src/olympusmn.hpp @@ -40,7 +40,6 @@ // ***************************************************************************** // included header files #include "types.hpp" -#include "makernote.hpp" #include "tags.hpp" // + standard includes @@ -52,108 +51,31 @@ // namespace extensions namespace Exiv2 { -// ***************************************************************************** -// class declarations - class Value; - -// ***************************************************************************** -// free functions - - /*! - @brief Return an auto-pointer to a newly created empty MakerNote - initialized to operate in the memory management model indicated. - The caller owns this copy and the auto-pointer ensures that it - will be deleted. - - @param alloc Memory management model for the new MakerNote. Determines if - memory required to store data should be allocated and deallocated - (true) or not (false). If false, only pointers to the buffer - provided to read() will be kept. See Ifd for more background on - this concept. - @param buf Pointer to the makernote character buffer (not used). - @param len Length of the makernote character buffer (not used). - @param byteOrder Byte order in which the Exif data (and possibly the - makernote) is encoded (not used). - @param offset Offset from the start of the TIFF header of the makernote - buffer (not used). - - @return An auto-pointer to a newly created empty MakerNote. The caller - owns this copy and the auto-pointer ensures that it will be - deleted. - */ - MakerNote::AutoPtr createOlympusMakerNote(bool alloc, - const byte* buf, - long len, - ByteOrder byteOrder, - long offset); - // ***************************************************************************** // class definitions //! MakerNote for Olympus cameras - class OlympusMakerNote : public IfdMakerNote { + class OlympusMakerNote { public: - //! Shortcut for a %OlympusMakerNote auto pointer. - typedef std::auto_ptr AutoPtr; - - //! @name Creators - //@{ - /*! - @brief Constructor. Allows to choose whether or not memory management - is required for the makernote entries. - */ - OlympusMakerNote(bool alloc =true); - //! Copy constructor - OlympusMakerNote(const OlympusMakerNote& rhs); - //! Virtual destructor - virtual ~OlympusMakerNote() {} - //@} - - //! @name Manipulators - //@{ - int readHeader(const byte* buf, - long len, - ByteOrder byteOrder); - //@} - - //! @name Accessors - //@{ - int checkHeader() const; - AutoPtr create(bool alloc =true) const; - AutoPtr clone() const; //! Return read-only list of built-in Olympus tags static const TagInfo* tagList(); - //@} //! @name Print functions for Olympus %MakerNote tags //@{ //! Print 'Special Mode' - static std::ostream& print0x0200(std::ostream& os, const Value& value); + 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); + 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); + static std::ostream& print0x1015(std::ostream& os, const Value& value, const ExifData*); //@} - //! @cond IGNORE - // Public only so that we can create a static instance - struct RegisterMn { - RegisterMn(); - }; - //! @endcond - private: - //! Internal virtual create function. - OlympusMakerNote* create_(bool alloc =true) const; - //! Internal virtual copy constructor. - OlympusMakerNote* clone_() const; - //! Tag information static const TagInfo tagInfo_[]; }; // class OlympusMakerNote - static OlympusMakerNote::RegisterMn registerOlympusMakerNote; } // namespace Exiv2 #endif // #ifndef OLYMPUSMN_HPP_ diff --git a/src/orfimage.cpp b/src/orfimage.cpp index eb70bd02..4689c283 100644 --- a/src/orfimage.cpp +++ b/src/orfimage.cpp @@ -38,7 +38,8 @@ EXIV2_RCSID("@(#) $Id$") #endif #include "orfimage.hpp" -#include "tiffparser.hpp" +#include "orfimage_int.hpp" +#include "tiffimage_int.hpp" #include "image.hpp" #include "basicio.hpp" #include "error.hpp" @@ -54,6 +55,8 @@ EXIV2_RCSID("@(#) $Id$") // class member definitions namespace Exiv2 { + using namespace Internal; + OrfImage::OrfImage(BasicIo::AutoPtr io, bool /*create*/) : Image(ImageType::orf, mdExif | mdIptc, io) { @@ -112,10 +115,12 @@ namespace Exiv2 { throw Error(3, "ORF"); } clearMetadata(); - OrfHeader orfHeader; - TiffParser::decode(this, io_->mmap(), io_->size(), - TiffCreator::create, TiffDecoder::findDecoder, - &orfHeader); + ByteOrder bo = OrfParser::decode(exifData_, + iptcData_, + xmpData_, + io_->mmap(), + io_->size()); + setByteOrder(bo); } // OrfImage::readMetadata void OrfImage::writeMetadata() @@ -124,38 +129,47 @@ namespace Exiv2 { throw(Error(31, "ORF")); } // OrfImage::writeMetadata - OrfHeader::OrfHeader() - : TiffHeaderBase('O'<< 8 | 'R', 8, littleEndian, 0x00000008) - { - } - - OrfHeader::~OrfHeader() + 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, + TiffCreator::create, + TiffMapping::findDecoder, + &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; - } - if (tag() != getUShort(pData + 2, byteOrder())) return false; - setOffset(getULong(pData + 4, byteOrder())); - if (offset() != 0x00000008) return false; - - return true; - } // OrfHeader::read - - void OrfHeader::write(Blob& blob) const + WriteMethod OrfParser::encode( + Blob& blob, + const byte* pData, + uint32_t size, + const ExifData& exifData, + const IptcData& iptcData, + const XmpData& xmpData + ) { - // Todo: Implement me! + /* Todo: Implement me! + + return TiffParserWorker::encode(blob, + pData, + size, + exifData, + iptcData, + xmpData, + TiffCreator::create, + TiffMapping::findEncoder); + */ + blob.clear(); + return wmIntrusive; } // ************************************************************************* @@ -186,3 +200,43 @@ namespace Exiv2 { } } // namespace Exiv2 + +namespace Exiv2 { + namespace Internal { + + OrfHeader::OrfHeader() + : TiffHeaderBase('O'<< 8 | 'R', 8, littleEndian, 0x00000008) + { + } + + 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; + } + if (tag() != getUShort(pData + 2, byteOrder())) return false; + setOffset(getULong(pData + 4, byteOrder())); + if (offset() != 0x00000008) return false; + + return true; + } // OrfHeader::read + + uint32_t OrfHeader::write(Blob& blob) const + { + // Todo: Implement me! + return 0; + } + +}} // namespace Internal, Exiv2 diff --git a/src/orfimage.hpp b/src/orfimage.hpp index b9f48291..de08a527 100644 --- a/src/orfimage.hpp +++ b/src/orfimage.hpp @@ -33,7 +33,7 @@ // included header files #include "image.hpp" #include "basicio.hpp" -#include "tiffimage.hpp" +#include "types.hpp" // + standard includes #include @@ -120,28 +120,38 @@ namespace Exiv2 { }; // class OrfImage /*! - @brief Olympus ORF header structure. + @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 OrfHeader : public TiffHeaderBase { + class OrfParser { public: - //! @name Creators - //@{ - //! Default constructor - OrfHeader(); - //! Destructor. - ~OrfHeader(); - //@} - - //! @name Manipulators - //@{ - bool read(const byte* pData, uint32_t size); - //@} - - //! @name Accessors - //@{ - void write(Blob& blob) const; - //@} - }; // class OrfHeader + /*! + @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( + Blob& blob, + const byte* pData, + uint32_t size, + const ExifData& exifData, + const IptcData& iptcData, + const XmpData& xmpData + ); + + }; // class OrfParser // ***************************************************************************** // template, inline and free functions diff --git a/src/orfimage_int.hpp b/src/orfimage_int.hpp new file mode 100644 index 00000000..37bf2837 --- /dev/null +++ b/src/orfimage_int.hpp @@ -0,0 +1,72 @@ +// ***************************************************************** -*- C++ -*- +/* + * Copyright (C) 2004-2008 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$ + @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(); + //! Destructor. + ~OrfHeader(); + //@} + + //! @name Manipulators + //@{ + bool read(const byte* pData, uint32_t size); + //@} + + //! @name Accessors + //@{ + uint32_t write(Blob& blob) const; + //@} + }; // class OrfHeader + +}} // namespace Internal, Exiv2 + +#endif // #ifndef ORFIMAGE_INT_HPP_ diff --git a/src/panasonicmn.cpp b/src/panasonicmn.cpp index 84e3e01e..3ab44e3a 100644 --- a/src/panasonicmn.cpp +++ b/src/panasonicmn.cpp @@ -34,7 +34,6 @@ EXIV2_RCSID("@(#) $Id$") // included header files #include "types.hpp" #include "panasonicmn.hpp" -#include "makernote.hpp" #include "value.hpp" #include "i18n.h" // NLS support. @@ -49,15 +48,6 @@ EXIV2_RCSID("@(#) $Id$") // class member definitions namespace Exiv2 { - //! @cond IGNORE - PanasonicMakerNote::RegisterMn::RegisterMn() - { - MakerNoteFactory::registerMakerNote("Panasonic", "*", createPanasonicMakerNote); - MakerNoteFactory::registerMakerNote( - panasonicIfdId, MakerNote::AutoPtr(new PanasonicMakerNote)); - } - //! @endcond - //! Quality, tag 0x0001 extern const TagDetails panasonicQuality[] = { { 2, N_("High") }, @@ -284,70 +274,9 @@ namespace Exiv2 { return tagInfo_; } - PanasonicMakerNote::PanasonicMakerNote(bool alloc) - : IfdMakerNote(panasonicIfdId, alloc, false) - { - byte buf[] = { - 'P', 'a', 'n', 'a', 's', 'o', 'n', 'i', 'c', 0x00, 0x00, 0x00 - }; - readHeader(buf, 12, byteOrder_); - } - - PanasonicMakerNote::PanasonicMakerNote(const PanasonicMakerNote& rhs) - : IfdMakerNote(rhs) - { - } - - int PanasonicMakerNote::readHeader(const byte* buf, - long len, - ByteOrder /*byteOrder*/) - { - if (len < 12) return 1; - - header_.alloc(12); - std::memcpy(header_.pData_, buf, header_.size_); - // Adjust the offset of the IFD for the prefix - start_ = 12; - return 0; - } - - int PanasonicMakerNote::checkHeader() const - { - int rc = 0; - // Check the Panasonic prefix - if ( header_.size_ < 12 - || std::string(reinterpret_cast(header_.pData_), 9) - != std::string("Panasonic", 9)) { - rc = 2; - } - return rc; - } - - PanasonicMakerNote::AutoPtr PanasonicMakerNote::create(bool alloc) const - { - return AutoPtr(create_(alloc)); - } - - PanasonicMakerNote* PanasonicMakerNote::create_(bool alloc) const - { - AutoPtr makerNote(new PanasonicMakerNote(alloc)); - assert(makerNote.get() != 0); - makerNote->readHeader(header_.pData_, header_.size_, byteOrder_); - return makerNote.release(); - } - - PanasonicMakerNote::AutoPtr PanasonicMakerNote::clone() const - { - return AutoPtr(clone_()); - } - - PanasonicMakerNote* PanasonicMakerNote::clone_() const - { - return new PanasonicMakerNote(*this); - } - std::ostream& PanasonicMakerNote::print0x000f(std::ostream& os, - const Value& value) + const Value& value, + const ExifData*) { if (value.count() < 2 || value.typeId() != unsignedByte) { return os << value; @@ -360,7 +289,8 @@ namespace Exiv2 { } // PanasonicMakerNote::print0x000f std::ostream& PanasonicMakerNote::print0x0023(std::ostream& os, - const Value& value) + const Value& value, + const ExifData*) { std::ostringstream oss; oss.copyfmt(os); @@ -372,16 +302,4 @@ namespace Exiv2 { } // PanasonicMakerNote::print0x0023 -// ***************************************************************************** -// free functions - - MakerNote::AutoPtr createPanasonicMakerNote(bool alloc, - const byte* /*buf*/, - long /*len*/, - ByteOrder /*byteOrder*/, - long /*offset*/) - { - return MakerNote::AutoPtr(new PanasonicMakerNote(alloc)); - } - } // namespace Exiv2 diff --git a/src/panasonicmn.hpp b/src/panasonicmn.hpp index b1bc6d02..465b3262 100644 --- a/src/panasonicmn.hpp +++ b/src/panasonicmn.hpp @@ -37,118 +37,39 @@ // ***************************************************************************** // included header files #include "types.hpp" -#include "makernote.hpp" #include "tags.hpp" // + standard includes #include #include -#include // ***************************************************************************** // namespace extensions namespace Exiv2 { -// ***************************************************************************** -// class declarations - class Value; - -// ***************************************************************************** -// free functions - - /*! - @brief Return an auto-pointer to a newly created empty MakerNote - initialized to operate in the memory management model indicated. - The caller owns this copy and the auto-pointer ensures that it - will be deleted. - - @param alloc Memory management model for the new MakerNote. Determines if - memory required to store data should be allocated and deallocated - (true) or not (false). If false, only pointers to the buffer - provided to read() will be kept. See Ifd for more background on - this concept. - @param buf Pointer to the makernote character buffer (not used). - @param len Length of the makernote character buffer (not used). - @param byteOrder Byte order in which the Exif data (and possibly the - makernote) is encoded (not used). - @param offset Offset from the start of the TIFF header of the makernote - buffer (not used). - - @return An auto-pointer to a newly created empty MakerNote. The caller - owns this copy and the auto-pointer ensures that it will be - deleted. - */ - MakerNote::AutoPtr createPanasonicMakerNote(bool alloc, - const byte* buf, - long len, - ByteOrder byteOrder, - long offset); - // ***************************************************************************** // class definitions //! MakerNote for Panasonic cameras - class PanasonicMakerNote : public IfdMakerNote { + class PanasonicMakerNote { public: - //! Shortcut for a %PanasonicMakerNote auto pointer. - typedef std::auto_ptr AutoPtr; - - //! @name Creators - //@{ - /*! - @brief Constructor. Allows to choose whether or not memory management - is required for the makernote entries. - */ - PanasonicMakerNote(bool alloc =true); - //! Copy constructor - PanasonicMakerNote(const PanasonicMakerNote& rhs); - //! Virtual destructor - virtual ~PanasonicMakerNote() {} - //@} - - //! @name Manipulators - //@{ - int readHeader(const byte* buf, - long len, - ByteOrder byteOrder); - //@} - - //! @name Accessors - //@{ - int checkHeader() const; - AutoPtr create(bool alloc =true) const; - AutoPtr clone() const; //! Return read-only list of built-in Panasonic tags static const TagInfo* tagList(); - //@} //! @name Print functions for Panasonic %MakerNote tags //@{ //! Print SpotMode - static std::ostream& print0x000f(std::ostream& os, const Value& value); + static std::ostream& print0x000f(std::ostream& os, const Value& value, const ExifData*); //! Print WhiteBalanceBias - static std::ostream& print0x0023(std::ostream& os, const Value& value); + static std::ostream& print0x0023(std::ostream& os, const Value& value, const ExifData*); //@} - //! @cond IGNORE - // Public only so that we can create a static instance - struct RegisterMn { - RegisterMn(); - }; - //! @endcond - private: - //! Internal virtual create function. - PanasonicMakerNote* create_(bool alloc =true) const; - //! Internal virtual copy constructor. - PanasonicMakerNote* clone_() const; - //! Tag information static const TagInfo tagInfo_[]; }; // class PanasonicMakerNote - static PanasonicMakerNote::RegisterMn registerPanasonicMakerNote; } // namespace Exiv2 #endif // #ifndef PANASONICMN_HPP_ diff --git a/src/pentaxmn.cpp b/src/pentaxmn.cpp index 65ecffd9..28b65c66 100644 --- a/src/pentaxmn.cpp +++ b/src/pentaxmn.cpp @@ -36,7 +36,6 @@ EXIV2_RCSID("@(#) $Id$") // included header files #include "types.hpp" #include "pentaxmn.hpp" -#include "makernote.hpp" #include "value.hpp" #include "i18n.h" // NLS support. @@ -51,15 +50,6 @@ EXIV2_RCSID("@(#) $Id$") // class member definitions namespace Exiv2 { - //! @cond IGNORE - PentaxMakerNote::RegisterMn::RegisterMn() - { - MakerNoteFactory::registerMakerNote("PENTAX*", "*", createPentaxMakerNote); - MakerNoteFactory::registerMakerNote( - pentaxIfdId, MakerNote::AutoPtr(new PentaxMakerNote)); - } - //! @endcond - //! ShootingMode, tag 0x0001 extern const TagDetails pentaxShootingMode[] = { { 0, N_("Auto") }, @@ -650,7 +640,7 @@ namespace Exiv2 { { 3, N_("Strong") }, }; - std::ostream& PentaxMakerNote::printPentaxVersion(std::ostream& os, const Value& value) + std::ostream& PentaxMakerNote::printPentaxVersion(std::ostream& os, const Value& value, const ExifData*) { std::string val = value.toString(); size_t i; @@ -661,7 +651,7 @@ namespace Exiv2 { return os; } - std::ostream& PentaxMakerNote::printPentaxResolution(std::ostream& os, const Value& value) + std::ostream& PentaxMakerNote::printPentaxResolution(std::ostream& os, const Value& value, const ExifData*) { std::string val = value.toString(); size_t i; @@ -672,7 +662,7 @@ namespace Exiv2 { return os; } - std::ostream& PentaxMakerNote::printPentaxDate(std::ostream& os, const Value& value) + 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)); @@ -683,7 +673,7 @@ namespace Exiv2 { return os; } - std::ostream& PentaxMakerNote::printPentaxTime(std::ostream& os, const Value& value) + std::ostream& PentaxMakerNote::printPentaxTime(std::ostream& os, const Value& value, const ExifData*) { os << std::setw(2) << std::setfill('0') << value.toLong(0); os << ":"; @@ -693,20 +683,20 @@ namespace Exiv2 { return os; } - std::ostream& PentaxMakerNote::printPentaxExposure(std::ostream& os, const Value& value) + 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) + 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) + std::ostream& PentaxMakerNote::printPentaxFocalLength(std::ostream& os, const Value& value, const ExifData*) { os << std::fixed << std::setprecision(1) << static_cast(value.toLong()) / 100 @@ -714,7 +704,7 @@ namespace Exiv2 { return os; } - std::ostream& PentaxMakerNote::printPentaxCompensation(std::ostream& os, const Value& value) + std::ostream& PentaxMakerNote::printPentaxCompensation(std::ostream& os, const Value& value, const ExifData*) { os << std::setprecision(2) << (static_cast(value.toLong()) - 50) / 10 @@ -722,13 +712,13 @@ namespace Exiv2 { return os; } - std::ostream& PentaxMakerNote::printPentaxTemperature(std::ostream& os, const Value& value) + 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) + std::ostream& PentaxMakerNote::printPentaxFlashCompensation(std::ostream& os, const Value& value, const ExifData*) { os << std::setprecision(2) << static_cast(value.toLong()) / 256 @@ -736,7 +726,7 @@ namespace Exiv2 { return os; } - std::ostream& PentaxMakerNote::printPentaxBracketing(std::ostream& os, const Value& value) + std::ostream& PentaxMakerNote::printPentaxBracketing(std::ostream& os, const Value& value, const ExifData*) { long l0 = value.toLong(0); @@ -1036,77 +1026,4 @@ namespace Exiv2 { return tagInfo_; } - PentaxMakerNote::PentaxMakerNote(bool alloc) - : IfdMakerNote(pentaxIfdId, alloc) - { - byte buf[] = { - 'A', 'O', 'C', 0x00, 'M', 'M' - }; - readHeader(buf, 6, byteOrder_); - } - - PentaxMakerNote::PentaxMakerNote(const PentaxMakerNote& rhs) - : IfdMakerNote(rhs) - { - } - - int PentaxMakerNote::readHeader(const byte* buf, - long len, - ByteOrder /*byteOrder*/) - { - if (len < 6) return 1; - - header_.alloc(6); - std::memcpy(header_.pData_, buf, header_.size_); - start_ = 6; - return 0; - } - - int PentaxMakerNote::checkHeader() const - { - int rc = 0; - // Check the AOC prefix - if ( header_.size_ < 6 - || std::string(reinterpret_cast(header_.pData_), 3) - != std::string("AOC", 3)) { - rc = 2; - } - return rc; - } - - PentaxMakerNote::AutoPtr PentaxMakerNote::create(bool alloc) const - { - return AutoPtr(create_(alloc)); - } - - PentaxMakerNote* PentaxMakerNote::create_(bool alloc) const - { - AutoPtr makerNote(new PentaxMakerNote(alloc)); - assert(makerNote.get() != 0); - makerNote->readHeader(header_.pData_, header_.size_, byteOrder_); - return makerNote.release(); - } - - PentaxMakerNote::AutoPtr PentaxMakerNote::clone() const - { - return AutoPtr(clone_()); - } - - PentaxMakerNote* PentaxMakerNote::clone_() const - { - return new PentaxMakerNote(*this); - } - -// ***************************************************************************** -// free functions - - MakerNote::AutoPtr createPentaxMakerNote(bool alloc, - const byte* /*buf*/, - long /*len*/, - ByteOrder /*byteOrder*/, - long /*offset*/) - { - return MakerNote::AutoPtr(new PentaxMakerNote(alloc)); - } - } // namespace Exiv2 diff --git a/src/pentaxmn.hpp b/src/pentaxmn.hpp index dd2c40df..8602ef09 100644 --- a/src/pentaxmn.hpp +++ b/src/pentaxmn.hpp @@ -35,7 +35,6 @@ // ***************************************************************************** // included header files #include "types.hpp" -#include "makernote.hpp" #include "tags.hpp" // + standard includes @@ -48,135 +47,57 @@ // namespace extensions namespace Exiv2 { -// ***************************************************************************** -// class declarations - class Value; - -// ***************************************************************************** -// free functions - - /*! - @brief Return an auto-pointer to a newly created empty MakerNote - initialized to operate in the memory management model indicated. - The caller owns this copy and the auto-pointer ensures that it - will be deleted. - - @param alloc Memory management model for the new MakerNote. Determines if - memory required to store data should be allocated and deallocated - (true) or not (false). If false, only pointers to the buffer - provided to read() will be kept. See Ifd for more background on - this concept. - @param buf Pointer to the makernote character buffer (not used). - @param len Length of the makernote character buffer (not used). - @param byteOrder Byte order in which the Exif data (and possibly the - makernote) is encoded (not used). - @param offset Offset from the start of the TIFF header of the makernote - buffer (not used). - - @return An auto-pointer to a newly created empty MakerNote. The caller - owns this copy and the auto-pointer ensures that it will be - deleted. - */ - MakerNote::AutoPtr createPentaxMakerNote(bool alloc, - const byte* buf, - long len, - ByteOrder byteOrder, - long offset); - // ***************************************************************************** // class definitions //! MakerNote for Pentaxfilm cameras - class PentaxMakerNote : public IfdMakerNote { + class PentaxMakerNote { public: - //! Shortcut for a %PentaxMakerNote auto pointer. - typedef std::auto_ptr AutoPtr; - - //! @name Creators - //@{ - /*! - @brief Constructor. Allows to choose whether or not memory management - is required for the makernote entries. - */ - PentaxMakerNote(bool alloc =true); - //! Copy constructor - PentaxMakerNote(const PentaxMakerNote& rhs); - //! Virtual destructor - virtual ~PentaxMakerNote() {} - //@} - - //! @name Manipulators - //@{ - int readHeader(const byte* buf, - long len, - ByteOrder byteOrder); - //@} - - //! @name Accessors - //@{ - int checkHeader() const; - AutoPtr create(bool alloc =true) const; - AutoPtr clone() const; //! Return read-only list of built-in Pentaxfilm tags static const TagInfo* tagList(); - //@} - - //! @cond IGNORE - // Public only so that we can create a static instance - struct RegisterMn { - RegisterMn(); - }; - //! @endcond //! Print Pentax version - static std::ostream& printPentaxVersion(std::ostream& os, const Value& value); + 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); + 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); + 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); + 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); + 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); + 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); + 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); + 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); + 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); + 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); + static std::ostream& printPentaxBracketing(std::ostream& os, const Value& value, const ExifData*); private: - //! Internal virtual create function. - PentaxMakerNote* create_(bool alloc =true) const; - //! Internal virtual copy constructor. - PentaxMakerNote* clone_() const; - //! Tag information static const TagInfo tagInfo_[]; }; // class PentaxMakerNote - static PentaxMakerNote::RegisterMn registerPentaxMakerNote; - /*! @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) + std::ostream& printCombiTag(std::ostream& os, const Value& value, const ExifData* metadata) { if ((value.count() != count && value.count() != (count + ignoredcount)) || count > 4) { - return printValue(os, value); + 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); + return printValue(os, value, metadata); } l += (value.toLong(c) << ((count - c - 1) * 8)); } diff --git a/src/pngchunk.cpp b/src/pngchunk.cpp index f4f46bc2..90f3242b 100644 --- a/src/pngchunk.cpp +++ b/src/pngchunk.cpp @@ -48,7 +48,7 @@ EXIV2_RCSID("@(#) $Id: pngchunk.cpp 823 2006-06-23 07:35:00Z cgilles $") #include #include "pngchunk.hpp" -#include "tiffparser.hpp" +#include "tiffimage.hpp" #include "exif.hpp" #include "iptc.hpp" #include "image.hpp" @@ -317,8 +317,12 @@ namespace Exiv2 { std::cerr << "Exiv2::PngChunk::decode: Exif header found at position " << pos << "\n"; #endif pos = pos + sizeof(exifHeader); - TiffParser::decode(pImage, exifData.pData_ + pos, length - pos, - TiffCreator::create, TiffDecoder::findDecoder); + ByteOrder bo = TiffParser::decode(pImage->exifData(), + pImage->iptcData(), + pImage->xmpData(), + exifData.pData_ + pos, + length - pos); + pImage->setByteOrder(bo); } } } @@ -332,7 +336,7 @@ namespace Exiv2 { long length = iptcData.size_; if (length > 0) - pImage->iptcData().load(iptcData.pData_, length); + IptcParser::decode(pImage->iptcData(), iptcData.pData_, length); } // We look if an ImageMagick XMP raw profile exist. diff --git a/src/properties.cpp b/src/properties.cpp index 65a3b2f4..bb18fa64 100644 --- a/src/properties.cpp +++ b/src/properties.cpp @@ -817,7 +817,7 @@ namespace Exiv2 { const XmpPrintInfo* info = find(xmpPrintInfo, key); if (info) fct = info->printFct_; } - return fct(os, value); + return fct(os, value, 0); } //! @cond IGNORE diff --git a/src/psdimage.cpp b/src/psdimage.cpp index 21ab8f1e..06d4057a 100644 --- a/src/psdimage.cpp +++ b/src/psdimage.cpp @@ -256,7 +256,7 @@ namespace Exiv2 { DataBuf rawIPTC(resourceSize); io_->read(rawIPTC.pData_, rawIPTC.size_); if (io_->error() || io_->eof()) throw Error(14); - if (iptcData_.load(rawIPTC.pData_, rawIPTC.size_)) { + if (IptcParser::decode(iptcData_, rawIPTC.pData_, rawIPTC.size_)) { #ifndef SUPPRESS_WARNINGS std::cerr << "Warning: Failed to decode IPTC metadata.\n"; #endif @@ -270,7 +270,9 @@ namespace Exiv2 { DataBuf rawExif(resourceSize); io_->read(rawExif.pData_, rawExif.size_); if (io_->error() || io_->eof()) throw Error(14); - if (exifData_.load(rawExif.pData_, rawExif.size_)) { + ByteOrder bo = ExifParser::decode(exifData_, rawExif.pData_, rawExif.size_); + setByteOrder(bo); + if (rawExif.size_ > 0 && byteOrder() == invalidByteOrder) { #ifndef SUPPRESS_WARNINGS std::cerr << "Warning: Failed to decode Exif metadata.\n"; #endif diff --git a/src/rafimage.cpp b/src/rafimage.cpp index 622586f6..debb585b 100644 --- a/src/rafimage.cpp +++ b/src/rafimage.cpp @@ -38,7 +38,7 @@ EXIV2_RCSID("@(#) $Id$") #endif #include "rafimage.hpp" -#include "tiffparser.hpp" +#include "tiffimage.hpp" #include "image.hpp" #include "basicio.hpp" #include "error.hpp" @@ -107,8 +107,12 @@ namespace Exiv2 { uint32_t const start = getULong(pData + 84, bigEndian) + 12; if (static_cast(size) < start) throw Error(14); clearMetadata(); - TiffParser::decode(this, pData + start, size - start, - TiffCreator::create, TiffDecoder::findDecoder); + ByteOrder bo = TiffParser::decode(exifData_, + iptcData_, + xmpData_, + pData + start, + size - start); + setByteOrder(bo); } // RafImage::readMetadata void RafImage::writeMetadata() diff --git a/src/sigmamn.cpp b/src/sigmamn.cpp index cba1b998..7db9d144 100644 --- a/src/sigmamn.cpp +++ b/src/sigmamn.cpp @@ -35,7 +35,6 @@ EXIV2_RCSID("@(#) $Id$") // included header files #include "types.hpp" #include "sigmamn.hpp" -#include "makernote.hpp" #include "value.hpp" #include "i18n.h" // NLS support. @@ -50,16 +49,6 @@ EXIV2_RCSID("@(#) $Id$") // class member definitions namespace Exiv2 { - //! @cond IGNORE - SigmaMakerNote::RegisterMn::RegisterMn() - { - MakerNoteFactory::registerMakerNote("SIGMA", "*", createSigmaMakerNote); - MakerNoteFactory::registerMakerNote("FOVEON", "*", createSigmaMakerNote); - MakerNoteFactory::registerMakerNote( - sigmaIfdId, MakerNote::AutoPtr(new SigmaMakerNote)); - } - //! @endcond - // Sigma (Foveon) MakerNote Tag Info const TagInfo SigmaMakerNote::tagInfo_[] = { TagInfo(0x0002, "SerialNumber", N_("Serial Number"), @@ -141,75 +130,9 @@ namespace Exiv2 { return tagInfo_; } - SigmaMakerNote::SigmaMakerNote(bool alloc) - : IfdMakerNote(sigmaIfdId, alloc) - { - byte buf[] = { - 'S', 'I', 'G', 'M', 'A', '\0', '\0', '\0', 0x01, 0x00 - }; - readHeader(buf, 10, byteOrder_); - } - - SigmaMakerNote::SigmaMakerNote(const SigmaMakerNote& rhs) - : IfdMakerNote(rhs) - { - } - - int SigmaMakerNote::readHeader(const byte* buf, - long len, - ByteOrder /*byteOrder*/) - { - if (len < 10) return 1; - - // Copy the header. My one and only Sigma sample has two undocumented - // extra bytes (0x01, 0x00) between the ID string and the start of the - // Makernote IFD. So we copy 10 bytes into the header. - header_.alloc(10); - std::memcpy(header_.pData_, buf, header_.size_); - // Adjust the offset of the IFD for the prefix - start_ = 10; - return 0; - } - - int SigmaMakerNote::checkHeader() const - { - int rc = 0; - // Check the SIGMA or FOVEON prefix - if ( header_.size_ < 10 - || ( std::string(reinterpret_cast(header_.pData_), 8) - != std::string("SIGMA\0\0\0", 8) - && std::string(reinterpret_cast(header_.pData_), 8) - != std::string("FOVEON\0\0", 8))) { - rc = 2; - } - return rc; - } - - SigmaMakerNote::AutoPtr SigmaMakerNote::create(bool alloc) const - { - return AutoPtr(create_(alloc)); - } - - SigmaMakerNote* SigmaMakerNote::create_(bool alloc) const - { - AutoPtr makerNote(new SigmaMakerNote(alloc)); - assert(makerNote.get() != 0); - makerNote->readHeader(header_.pData_, header_.size_, byteOrder_); - return makerNote.release(); - } - - SigmaMakerNote::AutoPtr SigmaMakerNote::clone() const - { - return AutoPtr(clone_()); - } - - SigmaMakerNote* SigmaMakerNote::clone_() const - { - return new SigmaMakerNote(*this); - } - std::ostream& SigmaMakerNote::printStripLabel(std::ostream& os, - const Value& value) + const Value& value, + const ExifData*) { std::string v = value.toString(); std::string::size_type pos = v.find(':'); @@ -221,7 +144,8 @@ namespace Exiv2 { } std::ostream& SigmaMakerNote::print0x0008(std::ostream& os, - const Value& value) + const Value& value, + const ExifData*) { switch (value.toString()[0]) { case 'P': os << _("Program"); break; @@ -234,7 +158,8 @@ namespace Exiv2 { } std::ostream& SigmaMakerNote::print0x0009(std::ostream& os, - const Value& value) + const Value& value, + const ExifData*) { switch (value.toString()[0]) { case 'A': os << _("Average"); break; @@ -245,16 +170,4 @@ namespace Exiv2 { return os; } -// ***************************************************************************** -// free functions - - MakerNote::AutoPtr createSigmaMakerNote(bool alloc, - const byte* /*buf*/, - long /*len*/, - ByteOrder /*byteOrder*/, - long /*offset*/) - { - return MakerNote::AutoPtr(new SigmaMakerNote(alloc)); - } - } // namespace Exiv2 diff --git a/src/sigmamn.hpp b/src/sigmamn.hpp index 095c993b..bc0eadeb 100644 --- a/src/sigmamn.hpp +++ b/src/sigmamn.hpp @@ -34,7 +34,6 @@ // ***************************************************************************** // included header files #include "types.hpp" -#include "makernote.hpp" #include "tags.hpp" // + standard includes @@ -46,108 +45,31 @@ // namespace extensions namespace Exiv2 { -// ***************************************************************************** -// class declarations - class Value; - -// ***************************************************************************** -// free functions - - /*! - @brief Return an auto-pointer to a newly created empty MakerNote - initialized to operate in the memory management model indicated. - The caller owns this copy and the auto-pointer ensures that it - will be deleted. - - @param alloc Memory management model for the new MakerNote. Determines if - memory required to store data should be allocated and deallocated - (true) or not (false). If false, only pointers to the buffer - provided to read() will be kept. See Ifd for more background on - this concept. - @param buf Pointer to the makernote character buffer (not used). - @param len Length of the makernote character buffer (not used). - @param byteOrder Byte order in which the Exif data (and possibly the - makernote) is encoded (not used). - @param offset Offset from the start of the TIFF header of the makernote - buffer (not used). - - @return An auto-pointer to a newly created empty MakerNote. The caller - owns this copy and the auto-pointer ensures that it will be - deleted. - */ - MakerNote::AutoPtr createSigmaMakerNote(bool alloc, - const byte* buf, - long len, - ByteOrder byteOrder, - long offset); - // ***************************************************************************** // class definitions //! MakerNote for Sigma (Foveon) cameras - class SigmaMakerNote : public IfdMakerNote { + class SigmaMakerNote { public: - //! Shortcut for a %SigmaMakerNote auto pointer. - typedef std::auto_ptr AutoPtr; - - //! @name Creators - //@{ - /*! - @brief Constructor. Allows to choose whether or not memory management - is required for the makernote entries. - */ - SigmaMakerNote(bool alloc =true); - //! Copy constructor - SigmaMakerNote(const SigmaMakerNote& rhs); - //! Virtual destructor - virtual ~SigmaMakerNote() {} - //@} - - //! @name Manipulators - //@{ - int readHeader(const byte* buf, - long len, - ByteOrder byteOrder); - //@} - - //! @name Accessors - //@{ - int checkHeader() const; - AutoPtr create(bool alloc =true) const; - AutoPtr clone() const; //! 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); + 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); + 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); + static std::ostream& print0x0009(std::ostream& os, const Value& value, const ExifData*); //@} - //! @cond IGNORE - // Public only so that we can create a static instance - struct RegisterMn { - RegisterMn(); - }; - //! @endcond - private: - //! Internal virtual create function. - SigmaMakerNote* create_(bool alloc =true) const; - //! Internal virtual copy constructor. - SigmaMakerNote* clone_() const; - //! Tag information static const TagInfo tagInfo_[]; }; // class SigmaMakerNote - static SigmaMakerNote::RegisterMn registerSigmaMakerNote; } // namespace Exiv2 #endif // #ifndef SIGMAMN_HPP_ diff --git a/src/sonymn.cpp b/src/sonymn.cpp index 2aa46633..429fa82a 100644 --- a/src/sonymn.cpp +++ b/src/sonymn.cpp @@ -32,7 +32,6 @@ EXIV2_RCSID("@(#) $Id$") // included header files #include "types.hpp" #include "sonymn.hpp" -#include "makernote.hpp" #include "value.hpp" #include "i18n.h" // NLS support. @@ -47,15 +46,6 @@ EXIV2_RCSID("@(#) $Id$") // class member definitions namespace Exiv2 { - //! @cond IGNORE - SonyMakerNote::RegisterMn::RegisterMn() - { - MakerNoteFactory::registerMakerNote("SONY", "*", createSonyMakerNote); - MakerNoteFactory::registerMakerNote( - sonyIfdId, MakerNote::AutoPtr(new SonyMakerNote)); - } - //! @endcond - // Sony MakerNote Tag Info const TagInfo SonyMakerNote::tagInfo_[] = { TagInfo(0x2000, "0x2000", "0x2000", @@ -96,77 +86,4 @@ namespace Exiv2 { return tagInfo_; } - SonyMakerNote::SonyMakerNote(bool alloc) - : IfdMakerNote(sonyIfdId, alloc, false) - { - byte buf[] = { - 'S', 'O', 'N', 'Y', ' ', 'D', 'S', 'C', ' ', '\0', '\0', '\0' - }; - readHeader(buf, 12, byteOrder_); - } - - SonyMakerNote::SonyMakerNote(const SonyMakerNote& rhs) - : IfdMakerNote(rhs) - { - } - - int SonyMakerNote::readHeader(const byte* buf, - long len, - ByteOrder /*byteOrder*/) - { - if (len < 12) return 1; - header_.alloc(12); - std::memcpy(header_.pData_, buf, header_.size_); - // Adjust the offset of the IFD for the prefix - start_ = 12; - return 0; - } - - int SonyMakerNote::checkHeader() const - { - int rc = 0; - // Check the SONY prefix - if ( header_.size_ < 12 - || std::string(reinterpret_cast(header_.pData_), 12) - != std::string("SONY DSC \0\0\0", 12)) { - rc = 2; - } - return rc; - } - - SonyMakerNote::AutoPtr SonyMakerNote::create(bool alloc) const - { - return AutoPtr(create_(alloc)); - } - - SonyMakerNote* SonyMakerNote::create_(bool alloc) const - { - AutoPtr makerNote(new SonyMakerNote(alloc)); - assert(makerNote.get() != 0); - makerNote->readHeader(header_.pData_, header_.size_, byteOrder_); - return makerNote.release(); - } - - SonyMakerNote::AutoPtr SonyMakerNote::clone() const - { - return AutoPtr(clone_()); - } - - SonyMakerNote* SonyMakerNote::clone_() const - { - return new SonyMakerNote(*this); - } - -// ***************************************************************************** -// free functions - - MakerNote::AutoPtr createSonyMakerNote(bool alloc, - const byte* /*buf*/, - long /*len*/, - ByteOrder /*byteOrder*/, - long /*offset*/) - { - return MakerNote::AutoPtr(new SonyMakerNote(alloc)); - } - } // namespace Exiv2 diff --git a/src/sonymn.hpp b/src/sonymn.hpp index 2e4dfc54..413ec3e4 100644 --- a/src/sonymn.hpp +++ b/src/sonymn.hpp @@ -32,110 +32,31 @@ // ***************************************************************************** // included header files #include "types.hpp" -#include "makernote.hpp" #include "tags.hpp" // + standard includes #include #include -#include // ***************************************************************************** // namespace extensions namespace Exiv2 { -// ***************************************************************************** -// class declarations - class Value; - -// ***************************************************************************** -// free functions - - /*! - @brief Return an auto-pointer to a newly created empty MakerNote - initialized to operate in the memory management model indicated. - The caller owns this copy and the auto-pointer ensures that it - will be deleted. - - @param alloc Memory management model for the new MakerNote. Determines if - memory required to store data should be allocated and deallocated - (true) or not (false). If false, only pointers to the buffer - provided to read() will be kept. See Ifd for more background on - this concept. - @param buf Pointer to the makernote character buffer (not used). - @param len Length of the makernote character buffer (not used). - @param byteOrder Byte order in which the Exif data (and possibly the - makernote) is encoded (not used). - @param offset Offset from the start of the TIFF header of the makernote - buffer (not used). - - @return An auto-pointer to a newly created empty MakerNote. The caller - owns this copy and the auto-pointer ensures that it will be - deleted. - */ - MakerNote::AutoPtr createSonyMakerNote(bool alloc, - const byte* buf, - long len, - ByteOrder byteOrder, - long offset); - // ***************************************************************************** // class definitions //! MakerNote for Sony cameras - class SonyMakerNote : public IfdMakerNote { + class SonyMakerNote { public: - //! Shortcut for a %SonyMakerNote auto pointer. - typedef std::auto_ptr AutoPtr; - - //! @name Creators - //@{ - /*! - @brief Constructor. Allows to choose whether or not memory management - is required for the makernote entries. - */ - SonyMakerNote(bool alloc =true); - //! Copy constructor - SonyMakerNote(const SonyMakerNote& rhs); - //! Virtual destructor - virtual ~SonyMakerNote() {} - //@} - - //! @name Manipulators - //@{ - int readHeader(const byte* buf, - long len, - ByteOrder byteOrder); - //@} - - //! @name Accessors - //@{ - int checkHeader() const; - AutoPtr create(bool alloc =true) const; - AutoPtr clone() const; //! Return read-only list of built-in Sony tags static const TagInfo* tagList(); - //@} - - //! @cond IGNORE - // Public only so that we can create a static instance - struct RegisterMn { - RegisterMn(); - }; - //! @endcond private: - //! Internal virtual create function. - SonyMakerNote* create_(bool alloc =true) const; - //! Internal virtual copy constructor. - SonyMakerNote* clone_() const; - //! Tag information static const TagInfo tagInfo_[]; }; // class SonyMakerNote - static SonyMakerNote::RegisterMn registerSonyMakerNote; } // namespace Exiv2 #endif // #ifndef SONYMN_HPP_ diff --git a/src/taglist.cpp b/src/taglist.cpp index cc48fcf6..3314b00a 100644 --- a/src/taglist.cpp +++ b/src/taglist.cpp @@ -8,7 +8,6 @@ History: 07-Jan-04, ahu: created */ // ***************************************************************************** -#include "makernote.hpp" #include "tags.hpp" #include "datasets.hpp" #include "properties.hpp" diff --git a/src/tags.cpp b/src/tags.cpp index c04ecec8..37df62d9 100644 --- a/src/tags.cpp +++ b/src/tags.cpp @@ -36,9 +36,7 @@ EXIV2_RCSID("@(#) $Id$") #include "tags.hpp" #include "error.hpp" #include "futils.hpp" -#include "ifd.hpp" #include "value.hpp" -#include "makernote.hpp" #include "mn.hpp" // To ensure that all makernotes are registered #include "i18n.h" // NLS support. @@ -513,9 +511,9 @@ namespace Exiv2 { TagInfo(0x9c9f, "XPSubject", N_("Windows Subject"), N_("Subject tag used by Windows, encoded in UCS2"), ifd0Id, otherTags, unsignedByte, printUcs2), // Windows Tag - TagInfo(0xc4a5, "PrintImageMatching", N_("Print Image Matching"), - N_("Print Image Matching, descriptiont needed."), - ifd0Id, otherTags, undefined, printValue), + TagInfo(0xc4a5, "PrintImageMatching", N_("Print Image Matching"), + N_("Print Image Matching, descriptiont needed."), + ifd0Id, otherTags, undefined, printValue), // End of list marker TagInfo(0xffff, "(UnknownIfdTag)", N_("Unknown IFD tag"), N_("Unknown IFD tag"), @@ -1259,6 +1257,20 @@ namespace Exiv2 { return rc; } // ExifTags::isMakerIfd + bool ExifTags::isExifIfd(IfdId ifdId) + { + bool rc; + switch (ifdId) { + case ifd0Id: rc = true; break; + case exifIfdId: rc = true; break; + case gpsIfdId: rc = true; break; + case iopIfdId: rc = true; break; + case ifd1Id: rc = true; break; + default: rc = false; break; + } + return rc; + } // ExifTags::isExifIfd + std::string ExifTags::tagName(uint16_t tag, IfdId ifdId) { const TagInfo* ti = tagInfo(tag, ifdId); @@ -1359,13 +1371,14 @@ namespace Exiv2 { std::ostream& ExifTags::printTag(std::ostream& os, uint16_t tag, IfdId ifdId, - const Value& value) + const Value& value, + const ExifData* pExifData) { if (value.count() == 0) return os; PrintFct fct = printValue; const TagInfo* ti = tagInfo(tag, ifdId); if (ti != 0) fct = ti->printFct_; - return fct(os, value); + return fct(os, value, pExifData); } // ExifTags::printTag void ExifTags::taglist(std::ostream& os) @@ -1408,9 +1421,8 @@ namespace Exiv2 { idx_(0), key_("") { IfdId ifdId = ExifTags::ifdIdByIfdItem(ifdItem); - if (ExifTags::isMakerIfd(ifdId)) { - MakerNote::AutoPtr makerNote = MakerNoteFactory::create(ifdId); - if (makerNote.get() == 0) throw Error(23, ifdId); + if (!ExifTags::isExifIfd(ifdId) && !ExifTags::isMakerIfd(ifdId)) { + throw Error(23, ifdId); } tag_ = tag; ifdId_ = ifdId; @@ -1418,14 +1430,6 @@ namespace Exiv2 { makeKey(); } - ExifKey::ExifKey(const Entry& e) - : tag_(e.tag()), ifdId_(e.ifdId()), - ifdItem_(ExifTags::ifdItem(e.ifdId())), - idx_(e.idx()), key_("") - { - makeKey(); - } - ExifKey::ExifKey(const ExifKey& rhs) : Key(rhs), tag_(rhs.tag_), ifdId_(rhs.ifdId_), ifdItem_(rhs.ifdItem_), idx_(rhs.idx_), key_(rhs.key_) @@ -1493,9 +1497,8 @@ namespace Exiv2 { // Find IfdId IfdId ifdId = ExifTags::ifdIdByIfdItem(ifdItem); if (ifdId == ifdIdNotSet) throw Error(6, key_); - if (ExifTags::isMakerIfd(ifdId)) { - MakerNote::AutoPtr makerNote = MakerNoteFactory::create(ifdId); - if (makerNote.get() == 0) throw Error(6, key_); + if (!ExifTags::isExifIfd(ifdId) && !ExifTags::isMakerIfd(ifdId)) { + throw Error(6, key_); } // Convert tag uint16_t tag = ExifTags::tag(tagName, ifdId); @@ -1519,20 +1522,6 @@ namespace Exiv2 { // ************************************************************************* // free functions - bool isExifIfd(IfdId ifdId) - { - bool rc; - switch (ifdId) { - case ifd0Id: rc = true; break; - case exifIfdId: rc = true; break; - case gpsIfdId: rc = true; break; - case iopIfdId: rc = true; break; - case ifd1Id: rc = true; break; - default: rc = false; break; - } - return rc; - } // isExifIfd - std::ostream& operator<<(std::ostream& os, const TagInfo& ti) { ExifKey exifKey(ti.tag_, ExifTags::ifdItem(ti.ifdId_)); @@ -1579,26 +1568,26 @@ namespace Exiv2 { return is; } - std::ostream& printValue(std::ostream& os, const Value& value) + std::ostream& printValue(std::ostream& os, const Value& value, const ExifData*) { return os << value; } - std::ostream& printLong(std::ostream& os, const Value& value) + 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) + 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) + std::ostream& printDegrees(std::ostream& os, const Value& value, const ExifData*) { if (value.count() == 3) { std::ostringstream oss; @@ -1628,7 +1617,7 @@ namespace Exiv2 { return os; } // printDegrees - std::ostream& printUcs2(std::ostream& os, const Value& value) + std::ostream& printUcs2(std::ostream& os, const Value& value, const ExifData*) { #if defined EXV_HAVE_ICONV && defined EXV_HAVE_PRINTUCS2 bool go = true; @@ -1686,12 +1675,12 @@ namespace Exiv2 { } // printUcs2 - std::ostream& printExifUnit(std::ostream& os, const Value& value) + std::ostream& printExifUnit(std::ostream& os, const Value& value, const ExifData* metadata) { - return EXV_PRINT_TAG(exifUnit)(os, value); + return EXV_PRINT_TAG(exifUnit)(os, value, metadata); } - std::ostream& print0x0000(std::ostream& os, const Value& value) + std::ostream& print0x0000(std::ostream& os, const Value& value, const ExifData*) { if (value.size() != 4 || value.typeId() != unsignedByte) { return os << value; @@ -1706,12 +1695,12 @@ namespace Exiv2 { return os; } - std::ostream& print0x0005(std::ostream& os, const Value& value) + std::ostream& print0x0005(std::ostream& os, const Value& value, const ExifData* metadata) { - return EXV_PRINT_TAG(exifGPSAltitudeRef)(os, value); + return EXV_PRINT_TAG(exifGPSAltitudeRef)(os, value, metadata); } - std::ostream& print0x0006(std::ostream& os, const Value& value) + std::ostream& print0x0006(std::ostream& os, const Value& value, const ExifData*) { std::ostringstream oss; oss.copyfmt(os); @@ -1724,7 +1713,7 @@ namespace Exiv2 { return os; } - std::ostream& print0x0007(std::ostream& os, const Value& value) + std::ostream& print0x0007(std::ostream& os, const Value& value, const ExifData*) { if (value.count() == 3) { for (int i = 0; i < 3; ++i) { @@ -1758,42 +1747,42 @@ namespace Exiv2 { return os; } - std::ostream& print0x0009(std::ostream& os, const Value& value) + std::ostream& print0x0009(std::ostream& os, const Value& value, const ExifData* metadata) { - return EXV_PRINT_TAG(exifGPSStatus)(os, value); + return EXV_PRINT_TAG(exifGPSStatus)(os, value, metadata); } - std::ostream& print0x000a(std::ostream& os, const Value& value) + std::ostream& print0x000a(std::ostream& os, const Value& value, const ExifData* metadata) { - return EXV_PRINT_TAG(exifGPSMeasureMode)(os, value); + return EXV_PRINT_TAG(exifGPSMeasureMode)(os, value, metadata); } - std::ostream& print0x000c(std::ostream& os, const Value& value) + std::ostream& print0x000c(std::ostream& os, const Value& value, const ExifData* metadata) { - return EXV_PRINT_TAG(exifGPSSpeedRef)(os, value); + return EXV_PRINT_TAG(exifGPSSpeedRef)(os, value, metadata); } - std::ostream& print0x0019(std::ostream& os, const Value& value) + std::ostream& print0x0019(std::ostream& os, const Value& value, const ExifData* metadata) { - return EXV_PRINT_TAG(exifGPSDestDistanceRef)(os, value); + return EXV_PRINT_TAG(exifGPSDestDistanceRef)(os, value, metadata); } - std::ostream& print0x001e(std::ostream& os, const Value& value) + std::ostream& print0x001e(std::ostream& os, const Value& value, const ExifData* metadata) { - return EXV_PRINT_TAG(exifGPSDifferential)(os, value); + return EXV_PRINT_TAG(exifGPSDifferential)(os, value, metadata); } - std::ostream& print0x0112(std::ostream& os, const Value& value) + std::ostream& print0x0112(std::ostream& os, const Value& value, const ExifData* metadata) { - return EXV_PRINT_TAG(exifOrientation)(os, value); + return EXV_PRINT_TAG(exifOrientation)(os, value, metadata); } - std::ostream& print0x0213(std::ostream& os, const Value& value) + std::ostream& print0x0213(std::ostream& os, const Value& value, const ExifData* metadata) { - return EXV_PRINT_TAG(exifYCbCrPositioning)(os, value); + return EXV_PRINT_TAG(exifYCbCrPositioning)(os, value, metadata); } - std::ostream& print0x8298(std::ostream& os, const Value& value) + 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(); @@ -1813,7 +1802,7 @@ namespace Exiv2 { return os; } - std::ostream& print0x829a(std::ostream& os, const Value& value) + 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) { @@ -1835,7 +1824,7 @@ namespace Exiv2 { return os; } - std::ostream& print0x829d(std::ostream& os, const Value& value) + std::ostream& print0x829d(std::ostream& os, const Value& value, const ExifData*) { Rational fnumber = value.toRational(); if (fnumber.second != 0) { @@ -1851,17 +1840,17 @@ namespace Exiv2 { return os; } - std::ostream& print0x8822(std::ostream& os, const Value& value) + std::ostream& print0x8822(std::ostream& os, const Value& value, const ExifData* metadata) { - return EXV_PRINT_TAG(exifExposureProgram)(os, value); + return EXV_PRINT_TAG(exifExposureProgram)(os, value, metadata); } - std::ostream& print0x8827(std::ostream& os, const Value& value) + std::ostream& print0x8827(std::ostream& os, const Value& value, const ExifData*) { return os << value.toLong(); } - std::ostream& print0x9101(std::ostream& os, const Value& value) + std::ostream& print0x9101(std::ostream& os, const Value& value, const ExifData*) { for (long i = 0; i < value.count(); ++i) { long l = value.toLong(i); @@ -1879,7 +1868,7 @@ namespace Exiv2 { return os; } - std::ostream& print0x9201(std::ostream& os, const Value& value) + std::ostream& print0x9201(std::ostream& os, const Value& value, const ExifData*) { Rational r = value.toRational(); if (!value.ok() || r.second == 0) return os << "(" << value << ")"; @@ -1892,7 +1881,7 @@ namespace Exiv2 { return os << " s"; } - std::ostream& print0x9202(std::ostream& os, const Value& value) + std::ostream& print0x9202(std::ostream& os, const Value& value, const ExifData*) { if ( value.count() == 0 || value.toRational().second == 0) { @@ -1905,7 +1894,7 @@ namespace Exiv2 { return os; } - std::ostream& print0x9204(std::ostream& os, const Value& value) + std::ostream& print0x9204(std::ostream& os, const Value& value, const ExifData*) { Rational bias = value.toRational(); if (bias.second <= 0) { @@ -1926,7 +1915,7 @@ namespace Exiv2 { return os; } - std::ostream& print0x9206(std::ostream& os, const Value& value) + std::ostream& print0x9206(std::ostream& os, const Value& value, const ExifData*) { Rational distance = value.toRational(); if (distance.first == 0) { @@ -1949,17 +1938,17 @@ namespace Exiv2 { return os; } - std::ostream& print0x9207(std::ostream& os, const Value& value) + std::ostream& print0x9207(std::ostream& os, const Value& value, const ExifData* metadata) { - return EXV_PRINT_TAG(exifMeteringMode)(os, value); + return EXV_PRINT_TAG(exifMeteringMode)(os, value, metadata); } - std::ostream& print0x9208(std::ostream& os, const Value& value) + std::ostream& print0x9208(std::ostream& os, const Value& value, const ExifData* metadata) { - return EXV_PRINT_TAG(exifLightSource)(os, value); + return EXV_PRINT_TAG(exifLightSource)(os, value, metadata); } - std::ostream& print0x920a(std::ostream& os, const Value& value) + std::ostream& print0x920a(std::ostream& os, const Value& value, const ExifData*) { Rational length = value.toRational(); if (length.second != 0) { @@ -1977,7 +1966,7 @@ namespace Exiv2 { } // Todo: Implement this properly - std::ostream& print0x9286(std::ostream& os, const Value& value) + std::ostream& print0x9286(std::ostream& os, const Value& value, const ExifData*) { if (value.size() > 8) { DataBuf buf(value.size()); @@ -1991,42 +1980,42 @@ namespace Exiv2 { return os; } - std::ostream& print0xa001(std::ostream& os, const Value& value) + std::ostream& print0xa001(std::ostream& os, const Value& value, const ExifData* metadata) { - return EXV_PRINT_TAG(exifColorSpace)(os, value); + return EXV_PRINT_TAG(exifColorSpace)(os, value, metadata); } - std::ostream& print0xa217(std::ostream& os, const Value& value) + std::ostream& print0xa217(std::ostream& os, const Value& value, const ExifData* metadata) { - return EXV_PRINT_TAG(exifSensingMethod)(os, value); + return EXV_PRINT_TAG(exifSensingMethod)(os, value, metadata); } - std::ostream& print0xa300(std::ostream& os, const Value& value) + std::ostream& print0xa300(std::ostream& os, const Value& value, const ExifData* metadata) { - return EXV_PRINT_TAG(exifFileSource)(os, value); + return EXV_PRINT_TAG(exifFileSource)(os, value, metadata); } - std::ostream& print0xa301(std::ostream& os, const Value& value) + std::ostream& print0xa301(std::ostream& os, const Value& value, const ExifData* metadata) { - return EXV_PRINT_TAG(exifSceneType)(os, value); + return EXV_PRINT_TAG(exifSceneType)(os, value, metadata); } - std::ostream& print0xa401(std::ostream& os, const Value& value) + std::ostream& print0xa401(std::ostream& os, const Value& value, const ExifData* metadata) { - return EXV_PRINT_TAG(exifCustomRendered)(os, value); + return EXV_PRINT_TAG(exifCustomRendered)(os, value, metadata); } - std::ostream& print0xa402(std::ostream& os, const Value& value) + std::ostream& print0xa402(std::ostream& os, const Value& value, const ExifData* metadata) { - return EXV_PRINT_TAG(exifExposureMode)(os, value); + return EXV_PRINT_TAG(exifExposureMode)(os, value, metadata); } - std::ostream& print0xa403(std::ostream& os, const Value& value) + std::ostream& print0xa403(std::ostream& os, const Value& value, const ExifData* metadata) { - return EXV_PRINT_TAG(exifWhiteBalance)(os, value); + return EXV_PRINT_TAG(exifWhiteBalance)(os, value, metadata); } - std::ostream& print0xa404(std::ostream& os, const Value& value) + std::ostream& print0xa404(std::ostream& os, const Value& value, const ExifData*) { Rational zoom = value.toRational(); if (zoom.second == 0) { @@ -2042,7 +2031,7 @@ namespace Exiv2 { return os; } - std::ostream& print0xa405(std::ostream& os, const Value& value) + std::ostream& print0xa405(std::ostream& os, const Value& value, const ExifData*) { long length = value.toLong(); if (length == 0) { @@ -2054,37 +2043,37 @@ namespace Exiv2 { return os; } - std::ostream& print0xa406(std::ostream& os, const Value& value) + std::ostream& print0xa406(std::ostream& os, const Value& value, const ExifData* metadata) { - return EXV_PRINT_TAG(exifSceneCaptureType)(os, value); + return EXV_PRINT_TAG(exifSceneCaptureType)(os, value, metadata); } - std::ostream& print0xa407(std::ostream& os, const Value& value) + std::ostream& print0xa407(std::ostream& os, const Value& value, const ExifData* metadata) { - return EXV_PRINT_TAG(exifGainControl)(os, value); + return EXV_PRINT_TAG(exifGainControl)(os, value, metadata); } - std::ostream& print0xa409(std::ostream& os, const Value& value) + std::ostream& print0xa409(std::ostream& os, const Value& value, const ExifData* metadata) { - return EXV_PRINT_TAG(exifSaturation)(os, value); + return EXV_PRINT_TAG(exifSaturation)(os, value, metadata); } - std::ostream& print0xa40c(std::ostream& os, const Value& value) + std::ostream& print0xa40c(std::ostream& os, const Value& value, const ExifData* metadata) { - return EXV_PRINT_TAG(exifSubjectDistanceRange)(os, value); + return EXV_PRINT_TAG(exifSubjectDistanceRange)(os, value, metadata); } - std::ostream& printGPSDirRef(std::ostream& os, const Value& value) + std::ostream& printGPSDirRef(std::ostream& os, const Value& value, const ExifData* metadata) { - return EXV_PRINT_TAG(exifGPSDirRef)(os, value); + return EXV_PRINT_TAG(exifGPSDirRef)(os, value, metadata); } - std::ostream& printNormalSoftHard(std::ostream& os, const Value& value) + std::ostream& printNormalSoftHard(std::ostream& os, const Value& value, const ExifData* metadata) { - return EXV_PRINT_TAG(exifNormalSoftHard)(os, value); + return EXV_PRINT_TAG(exifNormalSoftHard)(os, value, metadata); } - std::ostream& printExifVersion(std::ostream& os, const Value& value) + std::ostream& printExifVersion(std::ostream& os, const Value& value, const ExifData*) { if (value.size() != 4 || value.typeId() != undefined) { return os << "(" << value << ")"; @@ -2099,7 +2088,7 @@ namespace Exiv2 { return printVersion(os, s); } - std::ostream& printXmpVersion(std::ostream& os, const Value& value) + std::ostream& printXmpVersion(std::ostream& os, const Value& value, const ExifData*) { if (value.size() != 4 || value.typeId() != xmpText) { return os << "(" << value << ")"; @@ -2108,7 +2097,7 @@ namespace Exiv2 { return printVersion(os, value.toString()); } - std::ostream& printXmpDate(std::ostream& os, const Value& value) + std::ostream& printXmpDate(std::ostream& os, const Value& value, const ExifData*) { if (!(value.size() == 19 || value.size() == 20) || value.typeId() != xmpText) { return os << value; diff --git a/src/tags.hpp b/src/tags.hpp index b70e9980..5a740a1c 100644 --- a/src/tags.hpp +++ b/src/tags.hpp @@ -48,15 +48,15 @@ namespace Exiv2 { // ***************************************************************************** // class declarations + class ExifData; class Value; - class Entry; struct TagInfo; // ***************************************************************************** // type definitions //! Type for a function pointer for functions interpreting the tag value - typedef std::ostream& (*PrintFct)(std::ostream&, const Value&); + typedef std::ostream& (*PrintFct)(std::ostream&, const Value&, const ExifData* pExifData); //! A function returning a tag list. typedef const TagInfo* (*TagListFct)(); /*! @@ -146,7 +146,7 @@ namespace Exiv2 { by looking up a reference table. */ template - std::ostream& printTag(std::ostream& os, const Value& value) + std::ostream& printTag(std::ostream& os, const Value& value, const ExifData*) { const TagDetails* td = find(array, value.toLong()); if (td) { @@ -166,7 +166,7 @@ namespace Exiv2 { by looking up bitmasks in a reference table. */ template - std::ostream& printTagBitmask(std::ostream& os, const Value& value) + std::ostream& printTagBitmask(std::ostream& os, const Value& value, const ExifData*) { const uint32_t val = static_cast(value.toLong()); bool sep = false; @@ -279,7 +279,8 @@ namespace Exiv2 { static std::ostream& printTag(std::ostream& os, uint16_t tag, IfdId ifdId, - const Value& value); + const Value& value, + const ExifData* pExifData =0); //! Return read-only list of built-in IFD0/1 tags static const TagInfo* ifdTagList(); //! Return read-only list of built-in Exif IFD tags @@ -298,6 +299,13 @@ namespace Exiv2 { makerIfd returns false. */ static bool isMakerIfd(IfdId ifdId); + /*! + @brief Return true if \em ifdId is an Exif %Ifd Id, i.e., one of + ifd0Id, exifIfdId, gpsIfdId, iopIfdId or ifd1Id, else false. + This is used to differentiate between standard Exif %Ifds + and %Ifds associated with the makernote. + */ + static bool isExifIfd(IfdId ifdId); private: static const TagInfo* tagList(IfdId ifdId); @@ -338,8 +346,6 @@ namespace Exiv2 { item parameters. */ ExifKey(uint16_t tag, const std::string& ifdItem); - //! Constructor to build an ExifKey from an IFD entry. - explicit ExifKey(const Entry& e); //! Copy constructor ExifKey(const ExifKey& rhs); virtual ~ExifKey(); @@ -414,117 +420,109 @@ namespace Exiv2 { // ***************************************************************************** // free functions - /*! - @brief Return true if \em ifdId is an Exif %Ifd Id, i.e., one of - ifd0Id, exifIfdId, gpsIfdId, iopIfdId or ifd1Id, else false. - This is used to differentiate between standard Exif %Ifds - and %Ifds associated with the makernote. - */ - bool isExifIfd(IfdId ifdId); - //! Output operator for TagInfo std::ostream& operator<<(std::ostream& os, const TagInfo& ti); //! @name Functions printing interpreted tag values //@{ //! Default print function, using the Value output operator - std::ostream& printValue(std::ostream& os, const Value& value); + 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); + 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); + 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); + 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); + 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); + std::ostream& printExifUnit(std::ostream& os, const Value& value, const ExifData*); //! Print GPS version - std::ostream& print0x0000(std::ostream& os, const Value& value); + std::ostream& print0x0000(std::ostream& os, const Value& value, const ExifData*); //! Print GPS altitude ref - std::ostream& print0x0005(std::ostream& os, const Value& value); + std::ostream& print0x0005(std::ostream& os, const Value& value, const ExifData*); //! Print GPS altitude - std::ostream& print0x0006(std::ostream& os, const Value& value); + std::ostream& print0x0006(std::ostream& os, const Value& value, const ExifData*); //! Print GPS timestamp - std::ostream& print0x0007(std::ostream& os, const Value& value); + std::ostream& print0x0007(std::ostream& os, const Value& value, const ExifData*); //! Print GPS status - std::ostream& print0x0009(std::ostream& os, const Value& value); + std::ostream& print0x0009(std::ostream& os, const Value& value, const ExifData*); //! Print GPS measurement mode - std::ostream& print0x000a(std::ostream& os, const Value& value); + std::ostream& print0x000a(std::ostream& os, const Value& value, const ExifData*); //! Print GPS speed ref - std::ostream& print0x000c(std::ostream& os, const Value& value); + 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); + std::ostream& print0x0019(std::ostream& os, const Value& value, const ExifData*); //! Print GPS differential correction - std::ostream& print0x001e(std::ostream& os, const Value& value); + std::ostream& print0x001e(std::ostream& os, const Value& value, const ExifData*); //! Print orientation - std::ostream& print0x0112(std::ostream& os, const Value& value); + std::ostream& print0x0112(std::ostream& os, const Value& value, const ExifData*); //! Print YCbCrPositioning - std::ostream& print0x0213(std::ostream& os, const Value& value); + std::ostream& print0x0213(std::ostream& os, const Value& value, const ExifData*); //! Print the copyright - std::ostream& print0x8298(std::ostream& os, const Value& value); + std::ostream& print0x8298(std::ostream& os, const Value& value, const ExifData*); //! Print the exposure time - std::ostream& print0x829a(std::ostream& os, const Value& value); + std::ostream& print0x829a(std::ostream& os, const Value& value, const ExifData*); //! Print the f-number - std::ostream& print0x829d(std::ostream& os, const Value& value); + std::ostream& print0x829d(std::ostream& os, const Value& value, const ExifData*); //! Print exposure program - std::ostream& print0x8822(std::ostream& os, const Value& value); + std::ostream& print0x8822(std::ostream& os, const Value& value, const ExifData*); //! Print ISO speed ratings - std::ostream& print0x8827(std::ostream& os, const Value& value); + 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); + 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); + 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); + 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); + std::ostream& print0x9204(std::ostream& os, const Value& value, const ExifData*); //! Print the subject distance - std::ostream& print0x9206(std::ostream& os, const Value& value); + std::ostream& print0x9206(std::ostream& os, const Value& value, const ExifData*); //! Print metering mode - std::ostream& print0x9207(std::ostream& os, const Value& value); + std::ostream& print0x9207(std::ostream& os, const Value& value, const ExifData*); //! Print light source - std::ostream& print0x9208(std::ostream& os, const Value& value); + 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); + std::ostream& print0x920a(std::ostream& os, const Value& value, const ExifData*); //! Print the user comment - std::ostream& print0x9286(std::ostream& os, const Value& value); + std::ostream& print0x9286(std::ostream& os, const Value& value, const ExifData*); //! Print color space - std::ostream& print0xa001(std::ostream& os, const Value& value); + std::ostream& print0xa001(std::ostream& os, const Value& value, const ExifData*); //! Print sensing method - std::ostream& print0xa217(std::ostream& os, const Value& value); + std::ostream& print0xa217(std::ostream& os, const Value& value, const ExifData*); //! Print file source - std::ostream& print0xa300(std::ostream& os, const Value& value); + std::ostream& print0xa300(std::ostream& os, const Value& value, const ExifData*); //! Print scene type - std::ostream& print0xa301(std::ostream& os, const Value& value); + std::ostream& print0xa301(std::ostream& os, const Value& value, const ExifData*); //! Print custom rendered - std::ostream& print0xa401(std::ostream& os, const Value& value); + std::ostream& print0xa401(std::ostream& os, const Value& value, const ExifData*); //! Print exposure mode - std::ostream& print0xa402(std::ostream& os, const Value& value); + std::ostream& print0xa402(std::ostream& os, const Value& value, const ExifData*); //! Print white balance - std::ostream& print0xa403(std::ostream& os, const Value& value); + std::ostream& print0xa403(std::ostream& os, const Value& value, const ExifData*); //! Print digital zoom ratio - std::ostream& print0xa404(std::ostream& os, const Value& value); + 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); + std::ostream& print0xa405(std::ostream& os, const Value& value, const ExifData*); //! Print scene capture type - std::ostream& print0xa406(std::ostream& os, const Value& value); + std::ostream& print0xa406(std::ostream& os, const Value& value, const ExifData*); //! Print gain control - std::ostream& print0xa407(std::ostream& os, const Value& value); + std::ostream& print0xa407(std::ostream& os, const Value& value, const ExifData*); //! Print saturation - std::ostream& print0xa409(std::ostream& os, const Value& value); + std::ostream& print0xa409(std::ostream& os, const Value& value, const ExifData*); //! Print subject distance range - std::ostream& print0xa40c(std::ostream& os, const Value& value); + std::ostream& print0xa40c(std::ostream& os, const Value& value, const ExifData*); //! Print GPS direction ref - std::ostream& printGPSDirRef(std::ostream& os, const Value& value); + 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); + 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); + 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); + 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); + std::ostream& printXmpDate(std::ostream& os, const Value& value, const ExifData*); //@} //! Calculate F number from an APEX aperture value diff --git a/src/tiff-test.cpp b/src/tiff-test.cpp new file mode 100644 index 00000000..2110e4c0 --- /dev/null +++ b/src/tiff-test.cpp @@ -0,0 +1,76 @@ +// ***************************************************************** -*- C++ -*- +// tiff-test.cpp, $Rev$ +// 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"; + } +} diff --git a/src/tiffcomposite.cpp b/src/tiffcomposite.cpp index 3cb06820..88c925e6 100644 --- a/src/tiffcomposite.cpp +++ b/src/tiffcomposite.cpp @@ -36,30 +36,35 @@ EXIV2_RCSID("@(#) $Id$") # include "exv_conf.h" #endif -#include "tiffcomposite.hpp" -#include "tiffvisitor.hpp" -#include "makernote2.hpp" +#include "tiffcomposite_int.hpp" +#include "tiffvisitor_int.hpp" +#include "makernote2_int.hpp" #include "value.hpp" +#include "error.hpp" // + standard includes #include #include #include +#include // ***************************************************************************** // class member definitions namespace Exiv2 { + namespace Internal { //! Structure for group and group name info struct TiffGroupInfo { - //! comparison operator - bool operator==(uint16_t group) const; + //! Comparison operator for group (id) + bool operator==(const uint16_t& group) const; + //! Comparison operator for group name + bool operator==(const std::string& groupName) const; uint16_t group_; //!< group const char* name_; //!< group name }; - // Todo: This mapping table probably still belongs somewhere else + // Todo: This mapping table probably belongs somewhere else - move it //! List of groups and their names extern const TiffGroupInfo tiffGroupInfo[] = { { 1, "Image" }, @@ -96,11 +101,17 @@ namespace Exiv2 { { 279, "Pentax" } }; - bool TiffGroupInfo::operator==(uint16_t group) const + bool TiffGroupInfo::operator==(const uint16_t& group) const { return group_ == group; } + bool TiffGroupInfo::operator==(const std::string& groupName) const + { + std::string name(name_); + return name == groupName; + } + const char* tiffGroupName(uint16_t group) { const TiffGroupInfo* gi = find(tiffGroupInfo, group); @@ -108,13 +119,20 @@ namespace Exiv2 { return gi->name_; } + uint16_t tiffGroupId(const std::string& groupName) + { + const TiffGroupInfo* gi = find(tiffGroupInfo, groupName); + if (!gi) return 0; + return gi->group_; + } + bool TiffStructure::operator==(const TiffStructure::Key& key) const { return (Tag::all == extendedTag_ || key.e_ == extendedTag_) && key.g_ == group_; } - bool TiffDecoderInfo::operator==(const TiffDecoderInfo::Key& key) const + bool TiffMappingInfo::operator==(const TiffMappingInfo::Key& key) const { std::string make(make_); return ("*" == make || make == key.m_.substr(0, make.length())) @@ -122,11 +140,44 @@ namespace Exiv2 { && key.g_ == group_; } + TiffComponent::TiffComponent(uint16_t tag, uint16_t group) + : tag_(tag), group_(group), pStart_(0) + { + } + + TiffEntryBase::TiffEntryBase(uint16_t tag, uint16_t group, TypeId typeId) + : TiffComponent(tag, group), + type_(typeId), count_(0), offset_(0), + size_(0), pData_(0), isMalloced_(false), + pValue_(0) + { + } + + TiffSubIfd::TiffSubIfd(uint16_t tag, uint16_t group, uint16_t newGroup) + : TiffEntryBase(tag, group, unsignedLong), newGroup_(newGroup) + { + } + + TiffMnEntry::TiffMnEntry(uint16_t tag, uint16_t group, uint16_t mnGroup) + : TiffEntryBase(tag, group, undefined), mnGroup_(mnGroup), mn_(0) + { + } + + TiffArrayEntry::TiffArrayEntry(uint16_t tag, + uint16_t group, + uint16_t elGroup, + TypeId elTypeId, + bool addSizeElement) + : TiffEntryBase(tag, group, elTypeId), + elSize_(static_cast(TypeInfo::typeSize(elTypeId))), + elGroup_(elGroup), + addSizeElement_(addSizeElement) + { + } + TiffDirectory::~TiffDirectory() { - Components::iterator b = components_.begin(); - Components::iterator e = components_.end(); - for (Components::iterator i = b; i != e; ++i) { + for (Components::iterator i = components_.begin(); i != components_.end(); ++i) { delete *i; } delete pNext_; @@ -141,7 +192,7 @@ namespace Exiv2 { TiffEntryBase::~TiffEntryBase() { - if (isAllocated_) { + if (isMalloced_) { delete[] pData_; } delete pValue_; @@ -154,64 +205,311 @@ namespace Exiv2 { TiffArrayEntry::~TiffArrayEntry() { - Components::iterator b = elements_.begin(); - Components::iterator e = elements_.end(); - for (Components::iterator i = b; i != e; ++i) { + for (Components::iterator i = elements_.begin(); i != elements_.end(); ++i) { delete *i; } } // TiffArrayEntry::~TiffArrayEntry - // Possibly this function shouldn't be in this class... - std::string TiffComponent::groupName() const + void TiffEntryBase::allocData(uint32_t len) + { + if (isMalloced_) { + delete[] pData_; + } + pData_ = new byte[len]; + size_ = len; + isMalloced_ = true; + } // TiffEntryBase::allocData + + void TiffEntryBase::setData(byte* pData, int32_t size) { - return tiffGroupName(group_); + pData_ = pData; + size_ = size; + if (pData_ == 0) size_ = 0; } - void TiffComponent::addChild(TiffComponent::AutoPtr tiffComponent) + void TiffEntryBase::updateValue(Value::AutoPtr value, ByteOrder byteOrder) + { + uint32_t newSize = value->size(); + if (newSize > size_) { + allocData(newSize); + } + memset(pData_, 0x0, size_); + size_ = value->copy(pData_, byteOrder); + assert(size_ == newSize); + setValue(value); + } // TiffEntryBase::updateValue + + void TiffEntryBase::setValue(Value::AutoPtr value) + { + type_ = static_cast(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) + { + assert(pSize); + assert(pValue()); + + long size = 0; + for (long i = 0; i < pSize->count(); ++i) { + size += pSize->toLong(i); + } + long offset = 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 ( pValue()->toLong(pValue()->count()-1) + + pSize->toLong(pSize->count()-1) + - offset != size) { +#ifndef SUPPRESS_WARNINGS + std::cerr << "Warning: " + << "Directory " << tiffGroupName(group()) + << ", entry 0x" << std::setw(4) + << std::setfill('0') << std::hex << tag() + << " Data area is not contiguous, ignoring it.\n"; +#endif + return; + } + if (baseOffset + offset + size > sizeData) { +#ifndef SUPPRESS_WARNINGS + std::cerr << "Warning: " + << "Directory " << tiffGroupName(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) + { + assert(pSize); + assert(pValue()); + + if (pValue()->count() != pSize->count()) { +#ifndef SUPPRESS_WARNINGS + std::cerr << "Warning: " + << "Directory " << tiffGroupName(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 byte* pStrip = pData + baseOffset + pValue()->toLong(i); + const uint32_t stripSize = static_cast(pSize->toLong(i)); + if ( stripSize > 0 + && pData + sizeData > pStrip + && static_cast(pData + sizeData - pStrip) >= stripSize) { + strips_.push_back(std::make_pair(pStrip, stripSize)); + } +#ifndef SUPPRESS_WARNINGS + else { + std::cerr << "Warning: " + << "Directory " << tiffGroupName(group()) + << ", entry 0x" << std::setw(4) + << std::setfill('0') << std::hex << tag() + << ": Strip " << i + << " is outside of the data area; ignored.\n"; + } +#endif + } + } // TiffImageEntry::setStrips + + TiffComponent* TiffComponent::addPath(uint16_t tag, TiffPath& tiffPath) + { + return doAddPath(tag, tiffPath); + } // TiffComponent::addPath + + TiffComponent* TiffDirectory::doAddPath(uint16_t tag, TiffPath& tiffPath) + { + tiffPath.pop(); + assert(!tiffPath.empty()); + const TiffStructure* ts = tiffPath.top(); + assert(ts != 0); + TiffComponent* tc = 0; + // 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 + // Todo: Find a generic way to require subIFDs to be unique tags + if (tiffPath.size() > 1 || ts->newTiffCompFct_ == newTiffSubIfd) { + if (ts->extendedTag_ == Tag::next) { + tc = pNext_; + } + else { + for (Components::iterator i = components_.begin(); i != components_.end(); ++i) { + if ((*i)->tag() == ts->tag() && (*i)->group() == ts->group_) { + tc = *i; + break; + } + } + } + } + if (tc == 0) { + assert(ts->newTiffCompFct_ != 0); + uint16_t tg = tiffPath.size() == 1 ? tag : ts->tag(); + TiffComponent::AutoPtr atc(ts->newTiffCompFct_(tg, ts)); + if (ts->extendedTag_ == Tag::next) { + tc = this->addNext(atc); + } + else { + tc = this->addChild(atc); + } + } + return tc->addPath(tag, tiffPath); + } // TiffDirectory::doAddPath + + TiffComponent* TiffSubIfd::doAddPath(uint16_t tag, TiffPath& tiffPath) + { + const TiffStructure* ts1 = tiffPath.top(); + assert(ts1 != 0); + tiffPath.pop(); + if (tiffPath.empty()) { + // If the last element in the path is the sub-IFD tag itself we're done + return this; + } + const TiffStructure* ts2 = tiffPath.top(); + assert(ts2 != 0); + tiffPath.push(ts1); + uint16_t dt = ts1->tag(); + TiffComponent* tc = 0; + for (Ifds::iterator i = ifds_.begin(); i != ifds_.end(); ++i) { + if ((*i)->group() == ts2->group_) { + tc = *i; + break; + } + } + if (tc == 0) { + TiffComponent::AutoPtr atc(new TiffDirectory(dt, ts2->group_)); + tc = addChild(atc); + setCount(ifds_.size()); + } + return tc->addPath(tag, tiffPath); + } // TiffSubIfd::doAddPath + + TiffComponent* TiffMnEntry::doAddPath(uint16_t tag, TiffPath& tiffPath) { - doAddChild(tiffComponent); + const TiffStructure* ts1 = tiffPath.top(); + assert(ts1 != 0); + tiffPath.pop(); + if (tiffPath.empty()) { + // If the last element in the path is the makernote tag itself we're done + return this; + } + const TiffStructure* ts2 = tiffPath.top(); + assert(ts2 != 0); + tiffPath.push(ts1); + if (mn_ == 0) { + mnGroup_ = ts2->group_; + mn_ = TiffMnCreator::create(ts1->tag(), ts1->group_, mnGroup_); + assert(mn_); + } + return mn_->addPath(tag, tiffPath); + } // TiffMnEntry::doAddPath + + TiffComponent* TiffArrayEntry::doAddPath(uint16_t tag, TiffPath& tiffPath) + { + tiffPath.pop(); + assert(!tiffPath.empty()); + const TiffStructure* ts = tiffPath.top(); + assert(ts != 0); + TiffComponent* tc = 0; + // 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() == ts->tag() && (*i)->group() == ts->group_) { + tc = *i; + break; + } + } + } + if (tc == 0) { + assert(ts->newTiffCompFct_ != 0); + uint16_t tg = tiffPath.size() == 1 ? tag : ts->tag(); + TiffComponent::AutoPtr atc(ts->newTiffCompFct_(tg, ts)); + assert(ts->extendedTag_ != Tag::next); + tc = addChild(atc); + setCount(elements_.size()); + } + return tc->addPath(tag, tiffPath); + } // TiffArrayEntry::doAddPath + + TiffComponent* TiffComponent::addChild(TiffComponent::AutoPtr tiffComponent) + { + return doAddChild(tiffComponent); } // TiffComponent::addChild - void TiffDirectory::doAddChild(TiffComponent::AutoPtr tiffComponent) + TiffComponent* TiffDirectory::doAddChild(TiffComponent::AutoPtr tiffComponent) { - components_.push_back(tiffComponent.release()); + TiffComponent* tc = tiffComponent.release(); + components_.push_back(tc); + return tc; } // TiffDirectory::doAddChild - void TiffSubIfd::doAddChild(TiffComponent::AutoPtr tiffComponent) + TiffComponent* TiffSubIfd::doAddChild(TiffComponent::AutoPtr tiffComponent) { TiffDirectory* d = dynamic_cast(tiffComponent.release()); assert(d); ifds_.push_back(d); + return d; } // TiffSubIfd::doAddChild - void TiffMnEntry::doAddChild(TiffComponent::AutoPtr tiffComponent) + TiffComponent* TiffMnEntry::doAddChild(TiffComponent::AutoPtr tiffComponent) { - if (mn_) mn_->addChild(tiffComponent); + TiffComponent* tc = 0; + if (mn_) { + tc = mn_->addChild(tiffComponent); + } + return tc; } // TiffMnEntry::doAddChild - void TiffArrayEntry::doAddChild(TiffComponent::AutoPtr tiffComponent) + TiffComponent* TiffArrayEntry::doAddChild(TiffComponent::AutoPtr tiffComponent) { - elements_.push_back(tiffComponent.release()); + TiffComponent* tc = tiffComponent.release(); + elements_.push_back(tc); + return tc; } // TiffArrayEntry::doAddChild - void TiffComponent::addNext(TiffComponent::AutoPtr tiffComponent) + TiffComponent* TiffComponent::addNext(TiffComponent::AutoPtr tiffComponent) { - doAddNext(tiffComponent); + return doAddNext(tiffComponent); } // TiffComponent::addNext - void TiffDirectory::doAddNext(TiffComponent::AutoPtr tiffComponent) + TiffComponent* TiffDirectory::doAddNext(TiffComponent::AutoPtr tiffComponent) { - if (hasNext_) pNext_ = tiffComponent.release(); + TiffComponent* tc = 0; + if (hasNext_) { + tc = tiffComponent.release(); + pNext_ = tc; + } + return tc; } // TiffDirectory::doAddNext - void TiffMnEntry::doAddNext(TiffComponent::AutoPtr tiffComponent) + TiffComponent* TiffMnEntry::doAddNext(TiffComponent::AutoPtr tiffComponent) { - if (mn_) mn_->addNext(tiffComponent); + TiffComponent* tc = 0; + if (mn_) { + tc = mn_->addNext(tiffComponent); + } + return tc; } // TiffMnEntry::doAddNext void TiffComponent::accept(TiffVisitor& visitor) { - if (visitor.go()) doAccept(visitor); // one for NVI :) + if (visitor.go(TiffVisitor::geTraverse)) doAccept(visitor); // one for NVI :) } // TiffComponent::accept void TiffEntry::doAccept(TiffVisitor& visitor) @@ -224,6 +522,11 @@ namespace Exiv2 { visitor.visitDataEntry(this); } // TiffDataEntry::doAccept + void TiffImageEntry::doAccept(TiffVisitor& visitor) + { + visitor.visitImageEntry(this); + } // TiffImageEntry::doAccept + void TiffSizeEntry::doAccept(TiffVisitor& visitor) { visitor.visitSizeEntry(this); @@ -232,21 +535,20 @@ namespace Exiv2 { void TiffDirectory::doAccept(TiffVisitor& visitor) { visitor.visitDirectory(this); - Components::const_iterator b = components_.begin(); - Components::const_iterator e = components_.end(); - for (Components::const_iterator i = b; visitor.go() && i != e; ++i) { + for (Components::const_iterator i = components_.begin(); + visitor.go(TiffVisitor::geTraverse) && i != components_.end(); ++i) { (*i)->accept(visitor); } - if (visitor.go()) visitor.visitDirectoryNext(this); + if (visitor.go(TiffVisitor::geTraverse)) visitor.visitDirectoryNext(this); if (pNext_) pNext_->accept(visitor); - if (visitor.go()) visitor.visitDirectoryEnd(this); - + 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() && i != ifds_.end(); ++i) { + for (Ifds::iterator i = ifds_.begin(); + visitor.go(TiffVisitor::geTraverse) && i != ifds_.end(); ++i) { (*i)->accept(visitor); } } // TiffSubIfd::doAccept @@ -255,19 +557,18 @@ namespace Exiv2 { { visitor.visitMnEntry(this); if (mn_) mn_->accept(visitor); - if (!visitor.go()) { + if (!visitor.go(TiffVisitor::geKnownMakernote)) { delete mn_; mn_ = 0; - visitor.setGo(true); } + } // TiffMnEntry::doAccept void TiffArrayEntry::doAccept(TiffVisitor& visitor) { visitor.visitArrayEntry(this); - Components::const_iterator b = elements_.begin(); - Components::const_iterator e = elements_.end(); - for (Components::const_iterator i = b; visitor.go() && i != e; ++i) { + for (Components::const_iterator i = elements_.begin(); + visitor.go(TiffVisitor::geTraverse) && i != elements_.end(); ++i) { (*i)->accept(visitor); } } // TiffArrayEntry::doAccept @@ -277,9 +578,666 @@ namespace Exiv2 { visitor.visitArrayElement(this); } // TiffArrayElement::doAccept + void TiffEntryBase::encode(TiffEncoder& encoder, const Exifdatum* datum) + { + doEncode(encoder, datum); + } // TiffComponent::encode + + void TiffArrayElement::doEncode(TiffEncoder& encoder, const Exifdatum* datum) + { + encoder.encodeArrayElement(this, datum); + } // TiffArrayElement::doEncode + + void TiffArrayEntry::doEncode(TiffEncoder& encoder, const Exifdatum* datum) + { + encoder.encodeArrayEntry(this, datum); + } // TiffArrayEntry::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 components_.size(); + } + + uint32_t TiffEntryBase::doCount() const + { + return count_; + } + + uint32_t TiffMnEntry::doCount() const + { + // Count of tag Exif.Photo.MakerNote is the size of the Makernote in bytes + assert(typeId() == undefined); + return size(); + } + + uint32_t TiffArrayEntry::doCount() const + { + if (elements_.empty()) return 0; + + uint16_t maxTag = 0; + for (Components::const_iterator i = elements_.begin(); i != elements_.end(); ++i) { + if ((*i)->tag() > maxTag) maxTag = (*i)->tag(); + } + return maxTag + 1; + } + + uint32_t TiffComponent::write(Blob& blob, + ByteOrder byteOrder, + int32_t offset, + uint32_t valueIdx, + uint32_t dataIdx, + uint32_t imageIdx) + { + return doWrite(blob, byteOrder, offset, valueIdx, dataIdx, imageIdx); + } // TiffComponent::write + + uint32_t TiffDirectory::doWrite(Blob& blob, + ByteOrder byteOrder, + int32_t offset, + uint32_t valueIdx, + uint32_t dataIdx, + uint32_t imageIdx) + { + // Number of components to write + const uint32_t compCount = count(); + if (compCount > 0xffff) throw Error(49, tiffGroupName(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; + + // 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 + 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 (imageIdx == uint32_t(-1)) { + 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 (imageIdx == uint32_t(-1)) { // Offset to the image data + imageIdx = dataIdx + sizeData + sizeNext; + } + + // 1st: Write the IFD, a) Number of directory entries + byte buf[4]; + us2Data(buf, static_cast(compCount), byteOrder); + append(blob, 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(blob, 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); + } + append(blob, 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(blob, byteOrder, offset, valueIdx, dataIdx, imageIdx); + assert(sv == d); + if ((sv & 1) == 1) { + blob.push_back(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; + for (Components::const_iterator i = components_.begin(); i != components_.end(); ++i) { + uint32_t sd = (*i)->writeData(blob, byteOrder, offset, dataIdx, imageIdx); + assert((*i)->sizeData() == sd); + if ((sd & 1) == 1) { + blob.push_back(0x0); // Align data to word boundary + sd += 1; + } + idx += sd; + dataIdx += sd; + } + // No assertion (sizeData may not be available, see above) + // assert(idx == sizeDir + sizeValue + sizeData); + + // 4th: Write next-IFD + if (pNext_ && sizeNext) { + idx += pNext_->write(blob, byteOrder, offset + idx, uint32_t(-1), uint32_t(-1), imageIdx); + } + + // 5th: Write image data + imageIdx = idx; + for (Components::const_iterator i = components_.begin(); i != components_.end(); ++i) { + idx += (*i)->writeImage(blob, byteOrder, offset, imageIdx); + imageIdx += (*i)->sizeImage(); + } + + return idx; + } // TiffDirectory::doWrite + + uint32_t TiffDirectory::writeDirEntry(Blob& blob, + 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->typeId(), byteOrder); + ul2Data(buf + 4, pDirEntry->count(), byteOrder); + append(blob, buf, 8); + if (pDirEntry->size() > 4) { + pDirEntry->setOffset(offset + static_cast(valueIdx)); + l2Data(buf, pDirEntry->offset(), byteOrder); + append(blob, buf, 4); + } + else { + const uint32_t len = pDirEntry->write(blob, + byteOrder, + offset, + valueIdx, + dataIdx, + imageIdx); + assert(len <= 4); + if (len < 4) { + memset(buf, 0x0, 4); + append(blob, buf, 4 - len); + } + } + return 12; + } // TiffDirectory::writeDirEntry + + uint32_t TiffEntryBase::doWrite(Blob& blob, + 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); + append(blob, buf.pData_, buf.size_); + return buf.size_; + } // TiffEntryBase::doWrite + + uint32_t TiffEntryBase::writeOffset(byte* buf, + int32_t offset, + TypeId type, + ByteOrder byteOrder) + { + uint32_t rc = 0; + switch(type) { + case unsignedShort: + case signedShort: + if (static_cast(offset) > 0xffff) throw Error(26); + rc = s2Data(buf, static_cast(offset), byteOrder); + break; + case unsignedLong: + case signedLong: + rc = l2Data(buf, static_cast(offset), byteOrder); + break; + default: + throw Error(27); + break; + } + return rc; + } // TiffEntryBase::writeOffset + + uint32_t TiffDataEntry::doWrite(Blob& blob, + ByteOrder byteOrder, + int32_t offset, + uint32_t /*valueIdx*/, + uint32_t dataIdx, + uint32_t /*imageIdx*/) + { + if (!pValue()) 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, + typeId(), + byteOrder); + } + append(blob, buf.pData_, buf.size_); + return buf.size_; + } // TiffDataEntry::doWrite + + uint32_t TiffImageEntry::doWrite(Blob& blob, + ByteOrder byteOrder, + int32_t offset, + uint32_t /*valueIdx*/, + uint32_t /*dataIdx*/, + uint32_t imageIdx) + { + DataBuf buf(strips_.size() * 4); + uint32_t idx = 0; + for (Strips::const_iterator i = strips_.begin(); i != strips_.end(); ++i) { + idx += writeOffset(buf.pData_ + idx, offset + imageIdx, typeId(), byteOrder); + imageIdx += i->second; + } + append(blob, buf.pData_, buf.size_); + return buf.size_; + } // TiffImageEntry::doWrite + + uint32_t TiffSubIfd::doWrite(Blob& blob, + ByteOrder byteOrder, + int32_t offset, + uint32_t /*valueIdx*/, + uint32_t dataIdx, + uint32_t /*imageIdx*/) + { + DataBuf buf(ifds_.size() * 4); + uint32_t idx = 0; + for (Ifds::const_iterator i = ifds_.begin(); i != ifds_.end(); ++i) { + idx += writeOffset(buf.pData_ + idx, offset + dataIdx, typeId(), byteOrder); + dataIdx += (*i)->size(); + } + append(blob, buf.pData_, buf.size_); + return buf.size_; + } // TiffSubIfd::doWrite + + uint32_t TiffMnEntry::doWrite(Blob& blob, + ByteOrder byteOrder, + int32_t offset, + uint32_t valueIdx, + uint32_t dataIdx, + uint32_t imageIdx) + { + if (!mn_) { + return TiffEntryBase::doWrite(blob, byteOrder, offset, valueIdx, dataIdx, imageIdx); + } + return mn_->write(blob, byteOrder, offset + valueIdx, uint32_t(-1), uint32_t(-1), imageIdx); + } // TiffMnEntry::doWrite + + uint32_t TiffArrayEntry::doWrite(Blob& blob, + ByteOrder byteOrder, + int32_t offset, + uint32_t valueIdx, + uint32_t dataIdx, + uint32_t imageIdx) + { + const uint32_t cnt = count(); + if (cnt == 0) return 0; + + uint32_t idx = 0; + int32_t nextTag = 0; + + // Some array entries need to have the size in the first element + if (addSizeElement_) { + byte buf[4]; + switch (elSize_) { + case 2: + idx += us2Data(buf, size(), byteOrder); + break; + case 4: + idx += ul2Data(buf, size(), byteOrder); + break; + default: + assert(false); + } + append(blob, buf, elSize_); + nextTag = 1; + } + + // Tags must be sorted in ascending order + std::sort(elements_.begin(), elements_.end(), cmpTagLt); + uint32_t seq = 0; + for (Components::const_iterator i = elements_.begin(); i != elements_.end(); ++i) { + // Skip deleted entries at the end of the array + if (seq++ > cnt) break; + // Skip the manufactured tag, if it exists + if (addSizeElement_ && (*i)->tag() == 0x0000) continue; + // Fill gaps. Repeated tags will cause an exception + int32_t gap = ((*i)->tag() - nextTag) * elSize_; + if (gap < 0) throw Error(50, (*i)->tag()); + if (gap > 0) { + blob.insert(blob.end(), gap, 0); + idx += gap; + } + idx += (*i)->write(blob, byteOrder, offset + idx, valueIdx, dataIdx, imageIdx); + nextTag = (*i)->tag() + 1; + } + return idx; + } // TiffArrayEntry::doWrite + + uint32_t TiffArrayElement::doWrite(Blob& blob, + 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; + if (!(pv->count() == 1 && pv->typeId() == elTypeId_)) { + throw Error(51, tag()); + } + DataBuf buf(pv->size()); + if (elByteOrder_ != invalidByteOrder) byteOrder = elByteOrder_; + pv->copy(buf.pData_, byteOrder); + append(blob, buf.pData_, buf.size_); + return buf.size_; + } // TiffArrayElement::doWrite + + uint32_t TiffComponent::writeData(Blob& blob, + ByteOrder byteOrder, + int32_t offset, + uint32_t dataIdx, + uint32_t imageIdx) const + { + return doWriteData(blob, byteOrder, offset, dataIdx, imageIdx); + } // TiffComponent::writeData + + uint32_t TiffDirectory::doWriteData(Blob& /*blob*/, + ByteOrder /*byteOrder*/, + int32_t /*offset*/, + uint32_t /*dataIdx*/, + uint32_t /*imageIdx*/) const + { + // We don't expect this method to be called. This makes it obvious. + assert(false); + return 0; + } // TiffDirectory::doWriteData + + uint32_t TiffEntryBase::doWriteData(Blob& /*blob*/, + ByteOrder /*byteOrder*/, + int32_t /*offset*/, + uint32_t /*dataIdx*/, + uint32_t /*imageIdx*/) const + { + return 0; + } // TiffEntryBase::doWriteData + + uint32_t TiffDataEntry::doWriteData(Blob& blob, + ByteOrder /*byteOrder*/, + int32_t /*offset*/, + uint32_t /*dataIdx*/, + uint32_t /*imageIdx*/) const + { + if (!pValue()) return 0; + + DataBuf buf = pValue()->dataArea(); + append(blob, buf.pData_, buf.size_); + return buf.size_; + } // TiffDataEntry::doWriteData + + uint32_t TiffSubIfd::doWriteData(Blob& blob, + 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(blob, byteOrder, offset + dataIdx + len, uint32_t(-1), uint32_t(-1), imageIdx); + } + return len; + } // TiffSubIfd::doWriteData + + uint32_t TiffComponent::writeImage(Blob& blob, + ByteOrder byteOrder, + int32_t offset, + uint32_t imageIdx) const + { + return doWriteImage(blob, byteOrder, offset, imageIdx); + } // TiffComponent::writeImage + + uint32_t TiffDirectory::doWriteImage(Blob& /*blob*/, + ByteOrder /*byteOrder*/, + int32_t /*offset*/, + uint32_t /*imageIdx*/) const + { + // We don't expect this method to be called. This makes it obvious. + assert(false); + return 0; + } // TiffDirectory::doWriteImage + + uint32_t TiffEntryBase::doWriteImage(Blob& /*blob*/, + ByteOrder /*byteOrder*/, + int32_t /*offset*/, + uint32_t /*imageIdx*/) const + { + return 0; + } // TiffEntryBase::doWriteImage + + uint32_t TiffImageEntry::doWriteImage(Blob& blob, + ByteOrder /*byteOrder*/, + int32_t /*offset*/, + uint32_t /*imageIdx*/) const + { + uint32_t len = pValue()->sizeDataArea(); + if (len > 0) { + DataBuf buf = pValue()->dataArea(); + append(blob, buf.pData_, buf.size_); + } + else { + len = 0; + for (Strips::const_iterator i = strips_.begin(); i != strips_.end(); ++i) { + append(blob, i->first, i->second); + len += i->second; + } + } + return len; + } // TiffImageEntry::doWriteData + + 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 strips_.size() * 4; + } // TiffImageEntry::doSize + + uint32_t TiffSubIfd::doSize() const + { + return ifds_.size() * 4; + } // TiffSubIfd::doSize + + uint32_t TiffMnEntry::doSize() const + { + if (!mn_) { + return TiffEntryBase::doSize(); + } + return mn_->size(); + } // TiffMnEntry::doSize + + uint32_t TiffArrayEntry::doSize() const + { + return count() * elSize_; + } // TiffArrayEntry::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 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 TiffComponent::sizeImage() const + { + return doSizeImage(); + } // TiffComponent::sizeImage + + uint32_t TiffDirectory::doSizeImage() const + { + assert(false); + return 0; + } // TiffDirectory::doSizeImage + + uint32_t TiffEntryBase::doSizeImage() const + { + return 0; + } // TiffEntryBase::doSizeImage + + uint32_t TiffImageEntry::doSizeImage() const + { + 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 + bool cmpTagLt(TiffComponent const* lhs, TiffComponent const* rhs) + { + assert(lhs != 0); + assert(rhs != 0); + return lhs->tag() < rhs->tag(); + } + TiffComponent::AutoPtr newTiffDirectory(uint16_t tag, const TiffStructure* ts) { @@ -287,6 +1245,13 @@ namespace Exiv2 { return TiffComponent::AutoPtr(new TiffDirectory(tag, ts->newGroup_)); } + TiffComponent::AutoPtr newTiffEntry(uint16_t tag, + const TiffStructure* ts) + { + assert(ts); + return TiffComponent::AutoPtr(new TiffEntry(tag, ts->newGroup_)); + } + TiffComponent::AutoPtr newTiffSubIfd(uint16_t tag, const TiffStructure* ts) { @@ -305,4 +1270,4 @@ namespace Exiv2 { ts->newGroup_)); } -} // namespace Exiv2 +}} // namespace Internal, Exiv2 diff --git a/src/tiffcomposite.hpp b/src/tiffcomposite.hpp deleted file mode 100644 index f89389ba..00000000 --- a/src/tiffcomposite.hpp +++ /dev/null @@ -1,641 +0,0 @@ -// ***************************************************************** -*- C++ -*- -/* - * Copyright (C) 2004-2008 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.hpp - @brief Various classes used in a TIFF composite structure - @version $Rev$ - @author Andreas Huggel (ahu) - ahuggel@gmx.net - @date 11-Apr-06, ahu: created - */ -#ifndef TIFFCOMPOSITE_HPP_ -#define TIFFCOMPOSITE_HPP_ - -// ***************************************************************************** -// included header files -#include "image.hpp" // for Blob -#include "tifffwd.hpp" -#include "types.hpp" - -// + standard includes -#include -#include -#include -#include - -// ***************************************************************************** -// namespace extensions -namespace Exiv2 { - -// ***************************************************************************** -// class definitions - - /*! - Known TIFF groups - - Todo: what exactly are these and where should they go? - Are they going to be mapped to the second part of an Exif key or are they - the second part of the key? - */ - namespace Group { - const uint16_t none = 0; //!< Dummy group - const uint16_t ifd0 = 1; //!< Exif IFD0 - const uint16_t ifd1 = 2; //!< Thumbnail IFD - const uint16_t exif = 3; //!< Exif IFD - const uint16_t gps = 4; //!< GPS IFD - const uint16_t iop = 5; //!< Interoperability IFD - const uint16_t sub0_0 = 6; //!< Tiff SubIFD 0 in IFD0 - const uint16_t sub0_1 = 7; //!< Tiff SubIFD 1 in IFD0 - const uint16_t sub0_2 = 8; //!< Tiff SubIFD 2 in IFD0 - const uint16_t sub0_3 = 9; //!< Tiff SubIFD 3 in IFD0 - const uint16_t mn = 256; //!< Makernote - const uint16_t ignr = 511; //!< Read but do not decode - } - - /*! - Special TIFF tags for the use in TIFF structures only - - Todo: Same Q as above... - */ - 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 - } - - /*! - @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). - */ - 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, uint16_t group) - : tag_(tag), group_(group), pData_(0) {} - - //! Virtual destructor. - virtual ~TiffComponent() {} - //@} - - //! @name Manipulators - //@{ - //! Add a child to the component. Default is to do nothing. - void addChild(AutoPtr tiffComponent); - //! Add a "next" component to the component. Default is to do nothing. - void addNext(AutoPtr tiffComponent); - /*! - @brief Interface to accept visitors (Visitor pattern). - - @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* pData) { pData_ = const_cast(pData); } - //@} - - //! @name Accessors - //@{ - //! Return the tag of this entry. - uint16_t tag() const { return tag_; } - //! Return the group id of this component - uint16_t group() const { return group_; } - //! Return the group name of this component - std::string groupName() const; - //! Return a pointer to the start of the binary representation of the component - const byte* start() const { return pData_; } - - protected: - //! @name Manipulators - //@{ - //! Implements addChild(). The default implementation does nothing. - virtual void doAddChild(AutoPtr /*tiffComponent*/) {} - - //! Implements addNext(). The default implementation does nothing. - virtual void doAddNext(AutoPtr /*tiffComponent*/) {} - - //! Implements accept() - virtual void doAccept(TiffVisitor& visitor) =0; - //@} - - private: - // DATA - uint16_t tag_; //!< Tag that identifies the component - uint16_t 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* pData_; - - }; // class TiffComponent - - /*! - @brief Data structure used as a row (element) of a table (array) - describing the TIFF structure of an image format for reading and - writing. Different tables can be used to support different TIFF - based image formats. - */ - struct TiffStructure { - struct Key; - //! Comparison operator to compare a TiffStructure with a TiffStructure::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 - uint32_t extendedTag_; //!< Tag (32 bit so that it can contain special tags) - uint16_t group_; //!< Group that contains the tag - NewTiffCompFct newTiffCompFct_; //!< Function to create the correct TIFF component - uint16_t newGroup_; //!< Group of the newly created component - }; - - //! Search key for TIFF structure. - struct TiffStructure::Key { - //! Constructor - Key(uint32_t e, uint16_t g) : e_(e), g_(g) {} - uint32_t e_; //!< Extended tag - uint16_t g_; //!< %Group - }; - - //! TIFF decoder table for functions to decode special cases - struct TiffDecoderInfo { - struct Key; - /*! - @brief Compare a TiffDecoderInfo with a TiffDecoderInfo::Key. - The two are equal if TiffDecoderInfo::make_ equals a substring - of the key of the same size. E.g., decoder 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 this decoder function applies - uint32_t extendedTag_; //!< Tag (32 bit so that it can contain special tags) - uint16_t group_; //!< Group that contains the tag - DecoderFct decoderFct_; //!< Decoder function for matching tags - - }; // struct TiffDecoderInfo - - //! Search key for TIFF decoder structures. - struct TiffDecoderInfo::Key { - //! Constructor - Key(const std::string& m, uint32_t e, uint16_t g) : m_(m), e_(e), g_(g) {} - std::string m_; //!< Camera make - uint32_t e_; //!< Extended tag - uint16_t 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; - public: - //! @name Creators - //@{ - //! Default constructor - TiffEntryBase(uint16_t tag, uint16_t group) - : TiffComponent(tag, group), - type_(0), count_(0), offset_(0), - size_(0), pData_(0), isAllocated_(false), pValue_(0) {} - //! Virtual destructor. - virtual ~TiffEntryBase(); - //@} - - //! @name Accessors - //@{ - //! Return the Exiv2 type which corresponds to the field type - TypeId typeId() const { return TypeId(type_); } - //! Return the number of components in this entry - uint32_t count() const { return count_; } - /*! - Return the offset to the data area relative to the base for - the component (usually the start of the TIFF header) - */ - uint32_t offset() const { return offset_; } - //! Return the size of this component in bytes - uint32_t size() const { return size_; } - //! Return a pointer to the data area of this component - const byte* pData() const { return pData_; } - //! Return a pointer to the converted value of this component - const Value* pValue() const { return pValue_; } - //@} - - private: - // DATA - uint16_t type_; //!< Field Type - uint32_t count_; //!< The number of values of the indicated Type - uint32_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_; - const byte* pData_; //!< Pointer to the data area - bool isAllocated_; //!< True if this entry owns the value data - 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, uint16_t group) : TiffEntryBase(tag, group) {} - //! Virtual destructor. - virtual ~TiffEntry() {} - //@} - - private: - //! @name Manipulators - //@{ - virtual void doAccept(TiffVisitor& visitor); - //@} - - }; // class TiffEntry - - /*! - @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 is used, e.g., for - \em Exif.Thumbnail.JPEGInterchangeFormat for which the size is - provided in \em Exif.Thumbnail.JPEGInterchangeFormatLength. - */ - class TiffDataEntry : public TiffEntryBase { - public: - //! @name Creators - //@{ - //! Constructor - TiffDataEntry(uint16_t tag, uint16_t group, uint16_t szTag, uint16_t szGroup) - : TiffEntryBase(tag, group), szTag_(szTag), szGroup_(szGroup) {} - //! Virtual destructor. - virtual ~TiffDataEntry() {} - //@} - - //! @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 - uint16_t szGroup() const { return szGroup_; } - //@} - - private: - //! @name Manipulators - //@{ - virtual void doAccept(TiffVisitor& visitor); - //@} - - private: - // DATA - const uint16_t szTag_; //!< Tag of the entry with the size - const uint16_t szGroup_; //!< Group of the entry with the size - - }; // class TiffDataEntry - - /*! - @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, uint16_t group, uint16_t dtTag, uint16_t 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 - uint16_t dtGroup() const { return dtGroup_; } - //@} - - private: - //! @name Manipulators - //@{ - virtual void doAccept(TiffVisitor& visitor); - //@} - - private: - // DATA - const uint16_t dtTag_; //!< Tag of the entry with the data area - const uint16_t 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 TiffPrinter; - public: - //! @name Creators - //@{ - //! Default constructor - TiffDirectory(uint16_t tag, uint16_t group, bool hasNext =true) - : TiffComponent(tag, group), hasNext_(hasNext), pNext_(0) {} - //! Virtual destructor - virtual ~TiffDirectory(); - //@} - - //! @name Manipulators - //@{ - //! Return true if the directory has a next pointer - bool hasNext() const { return hasNext_; } - //@} - - private: - //! @name Manipulators - //@{ - virtual void doAddChild(TiffComponent::AutoPtr tiffComponent); - virtual void doAddNext(TiffComponent::AutoPtr tiffComponent); - virtual void doAccept(TiffVisitor& visitor); - //@} - - 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 - - //! A collection of TIFF directories (IFDs) - typedef std::vector Ifds; - - /*! - @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, uint16_t group, uint16_t newGroup) - : TiffEntryBase(tag, group), newGroup_(newGroup) {} - //! Virtual destructor - virtual ~TiffSubIfd(); - //@} - - private: - //! @name Manipulators - //@{ - virtual void doAddChild(TiffComponent::AutoPtr tiffComponent); - virtual void doAccept(TiffVisitor& visitor); - //@} - - private: - // DATA - uint16_t 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 TiffMetadataDecoder; - friend class TiffPrinter; - public: - //! @name Creators - //@{ - //! Default constructor - TiffMnEntry(uint16_t tag, uint16_t group, uint16_t mnGroup) - : TiffEntryBase(tag, group), mnGroup_(mnGroup), mn_(0) {} - //! Virtual destructor - virtual ~TiffMnEntry(); - //@} - - private: - //! @name Manipulators - //@{ - virtual void doAddChild(TiffComponent::AutoPtr tiffComponent); - virtual void doAddNext(TiffComponent::AutoPtr tiffComponent); - virtual void doAccept(TiffVisitor& visitor); - //@} - - private: - // DATA - uint16_t mnGroup_; //!< New group for concrete mn - TiffComponent* mn_; //!< The Makernote - - }; // class TiffMnEntry - - /*! - @brief Composite to model an array of tags, each consisting of one - unsigned short value. Canon and Minolta makernotes use such tags. - The elements of this component are usually of type - TiffArrayElement. - */ - class TiffArrayEntry : public TiffEntryBase { - public: - //! @name Creators - //@{ - //! Default constructor - TiffArrayEntry(uint16_t tag, - uint16_t group, - uint16_t elGroup, - uint16_t elSize) - : TiffEntryBase(tag, group), - elSize_(elSize), - elGroup_(elGroup) {} - //! Virtual destructor - virtual ~TiffArrayEntry(); - //@} - - //! @name Accessors - //@{ - //! Return the type for the array elements - uint16_t elSize() const { return elSize_; } - //! Return the group for the array elements - uint16_t elGroup() const { return elGroup_; } - //@} - - private: - //! @name Manipulators - //@{ - virtual void doAddChild(TiffComponent::AutoPtr tiffComponent); - virtual void doAccept(TiffVisitor& visitor); - //@} - - private: - // DATA - uint16_t elSize_; //!< Size of the array elements (in bytes) - uint16_t elGroup_; //!< Group for the elements - Components elements_; //!< List of elements in this composite - }; // class TiffArrayEntry - - /*! - @brief Element of a TiffArrayEntry. The value is exactly one unsigned - short component. Canon and Minolta makernotes use arrays of - such elements. - */ - class TiffArrayElement : public TiffEntryBase { - public: - //! @name Creators - //@{ - //! Constructor - TiffArrayElement(uint16_t tag, - uint16_t group, - TypeId elTypeId, - ByteOrder elByteOrder) - : TiffEntryBase(tag, group), - elTypeId_(elTypeId), - elByteOrder_(elByteOrder) {} - //! Virtual destructor. - virtual ~TiffArrayElement() {} - //@} - - //! @name Accessors - //@{ - TypeId elTypeId() const { return elTypeId_; } - ByteOrder elByteOrder() const { return elByteOrder_; } - //@} - - private: - //! @name Manipulators - //@{ - virtual void doAccept(TiffVisitor& visitor); - //@} - - private: - // DATA - TypeId elTypeId_; //!< Type of the element - ByteOrder elByteOrder_; //!< Byte order to read/write the element - - }; // class TiffArrayElement - -// ***************************************************************************** -// template, inline and free functions - - //! Return the group name for a group - const char* tiffGroupName(uint16_t group); - - //! Function to create and initialize a new TIFF directory - TiffComponent::AutoPtr newTiffDirectory(uint16_t tag, - const TiffStructure* ts); - - //! Function to create and initialize a new TIFF sub-directory - TiffComponent::AutoPtr newTiffSubIfd(uint16_t tag, - const TiffStructure* ts); - - //! Function to create and initialize a new TIFF makernote entry - TiffComponent::AutoPtr newTiffMnEntry(uint16_t tag, - const TiffStructure* ts); - - //! Function to create and initialize a new array entry - template - TiffComponent::AutoPtr newTiffArrayEntry(uint16_t tag, - const TiffStructure* ts) - { - assert(ts); - return TiffComponent::AutoPtr( - new TiffArrayEntry(tag, ts->group_, ts->newGroup_, elSize)); - } - - //! Function to create and initialize a new array element - template - TiffComponent::AutoPtr newTiffArrayElement(uint16_t tag, - const TiffStructure* ts) - { - assert(ts); - return TiffComponent::AutoPtr( - new TiffArrayElement(tag, ts->group_, typeId, byteOrder)); - } - - template - TiffComponent::AutoPtr newTiffArrayElement(uint16_t tag, - const TiffStructure* ts) - { - return newTiffArrayElement(tag, ts); - } - - //! Function to create and initialize a new TIFF entry for a thumbnail (data) - template - TiffComponent::AutoPtr newTiffThumbData(uint16_t tag, - const TiffStructure* ts) - { - assert(ts); - return TiffComponent::AutoPtr( - new TiffDataEntry(tag, ts->group_, szTag, szGroup)); - } - - //! Function to create and initialize a new TIFF entry for a thumbnail (size) - template - TiffComponent::AutoPtr newTiffThumbSize(uint16_t tag, - const TiffStructure* ts) - { - assert(ts); - return TiffComponent::AutoPtr( - new TiffSizeEntry(tag, ts->group_, dtTag, dtGroup)); - } - -} // namespace Exiv2 - -#endif // #ifndef TIFFCOMPOSITE_HPP_ diff --git a/src/tiffcomposite_int.hpp b/src/tiffcomposite_int.hpp new file mode 100644 index 00000000..cd45cd38 --- /dev/null +++ b/src/tiffcomposite_int.hpp @@ -0,0 +1,1261 @@ +// ***************************************************************** -*- C++ -*- +/* + * Copyright (C) 2004-2008 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$ + @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 "image.hpp" // for Blob +#include "tifffwd_int.hpp" +#include "types.hpp" + +// + standard includes +#include +#include +#include +#include + +// ***************************************************************************** +// namespace extensions +namespace Exiv2 { + namespace Internal { + +// ***************************************************************************** +// class definitions + + /*! + Known TIFF groups + + Todo: what exactly are these and where should they go? + Are they going to be mapped to the second part of an Exif key or are they + the second part of the key? + */ + namespace Group { + const uint16_t none = 0; //!< Dummy group + const uint16_t ifd0 = 1; //!< Exif IFD0 + const uint16_t ifd1 = 2; //!< Thumbnail IFD + const uint16_t exif = 3; //!< Exif IFD + const uint16_t gps = 4; //!< GPS IFD + const uint16_t iop = 5; //!< Interoperability IFD + const uint16_t sub0_0 = 6; //!< Tiff SubIFD 0 in IFD0 + const uint16_t sub0_1 = 7; //!< Tiff SubIFD 1 in IFD0 + const uint16_t sub0_2 = 8; //!< Tiff SubIFD 2 in IFD0 + const uint16_t sub0_3 = 9; //!< Tiff SubIFD 3 in IFD0 + const uint16_t mn = 256; //!< Makernote + const uint16_t ignr = 511; //!< Read but do not decode + } + + /*! + Special TIFF tags for the use in TIFF structures only + + Todo: Same Q as above... + */ + 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 + } + + /*! + @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, uint16_t 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. + + @return A pointer to the newly added TIFF entry. + */ + TiffComponent* addPath(uint16_t tag, TiffPath& tiffPath); + /*! + @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); } + //@} + + //! @name Accessors + //@{ + //! Return the tag of this entry. + uint16_t tag() const { return tag_; } + //! Return the group id of this component + uint16_t group() const { return group_; } + //! Return a pointer to the start of the binary representation of the component + byte* start() const { return pStart_; } + //@} + + //! @name Write support (Manipulators) + //@{ + /*! + @brief Write a TiffComponent to a binary image. + + @param blob Binary image to append the TiffComponent to. + @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 blob including all + nested components. + @throw Error If the component cannot be written. + */ + uint32_t write(Blob& blob, + ByteOrder byteOrder, + int32_t offset, + uint32_t valueIdx, + uint32_t dataIdx, + uint32_t imageIdx); + //@} + + //! @name Write support (Accessors) + //@{ + /*! + @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(Blob& blob, + 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. Components derived from + TiffEntryBase implement this method if needed. + */ + uint32_t writeImage(Blob& blob, + ByteOrder byteOrder, + int32_t offset, + uint32_t imageIdx) 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(). Components derived from TiffEntryBase implement this + method corresponding to their implementation of writeImage(). + */ + uint32_t sizeImage() const; + //@} + + protected: + //! @name Manipulators + //@{ + //! Implements addPath(). The default implementation does nothing. + virtual TiffComponent* doAddPath(uint16_t /*tag*/, + TiffPath& /*tiffPath*/) { return this; } + //! Implements addChild(). The default implementation does nothing. + virtual TiffComponent* doAddChild(AutoPtr /*tiffComponent*/) { return 0; } + //! Implements addNext(). The default implementation does nothing. + virtual TiffComponent* doAddNext(AutoPtr /*tiffComponent*/) { return 0; } + //! Implements accept(). + virtual void doAccept(TiffVisitor& visitor) =0; + //@} + + //! @name Write support (Manipulators) + //@{ + //! Implements write(). + virtual uint32_t doWrite(Blob& blob, + ByteOrder byteOrder, + int32_t offset, + uint32_t valueIdx, + uint32_t dataIdx, + uint32_t imageIdx) =0; + //@} + + //! @name Write support (Accessors) + //@{ + //! Implements writeData(). + virtual uint32_t doWriteData(Blob& blob, + ByteOrder byteOrder, + int32_t offset, + uint32_t dataIdx, + uint32_t imageIdx) const =0; + //! Implements writeImage(). + virtual uint32_t doWriteImage(Blob& blob, + ByteOrder byteOrder, + int32_t offset, + uint32_t imageIdx) 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 + uint16_t 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 + + /*! + @brief Data structure used as a row (element) of a table (array) + describing the TIFF structure of an image format for reading and + writing. Different tables can be used to support different TIFF + based image formats. + */ + struct TiffStructure { + struct Key; + //! Comparison operator to compare a TiffStructure with a TiffStructure::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 + uint32_t extendedTag_; //!< Tag (32 bit so that it can contain special tags) + uint16_t group_; //!< Group that contains the tag + uint16_t newGroup_; //!< Group of the newly created component + uint32_t parentExtTag_; //!< Parent tag (32 bit so that it can contain special tags) + uint16_t parentGroup_; //!< Parent group + NewTiffCompFct newTiffCompFct_; //!< Function to create the correct TIFF component + }; + + //! Search key for TIFF structure. + struct TiffStructure::Key { + //! Constructor + Key(uint32_t e, uint16_t g) : e_(e), g_(g) {} + uint32_t e_; //!< Extended tag + uint16_t g_; //!< %Group + }; + + //! 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) + uint16_t 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, uint16_t g) : m_(m), e_(e), g_(g) {} + std::string m_; //!< Camera make + uint32_t e_; //!< Extended tag + uint16_t 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; + public: + //! @name Creators + //@{ + //! Default constructor + TiffEntryBase(uint16_t tag, uint16_t group, TypeId typeId =invalidTypeId); + //! 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; } + void setData(byte* pData, int32_t size); + /*! + @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 Exiv2 type which corresponds to the field type + TypeId typeId() const { return TypeId(type_); } + /*! + @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 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 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; } + //@} + + //! @name Accessors + //@{ + //! Implements count(). + virtual uint32_t doCount() const; + //@} + //! @name Write support (Manipulators) + //@{ + /*! + @brief Implements write(). Write the value of a standard TIFF entry to + the \em blob, return the number of bytes written. Only the \em + blob and \em byteOrder arguments are used. + */ + virtual uint32_t doWrite(Blob& blob, + ByteOrder byteOrder, + int32_t offset, + uint32_t valueIdx, + uint32_t dataIdx, + uint32_t imageIdx); + //@} + //! @name Write support (Accessors) + //@{ + /*! + @brief Implements writeData(). Standard TIFF entries have no data: + write nothing and return 0. + */ + virtual uint32_t doWriteData(Blob& blob, + 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(Blob& blob, + ByteOrder byteOrder, + int32_t offset, + uint32_t imageIdx) 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, + TypeId type, + ByteOrder byteOrder); + + private: + //! @name Manipulators + //@{ + //! Allocate \em len bytes for the binary representation of the value. + void allocData(uint32_t len); + //@} + + // DATA + uint16_t type_; //!< Field 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 + 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, uint16_t group) : TiffEntryBase(tag, group) {} + //! Virtual destructor. + virtual ~TiffEntry() {} + //@} + + protected: + //! @name Manipulators + //@{ + virtual void doAccept(TiffVisitor& visitor); + virtual void doEncode(TiffEncoder& encoder, const Exifdatum* datum); + //@} + + }; // 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, uint16_t group, uint16_t szTag, uint16_t 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 + uint16_t szGroup() const { return szGroup_; } + //@} + + private: + // DATA + const uint16_t szTag_; //!< Tag of the entry with the size + const uint16_t 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, uint16_t group, uint16_t szTag, uint16_t 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 Manipulators + //@{ + virtual void doAccept(TiffVisitor& visitor); + virtual void doEncode(TiffEncoder& encoder, const Exifdatum* datum); + //@} + + //! @name Write support (Manipulators) + //@{ + /*! + @brief Implements write(). Write pointers into the data area to the + \em blob, 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(Blob& blob, + ByteOrder byteOrder, + int32_t offset, + uint32_t valueIdx, + uint32_t dataIdx, + uint32_t imageIdx); + //@} + //! @name Write support (Accessors) + //@{ + /*! + @brief Implements writeData(). Write the data area to the blob. Return + the number of bytes written. + */ + virtual uint32_t doWriteData(Blob& blob, + 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, uint16_t group, uint16_t szTag, uint16_t 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 Manipulators + //@{ + virtual void doAccept(TiffVisitor& visitor); + virtual void doEncode(TiffEncoder& encoder, const Exifdatum* datum); + //@} + + //! @name Write support (Manipulators) + //@{ + /*! + @brief Implements write(). Write pointers into the image data area to the + \em blob. Return the number of bytes written. The \em valueIdx + and \em dataIdx arguments are not used. + */ + virtual uint32_t doWrite(Blob& blob, + ByteOrder byteOrder, + int32_t offset, + uint32_t valueIdx, + uint32_t dataIdx, + uint32_t imageIdx); + //@} + //! @name Write support (Accessors) + //@{ + // Using doWriteData from base class + /*! + @brief Implements writeImage(). Write the image data area to the blob. + Return the number of bytes written. + */ + virtual uint32_t doWriteImage(Blob& blob, + ByteOrder byteOrder, + int32_t offset, + uint32_t imageIdx) const; + //! Implements size(). Return the size of the strip pointers. + virtual uint32_t doSize() const; + // Using doSizeData from base class + //! 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, uint16_t group, uint16_t dtTag, uint16_t 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 + uint16_t dtGroup() const { return dtGroup_; } + //@} + + protected: + //! @name Manipulators + //@{ + virtual void doAccept(TiffVisitor& visitor); + virtual void doEncode(TiffEncoder& encoder, const Exifdatum* datum); + //@} + + private: + // DATA + const uint16_t dtTag_; //!< Tag of the entry with the data area + const uint16_t 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; + friend class TiffPrinter; + public: + //! @name Creators + //@{ + //! Default constructor + TiffDirectory(uint16_t tag, uint16_t 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 Manipulators + //@{ + virtual TiffComponent* doAddPath(uint16_t tag, TiffPath& tiffPath); + virtual TiffComponent* doAddChild(TiffComponent::AutoPtr tiffComponent); + virtual TiffComponent* doAddNext(TiffComponent::AutoPtr tiffComponent); + virtual void doAccept(TiffVisitor& visitor); + //@} + + //! @name Write support (Manipulators) + //@{ + /*! + @brief Implements write(). Write the TIFF directory, values and + additional data, including the next-IFD, if any, to the blob, + return the number of bytes written. + */ + virtual uint32_t doWrite(Blob& blob, + ByteOrder byteOrder, + int32_t offset, + uint32_t valueIdx, + uint32_t dataIdx, + uint32_t imageIdx); + //@} + //! @name Write support (Accessors) + //@{ + /*! + @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(Blob& blob, + ByteOrder byteOrder, + int32_t offset, + uint32_t dataIdx, + uint32_t imageIdx) const; + /*! + @brief This class does not really implement writeImage(), it only has + write(). This method must not be called; it commits suicide. + */ + virtual uint32_t doWriteImage(Blob& blob, + ByteOrder byteOrder, + int32_t offset, + uint32_t imageIdx) 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 This class does not really implement sizeImage(), it only has + size(). This method must not be called; it commits suicide. + */ + virtual uint32_t doSizeImage() const; + //@} + + private: + //! @name Accessors + //@{ + //! Write a binary directory entry for a TIFF component. + uint32_t writeDirEntry(Blob& blob, + 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, uint16_t group, uint16_t newGroup); + //! Virtual destructor + virtual ~TiffSubIfd(); + //@} + + protected: + //! @name Manipulators + //@{ + virtual TiffComponent* doAddPath(uint16_t tag, TiffPath& tiffPath); + virtual TiffComponent* doAddChild(TiffComponent::AutoPtr tiffComponent); + virtual void doAccept(TiffVisitor& visitor); + virtual void doEncode(TiffEncoder& encoder, const Exifdatum* datum); + //@} + + //! @name Write support (Manipulators) + //@{ + /*! + @brief Implements write(). Write the sub-IFD pointers to the \em blob, + return the number of bytes written. The \em valueIdx and + \em imageIdx arguments are not used. + */ + virtual uint32_t doWrite(Blob& blob, + ByteOrder byteOrder, + int32_t offset, + uint32_t valueIdx, + uint32_t dataIdx, + uint32_t imageIdx); + //@} + //! @name Write support (Accessors) + //@{ + /*! + @brief Implements writeData(). Write the sub-IFDs to the blob. Return + the number of bytes written. + */ + virtual uint32_t doWriteData(Blob& blob, + ByteOrder byteOrder, + int32_t offset, + uint32_t dataIdx, + uint32_t imageIdx) const; + // Using doWriteImage from base class + //! 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; + // Using doSizeImage from base class + //@} + + private: + //! A collection of TIFF directories (IFDs) + typedef std::vector Ifds; + + // DATA + uint16_t 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; + friend class TiffPrinter; + public: + //! @name Creators + //@{ + //! Default constructor + TiffMnEntry(uint16_t tag, uint16_t group, uint16_t mnGroup); + //! Virtual destructor + virtual ~TiffMnEntry(); + //@} + + protected: + //! @name Manipulators + //@{ + virtual TiffComponent* doAddPath(uint16_t tag, TiffPath& tiffPath); + 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); + //@} + + //! @name Accessors + //@{ + //! Implements count(). Return number of components in the entry. + virtual uint32_t doCount() const; + //@} + + //! @name Write support (Manipulators) + //@{ + /*! + @brief Implements write() by forwarding the call to the actual + concrete Makernote, if there is one. + */ + virtual uint32_t doWrite(Blob& blob, + ByteOrder byteOrder, + int32_t offset, + uint32_t valueIdx, + uint32_t dataIdx, + uint32_t imageIdx); + //@} + //! @name Write support (Accessors) + //@{ + // 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: + // DATA + uint16_t mnGroup_; //!< New group for concrete mn + TiffComponent* mn_; //!< The Makernote + + }; // class TiffMnEntry + + /*! + @brief Composite to model an array of tags, each consisting of one value + of a given type. Canon and Minolta makernotes use such tags. The + elements of this component are of type TiffArrayElement. + */ + class TiffArrayEntry : public TiffEntryBase { + public: + //! @name Creators + //@{ + //! Constructor + TiffArrayEntry(uint16_t tag, + uint16_t group, + uint16_t elGroup, + TypeId elTypeId, + bool addSizeElement); + //! Virtual destructor + virtual ~TiffArrayEntry(); + //@} + + //! @name Accessors + //@{ + //! Return the type for the array elements + uint16_t elSize() const { return elSize_; } + //! Return the group for the array elements + uint16_t elGroup() const { return elGroup_; } + //@} + + protected: + //! @name Manipulators + //@{ + virtual TiffComponent* doAddPath(uint16_t tag, TiffPath& tiffPath); + virtual TiffComponent* doAddChild(TiffComponent::AutoPtr tiffComponent); + virtual void doAccept(TiffVisitor& visitor); + virtual void doEncode(TiffEncoder& encoder, const Exifdatum* datum); + //@} + + //! @name Accessors + //@{ + //! Implements count(). Return number of components in the entry. + virtual uint32_t doCount() const; + //@} + + //! @name Write support (Manipulators) + //@{ + /*! + @brief Implements write(). Write each component, fill gaps with 0s. + Check for duplicate tags and throw Error(50) if any are + detected. + */ + virtual uint32_t doWrite(Blob& blob, + ByteOrder byteOrder, + int32_t offset, + uint32_t valueIdx, + uint32_t dataIdx, + uint32_t imageIdx); + //@} + //! @name Write support (Accessors) + //@{ + // Using doWriteData from base class + // Using doWriteImage from base class + /*! + @brief Implements size(). + */ + virtual uint32_t doSize() const; + // Using doSizeData from base class + // Using doSizeImage from base class + //@} + + private: + // DATA + uint16_t elSize_; //!< Size of the array elements (in bytes) + uint16_t elGroup_; //!< Group for the elements + bool addSizeElement_; //!< Indicates size needs to be provided in the first element + Components elements_; //!< List of elements in this composite + }; // class TiffArrayEntry + + /*! + @brief Element of a TiffArrayEntry. The value is exactly one component of + a given type and all elements of a TiffArrayEntry have the same + type. Canon and Minolta makernotes use such arrays. + */ + class TiffArrayElement : public TiffEntryBase { + public: + //! @name Creators + //@{ + //! Constructor + TiffArrayElement(uint16_t tag, + uint16_t group, + TypeId elTypeId, + ByteOrder elByteOrder) + : TiffEntryBase(tag, group), + elTypeId_(elTypeId), + elByteOrder_(elByteOrder) {} + //! Virtual destructor. + virtual ~TiffArrayElement() {} + //@} + + //! @name Accessors + //@{ + TypeId elTypeId() const { return elTypeId_; } + ByteOrder elByteOrder() const { return elByteOrder_; } + //@} + + protected: + //! @name Manipulators + //@{ + virtual void doAccept(TiffVisitor& visitor); + virtual void doEncode(TiffEncoder& encoder, const Exifdatum* datum); + //@} + + //! @name Write support (Manipulators) + //@{ + /*! + @brief Implements write(). Write the value using the element specific + byte order, if any. Make sure the value has only one component + and that it is of the correct type, else throw Error(51). + */ + virtual uint32_t doWrite(Blob& blob, + ByteOrder byteOrder, + int32_t offset, + uint32_t valueIdx, + uint32_t dataIdx, + uint32_t imageIdx); + //@} + // Using doWriteData from base class + // Using doWriteImage from base class + // Using doSize from base class + // Using doSizeData from base class + // Using doSizeImage from base class + + private: + // DATA + TypeId elTypeId_; //!< Type of the element + ByteOrder elByteOrder_; //!< Byte order to read/write the element + + }; // class TiffArrayElement + +// ***************************************************************************** +// 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); + + //! Return the group name for a group + const char* tiffGroupName(uint16_t group); + + //! Return the TIFF group id for a group name + uint16_t tiffGroupId(const std::string& groupName); + + //! Function to create and initialize a new TIFF directory + TiffComponent::AutoPtr newTiffDirectory(uint16_t tag, + const TiffStructure* ts); + + //! Function to create and initialize a new TIFF entry + TiffComponent::AutoPtr newTiffEntry(uint16_t tag, + const TiffStructure* ts); + + //! Function to create and initialize a new TIFF sub-directory + TiffComponent::AutoPtr newTiffSubIfd(uint16_t tag, + const TiffStructure* ts); + + //! Function to create and initialize a new TIFF makernote entry + TiffComponent::AutoPtr newTiffMnEntry(uint16_t tag, + const TiffStructure* ts); + + //! Function to create and initialize a new array entry + template + TiffComponent::AutoPtr newTiffArrayEntry(uint16_t tag, + const TiffStructure* ts) + { + assert(ts); + return TiffComponent::AutoPtr( + new TiffArrayEntry(tag, ts->group_, ts->newGroup_, typeId, addSizeElement)); + } + + //! Function to create and initialize a new array element + template + TiffComponent::AutoPtr newTiffArrayElement(uint16_t tag, + const TiffStructure* ts) + { + assert(ts); + return TiffComponent::AutoPtr( + new TiffArrayElement(tag, ts->group_, typeId, byteOrder)); + } + + template + TiffComponent::AutoPtr newTiffArrayElement(uint16_t tag, + const TiffStructure* ts) + { + return newTiffArrayElement(tag, ts); + } + + //! Function to create and initialize a new TIFF entry for a thumbnail (data) + template + TiffComponent::AutoPtr newTiffThumbData(uint16_t tag, + const TiffStructure* ts) + { + assert(ts); + return TiffComponent::AutoPtr( + new TiffDataEntry(tag, ts->group_, szTag, szGroup)); + } + + //! Function to create and initialize a new TIFF entry for a thumbnail (size) + template + TiffComponent::AutoPtr newTiffThumbSize(uint16_t tag, + const TiffStructure* ts) + { + assert(ts); + return TiffComponent::AutoPtr( + new TiffSizeEntry(tag, ts->group_, dtTag, dtGroup)); + } + + //! Function to create and initialize a new TIFF entry for image data + template + TiffComponent::AutoPtr newTiffImageData(uint16_t tag, + const TiffStructure* ts) + { + assert(ts); + return TiffComponent::AutoPtr( + new TiffImageEntry(tag, ts->group_, szTag, szGroup)); + } + + //! Function to create and initialize a new TIFF entry for image data (size) + template + TiffComponent::AutoPtr newTiffImageSize(uint16_t tag, + const TiffStructure* ts) + { + // Todo: Same as newTiffThumbSize - consolidate (rename)? + assert(ts); + return TiffComponent::AutoPtr( + new TiffSizeEntry(tag, ts->group_, dtTag, dtGroup)); + } + +}} // namespace Internal, Exiv2 + +#endif // #ifndef TIFFCOMPOSITE_INT_HPP_ diff --git a/src/tifffwd.hpp b/src/tifffwd_int.hpp similarity index 67% rename from src/tifffwd.hpp rename to src/tifffwd_int.hpp index 753b5daf..58f53b37 100644 --- a/src/tifffwd.hpp +++ b/src/tifffwd_int.hpp @@ -19,15 +19,15 @@ * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! - @file tifffwd.hpp - @brief TIFF parser related typedefs and forward definitions. + @file tifffwd_int.hpp + @brief Internal TIFF parser related typedefs and forward definitions. @version $Rev$ @author Andreas Huggel (ahu) ahuggel@gmx.net @date 24-Jun-06, ahu: created */ -#ifndef TIFFFWD_HPP_ -#define TIFFFWD_HPP_ +#ifndef TIFFFWD_INT_HPP_ +#define TIFFFWD_INT_HPP_ // ***************************************************************************** // included header files @@ -35,14 +35,17 @@ // + standard includes #include +#include // ***************************************************************************** -// namespace extensions +// Exiv2 namespace extensions namespace Exiv2 { -// ***************************************************************************** -// class declarations + class Exifdatum; + + namespace Internal { + class TiffHeaderBase; class TiffComponent; struct TiffStructure; class TiffEntryBase; @@ -59,31 +62,41 @@ namespace Exiv2 { class TiffVisitor; class TiffFinder; - class TiffMetadataDecoder; + class TiffDecoder; + class TiffEncoder; class TiffReader; class TiffPrinter; - class TiffHeaderBase; class TiffRwState; - struct TiffDecoderInfo; - - class Image; - class Value; + struct TiffMappingInfo; // ***************************************************************************** -// class definitions +// type definitions /*! - @brief Function pointer type for a TiffMetadataDecoder member function + @brief Function pointer type for a TiffDecoder member function to decode a TIFF component. */ - typedef void (TiffMetadataDecoder::*DecoderFct)(const TiffEntryBase*); + 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, uint16_t 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, + uint16_t 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 @@ -91,14 +104,17 @@ namespace Exiv2 { */ typedef std::auto_ptr (*NewTiffCompFct)( uint16_t tag, const TiffStructure* ts); + //! Stack to hold a path from the TIFF root element to a TIFF entry + typedef std::stack TiffPath; + /*! @brief Type for a factory function to create new TIFF components. Use TiffComponent::AutoPtr, it is not used in this declaration only to reduce dependencies. */ - typedef std::auto_ptr (*TiffCompFactoryFct)(uint32_t extendedTag, - uint16_t group); + typedef std::auto_ptr (*TiffCompFactoryFct)(uint32_t extendedTag, + uint16_t group); -} // namespace Exiv2 +}} // namespace Internal, Exiv2 -#endif // #ifndef TIFFFWD_HPP_ +#endif // #ifndef TIFFFWD_INT_HPP_ diff --git a/src/tiffimage.cpp b/src/tiffimage.cpp index aa04a2c7..e608bf58 100644 --- a/src/tiffimage.cpp +++ b/src/tiffimage.cpp @@ -38,10 +38,14 @@ EXIV2_RCSID("@(#) $Id$") #endif #include "tiffimage.hpp" -#include "tiffparser.hpp" +#include "tiffimage_int.hpp" +#include "tiffcomposite_int.hpp" +#include "tiffvisitor_int.hpp" +#include "makernote2_int.hpp" #include "image.hpp" #include "error.hpp" #include "futils.hpp" +#include "types.hpp" #include "i18n.h" // NLS support. // + standard includes @@ -49,11 +53,49 @@ EXIV2_RCSID("@(#) $Id$") #include #include #include +#include + +/* -------------------------------------------------------------------------- + + Todo: + + + Support all TIFF data types + + Review boundary checking, is it better to check the offsets? + + Define and implement consistent error handling for recursive hierarchy + + Make TiffImage a template StandardImage, which can be parametrized with + a parser and the necessary checking functions to cover all types of + images which need to be loaded completely. + + TiffComponent: should it have end() and setEnd() or pData and size? + + Can NewTiffCompFct and TiffCompFactoryFct be combined? + + Create function is repeated when actually only the table changes. Fix it. + + Is it easier (for writing) to combine all creation tables into one? + + 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. + + Filtering of large unknown tags: Should be moved to writing/encoding code + and done only if really needed (i.e., if writing to a Jpeg segment) + + Make Tiff parser completely standalone, depending only on very low level + stuff from exiv2 + + in crwimage.* : + + + Fix CiffHeader according to TiffHeade2 + + Combine Error(15) and Error(33), add format argument %1 + + Search crwimage for todos, fix writeMetadata comment + + Add Ciff components to TIFF component hierarchy + + rename all Ciff stuff to Crw for easier reference - not needed when CIFF + components are part of the TIFF hierarchy + + 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, io) { @@ -79,18 +121,6 @@ namespace Exiv2 { return 0; } - void TiffImage::setExifData(const ExifData& /*exifData*/) - { - // Todo: implement me! - throw(Error(32, "Exif metadata", "TIFF")); - } - - void TiffImage::setIptcData(const IptcData& /*iptcData*/) - { - // Todo: implement me! - throw(Error(32, "IPTC metadata", "TIFF")); - } - void TiffImage::setComment(const std::string& /*comment*/) { // not supported @@ -110,16 +140,475 @@ namespace Exiv2 { throw Error(3, "TIFF"); } clearMetadata(); - TiffParser::decode(this, io_->mmap(), io_->size(), - TiffCreator::create, TiffDecoder::findDecoder); + ByteOrder bo = TiffParser::decode(exifData_, + iptcData_, + xmpData_, + io_->mmap(), + io_->size()); + setByteOrder(bo); } // TiffImage::readMetadata void TiffImage::writeMetadata() { - //! Todo: implement me! - throw(Error(31, "TIFF")); +#ifdef DEBUG + std::cerr << "Writing TIFF file " << io_->path() << "\n"; +#endif + // Read existing image + ByteOrder bo = byteOrder(); + DataBuf buf; + if (io_->open() == 0) { + IoCloser closer(*io_); + // Ensure that this is the correct image type + if (isTiffType(*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(); + } + TiffHeade2 tiffHeader; + if (0 == tiffHeader.read(buf.pData_, 8)) { + bo = tiffHeader.byteOrder(); + } + } + } + if (bo == invalidByteOrder) { + bo = littleEndian; + } + setByteOrder(bo); + Blob blob; + WriteMethod wm = TiffParser::encode(blob, + buf.pData_, + buf.size_, + bo, + exifData_, + iptcData_, + xmpData_); + // Write updated or new buffer to file + BasicIo::AutoPtr tempIo(io_->temporary()); // may throw + assert(tempIo.get() != 0); + if (wm == wmNonIntrusive) { + // Buffer may be modified but size is unchanged, write buffer back + tempIo->write(buf.pData_, buf.size_); + } + else { + // Size of the buffer changed, write from blob + tempIo->write(&blob[0], static_cast(blob.size())); + } + io_->close(); + io_->transfer(*tempIo); // 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, + TiffCreator::create, + TiffMapping::findDecoder); + } // TiffParser::decode + + WriteMethod TiffParser::encode( + Blob& blob, + const byte* pData, + uint32_t size, + ByteOrder byteOrder, + const ExifData& exifData, + const IptcData& iptcData, + const XmpData& xmpData + ) + { + std::auto_ptr header(new TiffHeade2(byteOrder)); + return TiffParserWorker::encode(blob, + pData, + size, + exifData, + iptcData, + xmpData, + TiffCreator::create, + TiffMapping::findEncoder, + header.get()); + } // 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; + } + TiffHeade2 tiffHeader; + bool rc = tiffHeader.read(buf, len); + if (!advance || !rc) { + iIo.seek(-len, BasicIo::cur); + } + return rc; + } + +} // namespace Exiv2 + +namespace Exiv2 { + namespace Internal { + + /* + This table describes the standard TIFF layout (including non-standard + Makernote structures) and determines the corresponding Exiv2 TIFF + components. 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 TIFF component. + Each entry of the table defines for a particular tag and group + combination, which create function is used, what the group and parent tag + and group of the new component are. + */ + const TiffStructure TiffCreator::tiffStructure_[] = { + // ext. tag group child group parent tag parent group create function + //--------- ----------------- ----------------- ---------- ----------------- ------------------- + // Root directory + { Tag::root, Group::none, Group::ifd0, Tag::root, Group::none, newTiffDirectory }, + + // IFD0 + { 0x8769, Group::ifd0, Group::exif, Tag::root, Group::none, newTiffSubIfd }, + { 0x8825, Group::ifd0, Group::gps, Tag::root, Group::none, newTiffSubIfd }, + { 0x0111, Group::ifd0, Group::ifd0, Tag::root, Group::none, newTiffImageData<0x0117, Group::ifd0> }, + { 0x0117, Group::ifd0, Group::ifd0, Tag::root, Group::none, newTiffImageSize<0x0111, Group::ifd0> }, + // SubIfd found in NEF images (up to 3 sub directories seen, groups sub0_0, sub0_1, sub0_2) + { 0x014a, Group::ifd0, Group::sub0_0, Tag::root, Group::none, newTiffSubIfd }, + { Tag::next, Group::ifd0, Group::ifd1, Tag::root, Group::none, newTiffDirectory }, + { Tag::all, Group::ifd0, Group::ifd0, Tag::root, Group::none, newTiffEntry }, + + // Subdir sub0_0 + { Tag::next, Group::sub0_0, Group::ignr, 0x014a, Group::ifd0, newTiffDirectory }, + { Tag::all, Group::sub0_0, Group::sub0_0, 0x014a, Group::ifd0, newTiffEntry }, + + // Subdir sub0_1 + { Tag::next, Group::sub0_1, Group::ignr, 0x014a, Group::ifd0, newTiffDirectory }, + { Tag::all, Group::sub0_1, Group::sub0_1, 0x014a, Group::ifd0, newTiffEntry }, + + // Subdir sub0_2 + { Tag::next, Group::sub0_2, Group::ignr, 0x014a, Group::ifd0, newTiffDirectory }, + { Tag::all, Group::sub0_2, Group::sub0_2, 0x014a, Group::ifd0, newTiffEntry }, + + // Exif subdir + { 0xa005, Group::exif, Group::iop, 0x8769, Group::ifd0, newTiffSubIfd }, + { 0x927c, Group::exif, Group::mn, 0x8769, Group::ifd0, newTiffMnEntry }, + { Tag::next, Group::exif, Group::ignr, 0x8769, Group::ifd0, newTiffDirectory }, + { Tag::all, Group::exif, Group::exif, 0x8769, Group::ifd0, newTiffEntry }, + + // GPS subdir + { Tag::next, Group::gps, Group::ignr, 0x8825, Group::ifd0, newTiffDirectory }, + { Tag::all, Group::gps, Group::gps, 0x8825, Group::ifd0, newTiffEntry }, + + // IOP subdir + { Tag::next, Group::iop, Group::ignr, 0xa005, Group::exif, newTiffDirectory }, + { Tag::all, Group::iop, Group::iop, 0xa005, Group::exif, newTiffEntry }, + + // IFD1 + { 0x0111, Group::ifd1, Group::ifd1, Tag::next, Group::ifd0, newTiffThumbData<0x0117, Group::ifd1> }, + { 0x0117, Group::ifd1, Group::ifd1, Tag::next, Group::ifd0, newTiffThumbSize<0x0111, Group::ifd1> }, + { 0x0201, Group::ifd1, Group::ifd1, Tag::next, Group::ifd0, newTiffThumbData<0x0202, Group::ifd1> }, + { 0x0202, Group::ifd1, Group::ifd1, Tag::next, Group::ifd0, newTiffThumbSize<0x0201, Group::ifd1> }, + { Tag::next, Group::ifd1, Group::ignr, Tag::next, Group::ifd0, newTiffDirectory }, + { Tag::all, Group::ifd1, Group::ifd1, Tag::next, Group::ifd0, 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, Group::olympmn, Group::minocso, 0x927c, Group::exif, newTiffArrayEntry }, + { 0x0003, Group::olympmn, Group::minocsn, 0x927c, Group::exif, newTiffArrayEntry }, + { Tag::next, Group::olympmn, Group::ignr, 0x927c, Group::exif, newTiffDirectory }, + { Tag::all, Group::olympmn, Group::olympmn, 0x927c, Group::exif, newTiffEntry }, + + // Fujifilm makernote + { Tag::next, Group::fujimn, Group::ignr, 0x927c, Group::exif, newTiffDirectory }, + { Tag::all, Group::fujimn, Group::fujimn, 0x927c, Group::exif, newTiffEntry }, + + // Canon makernote + { 0x0001, Group::canonmn, Group::canoncs, 0x927c, Group::exif, newTiffArrayEntry }, + { 0x0004, Group::canonmn, Group::canonsi, 0x927c, Group::exif, newTiffArrayEntry }, + { 0x0005, Group::canonmn, Group::canonpa, 0x927c, Group::exif, newTiffArrayEntry }, + { 0x000f, Group::canonmn, Group::canoncf, 0x927c, Group::exif, newTiffArrayEntry }, + { 0x0012, Group::canonmn, Group::canonpi, 0x927c, Group::exif, newTiffArrayEntry }, + { Tag::next, Group::canonmn, Group::ignr, 0x927c, Group::exif, newTiffDirectory }, + { Tag::all, Group::canonmn, Group::canonmn, 0x927c, Group::exif, newTiffEntry }, + + // Canon makernote composite tags + { Tag::all, Group::canoncs, Group::canoncs, 0x0001, Group::canonmn, newTiffArrayElement }, + { Tag::all, Group::canonsi, Group::canonsi, 0x0004, Group::canonmn, newTiffArrayElement }, + { Tag::all, Group::canonpa, Group::canonpa, 0x0005, Group::canonmn, newTiffArrayElement }, + { Tag::all, Group::canoncf, Group::canoncf, 0x000f, Group::canonmn, newTiffArrayElement }, + { Tag::all, Group::canonpi, Group::canonpi, 0x0012, Group::canonmn, newTiffArrayElement }, + + // Nikon1 makernote + { Tag::next, Group::nikon1mn, Group::ignr, 0x927c, Group::exif, newTiffDirectory }, + { Tag::all, Group::nikon1mn, Group::nikon1mn, 0x927c, Group::exif, newTiffEntry }, + + // Nikon2 makernote + { Tag::next, Group::nikon2mn, Group::ignr, 0x927c, Group::exif, newTiffDirectory }, + { Tag::all, Group::nikon2mn, Group::nikon2mn, 0x927c, Group::exif, newTiffEntry }, + + // Nikon3 makernote + { Tag::next, Group::nikon3mn, Group::ignr, 0x927c, Group::exif, newTiffDirectory }, + { Tag::all, Group::nikon3mn, Group::nikon3mn, 0x927c, Group::exif, newTiffEntry }, + + // Panasonic makernote + { Tag::next, Group::panamn, Group::ignr, 0x927c, Group::exif, newTiffDirectory }, + { Tag::all, Group::panamn, Group::panamn, 0x927c, Group::exif, newTiffEntry }, + + // Sigma/Foveon makernote + { Tag::next, Group::sigmamn, Group::ignr, 0x927c, Group::exif, newTiffDirectory }, + { Tag::all, Group::sigmamn, Group::sigmamn, 0x927c, Group::exif, newTiffEntry }, + + // Sony1 makernote + { Tag::next, Group::sony1mn, Group::ignr, 0x927c, Group::exif, newTiffDirectory }, + { Tag::all, Group::sony1mn, Group::sony1mn, 0x927c, Group::exif, newTiffEntry }, + + // Sony2 makernote + { Tag::next, Group::sony2mn, Group::ignr, 0x927c, Group::exif, newTiffDirectory }, + { Tag::all, Group::sony2mn, Group::sony2mn, 0x927c, Group::exif, newTiffEntry }, + + // Minolta makernote + { 0x0001, Group::minoltamn, Group::minocso, 0x927c, Group::exif, newTiffArrayEntry }, + { 0x0003, Group::minoltamn, Group::minocsn, 0x927c, Group::exif, newTiffArrayEntry }, + { 0x0004, Group::minoltamn, Group::minocs7, 0x927c, Group::exif, newTiffArrayEntry }, + { 0x0088, Group::minoltamn, Group::minoltamn, 0x927c, Group::exif, newTiffThumbData<0x0089, Group::minoltamn> }, + { 0x0089, Group::minoltamn, Group::minoltamn, 0x927c, Group::exif, newTiffThumbSize<0x0088, Group::minoltamn> }, + { 0x0114, Group::minoltamn, Group::minocs5, 0x927c, Group::exif, newTiffArrayEntry }, + { Tag::next, Group::minoltamn, Group::ignr, 0x927c, Group::exif, newTiffDirectory }, + { Tag::all, Group::minoltamn, Group::minoltamn, 0x927c, Group::exif, newTiffEntry }, + + // Minolta makernote composite tags + { Tag::all, Group::minocso, Group::minocso, 0x0001, Group::minoltamn, newTiffArrayElement }, + { Tag::all, Group::minocsn, Group::minocsn, 0x0003, Group::minoltamn, newTiffArrayElement }, + { Tag::all, Group::minocs7, Group::minocs7, 0x0004, Group::minoltamn, newTiffArrayElement }, + { Tag::all, Group::minocs5, Group::minocs5, 0x0114, Group::minoltamn, newTiffArrayElement }, + + // Tags which are not de/encoded + { Tag::next, Group::ignr, Group::ignr, Tag::none, Group::none, newTiffDirectory }, + { Tag::all, Group::ignr, Group::ignr, Tag::none, Group::none, newTiffEntry } + }; + + // TIFF mapping table for special decoding and encoding requirements + const TiffMappingInfo TiffMapping::tiffMappingInfo_[] = { + { "*", Tag::all, Group::ignr, 0, 0 }, // Do not decode tags with group == Group::ignr + { "OLYMPUS", 0x0100, Group::olympmn, &TiffDecoder::decodeOlympThumb, &TiffEncoder::encodeOlympThumb }, + { "*", 0x014a, Group::ifd0, 0, 0 }, // Todo: Controversial, causes problems with Exiftool + { "*", Tag::all, Group::sub0_0, &TiffDecoder::decodeSubIfd, 0 /*Todo*/ }, + { "*", Tag::all, Group::sub0_1, &TiffDecoder::decodeSubIfd, 0 /*Todo*/ }, + { "*", 0x02bc, Group::ifd0, &TiffDecoder::decodeXmp, &TiffEncoder::encodeXmp }, + { "*", 0x83bb, Group::ifd0, &TiffDecoder::decodeIptc, &TiffEncoder::encodeIptc }, + { "*", 0x8649, Group::ifd0, &TiffDecoder::decodeIptc, &TiffEncoder::encodeIptc }, + // Minolta makernote entries which need to be encoded in big endian byte order + { "*", Tag::all, Group::minocso, &TiffDecoder::decodeStdTiffEntry, &TiffEncoder::encodeBigEndianEntry }, + { "*", Tag::all, Group::minocso, &TiffDecoder::decodeStdTiffEntry, &TiffEncoder::encodeBigEndianEntry }, + { "*", Tag::all, Group::minocso, &TiffDecoder::decodeStdTiffEntry, &TiffEncoder::encodeBigEndianEntry }, + { "*", Tag::all, Group::minocso, &TiffDecoder::decodeStdTiffEntry, &TiffEncoder::encodeBigEndianEntry } + }; + + DecoderFct TiffMapping::findDecoder(const std::string& make, + uint32_t extendedTag, + uint16_t 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, + uint16_t 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; + } + + TiffComponent::AutoPtr TiffCreator::create(uint32_t extendedTag, + uint16_t group) + { + TiffComponent::AutoPtr tc(0); + uint16_t tag = static_cast(extendedTag & 0xffff); + const TiffStructure* ts = find(tiffStructure_, + TiffStructure::Key(extendedTag, group)); + if (ts && ts->newTiffCompFct_) { + tc = ts->newTiffCompFct_(tag, ts); + } +#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 " << tiffGroupName(group) << "\n"; + } +#endif + return tc; + } // TiffCreator::create + + void TiffCreator::getPath(TiffPath& tiffPath, uint32_t extendedTag, uint16_t group) + { + const TiffStructure* ts = 0; + do { + ts = find(tiffStructure_, TiffStructure::Key(extendedTag, group)); + assert(ts != 0); + tiffPath.push(ts); + extendedTag = ts->parentExtTag_; + group = ts->parentGroup_; + } while (!(ts->extendedTag_ == Tag::root && ts->group_ == Group::none)); + + } // TiffCreator::getPath + + ByteOrder TiffParserWorker::decode( + ExifData& exifData, + IptcData& iptcData, + XmpData& xmpData, + const byte* pData, + uint32_t size, + TiffCompFactoryFct createFct, + FindDecoderFct findDecoderFct, + TiffHeaderBase* pHeader + ) + { + // Create standard TIFF header if necessary + std::auto_ptr ph; + if (!pHeader) { + ph = std::auto_ptr(new TiffHeade2); + pHeader = ph.get(); + } + TiffComponent::AutoPtr rootDir = parse(pData, size, createFct, pHeader); + if (0 != rootDir.get()) { + TiffDecoder decoder(exifData, + iptcData, + xmpData, + rootDir.get(), + findDecoderFct); + rootDir->accept(decoder); + } + return pHeader->byteOrder(); + + } // TiffParserWorker::decode + + WriteMethod TiffParserWorker::encode( + Blob& blob, + const byte* pData, + uint32_t size, + const ExifData& exifData, + const IptcData& iptcData, + const XmpData& xmpData, + TiffCompFactoryFct createFct, + FindEncoderFct findEncoderFct, + TiffHeaderBase* pHeader + ) + { + /* + 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); + blob.clear(); + WriteMethod writeMethod = wmIntrusive; + TiffComponent::AutoPtr createdTree; + TiffComponent::AutoPtr parsedTree = parse(pData, size, createFct, pHeader); + if (0 != parsedTree.get()) { + // Attempt to update existing TIFF components based on metadata entries + TiffEncoder encoder(exifData, + iptcData, + xmpData, + parsedTree.get(), + pHeader->byteOrder(), + findEncoderFct); + parsedTree->accept(encoder); + if (!encoder.dirty()) writeMethod = wmNonIntrusive; + } + if (writeMethod == wmIntrusive) { + createdTree = createFct(Tag::root, Group::none); + TiffEncoder encoder(exifData, + iptcData, + xmpData, + createdTree.get(), + pHeader->byteOrder(), + findEncoderFct); + // Add entries from metadata to composite + encoder.add(createdTree.get(), parsedTree.get(), createFct); + // Write binary representation from the composite tree + uint32_t offset = pHeader->write(blob); + uint32_t len = createdTree->write(blob, pHeader->byteOrder(), offset, uint32_t(-1), uint32_t(-1), uint32_t(-1)); + // Avoid writing just the header if there is no IFD data + if (len == 0) blob.clear(); +#ifdef DEBUG + std::cerr << "Intrusive writing\n"; +#endif + } +#ifdef DEBUG + else { + std::cerr << "Non-intrusive writing\n"; + } +#endif + return writeMethod; + } // TiffParserWorker::encode + + TiffComponent::AutoPtr TiffParserWorker::parse( + const byte* pData, + uint32_t size, + TiffCompFactoryFct createFct, + 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 = createFct(Tag::root, Group::none); + if (0 != rootDir.get()) { + rootDir->setStart(pData + pHeader->offset()); + TiffRwState::AutoPtr state( + new TiffRwState(pHeader->byteOrder(), 0, createFct)); + TiffReader reader(pData, size, rootDir.get(), state); + rootDir->accept(reader); + } + return rootDir; + + } // TiffParserWorker::parse + TiffHeaderBase::TiffHeaderBase(uint16_t tag, uint32_t size, ByteOrder byteOrder, @@ -137,7 +626,7 @@ namespace Exiv2 { bool TiffHeaderBase::read(const byte* pData, uint32_t size) { - if (size < 8) return false; + if (!pData || size < 8) return false; if (pData[0] == 0x49 && pData[1] == 0x49) { byteOrder_ = littleEndian; @@ -154,9 +643,26 @@ namespace Exiv2 { return true; } // TiffHeaderBase::read - void TiffHeaderBase::write(Blob& blob) const + uint32_t TiffHeaderBase::write(Blob& blob) const { - // Todo: Implement me! + byte buf[8]; + switch (byteOrder_) { + case littleEndian: + buf[0] = 0x49; + buf[1] = 0x49; + break; + case bigEndian: + buf[0] = 0x4d; + buf[1] = 0x4d; + break; + case invalidByteOrder: + assert(false); + break; + } + us2Data(buf + 2, tag_, byteOrder_); + ul2Data(buf + 4, 0x00000008, byteOrder_); + append(blob, buf, 8); + return 8; } void TiffHeaderBase::print(std::ostream& os, const std::string& prefix) const @@ -204,8 +710,8 @@ namespace Exiv2 { return tag_; } - TiffHeade2::TiffHeade2() - : TiffHeaderBase(42, 8, littleEndian, 0x00000008) + TiffHeade2::TiffHeade2(ByteOrder byteOrder) + : TiffHeaderBase(42, 8, byteOrder, 0x00000008) { } @@ -213,31 +719,4 @@ namespace Exiv2 { { } - // ************************************************************************* - // 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; - } - TiffHeade2 tiffHeader; - bool rc = tiffHeader.read(buf, len); - if (!advance || !rc) { - iIo.seek(-len, BasicIo::cur); - } - return rc; - } - -} // namespace Exiv2 +}} // namespace Internal, Exiv2 diff --git a/src/tiffimage.hpp b/src/tiffimage.hpp index bc3702f6..1438b4de 100644 --- a/src/tiffimage.hpp +++ b/src/tiffimage.hpp @@ -78,21 +78,7 @@ namespace Exiv2 { //! @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. TIFF format does not contain a comment. Calling this function will throw an Error(32). @@ -119,90 +105,75 @@ namespace Exiv2 { }; // class TiffImage /*! - @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. + @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 TiffHeaderBase { + class TiffParser { public: - //! @name Constructors - //@{ - //! 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. - */ - 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 Write the image header to the binary image \em blob. - This method appends to the blob. - - @param blob Binary image to add to. - - @throw Error If the header cannot be written. - */ - virtual void write(Blob& blob) const; + @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 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; - //@} - - 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 - - /*! - @brief Standard TIFF header structure. - */ - class TiffHeade2 : public TiffHeaderBase { - public: - //! @name Creators - //@{ - //! Default constructor - TiffHeade2(); - //! Destructor - ~TiffHeade2(); - //@} - }; // class TiffHeade2 + @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 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 TIFF 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. + + @note If there is no metadata to encode, i.e., all metadata + containers are empty, then the return value is \c wmIntrusive + and the \em blob is empty, i.e., no TIFF header is written. + + @param blob Container for the binary image if "intrusive" + writing is necessary. Empty otherwise. + @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( + Blob& blob, + const byte* pData, + uint32_t size, + ByteOrder byteOrder, + const ExifData& exifData, + const IptcData& iptcData, + const XmpData& xmpData + ); + + }; // class TiffParser // ***************************************************************************** // template, inline and free functions diff --git a/src/tiffimage_int.hpp b/src/tiffimage_int.hpp new file mode 100644 index 00000000..b05c6b5d --- /dev/null +++ b/src/tiffimage_int.hpp @@ -0,0 +1,287 @@ +// ***************************************************************** -*- C++ -*- +/* + * Copyright (C) 2004-2008 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$ + @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 "image.hpp" +#include "types.hpp" + +// + standard includes + +// ***************************************************************************** +// 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 Write the image header to the binary image \em blob. + This method appends to the blob. + + @param blob Binary image to add to. + @return Number of bytes written. + */ + virtual uint32_t write(Blob& blob) 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; + //@} + + 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 + + /*! + @brief Standard TIFF header structure. + */ + class TiffHeade2 : public TiffHeaderBase { + public: + //! @name Creators + //@{ + //! Default constructor + TiffHeade2(ByteOrder byteOrder =littleEndian); + //! Destructor + ~TiffHeade2(); + //@} + }; // class TiffHeade2 + + /*! + @brief TIFF component factory for standard TIFF components. + */ + class TiffCreator { + public: + /*! + @brief Create the TiffComponent for TIFF entry \em extendedTag and + \em group based on the embedded lookup table. If the pointer + that is returned is 0, then the TIFF entry should be ignored. + */ + static std::auto_ptr create(uint32_t extendedTag, + uint16_t group); + /*! + @brief Get the path, i.e., a list of TiffStructure pointers, from + the root TIFF element to the TIFF entry \em extendedTag and + \em group. + */ + static void getPath(TiffPath& tiffPath, + uint32_t extendedTag, + uint16_t group); + + private: + static const TiffStructure tiffStructure_[]; // + parse(const byte* pData, + uint32_t size, + TiffCompFactoryFct createFct, + TiffHeaderBase* pHeader); + + }; // 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, + uint16_t 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, + uint16_t group + ); + + private: + static const TiffMappingInfo tiffMappingInfo_[]; // +#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"; + } +} diff --git a/samples/tiffparse.cpp b/src/tiffparse.cpp similarity index 100% rename from samples/tiffparse.cpp rename to src/tiffparse.cpp diff --git a/src/tiffparser.cpp b/src/tiffparser.cpp deleted file mode 100644 index 24d3794e..00000000 --- a/src/tiffparser.cpp +++ /dev/null @@ -1,214 +0,0 @@ -// ***************************************************************** -*- C++ -*- -/* - * Copyright (C) 2004-2008 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: tiffparser.cpp - Version: $Rev$ - Author(s): Andreas Huggel (ahu) - History: 15-Mar-06, ahu: created - - */ -// ***************************************************************************** -#include "rcsid.hpp" -EXIV2_RCSID("@(#) $Id$") - -// ***************************************************************************** -// included header files -#ifdef _MSC_VER -# include "exv_msvc.h" -#else -# include "exv_conf.h" -#endif - -#include "types.hpp" -#include "tiffparser.hpp" -#include "tiffcomposite.hpp" -#include "makernote2.hpp" -#include "tiffvisitor.hpp" -#include "tiffimage.hpp" -#include "error.hpp" - -// + standard includes -#include -#include - -/* -------------------------------------------------------------------------- - - Todo: - - + Add further child mgmt stuff to TIFF composite: remove - + Review boundary checking, is it better to check the offsets? - + Define and implement consistent error handling for recursive hierarchy - + Make TiffImage a template StandardImage, which can be parametrized with - a parser and the necessary checking functions to cover all types of - images which need to be loaded completely. - + TiffComponent: should it have end() and setEnd() or pData and size? - + Can NewTiffCompFct and TiffCompFactoryFct be combined? - + Create function is repeated when actually only the table changes. Fix it. - + Is it easier (for writing) to combine all creation tables into one? - + 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. - + Filtering of large unknown tags: Should be moved to writing/encoding code - and done only if really needed (i.e., if writing to a Jpeg segment) - - in crwimage.* : - - + Fix CiffHeader according to TiffHeade2 - + Combine Error(15) and Error(33), add format argument %1 - + Search crwimage for todos, fix writeMetadata comment - + rename all Ciff stuff to Crw for easier reference - - -------------------------------------------------------------------------- */ - - -// ***************************************************************************** -// class member definitions -namespace Exiv2 { - - /* - This table describes the standard TIFF layout (including non-standard - Makernote structures) and determines the corresponding Exiv2 TIFF - components. 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 TIFF component. - Each entry of the table defines for a particular tag and group - combination, which create function is used and what the group of the new - component is. - */ - const TiffStructure TiffCreator::tiffStructure_[] = { - // ext. tag group create function new group - //--------- -------------- ------------------- -------------- - { Tag::root, Group::none, newTiffDirectory, Group::ifd0 }, - { 0x8769, Group::ifd0, newTiffSubIfd, Group::exif }, - { 0x8825, Group::ifd0, newTiffSubIfd, Group::gps }, - { 0xa005, Group::exif, newTiffSubIfd, Group::iop }, - { 0x927c, Group::exif, newTiffMnEntry, Group::mn }, - { 0x0111, Group::ifd1, newTiffThumbData<0x0117, Group::ifd1>, Group::ifd1 }, - { 0x0117, Group::ifd1, newTiffThumbSize<0x0111, Group::ifd1>, Group::ifd1 }, - { 0x0201, Group::ifd1, newTiffThumbData<0x0202, Group::ifd1>, Group::ifd1 }, - { 0x0202, Group::ifd1, newTiffThumbSize<0x0201, Group::ifd1>, Group::ifd1 }, - { Tag::next, Group::ifd0, newTiffDirectory, Group::ifd1 }, - { Tag::next, Group::ifd1, newTiffDirectory, Group::ignr }, - { Tag::next, Group::ignr, newTiffDirectory, Group::ignr }, - // SubIfd found in NEF images - { 0x014a, Group::ifd0, newTiffSubIfd, Group::sub0_0 }, - // Canon makernote structure - { 0x0001, Group::canonmn, newTiffArrayEntry<2>, Group::canoncs }, - { 0x0004, Group::canonmn, newTiffArrayEntry<2>, Group::canonsi }, - { 0x0005, Group::canonmn, newTiffArrayEntry<2>, Group::canonpa }, - { 0x000f, Group::canonmn, newTiffArrayEntry<2>, Group::canoncf }, - { 0x0012, Group::canonmn, newTiffArrayEntry<2>, Group::canonpi }, - { Tag::all, Group::canoncs, newTiffArrayElement, Group::canoncs }, - { Tag::all, Group::canonsi, newTiffArrayElement, Group::canonsi }, - { Tag::all, Group::canonpa, newTiffArrayElement, Group::canonpa }, - { Tag::all, Group::canoncf, newTiffArrayElement, Group::canoncf }, - { Tag::all, Group::canonpi, newTiffArrayElement, Group::canonpi }, - // Some Olympus cameras use Minolta structures - { 0x0001, Group::olympmn, newTiffArrayEntry<4>, Group::minocso }, - { 0x0003, Group::olympmn, newTiffArrayEntry<4>, Group::minocsn }, - // Minolta makernote structure - { 0x0001, Group::minoltamn, newTiffArrayEntry<4>, Group::minocso }, - { 0x0003, Group::minoltamn, newTiffArrayEntry<4>, Group::minocsn }, - { 0x0004, Group::minoltamn, newTiffArrayEntry<2>, Group::minocs7 }, - { 0x0114, Group::minoltamn, newTiffArrayEntry<2>, Group::minocs5 }, - { Tag::all, Group::minocso, newTiffArrayElement, Group::minocso }, - { Tag::all, Group::minocsn, newTiffArrayElement, Group::minocsn }, - { Tag::all, Group::minocs7, newTiffArrayElement, Group::minocs7 }, - { Tag::all, Group::minocs5, newTiffArrayElement, Group::minocs5 } - }; - - // TIFF Decoder table for special decoding requirements, default decoder is decodeStdTiffEntry - const TiffDecoderInfo TiffDecoder::tiffDecoderInfo_[] = { - { "*", Tag::all, Group::ignr, 0 }, // Do not decode tags with group == Group::ignr - { "OLYMPUS", 0x0100, Group::olympmn, &TiffMetadataDecoder::decodeOlympThumb }, - { "*", 0x014a, Group::ifd0, 0 }, // Todo: Controversial, causes problems with Exiftool - { "*", Tag::all, Group::sub0_0, &TiffMetadataDecoder::decodeSubIfd }, - { "*", Tag::all, Group::sub0_1, &TiffMetadataDecoder::decodeSubIfd }, - { "*", 0x02bc, Group::ifd0, &TiffMetadataDecoder::decodeXmp }, - { "*", 0x83bb, Group::ifd0, &TiffMetadataDecoder::decodeIptc }, - { "*", 0x8649, Group::ifd0, &TiffMetadataDecoder::decodeIptc } - }; - - DecoderFct TiffDecoder::findDecoder(const std::string& make, - uint32_t extendedTag, - uint16_t group) - { - DecoderFct decoderFct = &TiffMetadataDecoder::decodeStdTiffEntry; - const TiffDecoderInfo* td = find(tiffDecoderInfo_, - TiffDecoderInfo::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; - } - - TiffComponent::AutoPtr TiffCreator::create(uint32_t extendedTag, - uint16_t group) - { - TiffComponent::AutoPtr tc(0); - uint16_t tag = static_cast(extendedTag & 0xffff); - const TiffStructure* ts = find(tiffStructure_, - TiffStructure::Key(extendedTag, group)); - if (ts && ts->newTiffCompFct_) { - tc = ts->newTiffCompFct_(tag, ts); - } - if (!ts && extendedTag != Tag::next) { - tc = TiffComponent::AutoPtr(new TiffEntry(tag, group)); - } - return tc; - } // TiffCreator::create - - void TiffParser::decode(Image* pImage, - const byte* pData, - uint32_t size, - TiffCompFactoryFct createFct, - FindDecoderFct findDecoderFct, - TiffHeaderBase* pHeader) - { - assert(pImage != 0); - assert(pData != 0); - - std::auto_ptr ph; - if (!pHeader) { - ph = std::auto_ptr(new TiffHeade2); - pHeader = ph.get(); - } - - if (!pHeader->read(pData, size) || pHeader->offset() >= size) { - throw Error(3, "TIFF"); - } - TiffComponent::AutoPtr rootDir = createFct(Tag::root, Group::none); - if (0 == rootDir.get()) return; - rootDir->setStart(pData + pHeader->offset()); - - TiffRwState::AutoPtr state( - new TiffRwState(pHeader->byteOrder(), 0, createFct)); - TiffReader reader(pData, size, rootDir.get(), state); - rootDir->accept(reader); - - TiffMetadataDecoder decoder(pImage, rootDir.get(), findDecoderFct, 4096); - rootDir->accept(decoder); - - } // TiffParser::decode - -} // namespace Exiv2 diff --git a/src/tiffparser.hpp b/src/tiffparser.hpp deleted file mode 100644 index 4d90bdb6..00000000 --- a/src/tiffparser.hpp +++ /dev/null @@ -1,132 +0,0 @@ -// ***************************************************************** -*- C++ -*- -/* - * Copyright (C) 2004-2008 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 tiffparser.hpp - @brief Class TiffParser to parse TIFF data. - @version $Rev$ - @author Andreas Huggel (ahu) - ahuggel@gmx.net - @date 15-Mar-06, ahu: created - */ -#ifndef TIFFPARSER_HPP_ -#define TIFFPARSER_HPP_ - -// ***************************************************************************** -// included header files -#include "tifffwd.hpp" -#include "types.hpp" - -// + standard includes -#include -#include - -// ***************************************************************************** -// namespace extensions -namespace Exiv2 { - -// ***************************************************************************** -// class definitions - - /*! - @brief TIFF component factory for standard TIFF components. - */ - class TiffCreator { - public: - /*! - @brief Create the TiffComponent for TIFF entry \em extendedTag and - \em group based on the embedded lookup table. - - If a tag and group combination is not found in the table, a TiffEntry - is created. If the pointer that is returned is 0, then the TIFF entry - should be ignored. - */ - static std::auto_ptr create(uint32_t extendedTag, - uint16_t group); - - private: - static const TiffStructure tiffStructure_[]; //= 0 && event < events_); + go_[event] = go; + } + + bool TiffVisitor::go(GoEvent event) const + { + assert(event >= 0 && event < events_); + return go_[event]; + } void TiffFinder::init(uint16_t tag, uint16_t group) { @@ -68,7 +88,7 @@ namespace Exiv2 { { if (object->tag() == tag_ && object->group() == group_) { tiffComponent_ = object; - setGo(false); + setGo(geTraverse, false); } } @@ -82,6 +102,11 @@ namespace Exiv2 { findObject(object); } + void TiffFinder::visitImageEntry(TiffImageEntry* object) + { + findObject(object); + } + void TiffFinder::visitSizeEntry(TiffSizeEntry* object) { findObject(object); @@ -117,16 +142,26 @@ namespace Exiv2 { findObject(object); } - TiffMetadataDecoder::TiffMetadataDecoder(Image* pImage, - TiffComponent* const pRoot, - FindDecoderFct findDecoderFct, - uint32_t threshold) - : pImage_(pImage), + TiffDecoder::TiffDecoder( + ExifData& exifData, + IptcData& iptcData, + XmpData& xmpData, + TiffComponent* const pRoot, + FindDecoderFct findDecoderFct + ) + : exifData_(exifData), + iptcData_(iptcData), + xmpData_(xmpData), pRoot_(pRoot), findDecoderFct_(findDecoderFct), - threshold_(threshold), decodedIptc_(false) { + assert(pRoot != 0); + + exifData_.clear(); + iptcData_.clear(); + xmpData_.clear(); + // Find camera make TiffFinder finder(0x010f, Group::ifd0); pRoot_->accept(finder); @@ -136,61 +171,65 @@ namespace Exiv2 { } } - void TiffMetadataDecoder::visitEntry(TiffEntry* object) + void TiffDecoder::visitEntry(TiffEntry* object) { decodeTiffEntry(object); } - void TiffMetadataDecoder::visitDataEntry(TiffDataEntry* object) + void TiffDecoder::visitDataEntry(TiffDataEntry* object) { decodeTiffEntry(object); } - void TiffMetadataDecoder::visitSizeEntry(TiffSizeEntry* object) + void TiffDecoder::visitImageEntry(TiffImageEntry* object) { decodeTiffEntry(object); } - void TiffMetadataDecoder::visitDirectory(TiffDirectory* /*object*/) + void TiffDecoder::visitSizeEntry(TiffSizeEntry* object) + { + decodeTiffEntry(object); + } + + void TiffDecoder::visitDirectory(TiffDirectory* /*object*/) { // Nothing to do } - void TiffMetadataDecoder::visitSubIfd(TiffSubIfd* object) + void TiffDecoder::visitSubIfd(TiffSubIfd* object) { decodeTiffEntry(object); } - void TiffMetadataDecoder::visitMnEntry(TiffMnEntry* object) + void TiffDecoder::visitMnEntry(TiffMnEntry* object) { if (!object->mn_) decodeTiffEntry(object); } - void TiffMetadataDecoder::visitIfdMakernote(TiffIfdMakernote* /*object*/) + void TiffDecoder::visitIfdMakernote(TiffIfdMakernote* /*object*/) { // Nothing to do } - void TiffMetadataDecoder::decodeOlympThumb(const TiffEntryBase* object) + void TiffDecoder::decodeOlympThumb(const TiffEntryBase* object) { const DataValue* v = dynamic_cast(object->pValue()); if (v != 0) { - ExifData& exifData = pImage_->exifData(); - exifData["Exif.Thumbnail.Compression"] = uint16_t(6); + exifData_["Exif.Thumbnail.Compression"] = uint16_t(6); DataBuf buf(v->size()); v->copy(buf.pData_); - Exifdatum& ed = exifData["Exif.Thumbnail.JPEGInterchangeFormat"]; + Exifdatum& ed = exifData_["Exif.Thumbnail.JPEGInterchangeFormat"]; ed = uint32_t(0); ed.setDataArea(buf.pData_, buf.size_); - exifData["Exif.Thumbnail.JPEGInterchangeFormatLength"] = uint32_t(buf.size_); + exifData_["Exif.Thumbnail.JPEGInterchangeFormatLength"] = uint32_t(buf.size_); } } - void TiffMetadataDecoder::getObjData(byte const*& pData, - long& size, - uint16_t tag, - uint16_t group, - const TiffEntryBase* object) + void TiffDecoder::getObjData(byte const*& pData, + long& size, + uint16_t tag, + uint16_t group, + const TiffEntryBase* object) { if (object && object->tag() == tag && object->group() == group) { pData = object->pData(); @@ -207,7 +246,7 @@ namespace Exiv2 { } } - void TiffMetadataDecoder::decodeXmp(const TiffEntryBase* object) + void TiffDecoder::decodeXmp(const TiffEntryBase* object) { // add Exif tag anyway decodeStdTiffEntry(object); @@ -216,7 +255,7 @@ namespace Exiv2 { long size = 0; getObjData(pData, size, 0x02bc, Group::ifd0, object); if (pData) { - std::string& xmpPacket = pImage_->xmpPacket(); + 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) { @@ -226,15 +265,15 @@ namespace Exiv2 { #endif xmpPacket = xmpPacket.substr(idx); } - if (XmpParser::decode(pImage_->xmpData(), xmpPacket)) { + if (XmpParser::decode(xmpData_, xmpPacket)) { #ifndef SUPPRESS_WARNINGS std::cerr << "Warning: Failed to decode XMP metadata.\n"; #endif } } - } // TiffMetadataDecoder::decodeXmp + } // TiffDecoder::decodeXmp - void TiffMetadataDecoder::decodeIptc(const TiffEntryBase* object) + void TiffDecoder::decodeIptc(const TiffEntryBase* object) { // add Exif tag anyway decodeStdTiffEntry(object); @@ -250,7 +289,7 @@ namespace Exiv2 { long size = 0; getObjData(pData, size, 0x83bb, Group::ifd0, object); if (pData) { - if (0 == pImage_->iptcData().load(pData, size)) { + if (0 == IptcParser::decode(iptcData_, pData, size)) { return; } #ifndef SUPPRESS_WARNINGS @@ -274,7 +313,7 @@ namespace Exiv2 { &record, &sizeHdr, &sizeData)) { return; } - if (0 == pImage_->iptcData().load(record + sizeHdr, sizeData)) { + if (0 == IptcParser::decode(iptcData_, record + sizeHdr, sizeData)) { return; } #ifndef SUPPRESS_WARNINGS @@ -286,7 +325,7 @@ namespace Exiv2 { } } // TiffMetadataDecoder::decodeIptc - void TiffMetadataDecoder::decodeSubIfd(const TiffEntryBase* object) + void TiffDecoder::decodeSubIfd(const TiffEntryBase* object) { assert(object); @@ -305,7 +344,7 @@ namespace Exiv2 { } - void TiffMetadataDecoder::decodeTiffEntry(const TiffEntryBase* object) + void TiffDecoder::decodeTiffEntry(const TiffEntryBase* object) { assert(object != 0); @@ -321,53 +360,484 @@ namespace Exiv2 { if (decoderFct) { EXV_CALL_MEMBER_FN(*this, decoderFct)(object); } - } // TiffMetadataDecoder::decodeTiffEntry + } // TiffDecoder::decodeTiffEntry - void TiffMetadataDecoder::decodeStdTiffEntry(const TiffEntryBase* object) + void TiffDecoder::decodeStdTiffEntry(const TiffEntryBase* object) { assert(object !=0); - assert(pImage_ != 0); // "Normal" tag has low priority: only decode if it doesn't exist yet. + // Todo: This also filters duplicates (common in some makernotes) // Todo: ExifKey should have an appropriate c'tor, it should not be // necessary to use groupName here - ExifKey key(object->tag(), object->groupName()); - // Todo: Too much searching here, optimize when threshold goes. - if (pImage_->exifData().findKey(key) == pImage_->exifData().end()) { - setExifTag(key, object->pValue()); + ExifKey key(object->tag(), tiffGroupName(object->group())); + ExifData::iterator pos = exifData_.findKey(key); + if (pos == exifData_.end()) { + exifData_.add(key, object->pValue()); } - } // TiffMetadataDecoder::decodeTiffEntry + } // TiffDecoder::decodeTiffEntry - void TiffMetadataDecoder::setExifTag(const ExifKey& key, const Value* pValue) + void TiffDecoder::setExifTag(const ExifKey& key, const Value* pValue) { - if ( threshold_ > 0 - && pValue != 0 - && static_cast(pValue->size()) > threshold_ - && key.tagName().substr(0, 2) == "0x") { -#ifndef SUPPRESS_WARNINGS - std::cerr << "Warning: " - << "Size " << pValue->size() << " of " << key.key() - << " exceeds " << threshold_ - << " bytes limit. Not decoded.\n"; + ExifData::iterator pos = exifData_.findKey(key); + if (pos != exifData_.end()) exifData_.erase(pos); + exifData_.add(key, pValue); + + } // TiffDecoder::setExifTag + + void TiffDecoder::visitArrayEntry(TiffArrayEntry* /*object*/) + { + // Nothing to do + } + + void TiffDecoder::visitArrayElement(TiffArrayElement* object) + { + decodeTiffEntry(object); + } + + TiffEncoder::TiffEncoder( + const ExifData& exifData, + const IptcData& iptcData, + const XmpData& xmpData, + TiffComponent* pRoot, + ByteOrder byteOrder, + FindEncoderFct findEncoderFct + ) + : exifData_(exifData), + iptcData_(iptcData), + xmpData_(xmpData), + del_(true), + pRoot_(pRoot), + pSourceTree_(0), + byteOrder_(byteOrder), + origByteOrder_(byteOrder), + findEncoderFct_(findEncoderFct), + dirty_(false), + writeMethod_(wmNonIntrusive) + { + assert(pRoot != 0); + + // 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, Group::ifd0); + pRoot_->accept(finder); + TiffEntryBase* te = dynamic_cast(finder.result()); + if (te && te->pValue()) { + make_ = te->pValue()->toString(); + } + } + } + + 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->typeId(), 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 - return; + 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); + } + + void TiffEncoder::visitIfdMakernote(TiffIfdMakernote* object) + { + assert(object != 0); + + // Modify encoder for Makernote peculiarities, byte order + if (object->byteOrder() != invalidByteOrder) { + byteOrder_ = object->byteOrder(); } - assert(pImage_ != 0); - ExifData::iterator pos = pImage_->exifData().findKey(key); - if (pos != pImage_->exifData().end()) pImage_->exifData().erase(pos); - pImage_->exifData().add(key, pValue); + } // TiffEncoder::visitIfdMakernote - } // TiffMetadataDecoder::addExifTag + void TiffEncoder::visitIfdMakernoteEnd(TiffIfdMakernote* /*object*/) + { + // Reset byte order back to that from the c'tor + byteOrder_ = origByteOrder_; + + } // TiffEncoder::visitIfdMakernoteEnd - void TiffMetadataDecoder::visitArrayEntry(TiffArrayEntry* /*object*/) + void TiffEncoder::visitArrayEntry(TiffArrayEntry* /*object*/) { // Nothing to do } - void TiffMetadataDecoder::visitArrayElement(TiffArrayElement* object) + void TiffEncoder::visitArrayElement(TiffArrayElement* object) { - decodeTiffEntry(object); + encodeTiffComponent(object); } + void TiffEncoder::encodeTiffComponent( + TiffEntryBase* object, + const Exifdatum* datum + ) + { + assert(object != 0); + + ExifData::iterator pos = exifData_.end(); + const Exifdatum* ed = datum; + if (ed == 0) { + ExifKey key(object->tag(), tiffGroupName(object->group())); + pos = exifData_.findKey(key); + if (pos == exifData_.end()) { // metadatum not found (deleted) +#ifdef DEBUG + std::cerr << "DELETING " << key << "\n"; +#endif + setDirty(); + } + else { + ed = &(*pos); + } + } + 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::encodeArrayElement(TiffArrayElement* object, const Exifdatum* datum) + { + encodeTiffEntryBase(object, datum); + } // TiffEncoder::encodeArrayElement + + void TiffEncoder::encodeArrayEntry(TiffArrayEntry* object, const Exifdatum* datum) + { + encodeOffsetEntry(object, datum); + } // TiffEncoder::encodeArrayEntry + + 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(), tiffGroupName(object->group())); + std::cerr << "DATAAREA GREW " << key << "\n"; +#endif + setDirty(); + } + else { + // Write the new dataarea, fill with 0x0 +#ifdef DEBUG + ExifKey key(object->tag(), tiffGroupName(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(), tiffGroupName(object->szGroup())); + ExifData::const_iterator pos = exifData_.findKey(key); + const byte* zero = 0; + if (pos == exifData_.end()) { +#ifndef SUPPRESS_WARNINGS + std::cerr << "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(), tiffGroupName(object->group())); + std::cerr << "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(), tiffGroupName(object->group())); + std::cerr << "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(), tiffGroupName(object->group())); + std::cerr << "UPDATING DATA " << key; + if (tooLarge) { + std::cerr << "\t\t\t ALLOCATED " << 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(), tiffGroupName(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(), tiffGroupName(object->group())); + std::cerr << "NOT UPDATING " << key; + std::cerr << "\t\t\t PRESERVE VALUE DATA"; +#endif + } + + } // TiffEncoder::encodeOffsetEntry + + void TiffEncoder::encodeOlympThumb(TiffEntryBase* object, const Exifdatum* datum) + { + // Todo + } + + void TiffEncoder::encodeIptc(TiffEntryBase* object, const Exifdatum* datum) + { + // Todo + } + + void TiffEncoder::encodeXmp(TiffEntryBase* object, const Exifdatum* datum) + { + // Todo + } + + void TiffEncoder::encodeBigEndianEntry(TiffEntryBase* object, const Exifdatum* datum) + { + byteOrder_ = bigEndian; + encodeTiffEntryBase(object, datum); + byteOrder_ = origByteOrder_; + } + + void TiffEncoder::add( + TiffComponent* pRootDir, + TiffComponent* pSourceDir, + TiffCompFactoryFct createFct + ) + { + 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; + + for (ExifData::const_iterator i = exifData_.begin(); + i != exifData_.end(); ++i) { + + // Assumption is that the corresponding TIFF entry doesn't exist + + // Todo: This takes tag and group straight from the Exif datum. + // There is a need for a simple mapping and a provision for quite + // sophisticated logic to determine the mapped tag and group to + // handle complex cases (eg, NEF sub-IFDs) + + // Todo: getPath depends on the Creator class, not the createFct + // how to get it through to here??? + + TiffPath tiffPath; + TiffCreator::getPath(tiffPath, i->tag(), tiffGroupId(i->groupName())); + TiffComponent* tc = pRootDir->addPath(i->tag(), tiffPath); + TiffEntryBase* object = dynamic_cast(tc); +#ifdef DEBUG + if (object == 0) { + std::cerr << "Warning: addPath() didn't add an entry for " + << tiffGroupId(i->groupName()) + << " tag 0x" << std::setw(4) << std::setfill('0') + << i->tag() << "\n"; + } +#endif + if (object != 0) { + encodeTiffComponent(object, &(*i)); + } + } + } // TiffEncoder::add + const std::string TiffPrinter::indent_(" "); void TiffPrinter::incIndent() @@ -395,7 +865,12 @@ namespace Exiv2 { << object->pValue()->sizeDataArea() << " " << _("bytes.\n"); } - } // TiffPrinter::visitEntry + } // TiffPrinter::visitDataEntry + + void TiffPrinter::visitImageEntry(TiffImageEntry* object) + { + printTiffEntry(object, prefix()); + } // TiffPrinter::visitImageEntry void TiffPrinter::visitSizeEntry(TiffSizeEntry* object) { @@ -405,10 +880,10 @@ namespace Exiv2 { void TiffPrinter::visitDirectory(TiffDirectory* object) { assert(object != 0); - - os_ << prefix() << object->groupName() << " " << _("directory with") << " " - // cast to make MSVC happy - << std::dec << static_cast(object->components_.size()); + os_ << prefix() << tiffGroupName(object->group()) + << " " << _("directory with") << " " + // cast to make MSVC happy + << std::dec << static_cast(object->components_.size()); if (object->components_.size() == 1) os_ << " " << _("entry:\n"); else os_ << " " << _("entries:\n"); incIndent(); @@ -451,7 +926,7 @@ namespace Exiv2 { { assert(object != 0); - os_ << px << object->groupName() + os_ << px << tiffGroupName(object->group()) << " " << _("tag") << " 0x" << std::setw(4) << std::setfill('0') << std::hex << std::right << object->tag() << ", " << _("type") << " " << TypeInfo::typeName(object->typeId()) @@ -469,15 +944,13 @@ namespace Exiv2 { void TiffPrinter::visitArrayEntry(TiffArrayEntry* object) { - // Array entry degenerates to a normal entry if type is not unsignedShort - if (object->typeId() != unsignedShort) { - printTiffEntry(object, prefix()); - } - else { - os_ << prefix() << _("Array Entry") << " " << object->groupName() - << " " << _("tag") << " 0x" << std::setw(4) << std::setfill('0') - << std::hex << std::right << object->tag() << "\n"; - } + os_ << prefix() << _("Array Entry") << " " << tiffGroupName(object->group()) + << " " << _("tag") << " 0x" << std::setw(4) << std::setfill('0') + << std::hex << std::right << object->tag() << " " << _("with") + << " " << std::dec << object->count() << " "; + if (object->count() > 1) os_ << _("elements"); + else os_ << _("element"); + os_ << "\n"; } // TiffPrinter::visitArrayEntry void TiffPrinter::visitArrayElement(TiffArrayElement* object) @@ -544,12 +1017,7 @@ namespace Exiv2 { return pState_->createFct_(extendedTag, group); } - void TiffReader::visitEntry(TiffEntry* object) - { - readTiffEntry(object); - } - - void TiffReader::visitDataEntry(TiffDataEntry* object) + void TiffReader::readDataEntryBase(TiffDataEntryBase* object) { assert(object != 0); @@ -558,10 +1026,25 @@ namespace Exiv2 { pRoot_->accept(finder); TiffEntryBase* te = dynamic_cast(finder.result()); if (te && te->pValue()) { - setDataArea(object, 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); @@ -569,52 +1052,12 @@ namespace Exiv2 { readTiffEntry(object); TiffFinder finder(object->dtTag(), object->dtGroup()); pRoot_->accept(finder); - TiffEntryBase* te = dynamic_cast(finder.result()); + TiffDataEntryBase* te = dynamic_cast(finder.result()); if (te && te->pValue()) { - setDataArea(te, object->pValue()); + te->setStrips(object->pValue(), pData_, size_, baseOffset()); } } - void TiffReader::setDataArea(TiffEntryBase* pOffsetEntry, const Value* pSize) - { - assert(pOffsetEntry); - assert(pSize); - - Value* pOffset = pOffsetEntry->pValue_; - assert(pOffset); - - long size = 0; - for (long i = 0; i < pSize->count(); ++i) { - size += pSize->toLong(i); - } - long offset = pOffset->toLong(0); - // Todo: Remove limitation of Jpeg writer: strips must be contiguous - // Until then we check: last offset + last size - first offset == size? - if ( pOffset->toLong(pOffset->count()-1) - + pSize->toLong(pSize->count()-1) - - offset != size) { -#ifndef SUPPRESS_WARNINGS - std::cerr << "Warning: " - << "Directory " << pOffsetEntry->groupName() - << ", entry 0x" << std::setw(4) - << std::setfill('0') << std::hex << pOffsetEntry->tag() - << " Data area is not contiguous, ignoring it.\n"; -#endif - return; - } - if (baseOffset() + offset + size > size_) { -#ifndef SUPPRESS_WARNINGS - std::cerr << "Warning: " - << "Directory " << pOffsetEntry->groupName() - << ", entry 0x" << std::setw(4) - << std::setfill('0') << std::hex << pOffsetEntry->tag() - << " Data area exceeds data buffer, ignoring it.\n"; -#endif - return; - } - pOffset->setDataArea(pData_ + baseOffset() + offset, size); - } - void TiffReader::visitDirectory(TiffDirectory* object) { assert(object != 0); @@ -625,7 +1068,7 @@ namespace Exiv2 { if (p + 2 > pLast_) { #ifndef SUPPRESS_WARNINGS std::cerr << "Error: " - << "Directory " << object->groupName() + << "Directory " << tiffGroupName(object->group()) << ": IFD exceeds data buffer, cannot read entry count.\n"; #endif return; @@ -636,7 +1079,7 @@ namespace Exiv2 { if (n > 256) { #ifndef SUPPRESS_WARNINGS std::cerr << "Error: " - << "Directory " << object->groupName() << " with " + << "Directory " << tiffGroupName(object->group()) << " with " << n << " entries considered invalid; not read.\n"; #endif return; @@ -645,7 +1088,7 @@ namespace Exiv2 { if (p + 12 > pLast_) { #ifndef SUPPRESS_WARNINGS std::cerr << "Error: " - << "Directory " << object->groupName() + << "Directory " << tiffGroupName(object->group()) << ": IFD entry " << i << " lies outside of the data buffer.\n"; #endif @@ -659,15 +1102,15 @@ namespace Exiv2 { p += 12; } - if (p + 4 > pLast_) { + if (object->hasNext()) { + if (p + 4 > pLast_) { #ifndef SUPPRESS_WARNINGS std::cerr << "Error: " - << "Directory " << object->groupName() + << "Directory " << tiffGroupName(object->group()) << ": IFD exceeds data buffer, cannot read next pointer.\n"; #endif return; - } - if (object->hasNext()) { + } TiffComponent::AutoPtr tc(0); uint32_t next = getLong(p, byteOrder()); if (next) { @@ -675,7 +1118,7 @@ namespace Exiv2 { #ifndef SUPPRESS_WARNINGS if (tc.get() == 0) { std::cerr << "Warning: " - << "Directory " << object->groupName() + << "Directory " << tiffGroupName(object->group()) << " has an unhandled next pointer.\n"; } #endif @@ -684,8 +1127,8 @@ namespace Exiv2 { if (baseOffset() + next > size_) { #ifndef SUPPRESS_WARNINGS std::cerr << "Error: " - << "Directory " << object->groupName() - << ": Next pointer is out of bounds.\n"; + << "Directory " << tiffGroupName(object->group()) + << ": Next pointer is out of bounds; ignored.\n"; #endif return; } @@ -701,13 +1144,15 @@ namespace Exiv2 { assert(object != 0); readTiffEntry(object); - if (object->typeId() == unsignedLong && object->count() >= 1) { + if ((object->typeId() == unsignedLong || object->typeId() == signedLong) + && object->count() >= 1) { for (uint32_t i = 0; i < object->count(); ++i) { - uint32_t offset = getULong(object->pData() + 4*i, byteOrder()); - if (baseOffset() + offset > size_) { + int32_t offset = getLong(object->pData() + 4*i, byteOrder()); + if ( baseOffset() + offset > size_ + || static_cast(baseOffset()) + offset < 0) { #ifndef SUPPRESS_WARNINGS std::cerr << "Error: " - << "Directory " << object->groupName() + << "Directory " << tiffGroupName(object->group()) << ", entry 0x" << std::setw(4) << std::setfill('0') << std::hex << object->tag() << " Sub-IFD pointer " << i @@ -725,10 +1170,10 @@ namespace Exiv2 { #ifndef SUPPRESS_WARNINGS else { std::cerr << "Warning: " - << "Directory " << object->groupName() + << "Directory " << tiffGroupName(object->group()) << ", entry 0x" << std::setw(4) << std::setfill('0') << std::hex << object->tag() - << " doesn't look like a sub-IFD."; + << " doesn't look like a sub-IFD.\n"; } #endif @@ -750,8 +1195,8 @@ namespace Exiv2 { object->mn_ = TiffMnCreator::create(object->tag(), object->mnGroup_, make, - object->pData(), - object->size(), + object->pData_, + object->size_, byteOrder()); } if (object->mn_) object->mn_->setStart(object->pData()); @@ -767,7 +1212,7 @@ namespace Exiv2 { byteOrder())) { #ifndef SUPPRESS_WARNINGS std::cerr << "Error: Failed to read " - << object->ifd_.groupName() + << tiffGroupName(object->ifd_.group()) << " IFD Makernote header.\n"; #ifdef DEBUG if (static_cast(pLast_ - object->start()) >= 16) { @@ -775,7 +1220,7 @@ namespace Exiv2 { } #endif // DEBUG #endif // SUPPRESS_WARNINGS - setGo(false); + setGo(geKnownMakernote, false); return; } // Modify reader for Makernote peculiarities, byte order and offset @@ -798,12 +1243,12 @@ namespace Exiv2 { { assert(object != 0); - const byte* p = object->start(); + byte* p = object->start(); assert(p >= pData_); if (p + 12 > pLast_) { #ifndef SUPPRESS_WARNINGS - std::cerr << "Error: Entry in directory " << object->groupName() + std::cerr << "Error: Entry in directory " << tiffGroupName(object->group()) << "requests access to memory beyond the data buffer. " << "Skipping entry.\n"; #endif @@ -811,76 +1256,86 @@ namespace Exiv2 { } // Component already has tag p += 2; - object->type_ = getUShort(p, byteOrder()); - long typeSize = TypeInfo::typeSize(object->typeId()); + uint16_t type = getUShort(p, byteOrder()); + long typeSize = TypeInfo::typeSize(TypeId(type)); if (0 == typeSize) { #ifndef SUPPRESS_WARNINGS - std::cerr << "Error: Directory " << object->groupName() + std::cerr << "Error: Directory " << tiffGroupName(object->group()) << ", entry 0x" << std::setw(4) << std::setfill('0') << std::hex << object->tag() << " has an invalid type:\n" - << "Type = " << std::dec << object->type_ + << "Type = " << std::dec << type << "; skipping entry.\n"; #endif return; } p += 2; - object->count_ = getULong(p, byteOrder()); + uint32_t count = getULong(p, byteOrder()); + if (count >= 0x10000000) { +#ifndef SUPPRESS_WARNINGS + std::cerr << "Error: Directory " << tiffGroupName(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; - object->size_ = typeSize * object->count(); - object->offset_ = getULong(p, byteOrder()); - object->pData_ = p; - if (object->size() > 4) { - if (baseOffset() + object->offset() >= size_) { + uint32_t size = typeSize * count; + uint32_t offset = getLong(p, byteOrder()); + byte* pData = p; + if (size > 4) { + if (baseOffset() + offset >= size_) { #ifndef SUPPRESS_WARNINGS std::cerr << "Error: Offset of " - << "directory " << object->groupName() + << "directory " << tiffGroupName(object->group()) << ", entry 0x" << std::setw(4) << std::setfill('0') << std::hex << object->tag() << " is out of bounds:\n" << "Offset = 0x" << std::setw(8) - << std::setfill('0') << std::hex << object->offset() + << std::setfill('0') << std::hex << offset << "; truncating the entry\n"; #endif - object->size_ = 0; - object->count_ = 0; - object->offset_ = 0; return; } - object->pData_ = pData_ + baseOffset() + object->offset(); - if (object->size() > static_cast(pLast_ - object->pData())) { + pData = const_cast(pData_) + baseOffset() + offset; + if (size > static_cast(pLast_ - pData)) { #ifndef SUPPRESS_WARNINGS std::cerr << "Warning: Upper boundary of data for " - << "directory " << object->groupName() + << "directory " << tiffGroupName(object->group()) << ", entry 0x" << std::setw(4) << std::setfill('0') << std::hex << object->tag() << " is out of bounds:\n" << "Offset = 0x" << std::setw(8) - << std::setfill('0') << std::hex << object->offset() - << ", size = " << std::dec << object->size() + << std::setfill('0') << std::hex << offset + << ", size = " << std::dec << size << ", exceeds buffer size by " // cast to make MSVC happy - << static_cast(object->pData() + object->size() - pLast_) + << static_cast(pData + size - pLast_) << " Bytes; adjusting the size\n"; #endif - object->size_ = static_cast(pLast_ - object->pData() + 1); - // todo: adjust count_, make size_ a multiple of typeSize + size = static_cast(pLast_ - pData + 1); + // Todo: adjust count, make size a multiple of typeSize } } // On the fly type conversion for Exif.Photo.UserComment // Todo: This should be somewhere else, maybe in a Value factory - // which takes a Key and Type - TypeId t = TypeId(object->typeId()); - if ( object->tag() == 0x9286 - && object->group() == Group::exif - && object->typeId() == undefined) { + // which takes a Key and Type + TypeId t = TypeId(type); + if ( object->tag() == 0x9286 + && object->group() == Group::exif + && t == undefined) { t = comment; } Value::AutoPtr v = Value::create(t); - if (v.get()) { - v->read(object->pData(), object->size(), byteOrder()); - object->pValue_ = v.release(); - } + assert(v.get()); + v->read(pData, size, byteOrder()); + + object->setValue(v); + object->setData(pData, size); + object->setOffset(offset); } // TiffReader::readTiffEntry @@ -889,7 +1344,8 @@ namespace Exiv2 { assert(object != 0); readTiffEntry(object); - uint16_t s = static_cast(object->size() / object->elSize()); + // Todo: size here is that of the data area + uint16_t s = static_cast(object->size_ / object->elSize()); for (uint16_t i = 0; i < s; ++i) { uint16_t tag = i; TiffComponent::AutoPtr tc = create(tag, object->elGroup()); @@ -904,31 +1360,32 @@ namespace Exiv2 { { assert(object != 0); - const byte* p = object->start(); - assert(p >= pData_); + uint16_t type = object->elTypeId(); + uint32_t size = TypeInfo::typeSize(TypeId(type)); + byte* pData = object->start(); + assert(pData >= pData_); - if (p + 2 > pLast_) { + if (pData + size > pLast_) { #ifndef SUPPRESS_WARNINGS - std::cerr << "Error: Array element in group " << object->groupName() + std::cerr << "Error: Array element in group " + << tiffGroupName(object->group()) << "requests access to memory beyond the data buffer. " << "Skipping element.\n"; #endif return; } - object->type_ = object->elTypeId(); - object->count_ = 1; - object->size_ = TypeInfo::typeSize(object->typeId()) * object->count(); - object->offset_ = 0; - object->pData_ = p; - Value::AutoPtr v = Value::create(object->typeId()); - if (v.get()) { - ByteOrder b = - object->elByteOrder() == invalidByteOrder ? - byteOrder() : object->elByteOrder(); - v->read(object->pData(), object->size(), b); - object->pValue_ = v.release(); - } + + ByteOrder bo = object->elByteOrder(); + if (bo == invalidByteOrder) bo = byteOrder(); + Value::AutoPtr v = Value::create(TypeId(type)); + assert(v.get()); + v->read(pData, size, bo); + + object->setValue(v); + object->setData(pData, size); + object->setOffset(0); + object->setCount(1); } // TiffReader::visitArrayElement -} // namespace Exiv2 +}} // namespace Internal, Exiv2 diff --git a/src/tiffvisitor.hpp b/src/tiffvisitor_int.hpp similarity index 59% rename from src/tiffvisitor.hpp rename to src/tiffvisitor_int.hpp index 72880483..72fd6aa6 100644 --- a/src/tiffvisitor.hpp +++ b/src/tiffvisitor_int.hpp @@ -19,20 +19,21 @@ * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! - @file tiffvisitor.hpp - @brief Operations on a TIFF composite tree, implemented as visitor classes. + @file tiffvisitor_int.hpp + @brief Internal operations on a TIFF composite tree, implemented as visitor + classes. @version $Rev$ @author Andreas Huggel (ahu) ahuggel@gmx.net @date 11-Apr-06, ahu: created */ -#ifndef TIFFVISITOR_HPP_ -#define TIFFVISITOR_HPP_ +#ifndef TIFFVISITOR_INT_HPP_ +#define TIFFVISITOR_INT_HPP_ // ***************************************************************************** // included header files #include "exif.hpp" -#include "tifffwd.hpp" +#include "tifffwd_int.hpp" #include "types.hpp" // + standard includes @@ -45,6 +46,7 @@ // ***************************************************************************** // namespace extensions namespace Exiv2 { + namespace Internal { // ***************************************************************************** // class definitions @@ -65,11 +67,25 @@ namespace Exiv2 { @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 - TiffVisitor() : go_(true) {} + //! Default constructor. Initialises all stop/go flags to true. + TiffVisitor(); //! Virtual destructor virtual ~TiffVisitor() {} //@} @@ -79,19 +95,21 @@ namespace Exiv2 { /*! @brief Set the stop/go flag: true for go, false for stop. - This mechanism can be used by concrete visitors to signal certain - events. For example, TiffFinder sets the stop flag as soon as it finds - the correct component to signal to that the search should be - stopped. TiffReader uses it to signal problems reading a makernote. - As the flag doesn't carry any information on the type of event which - triggered it, it is for each visitor to establish and adhere to - conventions about its meaning. + 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(bool go) { go_ = go; } + 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 @@ -122,13 +140,10 @@ namespace Exiv2 { //! @name Accessors //@{ - //! Check if stop flag is clear, return true if it's clear. - bool go() { return go_; } + //! Check if stop flag for \em event is clear, return true if it's clear. + bool go(GoEvent event) const; //@} - private: - bool go_; //!< Set this to false to abort the iteration - }; // class TiffVisitor /*! @@ -141,7 +156,7 @@ namespace Exiv2 { public: //! @name Creators //@{ - //! Constructor, taking the image to add the metadata to + //! Constructor, taking \em tag and \em group of the component to find. TiffFinder(uint16_t tag, uint16_t group) : tag_(tag), group_(group), tiffComponent_(0) {} //! Virtual destructor @@ -154,6 +169,8 @@ namespace Exiv2 { 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 @@ -196,23 +213,24 @@ namespace Exiv2 { pattern). Used by TiffParser to decode the metadata from a TIFF composite. */ - class TiffMetadataDecoder : public TiffVisitor { + class TiffDecoder : public TiffVisitor { public: //! @name Creators //@{ /*! - @brief Constructor, taking the image to add the metadata to, the root - element of the composite to decode and an optional - threshold. Unknown tags with values larger (in bytes) than the - threshold will be ignored. Default is not to ignore any - tags (0). + @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. */ - TiffMetadataDecoder(Image* pImage, - TiffComponent* const pRoot, - FindDecoderFct findDecoderFct =0, - uint32_t threshold =0); + TiffDecoder( + ExifData& exifData, + IptcData& iptcData, + XmpData& xmpData, + TiffComponent* const pRoot, + FindDecoderFct findDecoderFct + ); //! Virtual destructor - virtual ~TiffMetadataDecoder() {} + virtual ~TiffDecoder() {} //@} //! @name Manipulators @@ -221,6 +239,8 @@ namespace Exiv2 { 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 @@ -251,6 +271,8 @@ namespace Exiv2 { //@} private: + //! @name Manipulators + //@{ //! Set an Exif tag in the image. Overwrites existing tags void setExifTag(const ExifKey& key, const Value* pValue); /*! @@ -266,12 +288,15 @@ namespace Exiv2 { uint16_t tag, uint16_t group, const TiffEntryBase* object); + //@} + private: // DATA - Image* pImage_; //!< Pointer to the image to which the metadata is added + 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 - const uint32_t threshold_; //!< Threshold, see constructor documentation. std::string make_; //!< Camera make, determined from the tags to decode //! Type used to remember tag 0x00fe (NewSubfileType) for each group @@ -279,7 +304,193 @@ namespace Exiv2 { GroupType groupType_; //!< NewSubfileType for each group bool decodedIptc_; //!< Indicates if IPTC has been decoded yet - }; // class TiffMetadataDecoder + }; // 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, + ByteOrder byteOrder, + 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 an array entry component + virtual void visitArrayEntry(TiffArrayEntry* object); + //! Encode an array element + virtual void visitArrayElement(TiffArrayElement* 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 array element. + void encodeArrayElement(TiffArrayElement* object, const Exifdatum* datum); + //! Callback encoder function for an array entry. + void encodeArrayEntry(TiffArrayEntry* 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 an Olympus Thumbnail from the TIFF makernote into IFD1. + void encodeOlympThumb(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); + //! Special encoder function to encode an XMP packet to an XMLPacket tag. + void encodeXmp(TiffEntryBase* object, const Exifdatum* datum); + //! Special encoder function for a standard TIFF entry using big endian byte order. + void encodeBigEndianEntry(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, + TiffCompFactoryFct createFct + ); + //! 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 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; + //@} + + private: + // DATA + ExifData exifData_; //!< Copy of the Exif data to encode + IptcData iptcData_; //!< Copy of the IPTC data to encode + XmpData xmpData_; //!< Copy of the XMP data to encode + bool del_; //!< Indicates if Exif data entries should be deleted after encoding + TiffComponent* pRoot_; //!< Root element of the composite + 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 @@ -355,7 +566,7 @@ namespace Exiv2 { @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, byteorder and + @param state State object for creation function, byte order and base offset. */ TiffReader(const byte* pData, @@ -373,6 +584,8 @@ namespace Exiv2 { 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 @@ -392,6 +605,8 @@ namespace Exiv2 { //! 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. @@ -409,13 +624,6 @@ namespace Exiv2 { uint16_t group) const; //@} - private: - //! @name Manipulators - //@{ - //! Helper function to set the thumbnail data area - void setDataArea(TiffEntryBase* pOffsetEntry, const Value* pSize); - //@} - private: // DATA const byte* pData_; //!< Pointer to the memory buffer @@ -448,6 +656,8 @@ namespace Exiv2 { virtual void visitEntry(TiffEntry* object); //! Print a TIFF data entry. virtual void visitDataEntry(TiffDataEntry* object); + //! Print a TIFF image entry. + virtual void visitImageEntry(TiffImageEntry* object); //! Print a TIFF size entry. virtual void visitSizeEntry(TiffSizeEntry* object); //! Print a TIFF directory @@ -490,6 +700,6 @@ namespace Exiv2 { static const std::string indent_; //!< Indent for one level }; // class TiffPrinter -} // namespace Exiv2 +}} // namespace Internal, Exiv2 -#endif // #ifndef TIFFVISITOR_HPP_ +#endif // #ifndef TIFFVISITOR_INT_HPP_ diff --git a/src/types.hpp b/src/types.hpp index 0731fa88..55f3c78f 100644 --- a/src/types.hpp +++ b/src/types.hpp @@ -43,6 +43,7 @@ // + standard includes #include +#include #include #include #include @@ -89,6 +90,9 @@ namespace Exiv2 { //! 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 }; @@ -123,6 +127,9 @@ namespace Exiv2 { valueData, directoryData, lastDataLocId }; + //! Container for binary data + typedef std::vector Blob; + // ***************************************************************************** // class definitions diff --git a/src/value.cpp b/src/value.cpp index 9e40c3a5..6c9e4bb8 100644 --- a/src/value.cpp +++ b/src/value.cpp @@ -244,6 +244,7 @@ namespace Exiv2 { long StringValueBase::copy(byte* buf, ByteOrder /*byteOrder*/) const { + if (value_.size() == 0) return 0; // byteOrder not needed assert(buf != 0); return static_cast( @@ -463,7 +464,7 @@ namespace Exiv2 { std::ostringstream os; write(os); std::string s = os.str(); - std::memcpy(buf, &s[0], s.size()); + std::memcpy(buf, &s[0], s.size()); return static_cast(s.size()); } @@ -725,7 +726,7 @@ namespace Exiv2 { float LangAltValue::toFloat(long /*n*/) const { ok_ = false; - return 0.0; + return 0.0f; } Rational LangAltValue::toRational(long /*n*/) const diff --git a/src/value.hpp b/src/value.hpp index 82b5ddda..122b3749 100644 --- a/src/value.hpp +++ b/src/value.hpp @@ -1552,6 +1552,7 @@ namespace Exiv2 { 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 @@ -1559,6 +1560,7 @@ namespace Exiv2 { 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 @@ -1573,6 +1575,7 @@ namespace Exiv2 { 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 @@ -1580,6 +1583,7 @@ namespace Exiv2 { 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 diff --git a/src/xmpdump.cpp b/src/xmpdump.cpp new file mode 100644 index 00000000..727bb8c9 --- /dev/null +++ b/src/xmpdump.cpp @@ -0,0 +1,35 @@ +// ***************************************************************** -*- C++ -*- +// xmpdump.cpp, $Rev$ +// 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; +} diff --git a/test/Makefile b/test/Makefile index 26fadf75..47e5746b 100644 --- a/test/Makefile +++ b/test/Makefile @@ -57,10 +57,22 @@ SHELL = /bin/sh .PHONY: all test clean distclean maintainer-clean # Add test drivers to this list -TESTS = addmoddel.sh bugfixes-test.sh crw-test.sh exifdata-test.sh \ - exiv2-test.sh ifd-test.sh imagetest.sh iotest.sh iptctest.sh \ - makernote-test.sh modify-test.sh path-test.sh stringto-test.sh \ - write-test.sh write2-test.sh xmpparser-test.sh conversions.sh +TESTS = addmoddel.sh \ + bugfixes-test.sh \ + crw-test.sh \ + exifdata-test.sh \ + exiv2-test.sh \ + imagetest.sh \ + iotest.sh \ + iptctest.sh \ + modify-test.sh \ + path-test.sh \ + stringto-test.sh \ + tiff-test.sh \ + write-test.sh \ + write2-test.sh \ + xmpparser-test.sh \ + conversions.sh test: @list='$(TESTS)'; for p in $$list; do \ diff --git a/test/data/addmoddel.out b/test/data/addmoddel.out index 61963fb2..4934f1a7 100644 --- a/test/data/addmoddel.out +++ b/test/data/addmoddel.out @@ -8,5 +8,5 @@ Deleted key "Exif.Image.PrimaryChromaticities" 0x0115 Image SamplesPerPixel Short 1 162 0x011a Image XResolution SLong 1 -2 0x011b Image YResolution SRational 1 -2/3 -0x8769 Image ExifTag Long 1 89 +0x8769 Image ExifTag Long 1 90 0x9003 Photo DateTimeOriginal Ascii 20 2000:12:31 23:59:59 diff --git a/test/data/conversions.out b/test/data/conversions.out index c2fa3c24..223b0a44 100644 --- a/test/data/conversions.out +++ b/test/data/conversions.out @@ -96,12 +96,12 @@ Iptc.Application2.LocationName String 12 Kuala Lumpur Testcase 14 =========== Exif.Image.ExifTag Long 1 38 -Exif.Image.GPSTag Long 1 134 Exif.Photo.ExifVersion Undefined 4 48 50 50 49 Exif.Photo.DateTimeOriginal Ascii 20 2003:12:14 12:01:44 Exif.Photo.ComponentsConfiguration Undefined 4 1 2 3 0 Exif.Photo.Flash Short 1 73 Exif.Photo.SubSecTimeOriginal Ascii 10 999999999 +Exif.Image.GPSTag Long 1 134 Exif.GPSInfo.GPSVersionID Byte 4 2 2 0 1 Exif.GPSInfo.GPSLatitudeRef Ascii 2 N Exif.GPSInfo.GPSLatitude Rational 3 3/1 8/1 29734512/1000000 @@ -150,12 +150,12 @@ Xmp.tiff.DateTime XmpText 20 2003-12-14T12:01:44Z Xmp.photoshop.DateCreated XmpText 10 2007-05-09 Exif.Image.DateTime Ascii 20 2003:12:14 20:01:44 Exif.Image.ExifTag Long 1 70 -Exif.Image.GPSTag Long 1 166 Exif.Photo.ExifVersion Undefined 4 48 50 50 49 Exif.Photo.DateTimeOriginal Ascii 20 2003:12:14 12:01:44 Exif.Photo.ComponentsConfiguration Undefined 4 1 2 3 0 Exif.Photo.Flash Short 1 73 Exif.Photo.SubSecTimeOriginal Ascii 10 999999999 +Exif.Image.GPSTag Long 1 166 Exif.GPSInfo.GPSVersionID Byte 4 2 2 0 1 Exif.GPSInfo.GPSLatitudeRef Ascii 2 N Exif.GPSInfo.GPSLatitude Rational 3 3/1 8/1 1858407/62500 diff --git a/test/data/exifdata-test.out b/test/data/exifdata-test.out index 0b98607c..ac699855 100644 --- a/test/data/exifdata-test.out +++ b/test/data/exifdata-test.out @@ -7,7 +7,7 @@ Exif.Image.XResolution 0x011a IFD0 Rational 1 Exif.Image.YResolution 0x011b IFD0 Rational 1 72/1 Exif.Image.ResolutionUnit 0x0128 IFD0 Short 1 2 Exif.Image.Software 0x0131 IFD0 Ascii 22 DC-4300 Ver1.03 -Exif.Image.DateTime 0x0132 IFD0 Ascii 20 Sunday, 11am +Exif.Image.DateTime 0x0132 IFD0 Ascii 13 Sunday, 11am Exif.Image.YCbCrPositioning 0x0213 IFD0 Short 1 2 Exif.Image.ExifTag 0x8769 IFD0 Long 1 6480 Exif.Photo.ExposureTime 0x829a Exif Rational 1 1/95 @@ -15,7 +15,7 @@ Exif.Photo.FNumber 0x829d Exif Rational 1 Exif.Photo.ExposureProgram 0x8822 Exif Short 1 8 Exif.Photo.ISOSpeedRatings 0x8827 Exif Short 1 100 Exif.Photo.ExifVersion 0x9000 Exif Undefined 4 48 50 49 48 -Exif.Photo.DateTimeOriginal 0x9003 Exif Ascii 20 Sunday, 11am +Exif.Photo.DateTimeOriginal 0x9003 Exif Ascii 13 Sunday, 11am Exif.Photo.DateTimeDigitized 0x9004 Exif Ascii 20 2004:06:08 16:04:50 Exif.Photo.ComponentsConfiguration 0x9101 Exif Undefined 4 1 2 3 0 Exif.Photo.ShutterSpeedValue 0x9201 Exif SRational 1 66/10 @@ -30,14 +30,14 @@ Exif.Photo.ColorSpace 0xa001 Exif Short 1 Exif.Photo.PixelXDimension 0xa002 Exif Long 1 1600 Exif.Photo.PixelYDimension 0xa003 Exif Long 1 2400 Exif.Photo.InteroperabilityTag 0xa005 Exif Long 1 6738 -Exif.Photo.FileSource 0xa300 Exif Undefined 1 3 Exif.Iop.InteroperabilityIndex 0x0001 Iop Ascii 4 123 Exif.Iop.InteroperabilityVersion 0x0002 Iop Undefined 4 48 49 48 48 +Exif.Photo.FileSource 0xa300 Exif Undefined 1 3 Exif.Thumbnail.ImageWidth 0x0100 IFD1 Long 1 133 Exif.Thumbnail.ImageLength 0x0101 IFD1 Long 1 200 Exif.Thumbnail.Compression 0x0103 IFD1 Short 1 6 Exif.Thumbnail.Orientation 0x0112 IFD1 Short 1 1 -Exif.Thumbnail.JPEGInterchangeFormat 0x0201 IFD1 Long 1 0 +Exif.Thumbnail.JPEGInterchangeFormat 0x0201 IFD1 Long 1 196 Exif.Thumbnail.JPEGInterchangeFormatLength 0x0202 IFD1 Long 1 6144 ---------------------------------------------- Copy construction, intrusive changes @@ -51,7 +51,7 @@ Exif.Image.ResolutionUnit 0x0128 IFD0 Short 1 Exif.Image.Software 0x0131 IFD0 Ascii 22 DC-4300 Ver1.03 Exif.Image.DateTime 0x0132 IFD0 Ascii 29 Sunday, 11am and ten minutes Exif.Image.YCbCrPositioning 0x0213 IFD0 Short 1 2 -Exif.Image.ExifTag 0x8769 IFD0 Long 1 263 +Exif.Image.ExifTag 0x8769 IFD0 Long 1 264 Exif.Photo.ExposureTime 0x829a Exif Rational 1 1/95 Exif.Photo.FNumber 0x829d Exif Rational 1 91/10 Exif.Photo.ExposureProgram 0x8822 Exif Short 1 8 @@ -71,15 +71,15 @@ Exif.Photo.FlashpixVersion 0xa000 Exif Undefined 4 Exif.Photo.ColorSpace 0xa001 Exif Short 1 1 Exif.Photo.PixelXDimension 0xa002 Exif Long 1 1600 Exif.Photo.PixelYDimension 0xa003 Exif Long 1 2400 -Exif.Photo.InteroperabilityTag 0xa005 Exif Long 1 630 -Exif.Photo.FileSource 0xa300 Exif Undefined 1 3 +Exif.Photo.InteroperabilityTag 0xa005 Exif Long 1 632 Exif.Iop.InteroperabilityIndex 0x0001 Iop Ascii 5 1234 Exif.Iop.InteroperabilityVersion 0x0002 Iop Undefined 4 48 49 48 48 +Exif.Photo.FileSource 0xa300 Exif Undefined 1 3 Exif.Thumbnail.ImageWidth 0x0100 IFD1 Long 1 133 Exif.Thumbnail.ImageLength 0x0101 IFD1 Long 1 200 Exif.Thumbnail.Compression 0x0103 IFD1 Short 1 6 Exif.Thumbnail.Orientation 0x0112 IFD1 Short 5 2 3 4 5 6 -Exif.Thumbnail.JPEGInterchangeFormat 0x0201 IFD1 Long 1 0 +Exif.Thumbnail.JPEGInterchangeFormat 0x0201 IFD1 Long 1 756 Exif.Thumbnail.JPEGInterchangeFormatLength 0x0202 IFD1 Long 1 6144 ---------------------------------------------- Assignment, non-intrusive changes @@ -91,15 +91,15 @@ Exif.Image.XResolution 0x011a IFD0 Rational 1 Exif.Image.YResolution 0x011b IFD0 Rational 1 72/1 Exif.Image.ResolutionUnit 0x0128 IFD0 Short 1 2 Exif.Image.Software 0x0131 IFD0 Ascii 22 DC-4300 Ver1.03 -Exif.Image.DateTime 0x0132 IFD0 Ascii 20 Sunday, 11am +Exif.Image.DateTime 0x0132 IFD0 Ascii 13 Sunday, 11am Exif.Image.YCbCrPositioning 0x0213 IFD0 Short 1 2 -Exif.Image.ExifTag 0x8769 IFD0 Long 1 6480 +Exif.Image.ExifTag 0x8769 IFD0 Long 1 264 Exif.Photo.ExposureTime 0x829a Exif Rational 1 1/95 Exif.Photo.FNumber 0x829d Exif Rational 1 91/10 Exif.Photo.ExposureProgram 0x8822 Exif Short 1 8 Exif.Photo.ISOSpeedRatings 0x8827 Exif Short 1 100 Exif.Photo.ExifVersion 0x9000 Exif Undefined 4 48 50 49 48 -Exif.Photo.DateTimeOriginal 0x9003 Exif Ascii 20 Sunday, 11am +Exif.Photo.DateTimeOriginal 0x9003 Exif Ascii 13 Sunday, 11am Exif.Photo.DateTimeDigitized 0x9004 Exif Ascii 20 2004:06:08 16:04:50 Exif.Photo.ComponentsConfiguration 0x9101 Exif Undefined 4 1 2 3 0 Exif.Photo.ShutterSpeedValue 0x9201 Exif SRational 1 66/10 @@ -113,15 +113,15 @@ Exif.Photo.FlashpixVersion 0xa000 Exif Undefined 4 Exif.Photo.ColorSpace 0xa001 Exif Short 1 1 Exif.Photo.PixelXDimension 0xa002 Exif Long 1 1600 Exif.Photo.PixelYDimension 0xa003 Exif Long 1 2400 -Exif.Photo.InteroperabilityTag 0xa005 Exif Long 1 6738 -Exif.Photo.FileSource 0xa300 Exif Undefined 1 3 +Exif.Photo.InteroperabilityTag 0xa005 Exif Long 1 632 Exif.Iop.InteroperabilityIndex 0x0001 Iop Ascii 4 123 Exif.Iop.InteroperabilityVersion 0x0002 Iop Undefined 4 48 49 48 48 +Exif.Photo.FileSource 0xa300 Exif Undefined 1 3 Exif.Thumbnail.ImageWidth 0x0100 IFD1 Long 1 133 Exif.Thumbnail.ImageLength 0x0101 IFD1 Long 1 200 Exif.Thumbnail.Compression 0x0103 IFD1 Short 1 6 -Exif.Thumbnail.Orientation 0x0112 IFD1 Short 1 1 -Exif.Thumbnail.JPEGInterchangeFormat 0x0201 IFD1 Long 1 0 +Exif.Thumbnail.Orientation 0x0112 IFD1 Short 1 2 +Exif.Thumbnail.JPEGInterchangeFormat 0x0201 IFD1 Long 1 756 Exif.Thumbnail.JPEGInterchangeFormatLength 0x0202 IFD1 Long 1 6144 ---------------------------------------------- Assignment, intrusive changes @@ -135,7 +135,7 @@ Exif.Image.ResolutionUnit 0x0128 IFD0 Short 1 Exif.Image.Software 0x0131 IFD0 Ascii 22 DC-4300 Ver1.03 Exif.Image.DateTime 0x0132 IFD0 Ascii 29 Sunday, 11am and ten minutes Exif.Image.YCbCrPositioning 0x0213 IFD0 Short 1 2 -Exif.Image.ExifTag 0x8769 IFD0 Long 1 263 +Exif.Image.ExifTag 0x8769 IFD0 Long 1 264 Exif.Photo.ExposureTime 0x829a Exif Rational 1 1/95 Exif.Photo.FNumber 0x829d Exif Rational 1 91/10 Exif.Photo.ExposureProgram 0x8822 Exif Short 1 8 @@ -155,15 +155,15 @@ Exif.Photo.FlashpixVersion 0xa000 Exif Undefined 4 Exif.Photo.ColorSpace 0xa001 Exif Short 1 1 Exif.Photo.PixelXDimension 0xa002 Exif Long 1 1600 Exif.Photo.PixelYDimension 0xa003 Exif Long 1 2400 -Exif.Photo.InteroperabilityTag 0xa005 Exif Long 1 618 -Exif.Photo.FileSource 0xa300 Exif Undefined 1 3 +Exif.Photo.InteroperabilityTag 0xa005 Exif Long 1 620 Exif.Iop.InteroperabilityIndex 0x0001 Iop Ascii 4 123 Exif.Iop.InteroperabilityVersion 0x0002 Iop Undefined 4 48 49 48 48 +Exif.Photo.FileSource 0xa300 Exif Undefined 1 3 Exif.Thumbnail.ImageWidth 0x0100 IFD1 Long 1 133 Exif.Thumbnail.ImageLength 0x0101 IFD1 Long 1 200 Exif.Thumbnail.Compression 0x0103 IFD1 Short 1 6 Exif.Thumbnail.Orientation 0x0112 IFD1 Short 1 2 -Exif.Thumbnail.JPEGInterchangeFormat 0x0201 IFD1 Long 1 0 +Exif.Thumbnail.JPEGInterchangeFormat 0x0201 IFD1 Long 1 728 Exif.Thumbnail.JPEGInterchangeFormatLength 0x0202 IFD1 Long 1 6144 Copy construction, non-intrusive changes Exif.Image.Make 0x010f IFD0 Ascii 6 Canon @@ -172,13 +172,13 @@ Exif.Image.Orientation 0x0112 IFD0 Short 1 Exif.Image.XResolution 0x011a IFD0 Rational 1 180/1 Exif.Image.YResolution 0x011b IFD0 Rational 1 180/1 Exif.Image.ResolutionUnit 0x0128 IFD0 Short 1 2 -Exif.Image.DateTime 0x0132 IFD0 Ascii 20 Sunday, 11am +Exif.Image.DateTime 0x0132 IFD0 Ascii 13 Sunday, 11am Exif.Image.YCbCrPositioning 0x0213 IFD0 Short 1 1 -Exif.Image.ExifTag 0x8769 IFD0 Long 1 196 +Exif.Image.ExifTag 0x8769 IFD0 Long 1 178 Exif.Photo.ExposureTime 0x829a Exif Rational 1 1/500 Exif.Photo.FNumber 0x829d Exif Rational 1 49/10 Exif.Photo.ExifVersion 0x9000 Exif Undefined 4 48 50 50 48 -Exif.Photo.DateTimeOriginal 0x9003 Exif Ascii 20 Sunday, 11am +Exif.Photo.DateTimeOriginal 0x9003 Exif Ascii 13 Sunday, 11am Exif.Photo.DateTimeDigitized 0x9004 Exif Ascii 20 2003:12:14 12:01:44 Exif.Photo.ComponentsConfiguration 0x9101 Exif Undefined 4 1 2 3 0 Exif.Photo.CompressedBitsPerPixel 0x9102 Exif Rational 1 5/1 @@ -189,32 +189,8 @@ Exif.Photo.MaxApertureValue 0x9205 Exif Rational 1 Exif.Photo.MeteringMode 0x9207 Exif Short 1 1 Exif.Photo.Flash 0x9209 Exif Short 1 24 Exif.Photo.FocalLength 0x920a Exif Rational 1 682/32 -Exif.Photo.UserComment 0x9286 Exif Undefined 264 -Exif.Photo.FlashpixVersion 0xa000 Exif Undefined 4 48 49 48 48 -Exif.Photo.ColorSpace 0xa001 Exif Short 1 1 -Exif.Photo.PixelXDimension 0xa002 Exif Short 1 2272 -Exif.Photo.PixelYDimension 0xa003 Exif Short 1 1704 -Exif.Photo.InteroperabilityTag 0xa005 Exif Long 1 1416 -Exif.Photo.FocalPlaneXResolution 0xa20e Exif Rational 1 2272000/280 -Exif.Photo.FocalPlaneYResolution 0xa20f Exif Rational 1 1704000/210 -Exif.Photo.FocalPlaneResolutionUnit 0xa210 Exif Short 1 2 -Exif.Photo.SensingMethod 0xa217 Exif Short 1 2 -Exif.Photo.FileSource 0xa300 Exif Undefined 1 3 -Exif.Photo.CustomRendered 0xa401 Exif Short 1 0 -Exif.Photo.ExposureMode 0xa402 Exif Short 1 0 -Exif.Photo.WhiteBalance 0xa403 Exif Short 1 0 -Exif.Photo.DigitalZoomRatio 0xa404 Exif Rational 1 2272/2272 -Exif.Photo.SceneCaptureType 0xa406 Exif Short 1 0 -Exif.Canon.0x0002 0x0002 Makernote Short 4 2 682 286 215 -Exif.Canon.0x0003 0x0003 Makernote Short 4 0 0 0 0 Exif.Canon.0x0000 0x0000 Makernote Short 6 0 0 0 0 0 0 Exif.Canon.0x0000 0x0000 Makernote Short 4 0 0 0 0 -Exif.Canon.ImageType 0x0006 Makernote Ascii 32 IMG:PowerShot S40 JPEG -Exif.Canon.FirmwareVersion 0x0007 Makernote Ascii 24 Firmware Version 1.10 -Exif.Canon.ImageNumber 0x0008 Makernote Long 1 1171771 -Exif.Canon.OwnerName 0x0009 Makernote Ascii 32 Andreas Huggel -Exif.Canon.ModelID 0x0010 Makernote Long 1 17891328 -Exif.Canon.0x000d 0x000d Makernote Short 21 42 3 32769 378 32769 0 0 0 259 2 0 10 0 0 0 57 198 5 0 0 0 Exif.CanonCs.Macro 0x0001 Makernote Short 1 2 Exif.CanonCs.Selftimer 0x0002 Makernote Short 1 0 Exif.CanonCs.Quality 0x0003 Makernote Short 1 5 @@ -252,6 +228,8 @@ Exif.CanonCs.ZoomSourceWidth 0x0024 Makernote Short 1 Exif.CanonCs.ZoomTargetWidth 0x0025 Makernote Short 1 2272 Exif.CanonCs.0x0026 0x0026 Makernote Short 1 0 Exif.CanonCs.0x0027 0x0027 Makernote Short 1 1 +Exif.Canon.0x0002 0x0002 Makernote Short 4 2 682 286 215 +Exif.Canon.0x0003 0x0003 Makernote Short 4 0 0 0 0 Exif.CanonSi.0x0001 0x0001 Makernote Short 1 0 Exif.CanonSi.ISOSpeed 0x0002 Makernote Short 1 160 Exif.CanonSi.0x0003 0x0003 Makernote Short 1 276 @@ -278,15 +256,37 @@ Exif.CanonSi.0x0017 0x0017 Makernote Short 1 Exif.CanonSi.0x0018 0x0018 Makernote Short 1 0 Exif.CanonSi.0x0019 0x0019 Makernote Short 1 0 Exif.CanonSi.0x001a 0x001a Makernote Short 1 250 +Exif.Canon.ImageType 0x0006 Makernote Ascii 32 IMG:PowerShot S40 JPEG +Exif.Canon.FirmwareVersion 0x0007 Makernote Ascii 24 Firmware Version 1.10 +Exif.Canon.ImageNumber 0x0008 Makernote Long 1 1171771 +Exif.Canon.OwnerName 0x0009 Makernote Ascii 32 Andreas Huggel +Exif.Canon.0x000d 0x000d Makernote Short 21 42 3 32769 378 32769 0 0 0 259 2 0 10 0 0 0 57 198 5 0 0 0 +Exif.Canon.ModelID 0x0010 Makernote Long 1 17891328 +Exif.Photo.UserComment 0x9286 Exif Undefined 264 +Exif.Photo.FlashpixVersion 0xa000 Exif Undefined 4 48 49 48 48 +Exif.Photo.ColorSpace 0xa001 Exif Short 1 1 +Exif.Photo.PixelXDimension 0xa002 Exif Short 1 2272 +Exif.Photo.PixelYDimension 0xa003 Exif Short 1 1704 +Exif.Photo.InteroperabilityTag 0xa005 Exif Long 1 1372 Exif.Iop.InteroperabilityIndex 0x0001 Iop Ascii 4 123 Exif.Iop.InteroperabilityVersion 0x0002 Iop Undefined 4 48 49 48 48 Exif.Iop.RelatedImageWidth 0x1001 Iop Short 1 2272 Exif.Iop.RelatedImageLength 0x1002 Iop Short 1 1704 +Exif.Photo.FocalPlaneXResolution 0xa20e Exif Rational 1 2272000/280 +Exif.Photo.FocalPlaneYResolution 0xa20f Exif Rational 1 1704000/210 +Exif.Photo.FocalPlaneResolutionUnit 0xa210 Exif Short 1 2 +Exif.Photo.SensingMethod 0xa217 Exif Short 1 2 +Exif.Photo.FileSource 0xa300 Exif Undefined 1 3 +Exif.Photo.CustomRendered 0xa401 Exif Short 1 0 +Exif.Photo.ExposureMode 0xa402 Exif Short 1 0 +Exif.Photo.WhiteBalance 0xa403 Exif Short 1 0 +Exif.Photo.DigitalZoomRatio 0xa404 Exif Rational 1 2272/2272 +Exif.Photo.SceneCaptureType 0xa406 Exif Short 1 0 Exif.Thumbnail.Compression 0x0103 IFD1 Short 1 6 Exif.Thumbnail.XResolution 0x011a IFD1 Rational 1 180/1 Exif.Thumbnail.YResolution 0x011b IFD1 Rational 1 180/1 Exif.Thumbnail.ResolutionUnit 0x0128 IFD1 Short 1 2 -Exif.Thumbnail.JPEGInterchangeFormat 0x0201 IFD1 Long 1 0 +Exif.Thumbnail.JPEGInterchangeFormat 0x0201 IFD1 Long 1 1520 Exif.Thumbnail.JPEGInterchangeFormatLength 0x0202 IFD1 Long 1 5448 ---------------------------------------------- Copy construction, intrusive changes @@ -298,7 +298,7 @@ Exif.Image.YResolution 0x011b IFD0 Rational 1 Exif.Image.ResolutionUnit 0x0128 IFD0 Short 1 2 Exif.Image.DateTime 0x0132 IFD0 Ascii 29 Sunday, 11am and ten minutes Exif.Image.YCbCrPositioning 0x0213 IFD0 Short 1 1 -Exif.Image.ExifTag 0x8769 IFD0 Long 1 201 +Exif.Image.ExifTag 0x8769 IFD0 Long 1 202 Exif.Photo.ExposureTime 0x829a Exif Rational 1 1/500 Exif.Photo.FNumber 0x829d Exif Rational 1 49/10 Exif.Photo.ExifVersion 0x9000 Exif Undefined 4 48 50 50 48 @@ -313,32 +313,8 @@ Exif.Photo.MaxApertureValue 0x9205 Exif Rational 1 Exif.Photo.MeteringMode 0x9207 Exif Short 6 1 2 3 4 5 6 Exif.Photo.Flash 0x9209 Exif Short 1 24 Exif.Photo.FocalLength 0x920a Exif Rational 1 682/32 -Exif.Photo.UserComment 0x9286 Exif Undefined 264 -Exif.Photo.FlashpixVersion 0xa000 Exif Undefined 4 48 49 48 48 -Exif.Photo.ColorSpace 0xa001 Exif Short 1 1 -Exif.Photo.PixelXDimension 0xa002 Exif Short 1 2272 -Exif.Photo.PixelYDimension 0xa003 Exif Short 1 1704 -Exif.Photo.InteroperabilityTag 0xa005 Exif Long 1 1442 -Exif.Photo.FocalPlaneXResolution 0xa20e Exif Rational 1 2272000/280 -Exif.Photo.FocalPlaneYResolution 0xa20f Exif Rational 1 1704000/210 -Exif.Photo.FocalPlaneResolutionUnit 0xa210 Exif Short 1 2 -Exif.Photo.SensingMethod 0xa217 Exif Short 1 2 -Exif.Photo.FileSource 0xa300 Exif Undefined 1 3 -Exif.Photo.CustomRendered 0xa401 Exif Short 1 0 -Exif.Photo.ExposureMode 0xa402 Exif Short 1 0 -Exif.Photo.WhiteBalance 0xa403 Exif Short 1 0 -Exif.Photo.DigitalZoomRatio 0xa404 Exif Rational 1 2272/2272 -Exif.Photo.SceneCaptureType 0xa406 Exif Short 1 0 -Exif.Canon.0x0002 0x0002 Makernote Short 4 2 682 286 215 -Exif.Canon.0x0003 0x0003 Makernote Short 4 0 0 0 0 Exif.Canon.0x0000 0x0000 Makernote Short 6 0 0 0 0 0 0 Exif.Canon.0x0000 0x0000 Makernote Short 4 0 0 0 0 -Exif.Canon.ImageType 0x0006 Makernote Ascii 32 IMG:PowerShot S40 JPEG -Exif.Canon.FirmwareVersion 0x0007 Makernote Ascii 24 Firmware Version 1.10 -Exif.Canon.ImageNumber 0x0008 Makernote Long 1 1171771 -Exif.Canon.OwnerName 0x0009 Makernote Ascii 32 Andreas Huggel -Exif.Canon.ModelID 0x0010 Makernote Long 1 17891328 -Exif.Canon.0x000d 0x000d Makernote Short 21 42 3 32769 378 32769 0 0 0 259 2 0 10 0 0 0 57 198 5 0 0 0 Exif.CanonCs.Macro 0x0001 Makernote Short 1 2 Exif.CanonCs.Selftimer 0x0002 Makernote Short 1 0 Exif.CanonCs.Quality 0x0003 Makernote Short 1 5 @@ -376,6 +352,8 @@ Exif.CanonCs.ZoomSourceWidth 0x0024 Makernote Short 1 Exif.CanonCs.ZoomTargetWidth 0x0025 Makernote Short 1 2272 Exif.CanonCs.0x0026 0x0026 Makernote Short 1 0 Exif.CanonCs.0x0027 0x0027 Makernote Short 1 1 +Exif.Canon.0x0002 0x0002 Makernote Short 4 2 682 286 215 +Exif.Canon.0x0003 0x0003 Makernote Short 4 0 0 0 0 Exif.CanonSi.0x0001 0x0001 Makernote Short 1 0 Exif.CanonSi.ISOSpeed 0x0002 Makernote Short 1 160 Exif.CanonSi.0x0003 0x0003 Makernote Short 1 276 @@ -402,16 +380,38 @@ Exif.CanonSi.0x0017 0x0017 Makernote Short 1 Exif.CanonSi.0x0018 0x0018 Makernote Short 1 0 Exif.CanonSi.0x0019 0x0019 Makernote Short 1 0 Exif.CanonSi.0x001a 0x001a Makernote Short 1 250 +Exif.Canon.ImageType 0x0006 Makernote Ascii 32 IMG:PowerShot S40 JPEG +Exif.Canon.FirmwareVersion 0x0007 Makernote Ascii 24 Firmware Version 1.10 +Exif.Canon.ImageNumber 0x0008 Makernote Long 1 1171771 +Exif.Canon.OwnerName 0x0009 Makernote Ascii 32 Andreas Huggel +Exif.Canon.0x000d 0x000d Makernote Short 21 42 3 32769 378 32769 0 0 0 259 2 0 10 0 0 0 57 198 5 0 0 0 +Exif.Canon.ModelID 0x0010 Makernote Long 1 17891328 +Exif.Photo.UserComment 0x9286 Exif Undefined 264 +Exif.Photo.FlashpixVersion 0xa000 Exif Undefined 4 48 49 48 48 +Exif.Photo.ColorSpace 0xa001 Exif Short 1 1 +Exif.Photo.PixelXDimension 0xa002 Exif Short 1 2272 +Exif.Photo.PixelYDimension 0xa003 Exif Short 1 1704 +Exif.Photo.InteroperabilityTag 0xa005 Exif Long 1 1424 Exif.Iop.InteroperabilityIndex 0x0001 Iop Ascii 5 1234 Exif.Iop.InteroperabilityVersion 0x0002 Iop Undefined 4 48 49 48 48 Exif.Iop.RelatedImageWidth 0x1001 Iop Short 1 2272 Exif.Iop.RelatedImageLength 0x1002 Iop Short 1 1704 +Exif.Photo.FocalPlaneXResolution 0xa20e Exif Rational 1 2272000/280 +Exif.Photo.FocalPlaneYResolution 0xa20f Exif Rational 1 1704000/210 +Exif.Photo.FocalPlaneResolutionUnit 0xa210 Exif Short 1 2 +Exif.Photo.SensingMethod 0xa217 Exif Short 1 2 +Exif.Photo.FileSource 0xa300 Exif Undefined 1 3 +Exif.Photo.CustomRendered 0xa401 Exif Short 1 0 +Exif.Photo.ExposureMode 0xa402 Exif Short 1 0 +Exif.Photo.WhiteBalance 0xa403 Exif Short 1 0 +Exif.Photo.DigitalZoomRatio 0xa404 Exif Rational 1 2272/2272 +Exif.Photo.SceneCaptureType 0xa406 Exif Short 1 0 Exif.Thumbnail.Compression 0x0103 IFD1 Short 1 6 Exif.Thumbnail.Orientation 0x0112 IFD1 Short 5 2 3 4 5 6 Exif.Thumbnail.XResolution 0x011a IFD1 Rational 1 180/1 Exif.Thumbnail.YResolution 0x011b IFD1 Rational 1 180/1 Exif.Thumbnail.ResolutionUnit 0x0128 IFD1 Short 1 2 -Exif.Thumbnail.JPEGInterchangeFormat 0x0201 IFD1 Long 1 0 +Exif.Thumbnail.JPEGInterchangeFormat 0x0201 IFD1 Long 1 1600 Exif.Thumbnail.JPEGInterchangeFormatLength 0x0202 IFD1 Long 1 5448 ---------------------------------------------- Assignment, non-intrusive changes @@ -421,13 +421,13 @@ Exif.Image.Orientation 0x0112 IFD0 Short 1 Exif.Image.XResolution 0x011a IFD0 Rational 1 180/1 Exif.Image.YResolution 0x011b IFD0 Rational 1 180/1 Exif.Image.ResolutionUnit 0x0128 IFD0 Short 1 2 -Exif.Image.DateTime 0x0132 IFD0 Ascii 20 Sunday, 11am +Exif.Image.DateTime 0x0132 IFD0 Ascii 13 Sunday, 11am Exif.Image.YCbCrPositioning 0x0213 IFD0 Short 1 1 -Exif.Image.ExifTag 0x8769 IFD0 Long 1 196 +Exif.Image.ExifTag 0x8769 IFD0 Long 1 202 Exif.Photo.ExposureTime 0x829a Exif Rational 1 1/500 Exif.Photo.FNumber 0x829d Exif Rational 1 49/10 Exif.Photo.ExifVersion 0x9000 Exif Undefined 4 48 50 50 48 -Exif.Photo.DateTimeOriginal 0x9003 Exif Ascii 20 Sunday, 11am +Exif.Photo.DateTimeOriginal 0x9003 Exif Ascii 13 Sunday, 11am Exif.Photo.DateTimeDigitized 0x9004 Exif Ascii 20 2003:12:14 12:01:44 Exif.Photo.ComponentsConfiguration 0x9101 Exif Undefined 4 1 2 3 0 Exif.Photo.CompressedBitsPerPixel 0x9102 Exif Rational 1 5/1 @@ -438,32 +438,8 @@ Exif.Photo.MaxApertureValue 0x9205 Exif Rational 1 Exif.Photo.MeteringMode 0x9207 Exif Short 1 1 Exif.Photo.Flash 0x9209 Exif Short 1 24 Exif.Photo.FocalLength 0x920a Exif Rational 1 682/32 -Exif.Photo.UserComment 0x9286 Exif Undefined 264 -Exif.Photo.FlashpixVersion 0xa000 Exif Undefined 4 48 49 48 48 -Exif.Photo.ColorSpace 0xa001 Exif Short 1 1 -Exif.Photo.PixelXDimension 0xa002 Exif Short 1 2272 -Exif.Photo.PixelYDimension 0xa003 Exif Short 1 1704 -Exif.Photo.InteroperabilityTag 0xa005 Exif Long 1 1416 -Exif.Photo.FocalPlaneXResolution 0xa20e Exif Rational 1 2272000/280 -Exif.Photo.FocalPlaneYResolution 0xa20f Exif Rational 1 1704000/210 -Exif.Photo.FocalPlaneResolutionUnit 0xa210 Exif Short 1 2 -Exif.Photo.SensingMethod 0xa217 Exif Short 1 2 -Exif.Photo.FileSource 0xa300 Exif Undefined 1 3 -Exif.Photo.CustomRendered 0xa401 Exif Short 1 0 -Exif.Photo.ExposureMode 0xa402 Exif Short 1 0 -Exif.Photo.WhiteBalance 0xa403 Exif Short 1 0 -Exif.Photo.DigitalZoomRatio 0xa404 Exif Rational 1 2272/2272 -Exif.Photo.SceneCaptureType 0xa406 Exif Short 1 0 -Exif.Canon.0x0002 0x0002 Makernote Short 4 2 682 286 215 -Exif.Canon.0x0003 0x0003 Makernote Short 4 0 0 0 0 Exif.Canon.0x0000 0x0000 Makernote Short 6 0 0 0 0 0 0 Exif.Canon.0x0000 0x0000 Makernote Short 4 0 0 0 0 -Exif.Canon.ImageType 0x0006 Makernote Ascii 32 IMG:PowerShot S40 JPEG -Exif.Canon.FirmwareVersion 0x0007 Makernote Ascii 24 Firmware Version 1.10 -Exif.Canon.ImageNumber 0x0008 Makernote Long 1 1171771 -Exif.Canon.OwnerName 0x0009 Makernote Ascii 32 Andreas Huggel -Exif.Canon.ModelID 0x0010 Makernote Long 1 17891328 -Exif.Canon.0x000d 0x000d Makernote Short 21 42 3 32769 378 32769 0 0 0 259 2 0 10 0 0 0 57 198 5 0 0 0 Exif.CanonCs.Macro 0x0001 Makernote Short 1 2 Exif.CanonCs.Selftimer 0x0002 Makernote Short 1 0 Exif.CanonCs.Quality 0x0003 Makernote Short 1 5 @@ -501,6 +477,8 @@ Exif.CanonCs.ZoomSourceWidth 0x0024 Makernote Short 1 Exif.CanonCs.ZoomTargetWidth 0x0025 Makernote Short 1 2272 Exif.CanonCs.0x0026 0x0026 Makernote Short 1 0 Exif.CanonCs.0x0027 0x0027 Makernote Short 1 1 +Exif.Canon.0x0002 0x0002 Makernote Short 4 2 682 286 215 +Exif.Canon.0x0003 0x0003 Makernote Short 4 0 0 0 0 Exif.CanonSi.0x0001 0x0001 Makernote Short 1 0 Exif.CanonSi.ISOSpeed 0x0002 Makernote Short 1 160 Exif.CanonSi.0x0003 0x0003 Makernote Short 1 276 @@ -527,15 +505,38 @@ Exif.CanonSi.0x0017 0x0017 Makernote Short 1 Exif.CanonSi.0x0018 0x0018 Makernote Short 1 0 Exif.CanonSi.0x0019 0x0019 Makernote Short 1 0 Exif.CanonSi.0x001a 0x001a Makernote Short 1 250 +Exif.Canon.ImageType 0x0006 Makernote Ascii 32 IMG:PowerShot S40 JPEG +Exif.Canon.FirmwareVersion 0x0007 Makernote Ascii 24 Firmware Version 1.10 +Exif.Canon.ImageNumber 0x0008 Makernote Long 1 1171771 +Exif.Canon.OwnerName 0x0009 Makernote Ascii 32 Andreas Huggel +Exif.Canon.0x000d 0x000d Makernote Short 21 42 3 32769 378 32769 0 0 0 259 2 0 10 0 0 0 57 198 5 0 0 0 +Exif.Canon.ModelID 0x0010 Makernote Long 1 17891328 +Exif.Photo.UserComment 0x9286 Exif Undefined 264 +Exif.Photo.FlashpixVersion 0xa000 Exif Undefined 4 48 49 48 48 +Exif.Photo.ColorSpace 0xa001 Exif Short 1 1 +Exif.Photo.PixelXDimension 0xa002 Exif Short 1 2272 +Exif.Photo.PixelYDimension 0xa003 Exif Short 1 1704 +Exif.Photo.InteroperabilityTag 0xa005 Exif Long 1 1424 Exif.Iop.InteroperabilityIndex 0x0001 Iop Ascii 4 123 Exif.Iop.InteroperabilityVersion 0x0002 Iop Undefined 4 48 49 48 48 Exif.Iop.RelatedImageWidth 0x1001 Iop Short 1 2272 Exif.Iop.RelatedImageLength 0x1002 Iop Short 1 1704 +Exif.Photo.FocalPlaneXResolution 0xa20e Exif Rational 1 2272000/280 +Exif.Photo.FocalPlaneYResolution 0xa20f Exif Rational 1 1704000/210 +Exif.Photo.FocalPlaneResolutionUnit 0xa210 Exif Short 1 2 +Exif.Photo.SensingMethod 0xa217 Exif Short 1 2 +Exif.Photo.FileSource 0xa300 Exif Undefined 1 3 +Exif.Photo.CustomRendered 0xa401 Exif Short 1 0 +Exif.Photo.ExposureMode 0xa402 Exif Short 1 0 +Exif.Photo.WhiteBalance 0xa403 Exif Short 1 0 +Exif.Photo.DigitalZoomRatio 0xa404 Exif Rational 1 2272/2272 +Exif.Photo.SceneCaptureType 0xa406 Exif Short 1 0 Exif.Thumbnail.Compression 0x0103 IFD1 Short 1 6 +Exif.Thumbnail.Orientation 0x0112 IFD1 Short 1 2 Exif.Thumbnail.XResolution 0x011a IFD1 Rational 1 180/1 Exif.Thumbnail.YResolution 0x011b IFD1 Rational 1 180/1 Exif.Thumbnail.ResolutionUnit 0x0128 IFD1 Short 1 2 -Exif.Thumbnail.JPEGInterchangeFormat 0x0201 IFD1 Long 1 0 +Exif.Thumbnail.JPEGInterchangeFormat 0x0201 IFD1 Long 1 1600 Exif.Thumbnail.JPEGInterchangeFormatLength 0x0202 IFD1 Long 1 5448 ---------------------------------------------- Assignment, intrusive changes @@ -547,7 +548,7 @@ Exif.Image.YResolution 0x011b IFD0 Rational 1 Exif.Image.ResolutionUnit 0x0128 IFD0 Short 1 2 Exif.Image.DateTime 0x0132 IFD0 Ascii 29 Sunday, 11am and ten minutes Exif.Image.YCbCrPositioning 0x0213 IFD0 Short 1 1 -Exif.Image.ExifTag 0x8769 IFD0 Long 1 201 +Exif.Image.ExifTag 0x8769 IFD0 Long 1 202 Exif.Photo.ExposureTime 0x829a Exif Rational 1 1/500 Exif.Photo.FNumber 0x829d Exif Rational 1 49/10 Exif.Photo.ExifVersion 0x9000 Exif Undefined 4 48 50 50 48 @@ -562,32 +563,8 @@ Exif.Photo.MaxApertureValue 0x9205 Exif Rational 1 Exif.Photo.MeteringMode 0x9207 Exif Short 1 1 Exif.Photo.Flash 0x9209 Exif Short 1 24 Exif.Photo.FocalLength 0x920a Exif Rational 1 682/32 -Exif.Photo.UserComment 0x9286 Exif Undefined 264 -Exif.Photo.FlashpixVersion 0xa000 Exif Undefined 4 48 49 48 48 -Exif.Photo.ColorSpace 0xa001 Exif Short 1 1 -Exif.Photo.PixelXDimension 0xa002 Exif Short 1 2272 -Exif.Photo.PixelYDimension 0xa003 Exif Short 1 1704 -Exif.Photo.InteroperabilityTag 0xa005 Exif Long 1 1430 -Exif.Photo.FocalPlaneXResolution 0xa20e Exif Rational 1 2272000/280 -Exif.Photo.FocalPlaneYResolution 0xa20f Exif Rational 1 1704000/210 -Exif.Photo.FocalPlaneResolutionUnit 0xa210 Exif Short 1 2 -Exif.Photo.SensingMethod 0xa217 Exif Short 1 2 -Exif.Photo.FileSource 0xa300 Exif Undefined 1 3 -Exif.Photo.CustomRendered 0xa401 Exif Short 1 0 -Exif.Photo.ExposureMode 0xa402 Exif Short 1 0 -Exif.Photo.WhiteBalance 0xa403 Exif Short 1 0 -Exif.Photo.DigitalZoomRatio 0xa404 Exif Rational 1 2272/2272 -Exif.Photo.SceneCaptureType 0xa406 Exif Short 1 0 -Exif.Canon.0x0002 0x0002 Makernote Short 4 2 682 286 215 -Exif.Canon.0x0003 0x0003 Makernote Short 4 0 0 0 0 Exif.Canon.0x0000 0x0000 Makernote Short 6 0 0 0 0 0 0 Exif.Canon.0x0000 0x0000 Makernote Short 4 0 0 0 0 -Exif.Canon.ImageType 0x0006 Makernote Ascii 32 IMG:PowerShot S40 JPEG -Exif.Canon.FirmwareVersion 0x0007 Makernote Ascii 24 Firmware Version 1.10 -Exif.Canon.ImageNumber 0x0008 Makernote Long 1 1171771 -Exif.Canon.OwnerName 0x0009 Makernote Ascii 32 Andreas Huggel -Exif.Canon.ModelID 0x0010 Makernote Long 1 17891328 -Exif.Canon.0x000d 0x000d Makernote Short 21 42 3 32769 378 32769 0 0 0 259 2 0 10 0 0 0 57 198 5 0 0 0 Exif.CanonCs.Macro 0x0001 Makernote Short 1 2 Exif.CanonCs.Selftimer 0x0002 Makernote Short 1 0 Exif.CanonCs.Quality 0x0003 Makernote Short 1 5 @@ -625,6 +602,8 @@ Exif.CanonCs.ZoomSourceWidth 0x0024 Makernote Short 1 Exif.CanonCs.ZoomTargetWidth 0x0025 Makernote Short 1 2272 Exif.CanonCs.0x0026 0x0026 Makernote Short 1 0 Exif.CanonCs.0x0027 0x0027 Makernote Short 1 1 +Exif.Canon.0x0002 0x0002 Makernote Short 4 2 682 286 215 +Exif.Canon.0x0003 0x0003 Makernote Short 4 0 0 0 0 Exif.CanonSi.0x0001 0x0001 Makernote Short 1 0 Exif.CanonSi.ISOSpeed 0x0002 Makernote Short 1 160 Exif.CanonSi.0x0003 0x0003 Makernote Short 1 276 @@ -651,16 +630,38 @@ Exif.CanonSi.0x0017 0x0017 Makernote Short 1 Exif.CanonSi.0x0018 0x0018 Makernote Short 1 0 Exif.CanonSi.0x0019 0x0019 Makernote Short 1 0 Exif.CanonSi.0x001a 0x001a Makernote Short 1 250 +Exif.Canon.ImageType 0x0006 Makernote Ascii 32 IMG:PowerShot S40 JPEG +Exif.Canon.FirmwareVersion 0x0007 Makernote Ascii 24 Firmware Version 1.10 +Exif.Canon.ImageNumber 0x0008 Makernote Long 1 1171771 +Exif.Canon.OwnerName 0x0009 Makernote Ascii 32 Andreas Huggel +Exif.Canon.0x000d 0x000d Makernote Short 21 42 3 32769 378 32769 0 0 0 259 2 0 10 0 0 0 57 198 5 0 0 0 +Exif.Canon.ModelID 0x0010 Makernote Long 1 17891328 +Exif.Photo.UserComment 0x9286 Exif Undefined 264 +Exif.Photo.FlashpixVersion 0xa000 Exif Undefined 4 48 49 48 48 +Exif.Photo.ColorSpace 0xa001 Exif Short 1 1 +Exif.Photo.PixelXDimension 0xa002 Exif Short 1 2272 +Exif.Photo.PixelYDimension 0xa003 Exif Short 1 1704 +Exif.Photo.InteroperabilityTag 0xa005 Exif Long 1 1412 Exif.Iop.InteroperabilityIndex 0x0001 Iop Ascii 4 123 Exif.Iop.InteroperabilityVersion 0x0002 Iop Undefined 4 48 49 48 48 Exif.Iop.RelatedImageWidth 0x1001 Iop Short 1 2272 Exif.Iop.RelatedImageLength 0x1002 Iop Short 1 1704 +Exif.Photo.FocalPlaneXResolution 0xa20e Exif Rational 1 2272000/280 +Exif.Photo.FocalPlaneYResolution 0xa20f Exif Rational 1 1704000/210 +Exif.Photo.FocalPlaneResolutionUnit 0xa210 Exif Short 1 2 +Exif.Photo.SensingMethod 0xa217 Exif Short 1 2 +Exif.Photo.FileSource 0xa300 Exif Undefined 1 3 +Exif.Photo.CustomRendered 0xa401 Exif Short 1 0 +Exif.Photo.ExposureMode 0xa402 Exif Short 1 0 +Exif.Photo.WhiteBalance 0xa403 Exif Short 1 0 +Exif.Photo.DigitalZoomRatio 0xa404 Exif Rational 1 2272/2272 +Exif.Photo.SceneCaptureType 0xa406 Exif Short 1 0 Exif.Thumbnail.Compression 0x0103 IFD1 Short 1 6 Exif.Thumbnail.Orientation 0x0112 IFD1 Short 1 2 Exif.Thumbnail.XResolution 0x011a IFD1 Rational 1 180/1 Exif.Thumbnail.YResolution 0x011b IFD1 Rational 1 180/1 Exif.Thumbnail.ResolutionUnit 0x0128 IFD1 Short 1 2 -Exif.Thumbnail.JPEGInterchangeFormat 0x0201 IFD1 Long 1 0 +Exif.Thumbnail.JPEGInterchangeFormat 0x0201 IFD1 Long 1 1572 Exif.Thumbnail.JPEGInterchangeFormatLength 0x0202 IFD1 Long 1 5448 Copy construction, non-intrusive changes Exif.Image.Make 0x010f IFD0 Ascii 18 NIKON CORPORATION @@ -670,7 +671,7 @@ Exif.Image.XResolution 0x011a IFD0 Rational 1 Exif.Image.YResolution 0x011b IFD0 Rational 1 300/1 Exif.Image.ResolutionUnit 0x0128 IFD0 Short 1 2 Exif.Image.Software 0x0131 IFD0 Ascii 10 Ver.1.01 -Exif.Image.DateTime 0x0132 IFD0 Ascii 20 Sunday, 11am +Exif.Image.DateTime 0x0132 IFD0 Ascii 13 Sunday, 11am Exif.Image.WhitePoint 0x013e IFD0 Rational 2 313/1000 329/1000 Exif.Image.PrimaryChromaticities 0x013f IFD0 Rational 6 64/100 33/100 21/100 71/100 15/100 6/100 Exif.Image.YCbCrCoefficients 0x0211 IFD0 Rational 3 299/1000 587/1000 114/1000 @@ -680,7 +681,7 @@ Exif.Photo.ExposureTime 0x829a Exif Rational 1 Exif.Photo.FNumber 0x829d Exif Rational 1 90/10 Exif.Photo.ExposureProgram 0x8822 Exif Short 1 2 Exif.Photo.ExifVersion 0x9000 Exif Undefined 4 48 50 50 49 -Exif.Photo.DateTimeOriginal 0x9003 Exif Ascii 20 Sunday, 11am +Exif.Photo.DateTimeOriginal 0x9003 Exif Ascii 13 Sunday, 11am Exif.Photo.DateTimeDigitized 0x9004 Exif Ascii 20 2004:03:30 10:43:46 Exif.Photo.ComponentsConfiguration 0x9101 Exif Undefined 4 1 2 3 0 Exif.Photo.CompressedBitsPerPixel 0x9102 Exif Rational 1 4/1 @@ -690,31 +691,6 @@ Exif.Photo.MeteringMode 0x9207 Exif Short 1 Exif.Photo.LightSource 0x9208 Exif Short 1 0 Exif.Photo.Flash 0x9209 Exif Short 1 0 Exif.Photo.FocalLength 0x920a Exif Rational 1 500/10 -Exif.Photo.UserComment 0x9286 Exif Undefined 44 charset="Ascii" -Exif.Photo.SubSecTime 0x9290 Exif Ascii 3 00 -Exif.Photo.SubSecTimeOriginal 0x9291 Exif Ascii 3 00 -Exif.Photo.SubSecTimeDigitized 0x9292 Exif Ascii 3 00 -Exif.Photo.FlashpixVersion 0xa000 Exif Undefined 4 48 49 48 48 -Exif.Photo.ColorSpace 0xa001 Exif Short 1 65535 -Exif.Photo.PixelXDimension 0xa002 Exif Short 1 3008 -Exif.Photo.PixelYDimension 0xa003 Exif Short 1 2000 -Exif.Photo.InteroperabilityTag 0xa005 Exif Long 1 30306 -Exif.Photo.SensingMethod 0xa217 Exif Short 1 2 -Exif.Photo.FileSource 0xa300 Exif Undefined 1 3 -Exif.Photo.SceneType 0xa301 Exif Undefined 1 1 -Exif.Photo.CFAPattern 0xa302 Exif Undefined 8 0 2 0 2 2 1 1 0 -Exif.Photo.CustomRendered 0xa401 Exif Short 1 0 -Exif.Photo.ExposureMode 0xa402 Exif Short 1 0 -Exif.Photo.WhiteBalance 0xa403 Exif Short 1 0 -Exif.Photo.DigitalZoomRatio 0xa404 Exif Rational 1 1/1 -Exif.Photo.FocalLengthIn35mmFilm 0xa405 Exif Short 1 75 -Exif.Photo.SceneCaptureType 0xa406 Exif Short 1 0 -Exif.Photo.GainControl 0xa407 Exif Short 1 0 -Exif.Photo.Contrast 0xa408 Exif Short 1 0 -Exif.Photo.Saturation 0xa409 Exif Short 1 0 -Exif.Photo.Sharpness 0xa40a Exif Short 1 0 -Exif.Photo.SubjectDistanceRange 0xa40c Exif Short 1 0 -Exif.Photo.0xa500 0xa500 Exif Rational 1 22/10 Exif.Nikon3.Version 0x0001 Makernote Undefined 4 48 50 49 48 Exif.Nikon3.ISOSpeed 0x0002 Makernote Short 2 0 200 Exif.Nikon3.Quality 0x0004 Makernote Ascii 8 FINE @@ -757,13 +733,38 @@ Exif.Nikon3.0x00a8 0x00a8 Makernote Undefined 20 Exif.Nikon3.ImageOptimization 0x00a9 Makernote Ascii 16 NORMAL Exif.Nikon3.Saturation 0x00aa Makernote Ascii 16 NORMAL Exif.Nikon3.VariProgram 0x00ab Makernote Ascii 16 +Exif.Photo.UserComment 0x9286 Exif Undefined 44 charset="Ascii" +Exif.Photo.SubSecTime 0x9290 Exif Ascii 3 00 +Exif.Photo.SubSecTimeOriginal 0x9291 Exif Ascii 3 00 +Exif.Photo.SubSecTimeDigitized 0x9292 Exif Ascii 3 00 +Exif.Photo.FlashpixVersion 0xa000 Exif Undefined 4 48 49 48 48 +Exif.Photo.ColorSpace 0xa001 Exif Short 1 65535 +Exif.Photo.PixelXDimension 0xa002 Exif Short 1 3008 +Exif.Photo.PixelYDimension 0xa003 Exif Short 1 2000 +Exif.Photo.InteroperabilityTag 0xa005 Exif Long 1 30306 Exif.Iop.InteroperabilityIndex 0x0001 Iop Ascii 4 123 Exif.Iop.InteroperabilityVersion 0x0002 Iop Undefined 4 48 49 48 48 +Exif.Photo.SensingMethod 0xa217 Exif Short 1 2 +Exif.Photo.FileSource 0xa300 Exif Undefined 1 3 +Exif.Photo.SceneType 0xa301 Exif Undefined 1 1 +Exif.Photo.CFAPattern 0xa302 Exif Undefined 8 0 2 0 2 2 1 1 0 +Exif.Photo.CustomRendered 0xa401 Exif Short 1 0 +Exif.Photo.ExposureMode 0xa402 Exif Short 1 0 +Exif.Photo.WhiteBalance 0xa403 Exif Short 1 0 +Exif.Photo.DigitalZoomRatio 0xa404 Exif Rational 1 1/1 +Exif.Photo.FocalLengthIn35mmFilm 0xa405 Exif Short 1 75 +Exif.Photo.SceneCaptureType 0xa406 Exif Short 1 0 +Exif.Photo.GainControl 0xa407 Exif Short 1 0 +Exif.Photo.Contrast 0xa408 Exif Short 1 0 +Exif.Photo.Saturation 0xa409 Exif Short 1 0 +Exif.Photo.Sharpness 0xa40a Exif Short 1 0 +Exif.Photo.SubjectDistanceRange 0xa40c Exif Short 1 0 +Exif.Photo.0xa500 0xa500 Exif Rational 1 22/10 Exif.Thumbnail.Compression 0x0103 IFD1 Short 1 6 Exif.Thumbnail.XResolution 0x011a IFD1 Rational 1 300/1 Exif.Thumbnail.YResolution 0x011b IFD1 Rational 1 300/1 Exif.Thumbnail.ResolutionUnit 0x0128 IFD1 Short 1 2 -Exif.Thumbnail.JPEGInterchangeFormat 0x0201 IFD1 Long 1 0 +Exif.Thumbnail.JPEGInterchangeFormat 0x0201 IFD1 Long 1 30444 Exif.Thumbnail.JPEGInterchangeFormatLength 0x0202 IFD1 Long 1 8930 Exif.Thumbnail.YCbCrPositioning 0x0213 IFD1 Short 1 2 ---------------------------------------------- @@ -780,7 +781,7 @@ Exif.Image.WhitePoint 0x013e IFD0 Rational 2 Exif.Image.PrimaryChromaticities 0x013f IFD0 Rational 6 64/100 33/100 21/100 71/100 15/100 6/100 Exif.Image.YCbCrCoefficients 0x0211 IFD0 Rational 3 299/1000 587/1000 114/1000 Exif.Image.YCbCrPositioning 0x0213 IFD0 Short 1 2 -Exif.Image.ExifTag 0x8769 IFD0 Long 1 349 +Exif.Image.ExifTag 0x8769 IFD0 Long 1 350 Exif.Photo.ExposureTime 0x829a Exif Rational 1 10/2500 Exif.Photo.FNumber 0x829d Exif Rational 1 90/10 Exif.Photo.ExposureProgram 0x8822 Exif Short 1 2 @@ -795,31 +796,6 @@ Exif.Photo.MeteringMode 0x9207 Exif Short 6 Exif.Photo.LightSource 0x9208 Exif Short 1 0 Exif.Photo.Flash 0x9209 Exif Short 1 0 Exif.Photo.FocalLength 0x920a Exif Rational 1 500/10 -Exif.Photo.UserComment 0x9286 Exif Undefined 44 charset="Ascii" -Exif.Photo.SubSecTime 0x9290 Exif Ascii 3 00 -Exif.Photo.SubSecTimeOriginal 0x9291 Exif Ascii 3 00 -Exif.Photo.SubSecTimeDigitized 0x9292 Exif Ascii 3 00 -Exif.Photo.FlashpixVersion 0xa000 Exif Undefined 4 48 49 48 48 -Exif.Photo.ColorSpace 0xa001 Exif Short 1 65535 -Exif.Photo.PixelXDimension 0xa002 Exif Short 1 3008 -Exif.Photo.PixelYDimension 0xa003 Exif Short 1 2000 -Exif.Photo.InteroperabilityTag 0xa005 Exif Long 1 2425 -Exif.Photo.SensingMethod 0xa217 Exif Short 1 2 -Exif.Photo.FileSource 0xa300 Exif Undefined 1 3 -Exif.Photo.SceneType 0xa301 Exif Undefined 1 1 -Exif.Photo.CFAPattern 0xa302 Exif Undefined 8 0 2 0 2 2 1 1 0 -Exif.Photo.CustomRendered 0xa401 Exif Short 1 0 -Exif.Photo.ExposureMode 0xa402 Exif Short 1 0 -Exif.Photo.WhiteBalance 0xa403 Exif Short 1 0 -Exif.Photo.DigitalZoomRatio 0xa404 Exif Rational 1 1/1 -Exif.Photo.FocalLengthIn35mmFilm 0xa405 Exif Short 1 75 -Exif.Photo.SceneCaptureType 0xa406 Exif Short 1 0 -Exif.Photo.GainControl 0xa407 Exif Short 1 0 -Exif.Photo.Contrast 0xa408 Exif Short 1 0 -Exif.Photo.Saturation 0xa409 Exif Short 1 0 -Exif.Photo.Sharpness 0xa40a Exif Short 1 0 -Exif.Photo.SubjectDistanceRange 0xa40c Exif Short 1 0 -Exif.Photo.0xa500 0xa500 Exif Rational 1 22/10 Exif.Nikon3.Version 0x0001 Makernote Undefined 4 48 50 49 48 Exif.Nikon3.ISOSpeed 0x0002 Makernote Short 2 0 200 Exif.Nikon3.Quality 0x0004 Makernote Ascii 8 FINE @@ -862,14 +838,39 @@ Exif.Nikon3.0x00a8 0x00a8 Makernote Undefined 20 Exif.Nikon3.ImageOptimization 0x00a9 Makernote Ascii 16 NORMAL Exif.Nikon3.Saturation 0x00aa Makernote Ascii 16 NORMAL Exif.Nikon3.VariProgram 0x00ab Makernote Ascii 16 +Exif.Photo.UserComment 0x9286 Exif Undefined 44 charset="Ascii" +Exif.Photo.SubSecTime 0x9290 Exif Ascii 3 00 +Exif.Photo.SubSecTimeOriginal 0x9291 Exif Ascii 3 00 +Exif.Photo.SubSecTimeDigitized 0x9292 Exif Ascii 3 00 +Exif.Photo.FlashpixVersion 0xa000 Exif Undefined 4 48 49 48 48 +Exif.Photo.ColorSpace 0xa001 Exif Short 1 65535 +Exif.Photo.PixelXDimension 0xa002 Exif Short 1 3008 +Exif.Photo.PixelYDimension 0xa003 Exif Short 1 2000 +Exif.Photo.InteroperabilityTag 0xa005 Exif Long 1 2438 Exif.Iop.InteroperabilityIndex 0x0001 Iop Ascii 5 1234 Exif.Iop.InteroperabilityVersion 0x0002 Iop Undefined 4 48 49 48 48 +Exif.Photo.SensingMethod 0xa217 Exif Short 1 2 +Exif.Photo.FileSource 0xa300 Exif Undefined 1 3 +Exif.Photo.SceneType 0xa301 Exif Undefined 1 1 +Exif.Photo.CFAPattern 0xa302 Exif Undefined 8 0 2 0 2 2 1 1 0 +Exif.Photo.CustomRendered 0xa401 Exif Short 1 0 +Exif.Photo.ExposureMode 0xa402 Exif Short 1 0 +Exif.Photo.WhiteBalance 0xa403 Exif Short 1 0 +Exif.Photo.DigitalZoomRatio 0xa404 Exif Rational 1 1/1 +Exif.Photo.FocalLengthIn35mmFilm 0xa405 Exif Short 1 75 +Exif.Photo.SceneCaptureType 0xa406 Exif Short 1 0 +Exif.Photo.GainControl 0xa407 Exif Short 1 0 +Exif.Photo.Contrast 0xa408 Exif Short 1 0 +Exif.Photo.Saturation 0xa409 Exif Short 1 0 +Exif.Photo.Sharpness 0xa40a Exif Short 1 0 +Exif.Photo.SubjectDistanceRange 0xa40c Exif Short 1 0 +Exif.Photo.0xa500 0xa500 Exif Rational 1 22/10 Exif.Thumbnail.Compression 0x0103 IFD1 Short 1 6 Exif.Thumbnail.Orientation 0x0112 IFD1 Short 5 2 3 4 5 6 Exif.Thumbnail.XResolution 0x011a IFD1 Rational 1 300/1 Exif.Thumbnail.YResolution 0x011b IFD1 Rational 1 300/1 Exif.Thumbnail.ResolutionUnit 0x0128 IFD1 Short 1 2 -Exif.Thumbnail.JPEGInterchangeFormat 0x0201 IFD1 Long 1 0 +Exif.Thumbnail.JPEGInterchangeFormat 0x0201 IFD1 Long 1 2602 Exif.Thumbnail.JPEGInterchangeFormatLength 0x0202 IFD1 Long 1 8930 Exif.Thumbnail.YCbCrPositioning 0x0213 IFD1 Short 1 2 ---------------------------------------------- @@ -881,17 +882,17 @@ Exif.Image.XResolution 0x011a IFD0 Rational 1 Exif.Image.YResolution 0x011b IFD0 Rational 1 300/1 Exif.Image.ResolutionUnit 0x0128 IFD0 Short 1 2 Exif.Image.Software 0x0131 IFD0 Ascii 10 Ver.1.01 -Exif.Image.DateTime 0x0132 IFD0 Ascii 20 Sunday, 11am +Exif.Image.DateTime 0x0132 IFD0 Ascii 13 Sunday, 11am Exif.Image.WhitePoint 0x013e IFD0 Rational 2 313/1000 329/1000 Exif.Image.PrimaryChromaticities 0x013f IFD0 Rational 6 64/100 33/100 21/100 71/100 15/100 6/100 Exif.Image.YCbCrCoefficients 0x0211 IFD0 Rational 3 299/1000 587/1000 114/1000 Exif.Image.YCbCrPositioning 0x0213 IFD0 Short 1 2 -Exif.Image.ExifTag 0x8769 IFD0 Long 1 340 +Exif.Image.ExifTag 0x8769 IFD0 Long 1 350 Exif.Photo.ExposureTime 0x829a Exif Rational 1 10/2500 Exif.Photo.FNumber 0x829d Exif Rational 1 90/10 Exif.Photo.ExposureProgram 0x8822 Exif Short 1 2 Exif.Photo.ExifVersion 0x9000 Exif Undefined 4 48 50 50 49 -Exif.Photo.DateTimeOriginal 0x9003 Exif Ascii 20 Sunday, 11am +Exif.Photo.DateTimeOriginal 0x9003 Exif Ascii 13 Sunday, 11am Exif.Photo.DateTimeDigitized 0x9004 Exif Ascii 20 2004:03:30 10:43:46 Exif.Photo.ComponentsConfiguration 0x9101 Exif Undefined 4 1 2 3 0 Exif.Photo.CompressedBitsPerPixel 0x9102 Exif Rational 1 4/1 @@ -901,31 +902,6 @@ Exif.Photo.MeteringMode 0x9207 Exif Short 1 Exif.Photo.LightSource 0x9208 Exif Short 1 0 Exif.Photo.Flash 0x9209 Exif Short 1 0 Exif.Photo.FocalLength 0x920a Exif Rational 1 500/10 -Exif.Photo.UserComment 0x9286 Exif Undefined 44 charset="Ascii" -Exif.Photo.SubSecTime 0x9290 Exif Ascii 3 00 -Exif.Photo.SubSecTimeOriginal 0x9291 Exif Ascii 3 00 -Exif.Photo.SubSecTimeDigitized 0x9292 Exif Ascii 3 00 -Exif.Photo.FlashpixVersion 0xa000 Exif Undefined 4 48 49 48 48 -Exif.Photo.ColorSpace 0xa001 Exif Short 1 65535 -Exif.Photo.PixelXDimension 0xa002 Exif Short 1 3008 -Exif.Photo.PixelYDimension 0xa003 Exif Short 1 2000 -Exif.Photo.InteroperabilityTag 0xa005 Exif Long 1 30306 -Exif.Photo.SensingMethod 0xa217 Exif Short 1 2 -Exif.Photo.FileSource 0xa300 Exif Undefined 1 3 -Exif.Photo.SceneType 0xa301 Exif Undefined 1 1 -Exif.Photo.CFAPattern 0xa302 Exif Undefined 8 0 2 0 2 2 1 1 0 -Exif.Photo.CustomRendered 0xa401 Exif Short 1 0 -Exif.Photo.ExposureMode 0xa402 Exif Short 1 0 -Exif.Photo.WhiteBalance 0xa403 Exif Short 1 0 -Exif.Photo.DigitalZoomRatio 0xa404 Exif Rational 1 1/1 -Exif.Photo.FocalLengthIn35mmFilm 0xa405 Exif Short 1 75 -Exif.Photo.SceneCaptureType 0xa406 Exif Short 1 0 -Exif.Photo.GainControl 0xa407 Exif Short 1 0 -Exif.Photo.Contrast 0xa408 Exif Short 1 0 -Exif.Photo.Saturation 0xa409 Exif Short 1 0 -Exif.Photo.Sharpness 0xa40a Exif Short 1 0 -Exif.Photo.SubjectDistanceRange 0xa40c Exif Short 1 0 -Exif.Photo.0xa500 0xa500 Exif Rational 1 22/10 Exif.Nikon3.Version 0x0001 Makernote Undefined 4 48 50 49 48 Exif.Nikon3.ISOSpeed 0x0002 Makernote Short 2 0 200 Exif.Nikon3.Quality 0x0004 Makernote Ascii 8 FINE @@ -968,13 +944,39 @@ Exif.Nikon3.0x00a8 0x00a8 Makernote Undefined 20 Exif.Nikon3.ImageOptimization 0x00a9 Makernote Ascii 16 NORMAL Exif.Nikon3.Saturation 0x00aa Makernote Ascii 16 NORMAL Exif.Nikon3.VariProgram 0x00ab Makernote Ascii 16 +Exif.Photo.UserComment 0x9286 Exif Undefined 44 charset="Ascii" +Exif.Photo.SubSecTime 0x9290 Exif Ascii 3 00 +Exif.Photo.SubSecTimeOriginal 0x9291 Exif Ascii 3 00 +Exif.Photo.SubSecTimeDigitized 0x9292 Exif Ascii 3 00 +Exif.Photo.FlashpixVersion 0xa000 Exif Undefined 4 48 49 48 48 +Exif.Photo.ColorSpace 0xa001 Exif Short 1 65535 +Exif.Photo.PixelXDimension 0xa002 Exif Short 1 3008 +Exif.Photo.PixelYDimension 0xa003 Exif Short 1 2000 +Exif.Photo.InteroperabilityTag 0xa005 Exif Long 1 2438 Exif.Iop.InteroperabilityIndex 0x0001 Iop Ascii 4 123 Exif.Iop.InteroperabilityVersion 0x0002 Iop Undefined 4 48 49 48 48 +Exif.Photo.SensingMethod 0xa217 Exif Short 1 2 +Exif.Photo.FileSource 0xa300 Exif Undefined 1 3 +Exif.Photo.SceneType 0xa301 Exif Undefined 1 1 +Exif.Photo.CFAPattern 0xa302 Exif Undefined 8 0 2 0 2 2 1 1 0 +Exif.Photo.CustomRendered 0xa401 Exif Short 1 0 +Exif.Photo.ExposureMode 0xa402 Exif Short 1 0 +Exif.Photo.WhiteBalance 0xa403 Exif Short 1 0 +Exif.Photo.DigitalZoomRatio 0xa404 Exif Rational 1 1/1 +Exif.Photo.FocalLengthIn35mmFilm 0xa405 Exif Short 1 75 +Exif.Photo.SceneCaptureType 0xa406 Exif Short 1 0 +Exif.Photo.GainControl 0xa407 Exif Short 1 0 +Exif.Photo.Contrast 0xa408 Exif Short 1 0 +Exif.Photo.Saturation 0xa409 Exif Short 1 0 +Exif.Photo.Sharpness 0xa40a Exif Short 1 0 +Exif.Photo.SubjectDistanceRange 0xa40c Exif Short 1 0 +Exif.Photo.0xa500 0xa500 Exif Rational 1 22/10 Exif.Thumbnail.Compression 0x0103 IFD1 Short 1 6 +Exif.Thumbnail.Orientation 0x0112 IFD1 Short 1 2 Exif.Thumbnail.XResolution 0x011a IFD1 Rational 1 300/1 Exif.Thumbnail.YResolution 0x011b IFD1 Rational 1 300/1 Exif.Thumbnail.ResolutionUnit 0x0128 IFD1 Short 1 2 -Exif.Thumbnail.JPEGInterchangeFormat 0x0201 IFD1 Long 1 0 +Exif.Thumbnail.JPEGInterchangeFormat 0x0201 IFD1 Long 1 2602 Exif.Thumbnail.JPEGInterchangeFormatLength 0x0202 IFD1 Long 1 8930 Exif.Thumbnail.YCbCrPositioning 0x0213 IFD1 Short 1 2 ---------------------------------------------- @@ -991,7 +993,7 @@ Exif.Image.WhitePoint 0x013e IFD0 Rational 2 Exif.Image.PrimaryChromaticities 0x013f IFD0 Rational 6 64/100 33/100 21/100 71/100 15/100 6/100 Exif.Image.YCbCrCoefficients 0x0211 IFD0 Rational 3 299/1000 587/1000 114/1000 Exif.Image.YCbCrPositioning 0x0213 IFD0 Short 1 2 -Exif.Image.ExifTag 0x8769 IFD0 Long 1 349 +Exif.Image.ExifTag 0x8769 IFD0 Long 1 350 Exif.Photo.ExposureTime 0x829a Exif Rational 1 10/2500 Exif.Photo.FNumber 0x829d Exif Rational 1 90/10 Exif.Photo.ExposureProgram 0x8822 Exif Short 1 2 @@ -1006,31 +1008,6 @@ Exif.Photo.MeteringMode 0x9207 Exif Short 1 Exif.Photo.LightSource 0x9208 Exif Short 1 0 Exif.Photo.Flash 0x9209 Exif Short 1 0 Exif.Photo.FocalLength 0x920a Exif Rational 1 500/10 -Exif.Photo.UserComment 0x9286 Exif Undefined 44 charset="Ascii" -Exif.Photo.SubSecTime 0x9290 Exif Ascii 3 00 -Exif.Photo.SubSecTimeOriginal 0x9291 Exif Ascii 3 00 -Exif.Photo.SubSecTimeDigitized 0x9292 Exif Ascii 3 00 -Exif.Photo.FlashpixVersion 0xa000 Exif Undefined 4 48 49 48 48 -Exif.Photo.ColorSpace 0xa001 Exif Short 1 65535 -Exif.Photo.PixelXDimension 0xa002 Exif Short 1 3008 -Exif.Photo.PixelYDimension 0xa003 Exif Short 1 2000 -Exif.Photo.InteroperabilityTag 0xa005 Exif Long 1 2413 -Exif.Photo.SensingMethod 0xa217 Exif Short 1 2 -Exif.Photo.FileSource 0xa300 Exif Undefined 1 3 -Exif.Photo.SceneType 0xa301 Exif Undefined 1 1 -Exif.Photo.CFAPattern 0xa302 Exif Undefined 8 0 2 0 2 2 1 1 0 -Exif.Photo.CustomRendered 0xa401 Exif Short 1 0 -Exif.Photo.ExposureMode 0xa402 Exif Short 1 0 -Exif.Photo.WhiteBalance 0xa403 Exif Short 1 0 -Exif.Photo.DigitalZoomRatio 0xa404 Exif Rational 1 1/1 -Exif.Photo.FocalLengthIn35mmFilm 0xa405 Exif Short 1 75 -Exif.Photo.SceneCaptureType 0xa406 Exif Short 1 0 -Exif.Photo.GainControl 0xa407 Exif Short 1 0 -Exif.Photo.Contrast 0xa408 Exif Short 1 0 -Exif.Photo.Saturation 0xa409 Exif Short 1 0 -Exif.Photo.Sharpness 0xa40a Exif Short 1 0 -Exif.Photo.SubjectDistanceRange 0xa40c Exif Short 1 0 -Exif.Photo.0xa500 0xa500 Exif Rational 1 22/10 Exif.Nikon3.Version 0x0001 Makernote Undefined 4 48 50 49 48 Exif.Nikon3.ISOSpeed 0x0002 Makernote Short 2 0 200 Exif.Nikon3.Quality 0x0004 Makernote Ascii 8 FINE @@ -1073,13 +1050,38 @@ Exif.Nikon3.0x00a8 0x00a8 Makernote Undefined 20 Exif.Nikon3.ImageOptimization 0x00a9 Makernote Ascii 16 NORMAL Exif.Nikon3.Saturation 0x00aa Makernote Ascii 16 NORMAL Exif.Nikon3.VariProgram 0x00ab Makernote Ascii 16 +Exif.Photo.UserComment 0x9286 Exif Undefined 44 charset="Ascii" +Exif.Photo.SubSecTime 0x9290 Exif Ascii 3 00 +Exif.Photo.SubSecTimeOriginal 0x9291 Exif Ascii 3 00 +Exif.Photo.SubSecTimeDigitized 0x9292 Exif Ascii 3 00 +Exif.Photo.FlashpixVersion 0xa000 Exif Undefined 4 48 49 48 48 +Exif.Photo.ColorSpace 0xa001 Exif Short 1 65535 +Exif.Photo.PixelXDimension 0xa002 Exif Short 1 3008 +Exif.Photo.PixelYDimension 0xa003 Exif Short 1 2000 +Exif.Photo.InteroperabilityTag 0xa005 Exif Long 1 2426 Exif.Iop.InteroperabilityIndex 0x0001 Iop Ascii 4 123 Exif.Iop.InteroperabilityVersion 0x0002 Iop Undefined 4 48 49 48 48 +Exif.Photo.SensingMethod 0xa217 Exif Short 1 2 +Exif.Photo.FileSource 0xa300 Exif Undefined 1 3 +Exif.Photo.SceneType 0xa301 Exif Undefined 1 1 +Exif.Photo.CFAPattern 0xa302 Exif Undefined 8 0 2 0 2 2 1 1 0 +Exif.Photo.CustomRendered 0xa401 Exif Short 1 0 +Exif.Photo.ExposureMode 0xa402 Exif Short 1 0 +Exif.Photo.WhiteBalance 0xa403 Exif Short 1 0 +Exif.Photo.DigitalZoomRatio 0xa404 Exif Rational 1 1/1 +Exif.Photo.FocalLengthIn35mmFilm 0xa405 Exif Short 1 75 +Exif.Photo.SceneCaptureType 0xa406 Exif Short 1 0 +Exif.Photo.GainControl 0xa407 Exif Short 1 0 +Exif.Photo.Contrast 0xa408 Exif Short 1 0 +Exif.Photo.Saturation 0xa409 Exif Short 1 0 +Exif.Photo.Sharpness 0xa40a Exif Short 1 0 +Exif.Photo.SubjectDistanceRange 0xa40c Exif Short 1 0 +Exif.Photo.0xa500 0xa500 Exif Rational 1 22/10 Exif.Thumbnail.Compression 0x0103 IFD1 Short 1 6 Exif.Thumbnail.Orientation 0x0112 IFD1 Short 1 2 Exif.Thumbnail.XResolution 0x011a IFD1 Rational 1 300/1 Exif.Thumbnail.YResolution 0x011b IFD1 Rational 1 300/1 Exif.Thumbnail.ResolutionUnit 0x0128 IFD1 Short 1 2 -Exif.Thumbnail.JPEGInterchangeFormat 0x0201 IFD1 Long 1 0 +Exif.Thumbnail.JPEGInterchangeFormat 0x0201 IFD1 Long 1 2574 Exif.Thumbnail.JPEGInterchangeFormatLength 0x0202 IFD1 Long 1 8930 Exif.Thumbnail.YCbCrPositioning 0x0213 IFD1 Short 1 2 diff --git a/test/data/mini9.tif b/test/data/mini9.tif new file mode 100644 index 0000000000000000000000000000000000000000..bea858749c8ea51dd35a6e77600bb6e92f0570ee GIT binary patch literal 526 zcmYk1v2MaJ5Qfi5K`^vZBDF=pz=#-{nTbjaZ3d*i0uq5lf+C?*9s6j!0TYkG##$x( zXCD_kw*2|O`+qxWI-!3es=dhvs#Ve2?Cl~^1|A*zCHa1rCCmJ0 lv&pu}uJ|sdZ)LHj`5{}D*=qD#l=2hcL1>wkSz+Nj{vbXkj)OHZvpX)CMK|YAd?}podwK(1mZAEJY^u@ s0i;2;!05?bj9MDZ44ji7mIMH$m=-`ZEeEohq3j+Yn}K0-65~W}0G9R^w*UYD delta 210 zcmaDW`B`#;cfFKrMP?cUgRd`x76StV2LmS~9|IGRr3=JWj8Y7&K$;PVS1?M$*&7%& z7?{E0K$VP!VD;QU{tiYXFk2MJKEh}XX0rp?x0+^v*&uTm+A|qgfE0-Rh=F0^DFXo@ s%L6I`rYCbTYUwdBPvV4H62QQ)fC;W?`2uD*y9cNZ1bQ~dFizwK01n_6Q2+n{ diff --git a/test/data/smiley2.jpg.c2gd b/test/data/smiley2.jpg.c2gd index b7955e909fc9941f42d6cba6cd48794efbc8a7ea..66c08f57d2897a97ba0d952588a66915c67e57a9 100644 GIT binary patch delta 204 zcmew?`Brj*cfE*fMP?cUgQuq!0|x^G11AF?BNKxzkW~f5QjDw&j6iw?5KBYZ8-Q#L zMrN=$6Oe5PRL>2hcL1>wkSz+Nj{vbXkj)OHZvpX)CMK|YAd?}podwK(1mZAEJY^u@ s0i;2;!05?bj9MDZ44ji7mIMH$m=-`ZEeEohq3j+Yn}K0-65~W}0G9R^w*UYD delta 210 zcmaDW`B`#;cfFKrMP?cUgRd`x76StV2LmS~9|IGRr3=JWj8Y7&K$;PVS1?M$*&7%& z7?{E0K$VP!VD;QU{tiYXFk2MJKEh}XX0rp?x0+^v*&uTm+A|qgfE0-Rh=F0^DFXo@ s%L6I`rYCbTYUwdBPvV4H62QQ)fC;W?`2uD*y9cNZ1bQ~dFizwK01n_6Q2+n{ diff --git a/test/data/tiff-test.out b/test/data/tiff-test.out new file mode 100644 index 00000000..98ac9a45 --- /dev/null +++ b/test/data/tiff-test.out @@ -0,0 +1,138 @@ +File Name = mini9.tif +File Type = TIFF:II +File Size = 526 +@000000000=0 : TIFF(II=0x4949) magic=0x002a='*\0' ifd offset = 0xfc/252 +@0x00000fc=252 : 17 entries starting at file offset 0xfe=254 +@0x00000fe=254 : <0x00fe= 254> NewSubFileType [4 =LONG 1] = 0 = 'primary' +@0x000010a=266 : <0x0100= 256> ImageWidth [3 =SHORT 1] = 9 +@0x0000116=278 : <0x0101= 257> ImageLength [3 =SHORT 1] = 9 +@0x0000122=290 : <0x0102= 258> BitsPerSample [3 =SHORT 3] = @0x1ce=462 +@0x000012e=302 : <0x0103= 259> Compression [3 =SHORT 1] = 1 = 'uncompressed' +@0x000013a=314 : <0x0106= 262> PhotometricInterpretation [3 =SHORT 1] = 2 = 'RGB' +@0x0000146=326 : <0x010d= 269> DocumentName [2 =ASCII 24] = @0x1d4=468 +@0x0000152=338 : <0x010e= 270> ImageDescription [2 =ASCII 18] = @0x1ec=492 +@0x000015e=350 : <0x0111= 273> StripOffsets [4 =LONG 1] = @8 +@0x000016a=362 : <0x0112= 274> Orientation [3 =SHORT 1] = 1 = '0,0 is top left' +@0x0000176=374 : <0x0115= 277> SamplesPerPixel [3 =SHORT 1] = 3 +@0x0000182=386 : <0x0116= 278> RowsPerStrip [3 =SHORT 1] = 64 +@0x000018e=398 : <0x0117= 279> StripByteCounts [4 =LONG 1] = 243 +@0x000019a=410 : <0x011a= 282> XResolution [5 =RATIONAL 1] = @0x1fe=510 +@0x00001a6=422 : <0x011b= 283> YResolution [5 =RATIONAL 1] = @0x206=518 +@0x00001b2=434 : <0x011c= 284> PlanarConfiguration [3 =SHORT 1] = 1 = 'chunky/contig' +@0x00001be=446 : <0x0128= 296> ResolutionUnit [3 =SHORT 1] = 2 = 'pixels per inch' +@0x00001ca=458 : **** next IFD offset 0 +@0x00001ce=462 : ============= VALUES, IFD 0 ============ +@0x00001ce=462 : BitsPerSample = 8,8,8 +@0x00001d4=468 : DocumentName = '/home/ahuggel/mini9.tif\0' +@0x00001ec=492 : ImageDescription = 'Created with GIMP\0' +@0x00001fe=510 : XResolution = 72 +@0x0000206=518 : YResolution = 72 +@0x000020d=525 : +@0x0000008=8 : <=-=-=> Start of TIFF RGB uncompressed image data for IFD 0, data length 243 + 0x0000008=8 : ff 00 00 ff 00 00 ff 00 00 ff 00 00 00 ff 00 00 |................| + 0x0000018=24 : 00 ff ff 00 00 ff 00 00 ff 00 00 00 ff 00 00 ff |................| + 0x0000028=40 : 00 00 ff 00 3f 7f bf 3f 7f bf 3f 7f bf 00 ff 00 |....?..?..?.....| + 0x0000038=56 : 00 ff 00 00 ff 00 00 00 ff 00 00 ff 3f 7f bf ff |............?...| etc... +@0x00000fa=250 : End of image data +-0x000020d=525 : END OF FILE +@0x0000008=8 : Start of TIFF RGB uncompressed primary image [9x9] length 243 (IFD 0) +-0x00000fa=250 : End of TIFF primary image data +Number of images = 1 +File Format = TIFFEP + + +Test 1: Writing empty Exif data without original binary data: ok. +Test 2: Writing empty Exif data with original binary data: ok. +Test 3: Wrote non-empty Exif data without original binary data: +Exif.Image.ExifTag 0x8769 Long 1 26 +Exif.Photo.DateTimeOriginal 0x9003 Ascii 18 Yesterday at noon +MIME type: image/tiff +Image size: 9 x 9 +Before +Exif.Image.NewSubfileType 0x00fe Long 1 0 +Exif.Image.ImageWidth 0x0100 Short 1 9 +Exif.Image.ImageLength 0x0101 Short 1 9 +Exif.Image.BitsPerSample 0x0102 Short 3 8 8 8 +Exif.Image.Compression 0x0103 Short 1 1 +Exif.Image.PhotometricInterpretation 0x0106 Short 1 2 +Exif.Image.DocumentName 0x010d Ascii 24 /home/ahuggel/mini9.tif +Exif.Image.ImageDescription 0x010e Ascii 18 Created with GIMP +Exif.Image.StripOffsets 0x0111 Long 1 8 +Exif.Image.Orientation 0x0112 Short 1 1 +Exif.Image.SamplesPerPixel 0x0115 Short 1 3 +Exif.Image.RowsPerStrip 0x0116 Short 1 64 +Exif.Image.StripByteCounts 0x0117 Long 1 243 +Exif.Image.XResolution 0x011a Rational 1 1207959552/16777216 +Exif.Image.YResolution 0x011b Rational 1 1207959552/16777216 +Exif.Image.PlanarConfiguration 0x011c Short 1 1 +Exif.Image.ResolutionUnit 0x0128 Short 1 2 +====== +After +Exif.Image.NewSubfileType 0x00fe Long 1 0 +Exif.Image.ImageWidth 0x0100 Short 1 9 +Exif.Image.ImageLength 0x0101 Short 1 9 +Exif.Image.BitsPerSample 0x0102 Short 3 8 8 8 +Exif.Image.Compression 0x0103 Short 1 1 +Exif.Image.PhotometricInterpretation 0x0106 Short 1 2 +Exif.Image.DocumentName 0x010d Ascii 24 /home/ahuggel/mini9.tif +Exif.Image.ImageDescription 0x010e Ascii 18 Created with GIMP +Exif.Image.StripOffsets 0x0111 Long 1 8 +Exif.Image.Orientation 0x0112 Short 1 1 +Exif.Image.SamplesPerPixel 0x0115 Short 1 3 +Exif.Image.RowsPerStrip 0x0116 Short 1 64 +Exif.Image.StripByteCounts 0x0117 Long 1 243 +Exif.Image.XResolution 0x011a Rational 1 1207959552/16777216 +Exif.Image.YResolution 0x011b Rational 1 1207959552/16777216 +Exif.Image.PlanarConfiguration 0x011c Short 1 1 +Exif.Image.ResolutionUnit 0x0128 Short 1 2 +Exif.Photo.DateTimeOriginal 0x9003 Ascii 18 Yesterday at noon +File Name = mini9.tif +File Type = TIFF:II +File Size = 573 +@000000000=0 : TIFF(II=0x4949) magic=0x002a='*\0' ifd offset = 0x8/8 +@0x0000008=8 : 18 entries starting at file offset 0xa=10 +@0x000000a=10 : <0x00fe= 254> NewSubFileType [4 =LONG 1] = 0 = 'primary' +@0x0000016=22 : <0x0100= 256> ImageWidth [3 =SHORT 1] = 9 +@0x0000022=34 : <0x0101= 257> ImageLength [3 =SHORT 1] = 9 +@0x000002e=46 : <0x0102= 258> BitsPerSample [3 =SHORT 3] = @0xe6=230 +@0x000003a=58 : <0x0103= 259> Compression [3 =SHORT 1] = 1 = 'uncompressed' +@0x0000046=70 : <0x0106= 262> PhotometricInterpretation [3 =SHORT 1] = 2 = 'RGB' +@0x0000052=82 : <0x010d= 269> DocumentName [2 =ASCII 24] = @0xec=236 +@0x000005e=94 : <0x010e= 270> ImageDescription [2 =ASCII 18] = @0x104=260 +@0x000006a=106 : <0x0111= 273> StripOffsets [4 =LONG 1] = @330 +@0x0000076=118 : <0x0112= 274> Orientation [3 =SHORT 1] = 1 = '0,0 is top left' +@0x0000082=130 : <0x0115= 277> SamplesPerPixel [3 =SHORT 1] = 3 +@0x000008e=142 : <0x0116= 278> RowsPerStrip [3 =SHORT 1] = 64 +@0x000009a=154 : <0x0117= 279> StripByteCounts [4 =LONG 1] = 243 +@0x00000a6=166 : <0x011a= 282> XResolution [5 =RATIONAL 1] = @0x116=278 +@0x00000b2=178 : <0x011b= 283> YResolution [5 =RATIONAL 1] = @0x11e=286 +@0x00000be=190 : <0x011c= 284> PlanarConfiguration [3 =SHORT 1] = 1 = 'chunky/contig' +@0x00000ca=202 : <0x0128= 296> ResolutionUnit [3 =SHORT 1] = 2 = 'pixels per inch' +@0x00000d6=214 : <0x8769=34665> ExifIFDPointer [4 =LONG 1] = @0x126=294 +@0x00000e2=226 : **** next IFD offset 0 +@0x00000e6=230 : ============= VALUES, IFD 0 ============ +@0x00000e6=230 : BitsPerSample = 8,8,8 +@0x00000ec=236 : DocumentName = '/home/ahuggel/mini9.tif\0' +@0x0000104=260 : ImageDescription = 'Created with GIMP\0' +@0x0000116=278 : XResolution = 72 +@0x000011e=286 : YResolution = 72 +@0x0000126=294 : (in IFD 0) 1 entries starting at file offset 0x128=296 +@0x0000128=296 : <0x9003=36867> DateTimeOriginal [2 =ASCII 18] = @0x138=312 +@0x0000134=308 : **** next IFD offset 0 +@0x0000138=312 : ============= VALUES, EXIF IFD ============ +@0x0000138=312 : DateTimeOriginal = 'Yesterday at noon\0' +-0x0000149=329 : +@0x0000149=329 : +@0x000014a=330 : <=-=-=> Start of TIFF RGB uncompressed image data for IFD 0, data length 243 + 0x000014a=330 : ff 00 00 ff 00 00 ff 00 00 ff 00 00 00 ff 00 00 |................| + 0x000015a=346 : 00 ff ff 00 00 ff 00 00 ff 00 00 00 ff 00 00 ff |................| + 0x000016a=362 : 00 00 ff 00 3f 7f bf 3f 7f bf 3f 7f bf 00 ff 00 |....?..?..?.....| + 0x000017a=378 : 00 ff 00 00 ff 00 00 00 ff 00 00 ff 3f 7f bf ff |............?...| etc... +@0x000023c=572 : End of image data +-0x000023c=572 : END OF FILE +@0x000014a=330 : Start of TIFF RGB uncompressed primary image [9x9] length 243 (IFD 0) +-0x000023c=572 : End of TIFF primary image data +Number of images = 1 +File Format = TIFFEP/EXIF + + diff --git a/test/data/write2-test.out b/test/data/write2-test.out index 307843ca..2ea0d74f 100644 --- a/test/data/write2-test.out +++ b/test/data/write2-test.out @@ -13,7 +13,6 @@ Exif.Photo.DateTimeOriginal 0x9003 Exif Ascii 7 Exif.Image.Make 0x010f IFD0 Ascii 6 Canon Exif.Image.Model 0x0110 IFD0 Ascii 20 Canon PowerShot S40 Exif.Image.ExifTag 0x8769 IFD0 Long 1 76 -Exif.Canon.0xabcd 0xabcd Makernote Ascii 22 A Canon makernote tag Exif.CanonCs.Macro 0x0001 Makernote Short 1 0 Exif.CanonCs.Selftimer 0x0002 Makernote Short 1 41 Exif.CanonSi.0x0001 0x0001 Makernote Short 1 0 @@ -24,12 +23,12 @@ Exif.CanonSi.TargetShutterSpeed 0x0005 Makernote Short 1 Exif.CanonPa.0x0001 0x0001 Makernote Short 1 45 Exif.CanonCf.NoiseReduction 0x0001 Makernote Short 1 43 Exif.CanonPi.0x0001 0x0001 Makernote Short 1 44 +Exif.Canon.0xabcd 0xabcd Makernote Ascii 22 A Canon makernote tag ----- Non-intrusive writing of special Canon MakerNote tags Exif.Image.Make 0x010f IFD0 Ascii 6 Canon Exif.Image.Model 0x0110 IFD0 Ascii 20 Canon PowerShot S40 Exif.Image.ExifTag 0x8769 IFD0 Long 1 76 -Exif.Canon.0xabcd 0xabcd Makernote Ascii 22 A Canon makernote tag Exif.CanonCs.Macro 0x0001 Makernote Short 1 88 Exif.CanonCs.Selftimer 0x0002 Makernote Short 1 41 Exif.CanonSi.0x0001 0x0001 Makernote Short 1 0 @@ -40,6 +39,7 @@ Exif.CanonSi.TargetShutterSpeed 0x0005 Makernote Short 1 Exif.CanonPa.0x0001 0x0001 Makernote Short 1 45 Exif.CanonCf.NoiseReduction 0x0001 Makernote Short 1 43 Exif.CanonPi.0x0001 0x0001 Makernote Short 1 44 +Exif.Canon.0xabcd 0xabcd Makernote Ascii 22 A Canon makernote tag ----- One Fujifilm MakerNote tag Exif.Image.Make 0x010f IFD0 Ascii 9 FUJIFILM diff --git a/test/ifd-test.sh b/test/ifd-test.sh deleted file mode 100755 index 1e1fac34..00000000 --- a/test/ifd-test.sh +++ /dev/null @@ -1,24 +0,0 @@ -#! /bin/sh -# Test driver for Ifd unit tests -results="./tmp/ifd-test.out" -good="./data/ifd-test.out" -diffargs="--strip-trailing-cr" -tmpfile=tmp/ttt -touch $tmpfile -diff -q $diffargs $tmpfile $tmpfile 2>/dev/null -if [ $? -ne 0 ] ; then - diffargs="" -fi -( -binpath=" $VALGRIND ../../samples" -cd ./tmp -$binpath/ifd-test -) > $results 2>&1 - -diff -q $diffargs $results $good -rc=$? -if [ $rc -eq 0 ] ; then - echo "All testcases passed." -else - diff $diffargs $results $good -fi diff --git a/test/makernote-test.sh b/test/makernote-test.sh deleted file mode 100755 index 163a4b84..00000000 --- a/test/makernote-test.sh +++ /dev/null @@ -1,24 +0,0 @@ -#! /bin/sh -# Test driver for tests of MakerNoteFactory::match -results="./tmp/makernote-test.out" -good="./data/makernote-test.out" -diffargs="--strip-trailing-cr" -tmpfile=tmp/ttt -touch $tmpfile -diff -q $diffargs $tmpfile $tmpfile 2>/dev/null -if [ $? -ne 0 ] ; then - diffargs="" -fi -( -binpath="$VALGRIND ../../samples" -cd ./tmp -$binpath/makernote-test -) > $results - -diff -q $diffargs $results $good -rc=$? -if [ $rc -eq 0 ] ; then - echo "All testcases passed." -else - diff $diffargs $results $good -fi diff --git a/test/tiff-test.sh b/test/tiff-test.sh new file mode 100644 index 00000000..037fe79f --- /dev/null +++ b/test/tiff-test.sh @@ -0,0 +1,35 @@ +#! /bin/sh +# TIFF parser test driver + +# ---------------------------------------------------------------------- +# Setup +results="./tmp/tiff-test.out" +good="./data/tiff-test.out" + +# ---------------------------------------------------------------------- +# Main routine +( +binpath="$VALGRIND ../../samples" +exiv2="$VALGRIND ../../src/exiv2" +cd ./tmp + +# ---------------------------------------------------------------------- +# Basic write test +testfile=mini9.tif +cp -f ../data/$testfile . +exifprobe $testfile +$binpath/tiff-test $testfile +exifprobe $testfile + +) > $results + +# ---------------------------------------------------------------------- +# Evaluate results +cat $results | tr -d '\r' > $results-stripped +diff -q $results-stripped $good +rc=$? +if [ $rc -eq 0 ] ; then + echo "All testcases passed." +else + diff $results-stripped $good +fi