Line data Source code
1 : /*
2 : Copyright 2015 Esri
3 :
4 : Licensed under the Apache License, Version 2.0 (the "License");
5 : you may not use this file except in compliance with the License.
6 : You may obtain a copy of the License at
7 :
8 : http://www.apache.org/licenses/LICENSE-2.0
9 :
10 : Unless required by applicable law or agreed to in writing, software
11 : distributed under the License is distributed on an "AS IS" BASIS,
12 : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 : See the License for the specific language governing permissions and
14 : limitations under the License.
15 :
16 : A local copy of the license and additional notices are located with the
17 : source distribution at:
18 :
19 : http://github.com/Esri/lerc/
20 :
21 : Contributors: Thomas Maurer
22 : */
23 :
24 : #include "Defines.h"
25 : #include "Lerc.h"
26 : #include "Lerc2.h"
27 : #include <typeinfo>
28 : #include <limits>
29 :
30 : #ifdef HAVE_LERC1_DECODE
31 : #include "Lerc1Decode/CntZImage.h"
32 : #endif
33 :
34 : using namespace std;
35 : USING_NAMESPACE_LERC
36 :
37 : // -------------------------------------------------------------------------- ;
38 :
39 0 : ErrCode Lerc::ComputeCompressedSize(const void* pData, int version, DataType dt, int nDim, int nCols, int nRows, int nBands,
40 : const BitMask* pBitMask, double maxZErr, unsigned int& numBytesNeeded)
41 : {
42 0 : switch (dt)
43 : {
44 0 : case DT_Char: return ComputeCompressedSizeTempl((const signed char*)pData, version, nDim, nCols, nRows, nBands, pBitMask, maxZErr, numBytesNeeded);
45 0 : case DT_Byte: return ComputeCompressedSizeTempl((const Byte*)pData, version, nDim, nCols, nRows, nBands, pBitMask, maxZErr, numBytesNeeded);
46 0 : case DT_Short: return ComputeCompressedSizeTempl((const short*)pData, version, nDim, nCols, nRows, nBands, pBitMask, maxZErr, numBytesNeeded);
47 0 : case DT_UShort: return ComputeCompressedSizeTempl((const unsigned short*)pData, version, nDim, nCols, nRows, nBands, pBitMask, maxZErr, numBytesNeeded);
48 0 : case DT_Int: return ComputeCompressedSizeTempl((const int*)pData, version, nDim, nCols, nRows, nBands, pBitMask, maxZErr, numBytesNeeded);
49 0 : case DT_UInt: return ComputeCompressedSizeTempl((const unsigned int*)pData, version, nDim, nCols, nRows, nBands, pBitMask, maxZErr, numBytesNeeded);
50 0 : case DT_Float: return ComputeCompressedSizeTempl((const float*)pData, version, nDim, nCols, nRows, nBands, pBitMask, maxZErr, numBytesNeeded);
51 0 : case DT_Double: return ComputeCompressedSizeTempl((const double*)pData, version, nDim, nCols, nRows, nBands, pBitMask, maxZErr, numBytesNeeded);
52 :
53 0 : default:
54 0 : return ErrCode::WrongParam;
55 : }
56 : }
57 :
58 : // -------------------------------------------------------------------------- ;
59 :
60 5181 : ErrCode Lerc::Encode(const void* pData, int version, DataType dt, int nDim, int nCols, int nRows, int nBands,
61 : const BitMask* pBitMask, double maxZErr, Byte* pBuffer, unsigned int numBytesBuffer, unsigned int& numBytesWritten)
62 : {
63 5181 : switch (dt)
64 : {
65 1 : case DT_Char: return EncodeTempl((const signed char*)pData, version, nDim, nCols, nRows, nBands, pBitMask, maxZErr, pBuffer, numBytesBuffer, numBytesWritten);
66 5119 : case DT_Byte: return EncodeTempl((const Byte*)pData, version, nDim, nCols, nRows, nBands, pBitMask, maxZErr, pBuffer, numBytesBuffer, numBytesWritten);
67 2 : case DT_Short: return EncodeTempl((const short*)pData, version, nDim, nCols, nRows, nBands, pBitMask, maxZErr, pBuffer, numBytesBuffer, numBytesWritten);
68 2 : case DT_UShort: return EncodeTempl((const unsigned short*)pData, version, nDim, nCols, nRows, nBands, pBitMask, maxZErr, pBuffer, numBytesBuffer, numBytesWritten);
69 2 : case DT_Int: return EncodeTempl((const int*)pData, version, nDim, nCols, nRows, nBands, pBitMask, maxZErr, pBuffer, numBytesBuffer, numBytesWritten);
70 2 : case DT_UInt: return EncodeTempl((const unsigned int*)pData, version, nDim, nCols, nRows, nBands, pBitMask, maxZErr, pBuffer, numBytesBuffer, numBytesWritten);
71 27 : case DT_Float: return EncodeTempl((const float*)pData, version, nDim, nCols, nRows, nBands, pBitMask, maxZErr, pBuffer, numBytesBuffer, numBytesWritten);
72 26 : case DT_Double: return EncodeTempl((const double*)pData, version, nDim, nCols, nRows, nBands, pBitMask, maxZErr, pBuffer, numBytesBuffer, numBytesWritten);
73 :
74 0 : default:
75 0 : return ErrCode::WrongParam;
76 : }
77 : }
78 :
79 : // -------------------------------------------------------------------------- ;
80 :
81 531 : ErrCode Lerc::GetLercInfo(const Byte* pLercBlob, unsigned int numBytesBlob, struct LercInfo& lercInfo)
82 : {
83 531 : lercInfo.RawInit();
84 :
85 : // first try Lerc2
86 : struct Lerc2::HeaderInfo lerc2Info;
87 531 : if (Lerc2::GetHeaderInfo(pLercBlob, numBytesBlob, lerc2Info))
88 : {
89 531 : lercInfo.version = lerc2Info.version;
90 531 : lercInfo.nDim = lerc2Info.nDim;
91 531 : lercInfo.nCols = lerc2Info.nCols;
92 531 : lercInfo.nRows = lerc2Info.nRows;
93 531 : lercInfo.numValidPixel = lerc2Info.numValidPixel;
94 531 : lercInfo.nBands = 1;
95 531 : lercInfo.blobSize = lerc2Info.blobSize;
96 531 : lercInfo.dt = (DataType)lerc2Info.dt;
97 531 : lercInfo.zMin = lerc2Info.zMin;
98 531 : lercInfo.zMax = lerc2Info.zMax;
99 531 : lercInfo.maxZError = lerc2Info.maxZError;
100 :
101 531 : if (lercInfo.blobSize > (int)numBytesBlob) // truncated blob, we won't be able to read this band
102 0 : return ErrCode::BufferTooSmall;
103 :
104 : struct Lerc2::HeaderInfo hdInfo;
105 531 : while (Lerc2::GetHeaderInfo(pLercBlob + lercInfo.blobSize, numBytesBlob - lercInfo.blobSize, hdInfo))
106 : {
107 0 : if (hdInfo.nDim != lercInfo.nDim
108 0 : || hdInfo.nCols != lercInfo.nCols
109 0 : || hdInfo.nRows != lercInfo.nRows
110 0 : || hdInfo.numValidPixel != lercInfo.numValidPixel
111 0 : || (int)hdInfo.dt != (int)lercInfo.dt)
112 : //|| hdInfo.maxZError != lercInfo.maxZError) // with the new bitplane compression, maxZError can vary between bands
113 : {
114 0 : return ErrCode::Failed;
115 : }
116 :
117 0 : if (lercInfo.blobSize > std::numeric_limits<int>::max() - hdInfo.blobSize)
118 0 : return ErrCode::Failed;
119 :
120 0 : lercInfo.blobSize += hdInfo.blobSize;
121 :
122 0 : if (lercInfo.blobSize > (int)numBytesBlob) // truncated blob, we won't be able to read this band
123 0 : return ErrCode::BufferTooSmall;
124 :
125 0 : lercInfo.nBands++;
126 0 : lercInfo.zMin = min(lercInfo.zMin, hdInfo.zMin);
127 0 : lercInfo.zMax = max(lercInfo.zMax, hdInfo.zMax);
128 0 : lercInfo.maxZError = max(lercInfo.maxZError, hdInfo.maxZError); // with the new bitplane compression, maxZError can vary between bands
129 : }
130 :
131 531 : return ErrCode::Ok;
132 : }
133 :
134 :
135 : #ifdef HAVE_LERC1_DECODE
136 : // only if not Lerc2, try legacy Lerc1
137 : unsigned int numBytesHeaderBand0 = CntZImage::computeNumBytesNeededToReadHeader(false);
138 : unsigned int numBytesHeaderBand1 = CntZImage::computeNumBytesNeededToReadHeader(true);
139 : Byte* pByte = const_cast<Byte*>(pLercBlob);
140 :
141 : lercInfo.zMin = FLT_MAX;
142 : lercInfo.zMax = -FLT_MAX;
143 :
144 : CntZImage cntZImg;
145 : if (numBytesHeaderBand0 <= numBytesBlob && cntZImg.read(&pByte, 1e12, true)) // read just the header
146 : {
147 : size_t nBytesRead = pByte - pLercBlob;
148 : size_t nBytesNeeded = 10 + 4 * sizeof(int) + 1 * sizeof(double);
149 :
150 : if (nBytesRead < nBytesNeeded)
151 : return ErrCode::Failed;
152 :
153 : Byte* ptr = const_cast<Byte*>(pLercBlob);
154 : ptr += 10 + 2 * sizeof(int);
155 :
156 : int height(0), width(0);
157 : memcpy(&height, ptr, sizeof(int)); ptr += sizeof(int);
158 : memcpy(&width, ptr, sizeof(int)); ptr += sizeof(int);
159 : double maxZErrorInFile(0);
160 : memcpy(&maxZErrorInFile, ptr, sizeof(double));
161 :
162 : if (height > 20000 || width > 20000) // guard against bogus numbers; size limitation for old Lerc1
163 : return ErrCode::Failed;
164 :
165 : lercInfo.nDim = 1;
166 : lercInfo.nCols = width;
167 : lercInfo.nRows = height;
168 : lercInfo.dt = Lerc::DT_Float;
169 : lercInfo.maxZError = maxZErrorInFile;
170 :
171 : Byte* pByte = const_cast<Byte*>(pLercBlob);
172 : bool onlyZPart = false;
173 :
174 : while (lercInfo.blobSize + numBytesHeaderBand1 < numBytesBlob) // means there could be another band
175 : {
176 : if (!cntZImg.read(&pByte, 1e12, false, onlyZPart))
177 : return (lercInfo.nBands > 0) ? ErrCode::Ok : ErrCode::Failed; // no other band, we are done
178 :
179 : onlyZPart = true;
180 :
181 : lercInfo.nBands++;
182 : lercInfo.blobSize = (int)(pByte - pLercBlob);
183 :
184 : // now that we have decoded it, we can go the extra mile and collect some extra info
185 : int numValidPixels = 0;
186 : float zMin = FLT_MAX;
187 : float zMax = -FLT_MAX;
188 :
189 : for (int i = 0; i < height; i++)
190 : {
191 : for (int j = 0; j < width; j++)
192 : if (cntZImg(i, j).cnt > 0)
193 : {
194 : numValidPixels++;
195 : float z = cntZImg(i, j).z;
196 : zMax = max(zMax, z);
197 : zMin = min(zMin, z);
198 : }
199 : }
200 :
201 : lercInfo.numValidPixel = numValidPixels;
202 : lercInfo.zMin = std::min(lercInfo.zMin, (double)zMin);
203 : lercInfo.zMax = std::max(lercInfo.zMax, (double)zMax);
204 : }
205 :
206 : return ErrCode::Ok;
207 : }
208 : #endif
209 :
210 0 : return ErrCode::Failed;
211 : }
212 :
213 : // -------------------------------------------------------------------------- ;
214 :
215 2142 : ErrCode Lerc::Decode(const Byte* pLercBlob, unsigned int numBytesBlob, BitMask* pBitMask,
216 : int nDim, int nCols, int nRows, int nBands, DataType dt, void* pData)
217 : {
218 2142 : switch (dt)
219 : {
220 1 : case DT_Char: return DecodeTempl((signed char*)pData, pLercBlob, numBytesBlob, nDim, nCols, nRows, nBands, pBitMask);
221 2082 : case DT_Byte: return DecodeTempl((Byte*)pData, pLercBlob, numBytesBlob, nDim, nCols, nRows, nBands, pBitMask);
222 2 : case DT_Short: return DecodeTempl((short*)pData, pLercBlob, numBytesBlob, nDim, nCols, nRows, nBands, pBitMask);
223 2 : case DT_UShort: return DecodeTempl((unsigned short*)pData, pLercBlob, numBytesBlob, nDim, nCols, nRows, nBands, pBitMask);
224 2 : case DT_Int: return DecodeTempl((int*)pData, pLercBlob, numBytesBlob, nDim, nCols, nRows, nBands, pBitMask);
225 2 : case DT_UInt: return DecodeTempl((unsigned int*)pData, pLercBlob, numBytesBlob, nDim, nCols, nRows, nBands, pBitMask);
226 25 : case DT_Float: return DecodeTempl((float*)pData, pLercBlob, numBytesBlob, nDim, nCols, nRows, nBands, pBitMask);
227 26 : case DT_Double: return DecodeTempl((double*)pData, pLercBlob, numBytesBlob, nDim, nCols, nRows, nBands, pBitMask);
228 :
229 0 : default:
230 0 : return ErrCode::WrongParam;
231 : }
232 : }
233 :
234 : // -------------------------------------------------------------------------- ;
235 :
236 0 : ErrCode Lerc::ConvertToDouble(const void* pDataIn, DataType dt, size_t nDataValues, double* pDataOut)
237 : {
238 0 : switch (dt)
239 : {
240 0 : case DT_Char: return ConvertToDoubleTempl((const signed char*)pDataIn, nDataValues, pDataOut);
241 0 : case DT_Byte: return ConvertToDoubleTempl((const Byte*)pDataIn, nDataValues, pDataOut);
242 0 : case DT_Short: return ConvertToDoubleTempl((const short*)pDataIn, nDataValues, pDataOut);
243 0 : case DT_UShort: return ConvertToDoubleTempl((const unsigned short*)pDataIn, nDataValues, pDataOut);
244 0 : case DT_Int: return ConvertToDoubleTempl((const int*)pDataIn, nDataValues, pDataOut);
245 0 : case DT_UInt: return ConvertToDoubleTempl((const unsigned int*)pDataIn, nDataValues, pDataOut);
246 0 : case DT_Float: return ConvertToDoubleTempl((const float*)pDataIn, nDataValues, pDataOut);
247 : //case DT_Double: no convert double to double
248 :
249 0 : default:
250 0 : return ErrCode::WrongParam;
251 : }
252 : }
253 :
254 : // -------------------------------------------------------------------------- ;
255 : // -------------------------------------------------------------------------- ;
256 :
257 : template<class T>
258 0 : ErrCode Lerc::ComputeCompressedSizeTempl(const T* pData, int version, int nDim, int nCols, int nRows, int nBands,
259 : const BitMask* pBitMask, double maxZErr, unsigned int& numBytesNeeded)
260 : {
261 0 : numBytesNeeded = 0;
262 :
263 0 : if (!pData || nDim <= 0 || nCols <= 0 || nRows <= 0 || nBands <= 0 || maxZErr < 0)
264 0 : return ErrCode::WrongParam;
265 :
266 0 : if (pBitMask && (pBitMask->GetHeight() != nRows || pBitMask->GetWidth() != nCols))
267 0 : return ErrCode::WrongParam;
268 :
269 0 : Lerc2 lerc2;
270 0 : if (version >= 0 && !lerc2.SetEncoderToOldVersion(version))
271 0 : return ErrCode::WrongParam;
272 :
273 0 : bool rv = pBitMask ? lerc2.Set(nDim, nCols, nRows, pBitMask->Bits()) : lerc2.Set(nDim, nCols, nRows);
274 0 : if (!rv)
275 0 : return ErrCode::Failed;
276 :
277 : // loop over the bands
278 0 : for (int iBand = 0; iBand < nBands; iBand++)
279 : {
280 0 : bool encMsk = (iBand == 0); // store bit mask with first band only
281 0 : const T* arr = pData + nDim * nCols * nRows * iBand;
282 :
283 0 : ErrCode errCode = CheckForNaN(arr, nDim, nCols, nRows, pBitMask);
284 0 : if (errCode != ErrCode::Ok)
285 0 : return errCode;
286 :
287 0 : unsigned int nBytes = lerc2.ComputeNumBytesNeededToWrite(arr, maxZErr, encMsk);
288 0 : if (nBytes <= 0)
289 0 : return ErrCode::Failed;
290 :
291 0 : numBytesNeeded += nBytes;
292 : }
293 :
294 0 : return ErrCode::Ok;
295 : }
296 :
297 : // -------------------------------------------------------------------------- ;
298 :
299 : template<class T>
300 5181 : ErrCode Lerc::EncodeTempl(const T* pData, int version, int nDim, int nCols, int nRows, int nBands,
301 : const BitMask* pBitMask, double maxZErr, Byte* pBuffer, unsigned int numBytesBuffer, unsigned int& numBytesWritten)
302 : {
303 5181 : numBytesWritten = 0;
304 :
305 5181 : if (!pData || nDim <= 0 || nCols <= 0 || nRows <= 0 || nBands <= 0 || maxZErr < 0 || !pBuffer || !numBytesBuffer)
306 0 : return ErrCode::WrongParam;
307 :
308 5181 : if (pBitMask && (pBitMask->GetHeight() != nRows || pBitMask->GetWidth() != nCols))
309 0 : return ErrCode::WrongParam;
310 :
311 10362 : Lerc2 lerc2;
312 5181 : if (version >= 0 && !lerc2.SetEncoderToOldVersion(version))
313 0 : return ErrCode::WrongParam;
314 :
315 5181 : bool rv = pBitMask ? lerc2.Set(nDim, nCols, nRows, pBitMask->Bits()) : lerc2.Set(nDim, nCols, nRows);
316 5181 : if (!rv)
317 0 : return ErrCode::Failed;
318 :
319 5181 : Byte* pByte = pBuffer;
320 :
321 : // loop over the bands, encode into array of single band Lerc blobs
322 10361 : for (int iBand = 0; iBand < nBands; iBand++)
323 : {
324 5181 : bool encMsk = (iBand == 0); // store bit mask with first band only
325 5181 : const T* arr = pData + nDim * nCols * nRows * iBand;
326 :
327 5181 : ErrCode errCode = CheckForNaN(arr, nDim, nCols, nRows, pBitMask);
328 5181 : if (errCode != ErrCode::Ok)
329 0 : return errCode;
330 :
331 5181 : unsigned int nBytes = lerc2.ComputeNumBytesNeededToWrite(arr, maxZErr, encMsk);
332 5181 : if (nBytes == 0)
333 0 : return ErrCode::Failed;
334 :
335 5181 : unsigned int nBytesAlloc = nBytes;
336 :
337 5181 : if ((size_t)(pByte - pBuffer) + nBytesAlloc > numBytesBuffer) // check we have enough space left
338 0 : return ErrCode::BufferTooSmall;
339 :
340 5181 : if (!lerc2.Encode(arr, &pByte))
341 1 : return ErrCode::Failed;
342 : }
343 :
344 5180 : numBytesWritten = (unsigned int)(pByte - pBuffer);
345 5180 : return ErrCode::Ok;
346 : }
347 :
348 : // -------------------------------------------------------------------------- ;
349 :
350 : template<class T>
351 2142 : ErrCode Lerc::DecodeTempl(T* pData, const Byte* pLercBlob, unsigned int numBytesBlob,
352 : int nDim, int nCols, int nRows, int nBands, BitMask* pBitMask)
353 : {
354 2142 : if (!pData || nDim <= 0 || nCols <= 0 || nRows <= 0 || nBands <= 0 || !pLercBlob || !numBytesBlob)
355 0 : return ErrCode::WrongParam;
356 :
357 2142 : if (pBitMask && (pBitMask->GetHeight() != nRows || pBitMask->GetWidth() != nCols))
358 0 : return ErrCode::WrongParam;
359 :
360 2142 : const Byte* pByte = pLercBlob;
361 : #ifdef HAVE_LERC1_DECODE
362 : Byte* pByte1 = const_cast<Byte*>(pLercBlob);
363 : #endif
364 : Lerc2::HeaderInfo hdInfo;
365 :
366 2142 : if (Lerc2::GetHeaderInfo(pByte, numBytesBlob, hdInfo) && hdInfo.version >= 1) // is Lerc2
367 : {
368 2142 : size_t nBytesRemaining = numBytesBlob;
369 2142 : Lerc2 lerc2;
370 :
371 4284 : for (int iBand = 0; iBand < nBands; iBand++)
372 : {
373 2142 : if (((size_t)(pByte - pLercBlob) < numBytesBlob) && Lerc2::GetHeaderInfo(pByte, nBytesRemaining, hdInfo))
374 : {
375 2142 : if (hdInfo.nDim != nDim || hdInfo.nCols != nCols || hdInfo.nRows != nRows)
376 0 : return ErrCode::Failed;
377 :
378 2142 : if ((pByte - pLercBlob) + (size_t)hdInfo.blobSize > numBytesBlob)
379 0 : return ErrCode::BufferTooSmall;
380 :
381 2142 : T* arr = pData + nDim * nCols * nRows * iBand;
382 :
383 2142 : if (!lerc2.Decode(&pByte, nBytesRemaining, arr, (pBitMask && iBand == 0) ? pBitMask->Bits() : nullptr))
384 0 : return ErrCode::Failed;
385 : }
386 : }
387 : }
388 :
389 : else // might be old Lerc1
390 : {
391 : #ifdef HAVE_LERC1_DECODE
392 : unsigned int numBytesHeaderBand0 = CntZImage::computeNumBytesNeededToReadHeader(false);
393 : unsigned int numBytesHeaderBand1 = CntZImage::computeNumBytesNeededToReadHeader(true);
394 : CntZImage zImg;
395 :
396 : for (int iBand = 0; iBand < nBands; iBand++)
397 : {
398 : unsigned int numBytesHeader = iBand == 0 ? numBytesHeaderBand0 : numBytesHeaderBand1;
399 : if ((size_t)(pByte - pLercBlob) + numBytesHeader > numBytesBlob)
400 : return ErrCode::BufferTooSmall;
401 :
402 : bool onlyZPart = iBand > 0;
403 : if (!zImg.read(&pByte1, 1e12, false, onlyZPart))
404 : return ErrCode::Failed;
405 :
406 : if (zImg.getWidth() != nCols || zImg.getHeight() != nRows)
407 : return ErrCode::Failed;
408 :
409 : T* arr = pData + nCols * nRows * iBand;
410 :
411 : if (!Convert(zImg, arr, pBitMask))
412 : return ErrCode::Failed;
413 : }
414 : #else
415 0 : return ErrCode::Failed;
416 : #endif
417 : }
418 :
419 2142 : return ErrCode::Ok;
420 : }
421 :
422 : // -------------------------------------------------------------------------- ;
423 : // -------------------------------------------------------------------------- ;
424 :
425 : #ifdef HAVE_LERC1_DECODE
426 : template<class T>
427 : bool Lerc::Convert(const CntZImage& zImg, T* arr, BitMask* pBitMask)
428 : {
429 : if (!arr || !zImg.getSize())
430 : return false;
431 :
432 : const bool fltPnt = (typeid(*arr) == typeid(double)) || (typeid(*arr) == typeid(float));
433 :
434 : int h = zImg.getHeight();
435 : int w = zImg.getWidth();
436 :
437 : if (pBitMask && (pBitMask->GetHeight() != h || pBitMask->GetWidth() != w))
438 : return false;
439 :
440 : if (pBitMask)
441 : pBitMask->SetAllValid();
442 :
443 : const CntZ* srcPtr = zImg.getData();
444 : T* dstPtr = arr;
445 : int num = w * h;
446 : for (int k = 0; k < num; k++)
447 : {
448 : if (srcPtr->cnt > 0)
449 : *dstPtr = fltPnt ? (T)srcPtr->z : (T)floor(srcPtr->z + 0.5);
450 : else if (pBitMask)
451 : pBitMask->SetInvalid(k);
452 :
453 : srcPtr++;
454 : dstPtr++;
455 : }
456 :
457 : return true;
458 : }
459 : #endif
460 :
461 : // -------------------------------------------------------------------------- ;
462 :
463 : template<class T>
464 0 : ErrCode Lerc::ConvertToDoubleTempl(const T* pDataIn, size_t nDataValues, double* pDataOut)
465 : {
466 0 : if (!pDataIn || !nDataValues || !pDataOut)
467 0 : return ErrCode::WrongParam;
468 :
469 0 : for (size_t k = 0; k < nDataValues; k++)
470 0 : pDataOut[k] = pDataIn[k];
471 :
472 0 : return ErrCode::Ok;
473 : }
474 :
475 : // -------------------------------------------------------------------------- ;
476 :
477 5181 : template<class T> ErrCode Lerc::CheckForNaN(const T* arr, int nDim, int nCols, int nRows, const BitMask* pBitMask)
478 : {
479 5181 : if (!arr || nDim <= 0 || nCols <= 0 || nRows <= 0)
480 0 : return ErrCode::WrongParam;
481 :
482 : #ifdef CHECK_FOR_NAN
483 :
484 5181 : if (typeid(T) == typeid(double) || typeid(T) == typeid(float))
485 : {
486 53 : bool foundNaN = false;
487 :
488 1899 : for (int k = 0, i = 0; i < nRows; i++)
489 : {
490 1846 : const T* rowArr = &(arr[i * nCols * nDim]);
491 :
492 1846 : if (!pBitMask) // all valid
493 : {
494 817184 : for (int n = 0, j = 0; j < nCols; j++, n += nDim)
495 4115020 : for (int m = 0; m < nDim; m++)
496 3299668 : if (std::isnan((double)rowArr[n + m]))
497 0 : foundNaN = true;
498 : }
499 : else // not all valid
500 : {
501 1228 : for (int n = 0, j = 0; j < nCols; j++, k++, n += nDim)
502 1212 : if (pBitMask->IsValid(k))
503 : {
504 808 : for (int m = 0; m < nDim; m++)
505 404 : if (std::isnan((double)rowArr[n + m]))
506 0 : foundNaN = true;
507 : }
508 : }
509 :
510 1846 : if (foundNaN)
511 0 : return ErrCode::NaN;
512 : }
513 : }
514 :
515 : #endif
516 :
517 5181 : return ErrCode::Ok;
518 : }
519 :
520 : // -------------------------------------------------------------------------- ;
521 :
|