1 : /******************************************************************************
2 : * $Id: hfaentry.cpp 23494 2011-12-07 23:56:41Z rouault $
3 : *
4 : * Project: Erdas Imagine (.img) Translator
5 : * Purpose: Implementation of the HFAEntry class for reading and relating
6 : * one node in the HFA object tree structure.
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 : * hfaentry.cpp
32 : *
33 : * Implementation of the HFAEntry class.
34 : *
35 : */
36 :
37 : #include "hfa_p.h"
38 : #include "cpl_conv.h"
39 :
40 : CPL_CVSID("$Id: hfaentry.cpp 23494 2011-12-07 23:56:41Z rouault $");
41 :
42 : /************************************************************************/
43 : /* HFAEntry() */
44 : /* */
45 : /* Construct an HFAEntry from the source file. */
46 : /************************************************************************/
47 :
48 3478 : HFAEntry::HFAEntry( HFAInfo_t * psHFAIn, GUInt32 nPos,
49 3478 : HFAEntry * poParentIn, HFAEntry * poPrevIn )
50 :
51 : {
52 3478 : psHFA = psHFAIn;
53 :
54 3478 : nFilePos = nPos;
55 3478 : bDirty = FALSE;
56 3478 : bIsMIFObject = FALSE;
57 :
58 3478 : poParent = poParentIn;
59 3478 : poPrev = poPrevIn;
60 :
61 : /* -------------------------------------------------------------------- */
62 : /* Initialize fields to null values in case there is a read */
63 : /* error, so the entry will be in a harmless state. */
64 : /* -------------------------------------------------------------------- */
65 3478 : poNext = poChild = NULL;
66 :
67 3478 : nDataPos = nDataSize = 0;
68 3478 : nNextPos = nChildPos = 0;
69 :
70 3478 : szName[0] = szType[0] = '\0';
71 :
72 3478 : pabyData = NULL;
73 :
74 3478 : poType = NULL;
75 :
76 : /* -------------------------------------------------------------------- */
77 : /* Read the entry information from the file. */
78 : /* -------------------------------------------------------------------- */
79 : GInt32 anEntryNums[6];
80 : int i;
81 :
82 3478 : if( VSIFSeekL( psHFA->fp, nFilePos, SEEK_SET ) == -1
83 : || VSIFReadL( anEntryNums, sizeof(GInt32), 6, psHFA->fp ) < 1 )
84 : {
85 : CPLError( CE_Failure, CPLE_FileIO,
86 : "VSIFReadL(%p,6*4) @ %d failed in HFAEntry().\n%s",
87 0 : psHFA->fp, nFilePos, VSIStrerror( errno ) );
88 0 : return;
89 : }
90 :
91 3478 : for( i = 0; i < 6; i++ )
92 : HFAStandard( 4, anEntryNums + i );
93 :
94 3478 : nNextPos = anEntryNums[0];
95 3478 : nChildPos = anEntryNums[3];
96 3478 : nDataPos = anEntryNums[4];
97 3478 : nDataSize = anEntryNums[5];
98 :
99 : /* -------------------------------------------------------------------- */
100 : /* Read the name, and type. */
101 : /* -------------------------------------------------------------------- */
102 3478 : if( VSIFReadL( szName, 1, 64, psHFA->fp ) < 1
103 : || VSIFReadL( szType, 1, 32, psHFA->fp ) < 1 )
104 : {
105 0 : szName[sizeof(szName)-1] = '\0';
106 0 : szType[sizeof(szType)-1] = '\0';
107 : CPLError( CE_Failure, CPLE_FileIO,
108 0 : "VSIFReadL() failed in HFAEntry()." );
109 0 : return;
110 : }
111 3478 : szName[sizeof(szName)-1] = '\0';
112 3478 : szType[sizeof(szType)-1] = '\0';
113 : }
114 :
115 : /************************************************************************/
116 : /* HFAEntry() */
117 : /* */
118 : /* Construct an HFAEntry in memory, with the intention that it */
119 : /* would be written to disk later. */
120 : /************************************************************************/
121 :
122 1400 : HFAEntry::HFAEntry( HFAInfo_t * psHFAIn,
123 : const char * pszNodeName,
124 : const char * pszTypeName,
125 1400 : HFAEntry * poParentIn )
126 :
127 : {
128 : /* -------------------------------------------------------------------- */
129 : /* Initialize Entry */
130 : /* -------------------------------------------------------------------- */
131 1400 : psHFA = psHFAIn;
132 :
133 1400 : nFilePos = 0;
134 1400 : bIsMIFObject = FALSE;
135 :
136 1400 : poParent = poParentIn;
137 1400 : poPrev = poNext = poChild = NULL;
138 :
139 1400 : nDataPos = nDataSize = 0;
140 1400 : nNextPos = nChildPos = 0;
141 :
142 1400 : SetName( pszNodeName );
143 1400 : memset( szType, 0, sizeof(szType) );
144 1400 : strncpy( szType, pszTypeName, sizeof(szType) );
145 1400 : szType[sizeof(szType)-1] = '\0';
146 :
147 1400 : pabyData = NULL;
148 1400 : poType = NULL;
149 :
150 : /* -------------------------------------------------------------------- */
151 : /* Update the previous or parent node to refer to this one. */
152 : /* -------------------------------------------------------------------- */
153 1400 : if( poParent == NULL )
154 : {
155 : /* do nothing */
156 : }
157 1271 : else if( poParent->poChild == NULL )
158 : {
159 454 : poParent->poChild = this;
160 454 : poParent->MarkDirty();
161 : }
162 : else
163 : {
164 817 : poPrev = poParent->poChild;
165 2573 : while( poPrev->poNext != NULL )
166 939 : poPrev = poPrev->poNext;
167 :
168 817 : poPrev->poNext = this;
169 817 : poPrev->MarkDirty();
170 : }
171 :
172 1400 : MarkDirty();
173 1400 : }
174 :
175 : /************************************************************************/
176 : /* BuildEntryFromMIFObject() */
177 : /* */
178 : /* Create a pseudo-HFAEntry wrapping a MIFObject. */
179 : /************************************************************************/
180 :
181 2 : HFAEntry* HFAEntry::BuildEntryFromMIFObject( HFAEntry *poContainer, const char *pszMIFObjectPath )
182 : {
183 : const char* pszField;
184 2 : CPLString osFieldName;
185 :
186 2 : osFieldName.Printf("%s.%s", pszMIFObjectPath, "MIFDictionary" );
187 2 : pszField = poContainer->GetStringField( osFieldName.c_str() );
188 2 : if (pszField == NULL)
189 : {
190 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot find %s entry",
191 0 : osFieldName.c_str());
192 0 : return NULL;
193 : }
194 2 : CPLString osDictionnary = pszField;
195 :
196 2 : osFieldName.Printf("%s.%s", pszMIFObjectPath, "type.string" );
197 2 : pszField = poContainer->GetStringField( osFieldName.c_str() );
198 2 : if (pszField == NULL)
199 : {
200 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot find %s entry",
201 0 : osFieldName.c_str());
202 0 : return NULL;
203 : }
204 2 : CPLString osType = pszField;
205 :
206 2 : osFieldName.Printf("%s.%s", pszMIFObjectPath, "MIFObject" );
207 2 : int nRemainingDataSize = 0;
208 : pszField = poContainer->GetStringField( osFieldName.c_str(),
209 2 : NULL, &nRemainingDataSize );
210 2 : if (pszField == NULL)
211 : {
212 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot find %s entry",
213 0 : osFieldName.c_str());
214 0 : return NULL;
215 : }
216 :
217 : GInt32 nMIFObjectSize;
218 : // we rudely look before the field data to get at the pointer/size info
219 2 : memcpy( &nMIFObjectSize, pszField-8, 4 );
220 : HFAStandard( 4, &nMIFObjectSize );
221 2 : if (nMIFObjectSize <= 0)
222 : {
223 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid MIF object size (%d)",
224 0 : nMIFObjectSize);
225 0 : return NULL;
226 : }
227 :
228 : // check that we won't copy more bytes than available in the buffer
229 2 : if (nMIFObjectSize > nRemainingDataSize)
230 : {
231 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid MIF object size (%d > %d)",
232 0 : nMIFObjectSize, nRemainingDataSize);
233 0 : return NULL;
234 : }
235 :
236 2 : GByte* pabyData = (GByte *) VSIMalloc(nMIFObjectSize);
237 2 : if (pabyData == NULL)
238 0 : return NULL;
239 :
240 2 : memcpy( pabyData, pszField, nMIFObjectSize );
241 :
242 : return new HFAEntry(poContainer, pszMIFObjectPath,
243 : osDictionnary, osType,
244 2 : nMIFObjectSize, pabyData);
245 :
246 : }
247 :
248 : /************************************************************************/
249 : /* HFAEntry() */
250 : /* */
251 : /* Create a pseudo-HFAEntry wrapping a MIFObject. */
252 : /************************************************************************/
253 :
254 2 : HFAEntry::HFAEntry( HFAEntry * poContainer,
255 : const char *pszMIFObjectPath,
256 : const char * pszDictionnary,
257 : const char * pszTypeName,
258 : int nDataSizeIn,
259 2 : GByte* pabyDataIn )
260 :
261 : {
262 : /* -------------------------------------------------------------------- */
263 : /* Initialize Entry */
264 : /* -------------------------------------------------------------------- */
265 2 : nFilePos = 0;
266 :
267 2 : poParent = poPrev = poNext = poChild = NULL;
268 :
269 2 : bIsMIFObject = TRUE;
270 :
271 2 : nDataPos = nDataSize = 0;
272 2 : nNextPos = nChildPos = 0;
273 :
274 2 : memset( szName, 0, sizeof(szName) );
275 :
276 : /* -------------------------------------------------------------------- */
277 : /* Create a dummy HFAInfo_t. */
278 : /* -------------------------------------------------------------------- */
279 2 : psHFA = (HFAInfo_t *) CPLCalloc(sizeof(HFAInfo_t),1);
280 :
281 2 : psHFA->eAccess = HFA_ReadOnly;
282 2 : psHFA->bTreeDirty = FALSE;
283 2 : psHFA->poRoot = this;
284 :
285 2 : psHFA->poDictionary = new HFADictionary( pszDictionnary );
286 :
287 : /* -------------------------------------------------------------------- */
288 : /* Work out the type for this MIFObject. */
289 : /* -------------------------------------------------------------------- */
290 2 : memset( szType, 0, sizeof(szType) );
291 2 : strncpy( szType, pszTypeName, sizeof(szType) );
292 2 : szType[sizeof(szType)-1] = '\0';
293 :
294 2 : poType = psHFA->poDictionary->FindType( szType );
295 :
296 2 : nDataSize = nDataSizeIn;
297 2 : pabyData = pabyDataIn;
298 2 : }
299 :
300 : /************************************************************************/
301 : /* ~HFAEntry() */
302 : /* */
303 : /* Ensure that children are cleaned up when this node is */
304 : /* cleaned up. */
305 : /************************************************************************/
306 :
307 4880 : HFAEntry::~HFAEntry()
308 :
309 : {
310 4880 : CPLFree( pabyData );
311 :
312 4880 : if( poNext != NULL )
313 2788 : delete poNext;
314 :
315 4880 : if( poChild != NULL )
316 1557 : delete poChild;
317 :
318 4880 : if( bIsMIFObject )
319 : {
320 2 : delete psHFA->poDictionary;
321 2 : CPLFree( psHFA );
322 : }
323 4880 : }
324 :
325 : /************************************************************************/
326 : /* RemoveAndDestroy() */
327 : /* */
328 : /* Removes this entry, and it's children from the current */
329 : /* tree. The parent and/or siblings are appropriately updated */
330 : /* so that they will be flushed back to disk without the */
331 : /* reference to this node. */
332 : /************************************************************************/
333 :
334 9 : CPLErr HFAEntry::RemoveAndDestroy()
335 :
336 : {
337 9 : if( poPrev != NULL )
338 : {
339 9 : poPrev->poNext = poNext;
340 9 : if( poNext != NULL )
341 7 : poPrev->nNextPos = poNext->nFilePos;
342 : else
343 2 : poPrev->nNextPos = 0;
344 9 : poPrev->MarkDirty();
345 : }
346 9 : if( poParent != NULL && poParent->poChild == this )
347 : {
348 0 : poParent->poChild = poNext;
349 0 : if( poNext )
350 0 : poParent->nChildPos = poNext->nFilePos;
351 : else
352 0 : poParent->nChildPos = 0;
353 0 : poParent->MarkDirty();
354 : }
355 :
356 9 : if( poNext != NULL )
357 : {
358 7 : poNext->poPrev = poPrev;
359 : }
360 :
361 9 : poNext = NULL;
362 9 : poPrev = NULL;
363 9 : poParent = NULL;
364 :
365 9 : delete this;
366 :
367 9 : return CE_None;
368 : }
369 :
370 : /************************************************************************/
371 : /* SetName() */
372 : /* */
373 : /* Changes the name assigned to this node */
374 : /************************************************************************/
375 :
376 1405 : void HFAEntry::SetName( const char *pszNodeName )
377 : {
378 1405 : memset( szName, 0, sizeof(szName) );
379 1405 : strncpy( szName, pszNodeName, sizeof(szName) );
380 1405 : szName[sizeof(szName)-1] = '\0';
381 :
382 1405 : MarkDirty();
383 1405 : }
384 :
385 : /************************************************************************/
386 : /* GetChild() */
387 : /************************************************************************/
388 :
389 15468 : HFAEntry *HFAEntry::GetChild()
390 :
391 : {
392 : /* -------------------------------------------------------------------- */
393 : /* Do we need to create the child node? */
394 : /* -------------------------------------------------------------------- */
395 15468 : if( poChild == NULL && nChildPos != 0 )
396 : {
397 1103 : poChild = new HFAEntry( psHFA, nChildPos, this, NULL );
398 : }
399 :
400 15468 : return( poChild );
401 : }
402 :
403 : /************************************************************************/
404 : /* GetNext() */
405 : /************************************************************************/
406 :
407 41833 : HFAEntry *HFAEntry::GetNext()
408 :
409 : {
410 : /* -------------------------------------------------------------------- */
411 : /* Do we need to create the next node? */
412 : /* -------------------------------------------------------------------- */
413 41833 : if( poNext == NULL && nNextPos != 0 )
414 : {
415 : // Check if we have a loop on the next node in this sibling chain.
416 : HFAEntry *poPast;
417 :
418 1981 : for( poPast = this;
419 : poPast != NULL && poPast->nFilePos != nNextPos;
420 : poPast = poPast->poPrev ) {}
421 :
422 1981 : if( poPast != NULL )
423 : {
424 : CPLError( CE_Warning, CPLE_AppDefined,
425 : "Corrupt (looping) entry in %s, ignoring some entries after %s.",
426 : psHFA->pszFilename,
427 1 : szName );
428 1 : nNextPos = 0;
429 1 : return NULL;
430 : }
431 :
432 1980 : poNext = new HFAEntry( psHFA, nNextPos, poParent, this );
433 : }
434 :
435 41832 : return( poNext );
436 : }
437 :
438 : /************************************************************************/
439 : /* LoadData() */
440 : /* */
441 : /* Load the data for this entry, and build up the field */
442 : /* information for it. */
443 : /************************************************************************/
444 :
445 29195 : void HFAEntry::LoadData()
446 :
447 : {
448 29195 : if( pabyData != NULL || nDataSize == 0 )
449 27379 : return;
450 :
451 : /* -------------------------------------------------------------------- */
452 : /* Allocate buffer, and read data. */
453 : /* -------------------------------------------------------------------- */
454 1816 : pabyData = (GByte *) VSIMalloc(nDataSize + 1);
455 1816 : if (pabyData == NULL)
456 : {
457 : CPLError( CE_Failure, CPLE_OutOfMemory,
458 0 : "VSIMalloc() failed in HFAEntry::LoadData()." );
459 0 : return;
460 : }
461 :
462 1816 : if( VSIFSeekL( psHFA->fp, nDataPos, SEEK_SET ) < 0 )
463 : {
464 : CPLError( CE_Failure, CPLE_FileIO,
465 0 : "VSIFSeekL() failed in HFAEntry::LoadData()." );
466 0 : return;
467 : }
468 :
469 1816 : if( VSIFReadL( pabyData, 1, nDataSize, psHFA->fp ) < 1 )
470 : {
471 : CPLError( CE_Failure, CPLE_FileIO,
472 0 : "VSIFReadL() failed in HFAEntry::LoadData()." );
473 0 : return;
474 : }
475 :
476 : /* Make sure the buffer is always null terminated to avoid */
477 : /* issues when extracting strings from a corrupted file */
478 1816 : pabyData[nDataSize] = '\0';
479 :
480 : /* -------------------------------------------------------------------- */
481 : /* Get the type corresponding to this entry. */
482 : /* -------------------------------------------------------------------- */
483 1816 : poType = psHFA->poDictionary->FindType( szType );
484 1816 : if( poType == NULL )
485 0 : return;
486 : }
487 :
488 : /************************************************************************/
489 : /* GetTypeObject() */
490 : /************************************************************************/
491 :
492 116 : HFAType *HFAEntry::GetTypeObject()
493 :
494 : {
495 116 : if( poType == NULL )
496 116 : poType = psHFA->poDictionary->FindType( szType );
497 :
498 116 : return poType;
499 : }
500 :
501 : /************************************************************************/
502 : /* MakeData() */
503 : /* */
504 : /* Create a data block on the this HFAEntry in memory. By */
505 : /* default it will create the data the correct size for fixed */
506 : /* sized types, or do nothing for variable length types. */
507 : /* However, the caller can supply a desired size for variable */
508 : /* sized fields. */
509 : /************************************************************************/
510 :
511 8927 : GByte *HFAEntry::MakeData( int nSize )
512 :
513 : {
514 8927 : if( poType == NULL )
515 : {
516 1155 : poType = psHFA->poDictionary->FindType( szType );
517 1155 : if( poType == NULL )
518 0 : return NULL;
519 : }
520 :
521 8927 : if( nSize == 0 && poType->nBytes > 0 )
522 2090 : nSize = poType->nBytes;
523 :
524 10202 : if( (int) nDataSize < nSize && nSize > 0 )
525 : {
526 1275 : pabyData = (GByte *) CPLRealloc(pabyData, nSize);
527 1275 : memset( pabyData + nDataSize, 0, nSize - nDataSize );
528 1275 : nDataSize = nSize;
529 :
530 1275 : MarkDirty();
531 :
532 : /* -------------------------------------------------------------------- */
533 : /* If the data already had a file position, we now need to */
534 : /* clear that, forcing it to be rewritten at the end of the */
535 : /* file. Referencing nodes will need to be marked dirty so */
536 : /* they are rewritten. */
537 : /* -------------------------------------------------------------------- */
538 1275 : if( nFilePos != 0 )
539 : {
540 5 : nFilePos = 0;
541 5 : nDataPos = 0;
542 5 : if (poPrev != NULL) poPrev->MarkDirty();
543 5 : if (poNext != NULL) poNext->MarkDirty();
544 5 : if (poChild != NULL) poChild->MarkDirty();
545 5 : if (poParent != NULL) poParent->MarkDirty();
546 : }
547 : }
548 : else
549 7652 : LoadData(); // make sure the data is loaded before we return pointer.
550 :
551 8927 : return pabyData;
552 : }
553 :
554 :
555 : /************************************************************************/
556 : /* DumpFieldValues() */
557 : /************************************************************************/
558 :
559 0 : void HFAEntry::DumpFieldValues( FILE * fp, const char * pszPrefix )
560 :
561 : {
562 0 : if( pszPrefix == NULL )
563 0 : pszPrefix = "";
564 :
565 0 : LoadData();
566 :
567 0 : if( pabyData == NULL || poType == NULL )
568 0 : return;
569 :
570 : poType->DumpInstValue( fp,
571 : pabyData, nDataPos, nDataSize,
572 0 : pszPrefix );
573 : }
574 :
575 : /************************************************************************/
576 : /* FindChildren() */
577 : /* */
578 : /* Find all the children of the current node that match the */
579 : /* name and type provided. Either may be NULL if it is not a */
580 : /* factor. The pszName should be just the node name, not a */
581 : /* path. */
582 : /************************************************************************/
583 :
584 1052 : std::vector<HFAEntry*> HFAEntry::FindChildren( const char *pszName,
585 : const char *pszType,
586 : int nRecLevel )
587 :
588 : {
589 1052 : std::vector<HFAEntry*> apoChildren;
590 : HFAEntry *poEntry;
591 :
592 1052 : if( nRecLevel == 50 )
593 : {
594 : CPLError(CE_Failure, CPLE_AppDefined,
595 0 : "Bad entry structure: recursion detected !");
596 0 : return apoChildren;
597 : }
598 :
599 1052 : if( this == NULL )
600 0 : return apoChildren;
601 :
602 1986 : for( poEntry = GetChild(); poEntry != NULL; poEntry = poEntry->GetNext() )
603 : {
604 934 : std::vector<HFAEntry*> apoEntryChildren;
605 : size_t i;
606 :
607 934 : if( (pszName == NULL || EQUAL(poEntry->GetName(),pszName))
608 : && (pszType == NULL || EQUAL(poEntry->GetType(),pszType)) )
609 39 : apoChildren.push_back( poEntry );
610 :
611 934 : apoEntryChildren = poEntry->FindChildren( pszName, pszType, nRecLevel + 1 );
612 :
613 978 : for( i = 0; i < apoEntryChildren.size(); i++ )
614 44 : apoChildren.push_back( apoEntryChildren[i] );
615 : }
616 :
617 1052 : return apoChildren;
618 : }
619 :
620 : /************************************************************************/
621 : /* GetNamedChild() */
622 : /************************************************************************/
623 :
624 12416 : HFAEntry *HFAEntry::GetNamedChild( const char * pszName )
625 :
626 : {
627 : int nNameLen;
628 : HFAEntry *poEntry;
629 :
630 : /* -------------------------------------------------------------------- */
631 : /* Establish how much of this name path is for the next child. */
632 : /* Up to the '.' or end of estring. */
633 : /* -------------------------------------------------------------------- */
634 551370 : for( nNameLen = 0;
635 184418 : pszName[nNameLen] != '.'
636 182534 : && pszName[nNameLen] != '\0'
637 172002 : && pszName[nNameLen] != ':';
638 : nNameLen++ ) {}
639 :
640 : /* -------------------------------------------------------------------- */
641 : /* Scan children looking for this name. */
642 : /* -------------------------------------------------------------------- */
643 47953 : for( poEntry = GetChild(); poEntry != NULL; poEntry = poEntry->GetNext() )
644 : {
645 37699 : if( EQUALN(poEntry->GetName(),pszName,nNameLen)
646 : && (int) strlen(poEntry->GetName()) == nNameLen )
647 : {
648 2256 : if( pszName[nNameLen] == '.' )
649 : {
650 : HFAEntry *poResult;
651 :
652 270 : poResult = poEntry->GetNamedChild( pszName+nNameLen+1 );
653 270 : if( poResult != NULL )
654 176 : return poResult;
655 : }
656 : else
657 1986 : return poEntry;
658 : }
659 : }
660 :
661 10254 : return NULL;
662 : }
663 :
664 : /************************************************************************/
665 : /* GetFieldValue() */
666 : /************************************************************************/
667 :
668 12640 : int HFAEntry::GetFieldValue( const char * pszFieldPath,
669 : char chReqType, void *pReqReturn,
670 : int *pnRemainingDataSize)
671 :
672 : {
673 12640 : HFAEntry *poEntry = this;
674 :
675 : /* -------------------------------------------------------------------- */
676 : /* Is there a node path in this string? */
677 : /* -------------------------------------------------------------------- */
678 12640 : if( strchr(pszFieldPath,':') != NULL )
679 : {
680 0 : poEntry = GetNamedChild( pszFieldPath );
681 0 : if( poEntry == NULL )
682 0 : return FALSE;
683 :
684 0 : pszFieldPath = strchr(pszFieldPath,':') + 1;
685 : }
686 :
687 : /* -------------------------------------------------------------------- */
688 : /* Do we have the data and type for this node? */
689 : /* -------------------------------------------------------------------- */
690 12640 : LoadData();
691 :
692 12640 : if( pabyData == NULL )
693 14 : return FALSE;
694 :
695 12626 : if( poType == NULL )
696 0 : return FALSE;
697 :
698 : /* -------------------------------------------------------------------- */
699 : /* Extract the instance information. */
700 : /* -------------------------------------------------------------------- */
701 :
702 :
703 : return( poType->ExtractInstValue( pszFieldPath,
704 : pabyData, nDataPos, nDataSize,
705 12626 : chReqType, pReqReturn, pnRemainingDataSize ) );
706 : }
707 :
708 : /************************************************************************/
709 : /* GetFieldCount() */
710 : /************************************************************************/
711 :
712 540 : int HFAEntry::GetFieldCount( const char * pszFieldPath, CPLErr *peErr )
713 :
714 : {
715 540 : HFAEntry *poEntry = this;
716 :
717 : /* -------------------------------------------------------------------- */
718 : /* Is there a node path in this string? */
719 : /* -------------------------------------------------------------------- */
720 540 : if( strchr(pszFieldPath,':') != NULL )
721 : {
722 0 : poEntry = GetNamedChild( pszFieldPath );
723 0 : if( poEntry == NULL )
724 0 : return -1;
725 :
726 0 : pszFieldPath = strchr(pszFieldPath,':') + 1;
727 : }
728 :
729 : /* -------------------------------------------------------------------- */
730 : /* Do we have the data and type for this node? */
731 : /* -------------------------------------------------------------------- */
732 540 : LoadData();
733 :
734 540 : if( pabyData == NULL )
735 0 : return -1;
736 :
737 540 : if( poType == NULL )
738 0 : return -1;
739 :
740 : /* -------------------------------------------------------------------- */
741 : /* Extract the instance information. */
742 : /* -------------------------------------------------------------------- */
743 :
744 : return( poType->GetInstCount( pszFieldPath,
745 540 : pabyData, nDataPos, nDataSize ) );
746 : }
747 :
748 : /************************************************************************/
749 : /* GetIntField() */
750 : /************************************************************************/
751 :
752 8569 : GInt32 HFAEntry::GetIntField( const char * pszFieldPath, CPLErr *peErr )
753 :
754 : {
755 : GInt32 nIntValue;
756 :
757 8569 : if( !GetFieldValue( pszFieldPath, 'i', &nIntValue, NULL ) )
758 : {
759 25 : if( peErr != NULL )
760 10 : *peErr = CE_Failure;
761 :
762 25 : return 0;
763 : }
764 : else
765 : {
766 8544 : if( peErr != NULL )
767 122 : *peErr = CE_None;
768 :
769 8544 : return nIntValue;
770 : }
771 : }
772 :
773 : /************************************************************************/
774 : /* GetBigIntField() */
775 : /* */
776 : /* This is just a helper method that reads two ULONG array */
777 : /* entries as a GBigInt. The passed name should be the name of */
778 : /* the array with no array index. Array indexes 0 and 1 will */
779 : /* be concatenated. */
780 : /************************************************************************/
781 :
782 32 : GIntBig HFAEntry::GetBigIntField( const char *pszFieldPath, CPLErr *peErr )
783 :
784 : {
785 : GUInt32 nLower, nUpper;
786 : char szFullFieldPath[1024];
787 :
788 32 : sprintf( szFullFieldPath, "%s[0]", pszFieldPath );
789 32 : nLower = GetIntField( szFullFieldPath, peErr );
790 32 : if( peErr != NULL && *peErr != CE_None )
791 0 : return 0;
792 :
793 32 : sprintf( szFullFieldPath, "%s[1]", pszFieldPath );
794 32 : nUpper = GetIntField( szFullFieldPath, peErr );
795 32 : if( peErr != NULL && *peErr != CE_None )
796 0 : return 0;
797 :
798 32 : return nLower + (((GIntBig) nUpper) << 32);
799 : }
800 :
801 : /************************************************************************/
802 : /* GetDoubleField() */
803 : /************************************************************************/
804 :
805 2526 : double HFAEntry::GetDoubleField( const char * pszFieldPath, CPLErr *peErr )
806 :
807 : {
808 : double dfDoubleValue;
809 :
810 2526 : if( !GetFieldValue( pszFieldPath, 'd', &dfDoubleValue, NULL ) )
811 : {
812 154 : if( peErr != NULL )
813 20 : *peErr = CE_Failure;
814 :
815 154 : return 0.0;
816 : }
817 : else
818 : {
819 2372 : if( peErr != NULL )
820 683 : *peErr = CE_None;
821 :
822 2372 : return dfDoubleValue;
823 : }
824 : }
825 :
826 : /************************************************************************/
827 : /* GetStringField() */
828 : /************************************************************************/
829 :
830 1545 : const char *HFAEntry::GetStringField( const char * pszFieldPath, CPLErr *peErr,
831 : int *pnRemainingDataSize)
832 :
833 : {
834 1545 : char *pszResult = NULL;
835 :
836 1545 : if( !GetFieldValue( pszFieldPath, 's', &pszResult, pnRemainingDataSize ) )
837 : {
838 79 : if( peErr != NULL )
839 25 : *peErr = CE_Failure;
840 :
841 79 : return NULL;
842 : }
843 : else
844 : {
845 1466 : if( peErr != NULL )
846 482 : *peErr = CE_None;
847 :
848 1466 : return pszResult;
849 : }
850 : }
851 :
852 : /************************************************************************/
853 : /* SetFieldValue() */
854 : /************************************************************************/
855 :
856 7933 : CPLErr HFAEntry::SetFieldValue( const char * pszFieldPath,
857 : char chReqType, void *pValue )
858 :
859 : {
860 7933 : HFAEntry *poEntry = this;
861 :
862 : /* -------------------------------------------------------------------- */
863 : /* Is there a node path in this string? */
864 : /* -------------------------------------------------------------------- */
865 7933 : if( strchr(pszFieldPath,':') != NULL )
866 : {
867 0 : poEntry = GetNamedChild( pszFieldPath );
868 0 : if( poEntry == NULL )
869 0 : return CE_Failure;
870 :
871 0 : pszFieldPath = strchr(pszFieldPath,':') + 1;
872 : }
873 :
874 : /* -------------------------------------------------------------------- */
875 : /* Do we have the data and type for this node? Try loading */
876 : /* from a file, or instantiating a new node. */
877 : /* -------------------------------------------------------------------- */
878 7933 : LoadData();
879 7933 : if( MakeData() == NULL
880 : || pabyData == NULL
881 : || poType == NULL )
882 : {
883 0 : CPLAssert( FALSE );
884 0 : return CE_Failure;
885 : }
886 :
887 : /* -------------------------------------------------------------------- */
888 : /* Extract the instance information. */
889 : /* -------------------------------------------------------------------- */
890 7933 : MarkDirty();
891 :
892 : return( poType->SetInstValue( pszFieldPath,
893 : pabyData, nDataPos, nDataSize,
894 7933 : chReqType, pValue ) );
895 : }
896 :
897 : /************************************************************************/
898 : /* SetStringField() */
899 : /************************************************************************/
900 :
901 1874 : CPLErr HFAEntry::SetStringField( const char * pszFieldPath,
902 : const char * pszValue )
903 :
904 : {
905 1874 : return SetFieldValue( pszFieldPath, 's', (void *) pszValue );
906 : }
907 :
908 : /************************************************************************/
909 : /* SetIntField() */
910 : /************************************************************************/
911 :
912 2446 : CPLErr HFAEntry::SetIntField( const char * pszFieldPath, int nValue )
913 :
914 : {
915 2446 : return SetFieldValue( pszFieldPath, 'i', &nValue );
916 : }
917 :
918 : /************************************************************************/
919 : /* SetDoubleField() */
920 : /************************************************************************/
921 :
922 3613 : CPLErr HFAEntry::SetDoubleField( const char * pszFieldPath,
923 : double dfValue )
924 :
925 : {
926 3613 : return SetFieldValue( pszFieldPath, 'd', &dfValue );
927 : }
928 :
929 : /************************************************************************/
930 : /* SetPosition() */
931 : /* */
932 : /* Set the disk position for this entry, and recursively apply */
933 : /* to any children of this node. The parent will take care of */
934 : /* our siblings. */
935 : /************************************************************************/
936 :
937 3039 : void HFAEntry::SetPosition()
938 :
939 : {
940 : /* -------------------------------------------------------------------- */
941 : /* Establish the location of this entry, and it's data. */
942 : /* -------------------------------------------------------------------- */
943 3039 : if( nFilePos == 0 )
944 : {
945 : nFilePos = HFAAllocateSpace( psHFA,
946 : psHFA->nEntryHeaderLength
947 1405 : + nDataSize );
948 :
949 1405 : if( nDataSize > 0 )
950 1275 : nDataPos = nFilePos + psHFA->nEntryHeaderLength;
951 : }
952 :
953 : /* -------------------------------------------------------------------- */
954 : /* Force all children to set their position. */
955 : /* -------------------------------------------------------------------- */
956 5019 : for( HFAEntry *poThisChild = poChild;
957 : poThisChild != NULL;
958 : poThisChild = poThisChild->poNext )
959 : {
960 1980 : poThisChild->SetPosition();
961 : }
962 3039 : }
963 :
964 : /************************************************************************/
965 : /* FlushToDisk() */
966 : /* */
967 : /* Write this entry, and it's data to disk if the entries */
968 : /* information is dirty. Also force children to do the same. */
969 : /************************************************************************/
970 :
971 2243 : CPLErr HFAEntry::FlushToDisk()
972 :
973 : {
974 2243 : CPLErr eErr = CE_None;
975 :
976 : /* -------------------------------------------------------------------- */
977 : /* If we are the root node, call SetPosition() on the whole */
978 : /* tree to ensure that all entries have an allocated position. */
979 : /* -------------------------------------------------------------------- */
980 2243 : if( poParent == NULL )
981 263 : SetPosition();
982 :
983 : /* ==================================================================== */
984 : /* Only write this node out if it is dirty. */
985 : /* ==================================================================== */
986 2243 : if( bDirty )
987 : {
988 : /* -------------------------------------------------------------------- */
989 : /* Ensure we know where the relative entries are located. */
990 : /* -------------------------------------------------------------------- */
991 1672 : if( poNext != NULL )
992 892 : nNextPos = poNext->nFilePos;
993 :
994 1672 : if( poChild != NULL )
995 513 : nChildPos = poChild->nFilePos;
996 :
997 : /* -------------------------------------------------------------------- */
998 : /* Write the Ehfa_Entry fields. */
999 : /* -------------------------------------------------------------------- */
1000 : GUInt32 nLong;
1001 :
1002 : //VSIFFlushL( psHFA->fp );
1003 1672 : if( VSIFSeekL( psHFA->fp, nFilePos, SEEK_SET ) != 0 )
1004 : {
1005 : CPLError( CE_Failure, CPLE_FileIO,
1006 : "Failed to seek to %d for writing, out of disk space?",
1007 0 : nFilePos );
1008 0 : return CE_Failure;
1009 : }
1010 :
1011 1672 : nLong = nNextPos;
1012 : HFAStandard( 4, &nLong );
1013 1672 : VSIFWriteL( &nLong, 4, 1, psHFA->fp );
1014 :
1015 1672 : if( poPrev != NULL )
1016 1015 : nLong = poPrev->nFilePos;
1017 : else
1018 657 : nLong = 0;
1019 : HFAStandard( 4, &nLong );
1020 1672 : VSIFWriteL( &nLong, 4, 1, psHFA->fp );
1021 :
1022 1672 : if( poParent != NULL )
1023 1542 : nLong = poParent->nFilePos;
1024 : else
1025 130 : nLong = 0;
1026 : HFAStandard( 4, &nLong );
1027 1672 : VSIFWriteL( &nLong, 4, 1, psHFA->fp );
1028 :
1029 1672 : nLong = nChildPos;
1030 : HFAStandard( 4, &nLong );
1031 1672 : VSIFWriteL( &nLong, 4, 1, psHFA->fp );
1032 :
1033 :
1034 1672 : nLong = nDataPos;
1035 : HFAStandard( 4, &nLong );
1036 1672 : VSIFWriteL( &nLong, 4, 1, psHFA->fp );
1037 :
1038 1672 : nLong = nDataSize;
1039 : HFAStandard( 4, &nLong );
1040 1672 : VSIFWriteL( &nLong, 4, 1, psHFA->fp );
1041 :
1042 1672 : VSIFWriteL( szName, 1, 64, psHFA->fp );
1043 1672 : VSIFWriteL( szType, 1, 32, psHFA->fp );
1044 :
1045 1672 : nLong = 0; /* Should we keep the time, or set it more reasonably? */
1046 1672 : if( VSIFWriteL( &nLong, 4, 1, psHFA->fp ) != 1 )
1047 : {
1048 : CPLError( CE_Failure, CPLE_FileIO,
1049 : "Failed to write HFAEntry %s(%s), out of disk space?",
1050 0 : szName, szType );
1051 0 : return CE_Failure;
1052 : }
1053 :
1054 : /* -------------------------------------------------------------------- */
1055 : /* Write out the data. */
1056 : /* -------------------------------------------------------------------- */
1057 : //VSIFFlushL( psHFA->fp );
1058 1672 : if( nDataSize > 0 && pabyData != NULL )
1059 : {
1060 1403 : if( VSIFSeekL( psHFA->fp, nDataPos, SEEK_SET ) != 0
1061 : || VSIFWriteL( pabyData, nDataSize, 1, psHFA->fp ) != 1 )
1062 : {
1063 : CPLError( CE_Failure, CPLE_FileIO,
1064 : "Failed to write %d bytes HFAEntry %s(%s) data,\n"
1065 : "out of disk space?",
1066 0 : nDataSize, szName, szType );
1067 0 : return CE_Failure;
1068 : }
1069 : }
1070 :
1071 : //VSIFFlushL( psHFA->fp );
1072 : }
1073 :
1074 : /* -------------------------------------------------------------------- */
1075 : /* Process all the children of this node */
1076 : /* -------------------------------------------------------------------- */
1077 4223 : for( HFAEntry *poThisChild = poChild;
1078 : poThisChild != NULL;
1079 : poThisChild = poThisChild->poNext )
1080 : {
1081 1980 : eErr = poThisChild->FlushToDisk();
1082 1980 : if( eErr != CE_None )
1083 0 : return eErr;
1084 : }
1085 :
1086 2243 : bDirty = FALSE;
1087 :
1088 2243 : return CE_None;
1089 : }
1090 :
1091 : /************************************************************************/
1092 : /* MarkDirty() */
1093 : /* */
1094 : /* Mark this node as dirty (in need of writing to disk), and */
1095 : /* also mark the tree as a whole as being dirty. */
1096 : /************************************************************************/
1097 :
1098 13639 : void HFAEntry::MarkDirty()
1099 :
1100 : {
1101 13639 : bDirty = TRUE;
1102 13639 : psHFA->bTreeDirty = TRUE;
1103 13639 : }
1104 :
|