static int cover_add(cover, beg, end)
    cover_t *cover;
    bound_t beg;
    bound_t end;
{
    size_t pos;
    int prec, foll;

    if (beg >= end)
    /* The new span is invalid. */
        return -1;

    /* Find where the new span should go, and make sure that it does not
       overlap with any existing spans. */
    pos = cover_find(cover, beg);
    if ((pos > 0 && beg < cover->span[pos - 1].end) ||
        (pos < cover->num && end > cover->span[pos].beg))
        return 1;

    /* Check for adjacencies. */
    prec = pos > 0 && beg == cover->span[pos - 1].end;
    foll = pos < cover->num && end == cover->span[pos].beg;
    if (prec && foll) {
        /* The new span connects the preceding and following spans. Merge the
           following span into the preceding span, and delete the following
           span. */
        cover->span[pos - 1].end = cover->span[pos].end;
        cover->num--;
        memmove(cover->span + pos, cover->span + pos + 1,
                (cover->num - pos) * sizeof(span_t));
    }
    else if (prec)
        /* The new span is adjacent only to the preceding span. Extend the end
           of the preceding span. */
        cover->span[pos - 1].end = end;
    else if (foll)
        /* The new span is adjacent only to the following span. Extend the
           beginning of the following span. */
        cover->span[pos].beg = beg;
    else {
        /* The new span has gaps between both the preceding and the following
           spans. Assure that there is room and insert the span.  */
        if (cover->num == cover->max) {
            size_t max = cover->max == 0 ? 16 : cover->max << 1;
            span_t *span = realloc(cover->span, max * sizeof(span_t));
            if (span == NULL)
                return -2;
            cover->span = span;
            cover->max = max;
        }
        memmove(cover->span + pos + 1, cover->span + pos,
                (cover->num - pos) * sizeof(span_t));
        cover->num++;
        cover->span[pos].beg = beg;
        cover->span[pos].end = end;
    }
    return 0;
}


void hci_chan_del(struct hci_chan *chan)
{
	struct hci_conn *conn = chan->conn;
	struct hci_dev *hdev = conn->hdev;

	BT_DBG("%s hcon %p chan %p", hdev->name, conn, chan);

	list_del_rcu(&chan->list);

	synchronize_rcu();

	/* Prevent new hci_chan's to be created for this hci_conn */
	set_bit(HCI_CONN_DROP, &conn->flags);

	hci_conn_put(conn);

	skb_queue_purge(&chan->data_q);
	kfree(chan);
}


static u32 get_link_mode(struct hci_conn *conn)
{
	u32 link_mode = 0;

	if (conn->role == HCI_ROLE_MASTER)
		link_mode |= HCI_LM_MASTER;

	if (test_bit(HCI_CONN_ENCRYPT, &conn->flags))
		link_mode |= HCI_LM_ENCRYPT;

	if (test_bit(HCI_CONN_AUTH, &conn->flags))
		link_mode |= HCI_LM_AUTH;

	if (test_bit(HCI_CONN_SECURE, &conn->flags))
		link_mode |= HCI_LM_SECURE;

	if (test_bit(HCI_CONN_FIPS, &conn->flags))
		link_mode |= HCI_LM_FIPS;

	return link_mode;
}


struct hci_conn *hci_connect_le_scan(struct hci_dev *hdev, bdaddr_t *dst,
				     u8 dst_type, u8 sec_level,
				     u16 conn_timeout)
{
	struct hci_conn *conn;

	/* Let's make sure that le is enabled.*/
	if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
		if (lmp_le_capable(hdev))
			return ERR_PTR(-ECONNREFUSED);

		return ERR_PTR(-EOPNOTSUPP);
	}

	/* Some devices send ATT messages as soon as the physical link is
	 * established. To be able to handle these ATT messages, the user-
	 * space first establishes the connection and then starts the pairing
	 * process.
	 *
	 * So if a hci_conn object already exists for the following connection
	 * attempt, we simply update pending_sec_level and auth_type fields
	 * and return the object found.
	 */
	conn = hci_conn_hash_lookup_le(hdev, dst, dst_type);
	if (conn) {
		if (conn->pending_sec_level < sec_level)
			conn->pending_sec_level = sec_level;
		goto done;
	}

	BT_DBG("requesting refresh of dst_addr");

	conn = hci_conn_add(hdev, LE_LINK, dst, HCI_ROLE_MASTER);
	if (!conn)
		return ERR_PTR(-ENOMEM);

	if (hci_explicit_conn_params_set(hdev, dst, dst_type) < 0)
		return ERR_PTR(-EBUSY);

	conn->state = BT_CONNECT;
	set_bit(HCI_CONN_SCANNING, &conn->flags);
	conn->dst_type = dst_type;
	conn->sec_level = BT_SECURITY_LOW;
	conn->pending_sec_level = sec_level;
	conn->conn_timeout = conn_timeout;

	hci_update_background_scan(hdev);

done:
	hci_conn_hold(conn);
	return conn;
}


static void hci_add_sco(struct hci_conn *conn, __u16 handle)
{
	struct hci_dev *hdev = conn->hdev;
	struct hci_cp_add_sco cp;

	BT_DBG("hcon %p", conn);

	conn->state = BT_CONNECT;
	conn->out = true;

	conn->attempt++;

	cp.handle   = cpu_to_le16(handle);
	cp.pkt_type = cpu_to_le16(conn->pkt_type);

	hci_send_cmd(hdev, HCI_OP_ADD_SCO, sizeof(cp), &cp);
}


