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 213987 : const char *GetName() const
254 : {
255 213987 : 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 111837 : int GetSubfieldCount() const
268 : {
269 111837 : 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 28224 : int GetFixedWidth() const
283 : {
284 28224 : 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 7918 : int IsRepeating() const
293 : {
294 7918 : 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 :
353 : /************************************************************************/
354 : /* DDFSubfieldDefn */
355 : /* */
356 : /* Information from the DDR record for one subfield of a */
357 : /* particular field. */
358 : /************************************************************************/
359 :
360 : /**
361 : * Information from the DDR record describing one subfield of a DDFFieldDefn.
362 : * All subfields of a field will occur in each occurrence of that field
363 : * (as a DDFField) in a DDFRecord. Subfield's actually contain formatted
364 : * data (as instances within a record).
365 : */
366 :
367 : class CPL_ODLL DDFSubfieldDefn
368 : {
369 : public:
370 : DDFSubfieldDefn();
371 : ~DDFSubfieldDefn();
372 :
373 : void SetName(const char *pszName);
374 :
375 : /** Get pointer to subfield name. */
376 100425 : const char *GetName() const
377 : {
378 100425 : return pszName;
379 : }
380 :
381 : /** Get pointer to subfield format string */
382 5438 : const char *GetFormat() const
383 : {
384 5438 : return pszFormatString;
385 : }
386 :
387 : int SetFormat(const char *pszFormat);
388 :
389 : /**
390 : * Get the general type of the subfield. This can be used to
391 : * determine which of ExtractFloatData(), ExtractIntData() or
392 : * ExtractStringData() should be used.
393 : * @return The subfield type. One of DDFInt, DDFFloat, DDFString or
394 : * DDFBinaryString.
395 : */
396 :
397 108 : DDFDataType GetType() const
398 : {
399 108 : return eType;
400 : }
401 :
402 : double ExtractFloatData(const char *pachData, int nMaxBytes,
403 : int *pnConsumedBytes) const;
404 : int ExtractIntData(const char *pachData, int nMaxBytes,
405 : int *pnConsumedBytes) const;
406 : const char *ExtractStringData(const char *pachData, int nMaxBytes,
407 : int *pnConsumedBytes) const;
408 : int GetDataLength(const char *, int, int *) const;
409 : void DumpData(const char *pachData, int nMaxBytes, FILE *fp) const;
410 :
411 : int FormatStringValue(char *pachData, int nBytesAvailable, int *pnBytesUsed,
412 : const char *pszValue, int nValueLength = -1) const;
413 :
414 : int FormatIntValue(char *pachData, int nBytesAvailable, int *pnBytesUsed,
415 : int nNewValue) const;
416 :
417 : int FormatFloatValue(char *pachData, int nBytesAvailable, int *pnBytesUsed,
418 : double dfNewValue) const;
419 :
420 : /** Get the subfield width (zero for variable). */
421 16994 : int GetWidth() const
422 : {
423 16994 : return nFormatWidth;
424 : } // zero for variable.
425 :
426 : int GetDefaultValue(char *pachData, int nBytesAvailable,
427 : int *pnBytesUsed) const;
428 :
429 : void Dump(FILE *fp);
430 :
431 : /**
432 : Binary format: this is the digit immediately following the B or b for
433 : binary formats.
434 : */
435 : typedef enum
436 : {
437 : NotBinary = 0,
438 : UInt = 1,
439 : SInt = 2,
440 : FPReal = 3,
441 : FloatReal = 4,
442 : FloatComplex = 5
443 : } DDFBinaryFormat;
444 :
445 6791 : DDFBinaryFormat GetBinaryFormat() const
446 : {
447 6791 : return eBinaryFormat;
448 : }
449 :
450 : private:
451 : char *pszName; // a.k.a. subfield mnemonic
452 : char *pszFormatString;
453 :
454 : DDFDataType eType;
455 : DDFBinaryFormat eBinaryFormat;
456 :
457 : /* -------------------------------------------------------------------- */
458 : /* bIsVariable determines whether we using the */
459 : /* chFormatDelimiter (TRUE), or the fixed width (FALSE). */
460 : /* -------------------------------------------------------------------- */
461 : int bIsVariable;
462 :
463 : char chFormatDelimiter;
464 : int nFormatWidth;
465 :
466 : /* -------------------------------------------------------------------- */
467 : /* Fetched string cache. This is where we hold the values */
468 : /* returned from ExtractStringData(). */
469 : /* -------------------------------------------------------------------- */
470 : mutable int nMaxBufChars;
471 : mutable char *pachBuffer;
472 : };
473 :
474 : /************************************************************************/
475 : /* DDFRecord */
476 : /* */
477 : /* Class that contains one DR record from a file. We read into */
478 : /* the same record object repeatedly to ensure that repeated */
479 : /* leaders can be easily preserved. */
480 : /************************************************************************/
481 :
482 : /**
483 : * Contains instance data from one data record (DR). The data is contained
484 : * as a list of DDFField instances partitioning the raw data into fields.
485 : */
486 :
487 : class CPL_ODLL DDFRecord
488 : {
489 : public:
490 : explicit DDFRecord(DDFModule *);
491 : ~DDFRecord();
492 :
493 : DDFRecord *Clone();
494 : DDFRecord *CloneOn(DDFModule *);
495 :
496 : void Dump(FILE *);
497 :
498 : /** Get the number of DDFFields on this record. */
499 14959 : int GetFieldCount() const
500 : {
501 14959 : return nFieldCount;
502 : }
503 :
504 : const DDFField *FindField(const char *, int = 0) const;
505 :
506 14969 : DDFField *FindField(const char *name, int i = 0)
507 : {
508 : return const_cast<DDFField *>(
509 14969 : const_cast<const DDFRecord *>(this)->FindField(name, i));
510 : }
511 :
512 : const DDFField *GetField(int) const;
513 :
514 14310 : DDFField *GetField(int i)
515 : {
516 : return const_cast<DDFField *>(
517 14310 : const_cast<const DDFRecord *>(this)->GetField(i));
518 : }
519 :
520 : int GetIntSubfield(const char *, int, const char *, int,
521 : int * = nullptr) const;
522 : double GetFloatSubfield(const char *, int, const char *, int,
523 : int * = nullptr);
524 : const char *GetStringSubfield(const char *, int, const char *, int,
525 : int * = nullptr);
526 :
527 : int SetIntSubfield(const char *pszField, int iFieldIndex,
528 : const char *pszSubfield, int iSubfieldIndex, int nValue);
529 : int SetStringSubfield(const char *pszField, int iFieldIndex,
530 : const char *pszSubfield, int iSubfieldIndex,
531 : const char *pszValue, int nValueLength = -1);
532 : int SetFloatSubfield(const char *pszField, int iFieldIndex,
533 : const char *pszSubfield, int iSubfieldIndex,
534 : double dfNewValue);
535 :
536 : /** Fetch size of records raw data (GetData()) in bytes. */
537 : int GetDataSize() const
538 : {
539 : return nDataSize;
540 : }
541 :
542 : /**
543 : * Fetch the raw data for this record. The returned pointer is effectively
544 : * to the data for the first field of the record, and is of size
545 : * GetDataSize().
546 : */
547 154 : const char *GetData() const
548 : {
549 154 : return pachData;
550 : }
551 :
552 : /**
553 : * Fetch the DDFModule with which this record is associated.
554 : */
555 :
556 0 : DDFModule *GetModule()
557 : {
558 0 : return poModule;
559 : }
560 :
561 : int ResizeField(DDFField *poField, int nNewDataSize);
562 : int DeleteField(DDFField *poField);
563 : DDFField *AddField(DDFFieldDefn *);
564 :
565 : int CreateDefaultFieldInstance(DDFField *poField, int iIndexWithinField);
566 :
567 : int SetFieldRaw(DDFField *poField, int iIndexWithinField,
568 : const char *pachRawData, int nRawDataSize);
569 : int UpdateFieldRaw(DDFField *poField, int iIndexWithinField,
570 : int nStartOffset, int nOldSize, const char *pachRawData,
571 : int nRawDataSize);
572 :
573 : int Write();
574 :
575 : // Advanced uses for 8211dump/8211createfromxml
576 : int GetReuseHeader() const
577 : {
578 : return nReuseHeader;
579 : }
580 :
581 : int GetSizeFieldTag() const
582 : {
583 : return _sizeFieldTag;
584 : }
585 :
586 : int GetSizeFieldPos() const
587 : {
588 : return _sizeFieldPos;
589 : }
590 :
591 : int GetSizeFieldLength() const
592 : {
593 : return _sizeFieldLength;
594 : }
595 :
596 : // void SetReuseHeader(int bFlag) { nReuseHeader = bFlag; }
597 : void SetSizeFieldTag(int nVal)
598 : {
599 : _sizeFieldTag = nVal;
600 : }
601 :
602 : void SetSizeFieldPos(int nVal)
603 : {
604 : _sizeFieldPos = nVal;
605 : }
606 :
607 : void SetSizeFieldLength(int nVal)
608 : {
609 : _sizeFieldLength = nVal;
610 : }
611 :
612 : // This is really just for the DDFModule class.
613 : int Read();
614 : void Clear();
615 : void ResetDirectory();
616 :
617 1358 : void RemoveIsCloneFlag()
618 : {
619 1358 : bIsClone = FALSE;
620 1358 : }
621 :
622 : private:
623 : int ReadHeader();
624 :
625 : DDFModule *poModule;
626 :
627 : int nReuseHeader;
628 :
629 : int nFieldOffset; // field data area, not dir entries.
630 :
631 : int _sizeFieldTag;
632 : int _sizeFieldPos;
633 : int _sizeFieldLength;
634 :
635 : int nDataSize; // Whole record except leader with header
636 : char *pachData;
637 :
638 : int nFieldCount;
639 : DDFField *paoFields;
640 :
641 : int bIsClone;
642 : };
643 :
644 : /************************************************************************/
645 : /* DDFField */
646 : /* */
647 : /* This object represents one field in a DDFRecord. */
648 : /************************************************************************/
649 :
650 : /**
651 : * This object represents one field in a DDFRecord. This
652 : * models an instance of the fields data, rather than its data definition,
653 : * which is handled by the DDFFieldDefn class. Note that a DDFField
654 : * doesn't have DDFSubfield children as you would expect. To extract
655 : * subfield values use GetSubfieldData() to find the right data pointer and
656 : * then use ExtractIntData(), ExtractFloatData() or ExtractStringData().
657 : */
658 :
659 : class CPL_ODLL DDFField
660 : {
661 : public:
662 12528 : DDFField() : poDefn(nullptr), nDataSize(0), pachData(nullptr)
663 : {
664 12528 : }
665 :
666 : void Initialize(DDFFieldDefn *, const char *pszData, int nSize);
667 :
668 : void Dump(FILE *fp);
669 :
670 : const char *GetSubfieldData(const DDFSubfieldDefn *, int * = nullptr,
671 : int = 0) const;
672 :
673 : const char *GetInstanceData(int nInstance, int *pnSize);
674 :
675 : /**
676 : * Return the pointer to the entire data block for this record. This
677 : * is an internal copy, and should not be freed by the application.
678 : */
679 11610 : const char *GetData() const
680 : {
681 11610 : return pachData;
682 : }
683 :
684 : /** Return the number of bytes in the data block returned by GetData(). */
685 12101 : int GetDataSize() const
686 : {
687 12101 : return nDataSize;
688 : }
689 :
690 : int GetRepeatCount() const;
691 :
692 : /** Fetch the corresponding DDFFieldDefn. */
693 147401 : DDFFieldDefn *GetFieldDefn()
694 : {
695 147401 : return poDefn;
696 : }
697 :
698 : /** Fetch the corresponding DDFFieldDefn. */
699 64393 : const DDFFieldDefn *GetFieldDefn() const
700 : {
701 64393 : return poDefn;
702 : }
703 :
704 : private:
705 : DDFFieldDefn *poDefn;
706 :
707 : int nDataSize;
708 :
709 : const char *pachData;
710 : };
711 :
712 : #endif /* ndef ISO8211_H_INCLUDED */
|