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