static void l2cap_le_connect(struct l2cap_chan *chan)
{
	struct l2cap_conn *conn = chan->conn;
	struct l2cap_le_conn_req req;

	if (test_and_set_bit(FLAG_LE_CONN_REQ_SENT, &chan->flags))
		return;

	l2cap_le_flowctl_init(chan, 0);

	req.psm     = chan->psm;
	req.scid    = cpu_to_le16(chan->scid);
	req.mtu     = cpu_to_le16(chan->imtu);
	req.mps     = cpu_to_le16(chan->mps);
	req.credits = cpu_to_le16(chan->rx_credits);

	chan->ident = l2cap_get_ident(conn);

	l2cap_send_cmd(conn, chan->ident, L2CAP_LE_CONN_REQ,
		       sizeof(req), &req);
}


    void PngImage::writeMetadata()
    {
        if (io_->open() != 0)
        {
            throw Error(kerDataSourceOpenFailed, io_->path(), strError());
        }
        IoCloser closer(*io_);
        BasicIo::AutoPtr tempIo(new MemIo);
        assert (tempIo.get() != 0);

        doWriteMetadata(*tempIo); // may throw
        io_->close();
        io_->transfer(*tempIo); // may throw

    } // PngImage::writeMetadata


    bool isPngType(BasicIo& iIo, bool advance)
    {
        if (iIo.error() || iIo.eof()) {
            throw Error(kerInputDataReadFailed);
        }
        const int32_t len = 8;
        byte buf[len];
        iIo.read(buf, len);
        if (iIo.error() || iIo.eof())
        {
            return false;
        }
        int rc = memcmp(buf, pngSignature, 8);
        if (!advance || rc != 0)
        {
            iIo.seek(-len, BasicIo::cur);
        }

        return rc == 0;
    }


    void PngImage::readMetadata()
    {
#ifdef DEBUG
        std::cerr << "Exiv2::PngImage::readMetadata: Reading PNG file " << io_->path() << std::endl;
#endif
        if (io_->open() != 0) {
            throw Error(kerDataSourceOpenFailed, io_->path(), strError());
        }
        IoCloser closer(*io_);
        if (!isPngType(*io_, true)) {
            throw Error(kerNotAnImage, "PNG");
        }
        clearMetadata();

        const long imgSize = (long)io_->size();
        DataBuf cheaderBuf(8);  // Chunk header: 4 bytes (data size) + 4 bytes (chunk type).

        while (!io_->eof()) {
            std::memset(cheaderBuf.pData_, 0x0, cheaderBuf.size_);
            readChunk(cheaderBuf, *io_);  // Read chunk header.

            // Decode chunk data length.
            uint32_t chunkLength = Exiv2::getULong(cheaderBuf.pData_, Exiv2::bigEndian);
            long pos = io_->tell();
            if (pos == -1 || chunkLength > uint32_t(0x7FFFFFFF) || static_cast<long>(chunkLength) > imgSize - pos) {
                throw Exiv2::Error(kerFailedToReadImageData);
            }

            std::string chunkType(reinterpret_cast<char*>(cheaderBuf.pData_) + 4, 4);
#ifdef DEBUG
            std::cout << "Exiv2::PngImage::readMetadata: chunk type: " << chunkType << " length: " << chunkLength
                      << std::endl;
#endif

            /// \todo analyse remaining chunks of the standard
            // Perform a chunk triage for item that we need.
            if (chunkType == "IEND" || chunkType == "IHDR" || chunkType == "tEXt" || chunkType == "zTXt" ||
                chunkType == "iTXt" || chunkType == "iCCP") {
                DataBuf chunkData(chunkLength);
                readChunk(chunkData, *io_);  // Extract chunk data.

                if (chunkType == "IEND") {
                    return;  // Last chunk found: we stop parsing.
                } else if (chunkType == "IHDR" && chunkData.size_ >= 8) {
                    Internal::PngImageHeader header;
                    PngChunk::decodeIHDRChunk(chunkData, header);
                    pixelWidth_ = header.width;
                    pixelHeight_ = header.height;
                    /// \todo handle rest of data
                } else if (chunkType == "tEXt") {
                    PngChunk::decodeTXTChunk(this, chunkData, PngChunk::tEXt_Chunk);
                } else if (chunkType == "zTXt") {
                    PngChunk::decodeTXTChunk(this, chunkData, PngChunk::zTXt_Chunk);
                } else if (chunkType == "iTXt") {
                    PngChunk::decodeTXTChunk(this, chunkData, PngChunk::iTXt_Chunk);
                } else if (chunkType == "iCCP") {
                    // The ICC profile name can vary from 1-79 characters.
                    uint32_t iccOffset = 0;
                    while (iccOffset < 80 && iccOffset < chunkLength) {
                        if (chunkData.pData_[iccOffset++] == 0x00) {
                            break;
                        }
                    }
                    profileName_ = std::string(reinterpret_cast<char*>(chunkData.pData_), iccOffset - 1);
                    ++iccOffset;  // +1 = 'compressed' flag
                    enforce(iccOffset <= chunkLength, Exiv2::kerCorruptedMetadata);

                    zlibToDataBuf(chunkData.pData_ + iccOffset, chunkLength - iccOffset, iccProfile_);
#ifdef DEBUG
                    std::cout << "Exiv2::PngImage::readMetadata: profile name: " << profileName_ << std::endl;
                    std::cout << "Exiv2::PngImage::readMetadata: iccProfile.size_ (uncompressed) : "
                              << iccProfile_.size_ << std::endl;
#endif
                }

                // Set chunkLength to 0 in case we have read a supported chunk type. Otherwise, we need to seek the
                // file to the next chunk position.
                chunkLength = 0;
            }

            // Move to the next chunk: chunk data size + 4 CRC bytes.
#ifdef DEBUG
            std::cout << "Exiv2::PngImage::readMetadata: Seek to offset: " << chunkLength + 4 << std::endl;
#endif
            io_->seek(chunkLength + 4, BasicIo::cur);
            if (io_->error() || io_->eof()) {
                throw Error(kerFailedToReadImageData);
            }
        }
    }  // PngImage::readMetadata


    static bool zlibToCompressed(const byte* bytes, long length, DataBuf& result)
    {
        uLongf compressedLen = length;  // just a starting point
        int zlibResult;

        do {
            result.alloc(compressedLen);
            zlibResult = compress((Bytef*)result.pData_, &compressedLen, bytes, length);
            if (zlibResult == Z_BUF_ERROR) {
                // the compressedArray needs to be larger
                result.free();
                compressedLen *= 2;
            } else {
                result.free();
                result.alloc(compressedLen);
                zlibResult = compress((Bytef*)result.pData_, &compressedLen, bytes, length);
            }
        } while (zlibResult == Z_BUF_ERROR);

        return zlibResult == Z_OK;
    }


    void PngImage::printStructure(std::ostream& out, PrintStructureOption option, int depth)
    {
        if (io_->open() != 0) {
            throw Error(kerDataSourceOpenFailed, io_->path(), strError());
        }
        if (!isPngType(*io_, true)) {
            throw Error(kerNotAnImage, "PNG");
        }

        char chType[5];
        chType[0] = 0;
        chType[4] = 0;

        if (option == kpsBasic || option == kpsXMP || option == kpsIccProfile || option == kpsRecursive) {
            const std::string xmpKey = "XML:com.adobe.xmp";
            const std::string exifKey = "Raw profile type exif";
            const std::string app1Key = "Raw profile type APP1";
            const std::string iptcKey = "Raw profile type iptc";
            const std::string iccKey = "icc";
            const std::string softKey = "Software";
            const std::string commKey = "Comment";
            const std::string descKey = "Description";

            bool bPrint = option == kpsBasic || option == kpsRecursive;
            if (bPrint) {
                out << "STRUCTURE OF PNG FILE: " << io_->path() << std::endl;
                out << " address | chunk |  length | data                           | checksum" << std::endl;
            }

            const long imgSize = (long)io_->size();
            DataBuf cheaderBuf(8);

            while (!io_->eof() && ::strcmp(chType, "IEND")) {
                size_t address = io_->tell();

                std::memset(cheaderBuf.pData_, 0x0, cheaderBuf.size_);
                long bufRead = io_->read(cheaderBuf.pData_, cheaderBuf.size_);
                if (io_->error())
                    throw Error(kerFailedToReadImageData);
                if (bufRead != cheaderBuf.size_)
                    throw Error(kerInputDataReadFailed);

                // Decode chunk data length.
                uint32_t dataOffset = Exiv2::getULong(cheaderBuf.pData_, Exiv2::bigEndian);
                for (int i = 4; i < 8; i++) {
                    chType[i - 4] = cheaderBuf.pData_[i];
                }

                // test that we haven't hit EOF, or wanting to read excessive data
                long restore = io_->tell();
                if (restore == -1 || dataOffset > uint32_t(0x7FFFFFFF) ||
                    static_cast<long>(dataOffset) > imgSize - restore) {
                    throw Exiv2::Error(kerFailedToReadImageData);
                }

                DataBuf buff(dataOffset);
                io_->read(buff.pData_, dataOffset);
                io_->seek(restore, BasicIo::beg);

                // format output
                const int iMax = 30;
                const uint32_t blen = dataOffset > iMax ? iMax : dataOffset;
                std::string dataString = "";
                // if blen == 0 => slice construction fails
                if (blen > 0) {
                    std::stringstream ss;
                    ss << Internal::binaryToString(makeSlice(buff, 0, blen));
                    dataString = ss.str();
                }
                while (dataString.size() < iMax)
                    dataString += ' ';
                dataString = dataString.substr(0, iMax);

                if (bPrint) {
                    io_->seek(dataOffset, BasicIo::cur);  // jump to checksum
                    byte checksum[4];
                    io_->read(checksum, 4);
                    io_->seek(restore, BasicIo::beg);  // restore file pointer

                    out << Internal::stringFormat("%8d | %-5s |%8d | ", (uint32_t)address, chType, dataOffset)
                        << dataString
                        << Internal::stringFormat(" | 0x%02x%02x%02x%02x", checksum[0], checksum[1], checksum[2],
                                                  checksum[3])
                        << std::endl;
                }

                // chunk type
                bool tEXt = std::strcmp(chType, "tEXt") == 0;
                bool zTXt = std::strcmp(chType, "zTXt") == 0;
                bool iCCP = std::strcmp(chType, "iCCP") == 0;
                bool iTXt = std::strcmp(chType, "iTXt") == 0;

                // for XMP, ICC etc: read and format data
                bool bXMP = option == kpsXMP && findi(dataString, xmpKey) == 0;
                bool bICC = option == kpsIccProfile && findi(dataString, iccKey) == 0;
                bool bExif =
                    option == kpsRecursive && (findi(dataString, exifKey) == 0 || findi(dataString, app1Key) == 0);
                bool bIptc = option == kpsRecursive && findi(dataString, iptcKey) == 0;
                bool bSoft = option == kpsRecursive && findi(dataString, softKey) == 0;
                bool bComm = option == kpsRecursive && findi(dataString, commKey) == 0;
                bool bDesc = option == kpsRecursive && findi(dataString, descKey) == 0;
                bool bDump = bXMP || bICC || bExif || bIptc || bSoft || bComm || bDesc;

                if (bDump) {
                    DataBuf dataBuf;
                    byte* data = new byte[dataOffset + 1];
                    data[dataOffset] = 0;
                    io_->read(data, dataOffset);
                    io_->seek(restore, BasicIo::beg);
                    uint32_t name_l = (uint32_t)std::strlen((const char*)data) + 1;  // leading string length
                    uint32_t start = name_l;

                    // decode the chunk
                    bool bGood = false;
                    if (tEXt) {
                        bGood = tEXtToDataBuf(data + name_l, dataOffset - name_l, dataBuf);
                    }
                    if (zTXt || iCCP) {
                        bGood = zlibToDataBuf(data + name_l + 1, dataOffset - name_l - 1,
                                              dataBuf);  // +1 = 'compressed' flag
                    }
                    if (iTXt) {
                        bGood = (start + 3) < dataOffset;  // good if not a nul chunk
                    }

                    // format is content dependent
                    if (bGood) {
                        bool bLF = false;
                        if (bXMP) {
                            while (!data[start] && start < dataOffset)
                                start++;          // skip leading nul bytes
                            out << data + start;  // output the xmp
                        }

                        if (bExif || bIptc) {
                            DataBuf parsedBuf = PngChunk::readRawProfile(dataBuf, tEXt);
#if DEBUG
                            std::cerr << Exiv2::Internal::binaryToString(parsedBuf.pData_,
                                                                         parsedBuf.size_ > 50 ? 50 : parsedBuf.size_, 0)
                                      << std::endl;
#endif
                            if (parsedBuf.size_) {
                                if (bExif) {
                                    // create memio object with the data, then print the structure
                                    BasicIo::UniquePtr p =
                                        BasicIo::UniquePtr(new MemIo(parsedBuf.pData_ + 6, parsedBuf.size_ - 6));
                                    printTiffStructure(*p, out, option, depth);
                                }
                                if (bIptc) {
                                    IptcData::printStructure(out, makeSlice(parsedBuf.pData_, 0, parsedBuf.size_),
                                                             depth);
                                }
                            }
                        }

                        if (bSoft && dataBuf.size_ > 0) {
                            DataBuf s(dataBuf.size_ + 1);                     // allocate buffer with an extra byte
                            memcpy(s.pData_, dataBuf.pData_, dataBuf.size_);  // copy in the dataBuf
                            s.pData_[dataBuf.size_] = 0;                      // nul terminate it
                            const char* str = (const char*)s.pData_;          // give it name
                            out << Internal::indent(depth) << (const char*)buff.pData_ << ": " << str;
                            bLF = true;
                        }

                        if (bICC || bComm) {
                            out.write((const char*)dataBuf.pData_, dataBuf.size_);
                            bLF = bComm;
                        }

                        if (bDesc && iTXt) {
                            DataBuf decoded = PngChunk::decodeTXTChunk(buff, PngChunk::iTXt_Chunk);
                            out.write((const char*)decoded.pData_, decoded.size_);
                            bLF = true;
                        }

                        if (bLF)
                            out << std::endl;
                    }
                    delete[] data;
                }
                io_->seek(dataOffset + 4, BasicIo::cur);  // jump past checksum
                if (io_->error())
                    throw Error(kerFailedToReadImageData);
            }
        }
    }


    void CiffComponent::doPrint(std::ostream&      os,
                                ByteOrder          byteOrder,
                                const std::string& prefix) const
    {
        os << prefix
           << _("tag") << " = 0x" << std::setw(4) << std::setfill('0')
           << std::hex << std::right << tagId()
           << ", " << _("dir") << " = 0x" << std::setw(4) << std::setfill('0')
           << std::hex << std::right << dir()
           << ", " << _("type") << " = " << TypeInfo::typeName(typeId())
           << ", " << _("size") << " = " << std::dec << size_
           << ", " << _("offset") << " = " << offset_ << "\n";

        Value::UniquePtr value;
        if (typeId() != directory) {
            value = Value::create(typeId());
            value->read(pData_, size_, byteOrder);
            if (value->size() < 100) {
                os << prefix << *value << "\n";
            }
        }
    } // CiffComponent::doPrint


    void CiffComponent::add(UniquePtr component)
    {
        doAddComponent(std::move(component));
    }


        void    populate (byte* source, size_t num)
        {
            size_ = num;
            data_ = (byte*)std::malloc(size_);
            type_ = bMemory;
            std::memcpy(data_, source, size_);
        }


    long writeFile(const DataBuf& buf, const std::string& path)
    {
        FileIo file(path);
        if (file.open("wb") != 0) {
            throw Error(kerFileOpenFailed, path, "wb", strError());
        }
        return file.write(buf.pData_, buf.size_);
    }


    MemIo::~MemIo()
    {
        if (p_->isMalloced_) {
            std::free(p_->data_);
        }
    }


    long CurlIo::write(BasicIo& src)
    {
        if (p_->protocol_ == pHttp || p_->protocol_ == pHttps) {
            return RemoteIo::write(src);
        } else {
            throw Error(kerErrorMessage, "doesnt support write for this protocol.");
        }
    }


    FileIo::~FileIo()
    {
        close();
    }


    DataBuf BasicIo::readOrThrow(long rcount, ErrorCode err) {
      DataBuf result = read(rcount);
      enforce(result.size_ == rcount, err);
      enforce(!error(), err);
      return result;
    }


    long FileIo::write(BasicIo& src)
    {
        assert(p_->fp_ != 0);
        if (static_cast<BasicIo*>(this) == &src) return 0;
        if (!src.isopen()) return 0;
        if (p_->switchMode(Impl::opWrite) != 0) return 0;

        byte buf[4096];
        long readCount = 0;
        long writeTotal = 0;
        while ((readCount = src.read(buf, sizeof(buf)))) {
            const long writeCount = static_cast<long>(std::fwrite(buf, 1, static_cast<size_t>(readCount), p_->fp_));
            writeTotal += writeCount;
            if (writeCount != readCount) {
                // try to reset back to where write stopped
                src.seek(writeCount-readCount, BasicIo::cur);
                break;
            }
        }

        return writeTotal;
    }


    SshIo::SshImpl::SshImpl(const std::string& url, size_t blockSize):Impl(url, blockSize)
    {
        hostInfo_ = Exiv2::Uri::Parse(url);
        Exiv2::Uri::Decode(hostInfo_);

        // remove / at the beginning of the path
        if (hostInfo_.Path[0] == '/') {
            hostInfo_.Path = hostInfo_.Path.substr(1);
        }
        ssh_ = new SSH(hostInfo_.Host, hostInfo_.Username, hostInfo_.Password, hostInfo_.Port);

        if (protocol_ == pSftp) {
            ssh_->getFileSftp(hostInfo_.Path, fileHandler_);
            if (fileHandler_ == nullptr) throw Error(kerErrorMessage, "Unable to open the file");
        } else {
            fileHandler_ = nullptr;
        }
    }


    void WebPImage::decodeChunks(uint32_t filesize)
    {
        DataBuf   chunkId(5);
        byte      size_buff[WEBP_TAG_SIZE];
        bool      has_canvas_data = false;

#ifdef DEBUG
        std::cout << "Reading metadata" << std::endl;
#endif

        chunkId.pData_[4] = '\0' ;
        while ( !io_->eof() && (uint64_t) io_->tell() < filesize) {
            readOrThrow(*io_, chunkId.pData_, WEBP_TAG_SIZE, Exiv2::kerCorruptedMetadata);
            readOrThrow(*io_, size_buff, WEBP_TAG_SIZE, Exiv2::kerCorruptedMetadata);
            const uint32_t size = Exiv2::getULong(size_buff, littleEndian);
            enforce(io_->tell() <= filesize, Exiv2::kerCorruptedMetadata);
            enforce(size <= (filesize - io_->tell()), Exiv2::kerCorruptedMetadata);

            DataBuf payload(size);

            if (equalsWebPTag(chunkId, WEBP_CHUNK_HEADER_VP8X) && !has_canvas_data) {
                enforce(size >= 10, Exiv2::kerCorruptedMetadata);

                has_canvas_data = true;
                byte size_buf[WEBP_TAG_SIZE];

                readOrThrow(*io_, payload.pData_, payload.size_, Exiv2::kerCorruptedMetadata);

                // Fetch width
                memcpy(&size_buf, &payload.pData_[4], 3);
                size_buf[3] = 0;
                pixelWidth_ = Exiv2::getULong(size_buf, littleEndian) + 1;

                // Fetch height
                memcpy(&size_buf, &payload.pData_[7], 3);
                size_buf[3] = 0;
                pixelHeight_ = Exiv2::getULong(size_buf, littleEndian) + 1;
            } else if (equalsWebPTag(chunkId, WEBP_CHUNK_HEADER_VP8) && !has_canvas_data) {
                enforce(size >= 10, Exiv2::kerCorruptedMetadata);

                has_canvas_data = true;
                readOrThrow(*io_, payload.pData_, payload.size_, Exiv2::kerCorruptedMetadata);
                byte size_buf[WEBP_TAG_SIZE];

                // Fetch width""
                memcpy(&size_buf, &payload.pData_[6], 2);
                size_buf[2] = 0;
                size_buf[3] = 0;
                pixelWidth_ = Exiv2::getULong(size_buf, littleEndian) & 0x3fff;

                // Fetch height
                memcpy(&size_buf, &payload.pData_[8], 2);
                size_buf[2] = 0;
                size_buf[3] = 0;
                pixelHeight_ = Exiv2::getULong(size_buf, littleEndian) & 0x3fff;
            } else if (equalsWebPTag(chunkId, WEBP_CHUNK_HEADER_VP8L) && !has_canvas_data) {
                enforce(size >= 5, Exiv2::kerCorruptedMetadata);

                has_canvas_data = true;
                byte size_buf_w[2];
                byte size_buf_h[3];

                readOrThrow(*io_, payload.pData_, payload.size_, Exiv2::kerCorruptedMetadata);

                // Fetch width
                memcpy(&size_buf_w, &payload.pData_[1], 2);
                size_buf_w[1] &= 0x3F;
                pixelWidth_ = Exiv2::getUShort(size_buf_w, littleEndian) + 1;

                // Fetch height
                memcpy(&size_buf_h, &payload.pData_[2], 3);
                size_buf_h[0] = ((size_buf_h[0] >> 6) & 0x3) | ((size_buf_h[1]  & 0x3F) << 0x2);
                size_buf_h[1] = ((size_buf_h[1] >> 6) & 0x3) | ((size_buf_h[2] & 0xF) << 0x2);
                pixelHeight_ = Exiv2::getUShort(size_buf_h, littleEndian) + 1;
            } else if (equalsWebPTag(chunkId, WEBP_CHUNK_HEADER_ANMF) && !has_canvas_data) {
                enforce(size >= 12, Exiv2::kerCorruptedMetadata);

                has_canvas_data = true;
                byte size_buf[WEBP_TAG_SIZE];

                readOrThrow(*io_, payload.pData_, payload.size_, Exiv2::kerCorruptedMetadata);

                // Fetch width
                memcpy(&size_buf, &payload.pData_[6], 3);
                size_buf[3] = 0;
                pixelWidth_ = Exiv2::getULong(size_buf, littleEndian) + 1;

                // Fetch height
                memcpy(&size_buf, &payload.pData_[9], 3);
                size_buf[3] = 0;
                pixelHeight_ = Exiv2::getULong(size_buf, littleEndian) + 1;
            } else if (equalsWebPTag(chunkId, WEBP_CHUNK_HEADER_ICCP)) {
                readOrThrow(*io_, payload.pData_, payload.size_, Exiv2::kerCorruptedMetadata);
                this->setIccProfile(payload);
            } else if (equalsWebPTag(chunkId, WEBP_CHUNK_HEADER_EXIF)) {
                readOrThrow(*io_, payload.pData_, payload.size_, Exiv2::kerCorruptedMetadata);

                byte  size_buff[2];
                // 4 meaningful bytes + 2 padding bytes
                byte  exifLongHeader[]   = { 0xFF, 0x01, 0xFF, 0xE1, 0x00, 0x00 };
                byte  exifShortHeader[]  = { 0x45, 0x78, 0x69, 0x66, 0x00, 0x00 };
                byte  exifTiffLEHeader[] = { 0x49, 0x49, 0x2A };       // "MM*"
                byte  exifTiffBEHeader[] = { 0x4D, 0x4D, 0x00, 0x2A }; // "II\0*"
                byte* rawExifData = NULL;
                long  offset = 0;
                bool  s_header = false;
                bool  le_header = false;
                bool  be_header = false;
                long  pos = getHeaderOffset (payload.pData_, payload.size_, (byte*)&exifLongHeader, 4);

                if (pos == -1) {
                    pos = getHeaderOffset (payload.pData_, payload.size_, (byte*)&exifLongHeader, 6);
                    if (pos != -1) {
                        s_header = true;
                    }
                }
                if (pos == -1) {
                    pos = getHeaderOffset (payload.pData_, payload.size_, (byte*)&exifTiffLEHeader, 3);
                    if (pos != -1) {
                        le_header = true;
                    }
                }
                if (pos == -1) {
                    pos = getHeaderOffset (payload.pData_, payload.size_, (byte*)&exifTiffBEHeader, 4);
                    if (pos != -1) {
                        be_header = true;
                    }
                }

                if (s_header) {
                    offset += 6;
                }
                if (be_header || le_header) {
                    offset += 12;
                }

                const long size = payload.size_ + offset;
                rawExifData = (byte*)malloc(size);

                if (s_header) {
                    us2Data(size_buff, (uint16_t) (size - 6), bigEndian);
                    memcpy(rawExifData, (char*)&exifLongHeader, 4);
                    memcpy(rawExifData + 4, (char*)&size_buff, 2);
                }

                if (be_header || le_header) {
                    us2Data(size_buff, (uint16_t) (size - 6), bigEndian);
                    memcpy(rawExifData, (char*)&exifLongHeader, 4);
                    memcpy(rawExifData + 4, (char*)&size_buff, 2);
                    memcpy(rawExifData + 6, (char*)&exifShortHeader, 6);
                }

                memcpy(rawExifData + offset, payload.pData_, payload.size_);

#ifdef DEBUG
                std::cout << "Display Hex Dump [size:" << (unsigned long)size << "]" << std::endl;
                std::cout << Internal::binaryToHex(rawExifData, size);
#endif

                if (pos != -1) {
                    XmpData  xmpData;
                    ByteOrder bo = ExifParser::decode(exifData_,
                                                      payload.pData_ + pos,
                                                      payload.size_ - pos);
                    setByteOrder(bo);
                }
                else
                {
#ifndef SUPPRESS_WARNINGS
                    EXV_WARNING << "Failed to decode Exif metadata." << std::endl;
#endif
                    exifData_.clear();
                }

                if (rawExifData) free(rawExifData);
            } else if (equalsWebPTag(chunkId, WEBP_CHUNK_HEADER_XMP)) {
                readOrThrow(*io_, payload.pData_, payload.size_, Exiv2::kerCorruptedMetadata);
                xmpPacket_.assign(reinterpret_cast<char*>(payload.pData_), payload.size_);
                if (xmpPacket_.size() > 0 && XmpParser::decode(xmpData_, xmpPacket_)) {
#ifndef SUPPRESS_WARNINGS
                    EXV_WARNING << "Failed to decode XMP metadata." << std::endl;
#endif
                } else {
#ifdef DEBUG
                    std::cout << "Display Hex Dump [size:" << (unsigned long)payload.size_ << "]" << std::endl;
                    std::cout << Internal::binaryToHex(payload.pData_, payload.size_);
#endif
                }
            } else {
                io_->seek(size, BasicIo::cur);
            }

            if ( io_->tell() % 2 ) io_->seek(+1, BasicIo::cur);
        }
    }


        DataBuf PngChunk::decodeTXTChunk(const DataBuf& data, TxtChunkType type)
        {
            DataBuf key = keyTXTChunk(data);

#ifdef DEBUG
            std::cout << "Exiv2::PngChunk::decodeTXTChunk: TXT chunk key: "
                      << std::string((const char*)key.pData_, key.size_) << std::endl;
#endif
            return parseTXTChunk(data, key.size_, type);

        }  // PngChunk::decodeTXTChunk


        std::string PngChunk::zlibCompress(const std::string& text)
        {
            uLongf compressedLen = static_cast<uLongf>(text.size() * 2);  // just a starting point
            int zlibResult;

            DataBuf arr;
            do {
                arr.alloc(compressedLen);
                zlibResult = compress2((Bytef*)arr.pData_, &compressedLen, (const Bytef*)text.data(),
                                       static_cast<uLong>(text.size()), Z_BEST_COMPRESSION);

                switch (zlibResult) {
                    case Z_OK:
                        assert((uLongf)arr.size_ >= compressedLen);
                        arr.size_ = compressedLen;
                        break;
                    case Z_BUF_ERROR:
                        // The compressed array needs to be larger
#ifdef DEBUG
                        std::cout << "Exiv2::PngChunk::parsePngChunk: doubling size for compression.\n";
#endif
                        compressedLen *= 2;
                        // DoS protection. Cap max compressed size
                        if (compressedLen > 131072)
                            throw Error(kerFailedToReadImageData);
                        break;
                    default:
                        // Something bad happened
                        throw Error(kerFailedToReadImageData);
                }
            } while (zlibResult == Z_BUF_ERROR);

            return std::string((const char*)arr.pData_, arr.size_);

        }  // PngChunk::zlibCompress


    DataBuf PngChunk::readRawProfile(const DataBuf& text,bool iTXt)
    {
        DataBuf                 info;
        unsigned char           unhex[103]={0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
            0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
            0,0,0,0,0,0,0,0,0,1, 2,3,4,5,6,7,8,9,0,0,
            0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
            0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,10,11,12,
            13,14,15};
        if (text.size_ == 0) {
            return DataBuf();
        }

        if ( iTXt ) {
            info.alloc(text.size_);
            ::memcpy(info.pData_,text.pData_,text.size_);
            return  info;
        }

        const char *sp  = (char*) text.pData_+1;          // current byte (space pointer)
        const char *eot = (char*) text.pData_+text.size_; // end of text

        if (sp >= eot) {
            return DataBuf();
        }

        // Look for newline
        while (*sp != '\n')
        {
            sp++;
            if ( sp == eot )
            {
                return DataBuf();
            }
        }
        sp++ ; // step over '\n'
        if (sp == eot) {
            return DataBuf();
        }

        // Look for length
        while (*sp == '\0' || *sp == ' ' || *sp == '\n')
        {
            sp++;
            if (sp == eot )
            {
                return DataBuf();
            }
        }

        const char* startOfLength = sp;
        while ('0' <= *sp && *sp <= '9')
        {
            sp++;
            if (sp == eot )
            {
                return DataBuf();
            }
        }
        sp++ ; // step over '\n'
        if (sp == eot) {
            return DataBuf();
        }

        long length = (long) atol(startOfLength);
        enforce(0 <= length && length <= (eot - sp)/2, Exiv2::kerCorruptedMetadata);

        // Allocate space
        if (length == 0)
        {
#ifdef DEBUG
            std::cerr << "Exiv2::PngChunk::readRawProfile: Unable To Copy Raw Profile: invalid profile length\n";
#endif
        }
        info.alloc(length);
        if (info.size_ != length)
        {
#ifdef DEBUG
            std::cerr << "Exiv2::PngChunk::readRawProfile: Unable To Copy Raw Profile: cannot allocate memory\n";
#endif
            return DataBuf();
        }

        // Copy profile, skipping white space and column 1 "=" signs

        unsigned char *dp = (unsigned char*)info.pData_; // decode pointer
        unsigned int nibbles = length * 2;

        for (long i = 0; i < (long) nibbles; i++)
        {
            enforce(sp < eot, Exiv2::kerCorruptedMetadata);
            while (*sp < '0' || (*sp > '9' && *sp < 'a') || *sp > 'f')
            {
                if (*sp == '\0')
                {
#ifdef DEBUG
                    std::cerr << "Exiv2::PngChunk::readRawProfile: Unable To Copy Raw Profile: ran out of data\n";
#endif
                    return DataBuf();
                }

                sp++;
                enforce(sp < eot, Exiv2::kerCorruptedMetadata);
            }

            if (i%2 == 0)
                *dp = (unsigned char) (16*unhex[(int) *sp++]);
            else
                (*dp++) += unhex[(int) *sp++];
        }

        return info;

    } // PngChunk::readRawProfile


    DataLocId CiffComponent::dataLocation(uint16_t tag)
    {
        switch (tag & 0xc000) {
        case 0x0000: return valueData;
        case 0x4000: return directoryData;
        default: throw Error(kerCorruptedMetadata);
        }
    } // CiffComponent::dataLocation


