00001 #include "FileList.h"
00002 #include <stdio.h>
00003 #include "RakAssert.h"
00004 #if defined(_WIN32) || defined(__CYGWIN__)
00005 #include <io.h>
00006 #elif !defined ( __APPLE__ ) && !defined ( __APPLE_CC__ ) && !defined ( __PPC__ ) && !defined ( __FreeBSD__ )
00007 #include <sys/io.h>
00008 #endif
00009 #include "DS_Queue.h"
00010 #ifdef _WIN32
00011
00012 #include <direct.h>
00013 #else
00014 #include <sys/stat.h>
00015 #endif
00016
00017 #include "StringCompressor.h"
00018 #include "BitStream.h"
00019 #include "FileOperations.h"
00020 #include "SuperFastHash.h"
00021 #include "RakAssert.h"
00022 #include "LinuxStrings.h"
00023
00024 #define MAX_FILENAME_LENGTH 512
00025 static const unsigned HASH_LENGTH=sizeof(unsigned int);
00026
00027
00028 #if defined(_XBOX) || defined(X360)
00029 #elif defined(_WIN32)
00030 #include <malloc.h>
00031 #else
00032 #if !defined ( __FreeBSD__ )
00033 #include <alloca.h>
00034 #endif
00035 #include <unistd.h>
00036 #include <stdlib.h>
00037 #include <sys/stat.h>
00038 #include "_FindFirst.h"
00039 #include <stdint.h>
00040 #endif
00041
00042 #include "RakAlloca.h"
00043
00044
00045
00046
00047
00048
00049
00050 #ifdef _MSC_VER
00051 #pragma warning( push )
00052 #endif
00053
00055 void FLP_Printf::OnAddFilesFromDirectoryStarted(FileList *fileList, char *dir) {
00056 (void) fileList;
00057 RAKNET_DEBUG_PRINTF("Adding files from directory %s\n",dir);}
00058
00060 void FLP_Printf::OnDirectory(FileList *fileList, char *dir, unsigned int directoriesRemaining) {
00061 (void) fileList;
00062 RAKNET_DEBUG_PRINTF("Adding %s. %i remaining.\n", dir, directoriesRemaining);}
00063
00064 FileList::FileList()
00065 {
00066 callback=0;
00067 }
00068 FileList::~FileList()
00069 {
00070 Clear();
00071 }
00072 void FileList::AddFile(const char *filepath, const char *filename, FileListNodeContext context)
00073 {
00074 if (filepath==0 || filename==0)
00075 return;
00076
00077 char *data;
00078
00079
00080
00081 FILE *fp = fopen(filepath, "rb");
00082 if (fp==0)
00083 return;
00084 fseek(fp, 0, SEEK_END);
00085 int length = ftell(fp);
00086 fseek(fp, 0, SEEK_SET);
00087
00088 if (length > (int) ((unsigned int)-1 / 8))
00089 {
00090
00091 RakAssert("Cannot add files over 536 MB" && 0);
00092 fclose(fp);
00093 return;
00094 }
00095
00096
00097 #if !defined(_XBOX) && !defined(_X360)
00098 bool usedAlloca=false;
00099 if (length < MAX_ALLOCA_STACK_ALLOCATION)
00100 {
00101 data = ( char* ) alloca( length );
00102 usedAlloca=true;
00103 }
00104 else
00105 #endif
00106 {
00107 data = (char*) rakMalloc_Ex( length, __FILE__, __LINE__ );
00108 }
00109
00110 fread(data, 1, length, fp);
00111 AddFile(filename, filepath, data, length, length, context);
00112 fclose(fp);
00113
00114 #if !defined(_XBOX) && !defined(_X360)
00115 if (usedAlloca==false)
00116 #endif
00117 rakFree_Ex(data, __FILE__, __LINE__ );
00118
00119 }
00120 void FileList::AddFile(const char *filename, const char *fullPathToFile, const char *data, const unsigned dataLength, const unsigned fileLength, FileListNodeContext context, bool isAReference)
00121 {
00122 if (filename==0)
00123 return;
00124 if (strlen(filename)>MAX_FILENAME_LENGTH)
00125 {
00126
00127 RakAssert(0);
00128 return;
00129 }
00130
00131 RakAssert(isAReference==false || data==0);
00132
00133 unsigned i;
00134 for (i=0; i<fileList.Size();i++)
00135 {
00136 if (strcmp(fileList[i].filename, filename)==0)
00137 {
00138 if (fileList[i].fileLengthBytes==fileLength && fileList[i].dataLengthBytes==dataLength &&
00139 (dataLength==0 || fileList[i].data==0 ||
00140 memcmp(fileList[i].data, data, dataLength)==0
00141 ))
00142
00143 return;
00144
00145
00146 rakFree_Ex(fileList[i].data, __FILE__, __LINE__ );
00147 fileList.RemoveAtIndex(i);
00148 break;
00149 }
00150 }
00151
00152 FileListNode n;
00153
00154 if (dataLength && data)
00155 {
00156 n.data=(char*) rakMalloc_Ex( dataLength, __FILE__, __LINE__ );
00157 memcpy(n.data, data, dataLength);
00158 }
00159 else
00160 n.data=0;
00161 n.dataLengthBytes=dataLength;
00162 n.fileLengthBytes=fileLength;
00163 n.isAReference=isAReference;
00164 n.context=context;
00165 n.filename=filename;
00166 n.fullPathToFile=fullPathToFile;
00167
00168 fileList.Insert(n, __FILE__, __LINE__);
00169 }
00170 void FileList::AddFilesFromDirectory(const char *applicationDirectory, const char *subDirectory, bool writeHash, bool writeData, bool recursive, FileListNodeContext context)
00171 {
00172 DataStructures::Queue<char*> dirList;
00173 char root[260];
00174 char fullPath[520];
00175 _finddata_t fileInfo;
00176 intptr_t dir;
00177 FILE *fp;
00178 char *dirSoFar, *fileData;
00179 dirSoFar=(char*) rakMalloc_Ex( 520, __FILE__, __LINE__ );
00180
00181 if (applicationDirectory)
00182 strcpy(root, applicationDirectory);
00183 else
00184 root[0]=0;
00185
00186 int rootLen=(int)strlen(root);
00187 if (rootLen)
00188 {
00189 strcpy(dirSoFar, root);
00190 if (FixEndingSlash(dirSoFar))
00191 rootLen++;
00192 }
00193 else
00194 dirSoFar[0]=0;
00195
00196 if (subDirectory)
00197 {
00198 strcat(dirSoFar, subDirectory);
00199 FixEndingSlash(dirSoFar);
00200 }
00201 if (callback)
00202 callback->OnAddFilesFromDirectoryStarted(this, dirSoFar);
00203
00204 dirList.Push(dirSoFar, __FILE__, __LINE__ );
00205 while (dirList.Size())
00206 {
00207 dirSoFar=dirList.Pop();
00208 strcpy(fullPath, dirSoFar);
00209
00210 strcat(fullPath, "*");
00211
00212
00213 dir=_findfirst(fullPath, &fileInfo );
00214 if (dir==-1)
00215 {
00216 _findclose(dir);
00217 rakFree_Ex(dirSoFar, __FILE__, __LINE__ );
00218 unsigned i;
00219 for (i=0; i < dirList.Size(); i++)
00220 rakFree_Ex(dirList[i], __FILE__, __LINE__ );
00221 return;
00222 }
00223
00224
00225 if (callback)
00226 callback->OnDirectory(this, fullPath, dirList.Size());
00227
00228 do
00229 {
00230
00231 if (strcmp("." , fileInfo.name) == 0 ||
00232 strcmp("..", fileInfo.name) == 0)
00233 {
00234 continue;
00235 }
00236
00237 if ((fileInfo.attrib & (_A_HIDDEN | _A_SUBDIR | _A_SYSTEM))==0)
00238 {
00239 strcpy(fullPath, dirSoFar);
00240 strcat(fullPath, fileInfo.name);
00241 fileData=0;
00242
00243 if (callback)
00244 callback->OnFile(this, dirSoFar, fileInfo.name, fileInfo.size);
00245
00246 if (writeData && writeHash)
00247 {
00248 fileData= (char*) rakMalloc_Ex( fileInfo.size+HASH_LENGTH, __FILE__, __LINE__ );
00249 fp = fopen(fullPath, "rb");
00250 fread(fileData+HASH_LENGTH, fileInfo.size, 1, fp);
00251 fclose(fp);
00252
00253 unsigned int hash = SuperFastHash(fileData+HASH_LENGTH, fileInfo.size);
00254 if (RakNet::BitStream::DoEndianSwap())
00255 RakNet::BitStream::ReverseBytesInPlace((unsigned char*) &hash, sizeof(hash));
00256 memcpy(fileData, &hash, HASH_LENGTH);
00257
00258
00259
00260
00261
00262
00263 AddFile((const char*)fullPath+rootLen, fullPath, fileData, fileInfo.size+HASH_LENGTH, fileInfo.size, context);
00264 }
00265 else if (writeHash)
00266 {
00267
00268
00269
00270
00271 unsigned int hash = SuperFastHashFile(fullPath);
00272 if (RakNet::BitStream::DoEndianSwap())
00273 RakNet::BitStream::ReverseBytesInPlace((unsigned char*) &hash, sizeof(hash));
00274
00275
00276
00277 AddFile((const char*)fullPath+rootLen, fullPath, (const char*)&hash, HASH_LENGTH, fileInfo.size, context);
00278 }
00279 else if (writeData)
00280 {
00281 fileData= (char*) rakMalloc_Ex( fileInfo.size, __FILE__, __LINE__ );
00282 fp = fopen(fullPath, "rb");
00283 fread(fileData, fileInfo.size, 1, fp);
00284 fclose(fp);
00285
00286
00287 AddFile(fullPath+rootLen, fullPath, fileData, fileInfo.size, fileInfo.size, context);
00288 }
00289 else
00290 {
00291
00292 AddFile(fullPath+rootLen, fullPath, 0, 0, fileInfo.size, context);
00293 }
00294
00295 if (fileData)
00296 rakFree_Ex(fileData, __FILE__, __LINE__ );
00297 }
00298 else if ((fileInfo.attrib & _A_SUBDIR) && (fileInfo.attrib & (_A_HIDDEN | _A_SYSTEM))==0 && recursive)
00299 {
00300 char *newDir=(char*) rakMalloc_Ex( 520, __FILE__, __LINE__ );
00301 strcpy(newDir, dirSoFar);
00302 strcat(newDir, fileInfo.name);
00303 strcat(newDir, "/");
00304 dirList.Push(newDir, __FILE__, __LINE__ );
00305 }
00306
00307 } while (_findnext(dir, &fileInfo ) != -1);
00308
00309 _findclose(dir);
00310 rakFree_Ex(dirSoFar, __FILE__, __LINE__ );
00311 }
00312 }
00313 void FileList::Clear(void)
00314 {
00315 unsigned i;
00316 for (i=0; i<fileList.Size(); i++)
00317 {
00318 rakFree_Ex(fileList[i].data, __FILE__, __LINE__ );
00319 }
00320 fileList.Clear(false, __FILE__, __LINE__);
00321 }
00322 void FileList::Serialize(RakNet::BitStream *outBitStream)
00323 {
00324 outBitStream->WriteCompressed(fileList.Size());
00325 unsigned i;
00326 for (i=0; i < fileList.Size(); i++)
00327 {
00328 outBitStream->WriteCompressed(fileList[i].context.op);
00329 outBitStream->WriteCompressed(fileList[i].context.fileId);
00330 stringCompressor->EncodeString(fileList[i].filename.C_String(), MAX_FILENAME_LENGTH, outBitStream);
00331 outBitStream->Write((bool)(fileList[i].dataLengthBytes>0==true));
00332 if (fileList[i].dataLengthBytes>0)
00333 {
00334 outBitStream->WriteCompressed(fileList[i].dataLengthBytes);
00335 outBitStream->Write(fileList[i].data, fileList[i].dataLengthBytes);
00336 }
00337
00338 outBitStream->Write((bool)(fileList[i].fileLengthBytes==fileList[i].dataLengthBytes));
00339 if (fileList[i].fileLengthBytes!=fileList[i].dataLengthBytes)
00340 outBitStream->WriteCompressed(fileList[i].fileLengthBytes);
00341 }
00342 }
00343 bool FileList::Deserialize(RakNet::BitStream *inBitStream)
00344 {
00345 bool b, dataLenNonZero=false, fileLenMatchesDataLen=false;
00346 char filename[512];
00347 unsigned int fileListSize;
00348 FileListNode n;
00349 b=inBitStream->ReadCompressed(fileListSize);
00350 #ifdef _DEBUG
00351 RakAssert(b);
00352 RakAssert(fileListSize < 10000);
00353 #endif
00354 if (b==false || fileListSize > 10000)
00355 return false;
00356 Clear();
00357 unsigned i;
00358 for (i=0; i < fileListSize; i++)
00359 {
00360 inBitStream->ReadCompressed(n.context.op);
00361 inBitStream->ReadCompressed(n.context.fileId);
00362 stringCompressor->DecodeString((char*)filename, MAX_FILENAME_LENGTH, inBitStream);
00363 inBitStream->Read(dataLenNonZero);
00364 if (dataLenNonZero)
00365 {
00366 inBitStream->ReadCompressed(n.dataLengthBytes);
00367
00368 if (n.dataLengthBytes>2000000000)
00369 {
00370 #ifdef _DEBUG
00371 RakAssert(n.dataLengthBytes<=2000000000);
00372 #endif
00373 return false;
00374 }
00375 n.data=(char*) rakMalloc_Ex( (size_t) n.dataLengthBytes, __FILE__, __LINE__ );
00376 inBitStream->Read(n.data, n.dataLengthBytes);
00377 }
00378 else
00379 {
00380 n.dataLengthBytes=0;
00381 n.data=0;
00382 }
00383
00384 b=inBitStream->Read(fileLenMatchesDataLen);
00385 if (fileLenMatchesDataLen)
00386 n.fileLengthBytes=(unsigned) n.dataLengthBytes;
00387 else
00388 b=inBitStream->ReadCompressed(n.fileLengthBytes);
00389 #ifdef _DEBUG
00390 RakAssert(b);
00391 #endif
00392 if (b==0)
00393 {
00394 Clear();
00395 return false;
00396 }
00397 n.filename=filename;
00398 n.fullPathToFile=filename;
00399 fileList.Insert(n, __FILE__, __LINE__);
00400 }
00401
00402 return true;
00403 }
00404 void FileList::GetDeltaToCurrent(FileList *input, FileList *output, const char *dirSubset, const char *remoteSubdir)
00405 {
00406
00407
00408 unsigned thisIndex, inputIndex;
00409 unsigned dirSubsetLen, localPathLen, remoteSubdirLen;
00410 bool match;
00411 if (dirSubset)
00412 dirSubsetLen = (unsigned int) strlen(dirSubset);
00413 else
00414 dirSubsetLen = 0;
00415 if (remoteSubdir && remoteSubdir[0])
00416 {
00417 remoteSubdirLen=(unsigned int) strlen(remoteSubdir);
00418 if (IsSlash(remoteSubdir[remoteSubdirLen-1]))
00419 remoteSubdirLen--;
00420 }
00421 else
00422 remoteSubdirLen=0;
00423
00424 for (thisIndex=0; thisIndex < fileList.Size(); thisIndex++)
00425 {
00426 localPathLen = (unsigned int) fileList[thisIndex].filename.GetLength();
00427 while (localPathLen>0)
00428 {
00429 if (IsSlash(fileList[thisIndex].filename[localPathLen-1]))
00430 {
00431 localPathLen--;
00432 break;
00433 }
00434 localPathLen--;
00435 }
00436
00437
00438 if (dirSubsetLen>0 &&
00439 (localPathLen<dirSubsetLen ||
00440 _strnicmp(fileList[thisIndex].filename.C_String(), dirSubset, dirSubsetLen)!=0 ||
00441 (localPathLen>dirSubsetLen && IsSlash(fileList[thisIndex].filename[dirSubsetLen])==false)))
00442 continue;
00443
00444 match=false;
00445 for (inputIndex=0; inputIndex < input->fileList.Size(); inputIndex++)
00446 {
00447
00448 if (_stricmp(input->fileList[inputIndex].filename.C_String()+remoteSubdirLen,fileList[thisIndex].filename.C_String()+dirSubsetLen)==0)
00449 {
00450 match=true;
00451 if (input->fileList[inputIndex].fileLengthBytes==fileList[thisIndex].fileLengthBytes &&
00452 input->fileList[inputIndex].dataLengthBytes==fileList[thisIndex].dataLengthBytes &&
00453 memcmp(input->fileList[inputIndex].data,fileList[thisIndex].data,(size_t) fileList[thisIndex].dataLengthBytes)==0)
00454 {
00455
00456 break;
00457 }
00458 else
00459 {
00460
00461 output->AddFile(fileList[thisIndex].filename, fileList[thisIndex].fullPathToFile, 0,0, fileList[thisIndex].fileLengthBytes, FileListNodeContext(0,0), false);
00462 break;
00463 }
00464 }
00465 }
00466 if (match==false)
00467 {
00468
00469 output->AddFile(fileList[thisIndex].filename, fileList[thisIndex].fullPathToFile, 0,0, fileList[thisIndex].fileLengthBytes, FileListNodeContext(0,0), false);
00470 }
00471 }
00472 }
00473 void FileList::ListMissingOrChangedFiles(const char *applicationDirectory, FileList *missingOrChangedFiles, bool alwaysWriteHash, bool neverWriteHash)
00474 {
00475 unsigned fileLength;
00476
00477 FILE *fp;
00478 char fullPath[512];
00479 unsigned i;
00480
00481
00482 for (i=0; i < fileList.Size(); i++)
00483 {
00484 strcpy(fullPath, applicationDirectory);
00485 FixEndingSlash(fullPath);
00486 strcat(fullPath,fileList[i].filename);
00487 fp=fopen(fullPath, "rb");
00488 if (fp==0)
00489 {
00490 missingOrChangedFiles->AddFile(fileList[i].filename, fileList[i].fullPathToFile, 0, 0, 0, FileListNodeContext(0,0), false);
00491 }
00492 else
00493 {
00494 fseek(fp, 0, SEEK_END);
00495 fileLength = ftell(fp);
00496 fseek(fp, 0, SEEK_SET);
00497
00498 if (fileLength != fileList[i].fileLengthBytes && alwaysWriteHash==false)
00499 {
00500 missingOrChangedFiles->AddFile(fileList[i].filename, fileList[i].fullPathToFile, 0, 0, fileLength, FileListNodeContext(0,0), false);
00501 }
00502 else
00503 {
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514 unsigned int hash = SuperFastHashFilePtr(fp);
00515 if (RakNet::BitStream::DoEndianSwap())
00516 RakNet::BitStream::ReverseBytesInPlace((unsigned char*) &hash, sizeof(hash));
00517
00518
00519 if (fileLength != fileList[i].fileLengthBytes || memcmp( &hash, fileList[i].data, HASH_LENGTH)!=0)
00520 {
00521 if (neverWriteHash==false)
00522
00523 missingOrChangedFiles->AddFile((const char*)fileList[i].filename, (const char*)fileList[i].fullPathToFile, (const char *) &hash, HASH_LENGTH, fileLength, FileListNodeContext(0,0), false);
00524 else
00525 missingOrChangedFiles->AddFile((const char*)fileList[i].filename, (const char*)fileList[i].fullPathToFile, 0, 0, fileLength, FileListNodeContext(0,0), false);
00526 }
00527 }
00528 fclose(fp);
00529 }
00530 }
00531 }
00532 void FileList::PopulateDataFromDisk(const char *applicationDirectory, bool writeFileData, bool writeFileHash, bool removeUnknownFiles)
00533 {
00534 FILE *fp;
00535 char fullPath[512];
00536 unsigned i;
00537
00538
00539 i=0;
00540 while (i < fileList.Size())
00541 {
00542 rakFree_Ex(fileList[i].data, __FILE__, __LINE__ );
00543 strcpy(fullPath, applicationDirectory);
00544 FixEndingSlash(fullPath);
00545 strcat(fullPath,fileList[i].filename.C_String());
00546 fp=fopen(fullPath, "rb");
00547 if (fp)
00548 {
00549 if (writeFileHash || writeFileData)
00550 {
00551 fseek(fp, 0, SEEK_END);
00552 fileList[i].fileLengthBytes = ftell(fp);
00553 fseek(fp, 0, SEEK_SET);
00554 if (writeFileHash)
00555 {
00556 if (writeFileData)
00557 {
00558
00559 fileList[i].data=(char*) rakMalloc_Ex( fileList[i].fileLengthBytes+HASH_LENGTH, __FILE__, __LINE__ );
00560 fread(fileList[i].data+HASH_LENGTH, fileList[i].fileLengthBytes, 1, fp);
00561
00562
00563
00564 unsigned int hash = SuperFastHash(fileList[i].data+HASH_LENGTH, fileList[i].fileLengthBytes);
00565 if (RakNet::BitStream::DoEndianSwap())
00566 RakNet::BitStream::ReverseBytesInPlace((unsigned char*) &hash, sizeof(hash));
00567
00568 memcpy(fileList[i].data, &hash, HASH_LENGTH);
00569 }
00570 else
00571 {
00572
00573 fileList[i].dataLengthBytes=HASH_LENGTH;
00574 if (fileList[i].fileLengthBytes < HASH_LENGTH)
00575 fileList[i].data=(char*) rakMalloc_Ex( HASH_LENGTH, __FILE__, __LINE__ );
00576 else
00577 fileList[i].data=(char*) rakMalloc_Ex( fileList[i].fileLengthBytes, __FILE__, __LINE__ );
00578 fread(fileList[i].data, fileList[i].fileLengthBytes, 1, fp);
00579
00580
00581
00582 unsigned int hash = SuperFastHash(fileList[i].data, fileList[i].fileLengthBytes);
00583 if (RakNet::BitStream::DoEndianSwap())
00584 RakNet::BitStream::ReverseBytesInPlace((unsigned char*) &hash, sizeof(hash));
00585
00586 memcpy(fileList[i].data, &hash, HASH_LENGTH);
00587 }
00588 }
00589 else
00590 {
00591
00592 fileList[i].dataLengthBytes=fileList[i].fileLengthBytes;
00593 fileList[i].data=(char*) rakMalloc_Ex( fileList[i].fileLengthBytes, __FILE__, __LINE__ );
00594 fread(fileList[i].data, fileList[i].fileLengthBytes, 1, fp);
00595 }
00596
00597 fclose(fp);
00598 i++;
00599 }
00600 else
00601 {
00602 fileList[i].data=0;
00603 fileList[i].dataLengthBytes=0;
00604 }
00605 }
00606 else
00607 {
00608 if (removeUnknownFiles)
00609 {
00610 fileList.RemoveAtIndex(i);
00611 }
00612 else
00613 i++;
00614 }
00615 }
00616 }
00617 void FileList::FlagFilesAsReferences(void)
00618 {
00619 for (unsigned int i=0; i < fileList.Size(); i++)
00620 {
00621 fileList[i].isAReference=true;
00622 fileList[i].dataLengthBytes=fileList[i].fileLengthBytes;
00623 }
00624 }
00625 void FileList::WriteDataToDisk(const char *applicationDirectory)
00626 {
00627 char fullPath[512];
00628 unsigned i,j;
00629
00630 for (i=0; i < fileList.Size(); i++)
00631 {
00632 strcpy(fullPath, applicationDirectory);
00633 FixEndingSlash(fullPath);
00634 strcat(fullPath,fileList[i].filename.C_String());
00635
00636
00637 for (j=1; j < fileList[i].filename.GetLength(); j++)
00638 {
00639 if (fileList[i].filename[j]=='.' && fileList[i].filename[j-1]=='.')
00640 {
00641 #ifdef _DEBUG
00642 RakAssert(0);
00643 #endif
00644
00645 return;
00646 }
00647 }
00648
00649 WriteFileWithDirectories(fullPath, fileList[i].data, (unsigned int) fileList[i].dataLengthBytes);
00650 }
00651 }
00652
00653 #ifdef _MSC_VER
00654 #pragma warning( disable : 4966 ) // unlink declared deprecated by Microsoft in order to make it harder to be cross platform. I don't agree it's deprecated.
00655 #endif
00656 void FileList::DeleteFiles(const char *applicationDirectory)
00657 {
00658 char fullPath[512];
00659 unsigned i,j;
00660
00661 for (i=0; i < fileList.Size(); i++)
00662 {
00663
00664 for (j=1; j < fileList[i].filename.GetLength(); j++)
00665 {
00666 if (fileList[i].filename[j]=='.' && fileList[i].filename[j-1]=='.')
00667 {
00668 #ifdef _DEBUG
00669 RakAssert(0);
00670 #endif
00671
00672 return;
00673 }
00674 }
00675
00676 strcpy(fullPath, applicationDirectory);
00677 FixEndingSlash(fullPath);
00678 strcat(fullPath, fileList[i].filename.C_String());
00679
00680 #ifdef _MSC_VER
00681 #pragma warning( disable : 4966 ) // unlink declared deprecated by Microsoft in order to make it harder to be cross platform. I don't agree it's deprecated.
00682 #endif
00683 int result = unlink(fullPath);
00684 if (result!=0)
00685 {
00686 RAKNET_DEBUG_PRINTF("FileList::DeleteFiles: unlink (%s) failed.\n", fullPath);
00687 }
00688 }
00689 }
00690
00691 void FileList::SetCallback(FileListProgress *cb)
00692 {
00693 callback=cb;
00694 }
00695
00696 bool FileList::FixEndingSlash(char *str)
00697 {
00698 #ifdef _WIN32
00699 if (str[strlen(str)-1]!='/' && str[strlen(str)-1]!='\\')
00700 {
00701 strcat(str, "\\");
00702 return true;
00703 }
00704 #else
00705 if (str[strlen(str)-1]!='\\' && str[strlen(str)-1]!='/')
00706 {
00707 strcat(str, "/");
00708 return true;
00709 }
00710 #endif
00711
00712 return false;
00713 }
00714
00715 #ifdef _MSC_VER
00716 #pragma warning( pop )
00717 #endif