Blame src/value.cpp

Packit 01d647
// ***************************************************************** -*- C++ -*-
Packit 01d647
/*
Packit 01d647
 * Copyright (C) 2004-2018 Exiv2 authors
Packit 01d647
 * This program is part of the Exiv2 distribution.
Packit 01d647
 *
Packit 01d647
 * This program is free software; you can redistribute it and/or
Packit 01d647
 * modify it under the terms of the GNU General Public License
Packit 01d647
 * as published by the Free Software Foundation; either version 2
Packit 01d647
 * of the License, or (at your option) any later version.
Packit 01d647
 *
Packit 01d647
 * This program is distributed in the hope that it will be useful,
Packit 01d647
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 01d647
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 01d647
 * GNU General Public License for more details.
Packit 01d647
 *
Packit 01d647
 * You should have received a copy of the GNU General Public License
Packit 01d647
 * along with this program; if not, write to the Free Software
Packit 01d647
 * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA.
Packit 01d647
 */
Packit 01d647
/*
Packit 01d647
  File:      value.cpp
Packit 01d647
  Author(s): Andreas Huggel (ahu) <ahuggel@gmx.net>
Packit 01d647
  History:   26-Jan-04, ahu: created
Packit 01d647
             11-Feb-04, ahu: isolated as a component
Packit 01d647
             31-Jul-04, brad: added Time, Date and String values
Packit 01d647
 */
