Values implemented

v0.27.3
Andreas Huggel 22 years ago
parent bb6380825d
commit 440571b544

@ -12,7 +12,7 @@
RCS information RCS information
$Name: $ $Name: $
$Revision: 1.3 $ $Revision: 1.4 $
*/ */
// ***************************************************************************** // *****************************************************************************
// included header files // included header files
@ -24,6 +24,7 @@
#include <iomanip> #include <iomanip>
#include <sstream> #include <sstream>
#include <fstream> #include <fstream>
#include <utility>
#include <cstring> #include <cstring>
@ -101,15 +102,15 @@ namespace Exif {
if (getUShort(marker, bigEndian) != app1_) return 3; if (getUShort(marker, bigEndian) != app1_) return 3;
// Read the length of the APP1 field and the Exif identifier // Read the length of the APP1 field and the Exif identifier
char buf[8]; char tmpbuf[8];
::memset(buf, 0x0, 8); ::memset(tmpbuf, 0x0, 8);
is.read(buf, 8); is.read(tmpbuf, 8);
if (!is.good()) return 1; if (!is.good()) return 1;
// Get the length of the APP1 field and do a plausibility check // 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; if (app1Length < 8) return 4;
// Check the Exif identifier // 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) // Read the rest of the APP1 field (Exif data)
long sizeExifData = app1Length - 8; long sizeExifData = app1Length - 8;
@ -166,95 +167,112 @@ namespace Exif {
return size(); return size();
} }
Value* Value::create(TypeId typeId, ByteOrder byteOrder) Value* Value::create(TypeId typeId)
{ {
Value* value = 0; Value* value = 0;
switch (typeId) { switch (typeId) {
case invalid: case invalid:
value = new DataValue(invalid);
break; break;
case unsignedByte: case unsignedByte:
value = new AsciiValue; value = new DataValue(unsignedByte);
break; break;
case asciiString: case asciiString:
value = new AsciiValue; value = new AsciiValue;
break; break;
case unsignedShort: case unsignedShort:
value = new UShortValue(byteOrder); value = new ValueType<uint16>;
break; break;
case unsignedLong: case unsignedLong:
value = new ValueType<uint32>;
break;
case unsignedRational: case unsignedRational:
case signedByte: value = new ValueType<URational>;
break;
case invalid6:
value = new DataValue(invalid6);
break;
case undefined: case undefined:
value = new DataValue;
break;
case signedShort: case signedShort:
value = new ValueType<int16>;
break;
case signedLong: case signedLong:
value = new ValueType<int32>;
break;
case signedRational: case signedRational:
case singleFloat: value = new ValueType<Rational>;
case doubleFloat:
value = new AsciiValue;
break; break;
} }
return value; return value;
} // Value::create } // 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); value_ = std::string(buf, len);
} }
void AsciiValue::read(const std::string& buf) void DataValue::read(const std::string& buf)
{ {
// Todo: read from a string of bytes??
value_ = buf; value_ = buf;
} }
long AsciiValue::copy(char* buf) const long DataValue::copy(char* buf, ByteOrder byteOrder) const
{ {
// byteOrder not needed
return value_.copy(buf, value_.size()); return value_.copy(buf, value_.size());
} }
long AsciiValue::size() const long DataValue::size() const
{ {
return value_.size(); return value_.size();
} }
Value* AsciiValue::clone() const Value* DataValue::clone() const
{ {
return new AsciiValue(*this); return new DataValue(*this);
} }
std::ostream& AsciiValue::write(std::ostream& os) const std::ostream& DataValue::write(std::ostream& os) const
{ {
return os << value_; 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 UShortValue::read(const char* buf, long len) void AsciiValue::read(const char* buf, long len, ByteOrder byteOrder)
{ {
// Todo: Should we check to make sure that len is 2 // byteOrder not needed
value_ = getUShort(buf, byteOrder_); value_ = std::string(buf, len);
} }
void UShortValue::read(const std::string& buf) void AsciiValue::read(const std::string& buf)
{ {
std::istringstream is(buf); value_ = buf;
is >> value_;
} }
long UShortValue::copy(char* buf) const long AsciiValue::copy(char* buf, ByteOrder byteOrder) const
{ {
us2Data(buf, value_, byteOrder_); // byteOrder not needed
return size(); return value_.copy(buf, value_.size());
} }
long UShortValue::size() const long AsciiValue::size() const
{ {
return 2; return value_.size();
} }
Value* UShortValue::clone() const Value* AsciiValue::clone() const
{ {
return new UShortValue(*this); return new AsciiValue(*this);
} }
std::ostream& UShortValue::write(std::ostream& os) const std::ostream& AsciiValue::write(std::ostream& os) const
{ {
return os << value_; return os << value_;
} }
@ -287,6 +305,8 @@ namespace Exif {
Metadatum& Metadatum::operator=(const Metadatum& rhs) Metadatum& Metadatum::operator=(const Metadatum& rhs)
{ {
if (this == &rhs) return *this;
tag_ = rhs.tag_; tag_ = rhs.tag_;
type_ = rhs.type_; type_ = rhs.type_;
count_ = rhs.count_; count_ = rhs.count_;
@ -361,15 +381,15 @@ namespace Exif {
for (i = eb; i != ee; ++i) { for (i = eb; i != ee; ++i) {
delete i->value_; delete i->value_;
//! Todo: Create the correct type here, once we have them //! 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) { if (i->size_ > 4) {
i->offset_ = i->offset_ - offset_; i->offset_ = i->offset_ - offset_;
i->value_->read(buf + i->offset_, i->size_); i->value_->read(buf + i->offset_, i->size_, byteOrder);
} }
else { else {
char value[4]; char tmpbuf[4];
ul2Data(value, i->offset_, byteOrder); ul2Data(tmpbuf, i->offset_, byteOrder);
i->value_->read(value, 4); i->value_->read(tmpbuf, i->size_, byteOrder);
} }
} }
return 0; return 0;
@ -411,7 +431,10 @@ namespace Exif {
dataSize += i->size_; dataSize += i->size_;
} }
else { 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; o += 12;
} }
@ -432,7 +455,7 @@ namespace Exif {
// Todo: Check this! There seems to be an inconsistency // Todo: Check this! There seems to be an inconsistency
// in the use of size_ and the return value of copy() here // in the use of size_ and the return value of copy() here
// Todo: And can value_ be 0? // 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: " << ", IFD Entries: "
<< std::setfill(' ') << std::dec << std::right << std::setfill(' ') << std::dec << std::right
<< entries_.size() << "\n" << entries_.size() << "\n"
<< prefix << "Entry Tag Format (Bytes each) Number Offset/Data\n" << prefix << "Entry Tag Format (Bytes each) Number Offset\n"
<< prefix << "----- ------ --------------------- ------ -----------\n"; << prefix << "----- ------ --------------------- ------ -----------\n";
const Metadata::const_iterator b = entries_.begin(); const Metadata::const_iterator b = entries_.begin();
@ -458,19 +481,22 @@ namespace Exif {
for (; i != e; ++i) { for (; i != e; ++i) {
std::ostringstream offset; std::ostringstream offset;
if (i->typeSize() * i->count_ <= 4) { 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: Fix me! This doesn't work with Value anymore because we do not know
// Todo: can value_ be 0 here? // the byte order here. (Wait for Ifd to use a more special type)
char tmpbuf[4]; //
i->value_->copy(tmpbuf); // char tmpbuf[4];
offset << std::setw(2) << std::setfill('0') << std::hex // i->value_->copy(tmpbuf, byteOrder);
<< (int)*(unsigned char*)tmpbuf << " " // offset << std::setw(2) << std::setfill('0') << std::hex
<< std::setw(2) << std::setfill('0') << std::hex // << (int)*(unsigned char*)tmpbuf << " "
<< (int)*(unsigned char*)(tmpbuf+1) << " " // << std::setw(2) << std::setfill('0') << std::hex
<< std::setw(2) << std::setfill('0') << std::hex // << (int)*(unsigned char*)(tmpbuf+1) << " "
<< (int)*(unsigned char*)(tmpbuf+2) << " " // << std::setw(2) << std::setfill('0') << std::hex
<< std::setw(2) << std::setfill('0') << std::hex // << (int)*(unsigned char*)(tmpbuf+2) << " "
<< (int)*(unsigned char*)(tmpbuf+3) << " "; // << std::setw(2) << std::setfill('0') << std::hex
// << (int)*(unsigned char*)(tmpbuf+3) << " ";
offset << "n/a";
} }
else { else {
offset << " 0x" << std::setw(8) << std::setfill('0') << std::hex offset << " 0x" << std::setw(8) << std::setfill('0') << std::hex
@ -622,13 +648,80 @@ namespace Exif {
} }
} }
std::string getString(const char* buf, long len) URational getURational(const char* buf, ByteOrder byteOrder)
{
uint32 nominator = getULong(buf, byteOrder);
uint32 denominator = getULong(buf + 4, byteOrder);
return std::make_pair(nominator, denominator);
}
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;
buf[1] = (s & 0xff00) >> 8;
}
else {
buf[0] = (s & 0xff00) >> 8;
buf[1] = s & 0x00ff;
}
return 2;
}
long ul2Data(char* buf, uint32 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 ur2Data(char* buf, URational l, ByteOrder byteOrder)
{ {
std::string txt(buf, len); long o = ul2Data(buf, l.first, byteOrder);
return txt; o += ul2Data(buf+o, l.second, byteOrder);
return o;
} }
char* us2Data(char* buf, uint16 s, ByteOrder byteOrder) long s2Data(char* buf, int16 s, ByteOrder byteOrder)
{ {
if (byteOrder == littleEndian) { if (byteOrder == littleEndian) {
buf[0] = s & 0x00ff; buf[0] = s & 0x00ff;
@ -638,10 +731,10 @@ namespace Exif {
buf[0] = (s & 0xff00) >> 8; buf[0] = (s & 0xff00) >> 8;
buf[1] = s & 0x00ff; buf[1] = s & 0x00ff;
} }
return buf; return 2;
} }
char* ul2Data(char* buf, uint32 l, ByteOrder byteOrder) long l2Data(char* buf, int32 l, ByteOrder byteOrder)
{ {
if (byteOrder == littleEndian) { if (byteOrder == littleEndian) {
buf[0] = l & 0x000000ff; buf[0] = l & 0x000000ff;
@ -655,7 +748,14 @@ namespace Exif {
buf[2] = (l & 0x0000ff00) >> 8; buf[2] = (l & 0x0000ff00) >> 8;
buf[3] = l & 0x000000ff; buf[3] = l & 0x000000ff;
} }
return buf; 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) void hexdump(std::ostream& os, const char* buf, long len)

@ -8,7 +8,7 @@
/*! /*!
@file exif.hpp @file exif.hpp
@brief Encoding and decoding of %Exif data @brief Encoding and decoding of %Exif data
@version $Name: $ $Revision: 1.3 $ @version $Name: $ $Revision: 1.4 $
@author Andreas Huggel (ahu) @author Andreas Huggel (ahu)
@date 09-Jan-03, ahu: created @date 09-Jan-03, ahu: created
*/ */
@ -22,7 +22,8 @@
// + standard includes // + standard includes
#include <string> #include <string>
#include <vector> #include <vector>
#include <iosfwd> #include <iostream>
#include <sstream>
// ***************************************************************************** // *****************************************************************************
// namespace extensions // namespace extensions
@ -145,7 +146,14 @@ namespace Exif {
uint32 offset_; uint32 offset_;
}; // class TiffHeader }; // 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 { class Value {
public: public:
//! Constructor, taking a type id to initialize the base class with //! 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 buf Pointer to the data buffer to read from
@param len Number of bytes in the data buffer @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 //! Set the value from a string buffer
virtual void read(const std::string& buf) =0; virtual void read(const std::string& buf) =0;
/*! /*!
@ -168,13 +177,14 @@ namespace Exif {
the call results in undefined behaviour. the call results in undefined behaviour.
@param buf Data buffer to write to. @param buf Data buffer to write to.
@param byteOrder Applicable byte order (little or big endian).
@return Number of characters written. @return Number of characters written.
*/ */
virtual long copy(char* buf) const =0; virtual long copy(char* buf, ByteOrder byteOrder) const =0;
//! Returns the size of the value in bytes //! Return the size of the value in bytes
virtual long size() const =0; 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! The caller owns this copy and is responsible to delete it!
*/ */
virtual Value* clone() const =0; virtual Value* clone() const =0;
@ -185,12 +195,10 @@ namespace Exif {
@brief A (simple) factory to create a Value type. @brief A (simple) factory to create a Value type.
@param typeId Type of the value. @param typeId Type of the value.
@param byteOrder Applicable byte order (little or big endian).
@return Pointer to the newly created Value. @return Pointer to the newly created Value.
The caller owns this copy and is responsible to delete it! The caller owns this copy and is responsible to delete it!
*/ */
static Value* create(TypeId typeId, ByteOrder byteOrder); static Value* create(TypeId typeId);
protected: protected:
const TypeId typeId_; //!< Format type identifier const TypeId typeId_; //!< Format type identifier
@ -203,14 +211,31 @@ namespace Exif {
return value.write(os); return value.write(os);
} }
//! %Value representing an Ascii string type. //! %Value for an undefined data type.
class DataValue : public Value {
public:
//! Default constructor.
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, ByteOrder byteOrder) const;
virtual long size() const;
virtual Value* clone() const;
virtual std::ostream& write(std::ostream& os) const;
private:
std::string value_;
};
//! %Value for an Ascii string type.
class AsciiValue : public Value { class AsciiValue : public Value {
public: public:
//! Default constructor. //! Default constructor.
AsciiValue() : Value(asciiString) {} AsciiValue() : Value(asciiString) {}
virtual void read(const char* buf, long len); virtual void read(const char* buf, long len, ByteOrder byteOrder);
virtual void read(const std::string& buf); 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 long size() const;
virtual Value* clone() const; virtual Value* clone() const;
virtual std::ostream& write(std::ostream& os) const; virtual std::ostream& write(std::ostream& os) const;
@ -220,22 +245,25 @@ namespace Exif {
}; };
//! %Value representing one unsigned short type. /*!
class UShortValue : public 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: public:
//! Constructor, taking the byte order (endianness) as argument //! Default constructor.
UShortValue(ByteOrder byteOrder) ValueType() : Value(getType<T>()) {}
: Value(unsignedShort), byteOrder_(byteOrder) {} virtual void read(const char* buf, long len, ByteOrder byteOrder);
virtual void read(const char* buf, long len);
virtual void read(const std::string& buf); 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 long size() const;
virtual Value* clone() const; virtual Value* clone() const;
virtual std::ostream& write(std::ostream& os) const; virtual std::ostream& write(std::ostream& os) const;
private: private:
ByteOrder byteOrder_; typedef std::vector<T> ValueList;
uint16 value_; ValueList value_;
}; };
@ -252,9 +280,9 @@ namespace Exif {
//! Return the name of the type //! Return the name of the type
const char* tagName() const { return ExifTags::tagName(tag_, ifdId_); } const char* tagName() const { return ExifTags::tagName(tag_, ifdId_); }
//! Return the name of the type //! 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 //! 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 //! Return the name of the IFD
const char* ifdName() const { return ExifTags::ifdName(ifdId_); } const char* ifdName() const { return ExifTags::ifdName(ifdId_); }
//! Return the related image item (image or thumbnail) //! Return the related image item (image or thumbnail)
@ -273,7 +301,7 @@ namespace Exif {
public: public:
uint16 tag_; //!< Tag value 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 count_; //!< Number of components
uint32 offset_; //!< Offset of the data from start of IFD uint32 offset_; //!< Offset of the data from start of IFD
long size_; //!< Size of the data in bytes long size_; //!< Size of the data in bytes
@ -445,28 +473,220 @@ namespace Exif {
TiffHeader tiffHeader_; TiffHeader tiffHeader_;
Metadata metadata_; Metadata metadata_;
}; // class ExifData }; // class ExifData
// ***************************************************************************** // *****************************************************************************
// free functions // free functions
//! Read a 2 byte unsigned short value from the data buffer //! Read a 2 byte unsigned short value from the data buffer
uint16 getUShort(const char* buf, ByteOrder byteOrder); uint16 getUShort(const char* buf, ByteOrder byteOrder);
//! Read a 4 byte unsigned long value from the data buffer //! Read a 4 byte unsigned long value from the data buffer
uint32 getULong(const char* buf, ByteOrder byteOrder); 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);
/*!
@brief Read a value of type T from 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 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);
//! Convert len bytes from the data buffer into a string /*!
std::string getString(const char* buf, long len); @brief Convert a value of type T to data, write the data to the data buffer.
//! Write an unsigned short to the data buffer We need this template function for the ValueType template classes.
char* us2Data(char* buf, uint16 s, ByteOrder byteOrder); 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 @param buf Pointer to the data buffer to write to.
char* ul2Data(char* buf, uint32 l, ByteOrder byteOrder); @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 //! Print len bytes from buf in hex and ASCII format to the given stream
void hexdump(std::ostream& os, const char* buf, long len); 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 } // namespace Exif
#endif // #ifndef _EXIF_HPP_ #endif // #ifndef _EXIF_HPP_

@ -1,3 +1,4 @@
#include "tags.hpp"
#include "exif.hpp" #include "exif.hpp"
#include <iostream> #include <iostream>
#include <iomanip> #include <iomanip>
@ -19,34 +20,39 @@ int main(int argc, char* const argv[])
ExifData::const_iterator end = exifData.end(); ExifData::const_iterator end = exifData.end();
ExifData::const_iterator i = beg; ExifData::const_iterator i = beg;
for (; i != end; ++i) { for (; i != end; ++i) {
std::cout << "0x" std::cout << "0x"
<< std::hex << std::setw(4) << std::setfill('0') << std::right << std::hex << std::setw(4) << std::setfill('0') << std::right
<< i->tag_ << " " << i->tag_ << " "
<< std::setw(50) << std::setfill(' ') << std::left << std::setw(27) << std::setfill(' ') << std::left
<< i->key() << " "; << i->tagName() << " "
<< std::setw(17) << std::setfill(' ') << std::left
if (i->type_ == 2 || i->type_ == 3) { << i->typeName() << " "
std::cout << std::dec << i->value() << "\n"; << std::dec << std::setw(3)
} << std::setfill(' ') << std::right
else { << i->count_ << " "
std::cout << std::setw(17) << std::setfill(' ') << std::left << std::dec << i->value() << "\n";
<< 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::string tmp = "12"; // std::string tmp = "12 2ddd4. xd35";
Value* val = Value::create(unsignedShort, littleEndian); std::string tmp = " 1 2 3";
Value* val = Value::create(unsignedShort);
std::cout << "Reading test string \"" << tmp << "\"\n";
val->read(tmp); 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; return rc;

@ -12,12 +12,14 @@
RCS information RCS information
$Name: $ $Name: $
$Revision: 1.3 $ $Revision: 1.4 $
*/ */
// ***************************************************************************** // *****************************************************************************
// included header files // included header files
#include "tags.hpp" #include "tags.hpp"
#include <iostream>
// ***************************************************************************** // *****************************************************************************
// class member definitions // class member definitions
namespace Exif { namespace Exif {
@ -80,13 +82,11 @@ namespace Exif {
TagFormat(unsignedShort, "unsigned short", 2), TagFormat(unsignedShort, "unsigned short", 2),
TagFormat(unsignedLong, "unsigned long", 4), TagFormat(unsignedLong, "unsigned long", 4),
TagFormat(unsignedRational, "unsigned rational", 8), TagFormat(unsignedRational, "unsigned rational", 8),
TagFormat(signedByte, "signed byte", 1), TagFormat(invalid6, "invalid (6)", 1),
TagFormat(undefined, "undefined", 1), TagFormat(undefined, "undefined", 1),
TagFormat(signedShort, "signed short", 2), TagFormat(signedShort, "signed short", 2),
TagFormat(signedLong, "signed long", 4), TagFormat(signedLong, "signed long", 4),
TagFormat(signedRational, "signed rational", 8), TagFormat(signedRational, "signed rational", 8)
TagFormat(singleFloat, "single float", 4),
TagFormat(doubleFloat, "double float", 8)
}; };
TagInfo::TagInfo( TagInfo::TagInfo(
@ -281,14 +281,14 @@ namespace Exif {
return sectionInfo_[tagInfo[tagInfoIdx(tag, ifdId)].sectionId_].name_; 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) const char* ExifTags::ifdName(IfdId ifdId)
@ -306,4 +306,38 @@ namespace Exif {
return sectionInfo_[sectionId].name_; 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 } // namespace Exif

@ -8,7 +8,7 @@
/*! /*!
@file tags.hpp @file tags.hpp
@brief %Exif tag and type information @brief %Exif tag and type information
@version $Name: $ $Revision: 1.3 $ @version $Name: $ $Revision: 1.4 $
@author Andreas Huggel (ahu) @author Andreas Huggel (ahu)
@date 15-Jan-03, ahu: created @date 15-Jan-03, ahu: created
*/ */
@ -20,6 +20,7 @@
// + standard includes // + standard includes
#include <utility> // for std::pair #include <utility> // for std::pair
#include <iosfwd>
// ***************************************************************************** // *****************************************************************************
// namespace extensions // namespace extensions
@ -44,16 +45,18 @@ namespace Exif {
//! Type identifiers for IFD format types //! Type identifiers for IFD format types
enum TypeId { invalid, unsignedByte, asciiString, unsignedShort, enum TypeId { invalid, unsignedByte, asciiString, unsignedShort,
unsignedLong, unsignedRational, signedByte, undefined, unsignedLong, unsignedRational, invalid6, undefined,
signedShort, signedLong, signedRational, singleFloat, signedShort, signedLong, signedRational };
doubleFloat };
//! Type to specify the IFD to which a metadata belongs //! Type to specify the IFD to which a metadata belongs
enum IfdId { IfdIdNotSet, enum IfdId { IfdIdNotSet,
ifd0, exifIfd, gpsIfd, makerIfd, iopIfd, ifd0, exifIfd, gpsIfd, makerIfd, iopIfd,
ifd1, ifd1ExifIfd, ifd1GpsIfd, ifd1MakerIfd, ifd1IopIfd }; 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, enum SectionId { SectionIdNotSet,
imgStruct, recOffset, imgCharacter, otherTags, exifFormat, imgStruct, recOffset, imgCharacter, otherTags, exifFormat,
exifVersion, imgConfig, userInfo, relatedFile, dateTime, exifVersion, imgConfig, userInfo, relatedFile, dateTime,
@ -119,9 +122,9 @@ namespace Exif {
//! Returns the name of the tag //! Returns the name of the tag
static const char* tagName(uint16 tag, IfdId ifdId); static const char* tagName(uint16 tag, IfdId ifdId);
//! Returns the name of the type //! 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 //! 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 //! Returns the name of the IFD
static const char* ifdName(IfdId ifdId); static const char* ifdName(IfdId ifdId);
//! Returns the related image item (image or thumbnail) //! Returns the related image item (image or thumbnail)
@ -145,6 +148,34 @@ namespace Exif {
// ***************************************************************************** // *****************************************************************************
// free functions // 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 } // namespace Exif
#endif // #ifndef _TAGS_HPP_ #endif // #ifndef _TAGS_HPP_

Loading…
Cancel
Save