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 10639 : DDFSubfieldDefn::DDFSubfieldDefn()
32 21278 : : pszName(nullptr), pszFormatString(CPLStrdup("")), eType(DDFString),
33 : eBinaryFormat(NotBinary), bIsVariable(TRUE),
34 : chFormatDelimiter(DDF_UNIT_TERMINATOR), nFormatWidth(0), nMaxBufChars(0),
35 10639 : pachBuffer(nullptr)
36 : {
37 10639 : }
38 :
39 : /************************************************************************/
40 : /* ~DDFSubfieldDefn() */
41 : /************************************************************************/
42 :
43 21278 : DDFSubfieldDefn::~DDFSubfieldDefn()
44 :
45 : {
46 10639 : CPLFree(pszName);
47 10639 : CPLFree(pszFormatString);
48 10639 : CPLFree(pachBuffer);
49 10639 : }
50 :
51 : /************************************************************************/
52 : /* SetName() */
53 : /************************************************************************/
54 :
55 10639 : void DDFSubfieldDefn::SetName(const char *pszNewName)
56 :
57 : {
58 : int i;
59 :
60 10639 : CPLFree(pszName);
61 :
62 10639 : pszName = CPLStrdup(pszNewName);
63 :
64 10933 : for (i = static_cast<int>(strlen(pszName)) - 1; i > 0 && pszName[i] == ' ';
65 : i--)
66 294 : pszName[i] = '\0';
67 10639 : }
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 10639 : int DDFSubfieldDefn::SetFormat(const char *pszFormat)
81 :
82 : {
83 10639 : CPLFree(pszFormatString);
84 10639 : pszFormatString = CPLStrdup(pszFormat);
85 :
86 : /* -------------------------------------------------------------------- */
87 : /* These values will likely be used. */
88 : /* -------------------------------------------------------------------- */
89 10639 : if (pszFormatString[1] == '(')
90 : {
91 4347 : nFormatWidth = atoi(pszFormatString + 2);
92 4347 : 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 4347 : bIsVariable = nFormatWidth == 0;
99 : }
100 : else
101 6292 : bIsVariable = TRUE;
102 :
103 : /* -------------------------------------------------------------------- */
104 : /* Interpret the format string. */
105 : /* -------------------------------------------------------------------- */
106 10639 : switch (pszFormatString[0])
107 : {
108 2777 : case 'A':
109 : case 'C': // It isn't clear to me how this is different than 'A'
110 2777 : eType = DDFString;
111 2777 : break;
112 :
113 474 : case 'R':
114 474 : eType = DDFFloat;
115 474 : break;
116 :
117 2108 : case 'I':
118 : case 'S':
119 2108 : eType = DDFInt;
120 2108 : break;
121 :
122 5280 : case 'B':
123 : case 'b':
124 : // Is the width expressed in bits? (is it a bitstring)
125 5280 : bIsVariable = FALSE;
126 5280 : if (pszFormatString[1] == '\0')
127 0 : return FALSE;
128 :
129 5280 : if (pszFormatString[1] == '(')
130 : {
131 232 : nFormatWidth = atoi(pszFormatString + 2);
132 232 : 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 232 : nFormatWidth = nFormatWidth / 8;
141 232 : eBinaryFormat = SInt; // good default, works for SDTS.
142 :
143 232 : if (nFormatWidth < 5)
144 22 : eType = DDFInt;
145 : else
146 210 : eType = DDFBinaryString;
147 : }
148 :
149 : // or do we have a binary type indicator? (is it binary)
150 : else
151 : {
152 5048 : 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 5048 : eBinaryFormat = (DDFBinaryFormat)(pszFormatString[1] - '0');
160 5048 : nFormatWidth = atoi(pszFormatString + 2);
161 5048 : 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 5048 : if (eBinaryFormat == SInt || eBinaryFormat == UInt)
170 5048 : eType = DDFInt;
171 : else
172 0 : eType = DDFFloat;
173 : }
174 5280 : 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 10639 : 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 97012 : int DDFSubfieldDefn::GetDataLength(const char *pachSourceData, int nMaxBytes,
248 : int *pnConsumedBytes)
249 :
250 : {
251 97012 : if (!bIsVariable)
252 : {
253 88253 : 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 : nMaxBytes, pszName, pszFormatString);
259 :
260 0 : if (pnConsumedBytes != nullptr)
261 0 : *pnConsumedBytes = nMaxBytes;
262 :
263 0 : return nMaxBytes;
264 : }
265 : else
266 : {
267 88253 : if (pnConsumedBytes != nullptr)
268 84775 : *pnConsumedBytes = nFormatWidth;
269 :
270 88253 : return nFormatWidth;
271 : }
272 : }
273 : else
274 : {
275 8759 : int nLength = 0;
276 8759 : int bAsciiField = TRUE;
277 8759 : 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 8759 : if (nMaxBytes > 1 &&
301 8759 : (pachSourceData[nMaxBytes - 2] == chFormatDelimiter ||
302 2773 : 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 41813 : while (nLength < nMaxBytes)
310 : {
311 41813 : if (bAsciiField)
312 : {
313 41553 : if (pachSourceData[nLength] == chFormatDelimiter ||
314 32812 : 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 33054 : nLength++;
335 : }
336 :
337 8759 : if (pnConsumedBytes != nullptr)
338 : {
339 7189 : if (nMaxBytes == 0)
340 0 : *pnConsumedBytes = nLength + extraConsumedBytes;
341 : else
342 7189 : *pnConsumedBytes = nLength + extraConsumedBytes + 1;
343 : }
344 :
345 8759 : 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 : * @param pachSourceData The pointer to the raw data for this field. This
367 : * may have come from DDFRecord::GetData(), taking into account skip factors
368 : * over previous subfields data.
369 : * @param nMaxBytes The maximum number of bytes that are accessible after
370 : * pachSourceData.
371 : * @param pnConsumedBytes Pointer to an integer into which the number of
372 : * bytes consumed by this field should be written. May be NULL to ignore.
373 : * This is used as a skip factor to increment pachSourceData to point to the
374 : * next subfields data.
375 : *
376 : * @return A pointer to a buffer containing the data for this field. The
377 : * returned pointer is to an internal buffer which is invalidated on the
378 : * next ExtractStringData() call on this DDFSubfieldDefn(). It should not
379 : * be freed by the application.
380 : *
381 : * @see ExtractIntData(), ExtractFloatData()
382 : */
383 :
384 5720 : const char *DDFSubfieldDefn::ExtractStringData(const char *pachSourceData,
385 : int nMaxBytes,
386 : int *pnConsumedBytes)
387 :
388 : {
389 5720 : int nLength = GetDataLength(pachSourceData, nMaxBytes, pnConsumedBytes);
390 :
391 : /* -------------------------------------------------------------------- */
392 : /* Do we need to grow the buffer. */
393 : /* -------------------------------------------------------------------- */
394 5720 : if (nMaxBufChars < nLength + 1)
395 : {
396 1013 : CPLFree(pachBuffer);
397 :
398 1013 : nMaxBufChars = nLength + 1;
399 1013 : pachBuffer = (char *)CPLMalloc(nMaxBufChars);
400 : }
401 :
402 : /* -------------------------------------------------------------------- */
403 : /* Copy the data to the buffer. We use memcpy() so that it */
404 : /* will work for binary data. */
405 : /* -------------------------------------------------------------------- */
406 5720 : memcpy(pachBuffer, pachSourceData, nLength);
407 5720 : pachBuffer[nLength] = '\0';
408 :
409 5720 : return pachBuffer;
410 : }
411 :
412 : /************************************************************************/
413 : /* ExtractFloatData() */
414 : /************************************************************************/
415 :
416 : /**
417 : * Extract a subfield value as a float. Given a pointer to the data
418 : * for this subfield (from within a DDFRecord) this method will return the
419 : * floating point data for this subfield. The number of bytes
420 : * consumed as part of this field can also be fetched. This method may be
421 : * called for any type of subfield, and will return zero if the subfield is
422 : * not numeric.
423 : *
424 : * @param pachSourceData The pointer to the raw data for this field. This
425 : * may have come from DDFRecord::GetData(), taking into account skip factors
426 : * over previous subfields data.
427 : * @param nMaxBytes The maximum number of bytes that are accessible after
428 : * pachSourceData.
429 : * @param pnConsumedBytes Pointer to an integer into which the number of
430 : * bytes consumed by this field should be written. May be NULL to ignore.
431 : * This is used as a skip factor to increment pachSourceData to point to the
432 : * next subfields data.
433 : *
434 : * @return The subfield's numeric value (or zero if it isn't numeric).
435 : *
436 : * @see ExtractIntData(), ExtractStringData()
437 : */
438 :
439 166 : double DDFSubfieldDefn::ExtractFloatData(const char *pachSourceData,
440 : int nMaxBytes, int *pnConsumedBytes)
441 :
442 : {
443 166 : switch (pszFormatString[0])
444 : {
445 166 : case 'A':
446 : case 'I':
447 : case 'R':
448 : case 'S':
449 : case 'C':
450 166 : return CPLAtof(
451 166 : ExtractStringData(pachSourceData, nMaxBytes, pnConsumedBytes));
452 :
453 0 : case 'B':
454 : case 'b':
455 : {
456 : unsigned char abyData[8];
457 0 : void *pabyData = abyData;
458 :
459 0 : if (nFormatWidth > nMaxBytes)
460 : {
461 0 : CPLError(CE_Warning, CPLE_AppDefined,
462 : "Attempt to extract float subfield %s with format %s\n"
463 : "failed as only %d bytes available. Using zero.",
464 : pszName, pszFormatString, nMaxBytes);
465 0 : return 0;
466 : }
467 0 : if (nFormatWidth > static_cast<int>(sizeof(abyData)))
468 : {
469 0 : CPLError(CE_Failure, CPLE_AppDefined,
470 : "Format width %d too large", nFormatWidth);
471 0 : return 0;
472 : }
473 :
474 0 : if (pnConsumedBytes != nullptr)
475 0 : *pnConsumedBytes = nFormatWidth;
476 :
477 : // Byte swap the data if it isn't in machine native format.
478 : // In any event we copy it into our buffer to ensure it is
479 : // word aligned.
480 : #ifdef CPL_LSB
481 0 : if (pszFormatString[0] == 'B')
482 : #else
483 : if (pszFormatString[0] == 'b')
484 : #endif
485 : {
486 0 : for (int i = 0; i < nFormatWidth; i++)
487 0 : abyData[nFormatWidth - i - 1] = pachSourceData[i];
488 : }
489 : else
490 : {
491 0 : memcpy(abyData, pachSourceData, nFormatWidth);
492 : }
493 :
494 : // Interpret the bytes of data.
495 0 : switch (eBinaryFormat)
496 : {
497 0 : case UInt:
498 0 : if (nFormatWidth == 1)
499 0 : return abyData[0];
500 0 : else if (nFormatWidth == 2)
501 0 : return *((GUInt16 *)pabyData);
502 0 : else if (nFormatWidth == 4)
503 0 : return *((GUInt32 *)pabyData);
504 : else
505 : {
506 : // CPLAssert( false );
507 0 : return 0.0;
508 : }
509 :
510 0 : case SInt:
511 0 : if (nFormatWidth == 1)
512 0 : return *((signed char *)abyData);
513 0 : else if (nFormatWidth == 2)
514 0 : return *((GInt16 *)pabyData);
515 0 : else if (nFormatWidth == 4)
516 0 : return *((GInt32 *)pabyData);
517 : else
518 : {
519 : // CPLAssert( false );
520 0 : return 0.0;
521 : }
522 :
523 0 : case FloatReal:
524 0 : if (nFormatWidth == 4)
525 0 : return *((float *)pabyData);
526 0 : else if (nFormatWidth == 8)
527 0 : return *((double *)pabyData);
528 : else
529 : {
530 : // CPLAssert( false );
531 0 : return 0.0;
532 : }
533 :
534 0 : case NotBinary:
535 : case FPReal:
536 : case FloatComplex:
537 : // CPLAssert( false );
538 0 : return 0.0;
539 : }
540 0 : break;
541 : // end of 'b'/'B' case.
542 : }
543 :
544 0 : default:
545 : // CPLAssert( false );
546 0 : return 0.0;
547 : }
548 :
549 : // CPLAssert( false );
550 0 : return 0.0;
551 : }
552 :
553 : /************************************************************************/
554 : /* ExtractIntData() */
555 : /************************************************************************/
556 :
557 : /**
558 : * Extract a subfield value as an integer. Given a pointer to the data
559 : * for this subfield (from within a DDFRecord) this method will return the
560 : * int data for this subfield. The number of bytes
561 : * consumed as part of this field can also be fetched. This method may be
562 : * called for any type of subfield, and will return zero if the subfield is
563 : * not numeric.
564 : *
565 : * @param pachSourceData The pointer to the raw data for this field. This
566 : * may have come from DDFRecord::GetData(), taking into account skip factors
567 : * over previous subfields data.
568 : * @param nMaxBytes The maximum number of bytes that are accessible after
569 : * pachSourceData.
570 : * @param pnConsumedBytes Pointer to an integer into which the number of
571 : * bytes consumed by this field should be written. May be NULL to ignore.
572 : * This is used as a skip factor to increment pachSourceData to point to the
573 : * next subfields data.
574 : *
575 : * @return The subfield's numeric value (or zero if it isn't numeric).
576 : *
577 : * @see ExtractFloatData(), ExtractStringData()
578 : */
579 :
580 30119 : int DDFSubfieldDefn::ExtractIntData(const char *pachSourceData, int nMaxBytes,
581 : int *pnConsumedBytes)
582 :
583 : {
584 30119 : switch (pszFormatString[0])
585 : {
586 874 : case 'A':
587 : case 'I':
588 : case 'R':
589 : case 'S':
590 : case 'C':
591 874 : return atoi(
592 874 : ExtractStringData(pachSourceData, nMaxBytes, pnConsumedBytes));
593 :
594 29245 : case 'B':
595 : case 'b':
596 : {
597 : unsigned char abyData[8];
598 29245 : void *pabyData = abyData;
599 :
600 29245 : if (nFormatWidth > nMaxBytes ||
601 29245 : nFormatWidth >= (int)sizeof(abyData))
602 : {
603 0 : CPLError(
604 : CE_Warning, CPLE_AppDefined,
605 : "Attempt to extract int subfield %s with format %s\n"
606 : "failed as only %d bytes available. Using zero.",
607 : pszName, pszFormatString,
608 0 : std::min(nMaxBytes, static_cast<int>(sizeof(abyData))));
609 29245 : return 0;
610 : }
611 :
612 29245 : if (pnConsumedBytes != nullptr)
613 26489 : *pnConsumedBytes = nFormatWidth;
614 :
615 : // Byte swap the data if it isn't in machine native format.
616 : // In any event we copy it into our buffer to ensure it is
617 : // word aligned.
618 : #ifdef CPL_LSB
619 29245 : if (pszFormatString[0] == 'B')
620 : #else
621 : if (pszFormatString[0] == 'b')
622 : #endif
623 : {
624 0 : for (int i = 0; i < nFormatWidth; i++)
625 0 : abyData[nFormatWidth - i - 1] = pachSourceData[i];
626 : }
627 : else
628 : {
629 29245 : memcpy(abyData, pachSourceData, nFormatWidth);
630 : }
631 :
632 : // Interpret the bytes of data.
633 29245 : switch (eBinaryFormat)
634 : {
635 13630 : case UInt:
636 13630 : if (nFormatWidth == 4)
637 3405 : return (int)*((GUInt32 *)pabyData);
638 10225 : else if (nFormatWidth == 1)
639 4887 : return abyData[0];
640 5338 : else if (nFormatWidth == 2)
641 5338 : return *((GUInt16 *)pabyData);
642 : else
643 : {
644 : // CPLAssert( false );
645 0 : return 0;
646 : }
647 :
648 15615 : case SInt:
649 15615 : if (nFormatWidth == 4)
650 15615 : return *((GInt32 *)pabyData);
651 0 : else if (nFormatWidth == 1)
652 0 : return *((signed char *)abyData);
653 0 : else if (nFormatWidth == 2)
654 0 : return *((GInt16 *)pabyData);
655 : else
656 : {
657 : // CPLAssert( false );
658 0 : return 0;
659 : }
660 :
661 0 : case FloatReal:
662 0 : if (nFormatWidth == 4)
663 0 : return (int)*((float *)pabyData);
664 0 : else if (nFormatWidth == 8)
665 0 : return (int)*((double *)pabyData);
666 : else
667 : {
668 : // CPLAssert( false );
669 0 : return 0;
670 : }
671 :
672 0 : case NotBinary:
673 : case FPReal:
674 : case FloatComplex:
675 : // CPLAssert( false );
676 0 : return 0;
677 : }
678 0 : break;
679 : // end of 'b'/'B' case.
680 : }
681 :
682 0 : default:
683 : // CPLAssert( false );
684 0 : return 0;
685 : }
686 :
687 : // CPLAssert( false );
688 0 : return 0;
689 : }
690 :
691 : /************************************************************************/
692 : /* DumpData() */
693 : /* */
694 : /* Dump the instance data for this subfield from a data */
695 : /* record. This fits into the output dump stream of a DDFField. */
696 : /************************************************************************/
697 :
698 : /**
699 : * Dump subfield value to debugging file.
700 : *
701 : * @param pachData Pointer to data for this subfield.
702 : * @param nMaxBytes Maximum number of bytes available in pachData.
703 : * @param fp File to write report to.
704 : */
705 :
706 0 : void DDFSubfieldDefn::DumpData(const char *pachData, int nMaxBytes, FILE *fp)
707 :
708 : {
709 0 : if (nMaxBytes < 0)
710 : {
711 0 : fprintf(fp, " Subfield `%s' = {invalid length}\n", pszName);
712 0 : return;
713 : }
714 0 : if (eType == DDFFloat)
715 0 : fprintf(fp, " Subfield `%s' = %f\n", pszName,
716 : ExtractFloatData(pachData, nMaxBytes, nullptr));
717 0 : else if (eType == DDFInt)
718 0 : fprintf(fp, " Subfield `%s' = %d\n", pszName,
719 : ExtractIntData(pachData, nMaxBytes, nullptr));
720 0 : else if (eType == DDFBinaryString)
721 : {
722 0 : int nBytes = 0;
723 : GByte *pabyBString =
724 0 : (GByte *)ExtractStringData(pachData, nMaxBytes, &nBytes);
725 :
726 0 : fprintf(fp, " Subfield `%s' = 0x", pszName);
727 0 : for (int i = 0; i < std::min(nBytes, 24); i++)
728 0 : fprintf(fp, "%02X", pabyBString[i]);
729 :
730 0 : if (nBytes > 24)
731 0 : fprintf(fp, "%s", "...");
732 :
733 0 : fprintf(fp, "\n");
734 : }
735 : else
736 0 : fprintf(fp, " Subfield `%s' = `%s'\n", pszName,
737 : ExtractStringData(pachData, nMaxBytes, nullptr));
738 : }
739 :
740 : /************************************************************************/
741 : /* GetDefaultValue() */
742 : /************************************************************************/
743 :
744 : /**
745 : * Get default data.
746 : *
747 : * Returns the default subfield data contents for this subfield definition.
748 : * For variable length numbers this will normally be "0<unit-terminator>".
749 : * For variable length strings it will be "<unit-terminator>". For fixed
750 : * length numbers it is zero filled. For fixed length strings it is space
751 : * filled. For binary numbers it is binary zero filled.
752 : *
753 : * @param pachData the buffer into which the returned default will be placed.
754 : * May be NULL if just querying default size.
755 : * @param nBytesAvailable the size of pachData in bytes.
756 : * @param pnBytesUsed will receive the size of the subfield default data in
757 : * bytes.
758 : *
759 : * @return TRUE on success or FALSE on failure or if the passed buffer is too
760 : * small to hold the default.
761 : */
762 :
763 4228 : int DDFSubfieldDefn::GetDefaultValue(char *pachData, int nBytesAvailable,
764 : int *pnBytesUsed) const
765 :
766 : {
767 : int nDefaultSize;
768 :
769 4228 : if (!bIsVariable)
770 3938 : nDefaultSize = nFormatWidth;
771 : else
772 290 : nDefaultSize = 1;
773 :
774 4228 : if (pnBytesUsed != nullptr)
775 4228 : *pnBytesUsed = nDefaultSize;
776 :
777 4228 : if (pachData == nullptr)
778 2114 : return TRUE;
779 :
780 2114 : if (nBytesAvailable < nDefaultSize)
781 0 : return FALSE;
782 :
783 2114 : if (bIsVariable)
784 : {
785 145 : pachData[0] = DDF_UNIT_TERMINATOR;
786 : }
787 : else
788 : {
789 : char chFillChar;
790 1969 : if (GetBinaryFormat() == NotBinary)
791 : {
792 54 : if (GetType() == DDFInt || GetType() == DDFFloat)
793 18 : chFillChar = '0'; /* ASCII zero intended */
794 : else
795 36 : chFillChar = ' ';
796 : }
797 : else
798 1915 : chFillChar = 0;
799 1969 : memset(pachData, chFillChar, nDefaultSize);
800 : }
801 :
802 2114 : return TRUE;
803 : }
804 :
805 : /************************************************************************/
806 : /* FormatStringValue() */
807 : /************************************************************************/
808 :
809 : /**
810 : * Format string subfield value.
811 : *
812 : * Returns a buffer with the passed in string value reformatted in a way
813 : * suitable for storage in a DDFField for this subfield.
814 : */
815 :
816 524 : int DDFSubfieldDefn::FormatStringValue(char *pachData, int nBytesAvailable,
817 : int *pnBytesUsed, const char *pszValue,
818 : int nValueLength) const
819 :
820 : {
821 : int nSize;
822 :
823 524 : if (nValueLength == -1)
824 324 : nValueLength = static_cast<int>(strlen(pszValue));
825 :
826 524 : if (bIsVariable)
827 : {
828 216 : nSize = nValueLength + 1;
829 : }
830 : else
831 : {
832 308 : nSize = nFormatWidth;
833 : }
834 :
835 524 : if (pnBytesUsed != nullptr)
836 262 : *pnBytesUsed = nSize;
837 :
838 524 : if (pachData == nullptr)
839 262 : return TRUE;
840 :
841 262 : if (nBytesAvailable < nSize)
842 0 : return FALSE;
843 :
844 262 : if (bIsVariable)
845 : {
846 108 : strncpy(pachData, pszValue, nSize - 1);
847 108 : pachData[nSize - 1] = DDF_UNIT_TERMINATOR;
848 : }
849 : else
850 : {
851 154 : if (GetBinaryFormat() == NotBinary)
852 : {
853 54 : memset(pachData, ' ', nSize);
854 : // cppcheck-suppress redundantCopy
855 54 : memcpy(pachData, pszValue, std::min(nValueLength, nSize));
856 : }
857 : else
858 : {
859 100 : memset(pachData, 0, nSize);
860 : // cppcheck-suppress redundantCopy
861 100 : memcpy(pachData, pszValue, std::min(nValueLength, nSize));
862 : }
863 : }
864 :
865 262 : return TRUE;
866 : }
867 :
868 : /************************************************************************/
869 : /* FormatIntValue() */
870 : /************************************************************************/
871 :
872 : /**
873 : * Format int subfield value.
874 : *
875 : * Returns a buffer with the passed in int value reformatted in a way
876 : * suitable for storage in a DDFField for this subfield.
877 : */
878 :
879 3112 : int DDFSubfieldDefn::FormatIntValue(char *pachData, int nBytesAvailable,
880 : int *pnBytesUsed, int nNewValue) const
881 :
882 : {
883 : int nSize;
884 : char szWork[30];
885 :
886 3112 : snprintf(szWork, sizeof(szWork), "%d", nNewValue);
887 :
888 3112 : if (bIsVariable)
889 : {
890 0 : nSize = static_cast<int>(strlen(szWork)) + 1;
891 : }
892 : else
893 : {
894 3112 : nSize = nFormatWidth;
895 :
896 3112 : if (GetBinaryFormat() == NotBinary && (int)strlen(szWork) > nSize)
897 0 : return FALSE;
898 : }
899 :
900 3112 : if (pnBytesUsed != nullptr)
901 1556 : *pnBytesUsed = nSize;
902 :
903 3112 : if (pachData == nullptr)
904 1556 : return TRUE;
905 :
906 1556 : if (nBytesAvailable < nSize)
907 0 : return FALSE;
908 :
909 1556 : if (bIsVariable)
910 : {
911 0 : strncpy(pachData, szWork, nSize - 1);
912 0 : pachData[nSize - 1] = DDF_UNIT_TERMINATOR;
913 : }
914 : else
915 : {
916 1556 : GUInt32 nMask = 0xff;
917 : int i;
918 :
919 1556 : switch (GetBinaryFormat())
920 : {
921 0 : case NotBinary:
922 : {
923 0 : char chFillChar = '0'; /* ASCII zero intended */
924 0 : memset(pachData, chFillChar, nSize);
925 0 : memcpy(pachData + nSize - strlen(szWork), szWork,
926 : strlen(szWork));
927 0 : break;
928 : }
929 :
930 1556 : case UInt:
931 : case SInt:
932 4448 : for (i = 0; i < nFormatWidth; i++)
933 : {
934 : int iOut;
935 :
936 : // big endian required?
937 2892 : if (pszFormatString[0] == 'B')
938 0 : iOut = nFormatWidth - i - 1;
939 : else
940 2892 : iOut = i;
941 :
942 2892 : pachData[iOut] = (char)((nNewValue & nMask) >> (i * 8));
943 2892 : nMask <<= 8;
944 : }
945 1556 : break;
946 :
947 0 : case FloatReal:
948 0 : CPLAssert(false);
949 : break;
950 :
951 0 : default:
952 0 : CPLAssert(false);
953 : break;
954 : }
955 : }
956 :
957 1556 : return TRUE;
958 : }
959 :
960 : /************************************************************************/
961 : /* FormatFloatValue() */
962 : /************************************************************************/
963 :
964 : /**
965 : * Format float subfield value.
966 : *
967 : * Returns a buffer with the passed in float value reformatted in a way
968 : * suitable for storage in a DDFField for this subfield.
969 : */
970 :
971 0 : int DDFSubfieldDefn::FormatFloatValue(char *pachData, int nBytesAvailable,
972 : int *pnBytesUsed, double dfNewValue) const
973 :
974 : {
975 : int nSize;
976 : char szWork[120];
977 :
978 0 : CPLsnprintf(szWork, sizeof(szWork), "%.16g", dfNewValue);
979 :
980 0 : if (bIsVariable)
981 : {
982 0 : nSize = static_cast<int>(strlen(szWork)) + 1;
983 : }
984 : else
985 : {
986 0 : nSize = nFormatWidth;
987 :
988 0 : if (GetBinaryFormat() == NotBinary && (int)strlen(szWork) > nSize)
989 0 : return FALSE;
990 : }
991 :
992 0 : if (pnBytesUsed != nullptr)
993 0 : *pnBytesUsed = nSize;
994 :
995 0 : if (pachData == nullptr)
996 0 : return TRUE;
997 :
998 0 : if (nBytesAvailable < nSize)
999 0 : return FALSE;
1000 :
1001 0 : if (bIsVariable)
1002 : {
1003 0 : strncpy(pachData, szWork, nSize - 1);
1004 0 : pachData[nSize - 1] = DDF_UNIT_TERMINATOR;
1005 : }
1006 : else
1007 : {
1008 0 : if (GetBinaryFormat() == NotBinary)
1009 : {
1010 0 : const char chFillZeroASCII = '0'; /* ASCII zero intended */
1011 : /* coverity[bad_memset] */
1012 0 : memset(pachData, chFillZeroASCII, nSize);
1013 0 : memcpy(pachData + nSize - strlen(szWork), szWork, strlen(szWork));
1014 : }
1015 : else
1016 : {
1017 0 : CPLAssert(false);
1018 : /* implement me */
1019 : }
1020 : }
1021 :
1022 0 : return TRUE;
1023 : }
|