Commit message: Change BasicIO read/write methods to use size_t
CVE: CVE-2019-13504
Vulnerability description: There is an out-of-bounds read in Exiv2::MrwImage::readMetadata in mrwimage.cpp in Exiv2 through 0.27.2.

Project: exiv2
File: jp2image.cpp

    void Jp2Image::readMetadata()
    {
#ifdef DEBUG
        std::cerr << "Exiv2::Jp2Image::readMetadata: Reading JPEG-2000 file " << io_->path() << std::endl;
#endif
        if (io_->open() != 0)
        {
            throw Error(kerDataSourceOpenFailed, io_->path(), strError());
        }
        IoCloser closer(*io_);
        // Ensure that this is the correct image type
        if (!isJp2Type(*io_, true))
        {
            if (io_->error() || io_->eof()) throw Error(kerFailedToReadImageData);
            throw Error(kerNotAnImage, "JPEG-2000");
        }

        Jp2BoxHeader      box       = {0,0};
        Jp2BoxHeader      subBox    = {0,0};
        Jp2ImageHeaderBox ihdr      = {0,0,0,0,0,0,0,0};
        Jp2UuidBox        uuid      = {{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};

        while (io_->read((byte*)&box, sizeof(box)) == sizeof(box))
        {
            long position = io_->tell();
            box.length = getLong((byte*)&box.length, bigEndian);
            box.type   = getLong((byte*)&box.type, bigEndian);
#ifdef DEBUG
            std::cout << "Exiv2::Jp2Image::readMetadata: "
                      << "Position: " << position
                      << " box type: " << toAscii(box.type)
                      << " length: " << box.length
                      << std::endl;
#endif

            if (box.length == 0) return ;

            if (box.length == 1)
            {
                // FIXME. Special case. the real box size is given in another place.
            }

            switch(box.type)
            {
                case kJp2BoxTypeJp2Header:
                {
#ifdef DEBUG
                    std::cout << "Exiv2::Jp2Image::readMetadata: JP2Header box found" << std::endl;
#endif
                    long restore = io_->tell();

                    while (io_->read((byte*)&subBox, sizeof(subBox)) == sizeof(subBox) && subBox.length )
                    {
                        subBox.length = getLong((byte*)&subBox.length, bigEndian);
                        subBox.type   = getLong((byte*)&subBox.type, bigEndian);
#ifdef DEBUG
                        std::cout << "Exiv2::Jp2Image::readMetadata: "
                        << "subBox = " << toAscii(subBox.type) << " length = " << subBox.length << std::endl;
#endif
                        if(subBox.type == kJp2BoxTypeColorHeader && subBox.length != 15)
                        {
#ifdef DEBUG
                            std::cout << "Exiv2::Jp2Image::readMetadata: "
                                     << "Color data found" << std::endl;
#endif

                            const long pad = 3 ; // 3 padding bytes 2 0 0
                            const size_t data_length = Safe::add(subBox.length, static_cast<uint32_t>(8));
                            // data_length makes no sense if it is larger than the rest of the file
                            if (data_length > io_->size() - io_->tell()) {
                                throw Error(kerCorruptedMetadata);
                            }
                            DataBuf data(static_cast<long>(data_length));
                            io_->read(data.pData_,data.size_);
                            const size_t iccLength = getULong(data.pData_+pad, bigEndian);
                            // subtracting pad from data.size_ is safe:
                            // size_ is at least 8 and pad = 3
                            if (iccLength > data.size_ - pad) {
                                throw Error(kerCorruptedMetadata);
                            }
                            DataBuf icc(iccLength);
                            ::memcpy(icc.pData_,data.pData_+pad,icc.size_);
#ifdef DEBUG
                            const char* iccPath = "/tmp/libexiv2_jp2.icc";
                            FILE* f = fopen(iccPath,"wb");
                            if ( f ) {
                                fwrite(icc.pData_,icc.size_,1,f);
                                fclose(f);
                            }
                            std::cout << "Exiv2::Jp2Image::readMetadata: wrote iccProfile " << icc.size_<< " bytes to " << iccPath << std::endl ;
#endif
                            setIccProfile(icc);
                        }

                        if( subBox.type == kJp2BoxTypeImageHeader)
                        {
                            io_->read((byte*)&ihdr, sizeof(ihdr));
#ifdef DEBUG
                            std::cout << "Exiv2::Jp2Image::readMetadata: Ihdr data found" << std::endl;
#endif
                            ihdr.imageHeight            = getLong((byte*)&ihdr.imageHeight, bigEndian);
                            ihdr.imageWidth             = getLong((byte*)&ihdr.imageWidth, bigEndian);
                            ihdr.componentCount         = getShort((byte*)&ihdr.componentCount, bigEndian);
                            ihdr.compressionTypeProfile = getShort((byte*)&ihdr.compressionTypeProfile, bigEndian);

                            pixelWidth_  = ihdr.imageWidth;
                            pixelHeight_ = ihdr.imageHeight;
                        }

                        io_->seek(restore,BasicIo::beg);
                        io_->seek(subBox.length, Exiv2::BasicIo::cur);
                        restore = io_->tell();
                    }
                    break;
                }

                case kJp2BoxTypeUuid:
                {
#ifdef DEBUG
                    std::cout << "Exiv2::Jp2Image::readMetadata: UUID box found" << std::endl;
#endif

                    if (io_->read((byte*)&uuid, sizeof(uuid)) == sizeof(uuid))
                    {
                        DataBuf rawData;
                        size_t  bufRead;
                        bool    bIsExif = memcmp(uuid.uuid, kJp2UuidExif, sizeof(uuid))==0;
                        bool    bIsIPTC = memcmp(uuid.uuid, kJp2UuidIptc, sizeof(uuid))==0;
                        bool    bIsXMP  = memcmp(uuid.uuid, kJp2UuidXmp , sizeof(uuid))==0;

                        if(bIsExif)
                        {
#ifdef DEBUG
                           std::cout << "Exiv2::Jp2Image::readMetadata: Exif data found" << std::endl ;
#endif
                            rawData.alloc(box.length - (sizeof(box) + sizeof(uuid)));
                            bufRead = io_->read(rawData.pData_, rawData.size_);
                            if (io_->error()) throw Error(kerFailedToReadImageData);
                            if (bufRead != rawData.size_) throw Error(kerInputDataReadFailed);

                            if (rawData.size_ > 1)
                            {
                                bool foundPos{ false };
                                size_t pos{ 0 };
                                if ((rawData.pData_[0] == rawData.pData_[1]) &&
                                    (rawData.pData_[0] == 'I' || rawData.pData_[0] == 'M')) {
                                    foundPos = true;
                                } else {
                                    const std::array<byte, 6> exifHeader{ 0x45, 0x78, 0x69, 0x66, 0x00, 0x00 };
                                    const auto& it = std::search(rawData.cbegin(), rawData.cend(), exifHeader.cbegin(), exifHeader.cend());
                                    if (it != rawData.cend()) {
                                        pos = it - rawData.cbegin() + exifHeader.size();
                                        foundPos = true;
#ifndef SUPPRESS_WARNINGS
                                        EXV_WARNING << "Reading non-standard UUID-EXIF_bad box in " << io_->path() << std::endl;
#endif

                                    }
                                }

                                // If found it, store only these data at from this place.
                                if (foundPos)
                                {
#ifdef DEBUG
                                    std::cout << "Exiv2::Jp2Image::readMetadata: Exif header found at position " << pos << std::endl;
#endif
                                    ByteOrder bo = TiffParser::decode(exifData(),
                                                                      iptcData(),
                                                                      xmpData(),
                                                                      rawData.pData_ + pos,
                                                                      (uint32_t)(rawData.size_ - pos));
                                    setByteOrder(bo);
                                }
                            }
                            else
                            {
#ifndef SUPPRESS_WARNINGS
                                EXV_WARNING << "Failed to decode Exif metadata." << std::endl;
#endif
                                exifData_.clear();
                            }
                        }

                        if(bIsIPTC)
                        {
#ifdef DEBUG
                           std::cout << "Exiv2::Jp2Image::readMetadata: Iptc data found" << std::endl;
#endif
                            rawData.alloc(box.length - (sizeof(box) + sizeof(uuid)));
                            bufRead = io_->read(rawData.pData_, rawData.size_);
                            if (io_->error()) throw Error(kerFailedToReadImageData);
                            if (bufRead != rawData.size_) throw Error(kerInputDataReadFailed);

                            if (IptcParser::decode(iptcData_, rawData.pData_, rawData.size_))
                            {
#ifndef SUPPRESS_WARNINGS
                                EXV_WARNING << "Failed to decode IPTC metadata." << std::endl;
#endif
                                iptcData_.clear();
                            }
                        }

                        if(bIsXMP)
                        {
#ifdef DEBUG
                           std::cout << "Exiv2::Jp2Image::readMetadata: Xmp data found" << std::endl;
#endif
                            rawData.alloc(box.length - (uint32_t)(sizeof(box) + sizeof(uuid)));
                            bufRead = io_->read(rawData.pData_, rawData.size_);
                            if (io_->error()) throw Error(kerFailedToReadImageData);
                            if (bufRead != rawData.size_) throw Error(kerInputDataReadFailed);
                            xmpPacket_.assign(reinterpret_cast<char *>(rawData.pData_), rawData.size_);

                            std::string::size_type idx = xmpPacket_.find_first_of('<');
                            if (idx != std::string::npos && idx > 0)
                            {
#ifndef SUPPRESS_WARNINGS
                                EXV_WARNING << "Removing " << static_cast<uint32_t>(idx)
                                            << " characters from the beginning of the XMP packet" << std::endl;
#endif
                                xmpPacket_ = xmpPacket_.substr(idx);
                            }

                            if (xmpPacket_.size() > 0 && XmpParser::decode(xmpData_, xmpPacket_))
                            {
#ifndef SUPPRESS_WARNINGS
                                EXV_WARNING << "Failed to decode XMP metadata." << std::endl;
#endif
                            }
                        }
                    }
                    break;
                }

                default:
                {
                    break;
                }
            }

            // Move to the next box.
            io_->seek(static_cast<long>(position - sizeof(box) + box.length), BasicIo::beg);
            if (io_->error()) throw Error(kerFailedToReadImageData);
        }

    } // Jp2Image::readMetadata

Project: exiv2
File: tiffvisitor_int.cpp

    bool TiffVisitor::go(GoEvent event) const
    {
        assert(event >= 0 && static_cast<int>(event) < events_);
        return go_[event];
    }

Project: exiv2
File: types.cpp

    std::istream& operator>>(std::istream& is, Rational& r)
    {
        // http://dev.exiv2.org/boards/3/topics/1912?r=1915
        if ( std::tolower(is.peek()) == 'f' ) {
            char  F = 0;
            float f = 0.f;
            is >> F >> f ;
            f  = 2.0f * std::log(f) / std::log(2.0f) ;
            r  = Exiv2::floatToRationalCast(f);
        } else {
            int32_t nominator = 0;
            int32_t denominator = 0;
            char c('\0');
            is >> nominator >> c >> denominator;
            if (c != '/')
                is.setstate(std::ios::failbit);
            if (is)
                r = std::make_pair(nominator, denominator);
        }
        return is;
    }

Project: exiv2
File: tiffcomposite_int.cpp

    TiffDirectory::~TiffDirectory()
    {
        for (Components::iterator i = components_.begin(); i != components_.end(); ++i) {
            delete *i;
        }
        delete pNext_;
    }

Project: exiv2
File: image.cpp

    void Image::setComment(const std::string& comment)
    {
        comment_ = comment;
    }

Project: exiv2
File: exif.cpp

    void ExifThumb::erase()
    {
        eraseIfd(exifData_, ifd1Id);
    }

Project: exiv2
File: value.cpp

    std::ostream& StringValueBase::write(std::ostream& os) const
    {
        return os << value_;
    }

Project: exiv2
File: image.cpp

    BasicIo& Image::io() const
    {
        return *io_;
    }

Project: exiv2
File: basicio.cpp

    byte* RemoteIo::mmap(bool /*isWriteable*/)
    {
        if ( !bigBlock_ ) {
            size_t nRealData = 0 ;
            size_t blockSize = p_->blockSize_;
            size_t blocks = (p_->size_ + blockSize -1)/blockSize ;
            bigBlock_   = new byte[blocks*blockSize] ;
            for ( size_t block = 0 ; block < blocks ; block ++ ) {
                void* p = p_->blocksMap_[block].getData();
                if  ( p ) {
                    nRealData += blockSize ;
                    memcpy(bigBlock_+(block*blockSize),p,blockSize);
                }
            }
#ifdef DEBUG
            std::cerr << "RemoteIo::mmap nRealData = " << nRealData << std::endl;
#endif
        }

        return bigBlock_;
    }

Project: exiv2
File: value.cpp

    long XmpArrayValue::count() const
    {
        return static_cast<long>(value_.size());
    }

Project: exiv2
File: mrwimage.cpp

    Image::UniquePtr newMrwInstance(BasicIo::UniquePtr io, bool create)
    {
        Image::UniquePtr image(new MrwImage(std::move(io), create));
        if (!image->good()) {
            image.reset();
        }
        return image;
    }

Project: exiv2
File: pngchunk_int.cpp

        std::string PngChunk::makeUtf8TxtChunk(const std::string& keyword, const std::string& text, bool compress)
        {
            // Chunk structure: length (4 bytes) + chunk type + chunk data + CRC (4 bytes)
            // Length is the size of the chunk data
            // CRC is calculated on chunk type + chunk data

            // Chunk data format : keyword + 0x00 + compression flag (0x00: uncompressed - 0x01: compressed)
            //                     + compression method (0x00: zlib format) + language tag (null) + 0x00
            //                     + translated keyword (null) + 0x00 + text (compressed or not)

            // Build chunk data, determine chunk type
            std::string chunkData = keyword;
            if (compress) {
                static const char flags[] = {0x00, 0x01, 0x00, 0x00, 0x00};
                chunkData += std::string(flags, 5) + zlibCompress(text);
            } else {
                static const char flags[] = {0x00, 0x00, 0x00, 0x00, 0x00};
                chunkData += std::string(flags, 5) + text;
            }
            // Determine length of the chunk data
            byte length[4];
            ul2Data(length, static_cast<uint32_t>(chunkData.size()), bigEndian);
            // Calculate CRC on chunk type and chunk data
            std::string chunkType = "iTXt";
            std::string crcData = chunkType + chunkData;
            uLong tmp = crc32(0L, Z_NULL, 0);
            tmp = crc32(tmp, (const Bytef*)crcData.data(), static_cast<uInt>(crcData.size()));
            byte crc[4];
            ul2Data(crc, tmp, bigEndian);
            // Assemble the chunk
            return std::string((const char*)length, 4) + chunkType + chunkData + std::string((const char*)crc, 4);

        }  // PngChunk::makeUtf8TxtChunk

Project: exiv2
File: exif.cpp

    const char* JpegThumbnail::mimeType() const
    {
        return "image/jpeg";
    }

Project: exiv2
File: rafimage.cpp

    std::string RafImage::mimeType() const
    {
        return "image/x-fuji-raf";
    }

Project: exiv2
File: exif.cpp

        virtual ~Thumbnail() {}

Project: exiv2
File: value.cpp

    DateValue* DateValue::clone_() const
    {
        return new DateValue(*this);
    }

Project: exiv2
File: crwimage_int.cpp

    CiffComponent* CiffDirectory::doAdd(CrwDirs& crwDirs, uint16_t crwTagId)
    {
        /*
          add()
            if stack not empty
              pop from stack
              find dir among components
              if not found, create it
              add()
            else
              find tag among components
              if not found, create it
              set value
        */
        const Components::iterator b = components_.begin();
        const Components::iterator e = components_.end();

        if (!crwDirs.empty()) {
            CrwSubDir csd = crwDirs.top();
            crwDirs.pop();
            // Find the directory
            for (Components::iterator i = b; i != e; ++i) {
                if ((*i)->tag() == csd.crwDir_) {
                    cc_ = *i;
                    break;
                }
            }
            if (cc_ == 0) {
                // Directory doesn't exist yet, add it
                m_ = UniquePtr(new CiffDirectory(csd.crwDir_, csd.parent_));
                cc_ = m_.get();
                add(std::move(m_));
            }
            // Recursive call to next lower level directory
            cc_ = cc_->add(crwDirs, crwTagId);
        }
        else {
            // Find the tag
            for (Components::iterator i = b; i != e; ++i) {
                if ((*i)->tagId() == crwTagId) {
                    cc_ = *i;
                    break;
                }
            }
            if (cc_ == 0) {
                // Tag doesn't exist yet, add it
                m_ = UniquePtr(new CiffEntry(crwTagId, tag()));
                cc_ = m_.get();
                add(std::move(m_));
            }
        }
        return cc_;
    }

Project: exiv2
File: exif.cpp

    const char* ExifThumbC::mimeType() const
    {
        Thumbnail::UniquePtr thumbnail = Thumbnail::create(exifData_);
        if (thumbnail.get() == 0) return "";
        return thumbnail->mimeType();
    }

Project: exiv2
File: actions.cpp

    int Print::printTag(const Exiv2::ExifData& exifData, const std::string& key, const std::string& label) const
    {
        int rc = 0;
        if (!label.empty()) {
            printLabel(label);
        }
        Exiv2::ExifKey ek(key);
        auto md = exifData.findKey(ek);
        if (md != exifData.end()) {
            md->write(std::cout, &exifData);
            rc = 1;
        }
        if (!label.empty())
            std::cout << std::endl;
        return rc;
    }

Project: exiv2
File: value.cpp

    XmpValue::XmpArrayType XmpValue::xmpArrayType(TypeId typeId)
    {
        XmpArrayType xa = xaNone;
        switch (typeId) {
        case xmpAlt: xa = xaAlt; break;
        case xmpBag: xa = xaBag; break;
        case xmpSeq: xa = xaSeq; break;
        default: break;
        }
        return xa;
    }

Project: exiv2
File: tiffvisitor_int.cpp

    void TiffEncoder::visitIfdMakernoteEnd(TiffIfdMakernote* /*object*/)
    {
        // Reset byte order back to that from the c'tor
        byteOrder_ = origByteOrder_;

    } // TiffEncoder::visitIfdMakernoteEnd

Project: exiv2
File: value.cpp

    void XmpValue::setXmpArrayType(XmpArrayType xmpArrayType)
    {
        xmpArrayType_ = xmpArrayType;
    }

Project: exiv2
File: tiffcomposite_int.cpp

    TiffComponent* TiffIfdMakernote::doAddPath(uint16_t tag,
                                               TiffPath& tiffPath,
                                               TiffComponent* const pRoot,
                                               TiffComponent::UniquePtr object)
    {
        return ifd_.addPath(tag, tiffPath, pRoot, std::move(object));
    }

Project: exiv2
File: xmp.cpp

    XmpData::iterator XmpData::findKey(const XmpKey& key)
    {
        return std::find_if(xmpMetadata_.begin(), xmpMetadata_.end(),
                            FindXmpdatum(key));
    }

Project: exiv2
File: xmp.cpp

    bool XmpParser::initialize(XmpParser::XmpLockFct xmpLockFct, void* pLockData)
    {
        if (!initialized_) {
            xmpLockFct_ = xmpLockFct;
            pLockData_ = pLockData;
            initialized_ = SXMPMeta::Initialize();
#ifdef EXV_ADOBE_XMPSDK
            SXMPMeta::RegisterNamespace("http://ns.adobe.com/lightroom/1.0/", "lr",nullptr);
            SXMPMeta::RegisterNamespace("http://rs.tdwg.org/dwc/index.htm", "dwc",nullptr);
            SXMPMeta::RegisterNamespace("http://purl.org/dc/terms/", "dcterms",nullptr);
            SXMPMeta::RegisterNamespace("http://www.digikam.org/ns/1.0/", "digiKam",nullptr);
            SXMPMeta::RegisterNamespace("http://www.digikam.org/ns/kipi/1.0/", "kipi",nullptr);
            SXMPMeta::RegisterNamespace("http://ns.microsoft.com/photo/1.0/", "MicrosoftPhoto",nullptr);
            SXMPMeta::RegisterNamespace("http://ns.acdsee.com/iptc/1.0/", "acdsee",nullptr);
            SXMPMeta::RegisterNamespace("http://iptc.org/std/Iptc4xmpExt/2008-02-29/", "iptcExt",nullptr);
            SXMPMeta::RegisterNamespace("http://ns.useplus.org/ldf/xmp/1.0/", "plus",nullptr);
            SXMPMeta::RegisterNamespace("http://ns.iview-multimedia.com/mediapro/1.0/", "mediapro",nullptr);
            SXMPMeta::RegisterNamespace("http://ns.microsoft.com/expressionmedia/1.0/", "expressionmedia",nullptr);
            SXMPMeta::RegisterNamespace("http://ns.microsoft.com/photo/1.2/", "MP",nullptr);
            SXMPMeta::RegisterNamespace("http://ns.microsoft.com/photo/1.2/t/RegionInfo#", "MPRI",nullptr);
            SXMPMeta::RegisterNamespace("http://ns.microsoft.com/photo/1.2/t/Region#", "MPReg",nullptr);
            SXMPMeta::RegisterNamespace("http://ns.google.com/photos/1.0/panorama/", "GPano",nullptr);
            SXMPMeta::RegisterNamespace("http://www.metadataworkinggroup.com/schemas/regions/", "mwg-rs",nullptr);
            SXMPMeta::RegisterNamespace("http://www.metadataworkinggroup.com/schemas/keywords/", "mwg-kw",nullptr);
            SXMPMeta::RegisterNamespace("http://ns.adobe.com/xmp/sType/Area#", "stArea",nullptr);
            SXMPMeta::RegisterNamespace("http://cipa.jp/exif/1.0/", "exifEX",nullptr);
            SXMPMeta::RegisterNamespace("http://ns.adobe.com/camera-raw-saved-settings/1.0/", "crss",nullptr);
            SXMPMeta::RegisterNamespace("http://www.audio/", "audio",nullptr);
            SXMPMeta::RegisterNamespace("http://www.video/", "video",nullptr);
#else
            SXMPMeta::RegisterNamespace("http://ns.adobe.com/lightroom/1.0/", "lr");
            SXMPMeta::RegisterNamespace("http://rs.tdwg.org/dwc/index.htm", "dwc");
            SXMPMeta::RegisterNamespace("http://purl.org/dc/terms/", "dcterms");
            SXMPMeta::RegisterNamespace("http://www.digikam.org/ns/1.0/", "digiKam");
            SXMPMeta::RegisterNamespace("http://www.digikam.org/ns/kipi/1.0/", "kipi");
            SXMPMeta::RegisterNamespace("http://ns.microsoft.com/photo/1.0/", "MicrosoftPhoto");
            SXMPMeta::RegisterNamespace("http://ns.acdsee.com/iptc/1.0/", "acdsee");
            SXMPMeta::RegisterNamespace("http://iptc.org/std/Iptc4xmpExt/2008-02-29/", "iptcExt");
            SXMPMeta::RegisterNamespace("http://ns.useplus.org/ldf/xmp/1.0/", "plus");
            SXMPMeta::RegisterNamespace("http://ns.iview-multimedia.com/mediapro/1.0/", "mediapro");
            SXMPMeta::RegisterNamespace("http://ns.microsoft.com/expressionmedia/1.0/", "expressionmedia");
            SXMPMeta::RegisterNamespace("http://ns.microsoft.com/photo/1.2/", "MP");
            SXMPMeta::RegisterNamespace("http://ns.microsoft.com/photo/1.2/t/RegionInfo#", "MPRI");
            SXMPMeta::RegisterNamespace("http://ns.microsoft.com/photo/1.2/t/Region#", "MPReg");
            SXMPMeta::RegisterNamespace("http://ns.google.com/photos/1.0/panorama/", "GPano");
            SXMPMeta::RegisterNamespace("http://www.metadataworkinggroup.com/schemas/regions/", "mwg-rs");
            SXMPMeta::RegisterNamespace("http://www.metadataworkinggroup.com/schemas/keywords/", "mwg-kw");
            SXMPMeta::RegisterNamespace("http://ns.adobe.com/xmp/sType/Area#", "stArea");
            SXMPMeta::RegisterNamespace("http://cipa.jp/exif/1.0/", "exifEX");
            SXMPMeta::RegisterNamespace("http://ns.adobe.com/camera-raw-saved-settings/1.0/", "crss");
            SXMPMeta::RegisterNamespace("http://www.audio/", "audio");
            SXMPMeta::RegisterNamespace("http://www.video/", "video");
#endif
        }
        return initialized_;
    }

Project: exiv2
File: iptc.cpp

    float Iptcdatum::toFloat(long n) const
    {
        return value_.get() == 0 ? -1 : value_->toFloat(n);
    }

Project: exiv2
File: actions.cpp

    int renameFile(std::string& newPath, const struct tm* tm)
    {
        std::string path = newPath;
        std::string format = Params::instance().format_;
        Util::replace(format, ":basename:", Util::basename(path, true));
        Util::replace(format, ":dirname:", Util::basename(Util::dirname(path)));
        Util::replace(format, ":parentname:", Util::basename(Util::dirname(Util::dirname(path))));

        const size_t max = 1024;
        char basename[max];
        std::memset(basename, 0x0, max);
        if (strftime(basename, max, format.c_str(), tm) == 0) {
            std::cerr << _("Filename format yields empty filename for the file") << " " << path << "\n";
            return 1;
        }
        newPath = Util::dirname(path) + EXV_SEPARATOR_STR + basename + Util::suffix(path);
        if (Util::dirname(newPath) == Util::dirname(path) && Util::basename(newPath) == Util::basename(path)) {
            if (Params::instance().verbose_) {
                std::cout << _("This file already has the correct name") << std::endl;
            }
            return -1;
        }

        bool go = true;
        int seq = 1;
        std::string s;
        Params::FileExistsPolicy fileExistsPolicy = Params::instance().fileExistsPolicy_;
        while (go) {
            if (Exiv2::fileExists(newPath)) {
                switch (fileExistsPolicy) {
                    case Params::overwritePolicy:
                        go = false;
                        break;
                    case Params::renamePolicy:
                        newPath = Util::dirname(path) + EXV_SEPARATOR_STR + basename + "_" + Exiv2::toString(seq++) +
                                  Util::suffix(path);
                        break;
                    case Params::askPolicy:
                        std::cout << Params::instance().progname() << ": " << _("File") << " `" << newPath << "' "
                                  << _("exists. [O]verwrite, [r]ename or [s]kip?") << " ";
                        std::cin >> s;
                        switch (s[0]) {
                            case 'o':
                            case 'O':
                                go = false;
                                break;
                            case 'r':
                            case 'R':
                                fileExistsPolicy = Params::renamePolicy;
                                newPath = Util::dirname(path) + EXV_SEPARATOR_STR + basename + "_" +
                                          Exiv2::toString(seq++) + Util::suffix(path);
                                break;
                            default:  // skip
                                return -1;
                        }
                }
            } else {
                go = false;
            }
        }

        if (Params::instance().verbose_) {
            std::cout << _("Renaming file to") << " " << newPath;
            if (Params::instance().timestamp_) {
                std::cout << ", " << _("updating timestamp");
            }
            std::cout << std::endl;
        }

        // Workaround for MinGW rename which does not overwrite existing files
        remove(newPath.c_str());
        if (std::rename(path.c_str(), newPath.c_str()) == -1) {
            std::cerr << Params::instance().progname() << ": " << _("Failed to rename") << " " << path << " " << _("to")
                      << " " << newPath << ": " << Exiv2::strError() << "\n";
            return 1;
        }

        return 0;
    }

Project: exiv2
File: iptc.cpp

    std::ostream& Iptcdatum::write(std::ostream& os, const ExifData*) const
    {
        return os << value();
    }

Project: exiv2
File: actions.cpp

    int Erase::eraseComment(Exiv2::Image* image) const
    {
        if (Params::instance().verbose_ && image->comment().size() > 0) {
            std::cout << _("Erasing JPEG comment from the file") << std::endl;
        }
        image->clearComment();
        return 0;
    }

Project: exiv2
File: exif.cpp

        bool operator()(const Exiv2::Exifdatum& exifdatum) const
        {
            return key_ == exifdatum.key();
        }

Project: exiv2
File: iptc.cpp

    Iptcdatum& Iptcdatum::operator=(const std::string& value)
    {
        setValue(value);
        return *this;
    }

Project: exiv2
File: crwimage_int.cpp

    void CrwMap::decode0x080a(const CiffComponent& ciffComponent,
                              const CrwMapping*    /*pCrwMapping*/,
                                    Image&         image,
                                    ByteOrder      byteOrder)
    {
        if (ciffComponent.typeId() != asciiString) return;

        // Make
        ExifKey key1("Exif.Image.Make");
        Value::UniquePtr value1 = Value::create(ciffComponent.typeId());
        uint32_t i = 0;
        for (;    i < ciffComponent.size()
               && ciffComponent.pData()[i] != '\0'; ++i) {
            // empty
        }
        value1->read(ciffComponent.pData(), ++i, byteOrder);
        image.exifData().add(key1, value1.get());

        // Model
        ExifKey key2("Exif.Image.Model");
        Value::UniquePtr value2 = Value::create(ciffComponent.typeId());
        uint32_t j = i;
        for (;    i < ciffComponent.size()
               && ciffComponent.pData()[i] != '\0'; ++i) {
            // empty
        }
        value2->read(ciffComponent.pData() + j, i - j + 1, byteOrder);
        image.exifData().add(key2, value2.get());
    } // CrwMap::decode0x080a

Project: exiv2
File: jpgimage.cpp

    bool JpegImage::isThisType(BasicIo& iIo, bool advance) const
    {
        return isJpegType(iIo, advance);
    }

Project: exiv2
File: image.cpp

    bool Image::isShortType(uint16_t type) {
         return type == Exiv2::unsignedShort
             || type == Exiv2::signedShort
             ;
    }

Project: exiv2
File: xmp.cpp

    std::string Xmpdatum::tagName() const
    {
        return p_->key_.get() == 0 ? "" : p_->key_->tagName();
    }

Project: exiv2
File: image.cpp

    bool Image::isLongLongType(uint16_t type) {
        return type == Exiv2::unsignedLongLong
            || type == Exiv2::signedLongLong
            ;
    }

Project: exiv2
File: tiffcomposite_int.cpp

    void TiffBinaryArray::doAccept(TiffVisitor& visitor)
    {
        visitor.visitBinaryArray(this);
        for (Components::const_iterator i = elements_.begin();
             visitor.go(TiffVisitor::geTraverse) && i != elements_.end(); ++i) {
            (*i)->accept(visitor);
        }
        if (visitor.go(TiffVisitor::geTraverse)) visitor.visitBinaryArrayEnd(this);
    } // TiffBinaryArray::doAccept

Project: exiv2
File: types.cpp

const char* _exvGettext(const char* str)
{
    // hold the mutex only as long as necessary
    {
        std::lock_guard<std::mutex> lock(exvGettextInitializedMutex);

        if (!exvGettextInitialized) {
            // bindtextdomain(EXV_PACKAGE_NAME, EXV_LOCALEDIR);
            const std::string localeDir = Exiv2::getProcessPath() + EXV_LOCALEDIR;
            bindtextdomain(EXV_PACKAGE_NAME, localeDir.c_str());
#ifdef EXV_HAVE_BIND_TEXTDOMAIN_CODESET
            bind_textdomain_codeset(EXV_PACKAGE_NAME, "UTF-8");
#endif
            exvGettextInitialized = true;
        }
    }
    return dgettext(EXV_PACKAGE_NAME, str);
}

Project: exiv2
File: iptc.cpp

    Iptcdatum& Iptcdatum::operator=(const uint16_t& value)
    {
        UShortValue::UniquePtr v(new UShortValue);
        v->value_.push_back(value);
        value_ = std::move(v);
        return *this;
    }

Project: exiv2
File: jpgimage.cpp

    int JpegBase::initImage(const byte initData[], long dataSize)
    {
        if (io_->open() != 0) {
            return 4;
        }
        IoCloser closer(*io_);
        if (io_->write(initData, dataSize) != static_cast<size_t>(dataSize)) {
            return 4;
        }
        return 0;
    }

Project: exiv2
File: iptc.cpp

    long IptcData::size() const
    {
        size_t newSize = 0;
        const_iterator iter = iptcMetadata_.begin();
        const_iterator end = iptcMetadata_.end();
        for ( ; iter != end; ++iter) {
            // marker, record Id, dataset num, first 2 bytes of size
            newSize += 5;
            size_t dataSize = iter->size();
            newSize += dataSize;
            if (dataSize > 32767) {
                // extended dataset (we always use 4 bytes)
                newSize += 4;
            }
        }
        return (long)newSize;
    }

Project: exiv2
File: makernote_int.cpp

    size_t Casio2MnHeader::size() const
    {
        return sizeOfSignature();
    }

Project: exiv2
File: image.cpp

    IptcData& Image::iptcData()
    {
        return iptcData_;
    }

Project: exiv2
File: makernote_int.cpp

    size_t PanasonicMnHeader::size() const
    {
        return sizeOfSignature();
    }

Project: exiv2
File: actions.cpp

    std::unique_ptr<Modify> Modify::clone() const
    {
        return std::unique_ptr<Modify>(clone_());
    }

Project: exiv2
File: psdimage.cpp

    uint32_t PsdImage::writeXmpData(const XmpData& xmpData, BasicIo& out) const
    {
        std::string xmpPacket;
        uint32_t resLength = 0;

#ifdef DEBUG
        std::cerr << "writeXmpFromPacket(): " << writeXmpFromPacket() << "\n";
#endif
        //        writeXmpFromPacket(true);
        if (writeXmpFromPacket() == false) {
            if (XmpParser::encode(xmpPacket, xmpData) > 1) {
#ifndef SUPPRESS_WARNINGS
                EXV_ERROR << "Failed to encode XMP metadata.\n";
#endif
            }
        }

        if (xmpPacket.size() > 0) {
#ifdef DEBUG
            std::cerr << std::hex << "write: resourceId: " << kPhotoshopResourceID_XMPPacket << "\n";
            std::cerr << std::dec << "Writing XMPPacket: size: " << xmpPacket.size() << "\n";
#endif
            byte buf[8];
            if (out.write(reinterpret_cast<const byte*>(Photoshop::irbId_[0]), 4) != 4)
                throw Error(kerImageWriteFailed);
            us2Data(buf, kPhotoshopResourceID_XMPPacket, bigEndian);
            if (out.write(buf, 2) != 2)
                throw Error(kerImageWriteFailed);
            us2Data(buf, 0, bigEndian);  // NULL resource name
            if (out.write(buf, 2) != 2)
                throw Error(kerImageWriteFailed);
            ul2Data(buf, static_cast<uint32_t>(xmpPacket.size()), bigEndian);
            if (out.write(buf, 4) != 4)
                throw Error(kerImageWriteFailed);
            // Write XMPPacket
            if (out.write(reinterpret_cast<const byte*>(xmpPacket.data()), static_cast<long>(xmpPacket.size())) !=
                static_cast<long>(xmpPacket.size()))
                throw Error(kerImageWriteFailed);
            if (out.error())
                throw Error(kerImageWriteFailed);
            resLength += static_cast<uint32_t>(xmpPacket.size()) + 12;
            if (xmpPacket.size() & 1)  // even padding
            {
                buf[0] = 0;
                if (out.write(buf, 1) != 1)
                    throw Error(kerImageWriteFailed);
                resLength++;
            }
        }
        return resLength;
    }

Project: exiv2
File: types.cpp

    const char* TypeInfo::typeName(TypeId typeId)
    {
        const TypeInfoTable* tit = find(typeInfoTable, typeId);
        if (!tit) return 0;
        return tit->name_;
    }

Project: exiv2
File: tiffvisitor_int.cpp

    void TiffDecoder::visitEntry(TiffEntry* object)
    {
        decodeTiffEntry(object);
    }

Project: exiv2
File: image.cpp

    bool Image::is2ByteType(uint16_t type)
    {
        return isShortType(type);
    }

Project: exiv2
File: value.cpp

    XmpValue::XmpStruct XmpValue::xmpStruct() const
    {
        return xmpStruct_;
    }

Project: exiv2
File: iptc.cpp

    const char *IptcData::detectCharset() const
    {
        const_iterator pos = findKey(IptcKey("Iptc.Envelope.CharacterSet"));
        if (pos != end()) {
            const std::string value = pos->toString();
            if (pos->value().ok()) {
                if (value == "\033%G") return "UTF-8";
                // other values are probably not practically relevant
            }
        }

        bool ascii = true;
        bool utf8 = true;

        for (pos = begin(); pos != end(); ++pos) {
            std::string value = pos->toString();
            if (pos->value().ok()) {
                int seqCount = 0;
                std::string::iterator i;
                for (i = value.begin(); i != value.end(); ++i) {
                    char c = *i;
                    if (seqCount) {
                        if ((c & 0xc0) != 0x80) {
                            utf8 = false;
                            break;
                        }
                        --seqCount;
                    }
                    else {
                        if (c & 0x80) ascii = false;
                        else continue; // ascii character

                        if      ((c & 0xe0) == 0xc0) seqCount = 1;
                        else if ((c & 0xf0) == 0xe0) seqCount = 2;
                        else if ((c & 0xf8) == 0xf0) seqCount = 3;
                        else if ((c & 0xfc) == 0xf8) seqCount = 4;
                        else if ((c & 0xfe) == 0xfc) seqCount = 5;
                        else {
                            utf8 = false;
                            break;
                        }
                    }
                }
                if (seqCount) utf8 = false; // unterminated seq
                if (!utf8) break;
            }
        }

        if (ascii) return "ASCII";
        if (utf8) return "UTF-8";
        return nullptr;
    }

Project: exiv2
File: actions.cpp

    } catch (const Exiv2::AnyError& e) {
        std::cerr << "Exiv2 exception in insert action for file " << path << ":\n" << e << "\n";
        return 1;
    }