static int makeNonBlocking(int sockfd)
{
#ifdef WIN32
    ULONG ioctl_opt = 1;
    return ioctlsocket(sockfd, FIONBIO, &ioctl_opt);
#else
    int result = fcntl(sockfd, F_SETFL, O_NONBLOCK);
    return result >= 0 ? result : SOCKET_ERROR;
#endif
}


static int makeNonBlocking(int sockfd)
{
#ifdef   WIN32
  ULONG  ioctl_opt = 1;
  return ioctlsocket(sockfd, FIONBIO, &ioctl_opt);
#else
  int    result  = fcntl(sockfd, F_SETFL, O_NONBLOCK);
  return result >= 0 ? result : SOCKET_ERROR ;
#endif
}


do_write (GVfsBackend *backend,
          GVfsJobWrite *write_job,
          GVfsBackendHandle handle,
          char *buffer,
          gsize buffer_size)
{
  GVfsJob *job = G_VFS_JOB (write_job);
  GOutputStream *stream = handle;
  GError *error = NULL;
  gssize bytes_written;

  bytes_written = g_output_stream_write (stream, buffer, buffer_size,
                                         job->cancellable, &error);
  if (bytes_written > -1)
    g_vfs_job_write_set_written_size (write_job, bytes_written);

  complete_job (job, error);
}


