1.1 --- a/core/GameDataFetcher.cpp Mon Dec 22 20:12:33 2008 -0600
1.2 +++ b/core/GameDataFetcher.cpp Fri Dec 26 23:26:21 2008 -0500
1.3 @@ -42,8 +42,9 @@
1.4 #include <netdb.h>
1.5 #include <arpa/inet.h>
1.6
1.7 -#define INVALID_SOCKET -1
1.8 -#define closesocket close
1.9 +#define INVALID_SOCKET -1
1.10 +#define closesocket close
1.11 +#define WSAGetLastError() errno
1.12 #endif
1.13
1.14 #include "sh_vector.h"
1.15 @@ -61,6 +62,7 @@
1.16 #include "TimerSys.h"
1.17 #include "compat_wrappers.h"
1.18 #include "sm_stringutil.h"
1.19 +#include "md5.h"
1.20
1.21 #define QUERY_MAX_LENGTH 1024
1.22
1.23 @@ -73,9 +75,9 @@
1.24 bool g_restartAfterUpdate = false;
1.25
1.26 int g_serverPort = 6500;
1.27 -char g_serverAddress[100] = "hayate.alliedmods.net";
1.28 +char g_serverAddress[100] = "smupdate.alliedmods.net";
1.29
1.30 -void FetcherThread::RunThread( IThreadHandle *pHandle )
1.31 +void FetcherThread::RunThread(IThreadHandle *pHandle)
1.32 {
1.33 char lock_path[PLATFORM_MAX_PATH];
1.34 g_SourceMod.BuildPath(Path_SM, lock_path, sizeof(lock_path), "data/temp");
1.35 @@ -127,9 +129,7 @@
1.36
1.37 if (g_disableGameDataUpdate)
1.38 {
1.39 -#ifdef DEBUG
1.40 g_Logger.LogMessage("Skipping GameData Query due to DisableAutoUpdate being set to true");
1.41 -#endif
1.42
1.43 fclose(logfile);
1.44 unlink(lock_path);
1.45 @@ -148,13 +148,15 @@
1.46
1.47 int sent = SendData(socketDescriptor, query, len);
1.48
1.49 -#ifdef DEBUG
1.50 - g_Logger.LogToOpenFile(logfile, "Sent Query!");
1.51 -#endif
1.52 +IF_DEBUG_SPEW
1.53 + g_Logger.LogToOpenFile(logfile, "Sent gamedata query");
1.54 +ENDIF_DEBUG_SPEW
1.55
1.56 if (sent == 0)
1.57 {
1.58 +IF_DEBUG_SPEW
1.59 g_Logger.LogToOpenFile(logfile, "Failed to send gamedata query data to remote host");
1.60 +ENDIF_DEBUG_SPEW
1.61
1.62 closesocket(socketDescriptor);
1.63 fclose(logfile);
1.64 @@ -170,12 +172,12 @@
1.65 unlink(lock_path);
1.66 }
1.67
1.68 -void FetcherThread::OnTerminate( IThreadHandle *pHandle, bool cancel )
1.69 +void FetcherThread::OnTerminate(IThreadHandle *pHandle, bool cancel)
1.70 {
1.71 g_blockGameDataLoad = false;
1.72 }
1.73
1.74 -int FetcherThread::BuildGameDataQuery( char *buffer, int maxlen )
1.75 +int FetcherThread::BuildGameDataQuery(char *buffer, int maxlen)
1.76 {
1.77 char gamedata_path[PLATFORM_MAX_PATH];
1.78 g_SourceMod.BuildPath(Path_SM, gamedata_path, sizeof(gamedata_path), "gamedata");
1.79 @@ -204,41 +206,39 @@
1.80 {
1.81 const char *name = dir->GetEntryName();
1.82 size_t len = strlen(name);
1.83 - if (len >= 4
1.84 - && strcmp(&name[len-4], ".txt") == 0)
1.85 + if (len >= 4 && strcmp(&name[len-4], ".txt") == 0)
1.86 {
1.87 + MD5 md5;
1.88 + SMCError err;
1.89 + SMCStates states;
1.90 + unsigned char raw[16];
1.91 char file[PLATFORM_MAX_PATH];
1.92
1.93 g_LibSys.PathFormat(file, sizeof(file), "%s/%s", gamedata_path, name);
1.94
1.95 - SMCStates states;
1.96 - if (g_TextParser.ParseFile_SMC(file, &g_MD5Builder, &states) == SMCError_Okay)
1.97 + g_MD5Builder.checksum = &md5;
1.98 + if ((err = g_TextParser.ParseFile_SMC(file, &g_MD5Builder, &states)) == SMCError_Okay)
1.99 {
1.100 - unsigned char *md5 = g_MD5Builder.GetMD5();
1.101 - if (md5 != NULL)
1.102 - {
1.103 - (uint8_t)buffer[10]++; //Increment the file counter
1.104 - Writer.WriteBytes(md5, 16);
1.105 -
1.106 - g_Logger.LogToOpenFile(logfile, "%s - \"%s\"", file, g_MD5Builder.GetMD5String());
1.107 + md5.raw_digest(raw);
1.108 + (uint8_t)buffer[10]++; //Increment the file counter
1.109 + Writer.WriteBytes(raw, 16);
1.110
1.111 - FileData *data = new FileData();
1.112 - data->filename = new SourceHook::String(file);
1.113 - memcpy(data->checksum, g_MD5Builder.GetMD5String(), 33);
1.114 - filenames.push_back(data);
1.115 - }
1.116 - else
1.117 - {
1.118 -#ifdef DEBUG
1.119 - g_Logger.LogToOpenFile(logfile, "%s no md5?", file);
1.120 -#endif
1.121 - }
1.122 + FileData *data = new FileData();
1.123 + data->filename = new SourceHook::String(file);
1.124 + md5.hex_digest(data->checksum);
1.125 + filenames.push_back(data);
1.126 +
1.127 +IF_DEBUG_SPEW
1.128 + g_Logger.LogToOpenFile(logfile, "Parsed file: %s as %s", file, data->checksum);
1.129 +ENDIF_DEBUG_SPEW
1.130 +
1.131 }
1.132 else
1.133 {
1.134 -#ifdef DEBUG
1.135 - g_Logger.LogToOpenFile(logfile, "%s failed!", file);
1.136 -#endif
1.137 +IF_DEBUG_SPEW
1.138 + const char *error = g_TextParser.GetSMCErrorString(err);
1.139 + g_Logger.LogToOpenFile(logfile, "Parsing of file %s failed: %s", file, error);
1.140 +ENDIF_DEBUG_SPEW
1.141 }
1.142 }
1.143 }
1.144 @@ -251,17 +251,16 @@
1.145
1.146 int FetcherThread::ConnectSocket()
1.147 {
1.148 - struct protoent *ptrp;
1.149 - ptrp = getprotobyname("tcp");
1.150 -
1.151 -#ifdef WIN32
1.152 +#if defined PLATFORM_WINDOWS
1.153 WSADATA wsaData;
1.154 WSAStartup(0x0101, &wsaData);
1.155 #endif
1.156
1.157 - if (ptrp == NULL)
1.158 + struct protoent *ptrp;
1.159 +
1.160 + if ((ptrp = getprotobyname("tcp")) == NULL)
1.161 {
1.162 - g_Logger.LogToOpenFile(logfile, "Failed to find TCP");
1.163 + g_Logger.LogToOpenFile(logfile, "Error: Failed to find TCP protocol");
1.164 return INVALID_SOCKET;
1.165 }
1.166
1.167 @@ -269,12 +268,9 @@
1.168
1.169 if (socketDescriptor == INVALID_SOCKET)
1.170 {
1.171 - //bugger aye?
1.172 -#ifdef WIN32
1.173 - g_Logger.LogToOpenFile(logfile, "Failed to create a new socket - Error %i", WSAGetLastError());
1.174 -#else
1.175 - g_Logger.LogToOpenFile(logfile, "Failed to create a new socket - Error %i", errno);
1.176 -#endif
1.177 + char error[255];
1.178 + g_LibSys.GetPlatformErrorEx(WSAGetLastError(), error, sizeof(error));
1.179 + g_Logger.LogToOpenFile(logfile, "Error: Failed to create socket: %s", error);
1.180 closesocket(socketDescriptor);
1.181 return INVALID_SOCKET;
1.182 }
1.183 @@ -291,7 +287,7 @@
1.184 {
1.185 if ((local_addr.sin_addr.s_addr = inet_addr(g_serverAddress)) == INADDR_NONE)
1.186 {
1.187 - g_Logger.LogToOpenFile(logfile, "Couldn't locate address");
1.188 + g_Logger.LogToOpenFile(logfile, "Couldn't locate address: %s", g_serverAddress);
1.189 closesocket(socketDescriptor);
1.190 return INVALID_SOCKET;
1.191 }
1.192 @@ -303,11 +299,9 @@
1.193
1.194 if (connect(socketDescriptor, (struct sockaddr *) &local_addr, sizeof(local_addr)) < 0)
1.195 {
1.196 -#ifdef WIN32
1.197 - g_Logger.LogToOpenFile(logfile, "Couldn't connect - Error %i", WSAGetLastError());
1.198 -#else
1.199 - g_Logger.LogToOpenFile(logfile, "Couldn't connect - Error %i", errno);
1.200 -#endif
1.201 + char error[255];
1.202 + g_LibSys.GetPlatformErrorEx(WSAGetLastError(), error, sizeof(error));
1.203 + g_Logger.LogToOpenFile(logfile, "Couldn't connect to %s: %s", g_serverAddress, error);
1.204 closesocket(socketDescriptor);
1.205 return INVALID_SOCKET;
1.206 }
1.207 @@ -318,35 +312,34 @@
1.208 void FetcherThread::ProcessGameDataQuery(int socketDescriptor)
1.209 {
1.210 char buffer[50];
1.211 -#ifdef DEBUG
1.212 +
1.213 +IF_DEBUG_SPEW
1.214 g_Logger.LogToOpenFile(logfile, "Waiting for reply!");
1.215 -#endif
1.216 +ENDIF_DEBUG_SPEW
1.217
1.218 //Read in the header bytes
1.219 int returnLen = RecvData(socketDescriptor, buffer, 12);
1.220
1.221 -#ifdef DEBUG
1.222 - g_Logger.LogToOpenFile(logfile, "Recv Completed");
1.223 -#endif
1.224
1.225 if (returnLen == 0)
1.226 {
1.227 -#ifdef DEBUG
1.228 - g_Logger.LogToOpenFile(logfile, ",but it failed.");
1.229 -#endif
1.230 - /* Timeout or fail? */
1.231 + char error[255];
1.232 + g_LibSys.GetPlatformErrorEx(WSAGetLastError(), error, sizeof(error));
1.233 + g_Logger.LogToOpenFile(logfile, "Did not receive reply: %s", error);
1.234 return;
1.235 }
1.236
1.237 -#ifdef DEBUG
1.238 +IF_DEBUG_SPEW
1.239 g_Logger.LogToOpenFile(logfile, "Received Header!");
1.240 -#endif
1.241 +ENDIF_DEBUG_SPEW
1.242
1.243 bf_read Reader = bf_read("GameDataQuery", buffer, 12);
1.244
1.245 if (Reader.ReadByte() != 'A' || Reader.ReadByte() != 'G')
1.246 {
1.247 +IF_DEBUG_SPEW
1.248 g_Logger.LogToOpenFile(logfile, "Unknown Query Response");
1.249 +ENDIF_DEBUG_SPEW
1.250 return;
1.251 }
1.252
1.253 @@ -359,17 +352,23 @@
1.254 build[2] = Reader.ReadShort();
1.255 build[3] = Reader.ReadShort();
1.256
1.257 -#ifdef DEBUG
1.258 - g_Logger.LogToOpenFile(logfile, "Update Status: %i - Latest %i.%i.%i.%i", updateStatus, build[0], build[1], build[2], build[3]);
1.259 -#endif
1.260 +IF_DEBUG_SPEW
1.261 + g_Logger.LogToOpenFile(logfile,
1.262 + "Update Status: %i - Latest %i.%i.%i.%i",
1.263 + updateStatus,
1.264 + build[0],
1.265 + build[1],
1.266 + build[2],
1.267 + build[3]);
1.268 +ENDIF_DEBUG_SPEW
1.269
1.270 HandleUpdateStatus(updateStatus, build);
1.271
1.272 int changedFiles = Reader.ReadByte();
1.273
1.274 -#ifdef DEBUG
1.275 +IF_DEBUG_SPEW
1.276 g_Logger.LogToOpenFile(logfile, "Files to download: %i", changedFiles);
1.277 -#endif
1.278 +ENDIF_DEBUG_SPEW
1.279
1.280 for (int i=0; i<changedFiles; i++)
1.281 {
1.282 @@ -387,9 +386,9 @@
1.283 int index = Reader.ReadByte();
1.284 int tempLen = Reader.ReadUBitLong(32);
1.285
1.286 -#ifdef DEBUG
1.287 +IF_DEBUG_SPEW
1.288 g_Logger.LogToOpenFile(logfile, "File index %i and length %i", index, tempLen);
1.289 -#endif
1.290 +ENDIF_DEBUG_SPEW
1.291
1.292 void *memPtr;
1.293 memtable->CreateMem(tempLen+1, &memPtr);
1.294 @@ -397,9 +396,9 @@
1.295 //Read the contents of our file into the memtable
1.296 returnLen = RecvData(socketDescriptor, (char *)memPtr, tempLen);
1.297
1.298 -#ifdef DEBUG
1.299 - g_Logger.LogToOpenFile(logfile, "Recieved %i bytes", returnLen);
1.300 -#endif
1.301 +IF_DEBUG_SPEW
1.302 + g_Logger.LogToOpenFile(logfile, "Received %i bytes", returnLen);
1.303 +ENDIF_DEBUG_SPEW
1.304
1.305 if (returnLen == 0)
1.306 {
1.307 @@ -410,7 +409,7 @@
1.308 ((unsigned char *)memPtr)[tempLen] = '\0';
1.309
1.310 FileData *data = filenames.at(index);
1.311 - const char* filename;
1.312 + const char *filename;
1.313 if (data != NULL)
1.314 {
1.315 filename = data->filename->c_str();
1.316 @@ -419,12 +418,12 @@
1.317
1.318 if (fp)
1.319 {
1.320 - fprintf(fp, (const char *)memPtr);
1.321 + fprintf(fp, "%s", (const char *)memPtr);
1.322 fclose(fp);
1.323 }
1.324 else
1.325 {
1.326 - g_Logger.LogToOpenFile(logfile, "Failed to open file \"%s\"", filename);
1.327 + g_Logger.LogToOpenFile(logfile, "Failed to open file \"%s\" for writing", filename);
1.328 }
1.329 }
1.330 else
1.331 @@ -434,14 +433,13 @@
1.332
1.333 memtable->Reset();
1.334
1.335 -#ifdef DEBUG
1.336 - g_Logger.LogToOpenFile(logfile, "Updated File %s", filename);
1.337 -#endif
1.338 +
1.339 + g_Logger.LogToOpenFile(logfile, "Updated file: %s", filename);
1.340 }
1.341
1.342 -#ifdef DEBUG
1.343 +IF_DEBUG_SPEW
1.344 g_Logger.LogToOpenFile(logfile, "File Downloads Completed!");
1.345 -#endif
1.346 +ENDIF_DEBUG_SPEW
1.347
1.348 bool needsRestart = false;
1.349
1.350 @@ -456,8 +454,9 @@
1.351
1.352 if (returnLen == 0)
1.353 {
1.354 - /* Timeout or fail? */
1.355 - g_Logger.LogToOpenFile(logfile, "Failed to receive unknown count");
1.356 + char error[255];
1.357 + g_LibSys.GetPlatformErrorEx(WSAGetLastError(), error, sizeof(error));
1.358 + g_Logger.LogToOpenFile(logfile, "Did not receive count reply: %s", error);
1.359 return;
1.360 }
1.361
1.362 @@ -465,28 +464,27 @@
1.363
1.364 changedFiles = Reader.ReadByte();
1.365
1.366 - if (changedFiles == 0)
1.367 + if (changedFiles < 1)
1.368 {
1.369 -#ifdef DEBUG
1.370 +IF_DEBUG_SPEW
1.371 g_Logger.LogToOpenFile(logfile, "No unknown files. We're all done");
1.372 -#endif
1.373 +ENDIF_DEBUG_SPEW
1.374 return;
1.375 }
1.376
1.377 char *changedFileIndexes = new char[changedFiles];
1.378
1.379 -#ifdef DEBUG
1.380 +IF_DEBUG_SPEW
1.381 g_Logger.LogToOpenFile(logfile, "%i Files were unknown", changedFiles);
1.382 -#endif
1.383 +ENDIF_DEBUG_SPEW
1.384
1.385 returnLen = RecvData(socketDescriptor, changedFileIndexes, changedFiles);
1.386
1.387 if (returnLen == 0)
1.388 {
1.389 - /* Timeout or fail? */
1.390 -#ifdef DEBUG
1.391 - g_Logger.LogToOpenFile(logfile, "Failed to receive unknown list");
1.392 -#endif
1.393 + char error[255];
1.394 + g_LibSys.GetPlatformErrorEx(WSAGetLastError(), error, sizeof(error));
1.395 + g_Logger.LogToOpenFile(logfile, "Did not receive list reply: %s", error);
1.396 return;
1.397 }
1.398
1.399 @@ -509,21 +507,22 @@
1.400 }
1.401
1.402 g_LibSys.GetFileFromPath(fileName, sizeof(fileName), pathname);
1.403 -#ifdef DEBUG
1.404 +IF_DEBUG_SPEW
1.405 g_Logger.LogToOpenFile(logfile, "Unknown File %i : %s", index, fileName);
1.406 -#endif
1.407 +ENDIF_DEBUG_SPEW
1.408 }
1.409
1.410 delete [] changedFileIndexes;
1.411
1.412 if (needsRestart && g_restartAfterUpdate)
1.413 {
1.414 + /* :TODO: none of this is thread safe. */
1.415 g_Logger.LogMessage("Automatically restarting server after a successful gamedata update!");
1.416 engine->ServerCommand("quit\n");
1.417 }
1.418 }
1.419
1.420 -int FetcherThread::RecvData( int socketDescriptor, char *buffer, int len )
1.421 +int FetcherThread::RecvData(int socketDescriptor, char *buffer, int len)
1.422 {
1.423 fd_set fds;
1.424 struct timeval tv;
1.425 @@ -562,7 +561,7 @@
1.426 return bytesReceivedTotal;
1.427 }
1.428
1.429 -int FetcherThread::SendData( int socketDescriptor, char *buffer, int len )
1.430 +int FetcherThread::SendData(int socketDescriptor, char *buffer, int len)
1.431 {
1.432 fd_set fds;
1.433 struct timeval tv;
1.434 @@ -597,7 +596,7 @@
1.435 return sentBytesTotal;
1.436 }
1.437
1.438 -void FetcherThread::HandleUpdateStatus( UpdateStatus status, short version[4] )
1.439 +void FetcherThread::HandleUpdateStatus(UpdateStatus status, short version[4])
1.440 {
1.441 switch (status)
1.442 {
1.443 @@ -609,14 +608,12 @@
1.444
1.445 case Update_NewBuild:
1.446 {
1.447 - g_Logger.LogMessage("SourceMod Update: A new Mercurial build is available from sourcemod.net");
1.448 - g_Logger.LogMessage("Current Version: %i.%i.%i.%i Available: %i.%i.%i.%i", version[0], version[1], version[2], version[3], version[0], version[1], version[2], version[3]);
1.449 break;
1.450 }
1.451
1.452 case Update_MinorAvailable:
1.453 {
1.454 - g_Logger.LogMessage("SourceMod Update: An incremental minor release of SourceMod is now available from sourcemod.net");
1.455 + g_Logger.LogMessage("SourceMod Update: A new release of SourceMod is now available from sourcemod.net");
1.456 g_Logger.LogMessage("Current Version: %i.%i.%i Available: %i.%i.%i", version[0], version[1], version[2], version[0], version[1], version[2]);
1.457 break;
1.458 }
1.459 @@ -630,8 +627,8 @@
1.460
1.461 case Update_CriticalAvailable:
1.462 {
1.463 - g_Logger.LogError("SourceMod Update: A new critical release of SourceMod is now available from sourcemod.net. It is strongly recommended that you update");
1.464 - g_Logger.LogMessage("Current Version: %i.%i.%i.%i Available: %i.%i.%i.%i", version[0], version[1], version[2], version[3], version[0], version[1], version[2], version[3]);
1.465 + g_Logger.LogError("SourceMod Update: A critical SourceMod release is available from sourcemod.net. It is strongly recommended that you update!");
1.466 + g_Logger.LogMessage("Current Version: %i.%i.%i Available: %i.%i.%i", version[0], version[1], version[2], version[0], version[1], version[2]);
1.467 break;
1.468 }
1.469 }
1.470 @@ -665,14 +662,14 @@
1.471 char *error,
1.472 size_t maxlength)
1.473 {
1.474 - if (strcmp(key, "DisableAutoUpdate") == 0)
1.475 + if (strcasecmp(key, "DisableAutoUpdate") == 0)
1.476 {
1.477 - if (strcmp(value, "yes") == 0)
1.478 + if (strcasecmp(value, "yes") == 0)
1.479 {
1.480 g_disableGameDataUpdate = true;
1.481 return ConfigResult_Accept;
1.482 }
1.483 - else if (strcmp(value, "no") == 0)
1.484 + else if (strcasecmp(value, "no") == 0)
1.485 {
1.486 g_disableGameDataUpdate = false;
1.487 return ConfigResult_Accept;
1.488 @@ -681,14 +678,14 @@
1.489 return ConfigResult_Reject;
1.490 }
1.491
1.492 - if (strcmp(key, "ForceRestartAfterUpdate") == 0)
1.493 + if (strcasecmp(key, "ForceRestartAfterUpdate") == 0)
1.494 {
1.495 - if (strcmp(value, "yes") == 0)
1.496 + if (strcasecmp(value, "yes") == 0)
1.497 {
1.498 g_restartAfterUpdate = true;
1.499 return ConfigResult_Accept;
1.500 }
1.501 - else if (strcmp(value, "no") == 0)
1.502 + else if (strcasecmp(value, "no") == 0)
1.503 {
1.504 g_restartAfterUpdate = false;
1.505 return ConfigResult_Accept;
1.506 @@ -697,14 +694,14 @@
1.507 return ConfigResult_Reject;
1.508 }
1.509
1.510 - if (strcmp(key, "AutoUpdateServer") == 0)
1.511 + if (strcasecmp(key, "AutoUpdateServer") == 0)
1.512 {
1.513 UTIL_Format(g_serverAddress, sizeof(g_serverAddress), "%s", value);
1.514
1.515 return ConfigResult_Accept;
1.516 }
1.517
1.518 - if (strcmp(key, "AutoUpdatePort") == 0)
1.519 + if (strcasecmp(key, "AutoUpdatePort") == 0)
1.520 {
1.521 int port = atoi(value);
1.522
1.523 @@ -722,6 +719,55 @@
1.524 }
1.525 } g_InitFetch;
1.526
1.527 +BuildMD5ableBuffer::BuildMD5ableBuffer()
1.528 +{
1.529 + stringTable = new BaseStringTable(2048);
1.530 +}
1.531 +
1.532 +BuildMD5ableBuffer::~BuildMD5ableBuffer()
1.533 +{
1.534 + delete stringTable;
1.535 +}
1.536 +
1.537 +void BuildMD5ableBuffer::ReadSMC_ParseStart()
1.538 +{
1.539 + stringTable->Reset();
1.540 +}
1.541 +
1.542 +SMCResult BuildMD5ableBuffer::ReadSMC_KeyValue(const SMCStates *states,
1.543 + const char *key,
1.544 + const char *value)
1.545 +{
1.546 + stringTable->AddString(key);
1.547 + stringTable->AddString(value);
1.548 +
1.549 + return SMCResult_Continue;
1.550 +}
1.551 +
1.552 +SMCResult BuildMD5ableBuffer::ReadSMC_NewSection(const SMCStates *states, const char *name)
1.553 +{
1.554 + stringTable->AddString(name);
1.555 +
1.556 + return SMCResult_Continue;
1.557 +}
1.558 +
1.559 +void BuildMD5ableBuffer::ReadSMC_ParseEnd(bool halted, bool failed)
1.560 +{
1.561 + if (halted || failed)
1.562 + {
1.563 + return;
1.564 + }
1.565 +
1.566 + void *data = stringTable->GetMemTable()->GetAddress(0);
1.567 +
1.568 + if (data != NULL)
1.569 + {
1.570 + checksum->update((unsigned char *)data, stringTable->GetMemTable()->GetActualMemUsed());
1.571 + }
1.572 +
1.573 + checksum->finalize();
1.574 +}
1.575 +
1.576 CON_COMMAND(sm_gamedata_md5, "Checks the MD5 sum for a given gamedata file")
1.577 {
1.578 #if !defined ORANGEBOX_BUILD
1.579 @@ -764,3 +810,25 @@
1.580
1.581 g_SMAPI->ConPrint("File not found!\n");
1.582 }
1.583 +
1.584 +FetcherThread::~FetcherThread()
1.585 +{
1.586 + //delete filenames;
1.587 + SourceHook::CVector<FileData *>::iterator iter = filenames.begin();
1.588 +
1.589 + FileData *curData;
1.590 +
1.591 + while (iter != filenames.end())
1.592 + {
1.593 + curData = (*iter);
1.594 + delete curData->filename;
1.595 + delete curData;
1.596 + iter = filenames.erase(iter);
1.597 + }
1.598 +}
1.599 +
1.600 +FetcherThread::FetcherThread()
1.601 +{
1.602 + memtable = new BaseMemTable(4096);
1.603 +}
1.604 +