Main Page | Alphabetical List | Compound List | File List | Compound Members | File Members

strblock.c

Go to the documentation of this file.
00001 /****************************************************************************************/
00002 /*  STRBLOCK.C                                                                                                                                                  */
00003 /*                                                                                      */
00004 /*  Author: Mike Sandige                                                                    */
00005 /*  Description: String block implementation.                                                                                   */
00006 /*                                                                                      */
00007 /*  The contents of this file are subject to the Genesis3D Public License               */
00008 /*  Version 1.01 (the "License"); you may not use this file except in                   */
00009 /*  compliance with the License. You may obtain a copy of the License at                */
00010 /*  http://www.genesis3d.com                                                            */
00011 /*                                                                                      */
00012 /*  Software distributed under the License is distributed on an "AS IS"                 */
00013 /*  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See                */
00014 /*  the License for the specific language governing rights and limitations              */
00015 /*  under the License.                                                                  */
00016 /*                                                                                      */
00017 /*  The Original Code is Genesis3D, released March 25, 1999.                            */
00018 /*Genesis3D Version 1.1 released November 15, 1999                            */
00019 /*  Copyright (C) 1999 WildTangent, Inc. All Rights Reserved           */
00020 /*                                                                                      */
00021 /****************************************************************************************/
00022 // strblock.c
00023 //   a list of strings implemented as a single block of memory for fast
00024 //   loading.  The 'Data' Field is interpreted as an array of integer 
00025 //   offsets relative to the beginning of the data field.  After the int list
00026 //   is the packed string data.  Since no additional allocations are needed 
00027 //   this object can be file loaded as one block. 
00028 #include <string.h>
00029 #include <assert.h>
00030 #include <stdio.h>
00031 
00032 #include "strblock.h"
00033 #include "ram.h"
00034 #include "errorlog.h"
00035 
00036 #define STRBLOCK_MAX_STRINGLEN 255
00037 
00038 typedef struct geStrBlock
00039 {
00040         int Count;
00041         geStrBlock *SanityCheck;
00042         union 
00043                 {
00044                         int IntArray[1];                // char offset into CharArray for string[n]
00045                         char CharArray[1];
00046                 } Data;
00047                 
00048 } geStrBlock;
00049 
00050 
00051 int GENESISCC geStrBlock_GetChecksum(const geStrBlock *SB)
00052 {
00053         int Count;
00054         int Len;
00055         int i,j;
00056         const char *Str;
00057         int Checksum=0;
00058         assert( SB != NULL );
00059 
00060         Count = geStrBlock_GetCount(SB);
00061         for (i=0; i<Count; i++)
00062                 {
00063                         Str = geStrBlock_GetString(SB,i);
00064                         assert(Str!=NULL);
00065                         Len = strlen(Str);
00066                         for (j=0; j<Len; j++)
00067                                  {
00068                                         Checksum += (int)Str[j];
00069                                 }
00070                         Checksum = Checksum*3;
00071                 }
00072         return Checksum;
00073 }
00074 
00075 geStrBlock *GENESISCC geStrBlock_Create(void)
00076 {
00077         geStrBlock *SB;
00078         
00079         SB = GE_RAM_ALLOCATE_STRUCT(geStrBlock);
00080 
00081         if ( SB == NULL )
00082                 {
00083                         geErrorLog_Add(ERR_STRBLOCK_ENOMEM, NULL);
00084                         return NULL;
00085                 }
00086         SB->Count=0;
00087         SB->SanityCheck = SB;
00088         return SB;
00089 }
00090 
00091 
00092 void GENESISCC geStrBlock_Destroy(geStrBlock **SB)
00093 {
00094         assert( (*SB)->SanityCheck == (*SB) );
00095         assert(  SB != NULL );
00096         assert( *SB != NULL );  
00097         geRam_Free( *SB );
00098         *SB = NULL;
00099 }
00100 
00101 
00102 static int GENESISCC geStrBlock_BlockSize(const geStrBlock *B)
00103 {
00104         int Offset;
00105         const char *LastStr;
00106         assert( B != NULL );
00107         assert( B->SanityCheck == B );
00108 
00109         if ( B->Count == 0 )
00110                 return 0;
00111         Offset = B->Data.IntArray[B->Count-1];
00112         LastStr = &(B->Data.CharArray[Offset]);
00113 
00114         return strlen(LastStr) + 1 + Offset;
00115 }
00116 
00117 
00118 void GENESISCC geStrBlock_Delete(geStrBlock **ppSB,int Nth)
00119 {
00120         int BlockSize;
00121         int StringLen;
00122         int CloseSize;
00123         const char *String;
00124         assert(  ppSB  != NULL );
00125         assert( *ppSB  != NULL );
00126         assert( Nth >=0 );
00127         assert( Nth < (*ppSB)->Count );
00128         assert( (*ppSB)->SanityCheck == (*ppSB) );
00129 
00130         String = geStrBlock_GetString(*ppSB,Nth);
00131         assert( String != NULL );
00132         StringLen = strlen(String) + 1;
00133                 
00134         BlockSize = geStrBlock_BlockSize(*ppSB);
00135 
00136         {
00137                 geStrBlock *B = *ppSB;
00138                 char *ToBeReplaced;
00139                 char *Replacement=NULL;
00140                 int i;
00141                 ToBeReplaced = &((*ppSB)->Data.CharArray[(*ppSB)->Data.IntArray[Nth]]);
00142                 if (Nth< (*ppSB)->Count-1)
00143                         Replacement  = &((*ppSB)->Data.CharArray[(*ppSB)->Data.IntArray[Nth+1]]);
00144                 for (i=Nth+1,CloseSize = 0; i<(*ppSB)->Count ; i++)
00145                         {
00146                                 CloseSize += strlen(&((*ppSB)->Data.CharArray[(*ppSB)->Data.IntArray[i]])) +1;
00147                                 B->Data.IntArray[i] -= StringLen;
00148                         }
00149                 for (i=0; i<(*ppSB)->Count ; i++)
00150                         {
00151                                 B->Data.IntArray[i] -= sizeof(int);
00152                         }
00153                 // crunch out Nth string
00154                 if (Nth< (*ppSB)->Count-1)
00155                         memmove(ToBeReplaced,Replacement,CloseSize);
00156                 // crunch out Nth index
00157                 memmove(&(B->Data.IntArray[Nth]),
00158                                 &(B->Data.IntArray[Nth+1]),
00159                                 BlockSize - ( sizeof(int) *  (Nth+1) ) );
00160 
00161         }
00162         
00163         {
00164                 geStrBlock * NewgeStrBlock;
00165 
00166                 NewgeStrBlock = geRam_Realloc( *ppSB, 
00167                         BlockSize                               // size of data block
00168                         + sizeof(geStrBlock)            // size of strblock structure
00169                         - StringLen                             // size of dying string
00170                         - sizeof(int) );                // size of new index to string
00171                 if ( NewgeStrBlock != NULL )
00172                         {
00173                                 *ppSB = NewgeStrBlock;
00174                                 (*ppSB)->SanityCheck = NewgeStrBlock;
00175                         }
00176         }
00177 
00178         (*ppSB)->Count--;
00179 }
00180 
00181 
00182 #if 0
00183         // as of yet un needed.  and this is untested
00184 geBoolean GENESISCC geStrBlock_SetString(geStrBlock **ppSB, int Index, const char *String)
00185 {
00186         assert(  ppSB  != NULL );
00187         assert( *ppSB  != NULL );
00188         assert( Index >=0 );
00189         assert( Index < (*ppSB)->Count );
00190         assert( String != NULL );
00191 
00192         if (geStrBlock_Insert(ppSB,Index,String) == GE_FALSE)
00193                 {
00194                         geErrorLog_Add(ERR_STRBLOCK_ENOMEM, NULL);
00195                         return GE_FALSE;
00196                 }
00197                         
00198         geStrBlock_Delete(ppSB,Index);
00199         return GE_TRUE;
00200 }
00201 #endif
00202 
00203 #if 0
00204         // as of yet un needed.  and this is untested
00205 geBoolean GENESISCC geStrBlock_Insert(geStrBlock **ppSB,int InsertAfterIndex,const char *String)
00206 {
00207         int BlockSize;
00208         int StringLen;
00209         int MoveSize;
00210         
00211         assert(  ppSB  != NULL );
00212         assert( *ppSB  != NULL );
00213         assert( InsertAfterIndex >=-1);
00214         assert( InsertAfterIndex < (*ppSB)->Count );
00215         assert( (*ppSB)->SanityCheck == (*ppSB) );
00216         assert( String != NULL );
00217         
00218         if (InsertAfterIndex == (*ppSB)->Count - 1)
00219                 {
00220                         if (geStrBlock_Append(ppSB,String)==GE_FALSE)
00221                                 {
00222                                         geErrorLog_Add(-1, NULL);
00223                                         return GE_FALSE;
00224                                 }
00225                         return GE_TRUE;
00226                 }
00227 
00228         StringLen = strlen(String) + 1;
00229                 
00230         BlockSize = geStrBlock_BlockSize(*ppSB);
00231 
00232         {
00233                 geStrBlock * NewgeStrBlock;
00234 
00235                 NewgeStrBlock = geRam_Realloc( *ppSB, 
00236                         BlockSize                               // size of data block
00237                         + sizeof(geStrBlock)    // size of strblock structure
00238                         + StringLen                             // size of new string
00239                         + sizeof(int) );                // size of new index to string
00240                 if ( NewgeStrBlock != NULL )
00241                         {
00242                                 *ppSB = NewgeStrBlock;
00243                                 (*ppSB)->SanityCheck = NewgeStrBlock;
00244                         }
00245         }
00246 
00247 
00248 
00249         {
00250                 geStrBlock *B = *ppSB;
00251                 char *Chars = B->Data.CharArray;
00252                 int  *Table = B->Data.IntArray;
00253                 char *MoveFrom;
00254                 char *MoveTo=NULL;
00255                 int i;
00256                 
00257                 MoveFrom  = &(Chars[Table[InsertAfterIndex+1]]);
00258                 
00259                 MoveTo = MoveFrom + StringLen;
00260                 
00261                 for (i=InsertAfterIndex+1,MoveSize = 0; i<B->Count ; i++)
00262                         {
00263                                 MoveSize += strlen(&(Chars[Table[i]])) +1;
00264                                 Table[i] += StringLen;
00265                         }
00266                 for (i=0; i<(*ppSB)->Count ; i++)
00267                         {
00268                                 Table[i] += sizeof(int);
00269                         }
00270                 // make room for string
00271                 memmove(MoveFrom,MoveTo,MoveSize);
00272                 // make room for new index
00273                 memmove(&(Table[InsertAfterIndex+1]),
00274                                 &(Table[InsertAfterIndex+2]),
00275                                 BlockSize - ( sizeof(int) *  (InsertAfterIndex+2) ) );
00276                 Table[InsertAfterIndex+1] = Table[InsertAfterIndex] 
00277                                                 + strlen(&(Chars[Table[InsertAfterIndex]])) +1;
00278 
00279         }
00280         
00281         
00282         (*ppSB)->Count++;
00283         return GE_TRUE;
00284 
00285 
00286 }
00287 #endif
00288 
00289 geBoolean GENESISCC geStrBlock_FindString(const geStrBlock* pSB, const char* String, int* pIndex)
00290 {
00291         int i;
00292         int Count;
00293         const char *Str;
00294 
00295         assert(pSB != NULL);
00296         assert(String != NULL);
00297         assert(pIndex != NULL);
00298         assert( pSB->SanityCheck == pSB );
00299 
00300         Count = geStrBlock_GetCount(pSB);
00301         for (i=0; i<Count; i++)
00302         {
00303                 Str = geStrBlock_GetString(pSB,i);
00304                 if(strcmp(String, Str) == 0)
00305                 {
00306                         *pIndex = i;
00307                         return GE_TRUE;
00308                 }
00309         }
00310         return GE_FALSE;
00311 }
00312 
00313 
00314 geBoolean GENESISCC geStrBlock_Append(geStrBlock **ppSB,const char *String)
00315 {
00316         int BlockSize;
00317         assert(  ppSB  != NULL );
00318         assert( *ppSB  != NULL );
00319         assert( String != NULL );
00320         assert( (*ppSB)->SanityCheck == (*ppSB) );
00321 
00322         if (strlen(String)>=STRBLOCK_MAX_STRINGLEN)
00323                 {
00324                         geErrorLog_Add(ERR_STRBLOCK_STRLEN, NULL);
00325                         return GE_FALSE;
00326                 }
00327 
00328         BlockSize = geStrBlock_BlockSize(*ppSB);
00329 
00330         {
00331                 geStrBlock * NewgeStrBlock;
00332 
00333                 NewgeStrBlock = geRam_Realloc( *ppSB, 
00334                         BlockSize                               // size of data block
00335                         + sizeof(geStrBlock)            // size of strblock structure
00336                         + strlen(String) + 1            // size of new string
00337                         + sizeof(int) );                // size of new index to string
00338                 if ( NewgeStrBlock == NULL )
00339                         {
00340                                 geErrorLog_Add(ERR_STRBLOCK_ENOMEM, NULL);
00341                                 return GE_FALSE;
00342                         }
00343                 *ppSB = NewgeStrBlock;
00344                 (*ppSB)->SanityCheck = NewgeStrBlock;
00345         }
00346 
00347         {
00348                 geStrBlock *B = *ppSB;
00349                 int i;
00350                 for (i=0; i<B->Count; i++)
00351                         {
00352                                 B->Data.IntArray[i] += sizeof(int);
00353                         }
00354                 if (B->Count > 0)
00355                         {
00356                                 memmove(&(B->Data.IntArray[B->Count+1]),
00357                                                 &(B->Data.IntArray[B->Count]),
00358                                                 BlockSize - sizeof(int) * B->Count);
00359                         }
00360                 B->Data.IntArray[B->Count] = BlockSize + sizeof(int);
00361                 strcpy(&(B->Data.CharArray[B->Data.IntArray[B->Count]]),String);
00362         }
00363         (*ppSB)->Count++;
00364         return GE_TRUE;
00365 }
00366 
00367         
00368 const char *GENESISCC geStrBlock_GetString(const geStrBlock *SB, int Index)
00369 {
00370         assert( SB != NULL );
00371         assert( Index >= 0 );
00372         assert( Index < SB->Count );
00373         assert( SB->SanityCheck == SB );
00374         return &(SB->Data.CharArray[SB->Data.IntArray[Index]]);
00375 }
00376 
00377 int GENESISCC geStrBlock_GetCount(const geStrBlock *SB)
00378 {
00379         assert( SB != NULL);
00380         assert( SB->SanityCheck == SB );
00381         return SB->Count;
00382 }
00383 
00384 
00385 #define CHECK_FOR_WRITE(uu) if(uu <= 0) { geErrorLog_Add( ERR_STRBLOCK_FILE_WRITE, NULL ); return GE_FALSE; }
00386 
00387 #define STRBLOCK_ASCII_FILE_TYPE 0x4B4C4253     // 'SBLK'
00388 #define STRBLOCK_BIN_FILE_TYPE 0x424B4253       // 'SBKB'
00389 #define STRBLOCK_FILE_VERSION 0x00F0            // Restrict version to 16 bits
00390 
00391 #define STRBLOCK_STRINGARRAY_ID         "Strings"
00392 #define STRBLOCK_NUM_ASCII_IDS       1  // Keep this up to date
00393 
00394 static geStrBlock *GENESISCC geStrBlock_CreateFromBinaryFile(geVFile *pFile);
00395 
00396 geStrBlock* GENESISCC geStrBlock_CreateFromFile(geVFile* pFile)
00397 {
00398         uint32 u, v;
00399         geStrBlock* SB;
00400         char    VersionString[32];
00401 
00402         assert( pFile != NULL );
00403 
00404         if(geVFile_Read(pFile, &u, sizeof(u)) == GE_FALSE)
00405         {
00406                 geErrorLog_Add( ERR_STRBLOCK_FILE_READ , NULL);
00407                 return NULL;
00408         }
00409 
00410         if(u == STRBLOCK_ASCII_FILE_TYPE)
00411         {
00412                 int NumItemsNeeded=0;
00413                 int NumItemsRead = 0;
00414                 char line[STRBLOCK_MAX_STRINGLEN];
00415 
00416                 SB = geStrBlock_Create();
00417                 if( SB == NULL )
00418                 {
00419                         geErrorLog_Add(ERR_STRBLOCK_ENOMEM, NULL);
00420                         return NULL;
00421                 }
00422 
00423                 // Read and build the version.  Then determine the number of items to read.
00424                 if      (geVFile_GetS(pFile, VersionString, sizeof(VersionString)) == GE_FALSE)
00425                 {
00426                         geErrorLog_Add( ERR_STRBLOCK_FILE_READ , NULL);
00427                         return NULL;
00428                 }
00429                 if      (sscanf(VersionString, "%X.%X\n", &u, &v) != 2)
00430                 {
00431                         geErrorLog_Add( ERR_STRBLOCK_FILE_READ , NULL);
00432                         return NULL;
00433                 }
00434                 v |= (u << 8);
00435                 if(v >= STRBLOCK_FILE_VERSION)
00436                 {
00437                         NumItemsNeeded = STRBLOCK_NUM_ASCII_IDS;
00438                 }
00439 
00440                 while(NumItemsRead < NumItemsNeeded)
00441                 {
00442                         if(geVFile_GetS(pFile, line, STRBLOCK_MAX_STRINGLEN) == GE_FALSE)
00443                                 {
00444                                         geErrorLog_Add( ERR_STRBLOCK_FILE_READ , NULL);
00445                                         break; // got to read something
00446                                 }
00447                         else if(strnicmp(line, STRBLOCK_STRINGARRAY_ID, sizeof(STRBLOCK_STRINGARRAY_ID)-1) == 0)
00448                         {
00449                                 int i,Count;
00450                                 if(sscanf(line + sizeof(STRBLOCK_STRINGARRAY_ID)-1, "%d", &Count) != 1)
00451                                         {                                               
00452                                                 geErrorLog_Add( ERR_STRBLOCK_FILE_READ , NULL);
00453                                                 break;           
00454                                         }
00455                                 for (i=0; i<Count;i++)
00456                                         {
00457                                                 if(geVFile_GetS(pFile, line, STRBLOCK_MAX_STRINGLEN) == GE_FALSE)
00458                                                         {
00459                                                                 geErrorLog_Add( ERR_STRBLOCK_FILE_READ , NULL);
00460                                                                 break; // got to read something
00461                                                         }
00462                                                 if ( line[0] != 0 )
00463                                                         line[strlen(line)-1] = 0;       // remove trailing /n  (textmode)
00464                                                 if ( line[0] != 0 )
00465                                                         {
00466                                                                 int len = strlen(line)-1;
00467                                                                 if (line[len] == 13)  // remove trailing /r  (binary file mode)
00468                                                                         {
00469                                                                                 line[len] = 0;
00470                                                                         }
00471                                                         }
00472                                                 if (geStrBlock_Append(&SB,line)==GE_FALSE)
00473                                                         {
00474                                                                 break; // error logged in _Append
00475                                                         }
00476                                         }
00477                                 NumItemsRead++;
00478                         }
00479 
00480                         
00481                 }
00482 
00483                 if(NumItemsNeeded == NumItemsRead)
00484                 {
00485                         return SB;
00486                 }
00487                 else
00488                 {
00489                         geErrorLog_Add( ERR_STRBLOCK_FILE_PARSE , NULL);
00490                         geStrBlock_Destroy(&SB); // try to destroy it
00491                         return NULL;
00492                 }
00493         }
00494         else
00495         {
00496                 if (u!=STRBLOCK_BIN_FILE_TYPE)
00497                         {
00498                                 geErrorLog_Add( ERR_STRBLOCK_FILE_PARSE , NULL);
00499                                 return NULL;
00500                         }
00501                 return geStrBlock_CreateFromBinaryFile(pFile);
00502         }
00503                         
00504         geErrorLog_Add( ERR_STRBLOCK_FILE_PARSE , NULL);
00505         return NULL;
00506 }
00507 
00508 geBoolean GENESISCC geStrBlock_WriteToFile(const geStrBlock *SB,geVFile *pFile)
00509 {
00510         uint32 u;
00511         int i,count;
00512 
00513         assert( SB != NULL );
00514         assert( pFile != NULL );
00515         assert( SB->SanityCheck == SB );
00516 
00517 
00518         // Write the format flag
00519         u = STRBLOCK_ASCII_FILE_TYPE;
00520         if(geVFile_Write(pFile, &u, sizeof(u)) == GE_FALSE)
00521         {
00522                 geErrorLog_Add( ERR_STRBLOCK_FILE_WRITE , NULL);
00523                 return GE_FALSE;
00524         }
00525 
00526         // Write the version
00527         if      (geVFile_Printf(pFile, " %X.%.2X\n", (STRBLOCK_FILE_VERSION & 0xFF00) >> 8, 
00528                                                                         STRBLOCK_FILE_VERSION & 0x00FF) == GE_FALSE)
00529         {
00530                 geErrorLog_Add( ERR_STRBLOCK_FILE_WRITE , NULL);
00531                 return GE_FALSE;
00532         }
00533 
00534         count = geStrBlock_GetCount(SB);
00535         if      (geVFile_Printf(pFile, "%s %d\n", STRBLOCK_STRINGARRAY_ID,count) == GE_FALSE)
00536         {
00537                 geErrorLog_Add( ERR_STRBLOCK_FILE_WRITE , NULL);
00538                 return GE_FALSE;
00539         }
00540         for (i=0; i<count; i++)
00541                 {
00542                         assert( strlen(geStrBlock_GetString(SB,i))<STRBLOCK_MAX_STRINGLEN);
00543                         if      (geVFile_Printf(pFile,"%s\n",geStrBlock_GetString(SB,i)) == GE_FALSE)
00544                         {
00545                                 geErrorLog_Add( ERR_STRBLOCK_FILE_WRITE , NULL);
00546                                 return GE_FALSE;
00547                         }
00548                 }
00549         return GE_TRUE;
00550 }
00551 
00552 typedef struct
00553 {
00554         int Count;
00555         uint32 Size;
00556 } geStrBlock_BinaryFileHeader;
00557 
00558 static geStrBlock *GENESISCC geStrBlock_CreateFromBinaryFile(geVFile *pFile)
00559 {
00560         geStrBlock *SB;
00561         geStrBlock_BinaryFileHeader Header;
00562 
00563         assert( pFile != NULL );
00564 
00565         if (geVFile_Read(pFile, &Header,sizeof(geStrBlock_BinaryFileHeader)) == GE_FALSE)
00566                 {
00567                         geErrorLog_Add( ERR_STRBLOCK_FILE_READ , NULL);
00568                         return NULL;
00569                 }
00570         
00571         SB = geRam_Allocate( sizeof(geStrBlock) + Header.Size );
00572         if( SB == NULL )
00573                 {
00574                         geErrorLog_Add(ERR_STRBLOCK_ENOMEM, NULL);
00575                         return NULL;    
00576                 }
00577         SB->SanityCheck = SB;
00578         SB->Count = Header.Count; 
00579 
00580         if (geVFile_Read(pFile, &(SB->Data),Header.Size) == GE_FALSE)
00581                 {
00582                         geErrorLog_Add( ERR_STRBLOCK_FILE_READ , NULL);
00583                         return NULL;
00584                 }
00585         return SB;
00586 }
00587                         
00588 
00589 geBoolean GENESISCC geStrBlock_WriteToBinaryFile(const geStrBlock *SB,geVFile *pFile)
00590 {
00591         uint32 u;
00592         geStrBlock_BinaryFileHeader Header;
00593 
00594         assert( SB != NULL );
00595         assert( pFile != NULL );
00596         assert( SB->SanityCheck == SB );
00597 
00598         // Write the format flag
00599         u = STRBLOCK_BIN_FILE_TYPE;
00600         if(geVFile_Write(pFile, &u, sizeof(u)) == GE_FALSE)
00601                 {
00602                         geErrorLog_Add( ERR_STRBLOCK_FILE_WRITE , NULL);
00603                         return GE_FALSE;
00604                 }
00605 
00606         Header.Size = geStrBlock_BlockSize(SB);
00607         Header.Count = SB->Count;
00608 
00609         if(geVFile_Write(pFile, &Header, sizeof(geStrBlock_BinaryFileHeader)) == GE_FALSE)
00610                 {
00611                         geErrorLog_Add( ERR_STRBLOCK_FILE_WRITE , NULL);
00612                         return GE_FALSE;
00613                 }
00614         
00615         if (geVFile_Write(pFile, &(SB->Data),Header.Size) == GE_FALSE)
00616                 {
00617                         geErrorLog_Add( ERR_STRBLOCK_FILE_WRITE , NULL);
00618                         return GE_FALSE;
00619                 }
00620                 
00621         return GE_TRUE;
00622 }

Generated on Tue Sep 30 12:36:26 2003 for GTestAndEngine by doxygen 1.3.2