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