]> git.mxchange.org Git - simgear.git/blob - simgear/scene/sky/clouds3d/SkyArchive.cpp
3ff750954db7eae42e79dd4e2803fe16429452cf
[simgear.git] / simgear / scene / sky / clouds3d / SkyArchive.cpp
1 //------------------------------------------------------------------------------
2 // File : SkyArchive.cpp
3 //------------------------------------------------------------------------------
4 // SkyWorks : Copyright 2002 Mark J. Harris and
5 //            The University of North Carolina at Chapel Hill
6 //------------------------------------------------------------------------------
7 // Permission to use, copy, modify, distribute and sell this software and its 
8 // documentation for any purpose is hereby granted without fee, provided that 
9 // the above copyright notice appear in all copies and that both that copyright 
10 // notice and this permission notice appear in supporting documentation. 
11 // Binaries may be compiled with this software without any royalties or 
12 // restrictions. 
13 //
14 // The author(s) and The University of North Carolina at Chapel Hill make no 
15 // representations about the suitability of this software for any purpose. 
16 // It is provided "as is" without express or 
17 // implied warranty.
18 /**
19  * @file SkyArchive.cpp
20  * 
21  * Implementation of class SkyArchive.
22  */
23
24 #include <plib/ul.h>
25 #include "SkyArchive.hpp"
26
27 // FIXME: Remove this section whenever plib has it's own endian conversion
28 //        funcrtions for 64-bit data types.
29 #ifndef ulEndianLittleDouble
30 // This hack doesn't actually do anything, but it's pressence
31 // marks the places that need endiannes attention.
32 inline double ulEndianLittleDouble(double x) {
33    return x;
34 }
35 #endif
36
37 #include <assert.h>
38
39 struct SkyArchiveEntry
40 {
41   SkyArchiveEntry() : type(0), pData(NULL), iDataSize(0) {}
42   unsigned char  type;
43   unsigned char* pData;
44   unsigned int   iDataSize;
45 };
46
47 struct SkyArchiveFileEntry
48 {
49   SkyArchiveFileEntry() : type(0), iDataSize(0) {}
50   unsigned char type;
51   char          pName[32];
52   unsigned int  iDataSize;
53 };
54
55
56 //------------------------------------------------------------------------------
57 // Function               : SkyArchive::SkyArchive
58 // Description      : 
59 //------------------------------------------------------------------------------
60 /**
61  * @fn SkyArchive::SkyArchive()
62  * @brief Default constructor.  Creates an empty, unnamed archive.                                             |
63  */ 
64 SkyArchive::SkyArchive()
65 : _pName(NULL)
66 {
67 }
68
69
70 //------------------------------------------------------------------------------
71 // Function               : SkyArchive::SkyArchive
72 // Description      : 
73 //------------------------------------------------------------------------------
74 /**
75  * @fn SkyArchive::SkyArchive(const char* pName)
76  * @brief Constructor.  Creates an empty, named archive. 
77  */ 
78 SkyArchive::SkyArchive(const char* pName)
79 {
80   _pName = new char[::strlen(pName)+1];
81   ::strcpy( _pName, pName);  
82 }
83
84
85 //.---------------------------------------------------------------------------.
86 //|   Function   : SkyArchive::SkyArchive                                 |
87 //|   Description: 
88 //.---------------------------------------------------------------------------.
89
90 //------------------------------------------------------------------------------
91 // Function               : SkyArchive::SkyArchive
92 // Description      : 
93 //------------------------------------------------------------------------------
94 /**
95  * @fn SkyArchive::SkyArchive(const SkyArchive& src)
96  * @brief Copy constructor.  Deep-copies the contents of one archive to another.
97  */ 
98 SkyArchive::SkyArchive(const SkyArchive& src)
99 {  
100   _pName = new char[::strlen(src._pName)+1];
101   ::strcpy( _pName, src._pName);
102   
103   _CopyDataTable( src._dataTable);
104 }
105
106 //------------------------------------------------------------------------------
107 // Function               : SkyArchive::~SkyArchive
108 // Description      : 
109 //------------------------------------------------------------------------------
110 /**
111  * @fn SkyArchive::~SkyArchive()
112  * @brief Destructor.
113  */ 
114 SkyArchive::~SkyArchive()
115 {
116   MakeEmpty();
117   SAFE_DELETE_ARRAY(_pName);
118 }
119
120
121 //.---------------------------------------------------------------------------.
122 //|   Function   : SkyArchive::operator=                                    |
123 //|   Description: |
124 //.---------------------------------------------------------------------------.
125
126 //------------------------------------------------------------------------------
127 // Function               : SkyArchive::operator=
128 // Description      : 
129 //------------------------------------------------------------------------------
130 /**
131  * @fn SkyArchive::operator=( const SkyArchive& src)
132  * @brief @todo Deep-copies the contents of one archive to another.
133  */ 
134 SkyArchive& SkyArchive::operator=( const SkyArchive& src)
135 {
136   if (this != &src)
137   {
138     MakeEmpty();
139     SAFE_DELETE_ARRAY(_pName);
140     _pName = new char[::strlen(src._pName)+1];
141     ::strcpy( _pName, src.GetName());
142     
143     _CopyDataTable( src._dataTable);
144   }
145   return *this;
146 }
147
148
149
150 //=============================================================================
151 //  Adding Content to SkyArchive
152 //=============================================================================
153
154 //------------------------------------------------------------------------------
155 // Function               : SkyArchive::AddData
156 // Description      : 
157 //------------------------------------------------------------------------------
158 /**
159 * @fn SkyArchive::AddData(const char*         pName, 
160 SkyArchiveTypeCode  eType, 
161 const void*         pData, 
162 unsigned int        iNumBytes, 
163 unsigned int        iNumItems)
164 * @brief Adds a new data field to the archive.
165
166 * Makes a copy of the data, stores it in a SkyArchiveEntry, and adds it to the
167 * database.  All specialized functions for the base types are implemented using 
168 * this function.
169
170 * PARAMETERS
171 * @param name Field name.  This is used as the key for the database entry.
172 * @param type Data type of the field.
173 * @param pData Pointer to the data to be added to the archive.
174 * @param iNumBytes Size of each individual item in the data
175 * @param iNumItems Number of items to copy                                  
176 */
177 SKYRESULT SkyArchive::AddData(const char*         pName, 
178                               SkyArchiveTypeCode  eType, 
179                               const void*         pData, 
180                               unsigned int        iNumBytes, 
181                               unsigned int        iNumItems /* = 1 */)
182 {
183   // fill out a new archive entry with the supplied data
184   SkyArchiveEntry* pNewEntry  = new SkyArchiveEntry;
185   pNewEntry->type             = eType;
186   pNewEntry->iDataSize        = iNumBytes * iNumItems;
187   
188   if (eType != ARCHIVE_TYPE)
189   {
190     pNewEntry->pData = new unsigned char[pNewEntry->iDataSize];
191     ::memcpy(pNewEntry->pData, pData, pNewEntry->iDataSize);
192   }
193   else
194   {
195     pNewEntry->pData = (unsigned char*)pData;
196   }
197   
198   char* pInternalName = new char[::strlen(pName)+1];
199   ::strcpy( pInternalName, pName);
200   _dataTable.insert(std::make_pair(pInternalName, pNewEntry));
201   
202   return SKYRESULT_OK;
203 }
204
205
206 //-----------------------------------------------------------------------------
207 //  SkyArchive :: AddBool( const char* pName, bool aBool)
208 //  SkyArchive :: AddInt8( const char* pName, Int8 anInt8)
209 //  SkyArchive :: AddInt16( const char* pName, Int16 anInt16)
210 //  SkyArchive :: AddInt32( const char* pName, Int32 anInt32)
211 //  ...
212 //-----------------------------------------------------------------------------
213 //
214 //  Specialized functions for the most common base types
215 //  
216 //-----------------------------------------------------------------------------
217
218
219 //------------------------------------------------------------------------------
220 // Function               : SkyArchive::AddBool
221 // Description      : 
222 //------------------------------------------------------------------------------
223 /**
224  * @fn SkyArchive::AddBool(const char* pName, bool aBool)
225  * @brief Adds a named bool to the archive.
226  */ 
227 SKYRESULT SkyArchive::AddBool(const char* pName, bool aBool)
228 {
229   return AddData( pName, BOOL_TYPE, &aBool, sizeof(bool));
230 }
231
232 //------------------------------------------------------------------------------
233 // Function               : SkyArchive::AddInt8
234 // Description      : 
235 //------------------------------------------------------------------------------
236 /**
237  * @fn SkyArchive::AddInt8(const char* pName, char anInt8)
238  * @brief Adds a named 8-bit integer to the archive.
239  */ 
240 SKYRESULT SkyArchive::AddInt8(const char* pName, char anInt8)
241 {
242   return AddData( pName, INT8_TYPE, &anInt8, sizeof(char));
243 }
244
245 //------------------------------------------------------------------------------
246 // Function               : SkyArchive::AddInt16
247 // Description      : 
248 //------------------------------------------------------------------------------
249 /**
250  * @fn SkyArchive::AddInt16(const char* pName, short anInt16)
251  * @brief Adds a named 16-bit integer to the archive.
252  */ 
253 SKYRESULT SkyArchive::AddInt16(const char* pName, short anInt16)
254 {
255   return AddData( pName, INT16_TYPE, &anInt16, sizeof(short));
256 }
257
258 //------------------------------------------------------------------------------
259 // Function               : SkyArchive::AddInt32
260 // Description      : 
261 //------------------------------------------------------------------------------
262 /**
263  * @fn SkyArchive::AddInt32(const char* pName, int anInt32)
264  * @brief Adds a named 32-bit integer to the archive.
265  */ 
266 SKYRESULT SkyArchive::AddInt32(const char* pName, int anInt32)
267 {
268   return AddData( pName, INT32_TYPE, &anInt32, sizeof(int));
269 }
270
271 //------------------------------------------------------------------------------
272 // Function               : SkyArchive::AddUInt8
273 // Description      : 
274 //------------------------------------------------------------------------------
275 /**
276  * @fn SkyArchive::AddUInt8(const char* pName, unsigned char anUInt8)
277  * @brief Adds a named unsigned 8-bit integer to the archive.
278  */ 
279 SKYRESULT SkyArchive::AddUInt8(const char* pName, unsigned char anUInt8)
280 {
281   return AddData( pName, UINT8_TYPE, &anUInt8, sizeof(unsigned char));
282 }
283
284 //------------------------------------------------------------------------------
285 // Function               : SkyArchive::AddUInt16
286 // Description      : 
287 //------------------------------------------------------------------------------
288 /**
289  * @fn SkyArchive::AddUInt16(const char* pName, unsigned short anUInt16)
290  * @brief Adds a named unsigned 16-bit integer to the archive.
291  */ 
292 SKYRESULT SkyArchive::AddUInt16(const char* pName, unsigned short anUInt16)
293 {
294   return AddData( pName, UINT16_TYPE, &anUInt16, sizeof(unsigned short));
295 }
296
297 //------------------------------------------------------------------------------
298 // Function               : SkyArchive::AddUInt32
299 // Description      : 
300 //------------------------------------------------------------------------------
301 /**
302  * @fn SkyArchive::AddUInt32(const char* pName, unsigned int anUInt32)
303  * @brief Adds a named unsigned 32-bit integer to the archive.
304  */ 
305 SKYRESULT SkyArchive::AddUInt32(const char* pName, unsigned int anUInt32)
306 {
307   return AddData( pName, UINT32_TYPE, &anUInt32, sizeof(unsigned int));
308 }
309
310 //------------------------------------------------------------------------------
311 // Function               : SkyArchive::AddFloat32
312 // Description      : 
313 //------------------------------------------------------------------------------
314 /**
315  * @fn SkyArchive::AddFloat32(const char* pName, float aFloat32)
316  * @brief Adds a named 32-bit real number to the archive.
317  */ 
318 SKYRESULT SkyArchive::AddFloat32(const char* pName, float aFloat32)
319 {
320   return AddData( pName, FLOAT32_TYPE, &aFloat32, sizeof(float));
321 }
322
323 //------------------------------------------------------------------------------
324 // Function               : SkyArchive::AddFloat64
325 // Description      : 
326 //------------------------------------------------------------------------------
327 /**
328  * @fn SkyArchive::AddFloat64(const char* pName, double aFloat64)
329  * @brief Adds a named 64-bit real number to the archive.
330  */ 
331 SKYRESULT SkyArchive::AddFloat64(const char* pName, double aFloat64)
332 {
333   return AddData( pName, FLOAT64_TYPE, &aFloat64, sizeof(double));
334 }
335
336 //------------------------------------------------------------------------------
337 // Function               : SkyArchive::AddString
338 // Description      : 
339 //------------------------------------------------------------------------------
340 /**
341  * @fn SkyArchive::AddString(const char* pName, const char* pString)
342  * @brief Adds a named string to the archive.
343  */ 
344 SKYRESULT SkyArchive::AddString(const char* pName, const char* pString)
345 {
346   return AddData( pName, STRING_TYPE, pString, ::strlen(pString)+1);
347 }
348
349 //------------------------------------------------------------------------------
350 // Function               : SkyArchive::AddArchive
351 // Description      : 
352 //------------------------------------------------------------------------------
353 /**
354  * @fn SkyArchive::AddArchive(const SkyArchive& anArchive)
355  * @brief Adds a subarchive to this archive.
356  *
357  * This method allows hierarchical data structures to be stored in an archive.
358  */
359 SKYRESULT SkyArchive::AddArchive(const SkyArchive& anArchive)
360 {
361   SkyArchive* pCopy = new SkyArchive(anArchive);
362   return AddData( pCopy->GetName(), ARCHIVE_TYPE, pCopy, sizeof(SkyArchive));
363 }
364
365 //-----------------------------------------------------------------------------
366 //  Adding Vector types
367 //-----------------------------------------------------------------------------
368
369 //------------------------------------------------------------------------------
370 // Function               : SkyArchive::AddVec2f
371 // Description      : 
372 //------------------------------------------------------------------------------
373 /**
374  * @fn SkyArchive::AddVec2f(const char* pName, const Vec2f& aVec2f)
375  * @brief Adds a 2-component 32-bit real number vector to the archive.
376  */ 
377 SKYRESULT SkyArchive::AddVec2f(const char* pName, const Vec2f& aVec2f)
378 {
379   return AddData( pName, VEC2F_TYPE, &aVec2f, sizeof(Vec2f));
380 }
381
382 //------------------------------------------------------------------------------
383 // Function               : SkyArchive::AddVec3f
384 // Description      : 
385 //------------------------------------------------------------------------------
386 /**
387  * @fn SkyArchive::AddVec3f(const char* pName, const Vec3f& aVec3f)
388  * @brief Adds a 3-component 32-bit real number vector to the archive.
389  */ 
390 SKYRESULT SkyArchive::AddVec3f(const char* pName, const Vec3f& aVec3f)
391 {
392   return AddData( pName, VEC3F_TYPE, &aVec3f, sizeof(Vec3f));
393 }
394
395 //------------------------------------------------------------------------------
396 // Function               : SkyArchive::AddVec4f
397 // Description      : 
398 //------------------------------------------------------------------------------
399 /**
400  * @fn SkyArchive::AddVec4f(const char* pName, const Vec4f& aVec4f)
401  * @brief Adds a 4-component 32-bit real number vector to the archive.
402  */ 
403 SKYRESULT SkyArchive::AddVec4f(const char* pName, const Vec4f& aVec4f)
404 {
405   return AddData( pName, VEC4F_TYPE, &aVec4f, sizeof(Vec4f));
406 }
407
408 //=============================================================================
409 //  Retrieving Content from SkyArchive
410 //=============================================================================
411
412 //------------------------------------------------------------------------------
413 // Function               : SkyArchive::FindData
414 // Description      : 
415 //------------------------------------------------------------------------------
416 /**
417  * @fn SkyArchive::FindData(const char*        pName, 
418                                SkyArchiveTypeCode eType, 
419                                void** const       pData, 
420                                unsigned int*      pNumBytes, 
421                                unsigned int       index) const
422  * @brief Retrieves datafield from _dataTable.
423  * 
424  * PARAMETERS
425  * @param name The field name.  used as the key for the multimap entry.
426  * @param type Data type of the field.
427  * @param pData Pointer to the returned data.
428  * @param pNumBytes Returns the size of the field entry returned.
429  * @param index Which item of the given \a name to locate.
430  */ 
431 SKYRESULT SkyArchive::FindData(const char*        pName, 
432                                SkyArchiveTypeCode eType, 
433                                void** const       pData, 
434                                unsigned int*      pNumBytes, 
435                                unsigned int       index /* = 0 */) const
436 {
437   const SkyArchiveEntry* pEntry = _FindEntry(pName, index, eType);
438   if (pEntry)
439   {
440     if (pData)
441     {
442       *pData = new unsigned char[pEntry->iDataSize];
443       ::memcpy( ((void*)*pData), pEntry->pData, pEntry->iDataSize);
444     }
445     
446     if (pNumBytes)
447     {
448       *pNumBytes = pEntry->iDataSize;
449     }
450     
451     return SKYRESULT_OK;
452   }
453   return SKYRESULT_FAIL;
454 }
455
456
457 //-----------------------------------------------------------------------------
458 //  SkyArchive :: FindBool( const char* pName, bool* aBool)
459 //  SkyArchive :: FindInt8( const char* pName, Int8* anInt8)
460 //  SkyArchive :: FindInt16( const char* pName, Int16* anInt16)
461 //  SkyArchive :: FindInt32( const char* pName, Int32* anInt32)
462 //  ...
463 //-----------------------------------------------------------------------------
464 //
465 //  specialized function for the most common base types
466 //  
467 //-----------------------------------------------------------------------------
468
469 //------------------------------------------------------------------------------
470 // Function               : SkyArchive::FindBool
471 // Description      : 
472 //------------------------------------------------------------------------------
473 /**
474  * @fn SkyArchive::FindBool(const char* pName, bool* pBool, unsigned int index) const
475  * @brief Finds a named bool in the archive.
476  */ 
477 SKYRESULT SkyArchive::FindBool(const char* pName, bool* pBool, unsigned int index) const
478 {
479   const SkyArchiveEntry* pEntry = _FindEntry(pName, index, BOOL_TYPE);
480   if (pEntry)
481   {
482     bool* pData = (bool*)(pEntry->pData);
483     *pBool      = *pData;
484     return SKYRESULT_OK;
485   }
486   return SKYRESULT_FAIL;
487 }
488
489 //------------------------------------------------------------------------------
490 // Function               : SkyArchive::FindInt8
491 // Description      : 
492 //------------------------------------------------------------------------------
493 /**
494  * @fn SkyArchive::FindInt8(const char* pName, char* pInt8, unsigned int index) const
495  * @brief Finds a named 8-bit integer in the archive.
496  */ 
497 SKYRESULT SkyArchive::FindInt8(const char* pName, char* pInt8, unsigned int index) const
498 {
499   const SkyArchiveEntry* pEntry = _FindEntry(pName, index, INT8_TYPE);
500   if (pEntry)
501   {
502     char* pData = (char*)(pEntry->pData);
503     *pInt8      = *pData;
504     return SKYRESULT_OK;
505   }
506   return SKYRESULT_FAIL;
507 }
508
509 //------------------------------------------------------------------------------
510 // Function               : SkyArchive::FindInt16
511 // Description      : 
512 //------------------------------------------------------------------------------
513 /**
514  * @fn SkyArchive::FindInt16(const char* pName, short* pInt16, unsigned int index) const
515  * @brief Finds a named 16-bit integer in the archive.
516  */ 
517 SKYRESULT SkyArchive::FindInt16(const char* pName, short* pInt16, unsigned int index) const
518 {
519   const SkyArchiveEntry* pEntry = _FindEntry(pName, index, INT16_TYPE);
520   if (pEntry)
521   {
522     unsigned short* pData  = (unsigned short*)(pEntry->pData);
523     *pInt16       = ulEndianLittle16(*pData);
524     return SKYRESULT_OK;
525   }
526   return SKYRESULT_FAIL;
527 }
528
529 //------------------------------------------------------------------------------
530 // Function               : SkyArchive::FindInt32
531 // Description      : 
532 //------------------------------------------------------------------------------
533 /**
534  * @fn SkyArchive::FindInt32(const char* pName, int* pInt32, unsigned int index) const
535  * @brief Finds a named 32-bit integer in the archive.
536  */ 
537 SKYRESULT SkyArchive::FindInt32(const char* pName, int* pInt32, unsigned int index) const
538 {
539   const SkyArchiveEntry* pEntry = _FindEntry(pName, index, INT32_TYPE);
540   if (pEntry)
541   {
542     unsigned int* pData  = (unsigned int*)(pEntry->pData);
543     *pInt32     = ulEndianLittle32(*pData);
544     return SKYRESULT_OK;
545   }
546   return SKYRESULT_FAIL;
547 }
548
549 //------------------------------------------------------------------------------
550 // Function               : SkyArchive::FindUInt8
551 // Description      : 
552 //------------------------------------------------------------------------------
553 /**
554  * @fn SkyArchive::FindUInt8(const char* pName, unsigned char* pUInt8, unsigned int index) const
555  * @brief Finds a named unsigned 8-bit integer in the archive.
556  */ 
557 SKYRESULT SkyArchive::FindUInt8(const char* pName, unsigned char* pUInt8, unsigned int index) const
558 {
559   const SkyArchiveEntry* pEntry = _FindEntry(pName, index, UINT8_TYPE);
560   if (pEntry)
561   {
562     unsigned char* pData  = (unsigned char*)(pEntry->pData);
563     *pUInt8               = *pData;
564     return SKYRESULT_OK;
565   }
566   return SKYRESULT_FAIL;
567 }
568
569 //------------------------------------------------------------------------------
570 // Function               : SkyArchive::FindUInt16
571 // Description      : 
572 //------------------------------------------------------------------------------
573 /**
574  * @fn SkyArchive::FindUInt16(const char* pName, unsigned short* pUInt16, unsigned int index) const
575  * @brief Finds a named unsigned 16-bit integer in the archive.
576  */ 
577 SKYRESULT SkyArchive::FindUInt16(const char* pName, unsigned short* pUInt16, unsigned int index) const
578 {
579   const SkyArchiveEntry* pEntry = _FindEntry(pName, index, UINT16_TYPE);
580   if (pEntry)
581   {
582     unsigned short* pData = (unsigned short*)(pEntry->pData);
583     *pUInt16              = ulEndianLittle16(*pData);
584     return SKYRESULT_OK;
585   }
586   return SKYRESULT_FAIL;
587 }
588
589 //------------------------------------------------------------------------------
590 // Function               : SkyArchive::FindUInt32
591 // Description      : 
592 //------------------------------------------------------------------------------
593 /**
594  * @fn SkyArchive::FindUInt32(const char* pName, unsigned int* pUInt32, unsigned int index) const
595  * @brief Finds a named unsigned 32-bit integer in the archive.
596  */ 
597 SKYRESULT SkyArchive::FindUInt32(const char* pName, unsigned int* pUInt32, unsigned int index) const
598 {
599   const SkyArchiveEntry* pEntry = _FindEntry(pName, index, UINT32_TYPE);
600   if (pEntry)
601   {
602     unsigned int* pData = (unsigned int*)(pEntry->pData);
603     *pUInt32            = ulEndianLittle32(*pData);
604     return SKYRESULT_OK;
605   }
606   return SKYRESULT_FAIL;
607 }
608
609 //------------------------------------------------------------------------------
610 // Function               : SkyArchive::FindFloat32
611 // Description      : 
612 //------------------------------------------------------------------------------
613 /**
614  * @fn SkyArchive::FindFloat32(const char* pName, float* pFloat32, unsigned int index) const
615  * @brief Finds a named 32-bit real number in the archive.
616  */ 
617 SKYRESULT SkyArchive::FindFloat32(const char* pName, float* pFloat32, unsigned int index) const
618 {
619   const SkyArchiveEntry* pEntry = _FindEntry(pName, index, FLOAT32_TYPE);
620   if (pEntry)
621   {
622     float* pData  = (float*)(pEntry->pData);
623     *pFloat32     = ulEndianLittleFloat(*pData);
624     return SKYRESULT_OK;
625   }
626   return SKYRESULT_FAIL;
627 }
628
629 //------------------------------------------------------------------------------
630 // Function               : SkyArchive::FindFloat64
631 // Description      : 
632 //------------------------------------------------------------------------------
633 /**
634  * @fn SkyArchive::FindFloat64(const char* pName, double* pFloat64, unsigned int index) const
635  * @brief Finds a named 64-bit real number in the archive.
636  */ 
637 SKYRESULT SkyArchive::FindFloat64(const char* pName, double* pFloat64, unsigned int index) const
638 {
639   const SkyArchiveEntry* pEntry = _FindEntry(pName, index, FLOAT64_TYPE);
640   if (pEntry)
641   {
642     double* pData = (double*)(pEntry->pData);
643     *pFloat64     = ulEndianLittleDouble(*pData);
644     return SKYRESULT_OK;
645   }
646   return SKYRESULT_FAIL;
647 }
648
649 //------------------------------------------------------------------------------
650 // Function               : SkyArchive::FindString
651 // Description      : 
652 //------------------------------------------------------------------------------
653 /**
654  * @fn SkyArchive::FindString(const char* pName, char** const pString, unsigned int index) const
655  * @brief Finds a named string in the archive.
656  */ 
657 SKYRESULT SkyArchive::FindString(const char* pName, char** const pString, unsigned int index) const
658 {
659   const SkyArchiveEntry* pEntry = _FindEntry(pName, index, STRING_TYPE);
660   if (pEntry)
661   {
662     char* pData = (char*)(pEntry->pData);
663     *pString    = new char[pEntry->iDataSize];
664     ::strcpy((char*)*pString, pData);
665     return SKYRESULT_OK;
666   }
667   return SKYRESULT_FAIL;
668 }
669
670 //------------------------------------------------------------------------------
671 // Function               : SkyArchive::FindArchive
672 // Description      : 
673 //------------------------------------------------------------------------------
674 /**
675  * @fn SkyArchive::FindArchive(const char* pName, SkyArchive* pArchive, unsigned int index) const
676  * @brief Finds a named sub-archive in the archive.
677  */ 
678 SKYRESULT SkyArchive::FindArchive(const char* pName, SkyArchive* pArchive, unsigned int index) const
679 {
680   const SkyArchiveEntry* pEntry = _FindEntry(pName, index, ARCHIVE_TYPE);
681   if (pEntry)
682   {
683     SkyArchive* pData  = (SkyArchive*)(pEntry->pData);
684     *pArchive         = *pData;
685     return SKYRESULT_OK;
686   }
687   return SKYRESULT_FAIL;
688 }
689
690 //------------------------------------------------------------------------------
691 // Function               : SkyArchive::FindVec2f
692 // Description      : 
693 //------------------------------------------------------------------------------
694 /**
695  * @fn SkyArchive::FindVec2f(const char* pName, Vec2f* pVec2f, unsigned int index) const
696  * @brief Finds a 2-component 32-bit real number vector in the archive.
697  */ 
698 SKYRESULT SkyArchive::FindVec2f(const char* pName, Vec2f* pVec2f, unsigned int index) const
699 {
700   const SkyArchiveEntry* pEntry = _FindEntry(pName, index, VEC2F_TYPE);
701   if (pEntry)
702   {
703     Vec2f* pData  = (Vec2f*)(pEntry->pData);
704     *pVec2f       = *pData;
705     return SKYRESULT_OK;
706   }
707   return SKYRESULT_FAIL;
708 }
709
710 //------------------------------------------------------------------------------
711 // Function               : SkyArchive::FindVec3f
712 // Description      : 
713 //------------------------------------------------------------------------------
714 /**
715  * @fn SkyArchive::FindVec3f(const char* pName, Vec3f* pVec3f, unsigned int index) const
716  * @brief Finds a 3-component 32-bit real number vector in the archive.
717  */ 
718 SKYRESULT SkyArchive::FindVec3f(const char* pName, Vec3f* pVec3f, unsigned int index) const
719 {
720   const SkyArchiveEntry* pEntry = _FindEntry(pName, index, VEC3F_TYPE);
721   if (pEntry)
722   {
723     Vec3f* pData  = (Vec3f*)(pEntry->pData);
724     *pVec3f       = *pData;
725     return SKYRESULT_OK;
726   }
727   return SKYRESULT_FAIL;
728 }
729
730 //------------------------------------------------------------------------------
731 // Function               : SkyArchive::FindVec4f
732 // Description      : 
733 //------------------------------------------------------------------------------
734 /**
735  * @fn SkyArchive::FindVec4f(const char* pName, Vec4f* pVec4f, unsigned int index) const
736  * @brief Finds a 4-component 32-bit real number vector in the archive.
737  */ 
738 SKYRESULT SkyArchive::FindVec4f(const char* pName, Vec4f* pVec4f, unsigned int index) const
739 {
740   const SkyArchiveEntry* pEntry = _FindEntry(pName, index, VEC4F_TYPE);
741   if (pEntry)
742   {
743     Vec4f* pData  = (Vec4f*)(pEntry->pData);
744     *pVec4f       = *pData;
745     return SKYRESULT_OK;
746   }
747   return SKYRESULT_FAIL;
748 }
749
750 //------------------------------------------------------------------------------
751 // Function               : SkyArchive::AccessArchive
752 // Description      : 
753 //------------------------------------------------------------------------------
754 /**
755  * @fn SkyArchive::AccessArchive(const char* pName, SkyArchive** pArchive, unsigned int index) const
756  * @brief Accesses a named sub-archive in an archive directly.
757  * 
758  * Note: The data are not copied!
759  */ 
760 SKYRESULT SkyArchive::AccessArchive(const char* pName, SkyArchive** pArchive, unsigned int index) const
761 {
762   const SkyArchiveEntry* pEntry = _FindEntry(pName, index, ARCHIVE_TYPE);
763   if (pEntry)
764   {
765     SkyArchive* pData = (SkyArchive*)(pEntry->pData);
766     *pArchive        = pData;
767     return SKYRESULT_OK;
768   }
769   return SKYRESULT_FAIL;
770 }
771
772
773 //------------------------------------------------------------------------------
774 // Function               : SkyArchive::GetInfo
775 // Description      : 
776 //------------------------------------------------------------------------------
777 /**
778  * @fn SkyArchive::GetInfo(const char* pName, SkyArchiveTypeCode eType, unsigned int* pNumFound) const
779  * @brief Computes the number of fields that contain the given name and type.
780  * 
781  * PARAMETERS
782  * @param pName Field name to search for.
783  * @param eType Field type to search for.
784  * @param pNumFound Returns the number of fields that contain given name and type.
785  */ 
786 SKYRESULT SkyArchive::GetInfo(const char*         pName, 
787                               SkyArchiveTypeCode  eType, 
788                               unsigned int*       pNumFound) const
789 {
790   //
791   // Find the range of entries in the mmap with the key matching pName
792   //
793   std::pair<SkyMMapConstIter, SkyMMapConstIter> b = _dataTable.equal_range((char*)pName);
794   
795   unsigned int count = 0;
796   for ( SkyMMapConstIter i = b.first; i != b.second; ++i )
797   {
798     //
799     // The entry's type must match...
800     //
801     const SkyArchiveEntry* pEntry = (*i).second;
802     if (pEntry->type == eType || ANY_TYPE == eType)
803     {
804       // only increment the count when the type matches
805       ++count;
806     }
807   }
808   
809   if (pNumFound)
810   {
811     *pNumFound = count;
812   }
813   
814   if (0 == count)
815     return SKYRESULT_FAIL;
816   
817   return SKYRESULT_OK;
818 }
819
820
821 //------------------------------------------------------------------------------
822 // Function               : SkyArchive::GetInfo
823 // Description      : 
824 //------------------------------------------------------------------------------
825 /**
826  * @fn SkyArchive::GetInfo(unsigned int iNameIndex, char** pNameFound, SkyArchiveTypeCode* pTypeCode, unsigned int* pNumFound)
827  * @brief Returns information about the key at the specified index.
828  * 
829  * PARAMETERS
830  * @param nameIndex Key index to look up.
831  * @param pNameFound Key name is returned here.
832  * @param pTypeCode Key type is returned here.
833  * @param pNumFound Number of fields held under key name is returned here.
834  */ 
835 SKYRESULT SkyArchive::GetInfo(unsigned int        iNameIndex, 
836                               char**              pNameFound, 
837                               SkyArchiveTypeCode* pTypeCode,
838                               unsigned int*       pNumFound)
839
840   assert( pNameFound != NULL);
841   
842   if (!pNameFound)
843     return SKYRESULT_FAIL;
844
845   unsigned int      iCurrentKeyIndex = 0;
846   SkyMMapConstIter  iter;
847   const char*       pLastKey = "";
848   
849   for (iter = _dataTable.begin(); iter != _dataTable.end(); iter++)
850   {
851     const char* pKey = (*iter).first;
852     if (::strcmp( pLastKey, pKey))
853     {
854       if (iCurrentKeyIndex == iNameIndex)
855       {
856         *pNameFound = new char[::strlen(pKey) + 1];
857         ::strcpy(*pNameFound, pKey);
858         
859         if (pTypeCode)
860         {
861           const SkyArchiveEntry* pEntry = (*iter).second;
862           *pTypeCode = (SkyArchiveTypeCode)pEntry->type;
863         }
864         
865         if (pNumFound)
866         {
867           return GetInfo( *pNameFound, *pTypeCode, pNumFound);
868         }
869         return SKYRESULT_OK;
870       }
871       
872       pLastKey = pKey;
873       ++iCurrentKeyIndex;
874     }
875   }
876   return SKYRESULT_FAIL;
877 }
878
879
880 //------------------------------------------------------------------------------
881 // Function               : SkyArchive::GetNumUniqueNames
882 // Description      : 
883 //------------------------------------------------------------------------------
884 /**
885 * @fn SkyArchive::GetNumUniqueNames() const
886 * @brief Computes the number of unique key names in _dataTable.
887 */ 
888 unsigned int SkyArchive::GetNumUniqueNames() const
889 {
890   // duh!
891   if (IsEmpty())
892     return 0;
893   
894   unsigned int      iNumKeys = 0;
895   SkyMMapConstIter  iter;
896   const char*       pLastKey = "";
897   
898   for (iter = _dataTable.begin(); iter != _dataTable.end(); iter++)
899   {
900     const char* pKey = (*iter).first;
901     if (::strcmp( pLastKey, pKey))
902     {
903       ++iNumKeys;
904       pLastKey = pKey;
905     }
906   }
907   return iNumKeys;
908 }
909
910
911 //=============================================================================
912 //  Removing Contents of SkyArchive
913 //=============================================================================
914
915 //------------------------------------------------------------------------------
916 // Function               : SkyArchive::MakeEmpty
917 // Description      : 
918 //------------------------------------------------------------------------------
919 /**
920 * @fn SkyArchive::MakeEmpty()
921 * @brief Remove all the contents of the database. 
922 */ 
923 SKYRESULT SkyArchive::MakeEmpty()
924 {
925   SkyMMapIter iter;
926   
927   for (iter = _dataTable.begin(); iter != _dataTable.end(); iter++)
928   {
929     SkyArchiveEntry* pEntry = (*iter).second;
930     char* pName = (*iter).first;
931     SAFE_DELETE_ARRAY(pName);
932     
933     if (ARCHIVE_TYPE == pEntry->type)
934     {
935       SkyArchive* pArchive = (SkyArchive*)(pEntry->pData);
936       SAFE_DELETE(pArchive);
937     }
938     else
939     {
940       SAFE_DELETE_ARRAY(pEntry->pData);
941     }
942     SAFE_DELETE(pEntry);
943   }
944   
945   _dataTable.clear();
946   
947   return SKYRESULT_OK;
948 }
949
950 //------------------------------------------------------------------------------
951 // Function               : SkyArchive::IsEmpty
952 // Description      : 
953 //------------------------------------------------------------------------------
954 /**
955 * @fn SkyArchive::IsEmpty() const
956 * @brief returns true if the archive is empty, false if it contains any data.
957 */ 
958 bool SkyArchive::IsEmpty() const
959 {
960   return (0 == _dataTable.size());
961 }
962
963
964 //------------------------------------------------------------------------------
965 // Function               : SkyArchive::Load
966 // Description      : 
967 //------------------------------------------------------------------------------
968 /**
969  * @fn SkyArchive::Load(const char* pFileName)
970  * @brief Load the contents of a SkyArchive from file storage.
971  */ 
972 SKYRESULT SkyArchive::Load(const char* pFileName)
973 {
974   if (!pFileName) {
975     FAIL_RETURN_MSG(SKYRESULT_FAIL, "Error: SkyArchive::Load(): file name is NULL.");
976         }
977   FILE* pSrcFile = NULL;
978   
979   char buf[512];
980   sprintf(buf,"SkyArchive::Load(%s)",pFileName);
981   SkyTrace(buf);
982   if (NULL == (pSrcFile = fopen(pFileName, "rb"))) // file opened successfully   
983   {
984     SkyTrace("Error: SkyArchive::Load(): failed to open file for reading.");
985     return SKYRESULT_FAIL;
986   }
987     
988   SKYRESULT retVal = _Load(pSrcFile);
989   fclose(pSrcFile);
990
991   FAIL_RETURN(retVal);
992   return SKYRESULT_OK;
993 }
994
995 //------------------------------------------------------------------------------
996 // Function               : SkyArchive::Commit
997 // Description      : 
998 //------------------------------------------------------------------------------
999 /**
1000  * @fn SkyArchive::Save(const char* pFilename) const
1001  * @brief Commit Contents of SkyArchive to file storage.                 
1002  */ 
1003 SKYRESULT SkyArchive::Save(const char* pFileName) const
1004 {
1005   if (!pFileName)
1006     FAIL_RETURN_MSG(SKYRESULT_FAIL, "Error: SkyArchive::Save(): file name is NULL.");
1007
1008   FILE* pDestFile = NULL;
1009   
1010   if (NULL == (pDestFile = fopen(pFileName, "wb"))) // file opened successfully   
1011     FAIL_RETURN_MSG(SKYRESULT_FAIL, "Error: SkyArchive::Save(): failed to open file for writing."); 
1012   
1013   SKYRESULT retVal = _Save(pDestFile);
1014   fflush(pDestFile);
1015   fclose(pDestFile);
1016
1017   FAIL_RETURN(retVal);
1018   return SKYRESULT_OK;
1019 }
1020
1021
1022 //=============================================================================
1023 // Private helper functions
1024 //=============================================================================
1025
1026 //------------------------------------------------------------------------------
1027 // Function               : SkyArchive::_FindEntry
1028 // Description      : 
1029 //------------------------------------------------------------------------------
1030 /**
1031  * @fn SkyArchive::_FindEntry(const char* pName, unsigned int index, SkyArchiveTypeCode  eType) const
1032  * @brief Locates and returns the SkyArchiveEntry with the specified name, index, and type.                                                                
1033  * 
1034  * PARAMETERS
1035  * @param pName Entry name to locate (this is used as the database key)
1036  * @param index Entry index to locate (in case of multiple entries)
1037  * @param type Entry must have this type (@see SkyArchiveTypeCode)
1038  *
1039  * Returns a pointer to the entry or NULL if no matching entry could be located.
1040  */ 
1041 const SkyArchiveEntry* SkyArchive::_FindEntry(const char*         pName, 
1042                                               unsigned int        index, 
1043                                               SkyArchiveTypeCode  eType) const
1044 {
1045   //
1046   // Find the range of entries in the mmap with the key matching /name/
1047   //
1048   std::pair< SkyMMapConstIter, SkyMMapConstIter > b = _dataTable.equal_range((char*)pName);
1049   
1050   unsigned int count = 0;
1051   for (SkyMMapConstIter i = b.first; (i != b.second) && (count <= index); ++i)
1052   {
1053     //
1054     // The entry's type and index must match...
1055     //
1056     const SkyArchiveEntry* pEntry = (*i).second;
1057     if (pEntry->type == eType)
1058     {
1059       if (count == index)
1060       {
1061         return pEntry;
1062       }
1063       
1064       // only increment the count when the type matches
1065       ++count;
1066     }
1067   }
1068   return NULL;
1069 }
1070
1071
1072 //.---------------------------------------------------------------------------.
1073 //|   Function   : SkyArchive::_CopyDataTable                               |
1074 //|   Description:                                                            |
1075 //.---------------------------------------------------------------------------.
1076 void SkyArchive::_CopyDataTable( const SkyArchiveMMap& src)
1077 {
1078   SkyMMapConstIter iter;
1079   
1080   for (iter = src.begin(); iter != src.end(); iter++)
1081   {
1082     const SkyArchiveEntry* pSrcEntry  = (*iter).second;
1083     const char* pSrcName              = (*iter).first;
1084     
1085     if (ARCHIVE_TYPE == pSrcEntry->type)
1086     {
1087       SkyArchive* pSrcArchive = (SkyArchive*)pSrcEntry->pData;
1088       AddArchive(*pSrcArchive);
1089     }
1090     else
1091     {
1092       SkyArchiveEntry* pNewEntry    = new SkyArchiveEntry;
1093       pNewEntry->type               = pSrcEntry->type;
1094       pNewEntry->iDataSize          = pSrcEntry->iDataSize;
1095       pNewEntry->pData              = new unsigned char[pNewEntry->iDataSize];
1096       ::memcpy( pNewEntry->pData, pSrcEntry->pData, pNewEntry->iDataSize);
1097       
1098       char* pName = new char[::strlen(pSrcName)+1];
1099       ::strcpy( pName, pSrcName );
1100       _dataTable.insert(std::make_pair(pName, pNewEntry));
1101     }
1102   }
1103 }
1104
1105 //------------------------------------------------------------------------------
1106 // Function               : SkyArchive::_Save
1107 // Description      : 
1108 //------------------------------------------------------------------------------
1109 /**
1110  * @fn SkyArchive::_Save(FILE* pDestFile) const
1111  * @brief Saves data to a file (possibly recursively in the case of subarchives).
1112  */ 
1113 SKYRESULT SkyArchive::_Save(FILE* pDestFile) const
1114 {
1115   // fill out a record for this archive & write it
1116   SkyArchiveFileEntry me;
1117   me.type       = ARCHIVE_TYPE;
1118   ::strncpy( me.pName, _pName, 32);
1119   me.iDataSize  = _dataTable.size();
1120   
1121   size_t iNumItemsWritten = fwrite((const void*)&me, sizeof(SkyArchiveFileEntry), 1, pDestFile);
1122   
1123   if (1 > iNumItemsWritten)
1124     FAIL_RETURN_MSG(SKYRESULT_FAIL, "Error: SkyArchive::_Save(): failed to write Archive header.");
1125   
1126   SkyMMapConstIter iter;
1127   for (iter = _dataTable.begin(); iter != _dataTable.end(); iter++)
1128   {
1129     // fill out a record for each item in _dataTable & write it
1130     const SkyArchiveEntry* pEntry = (*iter).second;
1131     switch(pEntry->type)
1132     {
1133     case ARCHIVE_TYPE:
1134       {
1135         ((SkyArchive*)(pEntry->pData))->_Save(pDestFile);
1136         break;
1137       }
1138       
1139     default:
1140       {
1141         SkyArchiveFileEntry item;
1142         item.type       = pEntry->type;
1143         ::strncpy( item.pName, (*iter).first, 32);
1144         item.iDataSize  = pEntry->iDataSize;
1145         
1146         iNumItemsWritten = fwrite((const void*)&item, sizeof(SkyArchiveFileEntry), 1, pDestFile);
1147         if (1 > iNumItemsWritten)
1148           FAIL_RETURN_MSG(SKYRESULT_FAIL, "Error: SkyArchive::_Save(): failed to write Archive Entry header.");
1149         iNumItemsWritten = fwrite((const void*)pEntry->pData, pEntry->iDataSize, 1, pDestFile);
1150         if (1 > iNumItemsWritten)
1151           FAIL_RETURN_MSG(SKYRESULT_FAIL, "Error: SkyArchive::_Save(): failed to write Archive Entry data.");
1152         break;
1153       }
1154     }
1155   }
1156   return SKYRESULT_OK;
1157 }
1158
1159
1160 //------------------------------------------------------------------------------
1161 // Function               : SkyArchive::_Load
1162 // Description      : 
1163 //------------------------------------------------------------------------------
1164 /**
1165 * @fn SkyArchive::_Load( FILE* pSrcFile)
1166 * @brief Loads data from a file (possibly recursively in the case of subarchives).
1167 */ 
1168 SKYRESULT SkyArchive::_Load( FILE* pSrcFile)
1169 {
1170   // first make sure the file is open and readable.
1171   
1172   // load the first record
1173   SkyArchiveFileEntry thisItem;
1174   size_t iNumItemsRead = fread((void*)&thisItem, sizeof(SkyArchiveFileEntry), 1, pSrcFile);
1175   if (!iNumItemsRead)
1176     FAIL_RETURN_MSG(SKYRESULT_FAIL, "Error: SkyArchive::_Load(): failed to read Archive header.");
1177
1178   unsigned int ui = thisItem.iDataSize;
1179   thisItem.iDataSize = ulEndianLittle32(ui);
1180
1181   _pName = new char[::strlen(thisItem.pName)+1];
1182   ::strcpy( _pName, thisItem.pName);
1183     
1184   for (unsigned int iNumItems = 0; iNumItems < thisItem.iDataSize; ++iNumItems)
1185   {
1186     SkyArchiveFileEntry embeddedItem;
1187     long iFileLoc = ftell(pSrcFile);  // store location before the read
1188     iNumItemsRead = fread((void*)&embeddedItem, sizeof(SkyArchiveFileEntry), 1, pSrcFile);
1189     if (1 > iNumItemsRead)
1190       FAIL_RETURN_MSG(SKYRESULT_FAIL, "Error: SkyArchive::_Load(): failed to read embedded archive item.");
1191
1192     unsigned int ui = embeddedItem.iDataSize;
1193     embeddedItem.iDataSize = ulEndianLittle32(ui);
1194
1195    
1196     switch( embeddedItem.type)
1197     {
1198     case ARCHIVE_TYPE:
1199       {
1200         if (0 != fseek(pSrcFile, iFileLoc, SEEK_SET))
1201           FAIL_RETURN_MSG(SKYRESULT_FAIL, "Error: SkyArchive::_Load(): failed to set the file position.");
1202         SkyArchive newArchive;
1203         newArchive._Load(pSrcFile); // recursively load the subarchive
1204         AddArchive(newArchive);     // add the loaded archive to the database in memory.
1205       }
1206       break;
1207     default:
1208       {
1209         unsigned char* pData = new unsigned char[embeddedItem.iDataSize];
1210         iNumItemsRead = fread((void*)pData, embeddedItem.iDataSize, 1, pSrcFile);
1211         if (1 > iNumItemsRead)
1212           FAIL_RETURN_MSG(SKYRESULT_FAIL, "Error: SkyArchive::_Load(): failed to read item data.");
1213         AddData( embeddedItem.pName, 
1214                 (SkyArchiveTypeCode)embeddedItem.type, 
1215                 pData, 
1216                 embeddedItem.iDataSize);
1217         delete[] pData;
1218         break;
1219       }      
1220     }
1221   }
1222   return SKYRESULT_OK;
1223 }