1 : /******************************************************************************
2 : * $Id: ogrntfdatasource.cpp 10645 2007-01-18 02:22:39Z warmerdam $
3 : *
4 : * Project: UK NTF Reader
5 : * Purpose: Implements OGRNTFDataSource class
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 "ntf.h"
31 : #include "cpl_conv.h"
32 : #include "cpl_string.h"
33 :
34 : CPL_CVSID("$Id: ogrntfdatasource.cpp 10645 2007-01-18 02:22:39Z warmerdam $");
35 :
36 : /************************************************************************/
37 : /* OGRNTFDataSource() */
38 : /************************************************************************/
39 :
40 939 : OGRNTFDataSource::OGRNTFDataSource()
41 :
42 : {
43 939 : nLayers = 0;
44 939 : papoLayers = NULL;
45 :
46 939 : nNTFFileCount = 0;
47 939 : papoNTFFileReader = NULL;
48 :
49 939 : pszName = NULL;
50 :
51 939 : iCurrentReader = -1;
52 939 : iCurrentFC = 0;
53 :
54 939 : nFCCount = 0;
55 939 : papszFCNum = NULL;
56 939 : papszFCName = NULL;
57 :
58 939 : poFCLayer = NULL;
59 :
60 939 : papszOptions = NULL;
61 :
62 1878 : poSpatialRef = new OGRSpatialReference( "PROJCS[\"OSGB 1936 / British National Grid\",GEOGCS[\"OSGB 1936\",DATUM[\"OSGB_1936\",SPHEROID[\"Airy 1830\",6377563.396,299.3249646,AUTHORITY[\"EPSG\",\"7001\"]],AUTHORITY[\"EPSG\",\"6277\"]],PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],UNIT[\"degree\",0.0174532925199433],AUTHORITY[\"EPSG\",\"4277\"]],PROJECTION[\"Transverse_Mercator\"],PARAMETER[\"latitude_of_origin\",49],PARAMETER[\"central_meridian\",-2],PARAMETER[\"scale_factor\",0.999601272],PARAMETER[\"false_easting\",400000],PARAMETER[\"false_northing\",-100000],UNIT[\"metre\",1,AUTHORITY[\"EPSG\",\"9001\"]],AUTHORITY[\"EPSG\",\"27700\"]]" );
63 :
64 :
65 : /* -------------------------------------------------------------------- */
66 : /* Allow initialization of options from the environment. */
67 : /* -------------------------------------------------------------------- */
68 939 : if( getenv("OGR_NTF_OPTIONS") != NULL )
69 : {
70 : papszOptions =
71 : CSLTokenizeStringComplex( getenv("OGR_NTF_OPTIONS"), ",",
72 0 : FALSE, FALSE );
73 : }
74 939 : }
75 :
76 : /************************************************************************/
77 : /* ~OGRNTFDataSource() */
78 : /************************************************************************/
79 :
80 939 : OGRNTFDataSource::~OGRNTFDataSource()
81 :
82 : {
83 : int i;
84 :
85 941 : for( i = 0; i < nNTFFileCount; i++ )
86 2 : delete papoNTFFileReader[i];
87 :
88 939 : CPLFree( papoNTFFileReader );
89 :
90 947 : for( i = 0; i < nLayers; i++ )
91 8 : delete papoLayers[i];
92 :
93 939 : if( poFCLayer != NULL )
94 2 : delete poFCLayer;
95 :
96 939 : CPLFree( papoLayers );
97 :
98 939 : CPLFree( pszName );
99 :
100 939 : CSLDestroy( papszOptions );
101 :
102 939 : CSLDestroy( papszFCNum );
103 939 : CSLDestroy( papszFCName );
104 :
105 939 : if( poSpatialRef )
106 939 : poSpatialRef->Release();
107 939 : }
108 :
109 : /************************************************************************/
110 : /* TestCapability() */
111 : /************************************************************************/
112 :
113 0 : int OGRNTFDataSource::TestCapability( const char * )
114 :
115 : {
116 0 : return FALSE;
117 : }
118 :
119 : /************************************************************************/
120 : /* GetNamedLayer() */
121 : /************************************************************************/
122 :
123 8 : OGRNTFLayer * OGRNTFDataSource::GetNamedLayer( const char * pszName )
124 :
125 : {
126 20 : for( int i = 0; i < nLayers; i++ )
127 : {
128 12 : if( EQUAL(papoLayers[i]->GetLayerDefn()->GetName(),pszName) )
129 0 : return (OGRNTFLayer *) papoLayers[i];
130 : }
131 :
132 8 : return NULL;
133 : }
134 :
135 : /************************************************************************/
136 : /* AddLayer() */
137 : /************************************************************************/
138 :
139 8 : void OGRNTFDataSource::AddLayer( OGRLayer * poNewLayer )
140 :
141 : {
142 : papoLayers = (OGRLayer **)
143 8 : CPLRealloc( papoLayers, sizeof(void*) * ++nLayers );
144 :
145 8 : papoLayers[nLayers-1] = poNewLayer;
146 8 : }
147 :
148 : /************************************************************************/
149 : /* GetLayer() */
150 : /************************************************************************/
151 :
152 34 : OGRLayer *OGRNTFDataSource::GetLayer( int iLayer )
153 :
154 : {
155 34 : if( iLayer < 0 || iLayer > nLayers )
156 0 : return NULL;
157 34 : else if( iLayer == nLayers )
158 2 : return poFCLayer;
159 : else
160 32 : return papoLayers[iLayer];
161 : }
162 :
163 : /************************************************************************/
164 : /* GetLayerCount() */
165 : /************************************************************************/
166 :
167 36 : int OGRNTFDataSource::GetLayerCount()
168 :
169 : {
170 36 : if( poFCLayer == NULL )
171 0 : return nLayers;
172 : else
173 36 : return nLayers + 1;
174 : }
175 :
176 :
177 : /************************************************************************/
178 : /* Open() */
179 : /************************************************************************/
180 :
181 939 : int OGRNTFDataSource::Open( const char * pszFilename, int bTestOpen,
182 : char ** papszLimitedFileList )
183 :
184 : {
185 : VSIStatBuf stat;
186 939 : char **papszFileList = NULL;
187 :
188 939 : pszName = CPLStrdup( pszFilename );
189 :
190 : /* -------------------------------------------------------------------- */
191 : /* Is the given path a directory or a regular file? */
192 : /* -------------------------------------------------------------------- */
193 939 : if( CPLStat( pszFilename, &stat ) != 0
194 : || (!VSI_ISDIR(stat.st_mode) && !VSI_ISREG(stat.st_mode)) )
195 : {
196 354 : if( !bTestOpen )
197 : CPLError( CE_Failure, CPLE_AppDefined,
198 : "%s is neither a file or directory, NTF access failed.\n",
199 0 : pszFilename );
200 :
201 354 : return FALSE;
202 : }
203 :
204 : /* -------------------------------------------------------------------- */
205 : /* Build a list of filenames we figure are NTF files. */
206 : /* -------------------------------------------------------------------- */
207 585 : if( VSI_ISREG(stat.st_mode) )
208 : {
209 552 : papszFileList = CSLAddString( NULL, pszFilename );
210 : }
211 : else
212 : {
213 33 : char **candidateFileList = CPLReadDir( pszFilename );
214 : int i;
215 :
216 3200 : for( i = 0;
217 1600 : candidateFileList != NULL && candidateFileList[i] != NULL;
218 : i++ )
219 : {
220 1567 : if( papszLimitedFileList != NULL
221 : && CSLFindString(papszLimitedFileList,
222 0 : candidateFileList[i]) == -1 )
223 : {
224 0 : continue;
225 : }
226 :
227 4535 : if( strlen(candidateFileList[i]) > 4
228 2968 : && EQUALN(candidateFileList[i] + strlen(candidateFileList[i])-4,
229 : ".ntf",4) )
230 : {
231 : char fullFilename[2048];
232 :
233 : sprintf( fullFilename, "%s%c%s",
234 : pszFilename,
235 : #ifdef WIN32
236 : '\\',
237 : #else
238 : '/',
239 : #endif
240 0 : candidateFileList[i] );
241 :
242 0 : papszFileList = CSLAddString( papszFileList, fullFilename );
243 : }
244 : }
245 :
246 33 : CSLDestroy( candidateFileList );
247 :
248 33 : if( CSLCount(papszFileList) == 0 )
249 : {
250 33 : if( !bTestOpen )
251 : CPLError( CE_Failure, CPLE_OpenFailed,
252 : "No candidate NTF files (.ntf) found in\n"
253 : "directory: %s",
254 0 : pszFilename );
255 :
256 33 : return FALSE;
257 : }
258 : }
259 :
260 : /* -------------------------------------------------------------------- */
261 : /* Loop over all these files trying to open them. In testopen */
262 : /* mode we first read the first 80 characters, to verify that */
263 : /* it looks like an NTF file. Note that we don't keep the file */
264 : /* open ... we don't want to occupy alot of file handles when */
265 : /* handling a whole directory. */
266 : /* -------------------------------------------------------------------- */
267 : int i;
268 :
269 : papoNTFFileReader = (NTFFileReader **)
270 552 : CPLCalloc(sizeof(void*), CSLCount(papszFileList));
271 :
272 1104 : for( i = 0; papszFileList[i] != NULL; i++ )
273 : {
274 552 : if( bTestOpen )
275 : {
276 : char szHeader[80];
277 : FILE *fp;
278 : int j;
279 :
280 552 : fp = VSIFOpen( papszFileList[i], "rb" );
281 552 : if( fp == NULL )
282 0 : continue;
283 :
284 552 : if( VSIFRead( szHeader, 80, 1, fp ) < 1 )
285 : {
286 27 : VSIFClose( fp );
287 27 : continue;
288 : }
289 :
290 525 : VSIFClose( fp );
291 :
292 525 : if( !EQUALN(szHeader,"01",2) )
293 517 : continue;
294 :
295 620 : for( j = 0; j < 80; j++ )
296 : {
297 614 : if( szHeader[j] == 10 || szHeader[j] == 13 )
298 2 : break;
299 : }
300 :
301 8 : if( j == 80 || szHeader[j-1] != '%' )
302 6 : continue;
303 :
304 : }
305 :
306 : NTFFileReader *poFR;
307 :
308 2 : poFR = new NTFFileReader( this );
309 :
310 2 : if( !poFR->Open( papszFileList[i] ) )
311 : {
312 0 : delete poFR;
313 0 : CSLDestroy( papszFileList );
314 :
315 0 : return FALSE;
316 : }
317 :
318 2 : poFR->SetBaseFID( nNTFFileCount * 1000000 + 1 );
319 2 : poFR->Close();
320 :
321 2 : EnsureTileNameUnique( poFR );
322 :
323 2 : papoNTFFileReader[nNTFFileCount++] = poFR;
324 : }
325 :
326 552 : CSLDestroy( papszFileList );
327 :
328 552 : if( nNTFFileCount == 0 )
329 550 : return FALSE;
330 :
331 : /* -------------------------------------------------------------------- */
332 : /* Establish generic layers. */
333 : /* -------------------------------------------------------------------- */
334 2 : EstablishGenericLayers();
335 :
336 : /* -------------------------------------------------------------------- */
337 : /* Loop over all the files, collecting a unique feature class */
338 : /* listing. */
339 : /* -------------------------------------------------------------------- */
340 4 : for( int iSrcFile = 0; iSrcFile < nNTFFileCount; iSrcFile++ )
341 : {
342 2 : NTFFileReader *poSrcReader = papoNTFFileReader[iSrcFile];
343 :
344 276 : for( int iSrcFC = 0; iSrcFC < poSrcReader->GetFCCount(); iSrcFC++ )
345 : {
346 : int iDstFC;
347 : char *pszSrcFCName, *pszSrcFCNum;
348 :
349 274 : poSrcReader->GetFeatureClass( iSrcFC, &pszSrcFCNum, &pszSrcFCName);
350 :
351 26475 : for( iDstFC = 0; iDstFC < nFCCount; iDstFC++ )
352 : {
353 26201 : if( EQUAL(pszSrcFCNum,papszFCNum[iDstFC]) )
354 0 : break;
355 : }
356 :
357 274 : if( iDstFC >= nFCCount )
358 : {
359 274 : nFCCount++;
360 274 : papszFCNum = CSLAddString(papszFCNum,pszSrcFCNum);
361 274 : papszFCName = CSLAddString(papszFCName,pszSrcFCName);
362 : }
363 : }
364 : }
365 :
366 : /* -------------------------------------------------------------------- */
367 : /* Create a new layer specifically for feature classes. */
368 : /* -------------------------------------------------------------------- */
369 2 : if( nFCCount > 0 )
370 2 : poFCLayer = new OGRNTFFeatureClassLayer( this );
371 : else
372 0 : poFCLayer = NULL;
373 :
374 2 : return TRUE;
375 : }
376 :
377 : /************************************************************************/
378 : /* ResetReading() */
379 : /* */
380 : /* Cleanup, and start over. */
381 : /************************************************************************/
382 :
383 0 : void OGRNTFDataSource::ResetReading()
384 :
385 : {
386 0 : for( int i = 0; i < nNTFFileCount; i++ )
387 0 : papoNTFFileReader[i]->Close();
388 :
389 0 : iCurrentReader = -1;
390 0 : nCurrentPos = -1;
391 0 : nCurrentFID = 1;
392 0 : iCurrentFC = 0;
393 0 : }
394 :
395 : /************************************************************************/
396 : /* GetNextFeature() */
397 : /************************************************************************/
398 :
399 0 : OGRFeature *OGRNTFDataSource::GetNextFeature()
400 :
401 : {
402 0 : OGRFeature *poFeature = NULL;
403 :
404 : /* -------------------------------------------------------------------- */
405 : /* If we have already read all the conventional features, we */
406 : /* should try and return feature class features. */
407 : /* -------------------------------------------------------------------- */
408 0 : if( iCurrentReader == nNTFFileCount )
409 : {
410 0 : if( iCurrentFC < nFCCount )
411 0 : return poFCLayer->GetFeature( iCurrentFC++ );
412 : else
413 0 : return NULL;
414 : }
415 :
416 : /* -------------------------------------------------------------------- */
417 : /* Do we need to open a file? */
418 : /* -------------------------------------------------------------------- */
419 0 : if( iCurrentReader == -1 )
420 : {
421 0 : iCurrentReader++;
422 0 : nCurrentPos = -1;
423 : }
424 :
425 0 : if( papoNTFFileReader[iCurrentReader]->GetFP() == NULL )
426 : {
427 0 : papoNTFFileReader[iCurrentReader]->Open();
428 : }
429 :
430 : /* -------------------------------------------------------------------- */
431 : /* Ensure we are reading on from the same point we were reading */
432 : /* from for the last feature, even if some other access */
433 : /* mechanism has moved the file pointer. */
434 : /* -------------------------------------------------------------------- */
435 0 : if( nCurrentPos != -1 )
436 0 : papoNTFFileReader[iCurrentReader]->SetFPPos( nCurrentPos,
437 0 : nCurrentFID );
438 :
439 : /* -------------------------------------------------------------------- */
440 : /* Read a feature. If we get NULL the file must be all */
441 : /* consumed, advance to the next file. */
442 : /* -------------------------------------------------------------------- */
443 0 : poFeature = papoNTFFileReader[iCurrentReader]->ReadOGRFeature();
444 0 : if( poFeature == NULL )
445 : {
446 0 : papoNTFFileReader[iCurrentReader]->Close();
447 0 : if( GetOption("CACHING") != NULL
448 : && EQUAL(GetOption("CACHING"),"OFF") )
449 0 : papoNTFFileReader[iCurrentReader]->DestroyIndex();
450 :
451 0 : iCurrentReader++;
452 0 : nCurrentPos = -1;
453 0 : nCurrentFID = 1;
454 :
455 0 : poFeature = GetNextFeature();
456 : }
457 : else
458 : {
459 0 : papoNTFFileReader[iCurrentReader]->GetFPPos(&nCurrentPos,
460 0 : &nCurrentFID);
461 : }
462 :
463 0 : return poFeature;
464 : }
465 :
466 : /************************************************************************/
467 : /* GetFeatureClass() */
468 : /************************************************************************/
469 :
470 0 : int OGRNTFDataSource::GetFeatureClass( int iFCIndex,
471 : char ** ppszFCId,
472 : char ** ppszFCName )
473 :
474 : {
475 0 : if( iFCIndex < 0 || iFCIndex >= nFCCount )
476 : {
477 0 : *ppszFCId = NULL;
478 0 : *ppszFCName = NULL;
479 0 : return FALSE;
480 : }
481 : else
482 : {
483 0 : *ppszFCId = papszFCNum[iFCIndex];
484 0 : *ppszFCName = papszFCName[iFCIndex];
485 0 : return TRUE;
486 : }
487 : }
488 :
489 : /************************************************************************/
490 : /* SetOptions() */
491 : /************************************************************************/
492 :
493 0 : void OGRNTFDataSource::SetOptionList( char ** papszNewOptions )
494 :
495 : {
496 0 : CSLDestroy( papszOptions );
497 0 : papszOptions = CSLDuplicate( papszNewOptions );
498 0 : }
499 :
500 : /************************************************************************/
501 : /* GetOption() */
502 : /************************************************************************/
503 :
504 12 : const char *OGRNTFDataSource::GetOption( const char * pszOption )
505 :
506 : {
507 12 : return CSLFetchNameValue( papszOptions, pszOption );
508 : }
509 :
510 : /************************************************************************/
511 : /* EnsureTileNameUnique() */
512 : /* */
513 : /* This method is called with an NTFFileReader to ensure that */
514 : /* it's tilename is unique relative to all the readers already */
515 : /* assigned to this data source. If not, a unique name is */
516 : /* selected for it and assigned. This method should not be */
517 : /* called with readers that are allready attached to the data */
518 : /* source. */
519 : /************************************************************************/
520 :
521 2 : void OGRNTFDataSource::EnsureTileNameUnique( NTFFileReader *poNewReader )
522 :
523 : {
524 2 : int iSequenceNumber = -1;
525 : int bIsUnique;
526 : char szCandidateName[11];
527 :
528 2 : szCandidateName[10] = '\0';
529 2 : do
530 : {
531 2 : bIsUnique = TRUE;
532 2 : if( iSequenceNumber++ == -1 )
533 2 : strncpy( szCandidateName, poNewReader->GetTileName(), 10 );
534 : else
535 0 : sprintf( szCandidateName, "%010d", iSequenceNumber );
536 :
537 2 : for( int iReader = 0; iReader < nNTFFileCount && bIsUnique; iReader++ )
538 : {
539 0 : if( strcmp( szCandidateName,
540 : GetFileReader( iReader )->GetTileName() ) == 0 )
541 0 : bIsUnique = FALSE;
542 : }
543 : } while( !bIsUnique );
544 :
545 2 : if( iSequenceNumber > 0 )
546 : {
547 0 : poNewReader->OverrideTileName( szCandidateName );
548 : CPLError( CE_Warning, CPLE_AppDefined,
549 : "Forcing TILE_REF to `%s' on file %s\n"
550 : "to avoid conflict with other tiles in this data source.",
551 0 : szCandidateName, poNewReader->GetFilename() );
552 : }
553 :
554 2 : }
|