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