| 193 | } |
| 194 | |
| 195 | std::vector<char> GetProjectFileBytes() { |
| 196 | std::vector<char> fileBytes = {}; |
| 197 | AEGP_ProjectH projectHandle = nullptr; |
| 198 | Suites->ProjSuite6()->AEGP_GetProjectByIndex(0, &projectHandle); |
| 199 | |
| 200 | AEGP_MemHandle pathMemory; |
| 201 | Suites->ProjSuite6()->AEGP_GetProjectPath(projectHandle, &pathMemory); |
| 202 | char16_t* projectPath = nullptr; |
| 203 | Suites->MemorySuite1()->AEGP_LockMemHandle(pathMemory, reinterpret_cast<void**>(&projectPath)); |
| 204 | |
| 205 | std::string filePath = Utf16ToUtf8(projectPath); |
| 206 | Suites->MemorySuite1()->AEGP_FreeMemHandle(pathMemory); |
| 207 | |
| 208 | A_Boolean isDirty = 0; |
| 209 | Suites->ProjSuite6()->AEGP_ProjectIsDirty(projectHandle, &isDirty); |
| 210 | bool isAEPX = false; |
| 211 | |
| 212 | if (!filePath.empty()) { |
| 213 | auto extension = filePath.substr(filePath.size() - 5, 5); |
| 214 | isAEPX = ToLowerCase(extension) == ".aepx"; |
| 215 | } |
| 216 | |
| 217 | exporter::TempFileDelete tempFile; |
| 218 | if (isDirty || filePath.empty() || isAEPX) { |
| 219 | auto tempFolder = exporter::GetTempFolderPath(); |
| 220 | if (!tempFolder.empty() && tempFolder.back() == '/') { |
| 221 | tempFolder.pop_back(); |
| 222 | } |
| 223 | filePath = tempFolder + u8"/.PAGAutoSave.aep"; |
| 224 | tempFile.setFilePath(filePath); |
| 225 | auto path = Utf8ToUtf16(filePath); |
| 226 | auto saveResult = Suites->ProjSuite6()->AEGP_SaveProjectToPath( |
| 227 | projectHandle, reinterpret_cast<const A_UTF16Char*>(path.c_str())); |
| 228 | if (saveResult != 0) { |
| 229 | return fileBytes; |
| 230 | } |
| 231 | |
| 232 | // AEGP_SaveProjectToPath can complete asynchronously, and there might be a delay |
| 233 | // before the file is fully written to disk by the file system. |
| 234 | // Therefore, we need a retry loop to wait for the file to become accessible |
| 235 | // before attempting to read it. |
| 236 | int maxRetries = 50; |
| 237 | int retryCount = 0; |
| 238 | std::ifstream testFile(filePath, std::ios::binary); |
| 239 | |
| 240 | // Loop to check if the file has been created and can be opened. |
| 241 | while (!testFile.is_open() && retryCount < maxRetries) { |
| 242 | std::this_thread::sleep_for(std::chrono::milliseconds(100)); |
| 243 | retryCount++; |
| 244 | testFile.open(filePath, std::ios::binary); |
| 245 | } |
| 246 | testFile.close(); |
| 247 | |
| 248 | if (retryCount >= maxRetries) { |
| 249 | auto errorMsg = QObject::tr( |
| 250 | "Failed to save project file. The file could not be written to disk after multiple " |
| 251 | "attempts. Please check disk space and file permissions, then try again."); |
| 252 | WindowManager::GetInstance().showSimpleError(errorMsg); |
no test coverage detected