Coverage Report

Created: 2025-08-11 09:23

/src/gdal/frmts/iso8211/iso8211.h
Line
Count
Source (jump to first uncovered line)
1
/******************************************************************************
2
 *
3
 * Project:  ISO 8211 Access
4
 * Purpose:  Main declarations for ISO 8211.
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
#ifndef ISO8211_H_INCLUDED
14
#define ISO8211_H_INCLUDED
15
16
#include "cpl_port.h"
17
#include "cpl_vsi.h"
18
19
/**
20
  General data type
21
    */
22
typedef enum
23
{
24
    DDFInt,
25
    DDFFloat,
26
    DDFString,
27
    DDFBinaryString
28
} DDFDataType;
29
30
/************************************************************************/
31
/*      These should really be private to the library ... they are      */
32
/*      mostly conveniences.                                            */
33
/************************************************************************/
34
35
int CPL_ODLL DDFScanInt(const char *pszString, int nMaxChars);
36
int CPL_ODLL DDFScanVariable(const char *pszString, int nMaxChars,
37
                             int nDelimChar);
38
char CPL_ODLL *DDFFetchVariable(const char *pszString, int nMaxChars,
39
                                int nDelimChar1, int nDelimChar2,
40
                                int *pnConsumedChars);
41
42
48.6M
#define DDF_FIELD_TERMINATOR 30
43
2.00M
#define DDF_UNIT_TERMINATOR 31
44
45
/************************************************************************/
46
/*                           Predeclarations                            */
47
/************************************************************************/
48
49
class DDFFieldDefn;
50
class DDFSubfieldDefn;
51
class DDFRecord;
52
class DDFField;
53
54
/************************************************************************/
55
/*                              DDFModule                               */
56
/************************************************************************/
57
58
/**
59
  The primary class for reading ISO 8211 files.  This class contains all
60
  the information read from the DDR record, and is used to read records
61
  from the file.
62
*/
63
64
class CPL_ODLL DDFModule
65
{
66
  public:
67
    DDFModule();
68
    ~DDFModule();
69
70
    int Open(const char *pszFilename, int bFailQuietly = FALSE);
71
    int Create(const char *pszFilename);
72
    void Close();
73
74
    int Initialize(char chInterchangeLevel = '3', char chLeaderIden = 'L',
75
                   char chCodeExtensionIndicator = 'E',
76
                   char chVersionNumber = '1', char chAppIndicator = ' ',
77
                   const char *pszExtendedCharSet = " ! ",
78
                   int nSizeFieldLength = 3, int nSizeFieldPos = 4,
79
                   int nSizeFieldTag = 4);
80
81
    void Dump(FILE *fp);
82
83
    DDFRecord *ReadRecord();
84
    void Rewind(long nOffset = -1);
85
86
    const DDFFieldDefn *FindFieldDefn(const char *) const;
87
88
    DDFFieldDefn *FindFieldDefn(const char *name)
89
284k
    {
90
284k
        return const_cast<DDFFieldDefn *>(
91
284k
            const_cast<const DDFModule *>(this)->FindFieldDefn(name));
92
284k
    }
93
94
    /** Fetch the number of defined fields. */
95
96
    int GetFieldCount() const
97
0
    {
98
0
        return nFieldDefnCount;
99
0
    }
100
101
    DDFFieldDefn *GetField(int);
102
    void AddField(DDFFieldDefn *poNewFDefn);
103
104
    // This is really just for internal use.
105
    int GetFieldControlLength() const
106
296k
    {
107
296k
        return _fieldControlLength;
108
296k
    }
109
110
    void AddCloneRecord(DDFRecord *);
111
    void RemoveCloneRecord(DDFRecord *);
112
113
    // This is just for DDFRecord.
114
    VSILFILE *GetFP()
115
12.0M
    {
116
12.0M
        return fpDDF;
117
12.0M
    }
118
119
    int GetSizeFieldTag() const
120
574k
    {
121
574k
        return (int)_sizeFieldTag;
122
574k
    }
123
124
    // Advanced uses for 8211dump/8211createfromxml
125
    int GetSizeFieldPos() const
126
0
    {
127
0
        return _sizeFieldPos;
128
0
    }
129
130
    int GetSizeFieldLength() const
131
0
    {
132
0
        return _sizeFieldLength;
133
0
    }
134
135
    char GetInterchangeLevel() const
136
0
    {
137
0
        return _interchangeLevel;
138
0
    }
139
140
    char GetLeaderIden() const
141
0
    {
142
0
        return _leaderIden;
143
0
    }
144
145
    char GetCodeExtensionIndicator() const
146
0
    {
147
0
        return _inlineCodeExtensionIndicator;
148
0
    }
149
150
    char GetVersionNumber() const
151
0
    {
152
0
        return _versionNumber;
153
0
    }
154
155
    char GetAppIndicator() const
156
0
    {
157
0
        return _appIndicator;
158
0
    }
159
160
    const char *GetExtendedCharSet() const
161
0
    {
162
0
        return _extendedCharSet;
163
0
    }
164
165
    void SetFieldControlLength(int nVal)
166
0
    {
167
0
        _fieldControlLength = nVal;
168
0
    }
169
170
  private:
171
    VSILFILE *fpDDF;
172
    int bReadOnly;
173
    long nFirstRecordOffset;
174
175
    char _interchangeLevel;
176
    char _inlineCodeExtensionIndicator;
177
    char _versionNumber;
178
    char _appIndicator;
179
    int _fieldControlLength;
180
    char _extendedCharSet[4];
181
182
    int _recLength;
183
    char _leaderIden;
184
    int _fieldAreaStart;
185
    int _sizeFieldLength;
186
    int _sizeFieldPos;
187
    int _sizeFieldTag;
188
189
    // One DirEntry per field.
190
    int nFieldDefnCount;
191
    DDFFieldDefn **papoFieldDefns;
192
193
    DDFRecord *poRecord;
194
195
    int nCloneCount;
196
    int nMaxCloneCount;
197
    DDFRecord **papoClones;
198
};
199
200
/************************************************************************/
201
/*                             DDFFieldDefn                             */
202
/************************************************************************/
203
204
typedef enum
205
{
206
    dsc_elementary,
207
    dsc_vector,
208
    dsc_array,
209
    dsc_concatenated
210
} DDF_data_struct_code;
211
212
typedef enum
213
{
214
    dtc_char_string,
215
    dtc_implicit_point,
216
    dtc_explicit_point,
217
    dtc_explicit_point_scaled,
218
    dtc_char_bit_string,
219
    dtc_bit_string,
220
    dtc_mixed_data_type
221
} DDF_data_type_code;
222
223
/**
224
 * Information from the DDR defining one field.  Note that just because
225
 * a field is defined for a DDFModule doesn't mean that it actually occurs
226
 * on any records in the module.  DDFFieldDefns are normally just significant
227
 * as containers of the DDFSubfieldDefns.
228
 */
