Changed Value::read() to return an int indicating success instead of throwing. Added Support for HHMMSS and H:M:S formats to TimeValue (assumes timezone is UTC). Fixes bug #440.

v0.27.3
Andreas Huggel 20 years ago
parent 06e5c0719e
commit c32e706c36

@ -1065,12 +1065,13 @@ namespace Action {
<< ")" << std::endl; << ")" << std::endl;
} }
Exiv2::Value::AutoPtr value = Exiv2::Value::create(modifyCmd.typeId_); Exiv2::Value::AutoPtr value = Exiv2::Value::create(modifyCmd.typeId_);
value->read(modifyCmd.value_); if (0 == value->read(modifyCmd.value_)) {
if (modifyCmd.metadataId_ == exif) { if (modifyCmd.metadataId_ == exif) {
image_->exifData().add(Exiv2::ExifKey(modifyCmd.key_), value.get()); image_->exifData().add(Exiv2::ExifKey(modifyCmd.key_), value.get());
} }
if (modifyCmd.metadataId_ == iptc) { if (modifyCmd.metadataId_ == iptc) {
image_->iptcData().add(Exiv2::IptcKey(modifyCmd.key_), value.get()); image_->iptcData().add(Exiv2::IptcKey(modifyCmd.key_), value.get());
}
} }
} }
@ -1100,8 +1101,9 @@ namespace Action {
if (modifyCmd.explicitType_ || value.get() == 0) { if (modifyCmd.explicitType_ || value.get() == 0) {
value = Exiv2::Value::create(modifyCmd.typeId_); value = Exiv2::Value::create(modifyCmd.typeId_);
} }
value->read(modifyCmd.value_); if (0 == value->read(modifyCmd.value_)) {
metadatum->setValue(value.get()); metadatum->setValue(value.get());
}
} }
void Modify::delMetadatum(const ModifyCmd& modifyCmd) void Modify::delMetadatum(const ModifyCmd& modifyCmd)

