path_parser.cpp 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. // Copyright 2016 Citra Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <algorithm>
  5. #include <set>
  6. #include "common/file_util.h"
  7. #include "common/string_util.h"
  8. #include "core/file_sys/path_parser.h"
  9. namespace FileSys {
  10. PathParser::PathParser(const Path& path) {
  11. if (path.GetType() != LowPathType::Char && path.GetType() != LowPathType::Wchar) {
  12. is_valid = false;
  13. return;
  14. }
  15. auto path_string = path.AsString();
  16. if (path_string.size() == 0 || path_string[0] != '/') {
  17. is_valid = false;
  18. return;
  19. }
  20. // Filter out invalid characters for the host system.
  21. // Although some of these characters are valid on 3DS, they are unlikely to be used by games.
  22. if (std::find_if(path_string.begin(), path_string.end(), [](char c) {
  23. static const std::set<char> invalid_chars{'<', '>', '\\', '|', ':', '\"', '*', '?'};
  24. return invalid_chars.find(c) != invalid_chars.end();
  25. }) != path_string.end()) {
  26. is_valid = false;
  27. return;
  28. }
  29. Common::SplitString(path_string, '/', path_sequence);
  30. auto begin = path_sequence.begin();
  31. auto end = path_sequence.end();
  32. end = std::remove_if(begin, end, [](std::string& str) { return str == "" || str == "."; });
  33. path_sequence = std::vector<std::string>(begin, end);
  34. // checks if the path is out of bounds.
  35. int level = 0;
  36. for (auto& node : path_sequence) {
  37. if (node == "..") {
  38. --level;
  39. if (level < 0) {
  40. is_valid = false;
  41. return;
  42. }
  43. } else {
  44. ++level;
  45. }
  46. }
  47. is_valid = true;
  48. is_root = level == 0;
  49. }
  50. PathParser::HostStatus PathParser::GetHostStatus(const std::string& mount_point) const {
  51. auto path = mount_point;
  52. if (!FileUtil::IsDirectory(path))
  53. return InvalidMountPoint;
  54. if (path_sequence.empty()) {
  55. return DirectoryFound;
  56. }
  57. for (auto iter = path_sequence.begin(); iter != path_sequence.end() - 1; iter++) {
  58. if (path.back() != '/')
  59. path += '/';
  60. path += *iter;
  61. if (!FileUtil::Exists(path))
  62. return PathNotFound;
  63. if (FileUtil::IsDirectory(path))
  64. continue;
  65. return FileInPath;
  66. }
  67. path += "/" + path_sequence.back();
  68. if (!FileUtil::Exists(path))
  69. return NotFound;
  70. if (FileUtil::IsDirectory(path))
  71. return DirectoryFound;
  72. return FileFound;
  73. }
  74. std::string PathParser::BuildHostPath(const std::string& mount_point) const {
  75. std::string path = mount_point;
  76. for (auto& node : path_sequence) {
  77. if (path.back() != '/')
  78. path += '/';
  79. path += node;
  80. }
  81. return path;
  82. }
  83. } // namespace FileSys