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 : DDFSubfieldDefn::DDFSubfieldDefn() = default;
32 :
33 : /************************************************************************/
34 : /* ~DDFSubfieldDefn() */
35 : /************************************************************************/
36 :
37 : DDFSubfieldDefn::~DDFSubfieldDefn() = default;
38 :
39 : /************************************************************************/
40 : /* SetName() */
41 : /************************************************************************/
42 :
43 64284 : void DDFSubfieldDefn::SetName(const char *pszNewName)
44 :
45 : {
46 64284 : osName = pszNewName;
47 64284 : while (!osName.empty() && osName.back() == ' ')
48 0 : osName.pop_back();
49 64284 : }
50 :
51 : /************************************************************************/
52 : /* SetFormat() */
53 : /* */
54 : /* While interpreting the format string we don't support: */
55 : /* */
56 : /* o Passing an explicit terminator for variable length field. */
57 : /* o 'X' for unused data ... this should really be filtered */
58 : /* out by DDFFieldDefn::ApplyFormats(), but isn't. */
59 : /* o 'B' bitstrings that aren't a multiple of eight. */
60 : /************************************************************************/
61 :
62 64284 : int DDFSubfieldDefn::SetFormat(const char *pszFormat)
63 :
64 : {
65 64284 : osFormatString = pszFormat;
66 :
67 : /* -------------------------------------------------------------------- */
68 : /* These values will likely be used. */
69 : /* -------------------------------------------------------------------- */
70 64284 : if (osFormatString.size() >= 2 && osFormatString[1] == '(')
71 : {
72 3370 : nFormatWidth = atoi(osFormatString.c_str() + 2);
73 3370 : if (nFormatWidth < 0)
74 : {
75 0 : CPLError(CE_Failure, CPLE_AppDefined, "Format width %s is invalid.",
76 0 : osFormatString.c_str() + 2);
77 0 : return FALSE;
78 : }
79 3370 : bIsVariable = nFormatWidth == 0;
80 : }
81 : else
82 60914 : bIsVariable = TRUE;
83 :
84 : /* -------------------------------------------------------------------- */
85 : /* Interpret the format string. */
86 : /* -------------------------------------------------------------------- */
87 64284 : switch (osFormatString[0])
88 : {
89 17005 : case 'A':
90 : case 'C': // It isn't clear to me how this is different than 'A'
91 17005 : eType = DDFString;
92 17005 : break;
93 :
94 328 : case 'R':
95 328 : eType = DDFFloat;
96 328 : break;
97 :
98 1151 : case 'I':
99 : case 'S':
100 1151 : eType = DDFInt;
101 1151 : break;
102 :
103 45800 : case 'B':
104 : case 'b':
105 : // Is the width expressed in bits? (is it a bitstring)
106 45800 : bIsVariable = FALSE;
107 45800 : if (osFormatString[1] == '\0')
108 0 : return FALSE;
109 :
110 45800 : if (osFormatString[1] == '(')
111 : {
112 192 : nFormatWidth = atoi(osFormatString.c_str() + 2);
113 192 : if (nFormatWidth < 0 || nFormatWidth % 8 != 0)
114 : {
115 0 : CPLError(CE_Failure, CPLE_AppDefined,
116 : "Format width %s is invalid.",
117 0 : osFormatString.c_str() + 2);
118 0 : return FALSE;
119 : }
120 :
121 192 : nFormatWidth = nFormatWidth / 8;
122 192 : eBinaryFormat = SInt; // good default, works for SDTS.
123 :
124 192 : if (nFormatWidth < 5)
125 0 : eType = DDFInt;
126 : else
127 192 : eType = DDFBinaryString;
128 : }
129 :
130 : // or do we have a binary type indicator? (is it binary)
131 : else
132 : {
133 45608 : if (osFormatString[1] < '0' || osFormatString[1] > '5')
134 : {
135 0 : CPLError(CE_Failure, CPLE_AppDefined,
136 : "Binary format = %c is invalid.",
137 0 : osFormatString[1]);
138 0 : return FALSE;
139 : }
140 45608 : eBinaryFormat =
141 45608 : static_cast<DDFBinaryFormat>(osFormatString[1] - '0');
142 45608 : nFormatWidth = atoi(osFormatString.c_str() + 2);
143 45608 : if (nFormatWidth < 0)
144 : {
145 0 : CPLError(CE_Failure, CPLE_AppDefined,
146 : "Format width %s is invalid.",
147 0 : osFormatString.c_str() + 2);
148 0 : return FALSE;
149 : }
150 :
151 45608 : if (eBinaryFormat == SInt || eBinaryFormat == UInt)
152 43104 : eType = DDFInt;
153 : else
154 2504 : eType = DDFFloat;
155 : }
156 45800 : break;
157 :
158 0 : case 'X':
159 : // 'X' is extra space, and should not be directly assigned to a
160 : // subfield ... I have not encountered it in use yet though.
161 0 : CPLError(CE_Failure, CPLE_AppDefined,
162 0 : "Format type of `%c' not supported.\n", osFormatString[0]);
163 :
164 0 : return FALSE;
165 :
166 0 : default:
167 0 : CPLError(CE_Failure, CPLE_AppDefined,
168 : "Format type of `%c' not recognised.\n",
169 0 : osFormatString[0]);
170 :
171 0 : return FALSE;
172 : }
173 :
174 64284 : return TRUE;
175 : }
176 :
177 : /************************************************************************/
178 : /* Dump() */
179 : /************************************************************************/
180 :
181 : /**
182 : * Write out subfield definition info to debugging file.
183 : *
184 : * A variety of information about this field definition is written to the
185 : * give debugging file handle.
186 : *
187 : * @param fp The standard IO file handle to write to. i.e. stderr
188 : */
189 :
190 0 : void DDFSubfieldDefn::Dump(FILE *fp, int nNestingLevel) const
191 :
192 : {
193 0 : std::string osIndent;
194 0 : for (int i = 0; i < nNestingLevel; ++i)
195 0 : osIndent += " ";
196 :
197 : #define Print(...) \
198 : do \
199 : { \
200 : fprintf(fp, "%s", osIndent.c_str()); \
201 : fprintf(fp, __VA_ARGS__); \
202 : } while (0)
203 :
204 0 : Print("DDFSubfieldDefn:\n");
205 0 : Print(" Label = `%s'\n", osName.c_str());
206 0 : Print(" FormatString = `%s'\n", osFormatString.c_str());
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 accessible 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 1869700 : int DDFSubfieldDefn::GetDataLength(const char *pachSourceData, int nMaxBytes,
240 : int *pnConsumedBytes) const
241 :
242 : {
243 1869700 : if (!bIsVariable)
244 : {
245 1446730 : if (nFormatWidth > nMaxBytes)
246 : {
247 0 : CPLError(CE_Warning, CPLE_AppDefined,
248 : "Only %d bytes available for subfield %s with\n"
249 : "format string %s ... returning shortened data.",
250 : nMaxBytes, osName.c_str(), osFormatString.c_str());
251 :
252 0 : if (pnConsumedBytes != nullptr)
253 0 : *pnConsumedBytes = nMaxBytes;
254 :
255 0 : return nMaxBytes;
256 : }
257 : else
258 : {
259 1446730 : if (pnConsumedBytes != nullptr)
260 1445780 : *pnConsumedBytes = nFormatWidth;
261 :
262 1446730 : return nFormatWidth;
263 : }
264 : }
265 : else
266 : {
267 422971 : int nLength = 0;
268 422971 : int bAsciiField = TRUE;
269 422971 : 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 422971 : if (nMaxBytes > 1 &&
293 421866 : (pachSourceData[nMaxBytes - 2] == chFormatDelimiter ||
294 173070 : pachSourceData[nMaxBytes - 2] == DDF_FIELD_TERMINATOR) &&
295 248798 : pachSourceData[nMaxBytes - 1] == 0x00)
296 2 : bAsciiField = FALSE;
297 :
298 : // if( !bAsciiField )
299 : // CPLDebug( "ISO8211", "Non-ASCII field detected." );
300 :
301 3441230 : while (nLength < nMaxBytes)
302 : {
303 3440860 : if (bAsciiField)
304 : {
305 3440600 : if (pachSourceData[nLength] == chFormatDelimiter ||
306 3018000 : pachSourceData[nLength] == DDF_FIELD_TERMINATOR)
307 : break;
308 : }
309 : else
310 : {
311 260 : if (nLength > 0 &&
312 258 : (pachSourceData[nLength - 1] == chFormatDelimiter ||
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 2 : if (nLength + 1 < nMaxBytes &&
320 2 : pachSourceData[nLength + 1] == DDF_FIELD_TERMINATOR)
321 2 : extraConsumedBytes++;
322 2 : break;
323 : }
324 : }
325 :
326 3018260 : nLength++;
327 : }
328 :
329 422971 : if (pnConsumedBytes != nullptr)
330 : {
331 383950 : if (nMaxBytes == 0)
332 372 : *pnConsumedBytes = nLength + extraConsumedBytes;
333 : else
334 383578 : *pnConsumedBytes = nLength + extraConsumedBytes + 1;
335 : }
336 :
337 422971 : 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 : * CAUTION: this method is not thread safe as it updates mutable member
359 : * variables.
360 : *
361 : * @param pachSourceData The pointer to the raw data for this field. This
362 : * may have come from DDFRecord::GetData(), taking into account skip factors
363 : * over previous subfields data.
364 : * @param nMaxBytes The maximum number of bytes that are accessible after
365 : * pachSourceData.
366 : * @param pnConsumedBytes Pointer to an integer into which the number of
367 : * bytes consumed by this field should be written. May be NULL to ignore.
368 : * This is used as a skip factor to increment pachSourceData to point to the
369 : * next subfields data.
370 : *
371 : * @return A pointer to a buffer containing the data for this field. The
372 : * returned pointer is to an internal buffer which is invalidated on the
373 : * next ExtractStringData() call on this DDFSubfieldDefn(). It should not
374 : * be freed by the application.
375 : *
376 : * @see ExtractIntData(), ExtractFloatData()
377 : */
378 :
379 40780 : const char *DDFSubfieldDefn::ExtractStringData(const char *pachSourceData,
380 : int nMaxBytes,
381 : int *pnConsumedBytes) const
382 :
383 : {
384 : const int nLength =
385 40780 : GetDataLength(pachSourceData, nMaxBytes, pnConsumedBytes);
386 :
387 40780 : osBuffer.assign(pachSourceData, pachSourceData + nLength);
388 :
389 40780 : return osBuffer.c_str();
390 : }
391 :
392 : /************************************************************************/
393 : /* ExtractFloatData() */
394 : /************************************************************************/
395 :
396 : /**
397 : * Extract a subfield value as a float. Given a pointer to the data
398 : * for this subfield (from within a DDFRecord) this method will return the
399 : * floating point data for this subfield. The number of bytes
400 : * consumed as part of this field can also be fetched. This method may be
401 : * called for any type of subfield, and will return zero if the subfield is
402 : * not numeric.
403 : *
404 : * @param pachSourceData The pointer to the raw data for this field. This
405 : * may have come from DDFRecord::GetData(), taking into account skip factors
406 : * over previous subfields data.
407 : * @param nMaxBytes The maximum number of bytes that are accessible after
408 : * pachSourceData.
409 : * @param pnConsumedBytes Pointer to an integer into which the number of
410 : * bytes consumed by this field should be written. May be NULL to ignore.
411 : * This is used as a skip factor to increment pachSourceData to point to the
412 : * next subfields data.
413 : *
414 : * @return The subfield's numeric value (or zero if it isn't numeric).
415 : *
416 : * @see ExtractIntData(), ExtractStringData()
417 : */
418 :
419 1912 : double DDFSubfieldDefn::ExtractFloatData(const char *pachSourceData,
420 : int nMaxBytes,
421 : int *pnConsumedBytes) const
422 :
423 : {
424 1912 : switch (osFormatString[0])
425 : {
426 120 : case 'A':
427 : case 'I':
428 : case 'R':
429 : case 'S':
430 : case 'C':
431 120 : return CPLAtof(
432 120 : ExtractStringData(pachSourceData, nMaxBytes, pnConsumedBytes));
433 :
434 1792 : case 'B':
435 : case 'b':
436 : {
437 : unsigned char abyData[8];
438 1792 : void *pabyData = abyData;
439 :
440 1792 : if (nFormatWidth > nMaxBytes)
441 : {
442 0 : CPLError(CE_Warning, CPLE_AppDefined,
443 : "Attempt to extract float subfield %s with format %s\n"
444 : "failed as only %d bytes available. Using zero.",
445 : osName.c_str(), osFormatString.c_str(), nMaxBytes);
446 1792 : return 0;
447 : }
448 1792 : if (nFormatWidth > static_cast<int>(sizeof(abyData)))
449 : {
450 0 : CPLError(CE_Failure, CPLE_AppDefined,
451 0 : "Format width %d too large", nFormatWidth);
452 0 : return 0;
453 : }
454 :
455 1792 : if (pnConsumedBytes != nullptr)
456 1788 : *pnConsumedBytes = nFormatWidth;
457 :
458 : // Byte swap the data if it isn't in machine native format.
459 : // In any event we copy it into our buffer to ensure it is
460 : // word aligned.
461 : #ifdef CPL_LSB
462 1792 : if (osFormatString[0] == 'B')
463 : #else
464 : if (osFormatString[0] == 'b')
465 : #endif
466 : {
467 14 : for (int i = 0; i < nFormatWidth; i++)
468 12 : abyData[nFormatWidth - i - 1] = pachSourceData[i];
469 : }
470 : else
471 : {
472 1790 : memcpy(abyData, pachSourceData, nFormatWidth);
473 : }
474 :
475 : // Interpret the bytes of data.
476 1792 : switch (eBinaryFormat)
477 : {
478 0 : case UInt:
479 0 : if (nFormatWidth == 1)
480 0 : return abyData[0];
481 0 : else if (nFormatWidth == 2)
482 0 : return *(static_cast<GUInt16 *>(pabyData));
483 0 : else if (nFormatWidth == 4)
484 0 : return *(static_cast<GUInt32 *>(pabyData));
485 : else
486 : {
487 : // CPLAssert( false );
488 0 : return 0.0;
489 : }
490 :
491 0 : case SInt:
492 0 : if (nFormatWidth == 1)
493 0 : return *(static_cast<signed char *>(pabyData));
494 0 : else if (nFormatWidth == 2)
495 0 : return *(static_cast<GInt16 *>(pabyData));
496 0 : else if (nFormatWidth == 4)
497 0 : return *(static_cast<GInt32 *>(pabyData));
498 : else
499 : {
500 : // CPLAssert( false );
501 0 : return 0.0;
502 : }
503 :
504 1792 : case FloatReal:
505 1792 : if (nFormatWidth == 4)
506 : return static_cast<double>(
507 2 : *(static_cast<float *>(pabyData)));
508 1790 : else if (nFormatWidth == 8)
509 1790 : return *(static_cast<double *>(pabyData));
510 : else
511 : {
512 : // CPLAssert( false );
513 0 : return 0.0;
514 : }
515 :
516 0 : case NotBinary:
517 : case FPReal:
518 : case FloatComplex:
519 : // CPLAssert( false );
520 0 : return 0.0;
521 : }
522 0 : break;
523 : // end of 'b'/'B' case.
524 : }
525 :
526 0 : default:
527 : // CPLAssert( false );
528 0 : return 0.0;
529 : }
530 :
531 : // CPLAssert( false );
532 0 : return 0.0;
533 : }
534 :
535 : /************************************************************************/
536 : /* ExtractIntData() */
537 : /************************************************************************/
538 :
539 : /**
540 : * Extract a subfield value as an integer. Given a pointer to the data
541 : * for this subfield (from within a DDFRecord) this method will return the
542 : * int data for this subfield. The number of bytes
543 : * consumed as part of this field can also be fetched. This method may be
544 : * called for any type of subfield, and will return zero if the subfield is
545 : * not numeric.
546 : *
547 : * @param pachSourceData The pointer to the raw data for this field. This
548 : * may have come from DDFRecord::GetData(), taking into account skip factors
549 : * over previous subfields data.
550 : * @param nMaxBytes The maximum number of bytes that are accessible after
551 : * pachSourceData.
552 : * @param pnConsumedBytes Pointer to an integer into which the number of
553 : * bytes consumed by this field should be written. May be NULL to ignore.
554 : * This is used as a skip factor to increment pachSourceData to point to the
555 : * next subfields data.
556 : *
557 : * @return The subfield's numeric value (or zero if it isn't numeric).
558 : *
559 : * @see ExtractFloatData(), ExtractStringData()
560 : */
561 :
562 797050 : int DDFSubfieldDefn::ExtractIntData(const char *pachSourceData, int nMaxBytes,
563 : int *pnConsumedBytes) const
564 :
565 : {
566 797050 : switch (osFormatString[0])
567 : {
568 427 : case 'A':
569 : case 'I':
570 : case 'R':
571 : case 'S':
572 : case 'C':
573 427 : return atoi(
574 427 : ExtractStringData(pachSourceData, nMaxBytes, pnConsumedBytes));
575 :
576 796623 : case 'B':
577 : case 'b':
578 : {
579 : unsigned char abyData[8];
580 796623 : void *pabyData = abyData;
581 :
582 796623 : if (nFormatWidth > nMaxBytes ||
583 796623 : nFormatWidth >= static_cast<int>(sizeof(abyData)))
584 : {
585 0 : CPLError(
586 : CE_Warning, CPLE_AppDefined,
587 : "Attempt to extract int subfield %s with format %s\n"
588 : "failed as only %d bytes available. Using zero.",
589 : osName.c_str(), osFormatString.c_str(),
590 0 : std::min(nMaxBytes, static_cast<int>(sizeof(abyData))));
591 796623 : return 0;
592 : }
593 :
594 796623 : if (pnConsumedBytes != nullptr)
595 500086 : *pnConsumedBytes = nFormatWidth;
596 :
597 : // Byte swap the data if it isn't in machine native format.
598 : // In any event we copy it into our buffer to ensure it is
599 : // word aligned.
600 : #ifdef CPL_LSB
601 796623 : if (osFormatString[0] == 'B')
602 : #else
603 : if (osFormatString[0] == 'b')
604 : #endif
605 : {
606 0 : for (int i = 0; i < nFormatWidth; i++)
607 0 : abyData[nFormatWidth - i - 1] = pachSourceData[i];
608 : }
609 : else
610 : {
611 796623 : memcpy(abyData, pachSourceData, nFormatWidth);
612 : }
613 :
614 : // Interpret the bytes of data.
615 796623 : switch (eBinaryFormat)
616 : {
617 280179 : case UInt:
618 280179 : if (nFormatWidth == 4)
619 : return static_cast<int>(
620 72607 : *(static_cast<GUInt32 *>(pabyData)));
621 207572 : else if (nFormatWidth == 1)
622 96617 : return abyData[0];
623 110955 : else if (nFormatWidth == 2)
624 110955 : return *(static_cast<GUInt16 *>(pabyData));
625 : else
626 : {
627 : // CPLAssert( false );
628 0 : return 0;
629 : }
630 :
631 516444 : case SInt:
632 516444 : if (nFormatWidth == 4)
633 516444 : return *(static_cast<GInt32 *>(pabyData));
634 0 : else if (nFormatWidth == 1)
635 0 : return *(static_cast<signed char *>(pabyData));
636 0 : else if (nFormatWidth == 2)
637 0 : return *(static_cast<GInt16 *>(pabyData));
638 : else
639 : {
640 : // CPLAssert( false );
641 0 : return 0;
642 : }
643 :
644 0 : case FloatReal:
645 0 : if (nFormatWidth == 4)
646 : return static_cast<int>(
647 0 : *(static_cast<float *>(pabyData)));
648 0 : else if (nFormatWidth == 8)
649 : return static_cast<int>(
650 0 : *(static_cast<double *>(pabyData)));
651 : else
652 : {
653 : // CPLAssert( false );
654 0 : return 0;
655 : }
656 :
657 0 : case NotBinary:
658 : case FPReal:
659 : case FloatComplex:
660 : // CPLAssert( false );
661 0 : return 0;
662 : }
663 0 : break;
664 : // end of 'b'/'B' case.
665 : }
666 :
667 0 : default:
668 : // CPLAssert( false );
669 0 : return 0;
670 : }
671 :
672 : // CPLAssert( false );
673 0 : return 0;
674 : }
675 :
676 : /************************************************************************/
677 : /* DumpData() */
678 : /* */
679 : /* Dump the instance data for this subfield from a data */
680 : /* record. This fits into the output dump stream of a DDFField. */
681 : /************************************************************************/
682 :
683 : /**
684 : * Dump subfield value to debugging file.
685 : *
686 : * @param pachData Pointer to data for this subfield.
687 : * @param nMaxBytes Maximum number of bytes available in pachData.
688 : * @param fp File to write report to.
689 : */
690 :
691 0 : void DDFSubfieldDefn::DumpData(const char *pachData, int nMaxBytes,
692 : FILE *fp) const
693 :
694 : {
695 0 : if (nMaxBytes < 0)
696 : {
697 0 : fprintf(fp, " Subfield `%s' = {invalid length}\n", osName.c_str());
698 0 : return;
699 : }
700 0 : if (eType == DDFFloat)
701 0 : fprintf(fp, " Subfield `%s' = %f\n", osName.c_str(),
702 : ExtractFloatData(pachData, nMaxBytes, nullptr));
703 0 : else if (eType == DDFInt)
704 0 : fprintf(fp, " Subfield `%s' = %d\n", osName.c_str(),
705 : ExtractIntData(pachData, nMaxBytes, nullptr));
706 0 : else if (eType == DDFBinaryString)
707 : {
708 0 : int nBytes = 0;
709 : const GByte *pabyBString = reinterpret_cast<const GByte *>(
710 0 : ExtractStringData(pachData, nMaxBytes, &nBytes));
711 :
712 0 : fprintf(fp, " Subfield `%s' = 0x", osName.c_str());
713 0 : for (int i = 0; i < std::min(nBytes, 24); i++)
714 0 : fprintf(fp, "%02X", pabyBString[i]);
715 :
716 0 : if (nBytes > 24)
717 0 : fprintf(fp, "%s", "...");
718 :
719 0 : fprintf(fp, "\n");
720 : }
721 : else
722 0 : fprintf(fp, " Subfield `%s' = `%s'\n", osName.c_str(),
723 : ExtractStringData(pachData, nMaxBytes, nullptr));
724 : }
725 :
726 : /************************************************************************/
727 : /* GetDefaultValue() */
728 : /************************************************************************/
729 :
730 : /**
731 : * Get default data.
732 : *
733 : * Returns the default subfield data contents for this subfield definition.
734 : * For variable length numbers this will normally be "0<unit-terminator>".
735 : * For variable length strings it will be "<unit-terminator>". For fixed
736 : * length numbers it is zero filled. For fixed length strings it is space
737 : * filled. For binary numbers it is binary zero filled.
738 : *
739 : * @param pachData the buffer into which the returned default will be placed.
740 : * May be NULL if just querying default size.
741 : * @param nBytesAvailable the size of pachData in bytes.
742 : * @param pnBytesUsed will receive the size of the subfield default data in
743 : * bytes.
744 : *
745 : * @return TRUE on success or FALSE on failure or if the passed buffer is too
746 : * small to hold the default.
747 : */
748 :
749 51378 : int DDFSubfieldDefn::GetDefaultValue(char *pachData, int nBytesAvailable,
750 : int *pnBytesUsed) const
751 :
752 : {
753 : int nDefaultSize;
754 :
755 51378 : if (!bIsVariable)
756 41796 : nDefaultSize = nFormatWidth;
757 : else
758 9582 : nDefaultSize = 1;
759 :
760 51378 : if (pnBytesUsed != nullptr)
761 51378 : *pnBytesUsed = nDefaultSize;
762 :
763 51378 : if (pachData == nullptr)
764 25689 : return TRUE;
765 :
766 25689 : if (nBytesAvailable < nDefaultSize)
767 0 : return FALSE;
768 :
769 25689 : if (bIsVariable)
770 : {
771 4791 : pachData[0] = DDF_UNIT_TERMINATOR;
772 : }
773 : else
774 : {
775 : char chFillChar;
776 20898 : if (GetBinaryFormat() == NotBinary)
777 : {
778 265 : if (GetType() == DDFInt || GetType() == DDFFloat)
779 19 : chFillChar = '0'; /* ASCII zero intended */
780 : else
781 246 : chFillChar = ' ';
782 : }
783 : else
784 20633 : chFillChar = 0;
785 20898 : memset(pachData, chFillChar, nDefaultSize);
786 : }
787 :
788 25689 : return TRUE;
789 : }
790 :
791 : /************************************************************************/
792 : /* FormatStringValue() */
793 : /************************************************************************/
794 :
795 : /**
796 : * Format string subfield value.
797 : *
798 : * Returns a buffer with the passed in string value reformatted in a way
799 : * suitable for storage in a DDFField for this subfield.
800 : */
801 :
802 10506 : int DDFSubfieldDefn::FormatStringValue(char *pachData, int nBytesAvailable,
803 : int *pnBytesUsed, const char *pszValue,
804 : int nValueLength) const
805 :
806 : {
807 : int nSize;
808 :
809 10506 : if (nValueLength == -1)
810 10036 : nValueLength = static_cast<int>(strlen(pszValue));
811 :
812 10506 : if (bIsVariable)
813 : {
814 9508 : nSize = nValueLength + 1;
815 : }
816 : else
817 : {
818 998 : nSize = nFormatWidth;
819 : }
820 :
821 10506 : if (pnBytesUsed != nullptr)
822 5253 : *pnBytesUsed = nSize;
823 :
824 10506 : if (pachData == nullptr)
825 5253 : return TRUE;
826 :
827 5253 : if (nBytesAvailable < nSize)
828 0 : return FALSE;
829 :
830 5253 : if (bIsVariable)
831 : {
832 4754 : strncpy(pachData, pszValue, nSize - 1);
833 4754 : pachData[nSize - 1] = DDF_UNIT_TERMINATOR;
834 : }
835 : else
836 : {
837 499 : if (GetBinaryFormat() == NotBinary)
838 : {
839 264 : memset(pachData, ' ', nSize);
840 : // cppcheck-suppress redundantCopy
841 264 : memcpy(pachData, pszValue, std::min(nValueLength, nSize));
842 : }
843 : else
844 : {
845 235 : memset(pachData, 0, nSize);
846 : // cppcheck-suppress redundantCopy
847 235 : memcpy(pachData, pszValue, std::min(nValueLength, nSize));
848 : }
849 : }
850 :
851 5253 : return TRUE;
852 : }
853 :
854 : /************************************************************************/
855 : /* FormatIntValue() */
856 : /************************************************************************/
857 :
858 : /**
859 : * Format int subfield value.
860 : *
861 : * Returns a buffer with the passed in int value reformatted in a way
862 : * suitable for storage in a DDFField for this subfield.
863 : */
864 :
865 39944 : int DDFSubfieldDefn::FormatIntValue(char *pachData, int nBytesAvailable,
866 : int *pnBytesUsed, int nNewValue) const
867 :
868 : {
869 : int nSize;
870 : char szWork[30];
871 :
872 39944 : snprintf(szWork, sizeof(szWork), "%d", nNewValue);
873 :
874 39944 : if (bIsVariable)
875 : {
876 0 : nSize = static_cast<int>(strlen(szWork)) + 1;
877 : }
878 : else
879 : {
880 39944 : nSize = nFormatWidth;
881 :
882 39944 : if (GetBinaryFormat() == NotBinary &&
883 0 : static_cast<int>(strlen(szWork)) > nSize)
884 0 : return FALSE;
885 : }
886 :
887 39944 : if (pnBytesUsed != nullptr)
888 19972 : *pnBytesUsed = nSize;
889 :
890 39944 : if (pachData == nullptr)
891 19972 : return TRUE;
892 :
893 19972 : if (nBytesAvailable < nSize)
894 0 : return FALSE;
895 :
896 19972 : if (bIsVariable)
897 : {
898 0 : memcpy(pachData, szWork, nSize - 1);
899 0 : pachData[nSize - 1] = DDF_UNIT_TERMINATOR;
900 : }
901 : else
902 : {
903 19972 : GUInt32 nMask = 0xff;
904 :
905 19972 : switch (GetBinaryFormat())
906 : {
907 0 : case NotBinary:
908 : {
909 0 : constexpr char chFillChar = '0'; /* ASCII zero intended */
910 0 : const int nZeroFillCount =
911 0 : nSize - static_cast<int>(strlen(szWork));
912 0 : for (int i = 0; i < nZeroFillCount; ++i)
913 0 : pachData[i] = chFillChar;
914 0 : memcpy(pachData + nZeroFillCount, szWork, strlen(szWork));
915 0 : break;
916 : }
917 :
918 19972 : case UInt:
919 : case SInt:
920 66390 : for (int i = 0; i < nFormatWidth; i++)
921 : {
922 : int iOut;
923 :
924 : // big endian required?
925 46418 : if (osFormatString[0] == 'B')
926 0 : iOut = nFormatWidth - i - 1;
927 : else
928 46418 : iOut = i;
929 :
930 46418 : pachData[iOut] =
931 46418 : static_cast<char>((nNewValue & nMask) >> (i * 8));
932 46418 : nMask <<= 8;
933 : }
934 19972 : break;
935 :
936 0 : case FloatReal:
937 0 : CPLAssert(false);
938 : break;
939 :
940 0 : default:
941 0 : CPLAssert(false);
942 : break;
943 : }
944 : }
945 :
946 19972 : return TRUE;
947 : }
948 :
949 : /************************************************************************/
950 : /* FormatFloatValue() */
951 : /************************************************************************/
952 :
953 : /**
954 : * Format float subfield value.
955 : *
956 : * Returns a buffer with the passed in float value reformatted in a way
957 : * suitable for storage in a DDFField for this subfield.
958 : */
959 :
960 1240 : int DDFSubfieldDefn::FormatFloatValue(char *pachData, int nBytesAvailable,
961 : int *pnBytesUsed, double dfNewValue) const
962 :
963 : {
964 : int nSize;
965 : char szWork[120];
966 :
967 1240 : CPLsnprintf(szWork, sizeof(szWork), "%.16g", dfNewValue);
968 :
969 1240 : if (bIsVariable)
970 : {
971 0 : nSize = static_cast<int>(strlen(szWork)) + 1;
972 : }
973 : else
974 : {
975 1240 : nSize = nFormatWidth;
976 :
977 1242 : if (GetBinaryFormat() == NotBinary &&
978 2 : static_cast<int>(strlen(szWork)) > nSize)
979 0 : return FALSE;
980 : }
981 :
982 1240 : if (pnBytesUsed != nullptr)
983 620 : *pnBytesUsed = nSize;
984 :
985 1240 : if (pachData == nullptr)
986 620 : return TRUE;
987 :
988 620 : if (nBytesAvailable < nSize)
989 0 : return FALSE;
990 :
991 620 : if (bIsVariable)
992 : {
993 0 : memcpy(pachData, szWork, nSize - 1);
994 0 : pachData[nSize - 1] = DDF_UNIT_TERMINATOR;
995 : }
996 : else
997 : {
998 620 : if (GetBinaryFormat() == NotBinary)
999 : {
1000 1 : constexpr char chFillChar = '0'; /* ASCII zero intended */
1001 1 : const int nZeroFillCount = nSize - static_cast<int>(strlen(szWork));
1002 4 : for (int i = 0; i < nZeroFillCount; ++i)
1003 3 : pachData[i] = chFillChar;
1004 1 : memcpy(pachData + nZeroFillCount, szWork, strlen(szWork));
1005 : }
1006 619 : else if (GetBinaryFormat() == FloatReal)
1007 : {
1008 619 : if (nFormatWidth == 8)
1009 : {
1010 617 : if (osFormatString[0] == 'B')
1011 : {
1012 1 : CPL_MSBPTR64(&dfNewValue);
1013 : }
1014 : else
1015 : {
1016 616 : CPL_LSBPTR64(&dfNewValue);
1017 : }
1018 617 : memcpy(pachData, &dfNewValue, sizeof(dfNewValue));
1019 : }
1020 : else
1021 : {
1022 2 : CPLAssert(nFormatWidth == 4);
1023 2 : float f = static_cast<float>(dfNewValue);
1024 2 : if (osFormatString[0] == 'B')
1025 : {
1026 1 : CPL_MSBPTR32(&f);
1027 : }
1028 : else
1029 : {
1030 1 : CPL_LSBPTR32(&f);
1031 : }
1032 2 : memcpy(pachData, &f, sizeof(f));
1033 : }
1034 : }
1035 : else
1036 : {
1037 0 : CPLAssert(false);
1038 : /* implement me */
1039 : }
1040 : }
1041 :
1042 620 : return TRUE;
1043 : }
|