do_seek_on_write (GVfsBackend *backend,
                  GVfsJobSeekWrite *seek_write_job,
                  GVfsBackendHandle handle,
                  goffset offset,
                  GSeekType type)
{
  GVfsJob *job = G_VFS_JOB (seek_write_job);
  GSeekable *seekable = handle;
  GError *error = NULL;

  if (g_seekable_seek (seekable, offset, type, job->cancellable, &error))
    g_vfs_job_seek_write_set_offset (seek_write_job,
                                     g_seekable_tell (seekable));

  complete_job (job, error);
}


do_seek_on_read (GVfsBackend *backend,
                 GVfsJobSeekRead *seek_read_job,
                 GVfsBackendHandle handle,
                 goffset offset,
                 GSeekType type)
{
  GVfsJob *job = G_VFS_JOB (seek_read_job);
  GSeekable *seekable = handle;
  GError *error = NULL;

  if (g_seekable_seek (seekable, offset, type, job->cancellable, &error))
    g_vfs_job_seek_read_set_offset (seek_read_job, g_seekable_tell (seekable));

  complete_job (job, error);
}


set_to_keyfile (GKeyfileSettingsBackend *kfsb,
                const gchar             *key,
                GVariant                *value)
{
  gchar *group, *name;

  if (g_hash_table_contains (kfsb->system_locks, key))
    return FALSE;

  if (convert_path (kfsb, key, &group, &name))
    {
      if (value)
        {
          gchar *str = g_variant_print (value, FALSE);
          g_key_file_set_value (kfsb->keyfile, group, name, str);
          g_variant_unref (g_variant_ref_sink (value));
          g_free (str);
        }
      else
        {
          if (*name == '\0')
            {
              gchar **groups;
              gint i;

              groups = g_key_file_get_groups (kfsb->keyfile, NULL);

              for (i = 0; groups[i]; i++)
                if (group_name_matches (groups[i], group))
                  g_key_file_remove_group (kfsb->keyfile, groups[i], NULL);

              g_strfreev (groups);
            }
          else
            g_key_file_remove_key (kfsb->keyfile, group, name, NULL);
        }

      g_free (group);
      g_free (name);

      return TRUE;
    }

  return FALSE;
}


g_keyfile_settings_backend_write (GSettingsBackend *backend,
                                  const gchar      *key,
                                  GVariant         *value,
                                  gpointer          origin_tag)
{
  GKeyfileSettingsBackend *kfsb = G_KEYFILE_SETTINGS_BACKEND (backend);
  gboolean success;

  if (!kfsb->writable)
    return FALSE;

  success = set_to_keyfile (kfsb, key, value);

  if (success)
    {
      g_settings_backend_changed (backend, key, origin_tag);
      g_keyfile_settings_backend_keyfile_write (kfsb);
    }

  return success;
}


keyfile_to_tree (GKeyfileSettingsBackend *kfsb,
                 GTree                   *tree,
                 GKeyFile                *keyfile,
                 gboolean                 dup_check)
{
  gchar **groups;
  gint i;

  groups = g_key_file_get_groups (keyfile, NULL);
  for (i = 0; groups[i]; i++)
    {
      gboolean is_root_group;
      gchar **keys;
      gint j;

      is_root_group = g_strcmp0 (kfsb->root_group, groups[i]) == 0;

      /* reject group names that will form invalid key names */
      if (!is_root_group &&
          (g_str_has_prefix (groups[i], "/") ||
           g_str_has_suffix (groups[i], "/") || strstr (groups[i], "//")))
        continue;

      keys = g_key_file_get_keys (keyfile, groups[i], NULL, NULL);
      g_assert (keys != NULL);

      for (j = 0; keys[j]; j++)
        {
          gchar *path, *value;

          /* reject key names with slashes in them */
          if (strchr (keys[j], '/'))
            continue;

          if (is_root_group)
            path = g_strdup_printf ("%s%s", kfsb->prefix, keys[j]);
          else
            path = g_strdup_printf ("%s%s/%s", kfsb->prefix, groups[i], keys[j]);

          value = g_key_file_get_value (keyfile, groups[i], keys[j], NULL);

          if (dup_check && g_strcmp0 (g_tree_lookup (tree, path), value) == 0)
            {
              g_tree_remove (tree, path);
              g_free (value);
              g_free (path);
            }
          else
            g_tree_insert (tree, path, value);
        }

      g_strfreev (keys);
    }
  g_strfreev (groups);
}


path_is_valid (GKeyfileSettingsBackend *kfsb,
               const gchar             *path)
{
  return convert_path (kfsb, path, NULL, NULL);
}


load_system_settings (GKeyfileSettingsBackend *kfsb)
{
  GError *error = NULL;
  const char *dir = "/etc/glib-2.0/settings";
  char *path;
  char *contents;

  kfsb->system_keyfile = g_key_file_new ();
  kfsb->system_locks = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);

  if (kfsb->defaults_dir)
    dir = kfsb->defaults_dir;

  path = g_build_filename (dir, "defaults", NULL);

  /* The defaults are in the same keyfile format that we use for the settings.
   * It can be produced from a dconf database using: dconf dump
   */
  if (!g_key_file_load_from_file (kfsb->system_keyfile, path, G_KEY_FILE_NONE, &error))
    {
      if (!g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT))
        g_warning ("Failed to read %s: %s", path, error->message);
      g_clear_error (&error);
    }
  else
    g_debug ("Loading default settings from %s", path);

  g_free (path);

  path = g_build_filename (dir, "locks", NULL);

  /* The locks file is a text file containing a list paths to lock, one per line.
   * It can be produced from a dconf database using: dconf list-locks
   */
  if (!g_file_get_contents (path, &contents, NULL, &error))
    {
      if (!g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT))
        g_warning ("Failed to read %s: %s", path, error->message);
      g_clear_error (&error);
    }
  else
    {
      char **lines;
      gsize i;

      g_debug ("Loading locks from %s", path);

      lines = g_strsplit (contents, "\n", 0);
      for (i = 0; lines[i]; i++)
        {
          char *line = lines[i];
          if (line[0] == '#' || line[0] == '\0')
            {
              g_free (line);
              continue;
            }

          g_debug ("Locking key %s", line);
          g_hash_table_add (kfsb->system_locks, g_steal_pointer (&line));
        }

      g_free (lines);
    }
  g_free (contents);

  g_free (path);
}


    DataBuf RemoteIo::read(long rcount)
    {
        DataBuf buf(rcount);
        size_t readCount = read(buf.pData_, buf.size_);
        buf.size_ = readCount;
        return buf;
    }


    size_t writeFile(const DataBuf& buf, const std::string& path)
    {
        FileIo file(path);
        if (file.open("wb") != 0) {
            throw Error(kerFileOpenFailed, path, "wb", strError());
        }
        return file.write(buf.pData_, buf.size_);
    }


    void FileIo::Impl::copyXattrFrom(const FileIo&)
#endif
    {
#if defined(__APPLE__)
# if defined(EXV_UNICODE_PATH)
#  error No xattr API for MacOS X with unicode support
# endif
        ssize_t namebufSize = ::listxattr(src.p_->path_.c_str(), 0, 0, 0);
        if (namebufSize < 0) {
            throw Error(kerCallFailed, src.p_->path_, strError(), "listxattr");
        }
        if (namebufSize == 0) {
            // No extended attributes in source file
            return;
        }
        char* namebuf = new char[namebufSize];
        if (::listxattr(src.p_->path_.c_str(), namebuf, namebufSize, 0) != namebufSize) {
            throw Error(kerCallFailed, src.p_->path_, strError(), "listxattr");
        }
        for (ssize_t namebufPos = 0; namebufPos < namebufSize;) {
            const char *name = namebuf + namebufPos;
            namebufPos += strlen(name) + 1;
            const ssize_t valueSize = ::getxattr(src.p_->path_.c_str(), name, 0, 0, 0, 0);
            if (valueSize < 0) {
                throw Error(kerCallFailed, src.p_->path_, strError(), "getxattr");
            }
            char* value = new char[valueSize];
            if (::getxattr(src.p_->path_.c_str(), name, value, valueSize, 0, 0) != valueSize) {
                throw Error(kerCallFailed, src.p_->path_, strError(), "getxattr");
            }
// #906.  Mountain Lion 'sandbox' terminates the app when we call setxattr
#ifndef __APPLE__
#ifdef  EXIV2_DEBUG_MESSAGES
            EXV_DEBUG << "Copying xattr \"" << name << "\" with value size " << valueSize << "\n";
#endif
            if (::setxattr(path_.c_str(), name, value, valueSize, 0, 0) != 0) {
                throw Error(kerCallFailed, path_, strError(), "setxattr");
            }
            delete [] value;
#endif
        }
        delete [] namebuf;
#else
        // No xattr support for this platform.
#endif
    } // FileIo::Impl::copyXattrFrom


    size_t RemoteIo::read(byte* buf, size_t rcount)
    {
        assert(p_->isMalloced_);
        if (p_->eof_) return 0;
        p_->totalRead_ += (uint32_t)rcount;

        size_t allow     = std::min(rcount, p_->size_ - p_->idx_);
        size_t lowBlock  =  p_->idx_         /p_->blockSize_;
        size_t highBlock = (p_->idx_ + allow)/p_->blockSize_;

        // connect to the remote machine & populate the blocks just in time.
        p_->populateBlocks(lowBlock, highBlock);
        byte* fakeData = (byte*) std::calloc(p_->blockSize_, sizeof(byte));
        if (!fakeData) {
            throw Error(kerErrorMessage, "Unable to allocate data");
        }

        size_t iBlock = lowBlock;
        size_t startPos = p_->idx_ - lowBlock*p_->blockSize_;
        size_t totalRead = 0;
        do {
            byte* data = p_->blocksMap_[iBlock++].getData();
            if (data == nullptr) data = fakeData;
            size_t blockR = std::min(allow, p_->blockSize_ - startPos);
            std::memcpy(&buf[totalRead], &data[startPos], blockR);
            totalRead += blockR;
            startPos = 0;
            allow -= blockR;
        } while(allow);

        if (fakeData) std::free(fakeData);

        p_->idx_ += (long)totalRead;
        p_->eof_ = (p_->idx_ == p_->size_);

        return totalRead;
    }


    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 EXIV2_DEBUG_MESSAGES
            std::cerr << "RemoteIo::mmap nRealData = " << nRealData << std::endl;
