Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: Arc/Info Binary Grid Translator
4 : * Purpose: Grid file reading code.
5 : * Author: Frank Warmerdam, warmerdam@pobox.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 1999, Frank Warmerdam
9 : * Copyright (c) 2007-2010, Even Rouault <even dot rouault at spatialys.com>
10 : *
11 : * SPDX-License-Identifier: MIT
12 : ****************************************************************************/
13 :
14 : #include "aigrid.h"
15 :
16 : #ifndef CPL_IGNORE_RET_VAL_INT_defined
17 : #define CPL_IGNORE_RET_VAL_INT_defined
18 :
19 30 : CPL_INLINE static void CPL_IGNORE_RET_VAL_INT(CPL_UNUSED int unused)
20 : {
21 30 : }
22 : #endif
23 :
24 : /************************************************************************/
25 : /* AIGProcessRaw32bitFloatBlock() */
26 : /* */
27 : /* Process a block using ``00'' (32 bit) raw format. */
28 : /************************************************************************/
29 :
30 0 : static CPLErr AIGProcessRaw32BitFloatBlock(GByte *pabyCur, int nDataSize,
31 : int nMin, int nBlockXSize,
32 : int nBlockYSize, float *pafData)
33 :
34 : {
35 : int i;
36 :
37 : (void)nMin;
38 0 : if (nDataSize < nBlockXSize * nBlockYSize * 4)
39 : {
40 0 : CPLError(CE_Failure, CPLE_AppDefined, "Block too small");
41 0 : return CE_Failure;
42 : }
43 :
44 : /* -------------------------------------------------------------------- */
45 : /* Collect raw data. */
46 : /* -------------------------------------------------------------------- */
47 0 : for (i = 0; i < nBlockXSize * nBlockYSize; i++)
48 : {
49 : float fWork;
50 :
51 : #ifdef CPL_LSB
52 0 : ((GByte *)&fWork)[3] = *(pabyCur++);
53 0 : ((GByte *)&fWork)[2] = *(pabyCur++);
54 0 : ((GByte *)&fWork)[1] = *(pabyCur++);
55 0 : ((GByte *)&fWork)[0] = *(pabyCur++);
56 : #else
57 : ((GByte *)&fWork)[0] = *(pabyCur++);
58 : ((GByte *)&fWork)[1] = *(pabyCur++);
59 : ((GByte *)&fWork)[2] = *(pabyCur++);
60 : ((GByte *)&fWork)[3] = *(pabyCur++);
61 : #endif
62 :
63 0 : pafData[i] = fWork;
64 : }
65 :
66 0 : return (CE_None);
67 : }
68 :
69 : /************************************************************************/
70 : /* AIGProcessIntConstBlock() */
71 : /* */
72 : /* Process a block using ``00'' constant 32bit integer format. */
73 : /************************************************************************/
74 :
75 0 : static CPLErr AIGProcessIntConstBlock(GByte *pabyCur, int nDataSize, int nMin,
76 : int nBlockXSize, int nBlockYSize,
77 : GInt32 *panData)
78 :
79 : {
80 : int i;
81 :
82 : (void)pabyCur;
83 : (void)nDataSize;
84 :
85 : /* -------------------------------------------------------------------- */
86 : /* Apply constant min value. */
87 : /* -------------------------------------------------------------------- */
88 0 : for (i = 0; i < nBlockXSize * nBlockYSize; i++)
89 0 : panData[i] = nMin;
90 :
91 0 : return (CE_None);
92 : }
93 :
94 : /************************************************************************/
95 : /* AIGRolloverSignedAdd() */
96 : /************************************************************************/
97 :
98 : CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW
99 6 : static GInt32 AIGRolloverSignedAdd(GInt32 a, GInt32 b)
100 : {
101 : // Not really portable as assumes complement to 2 representation
102 : // but AIG assumes typical unsigned rollover on signed
103 : // integer operations.
104 : GInt32 res;
105 6 : GUInt32 resUnsigned = (GUInt32)(a) + (GUInt32)(b);
106 6 : memcpy(&res, &resUnsigned, sizeof(res));
107 6 : return res;
108 : }
109 :
110 : /************************************************************************/
111 : /* AIGProcess32bitRawBlock() */
112 : /* */
113 : /* Process a block using ``20'' (thirty two bit) raw format. */
114 : /************************************************************************/
115 :
116 0 : static CPLErr AIGProcessRaw32BitBlock(GByte *pabyCur, int nDataSize, int nMin,
117 : int nBlockXSize, int nBlockYSize,
118 : GInt32 *panData)
119 :
120 : {
121 : int i;
122 :
123 0 : if (nDataSize < nBlockXSize * nBlockYSize * 4)
124 : {
125 0 : CPLError(CE_Failure, CPLE_AppDefined, "Block too small");
126 0 : return CE_Failure;
127 : }
128 :
129 : /* -------------------------------------------------------------------- */
130 : /* Collect raw data. */
131 : /* -------------------------------------------------------------------- */
132 0 : for (i = 0; i < nBlockXSize * nBlockYSize; i++)
133 : {
134 0 : memcpy(panData + i, pabyCur, 4);
135 0 : panData[i] = CPL_MSBWORD32(panData[i]);
136 0 : panData[i] = AIGRolloverSignedAdd(panData[i], nMin);
137 0 : pabyCur += 4;
138 : }
139 :
140 0 : return (CE_None);
141 : }
142 :
143 : /************************************************************************/
144 : /* AIGProcess16bitRawBlock() */
145 : /* */
146 : /* Process a block using ``10'' (sixteen bit) raw format. */
147 : /************************************************************************/
148 :
149 0 : static CPLErr AIGProcessRaw16BitBlock(GByte *pabyCur, int nDataSize, int nMin,
150 : int nBlockXSize, int nBlockYSize,
151 : GInt32 *panData)
152 :
153 : {
154 : int i;
155 :
156 0 : if (nDataSize < nBlockXSize * nBlockYSize * 2)
157 : {
158 0 : CPLError(CE_Failure, CPLE_AppDefined, "Block too small");
159 0 : return CE_Failure;
160 : }
161 :
162 : /* -------------------------------------------------------------------- */
163 : /* Collect raw data. */
164 : /* -------------------------------------------------------------------- */
165 0 : for (i = 0; i < nBlockXSize * nBlockYSize; i++)
166 : {
167 0 : panData[i] = AIGRolloverSignedAdd(pabyCur[0] * 256 + pabyCur[1], nMin);
168 0 : pabyCur += 2;
169 : }
170 :
171 0 : return (CE_None);
172 : }
173 :
174 : /************************************************************************/
175 : /* AIGProcess4BitRawBlock() */
176 : /* */
177 : /* Process a block using ``08'' raw format. */
178 : /************************************************************************/
179 :
180 0 : static CPLErr AIGProcessRaw4BitBlock(GByte *pabyCur, int nDataSize, int nMin,
181 : int nBlockXSize, int nBlockYSize,
182 : GInt32 *panData)
183 :
184 : {
185 : int i;
186 :
187 0 : if (nDataSize < (nBlockXSize * nBlockYSize + 1) / 2)
188 : {
189 0 : CPLError(CE_Failure, CPLE_AppDefined, "Block too small");
190 0 : return CE_Failure;
191 : }
192 :
193 : /* -------------------------------------------------------------------- */
194 : /* Collect raw data. */
195 : /* -------------------------------------------------------------------- */
196 0 : for (i = 0; i < nBlockXSize * nBlockYSize; i++)
197 : {
198 0 : if (i % 2 == 0)
199 0 : panData[i] = AIGRolloverSignedAdd((*(pabyCur)&0xf0) >> 4, nMin);
200 : else
201 0 : panData[i] = AIGRolloverSignedAdd(*(pabyCur++) & 0xf, nMin);
202 : }
203 :
204 0 : return (CE_None);
205 : }
206 :
207 : /************************************************************************/
208 : /* AIGProcess1BitRawBlock() */
209 : /* */
210 : /* Process a block using ``0x01'' raw format. */
211 : /************************************************************************/
212 :
213 0 : static CPLErr AIGProcessRaw1BitBlock(GByte *pabyCur, int nDataSize, int nMin,
214 : int nBlockXSize, int nBlockYSize,
215 : GInt32 *panData)
216 :
217 : {
218 : int i;
219 :
220 0 : if (nDataSize < (nBlockXSize * nBlockYSize + 7) / 8)
221 : {
222 0 : CPLError(CE_Failure, CPLE_AppDefined, "Block too small");
223 0 : return CE_Failure;
224 : }
225 :
226 : /* -------------------------------------------------------------------- */
227 : /* Collect raw data. */
228 : /* -------------------------------------------------------------------- */
229 0 : for (i = 0; i < nBlockXSize * nBlockYSize; i++)
230 : {
231 0 : if (pabyCur[i >> 3] & (0x80 >> (i & 0x7)))
232 0 : panData[i] = AIGRolloverSignedAdd(1, nMin);
233 : else
234 0 : panData[i] = 0 + nMin;
235 : }
236 :
237 0 : return (CE_None);
238 : }
239 :
240 : /************************************************************************/
241 : /* AIGProcessRawBlock() */
242 : /* */
243 : /* Process a block using ``08'' raw format. */
244 : /************************************************************************/
245 :
246 0 : static CPLErr AIGProcessRawBlock(GByte *pabyCur, int nDataSize, int nMin,
247 : int nBlockXSize, int nBlockYSize,
248 : GInt32 *panData)
249 :
250 : {
251 : int i;
252 :
253 0 : if (nDataSize < nBlockXSize * nBlockYSize)
254 : {
255 0 : CPLError(CE_Failure, CPLE_AppDefined, "Block too small");
256 0 : return CE_Failure;
257 : }
258 :
259 : /* -------------------------------------------------------------------- */
260 : /* Collect raw data. */
261 : /* -------------------------------------------------------------------- */
262 0 : for (i = 0; i < nBlockXSize * nBlockYSize; i++)
263 : {
264 0 : panData[i] = AIGRolloverSignedAdd(*(pabyCur++), nMin);
265 : }
266 :
267 0 : return (CE_None);
268 : }
269 :
270 : /************************************************************************/
271 : /* AIGProcessFFBlock() */
272 : /* */
273 : /* Process a type 0xFF (CCITT RLE) compressed block. */
274 : /************************************************************************/
275 :
276 0 : static CPLErr AIGProcessFFBlock(GByte *pabyCur, int nDataSize, int nMin,
277 : int nBlockXSize, int nBlockYSize,
278 : GInt32 *panData)
279 :
280 : {
281 : /* -------------------------------------------------------------------- */
282 : /* Convert CCITT compress bitstream into 1bit raw data. */
283 : /* -------------------------------------------------------------------- */
284 : CPLErr eErr;
285 0 : int i, nDstBytes = (nBlockXSize * nBlockYSize + 7) / 8;
286 : unsigned char *pabyIntermediate;
287 :
288 0 : pabyIntermediate = (unsigned char *)VSI_MALLOC_VERBOSE(nDstBytes);
289 0 : if (pabyIntermediate == NULL)
290 : {
291 0 : return CE_Failure;
292 : }
293 :
294 0 : eErr = DecompressCCITTRLETile(pabyCur, nDataSize, pabyIntermediate,
295 : nDstBytes, nBlockXSize, nBlockYSize);
296 0 : if (eErr != CE_None)
297 : {
298 0 : CPLFree(pabyIntermediate);
299 0 : return eErr;
300 : }
301 :
302 : /* -------------------------------------------------------------------- */
303 : /* Convert the bit buffer into 32bit integers and account for */
304 : /* nMin. */
305 : /* -------------------------------------------------------------------- */
306 0 : for (i = 0; i < nBlockXSize * nBlockYSize; i++)
307 : {
308 0 : if (pabyIntermediate[i >> 3] & (0x80 >> (i & 0x7)))
309 0 : panData[i] = AIGRolloverSignedAdd(nMin, 1);
310 : else
311 0 : panData[i] = nMin;
312 : }
313 :
314 0 : CPLFree(pabyIntermediate);
315 :
316 0 : return (CE_None);
317 : }
318 :
319 : /************************************************************************/
320 : /* AIGProcessBlock() */
321 : /* */
322 : /* Process a block using ``D7'', ``E0'' or ``DF'' compression. */
323 : /************************************************************************/
324 :
325 2 : static CPLErr AIGProcessBlock(GByte *pabyCur, int nDataSize, int nMin,
326 : int nMagic, int nBlockXSize, int nBlockYSize,
327 : GInt32 *panData)
328 :
329 : {
330 : int nTotPixels, nPixels;
331 : int i;
332 :
333 : /* ==================================================================== */
334 : /* Process runs till we are done. */
335 : /* ==================================================================== */
336 2 : nTotPixels = nBlockXSize * nBlockYSize;
337 2 : nPixels = 0;
338 :
339 22 : while (nPixels < nTotPixels && nDataSize > 0)
340 : {
341 20 : int nMarker = *(pabyCur++);
342 :
343 20 : nDataSize--;
344 :
345 : /* --------------------------------------------------------------------
346 : */
347 : /* Repeat data - four byte data block (0xE0) */
348 : /* --------------------------------------------------------------------
349 : */
350 20 : if (nMagic == 0xE0)
351 : {
352 : GInt32 nValue;
353 :
354 0 : if (nMarker + nPixels > nTotPixels)
355 : {
356 0 : CPLError(CE_Failure, CPLE_AppDefined,
357 : "Run too long in AIGProcessBlock, needed %d values, "
358 : "got %d.",
359 : nTotPixels - nPixels, nMarker);
360 0 : return CE_Failure;
361 : }
362 :
363 0 : if (nDataSize < 4)
364 : {
365 0 : CPLError(CE_Failure, CPLE_AppDefined, "Block too small");
366 0 : return CE_Failure;
367 : }
368 :
369 0 : nValue = 0;
370 0 : memcpy(&nValue, pabyCur, 4);
371 0 : pabyCur += 4;
372 0 : nDataSize -= 4;
373 :
374 0 : nValue = CPL_MSBWORD32(nValue);
375 0 : nValue = AIGRolloverSignedAdd(nValue, nMin);
376 0 : for (i = 0; i < nMarker; i++)
377 0 : panData[nPixels++] = nValue;
378 : }
379 :
380 : /* --------------------------------------------------------------------
381 : */
382 : /* Repeat data - two byte data block (0xF0) */
383 : /* --------------------------------------------------------------------
384 : */
385 20 : else if (nMagic == 0xF0)
386 : {
387 : GInt32 nValue;
388 :
389 0 : if (nMarker + nPixels > nTotPixels)
390 : {
391 0 : CPLError(CE_Failure, CPLE_AppDefined,
392 : "Run too long in AIGProcessBlock, needed %d values, "
393 : "got %d.",
394 : nTotPixels - nPixels, nMarker);
395 0 : return CE_Failure;
396 : }
397 :
398 0 : if (nDataSize < 2)
399 : {
400 0 : CPLError(CE_Failure, CPLE_AppDefined, "Block too small");
401 0 : return CE_Failure;
402 : }
403 :
404 0 : nValue = AIGRolloverSignedAdd(pabyCur[0] * 256 + pabyCur[1], nMin);
405 0 : pabyCur += 2;
406 0 : nDataSize -= 2;
407 :
408 0 : for (i = 0; i < nMarker; i++)
409 0 : panData[nPixels++] = nValue;
410 : }
411 :
412 : /* --------------------------------------------------------------------
413 : */
414 : /* Repeat data - one byte data block (0xFC) */
415 : /* --------------------------------------------------------------------
416 : */
417 20 : else if (nMagic == 0xFC || nMagic == 0xF8)
418 0 : {
419 : GInt32 nValue;
420 :
421 0 : if (nMarker + nPixels > nTotPixels)
422 : {
423 0 : CPLError(CE_Failure, CPLE_AppDefined,
424 : "Run too long in AIGProcessBlock, needed %d values, "
425 : "got %d.",
426 : nTotPixels - nPixels, nMarker);
427 0 : return CE_Failure;
428 : }
429 :
430 0 : if (nDataSize < 1)
431 : {
432 0 : CPLError(CE_Failure, CPLE_AppDefined, "Block too small");
433 0 : return CE_Failure;
434 : }
435 :
436 0 : nValue = AIGRolloverSignedAdd(*(pabyCur++), nMin);
437 0 : nDataSize--;
438 :
439 0 : for (i = 0; i < nMarker; i++)
440 0 : panData[nPixels++] = nValue;
441 : }
442 :
443 : /* --------------------------------------------------------------------
444 : */
445 : /* Repeat data - no actual data, just assign minimum (0xDF) */
446 : /* --------------------------------------------------------------------
447 : */
448 20 : else if (nMagic == 0xDF && nMarker < 128)
449 : {
450 0 : if (nMarker + nPixels > nTotPixels)
451 : {
452 0 : CPLError(CE_Failure, CPLE_AppDefined,
453 : "Run too long in AIGProcessBlock, needed %d values, "
454 : "got %d.",
455 : nTotPixels - nPixels, nMarker);
456 0 : return CE_Failure;
457 : }
458 :
459 0 : for (i = 0; i < nMarker; i++)
460 0 : panData[nPixels++] = nMin;
461 : }
462 :
463 : /* --------------------------------------------------------------------
464 : */
465 : /* Literal data (0xD7): 8bit values. */
466 : /* --------------------------------------------------------------------
467 : */
468 20 : else if (nMagic == 0xD7 && nMarker < 128)
469 : {
470 2 : if (nMarker + nPixels > nTotPixels)
471 : {
472 0 : CPLError(CE_Failure, CPLE_AppDefined,
473 : "Run too long in AIGProcessBlock, needed %d values, "
474 : "got %d.",
475 : nTotPixels - nPixels, nMarker);
476 0 : return CE_Failure;
477 : }
478 :
479 8 : while (nMarker > 0 && nDataSize > 0)
480 : {
481 6 : panData[nPixels++] = AIGRolloverSignedAdd(*(pabyCur++), nMin);
482 6 : nMarker--;
483 6 : nDataSize--;
484 : }
485 : }
486 :
487 : /* --------------------------------------------------------------------
488 : */
489 : /* Literal data (0xCF): 16 bit values. */
490 : /* --------------------------------------------------------------------
491 : */
492 18 : else if (nMagic == 0xCF && nMarker < 128)
493 0 : {
494 : GInt32 nValue;
495 :
496 0 : if (nMarker + nPixels > nTotPixels)
497 : {
498 0 : CPLError(CE_Failure, CPLE_AppDefined,
499 : "Run too long in AIGProcessBlock, needed %d values, "
500 : "got %d.",
501 : nTotPixels - nPixels, nMarker);
502 0 : return CE_Failure;
503 : }
504 :
505 0 : while (nMarker > 0 && nDataSize >= 2)
506 : {
507 : nValue =
508 0 : AIGRolloverSignedAdd(pabyCur[0] * 256 + pabyCur[1], nMin);
509 0 : panData[nPixels++] = nValue;
510 0 : pabyCur += 2;
511 :
512 0 : nMarker--;
513 0 : nDataSize -= 2;
514 : }
515 : }
516 :
517 : /* --------------------------------------------------------------------
518 : */
519 : /* Nodata repeat */
520 : /* --------------------------------------------------------------------
521 : */
522 18 : else if (nMarker > 128)
523 : {
524 18 : nMarker = 256 - nMarker;
525 :
526 18 : if (nMarker + nPixels > nTotPixels)
527 : {
528 0 : CPLError(CE_Failure, CPLE_AppDefined,
529 : "Run too long in AIGProcessBlock, needed %d values, "
530 : "got %d.",
531 : nTotPixels - nPixels, nMarker);
532 0 : return CE_Failure;
533 : }
534 :
535 2060 : while (nMarker > 0)
536 : {
537 2042 : panData[nPixels++] = ESRI_GRID_NO_DATA;
538 2042 : nMarker--;
539 : }
540 : }
541 :
542 : else
543 : {
544 0 : return CE_Failure;
545 : }
546 : }
547 :
548 2 : if (nPixels < nTotPixels || nDataSize < 0)
549 : {
550 0 : CPLError(CE_Failure, CPLE_AppDefined,
551 : "Ran out of data processing block with nMagic=%d.", nMagic);
552 0 : return CE_Failure;
553 : }
554 :
555 2 : return CE_None;
556 : }
557 :
558 : /************************************************************************/
559 : /* AIGReadBlock() */
560 : /* */
561 : /* Read a single block of integer grid data. */
562 : /************************************************************************/
563 :
564 2 : CPLErr AIGReadBlock(VSILFILE *fp, GUInt32 nBlockOffset, int nBlockSize,
565 : int nBlockXSize, int nBlockYSize, GInt32 *panData,
566 : int nCellType, int bCompressed)
567 :
568 : {
569 : GByte *pabyRaw, *pabyCur;
570 : CPLErr eErr;
571 2 : int i, nMagic, nMinSize = 0, nDataSize;
572 2 : GInt32 nMin = 0;
573 :
574 : /* -------------------------------------------------------------------- */
575 : /* If the block has zero size it is all dummies. */
576 : /* -------------------------------------------------------------------- */
577 2 : if (nBlockSize == 0)
578 : {
579 0 : for (i = 0; i < nBlockXSize * nBlockYSize; i++)
580 0 : panData[i] = ESRI_GRID_NO_DATA;
581 :
582 0 : return (CE_None);
583 : }
584 :
585 : /* -------------------------------------------------------------------- */
586 : /* Read the block into memory. */
587 : /* -------------------------------------------------------------------- */
588 2 : if (nBlockSize <= 0 || nBlockSize > 65535 * 2)
589 : {
590 0 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid block size : %d",
591 : nBlockSize);
592 0 : return CE_Failure;
593 : }
594 :
595 2 : pabyRaw = (GByte *)VSIMalloc(nBlockSize + 2);
596 2 : if (pabyRaw == NULL)
597 : {
598 0 : CPLError(CE_Failure, CPLE_AppDefined,
599 : "Cannot allocate memory for block");
600 0 : return CE_Failure;
601 : }
602 :
603 4 : if (VSIFSeekL(fp, nBlockOffset, SEEK_SET) != 0 ||
604 2 : VSIFReadL(pabyRaw, nBlockSize + 2, 1, fp) != 1)
605 : {
606 0 : memset(panData, 0, sizeof(int32_t) * nBlockXSize * nBlockYSize);
607 0 : CPLError(CE_Failure, CPLE_AppDefined,
608 : "Read of %d bytes from offset %d for grid block failed.",
609 : nBlockSize + 2, nBlockOffset);
610 0 : CPLFree(pabyRaw);
611 0 : return CE_Failure;
612 : }
613 :
614 : /* -------------------------------------------------------------------- */
615 : /* Verify the block size. */
616 : /* -------------------------------------------------------------------- */
617 2 : if (nBlockSize != (pabyRaw[0] * 256 + pabyRaw[1]) * 2)
618 : {
619 0 : memset(panData, 0, sizeof(int32_t) * nBlockXSize * nBlockYSize);
620 0 : CPLError(CE_Failure, CPLE_AppDefined,
621 : "Block is corrupt, block size was %d, but expected to be %d.",
622 0 : (pabyRaw[0] * 256 + pabyRaw[1]) * 2, nBlockSize);
623 0 : CPLFree(pabyRaw);
624 0 : return CE_Failure;
625 : }
626 :
627 2 : nDataSize = nBlockSize;
628 :
629 : /* -------------------------------------------------------------------- */
630 : /* Handle float files and uncompressed integer files directly. */
631 : /* -------------------------------------------------------------------- */
632 2 : if (nCellType == AIG_CELLTYPE_FLOAT)
633 : {
634 0 : AIGProcessRaw32BitFloatBlock(pabyRaw + 2, nDataSize, 0, nBlockXSize,
635 : nBlockYSize, (float *)panData);
636 0 : CPLFree(pabyRaw);
637 :
638 0 : return CE_None;
639 : }
640 :
641 2 : if (nCellType == AIG_CELLTYPE_INT && !bCompressed)
642 : {
643 0 : AIGProcessRaw32BitBlock(pabyRaw + 2, nDataSize, nMin, nBlockXSize,
644 : nBlockYSize, panData);
645 0 : CPLFree(pabyRaw);
646 0 : return CE_None;
647 : }
648 :
649 : /* -------------------------------------------------------------------- */
650 : /* Collect minimum value. */
651 : /* -------------------------------------------------------------------- */
652 :
653 : /* The first 2 bytes that give the block size are not included in nDataSize
654 : */
655 : /* and have already been safely read */
656 2 : pabyCur = pabyRaw + 2;
657 :
658 : /* Need at least 2 byte to read the nMinSize and the nMagic */
659 2 : if (nDataSize < 2)
660 : {
661 0 : CPLError(CE_Failure, CPLE_AppDefined,
662 : "Corrupt block. Need 2 bytes to read nMagic and nMinSize, "
663 : "only %d available",
664 : nDataSize);
665 0 : CPLFree(pabyRaw);
666 0 : return CE_Failure;
667 : }
668 2 : nMagic = pabyCur[0];
669 2 : nMinSize = pabyCur[1];
670 2 : pabyCur += 2;
671 2 : nDataSize -= 2;
672 :
673 : /* Need at least nMinSize bytes to read the nMin value */
674 2 : if (nDataSize < nMinSize)
675 : {
676 0 : CPLError(CE_Failure, CPLE_AppDefined,
677 : "Corrupt block. Need %d bytes to read nMin. Only %d available",
678 : nMinSize, nDataSize);
679 0 : CPLFree(pabyRaw);
680 0 : return CE_Failure;
681 : }
682 :
683 2 : if (nMinSize > 4)
684 : {
685 0 : memset(panData, 0, sizeof(int32_t) * nBlockXSize * nBlockYSize);
686 0 : CPLError(CE_Failure, CPLE_AppDefined,
687 : "Corrupt 'minsize' of %d in block header. Read aborted.",
688 : nMinSize);
689 0 : CPLFree(pabyRaw);
690 0 : return CE_Failure;
691 : }
692 :
693 2 : if (nMinSize == 4)
694 : {
695 0 : memcpy(&nMin, pabyCur, 4);
696 0 : nMin = CPL_MSBWORD32(nMin);
697 0 : pabyCur += 4;
698 : }
699 : else
700 : {
701 2 : nMin = 0;
702 2 : for (i = 0; i < nMinSize; i++)
703 : {
704 0 : nMin = nMin * 256 + *pabyCur;
705 0 : pabyCur++;
706 : }
707 :
708 : /* If nMinSize = 0, then we might have only 4 bytes in pabyRaw */
709 : /* don't try to read the 5th one then */
710 2 : if (nMinSize != 0 && pabyRaw[4] > 127)
711 : {
712 0 : if (nMinSize == 2)
713 0 : nMin = nMin - 65536;
714 0 : else if (nMinSize == 1)
715 0 : nMin = nMin - 256;
716 0 : else if (nMinSize == 3)
717 0 : nMin = nMin - 256 * 256 * 256;
718 : }
719 : }
720 :
721 2 : nDataSize -= nMinSize;
722 :
723 : /* -------------------------------------------------------------------- */
724 : /* Call an appropriate handler depending on magic code. */
725 : /* -------------------------------------------------------------------- */
726 2 : eErr = CE_None;
727 2 : if (nMagic == 0x08)
728 : {
729 0 : AIGProcessRawBlock(pabyCur, nDataSize, nMin, nBlockXSize, nBlockYSize,
730 : panData);
731 : }
732 2 : else if (nMagic == 0x04)
733 : {
734 0 : AIGProcessRaw4BitBlock(pabyCur, nDataSize, nMin, nBlockXSize,
735 : nBlockYSize, panData);
736 : }
737 2 : else if (nMagic == 0x01)
738 : {
739 0 : AIGProcessRaw1BitBlock(pabyCur, nDataSize, nMin, nBlockXSize,
740 : nBlockYSize, panData);
741 : }
742 2 : else if (nMagic == 0x00)
743 : {
744 0 : AIGProcessIntConstBlock(pabyCur, nDataSize, nMin, nBlockXSize,
745 : nBlockYSize, panData);
746 : }
747 2 : else if (nMagic == 0x10)
748 : {
749 0 : AIGProcessRaw16BitBlock(pabyCur, nDataSize, nMin, nBlockXSize,
750 : nBlockYSize, panData);
751 : }
752 2 : else if (nMagic == 0x20)
753 : {
754 0 : AIGProcessRaw32BitBlock(pabyCur, nDataSize, nMin, nBlockXSize,
755 : nBlockYSize, panData);
756 : }
757 2 : else if (nMagic == 0xFF)
758 : {
759 0 : eErr = AIGProcessFFBlock(pabyCur, nDataSize, nMin, nBlockXSize,
760 : nBlockYSize, panData);
761 : }
762 : else
763 : {
764 2 : eErr = AIGProcessBlock(pabyCur, nDataSize, nMin, nMagic, nBlockXSize,
765 : nBlockYSize, panData);
766 :
767 2 : if (eErr == CE_Failure)
768 : {
769 0 : for (i = 0; i < nBlockXSize * nBlockYSize; i++)
770 0 : panData[i] = ESRI_GRID_NO_DATA;
771 :
772 0 : CPLErrorOnce(CE_Warning, CPLE_AppDefined,
773 : "Unsupported Arc/Info Binary Grid tile of type 0x%X"
774 : " encountered.\n"
775 : "This and subsequent unsupported tile types set to"
776 : " no data value.\n",
777 : nMagic);
778 : }
779 : }
780 :
781 2 : CPLFree(pabyRaw);
782 :
783 2 : return eErr;
784 : }
785 :
786 : /************************************************************************/
787 : /* AIGReadHeader() */
788 : /* */
789 : /* Read the hdr.adf file, and populate the given info structure */
790 : /* appropriately. */
791 : /************************************************************************/
792 :
793 9 : CPLErr AIGReadHeader(const char *pszCoverName, AIGInfo_t *psInfo)
794 :
795 : {
796 : char *pszHDRFilename;
797 : VSILFILE *fp;
798 : GByte abyData[308];
799 9 : const size_t nHDRFilenameLen = strlen(pszCoverName) + 30;
800 :
801 : /* -------------------------------------------------------------------- */
802 : /* Open the file hdr.adf file. */
803 : /* -------------------------------------------------------------------- */
804 9 : pszHDRFilename = (char *)CPLMalloc(nHDRFilenameLen);
805 9 : snprintf(pszHDRFilename, nHDRFilenameLen, "%s/hdr.adf", pszCoverName);
806 :
807 9 : fp = AIGLLOpen(pszHDRFilename, "rb");
808 :
809 9 : if (fp == NULL)
810 : {
811 0 : CPLError(CE_Failure, CPLE_OpenFailed,
812 : "Failed to open grid header file:\n%s\n", pszHDRFilename);
813 :
814 0 : CPLFree(pszHDRFilename);
815 0 : return (CE_Failure);
816 : }
817 :
818 9 : CPLFree(pszHDRFilename);
819 :
820 : /* -------------------------------------------------------------------- */
821 : /* Read the whole file (we expect it to always be 308 bytes */
822 : /* long. */
823 : /* -------------------------------------------------------------------- */
824 :
825 9 : if (VSIFReadL(abyData, 1, 308, fp) != 308)
826 : {
827 0 : CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
828 0 : return (CE_Failure);
829 : }
830 :
831 9 : CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
832 :
833 : /* -------------------------------------------------------------------- */
834 : /* Read the block size information. */
835 : /* -------------------------------------------------------------------- */
836 9 : memcpy(&(psInfo->nCellType), abyData + 16, 4);
837 9 : memcpy(&(psInfo->bCompressed), abyData + 20, 4);
838 9 : memcpy(&(psInfo->nBlocksPerRow), abyData + 288, 4);
839 9 : memcpy(&(psInfo->nBlocksPerColumn), abyData + 292, 4);
840 9 : memcpy(&(psInfo->nBlockXSize), abyData + 296, 4);
841 9 : memcpy(&(psInfo->nBlockYSize), abyData + 304, 4);
842 9 : memcpy(&(psInfo->dfCellSizeX), abyData + 256, 8);
843 9 : memcpy(&(psInfo->dfCellSizeY), abyData + 264, 8);
844 :
845 : #ifdef CPL_LSB
846 9 : psInfo->nCellType = CPL_SWAP32(psInfo->nCellType);
847 9 : psInfo->bCompressed = CPL_SWAP32(psInfo->bCompressed);
848 9 : psInfo->nBlocksPerRow = CPL_SWAP32(psInfo->nBlocksPerRow);
849 9 : psInfo->nBlocksPerColumn = CPL_SWAP32(psInfo->nBlocksPerColumn);
850 9 : psInfo->nBlockXSize = CPL_SWAP32(psInfo->nBlockXSize);
851 9 : psInfo->nBlockYSize = CPL_SWAP32(psInfo->nBlockYSize);
852 9 : CPL_SWAPDOUBLE(&(psInfo->dfCellSizeX));
853 9 : CPL_SWAPDOUBLE(&(psInfo->dfCellSizeY));
854 : #endif
855 :
856 9 : psInfo->bCompressed = !psInfo->bCompressed;
857 :
858 9 : return (CE_None);
859 : }
860 :
861 : /************************************************************************/
862 : /* AIGReadBlockIndex() */
863 : /* */
864 : /* Read the w001001x.adf file, and populate the given info */
865 : /* structure with the block offsets, and sizes. */
866 : /************************************************************************/
867 :
868 3 : CPLErr AIGReadBlockIndex(AIGInfo_t *psInfo, AIGTileInfo *psTInfo,
869 : const char *pszBasename)
870 :
871 : {
872 : char *pszHDRFilename;
873 : VSILFILE *fp;
874 : int i;
875 : GUInt32 nValue, nLength;
876 : GUInt32 *panIndex;
877 : GByte abyHeader[8];
878 3 : const size_t nHDRFilenameLen = strlen(psInfo->pszCoverName) + 40;
879 :
880 : /* -------------------------------------------------------------------- */
881 : /* Open the file hdr.adf file. */
882 : /* -------------------------------------------------------------------- */
883 3 : pszHDRFilename = (char *)CPLMalloc(nHDRFilenameLen);
884 3 : snprintf(pszHDRFilename, nHDRFilenameLen, "%s/%sx.adf",
885 : psInfo->pszCoverName, pszBasename);
886 :
887 3 : fp = AIGLLOpen(pszHDRFilename, "rb");
888 :
889 3 : if (fp == NULL)
890 : {
891 0 : CPLError(CE_Failure, CPLE_OpenFailed,
892 : "Failed to open grid block index file:\n%s\n", pszHDRFilename);
893 :
894 0 : CPLFree(pszHDRFilename);
895 0 : return (CE_Failure);
896 : }
897 :
898 3 : CPLFree(pszHDRFilename);
899 :
900 : /* -------------------------------------------------------------------- */
901 : /* Verify the magic number. This is often corrupted by CR/LF */
902 : /* translation. */
903 : /* -------------------------------------------------------------------- */
904 3 : if (VSIFReadL(abyHeader, 1, 8, fp) != 8)
905 : {
906 0 : CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
907 0 : return CE_Failure;
908 : }
909 3 : if (abyHeader[3] == 0x0D && abyHeader[4] == 0x0A)
910 : {
911 0 : CPLError(CE_Failure, CPLE_AppDefined,
912 : "w001001x.adf file header has been corrupted by unix to dos "
913 : "text conversion.");
914 0 : CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
915 0 : return CE_Failure;
916 : }
917 :
918 3 : if (abyHeader[0] != 0x00 || abyHeader[1] != 0x00 || abyHeader[2] != 0x27 ||
919 3 : abyHeader[3] != 0x0A || abyHeader[4] != 0xFF || abyHeader[5] != 0xFF)
920 : {
921 0 : CPLError(CE_Failure, CPLE_AppDefined,
922 : "w001001x.adf file header magic number is corrupt.");
923 0 : CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
924 0 : return CE_Failure;
925 : }
926 :
927 : /* -------------------------------------------------------------------- */
928 : /* Get the file length (in 2 byte shorts) */
929 : /* -------------------------------------------------------------------- */
930 3 : if (VSIFSeekL(fp, 24, SEEK_SET) != 0 || VSIFReadL(&nValue, 1, 4, fp) != 4)
931 : {
932 0 : CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
933 0 : return CE_Failure;
934 : }
935 :
936 3 : nValue = CPL_MSBWORD32(nValue);
937 3 : if (nValue > INT_MAX)
938 : {
939 0 : CPLError(CE_Failure, CPLE_AppDefined, "AIGReadBlockIndex: Bad length");
940 0 : CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
941 0 : return CE_Failure;
942 : }
943 3 : nLength = nValue * 2;
944 3 : if (nLength <= 100)
945 : {
946 0 : CPLError(CE_Failure, CPLE_AppDefined, "AIGReadBlockIndex: Bad length");
947 0 : CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
948 0 : return CE_Failure;
949 : }
950 :
951 : /* -------------------------------------------------------------------- */
952 : /* Allocate buffer, and read the file (from beyond the header) */
953 : /* into the buffer. */
954 : /* -------------------------------------------------------------------- */
955 3 : psTInfo->nBlocks = (nLength - 100) / 8;
956 3 : if (psTInfo->nBlocks >= 1000000)
957 : {
958 : // Avoid excessive memory consumption.
959 : vsi_l_offset nFileSize;
960 0 : VSIFSeekL(fp, 0, SEEK_END);
961 0 : nFileSize = VSIFTellL(fp);
962 0 : if (nFileSize < 100 ||
963 0 : (vsi_l_offset)psTInfo->nBlocks > (nFileSize - 100) / 8)
964 : {
965 0 : CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
966 0 : return CE_Failure;
967 : }
968 : }
969 3 : panIndex = (GUInt32 *)VSI_MALLOC2_VERBOSE(psTInfo->nBlocks, 8);
970 3 : if (panIndex == NULL)
971 : {
972 0 : CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
973 0 : return CE_Failure;
974 : }
975 3 : if (VSIFSeekL(fp, 100, SEEK_SET) != 0 ||
976 3 : (int)VSIFReadL(panIndex, 8, psTInfo->nBlocks, fp) != psTInfo->nBlocks)
977 : {
978 0 : CPLError(CE_Failure, CPLE_AppDefined,
979 : "AIGReadBlockIndex: Cannot read block info");
980 0 : CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
981 0 : CPLFree(panIndex);
982 0 : return CE_Failure;
983 : }
984 :
985 3 : CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
986 :
987 : /* -------------------------------------------------------------------- */
988 : /* Allocate AIGInfo block info arrays. */
989 : /* -------------------------------------------------------------------- */
990 3 : psTInfo->panBlockOffset =
991 3 : (GUInt32 *)VSI_MALLOC2_VERBOSE(4, psTInfo->nBlocks);
992 3 : psTInfo->panBlockSize = (int *)VSI_MALLOC2_VERBOSE(4, psTInfo->nBlocks);
993 3 : if (psTInfo->panBlockOffset == NULL || psTInfo->panBlockSize == NULL)
994 : {
995 0 : CPLFree(psTInfo->panBlockOffset);
996 0 : CPLFree(psTInfo->panBlockSize);
997 0 : psTInfo->panBlockOffset = NULL;
998 0 : psTInfo->panBlockSize = NULL;
999 0 : CPLFree(panIndex);
1000 0 : return CE_Failure;
1001 : }
1002 :
1003 : /* -------------------------------------------------------------------- */
1004 : /* Populate the block information. */
1005 : /* -------------------------------------------------------------------- */
1006 5 : for (i = 0; i < psTInfo->nBlocks; i++)
1007 : {
1008 : GUInt32 nVal;
1009 :
1010 3 : nVal = CPL_MSBWORD32(panIndex[i * 2]);
1011 3 : if (nVal >= INT_MAX)
1012 : {
1013 1 : CPLError(CE_Failure, CPLE_AppDefined,
1014 : "AIGReadBlockIndex: Bad offset for block %d", i);
1015 1 : CPLFree(psTInfo->panBlockOffset);
1016 1 : CPLFree(psTInfo->panBlockSize);
1017 1 : psTInfo->panBlockOffset = NULL;
1018 1 : psTInfo->panBlockSize = NULL;
1019 1 : CPLFree(panIndex);
1020 1 : return CE_Failure;
1021 : }
1022 2 : psTInfo->panBlockOffset[i] = nVal * 2;
1023 :
1024 2 : nVal = CPL_MSBWORD32(panIndex[i * 2 + 1]);
1025 2 : if (nVal >= INT_MAX / 2)
1026 : {
1027 0 : CPLError(CE_Failure, CPLE_AppDefined,
1028 : "AIGReadBlockIndex: Bad size for block %d", i);
1029 0 : CPLFree(psTInfo->panBlockOffset);
1030 0 : CPLFree(psTInfo->panBlockSize);
1031 0 : psTInfo->panBlockOffset = NULL;
1032 0 : psTInfo->panBlockSize = NULL;
1033 0 : CPLFree(panIndex);
1034 0 : return CE_Failure;
1035 : }
1036 2 : psTInfo->panBlockSize[i] = nVal * 2;
1037 : }
1038 :
1039 2 : CPLFree(panIndex);
1040 :
1041 2 : return (CE_None);
1042 : }
1043 :
1044 : /************************************************************************/
1045 : /* AIGReadBounds() */
1046 : /* */
1047 : /* Read the dblbnd.adf file for the georeferenced bounds. */
1048 : /************************************************************************/
1049 :
1050 9 : CPLErr AIGReadBounds(const char *pszCoverName, AIGInfo_t *psInfo)
1051 :
1052 : {
1053 : char *pszHDRFilename;
1054 : VSILFILE *fp;
1055 : double adfBound[4];
1056 9 : const size_t nHDRFilenameLen = strlen(pszCoverName) + 40;
1057 :
1058 : /* -------------------------------------------------------------------- */
1059 : /* Open the file dblbnd.adf file. */
1060 : /* -------------------------------------------------------------------- */
1061 9 : pszHDRFilename = (char *)CPLMalloc(nHDRFilenameLen);
1062 9 : snprintf(pszHDRFilename, nHDRFilenameLen, "%s/dblbnd.adf", pszCoverName);
1063 :
1064 9 : fp = AIGLLOpen(pszHDRFilename, "rb");
1065 :
1066 9 : if (fp == NULL)
1067 : {
1068 0 : CPLError(CE_Failure, CPLE_OpenFailed,
1069 : "Failed to open grid bounds file:\n%s\n", pszHDRFilename);
1070 :
1071 0 : CPLFree(pszHDRFilename);
1072 0 : return (CE_Failure);
1073 : }
1074 :
1075 9 : CPLFree(pszHDRFilename);
1076 :
1077 : /* -------------------------------------------------------------------- */
1078 : /* Get the contents - four doubles. */
1079 : /* -------------------------------------------------------------------- */
1080 9 : if (VSIFReadL(adfBound, 1, 32, fp) != 32)
1081 : {
1082 0 : CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
1083 0 : return CE_Failure;
1084 : }
1085 :
1086 9 : CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
1087 :
1088 : #ifdef CPL_LSB
1089 9 : CPL_SWAPDOUBLE(adfBound + 0);
1090 9 : CPL_SWAPDOUBLE(adfBound + 1);
1091 9 : CPL_SWAPDOUBLE(adfBound + 2);
1092 9 : CPL_SWAPDOUBLE(adfBound + 3);
1093 : #endif
1094 :
1095 9 : psInfo->dfLLX = adfBound[0];
1096 9 : psInfo->dfLLY = adfBound[1];
1097 9 : psInfo->dfURX = adfBound[2];
1098 9 : psInfo->dfURY = adfBound[3];
1099 :
1100 9 : return (CE_None);
1101 : }
1102 :
1103 : /************************************************************************/
1104 : /* AIGReadStatistics() */
1105 : /* */
1106 : /* Read the sta.adf file for the layer statistics. */
1107 : /************************************************************************/
1108 :
1109 9 : CPLErr AIGReadStatistics(const char *pszCoverName, AIGInfo_t *psInfo)
1110 :
1111 : {
1112 : char *pszHDRFilename;
1113 : VSILFILE *fp;
1114 : double adfStats[4];
1115 9 : const size_t nHDRFilenameLen = strlen(pszCoverName) + 40;
1116 : size_t nRead;
1117 :
1118 9 : psInfo->dfMin = 0.0;
1119 9 : psInfo->dfMax = 0.0;
1120 9 : psInfo->dfMean = 0.0;
1121 9 : psInfo->dfStdDev = -1.0;
1122 :
1123 : /* -------------------------------------------------------------------- */
1124 : /* Open the file sta.adf file. */
1125 : /* -------------------------------------------------------------------- */
1126 9 : pszHDRFilename = (char *)CPLMalloc(nHDRFilenameLen);
1127 9 : snprintf(pszHDRFilename, nHDRFilenameLen, "%s/sta.adf", pszCoverName);
1128 :
1129 9 : fp = AIGLLOpen(pszHDRFilename, "rb");
1130 :
1131 9 : if (fp == NULL)
1132 : {
1133 0 : CPLError(CE_Failure, CPLE_OpenFailed,
1134 : "Failed to open grid statistics file:\n%s\n", pszHDRFilename);
1135 :
1136 0 : CPLFree(pszHDRFilename);
1137 0 : return (CE_Failure);
1138 : }
1139 :
1140 : /* -------------------------------------------------------------------- */
1141 : /* Get the contents - 3 or 4 doubles. */
1142 : /* -------------------------------------------------------------------- */
1143 9 : nRead = VSIFReadL(adfStats, 1, 32, fp);
1144 :
1145 9 : CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
1146 :
1147 9 : if (nRead == 32)
1148 : {
1149 : #ifdef CPL_LSB
1150 8 : CPL_SWAPDOUBLE(adfStats + 0);
1151 8 : CPL_SWAPDOUBLE(adfStats + 1);
1152 8 : CPL_SWAPDOUBLE(adfStats + 2);
1153 8 : CPL_SWAPDOUBLE(adfStats + 3);
1154 : #endif
1155 :
1156 8 : psInfo->dfMin = adfStats[0];
1157 8 : psInfo->dfMax = adfStats[1];
1158 8 : psInfo->dfMean = adfStats[2];
1159 8 : psInfo->dfStdDev = adfStats[3];
1160 : }
1161 1 : else if (nRead == 24)
1162 : {
1163 : /* See dataset at https://trac.osgeo.org/gdal/ticket/6633 */
1164 : /* In that case, we have only min, max and mean, in LSB ordering */
1165 : CPL_LSBPTR64(adfStats + 0);
1166 : CPL_LSBPTR64(adfStats + 1);
1167 : CPL_LSBPTR64(adfStats + 2);
1168 :
1169 1 : psInfo->dfMin = adfStats[0];
1170 1 : psInfo->dfMax = adfStats[1];
1171 1 : psInfo->dfMean = adfStats[2];
1172 : }
1173 : else
1174 : {
1175 0 : CPLError(CE_Failure, CPLE_AppDefined, "Wrong content for %s",
1176 : pszHDRFilename);
1177 0 : CPLFree(pszHDRFilename);
1178 0 : return CE_Failure;
1179 : }
1180 :
1181 9 : CPLFree(pszHDRFilename);
1182 9 : return CE_None;
1183 : }
|