1 : /******************************************************************************
2 : * $Id: aigopen.c 16403 2009-02-23 21:55:44Z rouault $
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 16403 2009-02-23 21:55:44Z rouault $");
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 : 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 )
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 :
220 3 : if( psTInfo->fpGrid == NULL )
221 : {
222 0 : CPLError( CE_Failure, CPLE_OpenFailed,
223 : "Failed to open grid file:\n%s\n",
224 : pszFilename );
225 0 : return CE_Failure;
226 : }
227 :
228 3 : CPLFree( pszFilename );
229 3 : pszFilename = NULL;
230 :
231 : /* -------------------------------------------------------------------- */
232 : /* Read the block index file. */
233 : /* -------------------------------------------------------------------- */
234 3 : return AIGReadBlockIndex( psInfo, psTInfo, szBasename );
235 : }
236 :
237 : /************************************************************************/
238 : /* AIGReadTile() */
239 : /************************************************************************/
240 :
241 5898 : CPLErr AIGReadTile( AIGInfo_t * psInfo, int nBlockXOff, int nBlockYOff,
242 : GInt32 *panData )
243 :
244 : {
245 : int nBlockID;
246 : CPLErr eErr;
247 : int iTileX, iTileY;
248 : AIGTileInfo *psTInfo;
249 :
250 : /* -------------------------------------------------------------------- */
251 : /* Compute our tile, and ensure it is accessable (open). Then */
252 : /* reduce block x/y values to be the block within that tile. */
253 : /* -------------------------------------------------------------------- */
254 5898 : iTileX = nBlockXOff / psInfo->nBlocksPerRow;
255 5898 : iTileY = nBlockYOff / psInfo->nBlocksPerColumn;
256 :
257 5898 : eErr = AIGAccessTile( psInfo, iTileX, iTileY );
258 5898 : if( eErr != CE_None )
259 0 : return eErr;
260 :
261 5898 : psTInfo = psInfo->pasTileInfo + iTileX + iTileY * psInfo->nTilesPerRow;
262 :
263 5898 : nBlockXOff -= iTileX * psInfo->nBlocksPerRow;
264 5898 : nBlockYOff -= iTileY * psInfo->nBlocksPerColumn;
265 :
266 : /* -------------------------------------------------------------------- */
267 : /* validate block id. */
268 : /* -------------------------------------------------------------------- */
269 5898 : nBlockID = nBlockXOff + nBlockYOff * psInfo->nBlocksPerRow;
270 11796 : if( nBlockID < 0
271 5898 : || nBlockID >= psInfo->nBlocksPerRow * psInfo->nBlocksPerColumn )
272 : {
273 0 : CPLError( CE_Failure, CPLE_AppDefined,
274 : "Illegal block requested." );
275 0 : return CE_Failure;
276 : }
277 :
278 5898 : if( nBlockID >= psTInfo->nBlocks )
279 : {
280 : int i;
281 0 : CPLDebug( "AIG",
282 : "Request legal block, but from beyond end of block map.\n"
283 : "Assuming all nodata." );
284 0 : for( i = psInfo->nBlockXSize * psInfo->nBlockYSize - 1; i >= 0; i-- )
285 0 : panData[i] = ESRI_GRID_NO_DATA;
286 0 : return CE_None;
287 : }
288 :
289 : /* -------------------------------------------------------------------- */
290 : /* Read block. */
291 : /* -------------------------------------------------------------------- */
292 17694 : eErr = AIGReadBlock( psTInfo->fpGrid,
293 5898 : psTInfo->panBlockOffset[nBlockID],
294 5898 : psTInfo->panBlockSize[nBlockID],
295 : psInfo->nBlockXSize, psInfo->nBlockYSize,
296 : panData, psInfo->nCellType );
297 :
298 : /* -------------------------------------------------------------------- */
299 : /* Apply floating point post-processing. */
300 : /* -------------------------------------------------------------------- */
301 5898 : if( eErr == CE_None && psInfo->nCellType == AIG_CELLTYPE_FLOAT )
302 : {
303 0 : float *pafData = (float *) panData;
304 0 : int i, nPixels = psInfo->nBlockXSize * psInfo->nBlockYSize;
305 :
306 0 : for( i = 0; i < nPixels; i++ )
307 : {
308 0 : panData[i] = (int) pafData[i];
309 : }
310 : }
311 :
312 5898 : return( eErr );
313 : }
314 :
315 : /************************************************************************/
316 : /* AIGReadFloatTile() */
317 : /************************************************************************/
318 :
319 0 : CPLErr AIGReadFloatTile( AIGInfo_t * psInfo, int nBlockXOff, int nBlockYOff,
320 : float *pafData )
321 :
322 : {
323 : int nBlockID;
324 : CPLErr eErr;
325 : int iTileX, iTileY;
326 : AIGTileInfo *psTInfo;
327 :
328 : /* -------------------------------------------------------------------- */
329 : /* Compute our tile, and ensure it is accessable (open). Then */
330 : /* reduce block x/y values to be the block within that tile. */
331 : /* -------------------------------------------------------------------- */
332 0 : iTileX = nBlockXOff / psInfo->nBlocksPerRow;
333 0 : iTileY = nBlockYOff / psInfo->nBlocksPerColumn;
334 :
335 0 : eErr = AIGAccessTile( psInfo, iTileX, iTileY );
336 0 : if( eErr != CE_None )
337 0 : return eErr;
338 :
339 0 : psTInfo = psInfo->pasTileInfo + iTileX + iTileY * psInfo->nTilesPerRow;
340 :
341 0 : nBlockXOff -= iTileX * psInfo->nBlocksPerRow;
342 0 : nBlockYOff -= iTileY * psInfo->nBlocksPerColumn;
343 :
344 : /* -------------------------------------------------------------------- */
345 : /* validate block id. */
346 : /* -------------------------------------------------------------------- */
347 0 : nBlockID = nBlockXOff + nBlockYOff * psInfo->nBlocksPerRow;
348 0 : if( nBlockID < 0
349 0 : || nBlockID >= psInfo->nBlocksPerRow * psInfo->nBlocksPerColumn )
350 : {
351 0 : CPLError( CE_Failure, CPLE_AppDefined,
352 : "Illegal block requested." );
353 0 : return CE_Failure;
354 : }
355 :
356 0 : if( nBlockID >= psTInfo->nBlocks )
357 : {
358 : int i;
359 0 : CPLDebug( "AIG",
360 : "Request legal block, but from beyond end of block map.\n"
361 : "Assuming all nodata." );
362 0 : for( i = psInfo->nBlockXSize * psInfo->nBlockYSize - 1; i >= 0; i-- )
363 0 : pafData[i] = ESRI_GRID_FLOAT_NO_DATA;
364 0 : return CE_None;
365 : }
366 :
367 : /* -------------------------------------------------------------------- */
368 : /* Read block. */
369 : /* -------------------------------------------------------------------- */
370 0 : eErr = AIGReadBlock( psTInfo->fpGrid,
371 0 : psTInfo->panBlockOffset[nBlockID],
372 0 : psTInfo->panBlockSize[nBlockID],
373 : psInfo->nBlockXSize, psInfo->nBlockYSize,
374 : (GInt32 *) pafData, psInfo->nCellType );
375 :
376 : /* -------------------------------------------------------------------- */
377 : /* Perform integer post processing. */
378 : /* -------------------------------------------------------------------- */
379 0 : if( eErr == CE_None && psInfo->nCellType == AIG_CELLTYPE_INT )
380 : {
381 0 : GUInt32 *panData = (GUInt32 *) pafData;
382 0 : int i, nPixels = psInfo->nBlockXSize * psInfo->nBlockYSize;
383 :
384 0 : for( i = 0; i < nPixels; i++ )
385 : {
386 0 : pafData[i] = (float) panData[i];
387 : }
388 : }
389 :
390 0 : return( eErr );
391 : }
392 :
393 : /************************************************************************/
394 : /* AIGClose() */
395 : /************************************************************************/
396 :
397 7 : void AIGClose( AIGInfo_t * psInfo )
398 :
399 : {
400 7 : int nTileCount = psInfo->nTilesPerRow * psInfo->nTilesPerColumn;
401 : int iTile;
402 :
403 14 : for( iTile = 0; iTile < nTileCount; iTile++ )
404 : {
405 7 : if( psInfo->pasTileInfo[iTile].fpGrid )
406 : {
407 3 : VSIFCloseL( psInfo->pasTileInfo[iTile].fpGrid );
408 :
409 3 : CPLFree( psInfo->pasTileInfo[iTile].panBlockOffset );
410 3 : CPLFree( psInfo->pasTileInfo[iTile].panBlockSize );
411 : }
412 : }
413 :
414 7 : CPLFree( psInfo->pasTileInfo );
415 7 : CPLFree( psInfo->pszCoverName );
416 7 : CPLFree( psInfo );
417 7 : }
418 :
419 : /************************************************************************/
420 : /* AIGLLOpen() */
421 : /* */
422 : /* Low level fopen() replacement that will try provided, and */
423 : /* upper cased versions of file names. */
424 : /************************************************************************/
425 :
426 27 : FILE *AIGLLOpen( const char *pszFilename, const char *pszAccess )
427 :
428 : {
429 : FILE *fp;
430 :
431 27 : fp = VSIFOpenL( pszFilename, pszAccess );
432 27 : if( fp == NULL )
433 : {
434 8 : char *pszUCFilename = CPLStrdup(pszFilename);
435 : int i;
436 :
437 158 : for( i = strlen(pszUCFilename)-1;
438 150 : pszUCFilename[i] != '/' && pszUCFilename[i] != '\\';
439 71 : i-- )
440 : {
441 71 : pszUCFilename[i] = (char) toupper(pszUCFilename[i]);
442 : }
443 :
444 8 : fp = VSIFOpenL( pszUCFilename, pszAccess );
445 :
446 8 : CPLFree( pszUCFilename );
447 : }
448 :
449 27 : return fp;
450 : }
451 :
|