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; }