| 76 | const OsPath cacheFileName = GetDirectoryName() / L"replayCache.json"; |
| 77 | JS::RootedObject cachedReplaysObject(cx); |
| 78 | |
| 79 | bool cacheFound = FileExists(cacheFileName); |
| 80 | if (cacheFound) |
| 81 | { |
| 82 | // Open cache file |
| 83 | std::istream* cacheStream = new std::ifstream(cacheFileName.string8().c_str()); |
| 84 | |
| 85 | // Read file into chacheStr |
| 86 | CStr cacheStr((std::istreambuf_iterator<char>(*cacheStream)), std::istreambuf_iterator<char>()); |
| 87 | |
| 88 | // Create empty JS object and parse the context of the cache into it |
| 89 | JS::RootedValue cachedReplays(cx); |
| 90 | scriptInterface.ParseJSON(cacheStr, &cachedReplays); |
| 91 | SAFE_DELETE(cacheStream); |
| 92 | |
| 93 | JS::RootedObject temp(cx, &cachedReplays.toObject()); |
| 94 | cachedReplaysObject = temp; |
| 95 | |
| 96 | // Create list of files included in the cache |
| 97 | u32 cacheLength = 0; |
| 98 | JS_GetArrayLength(cx, cachedReplaysObject, &cacheLength); |
| 99 | for (u32 j = 0; j < cacheLength ; ++j) |
| 100 | { |
| 101 | JS::RootedValue replay(cx); |
| 102 | JS_GetElement(cx, cachedReplaysObject, j, &replay); |
| 103 | |
| 104 | JS::RootedObject replayObject(cx, &replay.toObject()); |
| 105 | JS::RootedValue file(cx); |
| 106 | JS_GetProperty(cx, replayObject, "directory", &file); |
| 107 | |
| 108 | CStr fileName; |
| 109 | scriptInterface.FromJSVal(cx, file, fileName); |
| 110 | fileList.emplace(fileName, j); |
| 111 | } |
| 112 | } |
| 113 | |
| 114 | JS::RootedObject replays(cx, JS_NewArrayObject(cx, 0)); |
| 115 | bool newReplays = false; |
| 116 | DirectoryNames directories; |
86 | | JS::RootedValue replayData(cx, LoadReplayData(scriptInterface, directory)); |
87 | | if (!replayData.isNull()) |
88 | | JS_SetElement(cx, replays, i++, replayData); |
| 125 | std::map<CStr, u32>::iterator it = fileList.find(directory.string8()); |
| 126 | |
| 127 | // directory is not element of fileList |
| 128 | if (it == fileList.end()) |
| 129 | { |
| 130 | JS::RootedValue replayData(cx, LoadReplayData(scriptInterface, directory)); |
| 131 | if (!replayData.isNull()) |
| 132 | { |
| 133 | JS_SetElement(cx, replays, i++, replayData); |
| 134 | newReplays = true; |
| 135 | } |
| 136 | } |
| 137 | else |
| 138 | fileList.erase(it); |
| 140 | |
| 141 | // No replay was changed, so just return the cache |
| 142 | if (!newReplays && fileList.empty()) |
| 143 | return JS::ObjectValue(*cachedReplaysObject); |
| 144 | // Cache found, so copy the replays from the cache that are not deleted |
| 145 | if (cacheFound) |
| 146 | { |
| 147 | std::vector<u32> deleteIndices; |
| 148 | for (const std::pair<CStr, u32>& file : fileList) |
| 149 | deleteIndices.push_back(file.second); |
| 150 | |
| 151 | u32 cacheLength = 0; |
| 152 | JS_GetArrayLength(cx, cachedReplaysObject, &cacheLength); |
| 153 | |
| 154 | for (u32 j = 0; j < cacheLength; ++j) |
| 155 | // a not in deleteIndices, so copy it into replays |
| 156 | if (std::find(deleteIndices.begin(), deleteIndices.end(), j) == deleteIndices.end()) |
| 157 | { |
| 158 | JS::RootedValue replay(cx); |
| 159 | JS_GetElement(cx, cachedReplaysObject, j, &replay); |
| 160 | JS_SetElement(cx, replays, i++, replay); |
| 161 | } |
| 162 | } |
| 163 | |
| 164 | JS::RootedValue replaysRooted(cx, JS::ObjectValue(*replays)); |
| 165 | std::ofstream stream(cacheFileName.string8().c_str(), std::ofstream::out | std::ofstream::trunc); |
| 166 | stream << scriptInterface.StringifyJSON(&replaysRooted); |
| 167 | stream.close(); |
| 168 | } |
| 169 | |