00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
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];
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
00154 if (Nth< (*ppSB)->Count-1)
00155 memmove(ToBeReplaced,Replacement,CloseSize);
00156
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
00168 + sizeof(geStrBlock)
00169 - StringLen
00170 - sizeof(int) );
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
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
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
00237 + sizeof(geStrBlock)
00238 + StringLen
00239 + sizeof(int) );
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
00271 memmove(MoveFrom,MoveTo,MoveSize);
00272
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
00335 + sizeof(geStrBlock)
00336 + strlen(String) + 1
00337 + sizeof(int) );
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
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;
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;
00461 }
00462 if ( line[0] != 0 )
00463 line[strlen(line)-1] = 0;
00464 if ( line[0] != 0 )
00465 {
00466 int len = strlen(line)-1;
00467 if (line[len] == 13)
00468 {
00469 line[len] = 0;
00470 }
00471 }
00472 if (geStrBlock_Append(&SB,line)==GE_FALSE)
00473 {
00474 break;
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);
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
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
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
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 }