Project: exiv2
File: iptc.cpp

    int Iptcdatum::setValue(const std::string& value)
    {
        if (value_.get() == 0) {
            TypeId type = IptcDataSets::dataSetType(tag(), record());
            value_ = Value::create(type);
        }
        return value_->read(value);
    }

Project: exiv2
File: convert.cpp

    bool ucs2beToUtf8(std::string& str)
    {
        bool ret = swapBytes(str);
        if (ret) ret = wc2mb(CP_UTF8, str);
        return ret;
    }

Project: exiv2
File: jpgimage.cpp

    JpegBase::JpegBase(ImageType type, BasicIo::UniquePtr io, bool create,
                       const byte initData[], long dataSize)
        : Image(type, mdExif | mdIptc | mdXmp | mdComment, std::move(io))
    {
        if (create) {
            initImage(initData, dataSize);
        }
    }

Project: exiv2
File: makernote_int.cpp

    TiffComponent* newIfdMn(uint16_t    tag,
                            IfdId       group,
                            IfdId       mnGroup,
                            const byte* /*pData*/,
                            uint32_t    size,
                            ByteOrder   /*byteOrder*/)
    {
        // Require at least an IFD with 1 entry, but not necessarily a next pointer
        if (size < 14) return 0;
        return newIfdMn2(tag, group, mnGroup);
    }

