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