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