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