1 /******************************************************************************
2 *
3 * Project: ISO 8211 Access
4 * Purpose: Implements the DDFSubfieldDefn class.
5 * Author: Frank Warmerdam, warmerda@home.com
6 *
7 ******************************************************************************
8 * Copyright (c) 1999, Frank Warmerdam
9 *
10 * Permission is hereby granted, free of charge, to any person obtaining a
11 * copy of this software and associated documentation files (the "Software"),
12 * to deal in the Software without restriction, including without limitation
13 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 * and/or sell copies of the Software, and to permit persons to whom the
15 * Software is furnished to do so, subject to the following conditions:
16 *
17 * The above copyright notice and this permission notice shall be included
18 * in all copies or substantial portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 * DEALINGS IN THE SOFTWARE.
27 ******************************************************************************
28 *
29 * $Log: ddfsubfielddefn.cpp,v $
30 * Revision 1.1.1.1 2006/08/21 05:52:20 dsr
31 * Initial import as opencpn, GNU Automake compliant.
32 *
33 * Revision 1.1.1.1 2006/04/19 03:23:29 dsr
34 * Rename/Import to OpenCPN
35 *
36 * Revision 1.13 2004/01/06 19:07:14 warmerda
37 * Added braces within complex case in switch for HP/UX compatibility.
38 *
39 * Revision 1.12 2003/12/15 20:24:58 warmerda
40 * expand tabs
41 *
42 * Revision 1.11 2003/11/12 21:22:14 warmerda
43 * fixed some docs
44 *
45 * Revision 1.10 2003/09/05 19:13:45 warmerda
46 * added format support for binary ints
47 *
48 * Revision 1.9 2003/09/03 20:36:26 warmerda
49 * added subfield writing support
50 *
51 * Revision 1.8 2001/07/18 04:51:57 warmerda
52 *
53 * Revision 1.7 2000/09/19 14:09:34 warmerda
54 * avoid checking for field terminators in multi-byte strings
55 *
56 * Revision 1.6 2000/06/13 13:39:27 warmerda
57 * added warnings, and better handlng of short data for subfields
58 *
59 * Revision 1.5 1999/11/18 19:03:04 warmerda
60 * expanded tabs
61 *
62 * Revision 1.4 1999/05/10 17:36:23 warmerda
63 * Strip trailing spaces off subfield names.
64 *
65 * Revision 1.3 1999/05/06 15:15:07 warmerda
66 * Removed extra break;
67 *
68 * Revision 1.2 1999/05/06 14:25:43 warmerda
69 * added DDFBinaryString, and a bit of optimization
70 *
71 * Revision 1.1 1999/04/27 18:45:05 warmerda
72 * New
73 *
74 */
75
76 #include <algorithm>
77 #include "gdal/cpl_conv.h"
78 #include "iso8211.h"
79
80 /************************************************************************/
81 /* DDFSubfieldDefn() */
82 /************************************************************************/
83
DDFSubfieldDefn()84 DDFSubfieldDefn::DDFSubfieldDefn()
85
86 {
87 pszName = NULL;
88
89 bIsVariable = TRUE;
90 nFormatWidth = 0;
91 chFormatDelimeter = DDF_UNIT_TERMINATOR;
92 eBinaryFormat = NotBinary;
93 eType = DDFString;
94
95 pszFormatString = CPLStrdup("");
96
97 nMaxBufChars = 0;
98 pachBuffer = NULL;
99 }
100
101 /************************************************************************/
102 /* ~DDFSubfieldDefn() */
103 /************************************************************************/
104
~DDFSubfieldDefn()105 DDFSubfieldDefn::~DDFSubfieldDefn()
106
107 {
108 CPLFree( pszName );
109 CPLFree( pszFormatString );
110 CPLFree( pachBuffer );
111 }
112
113 /************************************************************************/
114 /* SetName() */
115 /************************************************************************/
116
SetName(const char * pszNewName)117 void DDFSubfieldDefn::SetName( const char * pszNewName )
118
119 {
120 int i;
121
122 CPLFree( pszName );
123
124 pszName = CPLStrdup( pszNewName );
125
126 for( i = strlen(pszName)-1; i > 0 && pszName[i] == ' '; i-- )
127 pszName[i] = '\0';
128 }
129
130 /************************************************************************/
131 /* SetFormat() */
132 /* */
133 /* While interpreting the format string we don't support: */
134 /* */
135 /* o Passing an explicit terminator for variable length field. */
136 /* o 'X' for unused data ... this should really be filtered */
137 /* out by DDFFieldDefn::ApplyFormats(), but isn't. */
138 /* o 'B' bitstrings that aren't a multiple of eight. */
139 /************************************************************************/
140
SetFormat(const char * pszFormat)141 int DDFSubfieldDefn::SetFormat( const char * pszFormat )
142
143 {
144 CPLFree( pszFormatString );
145 pszFormatString = CPLStrdup( pszFormat );
146
147 /* -------------------------------------------------------------------- */
148 /* These values will likely be used. */
149 /* -------------------------------------------------------------------- */
150 if( pszFormatString[1] == '(' )
151 {
152 nFormatWidth = atoi(pszFormatString+2);
153 bIsVariable = nFormatWidth == 0;
154 }
155 else
156 bIsVariable = TRUE;
157
158 /* -------------------------------------------------------------------- */
159 /* Interpret the format string. */
160 /* -------------------------------------------------------------------- */
161 switch( pszFormatString[0] )
162 {
163 case 'A':
164 case 'C': // It isn't clear to me how this is different than 'A'
165 eType = DDFString;
166 break;
167
168 case 'R':
169 eType = DDFFloat;
170 break;
171
172 case 'I':
173 case 'S':
174 eType = DDFInt;
175 break;
176
177 case 'B':
178 case 'b':
179 // Is the width expressed in bits? (is it a bitstring)
180 bIsVariable = FALSE;
181 if( pszFormatString[1] == '(' )
182 {
183 CPLAssert( atoi(pszFormatString+2) % 8 == 0 );
184
185 nFormatWidth = atoi(pszFormatString+2) / 8;
186 eBinaryFormat = SInt; // good default, works for SDTS.
187
188 if( nFormatWidth < 5 )
189 eType = DDFInt;
190 else
191 eType = DDFBinaryString;
192 }
193
194 // or do we have a binary type indicator? (is it binary)
195 else
196 {
197 eBinaryFormat = (DDFBinaryFormat) (pszFormatString[1] - '0');
198 nFormatWidth = atoi(pszFormatString+2);
199
200 if( eBinaryFormat == SInt || eBinaryFormat == UInt )
201 eType = DDFInt;
202 else
203 eType = DDFFloat;
204 }
205 break;
206
207 case 'X':
208 // 'X' is extra space, and shouldn't be directly assigned to a
209 // subfield ... I haven't encountered it in use yet though.
210 CPLError( CE_Failure, CPLE_AppDefined,
211 "Format type of `%c' not supported.\n",
212 pszFormatString[0] );
213
214 CPLAssert( FALSE );
215 return FALSE;
216
217 default:
218 CPLError( CE_Failure, CPLE_AppDefined,
219 "Format type of `%c' not recognised.\n",
220 pszFormatString[0] );
221
222 CPLAssert( FALSE );
223 return FALSE;
224 }
225
226 return TRUE;
227 }
228
229 /************************************************************************/
230 /* Dump() */
231 /************************************************************************/
232
233 /**
234 * Write out subfield definition info to debugging file.
235 *
236 * A variety of information about this field definition is written to the
237 * give debugging file handle.
238 *
239 * @param fp The standard io file handle to write to. ie. stderr
240 */
241
Dump(FILE * fp)242 void DDFSubfieldDefn::Dump( FILE * fp )
243
244 {
245 fprintf( fp, " DDFSubfieldDefn:\n" );
246 fprintf( fp, " Label = `%s'\n", pszName );
247 fprintf( fp, " FormatString = `%s'\n", pszFormatString );
248 }
249
250 /************************************************************************/
251 /* GetDataLength() */
252 /* */
253 /* This method will scan for the end of a variable field. */
254 /************************************************************************/
255
256 /**
257 * Scan for the end of variable length data. Given a pointer to the data
258 * for this subfield (from within a DDFRecord) this method will return the
259 * number of bytes which are data for this subfield. The number of bytes
260 * consumed as part of this field can also be fetched. This number may
261 * be one longer than the length if there is a terminator character
262 * used.<p>
263 *
264 * This method is mainly for internal use, or for applications which
265 * want the raw binary data to interpret themselves. Otherwise use one
266 * of ExtractStringData(), ExtractIntData() or ExtractFloatData().
267 *
268 * @param pachSourceData The pointer to the raw data for this field. This
269 * may have come from DDFRecord::GetData(), taking into account skip factors
270 * over previous subfields data.
271 * @param nMaxBytes The maximum number of bytes that are accessable after
272 * pachSourceData.
273 * @param pnConsumedBytes Pointer to an integer into which the number of
274 * bytes consumed by this field should be written. May be NULL to ignore.
275 *
276 * @return The number of bytes at pachSourceData which are actual data for
277 * this record (not including unit, or field terminator).
278 */
279
GetDataLength(const char * pachSourceData,int nMaxBytes,int * pnConsumedBytes)280 int DDFSubfieldDefn::GetDataLength( const char * pachSourceData,
281 int nMaxBytes, int * pnConsumedBytes )
282
283 {
284 if( !bIsVariable )
285 {
286 if( nFormatWidth > nMaxBytes )
287 {
288 CPLError( CE_Warning, CPLE_AppDefined,
289 "Only %d bytes available for subfield %s with\n"
290 "format string %s ... returning shortened data.",
291 nMaxBytes, pszName, pszFormatString );
292
293 if( pnConsumedBytes != NULL )
294 *pnConsumedBytes = nMaxBytes;
295
296 return nMaxBytes;
297 }
298 else
299 {
300 if( pnConsumedBytes != NULL )
301 *pnConsumedBytes = nFormatWidth;
302
303 return nFormatWidth;
304 }
305 }
306 #if 0
307 else
308 {
309 int nLength = 0;
310 int bCheckFieldTerminator = TRUE;
311
312 /* We only check for the field terminator because of some buggy
313 * datasets with missing format terminators. However, we have found
314 * the field terminator is a legal character within the fields of
315 * some extended datasets (such as JP34NC94.000). So we don't check
316 * for the field terminator if the field appears to be multi-byte
317 * which we established by the first character being out of the
318 * ASCII printable range (32-127).
319 */
320
321 if( pachSourceData[0] < 32 || pachSourceData[0] >= 127 )
322 bCheckFieldTerminator = FALSE;
323
324 while( nLength < nMaxBytes
325 && pachSourceData[nLength] != chFormatDelimeter )
326 {
327 if( bCheckFieldTerminator
328 && pachSourceData[nLength] == DDF_FIELD_TERMINATOR )
329 break;
330
331 nLength++;
332 }
333
334 if( pnConsumedBytes != NULL )
335 {
336 if( nMaxBytes == 0 )
337 *pnConsumedBytes = nLength;
338 else
339 *pnConsumedBytes = nLength+1;
340 }
341
342 return nLength;
343 }
344 #else
345 // This improved UTF-16 detection code comes from GDAL V110
346 else
347 {
348 int nLength = 0;
349 int bAsciiField = TRUE;
350 int extraConsumedBytes = 0;
351
352 /* We only check for the field terminator because of some buggy
353 * datasets with missing format terminators. However, we have found
354 * the field terminator and unit terminators are legal characters
355 * within the fields of some extended datasets (such as JP34NC94.000).
356 * So we don't check for the field terminator and unit terminators as
357 * a single byte if the field appears to be multi-byte which we
358 * establish by checking for the buffer ending with 0x1e 0x00 (a
359 * two byte field terminator).
360 *
361 * In the case of S57, the subfield ATVL of the NATF field can be
362 * encoded in lexical level 2 (see S57 specification, Edition 3.1,
363 * paragraph 2.4 and 2.5). In that case the Unit Terminator and Field
364 * Terminator are followed by the NULL character.
365 * A better fix would be to read the NALL tag in the DSSI to check
366 * that the lexical level is 2, instead of relying on the value of
367 * the first byte as we are doing - but that is not information
368 * that is available at the libiso8211 level (bug #1526)
369 */
370
371 // If the whole field ends with 0x1e 0x00 then we assume this
372 // field is a double byte character set.
373 if( nMaxBytes > 1
374 && (pachSourceData[nMaxBytes-2] == chFormatDelimeter
375 || pachSourceData[nMaxBytes-2] == DDF_FIELD_TERMINATOR)
376 && pachSourceData[nMaxBytes-1] == 0x00 )
377 bAsciiField = FALSE;
378
379 // if( !bAsciiField )
380 // CPLDebug( "ISO8211", "Non-ASCII field detected." );
381
382 while( nLength < nMaxBytes)
383 {
384 if (bAsciiField)
385 {
386 if (pachSourceData[nLength] == chFormatDelimeter ||
387 pachSourceData[nLength] == DDF_FIELD_TERMINATOR)
388 break;
389 }
390 else
391 {
392 if (nLength > 0
393 && (pachSourceData[nLength-1] == chFormatDelimeter
394 || pachSourceData[nLength-1] == DDF_FIELD_TERMINATOR)
395 && pachSourceData[nLength] == 0)
396 {
397 // Suck up the field terminator if one follows
398 // or else it will be interpreted as a new subfield.
399 // This is a pretty ugly counter-intuitive hack!
400 if (nLength+1 < nMaxBytes && pachSourceData[nLength+1] == DDF_FIELD_TERMINATOR)
401 extraConsumedBytes++;
402 if (nLength+2 < nMaxBytes && pachSourceData[nLength+2] == 0)
403 extraConsumedBytes++;
404
405
406 break;
407 }
408 }
409
410 nLength++;
411 }
412
413 if( pnConsumedBytes != NULL )
414 {
415 if( nMaxBytes == 0 )
416 *pnConsumedBytes = nLength + extraConsumedBytes;
417 else
418 *pnConsumedBytes = nLength + extraConsumedBytes + 1;
419 }
420
421 return nLength;
422 }
423 #endif
424 }
425
426 /************************************************************************/
427 /* ExtractStringData() */
428 /************************************************************************/
429
430 /**
431 * Extract a zero terminated string containing the data for this subfield.
432 * Given a pointer to the data
433 * for this subfield (from within a DDFRecord) this method will return the
434 * data for this subfield. The number of bytes
435 * consumed as part of this field can also be fetched. This number may
436 * be one longer than the string length if there is a terminator character
437 * used.<p>
438 *
439 * This function will return the raw binary data of a subfield for
440 * types other than DDFString, including data past zero chars. This is
441 * the standard way of extracting DDFBinaryString subfields for instance.<p>
442 *
443 * @param pachSourceData The pointer to the raw data for this field. This
444 * may have come from DDFRecord::GetData(), taking into account skip factors
445 * over previous subfields data.
446 * @param nMaxBytes The maximum number of bytes that are accessable after
447 * pachSourceData.
448 * @param pnConsumedBytes Pointer to an integer into which the number of
449 * bytes consumed by this field should be written. May be NULL to ignore.
450 * This is used as a skip factor to increment pachSourceData to point to the
451 * next subfields data.
452 *
453 * @return A pointer to a buffer containing the data for this field. The
454 * returned pointer is to an internal buffer which is invalidated on the
455 * next ExtractStringData() call on this DDFSubfieldDefn(). It should not
456 * be freed by the application.
457 *
458 * @see ExtractIntData(), ExtractFloatData()
459 */
460
461 const char *
ExtractStringData(const char * pachSourceData,int nMaxBytes,int * pnConsumedBytes)462 DDFSubfieldDefn::ExtractStringData( const char * pachSourceData,
463 int nMaxBytes, int * pnConsumedBytes )
464
465 {
466 int nLength = GetDataLength( pachSourceData, nMaxBytes,
467 pnConsumedBytes );
468
469 /* -------------------------------------------------------------------- */
470 /* Do we need to grow the buffer. */
471 /* -------------------------------------------------------------------- */
472 if( nMaxBufChars < nLength+1 )
473 {
474 CPLFree( pachBuffer );
475
476 nMaxBufChars = nLength+1;
477 pachBuffer = (char *) CPLMalloc(nMaxBufChars);
478 }
479
480 /* -------------------------------------------------------------------- */
481 /* Copy the data to the buffer. We use memcpy() so that it */
482 /* will work for binary data. */
483 /* -------------------------------------------------------------------- */
484 memcpy( pachBuffer, pachSourceData, nLength );
485 pachBuffer[nLength] = '\0';
486
487 return pachBuffer;
488 }
489
490 /************************************************************************/
491 /* ExtractFloatData() */
492 /************************************************************************/
493
494 /**
495 * Extract a subfield value as a float. Given a pointer to the data
496 * for this subfield (from within a DDFRecord) this method will return the
497 * floating point data for this subfield. The number of bytes
498 * consumed as part of this field can also be fetched. This method may be
499 * called for any type of subfield, and will return zero if the subfield is
500 * not numeric.
501 *
502 * @param pachSourceData The pointer to the raw data for this field. This
503 * may have come from DDFRecord::GetData(), taking into account skip factors
504 * over previous subfields data.
505 * @param nMaxBytes The maximum number of bytes that are accessable after
506 * pachSourceData.
507 * @param pnConsumedBytes Pointer to an integer into which the number of
508 * bytes consumed by this field should be written. May be NULL to ignore.
509 * This is used as a skip factor to increment pachSourceData to point to the
510 * next subfields data.
511 *
512 * @return The subfield's numeric value (or zero if it isn't numeric).
513 *
514 * @see ExtractIntData(), ExtractStringData()
515 */
516
517 double
ExtractFloatData(const char * pachSourceData,int nMaxBytes,int * pnConsumedBytes)518 DDFSubfieldDefn::ExtractFloatData( const char * pachSourceData,
519 int nMaxBytes, int * pnConsumedBytes )
520
521 {
522 switch( pszFormatString[0] )
523 {
524 case 'A':
525 case 'I':
526 case 'R':
527 case 'S':
528 case 'C':
529 return atof(ExtractStringData(pachSourceData, nMaxBytes,
530 pnConsumedBytes));
531
532 case 'B':
533 case 'b':
534 {
535 unsigned char abyData[8] = {0,0,0,0,0,0,0,0};
536
537 CPLAssert( nFormatWidth <= nMaxBytes );
538 if( pnConsumedBytes != NULL )
539 *pnConsumedBytes = nFormatWidth;
540
541 // Byte swap the data if it isn't in machine native format.
542 // In any event we copy it into our buffer to ensure it is
543 // word aligned.
544 #ifdef CPL_LSB
545 if( pszFormatString[0] == 'B' )
546 #else
547 if( pszFormatString[0] == 'b' )
548 #endif
549 {
550 for( int i = 0; i < nFormatWidth; i++ )
551 abyData[nFormatWidth-i-1] = pachSourceData[i];
552 }
553 else
554 {
555 memcpy( abyData, pachSourceData, nFormatWidth );
556 }
557
558 // Interpret the bytes of data.
559 switch( eBinaryFormat )
560 {
561 case UInt:
562 if( nFormatWidth == 1 )
563 return( abyData[0] );
564 else if( nFormatWidth == 2 )
565 return( *((GUInt16 *) abyData) );
566 else if( nFormatWidth == 4 )
567 return( *((GUInt32 *) abyData) );
568 else
569 {
570 CPLAssert( FALSE );
571 return 0.0;
572 }
573
574 case SInt:
575 if( nFormatWidth == 1 )
576 return( *((signed char *) abyData) );
577 else if( nFormatWidth == 2 )
578 return( *((GInt16 *) abyData) );
579 else if( nFormatWidth == 4 )
580 return( *((GInt32 *) abyData) );
581 else
582 {
583 CPLAssert( FALSE );
584 return 0.0;
585 }
586
587 case FloatReal:
588 if( nFormatWidth == 4 )
589 return( *((float *) abyData) );
590 else if( nFormatWidth == 8 )
591 return( *((double *) abyData) );
592 else
593 {
594 CPLAssert( FALSE );
595 return 0.0;
596 }
597
598 case NotBinary:
599 case FPReal:
600 case FloatComplex:
601 CPLAssert( FALSE );
602 return 0.0;
603 }
604 break;
605 // end of 'b'/'B' case.
606 }
607
608 default:
609 CPLAssert( FALSE );
610 return 0.0;
611 }
612
613 CPLAssert( FALSE );
614 return 0.0;
615 }
616
617 /************************************************************************/
618 /* ExtractIntData() */
619 /************************************************************************/
620
621 /**
622 * Extract a subfield value as an integer. Given a pointer to the data
623 * for this subfield (from within a DDFRecord) this method will return the
624 * int data for this subfield. The number of bytes
625 * consumed as part of this field can also be fetched. This method may be
626 * called for any type of subfield, and will return zero if the subfield is
627 * not numeric.
628 *
629 * @param pachSourceData The pointer to the raw data for this field. This
630 * may have come from DDFRecord::GetData(), taking into account skip factors
631 * over previous subfields data.
632 * @param nMaxBytes The maximum number of bytes that are accessable after
633 * pachSourceData.
634 * @param pnConsumedBytes Pointer to an integer into which the number of
635 * bytes consumed by this field should be written. May be NULL to ignore.
636 * This is used as a skip factor to increment pachSourceData to point to the
637 * next subfields data.
638 *
639 * @return The subfield's numeric value (or zero if it isn't numeric).
640 *
641 * @see ExtractFloatData(), ExtractStringData()
642 */
643
644 int
ExtractIntData(const char * pachSourceData,int nMaxBytes,int * pnConsumedBytes)645 DDFSubfieldDefn::ExtractIntData( const char * pachSourceData,
646 int nMaxBytes, int * pnConsumedBytes )
647
648 {
649 switch( pszFormatString[0] )
650 {
651 case 'A':
652 case 'I':
653 case 'R':
654 case 'S':
655 case 'C':
656 return atoi(ExtractStringData(pachSourceData, nMaxBytes,
657 pnConsumedBytes));
658
659 case 'B':
660 case 'b':
661 {
662 unsigned char abyData[8] = {0,0,0,0,0,0,0,0};
663
664 if( nFormatWidth > nMaxBytes )
665 {
666 CPLError( CE_Warning, CPLE_AppDefined,
667 "Attempt to extract int subfield %s with format %s\n"
668 "failed as only %d bytes available. Using zero.",
669 pszName, pszFormatString, nMaxBytes );
670 return 0;
671 }
672
673 if( pnConsumedBytes != NULL )
674 *pnConsumedBytes = nFormatWidth;
675
676 // Byte swap the data if it isn't in machine native format.
677 // In any event we copy it into our buffer to ensure it is
678 // word aligned.
679 #ifdef CPL_LSB
680 if( pszFormatString[0] == 'B' )
681 #else
682 if( pszFormatString[0] == 'b' )
683 #endif
684 {
685 for( int i = 0; i < nFormatWidth; i++ )
686 abyData[nFormatWidth-i-1] = pachSourceData[i];
687 }
688 else
689 {
690 memcpy( abyData, pachSourceData, nFormatWidth );
691 }
692
693 // Interpret the bytes of data.
694 switch( eBinaryFormat )
695 {
696 case UInt:
697 if( nFormatWidth == 4 )
698 return( (int) *((GUInt32 *) abyData) );
699 else if( nFormatWidth == 1 )
700 return( abyData[0] );
701 else if( nFormatWidth == 2 )
702 return( *((GUInt16 *) abyData) );
703 else
704 {
705 CPLAssert( FALSE );
706 return 0;
707 }
708
709 case SInt:
710 if( nFormatWidth == 4 )
711 return( *((GInt32 *) abyData) );
712 else if( nFormatWidth == 1 )
713 return( *((signed char *) abyData) );
714 else if( nFormatWidth == 2 )
715 return( *((GInt16 *) abyData) );
716 else
717 {
718 CPLAssert( FALSE );
719 return 0;
720 }
721
722 case FloatReal:
723 if( nFormatWidth == 4 )
724 return( (int) *((float *) abyData) );
725 else if( nFormatWidth == 8 )
726 return( (int) *((double *) abyData) );
727 else
728 {
729 CPLAssert( FALSE );
730 return 0;
731 }
732
733 case NotBinary:
734 case FPReal:
735 case FloatComplex:
736 CPLAssert( FALSE );
737 return 0;
738 }
739 break;
740 // end of 'b'/'B' case.
741 }
742
743 default:
744 CPLAssert( FALSE );
745 return 0;
746 }
747
748 CPLAssert( FALSE );
749 return 0;
750 }
751
752 /************************************************************************/
753 /* DumpData() */
754 /* */
755 /* Dump the instance data for this subfield from a data */
756 /* record. This fits into the output dump stream of a DDFField. */
757 /************************************************************************/
758
759 /**
760 * Dump subfield value to debugging file.
761 *
762 * @param pachData Pointer to data for this subfield.
763 * @param nMaxBytes Maximum number of bytes available in pachData.
764 * @param fp File to write report to.
765 */
766
DumpData(const char * pachData,int nMaxBytes,FILE * fp)767 void DDFSubfieldDefn::DumpData( const char * pachData, int nMaxBytes,
768 FILE * fp )
769
770 {
771 if( eType == DDFFloat )
772 fprintf( fp, " Subfield `%s' = %f\n",
773 pszName,
774 ExtractFloatData( pachData, nMaxBytes, NULL ) );
775 else if( eType == DDFInt )
776 fprintf( fp, " Subfield `%s' = %d\n",
777 pszName,
778 ExtractIntData( pachData, nMaxBytes, NULL ) );
779 else if( eType == DDFBinaryString )
780 {
781 int nBytes, i;
782 GByte *pabyBString = (GByte *) ExtractStringData( pachData, nMaxBytes, &nBytes );
783
784 fprintf( fp, " Subfield `%s' = 0x", pszName );
785 for( i = 0; i < std::min(nBytes,24); i++ )
786 fprintf( fp, "%02X", pabyBString[i] );
787
788 if( nBytes > 24 )
789 fprintf( fp, "%s", "..." );
790
791 fprintf( fp, "\n" );
792 }
793 else
794 fprintf( fp, " Subfield `%s' = `%s'\n",
795 pszName,
796 ExtractStringData( pachData, nMaxBytes, NULL ) );
797 }
798
799 /************************************************************************/
800 /* GetDefaultValue() */
801 /************************************************************************/
802
803 /**
804 * Get default data.
805 *
806 * Returns the default subfield data contents for this subfield definition.
807 * For variable length numbers this will normally be "0<unit-terminator>".
808 * For variable length strings it will be "<unit-terminator>". For fixed
809 * length numbers it is zero filled. For fixed length strings it is space
810 * filled. For binary numbers it is binary zero filled.
811 *
812 * @param pachData the buffer into which the returned default will be placed.
813 * May be NULL if just querying default size.
814 * @param nBytesAvailable the size of pachData in bytes.
815 * @param pnBytesUsed will receive the size of the subfield default data in
816 * bytes.
817 *
818 * @return TRUE on success or FALSE on failure or if the passed buffer is too
819 * small to hold the default.
820 */
821
GetDefaultValue(char * pachData,int nBytesAvailable,int * pnBytesUsed,bool b_isUTF16)822 int DDFSubfieldDefn::GetDefaultValue( char *pachData, int nBytesAvailable,
823 int *pnBytesUsed, bool b_isUTF16 )
824
825 {
826 int nDefaultSize;
827
828 if( !bIsVariable )
829 nDefaultSize = nFormatWidth;
830 else if(b_isUTF16 )
831 nDefaultSize = 2;
832 else
833 nDefaultSize = 1;
834
835 if( pnBytesUsed != NULL )
836 *pnBytesUsed = nDefaultSize;
837
838 if( pachData == NULL )
839 return TRUE;
840
841 if( nBytesAvailable < nDefaultSize )
842 return FALSE;
843
844 if( bIsVariable )
845 {
846 pachData[0] = DDF_UNIT_TERMINATOR;
847 if(b_isUTF16)
848 pachData[1] = 0;
849 }
850 else
851 {
852 if( GetBinaryFormat() == NotBinary )
853 {
854 if( GetType() == DDFInt || GetType() == DDFFloat )
855 memset( pachData, '0', nDefaultSize );
856 else
857 memset( pachData, ' ', nDefaultSize );
858 }
859 else
860 memset( pachData, 0, nDefaultSize );
861 }
862
863 return TRUE;
864 }
865
866 /************************************************************************/
867 /* FormatStringValue() */
868 /************************************************************************/
869
870 /**
871 * Format string subfield value.
872 *
873 * Returns a buffer with the passed in string value reformatted in a way
874 * suitable for storage in a DDFField for this subfield.
875 */
876
FormatStringValue(char * pachData,int nBytesAvailable,int * pnBytesUsed,const char * pszValue,int nValueLength)877 int DDFSubfieldDefn::FormatStringValue( char *pachData, int nBytesAvailable,
878 int *pnBytesUsed,
879 const char *pszValue,
880 int nValueLength )
881
882 {
883 int nSize;
884
885 if( nValueLength == -1 )
886 nValueLength = strlen(pszValue);
887
888 if( bIsVariable )
889 {
890 nSize = nValueLength + 1;
891 }
892 else
893 {
894 nSize = nFormatWidth;
895 }
896
897 if( pnBytesUsed != NULL )
898 *pnBytesUsed = nSize;
899
900 if( pachData == NULL )
901 return TRUE;
902
903 if( nBytesAvailable < nSize )
904 return FALSE;
905
906 if( bIsVariable )
907 {
908 strncpy( pachData, pszValue, nSize-1 );
909 pachData[nSize-1] = DDF_UNIT_TERMINATOR;
910 }
911 else
912 {
913 if( GetBinaryFormat() == NotBinary )
914 {
915 memset( pachData, ' ', nSize );
916 memcpy( pachData, pszValue, MIN(nValueLength,nSize) );
917 }
918 else
919 {
920 memset( pachData, 0, nSize );
921 memcpy( pachData, pszValue, MIN(nValueLength,nSize) );
922 }
923 }
924
925 return TRUE;
926 }
927
928 /************************************************************************/
929 /* FormatIntValue() */
930 /************************************************************************/
931
932 /**
933 * Format int subfield value.
934 *
935 * Returns a buffer with the passed in int value reformatted in a way
936 * suitable for storage in a DDFField for this subfield.
937 */
938
FormatIntValue(char * pachData,int nBytesAvailable,int * pnBytesUsed,int nNewValue)939 int DDFSubfieldDefn::FormatIntValue( char *pachData, int nBytesAvailable,
940 int *pnBytesUsed, int nNewValue )
941
942 {
943 #pragma GCC diagnostic push
944 #if defined(__GNUC__) && __GNUC__ >= 8
945 #pragma GCC diagnostic ignored "-Wstringop-truncation"
946 #pragma GCC diagnostic ignored "-Wstringop-overflow"
947 #endif
948
949 int nSize;
950 char szWork[30];
951
952 sprintf( szWork, "%d", nNewValue );
953
954 if( bIsVariable )
955 {
956 nSize = strlen(szWork) + 1;
957 }
958 else
959 {
960 nSize = nFormatWidth;
961
962 if( GetBinaryFormat() == NotBinary && (int) strlen(szWork) > nSize )
963 return FALSE;
964 }
965
966 if( pnBytesUsed != NULL )
967 *pnBytesUsed = nSize;
968
969 if( pachData == NULL )
970 return TRUE;
971
972 if( nBytesAvailable < nSize )
973 return FALSE;
974
975 if( bIsVariable )
976 {
977 strncpy( pachData, szWork, nSize-1 );
978 pachData[nSize-1] = DDF_UNIT_TERMINATOR;
979 }
980 else
981 {
982 GUInt32 nMask = 0xff;
983 int i;
984
985 switch( GetBinaryFormat() )
986 {
987 case NotBinary:
988 memset( pachData, '0', nSize );
989 strncpy( pachData + nSize - strlen(szWork), szWork,
990 strlen(szWork) );
991 break;
992
993 case UInt:
994 case SInt:
995 for( i = 0; i < nFormatWidth; i++ )
996 {
997 int iOut;
998
999 // big endian required?
1000 if( pszFormatString[0] == 'B' )
1001 iOut = nFormatWidth - i - 1;
1002 else
1003 iOut = i;
1004
1005 pachData[iOut] = (nNewValue & nMask) >> (i*8);
1006 nMask *= 256;
1007 }
1008 break;
1009
1010 case FloatReal:
1011 CPLAssert( FALSE );
1012 break;
1013
1014 default:
1015 CPLAssert( FALSE );
1016 break;
1017 }
1018 }
1019
1020 return TRUE;
1021 #pragma GCC diagnostic pop
1022 }
1023
1024 /************************************************************************/
1025 /* FormatFloatValue() */
1026 /************************************************************************/
1027
1028 /**
1029 * Format float subfield value.
1030 *
1031 * Returns a buffer with the passed in float value reformatted in a way
1032 * suitable for storage in a DDFField for this subfield.
1033 */
1034
FormatFloatValue(char * pachData,int nBytesAvailable,int * pnBytesUsed,double dfNewValue)1035 int DDFSubfieldDefn::FormatFloatValue( char *pachData, int nBytesAvailable,
1036 int *pnBytesUsed, double dfNewValue )
1037
1038 {
1039 #pragma GCC diagnostic push
1040 #if defined(__GNUC__) && __GNUC__ >= 8
1041 #pragma GCC diagnostic ignored "-Wstringop-truncation"
1042 #pragma GCC diagnostic ignored "-Wstringop-overflow"
1043 #endif
1044 int nSize;
1045 char szWork[120];
1046
1047 sprintf( szWork, "%.16g", dfNewValue );
1048
1049 if( bIsVariable )
1050 {
1051 nSize = strlen(szWork) + 1;
1052 }
1053 else
1054 {
1055 nSize = nFormatWidth;
1056
1057 if( GetBinaryFormat() == NotBinary && (int) strlen(szWork) > nSize )
1058 return FALSE;
1059 }
1060
1061 if( pnBytesUsed != NULL )
1062 *pnBytesUsed = nSize;
1063
1064 if( pachData == NULL )
1065 return TRUE;
1066
1067 if( nBytesAvailable < nSize )
1068 return FALSE;
1069
1070 if( bIsVariable )
1071 {
1072 strncpy( pachData, szWork, nSize-1 );
1073 pachData[nSize-1] = DDF_UNIT_TERMINATOR;
1074 }
1075 else
1076 {
1077 if( GetBinaryFormat() == NotBinary )
1078 {
1079 memset( pachData, '0', nSize );
1080 strncpy( pachData + nSize - strlen(szWork), szWork,
1081 strlen(szWork) );
1082 }
1083 else
1084 {
1085 CPLAssert( FALSE );
1086 /* implement me */
1087 }
1088 }
1089
1090 return TRUE;
1091 #pragma GCC diagnostic pop
1092 }
1093