1 : /******************************************************************************
2 : * $Id: ddfmodule.cpp 23595 2011-12-18 22:58:47Z rouault $
3 : *
4 : * Project: ISO 8211 Access
5 : * Purpose: Implements the DDFModule class.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 1999, Frank Warmerdam
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 "iso8211.h"
31 : #include "cpl_conv.h"
32 :
33 : CPL_CVSID("$Id: ddfmodule.cpp 23595 2011-12-18 22:58:47Z rouault $");
34 :
35 : /************************************************************************/
36 : /* DDFModule() */
37 : /************************************************************************/
38 :
39 : /**
40 : * The constructor.
41 : */
42 :
43 11889 : DDFModule::DDFModule()
44 :
45 : {
46 11889 : nFieldDefnCount = 0;
47 11889 : papoFieldDefns = NULL;
48 11889 : poRecord = NULL;
49 :
50 11889 : papoClones = NULL;
51 11889 : nCloneCount = nMaxCloneCount = 0;
52 :
53 11889 : fpDDF = NULL;
54 11889 : bReadOnly = TRUE;
55 :
56 11889 : _interchangeLevel = '\0';
57 11889 : _inlineCodeExtensionIndicator = '\0';
58 11889 : _versionNumber = '\0';
59 11889 : _appIndicator = '\0';
60 11889 : _fieldControlLength = '\0';
61 11889 : strcpy( _extendedCharSet, " ! " );
62 :
63 11889 : _recLength = 0;
64 11889 : _leaderIden = 'L';
65 11889 : _fieldAreaStart = 0;
66 11889 : _sizeFieldLength = 0;
67 11889 : _sizeFieldPos = 0;
68 11889 : _sizeFieldTag = 0;
69 11889 : }
70 :
71 : /************************************************************************/
72 : /* ~DDFModule() */
73 : /************************************************************************/
74 :
75 : /**
76 : * The destructor.
77 : */
78 :
79 11889 : DDFModule::~DDFModule()
80 :
81 : {
82 11889 : Close();
83 11889 : }
84 :
85 : /************************************************************************/
86 : /* Close() */
87 : /* */
88 : /* Note that closing a file also destroys essentially all other */
89 : /* module datastructures. */
90 : /************************************************************************/
91 :
92 : /**
93 : * Close an ISO 8211 file.
94 : */
95 :
96 11897 : void DDFModule::Close()
97 :
98 : {
99 : /* -------------------------------------------------------------------- */
100 : /* Close the file. */
101 : /* -------------------------------------------------------------------- */
102 11897 : if( fpDDF != NULL )
103 : {
104 85 : VSIFCloseL( fpDDF );
105 85 : fpDDF = NULL;
106 : }
107 :
108 : /* -------------------------------------------------------------------- */
109 : /* Cleanup the working record. */
110 : /* -------------------------------------------------------------------- */
111 11897 : if( poRecord != NULL )
112 : {
113 68 : delete poRecord;
114 68 : poRecord = NULL;
115 : }
116 :
117 : /* -------------------------------------------------------------------- */
118 : /* Cleanup the clones. Deleting them will cause a callback to */
119 : /* remove them from the list. */
120 : /* -------------------------------------------------------------------- */
121 47371 : while( nCloneCount > 0 )
122 23577 : delete papoClones[0];
123 :
124 11897 : nMaxCloneCount = 0;
125 11897 : CPLFree( papoClones );
126 11897 : papoClones = NULL;
127 :
128 : /* -------------------------------------------------------------------- */
129 : /* Cleanup the field definitions. */
130 : /* -------------------------------------------------------------------- */
131 : int i;
132 :
133 12575 : for( i = 0; i < nFieldDefnCount; i++ )
134 678 : delete papoFieldDefns[i];
135 11897 : CPLFree( papoFieldDefns );
136 11897 : papoFieldDefns = NULL;
137 11897 : nFieldDefnCount = 0;
138 11897 : }
139 :
140 : /************************************************************************/
141 : /* Open() */
142 : /* */
143 : /* Open an ISO 8211 file, and read the DDR record to build the */
144 : /* field definitions. */
145 : /************************************************************************/
146 :
147 : /**
148 : * Open a ISO 8211 (DDF) file for reading.
149 : *
150 : * If the open succeeds the data descriptive record (DDR) will have been
151 : * read, and all the field and subfield definitions will be available.
152 : *
153 : * @param pszFilename The name of the file to open.
154 : * @param bFailQuietly If FALSE a CPL Error is issued for non-8211 files,
155 : * otherwise quietly return NULL.
156 : *
157 : * @return FALSE if the open fails or TRUE if it succeeds. Errors messages
158 : * are issued internally with CPLError().
159 : */
160 :
161 91 : int DDFModule::Open( const char * pszFilename, int bFailQuietly )
162 :
163 : {
164 : static const int nLeaderSize = 24;
165 :
166 : /* -------------------------------------------------------------------- */
167 : /* Close the existing file if there is one. */
168 : /* -------------------------------------------------------------------- */
169 91 : if( fpDDF != NULL )
170 0 : Close();
171 :
172 : /* -------------------------------------------------------------------- */
173 : /* Open the file. */
174 : /* -------------------------------------------------------------------- */
175 91 : fpDDF = VSIFOpenL( pszFilename, "rb" );
176 :
177 91 : if( fpDDF == NULL )
178 : {
179 6 : if( !bFailQuietly )
180 : CPLError( CE_Failure, CPLE_OpenFailed,
181 : "Unable to open DDF file `%s'.",
182 0 : pszFilename );
183 6 : return FALSE;
184 : }
185 :
186 : /* -------------------------------------------------------------------- */
187 : /* Read the 24 byte leader. */
188 : /* -------------------------------------------------------------------- */
189 : char achLeader[nLeaderSize];
190 :
191 85 : if( (int)VSIFReadL( achLeader, 1, nLeaderSize, fpDDF ) != nLeaderSize )
192 : {
193 0 : VSIFCloseL( fpDDF );
194 0 : fpDDF = NULL;
195 :
196 0 : if( !bFailQuietly )
197 : CPLError( CE_Failure, CPLE_FileIO,
198 : "Leader is short on DDF file `%s'.",
199 0 : pszFilename );
200 :
201 0 : return FALSE;
202 : }
203 :
204 : /* -------------------------------------------------------------------- */
205 : /* Verify that this appears to be a valid DDF file. */
206 : /* -------------------------------------------------------------------- */
207 85 : int i, bValid = TRUE;
208 :
209 2125 : for( i = 0; i < nLeaderSize; i++ )
210 : {
211 2040 : if( achLeader[i] < 32 || achLeader[i] > 126 )
212 0 : bValid = FALSE;
213 : }
214 :
215 85 : if( achLeader[5] != '1' && achLeader[5] != '2' && achLeader[5] != '3' )
216 0 : bValid = FALSE;
217 :
218 85 : if( achLeader[6] != 'L' )
219 0 : bValid = FALSE;
220 85 : if( achLeader[8] != '1' && achLeader[8] != ' ' )
221 0 : bValid = FALSE;
222 :
223 : /* -------------------------------------------------------------------- */
224 : /* Extract information from leader. */
225 : /* -------------------------------------------------------------------- */
226 :
227 85 : if( bValid )
228 : {
229 85 : _recLength = DDFScanInt( achLeader+0, 5 );
230 85 : _interchangeLevel = achLeader[5];
231 85 : _leaderIden = achLeader[6];
232 85 : _inlineCodeExtensionIndicator = achLeader[7];
233 85 : _versionNumber = achLeader[8];
234 85 : _appIndicator = achLeader[9];
235 85 : _fieldControlLength = DDFScanInt(achLeader+10,2);
236 85 : _fieldAreaStart = DDFScanInt(achLeader+12,5);
237 85 : _extendedCharSet[0] = achLeader[17];
238 85 : _extendedCharSet[1] = achLeader[18];
239 85 : _extendedCharSet[2] = achLeader[19];
240 85 : _extendedCharSet[3] = '\0';
241 85 : _sizeFieldLength = DDFScanInt(achLeader+20,1);
242 85 : _sizeFieldPos = DDFScanInt(achLeader+21,1);
243 85 : _sizeFieldTag = DDFScanInt(achLeader+23,1);
244 :
245 85 : if( _recLength < nLeaderSize || _fieldControlLength == 0
246 : || _fieldAreaStart < 24 || _sizeFieldLength == 0
247 : || _sizeFieldPos == 0 || _sizeFieldTag == 0 )
248 : {
249 0 : bValid = FALSE;
250 : }
251 : }
252 :
253 : /* -------------------------------------------------------------------- */
254 : /* If the header is invalid, then clean up, report the error */
255 : /* and return. */
256 : /* -------------------------------------------------------------------- */
257 85 : if( !bValid )
258 : {
259 0 : VSIFCloseL( fpDDF );
260 0 : fpDDF = NULL;
261 :
262 0 : if( !bFailQuietly )
263 : CPLError( CE_Failure, CPLE_AppDefined,
264 : "File `%s' does not appear to have\n"
265 : "a valid ISO 8211 header.\n",
266 0 : pszFilename );
267 0 : return FALSE;
268 : }
269 :
270 : /* -------------------------------------------------------------------- */
271 : /* Read the whole record info memory. */
272 : /* -------------------------------------------------------------------- */
273 : char *pachRecord;
274 :
275 85 : pachRecord = (char *) CPLMalloc(_recLength);
276 85 : memcpy( pachRecord, achLeader, nLeaderSize );
277 :
278 85 : if( VSIFReadL( pachRecord+nLeaderSize, 1, _recLength-nLeaderSize, fpDDF )
279 : != _recLength - nLeaderSize )
280 : {
281 0 : if( !bFailQuietly )
282 : CPLError( CE_Failure, CPLE_FileIO,
283 : "Header record is short on DDF file `%s'.",
284 0 : pszFilename );
285 :
286 0 : return FALSE;
287 : }
288 :
289 : /* -------------------------------------------------------------------- */
290 : /* First make a pass counting the directory entries. */
291 : /* -------------------------------------------------------------------- */
292 85 : int nFieldEntryWidth, nFDCount = 0;
293 :
294 85 : nFieldEntryWidth = _sizeFieldLength + _sizeFieldPos + _sizeFieldTag;
295 :
296 763 : for( i = nLeaderSize; i < _recLength; i += nFieldEntryWidth )
297 : {
298 763 : if( pachRecord[i] == DDF_FIELD_TERMINATOR )
299 85 : break;
300 :
301 678 : nFDCount++;
302 : }
303 :
304 : /* -------------------------------------------------------------------- */
305 : /* Allocate, and read field definitions. */
306 : /* -------------------------------------------------------------------- */
307 763 : for( i = 0; i < nFDCount; i++ )
308 : {
309 : char szTag[128];
310 678 : int nEntryOffset = nLeaderSize + i*nFieldEntryWidth;
311 : int nFieldLength, nFieldPos;
312 : DDFFieldDefn *poFDefn;
313 :
314 678 : strncpy( szTag, pachRecord+nEntryOffset, _sizeFieldTag );
315 678 : szTag[_sizeFieldTag] = '\0';
316 :
317 678 : nEntryOffset += _sizeFieldTag;
318 678 : nFieldLength = DDFScanInt( pachRecord+nEntryOffset, _sizeFieldLength );
319 :
320 678 : nEntryOffset += _sizeFieldLength;
321 678 : nFieldPos = DDFScanInt( pachRecord+nEntryOffset, _sizeFieldPos );
322 :
323 678 : if (_fieldAreaStart+nFieldPos < 0 ||
324 : _recLength - (_fieldAreaStart+nFieldPos) < nFieldLength)
325 : {
326 0 : if( !bFailQuietly )
327 : CPLError( CE_Failure, CPLE_FileIO,
328 : "Header record invalid on DDF file `%s'.",
329 0 : pszFilename );
330 :
331 0 : CPLFree( pachRecord );
332 0 : return FALSE;
333 : }
334 :
335 678 : poFDefn = new DDFFieldDefn();
336 678 : if( poFDefn->Initialize( this, szTag, nFieldLength,
337 : pachRecord+_fieldAreaStart+nFieldPos ) )
338 678 : AddField( poFDefn );
339 : else
340 0 : delete poFDefn;
341 : }
342 :
343 85 : CPLFree( pachRecord );
344 :
345 : /* -------------------------------------------------------------------- */
346 : /* Record the current file offset, the beginning of the first */
347 : /* data record. */
348 : /* -------------------------------------------------------------------- */
349 85 : nFirstRecordOffset = (long)VSIFTellL( fpDDF );
350 :
351 85 : return TRUE;
352 : }
353 :
354 : /************************************************************************/
355 : /* Initialize() */
356 : /************************************************************************/
357 :
358 0 : int DDFModule::Initialize( char chInterchangeLevel,
359 : char chLeaderIden,
360 : char chCodeExtensionIndicator,
361 : char chVersionNumber,
362 : char chAppIndicator,
363 : const char *pszExtendedCharSet,
364 : int nSizeFieldLength,
365 : int nSizeFieldPos,
366 : int nSizeFieldTag )
367 :
368 : {
369 0 : _interchangeLevel = chInterchangeLevel;
370 0 : _leaderIden = chLeaderIden;
371 0 : _inlineCodeExtensionIndicator = chCodeExtensionIndicator;
372 0 : _versionNumber = chVersionNumber;
373 0 : _appIndicator = chAppIndicator;
374 0 : strcpy( _extendedCharSet, pszExtendedCharSet );
375 0 : _sizeFieldLength = nSizeFieldLength;
376 0 : _sizeFieldPos = nSizeFieldPos;
377 0 : _sizeFieldTag = nSizeFieldTag;
378 :
379 0 : return TRUE;
380 : }
381 :
382 : /************************************************************************/
383 : /* Create() */
384 : /************************************************************************/
385 :
386 0 : int DDFModule::Create( const char *pszFilename )
387 :
388 : {
389 0 : CPLAssert( fpDDF == NULL );
390 :
391 : /* -------------------------------------------------------------------- */
392 : /* Create the file on disk. */
393 : /* -------------------------------------------------------------------- */
394 0 : fpDDF = VSIFOpenL( pszFilename, "wb+" );
395 0 : if( fpDDF == NULL )
396 : {
397 : CPLError( CE_Failure, CPLE_OpenFailed,
398 : "Failed to create file %s, check path and permissions.",
399 0 : pszFilename );
400 0 : return FALSE;
401 : }
402 :
403 0 : bReadOnly = FALSE;
404 :
405 : /* -------------------------------------------------------------------- */
406 : /* Prepare all the field definition information. */
407 : /* -------------------------------------------------------------------- */
408 : int iField;
409 :
410 0 : _fieldControlLength = 9;
411 : _recLength = 24
412 : + nFieldDefnCount * (_sizeFieldLength+_sizeFieldPos+_sizeFieldTag)
413 0 : + 1;
414 :
415 0 : _fieldAreaStart = _recLength;
416 :
417 0 : for( iField=0; iField < nFieldDefnCount; iField++ )
418 : {
419 : int nLength;
420 :
421 0 : papoFieldDefns[iField]->GenerateDDREntry( NULL, &nLength );
422 0 : _recLength += nLength;
423 : }
424 :
425 : /* -------------------------------------------------------------------- */
426 : /* Setup 24 byte leader. */
427 : /* -------------------------------------------------------------------- */
428 : char achLeader[25];
429 :
430 0 : sprintf( achLeader+0, "%05d", (int) _recLength );
431 0 : achLeader[5] = _interchangeLevel;
432 0 : achLeader[6] = _leaderIden;
433 0 : achLeader[7] = _inlineCodeExtensionIndicator;
434 0 : achLeader[8] = _versionNumber;
435 0 : achLeader[9] = _appIndicator;
436 0 : sprintf( achLeader+10, "%02d", (int) _fieldControlLength );
437 0 : sprintf( achLeader+12, "%05d", (int) _fieldAreaStart );
438 0 : strncpy( achLeader+17, _extendedCharSet, 3 );
439 0 : sprintf( achLeader+20, "%1d", (int) _sizeFieldLength );
440 0 : sprintf( achLeader+21, "%1d", (int) _sizeFieldPos );
441 0 : achLeader[22] = '0';
442 0 : sprintf( achLeader+23, "%1d", (int) _sizeFieldTag );
443 0 : VSIFWriteL( achLeader, 24, 1, fpDDF );
444 :
445 : /* -------------------------------------------------------------------- */
446 : /* Write out directory entries. */
447 : /* -------------------------------------------------------------------- */
448 0 : int nOffset = 0;
449 0 : for( iField=0; iField < nFieldDefnCount; iField++ )
450 : {
451 : char achDirEntry[12];
452 : int nLength;
453 :
454 0 : papoFieldDefns[iField]->GenerateDDREntry( NULL, &nLength );
455 :
456 0 : strcpy( achDirEntry, papoFieldDefns[iField]->GetName() );
457 0 : sprintf( achDirEntry + _sizeFieldTag, "%03d", nLength );
458 : sprintf( achDirEntry + _sizeFieldTag + _sizeFieldLength,
459 0 : "%04d", nOffset );
460 0 : nOffset += nLength;
461 :
462 0 : VSIFWriteL( achDirEntry, 11, 1, fpDDF );
463 : }
464 :
465 0 : char chUT = DDF_FIELD_TERMINATOR;
466 0 : VSIFWriteL( &chUT, 1, 1, fpDDF );
467 :
468 : /* -------------------------------------------------------------------- */
469 : /* Write out the field descriptions themselves. */
470 : /* -------------------------------------------------------------------- */
471 0 : for( iField=0; iField < nFieldDefnCount; iField++ )
472 : {
473 : char *pachData;
474 : int nLength;
475 :
476 0 : papoFieldDefns[iField]->GenerateDDREntry( &pachData, &nLength );
477 0 : VSIFWriteL( pachData, nLength, 1, fpDDF );
478 0 : CPLFree( pachData );
479 : }
480 :
481 0 : return TRUE;
482 : }
483 :
484 : /************************************************************************/
485 : /* Dump() */
486 : /************************************************************************/
487 :
488 : /**
489 : * Write out module info to debugging file.
490 : *
491 : * A variety of information about the module is written to the debugging
492 : * file. This includes all the field and subfield definitions read from
493 : * the header.
494 : *
495 : * @param fp The standard io file handle to write to. ie. stderr.
496 : */
497 :
498 0 : void DDFModule::Dump( FILE * fp )
499 :
500 : {
501 0 : fprintf( fp, "DDFModule:\n" );
502 0 : fprintf( fp, " _recLength = %ld\n", _recLength );
503 0 : fprintf( fp, " _interchangeLevel = %c\n", _interchangeLevel );
504 0 : fprintf( fp, " _leaderIden = %c\n", _leaderIden );
505 : fprintf( fp, " _inlineCodeExtensionIndicator = %c\n",
506 0 : _inlineCodeExtensionIndicator );
507 0 : fprintf( fp, " _versionNumber = %c\n", _versionNumber );
508 0 : fprintf( fp, " _appIndicator = %c\n", _appIndicator );
509 0 : fprintf( fp, " _extendedCharSet = `%s'\n", _extendedCharSet );
510 0 : fprintf( fp, " _fieldControlLength = %d\n", _fieldControlLength );
511 0 : fprintf( fp, " _fieldAreaStart = %ld\n", _fieldAreaStart );
512 0 : fprintf( fp, " _sizeFieldLength = %ld\n", _sizeFieldLength );
513 0 : fprintf( fp, " _sizeFieldPos = %ld\n", _sizeFieldPos );
514 0 : fprintf( fp, " _sizeFieldTag = %ld\n", _sizeFieldTag );
515 :
516 0 : for( int i = 0; i < nFieldDefnCount; i++ )
517 : {
518 0 : papoFieldDefns[i]->Dump( fp );
519 : }
520 0 : }
521 :
522 : /************************************************************************/
523 : /* FindFieldDefn() */
524 : /************************************************************************/
525 :
526 : /**
527 : * Fetch the definition of the named field.
528 : *
529 : * This function will scan the DDFFieldDefn's on this module, to find
530 : * one with the indicated field name.
531 : *
532 : * @param pszFieldName The name of the field to search for. The comparison is
533 : * case insensitive.
534 : *
535 : * @return A pointer to the request DDFFieldDefn object is returned, or NULL
536 : * if none matching the name are found. The return object remains owned by
537 : * the DDFModule, and should not be deleted by application code.
538 : */
539 :
540 89958 : DDFFieldDefn *DDFModule::FindFieldDefn( const char *pszFieldName )
541 :
542 : {
543 : int i;
544 :
545 : /* -------------------------------------------------------------------- */
546 : /* This pass tries to reduce the cost of comparing strings by */
547 : /* first checking the first character, and by using strcmp() */
548 : /* -------------------------------------------------------------------- */
549 873840 : for( i = 0; i < nFieldDefnCount; i++ )
550 : {
551 873819 : const char *pszThisName = papoFieldDefns[i]->GetName();
552 :
553 873819 : if( *pszThisName == *pszFieldName
554 : && strcmp( pszFieldName+1, pszThisName+1) == 0 )
555 89937 : return papoFieldDefns[i];
556 : }
557 :
558 : /* -------------------------------------------------------------------- */
559 : /* Now do a more general check. Application code may not */
560 : /* always use the correct name case. */
561 : /* -------------------------------------------------------------------- */
562 160 : for( i = 0; i < nFieldDefnCount; i++ )
563 : {
564 139 : if( EQUAL(pszFieldName, papoFieldDefns[i]->GetName()) )
565 0 : return papoFieldDefns[i];
566 : }
567 :
568 21 : return NULL;
569 : }
570 :
571 : /************************************************************************/
572 : /* ReadRecord() */
573 : /* */
574 : /* Read one record from the file, and return to the */
575 : /* application. The returned record is owned by the module, */
576 : /* and is reused from call to call in order to preserve headers */
577 : /* when they aren't being re-read from record to record. */
578 : /************************************************************************/
579 :
580 : /**
581 : * Read one record from the file.
582 : *
583 : * @return A pointer to a DDFRecord object is returned, or NULL if a read
584 : * error, or end of file occurs. The returned record is owned by the
585 : * module, and should not be deleted by the application. The record is
586 : * only valid untill the next ReadRecord() at which point it is overwritten.
587 : */
588 :
589 24554 : DDFRecord *DDFModule::ReadRecord()
590 :
591 : {
592 24554 : if( poRecord == NULL )
593 68 : poRecord = new DDFRecord( this );
594 :
595 24554 : if( poRecord->Read() )
596 24519 : return poRecord;
597 : else
598 35 : return NULL;
599 : }
600 :
601 : /************************************************************************/
602 : /* AddField() */
603 : /************************************************************************/
604 :
605 : /**
606 : * Add new field definition.
607 : *
608 : * Field definitions may only be added to DDFModules being used for
609 : * writing, not those being used for reading. Ownership of the
610 : * DDFFieldDefn object is taken by the DDFModule.
611 : *
612 : * @param poNewFDefn definition to be added to the module.
613 : */
614 :
615 678 : void DDFModule::AddField( DDFFieldDefn *poNewFDefn )
616 :
617 : {
618 678 : nFieldDefnCount++;
619 : papoFieldDefns = (DDFFieldDefn **)
620 678 : CPLRealloc(papoFieldDefns, sizeof(void*)*nFieldDefnCount);
621 678 : papoFieldDefns[nFieldDefnCount-1] = poNewFDefn;
622 678 : }
623 :
624 : /************************************************************************/
625 : /* GetField() */
626 : /************************************************************************/
627 :
628 : /**
629 : * Fetch a field definition by index.
630 : *
631 : * @param i (from 0 to GetFieldCount() - 1.
632 : * @return the returned field pointer or NULL if the index is out of range.
633 : */
634 :
635 0 : DDFFieldDefn *DDFModule::GetField(int i)
636 :
637 : {
638 0 : if( i < 0 || i >= nFieldDefnCount )
639 0 : return NULL;
640 : else
641 0 : return papoFieldDefns[i];
642 : }
643 :
644 : /************************************************************************/
645 : /* AddCloneRecord() */
646 : /* */
647 : /* We want to keep track of cloned records, so we can clean */
648 : /* them up when the module is destroyed. */
649 : /************************************************************************/
650 :
651 23967 : void DDFModule::AddCloneRecord( DDFRecord * poRecord )
652 :
653 : {
654 : /* -------------------------------------------------------------------- */
655 : /* Do we need to grow the container array? */
656 : /* -------------------------------------------------------------------- */
657 23967 : if( nCloneCount == nMaxCloneCount )
658 : {
659 43 : nMaxCloneCount = nCloneCount*2 + 20;
660 : papoClones = (DDFRecord **) CPLRealloc(papoClones,
661 43 : nMaxCloneCount * sizeof(void*));
662 : }
663 :
664 : /* -------------------------------------------------------------------- */
665 : /* Add to the list. */
666 : /* -------------------------------------------------------------------- */
667 23967 : papoClones[nCloneCount++] = poRecord;
668 23967 : }
669 :
670 : /************************************************************************/
671 : /* RemoveCloneRecord() */
672 : /************************************************************************/
673 :
674 23967 : void DDFModule::RemoveCloneRecord( DDFRecord * poRecord )
675 :
676 : {
677 : int i;
678 :
679 31396 : for( i = 0; i < nCloneCount; i++ )
680 : {
681 31396 : if( papoClones[i] == poRecord )
682 : {
683 23967 : papoClones[i] = papoClones[nCloneCount-1];
684 23967 : nCloneCount--;
685 23967 : return;
686 : }
687 : }
688 :
689 0 : CPLAssert( FALSE );
690 : }
691 :
692 : /************************************************************************/
693 : /* Rewind() */
694 : /************************************************************************/
695 :
696 : /**
697 : * Return to first record.
698 : *
699 : * The next call to ReadRecord() will read the first data record in the file.
700 : *
701 : * @param nOffset the offset in the file to return to. By default this is
702 : * -1, a special value indicating that reading should return to the first
703 : * data record. Otherwise it is an absolute byte offset in the file.
704 : */
705 :
706 24 : void DDFModule::Rewind( long nOffset )
707 :
708 : {
709 24 : if( nOffset == -1 )
710 24 : nOffset = nFirstRecordOffset;
711 :
712 24 : if( fpDDF == NULL )
713 0 : return;
714 :
715 24 : VSIFSeekL( fpDDF, nOffset, SEEK_SET );
716 :
717 24 : if( nOffset == nFirstRecordOffset && poRecord != NULL )
718 16 : poRecord->Clear();
719 :
720 : }
|