CSndHandler.cpp 4.9 KB

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