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