From c32e706c3657e3276da2f3a3cd43566148d95dbc Mon Sep 17 00:00:00 2001 From: Andreas Huggel Date: Sat, 8 Oct 2005 11:34:32 +0000 Subject: [PATCH] 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. --- src/actions.cpp | 18 ++--- src/iptc.cpp | 16 ++--- src/value.cpp | 172 ++++++++++++++++++++++++++++++++++-------------- src/value.hpp | 79 ++++++++++++++-------- 4 files changed, 192 insertions(+), 93 deletions(-) diff --git a/src/actions.cpp b/src/actions.cpp index f8f02dce..be940764 100644 --- a/src/actions.cpp +++ b/src/actions.cpp @@ -1065,12 +1065,13 @@ namespace Action { << ")" << std::endl; } Exiv2::Value::AutoPtr value = Exiv2::Value::create(modifyCmd.typeId_); - value->read(modifyCmd.value_); - if (modifyCmd.metadataId_ == exif) { - image_->exifData().add(Exiv2::ExifKey(modifyCmd.key_), value.get()); - } - if (modifyCmd.metadataId_ == iptc) { - image_->iptcData().add(Exiv2::IptcKey(modifyCmd.key_), value.get()); + if (0 == value->read(modifyCmd.value_)) { + if (modifyCmd.metadataId_ == exif) { + image_->exifData().add(Exiv2::ExifKey(modifyCmd.key_), value.get()); + } + if (modifyCmd.metadataId_ == iptc) { + image_->iptcData().add(Exiv2::IptcKey(modifyCmd.key_), value.get()); + } } } @@ -1100,8 +1101,9 @@ namespace Action { if (modifyCmd.explicitType_ || value.get() == 0) { value = Exiv2::Value::create(modifyCmd.typeId_); } - value->read(modifyCmd.value_); - metadatum->setValue(value.get()); + if (0 == value->read(modifyCmd.value_)) { + metadatum->setValue(value.get()); + } } void Modify::delMetadatum(const ModifyCmd& modifyCmd) diff --git a/src/iptc.cpp b/src/iptc.cpp index 4bea0422..a53b0972 100644 --- a/src/iptc.cpp +++ b/src/iptc.cpp @@ -136,7 +136,6 @@ namespace Exiv2 { const byte* pRead = buf; iptcMetadata_.clear(); - int rc = 0; uint16_t record = 0; uint16_t dataSet = 0; uint32_t sizeData = 0; @@ -166,12 +165,11 @@ namespace Exiv2 { sizeData = getUShort(pRead, bigEndian); pRead += 2; } - rc = readData(dataSet, record, pRead, sizeData); - if( rc ) return rc; + readData(dataSet, record, pRead, sizeData); pRead += sizeData; } - return rc; + return 0; } // IptcData::read int IptcData::readData(uint16_t dataSet, uint16_t record, @@ -180,10 +178,12 @@ namespace Exiv2 { Value::AutoPtr value; TypeId type = IptcDataSets::dataSetType(dataSet, record); value = Value::create(type); - value->read(data, sizeData, bigEndian); - IptcKey key(dataSet, record); - add(key, value.get()); - return 0; + int rc = value->read(data, sizeData, bigEndian); + if (0 == rc) { + IptcKey key(dataSet, record); + add(key, value.get()); + } + return rc; } DataBuf IptcData::copy() diff --git a/src/value.cpp b/src/value.cpp index b3a6e58a..1a43c222 100644 --- a/src/value.cpp +++ b/src/value.cpp @@ -130,13 +130,14 @@ namespace Exiv2 { 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 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); int tmp; @@ -144,6 +145,7 @@ namespace Exiv2 { while (is >> tmp) { value_.push_back(static_cast(tmp)); } + return 0; } long DataValue::copy(byte* buf, ByteOrder byteOrder) const @@ -181,15 +183,17 @@ namespace Exiv2 { return *this; } - void StringValueBase::read(const std::string& buf) + int StringValueBase::read(const std::string& 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 value_ = std::string(reinterpret_cast(buf), len); + return 0; } long StringValueBase::copy(byte* buf, ByteOrder byteOrder) const @@ -229,10 +233,11 @@ namespace Exiv2 { return *this; } - void AsciiValue::read(const std::string& buf) + int AsciiValue::read(const std::string& buf) { value_ = buf; if (value_[value_.size()-1] != '\0') value_ += '\0'; + return 0; } AsciiValue* AsciiValue::clone_() const @@ -307,23 +312,28 @@ namespace Exiv2 { return *this; } - void CommentValue::read(const std::string& comment) + int CommentValue::read(const std::string& comment) { std::string c = comment; CharsetId charsetId = undefined; if (comment.length() > 8 && comment.substr(0, 8) == "charset=") { std::string::size_type pos = comment.find_first_of(' '); 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[name.length()-1] == '"') name = name.substr(0, name.length()-1); 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(); if (pos != std::string::npos) c = comment.substr(pos+1); } 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 @@ -374,43 +384,62 @@ namespace Exiv2 { 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 - 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(buf), "%4d%2d%2d", &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 - 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(), "%4d-%d-%d", &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_.month = src.month; 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 char temp[9]; - int wrote = sprintf( temp, "%04d%02d%02d", - date_.year, date_.month, date_.day); + int wrote = sprintf(temp, "%04d%02d%02d", + date_.year, date_.month, date_.day); assert(wrote == 8); memcpy(buf, temp, 8); return 8; @@ -465,40 +494,82 @@ namespace Exiv2 { 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 Iptc style times - if (len != 11) throw Error(30); - char plusMinus; - int scanned = sscanf(reinterpret_cast(buf), - "%2d%2d%2d%1c%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; + // Hard coded to read HHMMSS or Iptc style times + int rc = 1; + if (len == 6) { + // Try to read (non-standard) HHMMSS format + rc = scanTime3(reinterpret_cast(buf), + "%2d%2d%2d"); } + if (len == 11) { + rc = scanTime6(reinterpret_cast(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 Iptc style times - if (buf.length() < 9) throw Error(30); + // Hard coded to read H:M:S or Iptc style times + int rc = 1; + 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; - int scanned = sscanf(buf.data(), - "%d:%d:%d%1c%d:%d", - &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; + int scanned = sscanf(buf, format, &t.hour, &t.minute, &t.second, + &plusMinus, &t.tzHour, &t.tzMinute); + if ( scanned == 6 + && t.hour >= 0 && t.hour < 24 + && t.minute >= 0 && t.minute < 60 + && t.second >= 0 && t.second < 60 + && t.tzHour >= 0 && t.tzHour < 24 + && t.tzMinute >= 0 && t.tzMinute < 60) { + time_ = t; + if (plusMinus == '-') { + time_.tzHour *= -1; + time_.tzMinute *= -1; + } + rc = 0; } + return rc; } void TimeValue::setTime( const Time& src ) @@ -506,9 +577,8 @@ namespace Exiv2 { 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 char temp[12]; char plusMinus = '+'; diff --git a/src/value.hpp b/src/value.hpp index 734648a5..fb94ee7e 100644 --- a/src/value.hpp +++ b/src/value.hpp @@ -83,8 +83,10 @@ namespace Exiv2 { @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). + + @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 corresponds to that of the write() method, i.e., a string @@ -92,8 +94,10 @@ namespace Exiv2 { function. @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) the buffer pointed to by buf. @@ -270,12 +274,14 @@ namespace Exiv2 { @param buf Pointer to the data buffer to read from @param len Number of bytes in the data buffer @param byteOrder Byte order. Not needed. + + @return 0 if successful. */ - virtual void read(const byte* buf, + virtual int read(const byte* buf, long len, ByteOrder byteOrder =invalidByteOrder); //! 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 @@ -344,7 +350,7 @@ namespace Exiv2 { //! Assignment operator. StringValueBase& operator=(const StringValueBase& rhs); //! 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. @@ -354,8 +360,10 @@ namespace Exiv2 { @param buf Pointer to the data buffer to read from @param len Number of bytes in the data buffer @param byteOrder Byte order. Not needed. + + @return 0 if successful. */ - virtual void read(const byte* buf, + virtual int read(const byte* buf, long len, ByteOrder byteOrder =invalidByteOrder); //@} @@ -472,7 +480,7 @@ namespace Exiv2 { to append a terminating '\\0' character if buf doesn't end with '\\0'. */ - virtual void read(const std::string& buf); + virtual int read(const std::string& buf); //@} //! @name Accessors @@ -568,9 +576,10 @@ namespace Exiv2 {
The default charset is Undefined. - @throw Error if an invalid character set is encountered + @return 0 if successful
+ 1 if an invalid character set is encountered */ - void read(const std::string& comment); + int read(const std::string& comment); //@} //! @name Accessors @@ -636,9 +645,10 @@ namespace Exiv2 { @param len Number of bytes in the data buffer @param byteOrder Byte order. Not needed. - @throw Error in case of an unsupported date format + @return 0 if successful
+ 1 in case of an unsupported date format */ - virtual void read(const byte* buf, + virtual int read(const byte* buf, long len, ByteOrder byteOrder =invalidByteOrder); /*! @@ -646,9 +656,10 @@ namespace Exiv2 { @param buf String containing the date - @throw Error in case of an unsupported date format + @return 0 if successful
+ 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 void setDate(const Date& src); //@} @@ -721,6 +732,8 @@ namespace Exiv2 { //! Simple Time helper structure struct Time { + Time() : hour(0), minute(0), second(0), tzHour(0), tzMinute(0) {} + int hour; //!< Hour int minute; //!< Minute int second; //!< Second @@ -742,19 +755,21 @@ namespace Exiv2 { @param len Number of bytes in the data buffer @param byteOrder Byte order. Not needed. - @throw Error in case of an unsupported time format + @return 0 if successful
+ 1 in case of an unsupported time format */ - virtual void read(const byte* buf, - long len, - ByteOrder byteOrder =invalidByteOrder); + virtual int read(const byte* buf, + long len, + ByteOrder byteOrder =invalidByteOrder); /*! @brief Set the value to that of the string buf. @param buf String containing the time. - @throw Error in case of an unsupported time format + @return 0 if successful
+ 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 void setTime(const Time& src); //@} @@ -780,9 +795,7 @@ namespace Exiv2 { virtual const Time& getTime() const { return time_; } virtual long count() const { return size(); } virtual long size() const; - /*! - @brief Write the value to an output stream. . - */ + //! Write the value to an output stream. . virtual std::ostream& write(std::ostream& os) const; virtual long toLong(long n =0) const; virtual float toFloat(long n =0) const @@ -792,8 +805,20 @@ namespace Exiv2 { //@} 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. virtual TimeValue* clone_() const; + //@} + // DATA Time time_; @@ -845,14 +870,14 @@ namespace Exiv2 { //@{ //! Assignment operator. ValueType& operator=(const ValueType& 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., "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 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 pointed to by buf. @@ -1092,16 +1117,17 @@ namespace Exiv2 { } template - void ValueType::read(const byte* buf, long len, ByteOrder byteOrder) + int ValueType::read(const byte* buf, long len, ByteOrder byteOrder) { value_.clear(); for (long i = 0; i < len; i += TypeInfo::typeSize(typeId())) { value_.push_back(getValue(buf + i, byteOrder)); } + return 0; } template - void ValueType::read(const std::string& buf) + int ValueType::read(const std::string& buf) { std::istringstream is(buf); T tmp; @@ -1109,6 +1135,7 @@ namespace Exiv2 { while (is >> tmp) { value_.push_back(tmp); } + return 0; } template