1 : /******************************************************************************
2 : * $Id: iso8211.h 20996 2010-10-28 18:38:15Z rouault $
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 : DDFInt,
41 : DDFFloat,
42 : DDFString,
43 : DDFBinaryString
44 : } DDFDataType;
45 :
46 : /************************************************************************/
47 : /* These should really be private to the library ... they are */
48 : /* mostly conveniences. */
49 : /************************************************************************/
50 :
51 : long CPL_ODLL DDFScanInt( const char *pszString, int nMaxChars );
52 : int CPL_ODLL DDFScanVariable( const char * pszString, int nMaxChars, int nDelimChar );
53 : char CPL_ODLL *DDFFetchVariable( const char *pszString, int nMaxChars,
54 : int nDelimChar1, int nDelimChar2,
55 : int *pnConsumedChars );
56 :
57 : #define DDF_FIELD_TERMINATOR 30
58 : #define DDF_UNIT_TERMINATOR 31
59 :
60 : /************************************************************************/
61 : /* Predeclarations */
62 : /************************************************************************/
63 :
64 : class DDFFieldDefn;
65 : class DDFSubfieldDefn;
66 : class DDFRecord;
67 : class DDFField;
68 :
69 : /************************************************************************/
70 : /* DDFModule */
71 : /************************************************************************/
72 :
73 : /**
74 : The primary class for reading ISO 8211 files. This class contains all
75 : the information read from the DDR record, and is used to read records
76 : from the file.
77 :
78 : */
79 :
80 : class CPL_ODLL DDFModule
81 : {
82 : public:
83 : DDFModule();
84 : ~DDFModule();
85 :
86 : int Open( const char * pszFilename, int bFailQuietly = FALSE );
87 : int Create( const char *pszFilename );
88 : void Close();
89 :
90 : int Initialize( char chInterchangeLevel = '3',
91 : char chLeaderIden = 'L',
92 : char chCodeExtensionIndicator = 'E',
93 : char chVersionNumber = '1',
94 : char chAppIndicator = ' ',
95 : const char *pszExtendedCharSet = " ! ",
96 : int nSizeFieldLength = 3,
97 : int nSizeFieldPos = 4,
98 : int nSizeFieldTag = 4 );
99 :
100 : void Dump( FILE * fp );
101 :
102 : DDFRecord *ReadRecord( void );
103 : void Rewind( long nOffset = -1 );
104 :
105 : DDFFieldDefn *FindFieldDefn( const char * );
106 :
107 : /** Fetch the number of defined fields. */
108 :
109 : int GetFieldCount() { return nFieldDefnCount; }
110 : DDFFieldDefn *GetField(int);
111 : void AddField( DDFFieldDefn *poNewFDefn );
112 :
113 : // This is really just for internal use.
114 1104 : int GetFieldControlLength() { return _fieldControlLength; }
115 : void AddCloneRecord( DDFRecord * );
116 : void RemoveCloneRecord( DDFRecord * );
117 :
118 : // This is just for DDFRecord.
119 98474 : VSILFILE *GetFP() { return fpDDF; }
120 :
121 : private:
122 : VSILFILE *fpDDF;
123 : int bReadOnly;
124 : long nFirstRecordOffset;
125 :
126 : char _interchangeLevel;
127 : char _inlineCodeExtensionIndicator;
128 : char _versionNumber;
129 : char _appIndicator;
130 : int _fieldControlLength;
131 : char _extendedCharSet[4];
132 :
133 : long _recLength;
134 : char _leaderIden;
135 : long _fieldAreaStart;
136 : long _sizeFieldLength;
137 : long _sizeFieldPos;
138 : long _sizeFieldTag;
139 :
140 : // One DirEntry per field.
141 : int nFieldDefnCount;
142 : DDFFieldDefn **papoFieldDefns;
143 :
144 : DDFRecord *poRecord;
145 :
146 : int nCloneCount;
147 : int nMaxCloneCount;
148 : DDFRecord **papoClones;
149 : };
150 :
151 : /************************************************************************/
152 : /* DDFFieldDefn */
153 : /************************************************************************/
154 :
155 : typedef enum { dsc_elementary, dsc_vector, dsc_array, dsc_concatenated } DDF_data_struct_code;
156 : typedef enum { dtc_char_string,
157 : dtc_implicit_point,
158 : dtc_explicit_point,
159 : dtc_explicit_point_scaled,
160 : dtc_char_bit_string,
161 : dtc_bit_string,
162 : dtc_mixed_data_type } DDF_data_type_code;
163 :
164 : /**
165 : * Information from the DDR defining one field. Note that just because
166 : * a field is defined for a DDFModule doesn't mean that it actually occurs
167 : * on any records in the module. DDFFieldDefns are normally just significant
168 : * as containers of the DDFSubfieldDefns.
169 : */
170 :
171 : class CPL_ODLL DDFFieldDefn
172 : {
173 : public:
174 : DDFFieldDefn();
175 : ~DDFFieldDefn();
176 :
177 : int Create( const char *pszTag, const char *pszFieldName,
178 : const char *pszDescription,
179 : DDF_data_struct_code eDataStructCode,
180 : DDF_data_type_code eDataTypeCode,
181 : const char *pszFormat = NULL );
182 : void AddSubfield( DDFSubfieldDefn *poNewSFDefn,
183 : int bDontAddToFormat = FALSE );
184 : void AddSubfield( const char *pszName, const char *pszFormat );
185 : int GenerateDDREntry( char **ppachData, int *pnLength );
186 :
187 : int Initialize( DDFModule * poModule, const char *pszTag,
188 : int nSize, const char * pachRecord );
189 :
190 : void Dump( FILE * fp );
191 :
192 : /** Fetch a pointer to the field name (tag).
193 : * @return this is an internal copy and shouldn't be freed.
194 : */
195 2014620 : const char *GetName() { return pszTag; }
196 :
197 : /** Fetch a longer descriptio of this field.
198 : * @return this is an internal copy and shouldn't be freed.
199 : */
200 : const char *GetDescription() { return _fieldName; }
201 :
202 : /** Get the number of subfields. */
203 282818 : int GetSubfieldCount() { return nSubfieldCount; }
204 :
205 : DDFSubfieldDefn *GetSubfield( int i );
206 : DDFSubfieldDefn *FindSubfieldDefn( const char * );
207 :
208 : /**
209 : * Get the width of this field. This function isn't normally used
210 : * by applications.
211 : *
212 : * @return The width of the field in bytes, or zero if the field is not
213 : * apparently of a fixed width.
214 : */
215 1158 : int GetFixedWidth() { return nFixedWidth; }
216 :
217 : /**
218 : * Fetch repeating flag.
219 : * @see DDFField::GetRepeatCount()
220 : * @return TRUE if the field is marked as repeating.
221 : */
222 280 : int IsRepeating() { return bRepeatingSubfields; }
223 :
224 : static char *ExpandFormat( const char * );
225 :
226 : /** this is just for an S-57 hack for swedish data */
227 : void SetRepeatingFlag( int n ) { bRepeatingSubfields = n; }
228 :
229 : char *GetDefaultValue( int *pnSize );
230 :
231 : private:
232 :
233 : static char *ExtractSubstring( const char * );
234 :
235 : DDFModule * poModule;
236 : char * pszTag;
237 :
238 : char * _fieldName;
239 : char * _arrayDescr;
240 : char * _formatControls;
241 :
242 : int bRepeatingSubfields;
243 : int nFixedWidth; // zero if variable.
244 :
245 : int BuildSubfields();
246 : int ApplyFormats();
247 :
248 : DDF_data_struct_code _data_struct_code;
249 :
250 : DDF_data_type_code _data_type_code;
251 :
252 : int nSubfieldCount;
253 : DDFSubfieldDefn **papoSubfields;
254 : };
255 :
256 : /************************************************************************/
257 : /* DDFSubfieldDefn */
258 : /* */
259 : /* Information from the DDR record for one subfield of a */
260 : /* particular field. */
261 : /************************************************************************/
262 :
263 : /**
264 : * Information from the DDR record describing one subfield of a DDFFieldDefn.
265 : * All subfields of a field will occur in each occurance of that field
266 : * (as a DDFField) in a DDFRecord. Subfield's actually contain formatted
267 : * data (as instances within a record).
268 : */
269 :
270 : class CPL_ODLL DDFSubfieldDefn
271 : {
272 : public:
273 :
274 : DDFSubfieldDefn();
275 : ~DDFSubfieldDefn();
276 :
277 : void SetName( const char * pszName );
278 :
279 : /** Get pointer to subfield name. */
280 226042 : const char *GetName() { return pszName; }
281 :
282 : /** Get pointer to subfield format string */
283 486 : const char *GetFormat() { return pszFormatString; }
284 : int SetFormat( const char * pszFormat );
285 :
286 : /**
287 : * Get the general type of the subfield. This can be used to
288 : * determine which of ExtractFloatData(), ExtractIntData() or
289 : * ExtractStringData() should be used.
290 : * @return The subfield type. One of DDFInt, DDFFloat, DDFString or
291 : * DDFBinaryString.
292 : */
293 :
294 5792 : DDFDataType GetType() { return eType; }
295 :
296 : double ExtractFloatData( const char *pachData, int nMaxBytes,
297 : int * pnConsumedBytes );
298 : int ExtractIntData( const char *pachData, int nMaxBytes,
299 : int * pnConsumedBytes );
300 : const char *ExtractStringData( const char *pachData, int nMaxBytes,
301 : int * pnConsumedBytes );
302 : int GetDataLength( const char *, int, int * );
303 : void DumpData( const char *pachData, int nMaxBytes, FILE * fp );
304 :
305 : int FormatStringValue( char *pachData, int nBytesAvailable,
306 : int *pnBytesUsed, const char *pszValue,
307 : int nValueLength = -1 );
308 :
309 : int FormatIntValue( char *pachData, int nBytesAvailable,
310 : int *pnBytesUsed, int nNewValue );
311 :
312 : int FormatFloatValue( char *pachData, int nBytesAvailable,
313 : int *pnBytesUsed, double dfNewValue );
314 :
315 : /** Get the subfield width (zero for variable). */
316 11364 : int GetWidth() { return nFormatWidth; } // zero for variable.
317 :
318 : int GetDefaultValue( char *pachData, int nBytesAvailable,
319 : int *pnBytesUsed );
320 :
321 : void Dump( FILE * fp );
322 :
323 : /**
324 : Binary format: this is the digit immediately following the B or b for
325 : binary formats.
326 : */
327 : typedef enum {
328 : NotBinary=0,
329 : UInt=1,
330 : SInt=2,
331 : FPReal=3,
332 : FloatReal=4,
333 : FloatComplex=5
334 : } DDFBinaryFormat;
335 :
336 0 : DDFBinaryFormat GetBinaryFormat(void) const { return eBinaryFormat; }
337 :
338 :
339 : private:
340 :
341 : char *pszName; // a.k.a. subfield mnemonic
342 : char *pszFormatString;
343 :
344 : DDFDataType eType;
345 : DDFBinaryFormat eBinaryFormat;
346 :
347 : /* -------------------------------------------------------------------- */
348 : /* bIsVariable determines whether we using the */
349 : /* chFormatDelimeter (TRUE), or the fixed width (FALSE). */
350 : /* -------------------------------------------------------------------- */
351 : int bIsVariable;
352 :
353 : char chFormatDelimeter;
354 : int nFormatWidth;
355 :
356 : /* -------------------------------------------------------------------- */
357 : /* Fetched string cache. This is where we hold the values */
358 : /* returned from ExtractStringData(). */
359 : /* -------------------------------------------------------------------- */
360 : int nMaxBufChars;
361 : char *pachBuffer;
362 : };
363 :
364 : /************************************************************************/
365 : /* DDFRecord */
366 : /* */
367 : /* Class that contains one DR record from a file. We read into */
368 : /* the same record object repeatedly to ensure that repeated */
369 : /* leaders can be easily preserved. */
370 : /************************************************************************/
371 :
372 : /**
373 : * Contains instance data from one data record (DR). The data is contained
374 : * as a list of DDFField instances partitioning the raw data into fields.
375 : */
376 :
377 : class CPL_ODLL DDFRecord
378 : {
379 : public:
380 : DDFRecord( DDFModule * );
381 : ~DDFRecord();
382 :
383 : DDFRecord *Clone();
384 : DDFRecord *CloneOn( DDFModule * );
385 :
386 : void Dump( FILE * );
387 :
388 : /** Get the number of DDFFields on this record. */
389 : int GetFieldCount() { return nFieldCount; }
390 :
391 : DDFField *FindField( const char *, int = 0 );
392 : DDFField *GetField( int );
393 :
394 : int GetIntSubfield( const char *, int, const char *, int,
395 : int * = NULL );
396 : double GetFloatSubfield( const char *, int, const char *, int,
397 : int * = NULL );
398 : const char *GetStringSubfield( const char *, int, const char *, int,
399 : int * = NULL );
400 :
401 : int SetIntSubfield( const char *pszField, int iFieldIndex,
402 : const char *pszSubfield, int iSubfieldIndex,
403 : int nValue );
404 : int SetStringSubfield( const char *pszField, int iFieldIndex,
405 : const char *pszSubfield, int iSubfieldIndex,
406 : const char *pszValue, int nValueLength=-1 );
407 : int SetFloatSubfield( const char *pszField, int iFieldIndex,
408 : const char *pszSubfield, int iSubfieldIndex,
409 : double dfNewValue );
410 :
411 : /** Fetch size of records raw data (GetData()) in bytes. */
412 : int GetDataSize() { return nDataSize; }
413 :
414 : /**
415 : * Fetch the raw data for this record. The returned pointer is effectively
416 : * to the data for the first field of the record, and is of size
417 : * GetDataSize().
418 : */
419 0 : const char *GetData() { return pachData; }
420 :
421 : /**
422 : * Fetch the DDFModule with which this record is associated.
423 : */
424 :
425 : DDFModule * GetModule() { return poModule; }
426 :
427 : int ResizeField( DDFField *poField, int nNewDataSize );
428 : int DeleteField( DDFField *poField );
429 : DDFField* AddField( DDFFieldDefn * );
430 :
431 : int CreateDefaultFieldInstance( DDFField *poField, int iIndexWithinField );
432 :
433 : int SetFieldRaw( DDFField *poField, int iIndexWithinField,
434 : const char *pachRawData, int nRawDataSize );
435 : int UpdateFieldRaw( DDFField *poField, int iIndexWithinField,
436 : int nStartOffset, int nOldSize,
437 : const char *pachRawData, int nRawDataSize );
438 :
439 : int Write();
440 :
441 : // This is really just for the DDFModule class.
442 : int Read();
443 : void Clear();
444 : int ResetDirectory();
445 :
446 : private:
447 :
448 : int ReadHeader();
449 :
450 : DDFModule *poModule;
451 :
452 : int nReuseHeader;
453 :
454 : int nFieldOffset; // field data area, not dir entries.
455 :
456 : int _sizeFieldTag;
457 : int _sizeFieldPos;
458 : int _sizeFieldLength;
459 :
460 : int nDataSize; // Whole record except leader with header
461 : char *pachData;
462 :
463 : int nFieldCount;
464 : DDFField *paoFields;
465 :
466 : int bIsClone;
467 : };
468 :
469 : /************************************************************************/
470 : /* DDFField */
471 : /* */
472 : /* This object represents one field in a DDFRecord. */
473 : /************************************************************************/
474 :
475 : /**
476 : * This object represents one field in a DDFRecord. This
477 : * models an instance of the fields data, rather than it's data definition
478 : * which is handled by the DDFFieldDefn class. Note that a DDFField
479 : * doesn't have DDFSubfield children as you would expect. To extract
480 : * subfield values use GetSubfieldData() to find the right data pointer and
481 : * then use ExtractIntData(), ExtractFloatData() or ExtractStringData().
482 : */
483 :
484 : class CPL_ODLL DDFField
485 : {
486 : public:
487 : void Initialize( DDFFieldDefn *, const char *pszData,
488 : int nSize );
489 :
490 : void Dump( FILE * fp );
491 :
492 : const char *GetSubfieldData( DDFSubfieldDefn *,
493 : int * = NULL, int = 0 );
494 :
495 : const char *GetInstanceData( int nInstance, int *pnSize );
496 :
497 : /**
498 : * Return the pointer to the entire data block for this record. This
499 : * is an internal copy, and shouldn't be freed by the application.
500 : */
501 180362 : const char *GetData() { return pachData; }
502 :
503 : /** Return the number of bytes in the data block returned by GetData(). */
504 178852 : int GetDataSize() { return nDataSize; }
505 :
506 : int GetRepeatCount();
507 :
508 : /** Fetch the corresponding DDFFieldDefn. */
509 548102 : DDFFieldDefn *GetFieldDefn() { return poDefn; }
510 :
511 : private:
512 : DDFFieldDefn *poDefn;
513 :
514 : int nDataSize;
515 :
516 : const char *pachData;
517 : };
518 :
519 :
520 : #endif /* ndef _ISO8211_H_INCLUDED */
|