Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

wad.cpp

Go to the documentation of this file.
00001 // libdoomwad: manipulates Doom wad files.
00002 // Copyright (C) 2005  John Gaughan
00003 //
00004 // This library is free software; you can redistribute it and/or
00005 // modify it under the terms of the GNU Lesser General Public
00006 // License as published by the Free Software Foundation; either
00007 // version 2.1 of the License, or (at your option) any later version.
00008 //
00009 // This library is distributed in the hope that it will be useful,
00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012 // Lesser General Public License for more details.
00013 //
00014 // You should have received a copy of the GNU Lesser General Public
00015 // License along with this library; if not, write to the Free Software
00016 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017 //
00018 // This library is distributed with the full text of the LGPL. Please see
00019 // the accompanying file named COPYING.
00020 // 
00021 // You may contact the author at john@johngaughan.net
00022 
00028 // C++ required.
00029 #if !defined __cplusplus
00030 #error C++ compiler required
00031 #endif
00032 
00033 // C++ headers
00034 #include <algorithm>
00035 #include <fstream>
00036 #include <list>
00037 #include <sstream>
00038 #include <string>
00039 #include <vector>
00040 
00041 // Doom headers
00042 #include "global.hpp"
00043 #include "wad.hpp"
00044 
00045 using namespace Doomwad;
00046 
00050 Wad::Wad (void) throw () : m_type (PWAD)
00051 {
00052 }
00053 
00059 Wad::Wad (wad_type type) throw ()
00060 {
00061   this->setType (type);
00062 }
00063 
00069 Wad::Wad (const std::string &filename) throw ()
00070 {
00071   this->readFromFile (filename);
00072 }
00073 
00080 Wad::Wad (const Lump &lump, wad_type type) throw ()
00081 {
00082   this->m_type = type;
00083   this->assign (1, lump);
00084 }
00085 
00096 bool Wad::operator== (const Wad &wad) const throw ()
00097 {
00098   const_iterator iter, iter2, last;
00099 
00100   // Test addresses first
00101   if (this == &wad)
00102   {
00103     return true;
00104   }
00105 
00106   // Test primitives next
00107   if (this->m_type != wad.m_type || this->size () != wad.size ())
00108   {
00109     return false;
00110   }
00111 
00112   // Finally test each entry in order. Entries also use short-circuit logic, so
00113   // two wads that differ only by contents of their entries should return
00114   // fairly quickly from this method.
00115   for (iter = this->begin (), iter2 = wad.begin (), last = this->end (); iter != last; ++iter, ++iter2)
00116   {
00117     if (*iter != *iter2)
00118     {
00119       return false;
00120     }
00121   }
00122   return true;
00123 }
00124 
00132 bool Wad::operator!= (const Wad &wad) const throw ()
00133 {
00134   return !(*this == wad);
00135 }
00136 
00144 Wad& Wad::operator+= (const Wad &wad) throw ()
00145 {
00146 
00147   // TODO: make this smart so it overwrites entries that need to be overwritten.
00148   for (const_iterator iter = wad.begin (); iter != wad.end (); ++iter)
00149   {
00150     this->insert (this->end (), *iter);
00151   }
00152   return *this;
00153 }
00154 
00162 Wad Wad::operator+ (const Wad &wad) const throw ()
00163 {
00164   Wad w (*this);
00165   return w += wad;
00166 }
00167 
00173 bool Wad::isIwad (void) const throw ()
00174 {
00175   return this->m_type == IWAD;
00176 }
00177 
00183 bool Wad::isPwad (void) const throw ()
00184 {
00185   return this->m_type == PWAD;
00186 }
00187 
00193 Wad::wad_type Wad::getType (void) const throw ()
00194 {
00195   return this->m_type;
00196 }
00197 
00205 bool Wad::setType (wad_type type) throw ()
00206 {
00207   this->m_type = type;
00208   return true;
00209 }
00210 
00221 std::string Wad::getWadDirectory (char delimiter) const throw ()
00222 {
00223   std::ostringstream str;
00224   const_iterator iter = this->begin ();
00225 
00226   for (; iter != this->end (); ++iter)
00227   {
00228     str << iter->getName () << delimiter;
00229   }
00230 
00231   return str.str ();
00232 }
00233 
00243 bool Wad::writeToFile (const std::string &filename) const throw ()
00244 {
00245 
00246   // File output stream
00247   std::ofstream out;
00248 
00249   // Vector that holds entry offsets for directory
00250   std::vector<int> dir_offset;
00251   dir_offset.reserve (2 * this->size ());
00252 
00253   // Iterators
00254   std::vector<int>::const_iterator iter_offset, iter_offset_end;
00255   Wad::const_iterator iter_lump, iter_lump_end;
00256 
00257   // Miscellaneous
00258   size_t loc_dir = 0;
00259   size_t lumpsize = 0;
00260   char buffer_name[9];
00261   size_t num_entries = this->size ();
00262 
00263   // Check filename
00264   if (filename.empty ())
00265   {
00266     return false;
00267   }
00268 
00269   // Open file
00270   out.open (filename.c_str (), std::ios::out | std::ios::binary | std::ios::trunc);
00271   if (!out)
00272   {
00273     return false;
00274   }
00275 
00276   // Write header
00277   out.write ((this->m_type == IWAD ? "IWAD" : "PWAD"), 4);
00278   out.write (reinterpret_cast<const char *> (&num_entries), 4);
00279   out.write (reinterpret_cast<const char *> (&loc_dir), 4); // should be zero the first time, actually, does not matter. Just advance the write pointer.
00280 
00281   // Write each entry, one at a time
00282   for
00283   (
00284     iter_lump = this->begin (),
00285     iter_lump_end = this->end ();
00286 
00287     iter_lump != iter_lump_end;
00288 
00289     ++iter_lump
00290   )
00291   {
00292     while (out.tellp () % 4)
00293     {
00294       out << static_cast<const char> (NULL);
00295     }
00296     dir_offset.push_back (out.tellp ());
00297     (*iter_lump).writeToStream (out);
00298   }
00299 
00300   // Write directory
00301   while (out.tellp () % 4)
00302   {
00303     out << static_cast<const char> (NULL);
00304   }
00305   for
00306   (
00307     iter_offset     = dir_offset.begin (),
00308     iter_offset_end = dir_offset.end (),
00309     iter_lump       = this->begin (),
00310     iter_lump_end   = this->end (),
00311     loc_dir         = out.tellp ();
00312 
00313     iter_offset != iter_offset_end
00314     && iter_lump != iter_lump_end;
00315 
00316     ++iter_offset,
00317     ++iter_lump
00318   )
00319   {
00320 
00321     // Write offset and size of lump
00322     out.write (reinterpret_cast<const char *> (&(*iter_offset)), 4);
00323 
00324     lumpsize = (*iter_lump).size ();
00325     out.write (reinterpret_cast<const char *> (&lumpsize), 4);
00326 
00327     // Write name of lump
00328     memset (buffer_name, '\0', 8);
00329     strncpy (buffer_name, (*iter_lump).getName ().c_str (), 8);
00330     out.write (buffer_name, 8);
00331   }
00332 
00333   // Go back to header and write the directory offset
00334   out.seekp (8, std::ios::beg);
00335   out.write (reinterpret_cast<const char *> (&loc_dir), 4);
00336 
00337   // All done!
00338   out.close ();
00339   return true;
00340 }
00341 
00352 bool Wad::readFromFile (const std::string &filename) throw ()
00353 {
00354 
00355   // File insput stream
00356   std::ifstream in;
00357 
00358   // Temporary directory information
00359   std::vector<size_t> entry_offset, entry_size;
00360   std::vector<std::string> entry_name;
00361 
00362   // Iterators used for directory information
00363   std::vector<size_t>::iterator iter_offset, iter_size, iter_end;
00364   std::vector<std::string>::iterator iter_name;
00365 
00366   // Offsets and other primitives
00367   size_t num_entries = 0;
00368   size_t loc_dir = 0;
00369   size_t i = 0;
00370   char type[5];
00371   char buffer_dir[17];
00372 
00373   // Buffer for wad data
00374   size_t buffer_len = 0;
00375   char *buffer = NULL;
00376   Lump temp_lump;
00377 
00378   // Check filename
00379   if (filename.empty ())
00380   {
00381     return false;
00382   }
00383 
00384   // Try opening file
00385   in.open (filename.c_str (), std::ios::in | std::ios::binary);
00386   if (!in)
00387   {
00388     return false;
00389   }
00390 
00391   // Clear this object and hope for the best
00392   this->clear ();
00393 
00394   // Read the header
00395   in.read (type, 4);
00396   type[4] = 0;
00397   in.read (reinterpret_cast<char *> (&num_entries), 4);
00398   in.read (reinterpret_cast<char *> (&loc_dir), 4);
00399 
00400   // Parse wad type
00401   this->m_type = (strcmp (type, "IWAD") ? PWAD : IWAD);
00402 
00403   // Read directory
00404   in.seekg (loc_dir, std::ios::beg);
00405   entry_offset.reserve (2 * num_entries);
00406   entry_size.reserve (2 * num_entries);
00407   entry_name.reserve (2 * num_entries);
00408   for (i = buffer_dir[17] = 0; i < num_entries; ++i)
00409   {
00410     in.read (buffer_dir, 16);
00411     entry_offset.push_back (*(reinterpret_cast<int *> (&buffer_dir[0])));
00412     entry_size.push_back (*(reinterpret_cast<int *> (&buffer_dir[4])));
00413     entry_name.push_back (&buffer_dir[8]);
00414     buffer_len = std::max<size_t> (buffer_len, entry_size.back ());
00415   }
00416 
00417   // Create a buffer with the maximum needed size to avoid reallocating memory
00418   // each time, a relatively slow process
00419   buffer = new char[buffer_len];
00420 
00421   // Add each entry to the Wad
00422   for
00423   (
00424     iter_offset = entry_offset.begin (),
00425     iter_size   = entry_size.begin (),
00426     iter_end    = entry_size.end (),
00427     iter_name   = entry_name.begin ();
00428 
00429     iter_size != iter_end;
00430 
00431     ++iter_offset,
00432     ++iter_size,
00433     ++iter_name
00434   )
00435   {
00436 
00437      // Read data into buffer
00438      in.seekg (*iter_offset, std::ios::beg);
00439      in.read (buffer, *iter_size);
00440 
00441      // Set entry data
00442      temp_lump.setName (*iter_name);
00443      temp_lump.assign (reinterpret_cast<byte *> (buffer), *iter_size);
00444 
00445      this->push_back (temp_lump);
00446   }
00447 
00448   // All done!
00449   in.close ();
00450   delete [] buffer;
00451   return true;
00452 }

Generated on Fri Jun 10 19:38:51 2005 for libdoomwad by  doxygen 1.4.0