Merged unstable branch to trunk.
parent
b47b8085db
commit
0d55992e2f
@ -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 <exiv2/ifd.hpp>
|
||||
#include <exiv2/error.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
|
||||
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;
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
#include <exiv2/makernote.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
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";
|
||||
}
|
||||
}
|
@ -0,0 +1,108 @@
|
||||
// ***************************************************************** -*- C++ -*-
|
||||
// tiff-test.cpp, $Rev$
|
||||
// First and very simple TIFF write test.
|
||||
|
||||
#include <exiv2/tiffimage.hpp>
|
||||
#include <exiv2/exif.hpp>
|
||||
#include <exiv2/error.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <cassert>
|
||||
|
||||
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";
|
||||
}
|
||||
}
|
@ -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 <iostream>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
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;
|
||||
}
|
@ -0,0 +1,122 @@
|
||||
// ***************************************************************** -*- C++ -*-
|
||||
/*
|
||||
* Copyright (C) 2004-2008 Andreas Huggel <ahuggel@gmx.net>
|
||||
*
|
||||
* 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)
|
||||
<a href="mailto:ahuggel@gmx.net">ahuggel@gmx.net</a>
|
||||
@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 <string>
|
||||
|
||||
// *****************************************************************************
|
||||
// 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_[]; //<! CR2 mapping table
|
||||
|
||||
}; // class Cr2Mapping
|
||||
|
||||
/*!
|
||||
@brief Canon CR2 header structure.
|
||||
*/
|
||||
class Cr2Header : public TiffHeaderBase {
|
||||
public:
|
||||
//! @name Creators
|
||||
//@{
|
||||
//! Default constructor
|
||||
Cr2Header();
|
||||
//! Destructor.
|
||||
~Cr2Header();
|
||||
//@}
|
||||
|
||||
//! @name Manipulators
|
||||
//@{
|
||||
bool read(const byte* pData, uint32_t size);
|
||||
//@}
|
||||
|
||||
//! @name Accessors
|
||||
//@{
|
||||
uint32_t write(Blob& blob) const;
|
||||
//@}
|
||||
|
||||
private:
|
||||
// DATA
|
||||
uint32_t offset2_; //!< Bytes 12-15 from the header
|
||||
static const char* cr2sig_; //!< Signature for CR2 type TIFF
|
||||
}; // class Cr2Header
|
||||
|
||||
}} // namespace Internal, Exiv2
|
||||
|
||||
#endif // #ifndef CR2IMAGE_INT_HPP_
|
File diff suppressed because it is too large
Load Diff
@ -1,788 +0,0 @@
|
||||
// ***************************************************************** -*- C++ -*-
|
||||
/*
|
||||
* Copyright (C) 2004-2008 Andreas Huggel <ahuggel@gmx.net>
|
||||
*
|
||||
* 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) <ahuggel@gmx.net>
|
||||
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 <iostream>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <cassert>
|
||||
|
||||
// *****************************************************************************
|
||||
// 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<byte*>(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<byte*>(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<uint16_t>(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<int32_t>(offset) > 0xffff) throw Error(26);
|
||||
s2Data(buf, d + static_cast<int16_t>(offset), byteOrder);
|
||||
break;
|
||||
}
|
||||
case signedLong: {
|
||||
if (i == 0) flOffset = getLong(buf, byteOrder);
|
||||
int32_t d = getLong(buf, byteOrder) - flOffset;
|
||||
l2Data(buf, d + static_cast<int32_t>(offset), byteOrder);
|
||||
break;
|
||||
}
|
||||
case signedRational: {
|
||||
Rational d = getRational(buf, byteOrder);
|
||||
d.first = d.first + static_cast<int32_t>(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<byte*>(buf + o);
|
||||
}
|
||||
next_ = getULong(buf + o, byteOrder);
|
||||
if ( static_cast<long>(next_) + shift < 0
|
||||
|| static_cast<long>(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<int>(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<byte*>(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<uint16_t>(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<long>(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<unsigned int>(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<int32_t>(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<int>(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<int>(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
|
@ -1,616 +0,0 @@
|
||||
// ***************************************************************** -*- C++ -*-
|
||||
/*
|
||||
* Copyright (C) 2004-2008 Andreas Huggel <ahuggel@gmx.net>
|
||||
*
|
||||
* 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)
|
||||
<a href="mailto:ahuggel@gmx.net">ahuggel@gmx.net</a>
|
||||
@date 09-Jan-04, ahu: created<BR>
|
||||
11-Feb-04, ahu: isolated as a component
|
||||
*/
|
||||
#ifndef IFD_HPP_
|
||||
#define IFD_HPP_
|
||||
|
||||
// *****************************************************************************
|
||||
// included header files
|
||||
#include "types.hpp"
|
||||
|
||||
// + standard includes
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <iosfwd>
|
||||
|
||||
// *****************************************************************************
|
||||
// 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).
|
||||
<BR>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.
|
||||
<BR>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.
|
||||
<BR>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,<BR>
|
||||
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<Entry> 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.
|
||||
<BR>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.
|
||||
<BR> 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;<BR>
|
||||
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;<BR>
|
||||
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<long>(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<PreEntry> 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_
|
@ -1,459 +0,0 @@
|
||||
// ***************************************************************** -*- C++ -*-
|
||||
/*
|
||||
* Copyright (C) 2004-2008 Andreas Huggel <ahuggel@gmx.net>
|
||||
*
|
||||
* 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) <ahuggel@gmx.net>
|
||||
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 <string>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
// *****************************************************************************
|
||||
// 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<int>(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<int>(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
|
@ -1,519 +0,0 @@
|
||||
// ***************************************************************** -*- C++ -*-
|
||||
/*
|
||||
* Copyright (C) 2004-2008 Andreas Huggel <ahuggel@gmx.net>
|
||||
*
|
||||
* 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)
|
||||
<a href="mailto:ahuggel@gmx.net">ahuggel@gmx.net</a>
|
||||
@date 18-Feb-04, ahu: created
|
||||
*/
|
||||
#ifndef MAKERNOTE_HPP_
|
||||
#define MAKERNOTE_HPP_
|
||||
|
||||
// *****************************************************************************
|
||||
// included header files
|
||||
#include "types.hpp"
|
||||
#include "ifd.hpp"
|
||||
|
||||
// + standard includes
|
||||
#include <string>
|
||||
#include <iosfwd>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
// *****************************************************************************
|
||||
// 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. <BR>
|
||||
|
||||
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<MakerNote> 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 <B>not</B>
|
||||
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: <BR>
|
||||
True: requires memory allocation and deallocation, <BR>
|
||||
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<IfdMakerNote> 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:<BR>
|
||||
0: key and registry entry do not match<BR>
|
||||
1: a pure wildcard match, i.e., the registry entry is just
|
||||
a wildcard.<BR>
|
||||
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<std::pair<std::string, CreateFct> > ModelRegistry;
|
||||
//! Type used to store a list of make labels and model registries
|
||||
typedef std::vector<std::pair<std::string, ModelRegistry*> > Registry;
|
||||
//! Type used to store a list of IFD ids and %MakerNote prototypes
|
||||
typedef std::map<IfdId, MakerNote*> 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_
|
@ -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 <cassert>
|
||||
|
||||
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;
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
// ***************************************************************** -*- C++ -*-
|
||||
/*
|
||||
* Copyright (C) 2004-2008 Andreas Huggel <ahuggel@gmx.net>
|
||||
*
|
||||
* 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
|
||||
<a href="mailto:costlow@gmail.com">costlow@gmail.com</a>
|
||||
@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_
|
@ -0,0 +1,76 @@
|
||||
// ***************************************************************** -*- C++ -*-
|
||||
// tiff-test.cpp, $Rev$
|
||||
// TIFF writer tests.
|
||||
|
||||
#include "tiffimage.hpp"
|
||||
#include "exif.hpp"
|
||||
#include "error.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
|
||||
/*
|
||||
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";
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,641 +0,0 @@
|
||||
// ***************************************************************** -*- C++ -*-
|
||||
/*
|
||||
* Copyright (C) 2004-2008 Andreas Huggel <ahuggel@gmx.net>
|
||||
*
|
||||
* 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)
|
||||
<a href="mailto:ahuggel@gmx.net">ahuggel@gmx.net</a>
|
||||
@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 <iosfwd>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
|
||||
// *****************************************************************************
|
||||
// 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<TiffComponent> AutoPtr;
|
||||
//! Container type to hold all metadata
|
||||
typedef std::vector<TiffComponent*> 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<byte*>(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<uint16_t>(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<uint16_t>(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<TiffDirectory*> 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<uint16_t elSize>
|
||||
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<TypeId typeId, ByteOrder byteOrder>
|
||||
TiffComponent::AutoPtr newTiffArrayElement(uint16_t tag,
|
||||
const TiffStructure* ts)
|
||||
{
|
||||
assert(ts);
|
||||
return TiffComponent::AutoPtr(
|
||||
new TiffArrayElement(tag, ts->group_, typeId, byteOrder));
|
||||
}
|
||||
|
||||
template<TypeId typeId>
|
||||
TiffComponent::AutoPtr newTiffArrayElement(uint16_t tag,
|
||||
const TiffStructure* ts)
|
||||
{
|
||||
return newTiffArrayElement<typeId, invalidByteOrder>(tag, ts);
|
||||
}
|
||||
|
||||
//! Function to create and initialize a new TIFF entry for a thumbnail (data)
|
||||
template<uint16_t szTag, uint16_t szGroup>
|
||||
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<uint16_t dtTag, uint16_t dtGroup>
|
||||
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_
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,287 @@
|
||||
// ***************************************************************** -*- C++ -*-
|
||||
/*
|
||||
* Copyright (C) 2004-2008 Andreas Huggel <ahuggel@gmx.net>
|
||||
*
|
||||
* 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)
|
||||
<a href="mailto:ahuggel@gmx.net">ahuggel@gmx.net</a>
|
||||
@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 <b>libexiv2</b> 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<TiffComponent> 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_[]; //<! TIFF structure
|
||||
}; // class TiffCreator
|
||||
|
||||
/*!
|
||||
@brief Stateless parser class for data in TIFF format. Images use this
|
||||
class to decode and encode TIFF-based data.
|
||||
*/
|
||||
class TiffParserWorker {
|
||||
public:
|
||||
/*!
|
||||
@brief Decode TIFF metadata from a data buffer \em pData of length
|
||||
\em size into the provided metadata containers.
|
||||
|
||||
This is the entry point to access image data in TIFF format. The
|
||||
parser uses classes TiffHeade2 and the TiffComponent and TiffVisitor
|
||||
hierarchies.
|
||||
|
||||
@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.
|
||||
@param createFct Factory function to create new TIFF components.
|
||||
@param findDecoderFct Function to access special decoding info.
|
||||
@param pHeader Optional pointer to a TIFF header. If not provided,
|
||||
a standard TIFF header is used.
|
||||
|
||||
@return Byte order in which the data is encoded, invalidByteOrder if
|
||||
decoding failed.
|
||||
*/
|
||||
static ByteOrder decode(
|
||||
ExifData& exifData,
|
||||
IptcData& iptcData,
|
||||
XmpData& xmpData,
|
||||
const byte* pData,
|
||||
uint32_t size,
|
||||
TiffCompFactoryFct createFct,
|
||||
FindDecoderFct findDecoderFct,
|
||||
TiffHeaderBase* pHeader =0);
|
||||
/*!
|
||||
@brief Encode TIFF metadata from the metadata containers into a
|
||||
memory block \em blob.
|
||||
*/
|
||||
static WriteMethod encode(
|
||||
Blob& blob,
|
||||
const byte* pData,
|
||||
uint32_t size,
|
||||
const ExifData& exifData,
|
||||
const IptcData& iptcData,
|
||||
const XmpData& xmpData,
|
||||
TiffCompFactoryFct createFct,
|
||||
FindEncoderFct findEncoderFct,
|
||||
TiffHeaderBase* pHeader
|
||||
);
|
||||
|
||||
private:
|
||||
/*!
|
||||
@brief Parse TIFF metadata from a data buffer \em pData of length
|
||||
\em size into a TIFF composite structure.
|
||||
|
||||
@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 An auto pointer with the root element of the TIFF
|
||||
composite structure. If \em pData is 0 or \em size
|
||||
is 0, the return value is a 0 pointer.
|
||||
*/
|
||||
static std::auto_ptr<TiffComponent>
|
||||
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_[]; //<! TIFF mapping table
|
||||
|
||||
}; // class TiffMapping
|
||||
|
||||
}} // namespace Internal, Exiv2
|
||||
|
||||
#endif // #ifndef TIFFIMAGE_INT_HPP_
|
@ -0,0 +1,212 @@
|
||||
// ***************************************************************** -*- C++ -*-
|
||||
// tiffmn-test.cpp, $Rev$
|
||||
// Makernote TIFF writer tests.
|
||||
|
||||
#include "tiffimage.hpp"
|
||||
#include "exif.hpp"
|
||||
#include "error.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
|
||||
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";
|
||||
}
|
||||
}
|
@ -1,214 +0,0 @@
|
||||
// ***************************************************************** -*- C++ -*-
|
||||
/*
|
||||
* Copyright (C) 2004-2008 Andreas Huggel <ahuggel@gmx.net>
|
||||
*
|
||||
* 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) <ahuggel@gmx.net>
|
||||
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 <cassert>
|
||||
#include <memory>
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
|
||||
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<unsignedShort>, Group::canoncs },
|
||||
{ Tag::all, Group::canonsi, newTiffArrayElement<unsignedShort>, Group::canonsi },
|
||||
{ Tag::all, Group::canonpa, newTiffArrayElement<unsignedShort>, Group::canonpa },
|
||||
{ Tag::all, Group::canoncf, newTiffArrayElement<unsignedShort>, Group::canoncf },
|
||||
{ Tag::all, Group::canonpi, newTiffArrayElement<unsignedShort>, 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<unsignedLong, bigEndian>, Group::minocso },
|
||||
{ Tag::all, Group::minocsn, newTiffArrayElement<unsignedLong, bigEndian>, Group::minocsn },
|
||||
{ Tag::all, Group::minocs7, newTiffArrayElement<unsignedShort, bigEndian>, Group::minocs7 },
|
||||
{ Tag::all, Group::minocs5, newTiffArrayElement<unsignedShort, bigEndian>, 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<uint16_t>(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<TiffHeaderBase> ph;
|
||||
if (!pHeader) {
|
||||
ph = std::auto_ptr<TiffHeaderBase>(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
|
@ -1,132 +0,0 @@
|
||||
// ***************************************************************** -*- C++ -*-
|
||||
/*
|
||||
* Copyright (C) 2004-2008 Andreas Huggel <ahuggel@gmx.net>
|
||||
*
|
||||
* 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)
|
||||
<a href="mailto:ahuggel@gmx.net">ahuggel@gmx.net</a>
|
||||
@date 15-Mar-06, ahu: created
|
||||
*/
|
||||
#ifndef TIFFPARSER_HPP_
|
||||
#define TIFFPARSER_HPP_
|
||||
|
||||
// *****************************************************************************
|
||||
// included header files
|
||||
#include "tifffwd.hpp"
|
||||
#include "types.hpp"
|
||||
|
||||
// + standard includes
|
||||
#include <iosfwd>
|
||||
#include <cassert>
|
||||
|
||||
// *****************************************************************************
|
||||
// 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<TiffComponent> create(uint32_t extendedTag,
|
||||
uint16_t group);
|
||||
|
||||
private:
|
||||
static const TiffStructure tiffStructure_[]; //<! TIFF structure
|
||||
}; // class TiffCreator
|
||||
|
||||
/*!
|
||||
@brief Stateless parser class for data in TIFF format. Images use this
|
||||
class to decode and encode TIFF-based data. Uses class
|
||||
CreationPolicy for the creation of TIFF components.
|
||||
*/
|
||||
class TiffParser {
|
||||
public:
|
||||
/*!
|
||||
@brief Decode TIFF metadata from a data buffer \em pData of length
|
||||
\em size into \em pImage.
|
||||
|
||||
This is the entry point to access image data in TIFF format. The
|
||||
parser uses classes TiffHeade2 and the TiffComponent and TiffVisitor
|
||||
hierarchies.
|
||||
|
||||
@param pImage Pointer to the image to hold the metadata
|
||||
@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.
|
||||
@param createFct Factory function to create new TIFF components.
|
||||
@param findDecoderFct Function to access special decoding info.
|
||||
@param pHeader Optional pointer to a TIFF header. If not provided,
|
||||
a standard TIFF header is used.
|
||||
*/
|
||||
static void decode( Image* pImage,
|
||||
const byte* pData,
|
||||
uint32_t size,
|
||||
TiffCompFactoryFct createFct,
|
||||
FindDecoderFct findDecoderFct,
|
||||
TiffHeaderBase* pHeader =0);
|
||||
}; // class TiffParser
|
||||
|
||||
/*!
|
||||
@brief Table of TIFF decoding functions and find function.
|
||||
This class is separated from the metadata decoder visitor 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 TiffDecoder {
|
||||
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 tiffDecoderInfo_[]; //<! TIFF decoder table
|
||||
|
||||
}; // class TiffDecoder
|
||||
|
||||
} // namespace Exiv2
|
||||
|
||||
#endif // #ifndef TIFFPARSER_HPP_
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,35 @@
|
||||
// ***************************************************************** -*- C++ -*-
|
||||
// xmpdump.cpp, $Rev$
|
||||
// Sample program to dump the XMP packet of an image
|
||||
|
||||
#include "image.hpp"
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <cassert>
|
||||
|
||||
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;
|
||||
}
|