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