ModFiles.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 <engine/ModFiles.h>
00022 #include <common/Defines.h>
00023 #include <common/Logger.h>
00024 #include <common/FileList.h>
00025 #include <lang/LangResource.h>
00026 #include <stdio.h>
00027 
00028 ModFiles::ModFiles()
00029 {
00030 }
00031 
00032 ModFiles::~ModFiles()
00033 {
00034         std::map<std::string, ModFileEntry *>::iterator itor;
00035         for (itor = files_.begin();
00036                 itor != files_.end();
00037                 itor++)
00038         {
00039                 delete (*itor).second;
00040         }
00041         files_.clear();
00042 }
00043 
00044 bool ModFiles::fileEnding(const std::string &file, const std::string &ext)
00045 {
00046         int fileLen = file.size();
00047         int extLen = ext.size();
00048         if (fileLen < extLen) return false;
00049 
00050         for (int i=0; i<extLen; i++)
00051         {
00052                 if (file.c_str()[fileLen - i - 1] != ext.c_str()[extLen - i - 1])
00053                 {
00054                         return false;
00055                 }
00056         }
00057         return true;
00058 }
00059 
00060 bool ModFiles::excludeFile(const std::string &file)
00061 {
00062         if (file == "Thumbs.db") return true;
00063         if (file == "CVS") return true;
00064         if (file == "..") return true;
00065 
00066         if (!fileEnding(file, ".xml") &&
00067                 !fileEnding(file, ".bmp") &&
00068                 !fileEnding(file, ".txt") &&
00069                 !fileEnding(file, ".png") &&
00070                 !fileEnding(file, ".jpg") &&
00071                 !fileEnding(file, ".ico") &&
00072                 !fileEnding(file, ".ase") &&
00073                 !fileEnding(file, ".wav") &&
00074                 !fileEnding(file, ".ogg"))
00075         {
00076                 Logger::log(S3D::formatStringBuffer("Excluding mod file \"%s\"", file.c_str()));
00077                 return true;
00078         }
00079 
00080         return false;
00081 }
00082 
00083 bool ModFiles::loadModFiles(const std::string &mod, 
00084         bool createDir, ProgressCounter *counter)
00085 {
00086         {
00087                 // Get and check the user mod directory exists
00088                 std::string modDir = S3D::getModFile(mod);
00089                 if (S3D::dirExists(modDir))
00090                 {
00091                         if (counter) counter->setNewOp(LANG_RESOURCE("LOADING_USER_MODS", "Loading User Mods"));
00092                         if (!loadModDir(modDir, mod, counter)) return false;
00093                 }
00094                 else
00095                 {
00096                         if (createDir) S3D::dirMake(modDir);
00097                 }
00098         }
00099 
00100         {
00101                 // Get and check global mod directory
00102                 std::string modDir = S3D::getGlobalModFile(mod);
00103                 if (S3D::dirExists(modDir))
00104                 {
00105                         if (counter) counter->setNewOp(LANG_RESOURCE("LOADING_GLOBAL_MODS", "Loading Global Mods"));
00106                         if (!loadModDir(modDir, mod, counter)) return false;
00107                 }
00108         }
00109 
00110         // For the default "none" mod load some files that can
00111         // be downloaded
00112         if (mod == "none")
00113         {
00114                 loadLocalModFile("data/accessories.xml", mod);
00115                 loadLocalModFile("data/modinfo.xml", mod);
00116                 loadLocalModFile("data/landscapes.xml", mod);
00117 
00118                 const char *landscapesBase = "data/landscapes";
00119                 std::string dir = S3D::getDataFile(landscapesBase);
00120                 FileList fList(dir, "*.xml", true);
00121                 std::list<std::string> &files = fList.getFiles();
00122                 std::list<std::string>::iterator itor;
00123                 for (itor = files.begin();
00124                         itor != files.end();
00125                         itor++)
00126                 {
00127                         char *file = (char *) (*itor).c_str();
00128                         file += dir.size() - strlen(landscapesBase);
00129                         loadLocalModFile(file, mod);
00130                 }
00131         }
00132         
00133         {
00134                 unsigned int totalCompSize = 0, totalSize = 0;
00135                 std::map<std::string, ModFileEntry *>::iterator itor;
00136                 for (itor = files_.begin();
00137                         itor != files_.end();
00138                         itor++)
00139                 {
00140                         ModFileEntry *entry = (*itor).second;
00141                         totalCompSize += entry->getCompressedSize();
00142                         totalSize += entry->getUncompressedSize();
00143                 }
00144 
00145                 Logger::log(S3D::formatStringBuffer("Loaded mod \"%s\", %u files, space required %u (%u) bytes", 
00146                         mod.c_str(), files_.size(), totalCompSize, totalSize));
00147 
00148                 if (!createDir && files_.empty())
00149                 {
00150                         std::string modFile = S3D::getModFile(mod);
00151                         std::string globalModFile = S3D::getGlobalModFile(mod);
00152                         S3D::dialogMessage("Mod", S3D::formatStringBuffer(
00153                                 "Failed to find \"%s\" mod files in directories \"%s\" \"%s\"",
00154                                 mod.c_str(),
00155                                 modFile.c_str(),
00156                                 globalModFile.c_str()));
00157                         return false;
00158                 }
00159         }
00160 
00161         return true;
00162 }
00163 
00164 bool ModFiles::loadLocalModFile(const std::string &local, 
00165         const std::string &mod)
00166 {
00167         std::string dataFile = S3D::getDataFile(local);
00168         std::string modDirStr(dataFile.c_str());
00169         char *modDir = (char *) modDirStr.c_str();
00170         modDir[dataFile.size() - local.size()] = '\0';
00171 
00172         return loadModFile(dataFile, modDir, mod);
00173 }
00174 
00175 bool ModFiles::loadModDir(const std::string &modDir, 
00176         const std::string &mod, ProgressCounter *counter)
00177 {
00178         // Load all files contained in this directory
00179         FileList allfiles(modDir, "*", true, true);
00180         FileList::ListType &files = allfiles.getFiles();
00181         FileList::ListType::iterator itor;
00182 
00183         int i = 0;
00184         for (itor = files.begin();
00185                 itor != files.end();
00186                 itor++, i++)
00187         {
00188                 if (counter) counter->setNewPercentage(float(i) 
00189                         / float(files.size()) * 100.0f);
00190 
00191                 // Load the file
00192                 std::string &fileName = (*itor);
00193                 if (!loadModFile(fileName, modDir, mod))
00194                 {
00195                         return false;
00196                 }
00197         }
00198 
00199         return true;
00200 }
00201 
00202 bool ModFiles::loadModFile(const std::string &fullFileName,
00203         const std::string &modDir, const std::string &mod)
00204 {
00205         std::string shortFileNameStr(fullFileName.c_str());
00206         S3D::fileDos2Unix(shortFileNameStr);
00207         const char *shortFileName = shortFileNameStr.c_str();
00208 
00209         // Check to see if we ignore this file
00210         if (excludeFile(fullFileName)) return true;
00211 
00212         // Turn it into a unix style path and remove the 
00213         // name of the directory that contains it
00214         int modDirLen = modDir.size();
00215         shortFileName += modDirLen;
00216         while (shortFileName[0] == '/') shortFileName++;
00217 
00218         // Check that all files are lower case
00219         std::string oldFileName(shortFileName);
00220         _strlwr((char *) shortFileName);
00221         if (strcmp(oldFileName.c_str(), shortFileName) != 0)
00222         {
00223                 S3D::dialogMessage("Mod", S3D::formatStringBuffer(
00224                         "ERROR: All mod files must have lower case filenames.\n"
00225                         "File \"%s,%s\" has upper case charaters in it",
00226                         oldFileName.c_str(),
00227                         shortFileName));
00228                 return false;
00229         }
00230 
00231         // Check we don't have this file already
00232         if (files_.find(shortFileName) != files_.end()) return true;
00233 
00234         // Create the new mod file and load the file
00235         ModFileEntry *file = new ModFileEntry();
00236         if (!file->loadModFile(fullFileName))
00237         {
00238                 S3D::dialogMessage("Mod", S3D::formatStringBuffer(
00239                         "Error: Failed to load file \"%s\" mod directory \"%s\" in the \"%s\" mod",
00240                         fullFileName.c_str(),
00241                         modDir.c_str(),
00242                         mod.c_str()));
00243                 return false;
00244         }
00245 
00246         // Store for future
00247         file->setFileName(shortFileName);
00248         files_[shortFileName] = file;
00249         return true;
00250 }
00251 
00252 bool ModFiles::writeModFiles(const std::string &mod)
00253 {
00254         std::string modDir = S3D::getModFile(mod);
00255         if (!S3D::dirExists(modDir))
00256         {
00257                 S3D::dirMake(modDir);
00258         }
00259 
00260         std::map<std::string, ModFileEntry *>::iterator itor;
00261         for (itor = files_.begin();
00262                 itor != files_.end();
00263                 itor++)
00264         {
00265                 ModFileEntry *entry = (*itor).second;
00266                 if (!entry->writeModFile(entry->getFileName(), mod)) return false;
00267         }
00268         return true;
00269 }
00270 
00271 void ModFiles::clearData()
00272 {
00273          std::map<std::string, ModFileEntry *>::iterator itor;
00274          for (itor = files_.begin();
00275                 itor != files_.end();
00276                 itor++)
00277         {
00278                  ModFileEntry *entry = (*itor).second;
00279                  entry->getCompressedBuffer().clear();
00280         }
00281 }
00282 
00283 bool ModFiles::exportModFiles(const std::string &mod, const std::string &fileName)
00284 {
00285         FILE *out = fopen(fileName.c_str(), "wb");
00286         if (!out) return false;
00287 
00288         // Mod Name
00289         NetBuffer tmpBuffer;
00290         tmpBuffer.reset();
00291         tmpBuffer.addToBuffer(S3D::ScorchedProtocolVersion);
00292         tmpBuffer.addToBuffer(mod);
00293         fwrite(tmpBuffer.getBuffer(),
00294                 sizeof(unsigned char),
00295                 tmpBuffer.getBufferUsed(), 
00296                 out);   
00297 
00298         // Mod Files
00299         std::map<std::string, ModFileEntry *>::iterator itor;
00300         for (itor = files_.begin();
00301                 itor != files_.end();
00302                 itor++)
00303         {
00304                 ModFileEntry *entry = (*itor).second;
00305         
00306                 tmpBuffer.reset();
00307                 tmpBuffer.addToBuffer(entry->getFileName());
00308                 tmpBuffer.addToBuffer(entry->getUncompressedSize());
00309                 tmpBuffer.addToBuffer(entry->getCompressedBuffer().getBufferUsed());
00310                 tmpBuffer.addToBuffer(entry->getCompressedCrc());
00311                 tmpBuffer.addDataToBuffer(entry->getCompressedBuffer().getBuffer(),
00312                         entry->getCompressedBuffer().getBufferUsed());
00313 
00314                 fwrite(tmpBuffer.getBuffer(),
00315                         sizeof(unsigned char),
00316                         tmpBuffer.getBufferUsed(), 
00317                         out);
00318         }
00319 
00320         // End of Mod Files
00321         tmpBuffer.reset();
00322         tmpBuffer.addToBuffer("*");
00323         fwrite(tmpBuffer.getBuffer(),
00324                 sizeof(unsigned char),
00325                 tmpBuffer.getBufferUsed(), 
00326                 out);
00327 
00328         fclose(out);
00329         return true;
00330 }
00331 
00332 bool ModFiles::importModFiles(std::string &mod, const std::string &fileName)
00333 {
00334         FILE *in = fopen(fileName.c_str(), "rb");
00335         if (!in) return false;
00336 
00337         // Read Buffer
00338         NetBuffer tmpBuffer;
00339         unsigned char readBuf[512];
00340         while (unsigned int size = fread(readBuf, sizeof(unsigned char), 512, in))
00341         {
00342                 tmpBuffer.addDataToBuffer(readBuf, size);
00343         }
00344         fclose(in);
00345         return importModFiles(mod, tmpBuffer);
00346 }
00347 
00348 bool ModFiles::importModFiles(std::string &mod, NetBuffer &tmpBuffer)
00349 {
00350         // Mod Name
00351         static std::string modName;
00352         std::string version;
00353         NetBufferReader tmpReader(tmpBuffer);
00354         if (!tmpReader.getFromBuffer(version)) return false;
00355         if (!tmpReader.getFromBuffer(modName)) return false;
00356         mod = modName;
00357 
00358         if (version != S3D::ScorchedProtocolVersion)
00359         {
00360                 S3D::dialogMessage("Scorched3D", S3D::formatStringBuffer(
00361                         "Failed to import mod, scorched version differs.\n"
00362                         "Please obtain a newer version of this mod.\n"
00363                         "Import version = %s\n"
00364                         "Current version = %s\n",
00365                         version.c_str(),
00366                         S3D::ScorchedProtocolVersion.c_str()));
00367                 return false;
00368         }
00369 
00370         for (;;)
00371         {
00372                 // File Name
00373                 std::string name;
00374                 if (!tmpReader.getFromBuffer(name)) return false;
00375                 if (0 == strcmp(name.c_str(), "*")) break;
00376 
00377                 // File Header
00378                 unsigned int unCompressedSize;
00379                 unsigned int compressedSize;
00380                 unsigned int compressedCrc;
00381                 tmpReader.getFromBuffer(unCompressedSize);
00382                 tmpReader.getFromBuffer(compressedSize);
00383                 tmpReader.getFromBuffer(compressedCrc);
00384 
00385                 // File
00386                 ModFileEntry *entry = new ModFileEntry;
00387                 entry->setFileName(name.c_str());
00388                 entry->setCompressedCrc(compressedCrc);
00389                 entry->setUncompressedSize(unCompressedSize);
00390                 entry->getCompressedBuffer().allocate(compressedSize);
00391                 entry->getCompressedBuffer().setBufferUsed(compressedSize);
00392                 tmpReader.getDataFromBuffer(
00393                         entry->getCompressedBuffer().getBuffer(), 
00394                         compressedSize);
00395                 files_[name] = entry;
00396         }
00397 
00398         return true;
00399 }

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