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