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 nOffset = -1);
85 :
86 : const DDFFieldDefn *FindFieldDefn(const char *) const;
87 :
88 6529 : DDFFieldDefn *FindFieldDefn(const char *name)
89 : {
90 : return const_cast<DDFFieldDefn *>(
91 6529 : const_cast<const DDFModule *>(this)->FindFieldDefn(name));
92 : }
93 :
94 : /** Fetch the number of defined fields. */
95 :
96 : int GetFieldCount() const
97 : {
98 : return nFieldDefnCount;
99 : }
100 :
101 : DDFFieldDefn *GetField(int);
102 : void AddField(DDFFieldDefn *poNewFDefn);
103 :
104 : // This is really just for internal use.
105 2238 : int GetFieldControlLength() const
106 : {
107 2238 : return _fieldControlLength;
108 : }
109 :
110 : void AddCloneRecord(DDFRecord *);
111 : void RemoveCloneRecord(DDFRecord *);
112 :
113 : // This is just for DDFRecord.
114 3573 : VSILFILE *GetFP()
115 : {
116 3573 : return fpDDF;
117 : }
118 :
119 1674 : int GetSizeFieldTag() const
120 : {
121 1674 : return (int)_sizeFieldTag;
122 : }
123 :
124 : // Advanced uses for 8211dump/8211createfromxml
125 : int GetSizeFieldPos() const
126 : {
127 : return _sizeFieldPos;
128 : }
129 :
130 : int GetSizeFieldLength() const
131 : {
132 : return _sizeFieldLength;
133 : }
134 :
135 : char GetInterchangeLevel() const
136 : {
137 : return _interchangeLevel;
138 : }
139 :
140 : char GetLeaderIden() const
141 : {
142 : return _leaderIden;
143 : }
144 :
145 : char GetCodeExtensionIndicator() const
146 : {
147 : return _inlineCodeExtensionIndicator;
148 : }
149 :
150 : char GetVersionNumber() const
151 : {
152 : return _versionNumber;
153 : }
154 :
155 : char GetAppIndicator() const
156 : {
157 : return _appIndicator;
158 : }
159 :
160 : const char *GetExtendedCharSet() const
161 : {
162 : return _extendedCharSet;
163 : }
164 :
165 : void SetFieldControlLength(int nVal)
166 : {
167 : _fieldControlLength = nVal;
168 : }
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 220522 : const char *GetName() const
254 : {
255 220522 : return pszTag;
256 : }
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 : {
263 : return _fieldName;
264 : }
265 :
266 : /** Get the number of subfields. */
267 115382 : int GetSubfieldCount() const
268 : {
269 115382 : return nSubfieldCount;
270 : }
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 29443 : int GetFixedWidth() const
283 : {
284 29443 : return nFixedWidth;
285 : }
286 :
287 : /**
288 : * Fetch repeating flag.
289 : * @see DDFField::GetRepeatCount()
290 : * @return TRUE if the field is marked as repeating.
291 : */
292 8187 : int IsRepeating() const
293 : {
294 8187 : return bRepeatingSubfields;
295 : }
296 :
297 : static char *ExpandFormat(const char *);
298 :
299 : /** this is just for an S-57 hack for swedish data */
300 0 : void SetRepeatingFlag(int n)
301 : {
302 0 : bRepeatingSubfields = n;
303 0 : }
304 :
305 : char *GetDefaultValue(int *pnSize);
306 :
307 : const char *GetArrayDescr() const
308 : {
309 : return _arrayDescr;
310 : }
311 :
312 : const char *GetFormatControls() const
313 : {
314 : return _formatControls;
315 : }
316 :
317 : DDF_data_struct_code GetDataStructCode() const
318 : {
319 : return _data_struct_code;
320 : }
321 :
322 : DDF_data_type_code GetDataTypeCode() const
323 : {
324 : return _data_type_code;
325 : }
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 103722 : const char *GetName() const
379 : {
380 103722 : return pszName;
381 : }
382 :
383 : /** Get pointer to subfield format string */
384 5536 : const char *GetFormat() const
385 : {
386 5536 : return pszFormatString;
387 : }
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 108 : DDFDataType GetType() const
400 : {
401 108 : return eType;
402 : }
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 17074 : int GetWidth() const
424 : {
425 17074 : return nFormatWidth;
426 : } // 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 6791 : DDFBinaryFormat GetBinaryFormat() const
448 : {
449 6791 : return eBinaryFormat;
450 : }
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 15666 : int GetFieldCount() const
502 : {
503 15666 : return nFieldCount;
504 : }
505 :
506 : const DDFField *FindField(const char *, int = 0) const;
507 :
508 15557 : DDFField *FindField(const char *name, int i = 0)
509 : {
510 : return const_cast<DDFField *>(
511 15557 : const_cast<const DDFRecord *>(this)->FindField(name, i));
512 : }
513 :
514 : const DDFField *GetField(int) const;
515 :
516 14915 : DDFField *GetField(int i)
517 : {
518 : return const_cast<DDFField *>(
519 14915 : const_cast<const DDFRecord *>(this)->GetField(i));
520 : }
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 : {
541 : return nDataSize;
542 : }
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 154 : const char *GetData() const
550 : {
551 154 : return pachData;
552 : }
553 :
554 : /**
555 : * Fetch the DDFModule with which this record is associated.
556 : */
557 :
558 0 : DDFModule *GetModule()
559 : {
560 0 : return poModule;
561 : }
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 : {
580 : return nReuseHeader;
581 : }
582 :
583 : int GetSizeFieldTag() const
584 : {
585 : return _sizeFieldTag;
586 : }
587 :
588 : int GetSizeFieldPos() const
589 : {
590 : return _sizeFieldPos;
591 : }
592 :
593 : int GetSizeFieldLength() const
594 : {
595 : return _sizeFieldLength;
596 : }
597 :
598 : // void SetReuseHeader(int bFlag) { nReuseHeader = bFlag; }
599 : void SetSizeFieldTag(int nVal)
600 : {
601 : _sizeFieldTag = nVal;
602 : }
603 :
604 : void SetSizeFieldPos(int nVal)
605 : {
606 : _sizeFieldPos = nVal;
607 : }
608 :
609 : void SetSizeFieldLength(int nVal)
610 : {
611 : _sizeFieldLength = nVal;
612 : }
613 :
614 : // This is really just for the DDFModule class.
615 : int Read();
616 : void Clear();
617 : void ResetDirectory();
618 :
619 1358 : void RemoveIsCloneFlag()
620 : {
621 1358 : bIsClone = FALSE;
622 1358 : }
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 12528 : DDFField() : poDefn(nullptr), nDataSize(0), pachData(nullptr)
665 : {
666 12528 : }
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 11613 : const char *GetData() const
682 : {
683 11613 : return pachData;
684 : }
685 :
686 : /** Return the number of bytes in the data block returned by GetData(). */
687 12104 : int GetDataSize() const
688 : {
689 12104 : return nDataSize;
690 : }
691 :
692 : int GetRepeatCount() const;
693 :
694 : /** Fetch the corresponding DDFFieldDefn. */
695 152797 : DDFFieldDefn *GetFieldDefn()
696 : {
697 152797 : return poDefn;
698 : }
699 :
700 : /** Fetch the corresponding DDFFieldDefn. */
701 67209 : const DDFFieldDefn *GetFieldDefn() const
702 : {
703 67209 : return poDefn;
704 : }
705 :
706 : private:
707 : DDFFieldDefn *poDefn;
708 :
709 : int nDataSize;
710 :
711 : const char *pachData;
712 : };
713 :
714 : #endif /* ndef ISO8211_H_INCLUDED */
|