Project: exiv2
File: xmp.cpp

        explicit FindXmpdatum(const Exiv2::XmpKey& key) : key_(key.key())
        {
        }

Project: exiv2
File: crwimage.cpp

    bool isCrwType(BasicIo& iIo, bool advance)
    {
        bool result = true;
        byte tmpBuf[14];
        iIo.read(tmpBuf, 14);
        if (iIo.error() || iIo.eof()) {
            return false;
        }
        if (!(   ('I' == tmpBuf[0] && 'I' == tmpBuf[1])
              || ('M' == tmpBuf[0] && 'M' == tmpBuf[1]))) {
            result = false;
        }
        if (   true == result
            && std::memcmp(tmpBuf + 6, CiffHeader::signature(), 8) != 0) {
            result = false;
        }
        if (!advance || !result) iIo.seek(-14, BasicIo::cur);
        return result;
    }

Project: exiv2
File: value.cpp

    StringValueBase::StringValueBase(TypeId typeId)
        : Value(typeId)
    {
    }

Project: exiv2
File: jpgimage.cpp

    Image::UniquePtr newExvInstance(BasicIo::UniquePtr io, bool create)
    {
        Image::UniquePtr image;
        image = Image::UniquePtr(new ExvImage(std::move(io), create));
        if (!image->good()) image.reset();
        return image;
    }

