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