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