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