#endif
        }

        return bigBlock_;
    }


    int FileIo::seek(int64 offset, Position pos )
    {
        assert(p_->fp_ != 0);

        int fileSeek = 0;
        switch (pos) {
        case BasicIo::cur: fileSeek = SEEK_CUR; break;
        case BasicIo::beg: fileSeek = SEEK_SET; break;
        case BasicIo::end: fileSeek = SEEK_END; break;
        }

        if (p_->switchMode(Impl::opSeek) != 0) return 1;
#ifdef _WIN64
        return _fseeki64(p_->fp_, offset, fileSeek);
#else
        return std::fseek(p_->fp_,static_cast<long>(offset), fileSeek);
#endif
    }


    int RemoteIo::close()
    {
        if (p_->isMalloced_) {
            p_->eof_ = false;
            p_->idx_ = 0;
        }
#ifdef EXIV2_DEBUG_MESSAGES
        std::cerr << "RemoteIo::close totalRead_ = " << p_->totalRead_ << std::endl;
#endif
        if ( bigBlock_ ) {
            delete [] bigBlock_;
            bigBlock_=NULL;
        }
        return 0;
    }


    SshIo::SshImpl::SshImpl(const std::string& url, size_t blockSize):Impl(url, blockSize)
    {
        hostInfo_ = Exiv2::Uri::Parse(url);
        Exiv2::Uri::Decode(hostInfo_);

        // remove / at the beginning of the path
        if (hostInfo_.Path[0] == '/') {
            hostInfo_.Path = hostInfo_.Path.substr(1);
        }
        ssh_ = new SSH(hostInfo_.Host, hostInfo_.Username, hostInfo_.Password, hostInfo_.Port);

        if (protocol_ == pSftp) {
            ssh_->getFileSftp(hostInfo_.Path, fileHandler_);
            if (fileHandler_ == NULL) throw Error(kerErrorMessage, "Unable to open the file");
        } else {
            fileHandler_ = NULL;
        }
    }


static PixelChannels **DestroyPixelThreadSet(const Image *images,
  PixelChannels **pixels)
{
  register ssize_t
    i;

  size_t
    rows;

  assert(pixels != (PixelChannels **) NULL);
  rows=MagickMax(GetImageListLength(images),
    (size_t) GetMagickResourceLimit(ThreadResource));
  for (i=0; i < (ssize_t) rows; i++)
    if (pixels[i] != (PixelChannels *) NULL)
      pixels[i]=(PixelChannels *) RelinquishMagickMemory(pixels[i]);
  pixels=(PixelChannels **) RelinquishMagickMemory(pixels);
  return(pixels);
}


ModuleExport size_t RegisterVIDImage(void)
{
  MagickInfo
    *entry;

  entry=SetMagickInfo("VID");
  entry->decoder=(DecodeImageHandler *) ReadVIDImage;
  entry->encoder=(EncodeImageHandler *) WriteVIDImage;
  entry->format_type=ImplicitFormatType;
  entry->description=ConstantString("Visual Image Directory");
  entry->module=ConstantString("VID");
  (void) RegisterMagickInfo(entry);
  return(MagickImageCoderSignature);
}


ModuleExport void UnregisterVIDImage(void)
{
  (void) UnregisterMagickInfo("VID");
}


static Image *ReadVIDImage(const ImageInfo *image_info,ExceptionInfo *exception)
{
#define ClientName  "montage"

  char
    **filelist,
    *label,
    **list;

  Image
    *image,
    *images,
    *montage_image,
    *next_image,
    *thumbnail_image;

  ImageInfo
    *read_info;

  int
    number_files;

  MagickBooleanType
    status;

  MontageInfo
    *montage_info;

  RectangleInfo
    geometry;

  register ssize_t
    i;

  /*
    Expand the filename.
  */
  assert(image_info != (const ImageInfo *) NULL);
  assert(image_info->signature == MagickCoreSignature);
  if (image_info->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
      image_info->filename);
  assert(exception != (ExceptionInfo *) NULL);
  assert(exception->signature == MagickCoreSignature);
  image=AcquireImage(image_info,exception);
  list=(char **) AcquireMagickMemory(sizeof(*filelist));
  if (list == (char **) NULL)
    ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
  list[0]=ConstantString(image_info->filename);
  filelist=list;
  number_files=1;
  status=ExpandFilenames(&number_files,&filelist);
  list[0]=DestroyString(list[0]);
  list=(char **) RelinquishMagickMemory(list);
  if ((status == MagickFalse) || (number_files == 0))
    ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
  image=DestroyImage(image);
  /*
    Read each image and convert them to a tile.
  */
  images=NewImageList();
  read_info=CloneImageInfo(image_info);
  SetImageInfoBlob(read_info,(void *) NULL,0);
  (void) SetImageInfoProgressMonitor(read_info,(MagickProgressMonitor) NULL,
    (void *) NULL);
  if (read_info->size == (char *) NULL)
    (void) CloneString(&read_info->size,DefaultTileGeometry);
  for (i=0; i < (ssize_t) number_files; i++)
  {
    if (image_info->debug != MagickFalse)
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),"name: %s",
        filelist[i]);
    (void) CopyMagickString(read_info->filename,filelist[i],MagickPathExtent);
    filelist[i]=DestroyString(filelist[i]);
    *read_info->magick='\0';
    next_image=ReadImage(read_info,exception);
    CatchException(exception);
    if (next_image == (Image *) NULL)
      break;
    label=InterpretImageProperties((ImageInfo *) image_info,next_image,
      DefaultTileLabel,exception);
    if (label != (char *) NULL)
      {
        (void) SetImageProperty(next_image,"label",label,exception);
        label=DestroyString(label);
      }
    if (image_info->debug != MagickFalse)
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
        "geometry: %.20gx%.20g",(double) next_image->columns,(double)
        next_image->rows);
    SetGeometry(next_image,&geometry);
    (void) ParseMetaGeometry(read_info->size,&geometry.x,&geometry.y,
      &geometry.width,&geometry.height);
    thumbnail_image=ThumbnailImage(next_image,geometry.width,geometry.height,
      exception);
    if (thumbnail_image != (Image *) NULL)
      {
        next_image=DestroyImage(next_image);
        next_image=thumbnail_image;
      }
    if (image_info->debug != MagickFalse)
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
        "thumbnail geometry: %.20gx%.20g",(double) next_image->columns,(double)
        next_image->rows);
    AppendImageToList(&images,next_image);
    status=SetImageProgress(images,LoadImagesTag,i,number_files);
    if (status == MagickFalse)
      break;
  }
  read_info=DestroyImageInfo(read_info);
  filelist=(char **) RelinquishMagickMemory(filelist);
  if (images == (Image *) NULL)
    ThrowReaderException(CorruptImageError,
      "ImageFileDoesNotContainAnyImageData");
  /*
    Create the visual image directory.
  */
  montage_info=CloneMontageInfo(image_info,(MontageInfo *) NULL);
  if (image_info->debug != MagickFalse)
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),"creating montage");
  montage_image=MontageImageList(image_info,montage_info,
    GetFirstImageInList(images),exception);
  montage_info=DestroyMontageInfo(montage_info);
  images=DestroyImageList(images);
  return(montage_image);
}


static MagickBooleanType WritePCLImage(const ImageInfo *image_info,Image *image,
  ExceptionInfo *exception)
{
  char
    buffer[MagickPathExtent];

  CompressionType
    compression;

  const char
    *option;

  MagickBooleanType
    status;

  MagickOffsetType
    scene;

  register const Quantum *p;

  register ssize_t i, x;

  register unsigned char *q;

  size_t
    density,
    imageListLength,
    length,
    one,
    packets;

  ssize_t
    y;

  unsigned char
    bits_per_pixel,
    *compress_pixels,
    *pixels,
    *previous_pixels;

  /*
    Open output image file.
  */
  assert(image_info != (const ImageInfo *) NULL);
  assert(image_info->signature == MagickCoreSignature);
  assert(image != (Image *) NULL);
  assert(image->signature == MagickCoreSignature);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
  assert(exception != (ExceptionInfo *) NULL);
  assert(exception->signature == MagickCoreSignature);
  status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
  if (status == MagickFalse)
    return(status);
  density=75;
  if (image_info->density != (char *) NULL)
    {
      GeometryInfo
        geometry;

      (void) ParseGeometry(image_info->density,&geometry);
      density=(size_t) geometry.rho;
    }
  scene=0;
  one=1;
  imageListLength=GetImageListLength(image);
  do
  {
    /*
      Initialize the printer.
    */
    (void) TransformImageColorspace(image,sRGBColorspace,exception);
    (void) WriteBlobString(image,"\033E");  /* printer reset */
    (void) WriteBlobString(image,"\033*r3F");  /* set presentation mode */
    (void) FormatLocaleString(buffer,MagickPathExtent,"\033*r%.20gs%.20gT",
      (double) image->columns,(double) image->rows);
    (void) WriteBlobString(image,buffer);
    (void) FormatLocaleString(buffer,MagickPathExtent,"\033*t%.20gR",(double)
      density);
    (void) WriteBlobString(image,buffer);
    (void) WriteBlobString(image,"\033&l0E");  /* top margin 0 */
    if (SetImageMonochrome(image,exception) != MagickFalse)
      {
        /*
          Monochrome image: use default printer monochrome setup.
        */
        bits_per_pixel=1;
      }
    else
      if (image->storage_class == DirectClass)
        {
          /*
            DirectClass image.
          */
          bits_per_pixel=24;
          (void) WriteBlobString(image,"\033*v6W"); /* set color mode */
          (void) WriteBlobByte(image,0); /* RGB */
          (void) WriteBlobByte(image,3); /* direct by pixel */
          (void) WriteBlobByte(image,0); /* bits per index (ignored) */
          (void) WriteBlobByte(image,8); /* bits per red component */
          (void) WriteBlobByte(image,8); /* bits per green component */
          (void) WriteBlobByte(image,8); /* bits per blue component */
        }
      else
        {
          /*
            Colormapped image.
          */
          bits_per_pixel=8;
          (void) WriteBlobString(image,"\033*v6W"); /* set color mode... */
          (void) WriteBlobByte(image,0); /* RGB */
          (void) WriteBlobByte(image,1); /* indexed by pixel */
          (void) WriteBlobByte(image,bits_per_pixel); /* bits per index */
          (void) WriteBlobByte(image,8); /* bits per red component */
          (void) WriteBlobByte(image,8); /* bits per green component */
          (void) WriteBlobByte(image,8); /* bits per blue component */
          for (i=0; i < (ssize_t) image->colors; i++)
          {
            (void) FormatLocaleString(buffer,MagickPathExtent,
              "\033*v%da%db%dc%.20gI",
              ScaleQuantumToChar(image->colormap[i].red),
              ScaleQuantumToChar(image->colormap[i].green),
              ScaleQuantumToChar(image->colormap[i].blue),(double) i);
            (void) WriteBlobString(image,buffer);
          }
          for (one=1; i < (ssize_t) (one << bits_per_pixel); i++)
          {
            (void) FormatLocaleString(buffer,MagickPathExtent,"\033*v%.20gI",
              (double) i);
            (void) WriteBlobString(image,buffer);
          }
        }
    option=GetImageOption(image_info,"pcl:fit-to-page");
    if (IsStringTrue(option) != MagickFalse)
      (void) WriteBlobString(image,"\033*r3A");
    else
      (void) WriteBlobString(image,"\033*r1A");  /* start raster graphics */
    (void) WriteBlobString(image,"\033*b0Y");  /* set y offset */
    length=(image->columns*bits_per_pixel+7)/8;
    pixels=(unsigned char *) AcquireQuantumMemory(length+1,sizeof(*pixels));
    if (pixels == (unsigned char *) NULL)
      ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
    (void) memset(pixels,0,(length+1)*sizeof(*pixels));
    compress_pixels=(unsigned char *) NULL;
    previous_pixels=(unsigned char *) NULL;

    compression=UndefinedCompression;
    if (image_info->compression != UndefinedCompression)
      compression=image_info->compression;
    switch (compression)
    {
      case NoCompression:
      {
        (void) FormatLocaleString(buffer,MagickPathExtent,"\033*b0M");
        (void) WriteBlobString(image,buffer);
        break;
      }
      case RLECompression:
      {
        compress_pixels=(unsigned char *) AcquireQuantumMemory(length+256,
          sizeof(*compress_pixels));
        if (compress_pixels == (unsigned char *) NULL)
          {
            pixels=(unsigned char *) RelinquishMagickMemory(pixels);
            ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
          }
        (void) memset(compress_pixels,0,(length+256)*
          sizeof(*compress_pixels));
        (void) FormatLocaleString(buffer,MagickPathExtent,"\033*b2M");
        (void) WriteBlobString(image,buffer);
        break;
      }
      default:
      {
        compress_pixels=(unsigned char *) AcquireQuantumMemory(3*length+256,
          sizeof(*compress_pixels));
        if (compress_pixels == (unsigned char *) NULL)
          {
            pixels=(unsigned char *) RelinquishMagickMemory(pixels);
            ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
          }
        (void) memset(compress_pixels,0,(3*length+256)*
          sizeof(*compress_pixels));
        previous_pixels=(unsigned char *) AcquireQuantumMemory(length+1,
          sizeof(*previous_pixels));
        if (previous_pixels == (unsigned char *) NULL)
          {
            compress_pixels=(unsigned char *) RelinquishMagickMemory(
              compress_pixels);
            pixels=(unsigned char *) RelinquishMagickMemory(pixels);
            ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
          }
        (void) memset(previous_pixels,0,(length+1)*
          sizeof(*previous_pixels));
        (void) FormatLocaleString(buffer,MagickPathExtent,"\033*b3M");
        (void) WriteBlobString(image,buffer);
        break;
      }
    }
    for (y=0; y < (ssize_t) image->rows; y++)
    {
      p=GetVirtualPixels(image,0,y,image->columns,1,exception);
      if (p == (const Quantum *) NULL)
        break;
      q=pixels;
      switch (bits_per_pixel)
      {
        case 1:
        {
          register unsigned char
            bit,
            byte;

          /*
            Monochrome image.
          */
          bit=0;
          byte=0;
          for (x=0; x < (ssize_t) image->columns; x++)
          {
            byte<<=1;
            if (GetPixelLuma(image,p) < (QuantumRange/2.0))
              byte|=0x01;
            bit++;
            if (bit == 8)
              {
                *q++=byte;
                bit=0;
                byte=0;
              }
            p+=GetPixelChannels(image);
          }
          if (bit != 0)
            *q++=byte << (8-bit);
          break;
        }
        case 8:
        {
          /*
            Colormapped image.
          */
          for (x=0; x < (ssize_t) image->columns; x++)
          {
            *q++=(unsigned char) GetPixelIndex(image,p);
            p+=GetPixelChannels(image);
          }
          break;
        }
        case 24:
        case 32:
        {
          /*
            Truecolor image.
          */
          for (x=0; x < (ssize_t) image->columns; x++)
          {
            *q++=ScaleQuantumToChar(GetPixelRed(image,p));
            *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
            *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
            p+=GetPixelChannels(image);
          }
          break;
        }
      }
      switch (compression)
      {
        case NoCompression:
        {
          (void) FormatLocaleString(buffer,MagickPathExtent,"\033*b%.20gW",
            (double) length);
          (void) WriteBlobString(image,buffer);
          (void) WriteBlob(image,length,pixels);
          break;
        }
        case RLECompression:
        {
          packets=PCLPackbitsCompressImage(length,pixels,compress_pixels);
          (void) FormatLocaleString(buffer,MagickPathExtent,"\033*b%.20gW",
            (double) packets);
          (void) WriteBlobString(image,buffer);
          (void) WriteBlob(image,packets,compress_pixels);
          break;
        }
        default:
        {
          if (y == 0)
            for (i=0; i < (ssize_t) length; i++)
              previous_pixels[i]=(~pixels[i]);
          packets=PCLDeltaCompressImage(length,previous_pixels,pixels,
            compress_pixels);
          (void) FormatLocaleString(buffer,MagickPathExtent,"\033*b%.20gW",
            (double) packets);
          (void) WriteBlobString(image,buffer);
          (void) WriteBlob(image,packets,compress_pixels);
          (void) memcpy(previous_pixels,pixels,length*
            sizeof(*pixels));
          break;
        }
      }
    }
    (void) WriteBlobString(image,"\033*rB");  /* end graphics */
    switch (compression)
    {
      case NoCompression:
        break;
      case RLECompression:
      {
        compress_pixels=(unsigned char *) RelinquishMagickMemory(
          compress_pixels);
        break;
      }
      default:
      {
        previous_pixels=(unsigned char *) RelinquishMagickMemory(
          previous_pixels);
        compress_pixels=(unsigned char *) RelinquishMagickMemory(
          compress_pixels);
        break;
      }
    }
    pixels=(unsigned char *) RelinquishMagickMemory(pixels);
    if (GetNextImageInList(image) == (Image *) NULL)
      break;
    image=SyncNextImageInList(image);
    status=SetImageProgress(image,SaveImagesTag,scene++,imageListLength);
    if (status == MagickFalse)
      break;
  } while (image_info->adjoin != MagickFalse);
  (void) WriteBlobString(image,"\033E");
  (void) CloseBlob(image);
  return(MagickTrue);
}


