Пример #1
0
CPLErr GDALMRFRasterBand::IWriteBlock(int xblk, int yblk, void *buffer)

{
    GInt32 cstride = img.pagesize.c;
    ILSize req(xblk, yblk, 0, (nBand-1)/cstride, m_l);
    GUIntBig infooffset = IdxOffset(req, img);

    CPLDebug("MRF_IB", "IWriteBlock %d,%d,0,%d, level  %d, stride %d\n", xblk, yblk,
        nBand, m_l, cstride);

    // Finish the Create call
    if (!poDS->bCrystalized)
        poDS->Crystalize();

    if (1 == cstride) {     // Separate bands, we can write it as is
        // Empty page skip

        int success;
        double val = GetNoDataValue(&success);
        if (!success) val = 0.0;
        if (isAllVal(eDataType, buffer, img.pageSizeBytes, val))
            return poDS->WriteTile(nullptr, infooffset, 0);

        // Use the pbuffer to hold the compressed page before writing it
        poDS->tile = ILSize(); // Mark it corrupt

        buf_mgr src;
        src.buffer = (char *)buffer;
        src.size = static_cast<size_t>(img.pageSizeBytes);
        buf_mgr dst = {(char *)poDS->GetPBuffer(), poDS->GetPBufferSize()};

        // Swab the source before encoding if we need to
        if (is_Endianess_Dependent(img.dt, img.comp) && (img.nbo != NET_ORDER))
            swab_buff(src, img);

        // Compress functions need to return the compressed size in
        // the bytes in buffer field
        Compress(dst, src);
        void *usebuff = dst.buffer;
        if (deflatep) {
            usebuff = DeflateBlock(dst, poDS->pbsize - dst.size, deflate_flags);
            if (!usebuff) {
                CPLError(CE_Failure,CPLE_AppDefined, "MRF: Deflate error");
                return CE_Failure;
            }
        }
        return poDS->WriteTile(usebuff, infooffset , dst.size);
    }

    // Multiple bands per page, use a temporary to assemble the page
    // Temporary is large because we use it to hold both the uncompressed and the compressed
    poDS->tile=req; poDS->bdirty=0;

    // Keep track of what bands are empty
    GUIntBig empties=0;

    void *tbuffer = VSIMalloc(img.pageSizeBytes + poDS->pbsize);

    if (!tbuffer) {
        CPLError(CE_Failure,CPLE_AppDefined, "MRF: Can't allocate write buffer");
        return CE_Failure;
    }

    // Get the other bands from the block cache
    for (int iBand=0; iBand < poDS->nBands; iBand++ )
    {
        char *pabyThisImage = nullptr;
        GDALRasterBlock *poBlock = nullptr;

        if (iBand == nBand-1)
        {
            pabyThisImage = reinterpret_cast<char *>(buffer);
            poDS->bdirty |= bandbit();
        } else {
            GDALRasterBand *band = poDS->GetRasterBand(iBand +1);
            // Pick the right overview
            if (m_l) band = band->GetOverview(m_l -1);
            poBlock = (reinterpret_cast<GDALMRFRasterBand *>(band))->TryGetLockedBlockRef(xblk, yblk);
            if (nullptr==poBlock) continue;
            // This is where the image data is for this band

            pabyThisImage = reinterpret_cast<char*>(poBlock->GetDataRef());
            poDS->bdirty |= bandbit(iBand);
        }

        // Keep track of empty bands, but encode them anyhow, in case some are not empty
        int success;
        double val = GetNoDataValue(&success);
        if (!success) val = 0.0;
        if (isAllVal(eDataType, pabyThisImage, blockSizeBytes(), val))
            empties |= bandbit(iBand);

        // Copy the data into the dataset buffer here
        // Just the right mix of templates and macros make this real tidy
#define CpySO(T) cpy_stride_out<T> ((reinterpret_cast<T *>(tbuffer))+iBand, pabyThisImage,\
                blockSizeBytes()/sizeof(T), cstride)

        // Build the page in tbuffer
        switch (GDALGetDataTypeSize(eDataType)/8)
        {
            case 1: CpySO(GByte); break;
            case 2: CpySO(GInt16); break;
            case 4: CpySO(GInt32); break;
            case 8: CpySO(GIntBig); break;
            default:
            {
                CPLError(CE_Failure,CPLE_AppDefined, "MRF: Write datatype of %d bytes "
                        "not implemented", GDALGetDataTypeSize(eDataType)/8);
                if (poBlock != nullptr)
                {
                    poBlock->MarkClean();
                    poBlock->DropLock();
                }
                CPLFree(tbuffer);
                return CE_Failure;
            }
        }

        if (poBlock != nullptr)
        {
            poBlock->MarkClean();
            poBlock->DropLock();
        }
    }

    // Should keep track of the individual band buffers and only mix them if this is not
    // an empty page ( move the Copy with Stride Out from above below this test
    // This way works fine, but it does work extra for empty pages

    if (GIntBig(empties) == AllBandMask()) {
        CPLFree(tbuffer);
        return poDS->WriteTile(nullptr, infooffset, 0);
    }

    if (poDS->bdirty != AllBandMask())
        CPLError(CE_Warning, CPLE_AppDefined,
        "MRF: IWrite, band dirty mask is " CPL_FRMT_GIB " instead of " CPL_FRMT_GIB,
        poDS->bdirty, AllBandMask());

    buf_mgr src;
    src.buffer = (char *)tbuffer;
    src.size = static_cast<size_t>(img.pageSizeBytes);

    // Use the space after pagesizebytes for compressed output, it is of pbsize
    char *outbuff = (char *)tbuffer + img.pageSizeBytes;

    buf_mgr dst = {outbuff, poDS->pbsize};
    CPLErr ret;

    ret = Compress(dst, src);
    if (ret != CE_None) {
        // Compress failed, write it as an empty tile
        CPLFree(tbuffer);
        poDS->WriteTile(nullptr, infooffset, 0);
        return CE_None; // Should report the error, but it triggers partial band attempts
    }

    // Where the output is, in case we deflate
    void *usebuff = outbuff;
    if (deflatep) {
        // Move the packed part at the start of tbuffer, to make more space available
        memcpy(tbuffer, outbuff, dst.size);
        dst.buffer = (char *)tbuffer;
        usebuff = DeflateBlock(dst, img.pageSizeBytes + poDS->pbsize - dst.size, deflate_flags);
        if (!usebuff) {
            CPLError(CE_Failure,CPLE_AppDefined, "MRF: Deflate error");
            CPLFree(tbuffer);
            poDS->WriteTile(nullptr, infooffset, 0);
            poDS->bdirty = 0;
            return CE_Failure;
        }
    }

    ret = poDS->WriteTile(usebuff, infooffset, dst.size);
    CPLFree(tbuffer);

    poDS->bdirty = 0;
    return ret;
}