| 338 | #endif |
| 339 | |
| 340 | static std::vector<AutoCloudRuleNative> LoadAutoCloudRules(const std::string& steamPath, uint32_t appId) { |
| 341 | std::vector<AutoCloudRuleNative> rules; |
| 342 | std::filesystem::path appInfoPath = FileUtil::Utf8ToPath(steamPath) / "appcache" / "appinfo.vdf"; |
| 343 | std::error_code mtimeEc, sizeEc; |
| 344 | auto appInfoMtime = std::filesystem::last_write_time(appInfoPath, mtimeEc); |
| 345 | auto appInfoSize = std::filesystem::file_size(appInfoPath, sizeEc); |
| 346 | if (mtimeEc || sizeEc) { |
| 347 | LOG("GetAutoCloudFileList: failed to stat appinfo.vdf: %s", |
| 348 | (mtimeEc ? mtimeEc : sizeEc).message().c_str()); |
| 349 | return rules; |
| 350 | } |
| 351 | if (appInfoSize > kMaxAppInfoBytes) { |
| 352 | LOG("GetAutoCloudFileList: appinfo.vdf too large: %llu bytes", (unsigned long long)appInfoSize); |
| 353 | return rules; |
| 354 | } |
| 355 | |
| 356 | struct RulesCacheEntry { |
| 357 | std::filesystem::file_time_type mtime; |
| 358 | uintmax_t size = 0; |
| 359 | std::vector<AutoCloudRuleNative> rules; |
| 360 | }; |
| 361 | static std::mutex cacheMutex; |
| 362 | static std::unordered_map<std::string, RulesCacheEntry> cache; |
| 363 | // PathToUtf8 keeps non-ACP codepoints; path::string() would round-trip to '?'. |
| 364 | std::string cacheKey = FileUtil::PathToUtf8(appInfoPath) + "\n" + std::to_string(appId); |
| 365 | { |
| 366 | std::lock_guard<std::mutex> lock(cacheMutex); |
| 367 | auto it = cache.find(cacheKey); |
| 368 | if (it != cache.end() && it->second.mtime == appInfoMtime && it->second.size == appInfoSize) { |
| 369 | return it->second.rules; |
| 370 | } |
| 371 | } |
| 372 | |
| 373 | auto cacheRules = [&](const std::vector<AutoCloudRuleNative>& parsedRules) { |
| 374 | std::lock_guard<std::mutex> lock(cacheMutex); |
| 375 | cache[cacheKey] = RulesCacheEntry{appInfoMtime, appInfoSize, parsedRules}; |
| 376 | }; |
| 377 | |
| 378 | std::ifstream f(appInfoPath, std::ios::binary | std::ios::ate); |
| 379 | if (!f) { |
| 380 | LOG("GetAutoCloudFileList: appinfo.vdf not found: %s", FileUtil::PathToUtf8(appInfoPath).c_str()); |
| 381 | return rules; |
| 382 | } |
| 383 | |
| 384 | auto fileSize = f.tellg(); |
| 385 | if (fileSize < 16) return rules; |
| 386 | if (static_cast<uintmax_t>(fileSize) > kMaxAppInfoBytes) { |
| 387 | LOG("GetAutoCloudFileList: appinfo.vdf too large after open: %llu bytes", |
| 388 | (unsigned long long)fileSize); |
| 389 | return rules; |
| 390 | } |
| 391 | f.seekg(0, std::ios::beg); |
| 392 | std::vector<uint8_t> bytes((size_t)fileSize); |
| 393 | if (!f.read(reinterpret_cast<char*>(bytes.data()), fileSize)) return rules; |
| 394 | |
| 395 | size_t offset = 0; |
| 396 | uint32_t magic = 0, universe = 0, stringOffsetLo = 0, stringOffsetHi = 0; |
| 397 | if (!ReadU32(bytes, offset, magic) || !ReadU32(bytes, offset, universe) || |
nothing calls this directly
no test coverage detected