1 : /******************************************************************************
2 : * $Id: ogrtigerdatasource.cpp 22622 2011-06-29 21:33:28Z rouault $
3 : *
4 : * Project: TIGER/Line Translator
5 : * Purpose: Implements OGRTigerDataSource class
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 1999, Frank Warmerdam <warmerdam@pobox.com>
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 "ogr_tiger.h"
31 : #include "cpl_conv.h"
32 : #include "cpl_string.h"
33 : #include <ctype.h>
34 :
35 : CPL_CVSID("$Id: ogrtigerdatasource.cpp 22622 2011-06-29 21:33:28Z rouault $");
36 :
37 : /************************************************************************/
38 : /* TigerClassifyVersion() */
39 : /************************************************************************/
40 :
41 286 : TigerVersion TigerClassifyVersion( int nVersionCode )
42 :
43 : {
44 : TigerVersion nVersion;
45 : int nYear, nMonth;
46 :
47 : /*
48 : ** TIGER Versions
49 : **
50 : ** 0000 TIGER/Line Precensus Files, 1990
51 : ** 0002 TIGER/Line Initial Voting District Codes Files, 1990
52 : ** 0003 TIGER/Line Files, 1990
53 : ** 0005 TIGER/Line Files, 1992
54 : ** 0021 TIGER/Line Files, 1994
55 : ** 0024 TIGER/Line Files, 1995
56 : ** 9706 to 9810 TIGER/Line Files, 1997
57 : ** 9812 to 9904 TIGER/Line Files, 1998
58 : ** 0006 to 0008 TIGER/Line Files, 1999
59 : ** 0010 to 0011 TIGER/Line Files, Redistricting Census 2000
60 : ** 0103 to 0108 TIGER/Line Files, Census 2000
61 : **
62 : ** 0203 to 0205 TIGER/Line Files, UA 2000
63 : ** ???? ????
64 : **
65 : ** 0206 to 0299 TIGER/Line Files, 2002
66 : ** 0300 to 0399 TIGER/Line Files, 2003
67 : ** 0400+ TIGER/Line Files, 2004 - one sample is 0405
68 : ** ????
69 : */
70 :
71 286 : nVersion = TIGER_Unknown;
72 286 : if( nVersionCode == 0 )
73 0 : nVersion = TIGER_1990_Precensus;
74 286 : else if( nVersionCode == 2 )
75 0 : nVersion = TIGER_1990;
76 286 : else if( nVersionCode == 3 )
77 0 : nVersion = TIGER_1992;
78 286 : else if( nVersionCode == 5 )
79 0 : nVersion = TIGER_1994;
80 286 : else if( nVersionCode == 21 )
81 0 : nVersion = TIGER_1994;
82 286 : else if( nVersionCode == 24 )
83 0 : nVersion = TIGER_1995;
84 :
85 286 : else if( nVersionCode == 9999 ) /* special hack, fme bug 7625 */
86 0 : nVersion = TIGER_UA2000;
87 :
88 286 : nYear = nVersionCode % 100;
89 286 : nMonth = nVersionCode / 100;
90 :
91 286 : nVersionCode = nYear * 100 + nMonth;
92 :
93 286 : if( nVersion != TIGER_Unknown )
94 : /* do nothing */;
95 286 : else if( nVersionCode >= 9706 && nVersionCode <= 9810 )
96 0 : nVersion = TIGER_1997;
97 286 : else if( nVersionCode >= 9812 && nVersionCode <= 9904 )
98 0 : nVersion = TIGER_1998;
99 286 : else if( nVersionCode >= 6 /*0006*/ && nVersionCode <= 8 /*0008*/ )
100 0 : nVersion = TIGER_1999;
101 286 : else if( nVersionCode >= 10 /*0010*/ && nVersionCode <= 11 /*0011*/ )
102 0 : nVersion = TIGER_2000_Redistricting;
103 286 : else if( nVersionCode >= 103 /*0103*/ && nVersionCode <= 108 /*0108*/ )
104 0 : nVersion = TIGER_2000_Census;
105 286 : else if( nVersionCode >= 203 /*0302*/ && nVersionCode <= 205 /*0502*/ )
106 0 : nVersion = TIGER_UA2000;
107 286 : else if( nVersionCode >= 210 /*1002*/ && nVersionCode <= 306 /*0603*/)
108 0 : nVersion = TIGER_2002;
109 286 : else if( nVersionCode >= 312 /*1203*/ && nVersionCode <= 403 /*0304*/)
110 0 : nVersion = TIGER_2003;
111 286 : else if( nVersionCode >= 404 )
112 286 : nVersion = TIGER_2004;
113 :
114 286 : return nVersion;
115 : }
116 :
117 : /************************************************************************/
118 : /* TigerVersionString() */
119 : /************************************************************************/
120 :
121 6 : const char * TigerVersionString( TigerVersion nVersion )
122 : {
123 :
124 6 : if (nVersion == TIGER_1990_Precensus) { return "TIGER_1990_Precensus"; }
125 6 : if (nVersion == TIGER_1990) { return "TIGER_1990"; }
126 6 : if (nVersion == TIGER_1992) { return "TIGER_1992"; }
127 6 : if (nVersion == TIGER_1994) { return "TIGER_1994"; }
128 6 : if (nVersion == TIGER_1995) { return "TIGER_1995"; }
129 6 : if (nVersion == TIGER_1997) { return "TIGER_1997"; }
130 6 : if (nVersion == TIGER_1998) { return "TIGER_1998"; }
131 6 : if (nVersion == TIGER_1999) { return "TIGER_1999"; }
132 6 : if (nVersion == TIGER_2000_Redistricting) { return "TIGER_2000_Redistricting"; }
133 6 : if (nVersion == TIGER_UA2000) { return "TIGER_UA2000"; }
134 6 : if (nVersion == TIGER_2002) { return "TIGER_2002"; }
135 6 : if (nVersion == TIGER_2003) { return "TIGER_2003"; }
136 6 : if (nVersion == TIGER_2004) { return "TIGER_2004"; }
137 0 : if (nVersion == TIGER_Unknown) { return "TIGER_Unknown"; }
138 0 : return "???";
139 : }
140 :
141 : /************************************************************************/
142 : /* TigerCheckVersion() */
143 : /* */
144 : /* Some tiger products seem to be generated with version info */
145 : /* that doesn't match the tiger specs. We can sometimes */
146 : /* recognise the wrongness by checking the record length of */
147 : /* some well known changing files and adjusting the version */
148 : /* based on this. */
149 : /************************************************************************/
150 :
151 6 : TigerVersion OGRTigerDataSource::TigerCheckVersion( TigerVersion nOldVersion,
152 : const char *pszFilename )
153 :
154 : {
155 6 : if( nOldVersion != TIGER_2002 )
156 6 : return nOldVersion;
157 :
158 0 : char *pszRTCFilename = BuildFilename( pszFilename, "C" );
159 0 : FILE *fp = VSIFOpen( pszRTCFilename, "rb" );
160 0 : CPLFree( pszRTCFilename );
161 :
162 0 : if( fp == NULL )
163 0 : return nOldVersion;
164 :
165 : char szHeader[115];
166 :
167 0 : if( VSIFRead( szHeader, sizeof(szHeader)-1, 1, fp ) < 1 )
168 : {
169 0 : VSIFClose( fp );
170 0 : return nOldVersion;
171 : }
172 :
173 0 : VSIFClose( fp );
174 :
175 : /* -------------------------------------------------------------------- */
176 : /* Is the record length 112? If so, it is an older version */
177 : /* than 2002. */
178 : /* -------------------------------------------------------------------- */
179 0 : if( szHeader[112] == 10 || szHeader[112] == 13 )
180 : {
181 0 : CPLDebug( "TIGER", "Forcing version back to UA2000 since RTC records are short." );
182 0 : return TIGER_UA2000;
183 : }
184 : else
185 0 : return nOldVersion;
186 : }
187 :
188 : /************************************************************************/
189 : /* OGRTigerDataSource() */
190 : /************************************************************************/
191 :
192 670 : OGRTigerDataSource::OGRTigerDataSource()
193 :
194 : {
195 670 : bWriteMode = FALSE;
196 :
197 670 : nLayers = 0;
198 670 : papoLayers = NULL;
199 :
200 670 : nModules = 0;
201 670 : papszModules = NULL;
202 :
203 670 : pszName = NULL;
204 670 : pszPath = NULL;
205 :
206 670 : papszOptions = NULL;
207 :
208 670 : poSpatialRef = new OGRSpatialReference( "GEOGCS[\"NAD83\",DATUM[\"North_American_Datum_1983\",SPHEROID[\"GRS 1980\",6378137,298.257222101]],PRIMEM[\"Greenwich\",0],UNIT[\"degree\",0.0174532925199433]]" );
209 670 : }
210 :
211 : /************************************************************************/
212 : /* ~OGRTigerDataSource() */
213 : /************************************************************************/
214 :
215 670 : OGRTigerDataSource::~OGRTigerDataSource()
216 :
217 : {
218 : int i;
219 :
220 796 : for( i = 0; i < nLayers; i++ )
221 126 : delete papoLayers[i];
222 :
223 670 : CPLFree( papoLayers );
224 :
225 670 : CPLFree( pszName );
226 670 : CPLFree( pszPath );
227 :
228 670 : CSLDestroy( papszOptions );
229 :
230 670 : CSLDestroy( papszModules );
231 :
232 670 : delete poSpatialRef;
233 670 : }
234 :
235 : /************************************************************************/
236 : /* AddLayer() */
237 : /************************************************************************/
238 :
239 126 : void OGRTigerDataSource::AddLayer( OGRTigerLayer * poNewLayer )
240 :
241 : {
242 : papoLayers = (OGRTigerLayer **)
243 126 : CPLRealloc( papoLayers, sizeof(void*) * ++nLayers );
244 :
245 126 : papoLayers[nLayers-1] = poNewLayer;
246 126 : }
247 :
248 : /************************************************************************/
249 : /* GetLayer() */
250 : /************************************************************************/
251 :
252 861 : OGRLayer *OGRTigerDataSource::GetLayer( int iLayer )
253 :
254 : {
255 861 : if( iLayer < 0 || iLayer >= nLayers )
256 0 : return NULL;
257 : else
258 861 : return papoLayers[iLayer];
259 : }
260 :
261 : /************************************************************************/
262 : /* GetLayer() */
263 : /************************************************************************/
264 :
265 18 : OGRLayer *OGRTigerDataSource::GetLayer( const char *pszLayerName )
266 :
267 : {
268 171 : for( int iLayer = 0; iLayer < nLayers; iLayer++ )
269 : {
270 153 : if( EQUAL(papoLayers[iLayer]->GetLayerDefn()->GetName(),pszLayerName) )
271 0 : return papoLayers[iLayer];
272 : }
273 :
274 18 : return NULL;
275 : }
276 :
277 : /************************************************************************/
278 : /* GetLayerCount() */
279 : /************************************************************************/
280 :
281 876 : int OGRTigerDataSource::GetLayerCount()
282 :
283 : {
284 876 : return nLayers;
285 : }
286 :
287 : /************************************************************************/
288 : /* Open() */
289 : /************************************************************************/
290 :
291 669 : int OGRTigerDataSource::Open( const char * pszFilename, int bTestOpen,
292 : char ** papszLimitedFileList )
293 :
294 : {
295 : VSIStatBuf stat;
296 669 : char **papszFileList = NULL;
297 : int i;
298 :
299 669 : pszName = CPLStrdup( pszFilename );
300 :
301 : /* -------------------------------------------------------------------- */
302 : /* Is the given path a directory or a regular file? */
303 : /* -------------------------------------------------------------------- */
304 669 : if( CPLStat( pszFilename, &stat ) != 0
305 : || (!VSI_ISDIR(stat.st_mode) && !VSI_ISREG(stat.st_mode)) )
306 : {
307 248 : if( !bTestOpen )
308 : CPLError( CE_Failure, CPLE_AppDefined,
309 : "%s is neither a file or directory, Tiger access failed.\n",
310 0 : pszFilename );
311 :
312 248 : return FALSE;
313 : }
314 :
315 : /* -------------------------------------------------------------------- */
316 : /* Build a list of filenames we figure are Tiger files. */
317 : /* -------------------------------------------------------------------- */
318 421 : if( VSI_ISREG(stat.st_mode) )
319 : {
320 : char szModule[128];
321 :
322 400 : pszPath = CPLStrdup( CPLGetPath(pszFilename) );
323 :
324 400 : strncpy( szModule, CPLGetFilename(pszFilename), sizeof(szModule)-1 );
325 400 : szModule[sizeof(szModule)-1] = '\0';
326 :
327 400 : papszFileList = CSLAddString( papszFileList, szModule );
328 : }
329 : else
330 : {
331 21 : char **candidateFileList = CPLReadDir( pszFilename );
332 : int i;
333 :
334 21 : pszPath = CPLStrdup( pszFilename );
335 :
336 1542 : for( i = 0;
337 771 : candidateFileList != NULL && candidateFileList[i] != NULL;
338 : i++ )
339 : {
340 750 : int nCandidateLen = strlen(candidateFileList[i]);
341 :
342 750 : if( papszLimitedFileList != NULL
343 : && CSLFindString(papszLimitedFileList,
344 0 : CPLGetBasename(candidateFileList[i])) == -1 )
345 : {
346 0 : continue;
347 : }
348 :
349 2818 : if( nCandidateLen > 4
350 1398 : && candidateFileList[i][nCandidateLen-4] == '.'
351 670 : && candidateFileList[i][nCandidateLen-1] == '1')
352 : {
353 : char szModule[128];
354 :
355 6 : strncpy( szModule, candidateFileList[i],
356 12 : strlen(candidateFileList[i])-1 );
357 :
358 6 : szModule[strlen(candidateFileList[i])-1] = '\0';
359 :
360 6 : papszFileList = CSLAddString(papszFileList, szModule);
361 : }
362 : }
363 :
364 21 : CSLDestroy( candidateFileList );
365 :
366 21 : if( CSLCount(papszFileList) == 0 )
367 : {
368 15 : if( !bTestOpen )
369 : CPLError( CE_Failure, CPLE_OpenFailed,
370 : "No candidate Tiger files (TGR*.RT1) found in\n"
371 : "directory: %s",
372 0 : pszFilename );
373 :
374 15 : return FALSE;
375 : }
376 : }
377 :
378 : /* -------------------------------------------------------------------- */
379 : /* Loop over all these files trying to open them. In testopen */
380 : /* mode we first read the first 80 characters, to verify that */
381 : /* it looks like an Tiger file. Note that we don't keep the file */
382 : /* open ... we don't want to occupy alot of file handles when */
383 : /* handling a whole directory. */
384 : /* -------------------------------------------------------------------- */
385 406 : papszModules = NULL;
386 :
387 812 : for( i = 0; papszFileList[i] != NULL; i++ )
388 : {
389 406 : if( bTestOpen || i == 0 )
390 : {
391 : char szHeader[500];
392 : FILE *fp;
393 406 : char *pszRecStart = NULL;
394 406 : int bIsGDT = FALSE;
395 : char *pszFilename;
396 :
397 406 : pszFilename = BuildFilename( papszFileList[i], "1" );
398 :
399 406 : fp = VSIFOpen( pszFilename, "rb" );
400 406 : CPLFree( pszFilename );
401 :
402 406 : if( fp == NULL )
403 400 : continue;
404 :
405 6 : if( VSIFRead( szHeader, sizeof(szHeader)-1, 1, fp ) < 1 )
406 : {
407 0 : VSIFClose( fp );
408 0 : continue;
409 : }
410 :
411 6 : VSIFClose( fp );
412 :
413 6 : pszRecStart = szHeader;
414 6 : szHeader[sizeof(szHeader)-1] = '\0';
415 :
416 6 : if( EQUALN(pszRecStart,"Copyright (C)",13)
417 : && strstr(pszRecStart,"Geographic Data Tech") != NULL )
418 : {
419 0 : bIsGDT = TRUE;
420 :
421 0 : while( *pszRecStart != '\0'
422 : && *pszRecStart != 10
423 : && *pszRecStart != 13 )
424 0 : pszRecStart++;
425 :
426 0 : while( *pszRecStart == 10 || *pszRecStart == 13 )
427 0 : pszRecStart++;
428 : }
429 :
430 6 : if( pszRecStart[0] != '1' )
431 0 : continue;
432 :
433 18 : if( !isdigit(pszRecStart[1]) || !isdigit(pszRecStart[2])
434 12 : || !isdigit(pszRecStart[3]) || !isdigit(pszRecStart[4]) )
435 0 : continue;
436 :
437 6 : nVersionCode = atoi(TigerFileBase::GetField( pszRecStart, 2, 5 ));
438 6 : nVersion = TigerClassifyVersion( nVersionCode );
439 6 : nVersion = TigerCheckVersion( nVersion, papszFileList[i] );
440 :
441 : CPLDebug( "OGR", "Tiger Version Code=%d, Classified as %s ",
442 6 : nVersionCode, TigerVersionString(nVersion) );
443 :
444 18 : if( nVersionCode != 0
445 : && nVersionCode != 2
446 : && nVersionCode != 3
447 : && nVersionCode != 5
448 : && nVersionCode != 21
449 : && nVersionCode != 24
450 6 : && pszRecStart[3] != '9'
451 6 : && pszRecStart[3] != '0'
452 : && !bIsGDT )
453 0 : continue;
454 :
455 : // we could (and should) add a bunch more validation here.
456 : }
457 :
458 6 : papszModules = CSLAddString( papszModules, papszFileList[i] );
459 : }
460 :
461 406 : CSLDestroy( papszFileList );
462 :
463 406 : nModules = CSLCount( papszModules );
464 :
465 406 : if( nModules == 0 )
466 : {
467 400 : if( !bTestOpen )
468 : {
469 0 : if( VSI_ISREG(stat.st_mode) )
470 : CPLError( CE_Failure, CPLE_OpenFailed,
471 : "No TIGER/Line files (TGR*.RT1) found in\n"
472 : "directory: %s",
473 0 : pszFilename );
474 : else
475 : CPLError( CE_Failure, CPLE_OpenFailed,
476 : "File %s does not appear to be a TIGER/Line .RT1 file.",
477 0 : pszFilename );
478 : }
479 :
480 400 : return FALSE;
481 : }
482 :
483 : /* -------------------------------------------------------------------- */
484 : /* Do we have a user provided version override? */
485 : /* -------------------------------------------------------------------- */
486 6 : if( CPLGetConfigOption( "TIGER_VERSION", NULL ) != NULL )
487 : {
488 : const char *pszRequestedVersion =
489 0 : CPLGetConfigOption( "TIGER_VERSION", NULL );
490 :
491 0 : if( EQUALN(pszRequestedVersion,"TIGER_",6) )
492 : {
493 : int iCode;
494 :
495 0 : for( iCode = 1; iCode < TIGER_Unknown; iCode++ )
496 : {
497 0 : if( EQUAL(TigerVersionString((TigerVersion)iCode),
498 : pszRequestedVersion) )
499 : {
500 0 : nVersion = (TigerVersion) iCode;
501 0 : break;
502 : }
503 : }
504 :
505 0 : if( iCode == TIGER_Unknown )
506 : {
507 : CPLError( CE_Failure, CPLE_AppDefined,
508 : "Failed to recognise TIGER_VERSION setting: %s",
509 0 : pszRequestedVersion );
510 0 : return FALSE;
511 : }
512 :
513 : CPLDebug( "OGR", "OVERRIDE Tiger Version %s ",
514 0 : TigerVersionString(nVersion) );
515 : }
516 : else
517 : {
518 0 : nVersionCode = atoi(pszRequestedVersion);
519 0 : nVersion = TigerClassifyVersion( nVersionCode );
520 :
521 : CPLDebug( "OGR",
522 : "OVERRIDE Tiger Version Code=%d, Classified as %s ",
523 0 : nVersionCode, TigerVersionString(nVersion) );
524 : }
525 : }
526 :
527 : /* -------------------------------------------------------------------- */
528 : /* Create the layers which appear to exist. */
529 : /* -------------------------------------------------------------------- */
530 : // RT1, RT2, RT3
531 : AddLayer( new OGRTigerLayer( this,
532 : new TigerCompleteChain( this,
533 6 : papszModules[0]) ));
534 :
535 : /* should we have kept track of whether we encountered an RT4 file? */
536 : // RT4
537 : AddLayer( new OGRTigerLayer( this,
538 : new TigerAltName( this,
539 12 : papszModules[0]) ));
540 :
541 : // RT5
542 : AddLayer( new OGRTigerLayer( this,
543 : new TigerFeatureIds( this,
544 12 : papszModules[0]) ));
545 :
546 : // RT6
547 : AddLayer( new OGRTigerLayer( this,
548 : new TigerZipCodes( this,
549 12 : papszModules[0]) ));
550 : // RT7
551 : AddLayer( new OGRTigerLayer( this,
552 : new TigerLandmarks( this,
553 12 : papszModules[0]) ));
554 :
555 : // RT8
556 : AddLayer( new OGRTigerLayer( this,
557 : new TigerAreaLandmarks( this,
558 12 : papszModules[0]) ));
559 :
560 : // RT9
561 6 : if (nVersion < TIGER_2002) {
562 : AddLayer( new OGRTigerLayer( this,
563 : new TigerKeyFeatures( this,
564 0 : papszModules[0]) ));
565 : }
566 :
567 : // RTA, RTS
568 : AddLayer( new OGRTigerLayer( this,
569 : new TigerPolygon( this,
570 6 : papszModules[0]) ));
571 :
572 : // RTB
573 6 : if (nVersion >= TIGER_2002) {
574 : AddLayer( new OGRTigerLayer( this,
575 : new TigerPolygonCorrections( this,
576 6 : papszModules[0]) ));
577 : }
578 :
579 : // RTC
580 : AddLayer( new OGRTigerLayer( this,
581 : new TigerEntityNames( this,
582 6 : papszModules[0]) ));
583 :
584 : // RTE
585 6 : if (nVersion >= TIGER_2002) {
586 : AddLayer( new OGRTigerLayer( this,
587 : new TigerPolygonEconomic( this,
588 6 : papszModules[0]) ));
589 : }
590 :
591 : // RTH
592 : AddLayer( new OGRTigerLayer( this,
593 : new TigerIDHistory( this,
594 6 : papszModules[0]) ));
595 :
596 : // RTI
597 : AddLayer( new OGRTigerLayer( this,
598 : new TigerPolyChainLink( this,
599 12 : papszModules[0]) ));
600 :
601 : // RTM
602 : AddLayer( new OGRTigerLayer( this,
603 : new TigerSpatialMetadata( this,
604 12 : papszModules[0] ) ) );
605 :
606 : // RTP
607 : AddLayer( new OGRTigerLayer( this,
608 : new TigerPIP( this,
609 12 : papszModules[0]) ));
610 :
611 : // RTR
612 : AddLayer( new OGRTigerLayer( this,
613 : new TigerTLIDRange( this,
614 12 : papszModules[0]) ));
615 :
616 : // RTT
617 6 : if (nVersion >= TIGER_2002) {
618 : AddLayer( new OGRTigerLayer( this,
619 : new TigerZeroCellID( this,
620 6 : papszModules[0]) ));
621 : }
622 :
623 : // RTU
624 6 : if (nVersion >= TIGER_2002) {
625 : AddLayer( new OGRTigerLayer( this,
626 : new TigerOverUnder( this,
627 6 : papszModules[0]) ));
628 : }
629 :
630 : // RTZ
631 : AddLayer( new OGRTigerLayer( this,
632 : new TigerZipPlus4( this,
633 6 : papszModules[0]) ));
634 :
635 6 : return TRUE;
636 : }
637 :
638 : /************************************************************************/
639 : /* SetOptions() */
640 : /************************************************************************/
641 :
642 1 : void OGRTigerDataSource::SetOptionList( char ** papszNewOptions )
643 :
644 : {
645 1 : CSLDestroy( papszOptions );
646 1 : papszOptions = CSLDuplicate( papszNewOptions );
647 1 : }
648 :
649 : /************************************************************************/
650 : /* GetOption() */
651 : /************************************************************************/
652 :
653 2 : const char *OGRTigerDataSource::GetOption( const char * pszOption )
654 :
655 : {
656 2 : return CSLFetchNameValue( papszOptions, pszOption );
657 : }
658 :
659 : /************************************************************************/
660 : /* GetModule() */
661 : /************************************************************************/
662 :
663 291 : const char *OGRTigerDataSource::GetModule( int iModule )
664 :
665 : {
666 291 : if( iModule < 0 || iModule >= nModules )
667 0 : return NULL;
668 : else
669 291 : return papszModules[iModule];
670 : }
671 :
672 : /************************************************************************/
673 : /* CheckModule() */
674 : /* */
675 : /* This is used by the writer to check if this module has been */
676 : /* written to before. */
677 : /************************************************************************/
678 :
679 17 : int OGRTigerDataSource::CheckModule( const char *pszModule )
680 :
681 : {
682 : int i;
683 :
684 17 : for( i = 0; i < nModules; i++ )
685 : {
686 15 : if( EQUAL(pszModule,papszModules[i]) )
687 15 : return TRUE;
688 : }
689 2 : return FALSE;
690 : }
691 :
692 : /************************************************************************/
693 : /* AddModule() */
694 : /************************************************************************/
695 :
696 1 : void OGRTigerDataSource::AddModule( const char *pszModule )
697 :
698 : {
699 1 : if( CheckModule( pszModule ) )
700 0 : return;
701 :
702 1 : papszModules = CSLAddString( papszModules, pszModule );
703 1 : nModules++;
704 : }
705 :
706 : /************************************************************************/
707 : /* BuildFilename() */
708 : /************************************************************************/
709 :
710 24486 : char *OGRTigerDataSource::BuildFilename( const char *pszModuleName,
711 : const char *pszExtension )
712 :
713 : {
714 : char *pszFilename;
715 : char szLCExtension[3];
716 :
717 : /* -------------------------------------------------------------------- */
718 : /* Force the record type to lower case if the filename appears */
719 : /* to be in lower case. */
720 : /* -------------------------------------------------------------------- */
721 24486 : if( *pszExtension >= 'A' && *pszExtension <= 'Z' && *pszModuleName == 't' )
722 : {
723 0 : szLCExtension[0] = (*pszExtension) + 'a' - 'A';
724 0 : szLCExtension[1] = '\0';
725 0 : pszExtension = szLCExtension;
726 : }
727 :
728 : /* -------------------------------------------------------------------- */
729 : /* Build the filename. */
730 : /* -------------------------------------------------------------------- */
731 : pszFilename = (char *) CPLMalloc(strlen(GetDirPath())
732 : + strlen(pszModuleName)
733 24486 : + strlen(pszExtension) + 10);
734 :
735 24486 : if( strlen(GetDirPath()) == 0 )
736 : sprintf( pszFilename, "%s%s",
737 0 : pszModuleName, pszExtension );
738 : else
739 : sprintf( pszFilename, "%s/%s%s",
740 24486 : GetDirPath(), pszModuleName, pszExtension );
741 :
742 24486 : return pszFilename;
743 : }
744 :
745 : /************************************************************************/
746 : /* TestCapability() */
747 : /************************************************************************/
748 :
749 18 : int OGRTigerDataSource::TestCapability( const char *pszCap )
750 :
751 : {
752 18 : if( EQUAL(pszCap,ODsCCreateLayer) )
753 18 : return GetWriteMode();
754 : else
755 0 : return FALSE;
756 : }
757 :
758 : /************************************************************************/
759 : /* Create() */
760 : /************************************************************************/
761 :
762 1 : int OGRTigerDataSource::Create( const char *pszNameIn, char **papszOptions )
763 :
764 : {
765 : VSIStatBuf stat;
766 :
767 : /* -------------------------------------------------------------------- */
768 : /* Try to create directory if it doesn't already exist. */
769 : /* -------------------------------------------------------------------- */
770 1 : if( CPLStat( pszNameIn, &stat ) != 0 )
771 : {
772 0 : VSIMkdir( pszNameIn, 0755 );
773 : }
774 :
775 1 : if( CPLStat( pszNameIn, &stat ) != 0 || !VSI_ISDIR(stat.st_mode) )
776 : {
777 : CPLError( CE_Failure, CPLE_AppDefined,
778 : "%s is not a directory, nor can be directly created as one.",
779 0 : pszName );
780 0 : return FALSE;
781 : }
782 :
783 : /* -------------------------------------------------------------------- */
784 : /* Store various information. */
785 : /* -------------------------------------------------------------------- */
786 1 : pszPath = CPLStrdup( pszNameIn );
787 1 : pszName = CPLStrdup( pszNameIn );
788 1 : bWriteMode = TRUE;
789 :
790 1 : SetOptionList( papszOptions );
791 :
792 : /* -------------------------------------------------------------------- */
793 : /* Work out the version. */
794 : /* -------------------------------------------------------------------- */
795 : // nVersionCode = 1000; /* census 2000 */
796 :
797 1 : nVersionCode = 1002; /* census 2002 */
798 1 : if( GetOption("VERSION") != NULL )
799 : {
800 1 : nVersionCode = atoi(GetOption("VERSION"));
801 1 : nVersionCode = MAX(0,MIN(9999,nVersionCode));
802 : }
803 1 : nVersion = TigerClassifyVersion(nVersionCode);
804 :
805 1 : return TRUE;
806 : }
807 :
808 : /************************************************************************/
809 : /* CreateLayer() */
810 : /************************************************************************/
811 :
812 18 : OGRLayer *OGRTigerDataSource::CreateLayer( const char *pszLayerName,
813 : OGRSpatialReference *poSpatRef,
814 : OGRwkbGeometryType eGType,
815 : char **papszOptions )
816 :
817 : {
818 18 : OGRTigerLayer *poLayer = NULL;
819 :
820 18 : if( GetLayer( pszLayerName ) != NULL )
821 0 : return GetLayer( pszLayerName );
822 :
823 18 : if( poSpatRef != NULL &&
824 : (!poSpatRef->IsGeographic()
825 : || !EQUAL(poSpatRef->GetAttrValue("DATUM"),
826 : "North_American_Datum_1983")) )
827 : {
828 : CPLError( CE_Warning, CPLE_AppDefined,
829 : "Requested coordinate system wrong for Tiger, "
830 0 : "forcing to GEOGCS NAD83." );
831 : }
832 :
833 18 : if( EQUAL(pszLayerName,"PIP") )
834 : {
835 : poLayer = new OGRTigerLayer( this,
836 1 : new TigerPIP( this, NULL ) );
837 : }
838 17 : else if( EQUAL(pszLayerName,"ZipPlus4") )
839 : {
840 : poLayer = new OGRTigerLayer( this,
841 1 : new TigerZipPlus4( this, NULL ) );
842 : }
843 16 : else if( EQUAL(pszLayerName,"TLIDRange") )
844 : {
845 : poLayer = new OGRTigerLayer( this,
846 1 : new TigerTLIDRange( this, NULL ) );
847 : }
848 15 : else if( EQUAL(pszLayerName,"PolyChainLink") )
849 : {
850 : poLayer = new OGRTigerLayer( this,
851 1 : new TigerPolyChainLink( this, NULL ) );
852 : }
853 14 : else if( EQUAL(pszLayerName,"CompleteChain") )
854 : {
855 : poLayer = new OGRTigerLayer( this,
856 1 : new TigerCompleteChain( this, NULL ) );
857 : }
858 13 : else if( EQUAL(pszLayerName,"AltName") )
859 : {
860 : poLayer = new OGRTigerLayer( this,
861 1 : new TigerAltName( this, NULL ) );
862 : }
863 12 : else if( EQUAL(pszLayerName,"FeatureIds") )
864 : {
865 : poLayer = new OGRTigerLayer( this,
866 1 : new TigerFeatureIds( this, NULL ) );
867 : }
868 11 : else if( EQUAL(pszLayerName,"ZipCodes") )
869 : {
870 : poLayer = new OGRTigerLayer( this,
871 1 : new TigerZipCodes( this, NULL ) );
872 : }
873 10 : else if( EQUAL(pszLayerName,"Landmarks") )
874 : {
875 : poLayer = new OGRTigerLayer( this,
876 1 : new TigerLandmarks( this, NULL ) );
877 : }
878 9 : else if( EQUAL(pszLayerName,"AreaLandmarks") )
879 : {
880 : poLayer = new OGRTigerLayer( this,
881 1 : new TigerAreaLandmarks( this, NULL ) );
882 : }
883 8 : else if( EQUAL(pszLayerName,"KeyFeatures") )
884 : {
885 : poLayer = new OGRTigerLayer( this,
886 0 : new TigerKeyFeatures( this, NULL ) );
887 : }
888 8 : else if( EQUAL(pszLayerName,"EntityNames") )
889 : {
890 : poLayer = new OGRTigerLayer( this,
891 1 : new TigerEntityNames( this, NULL ) );
892 : }
893 7 : else if( EQUAL(pszLayerName,"IDHistory") )
894 : {
895 : poLayer = new OGRTigerLayer( this,
896 1 : new TigerIDHistory( this, NULL ) );
897 : }
898 6 : else if( EQUAL(pszLayerName,"Polygon") )
899 : {
900 : poLayer = new OGRTigerLayer( this,
901 1 : new TigerPolygon( this, NULL ) );
902 : }
903 :
904 5 : else if( EQUAL(pszLayerName,"PolygonCorrections") )
905 : {
906 : poLayer = new OGRTigerLayer( this,
907 1 : new TigerPolygonCorrections( this, NULL ) );
908 : }
909 :
910 4 : else if( EQUAL(pszLayerName,"PolygonEconomic") )
911 : {
912 : poLayer = new OGRTigerLayer( this,
913 1 : new TigerPolygonEconomic( this, NULL ) );
914 : }
915 :
916 3 : else if( EQUAL(pszLayerName,"SpatialMetadata") )
917 : {
918 : poLayer = new OGRTigerLayer( this,
919 1 : new TigerSpatialMetadata( this, NULL ) );
920 : }
921 :
922 2 : else if( EQUAL(pszLayerName,"ZeroCellID") )
923 : {
924 : poLayer = new OGRTigerLayer( this,
925 1 : new TigerZeroCellID( this, NULL ) );
926 : }
927 :
928 1 : else if( EQUAL(pszLayerName,"OverUnder") )
929 : {
930 : poLayer = new OGRTigerLayer( this,
931 1 : new TigerOverUnder( this, NULL ) );
932 : }
933 :
934 18 : if( poLayer == NULL )
935 : {
936 : CPLError( CE_Failure, CPLE_AppDefined,
937 : "Unable to create layer %s, not a known TIGER/Line layer.",
938 0 : pszLayerName );
939 : }
940 : else
941 18 : AddLayer( poLayer );
942 :
943 18 : return poLayer;
944 : }
945 :
946 : /************************************************************************/
947 : /* DeleteModuleFiles() */
948 : /************************************************************************/
949 :
950 1 : void OGRTigerDataSource::DeleteModuleFiles( const char *pszModule )
951 :
952 : {
953 1 : char **papszDirFiles = CPLReadDir( GetDirPath() );
954 1 : int i, nCount = CSLCount(papszDirFiles);
955 :
956 21 : for( i = 0; i < nCount; i++ )
957 : {
958 20 : if( EQUALN(pszModule,papszDirFiles[i],strlen(pszModule)) )
959 : {
960 : const char *pszFilename;
961 :
962 : pszFilename = CPLFormFilename( GetDirPath(),
963 18 : papszDirFiles[i],
964 36 : NULL );
965 18 : if( VSIUnlink( pszFilename ) != 0 )
966 : {
967 0 : CPLDebug( "OGR_TIGER", "Failed to unlink %s", pszFilename );
968 : }
969 : }
970 : }
971 :
972 1 : CSLDestroy( papszDirFiles );
973 1 : }
|