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