|
| 1 | +// Copyright (c) 2015-2016, NetEase Inc. All rights reserved. |
| 2 | +// |
| 3 | +// Author: litianyi <litianyi@corp.netease.com> |
| 4 | +// Date: 2015/10/20 |
| 5 | +// |
| 6 | +// NIM SDK内部使用的helper |
| 7 | + |
| 8 | +#include "common_helper.h" |
| 9 | +#include "base/files/file_path.h" |
| 10 | +#include "extension/file_util/path_util.h" |
| 11 | +#include "extension/strings/string_util.h" |
| 12 | + |
| 13 | +namespace node_nim { |
| 14 | + |
| 15 | +const std::string PathChecker::kCurrentDirectoryDescriptor = "."; |
| 16 | +const std::string PathChecker::kParentDirectoryDescriptor = ".."; |
| 17 | +const char PathChecker::kDriveLettar = ':'; |
| 18 | +const std::string PathChecker::kPathDelimiter = "/"; |
| 19 | +const std::string PathChecker::kPathDelimiter_WIN = "\\"; |
| 20 | +const char PathChecker::kCurrentDirectoryDescriptorLettar = '.'; |
| 21 | +const char PathChecker::kSpaceLettar = ' '; |
| 22 | + |
| 23 | +PathChecker::PathChecker(const std::string& path) |
| 24 | + : src_path_(path) {} |
| 25 | + |
| 26 | +PathChecker::Result PathChecker::Check() { |
| 27 | + if (!CheckFormat()) |
| 28 | + return Format_Error; |
| 29 | +#if !defined(OS_WIN) |
| 30 | + auto file_path = base::FilePath(src_path_); |
| 31 | + return file_path.IsAbsolute() ? Absolute_Path : Relative_Path; |
| 32 | +#else |
| 33 | + auto it = tokened_.begin(); |
| 34 | + bool has_drive; |
| 35 | + if (!CheckDrive(*it++, has_drive)) |
| 36 | + return Format_Error; |
| 37 | + while (it != tokened_.end()) { |
| 38 | + if ((it->compare(kParentDirectoryDescriptor) == 0 && it == tokened_.begin()) || |
| 39 | + (it != tokened_.begin() && it->find(kDriveLettar) != std::string::npos)) { |
| 40 | + return Format_Error; |
| 41 | + } else if (it->compare(kCurrentDirectoryDescriptor) == 0) { |
| 42 | + it = tokened_.erase(it); |
| 43 | + } else if (it->compare(kParentDirectoryDescriptor) == 0) { |
| 44 | + it = tokened_.erase(it); |
| 45 | + it--; |
| 46 | + it = tokened_.erase(it); |
| 47 | + } else { |
| 48 | + it++; |
| 49 | + } |
| 50 | + } |
| 51 | + if (has_drive) { |
| 52 | + bool has_drive_check; |
| 53 | + if (!CheckDrive(*tokened_.begin(), has_drive_check)) |
| 54 | + return Format_Error; |
| 55 | + return has_drive_check ? Absolute_Path : Format_Error; |
| 56 | + } |
| 57 | + return Relative_Path; |
| 58 | +#endif |
| 59 | +} |
| 60 | + |
| 61 | +std::string PathChecker::GetPath() { |
| 62 | +#if !defined(OS_WIN) |
| 63 | + return src_path_; |
| 64 | +#else |
| 65 | + std::string ret; |
| 66 | + auto it = tokened_.begin(); |
| 67 | + while (it != tokened_.end()) { |
| 68 | + ret.append(*it).append(kPathDelimiter); |
| 69 | + it++; |
| 70 | + } |
| 71 | + return ret; |
| 72 | +#endif |
| 73 | +} |
| 74 | + |
| 75 | +bool PathChecker::CheckFormat() { |
| 76 | + // 不可以含有不支持的字符 |
| 77 | + static const std::string kFobidenLettars = "*?\"<>|"; |
| 78 | + auto itFobidenLettars = kFobidenLettars.begin(); |
| 79 | + while (itFobidenLettars != kFobidenLettars.end()) { |
| 80 | + if (src_path_.find(*itFobidenLettars) != std::string::npos) |
| 81 | + return false; |
| 82 | + itFobidenLettars++; |
| 83 | + } |
| 84 | + // C:\A\B\C\..\..\..\..\D:\A\B\C这种格式同样不支持 |
| 85 | + if (src_path_.find(kDriveLettar) != std::string::npos && src_path_.find_first_of(kDriveLettar) != src_path_.find_last_of(kDriveLettar)) |
| 86 | + return false; |
| 87 | +#if !defined(OS_WIN) |
| 88 | + if (src_path_.length() == 0) |
| 89 | + return false; |
| 90 | +#else |
| 91 | + nbase::StringReplaceAll(kPathDelimiter_WIN, kPathDelimiter, src_path_); |
| 92 | + tokened_ = SplitPathItem(src_path_.c_str(), kPathDelimiter.c_str()); |
| 93 | + // 过滤掉最后一个右侧" "与"." |
| 94 | + { |
| 95 | + auto rit = tokened_.rbegin(); |
| 96 | + auto temp = *rit; |
| 97 | + while (!temp.empty()) { |
| 98 | + if (temp[temp.length() - 1] == kSpaceLettar || temp[temp.length() - 1] == kCurrentDirectoryDescriptorLettar) |
| 99 | + temp.resize(temp.length() - 1); |
| 100 | + else |
| 101 | + break; |
| 102 | + } |
| 103 | + if (temp.empty()) |
| 104 | + return false; |
| 105 | + if (rit->compare(temp) != 0) |
| 106 | + rit->assign(temp.begin(), temp.end()); |
| 107 | + } |
| 108 | + // 判断中间路径是否有不合规则的"."或者".."或者""或者" "或者(.... / .. .. / . . ./// ) 并移除掉所有的"." |
| 109 | + auto it = tokened_.begin(); |
| 110 | + while (it != tokened_.end()) { |
| 111 | + auto temp = *it; |
| 112 | + if (temp.compare(kCurrentDirectoryDescriptor) == 0) // 合格的 |
| 113 | + { |
| 114 | + it = tokened_.erase(it); |
| 115 | + } else if (temp.compare(kParentDirectoryDescriptor) == 0) // 合格的 |
| 116 | + { |
| 117 | + it++; |
| 118 | + } else { |
| 119 | + nbase::StringReplaceAll(" ", "", temp); |
| 120 | + nbase::StringReplaceAll(".", "", temp); |
| 121 | + if (temp.empty()) //(....、 .. ..、 . . .、 、这种型的) |
| 122 | + return false; |
| 123 | + temp = *it; |
| 124 | + if (*temp.rbegin() == kSpaceLettar) // 不可以是空格结尾 |
| 125 | + return false; |
| 126 | + if (temp.length() > 2) { |
| 127 | + if (temp[temp.length() - 1] == kCurrentDirectoryDescriptorLettar && |
| 128 | + (temp[temp.length() - 2] == kCurrentDirectoryDescriptorLettar || |
| 129 | + temp[temp.length() - 2] == kSpaceLettar)) // 末尾带一个点,合格,多于一个,不合格 |
| 130 | + return false; |
| 131 | + else if (temp[temp.length() - 1] == kCurrentDirectoryDescriptorLettar) { |
| 132 | + temp.resize(temp.length() - 1); |
| 133 | + it->assign(temp.begin(), temp.end()); |
| 134 | + } |
| 135 | + } |
| 136 | + it++; |
| 137 | + } |
| 138 | + } |
| 139 | + if (tokened_.empty()) |
| 140 | + return false; |
| 141 | + if (tokened_.begin()->compare(kParentDirectoryDescriptor) == 0) // ..\ABC\DEF 开头以..的不支持 但..ABC..\DEF是支持的 |
| 142 | + return false; |
| 143 | +#endif |
| 144 | + |
| 145 | + return true; |
| 146 | +} |
| 147 | + |
| 148 | +bool PathChecker::CheckDrive(const std::string& data, bool& has_drive) { |
| 149 | + has_drive = false; |
| 150 | + auto drive_pos = data.find(kDriveLettar); |
| 151 | + if (drive_pos == std::string::npos) { |
| 152 | + has_drive = false; |
| 153 | + return true; |
| 154 | + } |
| 155 | + std::string temp(data); |
| 156 | + if (temp.length() > 2) |
| 157 | + return false; |
| 158 | + auto drive = *data.begin(); |
| 159 | + static const std::string kDriveList = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; |
| 160 | + if (kDriveList.find(drive) != std::string::npos) { |
| 161 | + has_drive = true; |
| 162 | + return true; |
| 163 | + } |
| 164 | + return false; |
| 165 | +} |
| 166 | + |
| 167 | +std::list<std::string> PathChecker::SplitPathItem(const std::string& input, const char* delimitor) { |
| 168 | + std::list<std::string> output; |
| 169 | + std::string temp(input); |
| 170 | + if (*temp.rbegin() == *delimitor) |
| 171 | + temp.resize(temp.length() - 1); |
| 172 | + size_t pos{std::string::npos}; |
| 173 | + do { |
| 174 | + pos = temp.find_first_of(delimitor); |
| 175 | + if (pos != std::string::npos) { |
| 176 | + output.emplace_back(temp.substr(0, pos)); |
| 177 | + temp = temp.substr(pos + 1); |
| 178 | + } else { |
| 179 | + output.emplace_back(temp); |
| 180 | + } |
| 181 | + } while (pos != std::string::npos); |
| 182 | + return output; |
| 183 | +} |
| 184 | + |
| 185 | +bool parseAppdataPaths(const std::string& userAppData, base::FilePath& fullPath, std::string& parsedPath, std::string& parsedFolder) { |
| 186 | + std::string app_data_path = userAppData.empty() ? DEFAULT_APP_DATA_DIR : userAppData; |
| 187 | + node_nim::PathChecker path_checker(app_data_path); |
| 188 | + auto check_result = path_checker.Check(); |
| 189 | + if (check_result == node_nim::PathChecker::Format_Error) { |
| 190 | + return false; |
| 191 | + // return V2NIMError{V2NIM_ERROR_CODE_INVALID_PARAMETER, {"appDataPath", appDataPath}}; |
| 192 | + } |
| 193 | + base::FilePath local_app_data_path_obj; |
| 194 | + base::FilePath app_data_path_obj; |
| 195 | + if (check_result == node_nim::PathChecker::Absolute_Path) { |
| 196 | + std::list<UTF8String> path_components; |
| 197 | + bool result = nbase::ParsePathComponents(path_checker.GetPath().c_str(), path_components); |
| 198 | + if (!result) |
| 199 | + return false; |
| 200 | + std::size_t index = 0; |
| 201 | + for (const auto& path_component : path_components) { |
| 202 | + if (index < path_components.size() - 1) { |
| 203 | + parsedPath.append(path_component); |
| 204 | + } |
| 205 | + index++; |
| 206 | + } |
| 207 | + parsedFolder = base::FilePath::FromUTF8Unsafe(path_checker.GetPath()).BaseName().AsUTF8Unsafe(); |
| 208 | + } else { |
| 209 | + parsedPath = base::FilePath::FromUTF8Unsafe(base::extension::GetSysLocalAppDataDir()).AsUTF8Unsafe(); |
| 210 | + parsedFolder = app_data_path; |
| 211 | + } |
| 212 | + base::extension::SetLocalAppDataDir(parsedPath); |
| 213 | + base::extension::SetCustomAppDataDirName(parsedFolder); |
| 214 | + fullPath = base::FilePath::FromUTF8Unsafe(parsedPath).Append(base::FilePath::FromUTF8Unsafe(parsedFolder)); |
| 215 | + return true; |
| 216 | +} |
| 217 | + |
| 218 | +} // namespace node_nim |
0 commit comments