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 : * Permission is hereby granted, free of charge, to any person obtaining a
13 : * copy of this software and associated documentation files (the "Software"),
14 : * to deal in the Software without restriction, including without limitation
15 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 : * and/or sell copies of the Software, and to permit persons to whom the
17 : * Software is furnished to do so, subject to the following conditions:
18 : *
19 : * The above copyright notice and this permission notice shall be included
20 : * in all copies or substantial portions of the Software.
21 : *
22 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 : * DEALINGS IN THE SOFTWARE.
29 : ****************************************************************************/
30 :
31 : #include "cpl_port.h"
32 : #include "hfa_p.h"
33 :
34 : #include <climits>
35 : #include <cstdio>
36 : #include <cstdlib>
37 : #include <cstring>
38 :
39 : #include "cpl_conv.h"
40 : #include "cpl_error.h"
41 : #include "cpl_vsi.h"
42 :
43 : /************************************************************************/
44 : /* ==================================================================== */
45 : /* HFAType */
46 : /* ==================================================================== */
47 : /************************************************************************/
48 :
49 : /************************************************************************/
50 : /* HFAType() */
51 : /************************************************************************/
52 :
53 27361 : HFAType::HFAType() : bInCompleteDefn(false), nBytes(0), pszTypeName(nullptr)
54 : {
55 27361 : }
56 :
57 : /************************************************************************/
58 : /* ~HFAType() */
59 : /************************************************************************/
60 :
61 27361 : HFAType::~HFAType()
62 :
63 : {
64 27361 : CPLFree(pszTypeName);
65 27361 : }
66 :
67 : /************************************************************************/
68 : /* Initialize() */
69 : /************************************************************************/
70 :
71 27361 : const char *HFAType::Initialize(const char *pszInput)
72 :
73 : {
74 27361 : if (*pszInput != '{')
75 : {
76 1 : if (*pszInput != '\0')
77 1 : CPLDebug("HFAType", "Initialize(%60.60s) - unexpected input.",
78 : pszInput);
79 :
80 26 : while (*pszInput != '{' && *pszInput != '\0')
81 25 : pszInput++;
82 :
83 1 : if (*pszInput == '\0')
84 0 : return nullptr;
85 : }
86 :
87 27361 : pszInput++;
88 :
89 : // Read the field definitions.
90 130766 : while (pszInput != nullptr && *pszInput != '}')
91 : {
92 206810 : auto poNewField = std::make_unique<HFAField>();
93 :
94 103405 : pszInput = poNewField->Initialize(pszInput);
95 103405 : if (pszInput != nullptr)
96 : {
97 103404 : apoFields.emplace_back(std::move(poNewField));
98 : }
99 : }
100 :
101 27361 : if (pszInput == nullptr)
102 1 : return nullptr;
103 :
104 : // Collect the name.
105 27360 : pszInput++; // Skip `}'
106 27360 : int i = 0; // Used after for.
107 449962 : for (; pszInput[i] != '\0' && pszInput[i] != ','; i++)
108 : {
109 : }
110 27360 : if (pszInput[i] == '\0')
111 : {
112 6 : pszTypeName = CPLStrdup(pszInput);
113 6 : return nullptr;
114 : }
115 :
116 27354 : pszTypeName = static_cast<char *>(CPLMalloc(i + 1));
117 27354 : strncpy(pszTypeName, pszInput, i);
118 27354 : pszTypeName[i] = '\0';
119 :
120 27354 : pszInput += i + 1;
121 :
122 27354 : return pszInput;
123 : }
124 :
125 : /************************************************************************/
126 : /* CompleteDefn() */
127 : /************************************************************************/
128 :
129 38893 : bool HFAType::CompleteDefn(HFADictionary *poDict)
130 :
131 : {
132 : // This may already be done, if an earlier object required this
133 : // object (as a field), and forced an early computation of the size.
134 38893 : if (nBytes != 0)
135 11531 : return true;
136 :
137 27362 : if (bInCompleteDefn)
138 : {
139 2 : CPLError(CE_Failure, CPLE_AppDefined,
140 : "Recursion detected in HFAType::CompleteDefn()");
141 2 : return false;
142 : }
143 27360 : bInCompleteDefn = true;
144 :
145 : // Complete each of the fields, totaling up the sizes. This
146 : // isn't really accurate for object with variable sized subobjects.
147 27360 : bool bRet = true;
148 130756 : for (auto &poField : apoFields)
149 : {
150 103398 : if (!poField->CompleteDefn(poDict))
151 : {
152 2 : bRet = false;
153 2 : break;
154 : }
155 103396 : if (poField->nBytes < 0 || nBytes == -1)
156 44576 : nBytes = -1;
157 58820 : else if (nBytes < INT_MAX - poField->nBytes)
158 58820 : nBytes += poField->nBytes;
159 : else
160 0 : nBytes = -1;
161 : }
162 :
163 27360 : bInCompleteDefn = false;
164 27360 : return bRet;
165 : }
166 :
167 : /************************************************************************/
168 : /* Dump() */
169 : /************************************************************************/
170 :
171 0 : void HFAType::Dump(FILE *fp)
172 :
173 : {
174 0 : CPL_IGNORE_RET_VAL(
175 0 : VSIFPrintf(fp, "HFAType %s/%d bytes\n", pszTypeName, nBytes));
176 :
177 0 : for (auto &poField : apoFields)
178 : {
179 0 : poField->Dump(fp);
180 : }
181 :
182 0 : CPL_IGNORE_RET_VAL(VSIFPrintf(fp, "\n"));
183 0 : }
184 :
185 : /************************************************************************/
186 : /* SetInstValue() */
187 : /************************************************************************/
188 :
189 14312 : CPLErr HFAType::SetInstValue(const char *pszFieldPath, GByte *pabyData,
190 : GUInt32 nDataOffset, int nDataSize, char chReqType,
191 : void *pValue)
192 :
193 : {
194 14312 : int nArrayIndex = 0;
195 14312 : int nNameLen = 0;
196 14312 : const char *pszRemainder = nullptr;
197 :
198 : // Parse end of field name, possible index value and
199 : // establish where the remaining fields (if any) would start.
200 14312 : if (strchr(pszFieldPath, '[') != nullptr)
201 : {
202 3809 : const char *pszEnd = strchr(pszFieldPath, '[');
203 :
204 3809 : nArrayIndex = atoi(pszEnd + 1);
205 3809 : nNameLen = static_cast<int>(pszEnd - pszFieldPath);
206 :
207 3809 : pszRemainder = strchr(pszFieldPath, '.');
208 3809 : if (pszRemainder != nullptr)
209 151 : pszRemainder++;
210 : }
211 10503 : else if (strchr(pszFieldPath, '.') != nullptr)
212 : {
213 2740 : const char *pszEnd = strchr(pszFieldPath, '.');
214 :
215 2740 : nNameLen = static_cast<int>(pszEnd - pszFieldPath);
216 :
217 2740 : pszRemainder = pszEnd + 1;
218 : }
219 : else
220 : {
221 7763 : nNameLen = static_cast<int>(strlen(pszFieldPath));
222 7763 : pszRemainder = pszFieldPath /* NULL */;
223 : }
224 :
225 : // Find this field within this type, if possible.
226 14312 : int nByteOffset = 0;
227 14312 : size_t iField = 0;
228 14312 : const size_t nFields = apoFields.size();
229 48552 : for (; iField < nFields && nByteOffset < nDataSize; iField++)
230 : {
231 62828 : if (EQUALN(pszFieldPath, apoFields[iField]->pszFieldName, nNameLen) &&
232 14312 : apoFields[iField]->pszFieldName[nNameLen] == '\0')
233 : {
234 14276 : break;
235 : }
236 :
237 34240 : std::set<HFAField *> oVisitedFields;
238 34240 : const int nInc = apoFields[iField]->GetInstBytes(
239 34240 : pabyData + nByteOffset, nDataSize - nByteOffset, oVisitedFields);
240 :
241 34240 : if (nInc <= 0 || nByteOffset > INT_MAX - nInc)
242 : {
243 0 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid return value");
244 0 : return CE_Failure;
245 : }
246 :
247 34240 : nByteOffset += nInc;
248 : }
249 :
250 14312 : if (iField == nFields || nByteOffset >= nDataSize)
251 36 : return CE_Failure;
252 :
253 : // Extract this field value, and return.
254 14276 : return apoFields[iField]->SetInstValue(
255 14276 : pszRemainder, nArrayIndex, pabyData + nByteOffset,
256 14276 : nDataOffset + nByteOffset, nDataSize - nByteOffset, chReqType, pValue);
257 : }
258 :
259 : /************************************************************************/
260 : /* GetInstCount() */
261 : /************************************************************************/
262 :
263 886 : int HFAType::GetInstCount(const char *pszFieldPath, GByte *pabyData,
264 : GUInt32 /* nDataOffset */, int nDataSize)
265 : {
266 : // int nArrayIndex = 0;
267 886 : int nNameLen = 0;
268 : // const char *pszRemainder;
269 :
270 : // Parse end of field name, possible index value and
271 : // establish where the remaining fields (if any) would start.
272 886 : if (strchr(pszFieldPath, '[') != nullptr)
273 : {
274 0 : const char *pszEnd = strchr(pszFieldPath, '[');
275 :
276 : // nArrayIndex = atoi(pszEnd+1);
277 0 : nNameLen = static_cast<int>(pszEnd - pszFieldPath);
278 :
279 : // pszRemainder = strchr(pszFieldPath, '.');
280 : // if( pszRemainder != NULL )
281 : // pszRemainder++;
282 : }
283 886 : else if (strchr(pszFieldPath, '.') != nullptr)
284 : {
285 207 : const char *pszEnd = strchr(pszFieldPath, '.');
286 :
287 207 : nNameLen = static_cast<int>(pszEnd - pszFieldPath);
288 :
289 : // pszRemainder = pszEnd + 1;
290 : }
291 : else
292 : {
293 679 : nNameLen = static_cast<int>(strlen(pszFieldPath));
294 : // pszRemainder = NULL;
295 : }
296 :
297 : // Find this field within this type, if possible.
298 886 : int nByteOffset = 0;
299 886 : size_t iField = 0;
300 886 : const size_t nFields = apoFields.size();
301 3636 : for (; iField < nFields && nByteOffset < nDataSize; iField++)
302 : {
303 4522 : if (EQUALN(pszFieldPath, apoFields[iField]->pszFieldName, nNameLen) &&
304 886 : apoFields[iField]->pszFieldName[nNameLen] == '\0')
305 : {
306 886 : break;
307 : }
308 :
309 2750 : std::set<HFAField *> oVisitedFields;
310 2750 : const int nInc = apoFields[iField]->GetInstBytes(
311 2750 : pabyData + nByteOffset, nDataSize - nByteOffset, oVisitedFields);
312 :
313 2750 : if (nInc <= 0 || nByteOffset > INT_MAX - nInc)
314 : {
315 0 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid return value");
316 0 : return -1;
317 : }
318 :
319 2750 : nByteOffset += nInc;
320 : }
321 :
322 886 : if (iField == nFields || nByteOffset >= nDataSize)
323 0 : return -1;
324 :
325 : // Extract this field value, and return.
326 886 : return apoFields[iField]->GetInstCount(pabyData + nByteOffset,
327 886 : nDataSize - nByteOffset);
328 : }
329 :
330 : /************************************************************************/
331 : /* ExtractInstValue() */
332 : /* */
333 : /* Extract the value of a field instance within this type. */
334 : /* Most of the work is done by the ExtractInstValue() for the */
335 : /* HFAField, but this method does the field name parsing. */
336 : /* */
337 : /* field names have the form: */
338 : /* */
339 : /* fieldname{[index]}{.fieldname...} */
340 : /* */
341 : /* eg. */
342 : /* abc - field abc[0] */
343 : /* abc[3] - field abc[3] */
344 : /* abc[2].def - field def[0] of */
345 : /* the third abc struct. */
346 : /************************************************************************/
347 :
348 46148 : bool HFAType::ExtractInstValue(const char *pszFieldPath, GByte *pabyData,
349 : GUInt32 nDataOffset, int nDataSize,
350 : char chReqType, void *pReqReturn,
351 : int *pnRemainingDataSize)
352 :
353 : {
354 46148 : int nArrayIndex = 0;
355 46148 : int nNameLen = 0;
356 46148 : const char *pszRemainder = nullptr;
357 :
358 : // Parse end of field name, possible index value and
359 : // establish where the remaining fields (if any) would start.
360 46148 : const char *pszFirstArray = strchr(pszFieldPath, '[');
361 46148 : const char *pszFirstDot = strchr(pszFieldPath, '.');
362 :
363 46148 : if (pszFirstArray != nullptr &&
364 10205 : (pszFirstDot == nullptr || pszFirstDot > pszFirstArray))
365 : {
366 15403 : const char *pszEnd = pszFirstArray;
367 :
368 15403 : nArrayIndex = atoi(pszEnd + 1);
369 15403 : nNameLen = static_cast<int>(pszEnd - pszFieldPath);
370 :
371 15403 : pszRemainder = strchr(pszFieldPath, '.');
372 15403 : if (pszRemainder != nullptr)
373 15403 : pszRemainder++;
374 : }
375 30745 : else if (pszFirstDot != nullptr)
376 : {
377 4112 : const char *pszEnd = pszFirstDot;
378 :
379 4112 : nNameLen = static_cast<int>(pszEnd - pszFieldPath);
380 :
381 4112 : pszRemainder = pszEnd + 1;
382 : }
383 : else
384 : {
385 26633 : nNameLen = static_cast<int>(strlen(pszFieldPath));
386 26633 : pszRemainder = nullptr;
387 : }
388 :
389 : // Find this field within this type, if possible.
390 46148 : int nByteOffset = 0;
391 46148 : size_t iField = 0;
392 46148 : const size_t nFields = apoFields.size();
393 171670 : for (; iField < nFields && nByteOffset < nDataSize; iField++)
394 : {
395 217744 : if (EQUALN(pszFieldPath, apoFields[iField]->pszFieldName, nNameLen) &&
396 46111 : apoFields[iField]->pszFieldName[nNameLen] == '\0')
397 : {
398 46111 : break;
399 : }
400 :
401 125522 : std::set<HFAField *> oVisitedFields;
402 125522 : const int nInc = apoFields[iField]->GetInstBytes(
403 125522 : pabyData + nByteOffset, nDataSize - nByteOffset, oVisitedFields);
404 :
405 125522 : if (nInc <= 0 || nByteOffset > INT_MAX - nInc)
406 : {
407 0 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid return value");
408 0 : return false;
409 : }
410 :
411 125522 : nByteOffset += nInc;
412 : }
413 :
414 46148 : if (iField == nFields || nByteOffset >= nDataSize)
415 37 : return false;
416 :
417 : // Extract this field value, and return.
418 46111 : return apoFields[iField]->ExtractInstValue(
419 46111 : pszRemainder, nArrayIndex, pabyData + nByteOffset,
420 46111 : nDataOffset + nByteOffset, nDataSize - nByteOffset, chReqType,
421 46111 : pReqReturn, pnRemainingDataSize);
422 : }
423 :
424 : /************************************************************************/
425 : /* DumpInstValue() */
426 : /************************************************************************/
427 :
428 0 : void HFAType::DumpInstValue(FILE *fpOut, GByte *pabyData, GUInt32 nDataOffset,
429 : int nDataSize, const char *pszPrefix) const
430 :
431 : {
432 0 : const size_t nFields = apoFields.size();
433 0 : for (size_t iField = 0; iField < nFields && nDataSize > 0; iField++)
434 : {
435 0 : auto &poField = apoFields[iField];
436 :
437 0 : poField->DumpInstValue(fpOut, pabyData, nDataOffset, nDataSize,
438 : pszPrefix);
439 :
440 0 : std::set<HFAField *> oVisitedFields;
441 : const int nInstBytes =
442 0 : poField->GetInstBytes(pabyData, nDataSize, oVisitedFields);
443 0 : if (nInstBytes <= 0 || nDataOffset > UINT_MAX - nInstBytes)
444 : {
445 0 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid return value");
446 0 : return;
447 : }
448 :
449 0 : pabyData += nInstBytes;
450 0 : nDataOffset += nInstBytes;
451 0 : nDataSize -= nInstBytes;
452 : }
453 : }
454 :
455 : /************************************************************************/
456 : /* GetInstBytes() */
457 : /* */
458 : /* How many bytes in this particular instance of this type? */
459 : /************************************************************************/
460 :
461 2444 : int HFAType::GetInstBytes(GByte *pabyData, int nDataSize,
462 : std::set<HFAField *> &oVisitedFields) const
463 :
464 : {
465 2444 : if (nBytes >= 0)
466 0 : return nBytes;
467 :
468 2444 : int nTotal = 0;
469 2444 : const size_t nFields = apoFields.size();
470 5500 : for (size_t iField = 0; iField < nFields && nTotal < nDataSize; iField++)
471 : {
472 3056 : auto &poField = apoFields[iField];
473 :
474 : const int nInstBytes =
475 3056 : poField->GetInstBytes(pabyData, nDataSize - nTotal, oVisitedFields);
476 3056 : if (nInstBytes <= 0 || nTotal > INT_MAX - nInstBytes)
477 : {
478 0 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid return value");
479 0 : return -1;
480 : }
481 :
482 3056 : pabyData += nInstBytes;
483 3056 : nTotal += nInstBytes;
484 : }
485 :
486 2444 : return nTotal;
487 : }
|