Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: TIGER/Line Translator
4 : * Purpose: Implements OGRTigerDataSource class
5 : * Author: Frank Warmerdam, warmerdam@pobox.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 1999, Frank Warmerdam <warmerdam@pobox.com>
9 : *
10 : * Permission is hereby granted, free of charge, to any person obtaining a
11 : * copy of this software and associated documentation files (the "Software"),
12 : * to deal in the Software without restriction, including without limitation
13 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 : * and/or sell copies of the Software, and to permit persons to whom the
15 : * Software is furnished to do so, subject to the following conditions:
16 : *
17 : * The above copyright notice and this permission notice shall be included
18 : * in all copies or substantial portions of the Software.
19 : *
20 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 : * DEALINGS IN THE SOFTWARE.
27 : ****************************************************************************/
28 :
29 : #include "cpl_conv.h"
30 : #include "cpl_string.h"
31 : #include "ogr_tiger.h"
32 :
33 : #include <cctype>
34 : #include <algorithm>
35 :
36 : #define DIGIT_ZERO '0'
37 :
38 : /************************************************************************/
39 : /* TigerClassifyVersion() */
40 : /************************************************************************/
41 :
42 0 : TigerVersion TigerClassifyVersion(int nVersionCode)
43 :
44 : {
45 : TigerVersion nVersion;
46 : int nYear, nMonth;
47 :
48 : /*
49 : ** TIGER Versions
50 : **
51 : ** 0000 TIGER/Line Precensus Files, 1990
52 : ** 0002 TIGER/Line Initial Voting District Codes Files, 1990
53 : ** 0003 TIGER/Line Files, 1990
54 : ** 0005 TIGER/Line Files, 1992
55 : ** 0021 TIGER/Line Files, 1994
56 : ** 0024 TIGER/Line Files, 1995
57 : ** 9706 to 9810 TIGER/Line Files, 1997
58 : ** 9812 to 9904 TIGER/Line Files, 1998
59 : ** 0006 to 0008 TIGER/Line Files, 1999
60 : ** 0010 to 0011 TIGER/Line Files, Redistricting Census 2000
61 : ** 0103 to 0108 TIGER/Line Files, Census 2000
62 : **
63 : ** 0203 to 0205 TIGER/Line Files, UA 2000
64 : ** ???? ????
65 : **
66 : ** 0206 to 0299 TIGER/Line Files, 2002
67 : ** 0300 to 0399 TIGER/Line Files, 2003
68 : ** 0400+ TIGER/Line Files, 2004 - one sample is 0405
69 : ** ????
70 : */
71 :
72 0 : nVersion = TIGER_Unknown;
73 0 : if (nVersionCode == 0)
74 0 : nVersion = TIGER_1990_Precensus;
75 0 : else if (nVersionCode == 2)
76 0 : nVersion = TIGER_1990;
77 0 : else if (nVersionCode == 3)
78 0 : nVersion = TIGER_1992;
79 0 : else if (nVersionCode == 5)
80 0 : nVersion = TIGER_1994;
81 0 : else if (nVersionCode == 21)
82 0 : nVersion = TIGER_1994;
83 0 : else if (nVersionCode == 24)
84 0 : nVersion = TIGER_1995;
85 :
86 0 : else if (nVersionCode == 9999) /* special hack, fme bug 7625 */
87 0 : nVersion = TIGER_UA2000;
88 :
89 0 : nYear = nVersionCode % 100;
90 0 : nMonth = nVersionCode / 100;
91 :
92 0 : nVersionCode = nYear * 100 + nMonth;
93 :
94 0 : if (nVersion != TIGER_Unknown)
95 : /* do nothing */;
96 0 : else if (nVersionCode >= 9706 && nVersionCode <= 9810)
97 0 : nVersion = TIGER_1997;
98 0 : else if (nVersionCode >= 9812 && nVersionCode <= 9904)
99 0 : nVersion = TIGER_1998;
100 0 : else if (nVersionCode >= 6 /*0006*/ && nVersionCode <= 8 /*0008*/)
101 0 : nVersion = TIGER_1999;
102 0 : else if (nVersionCode >= 10 /*0010*/ && nVersionCode <= 11 /*0011*/)
103 0 : nVersion = TIGER_2000_Redistricting;
104 0 : else if (nVersionCode >= 103 /*0103*/ && nVersionCode <= 108 /*0108*/)
105 0 : nVersion = TIGER_2000_Census;
106 0 : else if (nVersionCode >= 203 /*0302*/ && nVersionCode <= 205 /*0502*/)
107 0 : nVersion = TIGER_UA2000;
108 0 : else if (nVersionCode >= 210 /*1002*/ && nVersionCode <= 306 /*0603*/)
109 0 : nVersion = TIGER_2002;
110 0 : else if (nVersionCode >= 312 /*1203*/ && nVersionCode <= 403 /*0304*/)
111 0 : nVersion = TIGER_2003;
112 0 : else if (nVersionCode >= 404)
113 0 : nVersion = TIGER_2004;
114 :
115 0 : return nVersion;
116 : }
117 :
118 : /************************************************************************/
119 : /* TigerVersionString() */
120 : /************************************************************************/
121 :
122 0 : const char *TigerVersionString(TigerVersion nVersion)
123 : {
124 :
125 0 : if (nVersion == TIGER_1990_Precensus)
126 : {
127 0 : return "TIGER_1990_Precensus";
128 : }
129 0 : if (nVersion == TIGER_1990)
130 : {
131 0 : return "TIGER_1990";
132 : }
133 0 : if (nVersion == TIGER_1992)
134 : {
135 0 : return "TIGER_1992";
136 : }
137 0 : if (nVersion == TIGER_1994)
138 : {
139 0 : return "TIGER_1994";
140 : }
141 0 : if (nVersion == TIGER_1995)
142 : {
143 0 : return "TIGER_1995";
144 : }
145 0 : if (nVersion == TIGER_1997)
146 : {
147 0 : return "TIGER_1997";
148 : }
149 0 : if (nVersion == TIGER_1998)
150 : {
151 0 : return "TIGER_1998";
152 : }
153 0 : if (nVersion == TIGER_1999)
154 : {
155 0 : return "TIGER_1999";
156 : }
157 0 : if (nVersion == TIGER_2000_Redistricting)
158 : {
159 0 : return "TIGER_2000_Redistricting";
160 : }
161 0 : if (nVersion == TIGER_UA2000)
162 : {
163 0 : return "TIGER_UA2000";
164 : }
165 0 : if (nVersion == TIGER_2002)
166 : {
167 0 : return "TIGER_2002";
168 : }
169 0 : if (nVersion == TIGER_2003)
170 : {
171 0 : return "TIGER_2003";
172 : }
173 0 : if (nVersion == TIGER_2004)
174 : {
175 0 : return "TIGER_2004";
176 : }
177 0 : if (nVersion == TIGER_Unknown)
178 : {
179 0 : return "TIGER_Unknown";
180 : }
181 0 : return "???";
182 : }
183 :
184 : /************************************************************************/
185 : /* TigerCheckVersion() */
186 : /* */
187 : /* Some tiger products seem to be generated with version info */
188 : /* that doesn't match the tiger specs. We can sometimes */
189 : /* recognise the wrongness by checking the record length of */
190 : /* some well known changing files and adjusting the version */
191 : /* based on this. */
192 : /************************************************************************/
193 :
194 0 : TigerVersion OGRTigerDataSource::TigerCheckVersion(TigerVersion nOldVersion,
195 : const char *pszFilename)
196 :
197 : {
198 0 : if (nOldVersion != TIGER_2002)
199 0 : return nOldVersion;
200 :
201 0 : char *pszRTCFilename = BuildFilename(pszFilename, "C");
202 0 : VSILFILE *fp = VSIFOpenL(pszRTCFilename, "rb");
203 0 : CPLFree(pszRTCFilename);
204 :
205 0 : if (fp == nullptr)
206 0 : return nOldVersion;
207 :
208 : char szHeader[115];
209 :
210 0 : if (VSIFReadL(szHeader, sizeof(szHeader) - 1, 1, fp) < 1)
211 : {
212 0 : VSIFCloseL(fp);
213 0 : return nOldVersion;
214 : }
215 :
216 0 : VSIFCloseL(fp);
217 :
218 : /* -------------------------------------------------------------------- */
219 : /* Is the record length 112? If so, it is an older version */
220 : /* than 2002. */
221 : /* -------------------------------------------------------------------- */
222 0 : if (szHeader[112] == 10 || szHeader[112] == 13)
223 : {
224 0 : CPLDebug("TIGER",
225 : "Forcing version back to UA2000 since RTC records are short.");
226 0 : return TIGER_UA2000;
227 : }
228 :
229 0 : return nOldVersion;
230 : }
231 :
232 : /************************************************************************/
233 : /* OGRTigerDataSource() */
234 : /************************************************************************/
235 :
236 470 : OGRTigerDataSource::OGRTigerDataSource()
237 : : pszName(nullptr), nLayers(0), papoLayers(nullptr),
238 470 : poSpatialRef(new OGRSpatialReference()), papszOptions(nullptr),
239 : pszPath(nullptr), nModules(0), papszModules(nullptr), nVersionCode(0),
240 470 : nVersion(TIGER_Unknown)
241 : {
242 470 : poSpatialRef->SetWellKnownGeogCS("NAD83");
243 470 : poSpatialRef->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
244 470 : }
245 :
246 : /************************************************************************/
247 : /* ~OGRTigerDataSource() */
248 : /************************************************************************/
249 :
250 940 : OGRTigerDataSource::~OGRTigerDataSource()
251 :
252 : {
253 470 : for (int i = 0; i < nLayers; i++)
254 0 : delete papoLayers[i];
255 :
256 470 : CPLFree(papoLayers);
257 :
258 470 : CPLFree(pszName);
259 470 : CPLFree(pszPath);
260 :
261 470 : CSLDestroy(papszOptions);
262 :
263 470 : CSLDestroy(papszModules);
264 :
265 470 : delete poSpatialRef;
266 940 : }
267 :
268 : /************************************************************************/
269 : /* AddLayer() */
270 : /************************************************************************/
271 :
272 0 : void OGRTigerDataSource::AddLayer(OGRTigerLayer *poNewLayer)
273 :
274 : {
275 0 : poNewLayer->SetDescription(poNewLayer->GetName());
276 0 : papoLayers = static_cast<OGRTigerLayer **>(
277 0 : CPLRealloc(papoLayers, sizeof(void *) * ++nLayers));
278 :
279 0 : papoLayers[nLayers - 1] = poNewLayer;
280 0 : }
281 :
282 : /************************************************************************/
283 : /* GetLayer() */
284 : /************************************************************************/
285 :
286 0 : OGRLayer *OGRTigerDataSource::GetLayer(int iLayer)
287 :
288 : {
289 0 : if (iLayer < 0 || iLayer >= nLayers)
290 0 : return nullptr;
291 :
292 0 : return papoLayers[iLayer];
293 : }
294 :
295 : /************************************************************************/
296 : /* GetLayer() */
297 : /************************************************************************/
298 :
299 0 : OGRLayer *OGRTigerDataSource::GetLayer(const char *pszLayerName)
300 :
301 : {
302 0 : for (int iLayer = 0; iLayer < nLayers; iLayer++)
303 : {
304 0 : if (EQUAL(papoLayers[iLayer]->GetLayerDefn()->GetName(), pszLayerName))
305 0 : return papoLayers[iLayer];
306 : }
307 :
308 0 : return nullptr;
309 : }
310 :
311 : /************************************************************************/
312 : /* GetLayerCount() */
313 : /************************************************************************/
314 :
315 0 : int OGRTigerDataSource::GetLayerCount()
316 :
317 : {
318 0 : return nLayers;
319 : }
320 :
321 : /************************************************************************/
322 : /* Open() */
323 : /************************************************************************/
324 :
325 470 : int OGRTigerDataSource::Open(const char *pszFilename, int bTestOpen,
326 : char **papszLimitedFileList)
327 :
328 : {
329 470 : pszName = CPLStrdup(pszFilename);
330 :
331 : /* -------------------------------------------------------------------- */
332 : /* Is the given path a directory or a regular file? */
333 : /* -------------------------------------------------------------------- */
334 : VSIStatBufL stat;
335 :
336 470 : if (VSIStatExL(pszFilename, &stat,
337 940 : VSI_STAT_EXISTS_FLAG | VSI_STAT_NATURE_FLAG) != 0 ||
338 470 : (!VSI_ISDIR(stat.st_mode) && !VSI_ISREG(stat.st_mode)))
339 : {
340 0 : if (!bTestOpen)
341 0 : CPLError(
342 : CE_Failure, CPLE_AppDefined,
343 : "%s is neither a file or directory, Tiger access failed.\n",
344 : pszFilename);
345 :
346 0 : return FALSE;
347 : }
348 :
349 : /* -------------------------------------------------------------------- */
350 : /* Build a list of filenames we figure are Tiger files. */
351 : /* -------------------------------------------------------------------- */
352 470 : char **papszFileList = nullptr;
353 470 : if (VSI_ISREG(stat.st_mode))
354 : {
355 : char szModule[128];
356 :
357 21 : if (strlen(CPLGetFilename(pszFilename)) == 0)
358 : {
359 0 : return FALSE;
360 : }
361 :
362 21 : pszPath = CPLStrdup(CPLGetPath(pszFilename));
363 :
364 21 : strncpy(szModule, CPLGetFilename(pszFilename), sizeof(szModule) - 1);
365 : /* Make sure the buffer is 0 terminated */
366 21 : szModule[sizeof(szModule) - 1] = '\0';
367 :
368 : /* And now remove last character of filename */
369 21 : szModule[strlen(szModule) - 1] = '\0';
370 :
371 21 : papszFileList = CSLAddString(papszFileList, szModule);
372 : }
373 : else
374 : {
375 449 : char **candidateFileList = VSIReadDir(pszFilename);
376 :
377 449 : pszPath = CPLStrdup(pszFilename);
378 :
379 23378 : for (int i = 0;
380 23378 : candidateFileList != nullptr && candidateFileList[i] != nullptr;
381 : i++)
382 : {
383 22929 : size_t nCandidateLen = strlen(candidateFileList[i]);
384 :
385 22929 : if (papszLimitedFileList != nullptr &&
386 0 : CSLFindString(papszLimitedFileList,
387 0 : CPLGetBasename(candidateFileList[i])) == -1)
388 : {
389 0 : continue;
390 : }
391 :
392 22929 : if (nCandidateLen > 4 &&
393 22166 : candidateFileList[i][nCandidateLen - 4] == '.' &&
394 6231 : candidateFileList[i][nCandidateLen - 1] == '1')
395 : {
396 : char szModule[128];
397 :
398 0 : snprintf(szModule, sizeof(szModule), "%s",
399 0 : candidateFileList[i]);
400 0 : const size_t nLen = strlen(szModule);
401 0 : if (nLen)
402 0 : szModule[nLen - 1] = '\0';
403 :
404 0 : papszFileList = CSLAddString(papszFileList, szModule);
405 : }
406 : }
407 :
408 449 : CSLDestroy(candidateFileList);
409 :
410 449 : if (CSLCount(papszFileList) == 0)
411 : {
412 449 : if (!bTestOpen)
413 0 : CPLError(CE_Failure, CPLE_OpenFailed,
414 : "No candidate Tiger files (TGR*.RT1) found in\n"
415 : "directory: %s",
416 : pszFilename);
417 449 : CSLDestroy(papszFileList);
418 449 : return FALSE;
419 : }
420 : }
421 :
422 : /* -------------------------------------------------------------------- */
423 : /* Loop over all these files trying to open them. In testopen */
424 : /* mode we first read the first 80 characters, to verify that */
425 : /* it looks like an Tiger file. Note that we don't keep the file */
426 : /* open ... we don't want to occupy a lot of file handles when */
427 : /* handling a whole directory. */
428 : /* -------------------------------------------------------------------- */
429 21 : papszModules = nullptr;
430 :
431 42 : for (int i = 0; papszFileList && papszFileList[i] != nullptr; i++)
432 : {
433 21 : if (bTestOpen || i == 0)
434 : {
435 21 : char *l_pszFilename = BuildFilename(papszFileList[i], "1");
436 :
437 21 : VSILFILE *fp = VSIFOpenL(l_pszFilename, "rb");
438 21 : CPLFree(l_pszFilename);
439 :
440 21 : if (fp == nullptr)
441 21 : continue;
442 :
443 0 : char szHeader[500] = {};
444 0 : if (VSIFReadL(szHeader, sizeof(szHeader) - 1, 1, fp) < 1)
445 : {
446 0 : VSIFCloseL(fp);
447 0 : continue;
448 : }
449 :
450 0 : VSIFCloseL(fp);
451 :
452 0 : char *pszRecStart = szHeader;
453 0 : szHeader[sizeof(szHeader) - 1] = '\0';
454 :
455 0 : bool bIsGDT = false;
456 :
457 0 : if (STARTS_WITH_CI(pszRecStart, "Copyright (C)") &&
458 0 : strstr(pszRecStart, "Geographic Data Tech") != nullptr)
459 : {
460 0 : bIsGDT = true;
461 :
462 0 : while (*pszRecStart != '\0' && *pszRecStart != 10 &&
463 0 : *pszRecStart != 13)
464 0 : pszRecStart++;
465 :
466 0 : while (*pszRecStart == 10 || *pszRecStart == 13)
467 0 : pszRecStart++;
468 : }
469 :
470 0 : if (pszRecStart[0] != '1')
471 0 : continue;
472 :
473 0 : if (!isdigit(static_cast<unsigned char>(pszRecStart[1])) ||
474 0 : !isdigit(static_cast<unsigned char>(pszRecStart[2])) ||
475 0 : !isdigit(static_cast<unsigned char>(pszRecStart[3])) ||
476 0 : !isdigit(static_cast<unsigned char>(pszRecStart[4])))
477 0 : continue;
478 :
479 0 : nVersionCode = atoi(TigerFileBase::GetField(pszRecStart, 2, 5));
480 0 : nVersion = TigerClassifyVersion(nVersionCode);
481 0 : nVersion = TigerCheckVersion(nVersion, papszFileList[i]);
482 :
483 0 : CPLDebug("OGR", "Tiger Version Code=%d, Classified as %s ",
484 : nVersionCode, TigerVersionString(nVersion));
485 :
486 0 : if (nVersionCode != 0 && nVersionCode != 2 && nVersionCode != 3 &&
487 0 : nVersionCode != 5 && nVersionCode != 21 && nVersionCode != 24 &&
488 0 : pszRecStart[3] != '9' && pszRecStart[3] != DIGIT_ZERO &&
489 0 : !bIsGDT)
490 0 : continue;
491 :
492 : // we could (and should) add a bunch more validation here.
493 : }
494 :
495 0 : papszModules = CSLAddString(papszModules, papszFileList[i]);
496 : }
497 :
498 21 : CSLDestroy(papszFileList);
499 :
500 21 : nModules = CSLCount(papszModules);
501 :
502 21 : if (nModules == 0 || papszModules == nullptr)
503 : {
504 21 : if (!bTestOpen)
505 : {
506 0 : if (VSI_ISREG(stat.st_mode))
507 0 : CPLError(CE_Failure, CPLE_OpenFailed,
508 : "No TIGER/Line files (TGR*.RT1) found in\n"
509 : "directory: %s",
510 : pszFilename);
511 : else
512 0 : CPLError(
513 : CE_Failure, CPLE_OpenFailed,
514 : "File %s does not appear to be a TIGER/Line .RT1 file.",
515 : pszFilename);
516 : }
517 :
518 21 : return FALSE;
519 : }
520 :
521 : /* -------------------------------------------------------------------- */
522 : /* Do we have a user provided version override? */
523 : /* -------------------------------------------------------------------- */
524 : const char *pszRequestedVersion =
525 0 : CPLGetConfigOption("TIGER_VERSION", nullptr);
526 0 : if (pszRequestedVersion != nullptr)
527 : {
528 :
529 0 : if (STARTS_WITH_CI(pszRequestedVersion, "TIGER_"))
530 : {
531 0 : int iCode = 1; // Used after for.
532 :
533 0 : for (; iCode < TIGER_Unknown; iCode++)
534 : {
535 0 : if (EQUAL(TigerVersionString((TigerVersion)iCode),
536 : pszRequestedVersion))
537 : {
538 0 : nVersion = (TigerVersion)iCode;
539 0 : break;
540 : }
541 : }
542 :
543 0 : if (iCode == TIGER_Unknown)
544 : {
545 0 : CPLError(CE_Failure, CPLE_AppDefined,
546 : "Failed to recognise TIGER_VERSION setting: %s",
547 : pszRequestedVersion);
548 0 : return FALSE;
549 : }
550 :
551 0 : CPLDebug("OGR", "OVERRIDE Tiger Version %s ",
552 : TigerVersionString(nVersion));
553 : }
554 : else
555 : {
556 0 : nVersionCode = atoi(pszRequestedVersion);
557 0 : nVersion = TigerClassifyVersion(nVersionCode);
558 :
559 0 : CPLDebug("OGR", "OVERRIDE Tiger Version Code=%d, Classified as %s ",
560 : nVersionCode, TigerVersionString(nVersion));
561 : }
562 : }
563 :
564 : /* -------------------------------------------------------------------- */
565 : /* Create the layers which appear to exist. */
566 : /* -------------------------------------------------------------------- */
567 : // RT1, RT2, RT3
568 0 : AddLayer(
569 0 : new OGRTigerLayer(this, new TigerCompleteChain(this, papszModules[0])));
570 :
571 : /* should we have kept track of whether we encountered an RT4 file? */
572 : // RT4
573 0 : AddLayer(new OGRTigerLayer(this, new TigerAltName(this, papszModules[0])));
574 :
575 : // RT5
576 0 : AddLayer(
577 0 : new OGRTigerLayer(this, new TigerFeatureIds(this, papszModules[0])));
578 :
579 : // RT6
580 0 : AddLayer(new OGRTigerLayer(this, new TigerZipCodes(this, papszModules[0])));
581 : // RT7
582 0 : AddLayer(
583 0 : new OGRTigerLayer(this, new TigerLandmarks(this, papszModules[0])));
584 :
585 : // RT8
586 0 : AddLayer(
587 0 : new OGRTigerLayer(this, new TigerAreaLandmarks(this, papszModules[0])));
588 :
589 : // RT9
590 0 : if (nVersion < TIGER_2002)
591 : {
592 0 : AddLayer(new OGRTigerLayer(
593 0 : this, new TigerKeyFeatures(this, papszModules[0])));
594 : }
595 :
596 : // RTA, RTS
597 0 : AddLayer(new OGRTigerLayer(this, new TigerPolygon(this, papszModules[0])));
598 :
599 : // RTB
600 0 : if (nVersion >= TIGER_2002)
601 : {
602 0 : AddLayer(new OGRTigerLayer(
603 0 : this, new TigerPolygonCorrections(this, papszModules[0])));
604 : }
605 :
606 : // RTC
607 0 : AddLayer(
608 0 : new OGRTigerLayer(this, new TigerEntityNames(this, papszModules[0])));
609 :
610 : // RTE
611 0 : if (nVersion >= TIGER_2002)
612 : {
613 0 : AddLayer(new OGRTigerLayer(
614 0 : this, new TigerPolygonEconomic(this, papszModules[0])));
615 : }
616 :
617 : // RTH
618 0 : AddLayer(
619 0 : new OGRTigerLayer(this, new TigerIDHistory(this, papszModules[0])));
620 :
621 : // RTI
622 0 : AddLayer(
623 0 : new OGRTigerLayer(this, new TigerPolyChainLink(this, papszModules[0])));
624 :
625 : // RTM
626 0 : AddLayer(new OGRTigerLayer(
627 0 : this, new TigerSpatialMetadata(this, papszModules[0])));
628 :
629 : // RTP
630 0 : AddLayer(new OGRTigerLayer(this, new TigerPIP(this, papszModules[0])));
631 :
632 : // RTR
633 0 : AddLayer(
634 0 : new OGRTigerLayer(this, new TigerTLIDRange(this, papszModules[0])));
635 :
636 : // RTT
637 0 : if (nVersion >= TIGER_2002)
638 : {
639 0 : AddLayer(new OGRTigerLayer(this,
640 0 : new TigerZeroCellID(this, papszModules[0])));
641 : }
642 :
643 : // RTU
644 0 : if (nVersion >= TIGER_2002)
645 : {
646 0 : AddLayer(
647 0 : new OGRTigerLayer(this, new TigerOverUnder(this, papszModules[0])));
648 : }
649 :
650 : // RTZ
651 0 : AddLayer(new OGRTigerLayer(this, new TigerZipPlus4(this, papszModules[0])));
652 :
653 0 : return TRUE;
654 : }
655 :
656 : /************************************************************************/
657 : /* GetOption() */
658 : /************************************************************************/
659 :
660 0 : const char *OGRTigerDataSource::GetOption(const char *pszOption)
661 :
662 : {
663 0 : return CSLFetchNameValue(papszOptions, pszOption);
664 : }
665 :
666 : /************************************************************************/
667 : /* GetModule() */
668 : /************************************************************************/
669 :
670 0 : const char *OGRTigerDataSource::GetModule(int iModule)
671 :
672 : {
673 0 : if (iModule < 0 || iModule >= nModules)
674 0 : return nullptr;
675 : else
676 0 : return papszModules[iModule];
677 : }
678 :
679 : /************************************************************************/
680 : /* CheckModule() */
681 : /* */
682 : /* This is used by the writer to check if this module has been */
683 : /* written to before. */
684 : /************************************************************************/
685 :
686 0 : bool OGRTigerDataSource::CheckModule(const char *pszModule)
687 :
688 : {
689 0 : for (int i = 0; i < nModules; i++)
690 : {
691 0 : if (EQUAL(pszModule, papszModules[i]))
692 0 : return true;
693 : }
694 0 : return false;
695 : }
696 :
697 : /************************************************************************/
698 : /* AddModule() */
699 : /************************************************************************/
700 :
701 0 : void OGRTigerDataSource::AddModule(const char *pszModule)
702 :
703 : {
704 0 : if (CheckModule(pszModule))
705 0 : return;
706 :
707 0 : papszModules = CSLAddString(papszModules, pszModule);
708 0 : nModules++;
709 : }
710 :
711 : /************************************************************************/
712 : /* BuildFilename() */
713 : /************************************************************************/
714 :
715 21 : char *OGRTigerDataSource::BuildFilename(const char *pszModuleName,
716 : const char *pszExtension)
717 :
718 : {
719 : /* -------------------------------------------------------------------- */
720 : /* Force the record type to lower case if the filename appears */
721 : /* to be in lower case. */
722 : /* -------------------------------------------------------------------- */
723 21 : char szLCExtension[3] = {};
724 21 : if (*pszExtension >= 'A' && *pszExtension <= 'Z' && *pszModuleName == 't')
725 : {
726 0 : szLCExtension[0] = (*pszExtension) + 'a' - 'A';
727 0 : szLCExtension[1] = '\0';
728 0 : pszExtension = szLCExtension;
729 : }
730 :
731 : /* -------------------------------------------------------------------- */
732 : /* Build the filename. */
733 : /* -------------------------------------------------------------------- */
734 21 : const size_t nFilenameLen = strlen(GetDirPath()) + strlen(pszModuleName) +
735 21 : strlen(pszExtension) + 10;
736 21 : char *pszFilename = (char *)CPLMalloc(nFilenameLen);
737 :
738 21 : if (strlen(GetDirPath()) == 0)
739 0 : snprintf(pszFilename, nFilenameLen, "%s%s", pszModuleName,
740 : pszExtension);
741 : else
742 21 : snprintf(pszFilename, nFilenameLen, "%s/%s%s", GetDirPath(),
743 : pszModuleName, pszExtension);
744 :
745 21 : return pszFilename;
746 : }
747 :
748 : /************************************************************************/
749 : /* TestCapability() */
750 : /************************************************************************/
751 :
752 0 : int OGRTigerDataSource::TestCapability(const char *)
753 :
754 : {
755 0 : return FALSE;
756 : }
|