Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: Erdas Imagine (.img) Translator
4 : * Purpose: Implementation of the HFAField class for managing information
5 : * about one field in a HFA dictionary type. Managed by HFAType.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 1999, Intergraph Corporation
10 : * Copyright (c) 2009-2011, Even Rouault <even dot rouault at spatialys.com>
11 : *
12 : * Permission is hereby granted, free of charge, to any person obtaining a
13 : * copy of this software and associated documentation files (the "Software"),
14 : * to deal in the Software without restriction, including without limitation
15 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 : * and/or sell copies of the Software, and to permit persons to whom the
17 : * Software is furnished to do so, subject to the following conditions:
18 : *
19 : * The above copyright notice and this permission notice shall be included
20 : * in all copies or substantial portions of the Software.
21 : *
22 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 : * DEALINGS IN THE SOFTWARE.
29 : ****************************************************************************/
30 :
31 : #include "cpl_port.h"
32 : #include "hfa_p.h"
33 :
34 : #include <cerrno>
35 : #include <climits>
36 : #include <cstddef>
37 : #include <cstdio>
38 : #include <cstring>
39 : #if HAVE_FCNTL_H
40 : #include <fcntl.h>
41 : #endif
42 : #include <algorithm>
43 : #include <limits>
44 : #include <vector>
45 :
46 : #include "cpl_conv.h"
47 : #include "cpl_error.h"
48 : #include "cpl_string.h"
49 : #include "cpl_vsi.h"
50 :
51 : constexpr int MAX_ENTRY_REPORT = 16;
52 :
53 : namespace
54 : {
55 :
56 0 : int FloatToIntClamp(float fValue)
57 : {
58 0 : if (CPLIsNan(fValue))
59 0 : return 0;
60 0 : if (fValue >= static_cast<float>(std::numeric_limits<int>::max()))
61 0 : return std::numeric_limits<int>::max();
62 0 : if (fValue <= static_cast<float>(std::numeric_limits<int>::min()))
63 0 : return std::numeric_limits<int>::min();
64 0 : return static_cast<int>(fValue);
65 : }
66 :
67 : } // namespace
68 :
69 : /************************************************************************/
70 : /* ==================================================================== */
71 : /* HFAField */
72 : /* ==================================================================== */
73 : /************************************************************************/
74 :
75 : /************************************************************************/
76 : /* HFAField() */
77 : /************************************************************************/
78 :
79 103405 : HFAField::HFAField()
80 : : nBytes(0), nItemCount(0), chPointer('\0'), chItemType('\0'),
81 : pszItemObjectType(nullptr), poItemObjectType(nullptr),
82 103405 : papszEnumNames(nullptr), pszFieldName(nullptr)
83 : {
84 103405 : memset(szNumberString, 0, sizeof(szNumberString));
85 103405 : }
86 :
87 : /************************************************************************/
88 : /* ~HFAField() */
89 : /************************************************************************/
90 :
91 206810 : HFAField::~HFAField()
92 :
93 : {
94 103405 : CPLFree(pszItemObjectType);
95 103405 : CSLDestroy(papszEnumNames);
96 103405 : CPLFree(pszFieldName);
97 103405 : }
98 :
99 : /************************************************************************/
100 : /* Initialize() */
101 : /************************************************************************/
102 :
103 103405 : const char *HFAField::Initialize(const char *pszInput)
104 :
105 : {
106 : // Read the number.
107 103405 : nItemCount = atoi(pszInput);
108 103405 : if (nItemCount < 0)
109 0 : return nullptr;
110 :
111 209009 : while (*pszInput != '\0' && *pszInput != ':')
112 105604 : pszInput++;
113 :
114 103405 : if (*pszInput == '\0')
115 0 : return nullptr;
116 :
117 103405 : pszInput++;
118 :
119 : // Is this a pointer?
120 103405 : if (*pszInput == 'p' || *pszInput == '*')
121 23733 : chPointer = *(pszInput++);
122 :
123 : // Get the general type.
124 103405 : if (*pszInput == '\0')
125 0 : return nullptr;
126 :
127 103405 : chItemType = *(pszInput++);
128 :
129 103405 : if (strchr("124cCesStlLfdmMbox", chItemType) == nullptr)
130 : {
131 1 : CPLError(CE_Failure, CPLE_AppDefined, "Unrecognized item type: %c",
132 1 : chItemType);
133 1 : return nullptr;
134 : }
135 :
136 : // If this is an object, we extract the type of the object.
137 103404 : int i = 0; // TODO: Describe why i needs to span chItemType blocks.
138 :
139 103404 : if (chItemType == 'o')
140 : {
141 167851 : for (i = 0; pszInput[i] != '\0' && pszInput[i] != ','; i++)
142 : {
143 : }
144 12351 : if (pszInput[i] == '\0')
145 0 : return nullptr;
146 :
147 12351 : pszItemObjectType = static_cast<char *>(CPLMalloc(i + 1));
148 12351 : strncpy(pszItemObjectType, pszInput, i);
149 12351 : pszItemObjectType[i] = '\0';
150 :
151 12351 : pszInput += i + 1;
152 : }
153 :
154 : // If this is an inline object, we need to skip past the
155 : // definition, and then extract the object class name.
156 : //
157 : // We ignore the actual definition, so if the object type isn't
158 : // already defined, things will not work properly. See the
159 : // file lceugr250_00_pct.aux for an example of inline defs.
160 103404 : if (chItemType == 'x' && *pszInput == '{')
161 : {
162 2805 : int nBraceDepth = 1;
163 2805 : pszInput++;
164 :
165 : // Skip past the definition.
166 91407 : while (nBraceDepth > 0 && *pszInput != '\0')
167 : {
168 88602 : if (*pszInput == '{')
169 1403 : nBraceDepth++;
170 87199 : else if (*pszInput == '}')
171 4208 : nBraceDepth--;
172 :
173 88602 : pszInput++;
174 : }
175 2805 : if (*pszInput == '\0')
176 0 : return nullptr;
177 :
178 2805 : chItemType = 'o';
179 :
180 : // Find the comma terminating the type name.
181 35787 : for (i = 0; pszInput[i] != '\0' && pszInput[i] != ','; i++)
182 : {
183 : }
184 2805 : if (pszInput[i] == '\0')
185 0 : return nullptr;
186 :
187 2805 : pszItemObjectType = static_cast<char *>(CPLMalloc(i + 1));
188 2805 : strncpy(pszItemObjectType, pszInput, i);
189 2805 : pszItemObjectType[i] = '\0';
190 :
191 2805 : pszInput += i + 1;
192 : }
193 :
194 : // If this is an enumeration we have to extract all the
195 : // enumeration values.
196 103404 : if (chItemType == 'e')
197 : {
198 14120 : const int nEnumCount = atoi(pszInput);
199 :
200 14120 : if (nEnumCount < 0 || nEnumCount > 100000)
201 0 : return nullptr;
202 :
203 14120 : pszInput = strchr(pszInput, ':');
204 14120 : if (pszInput == nullptr)
205 0 : return nullptr;
206 :
207 14120 : pszInput++;
208 :
209 14120 : papszEnumNames =
210 14120 : static_cast<char **>(VSICalloc(sizeof(char *), nEnumCount + 1));
211 14120 : if (papszEnumNames == nullptr)
212 0 : return nullptr;
213 :
214 79917 : for (int iEnum = 0; iEnum < nEnumCount; iEnum++)
215 : {
216 636951 : for (i = 0; pszInput[i] != '\0' && pszInput[i] != ','; i++)
217 : {
218 : }
219 :
220 65797 : if (pszInput[i] != ',')
221 0 : return nullptr;
222 :
223 65797 : char *pszToken = static_cast<char *>(CPLMalloc(i + 1));
224 65797 : strncpy(pszToken, pszInput, i);
225 65797 : pszToken[i] = '\0';
226 :
227 65797 : papszEnumNames[iEnum] = pszToken;
228 :
229 65797 : pszInput += i + 1;
230 : }
231 : }
232 :
233 : // Extract the field name.
234 998980 : for (i = 0; pszInput[i] != '\0' && pszInput[i] != ','; i++)
235 : {
236 : }
237 103404 : if (pszInput[i] == '\0')
238 0 : return nullptr;
239 :
240 103404 : pszFieldName = static_cast<char *>(CPLMalloc(i + 1));
241 103404 : strncpy(pszFieldName, pszInput, i);
242 103404 : pszFieldName[i] = '\0';
243 :
244 103404 : pszInput += i + 1;
245 :
246 103404 : return pszInput;
247 : }
248 :
249 : /************************************************************************/
250 : /* CompleteDefn() */
251 : /* */
252 : /* Establish size, and pointers to component types. */
253 : /************************************************************************/
254 :
255 103398 : bool HFAField::CompleteDefn(HFADictionary *poDict)
256 :
257 : {
258 : // Get a reference to the type object if we have a type name
259 : // for this field (not a built in).
260 103398 : if (pszItemObjectType != nullptr)
261 15150 : poItemObjectType = poDict->FindType(pszItemObjectType);
262 :
263 : // Figure out the size.
264 103398 : if (chPointer == 'p')
265 : {
266 16309 : nBytes = -1; // We can't know the instance size.
267 : }
268 87089 : else if (poItemObjectType != nullptr)
269 : {
270 11533 : if (!poItemObjectType->CompleteDefn(poDict))
271 2 : return false;
272 11531 : if (poItemObjectType->nBytes == -1)
273 9368 : nBytes = -1;
274 2163 : else if (poItemObjectType->nBytes != 0 &&
275 2163 : nItemCount > INT_MAX / poItemObjectType->nBytes)
276 0 : nBytes = -1;
277 : else
278 2163 : nBytes = poItemObjectType->nBytes * nItemCount;
279 :
280 : // TODO(schwehr): What does the 8 represent?
281 11531 : if (chPointer == '*' && nBytes != -1)
282 : {
283 2163 : if (nBytes > INT_MAX - 8)
284 0 : nBytes = -1;
285 : else
286 2163 : nBytes += 8; // Count, and offset.
287 : }
288 : }
289 : else
290 : {
291 75556 : const int nItemSize = poDict->GetItemSize(chItemType);
292 75556 : if (nItemSize != 0 && nItemCount > INT_MAX / nItemSize)
293 3863 : nBytes = -1;
294 : else
295 71693 : nBytes = nItemSize * nItemCount;
296 : }
297 103396 : return true;
298 : }
299 :
300 : /************************************************************************/
301 : /* Dump() */
302 : /************************************************************************/
303 :
304 0 : void HFAField::Dump(FILE *fp)
305 :
306 : {
307 : const char *pszTypeName;
308 :
309 0 : switch (chItemType)
310 : {
311 0 : case '1':
312 0 : pszTypeName = "U1";
313 0 : break;
314 :
315 0 : case '2':
316 0 : pszTypeName = "U2";
317 0 : break;
318 :
319 0 : case '4':
320 0 : pszTypeName = "U4";
321 0 : break;
322 :
323 0 : case 'c':
324 0 : pszTypeName = "UCHAR";
325 0 : break;
326 :
327 0 : case 'C':
328 0 : pszTypeName = "CHAR";
329 0 : break;
330 :
331 0 : case 'e':
332 0 : pszTypeName = "ENUM";
333 0 : break;
334 :
335 0 : case 's':
336 0 : pszTypeName = "USHORT";
337 0 : break;
338 :
339 0 : case 'S':
340 0 : pszTypeName = "SHORT";
341 0 : break;
342 :
343 0 : case 't':
344 0 : pszTypeName = "TIME";
345 0 : break;
346 :
347 0 : case 'l':
348 0 : pszTypeName = "ULONG";
349 0 : break;
350 :
351 0 : case 'L':
352 0 : pszTypeName = "LONG";
353 0 : break;
354 :
355 0 : case 'f':
356 0 : pszTypeName = "FLOAT";
357 0 : break;
358 :
359 0 : case 'd':
360 0 : pszTypeName = "DOUBLE";
361 0 : break;
362 :
363 0 : case 'm':
364 0 : pszTypeName = "COMPLEX";
365 0 : break;
366 :
367 0 : case 'M':
368 0 : pszTypeName = "DCOMPLEX";
369 0 : break;
370 :
371 0 : case 'b':
372 0 : pszTypeName = "BASEDATA";
373 0 : break;
374 :
375 0 : case 'o':
376 0 : pszTypeName = pszItemObjectType;
377 0 : break;
378 :
379 0 : case 'x':
380 0 : pszTypeName = "InlineType";
381 0 : break;
382 :
383 0 : default:
384 0 : CPLAssert(false);
385 : pszTypeName = "Unknown";
386 : }
387 :
388 0 : CPL_IGNORE_RET_VAL(VSIFPrintf(fp, " %-19s %c %s[%d];\n", pszTypeName,
389 0 : chPointer ? chPointer : ' ', pszFieldName,
390 : nItemCount));
391 :
392 0 : if (papszEnumNames != nullptr)
393 : {
394 0 : for (int i = 0; papszEnumNames[i] != nullptr; i++)
395 : {
396 0 : CPL_IGNORE_RET_VAL(
397 0 : VSIFPrintf(fp, " %s=%d\n", papszEnumNames[i], i));
398 : }
399 : }
400 0 : }
401 :
402 : /************************************************************************/
403 : /* SetInstValue() */
404 : /************************************************************************/
405 :
406 14276 : CPLErr HFAField::SetInstValue(const char *pszField, int nIndexValue,
407 : GByte *pabyData, GUInt32 nDataOffset,
408 : int nDataSize, char chReqType, void *pValue)
409 :
410 : {
411 : // If this field contains a pointer, then we will adjust the
412 : // data offset relative to it.
413 14276 : if (chPointer != '\0')
414 : {
415 7356 : GUInt32 nCount = 0;
416 :
417 : // The count returned for BASEDATA's are the contents,
418 : // but here we really want to mark it as one BASEDATA instance
419 : // (see #2144).
420 7356 : if (chItemType == 'b')
421 : {
422 45 : nCount = 1;
423 : }
424 : // Set the size from string length.
425 7311 : else if (chReqType == 's' && (chItemType == 'c' || chItemType == 'C'))
426 : {
427 1696 : if (pValue != nullptr)
428 1398 : nCount = static_cast<GUInt32>(strlen((char *)pValue) + 1);
429 : }
430 : // Set size based on index. Assumes in-order setting of array.
431 : else
432 : {
433 5615 : nCount = nIndexValue + 1;
434 : }
435 :
436 : // TODO(schwehr): What does the 8 represent?
437 7356 : if (static_cast<int>(nCount) + 8 > nDataSize)
438 : {
439 0 : CPLError(CE_Failure, CPLE_AppDefined,
440 : "Attempt to extend field %s in node past end of data, "
441 : "not currently supported.",
442 : pszField);
443 0 : return CE_Failure;
444 : }
445 :
446 : // We will update the object count iff we are writing beyond the end.
447 7356 : GUInt32 nOffset = 0;
448 7356 : memcpy(&nOffset, pabyData, 4);
449 : HFAStandard(4, &nOffset);
450 7356 : if (nOffset < nCount)
451 : {
452 5688 : nOffset = nCount;
453 : HFAStandard(4, &nOffset);
454 5688 : memcpy(pabyData, &nOffset, 4);
455 : }
456 :
457 7356 : if (pValue == nullptr)
458 298 : nOffset = 0;
459 : else
460 7058 : nOffset = nDataOffset + 8;
461 : HFAStandard(4, &nOffset);
462 7356 : memcpy(pabyData + 4, &nOffset, 4);
463 :
464 7356 : pabyData += 8;
465 :
466 7356 : nDataOffset += 8;
467 7356 : nDataSize -= 8;
468 : }
469 :
470 : // Pointers to char or uchar arrays requested as strings are
471 : // handled as a special case.
472 14276 : if ((chItemType == 'c' || chItemType == 'C') && chReqType == 's')
473 : {
474 1696 : int nBytesToCopy = 0;
475 :
476 1696 : if (nBytes == -1)
477 : {
478 1696 : if (pValue != nullptr)
479 1398 : nBytesToCopy = static_cast<int>(strlen((char *)pValue) + 1);
480 : }
481 : else
482 : {
483 0 : nBytesToCopy = nBytes;
484 : }
485 :
486 1696 : if (nBytesToCopy > nDataSize)
487 : {
488 0 : CPLError(CE_Failure, CPLE_AppDefined,
489 : "Attempt to extend field %s in node past end of data "
490 : "not currently supported.",
491 : pszField);
492 0 : return CE_Failure;
493 : }
494 :
495 1696 : memset(pabyData, 0, nBytesToCopy);
496 :
497 1696 : if (pValue != nullptr)
498 1398 : strncpy((char *)pabyData, (char *)pValue, nBytesToCopy);
499 :
500 1696 : return CE_None;
501 : }
502 :
503 : // Translate the passed type into different representations.
504 12580 : int nIntValue = 0;
505 12580 : double dfDoubleValue = 0.0;
506 :
507 12580 : if (chReqType == 's')
508 : {
509 2016 : CPLAssert(pValue != nullptr);
510 2016 : nIntValue = atoi((char *)pValue);
511 2016 : dfDoubleValue = CPLAtof((char *)pValue);
512 : }
513 10564 : else if (chReqType == 'd')
514 : {
515 7147 : CPLAssert(pValue != nullptr);
516 7147 : dfDoubleValue = *((double *)pValue);
517 7147 : if (dfDoubleValue > INT_MAX)
518 0 : nIntValue = INT_MAX;
519 7147 : else if (dfDoubleValue < INT_MIN)
520 1 : nIntValue = INT_MIN;
521 : else
522 7146 : nIntValue = static_cast<int>(dfDoubleValue);
523 : }
524 3417 : else if (chReqType == 'i')
525 : {
526 3417 : CPLAssert(pValue != nullptr);
527 3417 : nIntValue = *((int *)pValue);
528 3417 : dfDoubleValue = nIntValue;
529 : }
530 0 : else if (chReqType == 'p')
531 : {
532 0 : CPLError(
533 : CE_Failure, CPLE_NotSupported,
534 : "HFAField::SetInstValue() not supported yet for pointer values.");
535 :
536 0 : return CE_Failure;
537 : }
538 : else
539 : {
540 0 : CPLAssert(false);
541 : return CE_Failure;
542 : }
543 :
544 : // Handle by type.
545 12580 : switch (chItemType)
546 : {
547 0 : case 'c':
548 : case 'C':
549 0 : if (nIndexValue + 1 > nDataSize)
550 : {
551 0 : CPLError(CE_Failure, CPLE_AppDefined,
552 : "Attempt to extend field %s in node past end of data, "
553 : "not currently supported.",
554 : pszField);
555 0 : return CE_Failure;
556 : }
557 :
558 0 : if (chReqType == 's')
559 : {
560 0 : CPLAssert(pValue != nullptr);
561 0 : pabyData[nIndexValue] = ((char *)pValue)[0];
562 : }
563 : else
564 : {
565 0 : pabyData[nIndexValue] = static_cast<char>(nIntValue);
566 : }
567 0 : break;
568 :
569 1441 : case 'e':
570 : case 's':
571 : {
572 1441 : if (chItemType == 'e' && chReqType == 's')
573 : {
574 882 : CPLAssert(pValue != nullptr);
575 882 : nIntValue = CSLFindString(papszEnumNames, (char *)pValue);
576 882 : if (nIntValue == -1)
577 : {
578 0 : CPLError(CE_Failure, CPLE_AppDefined,
579 : "Attempt to set enumerated field with unknown"
580 : " value `%s'.",
581 : (char *)pValue);
582 0 : return CE_Failure;
583 : }
584 : }
585 :
586 1441 : if (nIndexValue * 2 + 2 > nDataSize)
587 : {
588 0 : CPLError(CE_Failure, CPLE_AppDefined,
589 : "Attempt to extend field %s in node past end of data, "
590 : "not currently supported.",
591 : pszField);
592 0 : return CE_Failure;
593 : }
594 :
595 : // TODO(schwehr): Warn on clamping.
596 1441 : unsigned short nNumber = static_cast<unsigned short>(nIntValue);
597 : // TODO(schwehr): What is this 2?
598 : HFAStandard(2, &nNumber);
599 1441 : memcpy(pabyData + nIndexValue * 2, &nNumber, 2);
600 : }
601 1441 : break;
602 :
603 0 : case 'S':
604 : {
605 0 : if (nIndexValue * 2 + 2 > nDataSize)
606 : {
607 0 : CPLError(CE_Failure, CPLE_AppDefined,
608 : "Attempt to extend field %s in node past end of data, "
609 : "not currently supported.",
610 : pszField);
611 0 : return CE_Failure;
612 : }
613 :
614 : // TODO(schwehr): Warn on clamping.
615 0 : short nNumber = static_cast<short>(nIntValue);
616 : // TODO(schwehr): What is this 2?
617 : HFAStandard(2, &nNumber);
618 0 : memcpy(pabyData + nIndexValue * 2, &nNumber, 2);
619 : }
620 0 : break;
621 :
622 2208 : case 't':
623 : case 'l':
624 : {
625 2208 : if (nIndexValue * 4 + 4 > nDataSize)
626 : {
627 0 : CPLError(CE_Failure, CPLE_AppDefined,
628 : "Attempt to extend field %s in node past end of data, "
629 : "not currently supported.",
630 : pszField);
631 0 : return CE_Failure;
632 : }
633 :
634 2208 : GUInt32 nNumber = nIntValue;
635 : // TODO(schwehr): What is this 4?
636 : HFAStandard(4, &nNumber);
637 2208 : memcpy(pabyData + nIndexValue * 4, &nNumber, 4);
638 : }
639 2208 : break;
640 :
641 581 : case 'L':
642 : {
643 581 : if (nIndexValue * 4 + 4 > nDataSize)
644 : {
645 0 : CPLError(CE_Failure, CPLE_AppDefined,
646 : "Attempt to extend field %s in node past end of data, "
647 : "not currently supported.",
648 : pszField);
649 0 : return CE_Failure;
650 : }
651 :
652 581 : GInt32 nNumber = nIntValue;
653 : HFAStandard(4, &nNumber);
654 581 : memcpy(pabyData + nIndexValue * 4, &nNumber, 4);
655 : }
656 581 : break;
657 :
658 0 : case 'f':
659 : {
660 0 : if (nIndexValue * 4 + 4 > nDataSize)
661 : {
662 0 : CPLError(CE_Failure, CPLE_AppDefined,
663 : "Attempt to extend field %s in node past end of data, "
664 : "not currently supported.",
665 : pszField);
666 0 : return CE_Failure;
667 : }
668 :
669 : // TODO(schwehr): Warn on clamping.
670 0 : float fNumber = static_cast<float>(dfDoubleValue);
671 : // TODO(schwehr): 4 == sizeof(float)?
672 : HFAStandard(4, &fNumber);
673 0 : memcpy(pabyData + nIndexValue * 4, &fNumber, 4);
674 : }
675 0 : break;
676 :
677 5414 : case 'd':
678 : {
679 5414 : if (nIndexValue * 8 + 8 > nDataSize)
680 : {
681 0 : CPLError(CE_Failure, CPLE_AppDefined,
682 : "Attempt to extend field %s in node past end of data, "
683 : "not currently supported.",
684 : pszField);
685 0 : return CE_Failure;
686 : }
687 :
688 5414 : double dfNumber = dfDoubleValue;
689 : HFAStandard(8, &dfNumber);
690 5414 : memcpy(pabyData + nIndexValue * 8, &dfNumber, 8);
691 : }
692 5414 : break;
693 :
694 45 : case 'b':
695 : {
696 : // Extract existing rows, columns, and datatype.
697 45 : GInt32 nRows = 1; // TODO(schwehr): Why init to 1 instead of 0?
698 45 : memcpy(&nRows, pabyData, 4);
699 : HFAStandard(4, &nRows);
700 :
701 45 : GInt32 nColumns = 1; // TODO(schwehr): Why init to 1 instead of 0?
702 45 : memcpy(&nColumns, pabyData + 4, 4);
703 : HFAStandard(4, &nColumns);
704 :
705 45 : GInt16 nBaseItemType = 0;
706 45 : memcpy(&nBaseItemType, pabyData + 8, 2);
707 : HFAStandard(2, &nBaseItemType);
708 :
709 : // Are we using special index values to update the rows, columns
710 : // or type?
711 :
712 45 : if (nIndexValue == -3)
713 10 : nBaseItemType = static_cast<GInt16>(nIntValue);
714 35 : else if (nIndexValue == -2)
715 10 : nColumns = nIntValue;
716 25 : else if (nIndexValue == -1)
717 10 : nRows = nIntValue;
718 :
719 45 : if (nIndexValue < -3 || nIndexValue >= nRows * nColumns)
720 1 : return CE_Failure;
721 :
722 : // Write back the rows, columns and basedatatype.
723 : HFAStandard(4, &nRows);
724 44 : memcpy(pabyData, &nRows, 4);
725 : HFAStandard(4, &nColumns);
726 44 : memcpy(pabyData + 4, &nColumns, 4);
727 : HFAStandard(2, &nBaseItemType);
728 44 : memcpy(pabyData + 8, &nBaseItemType, 2);
729 : HFAStandard(2, &nBaseItemType); // Swap back for our use.
730 :
731 44 : if (nBaseItemType < EPT_MIN || nBaseItemType > EPT_MAX)
732 0 : return CE_Failure;
733 44 : const EPTType eBaseItemType = static_cast<EPTType>(nBaseItemType);
734 :
735 : // We ignore the 2 byte objecttype value.
736 :
737 44 : nDataSize -= 12;
738 :
739 44 : if (nIndexValue >= 0)
740 : {
741 28 : if ((nIndexValue + 1) *
742 14 : (HFAGetDataTypeBits(eBaseItemType) / 8) >
743 : nDataSize)
744 : {
745 0 : CPLError(CE_Failure, CPLE_AppDefined,
746 : "Attempt to extend field %s in node past end of "
747 : "data, not currently supported.",
748 : pszField);
749 0 : return CE_Failure;
750 : }
751 :
752 14 : if (eBaseItemType == EPT_f64)
753 : {
754 14 : double dfNumber = dfDoubleValue;
755 :
756 : HFAStandard(8, &dfNumber);
757 14 : memcpy(pabyData + 12 + nIndexValue * 8, &dfNumber, 8);
758 : }
759 0 : else if (eBaseItemType == EPT_u8)
760 : {
761 : // TODO(schwehr): Warn on clamping.
762 0 : unsigned char nNumber =
763 0 : static_cast<unsigned char>(dfDoubleValue);
764 0 : memcpy(pabyData + 12 + nIndexValue, &nNumber, 1);
765 : }
766 : else
767 : {
768 0 : CPLError(CE_Failure, CPLE_AppDefined,
769 : "Setting basedata field %s with type %s "
770 : "not currently supported.",
771 : pszField, HFAGetDataTypeName(eBaseItemType));
772 0 : return CE_Failure;
773 : }
774 : }
775 : }
776 44 : break;
777 :
778 2891 : case 'o':
779 2891 : if (poItemObjectType != nullptr)
780 : {
781 2891 : int nExtraOffset = 0;
782 :
783 2891 : if (poItemObjectType->nBytes > 0)
784 : {
785 1193 : if (nIndexValue != 0 &&
786 43 : poItemObjectType->nBytes > INT_MAX / nIndexValue)
787 : {
788 0 : return CE_Failure;
789 : }
790 1193 : nExtraOffset = poItemObjectType->nBytes * nIndexValue;
791 : }
792 : else
793 : {
794 1707 : for (int iIndexCounter = 0; iIndexCounter < nIndexValue &&
795 : nExtraOffset < nDataSize;
796 : iIndexCounter++)
797 : {
798 9 : std::set<HFAField *> oVisitedFields;
799 18 : const int nInc = poItemObjectType->GetInstBytes(
800 9 : pabyData + nExtraOffset, nDataSize - nExtraOffset,
801 : oVisitedFields);
802 9 : if (nInc <= 0 || nExtraOffset > INT_MAX - nInc)
803 : {
804 0 : CPLError(CE_Failure, CPLE_AppDefined,
805 : "Invalid return value");
806 0 : return CE_Failure;
807 : }
808 :
809 9 : nExtraOffset += nInc;
810 : }
811 : }
812 :
813 2891 : if (nExtraOffset >= nDataSize)
814 1 : return CE_Failure;
815 :
816 2890 : if (pszField != nullptr && strlen(pszField) > 0)
817 : {
818 5780 : return poItemObjectType->SetInstValue(
819 2890 : pszField, pabyData + nExtraOffset,
820 2890 : nDataOffset + nExtraOffset, nDataSize - nExtraOffset,
821 2890 : chReqType, pValue);
822 : }
823 : else
824 : {
825 0 : CPLAssert(false);
826 : return CE_Failure;
827 : }
828 : }
829 0 : break;
830 :
831 0 : default:
832 0 : CPLAssert(false);
833 : return CE_Failure;
834 : break;
835 : }
836 :
837 9688 : return CE_None;
838 : }
839 :
840 : /************************************************************************/
841 : /* ExtractInstValue() */
842 : /* */
843 : /* Extract the value of an instance of a field. */
844 : /* */
845 : /* pszField should be NULL if this field is not a */
846 : /* substructure. */
847 : /************************************************************************/
848 :
849 46111 : bool HFAField::ExtractInstValue(const char *pszField, int nIndexValue,
850 : GByte *pabyData, GUInt32 nDataOffset,
851 : int nDataSize, char chReqType, void *pReqReturn,
852 : int *pnRemainingDataSize)
853 :
854 : {
855 46111 : const int nInstItemCount = GetInstCount(pabyData, nDataSize);
856 :
857 46111 : if (pnRemainingDataSize)
858 422 : *pnRemainingDataSize = -1;
859 :
860 : // Check the index value is valid.
861 : // Eventually this will have to account for variable fields.
862 46111 : if (nIndexValue < 0 || nIndexValue >= nInstItemCount)
863 : {
864 558 : if (chItemType == 'b' && nIndexValue >= -3 && nIndexValue < 0)
865 : /* ok - special index values */;
866 : else
867 558 : return false;
868 : }
869 :
870 : // If this field contains a pointer, then we will adjust the
871 : // data offset relative to it.
872 45553 : if (chPointer != '\0')
873 : {
874 19071 : if (nDataSize < 8)
875 : {
876 0 : CPLError(CE_Failure, CPLE_AppDefined, "Buffer too small");
877 0 : return false;
878 : }
879 :
880 19071 : GUInt32 nOffset = 0;
881 19071 : memcpy(&nOffset, pabyData + 4, 4);
882 : HFAStandard(4, &nOffset);
883 :
884 : #if DEBUG_VERBOSE
885 : if (nOffset != static_cast<GUInt32>(nDataOffset + 8))
886 : {
887 : // TODO(schwehr): Debug why this is happening.
888 : CPLError(CE_Warning, CPLE_AppDefined,
889 : "ExtractInstValue: "
890 : "%s.%s points at %d, not %d as expected",
891 : pszFieldName, pszField ? pszField : "", nOffset,
892 : nDataOffset + 8);
893 : }
894 : #endif
895 :
896 19071 : pabyData += 8;
897 19071 : nDataOffset += 8;
898 19071 : nDataSize -= 8;
899 : }
900 :
901 : // Pointers to char or uchar arrays requested as strings are
902 : // handled as a special case.
903 45553 : if ((chItemType == 'c' || chItemType == 'C') && chReqType == 's')
904 : {
905 2054 : *((GByte **)pReqReturn) = pabyData;
906 2054 : if (pnRemainingDataSize)
907 211 : *pnRemainingDataSize = nDataSize;
908 2054 : return pabyData != nullptr;
909 : }
910 :
911 : // Handle by type.
912 43499 : char *pszStringRet = nullptr;
913 43499 : int nIntRet = 0;
914 43499 : double dfDoubleRet = 0.0;
915 43499 : GByte *pabyRawData = nullptr;
916 :
917 43499 : switch (chItemType)
918 : {
919 0 : case 'c':
920 : case 'C':
921 0 : if (nIndexValue >= nDataSize)
922 : {
923 0 : CPLError(CE_Failure, CPLE_AppDefined, "Buffer too small");
924 0 : return false;
925 : }
926 0 : nIntRet = pabyData[nIndexValue];
927 0 : dfDoubleRet = nIntRet;
928 0 : break;
929 :
930 8722 : case 'e':
931 : case 's':
932 : {
933 8722 : if (nIndexValue * 2 + 2 > nDataSize)
934 : {
935 0 : CPLError(CE_Failure, CPLE_AppDefined, "Buffer too small");
936 0 : return false;
937 : }
938 8722 : unsigned short nNumber = 0;
939 8722 : memcpy(&nNumber, pabyData + nIndexValue * 2, 2);
940 : HFAStandard(2, &nNumber);
941 8722 : nIntRet = nNumber;
942 8722 : dfDoubleRet = nIntRet;
943 :
944 17444 : if (chItemType == 'e' &&
945 8722 : nNumber < static_cast<unsigned>(CSLCount(papszEnumNames)))
946 : {
947 8721 : pszStringRet = papszEnumNames[nNumber];
948 : }
949 : }
950 8722 : break;
951 :
952 0 : case 'S':
953 : {
954 0 : if (nIndexValue * 2 + 2 > nDataSize)
955 : {
956 0 : CPLError(CE_Failure, CPLE_AppDefined, "Buffer too small");
957 0 : return false;
958 : }
959 0 : short nNumber = 0;
960 0 : memcpy(&nNumber, pabyData + nIndexValue * 2, 2);
961 : HFAStandard(2, &nNumber);
962 0 : nIntRet = nNumber;
963 0 : dfDoubleRet = nIntRet;
964 : }
965 0 : break;
966 :
967 10450 : case 't':
968 : case 'l':
969 : {
970 10450 : if (nIndexValue * 4 + 4 > nDataSize)
971 : {
972 0 : CPLError(CE_Failure, CPLE_AppDefined, "Buffer too small");
973 0 : return false;
974 : }
975 10450 : GUInt32 nNumber = 0;
976 10450 : memcpy(&nNumber, pabyData + nIndexValue * 4, 4);
977 : HFAStandard(4, &nNumber);
978 10450 : nIntRet = nNumber;
979 10450 : dfDoubleRet = nIntRet;
980 : }
981 10450 : break;
982 :
983 3035 : case 'L':
984 : {
985 3035 : if (nIndexValue * 4 + 4 > nDataSize)
986 : {
987 0 : CPLError(CE_Failure, CPLE_AppDefined, "Buffer too small");
988 0 : return false;
989 : }
990 3035 : GInt32 nNumber = 0;
991 : // TODO(schwehr): What is 4?
992 3035 : memcpy(&nNumber, pabyData + nIndexValue * 4, 4);
993 : HFAStandard(4, &nNumber);
994 3035 : nIntRet = nNumber;
995 3035 : dfDoubleRet = nIntRet;
996 : }
997 3035 : break;
998 :
999 0 : case 'f':
1000 : {
1001 0 : if (nIndexValue * 4 + 4 > nDataSize)
1002 : {
1003 0 : CPLError(CE_Failure, CPLE_AppDefined, "Buffer too small");
1004 0 : return false;
1005 : }
1006 0 : float fNumber = 0.0f;
1007 : // TODO(schwehr): What is 4?
1008 0 : memcpy(&fNumber, pabyData + nIndexValue * 4, 4);
1009 : HFAStandard(4, &fNumber);
1010 0 : if (static_cast<double>(fNumber) >
1011 0 : std::numeric_limits<int>::max() ||
1012 0 : static_cast<double>(fNumber) <
1013 0 : std::numeric_limits<int>::min() ||
1014 0 : CPLIsNan(fNumber))
1015 : {
1016 0 : CPLError(CE_Failure, CPLE_AppDefined, "Too large for int: %f",
1017 : fNumber);
1018 0 : return false;
1019 : }
1020 0 : dfDoubleRet = fNumber;
1021 0 : nIntRet = static_cast<int>(fNumber);
1022 : }
1023 0 : break;
1024 :
1025 7239 : case 'd':
1026 : {
1027 7239 : if (nIndexValue * 8 + 8 > nDataSize)
1028 : {
1029 0 : CPLError(CE_Failure, CPLE_AppDefined, "Buffer too small");
1030 0 : return false;
1031 : }
1032 7239 : double dfNumber = 0;
1033 7239 : memcpy(&dfNumber, pabyData + nIndexValue * 8, 8);
1034 : HFAStandard(8, &dfNumber);
1035 7239 : dfDoubleRet = dfNumber;
1036 7239 : if (dfNumber > std::numeric_limits<int>::max() ||
1037 14478 : dfNumber < std::numeric_limits<int>::min() ||
1038 7239 : CPLIsNan(dfNumber))
1039 : {
1040 0 : CPLError(CE_Failure, CPLE_AppDefined, "Too large for int: %f",
1041 : dfNumber);
1042 0 : return false;
1043 : }
1044 7239 : nIntRet = static_cast<int>(dfNumber);
1045 : }
1046 7239 : break;
1047 :
1048 133 : case 'b':
1049 : {
1050 133 : if (nDataSize < 12)
1051 0 : return false;
1052 :
1053 133 : GInt32 nRows = 0;
1054 133 : memcpy(&nRows, pabyData, 4);
1055 : HFAStandard(4, &nRows);
1056 :
1057 133 : GInt32 nColumns = 0;
1058 133 : memcpy(&nColumns, pabyData + 4, 4);
1059 : HFAStandard(4, &nColumns);
1060 :
1061 133 : GInt16 nBaseItemType = 0;
1062 133 : memcpy(&nBaseItemType, pabyData + 8, 2);
1063 : HFAStandard(2, &nBaseItemType);
1064 : // We ignore the 2 byte objecttype value.
1065 :
1066 133 : if (nIndexValue < -3 || nRows <= 0 || nColumns <= 0 ||
1067 133 : nRows > INT_MAX / nColumns || nIndexValue >= nRows * nColumns)
1068 0 : return false;
1069 :
1070 133 : pabyData += 12;
1071 133 : nDataSize -= 12;
1072 :
1073 133 : if (nIndexValue == -3)
1074 : {
1075 0 : dfDoubleRet = nBaseItemType;
1076 0 : nIntRet = nBaseItemType;
1077 : }
1078 133 : else if (nIndexValue == -2)
1079 : {
1080 0 : dfDoubleRet = nColumns;
1081 0 : nIntRet = nColumns;
1082 : }
1083 133 : else if (nIndexValue == -1)
1084 : {
1085 0 : dfDoubleRet = nRows;
1086 0 : nIntRet = nRows;
1087 : }
1088 133 : else if (nBaseItemType == EPT_u1)
1089 : {
1090 : // TODO(schwehr): What are these constants like 8 and 0x7?
1091 0 : if (nIndexValue * 8 >= nDataSize)
1092 : {
1093 0 : CPLError(CE_Failure, CPLE_AppDefined, "Buffer too small");
1094 0 : return false;
1095 : }
1096 :
1097 0 : if (pabyData[nIndexValue >> 3] & (1 << (nIndexValue & 0x7)))
1098 : {
1099 0 : dfDoubleRet = 1;
1100 0 : nIntRet = 1;
1101 : }
1102 : else
1103 : {
1104 0 : dfDoubleRet = 0.0;
1105 0 : nIntRet = 0;
1106 : }
1107 : }
1108 133 : else if (nBaseItemType == EPT_u2)
1109 : {
1110 0 : const int nBitOffset = nIndexValue & 0x3;
1111 0 : const int nByteOffset = nIndexValue >> 2;
1112 :
1113 0 : if (nByteOffset >= nDataSize)
1114 : {
1115 0 : CPLError(CE_Failure, CPLE_AppDefined, "Buffer too small");
1116 0 : return false;
1117 : }
1118 :
1119 0 : const int nMask = 0x3;
1120 0 : nIntRet = (pabyData[nByteOffset] >> nBitOffset) & nMask;
1121 0 : dfDoubleRet = nIntRet;
1122 : }
1123 133 : else if (nBaseItemType == EPT_u4)
1124 : {
1125 0 : const int nBitOffset = nIndexValue & 0x7;
1126 0 : const int nByteOffset = nIndexValue >> 3;
1127 :
1128 0 : if (nByteOffset >= nDataSize)
1129 : {
1130 0 : CPLError(CE_Failure, CPLE_AppDefined, "Buffer too small");
1131 0 : return false;
1132 : }
1133 :
1134 0 : const int nMask = 0x7;
1135 0 : nIntRet = (pabyData[nByteOffset] >> nBitOffset) & nMask;
1136 0 : dfDoubleRet = nIntRet;
1137 : }
1138 133 : else if (nBaseItemType == EPT_u8)
1139 : {
1140 16 : if (nIndexValue >= nDataSize)
1141 : {
1142 0 : CPLError(CE_Failure, CPLE_AppDefined, "Buffer too small");
1143 0 : return false;
1144 : }
1145 16 : dfDoubleRet = pabyData[nIndexValue];
1146 16 : nIntRet = pabyData[nIndexValue];
1147 : }
1148 117 : else if (nBaseItemType == EPT_s8)
1149 : {
1150 0 : if (nIndexValue >= nDataSize)
1151 : {
1152 0 : CPLError(CE_Failure, CPLE_AppDefined, "Buffer too small");
1153 0 : return false;
1154 : }
1155 0 : dfDoubleRet = ((signed char *)pabyData)[nIndexValue];
1156 0 : nIntRet = ((signed char *)pabyData)[nIndexValue];
1157 : }
1158 117 : else if (nBaseItemType == EPT_s16)
1159 : {
1160 0 : if (nIndexValue * 2 + 2 > nDataSize)
1161 : {
1162 0 : CPLError(CE_Failure, CPLE_AppDefined, "Buffer too small");
1163 0 : return false;
1164 : }
1165 0 : GInt16 nValue = 0;
1166 0 : memcpy(&nValue, pabyData + 2 * nIndexValue, 2);
1167 : HFAStandard(2, &nValue);
1168 :
1169 0 : dfDoubleRet = nValue;
1170 0 : nIntRet = nValue;
1171 : }
1172 117 : else if (nBaseItemType == EPT_u16)
1173 : {
1174 0 : if (nIndexValue * 2 + 2 > nDataSize)
1175 : {
1176 0 : CPLError(CE_Failure, CPLE_AppDefined, "Buffer too small");
1177 0 : return false;
1178 : }
1179 0 : GUInt16 nValue = 0;
1180 0 : memcpy(&nValue, pabyData + 2 * nIndexValue, 2);
1181 : HFAStandard(2, &nValue);
1182 :
1183 0 : dfDoubleRet = nValue;
1184 0 : nIntRet = nValue;
1185 : }
1186 117 : else if (nBaseItemType == EPT_s32)
1187 : {
1188 0 : if (nIndexValue * 4 + 4 > nDataSize)
1189 : {
1190 0 : CPLError(CE_Failure, CPLE_AppDefined, "Buffer too small");
1191 0 : return false;
1192 : }
1193 0 : GInt32 nValue = 0;
1194 0 : memcpy(&nValue, pabyData + 4 * nIndexValue, 4);
1195 : HFAStandard(4, &nValue);
1196 :
1197 0 : dfDoubleRet = nValue;
1198 0 : nIntRet = nValue;
1199 : }
1200 117 : else if (nBaseItemType == EPT_u32)
1201 : {
1202 0 : if (nIndexValue * 4 + 4 > nDataSize)
1203 : {
1204 0 : CPLError(CE_Failure, CPLE_AppDefined, "Buffer too small");
1205 0 : return false;
1206 : }
1207 0 : GUInt32 nValue = 0;
1208 0 : memcpy(&nValue, pabyData + 4 * nIndexValue, 4);
1209 : HFAStandard(4, &nValue);
1210 :
1211 0 : dfDoubleRet = nValue;
1212 0 : nIntRet = nValue;
1213 : }
1214 117 : else if (nBaseItemType == EPT_f32)
1215 : {
1216 0 : if (nIndexValue * 4 + 4 > nDataSize)
1217 : {
1218 0 : CPLError(CE_Failure, CPLE_AppDefined, "Buffer too small");
1219 0 : return false;
1220 : }
1221 0 : float fValue = 0.0f;
1222 0 : memcpy(&fValue, pabyData + 4 * nIndexValue, 4);
1223 : HFAStandard(4, &fValue);
1224 :
1225 0 : dfDoubleRet = fValue;
1226 0 : nIntRet = FloatToIntClamp(fValue);
1227 : }
1228 117 : else if (nBaseItemType == EPT_f64)
1229 : {
1230 117 : if (nIndexValue * 8 + 8 > nDataSize)
1231 : {
1232 0 : CPLError(CE_Failure, CPLE_AppDefined, "Buffer too small");
1233 0 : return false;
1234 : }
1235 117 : double dfValue = 0.0;
1236 117 : memcpy(&dfValue, pabyData + 8 * nIndexValue, 8);
1237 : HFAStandard(8, &dfValue);
1238 :
1239 117 : dfDoubleRet = dfValue;
1240 117 : const int nMax = std::numeric_limits<int>::max();
1241 117 : const int nMin = std::numeric_limits<int>::min();
1242 117 : if (dfDoubleRet >= nMax)
1243 : {
1244 0 : nIntRet = nMax;
1245 : }
1246 117 : else if (dfDoubleRet <= nMin)
1247 : {
1248 1 : nIntRet = nMin;
1249 : }
1250 116 : else if (CPLIsNan(dfDoubleRet))
1251 : {
1252 0 : CPLError(CE_Warning, CPLE_AppDefined,
1253 : "NaN converted to INT_MAX.");
1254 0 : nIntRet = nMax;
1255 : }
1256 : else
1257 : {
1258 116 : nIntRet = static_cast<int>(dfDoubleRet);
1259 : }
1260 : }
1261 : else
1262 : {
1263 0 : CPLError(CE_Failure, CPLE_AppDefined,
1264 : "Unknown base item type: %d", nBaseItemType);
1265 0 : return false;
1266 : }
1267 : }
1268 133 : break;
1269 :
1270 13920 : case 'o':
1271 13920 : if (poItemObjectType != nullptr)
1272 : {
1273 13920 : int nExtraOffset = 0;
1274 :
1275 13920 : if (poItemObjectType->nBytes > 0)
1276 : {
1277 11298 : if (nIndexValue != 0 &&
1278 9228 : poItemObjectType->nBytes > INT_MAX / nIndexValue)
1279 : // TODO(schwehr): Why was this CE_Failure when the
1280 : // others are false?
1281 0 : return false;
1282 11298 : nExtraOffset = poItemObjectType->nBytes * nIndexValue;
1283 : }
1284 : else
1285 : {
1286 2643 : for (int iIndexCounter = 0; iIndexCounter < nIndexValue &&
1287 : nExtraOffset < nDataSize;
1288 : iIndexCounter++)
1289 : {
1290 21 : std::set<HFAField *> oVisitedFields;
1291 42 : const int nInc = poItemObjectType->GetInstBytes(
1292 21 : pabyData + nExtraOffset, nDataSize - nExtraOffset,
1293 : oVisitedFields);
1294 21 : if (nInc <= 0 || nExtraOffset > INT_MAX - nInc)
1295 : {
1296 0 : CPLError(CE_Failure, CPLE_AppDefined,
1297 : "Invalid return value");
1298 : // TODO(schwehr): Verify this false is okay.
1299 0 : return false;
1300 : }
1301 :
1302 21 : nExtraOffset += nInc;
1303 : }
1304 : }
1305 :
1306 13920 : if (nExtraOffset >= nDataSize)
1307 0 : return false;
1308 :
1309 13920 : pabyRawData = pabyData + nExtraOffset;
1310 :
1311 13920 : if (pszField != nullptr && strlen(pszField) > 0)
1312 : {
1313 27840 : return poItemObjectType->ExtractInstValue(
1314 13920 : pszField, pabyRawData, nDataOffset + nExtraOffset,
1315 : nDataSize - nExtraOffset, chReqType, pReqReturn,
1316 13920 : pnRemainingDataSize);
1317 : }
1318 : }
1319 : else
1320 : {
1321 : // E. Rouault: not completely sure about this, but helps avoid
1322 : // DoS timeouts in cases like
1323 : // https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=1806
1324 0 : return false;
1325 : }
1326 0 : break;
1327 :
1328 0 : default:
1329 0 : return false;
1330 : break;
1331 : }
1332 :
1333 : // Return the appropriate representation.
1334 29579 : if (chReqType == 's')
1335 : {
1336 1082 : if (pszStringRet == nullptr)
1337 : {
1338 : // HFAEntry:: BuildEntryFromMIFObject() expects to have always 8
1339 : // bytes before the data. In normal situations, it should not go
1340 : // here, but that can happen if the file is corrupted so reserve the
1341 : // first 8 bytes before the string to contain null bytes.
1342 39 : memset(szNumberString, 0, 8);
1343 39 : CPLsnprintf(szNumberString + 8, sizeof(szNumberString) - 8, "%.14g",
1344 : dfDoubleRet);
1345 39 : pszStringRet = szNumberString + 8;
1346 : }
1347 :
1348 1082 : *((char **)pReqReturn) = pszStringRet;
1349 1082 : return true;
1350 : }
1351 28497 : else if (chReqType == 'd')
1352 : {
1353 7333 : *((double *)pReqReturn) = dfDoubleRet;
1354 7333 : return true;
1355 : }
1356 21164 : else if (chReqType == 'i')
1357 : {
1358 21164 : *((int *)pReqReturn) = nIntRet;
1359 21164 : return true;
1360 : }
1361 0 : else if (chReqType == 'p')
1362 : {
1363 0 : *((GByte **)pReqReturn) = pabyRawData;
1364 0 : return true;
1365 : }
1366 : else
1367 : {
1368 0 : CPLAssert(false);
1369 : return false;
1370 : }
1371 : }
1372 :
1373 : /************************************************************************/
1374 : /* GetInstBytes() */
1375 : /* */
1376 : /* Get the number of bytes in a particular instance of a */
1377 : /* field. This will normally be the fixed internal nBytes */
1378 : /* value, but for pointer objects will include the variable */
1379 : /* portion. */
1380 : /************************************************************************/
1381 :
1382 165568 : int HFAField::GetInstBytes(GByte *pabyData, int nDataSize,
1383 : std::set<HFAField *> &oVisitedFields)
1384 :
1385 : {
1386 165568 : if (oVisitedFields.find(this) != oVisitedFields.end())
1387 : {
1388 0 : CPLError(CE_Failure, CPLE_AppDefined, "Recursion detected");
1389 0 : return -1;
1390 : }
1391 :
1392 165568 : if (nBytes > -1)
1393 133042 : return nBytes;
1394 :
1395 32526 : int nCount = 1;
1396 32526 : int nInstBytes = 0;
1397 :
1398 32526 : if (chPointer != '\0')
1399 : {
1400 30166 : if (nDataSize < 4)
1401 : {
1402 0 : CPLError(CE_Failure, CPLE_AppDefined, "Buffer too small");
1403 0 : return -1;
1404 : }
1405 :
1406 30166 : memcpy(&nCount, pabyData, 4);
1407 : HFAStandard(4, &nCount);
1408 :
1409 30166 : pabyData += 8;
1410 30166 : nInstBytes += 8;
1411 : }
1412 :
1413 32526 : if (chItemType == 'b' && nCount != 0) // BASEDATA
1414 : {
1415 505 : if (nDataSize - nInstBytes < 4 + 4 + 2)
1416 : {
1417 0 : CPLError(CE_Failure, CPLE_AppDefined, "Buffer too small");
1418 0 : return -1;
1419 : }
1420 :
1421 505 : GInt32 nRows = 0;
1422 505 : memcpy(&nRows, pabyData, 4);
1423 : HFAStandard(4, &nRows);
1424 505 : GInt32 nColumns = 0;
1425 505 : memcpy(&nColumns, pabyData + 4, 4);
1426 : HFAStandard(4, &nColumns);
1427 505 : GInt16 nBaseItemType = 0;
1428 505 : memcpy(&nBaseItemType, pabyData + 8, 2);
1429 : HFAStandard(2, &nBaseItemType);
1430 505 : if (nBaseItemType < EPT_MIN || nBaseItemType > EPT_MAX)
1431 0 : return -1;
1432 :
1433 505 : EPTType eBaseItemType = static_cast<EPTType>(nBaseItemType);
1434 :
1435 505 : nInstBytes += 12;
1436 :
1437 505 : if (nRows < 0 || nColumns < 0)
1438 0 : return -1;
1439 505 : if (nColumns != 0 && nRows > INT_MAX / nColumns)
1440 0 : return -1;
1441 1002 : if (nRows != 0 &&
1442 497 : ((HFAGetDataTypeBits(eBaseItemType) + 7) / 8) > INT_MAX / nRows)
1443 0 : return -1;
1444 1002 : if (nColumns != 0 &&
1445 497 : ((HFAGetDataTypeBits(eBaseItemType) + 7) / 8) * nRows >
1446 497 : INT_MAX / nColumns)
1447 0 : return -1;
1448 505 : if (((HFAGetDataTypeBits(eBaseItemType) + 7) / 8) * nRows * nColumns >
1449 505 : INT_MAX - nInstBytes)
1450 0 : return -1;
1451 :
1452 505 : nInstBytes +=
1453 505 : ((HFAGetDataTypeBits(eBaseItemType) + 7) / 8) * nRows * nColumns;
1454 : }
1455 32021 : else if (poItemObjectType == nullptr)
1456 : {
1457 48214 : if (nCount != 0 &&
1458 19519 : HFADictionary::GetItemSize(chItemType) > INT_MAX / nCount)
1459 0 : return -1;
1460 28695 : if (nCount * HFADictionary::GetItemSize(chItemType) >
1461 28695 : INT_MAX - nInstBytes)
1462 0 : return -1;
1463 28695 : nInstBytes += nCount * HFADictionary::GetItemSize(chItemType);
1464 : }
1465 : else
1466 : {
1467 3326 : oVisitedFields.insert(this);
1468 5740 : for (int i = 0; i < nCount && nInstBytes < nDataSize && nInstBytes >= 0;
1469 : i++)
1470 : {
1471 2414 : const int nThisBytes = poItemObjectType->GetInstBytes(
1472 : pabyData, nDataSize - nInstBytes, oVisitedFields);
1473 2414 : if (nThisBytes <= 0 || nInstBytes > INT_MAX - nThisBytes)
1474 : {
1475 0 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid return value");
1476 0 : return -1;
1477 : }
1478 :
1479 2414 : nInstBytes += nThisBytes;
1480 2414 : pabyData += nThisBytes;
1481 : }
1482 3326 : oVisitedFields.erase(this);
1483 : }
1484 :
1485 32526 : return nInstBytes;
1486 : }
1487 :
1488 : /************************************************************************/
1489 : /* GetInstCount() */
1490 : /* */
1491 : /* Get the count for a particular instance of a field. This */
1492 : /* will normally be the built in value, but for variable fields */
1493 : /* this is extracted from the data itself. */
1494 : /************************************************************************/
1495 :
1496 46997 : int HFAField::GetInstCount(GByte *pabyData, int nDataSize) const
1497 :
1498 : {
1499 46997 : if (chPointer == '\0')
1500 27110 : return nItemCount;
1501 :
1502 19887 : if (chItemType == 'b')
1503 : {
1504 207 : if (nDataSize < 20)
1505 0 : return 0;
1506 :
1507 207 : GInt32 nRows = 0;
1508 207 : memcpy(&nRows, pabyData + 8, 4);
1509 : HFAStandard(4, &nRows);
1510 207 : GInt32 nColumns = 0;
1511 207 : memcpy(&nColumns, pabyData + 12, 4);
1512 : HFAStandard(4, &nColumns);
1513 :
1514 207 : if (nRows < 0 || nColumns < 0)
1515 0 : return 0;
1516 207 : if (nColumns != 0 && nRows > INT_MAX / nColumns)
1517 0 : return 0;
1518 :
1519 207 : return nRows * nColumns;
1520 : }
1521 :
1522 19680 : if (nDataSize < 4)
1523 0 : return 0;
1524 :
1525 19680 : GInt32 nCount = 0;
1526 19680 : memcpy(&nCount, pabyData, 4);
1527 : HFAStandard(4, &nCount);
1528 19680 : return nCount;
1529 : }
1530 :
1531 : /************************************************************************/
1532 : /* DumpInstValue() */
1533 : /************************************************************************/
1534 :
1535 0 : void HFAField::DumpInstValue(FILE *fpOut, GByte *pabyData, GUInt32 nDataOffset,
1536 : int nDataSize, const char *pszPrefix)
1537 :
1538 : {
1539 0 : const int nEntries = GetInstCount(pabyData, nDataSize);
1540 :
1541 : // Special case for arrays of chars or uchars which are printed
1542 : // as a string.
1543 0 : if ((chItemType == 'c' || chItemType == 'C') && nEntries > 0)
1544 : {
1545 0 : void *pReturn = nullptr;
1546 0 : if (ExtractInstValue(nullptr, 0, pabyData, nDataOffset, nDataSize, 's',
1547 : &pReturn))
1548 0 : CPL_IGNORE_RET_VAL(VSIFPrintf(fpOut, "%s%s = `%s'\n", pszPrefix,
1549 : pszFieldName,
1550 : static_cast<char *>(pReturn)));
1551 : else
1552 0 : CPL_IGNORE_RET_VAL(VSIFPrintf(fpOut, "%s%s = (access failed)\n",
1553 : pszPrefix, pszFieldName));
1554 :
1555 0 : return;
1556 : }
1557 :
1558 : // For BASEDATA objects, we want to first dump their dimension and type.
1559 0 : if (chItemType == 'b')
1560 : {
1561 0 : int nDataType = 0;
1562 0 : const bool bSuccess = ExtractInstValue(
1563 : nullptr, -3, pabyData, nDataOffset, nDataSize, 'i', &nDataType);
1564 0 : if (bSuccess)
1565 : {
1566 0 : int nColumns = 0;
1567 0 : ExtractInstValue(nullptr, -2, pabyData, nDataOffset, nDataSize, 'i',
1568 : &nColumns);
1569 0 : int nRows = 0;
1570 0 : ExtractInstValue(nullptr, -1, pabyData, nDataOffset, nDataSize, 'i',
1571 : &nRows);
1572 0 : CPL_IGNORE_RET_VAL(VSIFPrintf(
1573 : fpOut, "%sBASEDATA(%s): %dx%d of %s\n", pszPrefix, pszFieldName,
1574 : nColumns, nRows,
1575 0 : (nDataType >= EPT_MIN && nDataType <= EPT_MAX)
1576 0 : ? HFAGetDataTypeName(static_cast<EPTType>(nDataType))
1577 : : "invalid type"));
1578 : }
1579 : else
1580 : {
1581 0 : CPL_IGNORE_RET_VAL(VSIFPrintf(fpOut, "%sBASEDATA(%s): empty\n",
1582 : pszPrefix, pszFieldName));
1583 : }
1584 : }
1585 :
1586 : // Dump each entry in the field array.
1587 0 : void *pReturn = nullptr;
1588 :
1589 0 : const int nMaxEntry = std::min(MAX_ENTRY_REPORT, nEntries);
1590 0 : for (int iEntry = 0; iEntry < nMaxEntry; iEntry++)
1591 : {
1592 0 : if (nEntries == 1)
1593 0 : CPL_IGNORE_RET_VAL(
1594 0 : VSIFPrintf(fpOut, "%s%s = ", pszPrefix, pszFieldName));
1595 : else
1596 0 : CPL_IGNORE_RET_VAL(VSIFPrintf(fpOut, "%s%s[%d] = ", pszPrefix,
1597 : pszFieldName, iEntry));
1598 :
1599 0 : switch (chItemType)
1600 : {
1601 0 : case 'f':
1602 : case 'd':
1603 : {
1604 0 : double dfValue = 0.0;
1605 0 : if (ExtractInstValue(nullptr, iEntry, pabyData, nDataOffset,
1606 : nDataSize, 'd', &dfValue))
1607 0 : CPL_IGNORE_RET_VAL(VSIFPrintf(fpOut, "%f\n", dfValue));
1608 : else
1609 0 : CPL_IGNORE_RET_VAL(VSIFPrintf(fpOut, "(access failed)\n"));
1610 : }
1611 0 : break;
1612 :
1613 0 : case 'b':
1614 : {
1615 0 : double dfValue = 0.0;
1616 :
1617 0 : if (ExtractInstValue(nullptr, iEntry, pabyData, nDataOffset,
1618 : nDataSize, 'd', &dfValue))
1619 0 : CPL_IGNORE_RET_VAL(
1620 0 : VSIFPrintf(fpOut, "%s%.15g\n", pszPrefix, dfValue));
1621 : else
1622 0 : CPL_IGNORE_RET_VAL(
1623 0 : VSIFPrintf(fpOut, "%s(access failed)\n", pszPrefix));
1624 : }
1625 0 : break;
1626 :
1627 0 : case 'e':
1628 0 : if (ExtractInstValue(nullptr, iEntry, pabyData, nDataOffset,
1629 : nDataSize, 's', &pReturn))
1630 0 : CPL_IGNORE_RET_VAL(
1631 0 : VSIFPrintf(fpOut, "%s\n", (char *)pReturn));
1632 : else
1633 0 : CPL_IGNORE_RET_VAL(VSIFPrintf(fpOut, "(access failed)\n"));
1634 0 : break;
1635 :
1636 0 : case 'o':
1637 0 : if (!ExtractInstValue(nullptr, iEntry, pabyData, nDataOffset,
1638 : nDataSize, 'p', &pReturn))
1639 : {
1640 0 : CPL_IGNORE_RET_VAL(VSIFPrintf(fpOut, "(access failed)\n"));
1641 : }
1642 : else
1643 : {
1644 0 : CPL_IGNORE_RET_VAL(VSIFPrintf(fpOut, "\n"));
1645 :
1646 0 : const int nByteOffset =
1647 0 : static_cast<int>(((GByte *)pReturn) - pabyData);
1648 :
1649 0 : char szLongFieldName[256] = {};
1650 0 : snprintf(szLongFieldName, sizeof(szLongFieldName), "%s ",
1651 : pszPrefix);
1652 :
1653 0 : if (poItemObjectType)
1654 0 : poItemObjectType->DumpInstValue(
1655 0 : fpOut, pabyData + nByteOffset,
1656 0 : nDataOffset + nByteOffset, nDataSize - nByteOffset,
1657 : szLongFieldName);
1658 : }
1659 0 : break;
1660 :
1661 0 : default:
1662 : {
1663 0 : GInt32 nIntValue = 0;
1664 :
1665 0 : if (ExtractInstValue(nullptr, iEntry, pabyData, nDataOffset,
1666 : nDataSize, 'i', &nIntValue))
1667 0 : CPL_IGNORE_RET_VAL(VSIFPrintf(fpOut, "%d\n", nIntValue));
1668 : else
1669 0 : CPL_IGNORE_RET_VAL(VSIFPrintf(fpOut, "(access failed)\n"));
1670 : }
1671 0 : break;
1672 : }
1673 : }
1674 :
1675 0 : if (nEntries > MAX_ENTRY_REPORT)
1676 0 : CPL_IGNORE_RET_VAL(VSIFPrintf(
1677 : fpOut, "%s ... remaining instances omitted ...\n", pszPrefix));
1678 :
1679 0 : if (nEntries == 0)
1680 0 : CPL_IGNORE_RET_VAL(
1681 0 : VSIFPrintf(fpOut, "%s%s = (no values)\n", pszPrefix, pszFieldName));
1682 : }
|