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