CLodArchiveLoader.cpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. #include "StdInc.h"
  2. #include "CLodArchiveLoader.h"
  3. #include "CInputStream.h"
  4. #include "CFileInputStream.h"
  5. #include "CCompressedStream.h"
  6. #include "CBinaryReader.h"
  7. #include "CFileInfo.h"
  8. #include <SDL_endian.h>
  9. ArchiveEntry::ArchiveEntry()
  10. : offset(0), realSize(0), size(0)
  11. {
  12. }
  13. CLodArchiveLoader::CLodArchiveLoader(const std::string & archive)
  14. {
  15. // Open archive file(.snd, .vid, .lod)
  16. this->archive = archive;
  17. CFileInputStream fileStream(archive);
  18. // Fake .lod file with no data has to be silently ignored.
  19. if(fileStream.getSize() < 10)
  20. return;
  21. // Retrieve file extension of archive in uppercase
  22. CFileInfo fileInfo(archive);
  23. std::string ext = fileInfo.getExtension();
  24. boost::to_upper(ext);
  25. // Init the specific lod container format
  26. if(ext == ".LOD" || ext == ".PAC")
  27. {
  28. initLODArchive(fileStream);
  29. }
  30. else if(ext == ".VID")
  31. {
  32. initVIDArchive(fileStream);
  33. }
  34. else if(ext == ".SND")
  35. {
  36. initSNDArchive(fileStream);
  37. }
  38. else
  39. {
  40. throw std::runtime_error("LOD archive format unknown. Cannot deal with " + archive);
  41. }
  42. }
  43. void CLodArchiveLoader::initLODArchive(CFileInputStream & fileStream)
  44. {
  45. // Read count of total files
  46. CBinaryReader reader(&fileStream);
  47. fileStream.seek(8);
  48. ui32 totalFiles = reader.readUInt32();
  49. // Get all entries from file
  50. fileStream.seek(0x5c);
  51. // Insert entries to list
  52. for(ui32 i = 0; i < totalFiles; i++)
  53. {
  54. char filename[16];
  55. reader.read(reinterpret_cast<ui8*>(filename), 16);
  56. // Create archive entry
  57. ArchiveEntry entry;
  58. entry.name = filename;
  59. entry.offset = reader.readUInt32();
  60. entry.realSize = reader.readUInt32();
  61. fileStream.skip(4); // unused, unknown
  62. entry.size = reader.readUInt32();
  63. // Add lod entry to local entries map
  64. entries[entry.name] = entry;
  65. }
  66. }
  67. void CLodArchiveLoader::initVIDArchive(CFileInputStream & fileStream)
  68. {
  69. // Define VideoEntryBlock struct
  70. struct VideoEntryBlock
  71. {
  72. char filename[40];
  73. ui32 offset;
  74. };
  75. // Read count of total files
  76. CBinaryReader reader(&fileStream);
  77. fileStream.seek(0);
  78. ui32 totalFiles = reader.readUInt32();
  79. // Get all entries from file
  80. fileStream.seek(4);
  81. struct VideoEntryBlock * vidEntries = new struct VideoEntryBlock[totalFiles];
  82. fileStream.read(reinterpret_cast<ui8 *>(vidEntries), sizeof(struct VideoEntryBlock) * totalFiles);
  83. // Insert entries to list
  84. for(ui32 i = 0; i < totalFiles; i++)
  85. {
  86. VideoEntryBlock vidEntry = vidEntries[i];
  87. ArchiveEntry entry;
  88. entry.name = vidEntry.filename;
  89. entry.offset = SDL_SwapLE32(vidEntry.offset);
  90. entry.size = 0;
  91. // There is no size, so check where the next file is
  92. if (i == totalFiles - 1)
  93. {
  94. entry.realSize = fileStream.getSize() - entry.offset;
  95. }
  96. else
  97. {
  98. VideoEntryBlock nextVidEntry = vidEntries[i + 1];
  99. entry.realSize = SDL_SwapLE32(nextVidEntry.offset) - entry.offset;
  100. }
  101. entries[entry.name] = entry;
  102. }
  103. // Delete vid entries array
  104. delete[] vidEntries;
  105. }
  106. void CLodArchiveLoader::initSNDArchive(CFileInputStream & fileStream)
  107. {
  108. // Define SoundEntryBlock struct
  109. struct SoundEntryBlock
  110. {
  111. char filename[40];
  112. ui32 offset;
  113. ui32 size;
  114. };
  115. // Read count of total files
  116. CBinaryReader reader(&fileStream);
  117. fileStream.seek(0);
  118. ui32 totalFiles = reader.readUInt32();
  119. // Get all entries from file
  120. fileStream.seek(4);
  121. struct SoundEntryBlock * sndEntries = new struct SoundEntryBlock[totalFiles];
  122. fileStream.read(reinterpret_cast<ui8 *>(sndEntries), sizeof(struct SoundEntryBlock) * totalFiles);
  123. // Insert entries to list
  124. for(ui32 i = 0; i < totalFiles; i++)
  125. {
  126. SoundEntryBlock sndEntry = sndEntries[i];
  127. ArchiveEntry entry;
  128. //for some reason entries in snd have format NAME\0WAVRUBBISH....
  129. //we need to replace first \0 with dot and take the 3 chars with extension (and drop the rest)
  130. entry.name = std::string(sndEntry.filename, 40);
  131. entry.name.resize(entry.name.find_first_of('\0') + 4); //+4 because we take dot and 3-char extension
  132. entry.name[entry.name.find_first_of('\0')] = '.';
  133. entry.offset = SDL_SwapLE32(sndEntry.offset);
  134. entry.realSize = SDL_SwapLE32(sndEntry.size);
  135. entry.size = 0;
  136. entries[entry.name] = entry;
  137. }
  138. // Delete snd entries array
  139. delete[] sndEntries;
  140. }
  141. std::unique_ptr<CInputStream> CLodArchiveLoader::load(const std::string & resourceName) const
  142. {
  143. assert(existsEntry(resourceName));
  144. const ArchiveEntry & entry = entries.find(resourceName)->second;
  145. if (entry.size != 0) //compressed data
  146. {
  147. std::unique_ptr<CInputStream> fileStream(new CFileInputStream(getOrigin(), entry.offset, entry.size));
  148. return std::unique_ptr<CInputStream>(new CCompressedStream(std::move(fileStream), false, entry.realSize));
  149. }
  150. else
  151. {
  152. return std::unique_ptr<CInputStream>(new CFileInputStream(getOrigin(), entry.offset, entry.realSize));
  153. }
  154. }
  155. boost::unordered_map<ResourceID, std::string> CLodArchiveLoader::getEntries() const
  156. {
  157. boost::unordered_map<ResourceID, std::string> retList;
  158. for(auto it = entries.begin(); it != entries.end(); ++it)
  159. {
  160. const ArchiveEntry & entry = it->second;
  161. retList[ResourceID(entry.name)] = entry.name;
  162. }
  163. return retList;
  164. }
  165. const ArchiveEntry * CLodArchiveLoader::getArchiveEntry(const std::string & resourceName) const
  166. {
  167. auto it = entries.find(resourceName);
  168. if(it != entries.end())
  169. {
  170. return &(it->second);
  171. }
  172. return nullptr;
  173. }
  174. bool CLodArchiveLoader::existsEntry(const std::string & resourceName) const
  175. {
  176. return entries.find(resourceName) != entries.end();
  177. }
  178. std::string CLodArchiveLoader::getOrigin() const
  179. {
  180. return archive;
  181. }