ClientFileHandler.cpp

Go to the documentation of this file.
00001 ////////////////////////////////////////////////////////////////////////////////
00002 //    Scorched3D (c) 2000-2009
00003 //
00004 //    This file is part of Scorched3D.
00005 //
00006 //    Scorched3D is free software; you can redistribute it and/or modify
00007 //    it under the terms of the GNU General Public License as published by
00008 //    the Free Software Foundation; either version 2 of the License, or
00009 //    (at your option) any later version.
00010 //
00011 //    Scorched3D is distributed in the hope that it will be useful,
00012 //    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 //    GNU General Public License for more details.
00015 //
00016 //    You should have received a copy of the GNU General Public License
00017 //    along with Scorched3D; if not, write to the Free Software
00018 //    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019 ////////////////////////////////////////////////////////////////////////////////
00020 
00021 #include <client/ClientFileHandler.h>
00022 #include <client/ClientState.h>
00023 #include <client/ScorchedClient.h>
00024 #include <engine/ModFiles.h>
00025 #include <dialogs/ProgressDialog.h>
00026 #include <common/Logger.h>
00027 #include <common/Defines.h>
00028 #include <common/OptionsScorched.h>
00029 #include <coms/ComsMessageSender.h>
00030 #include <coms/ComsFileMessage.h>
00031 #include <coms/ComsFileAkMessage.h>
00032 #include <lang/LangResource.h>
00033 
00034 ClientFileHandler *ClientFileHandler::instance_ = 0;
00035 
00036 ClientFileHandler *ClientFileHandler::instance()
00037 {
00038         if (!instance_)
00039         {
00040                 instance_ = new ClientFileHandler;
00041         }
00042         return instance_;
00043 }
00044 
00045 ClientFileHandler::ClientFileHandler() : totalBytes_(0)
00046 {
00047         ScorchedClient::instance()->getComsMessageHandler().addHandler(
00048                 "ComsFileMessage",
00049                 this);
00050 }
00051 
00052 ClientFileHandler::~ClientFileHandler()
00053 {
00054 }
00055 
00056 bool ClientFileHandler::processMessage(
00057         NetMessage &netMessage,
00058         const char *messageType,
00059         NetBufferReader &mainreader)
00060 {
00061         ComsFileMessage message;
00062         if (!message.readMessage(mainreader)) return false;
00063         NetBufferReader reader(message.fileBuffer);
00064 
00065         if (ScorchedClient::instance()->getGameState().getState() !=
00066                 ClientState::StateLoadFiles)
00067         {
00068                 ScorchedClient::instance()->getGameState().stimulate(
00069                         ClientState::StimLoadFiles);
00070         }
00071 
00072         std::map<std::string, ModFileEntry *> &files = 
00073                 ScorchedClient::instance()->getModFiles().getFiles();
00074 
00075         // Read the files one at a time
00076         for (;;)
00077         {
00078                 // Read the filename
00079                 // a zero length name means last file
00080                 std::string fileName;
00081                 reader.getFromBuffer(fileName);
00082                 if (fileName.size() == 0) break;
00083 
00084                 // Read flags
00085                 bool firstChunk = false;
00086                 bool lastChunk = false;
00087                 reader.getFromBuffer(firstChunk);
00088                 reader.getFromBuffer(lastChunk);
00089 
00090                 // Read file count
00091                 unsigned int bytesLeft = 0;
00092                 reader.getFromBuffer(bytesLeft);
00093                 if (totalBytes_ == 0) totalBytes_ = bytesLeft;
00094 
00095                 // Update progress
00096                 const char *shortFileName = fileName.c_str();
00097                 if (strrchr(shortFileName, '/')) shortFileName = strrchr(shortFileName, '/') + 1;
00098                 unsigned int doneBytes = totalBytes_ - bytesLeft;
00099                 ProgressDialog::instance()->progressChange(
00100                         LANG_RESOURCE_1("DOWNLOADING_FILE", "Downloading {0}", shortFileName), 
00101                         float(doneBytes * 100 / totalBytes_));
00102 
00103                 // Read the size
00104                 unsigned int maxsize = 0;
00105                 unsigned int uncompressedsize = 0;
00106                 unsigned int crc = 0;
00107                 unsigned int size = 0;
00108                 reader.getFromBuffer(maxsize);
00109                 reader.getFromBuffer(uncompressedsize);
00110                 reader.getFromBuffer(crc);
00111                 reader.getFromBuffer(size);
00112                 
00113                 // The first part
00114                 if (firstChunk)
00115                 {
00116                         // Remove the file if it already exists
00117                         std::map<std::string, ModFileEntry *>::iterator findItor = 
00118                                 files.find(fileName);
00119                         if (findItor != files.end())
00120                         {
00121                                 delete (*findItor).second;
00122                                 files.erase(findItor);
00123                         }
00124 
00125                         // Create a new file
00126                         ModFileEntry *fileEntry = new ModFileEntry;
00127                         fileEntry->setFileName(fileName.c_str());
00128                         fileEntry->setCompressedCrc(crc);
00129                         fileEntry->setUncompressedSize(uncompressedsize);
00130                         files[fileName] = fileEntry;
00131                 }
00132 
00133                 // Locate the file
00134                 std::map<std::string, ModFileEntry *>::iterator findItor = 
00135                         files.find(fileName);
00136                 if (findItor == files.end())
00137                 {
00138                         Logger::log(S3D::formatStringBuffer("Failed to find partial mod file \"%s\"", 
00139                                 fileName.c_str()));
00140                         return false;
00141                 }
00142                 ModFileEntry *entry = (*findItor).second;
00143 
00144                 // Add the bytes to the file
00145                 entry->getCompressedBuffer().addDataToBuffer(
00146                         reader.getBuffer() + reader.getReadSize(), size);
00147                 reader.setReadSize(reader.getReadSize() + size);
00148 
00149                 // Check if we have finished this file
00150                 if (lastChunk)
00151                 {
00152                         // Finished
00153                         Logger::log(S3D::formatStringBuffer(" %u/%u %s - %i bytes",
00154                                 doneBytes,
00155                                 totalBytes_,
00156                                 fileName.c_str(),
00157                                 entry->getCompressedSize()));
00158 
00159                         // Wrong size
00160                         if (entry->getCompressedSize() != maxsize)
00161                         {
00162                                 Logger::log(S3D::formatStringBuffer("Downloaded mod file incorrect size \"%s\".\n"
00163                                         "Expected %u, got %u.",
00164                                         fileName.c_str(), entry->getCompressedSize(), maxsize));
00165                                 return false;
00166                         }
00167 
00168                         // Write file
00169                         if (!entry->writeModFile(fileName.c_str(),
00170                                 ScorchedClient::instance()->getOptionsGame().getMod()))
00171                         {
00172                                 Logger::log(S3D::formatStringBuffer("Failed to write mod file \"%s\"",
00173                                         fileName.c_str()));
00174                                 return false;
00175                         }
00176                 }
00177         }
00178 
00179         // Send the ak for this file
00180         ComsFileAkMessage akMessage;
00181         ComsMessageSender::sendToServer(akMessage);
00182 
00183         return true;
00184 }

Generated on Mon Feb 16 15:14:36 2009 for Scorched3D by  doxygen 1.5.3