229
230
class CPL_ODLL DDFFieldDefn
231
{
232
  public:
233
    DDFFieldDefn();
234
    ~DDFFieldDefn();
235
236
    int Create(const char *pszTag, const char *pszFieldName,
237
               const char *pszDescription, DDF_data_struct_code eDataStructCode,
238
               DDF_data_type_code eDataTypeCode,
239
               const char *pszFormat = nullptr);
240
    void AddSubfield(DDFSubfieldDefn *poNewSFDefn,
241
                     int bDontAddToFormat = FALSE);
242
    void AddSubfield(const char *pszName, const char *pszFormat);
243
    int GenerateDDREntry(DDFModule *poModule, char **ppachData, int *pnLength);
244
245
    int Initialize(DDFModule *poModule, const char *pszTag, int nSize,
246
                   const char *pachRecord);
247
248
    void Dump(FILE *fp);
249
250
    /** Fetch a pointer to the field name (tag).
251
     * @return this is an internal copy and should not be freed.
252
     */
253
    const char *GetName() const
254
12.6M
    {
255
12.6M
        return pszTag;
256
12.6M
    }
257
258
    /** Fetch a longer description of this field.
259
     * @return this is an internal copy and should not be freed.
260
     */
261
    const char *GetDescription() const
262
0
    {
263
0
        return _fieldName;
264
0
    }
265
266
    /** Get the number of subfields. */
267
    int GetSubfieldCount() const
268
7.52M
    {
269
7.52M
        return nSubfieldCount;
270
7.52M
    }
271
272
    const DDFSubfieldDefn *GetSubfield(int i) const;
273
    const DDFSubfieldDefn *FindSubfieldDefn(const char *) const;
274
275
    /**
276
     * Get the width of this field.  This function isn't normally used
277
     * by applications.
278
     *
279
     * @return The width of the field in bytes, or zero if the field is not
280
     * apparently of a fixed width.
281
     */
282
    int GetFixedWidth() const
283
219k
    {
284
219k
        return nFixedWidth;
285
219k
    }
286
287
    /**
288
     * Fetch repeating flag.
289
     * @see DDFField::GetRepeatCount()
290
     * @return TRUE if the field is marked as repeating.
291
     */
292
    int IsRepeating() const
293
159k
    {
294
159k
        return bRepeatingSubfields;
295
159k
    }
296
297
    static char *ExpandFormat(const char *);
298
299
    /** this is just for an S-57 hack for swedish data */
300
    void SetRepeatingFlag(int n)
301
156
    {
302
156
        bRepeatingSubfields = n;
303
156
    }
304
305
    char *GetDefaultValue(int *pnSize);
306
307
    const char *GetArrayDescr() const
308
0
    {
309
0
        return _arrayDescr;
310
0
    }
311
312
    const char *GetFormatControls() const
313
0
    {
314
0
        return _formatControls;
315
0
    }
316
317
    DDF_data_struct_code GetDataStructCode() const
318
0
    {
319
0
        return _data_struct_code;
320
0
    }
321
322
    DDF_data_type_code GetDataTypeCode() const
323
0
    {
324
0
        return _data_type_code;
325
0
    }
326
327
    void SetFormatControls(const char *pszVal);
328
329
  private:
330
    static char *ExtractSubstring(const char *);
331
332
    DDFModule *poModule;
333
    char *pszTag;
334
335
    char *_fieldName;
336
    char *_arrayDescr;
337
    char *_formatControls;
338
339
    int bRepeatingSubfields;
340
    int nFixedWidth;  // zero if variable.
341
342
    void BuildSubfields();
343
    int ApplyFormats();
344
345
    DDF_data_struct_code _data_struct_code;
346
347
    DDF_data_type_code _data_type_code;
348
349
    int nSubfieldCount;
350
    DDFSubfieldDefn **papoSubfields;
351
352
    CPL_DISALLOW_COPY_ASSIGN(DDFFieldDefn)
353
};
354
355
/************************************************************************/
356
/*                           DDFSubfieldDefn                            */
357
/*                                                                      */
358
/*      Information from the DDR record for one subfield of a           */
359
/*      particular field.                                               */
360
/************************************************************************/
361
362
/**
363
 * Information from the DDR record describing one subfield of a DDFFieldDefn.
364
 * All subfields of a field will occur in each occurrence of that field
365
 * (as a DDFField) in a DDFRecord.  Subfield's actually contain formatted
366
 * data (as instances within a record).
367
 */
