vfs_libzip.cpp 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. // Copyright 2019 yuzu emulator team
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <string>
  5. #include <zip.h>
  6. #include "common/logging/backend.h"
  7. #include "core/file_sys/vfs.h"
  8. #include "core/file_sys/vfs_libzip.h"
  9. #include "core/file_sys/vfs_vector.h"
  10. namespace FileSys {
  11. VirtualDir ExtractZIP(VirtualFile file) {
  12. zip_error_t error{};
  13. const auto data = file->ReadAllBytes();
  14. std::unique_ptr<zip_source_t, decltype(&zip_source_close)> src{
  15. zip_source_buffer_create(data.data(), data.size(), 0, &error), zip_source_close};
  16. if (src == nullptr)
  17. return nullptr;
  18. std::unique_ptr<zip_t, decltype(&zip_close)> zip{zip_open_from_source(src.get(), 0, &error),
  19. zip_close};
  20. if (zip == nullptr)
  21. return nullptr;
  22. std::shared_ptr<VectorVfsDirectory> out = std::make_shared<VectorVfsDirectory>();
  23. const auto num_entries = static_cast<std::size_t>(zip_get_num_entries(zip.get(), 0));
  24. zip_stat_t stat{};
  25. zip_stat_init(&stat);
  26. for (std::size_t i = 0; i < num_entries; ++i) {
  27. const auto stat_res = zip_stat_index(zip.get(), i, 0, &stat);
  28. if (stat_res == -1)
  29. return nullptr;
  30. const std::string name(stat.name);
  31. if (name.empty())
  32. continue;
  33. if (name.back() != '/') {
  34. std::unique_ptr<zip_file_t, decltype(&zip_fclose)> file2{
  35. zip_fopen_index(zip.get(), i, 0), zip_fclose};
  36. std::vector<u8> buf(stat.size);
  37. if (zip_fread(file2.get(), buf.data(), buf.size()) != s64(buf.size()))
  38. return nullptr;
  39. const auto parts = FileUtil::SplitPathComponents(stat.name);
  40. const auto new_file = std::make_shared<VectorVfsFile>(buf, parts.back());
  41. std::shared_ptr<VectorVfsDirectory> dtrv = out;
  42. for (std::size_t j = 0; j < parts.size() - 1; ++j) {
  43. if (dtrv == nullptr)
  44. return nullptr;
  45. const auto subdir = dtrv->GetSubdirectory(parts[j]);
  46. if (subdir == nullptr) {
  47. const auto temp = std::make_shared<VectorVfsDirectory>(
  48. std::vector<VirtualFile>{}, std::vector<VirtualDir>{}, parts[j]);
  49. dtrv->AddDirectory(temp);
  50. dtrv = temp;
  51. } else {
  52. dtrv = std::dynamic_pointer_cast<VectorVfsDirectory>(subdir);
  53. }
  54. }
  55. if (dtrv == nullptr)
  56. return nullptr;
  57. dtrv->AddFile(new_file);
  58. }
  59. }
  60. return out;
  61. }
  62. } // namespace FileSys