@ -136,7 +136,6 @@ namespace Exiv2 {
const byte* pRead = buf; const byte* pRead = buf;
iptcMetadata_.clear(); iptcMetadata_.clear();
int rc = 0;
uint16_t record = 0; uint16_t record = 0;
uint16_t dataSet = 0; uint16_t dataSet = 0;
uint32_t sizeData = 0; uint32_t sizeData = 0;
@ -166,12 +165,11 @@ namespace Exiv2 {
sizeData = getUShort(pRead, bigEndian); sizeData = getUShort(pRead, bigEndian);
pRead += 2; pRead += 2;
} }
rc = readData(dataSet, record, pRead, sizeData); readData(dataSet, record, pRead, sizeData);
if( rc ) return rc;
pRead += sizeData; pRead += sizeData;
} }
return rc; return 0;
} // IptcData::read } // IptcData::read
int IptcData::readData(uint16_t dataSet, uint16_t record, int IptcData::readData(uint16_t dataSet, uint16_t record,
@ -180,10 +178,12 @@ namespace Exiv2 {
Value::AutoPtr value; Value::AutoPtr value;
TypeId type = IptcDataSets::dataSetType(dataSet, record); TypeId type = IptcDataSets::dataSetType(dataSet, record);
value = Value::create(type); value = Value::create(type);
value->read(data, sizeData, bigEndian); int rc = value->read(data, sizeData, bigEndian);
IptcKey key(dataSet, record); if (0 == rc) {
add(key, value.get()); IptcKey key(dataSet, record);
return 0; add(key, value.get());
}
return rc;
} }
DataBuf IptcData::copy() DataBuf IptcData::copy()

@ -130,13 +130,14 @@ namespace Exiv2 {
return *this; return *this;
} }
void DataValue::read(const byte* buf, long len, ByteOrder byteOrder) int DataValue::read(const byte* buf, long len, ByteOrder byteOrder)
{ {
// byteOrder not needed // byteOrder not needed
value_.assign(buf, buf + len); value_.assign(buf, buf + len);
return 0;
} }
void DataValue::read(const std::string& buf) int DataValue::read(const std::string& buf)
{ {
std::istringstream is(buf); std::istringstream is(buf);
int tmp; int tmp;
@ -144,6 +145,7 @@ namespace Exiv2 {
while (is >> tmp) { while (is >> tmp) {
value_.push_back(static_cast<byte>(tmp)); value_.push_back(static_cast<byte>(tmp));
} }
return 0;
} }
long DataValue::copy(byte* buf, ByteOrder byteOrder) const long DataValue::copy(byte* buf, ByteOrder byteOrder) const
@ -181,15 +183,17 @@ namespace Exiv2 {
return *this; return *this;
} }
void StringValueBase::read(const std::string& buf) int StringValueBase::read(const std::string& buf)
{ {
value_ = buf; value_ = buf;
return 0;
} }
void StringValueBase::read(const byte* buf, long len, ByteOrder byteOrder) int StringValueBase::read(const byte* buf, long len, ByteOrder byteOrder)
{ {
// byteOrder not needed // byteOrder not needed
value_ = std::string(reinterpret_cast<const char*>(buf), len); value_ = std::string(reinterpret_cast<const char*>(buf), len);
return 0;
} }
long StringValueBase::copy(byte* buf, ByteOrder byteOrder) const long StringValueBase::copy(byte* buf, ByteOrder byteOrder) const
@ -229,10 +233,11 @@ namespace Exiv2 {
return *this; return *this;
} }
void AsciiValue::read(const std::string& buf) int AsciiValue::read(const std::string& buf)
{ {
value_ = buf; value_ = buf;
if (value_[value_.size()-1] != '\0') value_ += '\0'; if (value_[value_.size()-1] != '\0') value_ += '\0';
return 0;
} }
AsciiValue* AsciiValue::clone_() const AsciiValue* AsciiValue::clone_() const
@ -307,23 +312,28 @@ namespace Exiv2 {
return *this; return *this;
} }
void CommentValue::read(const std::string& comment) int CommentValue::read(const std::string& comment)
{ {
std::string c = comment; std::string c = comment;
CharsetId charsetId = undefined; CharsetId charsetId = undefined;
if (comment.length() > 8 && comment.substr(0, 8) == "charset=") { if (comment.length() > 8 && comment.substr(0, 8) == "charset=") {
std::string::size_type pos = comment.find_first_of(' '); std::string::size_type pos = comment.find_first_of(' ');
std::string name = comment.substr(8, pos-8); std::string name = comment.substr(8, pos-8);
// Strip quotes (so you can also to specify the charset without quotes) // Strip quotes (so you can also specify the charset without quotes)
if (name[0] == '"') name = name.substr(1); if (name[0] == '"') name = name.substr(1);
if (name[name.length()-1] == '"') name = name.substr(0, name.length()-1); if (name[name.length()-1] == '"') name = name.substr(0, name.length()-1);
charsetId = CharsetInfo::charsetIdByName(name); charsetId = CharsetInfo::charsetIdByName(name);
if (charsetId == invalidCharsetId) throw Error(28, name); if (charsetId == invalidCharsetId) {
#ifndef SUPPRESS_WARNINGS
std::cerr << Error(28, name) << "\n";
#endif
return 1;
}
c.clear(); c.clear();
if (pos != std::string::npos) c = comment.substr(pos+1); if (pos != std::string::npos) c = comment.substr(pos+1);
} }
const std::string code(CharsetInfo::code(charsetId), 8); const std::string code(CharsetInfo::code(charsetId), 8);
StringValueBase::read(code + c); return StringValueBase::read(code + c);
} }
std::ostream& CommentValue::write(std::ostream& os) const std::ostream& CommentValue::write(std::ostream& os) const
@ -374,43 +384,62 @@ namespace Exiv2 {
return *this; return *this;
} }
void DateValue::read(const byte* buf, long len, ByteOrder byteOrder) int DateValue::read(const byte* buf, long len, ByteOrder /*byteOrder*/)
{ {
// byteOrder not needed
// Hard coded to read Iptc style dates // Hard coded to read Iptc style dates
if (len != 8) throw Error(29); if (len != 8) {
#ifndef SUPPRESS_WARNINGS
std::cerr << Error(29) << "\n";
#endif
return 1;
}
int scanned = sscanf(reinterpret_cast<const char*>(buf), int scanned = sscanf(reinterpret_cast<const char*>(buf),
"%4d%2d%2d", "%4d%2d%2d",
&date_.year, &date_.month, &date_.day); &date_.year, &date_.month, &date_.day);
if (scanned != 3) throw Error(29); if (scanned != 3) {
#ifndef SUPPRESS_WARNINGS
std::cerr << Error(29) << "\n";
#endif
return 1;
}
return 0;
} }
void DateValue::read(const std::string& buf) int DateValue::read(const std::string& buf)
{ {
// byteOrder not needed
// Hard coded to read Iptc style dates // Hard coded to read Iptc style dates
if (buf.length() < 8) throw Error(29); if (buf.length() < 8) {
#ifndef SUPPRESS_WARNINGS
std::cerr << Error(29) << "\n";
#endif
return 1;
}
int scanned = sscanf(buf.data(), int scanned = sscanf(buf.data(),
"%4d-%d-%d", "%4d-%d-%d",
&date_.year, &date_.month, &date_.day); &date_.year, &date_.month, &date_.day);
if (scanned != 3) throw Error(29); if (scanned != 3) {
#ifndef SUPPRESS_WARNINGS
std::cerr << Error(29) << "\n";
#endif
return 1;
}
return 0;
} }
void DateValue::setDate( const Date& src ) void DateValue::setDate(const Date& src)
{ {
date_.year = src.year; date_.year = src.year;
date_.month = src.month; date_.month = src.month;
date_.day = src.day; date_.day = src.day;
} }
long DateValue::copy(byte* buf, ByteOrder byteOrder) const long DateValue::copy(byte* buf, ByteOrder /*byteOrder*/) const
{ {
// byteOrder not needed
// sprintf wants to add the null terminator, so use oversized buffer // sprintf wants to add the null terminator, so use oversized buffer
char temp[9]; char temp[9];
int wrote = sprintf( temp, "%04d%02d%02d", int wrote = sprintf(temp, "%04d%02d%02d",
date_.year, date_.month, date_.day); date_.year, date_.month, date_.day);
assert(wrote == 8); assert(wrote == 8);
memcpy(buf, temp, 8); memcpy(buf, temp, 8);
return 8; return 8;
@ -465,40 +494,82 @@ namespace Exiv2 {
return *this; return *this;
} }
void TimeValue::read(const byte* buf, long len, ByteOrder byteOrder) int TimeValue::read(const byte* buf, long len, ByteOrder /*byteOrder*/)
{ {
// byteOrder not needed // Hard coded to read HHMMSS or Iptc style times
// Hard coded to read Iptc style times int rc = 1;
if (len != 11) throw Error(30); if (len == 6) {
char plusMinus; // Try to read (non-standard) HHMMSS format
int scanned = sscanf(reinterpret_cast<const char*>(buf), rc = scanTime3(reinterpret_cast<const char*>(buf),
"%2d%2d%2d%1c%2d%2d", "%2d%2d%2d");
&time_.hour, &time_.minute, &time_.second,
&plusMinus, &time_.tzHour, &time_.tzMinute );
if (scanned != 6) throw Error(30);
if (plusMinus == '-') {
time_.tzHour *= -1;
time_.tzMinute *= -1;
} }
if (len == 11) {
rc = scanTime6(reinterpret_cast<const char*>(buf),
"%2d%2d%2d%1c%2d%2d");
}
#ifndef SUPPRESS_WARNINGS
if (rc) {
std::cerr << Error(30) << "\n";
}
#endif
return rc;
} }
void TimeValue::read(const std::string& buf) int TimeValue::read(const std::string& buf)
{ {
// byteOrder not needed // Hard coded to read H:M:S or Iptc style times
// Hard coded to read Iptc style times int rc = 1;
if (buf.length() < 9) throw Error(30); if (buf.length() < 9) {
// Try to read (non-standard) H:M:S format
rc = scanTime3(buf.data(), "%d:%d:%d");
}
else {
rc = scanTime6(buf.data(), "%d:%d:%d%1c%d:%d");
}
#ifndef SUPPRESS_WARNINGS
if (rc) {
std::cerr << Error(30) << "\n";
}
#endif
return rc;
}
int TimeValue::scanTime3(const char* buf, const char* format)
{
int rc = 1;
Time t;
int scanned = sscanf(buf, format, &t.hour, &t.minute, &t.second);
if ( scanned == 3
&& t.hour >= 0 && t.hour < 24
&& t.minute >= 0 && t.minute < 60
&& t.second >= 0 && t.second < 60) {
time_ = t;
rc = 0;
}
return rc;
}
int TimeValue::scanTime6(const char* buf, const char* format)
{
int rc = 1;
Time t;
char plusMinus; char plusMinus;
int scanned = sscanf(buf.data(), int scanned = sscanf(buf, format, &t.hour, &t.minute, &t.second,
"%d:%d:%d%1c%d:%d", &plusMinus, &t.tzHour, &t.tzMinute);
&time_.hour, &time_.minute, &time_.second, if ( scanned == 6
&plusMinus, &time_.tzHour, &time_.tzMinute ); && t.hour >= 0 && t.hour < 24
&& t.minute >= 0 && t.minute < 60
if (scanned != 6) throw Error(30); && t.second >= 0 && t.second < 60
if (plusMinus == '-') { && t.tzHour >= 0 && t.tzHour < 24
time_.tzHour *= -1; && t.tzMinute >= 0 && t.tzMinute < 60) {
time_.tzMinute *= -1; time_ = t;
if (plusMinus == '-') {
time_.tzHour *= -1;
time_.tzMinute *= -1;
}
rc = 0;
} }
return rc;
} }
void TimeValue::setTime( const Time& src ) void TimeValue::setTime( const Time& src )
@ -506,9 +577,8 @@ namespace Exiv2 {
memcpy(&time_, &src, sizeof(time_)); memcpy(&time_, &src, sizeof(time_));
} }
long TimeValue::copy(byte* buf, ByteOrder byteOrder) const long TimeValue::copy(byte* buf, ByteOrder /*byteOrder*/) const
{ {
// byteOrder not needed
// sprintf wants to add the null terminator, so use oversized buffer // sprintf wants to add the null terminator, so use oversized buffer
char temp[12]; char temp[12];
char plusMinus = '+'; char plusMinus = '+';

@ -83,8 +83,10 @@ namespace Exiv2 {
@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). @param byteOrder Applicable byte order (little or big endian).
@return 0 if successful.
*/ */
virtual void read(const byte* buf, long len, ByteOrder byteOrder) =0; virtual int read(const byte* buf, long len, ByteOrder byteOrder) =0;
/*! /*!
@brief Set the value from a string buffer. The format of the string @brief Set the value from a string buffer. The format of the string
corresponds to that of the write() method, i.e., a string corresponds to that of the write() method, i.e., a string
@ -92,8 +94,10 @@ namespace Exiv2 {
function. function.
@param buf The string to read from. @param buf The string to read from.
@return 0 if successful.
*/ */
virtual void read(const std::string& buf) =0; virtual int read(const std::string& buf) =0;
/*! /*!
@brief Set the data area, if the value has one by copying (cloning) @brief Set the data area, if the value has one by copying (cloning)
the buffer pointed to by buf. the buffer pointed to by buf.
@ -270,12 +274,14 @@ namespace Exiv2 {
@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 Byte order. Not needed. @param byteOrder Byte order. Not needed.
@return 0 if successful.
*/ */
virtual void read(const byte* buf, virtual int read(const byte* buf,
long len, long len,
ByteOrder byteOrder =invalidByteOrder); ByteOrder byteOrder =invalidByteOrder);
//! Set the data from a string of integer values (e.g., "0 1 2 3") //! Set the data from a string of integer values (e.g., "0 1 2 3")
virtual void read(const std::string& buf); virtual int read(const std::string& buf);
//@} //@}
//! @name Accessors //! @name Accessors
@ -344,7 +350,7 @@ namespace Exiv2 {
//! Assignment operator. //! Assignment operator.
StringValueBase& operator=(const StringValueBase& rhs); StringValueBase& operator=(const StringValueBase& rhs);
//! Read the value from buf. This default implementation uses buf as it is. //! Read the value from buf. This default implementation uses buf as it is.
virtual void read(const std::string& buf); virtual int read(const std::string& buf);
/*! /*!
@brief Read the value from a character buffer. @brief Read the value from a character buffer.
@ -354,8 +360,10 @@ namespace Exiv2 {
@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 Byte order. Not needed. @param byteOrder Byte order. Not needed.
@return 0 if successful.
*/ */
virtual void read(const byte* buf, virtual int read(const byte* buf,
long len, long len,
ByteOrder byteOrder =invalidByteOrder); ByteOrder byteOrder =invalidByteOrder);
//@} //@}
@ -472,7 +480,7 @@ namespace Exiv2 {
to append a terminating '\\0' character if buf doesn't end to append a terminating '\\0' character if buf doesn't end
with '\\0'. with '\\0'.
*/ */
virtual void read(const std::string& buf); virtual int read(const std::string& buf);
//@} //@}
//! @name Accessors //! @name Accessors
@ -568,9 +576,10 @@ namespace Exiv2 {
<BR> <BR>
The default charset is Undefined. The default charset is Undefined.
@throw Error if an invalid character set is encountered @return 0 if successful<BR>
1 if an invalid character set is encountered
*/ */
void read(const std::string& comment); int read(const std::string& comment);
//@} //@}
//! @name Accessors //! @name Accessors
@ -636,9 +645,10 @@ namespace Exiv2 {
@param len Number of bytes in the data buffer @param len Number of bytes in the data buffer
@param byteOrder Byte order. Not needed. @param byteOrder Byte order. Not needed.
@throw Error in case of an unsupported date format @return 0 if successful<BR>
1 in case of an unsupported date format
*/ */
virtual void read(const byte* buf, virtual int read(const byte* buf,
long len, long len,
ByteOrder byteOrder =invalidByteOrder); ByteOrder byteOrder =invalidByteOrder);
/*! /*!
@ -646,9 +656,10 @@ namespace Exiv2 {
@param buf String containing the date @param buf String containing the date
@throw Error in case of an unsupported date format @return 0 if successful<BR>
1 in case of an unsupported date format
*/ */
virtual void read(const std::string& buf); virtual int read(const std::string& buf);
//! Set the date //! Set the date
void setDate(const Date& src); void setDate(const Date& src);
//@} //@}
@ -721,6 +732,8 @@ namespace Exiv2 {
//! Simple Time helper structure //! Simple Time helper structure
struct Time struct Time
{ {
Time() : hour(0), minute(0), second(0), tzHour(0), tzMinute(0) {}
int hour; //!< Hour int hour; //!< Hour
int minute; //!< Minute int minute; //!< Minute
int second; //!< Second int second; //!< Second
@ -742,19 +755,21 @@ namespace Exiv2 {
@param len Number of bytes in the data buffer @param len Number of bytes in the data buffer
@param byteOrder Byte order. Not needed. @param byteOrder Byte order. Not needed.
@throw Error in case of an unsupported time format @return 0 if successful<BR>
1 in case of an unsupported time format
*/ */
virtual void read(const byte* buf, virtual int read(const byte* buf,
long len, long len,
ByteOrder byteOrder =invalidByteOrder); ByteOrder byteOrder =invalidByteOrder);
/*! /*!
@brief Set the value to that of the string buf. @brief Set the value to that of the string buf.
@param buf String containing the time. @param buf String containing the time.
@throw Error in case of an unsupported time format @return 0 if successful<BR>
1 in case of an unsupported time format
*/ */
virtual void read(const std::string& buf); virtual int read(const std::string& buf);
//! Set the time //! Set the time
void setTime(const Time& src); void setTime(const Time& src);
//@} //@}
@ -780,9 +795,7 @@ namespace Exiv2 {
virtual const Time& getTime() const { return time_; } virtual const Time& getTime() const { return time_; }
virtual long count() const { return size(); } virtual long count() const { return size(); }
virtual long size() const; virtual long size() const;
/*! //! Write the value to an output stream. .
@brief Write the value to an output stream. .
*/
virtual std::ostream& write(std::ostream& os) const; virtual std::ostream& write(std::ostream& os) const;
virtual long toLong(long n =0) const; virtual long toLong(long n =0) const;
virtual float toFloat(long n =0) const virtual float toFloat(long n =0) const
@ -792,8 +805,20 @@ namespace Exiv2 {
//@} //@}
private: private:
//! @name Manipulators
//@{
//! Set time from \em buf if it conforms to \em format (3 input items)
int scanTime3(const char* buf, const char* format);
//! Set time from \em buf if it conforms to \em format (6 input items)
int scanTime6(const char* buf, const char* format);
//@}
//! @name Accessors
//@{
//! Internal virtual copy constructor. //! Internal virtual copy constructor.
virtual TimeValue* clone_() const; virtual TimeValue* clone_() const;
//@}
// DATA // DATA
Time time_; Time time_;
@ -845,14 +870,14 @@ namespace Exiv2 {
//@{ //@{
//! Assignment operator. //! Assignment operator.
ValueType<T>& operator=(const ValueType<T>& rhs); ValueType<T>& operator=(const ValueType<T>& rhs);
virtual void read(const byte* buf, long len, ByteOrder byteOrder); virtual int read(const byte* buf, long len, ByteOrder byteOrder);
/*! /*!
@brief Set the data from a string of values of type T (e.g., @brief Set the data from a string of values of type T (e.g.,
"0 1 2 3" or "1/2 1/3 1/4" depending on what T is). "0 1 2 3" or "1/2 1/3 1/4" depending on what T is).
Generally, the accepted input format is the same as that Generally, the accepted input format is the same as that
produced by the write() method. produced by the write() method.
*/ */
virtual void read(const std::string& buf); virtual int read(const std::string& buf);
/*! /*!
@brief Set the data area. This method copies (clones) the buffer @brief Set the data area. This method copies (clones) the buffer
pointed to by buf. pointed to by buf.
@ -1092,16 +1117,17 @@ namespace Exiv2 {
} }
template<typename T> template<typename T>
void ValueType<T>::read(const byte* buf, long len, ByteOrder byteOrder) int ValueType<T>::read(const byte* buf, long len, ByteOrder byteOrder)
{ {
value_.clear(); value_.clear();
for (long i = 0; i < len; i += TypeInfo::typeSize(typeId())) { for (long i = 0; i < len; i += TypeInfo::typeSize(typeId())) {
value_.push_back(getValue<T>(buf + i, byteOrder)); value_.push_back(getValue<T>(buf + i, byteOrder));
} }
return 0;
} }
template<typename T> template<typename T>
void ValueType<T>::read(const std::string& buf) int ValueType<T>::read(const std::string& buf)
{ {
std::istringstream is(buf); std::istringstream is(buf);
T tmp; T tmp;
@ -1109,6 +1135,7 @@ namespace Exiv2 {
while (is >> tmp) { while (is >> tmp) {
value_.push_back(tmp); value_.push_back(tmp);
} }
return 0;
} }
template<typename T> template<typename T>

Loading…
Cancel
Save