CArchiveLoader.cpp 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. #include "StdInc.h"
  2. #include "CArchiveLoader.h"
  3. #include "CFileInputStream.h"
  4. #include "CCompressedStream.h"
  5. #include "CBinaryReader.h"
  6. #include "CFileInfo.h"
  7. ArchiveEntry::ArchiveEntry()
  8. : offset(0), fullSize(0), compressedSize(0)
  9. {
  10. }
  11. CArchiveLoader::CArchiveLoader(const std::string &mountPoint, const std::string & archive):
  12. archive(archive),
  13. mountPoint(mountPoint)
  14. {
  15. // Open archive file(.snd, .vid, .lod)
  16. CFileInputStream fileStream(archive);
  17. // Fake .lod file with no data has to be silently ignored.
  18. if(fileStream.getSize() < 10)
  19. return;
  20. // Retrieve file extension of archive in uppercase
  21. CFileInfo fileInfo(archive);
  22. std::string ext = fileInfo.getExtension();
  23. boost::to_upper(ext);
  24. // Init the specific lod container format
  25. if(ext == ".LOD" || ext == ".PAC")
  26. {
  27. initLODArchive(mountPoint, fileStream);
  28. }
  29. else if(ext == ".VID")
  30. {
  31. initVIDArchive(mountPoint, fileStream);
  32. }
  33. else if(ext == ".SND")
  34. {
  35. initSNDArchive(mountPoint, fileStream);
  36. }
  37. else
  38. {
  39. throw std::runtime_error("LOD archive format unknown. Cannot deal with " + archive);
  40. }
  41. logGlobal->traceStream() << ext << "Archive loaded, " << entries.size() << " files found";
  42. }
  43. void CArchiveLoader::initLODArchive(const std::string &mountPoint, 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.fullSize = reader.readUInt32();
  61. fileStream.skip(4); // unused, unknown
  62. entry.compressedSize = reader.readUInt32();
  63. // Add lod entry to local entries map
  64. entries[ResourceID(mountPoint + entry.name)] = entry;
  65. }
  66. }
  67. void CArchiveLoader::initVIDArchive(const std::string &mountPoint, CFileInputStream & fileStream)
  68. {
  69. // Read count of total files
  70. CBinaryReader reader(&fileStream);
  71. fileStream.seek(0);
  72. ui32 totalFiles = reader.readUInt32();
  73. std::set<int> offsets;
  74. // Insert entries to list
  75. for(ui32 i = 0; i < totalFiles; i++)
  76. {
  77. char filename[40];
  78. reader.read(reinterpret_cast<ui8*>(filename), 40);
  79. ArchiveEntry entry;
  80. entry.name = filename;
  81. entry.offset = reader.readInt32();
  82. entry.compressedSize = 0;
  83. offsets.insert(entry.offset);
  84. entries[ResourceID(mountPoint + entry.name)] = entry;
  85. }
  86. offsets.insert(fileStream.getSize());
  87. // now when we know postion of all files their sizes can be set correctly
  88. for (auto & entry : entries)
  89. {
  90. auto it = offsets.find(entry.second.offset);
  91. it++;
  92. entry.second.fullSize = *it - entry.second.offset;
  93. }
  94. }
  95. void CArchiveLoader::initSNDArchive(const std::string &mountPoint, CFileInputStream & fileStream)
  96. {
  97. // Read count of total files
  98. CBinaryReader reader(&fileStream);
  99. fileStream.seek(0);
  100. ui32 totalFiles = reader.readUInt32();
  101. // Insert entries to list
  102. for(ui32 i = 0; i < totalFiles; i++)
  103. {
  104. char filename[40];
  105. reader.read(reinterpret_cast<ui8*>(filename), 40);
  106. //for some reason entries in snd have format NAME\0WAVRUBBISH....
  107. //we need to replace first \0 with dot and take the 3 chars with extension (and drop the rest)
  108. ArchiveEntry entry;
  109. entry.name = filename; // till 1st \0
  110. entry.name += '.';
  111. entry.name += std::string(filename + entry.name.size(), 3);
  112. entry.offset = reader.readInt32();
  113. entry.fullSize = reader.readInt32();
  114. entry.compressedSize = 0;
  115. entries[ResourceID(mountPoint + entry.name)] = entry;
  116. }
  117. }
  118. std::unique_ptr<CInputStream> CArchiveLoader::load(const ResourceID & resourceName) const
  119. {
  120. assert(existsResource(resourceName));
  121. const ArchiveEntry & entry = entries.at(resourceName);
  122. if (entry.compressedSize != 0) //compressed data
  123. {
  124. std::unique_ptr<CInputStream> fileStream(new CFileInputStream(archive, entry.offset, entry.compressedSize));
  125. return std::unique_ptr<CInputStream>(new CCompressedStream(std::move(fileStream), false, entry.fullSize));
  126. }
  127. else
  128. {
  129. return std::unique_ptr<CInputStream>(new CFileInputStream(archive, entry.offset, entry.fullSize));
  130. }
  131. }
  132. bool CArchiveLoader::existsResource(const ResourceID & resourceName) const
  133. {
  134. return entries.count(resourceName) != 0;
  135. }
  136. std::string CArchiveLoader::getMountPoint() const
  137. {
  138. return mountPoint;
  139. }
  140. std::unordered_set<ResourceID> CArchiveLoader::getFilteredFiles(std::function<bool(const ResourceID &)> filter) const
  141. {
  142. std::unordered_set<ResourceID> foundID;
  143. for (auto & file : entries)
  144. {
  145. if (filter(file.first))
  146. foundID.insert(file.first);
  147. }
  148. return foundID;
  149. }