368
369
class CPL_ODLL DDFSubfieldDefn
370
{
371
  public:
372
    DDFSubfieldDefn();
373
    ~DDFSubfieldDefn();
374
375
    void SetName(const char *pszName);
376
377
    /** Get pointer to subfield name. */
378
    const char *GetName() const
379
9.68M
    {
380
9.68M
        return pszName;
381
9.68M
    }
382
383
    /** Get pointer to subfield format string */
384
    const char *GetFormat() const
385
9.20k
    {
386
9.20k
        return pszFormatString;
387
9.20k
    }
388
389
    int SetFormat(const char *pszFormat);
390
391
    /**
392
     * Get the general type of the subfield.  This can be used to
393
     * determine which of ExtractFloatData(), ExtractIntData() or
394
     * ExtractStringData() should be used.
395
     * @return The subfield type.  One of DDFInt, DDFFloat, DDFString or
396
     * DDFBinaryString.
397
     */
398
399
    DDFDataType GetType() const
400
0
    {
401
0
        return eType;
402
0
    }
403
404
    double ExtractFloatData(const char *pachData, int nMaxBytes,
405
                            int *pnConsumedBytes) const;
406
    int ExtractIntData(const char *pachData, int nMaxBytes,
407
                       int *pnConsumedBytes) const;
408
    const char *ExtractStringData(const char *pachData, int nMaxBytes,
409
                                  int *pnConsumedBytes) const;
410
    int GetDataLength(const char *, int, int *) const;
411
    void DumpData(const char *pachData, int nMaxBytes, FILE *fp) const;
412
413
    int FormatStringValue(char *pachData, int nBytesAvailable, int *pnBytesUsed,
414
                          const char *pszValue, int nValueLength = -1) const;
415
416
    int FormatIntValue(char *pachData, int nBytesAvailable, int *pnBytesUsed,
417
                       int nNewValue) const;
418
419
    int FormatFloatValue(char *pachData, int nBytesAvailable, int *pnBytesUsed,
420
                         double dfNewValue) const;
421
422
    /** Get the subfield width (zero for variable). */
423
    int GetWidth() const
424
2.46M
    {
425
2.46M
        return nFormatWidth;
426
2.46M
    }  // zero for variable.
427
428
    int GetDefaultValue(char *pachData, int nBytesAvailable,
429
                        int *pnBytesUsed) const;
430
431
    void Dump(FILE *fp);
432
433
    /**
434
      Binary format: this is the digit immediately following the B or b for
435
      binary formats.
436
      */
437
    typedef enum
438
    {
439
        NotBinary = 0,
440
        UInt = 1,
441
        SInt = 2,
442
        FPReal = 3,
443
        FloatReal = 4,
444
        FloatComplex = 5
445
    } DDFBinaryFormat;
446
447
    DDFBinaryFormat GetBinaryFormat() const
448
0
    {
449
0
        return eBinaryFormat;
450
0
    }
451
452
  private:
453
    char *pszName;  // a.k.a. subfield mnemonic
454
    char *pszFormatString;
455
456
    DDFDataType eType;
457
    DDFBinaryFormat eBinaryFormat;
458
459
    /* -------------------------------------------------------------------- */
460
    /*      bIsVariable determines whether we using the                     */
461
    /*      chFormatDelimiter (TRUE), or the fixed width (FALSE).           */
462
    /* -------------------------------------------------------------------- */
463
    int bIsVariable;
464
465
    char chFormatDelimiter;
466
    int nFormatWidth;
467
468
    /* -------------------------------------------------------------------- */
469
    /*      Fetched string cache.  This is where we hold the values         */
470
    /*      returned from ExtractStringData().                              */
471
    /* -------------------------------------------------------------------- */
472
    mutable int nMaxBufChars;
473
    mutable char *pachBuffer;
474
};
475
476
/************************************************************************/
477
/*                              DDFRecord                               */
478
/*                                                                      */
479
/*      Class that contains one DR record from a file.  We read into    */
480
/*      the same record object repeatedly to ensure that repeated       */
481
/*      leaders can be easily preserved.                                */
482
/************************************************************************/
483
484
/**
485
 * Contains instance data from one data record (DR).  The data is contained
486
 * as a list of DDFField instances partitioning the raw data into fields.
487
 */
