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