MagickExport size_t InterpretImageFilename(const ImageInfo *image_info,
  Image *image,const char *format,int value,char *filename,
  ExceptionInfo *exception)
{
  char
    *q;

  int
    c;

  MagickBooleanType
    canonical;

  register const char
    *p;

  ssize_t
    field_width,
    offset;

  canonical=MagickFalse;
  offset=0;
  (void) CopyMagickString(filename,format,MagickPathExtent);
  for (p=strchr(format,'%'); p != (char *) NULL; p=strchr(p+1,'%'))
  {
    q=(char *) p+1;
    if (*q == '%')
      {
        p=q+1;
        continue;
      }
    field_width=0;
    if (*q == '0')
      field_width=(ssize_t) strtol(q,&q,10);
    switch (*q)
    {
      case 'd':
      case 'o':
      case 'x':
      {
        q++;
        c=(*q);
        *q='\0';
        (void) FormatLocaleString(filename+(p-format-offset),(size_t)
          (MagickPathExtent-(p-format-offset)),p,value);
        offset+=(4-field_width);
        *q=c;
        (void) ConcatenateMagickString(filename,q,MagickPathExtent);
        canonical=MagickTrue;
        if (*(q-1) != '%')
          break;
        p++;
        break;
      }
      case '[':
      {
        char
          pattern[MagickPathExtent];

        const char
          *option;

        register char
          *r;

        register ssize_t
          i;

        ssize_t
          depth;

        /*
          Image option.
        */
        if (strchr(p,']') == (char *) NULL)
          break;
        depth=1;
        r=q+1;
        for (i=0; (i < (MagickPathExtent-1L)) && (*r != '\0'); i++)
        {
          if (*r == '[')
            depth++;
          if (*r == ']')
            depth--;
          if (depth <= 0)
            break;
          pattern[i]=(*r++);
        }
        pattern[i]='\0';
        if (LocaleNCompare(pattern,"filename:",9) != 0)
          break;
        option=(const char *) NULL;
        if (image != (Image *) NULL)
          option=GetImageProperty(image,pattern,exception);
        if ((option == (const char *) NULL) && (image != (Image *) NULL))
          option=GetImageArtifact(image,pattern);
        if ((option == (const char *) NULL) &&
            (image_info != (ImageInfo *) NULL))
          option=GetImageOption(image_info,pattern);
        if (option == (const char *) NULL)
          break;
        q--;
        c=(*q);
        *q='\0';
        (void) CopyMagickString(filename+(p-format-offset),option,(size_t)
          (MagickPathExtent-(p-format-offset)));
        offset+=strlen(pattern)-strlen(option)+3;
        *q=c;
        (void) ConcatenateMagickString(filename,r+1,MagickPathExtent);
        canonical=MagickTrue;
        if (*(q-1) != '%')
          break;
        p++;
        break;
      }
      default:
        break;
    }
  }
  for (q=filename; *q != '\0'; q++)
    if ((*q == '%') && (*(q+1) == '%'))
      {
        (void) CopyMagickString(q,q+1,(size_t) (MagickPathExtent-(q-filename)));
        canonical=MagickTrue;
      }
  if (canonical == MagickFalse)
    (void) CopyMagickString(filename,format,MagickPathExtent);
  return(strlen(filename));
}


MagickExport MagickBooleanType SetImageAlpha(Image *image,const Quantum alpha,
  ExceptionInfo *exception)
{
  CacheView
    *image_view;

  MagickBooleanType
    status;

  ssize_t
    y;

  assert(image != (Image *) NULL);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
  assert(image->signature == MagickCoreSignature);
  image->alpha_trait=BlendPixelTrait;
  status=MagickTrue;
  image_view=AcquireAuthenticCacheView(image,exception);
#if defined(MAGICKCORE_OPENMP_SUPPORT)
  #pragma omp parallel for schedule(static) shared(status) \
    magick_number_threads(image,image,image->rows,1)
#endif
  for (y=0; y < (ssize_t) image->rows; y++)
  {
    register Quantum
      *magick_restrict q;

    register ssize_t
      x;

    if (status == MagickFalse)
      continue;
    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
    if (q == (Quantum *) NULL)
      {
        status=MagickFalse;
        continue;
      }
    for (x=0; x < (ssize_t) image->columns; x++)
    {
      SetPixelAlpha(image,alpha,q);
      q+=GetPixelChannels(image);
    }
    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
      status=MagickFalse;
  }
  image_view=DestroyCacheView(image_view);
  return(status);
}


MagickExport void AcquireNextImage(const ImageInfo *image_info,Image *image)
{
  /*
    Allocate image structure.
  */
  assert(image != (Image *) NULL);
  assert(image->signature == MagickCoreSignature);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
  image->next=AcquireImage(image_info);
  if (GetNextImageInList(image) == (Image *) NULL)
    return;
  (void) CopyMagickString(GetNextImageInList(image)->filename,image->filename,
    MaxTextExtent);
  if (image_info != (ImageInfo *) NULL)
    (void) CopyMagickString(GetNextImageInList(image)->filename,
      image_info->filename,MaxTextExtent);
  DestroyBlob(GetNextImageInList(image));
  image->next->blob=ReferenceBlob(image->blob);
  image->next->endian=image->endian;
  image->next->scene=image->scene+1;
  image->next->previous=image;
}


MagickExport MagickBooleanType SetImageOpacity(Image *image,
  const Quantum opacity)
{
  CacheView
    *image_view;

  ExceptionInfo
    *exception;

  MagickBooleanType
    status;

  ssize_t
    y;

  assert(image != (Image *) NULL);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
  assert(image->signature == MagickCoreSignature);
  image->matte=MagickTrue;
  status=MagickTrue;
  exception=(&image->exception);
  image_view=AcquireAuthenticCacheView(image,exception);
#if defined(MAGICKCORE_OPENMP_SUPPORT)
  #pragma omp parallel for schedule(static) shared(status) \
    magick_number_threads(image,image,image->rows,1)
#endif
  for (y=0; y < (ssize_t) image->rows; y++)
  {
    register PixelPacket
      *magick_restrict q;

    register ssize_t
      x;

    if (status == MagickFalse)
      continue;
    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
    if (q == (PixelPacket *) NULL)
      {
        status=MagickFalse;
        continue;
      }
    for (x=0; x < (ssize_t) image->columns; x++)
    {
      SetPixelOpacity(q,opacity);
      q++;
    }
    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
      status=MagickFalse;
  }
  image_view=DestroyCacheView(image_view);
  return(status);
}