488
489
class CPL_ODLL DDFRecord
490
{
491
  public:
492
    explicit DDFRecord(DDFModule *);
493
    ~DDFRecord();
494
495
    DDFRecord *Clone();
496
    DDFRecord *CloneOn(DDFModule *);
497
498
    void Dump(FILE *);
499
500
    /** Get the number of DDFFields on this record. */
501
    int GetFieldCount() const
502
192k
    {
503
192k
        return nFieldCount;
504
192k
    }
505
506
    const DDFField *FindField(const char *, int = 0) const;
507
508
    DDFField *FindField(const char *name, int i = 0)
509
1.96M
    {
510
1.96M
        return const_cast<DDFField *>(
511
1.96M
            const_cast<const DDFRecord *>(this)->FindField(name, i));
512
1.96M
    }
513
514
    const DDFField *GetField(int) const;
515
516
    DDFField *GetField(int i)
517
799k
    {
518
799k
        return const_cast<DDFField *>(
519
799k
            const_cast<const DDFRecord *>(this)->GetField(i));
520
799k
    }
521
522
    int GetIntSubfield(const char *, int, const char *, int,
523
                       int * = nullptr) const;
524
    double GetFloatSubfield(const char *, int, const char *, int,
525
                            int * = nullptr);
526
    const char *GetStringSubfield(const char *, int, const char *, int,
527
                                  int * = nullptr);
528
529
    int SetIntSubfield(const char *pszField, int iFieldIndex,
530
                       const char *pszSubfield, int iSubfieldIndex, int nValue);
531
    int SetStringSubfield(const char *pszField, int iFieldIndex,
532
                          const char *pszSubfield, int iSubfieldIndex,
533
                          const char *pszValue, int nValueLength = -1);
534
    int SetFloatSubfield(const char *pszField, int iFieldIndex,
535
                         const char *pszSubfield, int iSubfieldIndex,
536
                         double dfNewValue);
537
538
    /** Fetch size of records raw data (GetData()) in bytes. */
539
    int GetDataSize() const
540
0
    {
541
0
        return nDataSize;
542
0
    }
543
544
    /**
545
     * Fetch the raw data for this record.  The returned pointer is effectively
546
     * to the data for the first field of the record, and is of size
547
     * GetDataSize().
548
     */
549
    const char *GetData() const
550
0
    {
551
0
        return pachData;
552
0
    }
553
554
    /**
555
     * Fetch the DDFModule with which this record is associated.
556
     */
557
558
    DDFModule *GetModule()
559
0
    {
560
0
        return poModule;
561
0
    }
562
563
    int ResizeField(DDFField *poField, int nNewDataSize);
564
    int DeleteField(DDFField *poField);
565
    DDFField *AddField(DDFFieldDefn *);
566
567
    int CreateDefaultFieldInstance(DDFField *poField, int iIndexWithinField);
568
569
    int SetFieldRaw(DDFField *poField, int iIndexWithinField,
570
                    const char *pachRawData, int nRawDataSize);
571
    int UpdateFieldRaw(DDFField *poField, int iIndexWithinField,
572
                       int nStartOffset, int nOldSize, const char *pachRawData,
573
                       int nRawDataSize);
574
575
    int Write();
576
577
    // Advanced uses for 8211dump/8211createfromxml
578
    int GetReuseHeader() const
579
0
    {
580
0
        return nReuseHeader;
581
0
    }
582
583
    int GetSizeFieldTag() const
584
0
    {
585
0
        return _sizeFieldTag;
586
0
    }
587
588
    int GetSizeFieldPos() const
589
0
    {
590
0
        return _sizeFieldPos;
591
0
    }
592
593
    int GetSizeFieldLength() const
594
0
    {
595
0
        return _sizeFieldLength;
596
0
    }
597
598
    // void        SetReuseHeader(int bFlag) { nReuseHeader = bFlag; }
599
    void SetSizeFieldTag(int nVal)
600
0
    {
601
0
        _sizeFieldTag = nVal;
602
0
    }
603
604
    void SetSizeFieldPos(int nVal)
605
0
    {
606
0
        _sizeFieldPos = nVal;
607
0
    }
608
609
    void SetSizeFieldLength(int nVal)
610
0
    {
611
0
        _sizeFieldLength = nVal;
612
0
    }
613
614
    // This is really just for the DDFModule class.
615
    int Read();
616
    void Clear();
617
    void ResetDirectory();
618
619
    void RemoveIsCloneFlag()
620
484k
    {
621
484k
        bIsClone = FALSE;
622
484k
    }
623
624
  private:
625
    int ReadHeader();
626
627
    DDFModule *poModule;
628
629
    int nReuseHeader;
630
631
    int nFieldOffset;  // field data area, not dir entries.
632
633
    int _sizeFieldTag;
634
    int _sizeFieldPos;
635
    int _sizeFieldLength;
636
637
    int nDataSize;  // Whole record except leader with header
638
    char *pachData;
639
640
    int nFieldCount;
641
    DDFField *paoFields;
642
643
    int bIsClone;
644
};
645
646
/************************************************************************/
647
/*                               DDFField                               */
648
/*                                                                      */
649
/*      This object represents one field in a DDFRecord.                */
650
/************************************************************************/
651
652
/**
653
 * This object represents one field in a DDFRecord.  This
654
 * models an instance of the fields data, rather than its data definition,
655
 * which is handled by the DDFFieldDefn class.  Note that a DDFField
656
 * doesn't have DDFSubfield children as you would expect.  To extract
657
 * subfield values use GetSubfieldData() to find the right data pointer and
658
 * then use ExtractIntData(), ExtractFloatData() or ExtractStringData().
659
 */
