Coverage Report

Created: 2025-06-09 08:44

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