Values implemented
This commit is contained in:
parent
bb6380825d
commit
440571b544
252
src/exif.cpp
252
src/exif.cpp
@ -12,7 +12,7 @@
|
||||
|
||||
RCS information
|
||||
$Name: $
|
||||
$Revision: 1.3 $
|
||||
$Revision: 1.4 $
|
||||
*/
|
||||
// *****************************************************************************
|
||||
// included header files
|
||||
@ -24,6 +24,7 @@
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
#include <utility>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
@ -101,15 +102,15 @@ namespace Exif {
|
||||
if (getUShort(marker, bigEndian) != app1_) return 3;
|
||||
|
||||
// Read the length of the APP1 field and the Exif identifier
|
||||
char buf[8];
|
||||
::memset(buf, 0x0, 8);
|
||||
is.read(buf, 8);
|
||||
char tmpbuf[8];
|
||||
::memset(tmpbuf, 0x0, 8);
|
||||
is.read(tmpbuf, 8);
|
||||
if (!is.good()) return 1;
|
||||
// Get the length of the APP1 field and do a plausibility check
|
||||
long app1Length = getUShort(buf, bigEndian);
|
||||
long app1Length = getUShort(tmpbuf, bigEndian);
|
||||
if (app1Length < 8) return 4;
|
||||
// Check the Exif identifier
|
||||
if (::memcmp(buf+2, exifId_, 6) != 0) return 4;
|
||||
if (::memcmp(tmpbuf+2, exifId_, 6) != 0) return 4;
|
||||
|
||||
// Read the rest of the APP1 field (Exif data)
|
||||
long sizeExifData = app1Length - 8;
|
||||
@ -166,38 +167,87 @@ namespace Exif {
|
||||
return size();
|
||||
}
|
||||
|
||||
Value* Value::create(TypeId typeId, ByteOrder byteOrder)
|
||||
Value* Value::create(TypeId typeId)
|
||||
{
|
||||
Value* value = 0;
|
||||
switch (typeId) {
|
||||
case invalid:
|
||||
value = new DataValue(invalid);
|
||||
break;
|
||||
case unsignedByte:
|
||||
value = new AsciiValue;
|
||||
value = new DataValue(unsignedByte);
|
||||
break;
|
||||
case asciiString:
|
||||
value = new AsciiValue;
|
||||
break;
|
||||
case unsignedShort:
|
||||
value = new UShortValue(byteOrder);
|
||||
value = new ValueType<uint16>;
|
||||
break;
|
||||
case unsignedLong:
|
||||
value = new ValueType<uint32>;
|
||||
break;
|
||||
case unsignedRational:
|
||||
case signedByte:
|
||||
value = new ValueType<URational>;
|
||||
break;
|
||||
case invalid6:
|
||||
value = new DataValue(invalid6);
|
||||
break;
|
||||
case undefined:
|
||||
value = new DataValue;
|
||||
break;
|
||||
case signedShort:
|
||||
value = new ValueType<int16>;
|
||||
break;
|
||||
case signedLong:
|
||||
value = new ValueType<int32>;
|
||||
break;
|
||||
case signedRational:
|
||||
case singleFloat:
|
||||
case doubleFloat:
|
||||
value = new AsciiValue;
|
||||
value = new ValueType<Rational>;
|
||||
break;
|
||||
}
|
||||
return value;
|
||||
} // Value::create
|
||||
|
||||
void AsciiValue::read(const char* buf, long len)
|
||||
void DataValue::read(const char* buf, long len, ByteOrder byteOrder)
|
||||
{
|
||||
// byteOrder not needed
|
||||
value_ = std::string(buf, len);
|
||||
}
|
||||
|
||||
void DataValue::read(const std::string& buf)
|
||||
{
|
||||
// Todo: read from a string of bytes??
|
||||
value_ = buf;
|
||||
}
|
||||
|
||||
long DataValue::copy(char* buf, ByteOrder byteOrder) const
|
||||
{
|
||||
// byteOrder not needed
|
||||
return value_.copy(buf, value_.size());
|
||||
}
|
||||
|
||||
long DataValue::size() const
|
||||
{
|
||||
return value_.size();
|
||||
}
|
||||
|
||||
Value* DataValue::clone() const
|
||||
{
|
||||
return new DataValue(*this);
|
||||
}
|
||||
|
||||
std::ostream& DataValue::write(std::ostream& os) const
|
||||
{
|
||||
std::string::size_type end = value_.size();
|
||||
for (std::string::size_type i = 0; i != end; ++i) {
|
||||
os << (int)(unsigned char)value_[i] << " ";
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
void AsciiValue::read(const char* buf, long len, ByteOrder byteOrder)
|
||||
{
|
||||
// byteOrder not needed
|
||||
value_ = std::string(buf, len);
|
||||
}
|
||||
|
||||
@ -206,8 +256,9 @@ namespace Exif {
|
||||
value_ = buf;
|
||||
}
|
||||
|
||||
long AsciiValue::copy(char* buf) const
|
||||
long AsciiValue::copy(char* buf, ByteOrder byteOrder) const
|
||||
{
|
||||
// byteOrder not needed
|
||||
return value_.copy(buf, value_.size());
|
||||
}
|
||||
|
||||
@ -226,39 +277,6 @@ namespace Exif {
|
||||
return os << value_;
|
||||
}
|
||||
|
||||
void UShortValue::read(const char* buf, long len)
|
||||
{
|
||||
// Todo: Should we check to make sure that len is 2
|
||||
value_ = getUShort(buf, byteOrder_);
|
||||
}
|
||||
|
||||
void UShortValue::read(const std::string& buf)
|
||||
{
|
||||
std::istringstream is(buf);
|
||||
is >> value_;
|
||||
}
|
||||
|
||||
long UShortValue::copy(char* buf) const
|
||||
{
|
||||
us2Data(buf, value_, byteOrder_);
|
||||
return size();
|
||||
}
|
||||
|
||||
long UShortValue::size() const
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
Value* UShortValue::clone() const
|
||||
{
|
||||
return new UShortValue(*this);
|
||||
}
|
||||
|
||||
std::ostream& UShortValue::write(std::ostream& os) const
|
||||
{
|
||||
return os << value_;
|
||||
}
|
||||
|
||||
Metadatum::Metadatum()
|
||||
: tag_(0), type_(0), count_(0), offset_(0), size_(0),
|
||||
ifdId_(IfdIdNotSet), ifdIdx_(-1), value_(0)
|
||||
@ -287,6 +305,8 @@ namespace Exif {
|
||||
|
||||
Metadatum& Metadatum::operator=(const Metadatum& rhs)
|
||||
{
|
||||
if (this == &rhs) return *this;
|
||||
|
||||
tag_ = rhs.tag_;
|
||||
type_ = rhs.type_;
|
||||
count_ = rhs.count_;
|
||||
@ -361,15 +381,15 @@ namespace Exif {
|
||||
for (i = eb; i != ee; ++i) {
|
||||
delete i->value_;
|
||||
//! Todo: Create the correct type here, once we have them
|
||||
i->value_ = Value::create(TypeId(i->type_), byteOrder);
|
||||
i->value_ = Value::create(TypeId(i->type_));
|
||||
if (i->size_ > 4) {
|
||||
i->offset_ = i->offset_ - offset_;
|
||||
i->value_->read(buf + i->offset_, i->size_);
|
||||
i->value_->read(buf + i->offset_, i->size_, byteOrder);
|
||||
}
|
||||
else {
|
||||
char value[4];
|
||||
ul2Data(value, i->offset_, byteOrder);
|
||||
i->value_->read(value, 4);
|
||||
char tmpbuf[4];
|
||||
ul2Data(tmpbuf, i->offset_, byteOrder);
|
||||
i->value_->read(tmpbuf, i->size_, byteOrder);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@ -411,7 +431,10 @@ namespace Exif {
|
||||
dataSize += i->size_;
|
||||
}
|
||||
else {
|
||||
ul2Data(buf+o+8, i->offset_, byteOrder);
|
||||
char tmpbuf[4];
|
||||
::memset(tmpbuf, 0x0, 4);
|
||||
i->value_->copy(tmpbuf, byteOrder);
|
||||
::memcpy(buf+o+8, tmpbuf, 4);
|
||||
}
|
||||
o += 12;
|
||||
}
|
||||
@ -432,7 +455,7 @@ namespace Exif {
|
||||
// Todo: Check this! There seems to be an inconsistency
|
||||
// in the use of size_ and the return value of copy() here
|
||||
// Todo: And can value_ be 0?
|
||||
o += i->value_->copy(buf+o);
|
||||
o += i->value_->copy(buf+o, byteOrder);
|
||||
}
|
||||
}
|
||||
|
||||
@ -449,7 +472,7 @@ namespace Exif {
|
||||
<< ", IFD Entries: "
|
||||
<< std::setfill(' ') << std::dec << std::right
|
||||
<< entries_.size() << "\n"
|
||||
<< prefix << "Entry Tag Format (Bytes each) Number Offset/Data\n"
|
||||
<< prefix << "Entry Tag Format (Bytes each) Number Offset\n"
|
||||
<< prefix << "----- ------ --------------------- ------ -----------\n";
|
||||
|
||||
const Metadata::const_iterator b = entries_.begin();
|
||||
@ -458,19 +481,22 @@ namespace Exif {
|
||||
for (; i != e; ++i) {
|
||||
std::ostringstream offset;
|
||||
if (i->typeSize() * i->count_ <= 4) {
|
||||
// Minor cheat here: we use value_ instead of offset_ to avoid
|
||||
// having to invoke ul2Data() which would require byte order.
|
||||
// Todo: can value_ be 0 here?
|
||||
char tmpbuf[4];
|
||||
i->value_->copy(tmpbuf);
|
||||
offset << std::setw(2) << std::setfill('0') << std::hex
|
||||
<< (int)*(unsigned char*)tmpbuf << " "
|
||||
<< std::setw(2) << std::setfill('0') << std::hex
|
||||
<< (int)*(unsigned char*)(tmpbuf+1) << " "
|
||||
<< std::setw(2) << std::setfill('0') << std::hex
|
||||
<< (int)*(unsigned char*)(tmpbuf+2) << " "
|
||||
<< std::setw(2) << std::setfill('0') << std::hex
|
||||
<< (int)*(unsigned char*)(tmpbuf+3) << " ";
|
||||
|
||||
// Todo: Fix me! This doesn't work with Value anymore because we do not know
|
||||
// the byte order here. (Wait for Ifd to use a more special type)
|
||||
//
|
||||
// char tmpbuf[4];
|
||||
// i->value_->copy(tmpbuf, byteOrder);
|
||||
// offset << std::setw(2) << std::setfill('0') << std::hex
|
||||
// << (int)*(unsigned char*)tmpbuf << " "
|
||||
// << std::setw(2) << std::setfill('0') << std::hex
|
||||
// << (int)*(unsigned char*)(tmpbuf+1) << " "
|
||||
// << std::setw(2) << std::setfill('0') << std::hex
|
||||
// << (int)*(unsigned char*)(tmpbuf+2) << " "
|
||||
// << std::setw(2) << std::setfill('0') << std::hex
|
||||
// << (int)*(unsigned char*)(tmpbuf+3) << " ";
|
||||
|
||||
offset << "n/a";
|
||||
}
|
||||
else {
|
||||
offset << " 0x" << std::setw(8) << std::setfill('0') << std::hex
|
||||
@ -622,13 +648,43 @@ namespace Exif {
|
||||
}
|
||||
}
|
||||
|
||||
std::string getString(const char* buf, long len)
|
||||
URational getURational(const char* buf, ByteOrder byteOrder)
|
||||
{
|
||||
std::string txt(buf, len);
|
||||
return txt;
|
||||
uint32 nominator = getULong(buf, byteOrder);
|
||||
uint32 denominator = getULong(buf + 4, byteOrder);
|
||||
return std::make_pair(nominator, denominator);
|
||||
}
|
||||
|
||||
char* us2Data(char* buf, uint16 s, ByteOrder byteOrder)
|
||||
int16 getShort(const char* buf, ByteOrder byteOrder)
|
||||
{
|
||||
if (byteOrder == littleEndian) {
|
||||
return (unsigned char)buf[1] << 8 | (unsigned char)buf[0];
|
||||
}
|
||||
else {
|
||||
return (unsigned char)buf[0] << 8 | (unsigned char)buf[1];
|
||||
}
|
||||
}
|
||||
|
||||
int32 getLong(const char* buf, ByteOrder byteOrder)
|
||||
{
|
||||
if (byteOrder == littleEndian) {
|
||||
return (unsigned char)buf[3] << 24 | (unsigned char)buf[2] << 16
|
||||
| (unsigned char)buf[1] << 8 | (unsigned char)buf[0];
|
||||
}
|
||||
else {
|
||||
return (unsigned char)buf[0] << 24 | (unsigned char)buf[1] << 16
|
||||
| (unsigned char)buf[2] << 8 | (unsigned char)buf[3];
|
||||
}
|
||||
}
|
||||
|
||||
Rational getRational(const char* buf, ByteOrder byteOrder)
|
||||
{
|
||||
int32 nominator = getLong(buf, byteOrder);
|
||||
int32 denominator = getLong(buf + 4, byteOrder);
|
||||
return std::make_pair(nominator, denominator);
|
||||
}
|
||||
|
||||
long us2Data(char* buf, uint16 s, ByteOrder byteOrder)
|
||||
{
|
||||
if (byteOrder == littleEndian) {
|
||||
buf[0] = s & 0x00ff;
|
||||
@ -638,10 +694,10 @@ namespace Exif {
|
||||
buf[0] = (s & 0xff00) >> 8;
|
||||
buf[1] = s & 0x00ff;
|
||||
}
|
||||
return buf;
|
||||
return 2;
|
||||
}
|
||||
|
||||
char* ul2Data(char* buf, uint32 l, ByteOrder byteOrder)
|
||||
long ul2Data(char* buf, uint32 l, ByteOrder byteOrder)
|
||||
{
|
||||
if (byteOrder == littleEndian) {
|
||||
buf[0] = l & 0x000000ff;
|
||||
@ -655,7 +711,51 @@ namespace Exif {
|
||||
buf[2] = (l & 0x0000ff00) >> 8;
|
||||
buf[3] = l & 0x000000ff;
|
||||
}
|
||||
return buf;
|
||||
return 4;
|
||||
}
|
||||
|
||||
long ur2Data(char* buf, URational l, ByteOrder byteOrder)
|
||||
{
|
||||
long o = ul2Data(buf, l.first, byteOrder);
|
||||
o += ul2Data(buf+o, l.second, byteOrder);
|
||||
return o;
|
||||
}
|
||||
|
||||
long s2Data(char* buf, int16 s, ByteOrder byteOrder)
|
||||
{
|
||||
if (byteOrder == littleEndian) {
|
||||
buf[0] = s & 0x00ff;
|
||||
buf[1] = (s & 0xff00) >> 8;
|
||||
}
|
||||
else {
|
||||
buf[0] = (s & 0xff00) >> 8;
|
||||
buf[1] = s & 0x00ff;
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
|
||||
long l2Data(char* buf, int32 l, ByteOrder byteOrder)
|
||||
{
|
||||
if (byteOrder == littleEndian) {
|
||||
buf[0] = l & 0x000000ff;
|
||||
buf[1] = (l & 0x0000ff00) >> 8;
|
||||
buf[2] = (l & 0x00ff0000) >> 16;
|
||||
buf[3] = (l & 0xff000000) >> 24;
|
||||
}
|
||||
else {
|
||||
buf[0] = (l & 0xff000000) >> 24;
|
||||
buf[1] = (l & 0x00ff0000) >> 16;
|
||||
buf[2] = (l & 0x0000ff00) >> 8;
|
||||
buf[3] = l & 0x000000ff;
|
||||
}
|
||||
return 4;
|
||||
}
|
||||
|
||||
long r2Data(char* buf, Rational l, ByteOrder byteOrder)
|
||||
{
|
||||
long o = l2Data(buf, l.first, byteOrder);
|
||||
o += l2Data(buf+o, l.second, byteOrder);
|
||||
return o;
|
||||
}
|
||||
|
||||
void hexdump(std::ostream& os, const char* buf, long len)
|
||||
|
||||
290
src/exif.hpp
290
src/exif.hpp
@ -8,7 +8,7 @@
|
||||
/*!
|
||||
@file exif.hpp
|
||||
@brief Encoding and decoding of %Exif data
|
||||
@version $Name: $ $Revision: 1.3 $
|
||||
@version $Name: $ $Revision: 1.4 $
|
||||
@author Andreas Huggel (ahu)
|
||||
@date 09-Jan-03, ahu: created
|
||||
*/
|
||||
@ -22,7 +22,8 @@
|
||||
// + standard includes
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <iosfwd>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
// *****************************************************************************
|
||||
// namespace extensions
|
||||
@ -145,7 +146,14 @@ namespace Exif {
|
||||
uint32 offset_;
|
||||
}; // class TiffHeader
|
||||
|
||||
//! Common interface for all values
|
||||
/*!
|
||||
@brief Common interface for all values. The interface provides a uniform
|
||||
way to access values independent from their actual C++ type for
|
||||
simple tasks like reading the values. For other tasks, like modifying
|
||||
values you need to downcast it to the actual subclass of Value so
|
||||
that you can access the subclass specific interface (e.g., assignment
|
||||
operator for a vector of unsigned longs).
|
||||
*/
|
||||
class Value {
|
||||
public:
|
||||
//! Constructor, taking a type id to initialize the base class with
|
||||
@ -157,8 +165,9 @@ namespace Exif {
|
||||
|
||||
@param buf Pointer to the data buffer to read from
|
||||
@param len Number of bytes in the data buffer
|
||||
@param byteOrder Applicable byte order (little or big endian).
|
||||
*/
|
||||
virtual void read(const char* buf, long len) =0;
|
||||
virtual void read(const char* buf, long len, ByteOrder byteOrder) =0;
|
||||
//! Set the value from a string buffer
|
||||
virtual void read(const std::string& buf) =0;
|
||||
/*!
|
||||
@ -168,13 +177,14 @@ namespace Exif {
|
||||
the call results in undefined behaviour.
|
||||
|
||||
@param buf Data buffer to write to.
|
||||
@param byteOrder Applicable byte order (little or big endian).
|
||||
@return Number of characters written.
|
||||
*/
|
||||
virtual long copy(char* buf) const =0;
|
||||
//! Returns the size of the value in bytes
|
||||
virtual long copy(char* buf, ByteOrder byteOrder) const =0;
|
||||
//! Return the size of the value in bytes
|
||||
virtual long size() const =0;
|
||||
/*!
|
||||
@brief Returns a pointer to a copy of itself (deep copy).
|
||||
@brief Return a pointer to a copy of itself (deep copy).
|
||||
The caller owns this copy and is responsible to delete it!
|
||||
*/
|
||||
virtual Value* clone() const =0;
|
||||
@ -185,12 +195,10 @@ namespace Exif {
|
||||
@brief A (simple) factory to create a Value type.
|
||||
|
||||
@param typeId Type of the value.
|
||||
@param byteOrder Applicable byte order (little or big endian).
|
||||
|
||||
@return Pointer to the newly created Value.
|
||||
The caller owns this copy and is responsible to delete it!
|
||||
*/
|
||||
static Value* create(TypeId typeId, ByteOrder byteOrder);
|
||||
static Value* create(TypeId typeId);
|
||||
|
||||
protected:
|
||||
const TypeId typeId_; //!< Format type identifier
|
||||
@ -203,14 +211,14 @@ namespace Exif {
|
||||
return value.write(os);
|
||||
}
|
||||
|
||||
//! %Value representing an Ascii string type.
|
||||
class AsciiValue : public Value {
|
||||
//! %Value for an undefined data type.
|
||||
class DataValue : public Value {
|
||||
public:
|
||||
//! Default constructor.
|
||||
AsciiValue() : Value(asciiString) {}
|
||||
virtual void read(const char* buf, long len);
|
||||
DataValue(TypeId typeId =undefined) : Value(typeId) {}
|
||||
virtual void read(const char* buf, long len, ByteOrder byteOrder);
|
||||
virtual void read(const std::string& buf);
|
||||
virtual long copy(char* buf) const;
|
||||
virtual long copy(char* buf, ByteOrder byteOrder) const;
|
||||
virtual long size() const;
|
||||
virtual Value* clone() const;
|
||||
virtual std::ostream& write(std::ostream& os) const;
|
||||
@ -220,22 +228,42 @@ namespace Exif {
|
||||
|
||||
};
|
||||
|
||||
//! %Value representing one unsigned short type.
|
||||
class UShortValue : public Value {
|
||||
//! %Value for an Ascii string type.
|
||||
class AsciiValue : public Value {
|
||||
public:
|
||||
//! Constructor, taking the byte order (endianness) as argument
|
||||
UShortValue(ByteOrder byteOrder)
|
||||
: Value(unsignedShort), byteOrder_(byteOrder) {}
|
||||
virtual void read(const char* buf, long len);
|
||||
//! Default constructor.
|
||||
AsciiValue() : Value(asciiString) {}
|
||||
virtual void read(const char* buf, long len, ByteOrder byteOrder);
|
||||
virtual void read(const std::string& buf);
|
||||
virtual long copy(char* buf) const;
|
||||
virtual long copy(char* buf, ByteOrder byteOrder) const;
|
||||
virtual long size() const;
|
||||
virtual Value* clone() const;
|
||||
virtual std::ostream& write(std::ostream& os) const;
|
||||
|
||||
private:
|
||||
ByteOrder byteOrder_;
|
||||
uint16 value_;
|
||||
std::string value_;
|
||||
|
||||
};
|
||||
|
||||
/*!
|
||||
@brief Template for a %Value for a basic Type. This is used for unsigned
|
||||
and signed short, long and rational.
|
||||
*/
|
||||
template<typename T>
|
||||
class ValueType : public Value {
|
||||
public:
|
||||
//! Default constructor.
|
||||
ValueType() : Value(getType<T>()) {}
|
||||
virtual void read(const char* buf, long len, ByteOrder byteOrder);
|
||||
virtual void read(const std::string& buf);
|
||||
virtual long copy(char* buf, ByteOrder byteOrder) const;
|
||||
virtual long size() const;
|
||||
virtual Value* clone() const;
|
||||
virtual std::ostream& write(std::ostream& os) const;
|
||||
|
||||
private:
|
||||
typedef std::vector<T> ValueList;
|
||||
ValueList value_;
|
||||
|
||||
};
|
||||
|
||||
@ -252,9 +280,9 @@ namespace Exif {
|
||||
//! Return the name of the type
|
||||
const char* tagName() const { return ExifTags::tagName(tag_, ifdId_); }
|
||||
//! Return the name of the type
|
||||
const char* typeName() const { return ExifTags::typeName(type_); }
|
||||
const char* typeName() const { return ExifTags::typeName(TypeId(type_)); }
|
||||
//! Return the size in bytes of one element of this type
|
||||
long typeSize() const { return ExifTags::typeSize(type_); }
|
||||
long typeSize() const { return ExifTags::typeSize(TypeId(type_)); }
|
||||
//! Return the name of the IFD
|
||||
const char* ifdName() const { return ExifTags::ifdName(ifdId_); }
|
||||
//! Return the related image item (image or thumbnail)
|
||||
@ -273,7 +301,7 @@ namespace Exif {
|
||||
|
||||
public:
|
||||
uint16 tag_; //!< Tag value
|
||||
uint16 type_; //!< Type of the data
|
||||
uint16 type_; //!< Type of the data Todo: change to TypeId?
|
||||
uint32 count_; //!< Number of components
|
||||
uint32 offset_; //!< Offset of the data from start of IFD
|
||||
long size_; //!< Size of the data in bytes
|
||||
@ -445,28 +473,220 @@ namespace Exif {
|
||||
TiffHeader tiffHeader_;
|
||||
Metadata metadata_;
|
||||
}; // class ExifData
|
||||
|
||||
|
||||
// *****************************************************************************
|
||||
// free functions
|
||||
|
||||
//! Read a 2 byte unsigned short value from the data buffer
|
||||
uint16 getUShort(const char* buf, ByteOrder byteOrder);
|
||||
|
||||
//! Read a 4 byte unsigned long value from the data buffer
|
||||
uint32 getULong(const char* buf, ByteOrder byteOrder);
|
||||
//! Read an 8 byte unsigned rational value from the data buffer
|
||||
URational getURational(const char* buf, ByteOrder byteOrder);
|
||||
//! Read a 2 byte signed short value from the data buffer
|
||||
int16 getShort(const char* buf, ByteOrder byteOrder);
|
||||
//! Read a 4 byte signed long value from the data buffer
|
||||
int32 getLong(const char* buf, ByteOrder byteOrder);
|
||||
//! Read an 8 byte signed rational value from the data buffer
|
||||
Rational getRational(const char* buf, ByteOrder byteOrder);
|
||||
|
||||
//! Convert len bytes from the data buffer into a string
|
||||
std::string getString(const char* buf, long len);
|
||||
/*!
|
||||
@brief Read a value of type T from the data buffer.
|
||||
|
||||
//! Write an unsigned short to the data buffer
|
||||
char* us2Data(char* buf, uint16 s, ByteOrder byteOrder);
|
||||
We need this template function for the ValueType template classes.
|
||||
There are only specializations of this function available; no default
|
||||
implementation is provided.
|
||||
|
||||
//! Convert an unsigned long to data, write the data to the buffer
|
||||
char* ul2Data(char* buf, uint32 l, ByteOrder byteOrder);
|
||||
@param buf Pointer to the data buffer to read from.
|
||||
@param byteOrder Applicable byte order (little or big endian).
|
||||
@return A value of type T.
|
||||
*/
|
||||
template<typename T> T getValue(const char* buf, ByteOrder byteOrder);
|
||||
// Specialization for a 2 byte unsigned short value.
|
||||
template<> inline uint16 getValue(const char* buf, ByteOrder byteOrder)
|
||||
{
|
||||
return getUShort(buf, byteOrder);
|
||||
}
|
||||
// Specialization for a 4 byte unsigned long value.
|
||||
template<> inline uint32 getValue(const char* buf, ByteOrder byteOrder)
|
||||
{
|
||||
return getULong(buf, byteOrder);
|
||||
}
|
||||
// Specialization for an 8 byte unsigned rational value.
|
||||
template<> inline URational getValue(const char* buf, ByteOrder byteOrder)
|
||||
{
|
||||
return getURational(buf, byteOrder);
|
||||
}
|
||||
// Specialization for a 2 byte signed short value.
|
||||
template<> inline int16 getValue(const char* buf, ByteOrder byteOrder)
|
||||
{
|
||||
return getShort(buf, byteOrder);
|
||||
}
|
||||
// Specialization for a 4 byte signed long value.
|
||||
template<> inline int32 getValue(const char* buf, ByteOrder byteOrder)
|
||||
{
|
||||
return getLong(buf, byteOrder);
|
||||
}
|
||||
// Specialization for an 8 byte signed rational value.
|
||||
template<> inline Rational getValue(const char* buf, ByteOrder byteOrder)
|
||||
{
|
||||
return getRational(buf, byteOrder);
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Convert an unsigned short to data, write the data to the buffer,
|
||||
return number of bytes written.
|
||||
*/
|
||||
long us2Data(char* buf, uint16 s, ByteOrder byteOrder);
|
||||
/*!
|
||||
@brief Convert an unsigned long to data, write the data to the buffer,
|
||||
return number of bytes written.
|
||||
*/
|
||||
long ul2Data(char* buf, uint32 l, ByteOrder byteOrder);
|
||||
/*!
|
||||
@brief Convert an unsigned rational to data, write the data to the buffer,
|
||||
return number of bytes written.
|
||||
*/
|
||||
long ur2Data(char* buf, URational l, ByteOrder byteOrder);
|
||||
/*!
|
||||
@brief Convert a signed short to data, write the data to the buffer,
|
||||
return number of bytes written.
|
||||
*/
|
||||
long s2Data(char* buf, int16 s, ByteOrder byteOrder);
|
||||
/*!
|
||||
@brief Convert a signed long to data, write the data to the buffer,
|
||||
return number of bytes written.
|
||||
*/
|
||||
long l2Data(char* buf, int32 l, ByteOrder byteOrder);
|
||||
/*!
|
||||
@brief Convert a signed rational to data, write the data to the buffer,
|
||||
return number of bytes written.
|
||||
*/
|
||||
long r2Data(char* buf, Rational l, ByteOrder byteOrder);
|
||||
|
||||
/*!
|
||||
@brief Convert a value of type T to data, write the data to the data buffer.
|
||||
|
||||
We need this template function for the ValueType template classes.
|
||||
There are only specializations of this function available; no default
|
||||
implementation is provided.
|
||||
|
||||
@param buf Pointer to the data buffer to write to.
|
||||
@param t Value to be converted.
|
||||
@param byteOrder Applicable byte order (little or big endian).
|
||||
@return The number of bytes written to the buffer.
|
||||
*/
|
||||
template<typename T> long toData(char* buf, T t, ByteOrder byteOrder);
|
||||
/*!
|
||||
@brief Specialization to write an unsigned short to the data buffer.
|
||||
Return the number of bytes written.
|
||||
*/
|
||||
template<> inline long toData(char* buf, uint16 t, ByteOrder byteOrder)
|
||||
{
|
||||
return us2Data(buf, t, byteOrder);
|
||||
}
|
||||
/*!
|
||||
@brief Specialization to write an unsigned long to the data buffer.
|
||||
Return the number of bytes written.
|
||||
*/
|
||||
template<> inline long toData(char* buf, uint32 t, ByteOrder byteOrder)
|
||||
{
|
||||
return ul2Data(buf, t, byteOrder);
|
||||
}
|
||||
/*!
|
||||
@brief Specialization to write an unsigned rational to the data buffer.
|
||||
Return the number of bytes written.
|
||||
*/
|
||||
template<> inline long toData(char* buf, URational t, ByteOrder byteOrder)
|
||||
{
|
||||
return ur2Data(buf, t, byteOrder);
|
||||
}
|
||||
/*!
|
||||
@brief Specialization to write a signed short to the data buffer.
|
||||
Return the number of bytes written.
|
||||
*/
|
||||
template<> inline long toData(char* buf, int16 t, ByteOrder byteOrder)
|
||||
{
|
||||
return s2Data(buf, t, byteOrder);
|
||||
}
|
||||
/*!
|
||||
@brief Specialization to write a signed long to the data buffer.
|
||||
Return the number of bytes written.
|
||||
*/
|
||||
template<> inline long toData(char* buf, int32 t, ByteOrder byteOrder)
|
||||
{
|
||||
return l2Data(buf, t, byteOrder);
|
||||
}
|
||||
/*!
|
||||
@brief Specialization to write a signed rational to the data buffer.
|
||||
Return the number of bytes written.
|
||||
*/
|
||||
template<> inline long toData(char* buf, Rational t, ByteOrder byteOrder)
|
||||
{
|
||||
return r2Data(buf, t, byteOrder);
|
||||
}
|
||||
|
||||
//! Print len bytes from buf in hex and ASCII format to the given stream
|
||||
void hexdump(std::ostream& os, const char* buf, long len);
|
||||
|
||||
// *****************************************************************************
|
||||
// template definitions
|
||||
|
||||
template<typename T>
|
||||
void ValueType<T>::read(const char* buf, long len, ByteOrder byteOrder)
|
||||
{
|
||||
value_.clear();
|
||||
for (long i = 0; i < len; i += ExifTags::typeSize(typeId_)) {
|
||||
value_.push_back(getValue<T>(buf + i, byteOrder));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void ValueType<T>::read(const std::string& buf)
|
||||
{
|
||||
std::istringstream is(buf);
|
||||
T tmp;
|
||||
value_.clear();
|
||||
while (is >> tmp) {
|
||||
value_.push_back(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
long ValueType<T>::copy(char* buf, ByteOrder byteOrder) const
|
||||
{
|
||||
long offset = 0;
|
||||
typename ValueList::const_iterator end = value_.end();
|
||||
for (typename ValueList::const_iterator i = value_.begin(); i != end; ++i) {
|
||||
offset += toData(buf + offset, *i, byteOrder);
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
long ValueType<T>::size() const
|
||||
{
|
||||
return ExifTags::typeSize(typeId_) * value_.size();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Value* ValueType<T>::clone() const
|
||||
{
|
||||
return new ValueType(*this);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::ostream& ValueType<T>::write(std::ostream& os) const
|
||||
{
|
||||
typename ValueList::const_iterator end = value_.end();
|
||||
typename ValueList::const_iterator i = value_.begin();
|
||||
while (i != end) {
|
||||
os << *i;
|
||||
if (++i != end) os << " ";
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
} // namespace Exif
|
||||
|
||||
#endif // #ifndef _EXIF_HPP_
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
#include "tags.hpp"
|
||||
#include "exif.hpp"
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
@ -19,34 +20,39 @@ int main(int argc, char* const argv[])
|
||||
ExifData::const_iterator end = exifData.end();
|
||||
ExifData::const_iterator i = beg;
|
||||
for (; i != end; ++i) {
|
||||
|
||||
std::cout << "0x"
|
||||
<< std::hex << std::setw(4) << std::setfill('0') << std::right
|
||||
<< i->tag_ << " "
|
||||
<< std::setw(50) << std::setfill(' ') << std::left
|
||||
<< i->key() << " ";
|
||||
|
||||
if (i->type_ == 2 || i->type_ == 3) {
|
||||
std::cout << std::dec << i->value() << "\n";
|
||||
}
|
||||
else {
|
||||
std::cout << std::setw(17) << std::setfill(' ') << std::left
|
||||
<< i->typeName() << " "
|
||||
<< std::dec << std::setw(3)
|
||||
<< std::setfill(' ') << std::right
|
||||
<< i->count_ << " "
|
||||
<< std::dec << std::setw(3)
|
||||
<< std::setfill(' ') << std::right
|
||||
<< i->typeSize() * i->count_ << "\n";
|
||||
}
|
||||
|
||||
<< std::setw(27) << std::setfill(' ') << std::left
|
||||
<< i->tagName() << " "
|
||||
<< std::setw(17) << std::setfill(' ') << std::left
|
||||
<< i->typeName() << " "
|
||||
<< std::dec << std::setw(3)
|
||||
<< std::setfill(' ') << std::right
|
||||
<< i->count_ << " "
|
||||
<< std::dec << i->value() << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
std::string tmp = "12";
|
||||
Value* val = Value::create(unsignedShort, littleEndian);
|
||||
// std::string tmp = "12 2ddd4. xd35";
|
||||
std::string tmp = " 1 2 3";
|
||||
Value* val = Value::create(unsignedShort);
|
||||
std::cout << "Reading test string \"" << tmp << "\"\n";
|
||||
val->read(tmp);
|
||||
std::cout << "And the answer is: " << *val << "\n";
|
||||
std::cout << "And the answer is: " << *val << ", size is " << val->size() << "\n";
|
||||
Rational r = std::make_pair(1,72);
|
||||
URational ur = std::make_pair(2,3);
|
||||
|
||||
std::cout << "Rational r = " << r << "\n";
|
||||
std::cout << "URational ur = " << ur << "\n";
|
||||
|
||||
ValueType<Rational> vr;
|
||||
ValueType<URational> vur;
|
||||
|
||||
std::string str(" 4 / 5 x2 5/3");
|
||||
vr.read(str);
|
||||
std::cout << "ValueType<Rational> vr = " << vr
|
||||
<< ", size is " << vr.size() << "\n";
|
||||
|
||||
return rc;
|
||||
|
||||
|
||||
52
src/tags.cpp
52
src/tags.cpp
@ -12,12 +12,14 @@
|
||||
|
||||
RCS information
|
||||
$Name: $
|
||||
$Revision: 1.3 $
|
||||
$Revision: 1.4 $
|
||||
*/
|
||||
// *****************************************************************************
|
||||
// included header files
|
||||
#include "tags.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
// *****************************************************************************
|
||||
// class member definitions
|
||||
namespace Exif {
|
||||
@ -80,13 +82,11 @@ namespace Exif {
|
||||
TagFormat(unsignedShort, "unsigned short", 2),
|
||||
TagFormat(unsignedLong, "unsigned long", 4),
|
||||
TagFormat(unsignedRational, "unsigned rational", 8),
|
||||
TagFormat(signedByte, "signed byte", 1),
|
||||
TagFormat(invalid6, "invalid (6)", 1),
|
||||
TagFormat(undefined, "undefined", 1),
|
||||
TagFormat(signedShort, "signed short", 2),
|
||||
TagFormat(signedLong, "signed long", 4),
|
||||
TagFormat(signedRational, "signed rational", 8),
|
||||
TagFormat(singleFloat, "single float", 4),
|
||||
TagFormat(doubleFloat, "double float", 8)
|
||||
TagFormat(signedRational, "signed rational", 8)
|
||||
};
|
||||
|
||||
TagInfo::TagInfo(
|
||||
@ -281,14 +281,14 @@ namespace Exif {
|
||||
return sectionInfo_[tagInfo[tagInfoIdx(tag, ifdId)].sectionId_].name_;
|
||||
}
|
||||
|
||||
const char* ExifTags::typeName(uint16 type)
|
||||
const char* ExifTags::typeName(TypeId typeId)
|
||||
{
|
||||
return tagFormat_[type].name_;
|
||||
return tagFormat_[typeId].name_;
|
||||
}
|
||||
|
||||
long ExifTags::typeSize(uint16 type)
|
||||
long ExifTags::typeSize(TypeId typeId)
|
||||
{
|
||||
return tagFormat_[type].size_;
|
||||
return tagFormat_[typeId].size_;
|
||||
}
|
||||
|
||||
const char* ExifTags::ifdName(IfdId ifdId)
|
||||
@ -306,4 +306,38 @@ namespace Exif {
|
||||
return sectionInfo_[sectionId].name_;
|
||||
}
|
||||
|
||||
|
||||
// *************************************************************************
|
||||
// free functions
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const Rational& r)
|
||||
{
|
||||
return os << r.first << "/" << r.second;
|
||||
}
|
||||
|
||||
std::istream& operator>>(std::istream& is, Rational& r)
|
||||
{
|
||||
int32 nominator;
|
||||
int32 denominator;
|
||||
char c;
|
||||
is >> nominator >> c >> denominator;
|
||||
if (is && c == '/') r = std::make_pair(nominator, denominator);
|
||||
return is;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const URational& r)
|
||||
{
|
||||
return os << r.first << "/" << r.second;
|
||||
}
|
||||
|
||||
std::istream& operator>>(std::istream& is, URational& r)
|
||||
{
|
||||
uint32 nominator;
|
||||
uint32 denominator;
|
||||
char c;
|
||||
is >> nominator >> c >> denominator;
|
||||
if (is && c == '/') r = std::make_pair(nominator, denominator);
|
||||
return is;
|
||||
}
|
||||
|
||||
} // namespace Exif
|
||||
|
||||
45
src/tags.hpp
45
src/tags.hpp
@ -8,7 +8,7 @@
|
||||
/*!
|
||||
@file tags.hpp
|
||||
@brief %Exif tag and type information
|
||||
@version $Name: $ $Revision: 1.3 $
|
||||
@version $Name: $ $Revision: 1.4 $
|
||||
@author Andreas Huggel (ahu)
|
||||
@date 15-Jan-03, ahu: created
|
||||
*/
|
||||
@ -20,6 +20,7 @@
|
||||
|
||||
// + standard includes
|
||||
#include <utility> // for std::pair
|
||||
#include <iosfwd>
|
||||
|
||||
// *****************************************************************************
|
||||
// namespace extensions
|
||||
@ -44,16 +45,18 @@ namespace Exif {
|
||||
|
||||
//! Type identifiers for IFD format types
|
||||
enum TypeId { invalid, unsignedByte, asciiString, unsignedShort,
|
||||
unsignedLong, unsignedRational, signedByte, undefined,
|
||||
signedShort, signedLong, signedRational, singleFloat,
|
||||
doubleFloat };
|
||||
unsignedLong, unsignedRational, invalid6, undefined,
|
||||
signedShort, signedLong, signedRational };
|
||||
|
||||
//! Type to specify the IFD to which a metadata belongs
|
||||
enum IfdId { IfdIdNotSet,
|
||||
ifd0, exifIfd, gpsIfd, makerIfd, iopIfd,
|
||||
ifd1, ifd1ExifIfd, ifd1GpsIfd, ifd1MakerIfd, ifd1IopIfd };
|
||||
|
||||
//! Section identifiers to logically group tags
|
||||
/*!
|
||||
@brief Section identifiers to logically group tags. A section consists
|
||||
of nothing more than a name, based on the Exif standard.
|
||||
*/
|
||||
enum SectionId { SectionIdNotSet,
|
||||
imgStruct, recOffset, imgCharacter, otherTags, exifFormat,
|
||||
exifVersion, imgConfig, userInfo, relatedFile, dateTime,
|
||||
@ -119,9 +122,9 @@ namespace Exif {
|
||||
//! Returns the name of the tag
|
||||
static const char* tagName(uint16 tag, IfdId ifdId);
|
||||
//! Returns the name of the type
|
||||
static const char* typeName(uint16 type);
|
||||
static const char* typeName(TypeId typeId);
|
||||
//! Returns the size in bytes of one element of this type
|
||||
static long typeSize(uint16 type);
|
||||
static long typeSize(TypeId typeId);
|
||||
//! Returns the name of the IFD
|
||||
static const char* ifdName(IfdId ifdId);
|
||||
//! Returns the related image item (image or thumbnail)
|
||||
@ -145,6 +148,34 @@ namespace Exif {
|
||||
// *****************************************************************************
|
||||
// free functions
|
||||
|
||||
//! Output operator for our fake rational
|
||||
std::ostream& operator<<(std::ostream& os, const Rational& r);
|
||||
//! Input operator for our fake rational
|
||||
std::istream& operator>>(std::istream& is, Rational& r);
|
||||
//! Output operator for our fake unsigned rational
|
||||
std::ostream& operator<<(std::ostream& os, const URational& r);
|
||||
//! Input operator for our fake unsigned rational
|
||||
std::istream& operator>>(std::istream& is, URational& r);
|
||||
|
||||
//! Template to determine the TypeId for a type T
|
||||
template<typename T> TypeId getType();
|
||||
|
||||
//! Specialization for an unsigned short
|
||||
template<> inline TypeId getType<uint16>() { return unsignedShort; }
|
||||
//! Specialization for an unsigned long
|
||||
template<> inline TypeId getType<uint32>() { return unsignedLong; }
|
||||
//! Specialization for an unsigned rational
|
||||
template<> inline TypeId getType<URational>() { return unsignedRational; }
|
||||
//! Specialization for a signed short
|
||||
template<> inline TypeId getType<int16>() { return signedShort; }
|
||||
//! Specialization for a signed long
|
||||
template<> inline TypeId getType<int32>() { return signedLong; }
|
||||
//! Specialization for a signed rational
|
||||
template<> inline TypeId getType<Rational>() { return signedRational; }
|
||||
|
||||
// No default implementation: let the compiler/linker complain
|
||||
// template<typename T> inline TypeId getType() { return invalid; }
|
||||
|
||||
} // namespace Exif
|
||||
|
||||
#endif // #ifndef _TAGS_HPP_
|
||||
|
||||
Loading…
Reference in New Issue
Block a user