1 : /******************************************************************************
2 : * $Id: tigerfilebase.cpp 17225 2009-06-07 20:59:19Z rouault $
3 : *
4 : * Project: TIGER/Line Translator
5 : * Purpose: Implements TigerBaseFile class, providing common services to all
6 : * the tiger file readers.
7 : * Author: Frank Warmerdam, warmerdam@pobox.com
8 : *
9 : ******************************************************************************
10 : * Copyright (c) 1999, Frank Warmerdam
11 : *
12 : * Permission is hereby granted, free of charge, to any person obtaining a
13 : * copy of this software and associated documentation files (the "Software"),
14 : * to deal in the Software without restriction, including without limitation
15 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 : * and/or sell copies of the Software, and to permit persons to whom the
17 : * Software is furnished to do so, subject to the following conditions:
18 : *
19 : * The above copyright notice and this permission notice shall be included
20 : * in all copies or substantial portions of the Software.
21 : *
22 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 : * DEALINGS IN THE SOFTWARE.
29 : ****************************************************************************/
30 :
31 : #include "ogr_tiger.h"
32 : #include "cpl_conv.h"
33 : #include "cpl_error.h"
34 : #include "cpl_string.h"
35 :
36 : CPL_CVSID("$Id: tigerfilebase.cpp 17225 2009-06-07 20:59:19Z rouault $");
37 :
38 : /************************************************************************/
39 : /* TigerFileBase() */
40 : /************************************************************************/
41 :
42 0 : TigerFileBase::TigerFileBase()
43 :
44 : {
45 0 : pszShortModule = NULL;
46 0 : pszModule = NULL;
47 0 : fpPrimary = NULL;
48 0 : poFeatureDefn = NULL;
49 0 : nFeatures = 0;
50 0 : nVersionCode = 0;
51 0 : nVersion = TIGER_Unknown;
52 0 : }
53 :
54 : /************************************************************************/
55 : /* ~TigerFileBase() */
56 : /************************************************************************/
57 :
58 0 : TigerFileBase::~TigerFileBase()
59 :
60 : {
61 0 : CPLFree( pszModule );
62 0 : CPLFree( pszShortModule );
63 :
64 0 : if( poFeatureDefn != NULL )
65 : {
66 0 : poFeatureDefn->Release();
67 0 : poFeatureDefn = NULL;
68 : }
69 :
70 0 : if( fpPrimary != NULL )
71 : {
72 0 : VSIFClose( fpPrimary );
73 0 : fpPrimary = NULL;
74 : }
75 0 : }
76 :
77 : /************************************************************************/
78 : /* OpenFile() */
79 : /************************************************************************/
80 :
81 : int TigerFileBase::OpenFile( const char * pszModuleToOpen,
82 0 : const char *pszExtension )
83 :
84 : {
85 : char *pszFilename;
86 :
87 0 : CPLFree( pszModule );
88 0 : pszModule = NULL;
89 0 : CPLFree( pszShortModule );
90 0 : pszShortModule = NULL;
91 :
92 0 : if( fpPrimary != NULL )
93 : {
94 0 : VSIFClose( fpPrimary );
95 0 : fpPrimary = NULL;
96 : }
97 :
98 0 : if( pszModuleToOpen == NULL )
99 0 : return TRUE;
100 :
101 0 : pszFilename = poDS->BuildFilename( pszModuleToOpen, pszExtension );
102 :
103 0 : fpPrimary = VSIFOpen( pszFilename, "rb" );
104 :
105 0 : CPLFree( pszFilename );
106 :
107 0 : if( fpPrimary != NULL )
108 : {
109 0 : pszModule = CPLStrdup(pszModuleToOpen);
110 0 : pszShortModule = CPLStrdup(pszModuleToOpen);
111 0 : for( int i = 0; pszShortModule[i] != '\0'; i++ )
112 : {
113 0 : if( pszShortModule[i] == '.' )
114 0 : pszShortModule[i] = '\0';
115 : }
116 :
117 0 : SetupVersion();
118 :
119 0 : return TRUE;
120 : }
121 : else
122 0 : return FALSE;
123 : }
124 :
125 : /************************************************************************/
126 : /* SetupVersion() */
127 : /************************************************************************/
128 :
129 0 : void TigerFileBase::SetupVersion()
130 :
131 : {
132 : char aszRecordHead[6];
133 :
134 0 : VSIFSeek( fpPrimary, 0, SEEK_SET );
135 0 : VSIFRead( aszRecordHead, 1, 5, fpPrimary );
136 0 : aszRecordHead[5] = '\0';
137 0 : nVersionCode = atoi(aszRecordHead+1);
138 0 : VSIFSeek( fpPrimary, 0, SEEK_SET );
139 :
140 0 : nVersion = TigerClassifyVersion( nVersionCode );
141 0 : }
142 :
143 : /************************************************************************/
144 : /* EstablishRecordLength() */
145 : /************************************************************************/
146 :
147 0 : int TigerFileBase::EstablishRecordLength( FILE * fp )
148 :
149 : {
150 : char chCurrent;
151 0 : int nRecLen = 0;
152 :
153 0 : if( fp == NULL || VSIFSeek( fp, 0, SEEK_SET ) != 0 )
154 0 : return -1;
155 :
156 : /* -------------------------------------------------------------------- */
157 : /* Read through to the end of line. */
158 : /* -------------------------------------------------------------------- */
159 0 : chCurrent = '\0';
160 0 : while( VSIFRead( &chCurrent, 1, 1, fp ) == 1
161 : && chCurrent != 10
162 : && chCurrent != 13 )
163 : {
164 0 : nRecLen++;
165 : }
166 :
167 : /* -------------------------------------------------------------------- */
168 : /* Is the file zero length? */
169 : /* -------------------------------------------------------------------- */
170 0 : if( nRecLen == 0 )
171 : {
172 0 : return -1;
173 : }
174 :
175 0 : nRecLen++; /* for the 10 or 13 we encountered */
176 :
177 : /* -------------------------------------------------------------------- */
178 : /* Read through line terminator characters. We are trying to */
179 : /* handle cases of CR, CR/LF and LF/CR gracefully. */
180 : /* -------------------------------------------------------------------- */
181 0 : while( VSIFRead( &chCurrent, 1, 1, fp ) == 1
182 : && (chCurrent == 10 || chCurrent == 13 ) )
183 : {
184 0 : nRecLen++;
185 : }
186 :
187 0 : VSIFSeek( fp, 0, SEEK_SET );
188 :
189 0 : return nRecLen;
190 : }
191 :
192 : /************************************************************************/
193 : /* EstablishFeatureCount() */
194 : /************************************************************************/
195 :
196 0 : void TigerFileBase::EstablishFeatureCount()
197 :
198 : {
199 0 : if( fpPrimary == NULL )
200 0 : return;
201 :
202 0 : nRecordLength = EstablishRecordLength( fpPrimary );
203 :
204 0 : if( nRecordLength == -1 )
205 : {
206 0 : nRecordLength = 1;
207 0 : nFeatures = 0;
208 0 : return;
209 : }
210 :
211 : /* -------------------------------------------------------------------- */
212 : /* Now we think we know the fixed record length for the file */
213 : /* (including line terminators). Get the total file size, and */
214 : /* divide by this length to get the presumed number of records. */
215 : /* -------------------------------------------------------------------- */
216 : long nFileSize;
217 :
218 0 : VSIFSeek( fpPrimary, 0, SEEK_END );
219 0 : nFileSize = VSIFTell( fpPrimary );
220 :
221 0 : if( (nFileSize % nRecordLength) != 0 )
222 : {
223 : CPLError( CE_Warning, CPLE_FileIO,
224 : "TigerFileBase::EstablishFeatureCount(): "
225 : "File length %d doesn't divide by record length %d.\n",
226 0 : (int) nFileSize, (int) nRecordLength );
227 : }
228 :
229 0 : nFeatures = nFileSize / nRecordLength;
230 : }
231 :
232 : /************************************************************************/
233 : /* GetField() */
234 : /************************************************************************/
235 :
236 : CPLString TigerFileBase::GetField( const char * pachRawDataRecord,
237 0 : int nStartChar, int nEndChar )
238 :
239 : {
240 : char aszField[128];
241 0 : int nLength = nEndChar - nStartChar + 1;
242 :
243 0 : CPLAssert( nEndChar - nStartChar + 2 < (int) sizeof(aszField) );
244 :
245 0 : strncpy( aszField, pachRawDataRecord + nStartChar - 1, nLength );
246 :
247 0 : aszField[nLength] = '\0';
248 0 : while( nLength > 0 && aszField[nLength-1] == ' ' )
249 0 : aszField[--nLength] = '\0';
250 :
251 0 : return aszField;
252 : }
253 :
254 : /************************************************************************/
255 : /* SetField() */
256 : /* */
257 : /* Set a field on an OGRFeature from a tiger record, or leave */
258 : /* NULL if the value isn't found. */
259 : /************************************************************************/
260 :
261 : void TigerFileBase::SetField( OGRFeature *poFeature, const char *pszField,
262 0 : const char *pachRecord, int nStart, int nEnd )
263 :
264 : {
265 0 : const char *pszFieldValue = GetField( pachRecord, nStart, nEnd );
266 :
267 0 : if( pszFieldValue[0] == '\0' )
268 0 : return;
269 :
270 0 : poFeature->SetField( pszField, pszFieldValue );
271 : }
272 :
273 : /************************************************************************/
274 : /* WriteField() */
275 : /* */
276 : /* Write a field into a record buffer with the indicated */
277 : /* formatting, or leave blank if not found. */
278 : /************************************************************************/
279 :
280 : int TigerFileBase::WriteField( OGRFeature *poFeature, const char *pszField,
281 : char *pachRecord, int nStart, int nEnd,
282 0 : char chFormat, char chType )
283 :
284 : {
285 0 : int iField = poFeature->GetFieldIndex( pszField );
286 : char szValue[512], szFormat[32];
287 :
288 0 : CPLAssert( nEnd - nStart + 1 < (int) sizeof(szValue)-1 );
289 :
290 0 : if( iField < 0 || !poFeature->IsFieldSet( iField ) )
291 0 : return FALSE;
292 :
293 0 : if( chType == 'N' && chFormat == 'L' )
294 : {
295 0 : sprintf( szFormat, "%%0%dd", nEnd - nStart + 1 );
296 0 : sprintf( szValue, szFormat, poFeature->GetFieldAsInteger( iField ) );
297 : }
298 0 : else if( chType == 'N' && chFormat == 'R' )
299 : {
300 0 : sprintf( szFormat, "%%%dd", nEnd - nStart + 1 );
301 0 : sprintf( szValue, szFormat, poFeature->GetFieldAsInteger( iField ) );
302 : }
303 0 : else if( chType == 'A' && chFormat == 'L' )
304 : {
305 : strncpy( szValue, poFeature->GetFieldAsString( iField ),
306 0 : sizeof(szValue) - 1 );
307 0 : if( (int) strlen(szValue) < nEnd - nStart + 1 )
308 : memset( szValue + strlen(szValue), ' ',
309 0 : nEnd - nStart + 1 - strlen(szValue) );
310 : }
311 0 : else if( chType == 'A' && chFormat == 'R' )
312 : {
313 0 : sprintf( szFormat, "%%%ds", nEnd - nStart + 1 );
314 0 : sprintf( szValue, szFormat, poFeature->GetFieldAsString( iField ) );
315 : }
316 : else
317 : {
318 0 : CPLAssert( FALSE );
319 0 : return FALSE;
320 : }
321 :
322 0 : strncpy( pachRecord + nStart - 1, szValue, nEnd - nStart + 1 );
323 :
324 0 : return TRUE;
325 : }
326 :
327 : /************************************************************************/
328 : /* WritePoint() */
329 : /************************************************************************/
330 :
331 : int TigerFileBase::WritePoint( char *pachRecord, int nStart,
332 0 : double dfX, double dfY )
333 :
334 : {
335 : char szTemp[20];
336 :
337 0 : if( dfX == 0.0 && dfY == 0.0 )
338 : {
339 0 : strncpy( pachRecord + nStart - 1, "+000000000+00000000", 19 );
340 : }
341 : else
342 : {
343 : sprintf( szTemp, "%+10d%+9d",
344 : (int) floor(dfX * 1000000 + 0.5),
345 0 : (int) floor(dfY * 1000000 + 0.5) );
346 0 : strncpy( pachRecord + nStart - 1, szTemp, 19 );
347 : }
348 :
349 0 : return TRUE;
350 : }
351 :
352 : /************************************************************************/
353 : /* WriteRecord() */
354 : /************************************************************************/
355 :
356 : int TigerFileBase::WriteRecord( char *pachRecord, int nRecLen,
357 0 : const char *pszType, FILE * fp )
358 :
359 : {
360 0 : if( fp == NULL )
361 0 : fp = fpPrimary;
362 :
363 0 : pachRecord[0] = *pszType;
364 :
365 :
366 : /*
367 : * Prior to TIGER_2002, type 5 files lacked the version. So write
368 : * the version in the record iff we're using TIGER_2002 or higher,
369 : * or if this is not type "5"
370 : */
371 0 : if ( (poDS->GetVersion() >= TIGER_2002) ||
372 : (!EQUAL(pszType, "5")) )
373 : {
374 : char szVersion[5];
375 0 : sprintf( szVersion, "%04d", poDS->GetVersionCode() );
376 0 : strncpy( pachRecord + 1, szVersion, 4 );
377 : }
378 :
379 0 : VSIFWrite( pachRecord, nRecLen, 1, fp );
380 0 : VSIFWrite( (void *) "\r\n", 2, 1, fp );
381 :
382 0 : return TRUE;
383 : }
384 :
385 : /************************************************************************/
386 : /* SetWriteModule() */
387 : /* */
388 : /* Setup our access to be to the module indicated in the feature. */
389 : /************************************************************************/
390 :
391 : int TigerFileBase::SetWriteModule( const char *pszExtension, int nRecLen,
392 0 : OGRFeature *poFeature )
393 :
394 : {
395 : /* -------------------------------------------------------------------- */
396 : /* Work out what module we should be writing to. */
397 : /* -------------------------------------------------------------------- */
398 0 : const char *pszTargetModule = poFeature->GetFieldAsString( "MODULE" );
399 : char szFullModule[30];
400 :
401 : /* TODO/notdef: eventually more logic based on FILE and STATE/COUNTY can
402 : be inserted here. */
403 :
404 0 : if( pszTargetModule == NULL )
405 0 : return FALSE;
406 :
407 0 : sprintf( szFullModule, "%s.RT", pszTargetModule );
408 :
409 : /* -------------------------------------------------------------------- */
410 : /* Is this our current module? */
411 : /* -------------------------------------------------------------------- */
412 0 : if( pszModule != NULL && EQUAL(szFullModule,pszModule) )
413 0 : return TRUE;
414 :
415 : /* -------------------------------------------------------------------- */
416 : /* Cleanup the previous file, if any. */
417 : /* -------------------------------------------------------------------- */
418 0 : if( fpPrimary != NULL )
419 : {
420 0 : VSIFClose( fpPrimary );
421 0 : fpPrimary = NULL;
422 : }
423 :
424 0 : if( pszModule != NULL )
425 : {
426 0 : CPLFree( pszModule );
427 0 : pszModule = NULL;
428 : }
429 :
430 : /* -------------------------------------------------------------------- */
431 : /* Is this a module we have never written to before? If so, we */
432 : /* will try to blow away any existing files in this file set. */
433 : /* -------------------------------------------------------------------- */
434 0 : if( !poDS->CheckModule( szFullModule ) )
435 : {
436 0 : poDS->DeleteModuleFiles( szFullModule );
437 0 : poDS->AddModule( szFullModule );
438 : }
439 :
440 : /* -------------------------------------------------------------------- */
441 : /* Does this file already exist? */
442 : /* -------------------------------------------------------------------- */
443 : const char *pszFilename;
444 :
445 0 : pszFilename = poDS->BuildFilename( szFullModule, pszExtension );
446 :
447 0 : fpPrimary = VSIFOpen( pszFilename, "ab" );
448 0 : if( fpPrimary == NULL )
449 0 : return FALSE;
450 :
451 0 : pszModule = CPLStrdup( szFullModule );
452 :
453 0 : return TRUE;
454 : }
455 :
456 : /************************************************************************/
457 : /* AddFieldDefns() */
458 : /************************************************************************/
459 : void TigerFileBase::AddFieldDefns(TigerRecordInfo *psRTInfo,
460 0 : OGRFeatureDefn *poFeatureDefn)
461 : {
462 0 : OGRFieldDefn oField("",OFTInteger);
463 : int i, bLFieldHack;
464 :
465 : bLFieldHack =
466 0 : CSLTestBoolean( CPLGetConfigOption( "TIGER_LFIELD_AS_STRING", "NO" ) );
467 :
468 0 : for (i=0; i<psRTInfo->nFieldCount; ++i) {
469 0 : if (psRTInfo->pasFields[i].bDefine) {
470 0 : OGRFieldType eFT = psRTInfo->pasFields[i].OGRtype;
471 :
472 0 : if( bLFieldHack
473 : && psRTInfo->pasFields[i].cFmt == 'L'
474 : && psRTInfo->pasFields[i].cType == 'N' )
475 0 : eFT = OFTString;
476 :
477 : oField.Set( psRTInfo->pasFields[i].pszFieldName, eFT,
478 0 : psRTInfo->pasFields[i].nLen );
479 0 : poFeatureDefn->AddFieldDefn( &oField );
480 : }
481 0 : }
482 0 : }
483 :
484 : /************************************************************************/
485 : /* SetFields() */
486 : /************************************************************************/
487 :
488 : void TigerFileBase::SetFields(TigerRecordInfo *psRTInfo,
489 : OGRFeature *poFeature,
490 0 : char *achRecord)
491 : {
492 : int i;
493 0 : for (i=0; i<psRTInfo->nFieldCount; ++i) {
494 0 : if (psRTInfo->pasFields[i].bSet) {
495 : SetField( poFeature,
496 : psRTInfo->pasFields[i].pszFieldName,
497 : achRecord,
498 : psRTInfo->pasFields[i].nBeg,
499 0 : psRTInfo->pasFields[i].nEnd );
500 : }
501 : }
502 0 : }
503 :
504 : /************************************************************************/
505 : /* WriteField() */
506 : /************************************************************************/
507 : void TigerFileBase::WriteFields(TigerRecordInfo *psRTInfo,
508 : OGRFeature *poFeature,
509 0 : char *szRecord)
510 : {
511 : int i;
512 0 : for (i=0; i<psRTInfo->nFieldCount; ++i) {
513 0 : if (psRTInfo->pasFields[i].bWrite) {
514 : WriteField( poFeature,
515 : psRTInfo->pasFields[i].pszFieldName,
516 : szRecord,
517 : psRTInfo->pasFields[i].nBeg,
518 : psRTInfo->pasFields[i].nEnd,
519 : psRTInfo->pasFields[i].cFmt,
520 0 : psRTInfo->pasFields[i].cType );
521 : }
522 : }
523 0 : }
|