Project: exiv2
File: iptc.cpp

    Iptcdatum::~Iptcdatum()
    {
    }

Project: exiv2
File: xmp.cpp

    Xmpdatum& Xmpdatum::operator=(const Xmpdatum& rhs)
    {
        if (this == &rhs) return *this;
        Metadatum::operator=(rhs);
        *p_ = *rhs.p_;
        return *this;
    }

Project: exiv2
File: makernote_int.cpp

    uint32_t SonyMnHeader::ifdOffset() const
    {
        return start_;
    }

Project: exiv2
File: convert.cpp

    void syncExifWithXmp(ExifData& exifData, XmpData& xmpData)
    {
        Converter converter(exifData, xmpData);
        converter.syncExifWithXmp();
    }

Project: exiv2
File: tiffcomposite_int.cpp

    TiffComponent::UniquePtr TiffComponent::clone() const
    {
        return UniquePtr(doClone());
    }

Project: exiv2
File: pgfimage.cpp

    static uint32_t byteSwap_(uint32_t value,bool bSwap)
    {
        uint32_t result = 0;
        result |= (value & 0x000000FF) << 24;
        result |= (value & 0x0000FF00) << 8;
        result |= (value & 0x00FF0000) >> 8;
        result |= (value & 0xFF000000) >> 24;
        return bSwap ? result : value;
    }