MagickExport Image *AcquireImage(const ImageInfo *image_info)
{
  const char
    *option;

  Image
    *image;

  MagickStatusType
    flags;

  /*
    Allocate image structure.
  */
  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
  image=(Image *) AcquireCriticalMemory(sizeof(*image));
  (void) memset(image,0,sizeof(*image));
  /*
    Initialize Image structure.
  */
  (void) CopyMagickString(image->magick,"MIFF",MaxTextExtent);
  image->storage_class=DirectClass;
  image->depth=MAGICKCORE_QUANTUM_DEPTH;
  image->colorspace=sRGBColorspace;
  image->rendering_intent=PerceptualIntent;
  image->gamma=1.000f/2.200f;
  image->chromaticity.red_primary.x=0.6400f;
  image->chromaticity.red_primary.y=0.3300f;
  image->chromaticity.red_primary.z=0.0300f;
  image->chromaticity.green_primary.x=0.3000f;
  image->chromaticity.green_primary.y=0.6000f;
  image->chromaticity.green_primary.z=0.1000f;
  image->chromaticity.blue_primary.x=0.1500f;
  image->chromaticity.blue_primary.y=0.0600f;
  image->chromaticity.blue_primary.z=0.7900f;
  image->chromaticity.white_point.x=0.3127f;
  image->chromaticity.white_point.y=0.3290f;
  image->chromaticity.white_point.z=0.3583f;
  image->interlace=NoInterlace;
  image->ticks_per_second=UndefinedTicksPerSecond;
  image->compose=OverCompositeOp;
  image->blur=1.0;
  InitializeExceptionInfo(&image->exception);
  (void) QueryColorDatabase(BackgroundColor,&image->background_color,
    &image->exception);
  (void) QueryColorDatabase(BorderColor,&image->border_color,&image->exception);
  (void) QueryColorDatabase(MatteColor,&image->matte_color,&image->exception);
  (void) QueryColorDatabase(TransparentColor,&image->transparent_color,
    &image->exception);
  GetTimerInfo(&image->timer);
  image->ping=MagickFalse;
  image->cache=AcquirePixelCache(0);
  image->blob=CloneBlobInfo((BlobInfo *) NULL);
  image->timestamp=time((time_t *) NULL);
  image->debug=IsEventLogging();
  image->reference_count=1;
  image->semaphore=AllocateSemaphoreInfo();
  image->signature=MagickCoreSignature;
  if (image_info == (ImageInfo *) NULL)
    return(image);
  /*
    Transfer image info.
  */
  SetBlobExempt(image,image_info->file != (FILE *) NULL ? MagickTrue :
    MagickFalse);
  (void) CopyMagickString(image->filename,image_info->filename,MaxTextExtent);
  (void) CopyMagickString(image->magick_filename,image_info->filename,
    MaxTextExtent);
  (void) CopyMagickString(image->magick,image_info->magick,MaxTextExtent);
  if (image_info->size != (char *) NULL)
    {
      (void) ParseAbsoluteGeometry(image_info->size,&image->extract_info);
      image->columns=image->extract_info.width;
      image->rows=image->extract_info.height;
      image->offset=image->extract_info.x;
      image->extract_info.x=0;
      image->extract_info.y=0;
    }
  if (image_info->extract != (char *) NULL)
    {
      RectangleInfo
        geometry;

      (void) memset(&geometry,0,sizeof(geometry));
      flags=ParseAbsoluteGeometry(image_info->extract,&geometry);
      if (((flags & XValue) != 0) || ((flags & YValue) != 0))
        {
          image->extract_info=geometry;
          Swap(image->columns,image->extract_info.width);
          Swap(image->rows,image->extract_info.height);
        }
    }
  image->compression=image_info->compression;
  image->quality=image_info->quality;
  image->endian=image_info->endian;
  image->interlace=image_info->interlace;
  image->units=image_info->units;
  if (image_info->density != (char *) NULL)
    {
      GeometryInfo
        geometry_info;

      flags=ParseGeometry(image_info->density,&geometry_info);
      if ((flags & RhoValue) != 0)
        image->x_resolution=geometry_info.rho;
      image->y_resolution=image->x_resolution;
      if ((flags & SigmaValue) != 0)
        image->y_resolution=geometry_info.sigma;
    }
  if (image_info->page != (char *) NULL)
    {
      char
        *geometry;

      image->page=image->extract_info;
      geometry=GetPageGeometry(image_info->page);
      (void) ParseAbsoluteGeometry(geometry,&image->page);
      geometry=DestroyString(geometry);
    }
  if (image_info->depth != 0)
    image->depth=image_info->depth;
  image->dither=image_info->dither;
  image->background_color=image_info->background_color;
  image->border_color=image_info->border_color;
  image->matte_color=image_info->matte_color;
  image->transparent_color=image_info->transparent_color;
  image->ping=image_info->ping;
  image->progress_monitor=image_info->progress_monitor;
  image->client_data=image_info->client_data;
  if (image_info->cache != (void *) NULL)
    ClonePixelCacheMethods(image->cache,image_info->cache);
  (void) SyncImageSettings(image_info,image);
  option=GetImageOption(image_info,"delay");
  if (option != (const char *) NULL)
    {
      GeometryInfo
        geometry_info;

      flags=ParseGeometry(option,&geometry_info);
      if ((flags & GreaterValue) != 0)
        {
          if (image->delay > (size_t) floor(geometry_info.rho+0.5))
            image->delay=(size_t) floor(geometry_info.rho+0.5);
        }
      else
        if ((flags & LessValue) != 0)
          {
            if (image->delay < (size_t) floor(geometry_info.rho+0.5))
              image->ticks_per_second=(ssize_t) floor(geometry_info.sigma+0.5);
          }
        else
          image->delay=(size_t) floor(geometry_info.rho+0.5);
      if ((flags & SigmaValue) != 0)
        image->ticks_per_second=(ssize_t) floor(geometry_info.sigma+0.5);
    }
  option=GetImageOption(image_info,"dispose");
  if (option != (const char *) NULL)
    image->dispose=(DisposeType) ParseCommandOption(MagickDisposeOptions,
      MagickFalse,option);
  return(image);
}


