1 : /******************************************************************************
2 : * $Id: ddfsubfielddefn.cpp 23595 2011-12-18 22:58:47Z 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 23595 2011-12-18 22:58:47Z rouault $");
34 :
35 : /************************************************************************/
36 : /* DDFSubfieldDefn() */
37 : /************************************************************************/
38 :
39 5324 : DDFSubfieldDefn::DDFSubfieldDefn()
40 :
41 : {
42 5324 : pszName = NULL;
43 :
44 5324 : bIsVariable = TRUE;
45 5324 : nFormatWidth = 0;
46 5324 : chFormatDelimeter = DDF_UNIT_TERMINATOR;
47 5324 : eBinaryFormat = NotBinary;
48 5324 : eType = DDFString;
49 :
50 5324 : pszFormatString = CPLStrdup("");
51 :
52 5324 : nMaxBufChars = 0;
53 5324 : pachBuffer = NULL;
54 5324 : }
55 :
56 : /************************************************************************/
57 : /* ~DDFSubfieldDefn() */
58 : /************************************************************************/
59 :
60 5324 : DDFSubfieldDefn::~DDFSubfieldDefn()
61 :
62 : {
63 5324 : CPLFree( pszName );
64 5324 : CPLFree( pszFormatString );
65 5324 : CPLFree( pachBuffer );
66 5324 : }
67 :
68 : /************************************************************************/
69 : /* SetName() */
70 : /************************************************************************/
71 :
72 5324 : void DDFSubfieldDefn::SetName( const char * pszNewName )
73 :
74 : {
75 : int i;
76 :
77 5324 : CPLFree( pszName );
78 :
79 5324 : pszName = CPLStrdup( pszNewName );
80 :
81 5912 : for( i = strlen(pszName)-1; i > 0 && pszName[i] == ' '; i-- )
82 588 : pszName[i] = '\0';
83 5324 : }
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 5324 : int DDFSubfieldDefn::SetFormat( const char * pszFormat )
97 :
98 : {
99 5324 : CPLFree( pszFormatString );
100 5324 : pszFormatString = CPLStrdup( pszFormat );
101 :
102 : /* -------------------------------------------------------------------- */
103 : /* These values will likely be used. */
104 : /* -------------------------------------------------------------------- */
105 5324 : if( pszFormatString[1] == '(' )
106 : {
107 3776 : nFormatWidth = atoi(pszFormatString+2);
108 3776 : bIsVariable = nFormatWidth == 0;
109 : }
110 : else
111 1548 : bIsVariable = TRUE;
112 :
113 : /* -------------------------------------------------------------------- */
114 : /* Interpret the format string. */
115 : /* -------------------------------------------------------------------- */
116 5324 : switch( pszFormatString[0] )
117 : {
118 : case 'A':
119 : case 'C': // It isn't clear to me how this is different than 'A'
120 1974 : eType = DDFString;
121 1974 : break;
122 :
123 : case 'R':
124 280 : eType = DDFFloat;
125 280 : break;
126 :
127 : case 'I':
128 : case 'S':
129 2024 : eType = DDFInt;
130 2024 : break;
131 :
132 : case 'B':
133 : case 'b':
134 : // Is the width expressed in bits? (is it a bitstring)
135 1046 : bIsVariable = FALSE;
136 1046 : if( pszFormatString[1] == '(' )
137 : {
138 62 : 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 62 : nFormatWidth = atoi(pszFormatString+2) / 8;
147 62 : eBinaryFormat = SInt; // good default, works for SDTS.
148 :
149 62 : if( nFormatWidth < 5 )
150 20 : eType = DDFInt;
151 : else
152 42 : eType = DDFBinaryString;
153 : }
154 :
155 : // or do we have a binary type indicator? (is it binary)
156 : else
157 : {
158 984 : eBinaryFormat = (DDFBinaryFormat) (pszFormatString[1] - '0');
159 984 : nFormatWidth = atoi(pszFormatString+2);
160 :
161 1968 : if( eBinaryFormat == SInt || eBinaryFormat == UInt )
162 984 : eType = DDFInt;
163 : else
164 0 : eType = DDFFloat;
165 : }
166 1046 : 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 5324 : 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 174570 : int DDFSubfieldDefn::GetDataLength( const char * pachSourceData,
240 : int nMaxBytes, int * pnConsumedBytes )
241 :
242 : {
243 174570 : if( !bIsVariable )
244 : {
245 170858 : 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 170858 : if( pnConsumedBytes != NULL )
260 164176 : *pnConsumedBytes = nFormatWidth;
261 :
262 170858 : return nFormatWidth;
263 : }
264 : }
265 : else
266 : {
267 3712 : int nLength = 0;
268 3712 : int bAsciiField = TRUE;
269 3712 : 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 11140 : if( nMaxBytes > 1
293 3712 : && (pachSourceData[nMaxBytes-2] == chFormatDelimeter
294 3468 : || pachSourceData[nMaxBytes-2] == DDF_FIELD_TERMINATOR)
295 248 : && pachSourceData[nMaxBytes-1] == 0x00 )
296 4 : bAsciiField = FALSE;
297 :
298 : // if( !bAsciiField )
299 : // CPLDebug( "ISO8211", "Non-ASCII field detected." );
300 :
301 37390 : while( nLength < nMaxBytes)
302 : {
303 33678 : if (bAsciiField)
304 : {
305 62640 : if (pachSourceData[nLength] == chFormatDelimeter ||
306 29482 : pachSourceData[nLength] == DDF_FIELD_TERMINATOR)
307 3708 : break;
308 : }
309 : else
310 : {
311 1552 : if (nLength > 0
312 516 : && (pachSourceData[nLength-1] == chFormatDelimeter
313 508 : || pachSourceData[nLength-1] == DDF_FIELD_TERMINATOR)
314 8 : && 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 8 : if (nLength+1 < nMaxBytes &&
320 4 : pachSourceData[nLength+1] == DDF_FIELD_TERMINATOR)
321 4 : extraConsumedBytes++;
322 4 : break;
323 : }
324 : }
325 :
326 29966 : nLength++;
327 : }
328 :
329 3712 : if( pnConsumedBytes != NULL )
330 : {
331 2934 : if( nMaxBytes == 0 )
332 0 : *pnConsumedBytes = nLength + extraConsumedBytes;
333 : else
334 2934 : *pnConsumedBytes = nLength + extraConsumedBytes + 1;
335 : }
336 :
337 3712 : 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 7586 : DDFSubfieldDefn::ExtractStringData( const char * pachSourceData,
378 : int nMaxBytes, int * pnConsumedBytes )
379 :
380 : {
381 : int nLength = GetDataLength( pachSourceData, nMaxBytes,
382 7586 : pnConsumedBytes );
383 :
384 : /* -------------------------------------------------------------------- */
385 : /* Do we need to grow the buffer. */
386 : /* -------------------------------------------------------------------- */
387 7586 : if( nMaxBufChars < nLength+1 )
388 : {
389 770 : CPLFree( pachBuffer );
390 :
391 770 : nMaxBufChars = nLength+1;
392 770 : 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 7586 : memcpy( pachBuffer, pachSourceData, nLength );
400 7586 : pachBuffer[nLength] = '\0';
401 :
402 7586 : 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 116 : DDFSubfieldDefn::ExtractFloatData( const char * pachSourceData,
434 : int nMaxBytes, int * pnConsumedBytes )
435 :
436 : {
437 116 : 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 116 : pnConsumedBytes));
446 :
447 : case 'B':
448 : case 'b':
449 : {
450 : unsigned char abyData[8];
451 :
452 0 : if( nFormatWidth > nMaxBytes )
453 : {
454 : CPLError( CE_Warning, CPLE_AppDefined,
455 : "Attempt to extract float subfield %s with format %s\n"
456 : "failed as only %d bytes available. Using zero.",
457 0 : pszName, pszFormatString, nMaxBytes );
458 0 : return 0;
459 : }
460 :
461 0 : if( pnConsumedBytes != NULL )
462 0 : *pnConsumedBytes = nFormatWidth;
463 :
464 : // Byte swap the data if it isn't in machine native format.
465 : // In any event we copy it into our buffer to ensure it is
466 : // word aligned.
467 : #ifdef CPL_LSB
468 0 : if( pszFormatString[0] == 'B' )
469 : #else
470 : if( pszFormatString[0] == 'b' )
471 : #endif
472 : {
473 0 : for( int i = 0; i < nFormatWidth; i++ )
474 0 : abyData[nFormatWidth-i-1] = pachSourceData[i];
475 : }
476 : else
477 : {
478 0 : memcpy( abyData, pachSourceData, nFormatWidth );
479 : }
480 :
481 : // Interpret the bytes of data.
482 0 : switch( eBinaryFormat )
483 : {
484 : case UInt:
485 0 : if( nFormatWidth == 1 )
486 0 : return( abyData[0] );
487 0 : else if( nFormatWidth == 2 )
488 0 : return( *((GUInt16 *) abyData) );
489 0 : else if( nFormatWidth == 4 )
490 0 : return( *((GUInt32 *) abyData) );
491 : else
492 : {
493 : //CPLAssert( FALSE );
494 0 : return 0.0;
495 : }
496 :
497 : case SInt:
498 0 : if( nFormatWidth == 1 )
499 0 : return( *((signed char *) abyData) );
500 0 : else if( nFormatWidth == 2 )
501 0 : return( *((GInt16 *) abyData) );
502 0 : else if( nFormatWidth == 4 )
503 0 : return( *((GInt32 *) abyData) );
504 : else
505 : {
506 : //CPLAssert( FALSE );
507 0 : return 0.0;
508 : }
509 :
510 : case FloatReal:
511 0 : if( nFormatWidth == 4 )
512 0 : return( *((float *) abyData) );
513 0 : else if( nFormatWidth == 8 )
514 0 : return( *((double *) abyData) );
515 : else
516 : {
517 : //CPLAssert( FALSE );
518 0 : return 0.0;
519 : }
520 :
521 : case NotBinary:
522 : case FPReal:
523 : case FloatComplex:
524 : //CPLAssert( FALSE );
525 0 : return 0.0;
526 : }
527 : break;
528 : // end of 'b'/'B' case.
529 : }
530 :
531 : default:
532 : //CPLAssert( FALSE );
533 0 : return 0.0;
534 : }
535 :
536 : //CPLAssert( FALSE );
537 0 : return 0.0;
538 : }
539 :
540 : /************************************************************************/
541 : /* ExtractIntData() */
542 : /************************************************************************/
543 :
544 : /**
545 : * Extract a subfield value as an integer. Given a pointer to the data
546 : * for this subfield (from within a DDFRecord) this method will return the
547 : * int data for this subfield. The number of bytes
548 : * consumed as part of this field can also be fetched. This method may be
549 : * called for any type of subfield, and will return zero if the subfield is
550 : * not numeric.
551 : *
552 : * @param pachSourceData The pointer to the raw data for this field. This
553 : * may have come from DDFRecord::GetData(), taking into account skip factors
554 : * over previous subfields data.
555 : * @param nMaxBytes The maximum number of bytes that are accessable after
556 : * pachSourceData.
557 : * @param pnConsumedBytes Pointer to an integer into which the number of
558 : * bytes consumed by this field should be written. May be NULL to ignore.
559 : * This is used as a skip factor to increment pachSourceData to point to the
560 : * next subfields data.
561 : *
562 : * @return The subfield's numeric value (or zero if it isn't numeric).
563 : *
564 : * @see ExtractFloatData(), ExtractStringData()
565 : */
566 :
567 : int
568 98788 : DDFSubfieldDefn::ExtractIntData( const char * pachSourceData,
569 : int nMaxBytes, int * pnConsumedBytes )
570 :
571 : {
572 98788 : switch( pszFormatString[0] )
573 : {
574 : case 'A':
575 : case 'I':
576 : case 'R':
577 : case 'S':
578 : case 'C':
579 : return atoi(ExtractStringData(pachSourceData, nMaxBytes,
580 966 : pnConsumedBytes));
581 :
582 : case 'B':
583 : case 'b':
584 : {
585 : unsigned char abyData[8];
586 :
587 97822 : if( nFormatWidth > nMaxBytes )
588 : {
589 : CPLError( CE_Warning, CPLE_AppDefined,
590 : "Attempt to extract int subfield %s with format %s\n"
591 : "failed as only %d bytes available. Using zero.",
592 0 : pszName, pszFormatString, nMaxBytes );
593 0 : return 0;
594 : }
595 :
596 97822 : if( pnConsumedBytes != NULL )
597 97562 : *pnConsumedBytes = nFormatWidth;
598 :
599 : // Byte swap the data if it isn't in machine native format.
600 : // In any event we copy it into our buffer to ensure it is
601 : // word aligned.
602 : #ifdef CPL_LSB
603 97822 : if( pszFormatString[0] == 'B' )
604 : #else
605 : if( pszFormatString[0] == 'b' )
606 : #endif
607 : {
608 0 : for( int i = 0; i < nFormatWidth; i++ )
609 0 : abyData[nFormatWidth-i-1] = pachSourceData[i];
610 : }
611 : else
612 : {
613 97822 : memcpy( abyData, pachSourceData, nFormatWidth );
614 : }
615 :
616 : // Interpret the bytes of data.
617 97822 : switch( eBinaryFormat )
618 : {
619 : case UInt:
620 97334 : if( nFormatWidth == 4 )
621 47300 : return( (int) *((GUInt32 *) abyData) );
622 50034 : else if( nFormatWidth == 1 )
623 32998 : return( abyData[0] );
624 17036 : else if( nFormatWidth == 2 )
625 17036 : return( *((GUInt16 *) abyData) );
626 : else
627 : {
628 : //CPLAssert( FALSE );
629 0 : return 0;
630 : }
631 :
632 : case SInt:
633 488 : if( nFormatWidth == 4 )
634 488 : return( *((GInt32 *) abyData) );
635 0 : else if( nFormatWidth == 1 )
636 0 : return( *((signed char *) abyData) );
637 0 : else if( nFormatWidth == 2 )
638 0 : return( *((GInt16 *) abyData) );
639 : else
640 : {
641 : //CPLAssert( FALSE );
642 0 : return 0;
643 : }
644 :
645 : case FloatReal:
646 0 : if( nFormatWidth == 4 )
647 0 : return( (int) *((float *) abyData) );
648 0 : else if( nFormatWidth == 8 )
649 0 : return( (int) *((double *) abyData) );
650 : else
651 : {
652 : //CPLAssert( FALSE );
653 0 : return 0;
654 : }
655 :
656 : case NotBinary:
657 : case FPReal:
658 : case FloatComplex:
659 : //CPLAssert( FALSE );
660 0 : return 0;
661 : }
662 : break;
663 : // end of 'b'/'B' case.
664 : }
665 :
666 : default:
667 : //CPLAssert( FALSE );
668 0 : return 0;
669 : }
670 :
671 : //CPLAssert( FALSE );
672 0 : return 0;
673 : }
674 :
675 : /************************************************************************/
676 : /* DumpData() */
677 : /* */
678 : /* Dump the instance data for this subfield from a data */
679 : /* record. This fits into the output dump stream of a DDFField. */
680 : /************************************************************************/
681 :
682 : /**
683 : * Dump subfield value to debugging file.
684 : *
685 : * @param pachData Pointer to data for this subfield.
686 : * @param nMaxBytes Maximum number of bytes available in pachData.
687 : * @param fp File to write report to.
688 : */
689 :
690 0 : void DDFSubfieldDefn::DumpData( const char * pachData, int nMaxBytes,
691 : FILE * fp )
692 :
693 : {
694 0 : if( eType == DDFFloat )
695 : fprintf( fp, " Subfield `%s' = %f\n",
696 : pszName,
697 0 : ExtractFloatData( pachData, nMaxBytes, NULL ) );
698 0 : else if( eType == DDFInt )
699 : fprintf( fp, " Subfield `%s' = %d\n",
700 : pszName,
701 0 : ExtractIntData( pachData, nMaxBytes, NULL ) );
702 0 : else if( eType == DDFBinaryString )
703 : {
704 : int nBytes, i;
705 0 : GByte *pabyBString = (GByte *) ExtractStringData( pachData, nMaxBytes, &nBytes );
706 :
707 0 : fprintf( fp, " Subfield `%s' = 0x", pszName );
708 0 : for( i = 0; i < MIN(nBytes,24); i++ )
709 0 : fprintf( fp, "%02X", pabyBString[i] );
710 :
711 0 : if( nBytes > 24 )
712 0 : fprintf( fp, "%s", "..." );
713 :
714 0 : fprintf( fp, "\n" );
715 : }
716 : else
717 : fprintf( fp, " Subfield `%s' = `%s'\n",
718 : pszName,
719 0 : ExtractStringData( pachData, nMaxBytes, NULL ) );
720 0 : }
721 :
722 : /************************************************************************/
723 : /* GetDefaultValue() */
724 : /************************************************************************/
725 :
726 : /**
727 : * Get default data.
728 : *
729 : * Returns the default subfield data contents for this subfield definition.
730 : * For variable length numbers this will normally be "0<unit-terminator>".
731 : * For variable length strings it will be "<unit-terminator>". For fixed
732 : * length numbers it is zero filled. For fixed length strings it is space
733 : * filled. For binary numbers it is binary zero filled.
734 : *
735 : * @param pachData the buffer into which the returned default will be placed.
736 : * May be NULL if just querying default size.
737 : * @param nBytesAvailable the size of pachData in bytes.
738 : * @param pnBytesUsed will receive the size of the subfield default data in
739 : * bytes.
740 : *
741 : * @return TRUE on success or FALSE on failure or if the passed buffer is too
742 : * small to hold the default.
743 : */
744 :
745 0 : int DDFSubfieldDefn::GetDefaultValue( char *pachData, int nBytesAvailable,
746 : int *pnBytesUsed )
747 :
748 : {
749 : int nDefaultSize;
750 :
751 0 : if( !bIsVariable )
752 0 : nDefaultSize = nFormatWidth;
753 : else
754 0 : nDefaultSize = 1;
755 :
756 0 : if( pnBytesUsed != NULL )
757 0 : *pnBytesUsed = nDefaultSize;
758 :
759 0 : if( pachData == NULL )
760 0 : return TRUE;
761 :
762 0 : if( nBytesAvailable < nDefaultSize )
763 0 : return FALSE;
764 :
765 0 : if( bIsVariable )
766 : {
767 0 : pachData[0] = DDF_UNIT_TERMINATOR;
768 : }
769 : else
770 : {
771 0 : if( GetBinaryFormat() == NotBinary )
772 : {
773 0 : if( GetType() == DDFInt || GetType() == DDFFloat )
774 0 : memset( pachData, '0', nDefaultSize );
775 : else
776 0 : memset( pachData, ' ', nDefaultSize );
777 : }
778 : else
779 0 : memset( pachData, 0, nDefaultSize );
780 : }
781 :
782 0 : return TRUE;
783 : }
784 :
785 : /************************************************************************/
786 : /* FormatStringValue() */
787 : /************************************************************************/
788 :
789 : /**
790 : * Format string subfield value.
791 : *
792 : * Returns a buffer with the passed in string value reformatted in a way
793 : * suitable for storage in a DDFField for this subfield.
794 : */
795 :
796 0 : int DDFSubfieldDefn::FormatStringValue( char *pachData, int nBytesAvailable,
797 : int *pnBytesUsed,
798 : const char *pszValue,
799 : int nValueLength )
800 :
801 : {
802 : int nSize;
803 :
804 0 : if( nValueLength == -1 )
805 0 : nValueLength = strlen(pszValue);
806 :
807 0 : if( bIsVariable )
808 : {
809 0 : nSize = nValueLength + 1;
810 : }
811 : else
812 : {
813 0 : nSize = nFormatWidth;
814 : }
815 :
816 0 : if( pnBytesUsed != NULL )
817 0 : *pnBytesUsed = nSize;
818 :
819 0 : if( pachData == NULL )
820 0 : return TRUE;
821 :
822 0 : if( nBytesAvailable < nSize )
823 0 : return FALSE;
824 :
825 0 : if( bIsVariable )
826 : {
827 0 : strncpy( pachData, pszValue, nSize-1 );
828 0 : pachData[nSize-1] = DDF_UNIT_TERMINATOR;
829 : }
830 : else
831 : {
832 0 : if( GetBinaryFormat() == NotBinary )
833 : {
834 0 : memset( pachData, ' ', nSize );
835 0 : memcpy( pachData, pszValue, MIN(nValueLength,nSize) );
836 : }
837 : else
838 : {
839 0 : memset( pachData, 0, nSize );
840 0 : memcpy( pachData, pszValue, MIN(nValueLength,nSize) );
841 : }
842 : }
843 :
844 0 : return TRUE;
845 : }
846 :
847 : /************************************************************************/
848 : /* FormatIntValue() */
849 : /************************************************************************/
850 :
851 : /**
852 : * Format int subfield value.
853 : *
854 : * Returns a buffer with the passed in int value reformatted in a way
855 : * suitable for storage in a DDFField for this subfield.
856 : */
857 :
858 0 : int DDFSubfieldDefn::FormatIntValue( char *pachData, int nBytesAvailable,
859 : int *pnBytesUsed, int nNewValue )
860 :
861 : {
862 : int nSize;
863 : char szWork[30];
864 :
865 0 : sprintf( szWork, "%d", nNewValue );
866 :
867 0 : if( bIsVariable )
868 : {
869 0 : nSize = strlen(szWork) + 1;
870 : }
871 : else
872 : {
873 0 : nSize = nFormatWidth;
874 :
875 0 : if( GetBinaryFormat() == NotBinary && (int) strlen(szWork) > nSize )
876 0 : return FALSE;
877 : }
878 :
879 0 : if( pnBytesUsed != NULL )
880 0 : *pnBytesUsed = nSize;
881 :
882 0 : if( pachData == NULL )
883 0 : return TRUE;
884 :
885 0 : if( nBytesAvailable < nSize )
886 0 : return FALSE;
887 :
888 0 : if( bIsVariable )
889 : {
890 0 : strncpy( pachData, szWork, nSize-1 );
891 0 : pachData[nSize-1] = DDF_UNIT_TERMINATOR;
892 : }
893 : else
894 : {
895 0 : GUInt32 nMask = 0xff;
896 : int i;
897 :
898 0 : switch( GetBinaryFormat() )
899 : {
900 : case NotBinary:
901 0 : memset( pachData, '0', nSize );
902 : strncpy( pachData + nSize - strlen(szWork), szWork,
903 0 : strlen(szWork) );
904 0 : break;
905 :
906 : case UInt:
907 : case SInt:
908 0 : for( i = 0; i < nFormatWidth; i++ )
909 : {
910 : int iOut;
911 :
912 : // big endian required?
913 0 : if( pszFormatString[0] == 'B' )
914 0 : iOut = nFormatWidth - i - 1;
915 : else
916 0 : iOut = i;
917 :
918 0 : pachData[iOut] = (char)((nNewValue & nMask) >> (i*8));
919 0 : nMask *= 256;
920 : }
921 0 : break;
922 :
923 : case FloatReal:
924 0 : CPLAssert( FALSE );
925 0 : break;
926 :
927 : default:
928 0 : CPLAssert( FALSE );
929 : break;
930 : }
931 : }
932 :
933 0 : return TRUE;
934 : }
935 :
936 : /************************************************************************/
937 : /* FormatFloatValue() */
938 : /************************************************************************/
939 :
940 : /**
941 : * Format float subfield value.
942 : *
943 : * Returns a buffer with the passed in float value reformatted in a way
944 : * suitable for storage in a DDFField for this subfield.
945 : */
946 :
947 0 : int DDFSubfieldDefn::FormatFloatValue( char *pachData, int nBytesAvailable,
948 : int *pnBytesUsed, double dfNewValue )
949 :
950 : {
951 : int nSize;
952 : char szWork[120];
953 :
954 0 : sprintf( szWork, "%.16g", dfNewValue );
955 :
956 0 : if( bIsVariable )
957 : {
958 0 : nSize = strlen(szWork) + 1;
959 : }
960 : else
961 : {
962 0 : nSize = nFormatWidth;
963 :
964 0 : if( GetBinaryFormat() == NotBinary && (int) strlen(szWork) > nSize )
965 0 : return FALSE;
966 : }
967 :
968 0 : if( pnBytesUsed != NULL )
969 0 : *pnBytesUsed = nSize;
970 :
971 0 : if( pachData == NULL )
972 0 : return TRUE;
973 :
974 0 : if( nBytesAvailable < nSize )
975 0 : return FALSE;
976 :
977 0 : if( bIsVariable )
978 : {
979 0 : strncpy( pachData, szWork, nSize-1 );
980 0 : pachData[nSize-1] = DDF_UNIT_TERMINATOR;
981 : }
982 : else
983 : {
984 0 : if( GetBinaryFormat() == NotBinary )
985 : {
986 0 : memset( pachData, '0', nSize );
987 : strncpy( pachData + nSize - strlen(szWork), szWork,
988 0 : strlen(szWork) );
989 : }
990 : else
991 : {
992 0 : CPLAssert( FALSE );
993 : /* implement me */
994 : }
995 : }
996 :
997 0 : return TRUE;
998 : }
|