1 : /******************************************************************************
2 : * $Id: aigopen.c 22159 2011-04-14 18:18:54Z warmerdam $
3 : *
4 : * Project: Arc/Info Binary Grid Translator
5 : * Purpose: Grid file access cover API for non-GDAL use.
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: aigopen.c 22159 2011-04-14 18:18:54Z warmerdam $");
33 :
34 : /************************************************************************/
35 : /* AIGOpen() */
36 : /************************************************************************/
37 :
38 7 : AIGInfo_t *AIGOpen( const char * pszInputName, const char * pszAccess )
39 :
40 : {
41 : AIGInfo_t *psInfo;
42 : char *pszCoverName;
43 :
44 : (void) pszAccess;
45 :
46 : /* -------------------------------------------------------------------- */
47 : /* If the pass name ends in .adf assume a file within the */
48 : /* coverage has been selected, and strip that off the coverage */
49 : /* name. */
50 : /* -------------------------------------------------------------------- */
51 7 : pszCoverName = CPLStrdup( pszInputName );
52 7 : if( EQUAL(pszCoverName+strlen(pszCoverName)-4, ".adf") )
53 : {
54 : int i;
55 :
56 0 : for( i = strlen(pszCoverName)-1; i > 0; i-- )
57 : {
58 0 : if( pszCoverName[i] == '\\' || pszCoverName[i] == '/' )
59 : {
60 0 : pszCoverName[i] = '\0';
61 0 : break;
62 : }
63 : }
64 :
65 0 : if( i == 0 )
66 0 : strcpy(pszCoverName,".");
67 : }
68 :
69 : /* -------------------------------------------------------------------- */
70 : /* Allocate info structure. */
71 : /* -------------------------------------------------------------------- */
72 7 : psInfo = (AIGInfo_t *) CPLCalloc(sizeof(AIGInfo_t),1);
73 7 : psInfo->bHasWarned = FALSE;
74 7 : psInfo->pszCoverName = pszCoverName;
75 :
76 : /* -------------------------------------------------------------------- */
77 : /* Read the header file. */
78 : /* -------------------------------------------------------------------- */
79 7 : if( AIGReadHeader( pszCoverName, psInfo ) != CE_None )
80 : {
81 0 : CPLFree( pszCoverName );
82 0 : CPLFree( psInfo );
83 0 : return NULL;
84 : }
85 :
86 : /* -------------------------------------------------------------------- */
87 : /* Read the extents. */
88 : /* -------------------------------------------------------------------- */
89 7 : if( AIGReadBounds( pszCoverName, psInfo ) != CE_None )
90 : {
91 0 : AIGClose( psInfo );
92 0 : return NULL;
93 : }
94 :
95 : /* -------------------------------------------------------------------- */
96 : /* Compute the number of pixels and lines, and the number of */
97 : /* tile files. */
98 : /* -------------------------------------------------------------------- */
99 7 : if (psInfo->dfCellSizeX <= 0 || psInfo->dfCellSizeY <= 0)
100 : {
101 0 : CPLError( CE_Failure, CPLE_AppDefined,
102 : "Illegal cell size : %f x %f",
103 : psInfo->dfCellSizeX, psInfo->dfCellSizeY );
104 0 : AIGClose( psInfo );
105 0 : return NULL;
106 : }
107 :
108 7 : psInfo->nPixels = (int)
109 7 : ((psInfo->dfURX - psInfo->dfLLX + 0.5 * psInfo->dfCellSizeX)
110 : / psInfo->dfCellSizeX);
111 7 : psInfo->nLines = (int)
112 7 : ((psInfo->dfURY - psInfo->dfLLY + 0.5 * psInfo->dfCellSizeY)
113 : / psInfo->dfCellSizeY);
114 :
115 7 : if (psInfo->nPixels <= 0 || psInfo->nLines <= 0)
116 : {
117 0 : CPLError( CE_Failure, CPLE_AppDefined,
118 : "Invalid raster dimensions : %d x %d",
119 : psInfo->nPixels, psInfo->nLines );
120 0 : AIGClose( psInfo );
121 0 : return NULL;
122 : }
123 :
124 35 : if (psInfo->nBlockXSize <= 0 || psInfo->nBlockYSize <= 0 ||
125 14 : psInfo->nBlocksPerRow <= 0 || psInfo->nBlocksPerColumn <= 0 ||
126 7 : psInfo->nBlockXSize > INT_MAX / psInfo->nBlocksPerRow ||
127 7 : psInfo->nBlockYSize > INT_MAX / psInfo->nBlocksPerColumn)
128 : {
129 0 : CPLError( CE_Failure, CPLE_AppDefined,
130 : "Invalid block characteristics: nBlockXSize=%d, "
131 : "nBlockYSize=%d, nBlocksPerRow=%d, nBlocksPerColumn=%d",
132 : psInfo->nBlockXSize, psInfo->nBlockYSize,
133 : psInfo->nBlocksPerRow, psInfo->nBlocksPerColumn);
134 0 : AIGClose( psInfo );
135 0 : return NULL;
136 : }
137 :
138 7 : psInfo->nTileXSize = psInfo->nBlockXSize * psInfo->nBlocksPerRow;
139 7 : psInfo->nTileYSize = psInfo->nBlockYSize * psInfo->nBlocksPerColumn;
140 :
141 7 : psInfo->nTilesPerRow = (psInfo->nPixels-1) / psInfo->nTileXSize + 1;
142 7 : psInfo->nTilesPerColumn = (psInfo->nLines-1) / psInfo->nTileYSize + 1;
143 :
144 7 : if (psInfo->nTilesPerRow > INT_MAX / psInfo->nTilesPerColumn)
145 : {
146 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Too many tiles");
147 0 : AIGClose( psInfo );
148 0 : return NULL;
149 : }
150 :
151 : /* -------------------------------------------------------------------- */
152 : /* Setup tile infos, but defer reading of tile data. */
153 : /* -------------------------------------------------------------------- */
154 7 : psInfo->pasTileInfo = (AIGTileInfo *)
155 : VSICalloc(sizeof(AIGTileInfo),
156 7 : psInfo->nTilesPerRow * psInfo->nTilesPerColumn);
157 7 : if (psInfo->pasTileInfo == NULL)
158 : {
159 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Cannot allocate tile info array");
160 0 : AIGClose( psInfo );
161 0 : return NULL;
162 : }
163 :
164 : /* -------------------------------------------------------------------- */
165 : /* Read the statistics. */
166 : /* -------------------------------------------------------------------- */
167 7 : if( AIGReadStatistics( pszCoverName, psInfo ) != CE_None )
168 : {
169 0 : AIGClose( psInfo );
170 0 : return NULL;
171 : }
172 :
173 7 : return( psInfo );
174 : }
175 :
176 : /************************************************************************/
177 : /* AIGAccessTile() */
178 : /************************************************************************/
179 :
180 5898 : CPLErr AIGAccessTile( AIGInfo_t *psInfo, int iTileX, int iTileY )
181 :
182 : {
183 : char szBasename[20];
184 : char *pszFilename;
185 : AIGTileInfo *psTInfo;
186 :
187 : /* -------------------------------------------------------------------- */
188 : /* Identify our tile. */
189 : /* -------------------------------------------------------------------- */
190 17694 : if( iTileX < 0 || iTileX >= psInfo->nTilesPerRow
191 11796 : || iTileY < 0 || iTileY >= psInfo->nTilesPerColumn )
192 : {
193 0 : CPLAssert( FALSE );
194 0 : return CE_Failure;
195 : }
196 :
197 5898 : psTInfo = psInfo->pasTileInfo + iTileX + iTileY * psInfo->nTilesPerRow;
198 :
199 5898 : if( psTInfo->fpGrid != NULL || psTInfo->bTriedToLoad )
200 5895 : return CE_None;
201 :
202 : /* -------------------------------------------------------------------- */
203 : /* Compute the basename. */
204 : /* -------------------------------------------------------------------- */
205 3 : if( iTileY == 0 )
206 3 : sprintf( szBasename, "w%03d001", iTileX + 1 );
207 0 : else if( iTileY == 1 )
208 0 : sprintf( szBasename, "w%03d000", iTileX + 1 );
209 : else
210 0 : sprintf( szBasename, "z%03d%03d", iTileX + 1, iTileY - 1 );
211 :
212 : /* -------------------------------------------------------------------- */
213 : /* Open the file w001001.adf file itself. */
214 : /* -------------------------------------------------------------------- */
215 3 : pszFilename = (char *) CPLMalloc(strlen(psInfo->pszCoverName)+40);
216 3 : sprintf( pszFilename, "%s/%s.adf", psInfo->pszCoverName, szBasename );
217 :
218 3 : psTInfo->fpGrid = AIGLLOpen( pszFilename, "rb" );
219 3 : psTInfo->bTriedToLoad = TRUE;
220 :
221 3 : if( psTInfo->fpGrid == NULL )
222 : {
223 0 : CPLError( CE_Warning, CPLE_OpenFailed,
224 : "Failed to open grid file, assuming region is nodata:\n%s\n",
225 : pszFilename );
226 0 : CPLFree( pszFilename );
227 0 : return CE_Warning;
228 : }
229 :
230 3 : CPLFree( pszFilename );
231 3 : pszFilename = NULL;
232 :
233 : /* -------------------------------------------------------------------- */
234 : /* Read the block index file. */
235 : /* -------------------------------------------------------------------- */
236 3 : return AIGReadBlockIndex( psInfo, psTInfo, szBasename );
237 : }
238 :
239 : /************************************************************************/
240 : /* AIGReadTile() */
241 : /************************************************************************/
242 :
243 5898 : CPLErr AIGReadTile( AIGInfo_t * psInfo, int nBlockXOff, int nBlockYOff,
244 : GInt32 *panData )
245 :
246 : {
247 : int nBlockID;
248 : CPLErr eErr;
249 : int iTileX, iTileY;
250 : AIGTileInfo *psTInfo;
251 :
252 : /* -------------------------------------------------------------------- */
253 : /* Compute our tile, and ensure it is accessable (open). Then */
254 : /* reduce block x/y values to be the block within that tile. */
255 : /* -------------------------------------------------------------------- */
256 5898 : iTileX = nBlockXOff / psInfo->nBlocksPerRow;
257 5898 : iTileY = nBlockYOff / psInfo->nBlocksPerColumn;
258 :
259 5898 : eErr = AIGAccessTile( psInfo, iTileX, iTileY );
260 5898 : if( eErr == CE_Failure )
261 0 : return eErr;
262 :
263 5898 : psTInfo = psInfo->pasTileInfo + iTileX + iTileY * psInfo->nTilesPerRow;
264 :
265 5898 : nBlockXOff -= iTileX * psInfo->nBlocksPerRow;
266 5898 : nBlockYOff -= iTileY * psInfo->nBlocksPerColumn;
267 :
268 : /* -------------------------------------------------------------------- */
269 : /* Request for tile from a file which does not exist - treat as */
270 : /* all nodata. */
271 : /* -------------------------------------------------------------------- */
272 5898 : if( psTInfo->fpGrid == NULL )
273 : {
274 : int i;
275 0 : for( i = psInfo->nBlockXSize * psInfo->nBlockYSize - 1; i >= 0; i-- )
276 0 : panData[i] = ESRI_GRID_NO_DATA;
277 0 : return CE_None;
278 : }
279 :
280 : /* -------------------------------------------------------------------- */
281 : /* validate block id. */
282 : /* -------------------------------------------------------------------- */
283 5898 : nBlockID = nBlockXOff + nBlockYOff * psInfo->nBlocksPerRow;
284 11796 : if( nBlockID < 0
285 5898 : || nBlockID >= psInfo->nBlocksPerRow * psInfo->nBlocksPerColumn )
286 : {
287 0 : CPLError( CE_Failure, CPLE_AppDefined,
288 : "Illegal block requested." );
289 0 : return CE_Failure;
290 : }
291 :
292 5898 : if( nBlockID >= psTInfo->nBlocks )
293 : {
294 : int i;
295 0 : CPLDebug( "AIG",
296 : "Request legal block, but from beyond end of block map.\n"
297 : "Assuming all nodata." );
298 0 : for( i = psInfo->nBlockXSize * psInfo->nBlockYSize - 1; i >= 0; i-- )
299 0 : panData[i] = ESRI_GRID_NO_DATA;
300 0 : return CE_None;
301 : }
302 :
303 : /* -------------------------------------------------------------------- */
304 : /* Read block. */
305 : /* -------------------------------------------------------------------- */
306 17694 : eErr = AIGReadBlock( psTInfo->fpGrid,
307 5898 : psTInfo->panBlockOffset[nBlockID],
308 5898 : psTInfo->panBlockSize[nBlockID],
309 : psInfo->nBlockXSize, psInfo->nBlockYSize,
310 : panData, psInfo->nCellType, psInfo->bCompressed );
311 :
312 : /* -------------------------------------------------------------------- */
313 : /* Apply floating point post-processing. */
314 : /* -------------------------------------------------------------------- */
315 5898 : if( eErr == CE_None && psInfo->nCellType == AIG_CELLTYPE_FLOAT )
316 : {
317 0 : float *pafData = (float *) panData;
318 0 : int i, nPixels = psInfo->nBlockXSize * psInfo->nBlockYSize;
319 :
320 0 : for( i = 0; i < nPixels; i++ )
321 : {
322 0 : panData[i] = (int) pafData[i];
323 : }
324 : }
325 :
326 5898 : return( eErr );
327 : }
328 :
329 : /************************************************************************/
330 : /* AIGReadFloatTile() */
331 : /************************************************************************/
332 :
333 0 : CPLErr AIGReadFloatTile( AIGInfo_t * psInfo, int nBlockXOff, int nBlockYOff,
334 : float *pafData )
335 :
336 : {
337 : int nBlockID;
338 : CPLErr eErr;
339 : int iTileX, iTileY;
340 : AIGTileInfo *psTInfo;
341 :
342 : /* -------------------------------------------------------------------- */
343 : /* Compute our tile, and ensure it is accessable (open). Then */
344 : /* reduce block x/y values to be the block within that tile. */
345 : /* -------------------------------------------------------------------- */
346 0 : iTileX = nBlockXOff / psInfo->nBlocksPerRow;
347 0 : iTileY = nBlockYOff / psInfo->nBlocksPerColumn;
348 :
349 0 : eErr = AIGAccessTile( psInfo, iTileX, iTileY );
350 0 : if( eErr == CE_Failure )
351 0 : return eErr;
352 :
353 0 : psTInfo = psInfo->pasTileInfo + iTileX + iTileY * psInfo->nTilesPerRow;
354 :
355 0 : nBlockXOff -= iTileX * psInfo->nBlocksPerRow;
356 0 : nBlockYOff -= iTileY * psInfo->nBlocksPerColumn;
357 :
358 : /* -------------------------------------------------------------------- */
359 : /* Request for tile from a file which does not exist - treat as */
360 : /* all nodata. */
361 : /* -------------------------------------------------------------------- */
362 0 : if( psTInfo->fpGrid == NULL )
363 : {
364 : int i;
365 0 : for( i = psInfo->nBlockXSize * psInfo->nBlockYSize - 1; i >= 0; i-- )
366 0 : pafData[i] = ESRI_GRID_FLOAT_NO_DATA;
367 0 : return CE_None;
368 : }
369 :
370 : /* -------------------------------------------------------------------- */
371 : /* validate block id. */
372 : /* -------------------------------------------------------------------- */
373 0 : nBlockID = nBlockXOff + nBlockYOff * psInfo->nBlocksPerRow;
374 0 : if( nBlockID < 0
375 0 : || nBlockID >= psInfo->nBlocksPerRow * psInfo->nBlocksPerColumn )
376 : {
377 0 : CPLError( CE_Failure, CPLE_AppDefined,
378 : "Illegal block requested." );
379 0 : return CE_Failure;
380 : }
381 :
382 0 : if( nBlockID >= psTInfo->nBlocks )
383 : {
384 : int i;
385 0 : CPLDebug( "AIG",
386 : "Request legal block, but from beyond end of block map.\n"
387 : "Assuming all nodata." );
388 0 : for( i = psInfo->nBlockXSize * psInfo->nBlockYSize - 1; i >= 0; i-- )
389 0 : pafData[i] = ESRI_GRID_FLOAT_NO_DATA;
390 0 : return CE_None;
391 : }
392 :
393 : /* -------------------------------------------------------------------- */
394 : /* Read block. */
395 : /* -------------------------------------------------------------------- */
396 0 : eErr = AIGReadBlock( psTInfo->fpGrid,
397 0 : psTInfo->panBlockOffset[nBlockID],
398 0 : psTInfo->panBlockSize[nBlockID],
399 : psInfo->nBlockXSize, psInfo->nBlockYSize,
400 : (GInt32 *) pafData, psInfo->nCellType,
401 : psInfo->bCompressed );
402 :
403 : /* -------------------------------------------------------------------- */
404 : /* Perform integer post processing. */
405 : /* -------------------------------------------------------------------- */
406 0 : if( eErr == CE_None && psInfo->nCellType == AIG_CELLTYPE_INT )
407 : {
408 0 : GUInt32 *panData = (GUInt32 *) pafData;
409 0 : int i, nPixels = psInfo->nBlockXSize * psInfo->nBlockYSize;
410 :
411 0 : for( i = 0; i < nPixels; i++ )
412 : {
413 0 : pafData[i] = (float) panData[i];
414 : }
415 : }
416 :
417 0 : return( eErr );
418 : }
419 :
420 : /************************************************************************/
421 : /* AIGClose() */
422 : /************************************************************************/
423 :
424 7 : void AIGClose( AIGInfo_t * psInfo )
425 :
426 : {
427 7 : int nTileCount = psInfo->nTilesPerRow * psInfo->nTilesPerColumn;
428 : int iTile;
429 :
430 14 : for( iTile = 0; iTile < nTileCount; iTile++ )
431 : {
432 7 : if( psInfo->pasTileInfo[iTile].fpGrid )
433 : {
434 3 : VSIFCloseL( psInfo->pasTileInfo[iTile].fpGrid );
435 :
436 3 : CPLFree( psInfo->pasTileInfo[iTile].panBlockOffset );
437 3 : CPLFree( psInfo->pasTileInfo[iTile].panBlockSize );
438 : }
439 : }
440 :
441 7 : CPLFree( psInfo->pasTileInfo );
442 7 : CPLFree( psInfo->pszCoverName );
443 7 : CPLFree( psInfo );
444 7 : }
445 :
446 : /************************************************************************/
447 : /* AIGLLOpen() */
448 : /* */
449 : /* Low level fopen() replacement that will try provided, and */
450 : /* upper cased versions of file names. */
451 : /************************************************************************/
452 :
453 27 : VSILFILE *AIGLLOpen( const char *pszFilename, const char *pszAccess )
454 :
455 : {
456 : VSILFILE *fp;
457 :
458 27 : fp = VSIFOpenL( pszFilename, pszAccess );
459 27 : if( fp == NULL )
460 : {
461 8 : char *pszUCFilename = CPLStrdup(pszFilename);
462 : int i;
463 :
464 158 : for( i = strlen(pszUCFilename)-1;
465 150 : pszUCFilename[i] != '/' && pszUCFilename[i] != '\\';
466 71 : i-- )
467 : {
468 71 : pszUCFilename[i] = (char) toupper(pszUCFilename[i]);
469 : }
470 :
471 8 : fp = VSIFOpenL( pszUCFilename, pszAccess );
472 :
473 8 : CPLFree( pszUCFilename );
474 : }
475 :
476 27 : return fp;
477 : }
478 :
|