PakLoader.cpp 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. /*
  2. * PakLoader.cpp, part of VCMI engine
  3. *
  4. * Authors: listed in file AUTHORS in main folder
  5. *
  6. * License: GNU General Public License v2.0 or later
  7. * Full text of license available in license.txt file, in main folder
  8. *
  9. */
  10. #include "StdInc.h"
  11. #include "PakLoader.h"
  12. #include "../../../lib/filesystem/Filesystem.h"
  13. #include "../../../lib/filesystem/CBinaryReader.h"
  14. std::vector<std::vector<std::string>> stringtoTable(const std::string& input)
  15. {
  16. std::vector<std::vector<std::string>> result;
  17. std::vector<std::string> lines;
  18. boost::split(lines, input, boost::is_any_of("\n"));
  19. for(auto& line : lines)
  20. {
  21. boost::trim(line);
  22. if(line.empty())
  23. continue;
  24. std::vector<std::string> tokens;
  25. boost::split(tokens, line, boost::is_any_of(" "), boost::token_compress_on);
  26. result.push_back(tokens);
  27. }
  28. return result;
  29. }
  30. bool endsWithAny(const std::string & s, const std::unordered_set<std::string> & suffixes)
  31. {
  32. for(const auto & suf : suffixes)
  33. if(boost::algorithm::ends_with(s, suf))
  34. return true;
  35. return false;
  36. }
  37. void PakLoader::loadPak(ResourcePath path, int scale, std::unordered_set<std::string> animToSkip, std::unordered_set<std::string> imagesToSkip, std::unordered_set<std::string> suffixesToSkip)
  38. {
  39. auto file = CResourceHandler::get()->load(path);
  40. CBinaryReader reader(file.get());
  41. std::vector<ArchiveEntry> archiveEntries;
  42. [[maybe_unused]] uint32_t magic = reader.readUInt32();
  43. uint32_t headerOffset = reader.readUInt32();
  44. assert(magic == 4);
  45. file->seek(headerOffset);
  46. uint32_t entriesCount = reader.readUInt32();
  47. for(uint32_t i = 0; i < entriesCount; ++i)
  48. {
  49. ArchiveEntry entry;
  50. std::string buf(20, '\0');
  51. reader.read(reinterpret_cast<ui8*>(buf.data()), buf.size());
  52. size_t len = buf.find('\0');
  53. std::string s = buf.substr(0, len);
  54. entry.name = boost::algorithm::to_upper_copy(s);
  55. entry.metadataOffset = reader.readUInt32();
  56. entry.metadataSize = reader.readUInt32();
  57. entry.countSheets = reader.readUInt32();
  58. entry.compressedSize = reader.readUInt32();
  59. entry.fullSize = reader.readUInt32();
  60. entry.sheets.resize(entry.countSheets);
  61. for(uint32_t j = 0; j < entry.countSheets; ++j)
  62. entry.sheets[j].compressedSize = reader.readUInt32();
  63. for(uint32_t j = 0; j < entry.countSheets; ++j)
  64. entry.sheets[j].fullSize = reader.readUInt32();
  65. entry.scale = scale;
  66. if(animToSkip.find(entry.name) == animToSkip.end() && !endsWithAny(entry.name, suffixesToSkip))
  67. archiveEntries.push_back(entry);
  68. }
  69. for(auto & entry : archiveEntries)
  70. {
  71. file->seek(entry.metadataOffset);
  72. std::string buf(entry.metadataSize, '\0');
  73. reader.read(reinterpret_cast<ui8*>(buf.data()), buf.size());
  74. size_t len = buf.find('\0');
  75. std::string data = buf.substr(0, len);
  76. auto table = stringtoTable(data);
  77. for(const auto & sheet : entry.sheets)
  78. reader.skip(sheet.compressedSize);
  79. ImageEntry image;
  80. for(const auto & line : table)
  81. {
  82. assert(line.size() == 12 || line.size() == 18);
  83. image.name = boost::algorithm::to_upper_copy(line[0]);
  84. image.sheetIndex = std::stol(line[1]);
  85. image.spriteOffsetX = std::stol(line[2]);
  86. image.unknown1 = std::stol(line[3]);
  87. image.spriteOffsetY = std::stol(line[4]);
  88. image.unknown2 = std::stol(line[5]);
  89. image.sheetOffsetX = std::stol(line[6]);
  90. image.sheetOffsetY = std::stol(line[7]);
  91. image.width = std::stol(line[8]);
  92. image.height = std::stol(line[9]);
  93. image.rotation = std::stol(line[10]);
  94. image.hasShadow = std::stol(line[11]);
  95. assert(image.rotation == 0 || image.rotation == 1);
  96. if(image.hasShadow)
  97. {
  98. image.shadowSheetIndex = std::stol(line[12]);
  99. image.shadowSheetOffsetX = std::stol(line[13]);
  100. image.shadowSheetOffsetY = std::stol(line[14]);
  101. image.shadowWidth = std::stol(line[15]);
  102. image.shadowHeight = std::stol(line[16]);
  103. image.shadowRotation = std::stol(line[17]);
  104. assert(image.shadowRotation == 0 || image.shadowRotation == 1);
  105. }
  106. if(imagesToSkip.find(image.name) == imagesToSkip.end() && !endsWithAny(image.name, suffixesToSkip))
  107. entry.images.push_back(image);
  108. }
  109. }
  110. content[path] = archiveEntries;
  111. // Build indices for fast lookup
  112. for(auto& entry : content[path])
  113. {
  114. for(auto& image : entry.images)
  115. imagesByName[scale].try_emplace(image.name, path, &image, &entry);
  116. }
  117. }