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