CSndHandler.cpp 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. #include "../stdafx.h"
  2. #include <fstream>
  3. #include "CSndHandler.h"
  4. #include <boost/iostreams/device/mapped_file.hpp>
  5. #include <SDL_endian.h>
  6. /*
  7. * CSndHandler.cpp, part of VCMI engine
  8. *
  9. * Authors: listed in file AUTHORS in main folder
  10. *
  11. * License: GNU General Public License v2.0 or later
  12. * Full text of license available in license.txt file, in main folder
  13. *
  14. */
  15. /* Media file are kept in container files. We map these files in
  16. * memory, parse them and create an index of them to easily retrieve
  17. * the data+size of the objects. */
  18. CMediaHandler::~CMediaHandler()
  19. {
  20. std::vector<boost::iostreams::mapped_file_source *>::iterator it;
  21. entries.clear();
  22. fimap.clear();
  23. for (it=mfiles.begin() ; it < mfiles.end(); it++ ) {
  24. (*it)->close();
  25. delete *it;
  26. }
  27. }
  28. boost::iostreams::mapped_file_source *CMediaHandler::add_file(std::string fname, bool important /*= true*/)
  29. {
  30. boost::iostreams::mapped_file_source *mfile;
  31. try //c-tor of mapped_file_source throws exception on failure
  32. {
  33. mfile = new boost::iostreams::mapped_file_source(fname);
  34. if (!mfile->is_open()) //just in case
  35. throw std::runtime_error("Cannot open " + fname + ": !mfile->is_open()");
  36. }
  37. catch(std::exception &e)
  38. {
  39. if(important)
  40. tlog1 << "Cannot open " << fname << ": " << e.what() << std::endl;
  41. throw;
  42. }
  43. mfiles.push_back(mfile);
  44. return mfile;
  45. }
  46. void CMediaHandler::extract(int index, std::string dstfile) //saves selected file
  47. {
  48. std::ofstream out(dstfile.c_str(),std::ios_base::binary);
  49. Entry &entry = entries[index];
  50. out.write(entry.data, entry.size);
  51. out.close();
  52. }
  53. void CMediaHandler::extract(std::string srcfile, std::string dstfile, bool caseSens) //saves selected file
  54. {
  55. srcfile.erase(srcfile.find_last_of('.'));
  56. if (caseSens)
  57. {
  58. for (size_t i=0;i<entries.size();++i)
  59. {
  60. if (entries[i].name==srcfile)
  61. extract(i,dstfile);
  62. }
  63. }
  64. else
  65. {
  66. std::transform(srcfile.begin(),srcfile.end(),srcfile.begin(),tolower);
  67. for (size_t i=0;i<entries.size();++i)
  68. {
  69. if (entries[i].name==srcfile)
  70. {
  71. std::string por = entries[i].name;
  72. std::transform(por.begin(),por.end(),por.begin(),tolower);
  73. if (por==srcfile)
  74. extract(i,dstfile);
  75. }
  76. }
  77. }
  78. }
  79. #if 0
  80. // unused and not sure what it's supposed to do
  81. MemberFile CMediaHandler::getFile(std::string name)
  82. {
  83. MemberFile ret;
  84. std::transform(name.begin(),name.end(),name.begin(),tolower);
  85. for (size_t i=0;i<entries.size();++i)
  86. {
  87. if (entries[i].name==name)
  88. {
  89. std::string por = entries[i].name;
  90. std::transform(por.begin(),por.end(),por.begin(),tolower);
  91. if (por==name)
  92. {
  93. ret.length=entries[i].size;
  94. file.seekg(entries[i].offset,std::ios_base::beg);
  95. ret.ifs=&file;
  96. return ret;
  97. }
  98. }
  99. }
  100. return ret;
  101. }
  102. #endif
  103. const char * CMediaHandler::extract (int index, int & size)
  104. {
  105. Entry &entry = entries[index];
  106. size = entry.size;
  107. return entry.data;
  108. }
  109. const char * CMediaHandler::extract (std::string srcName, int &size)
  110. {
  111. int index;
  112. size_t dotPos = srcName.find_last_of('.');
  113. if (dotPos != std::string::npos)
  114. srcName.erase(dotPos);
  115. std::map<std::string, int>::iterator fit;
  116. if ((fit = fimap.find(srcName)) != fimap.end())
  117. {
  118. index = fit->second;
  119. return this->extract(index, size);
  120. }
  121. size = 0;
  122. return NULL;
  123. }
  124. void CSndHandler::add_file(std::string fname, bool important /*= true*/)
  125. {
  126. boost::iostreams::mapped_file_source *mfile = NULL;
  127. try
  128. {
  129. mfile = CMediaHandler::add_file(fname, important);
  130. }
  131. catch(...)
  132. {
  133. return;
  134. }
  135. const char *data = mfile->data();
  136. unsigned int numFiles = SDL_SwapLE32(*(Uint32 *)&data[0]);
  137. struct soundEntry *se = (struct soundEntry *)&data[4];
  138. for (unsigned int i=0; i<numFiles; i++, se++)
  139. {
  140. Entry entry;
  141. entry.name = se->filename;
  142. entry.offset = SDL_SwapLE32(se->offset);
  143. entry.size = SDL_SwapLE32(se->size);
  144. entry.data = mfile->data() + entry.offset;
  145. entries.push_back(entry);
  146. fimap[entry.name] = i;
  147. }
  148. }
  149. void CVidHandler::add_file(std::string fname)
  150. {
  151. boost::iostreams::mapped_file_source *mfile = NULL;
  152. try
  153. {
  154. mfile = CMediaHandler::add_file(fname);
  155. }
  156. catch(...)
  157. {
  158. return;
  159. }
  160. if(mfile->size() < 48)
  161. {
  162. tlog1 << fname << " doesn't contain needed data!\n";
  163. return;
  164. }
  165. const unsigned char *data = (const unsigned char *)mfile->data();
  166. unsigned int numFiles = SDL_SwapLE32(*(Uint32 *)&data[0]);
  167. struct videoEntry *ve = (struct videoEntry *)&data[4];
  168. for (unsigned int i=0; i<numFiles; i++, ve++)
  169. {
  170. Entry entry;
  171. entry.name = ve->filename;
  172. entry.offset = SDL_SwapLE32(ve->offset);
  173. entry.name.erase(entry.name.find_last_of('.'));
  174. // There is no size, so check where the next file is
  175. if (i == numFiles - 1) {
  176. entry.size = mfile->size() - entry.offset;
  177. } else {
  178. struct videoEntry *ve_next = ve+1;
  179. entry.size = SDL_SwapLE32(ve_next->offset) - entry.offset;
  180. }
  181. entry.data = mfile->data() + entry.offset;
  182. entries.push_back(entry);
  183. fimap[entry.name] = i;
  184. }
  185. }