1
// ***************************************************************** -*- C++ -*-
3
* Copyright (C) 2004, 2005 Andreas Huggel <ahuggel@gmx.net>
5
* This program is part of the Exiv2 distribution.
7
* This program is free software; you can redistribute it and/or
8
* modify it under the terms of the GNU General Public License
9
* as published by the Free Software Foundation; either version 2
10
* of the License, or (at your option) any later version.
12
* This program is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
* GNU General Public License for more details.
17
* You should have received a copy of the GNU General Public License
18
* along with this program; if not, write to the Free Software
19
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24
Author(s): Andreas Huggel (ahu) <ahuggel@gmx.net>
25
History: 26-Jan-04, ahu: created
26
11-Feb-04, ahu: isolated as a component
27
31-Jul-04, brad: added Time, Date and String values
29
// *****************************************************************************
31
EXIV2_RCSID("@(#) $Id: value.cpp 560 2005-04-17 11:51:32Z ahuggel $");
33
// *****************************************************************************
34
// included header files
39
// + standard includes
48
// *****************************************************************************
49
// class member definitions
52
Value& Value::operator=(const Value& rhs)
54
if (this == &rhs) return *this;
59
Value::AutoPtr Value::create(TypeId typeId)
64
value = AutoPtr(new DataValue(invalidTypeId));
67
value = AutoPtr(new DataValue(unsignedByte));
70
value = AutoPtr(new AsciiValue);
73
value = AutoPtr(new ValueType<uint16_t>);
76
value = AutoPtr(new ValueType<uint32_t>);
78
case unsignedRational:
79
value = AutoPtr(new ValueType<URational>);
82
value = AutoPtr(new DataValue(invalid6));
85
value = AutoPtr(new DataValue);
88
value = AutoPtr(new ValueType<int16_t>);
91
value = AutoPtr(new ValueType<int32_t>);
94
value = AutoPtr(new ValueType<Rational>);
97
value = AutoPtr(new StringValue);
100
value = AutoPtr(new DateValue);
103
value = AutoPtr(new TimeValue);
106
value = AutoPtr(new CommentValue);
109
value = AutoPtr(new DataValue(typeId));
115
std::string Value::toString() const
117
std::ostringstream os;
122
DataValue& DataValue::operator=(const DataValue& rhs)
124
if (this == &rhs) return *this;
125
Value::operator=(rhs);
130
void DataValue::read(const byte* buf, long len, ByteOrder byteOrder)
132
// byteOrder not needed
133
value_.assign(buf, buf + len);
136
void DataValue::read(const std::string& buf)
138
std::istringstream is(buf);
142
value_.push_back(static_cast<byte>(tmp));
146
long DataValue::copy(byte* buf, ByteOrder byteOrder) const
148
// byteOrder not needed
149
return static_cast<long>(
150
std::copy(value_.begin(), value_.end(), buf) - buf
154
long DataValue::size() const
156
return static_cast<long>(value_.size());
159
DataValue* DataValue::clone_() const
161
return new DataValue(*this);
164
std::ostream& DataValue::write(std::ostream& os) const
166
std::vector<byte>::size_type end = value_.size();
167
for (std::vector<byte>::size_type i = 0; i != end; ++i) {
168
os << static_cast<int>(value_[i]) << " ";
173
StringValueBase& StringValueBase::operator=(const StringValueBase& rhs)
175
if (this == &rhs) return *this;
176
Value::operator=(rhs);
181
void StringValueBase::read(const std::string& buf)
186
void StringValueBase::read(const byte* buf, long len, ByteOrder byteOrder)
188
// byteOrder not needed
189
value_ = std::string(reinterpret_cast<const char*>(buf), len);
192
long StringValueBase::copy(byte* buf, ByteOrder byteOrder) const
194
// byteOrder not needed
195
return static_cast<long>(
196
value_.copy(reinterpret_cast<char*>(buf), value_.size())
200
long StringValueBase::size() const
202
return static_cast<long>(value_.size());
205
std::ostream& StringValueBase::write(std::ostream& os) const
210
StringValue& StringValue::operator=(const StringValue& rhs)
212
if (this == &rhs) return *this;
213
StringValueBase::operator=(rhs);
217
StringValue* StringValue::clone_() const
219
return new StringValue(*this);
222
AsciiValue& AsciiValue::operator=(const AsciiValue& rhs)
224
if (this == &rhs) return *this;
225
StringValueBase::operator=(rhs);
229
void AsciiValue::read(const std::string& buf)
232
if (value_[value_.size()-1] != '\0') value_ += '\0';
235
AsciiValue* AsciiValue::clone_() const
237
return new AsciiValue(*this);
240
std::ostream& AsciiValue::write(std::ostream& os) const
242
// Strip all trailing '\0's (if any)
243
std::string::size_type pos = value_.find_last_not_of('\0');
244
return os << value_.substr(0, pos + 1);
247
CommentValue::CharsetTable::CharsetTable(CharsetId charsetId,
250
: charsetId_(charsetId), name_(name), code_(code)
254
//! Lookup list of supported IFD type information
255
const CommentValue::CharsetTable CommentValue::CharsetInfo::charsetTable_[] = {
256
CharsetTable(ascii, "Ascii", "ASCII\0\0\0"),
257
CharsetTable(jis, "Jis", "JIS\0\0\0\0\0"),
258
CharsetTable(unicode, "Unicode", "UNICODE\0"),
259
CharsetTable(undefined, "Undefined", "\0\0\0\0\0\0\0\0"),
260
CharsetTable(invalidCharsetId, "InvalidCharsetId", "\0\0\0\0\0\0\0\0"),
261
CharsetTable(lastCharsetId, "InvalidCharsetId", "\0\0\0\0\0\0\0\0")
264
const char* CommentValue::CharsetInfo::name(CharsetId charsetId)
266
return charsetTable_[ charsetId < lastCharsetId ? charsetId : undefined ].name_;
269
const char* CommentValue::CharsetInfo::code(CharsetId charsetId)
271
return charsetTable_[ charsetId < lastCharsetId ? charsetId : undefined ].code_;
274
CommentValue::CharsetId CommentValue::CharsetInfo::charsetIdByName(
275
const std::string& name)
278
for (; charsetTable_[i].charsetId_ != lastCharsetId
279
&& charsetTable_[i].name_ != name; ++i) {}
280
return charsetTable_[i].charsetId_ == lastCharsetId ?
281
invalidCharsetId : charsetTable_[i].charsetId_;
284
CommentValue::CharsetId CommentValue::CharsetInfo::charsetIdByCode(
285
const std::string& code)
288
for (; charsetTable_[i].charsetId_ != lastCharsetId
289
&& std::string(charsetTable_[i].code_, 8) != code; ++i) {}
290
return charsetTable_[i].charsetId_ == lastCharsetId ?
291
invalidCharsetId : charsetTable_[i].charsetId_;
294
CommentValue::CommentValue(const std::string& comment)
295
: StringValueBase(Exiv2::undefined)
300
CommentValue& CommentValue::operator=(const CommentValue& rhs)
302
if (this == &rhs) return *this;
303
StringValueBase::operator=(rhs);
307
void CommentValue::read(const std::string& comment)
309
std::string c = comment;
310
CharsetId charsetId = undefined;
311
if (comment.length() > 8 && comment.substr(0, 8) == "charset=") {
312
std::string::size_type pos = comment.find_first_of(' ');
313
std::string name = comment.substr(8, pos-8);
314
// Strip quotes (so you can also to specify the charset without quotes)
315
if (name[0] == '"') name = name.substr(1);
316
if (name[name.length()-1] == '"') name = name.substr(0, name.length()-1);
317
charsetId = CharsetInfo::charsetIdByName(name);
318
if (charsetId == invalidCharsetId) throw Error(28, name);
320
if (pos != std::string::npos) c = comment.substr(pos+1);
322
const std::string code(CharsetInfo::code(charsetId), 8);
323
StringValueBase::read(code + c);
326
std::ostream& CommentValue::write(std::ostream& os) const
328
CharsetId charsetId = this->charsetId();
329
if (charsetId != undefined) {
330
os << "charset=\"" << CharsetInfo::name(charsetId) << "\" ";
332
return os << comment();
335
std::string CommentValue::comment() const
337
if (value_.length() >= 8) return value_.substr(8);
341
CommentValue::CharsetId CommentValue::charsetId() const
343
CharsetId charsetId = undefined;
344
if (value_.length() >= 8) {
345
const std::string code = value_.substr(0, 8);
346
charsetId = CharsetInfo::charsetIdByCode(code);
351
CommentValue* CommentValue::clone_() const
353
return new CommentValue(*this);
356
DateValue::DateValue(int year, int month, int day)
364
DateValue& DateValue::operator=(const DateValue& rhs)
366
if (this == &rhs) return *this;
367
Value::operator=(rhs);
368
date_.year = rhs.date_.year;
369
date_.month = rhs.date_.month;
370
date_.day = rhs.date_.day;
374
void DateValue::read(const byte* buf, long len, ByteOrder byteOrder)
376
// byteOrder not needed
377
// Hard coded to read Iptc style dates
378
if (len != 8) throw Error(29);
379
int scanned = sscanf(reinterpret_cast<const char*>(buf),
381
&date_.year, &date_.month, &date_.day);
382
if (scanned != 3) throw Error(29);
385
void DateValue::read(const std::string& buf)
387
// byteOrder not needed
388
// Hard coded to read Iptc style dates
389
if (buf.length() < 8) throw Error(29);
390
int scanned = sscanf(buf.data(),
392
&date_.year, &date_.month, &date_.day);
393
if (scanned != 3) throw Error(29);
396
void DateValue::setDate( const Date& src )
398
date_.year = src.year;
399
date_.month = src.month;
403
long DateValue::copy(byte* buf, ByteOrder byteOrder) const
405
// byteOrder not needed
406
// sprintf wants to add the null terminator, so use oversized buffer
409
int wrote = sprintf( temp, "%04d%02d%02d",
410
date_.year, date_.month, date_.day);
412
memcpy(buf, temp, 8);
416
long DateValue::size() const
421
DateValue* DateValue::clone_() const
423
return new DateValue(*this);
426
std::ostream& DateValue::write(std::ostream& os) const
428
return os << date_.year << '-' << std::right
429
<< std::setw(2) << std::setfill('0') << date_.month << '-'
430
<< std::setw(2) << std::setfill('0') << date_.day;
433
long DateValue::toLong(long n) const
435
// Range of tm struct is limited to about 1970 to 2038
436
// This will return -1 if outside that range
438
memset(&tms, 0, sizeof(tms));
439
tms.tm_mday = date_.day;
440
tms.tm_mon = date_.month - 1;
441
tms.tm_year = date_.year - 1900;
442
return static_cast<long>(std::mktime(&tms));
445
TimeValue::TimeValue(int hour, int minute,
446
int second, int tzHour,
454
time_.tzMinute=tzMinute;
457
TimeValue& TimeValue::operator=(const TimeValue& rhs)
459
if (this == &rhs) return *this;
460
Value::operator=(rhs);
461
memcpy(&time_, &rhs.time_, sizeof(time_));
465
void TimeValue::read(const byte* buf, long len, ByteOrder byteOrder)
467
// byteOrder not needed
468
// Hard coded to read Iptc style times
469
if (len != 11) throw Error(30);
471
int scanned = sscanf(reinterpret_cast<const char*>(buf),
472
"%2d%2d%2d%1c%2d%2d",
473
&time_.hour, &time_.minute, &time_.second,
474
&plusMinus, &time_.tzHour, &time_.tzMinute );
476
if (scanned != 6) throw Error(30);
477
if (plusMinus == '-') {
479
time_.tzMinute *= -1;
483
void TimeValue::read(const std::string& buf)
485
// byteOrder not needed
486
// Hard coded to read Iptc style times
487
if (buf.length() < 9) throw Error(30);
489
int scanned = sscanf(buf.data(),
491
&time_.hour, &time_.minute, &time_.second,
492
&plusMinus, &time_.tzHour, &time_.tzMinute );
494
if (scanned != 6) throw Error(30);
495
if (plusMinus == '-') {
497
time_.tzMinute *= -1;
501
void TimeValue::setTime( const Time& src )
503
memcpy(&time_, &src, sizeof(time_));
506
long TimeValue::copy(byte* buf, ByteOrder byteOrder) const
508
// byteOrder not needed
509
// sprintf wants to add the null terminator, so use oversized buffer
511
char plusMinus = '+';
512
if (time_.tzHour < 0 || time_.tzMinute < 0) plusMinus = '-';
514
int wrote = sprintf(temp,
515
"%02d%02d%02d%1c%02d%02d",
516
time_.hour, time_.minute, time_.second,
517
plusMinus, abs(time_.tzHour), abs(time_.tzMinute));
520
memcpy(buf, temp, 11);
524
long TimeValue::size() const
529
TimeValue* TimeValue::clone_() const
531
return new TimeValue(*this);
534
std::ostream& TimeValue::write(std::ostream& os) const
536
char plusMinus = '+';
537
if (time_.tzHour < 0 || time_.tzMinute < 0) plusMinus = '-';
539
return os << std::right
540
<< std::setw(2) << std::setfill('0') << time_.hour << ':'
541
<< std::setw(2) << std::setfill('0') << time_.minute << ':'
542
<< std::setw(2) << std::setfill('0') << time_.second << plusMinus
543
<< std::setw(2) << std::setfill('0') << abs(time_.tzHour) << ':'
544
<< std::setw(2) << std::setfill('0') << abs(time_.tzMinute);
547
long TimeValue::toLong(long n) const
549
// Returns number of seconds in the day in UTC.
550
long result = (time_.hour - time_.tzHour) * 60 * 60;
551
result += (time_.minute - time_.tzMinute) * 60;
552
result += time_.second;