/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 */ |