Blame src/types.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:      types.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
 */
Packit 01d647
// *****************************************************************************
Packit 01d647
// included header files
Packit 01d647
#include "types.hpp"
Packit 01d647
#include "enforce.hpp"
Packit 01d647
#include "futils.hpp"
Packit 01d647
#include "i18n.h"  // for _exvGettext
Packit 01d647
#include "safe_op.hpp"
Packit 01d647
#include "unused.h"
Packit 01d647
Packit 01d647
// + standard includes
Packit 01d647
#ifdef EXV_UNICODE_PATH
Packit 01d647
# include <windows.h> // for MultiByteToWideChar etc
Packit 01d647
#endif
Packit 01d647
#include <string>
Packit 01d647
#include <iostream>
Packit 01d647
#include <iomanip>
Packit 01d647
#include <sstream>
Packit 01d647
#include <utility>
Packit 01d647
#include <cctype>
Packit 01d647
#include <ctime>
Packit 01d647
#include <cstdio>
Packit 01d647
#include <cstdlib>
Packit 01d647
#include <cassert>
Packit 01d647
#include <cstring>
Packit 01d647
#include <cmath>
Packit 01d647
#include <math.h>
Packit 01d647
Packit 01d647
// *****************************************************************************
Packit 01d647
namespace {
Packit 01d647
Packit 01d647
    //! Information pertaining to the defined %Exiv2 value type identifiers.
Packit 01d647
    struct TypeInfoTable {
Packit 01d647
        Exiv2::TypeId typeId_;                  //!< Type id
Packit 01d647
        const char* name_;                      //!< Name of the type
Packit 01d647
        long size_;                             //!< Bytes per data entry
Packit 01d647
        //! Comparison operator for \em typeId
Packit 01d647
        bool operator==(Exiv2::TypeId typeId) const
Packit 01d647
        {
Packit 01d647
            return typeId_ == typeId;
Packit 01d647
        }
Packit 01d647
        //! Comparison operator for \em name
Packit 01d647
        bool operator==(const std::string& name) const
Packit 01d647
        {
Packit 01d647
            return 0 == strcmp(name_, name.c_str());
Packit 01d647
        }
Packit 01d647
    }; // struct TypeInfoTable
Packit 01d647
Packit 01d647
    //! Lookup list with information of Exiv2 types
Packit 01d647
    const TypeInfoTable typeInfoTable[] = {
Packit 01d647
        { Exiv2::invalidTypeId,    "Invalid",     0 },
Packit 01d647
        { Exiv2::unsignedByte,     "Byte",        1 },
Packit 01d647
        { Exiv2::asciiString,      "Ascii",       1 },
Packit 01d647
        { Exiv2::unsignedShort,    "Short",       2 },
Packit 01d647
        { Exiv2::unsignedLong,     "Long",        4 },
Packit 01d647
        { Exiv2::unsignedRational, "Rational",    8 },
Packit 01d647
        { Exiv2::signedByte,       "SByte",       1 },
Packit 01d647
        { Exiv2::undefined,        "Undefined",   1 },
Packit 01d647
        { Exiv2::signedShort,      "SShort",      2 },
Packit 01d647
        { Exiv2::signedLong,       "SLong",       4 },
Packit 01d647
        { Exiv2::signedRational,   "SRational",   8 },
Packit 01d647
        { Exiv2::tiffFloat,        "Float",       4 },
Packit 01d647
        { Exiv2::tiffDouble,       "Double",      8 },
Packit 01d647
        { Exiv2::tiffIfd,          "Ifd",         4 },
Packit 01d647
        { Exiv2::string,           "String",      1 },
Packit 01d647
        { Exiv2::date,             "Date",        8 },
Packit 01d647
        { Exiv2::time,             "Time",       11 },
Packit 01d647
        { Exiv2::comment,          "Comment",     1 },
Packit 01d647
        { Exiv2::directory,        "Directory",   1 },
Packit 01d647
        { Exiv2::xmpText,          "XmpText",     1 },
Packit 01d647
        { Exiv2::xmpAlt,           "XmpAlt",      1 },
Packit 01d647
        { Exiv2::xmpBag,           "XmpBag",      1 },
Packit 01d647
        { Exiv2::xmpSeq,           "XmpSeq",      1 },
Packit 01d647
        { Exiv2::langAlt,          "LangAlt",     1 }
Packit 01d647
    };
Packit 01d647
Packit 01d647
}
Packit 01d647
Packit 01d647
// *****************************************************************************
Packit 01d647
// class member definitions
Packit 01d647
namespace Exiv2 {
Packit 01d647
Packit 01d647
    const char* TypeInfo::typeName(TypeId typeId)
Packit 01d647
    {
Packit 01d647
        const TypeInfoTable* tit = find(typeInfoTable, typeId);
Packit 01d647
        if (!tit) return 0;
Packit 01d647
        return tit->name_;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    TypeId TypeInfo::typeId(const std::string& typeName)
Packit 01d647
    {
Packit 01d647
        const TypeInfoTable* tit = find(typeInfoTable, typeName);
Packit 01d647
        if (!tit) return invalidTypeId;
Packit 01d647
        return tit->typeId_;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    long TypeInfo::typeSize(TypeId typeId)
Packit 01d647
    {
Packit 01d647
        const TypeInfoTable* tit = find(typeInfoTable, typeId);
Packit 01d647
        if (!tit) return 0;
Packit 01d647
        return tit->size_;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    DataBuf::DataBuf(DataBuf& rhs)
Packit 01d647
        : pData_(rhs.pData_), size_(rhs.size_)
Packit 01d647
    {
Packit 01d647
        std::pair<byte*, long> ret = rhs.release();
Packit 01d647
        UNUSED(ret);
Packit 01d647
    }
Packit 01d647
Packit 01d647
    DataBuf::~DataBuf()
Packit 01d647
    { delete[] pData_; }
Packit 01d647
Packit 01d647
    DataBuf::DataBuf() : pData_(0), size_(0)
Packit 01d647
    {}
Packit 01d647
Packit 01d647
    DataBuf::DataBuf(long size) : pData_(new byte[size]()), size_(size)
Packit 01d647
    {}
Packit 01d647
Packit 01d647
    DataBuf::DataBuf(const byte* pData, long size)
Packit 01d647
        : pData_(0), size_(0)
Packit 01d647
    {
Packit 01d647
        if (size > 0) {
Packit 01d647
            pData_ = new byte[size];
Packit 01d647
            std::memcpy(pData_, pData, size);
Packit 01d647
            size_ = size;
Packit 01d647
        }
Packit 01d647
    }
Packit 01d647
Packit 01d647
    DataBuf& DataBuf::operator=(DataBuf& rhs)
Packit 01d647
    {
Packit 01d647
        if (this == &rhs) return *this;
Packit 01d647
        reset(rhs.release());
Packit 01d647
        return *this;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    void DataBuf::alloc(long size)
Packit 01d647
    {
Packit 01d647
        if (size > size_) {
Packit 01d647
            delete[] pData_;
Packit 01d647
            pData_ = 0;
Packit 01d647
            size_ = 0;
Packit 01d647
            pData_ = new byte[size];
Packit 01d647
            size_ = size;
Packit 01d647
        }
Packit 01d647
    }
Packit 01d647
Packit 01d647
    EXV_WARN_UNUSED_RESULT std::pair<byte*, long> DataBuf::release()
Packit 01d647
    {
Packit 01d647
        std::pair<byte*, long> p = std::make_pair(pData_, size_);
Packit 01d647
        pData_ = 0;
Packit 01d647
        size_ = 0;
Packit 01d647
        return p;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    void DataBuf::free()
Packit 01d647
    {
Packit 01d647
        delete[] pData_;
Packit 01d647
        pData_ = 0;
Packit 01d647
        size_ = 0;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    void DataBuf::reset(std::pair<byte*, long> p)
Packit 01d647
    {
Packit 01d647
        if (pData_ != p.first) {
Packit 01d647
            delete[] pData_;
Packit 01d647
            pData_ = p.first;
Packit 01d647
        }
Packit 01d647
        size_ = p.second;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    DataBuf::DataBuf(const DataBufRef &rhs) : pData_(rhs.p.first), size_(rhs.p.second) {}
Packit 01d647
Packit 01d647
    DataBuf &DataBuf::operator=(DataBufRef rhs) { reset(rhs.p); return *this; }
Packit 01d647
Packit 01d647
    Exiv2::DataBuf::operator DataBufRef() { return DataBufRef(release()); }
Packit 01d647
Packit 01d647
    // *************************************************************************
Packit 01d647
    // free functions
Packit 01d647
Packit 01d647
    static void checkDataBufBounds(const DataBuf& buf, size_t end) {
Packit 01d647
        enforce<std::invalid_argument>(end <= static_cast<size_t>(std::numeric_limits<long>::max()),
Packit 01d647
                                       "end of slice too large to be compared with DataBuf bounds.");
Packit 01d647
        enforce<std::out_of_range>(static_cast<long>(end) <= buf.size_, "Invalid slice bounds specified");
Packit 01d647
    }
Packit 01d647
Packit 01d647
    Slice<byte*> makeSlice(DataBuf& buf, size_t begin, size_t end)
Packit 01d647
    {
Packit 01d647
        checkDataBufBounds(buf, end);
Packit 01d647
        return Slice<byte*>(buf.pData_, begin, end);
Packit 01d647
    }
Packit 01d647
Packit 01d647
    Slice<const byte*> makeSlice(const DataBuf& buf, size_t begin, size_t end)
Packit 01d647
    {
Packit 01d647
        checkDataBufBounds(buf, end);
Packit 01d647
        return Slice<const byte*>(buf.pData_, begin, end);
Packit 01d647
    }
Packit 01d647
Packit 01d647
    std::ostream& operator<<(std::ostream& os, const Rational& r)
Packit 01d647
    {
Packit 01d647
        return os << r.first << "/" << r.second;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    std::istream& operator>>(std::istream& is, Rational& r)
Packit 01d647
    {
Packit 01d647
        // http://dev.exiv2.org/boards/3/topics/1912?r=1915
Packit 01d647
        if ( std::tolower(is.peek()) == 'f' ) {
Packit 01d647
            char  F = 0;
Packit 01d647
            float f = 0.f;
Packit 01d647
            is >> F >> f ;
Packit 01d647
            f  = 2.0f * std::log(f) / std::log(2.0f) ;
Packit 01d647
            r  = Exiv2::floatToRationalCast(f);
Packit 01d647
        } else {
Packit 01d647
            int32_t nominator = 0;
Packit 01d647
            int32_t denominator = 0;
Packit 01d647
            char c('\0');
Packit 01d647
            is >> nominator >> c >> denominator;
Packit 01d647
            if (c != '/')
Packit 01d647
                is.setstate(std::ios::failbit);
Packit 01d647
            if (is)
Packit 01d647
                r = std::make_pair(nominator, denominator);
Packit 01d647
        }
Packit 01d647
        return is;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    std::ostream& operator<<(std::ostream& os, const URational& r)
Packit 01d647
    {
Packit 01d647
        return os << r.first << "/" << r.second;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    std::istream& operator>>(std::istream& is, URational& r)
Packit 01d647
    {
Packit 01d647
        // http://dev.exiv2.org/boards/3/topics/1912?r=1915
Packit 01d647
        /// \todo This implementation seems to be duplicated for the Rational type. Try to remove duplication
Packit 01d647
        if ( std::tolower(is.peek()) == 'f' ) {
Packit 01d647
            char  F = 0;
Packit 01d647
            float f = 0.f;
Packit 01d647
            is >> F >> f ;
Packit 01d647
            f  = 2.0f * std::log(f) / std::log(2.0f) ;
Packit 01d647
            r  = Exiv2::floatToRationalCast(f);
Packit 01d647
        } else {
Packit 01d647
            uint32_t nominator = 0;
Packit 01d647
            uint32_t denominator = 0;
Packit 01d647
            char c('\0');
Packit 01d647
            is >> nominator >> c >> denominator;
Packit 01d647
            if (c != '/')
Packit 01d647
                is.setstate(std::ios::failbit);
Packit 01d647
            if (is)
Packit 01d647
                r = std::make_pair(nominator, denominator);
Packit 01d647
        }
Packit 01d647
        return is;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    uint16_t getUShort(const byte* buf, ByteOrder byteOrder)
Packit 01d647
    {
Packit 01d647
        return getUShort(makeSliceUntil(buf, 2), byteOrder);
Packit 01d647
    }
Packit 01d647
Packit 01d647
    uint32_t getULong(const byte* buf, ByteOrder byteOrder)
Packit 01d647
    {
Packit 01d647
        if (byteOrder == littleEndian) {
Packit 01d647
            return   (byte)buf[3] << 24 | (byte)buf[2] << 16
Packit 01d647
                   | (byte)buf[1] <<  8 | (byte)buf[0];
Packit 01d647
        }
Packit 01d647
        else {
Packit 01d647
            return   (byte)buf[0] << 24 | (byte)buf[1] << 16
Packit 01d647
                   | (byte)buf[2] <<  8 | (byte)buf[3];
Packit 01d647
        }
Packit 01d647
    }
Packit 01d647
Packit 01d647
    uint64_t getULongLong(const byte* buf, ByteOrder byteOrder)
Packit 01d647
    {
Packit 01d647
        if (byteOrder == littleEndian) {
Packit 01d647
            return   (uint64_t)buf[7] << 56 | (uint64_t)buf[6] << 48
Packit 01d647
                   | (uint64_t)buf[5] << 40 | (uint64_t)buf[4] << 32
Packit 01d647
                   | (uint64_t)buf[3] << 24 | (uint64_t)buf[2] << 16
Packit 01d647
                   | (uint64_t)buf[1] <<  8 | (uint64_t)buf[0];
Packit 01d647
        }
Packit 01d647
        else {
Packit 01d647
            return   (uint64_t)buf[0] << 56 | (uint64_t)buf[1] << 48
Packit 01d647
                   | (uint64_t)buf[2] << 40 | (uint64_t)buf[3] << 32
Packit 01d647
                   | (uint64_t)buf[4] << 24 | (uint64_t)buf[5] << 16
Packit 01d647
                   | (uint64_t)buf[6] <<  8 | (uint64_t)buf[7];
Packit 01d647
        }
Packit 01d647
    }
Packit 01d647
Packit 01d647
    URational getURational(const byte* buf, ByteOrder byteOrder)
Packit 01d647
    {
Packit 01d647
        uint32_t nominator = getULong(buf, byteOrder);
Packit 01d647
        uint32_t denominator = getULong(buf + 4, byteOrder);
Packit 01d647
        return std::make_pair(nominator, denominator);
Packit 01d647
    }
Packit 01d647
Packit 01d647
    int16_t getShort(const byte* buf, ByteOrder byteOrder)
Packit 01d647
    {
Packit 01d647
        if (byteOrder == littleEndian) {
Packit 01d647
            return (byte)buf[1] << 8 | (byte)buf[0];
Packit 01d647
        }
Packit 01d647
        else {
Packit 01d647
            return (byte)buf[0] << 8 | (byte)buf[1];
Packit 01d647
        }
Packit 01d647
    }
Packit 01d647
Packit 01d647
    int32_t getLong(const byte* buf, ByteOrder byteOrder)
Packit 01d647
    {
Packit 01d647
        if (byteOrder == littleEndian) {
Packit 01d647
            return   (byte)buf[3] << 24 | (byte)buf[2] << 16
Packit 01d647
                   | (byte)buf[1] <<  8 | (byte)buf[0];
Packit 01d647
        }
Packit 01d647
        else {
Packit 01d647
            return   (byte)buf[0] << 24 | (byte)buf[1] << 16
Packit 01d647
                   | (byte)buf[2] <<  8 | (byte)buf[3];
Packit 01d647
        }
Packit 01d647
    }
Packit 01d647
Packit 01d647
    Rational getRational(const byte* buf, ByteOrder byteOrder)
Packit 01d647
    {
Packit 01d647
        int32_t nominator = getLong(buf, byteOrder);
Packit 01d647
        int32_t denominator = getLong(buf + 4, byteOrder);
Packit 01d647
        return std::make_pair(nominator, denominator);
Packit 01d647
    }
Packit 01d647
Packit 01d647
    float getFloat(const byte* buf, ByteOrder byteOrder)
Packit 01d647
    {
Packit 01d647
        // This algorithm assumes that the internal representation of the float
Packit 01d647
        // type is the 4-byte IEEE 754 binary32 format, which is common but not
Packit 01d647
        // required by the C++ standard.
Packit 01d647
        assert(sizeof(float) == 4);
Packit 01d647
        union {
Packit 01d647
            uint32_t ul_;
Packit 01d647
            float    f_;
Packit 01d647
        } u;
Packit 01d647
        u.ul_ = getULong(buf, byteOrder);
Packit 01d647
        return u.f_;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    double getDouble(const byte* buf, ByteOrder byteOrder)
Packit 01d647
    {
Packit 01d647
        // This algorithm assumes that the internal representation of the double
Packit 01d647
        // type is the 8-byte IEEE 754 binary64 format, which is common but not
Packit 01d647
        // required by the C++ standard.
Packit 01d647
        assert(sizeof(double) == 8);
Packit 01d647
        union {
Packit 01d647
            uint64_t ull_;
Packit 01d647
            double   d_;
Packit 01d647
        } u;
Packit 01d647
        u.ull_ = 0;
Packit 01d647
        if (byteOrder == littleEndian) {
Packit 01d647
            u.ull_ =   static_cast<uint64_t>(buf[7]) << 56
Packit 01d647
                     | static_cast<uint64_t>(buf[6]) << 48
Packit 01d647
                     | static_cast<uint64_t>(buf[5]) << 40
Packit 01d647
                     | static_cast<uint64_t>(buf[4]) << 32
Packit 01d647
                     | static_cast<uint64_t>(buf[3]) << 24
Packit 01d647
                     | static_cast<uint64_t>(buf[2]) << 16
Packit 01d647
                     | static_cast<uint64_t>(buf[1]) <<  8
Packit 01d647
                     | static_cast<uint64_t>(buf[0]);
Packit 01d647
        }
Packit 01d647
        else {
Packit 01d647
            u.ull_ =   static_cast<uint64_t>(buf[0]) << 56
Packit 01d647
                     | static_cast<uint64_t>(buf[1]) << 48
Packit 01d647
                     | static_cast<uint64_t>(buf[2]) << 40
Packit 01d647
                     | static_cast<uint64_t>(buf[3]) << 32
Packit 01d647
                     | static_cast<uint64_t>(buf[4]) << 24
Packit 01d647
                     | static_cast<uint64_t>(buf[5]) << 16
Packit 01d647
                     | static_cast<uint64_t>(buf[6]) <<  8
Packit 01d647
                     | static_cast<uint64_t>(buf[7]);
Packit 01d647
        }
Packit 01d647
        return u.d_;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    long us2Data(byte* buf, uint16_t s, ByteOrder byteOrder)
Packit 01d647
    {
Packit 01d647
        if (byteOrder == littleEndian) {
Packit 01d647
            buf[0] = (byte) (s & 0x00ff);
Packit 01d647
            buf[1] = (byte)((s & 0xff00) >> 8);
Packit 01d647
        }
Packit 01d647
        else {
Packit 01d647
            buf[0] = (byte)((s & 0xff00) >> 8);
Packit 01d647
            buf[1] = (byte) (s & 0x00ff);
Packit 01d647
        }
Packit 01d647
        return 2;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    long ul2Data(byte* buf, uint32_t l, ByteOrder byteOrder)
Packit 01d647
    {
Packit 01d647
        if (byteOrder == littleEndian) {
Packit 01d647
            buf[0] = (byte) (l & 0x000000ff);
Packit 01d647
            buf[1] = (byte)((l & 0x0000ff00) >> 8);
Packit 01d647
            buf[2] = (byte)((l & 0x00ff0000) >> 16);
Packit 01d647
            buf[3] = (byte)((l & 0xff000000) >> 24);
Packit 01d647
        }
Packit 01d647
        else {
Packit 01d647
            buf[0] = (byte)((l & 0xff000000) >> 24);
Packit 01d647
            buf[1] = (byte)((l & 0x00ff0000) >> 16);
Packit 01d647
            buf[2] = (byte)((l & 0x0000ff00) >> 8);
Packit 01d647
            buf[3] = (byte) (l & 0x000000ff);
Packit 01d647
        }
Packit 01d647
        return 4;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    long ur2Data(byte* buf, URational l, ByteOrder byteOrder)
Packit 01d647
    {
Packit 01d647
        long o = ul2Data(buf, l.first, byteOrder);
Packit 01d647
        o += ul2Data(buf+o, l.second, byteOrder);
Packit 01d647
        return o;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    long s2Data(byte* buf, int16_t s, ByteOrder byteOrder)
Packit 01d647
    {
Packit 01d647
        if (byteOrder == littleEndian) {
Packit 01d647
            buf[0] =  (byte)(s & 0x00ff);
Packit 01d647
            buf[1] = (byte)((s & 0xff00) >> 8);
Packit 01d647
        }
Packit 01d647
        else {
Packit 01d647
            buf[0] = (byte)((s & 0xff00) >> 8);
Packit 01d647
            buf[1] =  (byte)(s & 0x00ff);
Packit 01d647
        }
Packit 01d647
        return 2;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    long l2Data(byte* buf, int32_t l, ByteOrder byteOrder)
Packit 01d647
    {
Packit 01d647
        if (byteOrder == littleEndian) {
Packit 01d647
            buf[0] =  (byte)(l & 0x000000ff);
Packit 01d647
            buf[1] = (byte)((l & 0x0000ff00) >> 8);
Packit 01d647
            buf[2] = (byte)((l & 0x00ff0000) >> 16);
Packit 01d647
            buf[3] = (byte)((l & 0xff000000) >> 24);
Packit 01d647
        }
Packit 01d647
        else {
Packit 01d647
            buf[0] = (byte)((l & 0xff000000) >> 24);
Packit 01d647
            buf[1] = (byte)((l & 0x00ff0000) >> 16);
Packit 01d647
            buf[2] = (byte)((l & 0x0000ff00) >> 8);
Packit 01d647
            buf[3] =  (byte)(l & 0x000000ff);
Packit 01d647
        }
Packit 01d647
        return 4;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    long r2Data(byte* buf, Rational l, ByteOrder byteOrder)
Packit 01d647
    {
Packit 01d647
        long o = l2Data(buf, l.first, byteOrder);
Packit 01d647
        o += l2Data(buf+o, l.second, byteOrder);
Packit 01d647
        return o;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    long f2Data(byte* buf, float f, ByteOrder byteOrder)
Packit 01d647
    {
Packit 01d647
        // This algorithm assumes that the internal representation of the float
Packit 01d647
        // type is the 4-byte IEEE 754 binary32 format, which is common but not
Packit 01d647
        // required by the C++ standard.
Packit 01d647
        assert(sizeof(float) == 4);
Packit 01d647
        union {
Packit 01d647
            uint32_t ul_;
Packit 01d647
            float    f_;
Packit 01d647
        } u;
Packit 01d647
        u.f_ = f;
Packit 01d647
        return ul2Data(buf, u.ul_, byteOrder);
Packit 01d647
    }
Packit 01d647
Packit 01d647
    long d2Data(byte* buf, double d, ByteOrder byteOrder)
Packit 01d647
    {
Packit 01d647
        // This algorithm assumes that the internal representation of the double
Packit 01d647
        // type is the 8-byte IEEE 754 binary64 format, which is common but not
Packit 01d647
        // required by the C++ standard.
Packit 01d647
        assert(sizeof(double) == 8);
Packit 01d647
        union {
Packit 01d647
            uint64_t ull_;
Packit 01d647
            double   d_;
Packit 01d647
        } u;
Packit 01d647
        u.d_ = d;
Packit 01d647
        uint64_t m = 0xff;
Packit 01d647
        if (byteOrder == littleEndian) {
Packit 01d647
            buf[0] =  (byte)(u.ull_ & m);
Packit 01d647
            buf[1] = (byte)((u.ull_ & (m <<  8)) >>  8);
Packit 01d647
            buf[2] = (byte)((u.ull_ & (m << 16)) >> 16);
Packit 01d647
            buf[3] = (byte)((u.ull_ & (m << 24)) >> 24);
Packit 01d647
            buf[4] = (byte)((u.ull_ & (m << 32)) >> 32);
Packit 01d647
            buf[5] = (byte)((u.ull_ & (m << 40)) >> 40);
Packit 01d647
            buf[6] = (byte)((u.ull_ & (m << 48)) >> 48);
Packit 01d647
            buf[7] = (byte)((u.ull_ & (m << 56)) >> 56);
Packit 01d647
        }
Packit 01d647
        else {
Packit 01d647
            buf[0] = (byte)((u.ull_ & (m << 56)) >> 56);
Packit 01d647
            buf[1] = (byte)((u.ull_ & (m << 48)) >> 48);
Packit 01d647
            buf[2] = (byte)((u.ull_ & (m << 40)) >> 40);
Packit 01d647
            buf[3] = (byte)((u.ull_ & (m << 32)) >> 32);
Packit 01d647
            buf[4] = (byte)((u.ull_ & (m << 24)) >> 24);
Packit 01d647
            buf[5] = (byte)((u.ull_ & (m << 16)) >> 16);
Packit 01d647
            buf[6] = (byte)((u.ull_ & (m <<  8)) >>  8);
Packit 01d647
            buf[7] =  (byte)(u.ull_ & m);
Packit 01d647
        }
Packit 01d647
        return 8;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    void hexdump(std::ostream& os, const byte* buf, long len, long offset)
Packit 01d647
    {
Packit 01d647
        const std::string::size_type pos = 8 + 16 * 3 + 2;
Packit 01d647
        const std::string align(pos, ' ');
Packit 01d647
        std::ios::fmtflags f( os.flags() );
Packit 01d647
Packit 01d647
        long i = 0;
Packit 01d647
        while (i < len) {
Packit 01d647
            os << "  "
Packit 01d647
               << std::setw(4) << std::setfill('0') << std::hex
Packit 01d647
               << i + offset << "  ";
Packit 01d647
            std::ostringstream ss;
Packit 01d647
            do {
Packit 01d647
                byte c = buf[i];
Packit 01d647
                os << std::setw(2) << std::setfill('0') << std::right
Packit 01d647
                   << std::hex << (int)c << " ";
Packit 01d647
                ss << ((int)c >= 31 && (int)c < 127 ? char(buf[i]) : '.');
Packit 01d647
            } while (++i < len && i%16 != 0);
Packit 01d647
            std::string::size_type width = 9 + ((i-1)%16 + 1) * 3;
Packit 01d647
            os << (width > pos ? "" : align.substr(width)) << ss.str() << "\n";
Packit 01d647
        }
Packit 01d647
        os << std::dec << std::setfill(' ');
Packit 01d647
        os.flags(f);
Packit 01d647
    } // hexdump
Packit 01d647
Packit 01d647
    bool isHex(const std::string& str, size_t size, const std::string& prefix)
Packit 01d647
    {
Packit 01d647
        if (   str.size() <= prefix.size()
Packit 01d647
            || str.substr(0, prefix.size()) != prefix) return false;
Packit 01d647
        if (   size > 0
Packit 01d647
            && str.size() != size + prefix.size()) return false;
Packit 01d647
Packit 01d647
        for (size_t i = prefix.size(); i < str.size(); ++i) {
Packit 01d647
            if (!isxdigit(str[i])) return false;
Packit 01d647
        }
Packit 01d647
        return true;
Packit 01d647
    } // isHex
Packit 01d647
Packit 01d647
    int exifTime(const char* buf, struct tm* tm)
Packit 01d647
    {
Packit 01d647
        assert(buf != 0);
Packit 01d647
        assert(tm != 0);
Packit 01d647
        int rc = 1;
Packit 01d647
        int year, mon, mday, hour, min, sec;
Packit 01d647
        int scanned = std::sscanf(buf, "%4d:%2d:%2d %2d:%2d:%2d",
Packit 01d647
                                  &year, &mon, &mday, &hour, &min, &sec);
Packit 01d647
        if (scanned == 6) {
Packit 01d647
            tm->tm_year = year - 1900;
Packit 01d647
            tm->tm_mon  = mon - 1;
Packit 01d647
            tm->tm_mday = mday;
Packit 01d647
            tm->tm_hour = hour;
Packit 01d647
            tm->tm_min  = min;
Packit 01d647
            tm->tm_sec  = sec;
Packit 01d647
            rc = 0;
Packit 01d647
        }
Packit 01d647
        return rc;
Packit 01d647
    } // exifTime
Packit 01d647
Packit 01d647
    const char* exvGettext(const char* str)
Packit 01d647
    {
Packit 01d647
#ifdef EXV_ENABLE_NLS
Packit 01d647
        return _exvGettext(str);
Packit 01d647
#else
Packit 01d647
        return str;
Packit 01d647
#endif
Packit 01d647
    }
Packit 01d647
Packit 01d647
#ifdef EXV_UNICODE_PATH
Packit 01d647
    std::string ws2s(const std::wstring& s)
Packit 01d647
    {
Packit 01d647
        int len;
Packit 01d647
        int slength = (int)s.length() + 1;
Packit 01d647
        len = WideCharToMultiByte(CP_ACP, 0, s.c_str(), slength, 0, 0, 0, 0);
Packit 01d647
        char* buf = new char[len];
Packit 01d647
        WideCharToMultiByte(CP_ACP, 0, s.c_str(), slength, buf, len, 0, 0);
Packit 01d647
        std::string r(buf);
Packit 01d647
        delete[] buf;
Packit 01d647
        return r;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    std::wstring s2ws(const std::string& s)
Packit 01d647
    {
Packit 01d647
        int len;
Packit 01d647
        int slength = (int)s.length() + 1;
Packit 01d647
        len = MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, 0, 0);
Packit 01d647
        wchar_t* buf = new wchar_t[len];
Packit 01d647
        MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, buf, len);
Packit 01d647
        std::wstring r(buf);
Packit 01d647
        delete[] buf;
Packit 01d647
        return r;
Packit 01d647
    }
Packit 01d647
Packit 01d647
#endif // EXV_UNICODE_PATH
Packit 01d647
    template<>
Packit 01d647
    bool stringTo<bool>(const std::string& s, bool& ok)
Packit 01d647
    {
Packit 01d647
        std::string lcs(s); /* lowercase string */
Packit 01d647
        for(unsigned i = 0; i < lcs.length(); i++) {
Packit 01d647
            lcs[i] = std::tolower(s[i]);
Packit 01d647
        }
Packit 01d647
        /* handle the same values as xmp sdk */
Packit 01d647
        if (lcs == "false" || lcs == "f" || lcs == "0") {
Packit 01d647
            ok = true;
Packit 01d647
            return false;
Packit 01d647
        }
Packit 01d647
        if (lcs == "true" || lcs == "t" || lcs == "1") {
Packit 01d647
            ok = true;
Packit 01d647
            return true;
Packit 01d647
        }
Packit 01d647
        ok = false;
Packit 01d647
        return false;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    long parseLong(const std::string& s, bool& ok)
Packit 01d647
    {
Packit 01d647
        long ret = stringTo<long>(s, ok);
Packit 01d647
        if (ok) return ret;
Packit 01d647
Packit 01d647
        float f = stringTo<float>(s, ok);
Packit 01d647
        if (ok) return static_cast<long>(f);
Packit 01d647
Packit 01d647
        Rational r = stringTo<Rational>(s, ok);
Packit 01d647
        if (ok) {
Packit 01d647
            if (r.second == 0) {
Packit 01d647
                ok = false;
Packit 01d647
                return 0;
Packit 01d647
            }
Packit 01d647
            return static_cast<long>(static_cast<float>(r.first) / r.second);
Packit 01d647
        }
Packit 01d647
Packit 01d647
        bool b = stringTo<bool>(s, ok);
Packit 01d647
        if (ok) return b ? 1 : 0;
Packit 01d647
Packit 01d647
        // everything failed, return from stringTo<long> is probably the best fit
Packit 01d647
        return ret;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    float parseFloat(const std::string& s, bool& ok)
Packit 01d647
    {
Packit 01d647
        float ret = stringTo<float>(s, ok);
Packit 01d647
        if (ok) return ret;
Packit 01d647
Packit 01d647
        Rational r = stringTo<Rational>(s, ok);
Packit 01d647
        if (ok) {
Packit 01d647
            if (r.second == 0) {
Packit 01d647
                ok = false;
Packit 01d647
                return 0.0;
Packit 01d647
            }
Packit 01d647
            return static_cast<float>(r.first) / r.second;
Packit 01d647
        }
Packit 01d647
Packit 01d647
        bool b = stringTo<bool>(s, ok);
Packit 01d647
        if (ok) return b ? 1.0f : 0.0f;
Packit 01d647
Packit 01d647
        // everything failed, return from stringTo<float> is probably the best fit
Packit 01d647
        return ret;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    Rational parseRational(const std::string& s, bool& ok)
Packit 01d647
    {
Packit 01d647
        Rational ret = stringTo<Rational>(s, ok);
Packit 01d647
        if (ok) return ret;
Packit 01d647
Packit 01d647
        long l = stringTo<long>(s, ok);
Packit 01d647
        if (ok) return Rational(l, 1);
Packit 01d647
Packit 01d647
        float f = stringTo<float>(s, ok);
Packit 01d647
        if (ok) return floatToRationalCast(f);
Packit 01d647
Packit 01d647
        bool b = stringTo<bool>(s, ok);
Packit 01d647
        if (ok) return b ? Rational(1, 1) : Rational(0, 1);
Packit 01d647
Packit 01d647
        // everything failed, return from stringTo<Rational> is probably the best fit
Packit 01d647
        return ret;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    Rational floatToRationalCast(float f)
Packit 01d647
    {
Packit 01d647
#if defined(_MSC_VER) && _MSC_VER < 1800
Packit 01d647
        if (!_finite(f)) {
Packit 01d647
#else
Packit 01d647
        if (!std::isfinite(f)) {
Packit 01d647
#endif
Packit 01d647
            return Rational(f > 0 ? 1 : -1, 0);
Packit 01d647
        }
Packit 01d647
        // Beware: primitive conversion algorithm
Packit 01d647
        int32_t den = 1000000;
Packit 01d647
        const long f_as_long = static_cast<long>(f);
Packit 01d647
        if (Safe::abs(f_as_long) > 2147) {
Packit 01d647
            den = 10000;
Packit 01d647
        }
Packit 01d647
        if (Safe::abs(f_as_long) > 214748) {
Packit 01d647
            den = 100;
Packit 01d647
        }
Packit 01d647
        if (Safe::abs(f_as_long) > 21474836) {
Packit 01d647
            den = 1;
Packit 01d647
        }
Packit 01d647
        const float rnd = f >= 0 ? 0.5f : -0.5f;
Packit 01d647
        const int32_t nom = static_cast<int32_t>(f * den + rnd);
Packit 01d647
        const int32_t g = gcd(nom, den);
Packit 01d647
Packit 01d647
        return Rational(nom / g, den / g);
Packit 01d647
    }
Packit 01d647
Packit 01d647
}                                       // namespace Exiv2
Packit 01d647
Packit 01d647
#ifdef EXV_ENABLE_NLS
Packit 01d647
// Declaration is in i18n.h
Packit 01d647
const char* _exvGettext(const char* str)
Packit 01d647
{
Packit 01d647
    static bool exvGettextInitialized = false;
Packit 01d647
Packit 01d647
    if (!exvGettextInitialized) {
Packit 01d647
        //bindtextdomain(EXV_PACKAGE_NAME, EXV_LOCALEDIR);
Packit 01d647
        const std::string localeDir = Exiv2::getProcessPath() + EXV_LOCALEDIR;
Packit 01d647
        bindtextdomain(EXV_PACKAGE_NAME, localeDir.c_str());
Packit 01d647
# ifdef EXV_HAVE_BIND_TEXTDOMAIN_CODESET
Packit 01d647
        bind_textdomain_codeset (EXV_PACKAGE_NAME, "UTF-8");
Packit 01d647
# endif
Packit 01d647
        exvGettextInitialized = true;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    return dgettext(EXV_PACKAGE_NAME, str);
Packit 01d647
}
Packit 01d647
#endif // EXV_ENABLE_NLS