MagickExport MagickBooleanType SetImageInfo(ImageInfo *image_info,
  const unsigned int frames,ExceptionInfo *exception)
{
  char
    extension[MaxTextExtent],
    filename[MaxTextExtent],
    magic[MaxTextExtent],
    *q,
    subimage[MaxTextExtent];

  const MagicInfo
    *magic_info;

  const MagickInfo
    *magick_info;

  ExceptionInfo
    *sans_exception;

  Image
    *image;

  MagickBooleanType
    status;

  register const char
    *p;

  ssize_t
    count;

  unsigned char
    magick[2*MaxTextExtent];

  /*
    Look for 'image.format' in filename.
  */
  assert(image_info != (ImageInfo *) NULL);
  assert(image_info->signature == MagickCoreSignature);
  if (image_info->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
      image_info->filename);
  *subimage='\0';
  GetPathComponent(image_info->filename,SubimagePath,subimage);
  if (*subimage != '\0')
    {
      /*
        Look for scene specification (e.g. img0001.pcd[4]).
      */
      if (IsSceneGeometry(subimage,MagickFalse) == MagickFalse)
        {
          if (IsGeometry(subimage) != MagickFalse)
            (void) CloneString(&image_info->extract,subimage);
        }
      else
        {
          size_t
            first,
            last;

          (void) CloneString(&image_info->scenes,subimage);
          image_info->scene=StringToUnsignedLong(image_info->scenes);
          image_info->number_scenes=image_info->scene;
          p=image_info->scenes;
          for (q=(char *) image_info->scenes; *q != '\0'; p++)
          {
            while ((isspace((int) ((unsigned char) *p)) != 0) || (*p == ','))
              p++;
            first=(size_t) strtol(p,&q,10);
            last=first;
            while (isspace((int) ((unsigned char) *q)) != 0)
              q++;
            if (*q == '-')
              last=(size_t) strtol(q+1,&q,10);
            if (first > last)
              Swap(first,last);
            if (first < image_info->scene)
              image_info->scene=first;
            if (last > image_info->number_scenes)
              image_info->number_scenes=last;
            p=q;
          }
          image_info->number_scenes-=image_info->scene-1;
          image_info->subimage=image_info->scene;
          image_info->subrange=image_info->number_scenes;
        }
    }
  *extension='\0';
  if (*image_info->magick == '\0')
    GetPathComponent(image_info->filename,ExtensionPath,extension);
#if defined(MAGICKCORE_ZLIB_DELEGATE)
  if (*extension != '\0')
    if ((LocaleCompare(extension,"gz") == 0) ||
        (LocaleCompare(extension,"Z") == 0) ||
        (LocaleCompare(extension,"svgz") == 0) ||
        (LocaleCompare(extension,"wmz") == 0))
      {
        char
          path[MaxTextExtent];

        (void) CopyMagickString(path,image_info->filename,MaxTextExtent);
        path[strlen(path)-strlen(extension)-1]='\0';
        GetPathComponent(path,ExtensionPath,extension);
      }
#endif
#if defined(MAGICKCORE_BZLIB_DELEGATE)
  if (*extension != '\0')
    if (LocaleCompare(extension,"bz2") == 0)
      {
        char
          path[MaxTextExtent];

        (void) CopyMagickString(path,image_info->filename,MaxTextExtent);
        path[strlen(path)-strlen(extension)-1]='\0';
        GetPathComponent(path,ExtensionPath,extension);
      }
#endif
  image_info->affirm=MagickFalse;
  sans_exception=AcquireExceptionInfo();
  if ((*extension != '\0') && (IsGlob(extension) == MagickFalse))
    {
      MagickFormatType
        format_type;

      register ssize_t
        i;

      static const char
        *format_type_formats[] =
        {
          "AUTOTRACE",
          "BROWSE",
          "DCRAW",
          "EDIT",
          "LAUNCH",
          "MPEG:DECODE",
          "MPEG:ENCODE",
          "PRINT",
          "PS:ALPHA",
          "PS:CMYK",
          "PS:COLOR",
          "PS:GRAY",
          "PS:MONO",
          "SCAN",
          "SHOW",
          "WIN",
          (char *) NULL
        };

      /*
        User specified image format.
      */
      (void) CopyMagickString(magic,extension,MaxTextExtent);
      LocaleUpper(magic);
      /*
        Look for explicit image formats.
      */
      format_type=UndefinedFormatType;
      i=0;
      while ((format_type == UndefinedFormatType) &&
             (format_type_formats[i] != (char *) NULL))
      {
        if ((*magic == *format_type_formats[i]) &&
            (LocaleCompare(magic,format_type_formats[i]) == 0))
          format_type=ExplicitFormatType;
        i++;
      }
      magick_info=GetMagickInfo(magic,sans_exception);
      if ((magick_info != (const MagickInfo *) NULL) &&
          (magick_info->format_type != UndefinedFormatType))
        format_type=magick_info->format_type;
      if (format_type == UndefinedFormatType)
        (void) CopyMagickString(image_info->magick,magic,MaxTextExtent);
      else
        if (format_type == ExplicitFormatType)
          {
            image_info->affirm=MagickTrue;
            (void) CopyMagickString(image_info->magick,magic,MaxTextExtent);
          }
      if (LocaleCompare(magic,"RGB") == 0)
        image_info->affirm=MagickFalse;  /* maybe SGI disguised as RGB */
    }
  /*
    Look for explicit 'format:image' in filename.
  */
  *magic='\0';
  GetPathComponent(image_info->filename,MagickPath,magic);
  if (*magic == '\0')
    {
      (void) CopyMagickString(magic,image_info->magick,MaxTextExtent);
      magick_info=GetMagickInfo(magic,sans_exception);
      if (frames == 0)
        GetPathComponent(image_info->filename,CanonicalPath,filename);
      else
        GetPathComponent(image_info->filename,SubcanonicalPath,filename);
      (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
    }
  else
    {
      const DelegateInfo
        *delegate_info;

      /*
        User specified image format.
      */
      LocaleUpper(magic);
      magick_info=GetMagickInfo(magic,sans_exception);
      delegate_info=GetDelegateInfo(magic,"*",sans_exception);
      if (delegate_info == (const DelegateInfo *) NULL)
        delegate_info=GetDelegateInfo("*",magic,sans_exception);
      if (((magick_info != (const MagickInfo *) NULL) ||
           (delegate_info != (const DelegateInfo *) NULL)) &&
          (IsMagickConflict(magic) == MagickFalse))
        {
          image_info->affirm=MagickTrue;
          (void) CopyMagickString(image_info->magick,magic,MaxTextExtent);
          GetPathComponent(image_info->filename,CanonicalPath,filename);
          (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
        }
    }
  sans_exception=DestroyExceptionInfo(sans_exception);
  if ((magick_info == (const MagickInfo *) NULL) ||
      (GetMagickEndianSupport(magick_info) == MagickFalse))
    image_info->endian=UndefinedEndian;
  if ((image_info->adjoin != MagickFalse) && (frames > 1))
    {
      /*
        Test for multiple image support (e.g. image%02d.png).
      */
      (void) InterpretImageFilename(image_info,(Image *) NULL,
        image_info->filename,(int) image_info->scene,filename);
      if ((LocaleCompare(filename,image_info->filename) != 0) &&
          (strchr(filename,'%') == (char *) NULL))
        image_info->adjoin=MagickFalse;
    }
  if ((image_info->adjoin != MagickFalse) && (frames > 0))
    {
      /*
        Some image formats do not support multiple frames per file.
      */
      magick_info=GetMagickInfo(magic,exception);
      if (magick_info != (const MagickInfo *) NULL)
        if (GetMagickAdjoin(magick_info) == MagickFalse)
          image_info->adjoin=MagickFalse;
    }
  if (image_info->affirm != MagickFalse)
    return(MagickTrue);
  if (frames == 0)
    {
      /*
        Determine the image format from the first few bytes of the file.
      */
      image=AcquireImage(image_info);
      (void) CopyMagickString(image->filename,image_info->filename,
        MaxTextExtent);
      status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
      if (status == MagickFalse)
        {
          image=DestroyImage(image);
          return(MagickFalse);
        }
      if ((IsBlobSeekable(image) == MagickFalse) ||
          (IsBlobExempt(image) != MagickFalse))
        {
          /*
            Copy image to a seekable temporary file.
          */
          *filename='\0';
          status=ImageToFile(image,filename,exception);
          (void) CloseBlob(image);
          if (status == MagickFalse)
            {
              image=DestroyImage(image);
              return(MagickFalse);
            }
          SetImageInfoFile(image_info,(FILE *) NULL);
          (void) CopyMagickString(image->filename,filename,MaxTextExtent);
          status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
          if (status == MagickFalse)
            {
              image=DestroyImage(image);
              return(MagickFalse);
            }
          (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
          image_info->temporary=MagickTrue;
        }
      (void) memset(magick,0,sizeof(magick));
      count=ReadBlob(image,2*MaxTextExtent,magick);
      (void) SeekBlob(image,-((MagickOffsetType) count),SEEK_CUR);
      (void) CloseBlob(image);
      image=DestroyImage(image);
      /*
        Check magic.xml configuration file.
      */
      sans_exception=AcquireExceptionInfo();
      magic_info=GetMagicInfo(magick,(size_t) count,sans_exception);
      if ((magic_info != (const MagicInfo *) NULL) &&
          (GetMagicName(magic_info) != (char *) NULL))
        {
          (void) CopyMagickString(image_info->magick,GetMagicName(magic_info),
            MaxTextExtent);
          magick_info=GetMagickInfo(image_info->magick,sans_exception);
          if ((magick_info == (const MagickInfo *) NULL) ||
              (GetMagickEndianSupport(magick_info) == MagickFalse))
            image_info->endian=UndefinedEndian;
          sans_exception=DestroyExceptionInfo(sans_exception);
          return(MagickTrue);
        }
      magick_info=GetMagickInfo(image_info->magick,sans_exception);
      if ((magick_info == (const MagickInfo *) NULL) ||
          (GetMagickEndianSupport(magick_info) == MagickFalse))
        image_info->endian=UndefinedEndian;
      sans_exception=DestroyExceptionInfo(sans_exception);
    }
  return(MagickTrue);
}


MagickExport void GetImageException(Image *image,ExceptionInfo *exception)
{
  register Image
    *next;

  assert(image != (Image *) NULL);
  assert(image->signature == MagickCoreSignature);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
  assert(exception != (ExceptionInfo *) NULL);
  assert(exception->signature == MagickCoreSignature);
  for (next=image; next != (Image *) NULL; next=GetNextImageInList(next))
  {
    if (next->exception.severity == UndefinedException)
      continue;
    if (next->exception.severity > exception->severity)
      InheritException(exception,&next->exception);
    next->exception.severity=UndefinedException;
  }
}


MagickExport Image *GetImageClipMask(const Image *image,
  ExceptionInfo *exception)
{
  assert(image != (const Image *) NULL);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
  assert(image->signature == MagickCoreSignature);
  if (image->clip_mask == (Image *) NULL)
    return((Image *) NULL);
  return(CloneImage(image->clip_mask,0,0,MagickTrue,exception));
}


static ssize_t SmushXGap(const Image *smush_image,const Image *images,
  const ssize_t offset,ExceptionInfo *exception)
{
  CacheView
    *left_view,
    *right_view;

  const Image
    *left_image,
    *right_image;

  RectangleInfo
    left_geometry,
    right_geometry;

  register const PixelPacket
    *p;

  register ssize_t
    i,
    y;

  size_t
    gap;

  ssize_t
    x;

  if (images->previous == (Image *) NULL)
    return(0);
  right_image=images;
  SetGeometry(smush_image,&right_geometry);
  GravityAdjustGeometry(right_image->columns,right_image->rows,
    right_image->gravity,&right_geometry);
  left_image=images->previous;
  SetGeometry(smush_image,&left_geometry);
  GravityAdjustGeometry(left_image->columns,left_image->rows,
    left_image->gravity,&left_geometry);
  gap=right_image->columns;
  left_view=AcquireVirtualCacheView(left_image,exception);
  right_view=AcquireVirtualCacheView(right_image,exception);
  for (y=0; y < (ssize_t) smush_image->rows; y++)
  {
    for (x=(ssize_t) left_image->columns-1; x > 0; x--)
    {
      p=GetCacheViewVirtualPixels(left_view,x,left_geometry.y+y,1,1,exception);
      if ((p == (const PixelPacket *) NULL) ||
          (GetPixelOpacity(p) != TransparentOpacity) ||
          ((left_image->columns-x-1) >= gap))
        break;
    }
    i=(ssize_t) left_image->columns-x-1;
    for (x=0; x < (ssize_t) right_image->columns; x++)
    {
      p=GetCacheViewVirtualPixels(right_view,x,right_geometry.y+y,1,1,
        exception);
      if ((p == (const PixelPacket *) NULL) ||
          (GetPixelOpacity(p) != TransparentOpacity) ||
          ((x+i) >= (ssize_t) gap))
        break;
    }
    if ((x+i) < (ssize_t) gap)
      gap=(size_t) (x+i);
  }
  right_view=DestroyCacheView(right_view);
  left_view=DestroyCacheView(left_view);
  if (y < (ssize_t) smush_image->rows)
    return(offset);
  return((ssize_t) gap-offset);
}


void JPXStream::init()
{
  Object oLen, cspace, smaskInData;
  if (getDict()) {
    oLen = getDict()->lookup("Length");
    cspace = getDict()->lookup("ColorSpace");
    smaskInData = getDict()->lookup("SMaskInData");
  }

  int bufSize = BUFFER_INITIAL_SIZE;
  if (oLen.isInt() && oLen.getInt() > 0) bufSize = oLen.getInt();

  bool indexed = false;
  if (cspace.isArray() && cspace.arrayGetLength() > 0) {
    const Object cstype = cspace.arrayGet(0);
    if (cstype.isName("Indexed")) indexed = true;
  }

  priv->smaskInData = 0;
  if (smaskInData.isInt()) priv->smaskInData = smaskInData.getInt();

  int length = 0;
  unsigned char *buf = str->toUnsignedChars(&length, bufSize);
  priv->init2(OPJ_CODEC_JP2, buf, length, indexed);
  gfree(buf);

  if (priv->image) {
    int numComps = (priv->image) ? priv->image->numcomps : 1;
    int alpha = 0;
    if (priv->image) {
      if (priv->image->color_space == OPJ_CLRSPC_SRGB && numComps == 4) { numComps = 3; alpha = 1; }
      else if (priv->image->color_space == OPJ_CLRSPC_SYCC && numComps == 4) { numComps = 3; alpha = 1; }
      else if (numComps == 2) { numComps = 1; alpha = 1; }
      else if (numComps > 4) { numComps = 4; alpha = 1; }
      else { alpha = 0; }
    }
    priv->npixels = priv->image->comps[0].w * priv->image->comps[0].h;
    priv->ncomps = priv->image->numcomps;
    if (alpha == 1 && priv->smaskInData == 0) priv->ncomps--;
    for (int component = 0; component < priv->ncomps; component++) {
      if (priv->image->comps[component].data == nullptr) {
        close();
        break;
      }
      const int componentPixels = priv->image->comps[component].w * priv->image->comps[component].h;
      if (componentPixels != priv->npixels) {
        error(errSyntaxWarning, -1, "Component {0:d} has different WxH than component 0", component);
        close();
        break;
      }
      unsigned char *cdata = (unsigned char *)priv->image->comps[component].data;
      int adjust = 0;
      int depth = priv->image->comps[component].prec;
      if (priv->image->comps[component].prec > 8)
	adjust = priv->image->comps[component].prec - 8;
      int sgndcorr = 0;
      if (priv->image->comps[component].sgnd)
	sgndcorr = 1 << (priv->image->comps[0].prec - 1);
      for (int i = 0; i < priv->npixels; i++) {
	int r = priv->image->comps[component].data[i];
	*(cdata++) = adjustComp(r, adjust, depth, sgndcorr, indexed);
      }
    }
  } else {
    priv->npixels = 0;
  }

  priv->counter = 0;
  priv->ccounter = 0;
  priv->inited = true;
}


move_file (char const *from, bool *from_needs_removal,
	   struct stat const *fromst,
	   char const *to, mode_t mode, bool backup)
{
  struct stat to_st;
  int to_errno;

  to_errno = stat_file (to, &to_st);
  if (backup)
    create_backup (to, to_errno ? NULL : &to_st, false);
  if (! to_errno)
    insert_file_id (&to_st, OVERWRITTEN);

  if (from)
    {
      if (S_ISLNK (mode))
	{
	  bool to_dir_known_to_exist = false;

	  /* FROM contains the contents of the symlink we have patched; need
	     to convert that back into a symlink. */
	  char *buffer = xmalloc (PATH_MAX);
	  int fd, size = 0, i;

	  if ((fd = safe_open (from, O_RDONLY | O_BINARY, 0)) < 0)
	    pfatal ("Can't reopen file %s", quotearg (from));
	  while ((i = read (fd, buffer + size, PATH_MAX - size)) > 0)
	    size += i;
	  if (i != 0 || close (fd) != 0)
	    read_fatal ();
	  buffer[size] = 0;

	  if (! backup)
	    {
	      if (safe_unlink (to) == 0)
		to_dir_known_to_exist = true;
	    }
	  if (safe_symlink (buffer, to) != 0)
	    {
	      if (errno == ENOENT && ! to_dir_known_to_exist)
		makedirs (to);
	      if (safe_symlink (buffer, to) != 0)
		pfatal ("Can't create %s %s", "symbolic link", to);
	    }
	  free (buffer);
	  if (safe_lstat (to, &to_st) != 0)
	    pfatal ("Can't get file attributes of %s %s", "symbolic link", to);
	  insert_file_id (&to_st, CREATED);
	}
      else
	{
	  if (debug & 4)
	    say ("Renaming file %s to %s\n",
		 quotearg_n (0, from), quotearg_n (1, to));

	  if (safe_rename (from, to) != 0)
	    {
	      bool to_dir_known_to_exist = false;

	      if (errno == ENOENT
		  && (to_errno == -1 || to_errno == ENOENT))
		{
		  makedirs (to);
		  to_dir_known_to_exist = true;
		  if (safe_rename (from, to) == 0)
		    goto rename_succeeded;
		}

	      if (errno == EXDEV)
		{
		  struct stat tost;
		  if (! backup)
		    {
		      if (safe_unlink (to) == 0)
			to_dir_known_to_exist = true;
		      else if (errno != ENOENT)
			pfatal ("Can't remove file %s", quotearg (to));
		    }
		  copy_file (from, to, &tost, 0, mode, to_dir_known_to_exist);
		  insert_file_id (&tost, CREATED);
		  return;
		}

	      pfatal ("Can't rename file %s to %s",
		      quotearg_n (0, from), quotearg_n (1, to));
	    }

	rename_succeeded:
	  insert_file_id (fromst, CREATED);
	  /* Do not clear *FROM_NEEDS_REMOVAL if it's possible that the
	     rename returned zero because FROM and TO are hard links to
	     the same file.  */
	  if ((0 < to_errno
	       || (to_errno == 0 && to_st.st_nlink <= 1))
	      && from_needs_removal)
	    *from_needs_removal = false;
	}
    }
  else if (! backup)
    {
      if (debug & 4)
	say ("Removing file %s\n", quotearg (to));
      if (safe_unlink (to) != 0 && errno != ENOENT)
	pfatal ("Can't remove file %s", quotearg (to));
    }
}