Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: Erdas Imagine (.img) Translator
4 : * Purpose: Implementation of the HFAType class, for managing one type
5 : * defined in the HFA data dictionary. Managed by HFADictionary.
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 <climits>
19 : #include <cstdio>
20 : #include <cstdlib>
21 : #include <cstring>
22 :
23 : #include "cpl_conv.h"
24 : #include "cpl_error.h"
25 : #include "cpl_vsi.h"
26 :
27 : /************************************************************************/
28 : /* ==================================================================== */
29 : /* HFAType */
30 : /* ==================================================================== */
31 : /************************************************************************/
32 :
33 : /************************************************************************/
34 : /* HFAType() */
35 : /************************************************************************/
36 :
37 27396 : HFAType::HFAType() : bInCompleteDefn(false), nBytes(0), pszTypeName(nullptr)
38 : {
39 27396 : }
40 :
41 : /************************************************************************/
42 : /* ~HFAType() */
43 : /************************************************************************/
44 :
45 27396 : HFAType::~HFAType()
46 :
47 : {
48 27396 : CPLFree(pszTypeName);
49 27396 : }
50 :
51 : /************************************************************************/
52 : /* Initialize() */
53 : /************************************************************************/
54 :
55 27396 : const char *HFAType::Initialize(const char *pszInput)
56 :
57 : {
58 27396 : if (*pszInput != '{')
59 : {
60 1 : if (*pszInput != '\0')
61 1 : CPLDebug("HFAType", "Initialize(%60.60s) - unexpected input.",
62 : pszInput);
63 :
64 26 : while (*pszInput != '{' && *pszInput != '\0')
65 25 : pszInput++;
66 :
67 1 : if (*pszInput == '\0')
68 0 : return nullptr;
69 : }
70 :
71 27396 : pszInput++;
72 :
73 : // Read the field definitions.
74 130917 : while (pszInput != nullptr && *pszInput != '}')
75 : {
76 207042 : auto poNewField = std::make_unique<HFAField>();
77 :
78 103521 : pszInput = poNewField->Initialize(pszInput);
79 103521 : if (pszInput != nullptr)
80 : {
81 103520 : apoFields.emplace_back(std::move(poNewField));
82 : }
83 : }
84 :
85 27396 : if (pszInput == nullptr)
86 1 : return nullptr;
87 :
88 : // Collect the name.
89 27395 : pszInput++; // Skip `}'
90 27395 : int i = 0; // Used after for.
91 450530 : for (; pszInput[i] != '\0' && pszInput[i] != ','; i++)
92 : {
93 : }
94 27395 : if (pszInput[i] == '\0')
95 : {
96 6 : pszTypeName = CPLStrdup(pszInput);
97 6 : return nullptr;
98 : }
99 :
100 27389 : pszTypeName = static_cast<char *>(CPLMalloc(i + 1));
101 27389 : strncpy(pszTypeName, pszInput, i);
102 27389 : pszTypeName[i] = '\0';
103 :
104 27389 : pszInput += i + 1;
105 :
106 27389 : return pszInput;
107 : }
108 :
109 : /************************************************************************/
110 : /* CompleteDefn() */
111 : /************************************************************************/
112 :
113 38945 : bool HFAType::CompleteDefn(HFADictionary *poDict)
114 :
115 : {
116 : // This may already be done, if an earlier object required this
117 : // object (as a field), and forced an early computation of the size.
118 38945 : if (nBytes != 0)
119 11548 : return true;
120 :
121 27397 : if (bInCompleteDefn)
122 : {
123 2 : CPLError(CE_Failure, CPLE_AppDefined,
124 : "Recursion detected in HFAType::CompleteDefn()");
125 2 : return false;
126 : }
127 27395 : bInCompleteDefn = true;
128 :
129 : // Complete each of the fields, totaling up the sizes. This
130 : // isn't really accurate for object with variable sized subobjects.
131 27395 : bool bRet = true;
132 130907 : for (auto &poField : apoFields)
133 : {
134 103514 : if (!poField->CompleteDefn(poDict))
135 : {
136 2 : bRet = false;
137 2 : break;
138 : }
139 103512 : if (poField->nBytes < 0 || nBytes == -1)
140 44613 : nBytes = -1;
141 58899 : else if (nBytes < INT_MAX - poField->nBytes)
142 58899 : nBytes += poField->nBytes;
143 : else
144 0 : nBytes = -1;
145 : }
146 :
147 27395 : bInCompleteDefn = false;
148 27395 : return bRet;
149 : }
150 :
151 : /************************************************************************/
152 : /* Dump() */
153 : /************************************************************************/
154 :
155 0 : void HFAType::Dump(FILE *fp)
156 :
157 : {
158 0 : CPL_IGNORE_RET_VAL(
159 0 : VSIFPrintf(fp, "HFAType %s/%d bytes\n", pszTypeName, nBytes));
160 :
161 0 : for (auto &poField : apoFields)
162 : {
163 0 : poField->Dump(fp);
164 : }
165 :
166 0 : CPL_IGNORE_RET_VAL(VSIFPrintf(fp, "\n"));
167 0 : }
168 :
169 : /************************************************************************/
170 : /* SetInstValue() */
171 : /************************************************************************/
172 :
173 14312 : CPLErr HFAType::SetInstValue(const char *pszFieldPath, GByte *pabyData,
174 : GUInt32 nDataOffset, int nDataSize, char chReqType,
175 : void *pValue)
176 :
177 : {
178 14312 : int nArrayIndex = 0;
179 14312 : int nNameLen = 0;
180 14312 : const char *pszRemainder = nullptr;
181 :
182 : // Parse end of field name, possible index value and
183 : // establish where the remaining fields (if any) would start.
184 14312 : if (strchr(pszFieldPath, '[') != nullptr)
185 : {
186 3809 : const char *pszEnd = strchr(pszFieldPath, '[');
187 :
188 3809 : nArrayIndex = atoi(pszEnd + 1);
189 3809 : nNameLen = static_cast<int>(pszEnd - pszFieldPath);
190 :
191 3809 : pszRemainder = strchr(pszFieldPath, '.');
192 3809 : if (pszRemainder != nullptr)
193 151 : pszRemainder++;
194 : }
195 10503 : else if (strchr(pszFieldPath, '.') != nullptr)
196 : {
197 2740 : const char *pszEnd = strchr(pszFieldPath, '.');
198 :
199 2740 : nNameLen = static_cast<int>(pszEnd - pszFieldPath);
200 :
201 2740 : pszRemainder = pszEnd + 1;
202 : }
203 : else
204 : {
205 7763 : nNameLen = static_cast<int>(strlen(pszFieldPath));
206 7763 : pszRemainder = pszFieldPath /* NULL */;
207 : }
208 :
209 : // Find this field within this type, if possible.
210 14312 : int nByteOffset = 0;
211 14312 : size_t iField = 0;
212 14312 : const size_t nFields = apoFields.size();
213 48552 : for (; iField < nFields && nByteOffset < nDataSize; iField++)
214 : {
215 62828 : if (EQUALN(pszFieldPath, apoFields[iField]->pszFieldName, nNameLen) &&
216 14312 : apoFields[iField]->pszFieldName[nNameLen] == '\0')
217 : {
218 14276 : break;
219 : }
220 :
221 34240 : std::set<HFAField *> oVisitedFields;
222 34240 : const int nInc = apoFields[iField]->GetInstBytes(
223 34240 : pabyData + nByteOffset, nDataSize - nByteOffset, oVisitedFields);
224 :
225 34240 : if (nInc <= 0 || nByteOffset > INT_MAX - nInc)
226 : {
227 0 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid return value");
228 0 : return CE_Failure;
229 : }
230 :
231 34240 : nByteOffset += nInc;
232 : }
233 :
234 14312 : if (iField == nFields || nByteOffset >= nDataSize)
235 36 : return CE_Failure;
236 :
237 : // Extract this field value, and return.
238 14276 : return apoFields[iField]->SetInstValue(
239 14276 : pszRemainder, nArrayIndex, pabyData + nByteOffset,
240 14276 : nDataOffset + nByteOffset, nDataSize - nByteOffset, chReqType, pValue);
241 : }
242 :
243 : /************************************************************************/
244 : /* GetInstCount() */
245 : /************************************************************************/
246 :
247 898 : int HFAType::GetInstCount(const char *pszFieldPath, GByte *pabyData,
248 : GUInt32 /* nDataOffset */, int nDataSize)
249 : {
250 : // int nArrayIndex = 0;
251 898 : int nNameLen = 0;
252 : // const char *pszRemainder;
253 :
254 : // Parse end of field name, possible index value and
255 : // establish where the remaining fields (if any) would start.
256 898 : if (strchr(pszFieldPath, '[') != nullptr)
257 : {
258 0 : const char *pszEnd = strchr(pszFieldPath, '[');
259 :
260 : // nArrayIndex = atoi(pszEnd+1);
261 0 : nNameLen = static_cast<int>(pszEnd - pszFieldPath);
262 :
263 : // pszRemainder = strchr(pszFieldPath, '.');
264 : // if( pszRemainder != NULL )
265 : // pszRemainder++;
266 : }
267 898 : else if (strchr(pszFieldPath, '.') != nullptr)
268 : {
269 210 : const char *pszEnd = strchr(pszFieldPath, '.');
270 :
271 210 : nNameLen = static_cast<int>(pszEnd - pszFieldPath);
272 :
273 : // pszRemainder = pszEnd + 1;
274 : }
275 : else
276 : {
277 688 : nNameLen = static_cast<int>(strlen(pszFieldPath));
278 : // pszRemainder = NULL;
279 : }
280 :
281 : // Find this field within this type, if possible.
282 898 : int nByteOffset = 0;
283 898 : size_t iField = 0;
284 898 : const size_t nFields = apoFields.size();
285 3686 : for (; iField < nFields && nByteOffset < nDataSize; iField++)
286 : {
287 4584 : if (EQUALN(pszFieldPath, apoFields[iField]->pszFieldName, nNameLen) &&
288 898 : apoFields[iField]->pszFieldName[nNameLen] == '\0')
289 : {
290 898 : break;
291 : }
292 :
293 2788 : std::set<HFAField *> oVisitedFields;
294 2788 : const int nInc = apoFields[iField]->GetInstBytes(
295 2788 : pabyData + nByteOffset, nDataSize - nByteOffset, oVisitedFields);
296 :
297 2788 : if (nInc <= 0 || nByteOffset > INT_MAX - nInc)
298 : {
299 0 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid return value");
300 0 : return -1;
301 : }
302 :
303 2788 : nByteOffset += nInc;
304 : }
305 :
306 898 : if (iField == nFields || nByteOffset >= nDataSize)
307 0 : return -1;
308 :
309 : // Extract this field value, and return.
310 898 : return apoFields[iField]->GetInstCount(pabyData + nByteOffset,
311 898 : nDataSize - nByteOffset);
312 : }
313 :
314 : /************************************************************************/
315 : /* ExtractInstValue() */
316 : /* */
317 : /* Extract the value of a field instance within this type. */
318 : /* Most of the work is done by the ExtractInstValue() for the */
319 : /* HFAField, but this method does the field name parsing. */
320 : /* */
321 : /* field names have the form: */
322 : /* */
323 : /* fieldname{[index]}{.fieldname...} */
324 : /* */
325 : /* eg. */
326 : /* abc - field abc[0] */
327 : /* abc[3] - field abc[3] */
328 : /* abc[2].def - field def[0] of */
329 : /* the third abc struct. */
330 : /************************************************************************/
331 :
332 46060 : bool HFAType::ExtractInstValue(const char *pszFieldPath, GByte *pabyData,
333 : GUInt32 nDataOffset, int nDataSize,
334 : char chReqType, void *pReqReturn,
335 : int *pnRemainingDataSize)
336 :
337 : {
338 46060 : int nArrayIndex = 0;
339 46060 : int nNameLen = 0;
340 46060 : const char *pszRemainder = nullptr;
341 :
342 : // Parse end of field name, possible index value and
343 : // establish where the remaining fields (if any) would start.
344 46060 : const char *pszFirstArray = strchr(pszFieldPath, '[');
345 46060 : const char *pszFirstDot = strchr(pszFieldPath, '.');
346 :
347 46060 : if (pszFirstArray != nullptr &&
348 10208 : (pszFirstDot == nullptr || pszFirstDot > pszFirstArray))
349 : {
350 15415 : const char *pszEnd = pszFirstArray;
351 :
352 15415 : nArrayIndex = atoi(pszEnd + 1);
353 15415 : nNameLen = static_cast<int>(pszEnd - pszFieldPath);
354 :
355 15415 : pszRemainder = strchr(pszFieldPath, '.');
356 15415 : if (pszRemainder != nullptr)
357 15415 : pszRemainder++;
358 : }
359 30645 : else if (pszFirstDot != nullptr)
360 : {
361 4030 : const char *pszEnd = pszFirstDot;
362 :
363 4030 : nNameLen = static_cast<int>(pszEnd - pszFieldPath);
364 :
365 4030 : pszRemainder = pszEnd + 1;
366 : }
367 : else
368 : {
369 26615 : nNameLen = static_cast<int>(strlen(pszFieldPath));
370 26615 : pszRemainder = nullptr;
371 : }
372 :
373 : // Find this field within this type, if possible.
374 46060 : int nByteOffset = 0;
375 46060 : size_t iField = 0;
376 46060 : const size_t nFields = apoFields.size();
377 171695 : for (; iField < nFields && nByteOffset < nDataSize; iField++)
378 : {
379 217675 : if (EQUALN(pszFieldPath, apoFields[iField]->pszFieldName, nNameLen) &&
380 46020 : apoFields[iField]->pszFieldName[nNameLen] == '\0')
381 : {
382 46020 : break;
383 : }
384 :
385 125635 : std::set<HFAField *> oVisitedFields;
386 125635 : const int nInc = apoFields[iField]->GetInstBytes(
387 125635 : pabyData + nByteOffset, nDataSize - nByteOffset, oVisitedFields);
388 :
389 125635 : if (nInc <= 0 || nByteOffset > INT_MAX - nInc)
390 : {
391 0 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid return value");
392 0 : return false;
393 : }
394 :
395 125635 : nByteOffset += nInc;
396 : }
397 :
398 46060 : if (iField == nFields || nByteOffset >= nDataSize)
399 40 : return false;
400 :
401 : // Extract this field value, and return.
402 46020 : return apoFields[iField]->ExtractInstValue(
403 46020 : pszRemainder, nArrayIndex, pabyData + nByteOffset,
404 46020 : nDataOffset + nByteOffset, nDataSize - nByteOffset, chReqType,
405 46020 : pReqReturn, pnRemainingDataSize);
406 : }
407 :
408 : /************************************************************************/
409 : /* DumpInstValue() */
410 : /************************************************************************/
411 :
412 0 : void HFAType::DumpInstValue(FILE *fpOut, GByte *pabyData, GUInt32 nDataOffset,
413 : int nDataSize, const char *pszPrefix) const
414 :
415 : {
416 0 : const size_t nFields = apoFields.size();
417 0 : for (size_t iField = 0; iField < nFields && nDataSize > 0; iField++)
418 : {
419 0 : auto &poField = apoFields[iField];
420 :
421 0 : poField->DumpInstValue(fpOut, pabyData, nDataOffset, nDataSize,
422 : pszPrefix);
423 :
424 0 : std::set<HFAField *> oVisitedFields;
425 : const int nInstBytes =
426 0 : poField->GetInstBytes(pabyData, nDataSize, oVisitedFields);
427 0 : if (nInstBytes <= 0 || nDataOffset > UINT_MAX - nInstBytes)
428 : {
429 0 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid return value");
430 0 : return;
431 : }
432 :
433 0 : pabyData += nInstBytes;
434 0 : nDataOffset += nInstBytes;
435 0 : nDataSize -= nInstBytes;
436 : }
437 : }
438 :
439 : /************************************************************************/
440 : /* GetInstBytes() */
441 : /* */
442 : /* How many bytes in this particular instance of this type? */
443 : /************************************************************************/
444 :
445 2463 : int HFAType::GetInstBytes(GByte *pabyData, int nDataSize,
446 : std::set<HFAField *> &oVisitedFields) const
447 :
448 : {
449 2463 : if (nBytes >= 0)
450 0 : return nBytes;
451 :
452 2463 : int nTotal = 0;
453 2463 : const size_t nFields = apoFields.size();
454 5538 : for (size_t iField = 0; iField < nFields && nTotal < nDataSize; iField++)
455 : {
456 3075 : auto &poField = apoFields[iField];
457 :
458 : const int nInstBytes =
459 3075 : poField->GetInstBytes(pabyData, nDataSize - nTotal, oVisitedFields);
460 3075 : if (nInstBytes <= 0 || nTotal > INT_MAX - nInstBytes)
461 : {
462 0 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid return value");
463 0 : return -1;
464 : }
465 :
466 3075 : pabyData += nInstBytes;
467 3075 : nTotal += nInstBytes;
468 : }
469 :
470 2463 : return nTotal;
471 : }
|