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