/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 | } |