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