Coverage Report

Created: 2026-05-16 08:20

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