vfs_libzip.cpp 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  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. #ifdef __GNUC__
  6. #pragma GCC diagnostic push
  7. #pragma GCC diagnostic ignored "-Wshadow"
  8. #endif
  9. #include <zip.h>
  10. #ifdef __GNUC__
  11. #pragma GCC diagnostic pop
  12. #endif
  13. #include "common/fs/path_util.h"
  14. #include "core/file_sys/vfs.h"
  15. #include "core/file_sys/vfs_libzip.h"
  16. #include "core/file_sys/vfs_vector.h"
  17. namespace FileSys {
  18. VirtualDir ExtractZIP(VirtualFile file) {
  19. zip_error_t error{};
  20. const auto data = file->ReadAllBytes();
  21. std::unique_ptr<zip_source_t, decltype(&zip_source_close)> src{
  22. zip_source_buffer_create(data.data(), data.size(), 0, &error), zip_source_close};
  23. if (src == nullptr)
  24. return nullptr;
  25. std::unique_ptr<zip_t, decltype(&zip_close)> zip{zip_open_from_source(src.get(), 0, &error),
  26. zip_close};
  27. if (zip == nullptr)
  28. return nullptr;
  29. std::shared_ptr<VectorVfsDirectory> out = std::make_shared<VectorVfsDirectory>();
  30. const auto num_entries = static_cast<std::size_t>(zip_get_num_entries(zip.get(), 0));
  31. zip_stat_t stat{};
  32. zip_stat_init(&stat);
  33. for (std::size_t i = 0; i < num_entries; ++i) {
  34. const auto stat_res = zip_stat_index(zip.get(), i, 0, &stat);
  35. if (stat_res == -1)
  36. return nullptr;
  37. const std::string name(stat.name);
  38. if (name.empty())
  39. continue;
  40. if (name.back() != '/') {
  41. std::unique_ptr<zip_file_t, decltype(&zip_fclose)> file2{
  42. zip_fopen_index(zip.get(), i, 0), zip_fclose};
  43. std::vector<u8> buf(stat.size);
  44. if (zip_fread(file2.get(), buf.data(), buf.size()) != s64(buf.size()))
  45. return nullptr;
  46. const auto parts = Common::FS::SplitPathComponents(stat.name);
  47. const auto new_file = std::make_shared<VectorVfsFile>(buf, parts.back());
  48. std::shared_ptr<VectorVfsDirectory> dtrv = out;
  49. for (std::size_t j = 0; j < parts.size() - 1; ++j) {
  50. if (dtrv == nullptr)
  51. return nullptr;
  52. const auto subdir = dtrv->GetSubdirectory(parts[j]);
  53. if (subdir == nullptr) {
  54. const auto temp = std::make_shared<VectorVfsDirectory>(
  55. std::vector<VirtualFile>{}, std::vector<VirtualDir>{}, parts[j]);
  56. dtrv->AddDirectory(temp);
  57. dtrv = temp;
  58. } else {
  59. dtrv = std::dynamic_pointer_cast<VectorVfsDirectory>(subdir);
  60. }
  61. }
  62. if (dtrv == nullptr)
  63. return nullptr;
  64. dtrv->AddFile(new_file);
  65. }
  66. }
  67. return out;
  68. }
  69. } // namespace FileSys