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