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