660
661
class CPL_ODLL DDFField
662
{
663
  public:
664
2.06M
    DDFField() : poDefn(nullptr), nDataSize(0), pachData(nullptr)
665
2.06M
    {
666
2.06M
    }
667
668
    void Initialize(DDFFieldDefn *, const char *pszData, int nSize);
669
670
    void Dump(FILE *fp);
671
672
    const char *GetSubfieldData(const DDFSubfieldDefn *, int * = nullptr,
673
                                int = 0) const;
674
675
    const char *GetInstanceData(int nInstance, int *pnSize);
676
677
    /**
678
     * Return the pointer to the entire data block for this record. This
679
     * is an internal copy, and should not be freed by the application.
680
     */
681
    const char *GetData() const
682
1.16M
    {
683
1.16M
        return pachData;
684
1.16M
    }
685
686
    /** Return the number of bytes in the data block returned by GetData(). */
687
    int GetDataSize() const
688
1.16M
    {
689
1.16M
        return nDataSize;
690
1.16M
    }
691
692
    int GetRepeatCount() const;
693
694
    /** Fetch the corresponding DDFFieldDefn. */
695
    DDFFieldDefn *GetFieldDefn()
696
11.8M
    {
697
11.8M
        return poDefn;
698
11.8M
    }
699
700
    /** Fetch the corresponding DDFFieldDefn. */
701
    const DDFFieldDefn *GetFieldDefn() const
702
2.95M
    {
703
2.95M
        return poDefn;
704
2.95M
    }
705
706
  private:
707
    DDFFieldDefn *poDefn;
708
709
    int nDataSize;
710
711
    const char *pachData;
712
};
713
714
#endif /* ndef ISO8211_H_INCLUDED */