OSSIM - Open Source Software Image Map  Version 1.9.0 (20180803)
ossimDdfmodule.cpp
Go to the documentation of this file.
1 /******************************************************************************
2  * Copied from "gdal" project. See licence below.
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  * $Id: ossimDdfmodule.cpp 12978 2008-06-04 00:04:14Z dburken $
30  */
31 
32 #include <cstring>
36 
37 
38 /************************************************************************/
39 /* DDFModule() */
40 /************************************************************************/
41 
47 
48 {
49  nFieldDefnCount = 0;
50  papoFieldDefns = NULL;
51  poRecord = NULL;
52 
53  papoClones = NULL;
55 
56  fpDDF = NULL;
57  bReadOnly = true;
58 
59  _interchangeLevel = '\0';
61  _versionNumber = '\0';
62  _appIndicator = '\0';
63  _fieldControlLength = '\0';
64  strcpy( _extendedCharSet, " ! " );
65 
66  _recLength = 0;
67  _leaderIden = 'L';
68  _fieldAreaStart = 0;
69  _sizeFieldLength = 0;
70  _sizeFieldPos = 0;
71  _sizeFieldTag = 0;
72 }
73 
74 /************************************************************************/
75 /* ~DDFModule() */
76 /************************************************************************/
77 
83 
84 {
85  Close();
86 }
87 
88 /************************************************************************/
89 /* Close() */
90 /* */
91 /* Note that closing a file also destroys essentially all other */
92 /* module datastructures. */
93 /************************************************************************/
94 
100 
101 {
102 /* -------------------------------------------------------------------- */
103 /* Close the file. */
104 /* -------------------------------------------------------------------- */
105  if( fpDDF != NULL )
106  {
107  fclose( fpDDF );
108  fpDDF = NULL;
109  }
110 
111 /* -------------------------------------------------------------------- */
112 /* Cleanup the working record. */
113 /* -------------------------------------------------------------------- */
114  if( poRecord != NULL )
115  {
116  delete poRecord;
117  poRecord = NULL;
118  }
119 
120 /* -------------------------------------------------------------------- */
121 /* Cleanup the clones. Deleting them will cause a callback to */
122 /* remove them from the list. */
123 /* -------------------------------------------------------------------- */
124  while( nCloneCount > 0 )
125  delete papoClones[0];
126 
127  nMaxCloneCount = 0;
128  free( papoClones );
129  papoClones = NULL;
130 
131 /* -------------------------------------------------------------------- */
132 /* Cleanup the field definitions. */
133 /* -------------------------------------------------------------------- */
134  int i;
135 
136  for( i = 0; i < nFieldDefnCount; i++ )
137  delete papoFieldDefns[i];
138  free( papoFieldDefns );
139  papoFieldDefns = NULL;
140  nFieldDefnCount = 0;
141 }
142 
143 /************************************************************************/
144 /* Open() */
145 /* */
146 /* Open an ISO 8211 file, and read the DDR record to build the */
147 /* field definitions. */
148 /************************************************************************/
149 
164 int ossimDDFModule::Open( const char * pszFilename, int bFailQuietly )
165 
166 {
167  static const size_t nLeaderSize = 24;
168 
169 /* -------------------------------------------------------------------- */
170 /* Close the existing file if there is one. */
171 /* -------------------------------------------------------------------- */
172  if( fpDDF != NULL )
173  Close();
174 
175  // Check for empty filename.
176  if (!pszFilename)
177  {
178  return false;
179  }
180 
181 /* -------------------------------------------------------------------- */
182 /* Open the file. */
183 /* -------------------------------------------------------------------- */
184  fpDDF = fopen( pszFilename, "rb" );
185 
186  if( fpDDF == NULL )
187  {
188  if( !bFailQuietly )
190  << "Unable to open DDF file `%s'."
191  << pszFilename << std::endl;
192  return false;
193  }
194 
195 /* -------------------------------------------------------------------- */
196 /* Read the 24 byte leader. */
197 /* -------------------------------------------------------------------- */
198  char achLeader[nLeaderSize];
199 
200  if( fread( achLeader, 1, nLeaderSize, fpDDF ) != nLeaderSize )
201  {
202  fclose( fpDDF );
203  fpDDF = NULL;
204 
205  if( !bFailQuietly )
207  << "Leader is short on DDF file `%s'."
208  << pszFilename << std::endl;
209 
210  return false;
211  }
212 
213 /* -------------------------------------------------------------------- */
214 /* Verify that this appears to be a valid DDF file. */
215 /* -------------------------------------------------------------------- */
216  int i, bValid = true;
217 
218  for( i = 0; i < (int)nLeaderSize; i++ )
219  {
220  if( achLeader[i] < 32 || achLeader[i] > 126 )
221  bValid = false;
222  }
223 
224  if( achLeader[5] != '1' && achLeader[5] != '2' && achLeader[5] != '3' )
225  bValid = false;
226 
227  if( achLeader[6] != 'L' )
228  bValid = false;
229  if( achLeader[8] != '1' && achLeader[8] != ' ' )
230  bValid = false;
231 
232 /* -------------------------------------------------------------------- */
233 /* Extract information from leader. */
234 /* -------------------------------------------------------------------- */
235 
236  if( bValid )
237  {
238  _recLength = ossimDDFScanInt( achLeader+0, 5 );
239  _interchangeLevel = achLeader[5];
240  _leaderIden = achLeader[6];
241  _inlineCodeExtensionIndicator = achLeader[7];
242  _versionNumber = achLeader[8];
243  _appIndicator = achLeader[9];
244  _fieldControlLength = ossimDDFScanInt(achLeader+10,2);
245  _fieldAreaStart = ossimDDFScanInt(achLeader+12,5);
246  _extendedCharSet[0] = achLeader[17];
247  _extendedCharSet[1] = achLeader[18];
248  _extendedCharSet[2] = achLeader[19];
249  _extendedCharSet[3] = '\0';
250  _sizeFieldLength = ossimDDFScanInt(achLeader+20,1);
251  _sizeFieldPos = ossimDDFScanInt(achLeader+21,1);
252  _sizeFieldTag = ossimDDFScanInt(achLeader+23,1);
253 
254  if( _recLength < 12 || _fieldControlLength == 0
255  || _fieldAreaStart < 24 || _sizeFieldLength == 0
256  || _sizeFieldPos == 0 || _sizeFieldTag == 0 )
257  {
258  bValid = false;
259  }
260  }
261 
262 /* -------------------------------------------------------------------- */
263 /* If the header is invalid, then clean up, report the error */
264 /* and return. */
265 /* -------------------------------------------------------------------- */
266  if( !bValid )
267  {
268  fclose( fpDDF );
269  fpDDF = NULL;
270 
271  if( !bFailQuietly )
273  << "File `%s' does not appear to have\n"
274  << "a valid ISO 8211 header.\n"
275  << pszFilename << std::endl;
276  return false;
277  }
278 
279 /* -------------------------------------------------------------------- */
280 /* Read the whole record info memory. */
281 /* -------------------------------------------------------------------- */
282  char *pachRecord;
283 
284  pachRecord = (char *) malloc(_recLength);
285  memcpy( pachRecord, achLeader, nLeaderSize );
286 
287  if( fread( pachRecord+nLeaderSize, 1, _recLength-nLeaderSize, fpDDF )
288  != _recLength - nLeaderSize )
289  {
290  if( !bFailQuietly )
292  << "Header record is short on DDF file `%s'."
293  << pszFilename << std::endl;
294 
295  return false;
296  }
297 
298 /* -------------------------------------------------------------------- */
299 /* First make a pass counting the directory entries. */
300 /* -------------------------------------------------------------------- */
301  int nFieldEntryWidth, nFDCount = 0;
302 
303  nFieldEntryWidth = _sizeFieldLength + _sizeFieldPos + _sizeFieldTag;
304 
305  for( i = nLeaderSize; i < _recLength; i += nFieldEntryWidth )
306  {
307  if( pachRecord[i] == OSSIM_DDF_FIELD_TERMINATOR )
308  break;
309 
310  nFDCount++;
311  }
312 
313 /* -------------------------------------------------------------------- */
314 /* Allocate, and read field definitions. */
315 /* -------------------------------------------------------------------- */
316  for( i = 0; i < nFDCount; i++ )
317  {
318  char szTag[128];
319  int nEntryOffset = nLeaderSize + i*nFieldEntryWidth;
320  int nFieldLength, nFieldPos;
321  ossimDDFFieldDefn *poFDefn;
322 
323  strncpy( szTag, pachRecord+nEntryOffset, _sizeFieldTag );
324  szTag[_sizeFieldTag] = '\0';
325 
326  nEntryOffset += _sizeFieldTag;
327  nFieldLength = ossimDDFScanInt( pachRecord+nEntryOffset, _sizeFieldLength );
328 
329  nEntryOffset += _sizeFieldLength;
330  nFieldPos = ossimDDFScanInt( pachRecord+nEntryOffset, _sizeFieldPos );
331 
332  poFDefn = new ossimDDFFieldDefn();
333  poFDefn->Initialize( this, szTag, nFieldLength,
334  pachRecord+_fieldAreaStart+nFieldPos );
335  AddField( poFDefn );
336  }
337 
338  free( pachRecord );
339 
340 /* -------------------------------------------------------------------- */
341 /* Record the current file offset, the beginning of the first */
342 /* data record. */
343 /* -------------------------------------------------------------------- */
344  nFirstRecordOffset = ftell( fpDDF );
345 
346  return true;
347 }
348 
349 /************************************************************************/
350 /* Initialize() */
351 /************************************************************************/
352 
353 int ossimDDFModule::Initialize( char chInterchangeLevel,
354  char chLeaderIden,
355  char chCodeExtensionIndicator,
356  char chVersionNumber,
357  char chAppIndicator,
358  const char *pszExtendedCharSet,
359  int nSizeFieldLength,
360  int nSizeFieldPos,
361  int nSizeFieldTag )
362 
363 {
364  _interchangeLevel = chInterchangeLevel;
365  _leaderIden = chLeaderIden;
366  _inlineCodeExtensionIndicator = chCodeExtensionIndicator;
367  _versionNumber = chVersionNumber;
368  _appIndicator = chAppIndicator;
369  strcpy( _extendedCharSet, pszExtendedCharSet );
370  _sizeFieldLength = nSizeFieldLength;
371  _sizeFieldPos = nSizeFieldPos;
372  _sizeFieldTag = nSizeFieldTag;
373 
374  return true;
375 }
376 
377 /************************************************************************/
378 /* Create() */
379 /************************************************************************/
380 
381 int ossimDDFModule::Create( const char *pszFilename )
382 
383 {
384  // CPLAssert( fpDDF == NULL );
385 
386 /* -------------------------------------------------------------------- */
387 /* Create the file on disk. */
388 /* -------------------------------------------------------------------- */
389  fpDDF = fopen( pszFilename, "wb+" );
390  if( fpDDF == NULL )
391  {
393  << "Failed to create file %s, check path and permissions."
394  << pszFilename << std::endl;
395  return false;
396  }
397 
398  bReadOnly = false;
399 
400 /* -------------------------------------------------------------------- */
401 /* Prepare all the field definition information. */
402 /* -------------------------------------------------------------------- */
403  int iField;
404 
406  _recLength = 24
408  + 1;
409 
411 
412  for( iField=0; iField < nFieldDefnCount; iField++ )
413  {
414  int nLength;
415 
416  papoFieldDefns[iField]->GenerateDDREntry( NULL, &nLength );
417  _recLength += nLength;
418  }
419 
420 /* -------------------------------------------------------------------- */
421 /* Setup 24 byte leader. */
422 /* -------------------------------------------------------------------- */
423  char achLeader[25];
424 
425  sprintf( achLeader+0, "%05d", (int) _recLength );
426  achLeader[5] = _interchangeLevel;
427  achLeader[6] = _leaderIden;
428  achLeader[7] = _inlineCodeExtensionIndicator;
429  achLeader[8] = _versionNumber;
430  achLeader[9] = _appIndicator;
431  sprintf( achLeader+10, "%02d", (int) _fieldControlLength );
432  sprintf( achLeader+12, "%05d", (int) _fieldAreaStart );
433  strncpy( achLeader+17, _extendedCharSet, 3 );
434  sprintf( achLeader+20, "%1d", (int) _sizeFieldLength );
435  sprintf( achLeader+21, "%1d", (int) _sizeFieldPos );
436  achLeader[22] = '0';
437  sprintf( achLeader+23, "%1d", (int) _sizeFieldTag );
438  fwrite( achLeader, 24, 1, fpDDF );
439 
440 /* -------------------------------------------------------------------- */
441 /* Write out directory entries. */
442 /* -------------------------------------------------------------------- */
443  int nOffset = 0;
444  for( iField=0; iField < nFieldDefnCount; iField++ )
445  {
446  char achDirEntry[12];
447  int nLength;
448 
449  papoFieldDefns[iField]->GenerateDDREntry( NULL, &nLength );
450 
451  strcpy( achDirEntry, papoFieldDefns[iField]->GetName() );
452  sprintf( achDirEntry + _sizeFieldTag, "%03d", nLength );
453  sprintf( achDirEntry + _sizeFieldTag + _sizeFieldLength,
454  "%04d", nOffset );
455  nOffset += nLength;
456 
457  fwrite( achDirEntry, 11, 1, fpDDF );
458  }
459 
460  char chUT = OSSIM_DDF_FIELD_TERMINATOR;
461  fwrite( &chUT, 1, 1, fpDDF );
462 
463 /* -------------------------------------------------------------------- */
464 /* Write out the field descriptions themselves. */
465 /* -------------------------------------------------------------------- */
466  for( iField=0; iField < nFieldDefnCount; iField++ )
467  {
468  char *pachData;
469  int nLength;
470 
471  papoFieldDefns[iField]->GenerateDDREntry( &pachData, &nLength );
472  fwrite( pachData, nLength, 1, fpDDF );
473  free( pachData );
474  }
475 
476  return true;
477 }
478 
479 /************************************************************************/
480 /* Dump() */
481 /************************************************************************/
482 
493 void ossimDDFModule::Dump( FILE * fp )
494 
495 {
496  fprintf( fp, "DDFModule:\n" );
497  fprintf( fp, " _recLength = %ld\n", _recLength );
498  fprintf( fp, " _interchangeLevel = %c\n", _interchangeLevel );
499  fprintf( fp, " _leaderIden = %c\n", _leaderIden );
500  fprintf( fp, " _inlineCodeExtensionIndicator = %c\n",
502  fprintf( fp, " _versionNumber = %c\n", _versionNumber );
503  fprintf( fp, " _appIndicator = %c\n", _appIndicator );
504  fprintf( fp, " _extendedCharSet = `%s'\n", _extendedCharSet );
505  fprintf( fp, " _fieldControlLength = %d\n", _fieldControlLength );
506  fprintf( fp, " _fieldAreaStart = %ld\n", _fieldAreaStart );
507  fprintf( fp, " _sizeFieldLength = %ld\n", _sizeFieldLength );
508  fprintf( fp, " _sizeFieldPos = %ld\n", _sizeFieldPos );
509  fprintf( fp, " _sizeFieldTag = %ld\n", _sizeFieldTag );
510 
511  for( int i = 0; i < nFieldDefnCount; i++ )
512  {
513  papoFieldDefns[i]->Dump( fp );
514  }
515 }
516 
517 /************************************************************************/
518 /* FindFieldDefn() */
519 /************************************************************************/
520 
536 
537 {
538  int i;
539 
540 /* -------------------------------------------------------------------- */
541 /* This pass tries to reduce the cost of comparing strings by */
542 /* first checking the first character, and by using strcmp() */
543 /* -------------------------------------------------------------------- */
544  for( i = 0; i < nFieldDefnCount; i++ )
545  {
546  const char *pszThisName = papoFieldDefns[i]->GetName();
547 
548  if( *pszThisName == *pszFieldName
549  && strcmp( pszFieldName+1, pszThisName+1) == 0 )
550  return papoFieldDefns[i];
551  }
552 
553 /* -------------------------------------------------------------------- */
554 /* Now do a more general check. Application code may not */
555 /* always use the correct name case. */
556 /* -------------------------------------------------------------------- */
557  for( i = 0; i < nFieldDefnCount; i++ )
558  {
560  if( s == pszFieldName )
561  return papoFieldDefns[i];
562  }
563 
564  return NULL;
565 }
566 
567 /************************************************************************/
568 /* ReadRecord() */
569 /* */
570 /* Read one record from the file, and return to the */
571 /* application. The returned record is owned by the module, */
572 /* and is reused from call to call in order to preserve headers */
573 /* when they aren't being re-read from record to record. */
574 /************************************************************************/
575 
586 
587 {
588  if( poRecord == NULL )
589  poRecord = new ossimDDFRecord( this );
590 
591  if( poRecord->Read() )
592  return poRecord;
593  else
594  return NULL;
595 }
596 
597 /************************************************************************/
598 /* AddField() */
599 /************************************************************************/
600 
612 
613 {
614  nFieldDefnCount++;
617  papoFieldDefns[nFieldDefnCount-1] = poNewFDefn;
618 }
619 
620 /************************************************************************/
621 /* GetField() */
622 /************************************************************************/
623 
632 
633 {
634  if( i < 0 || i >= nFieldDefnCount )
635  return NULL;
636  else
637  return papoFieldDefns[i];
638 }
639 
640 /************************************************************************/
641 /* AddCloneRecord() */
642 /* */
643 /* We want to keep track of cloned records, so we can clean */
644 /* them up when the module is destroyed. */
645 /************************************************************************/
646 
648 
649 {
650 /* -------------------------------------------------------------------- */
651 /* Do we need to grow the container array? */
652 /* -------------------------------------------------------------------- */
653  if( nCloneCount == nMaxCloneCount )
654  {
655  nMaxCloneCount = nCloneCount*2 + 20;
657  nMaxCloneCount * sizeof(void*));
658  }
659 
660 /* -------------------------------------------------------------------- */
661 /* Add to the list. */
662 /* -------------------------------------------------------------------- */
664 }
665 
666 /************************************************************************/
667 /* RemoveCloneRecord() */
668 /************************************************************************/
669 
671 
672 {
673  int i;
674 
675  for( i = 0; i < nCloneCount; i++ )
676  {
677  if( papoClones[i] == poRecord )
678  {
680  nCloneCount--;
681  return;
682  }
683  }
684 
685  // CPLAssert( false );
686 }
687 
688 /************************************************************************/
689 /* Rewind() */
690 /************************************************************************/
691 
702 void ossimDDFModule::Rewind( long nOffset )
703 
704 {
705  if( nOffset == -1 )
706  nOffset = nFirstRecordOffset;
707 
708  if( fpDDF == NULL )
709  return;
710 
711  fseek( fpDDF, nOffset, SEEK_SET );
712 
713  if( nOffset == nFirstRecordOffset && poRecord != NULL )
714  poRecord->Clear();
715 
716 }
long nFirstRecordOffset
Definition: ossimIso8211.h:132
ossimDDFModule()
The constructor.
void RemoveCloneRecord(ossimDDFRecord *)
Information from the DDR defining one field.
Definition: ossimIso8211.h:179
const char * GetName()
Fetch a pointer to the field name (tag).
Definition: ossimIso8211.h:203
int Initialize(ossimDDFModule *poModule, const char *pszTag, int nSize, const char *pachRecord)
int Create(const char *pszFilename)
int GenerateDDREntry(char **ppachData, int *pnLength)
ossimDDFRecord * poRecord
Definition: ossimIso8211.h:152
void Dump(FILE *fp)
Write out module info to debugging file.
~ossimDDFModule()
The destructor.
ossimDDFFieldDefn * FindFieldDefn(const char *)
Fetch the definition of the named field.
ossimDDFRecord ** papoClones
Definition: ossimIso8211.h:156
void Dump(FILE *fp)
Write out field definition info to debugging file.
ossimDDFFieldDefn ** papoFieldDefns
Definition: ossimIso8211.h:150
void Rewind(long nOffset=-1)
Return to first record.
void AddField(ossimDDFFieldDefn *poNewFDefn)
Add new field definition.
ossimDDFFieldDefn * GetField(int)
Fetch a field definition by index.
void Close()
Close an ISO 8211 file.
int Open(const char *pszFilename, int bFailQuietly=false)
Open a ISO 8211 (DDF) file for reading.
char _extendedCharSet[4]
Definition: ossimIso8211.h:139
char _inlineCodeExtensionIndicator
Definition: ossimIso8211.h:135
ossimDDFRecord * ReadRecord(void)
Read one record from the file.
long ossimDDFScanInt(const char *pszString, int nMaxChars)
Contains instance data from one data record (DR).
Definition: ossimIso8211.h:385
OSSIMDLLEXPORT void * ossimCPLRealloc(void *pData, size_t nNewSize)
int Initialize(char chInterchangeLevel='3', char chLeaderIden='L', char chCodeExtensionIndicator='E', char chVersionNumber='1', char chAppIndicator=' ', const char *pszExtendedCharSet=" ! ", int nSizeFieldLength=3, int nSizeFieldPos=4, int nSizeFieldTag=4)
char _interchangeLevel
Definition: ossimIso8211.h:134
void AddCloneRecord(ossimDDFRecord *)
OSSIMDLLEXPORT std::ostream & ossimNotify(ossimNotifyLevel level=ossimNotifyLevel_WARN)
#define OSSIM_DDF_FIELD_TERMINATOR
Definition: ossimIso8211.h:62