Project: exiv2
File: psdimage.cpp

    PsdImage::PsdImage(BasicIo::UniquePtr io)
        : Image(ImageType::psd, mdExif | mdIptc | mdXmp, std::move(io))
    {
    }  // PsdImage::PsdImage

Project: exiv2
File: makernote_int.cpp

    Olympus2MnHeader::Olympus2MnHeader()
    {
        read(signature_, sizeOfSignature(), invalidByteOrder);
    }

Project: exiv2
File: convert.cpp

        void setOverwrite(bool onoff =true) { overwrite_ = onoff; }

Project: exiv2
File: actions.cpp

    void Extract::writePreviewFile(const Exiv2::PreviewImage& pvImg, int num) const
    {
        std::string pvFile = newFilePath(path_, "-preview") + Exiv2::toString(num);
        std::string pvPath = pvFile + pvImg.extension();
        if (dontOverwrite(pvPath))
            return;
        if (Params::instance().verbose_) {
            std::cout << _("Writing preview") << " " << num << " (" << pvImg.mimeType() << ", ";
            if (pvImg.width() != 0 && pvImg.height() != 0) {
                std::cout << pvImg.width() << "x" << pvImg.height() << " " << _("pixels") << ", ";
            }
            std::cout << pvImg.size() << " " << _("bytes") << ") " << _("to file") << " " << pvPath << std::endl;
        }
        long rc = pvImg.writeFile(pvFile);
        if (rc == 0) {
            std::cerr << path_ << ": " << _("Image does not have preview") << " " << num << "\n";
        }
    }

