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