Packit 01d647
// *****************************************************************************
Packit 01d647
// included header files
Packit 01d647
#include "value.hpp"
Packit 01d647
#include "types.hpp"
Packit 01d647
#include "enforce.hpp"
Packit 01d647
#include "error.hpp"
Packit 01d647
#include "convert.hpp"
Packit 01d647
#include "unused.h"
Packit 01d647
Packit 01d647
// + standard includes
Packit 01d647
#include <iostream>
Packit 01d647
#include <iomanip>
Packit 01d647
#include <sstream>
Packit 01d647
#include <cassert>
Packit 01d647
#include <cstring>
Packit 01d647
#include <ctime>
Packit 01d647
#include <cstdarg>
Packit 01d647
#include <cstdio>
Packit 01d647
#include <cstdlib>
Packit 01d647
#include <ctype.h>
Packit 01d647
Packit 01d647
#if defined(_MSC_VER) && _MSC_VER < 1900
Packit 01d647
Packit 01d647
#define snprintf c99_snprintf
Packit 01d647
#define vsnprintf c99_vsnprintf
Packit 01d647
Packit 01d647
__inline int c99_vsnprintf(char *outBuf, size_t size, const char *format, va_list ap)
Packit 01d647
{
Packit 01d647
    int count = -1;
Packit 01d647
Packit 01d647
    if (size != 0)
Packit 01d647
        count = _vsnprintf_s(outBuf, size, _TRUNCATE, format, ap);
Packit 01d647
    if (count == -1)
Packit 01d647
        count = _vscprintf(format, ap);
Packit 01d647
Packit 01d647
    return count;
Packit 01d647
}
Packit 01d647
Packit 01d647
__inline int c99_snprintf(char *outBuf, size_t size, const char *format, ...)
Packit 01d647
{
Packit 01d647
    int count;
Packit 01d647
    va_list ap;
Packit 01d647
Packit 01d647
    va_start(ap, format);
Packit 01d647
    count = c99_vsnprintf(outBuf, size, format, ap);
Packit 01d647
    va_end(ap);
Packit 01d647
Packit 01d647
    return count;
Packit 01d647
}
Packit 01d647
Packit 01d647
#endif
Packit 01d647
Packit 01d647
// *****************************************************************************
Packit 01d647
// class member definitions
Packit 01d647
namespace Exiv2 {
Packit 01d647
Packit 01d647
    Value::Value(TypeId typeId)
Packit 01d647
        : ok_(true), type_(typeId)
Packit 01d647
    {
Packit 01d647
    }
Packit 01d647
Packit 01d647
    Value::~Value()
Packit 01d647
    {
Packit 01d647
    }
Packit 01d647
Packit 01d647
    Value& Value::operator=(const Value& rhs)
Packit 01d647
    {
Packit 01d647
        if (this == &rhs) return *this;
Packit 01d647
        type_ = rhs.type_;
Packit 01d647
        ok_ = rhs.ok_;
Packit 01d647
        return *this;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    Value::AutoPtr Value::create(TypeId typeId)
Packit 01d647
    {
Packit 01d647
        AutoPtr value;
Packit 01d647
        switch (typeId) {
Packit 01d647
        case invalidTypeId:
Packit 01d647
        case signedByte:
Packit 01d647
        case unsignedByte:
Packit 01d647
            value = AutoPtr(new DataValue(typeId));
Packit 01d647
            break;
Packit 01d647
        case asciiString:
Packit 01d647
            value = AutoPtr(new AsciiValue);
Packit 01d647
            break;
Packit 01d647
        case unsignedShort:
Packit 01d647
            value = AutoPtr(new ValueType<uint16_t>);
Packit 01d647
            break;
Packit 01d647
        case unsignedLong:
Packit 01d647
        case tiffIfd:
Packit 01d647
            value = AutoPtr(new ValueType<uint32_t>(typeId));
Packit 01d647
            break;
Packit 01d647
        case unsignedRational:
Packit 01d647
            value = AutoPtr(new ValueType<URational>);
Packit 01d647
            break;
Packit 01d647
        case undefined:
Packit 01d647
            value = AutoPtr(new DataValue);
Packit 01d647
            break;
Packit 01d647
        case signedShort:
Packit 01d647
            value = AutoPtr(new ValueType<int16_t>);
Packit 01d647
            break;
Packit 01d647
        case signedLong:
Packit 01d647
            value = AutoPtr(new ValueType<int32_t>);
Packit 01d647
            break;
Packit 01d647
        case signedRational:
Packit 01d647
            value = AutoPtr(new ValueType<Rational>);
Packit 01d647
            break;
Packit 01d647
        case tiffFloat:
Packit 01d647
            value = AutoPtr(new ValueType<float>);
Packit 01d647
            break;
Packit 01d647
        case tiffDouble:
Packit 01d647
            value = AutoPtr(new ValueType<double>);
Packit 01d647
            break;
Packit 01d647
        case string:
Packit 01d647
            value = AutoPtr(new StringValue);
Packit 01d647
            break;
Packit 01d647
        case date:
Packit 01d647
            value = AutoPtr(new DateValue);
Packit 01d647
            break;
Packit 01d647
        case time:
Packit 01d647
            value = AutoPtr(new TimeValue);
Packit 01d647
            break;
Packit 01d647
        case comment:
Packit 01d647
            value = AutoPtr(new CommentValue);
Packit 01d647
            break;
Packit 01d647
        case xmpText:
Packit 01d647
            value = AutoPtr(new XmpTextValue);
Packit 01d647
            break;
Packit 01d647
        case xmpBag:
Packit 01d647
        case xmpSeq:
Packit 01d647
        case xmpAlt:
Packit 01d647
            value = AutoPtr(new XmpArrayValue(typeId));
Packit 01d647
            break;
Packit 01d647
        case langAlt:
Packit 01d647
            value = AutoPtr(new LangAltValue);
Packit 01d647
            break;
Packit 01d647
        default:
Packit 01d647
            value = AutoPtr(new DataValue(typeId));
Packit 01d647
            break;
Packit 01d647
        }
Packit 01d647
        return value;
Packit 01d647
    } // Value::create
Packit 01d647
Packit 01d647
    int Value::setDataArea(const byte* /*buf*/, long /*len*/)
Packit 01d647
    {
Packit 01d647
        return -1;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    std::string Value::toString() const
Packit 01d647
    {
Packit 01d647
        std::ostringstream os;
Packit 01d647
        write(os);
Packit 01d647
        ok_ = !os.fail();
Packit 01d647
        return os.str();
Packit 01d647
    }
Packit 01d647
Packit 01d647
    std::string Value::toString(long /*n*/) const
Packit 01d647
    {
Packit 01d647
        return toString();
Packit 01d647
    }
Packit 01d647
Packit 01d647
    long Value::sizeDataArea() const
Packit 01d647
    {
Packit 01d647
        return 0;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    DataBuf Value::dataArea() const
Packit 01d647
    {
Packit 01d647
        return DataBuf(0, 0);
Packit 01d647
    }
Packit 01d647
Packit 01d647
    DataValue::DataValue(TypeId typeId) : Value(typeId)
Packit 01d647
    {
Packit 01d647
    }
Packit 01d647
Packit 01d647
    DataValue::DataValue(const byte* buf,
Packit 01d647
              long len, ByteOrder byteOrder,TypeId typeId)
Packit 01d647
        : Value(typeId)
Packit 01d647
    {
Packit 01d647
        read(buf, len, byteOrder);
Packit 01d647
    }
Packit 01d647
Packit 01d647
    DataValue::~DataValue()
Packit 01d647
    {
Packit 01d647
    }
Packit 01d647
Packit 01d647
    long DataValue::count() const
Packit 01d647
    {
Packit 01d647
        return size();
Packit 01d647
    }
Packit 01d647
Packit 01d647
    int DataValue::read(const byte* buf, long len, ByteOrder /*byteOrder*/)
Packit 01d647
    {
Packit 01d647
        // byteOrder not needed
Packit 01d647
        value_.assign(buf, buf + len);
Packit 01d647
        return 0;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    int DataValue::read(const std::string& buf)
Packit 01d647
    {
Packit 01d647
        std::istringstream is(buf);
Packit 01d647
        int tmp;
Packit 01d647
        ValueType val;
Packit 01d647
        while (!(is.eof())) {
Packit 01d647
            is >> tmp;
Packit 01d647
            if (is.fail()) return 1;
Packit 01d647
            val.push_back(static_cast<byte>(tmp));
Packit 01d647
        }
Packit 01d647
        value_.swap(val);
Packit 01d647
        return 0;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    long DataValue::copy(byte* buf, ByteOrder /*byteOrder*/) const
Packit 01d647
    {
Packit 01d647
        // byteOrder not needed
Packit 01d647
        return static_cast<long>(
Packit 01d647
            std::copy(value_.begin(), value_.end(), buf) - buf
Packit 01d647
            );
Packit 01d647
    }
Packit 01d647
Packit 01d647
    long DataValue::size() const
Packit 01d647
    {
Packit 01d647
        return static_cast<long>(value_.size());
Packit 01d647
    }
Packit 01d647
Packit 01d647
    DataValue* DataValue::clone_() const
Packit 01d647
    {
Packit 01d647
        return new DataValue(*this);
Packit 01d647
    }
Packit 01d647
Packit 01d647
    std::ostream& DataValue::write(std::ostream& os) const
Packit 01d647
    {
Packit 01d647
        std::vector<byte>::size_type end = value_.size();
Packit 01d647
        for (std::vector<byte>::size_type i = 0; i != end; ++i) {
Packit 01d647
            os << static_cast<int>(value_[i]);
Packit 01d647
            if (i < end - 1) os << " ";
Packit 01d647
        }
Packit 01d647
        return os;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    std::string DataValue::toString(long n) const
Packit 01d647
    {
Packit 01d647
        std::ostringstream os;
Packit 01d647
        os << static_cast<int>(value_[n]);
Packit 01d647
        ok_ = !os.fail();
Packit 01d647
        return os.str();
Packit 01d647
    }
Packit 01d647
Packit 01d647
    long DataValue::toLong(long n) const
Packit 01d647
    {
Packit 01d647
        ok_ = true;
Packit 01d647
        return value_[n];
Packit 01d647
    }
Packit 01d647
Packit 01d647
    float DataValue::toFloat(long n) const
Packit 01d647
    {
Packit 01d647
        ok_ = true;
Packit 01d647
        return value_[n];
Packit 01d647
    }
Packit 01d647
Packit 01d647
    Rational DataValue::toRational(long n) const
Packit 01d647
    {
Packit 01d647
        ok_ = true;
Packit 01d647
        return Rational(value_[n], 1);
Packit 01d647
    }
Packit 01d647
Packit 01d647
    StringValueBase::StringValueBase(TypeId typeId)
Packit 01d647
        : Value(typeId)
Packit 01d647
    {
Packit 01d647
    }
Packit 01d647
Packit 01d647
    StringValueBase::StringValueBase(TypeId typeId, const std::string& buf)
Packit 01d647
        : Value(typeId)
Packit 01d647
    {
Packit 01d647
        read(buf);
Packit 01d647
    }
Packit 01d647
Packit 01d647
    StringValueBase::StringValueBase(const StringValueBase& rhs)
Packit 01d647
        : Value(rhs), value_(rhs.value_)
Packit 01d647
    {
Packit 01d647
    }
Packit 01d647
Packit 01d647
    StringValueBase::~StringValueBase()
Packit 01d647
    {
Packit 01d647
    }
Packit 01d647
Packit 01d647
    StringValueBase& StringValueBase::operator=(const StringValueBase& rhs)
Packit 01d647
    {
Packit 01d647
        if (this == &rhs) return *this;
Packit 01d647
        Value::operator=(rhs);
Packit 01d647
        value_ = rhs.value_;
Packit 01d647
        return *this;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    int StringValueBase::read(const std::string& buf)
Packit 01d647
    {
Packit 01d647
        value_ = buf;
Packit 01d647
        return 0;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    int StringValueBase::read(const byte* buf, long len, ByteOrder /*byteOrder*/)
Packit 01d647
    {
Packit 01d647
        // byteOrder not needed
Packit 01d647
        if (buf) value_ = std::string(reinterpret_cast<const char*>(buf), len);
Packit 01d647
        return 0;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    long StringValueBase::copy(byte* buf, ByteOrder /*byteOrder*/) const
Packit 01d647
    {
Packit 01d647
        if (value_.size() == 0) return 0;
Packit 01d647
        // byteOrder not needed
Packit 01d647
        assert(buf != 0);
Packit 01d647
        return static_cast<long>(
Packit 01d647
            value_.copy(reinterpret_cast<char*>(buf), value_.size())
Packit 01d647
            );
Packit 01d647
    }
Packit 01d647
Packit 01d647
    long StringValueBase::count() const
Packit 01d647
    {
Packit 01d647
        return size();
Packit 01d647
    }
Packit 01d647
Packit 01d647
    long StringValueBase::size() const
Packit 01d647
    {
Packit 01d647
        return static_cast<long>(value_.size());
Packit 01d647
    }
Packit 01d647
Packit 01d647
    std::ostream& StringValueBase::write(std::ostream& os) const
Packit 01d647
    {
Packit 01d647
        return os << value_;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    long StringValueBase::toLong(long n) const
Packit 01d647
    {
Packit 01d647
        ok_ = true;
Packit 01d647
        return value_[n];
Packit 01d647
    }
Packit 01d647
Packit 01d647
    float StringValueBase::toFloat(long n) const
Packit 01d647
    {
Packit 01d647
        ok_ = true;
Packit 01d647
        return value_[n];
Packit 01d647
    }
Packit 01d647
Packit 01d647
    Rational StringValueBase::toRational(long n) const
Packit 01d647
    {
Packit 01d647
        ok_ = true;
Packit 01d647
        return Rational(value_[n], 1);
Packit 01d647
    }
Packit 01d647
Packit 01d647
    StringValue::StringValue()
Packit 01d647
        : StringValueBase(string)
Packit 01d647
    {
Packit 01d647
    }
Packit 01d647
Packit 01d647
    StringValue::StringValue(const std::string& buf)
Packit 01d647
        : StringValueBase(string, buf)
Packit 01d647
    {
Packit 01d647
    }
Packit 01d647
Packit 01d647
    StringValue::~StringValue()
Packit 01d647
    {
Packit 01d647
    }
Packit 01d647
Packit 01d647
    StringValue* StringValue::clone_() const
Packit 01d647
    {
Packit 01d647
        return new StringValue(*this);
Packit 01d647
    }
Packit 01d647
Packit 01d647
    AsciiValue::AsciiValue()
Packit 01d647
        : StringValueBase(asciiString)
Packit 01d647
    {
Packit 01d647
    }
Packit 01d647
Packit 01d647
    AsciiValue::AsciiValue(const std::string& buf)
Packit 01d647
        : StringValueBase(asciiString, buf)
Packit 01d647
    {
Packit 01d647
    }
Packit 01d647
Packit 01d647
    AsciiValue::~AsciiValue()
Packit 01d647
    {
Packit 01d647
    }
Packit 01d647
Packit 01d647
    int AsciiValue::read(const std::string& buf)
Packit 01d647
    {
Packit 01d647
        value_ = buf;
Packit 01d647
        if (value_.size() > 0 && value_[value_.size()-1] != '\0') value_ += '\0';
Packit 01d647
        return 0;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    AsciiValue* AsciiValue::clone_() const
Packit 01d647
    {
Packit 01d647
        return new AsciiValue(*this);
Packit 01d647
    }
Packit 01d647
Packit 01d647
    std::ostream& AsciiValue::write(std::ostream& os) const
Packit 01d647
    {
Packit 01d647
        // Write only up to the first '\0' (if any)
Packit 01d647
        std::string::size_type pos = value_.find_first_of('\0');
Packit 01d647
        if (pos == std::string::npos) pos = value_.size();
Packit 01d647
        return os << value_.substr(0, pos);
Packit 01d647
    }
Packit 01d647
Packit 01d647
    CommentValue::CharsetTable::CharsetTable(CharsetId charsetId,
Packit 01d647
                                             const char* name,
Packit 01d647
                                             const char* code)
Packit 01d647
        : charsetId_(charsetId), name_(name), code_(code)
Packit 01d647
    {
Packit 01d647
    }
Packit 01d647
Packit 01d647
    //! Lookup list of supported IFD type information
Packit 01d647
    const CommentValue::CharsetTable CommentValue::CharsetInfo::charsetTable_[] = {
Packit 01d647
        CharsetTable(ascii,            "Ascii",            "ASCII\0\0\0"),
Packit 01d647
        CharsetTable(jis,              "Jis",              "JIS\0\0\0\0\0"),
Packit 01d647
        CharsetTable(unicode,          "Unicode",          "UNICODE\0"),
Packit 01d647
        CharsetTable(undefined,        "Undefined",        "\0\0\0\0\0\0\0\0"),
Packit 01d647
        CharsetTable(invalidCharsetId, "InvalidCharsetId", "\0\0\0\0\0\0\0\0"),
Packit 01d647
        CharsetTable(lastCharsetId,    "InvalidCharsetId", "\0\0\0\0\0\0\0\0")
Packit 01d647
    };
Packit 01d647
Packit 01d647
    const char* CommentValue::CharsetInfo::name(CharsetId charsetId)
Packit 01d647
    {
Packit 01d647
        return charsetTable_[ charsetId < lastCharsetId ? charsetId : undefined ].name_;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    const char* CommentValue::CharsetInfo::code(CharsetId charsetId)
Packit 01d647
    {
Packit 01d647
        return charsetTable_[ charsetId < lastCharsetId ? charsetId : undefined ].code_;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    CommentValue::CharsetId CommentValue::CharsetInfo::charsetIdByName(
Packit 01d647
        const std::string& name)
Packit 01d647
    {
Packit 01d647
        int i = 0;
Packit 01d647
        for (;    charsetTable_[i].charsetId_ != lastCharsetId
Packit 01d647
               && charsetTable_[i].name_ != name; ++i) {}
Packit 01d647
        return charsetTable_[i].charsetId_ == lastCharsetId ?
Packit 01d647
               invalidCharsetId : charsetTable_[i].charsetId_;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    CommentValue::CharsetId CommentValue::CharsetInfo::charsetIdByCode(
Packit 01d647
        const std::string& code)
Packit 01d647
    {
Packit 01d647
        int i = 0;
Packit 01d647
        for (;    charsetTable_[i].charsetId_ != lastCharsetId
Packit 01d647
               && std::string(charsetTable_[i].code_, 8) != code; ++i) {}
Packit 01d647
        return charsetTable_[i].charsetId_ == lastCharsetId ?
Packit 01d647
               invalidCharsetId : charsetTable_[i].charsetId_;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    CommentValue::CommentValue()
Packit 01d647
        : StringValueBase(Exiv2::undefined), byteOrder_(littleEndian)
Packit 01d647
    {
Packit 01d647
    }
Packit 01d647
Packit 01d647
    CommentValue::CommentValue(const std::string& comment)
Packit 01d647
        : StringValueBase(Exiv2::undefined), byteOrder_(littleEndian)
Packit 01d647
    {
Packit 01d647
        read(comment);
Packit 01d647
    }
Packit 01d647
Packit 01d647
    CommentValue::~CommentValue()
Packit 01d647
    {
Packit 01d647
    }
Packit 01d647
Packit 01d647
    int CommentValue::read(const std::string& comment)
Packit 01d647
    {
Packit 01d647
        std::string c = comment;
Packit 01d647
        CharsetId charsetId = undefined;
Packit 01d647
        if (comment.length() > 8 && comment.substr(0, 8) == "charset=") {
Packit 01d647
            std::string::size_type pos = comment.find_first_of(' ');
Packit 01d647
            std::string name = comment.substr(8, pos-8);
Packit 01d647
            // Strip quotes (so you can also specify the charset without quotes)
Packit 01d647
            if (name[0] == '"') name = name.substr(1);
Packit 01d647
            if (name[name.length()-1] == '"') name = name.substr(0, name.length()-1);
Packit 01d647
            charsetId = CharsetInfo::charsetIdByName(name);
Packit 01d647
            if (charsetId == invalidCharsetId) {
Packit 01d647
#ifndef SUPPRESS_WARNINGS
Packit 01d647
                EXV_WARNING << Error(kerInvalidCharset, name) << "\n";
Packit 01d647
#endif
Packit 01d647
                return 1;
Packit 01d647
            }
Packit 01d647
            c.clear();
Packit 01d647
            if (pos != std::string::npos) c = comment.substr(pos+1);
Packit 01d647
        }
Packit 01d647
        if (charsetId == unicode) {
Packit 01d647
            const char* to = byteOrder_ == littleEndian ? "UCS-2LE" : "UCS-2BE";
Packit 01d647
            convertStringCharset(c, "UTF-8", to);
Packit 01d647
        }
Packit 01d647
        const std::string code(CharsetInfo::code(charsetId), 8);
Packit 01d647
        return StringValueBase::read(code + c);
Packit 01d647
    }
Packit 01d647
Packit 01d647
    int CommentValue::read(const byte* buf, long len, ByteOrder byteOrder)
Packit 01d647
    {
Packit 01d647
        byteOrder_ = byteOrder;
Packit 01d647
        return StringValueBase::read(buf, len, byteOrder);
Packit 01d647
    }
Packit 01d647
Packit 01d647
    long CommentValue::copy(byte* buf, ByteOrder byteOrder) const
Packit 01d647
    {
Packit 01d647
        std::string c = value_;
Packit 01d647
        if (charsetId() == unicode) {
Packit 01d647
            c = value_.substr(8);
Packit 01d647
            const size_t sz = c.size();
Packit 01d647
            UNUSED(sz);
Packit 01d647
            if (byteOrder_ == littleEndian && byteOrder == bigEndian) {
Packit 01d647
                convertStringCharset(c, "UCS-2LE", "UCS-2BE");
Packit 01d647
                assert(c.size() == sz);
Packit 01d647
            }
Packit 01d647
            else if (byteOrder_ == bigEndian && byteOrder == littleEndian) {
Packit 01d647
                convertStringCharset(c, "UCS-2BE", "UCS-2LE");
Packit 01d647
                assert(c.size() == sz);
Packit 01d647
            }
Packit 01d647
            c = value_.substr(0, 8) + c;
Packit 01d647
        }
Packit 01d647
        if (c.size() == 0)
Packit 01d647
            return 0;
Packit 01d647
        assert(buf != 0);
Packit 01d647
        return static_cast<long>(c.copy(reinterpret_cast<char*>(buf), c.size()));
Packit 01d647
    }
Packit 01d647
Packit 01d647
    std::ostream& CommentValue::write(std::ostream& os) const
Packit 01d647
    {
Packit 01d647
        CharsetId csId = charsetId();
Packit 01d647
        if (csId != undefined) {
Packit 01d647
            os << "charset=\"" << CharsetInfo::name(csId) << "\" ";
Packit 01d647
        }
Packit 01d647
        return os << comment();
Packit 01d647
    }
Packit 01d647
Packit 01d647
    std::string CommentValue::comment(const char* encoding) const
Packit 01d647
    {
Packit 01d647
        std::string c;
Packit 01d647
        if (value_.length() < 8) {
Packit 01d647
            return c;
Packit 01d647
        }
Packit 01d647
        c = value_.substr(8);
Packit 01d647
        if (charsetId() == unicode) {
Packit 01d647
            const char* from = encoding == 0 || *encoding == '\0' ? detectCharset(c) : encoding;
Packit 01d647
            convertStringCharset(c, from, "UTF-8");
Packit 01d647
        }
Packit 01d647
        return c;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    CommentValue::CharsetId CommentValue::charsetId() const
Packit 01d647
    {
Packit 01d647
        CharsetId charsetId = undefined;
Packit 01d647
        if (value_.length() >= 8) {
Packit 01d647
            const std::string code = value_.substr(0, 8);
Packit 01d647
            charsetId = CharsetInfo::charsetIdByCode(code);
Packit 01d647
        }
Packit 01d647
        return charsetId;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    const char* CommentValue::detectCharset(std::string& c) const
Packit 01d647
    {
Packit 01d647
        // Interpret a BOM if there is one
Packit 01d647
        if (0 == strncmp(c.data(), "\xef\xbb\xbf", 3)) {
Packit 01d647
            c = c.substr(3);
Packit 01d647
            return "UTF-8";
Packit 01d647
        }
Packit 01d647
        if (0 == strncmp(c.data(), "\xff\xfe", 2)) {
Packit 01d647
            c = c.substr(2);
Packit 01d647
            return "UCS-2LE";
Packit 01d647
        }
Packit 01d647
        if (0 == strncmp(c.data(), "\xfe\xff", 2)) {
Packit 01d647
            c = c.substr(2);
Packit 01d647
            return "UCS-2BE";
Packit 01d647
        }
Packit 01d647
Packit 01d647
        // Todo: Add logic to guess if the comment is encoded in UTF-8
Packit 01d647
Packit 01d647
        return byteOrder_ == littleEndian ? "UCS-2LE" : "UCS-2BE";
Packit 01d647
    }
Packit 01d647
Packit 01d647
    CommentValue* CommentValue::clone_() const
Packit 01d647
    {
Packit 01d647
        return new CommentValue(*this);
Packit 01d647
    }
Packit 01d647
Packit 01d647
    XmpValue::XmpValue(TypeId typeId)
Packit 01d647
        : Value(typeId),
Packit 01d647
          xmpArrayType_(xaNone),
Packit 01d647
          xmpStruct_(xsNone)
Packit 01d647
    {
Packit 01d647
    }
Packit 01d647
Packit 01d647
    XmpValue& XmpValue::operator=(const XmpValue& rhs)
Packit 01d647
    {
Packit 01d647
        if (this == &rhs) return *this;
Packit 01d647
        xmpArrayType_ = rhs.xmpArrayType_;
Packit 01d647
        xmpStruct_ = rhs.xmpStruct_;
Packit 01d647
        return *this;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    void XmpValue::setXmpArrayType(XmpArrayType xmpArrayType)
Packit 01d647
    {
Packit 01d647
        xmpArrayType_ = xmpArrayType;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    void XmpValue::setXmpStruct(XmpStruct xmpStruct)
Packit 01d647
    {
Packit 01d647
        xmpStruct_ = xmpStruct;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    XmpValue::XmpArrayType XmpValue::xmpArrayType() const
Packit 01d647
    {
Packit 01d647
        return xmpArrayType_;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    XmpValue::XmpArrayType XmpValue::xmpArrayType(TypeId typeId)
Packit 01d647
    {
Packit 01d647
        XmpArrayType xa = xaNone;
Packit 01d647
        switch (typeId) {
Packit 01d647
        case xmpAlt: xa = xaAlt; break;
Packit 01d647
        case xmpBag: xa = xaBag; break;
Packit 01d647
        case xmpSeq: xa = xaSeq; break;
Packit 01d647
        default: break;
Packit 01d647
        }
Packit 01d647
        return xa;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    XmpValue::XmpStruct XmpValue::xmpStruct() const
Packit 01d647
    {
Packit 01d647
        return xmpStruct_;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    long XmpValue::copy(byte* buf,
Packit 01d647
                        ByteOrder /*byteOrder*/) const
Packit 01d647
    {
Packit 01d647
        std::ostringstream os;
Packit 01d647
        write(os);
Packit 01d647
        std::string s = os.str();
Packit 01d647
        if (s.size() > 0) std::memcpy(buf, &s[0], s.size());
Packit 01d647
        return static_cast<long>(s.size());
Packit 01d647
    }
Packit 01d647
Packit 01d647
    int XmpValue::read(const byte* buf,
Packit 01d647
                       long len,
Packit 01d647
                       ByteOrder /*byteOrder*/)
Packit 01d647
    {
Packit 01d647
        std::string s(reinterpret_cast<const char*>(buf), len);
Packit 01d647
        return read(s);
Packit 01d647
    }
Packit 01d647
Packit 01d647
    long XmpValue::size() const
Packit 01d647
    {
Packit 01d647
        std::ostringstream os;
Packit 01d647
        write(os);
Packit 01d647
        return static_cast<long>(os.str().size());
Packit 01d647
    }
Packit 01d647
Packit 01d647
    XmpTextValue::XmpTextValue()
Packit 01d647
        : XmpValue(xmpText)
Packit 01d647
    {
Packit 01d647
    }
Packit 01d647
Packit 01d647
    XmpTextValue::XmpTextValue(const std::string& buf)
Packit 01d647
        : XmpValue(xmpText)
Packit 01d647
    {
Packit 01d647
        read(buf);
Packit 01d647
    }
Packit 01d647
Packit 01d647
    int XmpTextValue::read(const std::string& buf)
Packit 01d647
    {
Packit 01d647
        // support a type=Alt,Bag,Seq,Struct indicator
Packit 01d647
        std::string b = buf;
Packit 01d647
        std::string type;
Packit 01d647
        if (buf.length() > 5 && buf.substr(0, 5) == "type=") {
Packit 01d647
            std::string::size_type pos = buf.find_first_of(' ');
Packit 01d647
            type = buf.substr(5, pos-5);
Packit 01d647
            // Strip quotes (so you can also specify the type without quotes)
Packit 01d647
            if (type[0] == '"') type = type.substr(1);
Packit 01d647
            if (type[type.length()-1] == '"') type = type.substr(0, type.length()-1);
Packit 01d647
            b.clear();
Packit 01d647
            if (pos != std::string::npos) b = buf.substr(pos+1);
Packit 01d647
        }
Packit 01d647
        if (!type.empty()) {
Packit 01d647
            if (type == "Alt") {
Packit 01d647
                setXmpArrayType(XmpValue::xaAlt);
Packit 01d647
            }
Packit 01d647
            else if (type == "Bag") {
Packit 01d647
                setXmpArrayType(XmpValue::xaBag);
Packit 01d647
            }
Packit 01d647
            else if (type == "Seq") {
Packit 01d647
                setXmpArrayType(XmpValue::xaSeq);
Packit 01d647
            }
Packit 01d647
            else if (type == "Struct") {
Packit 01d647
                setXmpStruct();
Packit 01d647
            }
Packit 01d647
            else {
Packit 01d647
                throw Error(kerInvalidXmpText, type);
Packit 01d647
            }
Packit 01d647
        }
Packit 01d647
        value_ = b;
Packit 01d647
        return 0;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    XmpTextValue::AutoPtr XmpTextValue::clone() const
Packit 01d647
    {
Packit 01d647
        return AutoPtr(clone_());
Packit 01d647
    }
Packit 01d647
Packit 01d647
    long XmpTextValue::size() const
Packit 01d647
    {
Packit 01d647
        return static_cast<long>(value_.size());
Packit 01d647
    }
Packit 01d647
Packit 01d647
    long XmpTextValue::count() const
Packit 01d647
    {
Packit 01d647
        return size();
Packit 01d647
    }
Packit 01d647
Packit 01d647
    std::ostream& XmpTextValue::write(std::ostream& os) const
Packit 01d647
    {
Packit 01d647
        bool del = false;
Packit 01d647
        if (xmpArrayType() != XmpValue::xaNone) {
Packit 01d647
            switch (xmpArrayType()) {
Packit 01d647
            case XmpValue::xaAlt: os << "type=\"Alt\""; break;
Packit 01d647
            case XmpValue::xaBag: os << "type=\"Bag\""; break;
Packit 01d647
            case XmpValue::xaSeq: os << "type=\"Seq\""; break;
Packit 01d647
            case XmpValue::xaNone: break; // just to suppress the warning
Packit 01d647
            }
Packit 01d647
            del = true;
Packit 01d647
        }
Packit 01d647
        else if (xmpStruct() != XmpValue::xsNone) {
Packit 01d647
            switch (xmpStruct()) {
Packit 01d647
            case XmpValue::xsStruct: os << "type=\"Struct\""; break;
Packit 01d647
            case XmpValue::xsNone: break; // just to suppress the warning
Packit 01d647
            }
Packit 01d647
            del = true;
Packit 01d647
        }
Packit 01d647
        if (del && !value_.empty()) os << " ";
Packit 01d647
        return os << value_;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    long XmpTextValue::toLong(long /*n*/) const
Packit 01d647
    {
Packit 01d647
        return parseLong(value_, ok_);
Packit 01d647
    }
Packit 01d647
Packit 01d647
    float XmpTextValue::toFloat(long /*n*/) const
Packit 01d647
    {
Packit 01d647
        return parseFloat(value_, ok_);
Packit 01d647
    }
Packit 01d647
Packit 01d647
    Rational XmpTextValue::toRational(long /*n*/) const
Packit 01d647
    {
Packit 01d647
        return parseRational(value_, ok_);
Packit 01d647
    }
Packit 01d647
Packit 01d647
    XmpTextValue* XmpTextValue::clone_() const
Packit 01d647
    {
Packit 01d647
        return new XmpTextValue(*this);
Packit 01d647
    }
Packit 01d647
Packit 01d647
    XmpArrayValue::XmpArrayValue(TypeId typeId)
Packit 01d647
        : XmpValue(typeId)
Packit 01d647
    {
Packit 01d647
        setXmpArrayType(xmpArrayType(typeId));
Packit 01d647
    }
Packit 01d647
Packit 01d647
    int XmpArrayValue::read(const std::string& buf)
Packit 01d647
    {
Packit 01d647
        if (!buf.empty()) value_.push_back(buf);
Packit 01d647
        return 0;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    XmpArrayValue::AutoPtr XmpArrayValue::clone() const
Packit 01d647
    {
Packit 01d647
        return AutoPtr(clone_());
Packit 01d647
    }
Packit 01d647
Packit 01d647
    long XmpArrayValue::count() const
Packit 01d647
    {
Packit 01d647
        return static_cast<long>(value_.size());
Packit 01d647
    }
Packit 01d647
Packit 01d647
    std::ostream& XmpArrayValue::write(std::ostream& os) const
Packit 01d647
    {
Packit 01d647
        for (std::vector<std::string>::const_iterator i = value_.begin();
Packit 01d647
             i != value_.end(); ++i) {
Packit 01d647
            if (i != value_.begin()) os << ", ";
Packit 01d647
            os << *i;
Packit 01d647
        }
Packit 01d647
        return os;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    std::string XmpArrayValue::toString(long n) const
Packit 01d647
    {
Packit 01d647
        ok_ = true;
Packit 01d647
        return value_[n];
Packit 01d647
    }
Packit 01d647
Packit 01d647
    long XmpArrayValue::toLong(long n) const
Packit 01d647
    {
Packit 01d647
        return parseLong(value_[n], ok_);
Packit 01d647
    }
Packit 01d647
Packit 01d647
    float XmpArrayValue::toFloat(long n) const
Packit 01d647
    {
Packit 01d647
        return parseFloat(value_[n], ok_);
Packit 01d647
    }
Packit 01d647
Packit 01d647
    Rational XmpArrayValue::toRational(long n) const
Packit 01d647
    {
Packit 01d647
        return parseRational(value_[n], ok_);
Packit 01d647
    }
Packit 01d647
Packit 01d647
    XmpArrayValue* XmpArrayValue::clone_() const
Packit 01d647
    {
Packit 01d647
        return new XmpArrayValue(*this);
Packit 01d647
    }
Packit 01d647
Packit 01d647
    LangAltValue::LangAltValue()
Packit 01d647
        : XmpValue(langAlt)
Packit 01d647
    {
Packit 01d647
    }
Packit 01d647
Packit 01d647
    LangAltValue::LangAltValue(const std::string& buf)
Packit 01d647
        : XmpValue(langAlt)
Packit 01d647
    {
Packit 01d647
        read(buf);
Packit 01d647
    }
Packit 01d647
Packit 01d647
    int LangAltValue::read(const std::string& buf)
Packit 01d647
    {
Packit 01d647
        std::string b = buf;
Packit 01d647
        std::string lang = "x-default";
Packit 01d647
        if (buf.length() > 5 && buf.substr(0, 5) == "lang=") {
Packit 01d647
            std::string::size_type pos = buf.find_first_of(' ');
Packit 01d647
            lang = buf.substr(5, pos-5);
Packit 01d647
            // Strip quotes (so you can also specify the language without quotes)
Packit 01d647
            if (lang[0] == '"') lang = lang.substr(1);
Packit 01d647
            if (lang[lang.length()-1] == '"') lang = lang.substr(0, lang.length()-1);
Packit 01d647
            b.clear();
Packit 01d647
            if (pos != std::string::npos) b = buf.substr(pos+1);
Packit 01d647
        }
Packit 01d647
        value_[lang] = b;
Packit 01d647
        return 0;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    LangAltValue::AutoPtr LangAltValue::clone() const
Packit 01d647
    {
Packit 01d647
        return AutoPtr(clone_());
Packit 01d647
    }
Packit 01d647
Packit 01d647
    long LangAltValue::count() const
Packit 01d647
    {
Packit 01d647
        return static_cast<long>(value_.size());
Packit 01d647
    }
Packit 01d647
Packit 01d647
    static const std::string x_default = "x-default";
Packit 01d647
Packit 01d647
    std::ostream& LangAltValue::write(std::ostream& os) const
Packit 01d647
    {
Packit 01d647
        bool        first     = true;
Packit 01d647
Packit 01d647
        // Write the default entry first
Packit 01d647
        ValueType::const_iterator i = value_.find(x_default);
Packit 01d647
        if (i != value_.end()) {
Packit 01d647
            os << "lang=\"" << i->first << "\" " << i->second;
Packit 01d647
            first = false;
Packit 01d647
        }
Packit 01d647
Packit 01d647
        // Write the others
Packit 01d647
        for (i = value_.begin(); i != value_.end(); ++i) {
Packit 01d647
            if (i->first != x_default ) {
Packit 01d647
                if (!first) os << ", ";
Packit 01d647
                os << "lang=\"" << i->first << "\" " << i->second;
Packit 01d647
                first = false;
Packit 01d647
            }
Packit 01d647
        }
Packit 01d647
        return os;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    std::string LangAltValue::toString(long /*n*/) const
Packit 01d647
    {
Packit 01d647
        return toString(x_default);
Packit 01d647
    }
Packit 01d647
Packit 01d647
    std::string LangAltValue::toString(const std::string& qualifier) const
Packit 01d647
    {
Packit 01d647
        ValueType::const_iterator i = value_.find(qualifier);
Packit 01d647
        if (i != value_.end()) {
Packit 01d647
            ok_ = true;
Packit 01d647
            return i->second;
Packit 01d647
        }
Packit 01d647
        ok_ = false;
Packit 01d647
        return "";
Packit 01d647
    }
Packit 01d647
Packit 01d647
    long LangAltValue::toLong(long /*n*/) const
Packit 01d647
    {
Packit 01d647
        ok_ = false;
Packit 01d647
        return 0;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    float LangAltValue::toFloat(long /*n*/) const
Packit 01d647
    {
Packit 01d647
        ok_ = false;
Packit 01d647
        return 0.0f;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    Rational LangAltValue::toRational(long /*n*/) const
Packit 01d647
    {
Packit 01d647
        ok_ = false;
Packit 01d647
        return Rational(0, 0);
Packit 01d647
    }
Packit 01d647
Packit 01d647
    LangAltValue* LangAltValue::clone_() const
Packit 01d647
    {
Packit 01d647
        return new LangAltValue(*this);
Packit 01d647
    }
Packit 01d647
Packit 01d647
    DateValue::DateValue()
Packit 01d647
        : Value(date)
Packit 01d647
    {
Packit 01d647
    }
Packit 01d647
Packit 01d647
    DateValue::DateValue(int year, int month, int day)
Packit 01d647
        : Value(date)
Packit 01d647
    {
Packit 01d647
        date_.year = year;
Packit 01d647
        date_.month = month;
Packit 01d647
        date_.day = day;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    DateValue::~DateValue()
Packit 01d647
    {
Packit 01d647
    }
Packit 01d647
Packit 01d647
    int DateValue::read(const byte* buf, long len, ByteOrder /*byteOrder*/)
Packit 01d647
    {
Packit 01d647
        // Hard coded to read Iptc style dates
Packit 01d647
        if (len != 8) {
Packit 01d647
#ifndef SUPPRESS_WARNINGS
Packit 01d647
            EXV_WARNING << Error(kerUnsupportedDateFormat) << "\n";
Packit 01d647
#endif
Packit 01d647
            return 1;
Packit 01d647
        }
Packit 01d647
        // Make the buffer a 0 terminated C-string for sscanf
Packit 01d647
        char b[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
Packit 01d647
        std::memcpy(b, reinterpret_cast<const char*>(buf), 8);
Packit 01d647
        int scanned = sscanf(b, "%4d%2d%2d",
Packit 01d647
                             &date_.year, &date_.month, &date_.day);
Packit 01d647
        if (scanned != 3) {
Packit 01d647
#ifndef SUPPRESS_WARNINGS
Packit 01d647
            EXV_WARNING << Error(kerUnsupportedDateFormat) << "\n";
Packit 01d647
#endif
Packit 01d647
            return 1;
Packit 01d647
        }
Packit 01d647
        return 0;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    int DateValue::read(const std::string& buf)
Packit 01d647
    {
Packit 01d647
        // Hard coded to read Iptc style dates
Packit 01d647
        if (buf.length() < 8) {
Packit 01d647
#ifndef SUPPRESS_WARNINGS
Packit 01d647
            EXV_WARNING << Error(kerUnsupportedDateFormat) << "\n";
Packit 01d647
#endif
Packit 01d647
            return 1;
Packit 01d647
        }
Packit 01d647
        int scanned = sscanf(buf.c_str(), "%4d-%d-%d",
Packit 01d647
                             &date_.year, &date_.month, &date_.day);
Packit 01d647
        if (scanned != 3) {
Packit 01d647
#ifndef SUPPRESS_WARNINGS
Packit 01d647
            EXV_WARNING << Error(kerUnsupportedDateFormat) << "\n";
Packit 01d647
#endif
Packit 01d647
            return 1;
Packit 01d647
        }
Packit 01d647
        return 0;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    void DateValue::setDate(const Date& src)
Packit 01d647
    {
Packit 01d647
        date_.year = src.year;
Packit 01d647
        date_.month = src.month;
Packit 01d647
        date_.day = src.day;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    long DateValue::copy(byte* buf, ByteOrder /*byteOrder*/) const
Packit 01d647
    {
Packit 01d647
        // sprintf wants to add the null terminator, so use oversized buffer
Packit 01d647
        char temp[9];
Packit 01d647
Packit 01d647
        int wrote = sprintf(temp, "%04d%02d%02d", date_.year, date_.month, date_.day);
Packit 01d647
        assert(wrote == 8);
Packit 01d647
        std::memcpy(buf, temp, wrote);
Packit 01d647
        return wrote;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    const DateValue::Date& DateValue::getDate() const
Packit 01d647
    {
Packit 01d647
        return date_;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    long DateValue::count() const
Packit 01d647
    {
Packit 01d647
        return size();
Packit 01d647
    }
Packit 01d647
Packit 01d647
    long DateValue::size() const
Packit 01d647
    {
Packit 01d647
        return 8;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    DateValue* DateValue::clone_() const
Packit 01d647
    {
Packit 01d647
        return new DateValue(*this);
Packit 01d647
    }
Packit 01d647
Packit 01d647
    std::ostream& DateValue::write(std::ostream& os) const
Packit 01d647
    {
Packit 01d647
        std::ios::fmtflags f( os.flags() );
Packit 01d647
        os << date_.year << '-' << std::right
Packit 01d647
           << std::setw(2) << std::setfill('0') << date_.month << '-'
Packit 01d647
           << std::setw(2) << std::setfill('0') << date_.day;
Packit 01d647
        os.flags(f);
Packit 01d647
        return os;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    long DateValue::toLong(long /*n*/) const
Packit 01d647
    {
Packit 01d647
        // Range of tm struct is limited to about 1970 to 2038
Packit 01d647
        // This will return -1 if outside that range
Packit 01d647
        std::tm tms;
Packit 01d647
        std::memset(&tms, 0, sizeof(tms));
Packit 01d647
        tms.tm_mday = date_.day;
Packit 01d647
        tms.tm_mon = date_.month - 1;
Packit 01d647
        tms.tm_year = date_.year - 1900;
Packit 01d647
        long l = static_cast<long>(std::mktime(&tms));
Packit 01d647
        ok_ = (l != -1);
Packit 01d647
        return l;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    float DateValue::toFloat(long n) const
Packit 01d647
    {
Packit 01d647
        return static_cast<float>(toLong(n));
Packit 01d647
    }
Packit 01d647
Packit 01d647
    Rational DateValue::toRational(long n) const
Packit 01d647
    {
Packit 01d647
        return Rational(toLong(n), 1);
Packit 01d647
    }
Packit 01d647
Packit 01d647
    TimeValue::TimeValue()
Packit 01d647
        : Value(time)
Packit 01d647
    {
Packit 01d647
    }
Packit 01d647
Packit 01d647
    TimeValue::TimeValue(int hour, int minute,
Packit 01d647
                         int second, int tzHour,
Packit 01d647
                         int tzMinute)
Packit 01d647
        : Value(date)
Packit 01d647
    {
Packit 01d647
        time_.hour = hour;
Packit 01d647
        time_.minute = minute;
Packit 01d647
        time_.second = second;
Packit 01d647
        time_.tzHour = tzHour;
Packit 01d647
        time_.tzMinute = tzMinute;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    TimeValue::~TimeValue()
Packit 01d647
    {
Packit 01d647
    }
Packit 01d647
Packit 01d647
    int TimeValue::read(const byte* buf, long len, ByteOrder /*byteOrder*/)
Packit 01d647
    {
Packit 01d647
        // Make the buffer a 0 terminated C-string for scanTime[36]
Packit 01d647
        char b[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
Packit 01d647
        std::memcpy(b, reinterpret_cast<const char*>(buf), (len < 12 ? len : 11));
Packit 01d647
        // Hard coded to read HHMMSS or Iptc style times
Packit 01d647
        int rc = 1;
Packit 01d647
        if (len == 6) {
Packit 01d647
            // Try to read (non-standard) HHMMSS format
Packit 01d647
            rc = scanTime3(b, "%2d%2d%2d");
Packit 01d647
        }
Packit 01d647
        if (len == 11) {
Packit 01d647
            rc = scanTime6(b, "%2d%2d%2d%1c%2d%2d");
Packit 01d647
        }
Packit 01d647
        if (rc) {
Packit 01d647
            rc = 1;
Packit 01d647
#ifndef SUPPRESS_WARNINGS
Packit 01d647
            EXV_WARNING << Error(kerUnsupportedTimeFormat) << "\n";
Packit 01d647
#endif
Packit 01d647
        }
Packit 01d647
        return rc;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    int TimeValue::read(const std::string& buf)
Packit 01d647
    {
Packit 01d647
        // Hard coded to read H:M:S or Iptc style times
Packit 01d647
        int rc = 1;
Packit 01d647
        if (buf.length() < 9) {
Packit 01d647
            // Try to read (non-standard) H:M:S format
Packit 01d647
            rc = scanTime3(buf.c_str(), "%d:%d:%d");
Packit 01d647
        }
Packit 01d647
        else {
Packit 01d647
            rc = scanTime6(buf.c_str(), "%d:%d:%d%1c%d:%d");
Packit 01d647
        }
Packit 01d647
        if (rc) {
Packit 01d647
            rc = 1;
Packit 01d647
#ifndef SUPPRESS_WARNINGS
Packit 01d647
            EXV_WARNING << Error(kerUnsupportedTimeFormat) << "\n";
Packit 01d647
#endif
Packit 01d647
        }
Packit 01d647
        return rc;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    int TimeValue::scanTime3(const char* buf, const char* format)
Packit 01d647
    {
Packit 01d647
        int rc = 1;
Packit 01d647
        Time t;
Packit 01d647
        int scanned = sscanf(buf, format, &t.hour, &t.minute, &t.second);
Packit 01d647
        if (   scanned  == 3
Packit 01d647
            && t.hour   >= 0 && t.hour   < 24
Packit 01d647
            && t.minute >= 0 && t.minute < 60
Packit 01d647
            && t.second >= 0 && t.second < 60) {
Packit 01d647
            time_ = t;
Packit 01d647
            rc = 0;
Packit 01d647
        }
Packit 01d647
        return rc;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    int TimeValue::scanTime6(const char* buf, const char* format)
Packit 01d647
    {
Packit 01d647
        int rc = 1;
Packit 01d647
        Time t;
Packit 01d647
        char plusMinus;
Packit 01d647
        int scanned = sscanf(buf, format, &t.hour, &t.minute, &t.second,
Packit 01d647
                             &plusMinus, &t.tzHour, &t.tzMinute);
Packit 01d647
        if (   scanned    == 6
Packit 01d647
            && t.hour     >= 0 && t.hour     < 24
Packit 01d647
            && t.minute   >= 0 && t.minute   < 60
Packit 01d647
            && t.second   >= 0 && t.second   < 60
Packit 01d647
            && t.tzHour   >= 0 && t.tzHour   < 24
Packit 01d647
            && t.tzMinute >= 0 && t.tzMinute < 60) {
Packit 01d647
            time_ = t;
Packit 01d647
            if (plusMinus == '-') {
Packit 01d647
                time_.tzHour *= -1;
Packit 01d647
                time_.tzMinute *= -1;
Packit 01d647
            }
Packit 01d647
            rc = 0;
Packit 01d647
        }
Packit 01d647
        return rc;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    void TimeValue::setTime( const Time& src )
Packit 01d647
    {
Packit 01d647
        std::memcpy(&time_, &src, sizeof(time_));
Packit 01d647
    }
Packit 01d647
Packit 01d647
    long TimeValue::copy(byte* buf, ByteOrder /*byteOrder*/) const
Packit 01d647
    {
Packit 01d647
        char temp[12];
Packit 01d647
        char plusMinus = '+';
Packit 01d647
        if (time_.tzHour < 0 || time_.tzMinute < 0)
Packit 01d647
            plusMinus = '-';
Packit 01d647
Packit 01d647
        const int wrote = snprintf(temp, sizeof(temp), // 11 bytes are written + \0
Packit 01d647
                   "%02d%02d%02d%1c%02d%02d",
Packit 01d647
                   time_.hour, time_.minute, time_.second,
Packit 01d647
                   plusMinus, abs(time_.tzHour), abs(time_.tzMinute));
Packit 01d647
Packit 01d647
        enforce(wrote == 11, Exiv2::kerUnsupportedTimeFormat);
Packit 01d647
        std::memcpy(buf, temp, wrote);
Packit 01d647
        return wrote;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    const TimeValue::Time& TimeValue::getTime() const
Packit 01d647
    {
Packit 01d647
        return time_;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    long TimeValue::count() const
Packit 01d647
    {
Packit 01d647
        return size();
Packit 01d647
    }
Packit 01d647
Packit 01d647
    long TimeValue::size() const
Packit 01d647
    {
Packit 01d647
        return 11;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    TimeValue* TimeValue::clone_() const
Packit 01d647
    {
Packit 01d647
        return new TimeValue(*this);
Packit 01d647
    }
Packit 01d647
Packit 01d647
    std::ostream& TimeValue::write(std::ostream& os) const
Packit 01d647
    {
Packit 01d647
        char plusMinus = '+';
Packit 01d647
        if (time_.tzHour < 0 || time_.tzMinute < 0) plusMinus = '-';
Packit 01d647
Packit 01d647
        std::ios::fmtflags f( os.flags() );
Packit 01d647
        os << std::right
Packit 01d647
           << std::setw(2) << std::setfill('0') << time_.hour << ':'
Packit 01d647
           << std::setw(2) << std::setfill('0') << time_.minute << ':'
Packit 01d647
           << std::setw(2) << std::setfill('0') << time_.second << plusMinus
Packit 01d647
           << std::setw(2) << std::setfill('0') << abs(time_.tzHour) << ':'
Packit 01d647
           << std::setw(2) << std::setfill('0') << abs(time_.tzMinute);
Packit 01d647
        os.flags(f);
Packit 01d647
Packit 01d647
        return os;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    long TimeValue::toLong(long /*n*/) const
Packit 01d647
    {
Packit 01d647
        // Returns number of seconds in the day in UTC.
Packit 01d647
        long result = (time_.hour - time_.tzHour) * 60 * 60;
Packit 01d647
        result += (time_.minute - time_.tzMinute) * 60;
Packit 01d647
        result += time_.second;
Packit 01d647
        if (result < 0) {
Packit 01d647
            result += 86400;
Packit 01d647
        }
Packit 01d647
        ok_ = true;
Packit 01d647
        return result;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    float TimeValue::toFloat(long n) const
Packit 01d647
    {
Packit 01d647
        return static_cast<float>(toLong(n));
Packit 01d647
    }
Packit 01d647
Packit 01d647
    Rational TimeValue::toRational(long n) const
Packit 01d647
    {
Packit 01d647
        return Rational(toLong(n), 1);
Packit 01d647
    }
Packit 01d647
Packit 01d647
}                                       // namespace Exiv2