1 : /******************************************************************************
2 : * $Id: hfatype.cpp 23495 2011-12-08 00:16:33Z rouault $
3 : *
4 : * Project: Erdas Imagine (.img) Translator
5 : * Purpose: Implementation of the HFAType class, for managing one type
6 : * defined in the HFA data dictionary. Managed by HFADictionary.
7 : * Author: Frank Warmerdam, warmerdam@pobox.com
8 : *
9 : ******************************************************************************
10 : * Copyright (c) 1999, Intergraph Corporation
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 "hfa_p.h"
32 :
33 : CPL_CVSID("$Id: hfatype.cpp 23495 2011-12-08 00:16:33Z rouault $");
34 :
35 : /************************************************************************/
36 : /* ==================================================================== */
37 : /* HFAType */
38 : /* ==================================================================== */
39 : /************************************************************************/
40 :
41 : /************************************************************************/
42 : /* HFAType() */
43 : /************************************************************************/
44 :
45 19941 : HFAType::HFAType()
46 :
47 : {
48 19941 : nBytes = 0;
49 19941 : nFields = 0;
50 19941 : papoFields = NULL;
51 19941 : pszTypeName = NULL;
52 19941 : bInCompleteDefn = FALSE;
53 19941 : }
54 :
55 : /************************************************************************/
56 : /* ~HFAType() */
57 : /************************************************************************/
58 :
59 19941 : HFAType::~HFAType()
60 :
61 : {
62 : int i;
63 :
64 95533 : for( i = 0; i < nFields; i++ )
65 : {
66 75592 : delete papoFields[i];
67 : }
68 :
69 19941 : CPLFree( papoFields );
70 :
71 19941 : CPLFree( pszTypeName );
72 19941 : }
73 :
74 : /************************************************************************/
75 : /* Initialize() */
76 : /************************************************************************/
77 :
78 19941 : const char *HFAType::Initialize( const char * pszInput )
79 :
80 : {
81 : int i;
82 :
83 :
84 19941 : if( *pszInput != '{' )
85 : {
86 0 : if( *pszInput != '\0' )
87 : CPLDebug( "HFAType", "Initialize(%60.60s) - unexpected input.",
88 0 : pszInput );
89 :
90 0 : while( *pszInput != '{' && *pszInput != '\0' )
91 0 : pszInput++;
92 :
93 0 : if( *pszInput == '\0' )
94 0 : return NULL;
95 : }
96 :
97 19941 : pszInput++;
98 :
99 : /* -------------------------------------------------------------------- */
100 : /* Read the field definitions. */
101 : /* -------------------------------------------------------------------- */
102 115474 : while( pszInput != NULL && *pszInput != '}' )
103 : {
104 75592 : HFAField *poNewField = new HFAField();
105 :
106 75592 : pszInput = poNewField->Initialize( pszInput );
107 75592 : if( pszInput != NULL )
108 : {
109 : papoFields = (HFAField **)
110 75592 : CPLRealloc(papoFields, sizeof(void*) * (nFields+1) );
111 75592 : papoFields[nFields++] = poNewField;
112 : }
113 : else
114 0 : delete poNewField;
115 : }
116 :
117 19941 : if( pszInput == NULL )
118 0 : return NULL;
119 :
120 : /* -------------------------------------------------------------------- */
121 : /* Collect the name. */
122 : /* -------------------------------------------------------------------- */
123 19941 : pszInput++; /* skip `}' */
124 :
125 19941 : for( i = 0; pszInput[i] != '\0' && pszInput[i] != ','; i++ ) {}
126 19941 : if (pszInput[i] == '\0')
127 3 : return NULL;
128 :
129 19938 : pszTypeName = (char *) CPLMalloc(i+1);
130 19938 : strncpy( pszTypeName, pszInput, i );
131 19938 : pszTypeName[i] = '\0';
132 :
133 19938 : pszInput += i+1;
134 :
135 19938 : return( pszInput );
136 : }
137 :
138 : /************************************************************************/
139 : /* CompleteDefn() */
140 : /************************************************************************/
141 :
142 28465 : void HFAType::CompleteDefn( HFADictionary * poDict )
143 :
144 : {
145 : int i;
146 :
147 : /* -------------------------------------------------------------------- */
148 : /* This may already be done, if an earlier object required this */
149 : /* object (as a field), and forced an early computation of the */
150 : /* size. */
151 : /* -------------------------------------------------------------------- */
152 28465 : if( nBytes != 0 )
153 8524 : return;
154 :
155 :
156 19941 : if( bInCompleteDefn )
157 : {
158 : CPLError(CE_Failure, CPLE_AppDefined,
159 0 : "Recursion detected in HFAType::CompleteDefn()");
160 0 : return;
161 : }
162 19941 : bInCompleteDefn = TRUE;
163 :
164 : /* -------------------------------------------------------------------- */
165 : /* Complete each of the fields, totaling up the sizes. This */
166 : /* isn't really accurate for object with variable sized */
167 : /* subobjects. */
168 : /* -------------------------------------------------------------------- */
169 95533 : for( i = 0; i < nFields; i++ )
170 : {
171 75592 : papoFields[i]->CompleteDefn( poDict );
172 108424 : if( papoFields[i]->nBytes < 0 || nBytes == -1 )
173 32832 : nBytes = -1;
174 : else
175 42760 : nBytes += papoFields[i]->nBytes;
176 : }
177 :
178 19941 : bInCompleteDefn = FALSE;
179 : }
180 :
181 : /************************************************************************/
182 : /* Dump() */
183 : /************************************************************************/
184 :
185 0 : void HFAType::Dump( FILE * fp )
186 :
187 : {
188 : int i;
189 :
190 0 : VSIFPrintf( fp, "HFAType %s/%d bytes\n", pszTypeName, nBytes );
191 :
192 0 : for( i = 0; i < nFields; i++ )
193 : {
194 0 : papoFields[i]->Dump( fp );
195 : }
196 :
197 0 : VSIFPrintf( fp, "\n" );
198 0 : }
199 :
200 : /************************************************************************/
201 : /* SetInstValue() */
202 : /************************************************************************/
203 :
204 : CPLErr
205 10084 : HFAType::SetInstValue( const char * pszFieldPath,
206 : GByte *pabyData, GUInt32 nDataOffset, int nDataSize,
207 : char chReqType, void *pValue )
208 :
209 : {
210 10084 : int nArrayIndex = 0, nNameLen, iField, nByteOffset;
211 : const char *pszRemainder;
212 :
213 : /* -------------------------------------------------------------------- */
214 : /* Parse end of field name, possible index value and */
215 : /* establish where the remaining fields (if any) would start. */
216 : /* -------------------------------------------------------------------- */
217 10084 : if( strchr(pszFieldPath,'[') != NULL )
218 : {
219 2531 : const char *pszEnd = strchr(pszFieldPath,'[');
220 :
221 2531 : nArrayIndex = atoi(pszEnd+1);
222 2531 : nNameLen = pszEnd - pszFieldPath;
223 :
224 2531 : pszRemainder = strchr(pszFieldPath,'.');
225 2531 : if( pszRemainder != NULL )
226 127 : pszRemainder++;
227 : }
228 :
229 7553 : else if( strchr(pszFieldPath,'.') != NULL )
230 : {
231 1912 : const char *pszEnd = strchr(pszFieldPath,'.');
232 :
233 1912 : nNameLen = pszEnd - pszFieldPath;
234 :
235 1912 : pszRemainder = pszEnd + 1;
236 : }
237 :
238 : else
239 : {
240 5641 : nNameLen = strlen(pszFieldPath);
241 5641 : pszRemainder = pszFieldPath/*NULL*/;
242 : }
243 :
244 : /* -------------------------------------------------------------------- */
245 : /* Find this field within this type, if possible. */
246 : /* -------------------------------------------------------------------- */
247 10084 : nByteOffset = 0;
248 33625 : for( iField = 0; iField < nFields && nByteOffset < nDataSize; iField++ )
249 : {
250 53747 : if( EQUALN(pszFieldPath,papoFields[iField]->pszFieldName,nNameLen)
251 20168 : && papoFields[iField]->pszFieldName[nNameLen] == '\0' )
252 : {
253 10038 : break;
254 : }
255 :
256 23541 : int nInc = papoFields[iField]->GetInstBytes( pabyData+nByteOffset,
257 47082 : nDataSize - nByteOffset );
258 :
259 23541 : if (nInc < 0 || nByteOffset > INT_MAX - nInc)
260 : {
261 0 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid return value");
262 0 : return CE_Failure;
263 : }
264 :
265 23541 : nByteOffset += nInc;
266 : }
267 :
268 10084 : if( iField == nFields || nByteOffset >= nDataSize )
269 46 : return CE_Failure;
270 :
271 : /* -------------------------------------------------------------------- */
272 : /* Extract this field value, and return. */
273 : /* -------------------------------------------------------------------- */
274 10038 : return( papoFields[iField]->SetInstValue( pszRemainder, nArrayIndex,
275 : pabyData + nByteOffset,
276 : nDataOffset + nByteOffset,
277 : nDataSize - nByteOffset,
278 20076 : chReqType, pValue ) );
279 : }
280 :
281 : /************************************************************************/
282 : /* GetInstCount() */
283 : /************************************************************************/
284 :
285 : int
286 552 : HFAType::GetInstCount( const char * pszFieldPath,
287 : GByte *pabyData, GUInt32 nDataOffset, int nDataSize )
288 :
289 : {
290 552 : int nArrayIndex = 0, nNameLen, iField, nByteOffset;
291 : const char *pszRemainder;
292 :
293 : /* -------------------------------------------------------------------- */
294 : /* Parse end of field name, possible index value and */
295 : /* establish where the remaining fields (if any) would start. */
296 : /* -------------------------------------------------------------------- */
297 552 : if( strchr(pszFieldPath,'[') != NULL )
298 : {
299 0 : const char *pszEnd = strchr(pszFieldPath,'[');
300 :
301 0 : nArrayIndex = atoi(pszEnd+1);
302 0 : nNameLen = pszEnd - pszFieldPath;
303 :
304 0 : pszRemainder = strchr(pszFieldPath,'.');
305 0 : if( pszRemainder != NULL )
306 0 : pszRemainder++;
307 : }
308 :
309 552 : else if( strchr(pszFieldPath,'.') != NULL )
310 : {
311 126 : const char *pszEnd = strchr(pszFieldPath,'.');
312 :
313 126 : nNameLen = pszEnd - pszFieldPath;
314 :
315 126 : pszRemainder = pszEnd + 1;
316 : }
317 :
318 : else
319 : {
320 426 : nNameLen = strlen(pszFieldPath);
321 426 : pszRemainder = NULL;
322 : }
323 :
324 : /* -------------------------------------------------------------------- */
325 : /* Find this field within this type, if possible. */
326 : /* -------------------------------------------------------------------- */
327 552 : nByteOffset = 0;
328 2252 : for( iField = 0; iField < nFields && nByteOffset < nDataSize; iField++ )
329 : {
330 3356 : if( EQUALN(pszFieldPath,papoFields[iField]->pszFieldName,nNameLen)
331 1104 : && papoFields[iField]->pszFieldName[nNameLen] == '\0' )
332 : {
333 552 : break;
334 : }
335 :
336 1700 : int nInc = papoFields[iField]->GetInstBytes( pabyData+nByteOffset,
337 3400 : nDataSize - nByteOffset );
338 :
339 1700 : if (nInc < 0 || nByteOffset > INT_MAX - nInc)
340 : {
341 0 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid return value");
342 0 : return -1;
343 : }
344 :
345 1700 : nByteOffset += nInc;
346 : }
347 :
348 552 : if( iField == nFields || nByteOffset >= nDataSize )
349 0 : return -1;
350 :
351 : /* -------------------------------------------------------------------- */
352 : /* Extract this field value, and return. */
353 : /* -------------------------------------------------------------------- */
354 552 : return( papoFields[iField]->GetInstCount( pabyData + nByteOffset,
355 1104 : nDataSize - nByteOffset ) );
356 : }
357 :
358 : /************************************************************************/
359 : /* ExtractInstValue() */
360 : /* */
361 : /* Extract the value of a field instance within this type. */
362 : /* Most of the work is done by the ExtractInstValue() for the */
363 : /* HFAField, but this methond does the field name parsing. */
364 : /* */
365 : /* field names have the form: */
366 : /* */
367 : /* fieldname{[index]}{.fieldname...} */
368 : /* */
369 : /* eg. */
370 : /* abc - field abc[0] */
371 : /* abc[3] - field abc[3] */
372 : /* abc[2].def - field def[0] of */
373 : /* the third abc struct. */
374 : /************************************************************************/
375 :
376 : int
377 16358 : HFAType::ExtractInstValue( const char * pszFieldPath,
378 : GByte *pabyData, GUInt32 nDataOffset, int nDataSize,
379 : char chReqType, void *pReqReturn, int *pnRemainingDataSize )
380 :
381 : {
382 16358 : int nArrayIndex = 0, nNameLen, iField, nByteOffset;
383 : const char *pszRemainder;
384 :
385 : /* -------------------------------------------------------------------- */
386 : /* Parse end of field name, possible index value and */
387 : /* establish where the remaining fields (if any) would start. */
388 : /* -------------------------------------------------------------------- */
389 16358 : const char *pszFirstArray = strchr(pszFieldPath,'[');
390 16358 : const char *pszFirstDot = strchr(pszFieldPath,'.');
391 :
392 19478 : if( pszFirstArray != NULL
393 : && (pszFirstDot == NULL
394 : || pszFirstDot > pszFirstArray) )
395 : {
396 3120 : const char *pszEnd = pszFirstArray;
397 :
398 3120 : nArrayIndex = atoi(pszEnd+1);
399 3120 : nNameLen = pszEnd - pszFieldPath;
400 :
401 3120 : pszRemainder = strchr(pszFieldPath,'.');
402 3120 : if( pszRemainder != NULL )
403 1553 : pszRemainder++;
404 : }
405 :
406 13238 : else if( pszFirstDot != NULL )
407 : {
408 1830 : const char *pszEnd = pszFirstDot;
409 :
410 1830 : nNameLen = pszEnd - pszFieldPath;
411 :
412 1830 : pszRemainder = pszEnd + 1;
413 : }
414 :
415 : else
416 : {
417 11408 : nNameLen = strlen(pszFieldPath);
418 11408 : pszRemainder = NULL;
419 : }
420 :
421 : /* -------------------------------------------------------------------- */
422 : /* Find this field within this type, if possible. */
423 : /* -------------------------------------------------------------------- */
424 16358 : nByteOffset = 0;
425 51841 : for( iField = 0; iField < nFields && nByteOffset < nDataSize; iField++ )
426 : {
427 84464 : if( EQUALN(pszFieldPath,papoFields[iField]->pszFieldName,nNameLen)
428 32654 : && papoFields[iField]->pszFieldName[nNameLen] == '\0' )
429 : {
430 16327 : break;
431 : }
432 :
433 35483 : int nInc = papoFields[iField]->GetInstBytes( pabyData+nByteOffset,
434 70966 : nDataSize - nByteOffset );
435 :
436 35483 : if (nInc < 0 || nByteOffset > INT_MAX - nInc)
437 : {
438 0 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid return value");
439 0 : return FALSE;
440 : }
441 :
442 35483 : nByteOffset += nInc;
443 : }
444 :
445 16358 : if( iField == nFields || nByteOffset >= nDataSize )
446 31 : return FALSE;
447 :
448 : /* -------------------------------------------------------------------- */
449 : /* Extract this field value, and return. */
450 : /* -------------------------------------------------------------------- */
451 16327 : return( papoFields[iField]->
452 : ExtractInstValue( pszRemainder, nArrayIndex,
453 : pabyData + nByteOffset,
454 : nDataOffset + nByteOffset,
455 : nDataSize - nByteOffset,
456 : chReqType, pReqReturn,
457 32654 : pnRemainingDataSize) );
458 : }
459 :
460 :
461 : /************************************************************************/
462 : /* DumpInstValue() */
463 : /************************************************************************/
464 :
465 0 : void HFAType::DumpInstValue( FILE * fpOut,
466 : GByte *pabyData, GUInt32 nDataOffset,
467 : int nDataSize, const char * pszPrefix )
468 :
469 : {
470 : int iField;
471 :
472 0 : for ( iField = 0; iField < nFields && nDataSize > 0; iField++ )
473 : {
474 0 : HFAField *poField = papoFields[iField];
475 : int nInstBytes;
476 :
477 : poField->DumpInstValue( fpOut, pabyData, nDataOffset,
478 0 : nDataSize, pszPrefix );
479 :
480 0 : nInstBytes = poField->GetInstBytes( pabyData, nDataSize );
481 0 : if (nInstBytes < 0 || nDataOffset > UINT_MAX - nInstBytes)
482 : {
483 0 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid return value");
484 0 : return;
485 : }
486 :
487 0 : pabyData += nInstBytes;
488 0 : nDataOffset += nInstBytes;
489 0 : nDataSize -= nInstBytes;
490 : }
491 : }
492 :
493 : /************************************************************************/
494 : /* GetInstBytes() */
495 : /* */
496 : /* How many bytes in this particular instance of this type? */
497 : /************************************************************************/
498 :
499 1446 : int HFAType::GetInstBytes( GByte *pabyData, int nDataSize )
500 :
501 : {
502 1446 : if( nBytes >= 0 )
503 0 : return( nBytes );
504 : else
505 : {
506 1446 : int nTotal = 0;
507 : int iField;
508 :
509 3401 : for( iField = 0; iField < nFields && nTotal < nDataSize; iField++ )
510 : {
511 1955 : HFAField *poField = papoFields[iField];
512 :
513 : int nInstBytes = poField->GetInstBytes( pabyData,
514 1955 : nDataSize - nTotal );
515 1955 : if (nInstBytes < 0 || nTotal > INT_MAX - nInstBytes)
516 : {
517 0 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid return value");
518 0 : return -1;
519 : }
520 :
521 1955 : pabyData += nInstBytes;
522 1955 : nTotal += nInstBytes;
523 : }
524 :
525 1446 : return( nTotal );
526 : }
527 : }
|