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