Project: exiv2
File: basicio.cpp

    size_t MemIo::write(BasicIo& src)
    {
        if (static_cast<BasicIo*>(this) == &src) return 0;
        if (!src.isopen()) return 0;

        byte buf[4096];
        size_t readCount = 0;
        size_t writeTotal = 0;
        while ((readCount = src.read(buf, sizeof(buf)))) {
            write(buf, readCount);
            writeTotal += readCount;
        }

        return writeTotal;
    }

Project: exiv2
File: tiffcomposite_int.cpp

    TiffIfdMakernote::~TiffIfdMakernote()
    {
        delete pHeader_;
    }

Project: exiv2
File: basicio.cpp

    size_t MemIo::read(byte* buf, size_t rcount)
    {
        size_t avail = EXV_MAX(p_->size_ - p_->idx_, 0);
        size_t allow = EXV_MIN(rcount, avail);
        if (p_->data_ == nullptr) {
            throw Error(kerCallFailed, "std::memcpy with src == nullptr");
        }
        std::memcpy(buf, &p_->data_[p_->idx_], allow);
        p_->idx_ += allow;
        if (rcount > avail)
            p_->eof_ = true;
        return allow;
    }

Project: exiv2
File: value.cpp

    int TimeValue::read(const byte* buf, size_t len, ByteOrder /*byteOrder*/)
    {
        // Make the buffer a 0 terminated C-string for scanTime[36]
        char b[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
        std::memcpy(b, reinterpret_cast<const char*>(buf), (len < 12 ? len : 11));
        // Hard coded to read HHMMSS or Iptc style times
        int rc = 1;
        if (len == 6) {
            // Try to read (non-standard) HHMMSS format
            rc = scanTime3(b, "%2d%2d%2d");
        }
        if (len == 11) {
            rc = scanTime6(b, "%2d%2d%2d%1c%2d%2d");
        }
        if (rc) {
            rc = 1;
#ifndef SUPPRESS_WARNINGS
            EXV_WARNING << Error(kerUnsupportedTimeFormat) << "\n";
#endif
        }
        return rc;
    }

Project: exiv2
File: value.cpp

    int LangAltValue::read(const std::string& buf)
    {
        std::string b = buf;
        std::string lang = "x-default";
        if (buf.length() > 5 && buf.substr(0, 5) == "lang=") {
            std::string::size_type pos = buf.find_first_of(' ');
            lang = buf.substr(5, pos-5);
            // Strip quotes (so you can also specify the language without quotes)
            if (lang[0] == '"') lang = lang.substr(1);
            if (lang[lang.length()-1] == '"') lang = lang.substr(0, lang.length()-1);
            b.clear();
            if (pos != std::string::npos) b = buf.substr(pos+1);
        }
        value_[lang] = b;
        return 0;
    }