static CPLErr DecompressLERC(buf_mgr &dst, buf_mgr &src, const ILImage &img) { CntZImage zImg; Byte *ptr = (Byte *)src.buffer; if (!zImg.read(&ptr, 1e12)) { CPLError(CE_Failure,CPLE_AppDefined,"MRF: Error during LERC decompression"); return CE_Failure; } // Unpack from zImg to dst buffer, calling the right type #define UFILL(T) CntZImgUFill(zImg, (T *)(dst.buffer), img) switch (img.dt) { case GDT_Byte: UFILL(GByte); break; case GDT_UInt16: UFILL(GUInt16); break; case GDT_Int16: UFILL(GInt16); break; case GDT_Int32: UFILL(GInt32); break; case GDT_UInt32: UFILL(GUInt32); break; case GDT_Float32: UFILL(float); break; case GDT_Float64: UFILL(double); break; default: break; } #undef UFILL return CE_None; }
bool Lerc::DecodeTempl(T* pData, // outgoing data bands const Byte* pLercBlob, size_t numBytesBlob, int nCols, int nRows, int nBands, BitMask* pBitMask) const // gets filled if not 0, even if all valid { if (!pLercBlob || !pData) return false; const Byte* pByte = pLercBlob; Byte* pByte1 = const_cast<Byte*>(pLercBlob); Lerc2 lerc2; CntZImage zImg; for (int iBand = 0; iBand < nBands; iBand++) { // first try Lerc2 unsigned int numBytesHeader = lerc2.ComputeNumBytesHeader(); Lerc2::HeaderInfo hdInfo; if (((size_t)(pByte - pLercBlob) + numBytesHeader <= numBytesBlob) && lerc2.GetHeaderInfo(pByte, hdInfo)) { if (hdInfo.nCols != nCols || hdInfo.nRows != nRows) return false; if ((pByte - pLercBlob) + (size_t)hdInfo.blobSize > numBytesBlob) return false; // init bitMask if (pBitMask && iBand == 0) pBitMask->SetSize(nCols, nRows); T* arr = pData + nCols * nRows * iBand; if (!lerc2.Decode(&pByte, arr, (pBitMask && iBand == 0) ? pBitMask->Bits() : 0)) return false; } else // then try Lerc1 { unsigned int numBytesHeader = CntZImage::computeNumBytesNeededToReadHeader(); if ((size_t)(pByte - pLercBlob) + numBytesHeader > numBytesBlob) return false; bool onlyZPart = iBand > 0; if (!zImg.read(&pByte1, 1e12, false, onlyZPart)) return false; if (zImg.getWidth() != nCols || zImg.getHeight() != nRows) return false; T* arr = pData + nCols * nRows * iBand; if (!Convert(zImg, arr, pBitMask)) return false; } } // iBand return true; }
bool Lerc::GetLercInfo(const Byte* pLercBlob, size_t numBytesBlob, struct LercInfo& lercInfo) const { lercInfo.RawInit(); // first try Lerc2 Lerc2 lerc2; unsigned int numBytesHeader = lerc2.ComputeNumBytesHeader(); struct Lerc2::HeaderInfo lerc2Info; if (numBytesHeader <= numBytesBlob && lerc2.GetHeaderInfo(pLercBlob, lerc2Info)) { lercInfo.version = lerc2Info.version; lercInfo.nCols = lerc2Info.nCols; lercInfo.nRows = lerc2Info.nRows; lercInfo.numValidPixel = lerc2Info.numValidPixel; lercInfo.nBands = 1; lercInfo.blobSize = lerc2Info.blobSize; lercInfo.dt = (DataType)lerc2Info.dt; lercInfo.zMin = lerc2Info.zMin; lercInfo.zMax = lerc2Info.zMax; lercInfo.maxZError = lerc2Info.maxZError; if (lercInfo.blobSize > (int)numBytesBlob) // truncated blob, we won't be able to read this band return false; while (lercInfo.blobSize + numBytesHeader < numBytesBlob) // means there could be another band { struct Lerc2::HeaderInfo hdInfo; if (!lerc2.GetHeaderInfo(pLercBlob + lercInfo.blobSize, hdInfo)) return true; // no other band, we are done if (hdInfo.nCols != lercInfo.nCols || hdInfo.nRows != lercInfo.nRows || hdInfo.numValidPixel != lercInfo.numValidPixel || (int)hdInfo.dt != (int)lercInfo.dt || hdInfo.maxZError != lercInfo.maxZError) { return false; } lercInfo.blobSize += hdInfo.blobSize; if (lercInfo.blobSize > (int)numBytesBlob) // truncated blob, we won't be able to read this band return false; lercInfo.nBands++; lercInfo.zMin = min(lercInfo.zMin, hdInfo.zMin); lercInfo.zMax = max(lercInfo.zMax, hdInfo.zMax); } return true; } // then try Lerc1 numBytesHeader = CntZImage::computeNumBytesNeededToReadHeader(); Byte* pByte = const_cast<Byte*>(pLercBlob); CntZImage cntZImg; if (numBytesHeader <= numBytesBlob && cntZImg.read(&pByte, 1e12, true)) // read just the header { size_t nBytesRead = pByte - pLercBlob; size_t nBytesNeeded = 10 + 4 * sizeof(int) + 1 * sizeof(double); if (nBytesRead < nBytesNeeded) return false; Byte* ptr = const_cast<Byte*>(pLercBlob); ptr += 10 + 2 * sizeof(int); int height = *((const int*)ptr); ptr += sizeof(int); int width = *((const int*)ptr); ptr += sizeof(int); double maxZErrorInFile = *((const double*)ptr); if (height > 20000 || width > 20000) // guard against bogus numbers return false; lercInfo.nCols = width; lercInfo.nRows = height; lercInfo.dt = Lerc::DT_Float; lercInfo.maxZError = maxZErrorInFile; Byte* pByte = const_cast<Byte*>(pLercBlob); bool onlyZPart = false; while (lercInfo.blobSize + numBytesHeader < numBytesBlob) // means there could be another band { if (!cntZImg.read(&pByte, 1e12, false, onlyZPart)) return (lercInfo.nBands > 0); // no other band, we are done onlyZPart = true; lercInfo.nBands++; lercInfo.blobSize = (int)(pByte - pLercBlob); // now that we have decoded it, we can go the extra mile and collect some extra info int numValidPixels = 0; float zMin = FLT_MAX; float zMax = -FLT_MAX; for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) if (cntZImg(i, j).cnt > 0) { numValidPixels++; float z = cntZImg(i, j).z; zMax = max(zMax, z); zMin = min(zMin, z); } } lercInfo.numValidPixel = numValidPixels; lercInfo.zMin = min(lercInfo.zMin, zMin); lercInfo.zMax = max(lercInfo.zMax, zMax); } return true; } return false; }