FileSystemPath.cpp 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. #include "FileSystemPath.h"
  2. #include "StringBuilder.h"
  3. #include "Vector.h"
  4. #include "kstdio.h"
  5. namespace AK {
  6. FileSystemPath::FileSystemPath(const StringView& s)
  7. : m_string(s)
  8. {
  9. canonicalize();
  10. m_is_valid = true;
  11. }
  12. void FileSystemPath::canonicalize()
  13. {
  14. if (m_string.is_empty()) {
  15. m_parts.clear();
  16. return;
  17. }
  18. bool is_absolute_path = m_string[0] == '/';
  19. auto parts = m_string.split_view('/');
  20. if (!is_absolute_path)
  21. parts.prepend(".");
  22. int approximate_canonical_length = 0;
  23. Vector<String> canonical_parts;
  24. for (int i = 0; i < parts.size(); ++i) {
  25. auto& part = parts[i];
  26. if (is_absolute_path || i != 0) {
  27. if (part == ".")
  28. continue;
  29. }
  30. if (part == "..") {
  31. if (!canonical_parts.is_empty())
  32. canonical_parts.take_last();
  33. continue;
  34. }
  35. if (!part.is_empty()) {
  36. approximate_canonical_length += part.length() + 1;
  37. canonical_parts.append(part);
  38. }
  39. }
  40. if (canonical_parts.is_empty()) {
  41. m_string = m_basename = m_dirname = "/";
  42. return;
  43. }
  44. StringBuilder dirname_builder(approximate_canonical_length);
  45. for (int i = 0; i < canonical_parts.size() - 1; ++i) {
  46. auto& canonical_part = canonical_parts[i];
  47. if (is_absolute_path || i != 0)
  48. dirname_builder.append('/');
  49. dirname_builder.append(canonical_part);
  50. }
  51. m_dirname = dirname_builder.to_string();
  52. m_basename = canonical_parts.last();
  53. auto name_parts = m_basename.split('.');
  54. m_title = name_parts[0];
  55. if (name_parts.size() > 1)
  56. m_extension = name_parts[1];
  57. StringBuilder builder(approximate_canonical_length);
  58. for (int i = 0; i < canonical_parts.size(); ++i) {
  59. auto& canonical_part = canonical_parts[i];
  60. if (is_absolute_path || i != 0)
  61. builder.append('/');
  62. builder.append(canonical_part);
  63. }
  64. m_parts = move(canonical_parts);
  65. m_string = builder.to_string();
  66. }
  67. bool FileSystemPath::has_extension(StringView extension) const
  68. {
  69. // FIXME: This is inefficient, expand StringView with enough functionality that we don't need to copy strings here.
  70. String extension_string = extension;
  71. return m_string.to_lowercase().ends_with(extension_string.to_lowercase());
  72. }
  73. String canonicalized_path(const StringView& path)
  74. {
  75. return FileSystemPath(path).string();
  76. }
  77. }