CSndHandler.cpp 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. #include "../stdafx.h"
  2. #include <fstream>
  3. #include "CSndHandler.h"
  4. #include <boost/iostreams/device/mapped_file.hpp>
  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. CSndHandler::~CSndHandler()
  15. {
  16. entries.clear();
  17. fimap.clear();
  18. mfile->close();
  19. delete mfile;
  20. }
  21. // Analyze the sound file. Half of this could go away if we were using
  22. // a simple structure. However, some post treatment would be necessary: file
  23. // size and offsets are little endian, and filename have a NUL in
  24. // them. */
  25. CSndHandler::CSndHandler(std::string fname)
  26. {
  27. mfile = new boost::iostreams::mapped_file_source(fname);
  28. if (!mfile->is_open())
  29. {
  30. tlog1 << "Cannot open " << fname << std::endl;
  31. throw std::string("Cannot open ")+fname;
  32. }
  33. const unsigned char *data = (const unsigned char *)mfile->data();
  34. unsigned int numFiles = readNormalNr(&data[0]);
  35. for (unsigned int i=0; i<numFiles; i++)
  36. {
  37. Entry entry;
  38. const unsigned char *p;
  39. // Read file name and extension
  40. p = &data[4+48*i];
  41. while(*p) {
  42. entry.name += *p;
  43. p++;
  44. }
  45. entry.name+='.';
  46. p++;
  47. while(*p)
  48. {
  49. entry.name += *p;
  50. p++;
  51. }
  52. // Read offset and size
  53. p = &data[4+48*i+40];
  54. entry.offset = readNormalNr(p);
  55. p += 4;
  56. entry.size = readNormalNr(p);
  57. entries.push_back(entry);
  58. fimap[entry.name] = i;
  59. }
  60. }
  61. // Reads a 4 byte integer. Format on file is little endian.
  62. unsigned int CSndHandler::readNormalNr (const unsigned char *p)
  63. {
  64. return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
  65. }
  66. void CSndHandler::extract(int index, std::string dstfile) //saves selected file
  67. {
  68. std::ofstream out(dstfile.c_str(),std::ios_base::binary);
  69. const char *data = mfile->data();
  70. out.write(&data[entries[index].offset], entries[index].size);
  71. out.close();
  72. }
  73. void CSndHandler::extract(std::string srcfile, std::string dstfile, bool caseSens) //saves selected file
  74. {
  75. if (caseSens)
  76. {
  77. for (size_t i=0;i<entries.size();++i)
  78. {
  79. if (entries[i].name==srcfile)
  80. extract(i,dstfile);
  81. }
  82. }
  83. else
  84. {
  85. std::transform(srcfile.begin(),srcfile.end(),srcfile.begin(),tolower);
  86. for (size_t i=0;i<entries.size();++i)
  87. {
  88. if (entries[i].name==srcfile)
  89. {
  90. std::string por = entries[i].name;
  91. std::transform(por.begin(),por.end(),por.begin(),tolower);
  92. if (por==srcfile)
  93. extract(i,dstfile);
  94. }
  95. }
  96. }
  97. }
  98. #if 0
  99. // unused and not sure what it's supposed to do
  100. MemberFile CSndHandler::getFile(std::string name)
  101. {
  102. MemberFile ret;
  103. std::transform(name.begin(),name.end(),name.begin(),tolower);
  104. for (size_t i=0;i<entries.size();++i)
  105. {
  106. if (entries[i].name==name)
  107. {
  108. std::string por = entries[i].name;
  109. std::transform(por.begin(),por.end(),por.begin(),tolower);
  110. if (por==name)
  111. {
  112. ret.length=entries[i].size;
  113. file.seekg(entries[i].offset,std::ios_base::beg);
  114. ret.ifs=&file;
  115. return ret;
  116. }
  117. }
  118. }
  119. return ret;
  120. }
  121. #endif
  122. const char * CSndHandler::extract (int index, int & size)
  123. {
  124. size = entries[index].size;
  125. const char *data = mfile->data();
  126. return &data[entries[index].offset];
  127. }
  128. const char * CSndHandler::extract (std::string srcName, int &size)
  129. {
  130. int index;
  131. std::map<std::string, int>::iterator fit;
  132. if ((fit = fimap.find(srcName)) != fimap.end())
  133. {
  134. index = fit->second;
  135. return this->extract(index, size);
  136. }
  137. size = 0;
  138. return NULL;
  139. }
  140. CVidHandler::~CVidHandler()
  141. {
  142. entries.clear();
  143. file.close();
  144. }
  145. CVidHandler::CVidHandler(std::string fname):CHUNK(65535)
  146. {
  147. file.open(fname.c_str(),std::ios::binary);
  148. if (!file.is_open())
  149. #ifndef __GNUC__
  150. throw new std::exception((std::string("Cannot open ")+fname).c_str());
  151. #else
  152. throw new std::exception();
  153. #endif
  154. int nr = readNormalNr(0,4);
  155. char tempc;
  156. for (int i=0;i<nr;i++)
  157. {
  158. Entry entry;
  159. while(true)
  160. {
  161. file.read(&tempc,1);
  162. if (tempc)
  163. entry.name+=tempc;
  164. else break;
  165. }
  166. entry.something=readNormalNr(-1,4);
  167. file.seekg(44-entry.name.length()-9,std::ios_base::cur);
  168. entry.offset = readNormalNr(-1,4);
  169. if (i>0)
  170. entries[i-1].size=entry.offset-entries[i-1].offset;
  171. if (i==nr-1)
  172. {
  173. file.seekg(0,std::ios::end);
  174. entry.size = ((int)file.tellg())-entry.offset;
  175. file.seekg(0,std::ios::beg);
  176. }
  177. entries.push_back(entry);
  178. }
  179. }
  180. int CVidHandler::readNormalNr (int pos, int bytCon)
  181. {
  182. if (pos>=0)
  183. file.seekg(pos,std::ios_base::beg);
  184. int ret=0;
  185. int amp=1;
  186. unsigned char zcz=0;
  187. for (int i=0; i<bytCon; i++)
  188. {
  189. file.read((char*)(&zcz),1);
  190. ret+=zcz*amp;
  191. amp*=256;
  192. }
  193. return ret;
  194. }
  195. void CVidHandler::extract(int index, std::string dstfile) //saves selected file
  196. {
  197. std::ofstream out(dstfile.c_str(),std::ios_base::binary);
  198. file.seekg(entries[index].offset,std::ios_base::beg);
  199. int toRead=entries[index].size;
  200. char * buffer = new char[std::min(CHUNK,entries[index].size)];
  201. while (toRead>CHUNK)
  202. {
  203. file.read(buffer,CHUNK);
  204. out.write(buffer,CHUNK);
  205. toRead-=CHUNK;
  206. }
  207. file.read(buffer,toRead);
  208. out.write(buffer,toRead);
  209. out.close();
  210. }
  211. void CVidHandler::extract(std::string srcfile, std::string dstfile, bool caseSens) //saves selected file
  212. {
  213. if (caseSens)
  214. {
  215. for (size_t i=0;i<entries.size();++i)
  216. {
  217. if (entries[i].name==srcfile)
  218. extract(i,dstfile);
  219. }
  220. }
  221. else
  222. {
  223. std::transform(srcfile.begin(),srcfile.end(),srcfile.begin(),tolower);
  224. for (size_t i=0;i<entries.size();++i)
  225. {
  226. if (entries[i].name==srcfile)
  227. {
  228. std::string por = entries[i].name;
  229. std::transform(por.begin(),por.end(),por.begin(),tolower);
  230. if (por==srcfile)
  231. extract(i,dstfile);
  232. }
  233. }
  234. }
  235. }
  236. MemberFile CVidHandler::getFile(std::string name)
  237. {
  238. MemberFile ret;
  239. std::transform(name.begin(),name.end(),name.begin(),tolower);
  240. for (size_t i=0;i<entries.size();++i)
  241. {
  242. if (entries[i].name==name)
  243. {
  244. std::string por = entries[i].name;
  245. std::transform(por.begin(),por.end(),por.begin(),tolower);
  246. if (por==name)
  247. {
  248. ret.length=entries[i].size;
  249. file.seekg(entries[i].offset,std::ios_base::beg);
  250. ret.ifs=&file;
  251. return ret;
  252. }
  253. }
  254. }
  255. throw ret;
  256. //return ret;
  257. }