Skip to content

Commit 511f6de

Browse files
fix: cleanup processes in finally blocks and unify CUE/TOC file parsing logic
1 parent 6ee9530 commit 511f6de

5 files changed

Lines changed: 20 additions & 158 deletions

File tree

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,5 @@ riderModule.iml
55
/_ReSharper.Caches/
66
.idea/
77
[Bb]atch[Cc]onvertTo[Cc][Hh][Dd]/[Rr]eferences/
8+
*.DotSettings.user
9+
*.user

BatchConvertToCHD/Folder.DotSettings.user

Lines changed: 0 additions & 2 deletions
This file was deleted.

BatchConvertToCHD/MainWindow.xaml.cs

Lines changed: 4 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1796,7 +1796,6 @@ private static async Task MoveVerifiedFileAsync(string sourceFile, string target
17961796
catch (Exception ex)
17971797
{
17981798
// Log error but don't fail the verification
1799-
Debug.WriteLine($"Failed to move file {sourceFile}: {ex.Message}");
18001799
_ = ReportBugAsync($"Failed to move file {sourceFile}", ex);
18011800
}
18021801
}
@@ -1927,32 +1926,20 @@ private async Task<bool> ExtractChdAsync(string chdmanPath, string chdFile, stri
19271926
}
19281927
catch (OperationCanceledException)
19291928
{
1930-
if (!process.HasExited)
1931-
{
1932-
process.Kill(true);
1933-
// Wait for process to fully exit and release file handles
1934-
await Task.Run(() => process.WaitForExit(5000), CancellationToken.None);
1935-
}
1936-
19371929
// Wait a bit more for file handles to be fully released
19381930
await Task.Delay(500, CancellationToken.None);
19391931
// Clean up partially extracted file
19401932
await TryDeleteFileAsync(outputFile, "partially extracted file", CancellationToken.None);
19411933
throw;
19421934
}
1943-
catch (Exception)
1935+
finally
19441936
{
1945-
// Ensure process is terminated on any other exception
19461937
if (!process.HasExited)
19471938
{
19481939
process.Kill(true);
19491940
await Task.Run(() => process.WaitForExit(5000), CancellationToken.None);
19501941
}
19511942

1952-
throw;
1953-
}
1954-
finally
1955-
{
19561943
ctsSpeed.Cancel();
19571944
await Task.WhenAny(readSpeedTask, Task.Delay(500, CancellationToken.None));
19581945
// Ensure output streams are properly drained before disposal
@@ -2268,39 +2255,23 @@ private async Task<bool> ConvertToChdAsync(string chdmanPath, string inputFile,
22682255
{
22692256
await process.WaitForExitAsync(token);
22702257
}
2271-
2272-
if (token.IsCancellationRequested && !process.HasExited)
2273-
{
2274-
process.Kill(true);
2275-
await Task.Run(() => process.WaitForExit(5000), CancellationToken.None);
2276-
}
22772258
}
22782259
catch (Exception ex) when (ex is OperationCanceledException)
22792260
{
2280-
if (!process.HasExited)
2281-
{
2282-
process.Kill(true);
2283-
await Task.Run(() => process.WaitForExit(5000), CancellationToken.None);
2284-
}
2285-
22862261
if (token.IsCancellationRequested)
22872262
throw;
22882263

22892264
if (timeoutMinutes != null) LogMessage($"TIMEOUT: Conversion of '{Path.GetFileName(inputFile)}' exceeded {timeoutMinutes.Value} minute(s). Marking as failed.");
22902265
return false;
22912266
}
2292-
catch (Exception)
2267+
finally
22932268
{
22942269
if (!process.HasExited)
22952270
{
22962271
process.Kill(true);
22972272
await Task.Run(() => process.WaitForExit(5000), CancellationToken.None);
22982273
}
22992274

2300-
throw;
2301-
}
2302-
finally
2303-
{
23042275
ctsSpeed.Cancel();
23052276
await Task.WhenAny(speedMonitoringTask, Task.Delay(500, CancellationToken.None));
23062277
process.CancelOutputRead();
@@ -2349,31 +2320,16 @@ private async Task<PbpExtractionResult> ExtractPbpToCueBinAsync(string psxPackag
23492320
await process.WaitForExitAsync(timeoutCts.Token);
23502321
if (token.IsCancellationRequested && !process.HasExited)
23512322
{
2352-
process.Kill(true);
2353-
await Task.Run(() => process.WaitForExit(5000), CancellationToken.None);
23542323
throw new OperationCanceledException();
23552324
}
23562325
}
2357-
catch (OperationCanceledException)
2358-
{
2359-
if (!process.HasExited)
2360-
{
2361-
process.Kill(true);
2362-
}
2363-
2364-
await Task.Run(() => process.WaitForExit(5000), CancellationToken.None);
2365-
throw;
2366-
}
2367-
catch (Exception)
2326+
finally
23682327
{
2369-
// Ensure process is terminated on any other exception
23702328
if (!process.HasExited)
23712329
{
23722330
process.Kill(true);
23732331
await Task.Run(() => process.WaitForExit(5000), CancellationToken.None);
23742332
}
2375-
2376-
throw;
23772333
}
23782334

23792335
if (process.ExitCode != 0)
@@ -2516,29 +2472,14 @@ private async Task<bool> VerifyChdAsync(string chdmanPath, string chdFile, Cance
25162472
{
25172473
await process.WaitForExitAsync(token);
25182474
}
2519-
catch (OperationCanceledException)
2520-
{
2521-
if (!process.HasExited)
2522-
{
2523-
process.Kill(true);
2524-
}
2525-
2526-
await Task.Run(() => process.WaitForExit(5000), CancellationToken.None);
2527-
throw;
2528-
}
2529-
catch (Exception)
2475+
finally
25302476
{
2531-
// Ensure process is terminated on any other exception
25322477
if (!process.HasExited)
25332478
{
25342479
process.Kill(true);
25352480
await Task.Run(() => process.WaitForExit(5000), CancellationToken.None);
25362481
}
25372482

2538-
throw;
2539-
}
2540-
finally
2541-
{
25422483
ctsSpeed.Cancel();
25432484
await Task.WhenAny(readSpeedTask, Task.Delay(500, CancellationToken.None));
25442485
// Ensure output streams are properly drained before disposal

BatchConvertToCHD/Utilities/GameFileParser.cs

Lines changed: 14 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -17,88 +17,9 @@ public static class GameFileParser
1717
/// <param name="onLog">Callback for logging messages.</param>
1818
/// <param name="token">Cancellation token to cancel the operation.</param>
1919
/// <returns>A list of file paths referenced by the CUE sheet.</returns>
20-
public static async Task<List<string>> GetReferencedFilesFromCueAsync(string cuePath, Action<string> onLog, CancellationToken token)
20+
public static Task<List<string>> GetReferencedFilesFromCueAsync(string cuePath, Action<string> onLog, CancellationToken token)
2121
{
22-
var referencedFiles = new List<string>();
23-
var cueDir = Path.GetDirectoryName(cuePath) ?? string.Empty;
24-
try
25-
{
26-
var lines = await File.ReadAllLinesAsync(cuePath, token);
27-
token.ThrowIfCancellationRequested();
28-
foreach (var line in lines)
29-
{
30-
var trimmedLine = line.Trim();
31-
if (!trimmedLine.StartsWith("FILE ", StringComparison.OrdinalIgnoreCase))
32-
{
33-
continue;
34-
}
35-
36-
string fileName;
37-
var firstQuote = trimmedLine.IndexOf('"');
38-
var lastQuote = trimmedLine.LastIndexOf('"');
39-
40-
if (firstQuote != -1 && lastQuote > firstQuote)
41-
{
42-
fileName = trimmedLine.Substring(firstQuote + 1, lastQuote - firstQuote - 1);
43-
}
44-
else
45-
{
46-
// Unquoted fallback: split with limit to preserve filename+spaces+type
47-
var parts = trimmedLine.Split(Separator, 2, StringSplitOptions.RemoveEmptyEntries);
48-
if (parts.Length < 2)
49-
{
50-
continue;
51-
}
52-
53-
// parts[1] is now "filename TYPE" — strip the trailing file type keyword
54-
var rest = parts[1].TrimEnd();
55-
var lastSpace = rest.LastIndexOf(' ');
56-
if (lastSpace > 0)
57-
{
58-
// Known CUE file type keywords that follow the filename
59-
var afterFilename = rest[(lastSpace + 1)..];
60-
if (afterFilename.Equals("BINARY", StringComparison.OrdinalIgnoreCase) ||
61-
afterFilename.Equals("WAVE", StringComparison.OrdinalIgnoreCase) ||
62-
afterFilename.Equals("MP3", StringComparison.OrdinalIgnoreCase) ||
63-
afterFilename.Equals("AIFF", StringComparison.OrdinalIgnoreCase) ||
64-
afterFilename.Equals("MOTOROLA", StringComparison.OrdinalIgnoreCase) ||
65-
afterFilename.Equals("AUDIO", StringComparison.OrdinalIgnoreCase))
66-
{
67-
fileName = rest[..lastSpace];
68-
}
69-
else
70-
{
71-
fileName = rest;
72-
}
73-
}
74-
else
75-
{
76-
fileName = rest;
77-
}
78-
}
79-
80-
referencedFiles.Add(Path.Combine(cueDir, fileName));
81-
}
82-
}
83-
catch (OperationCanceledException)
84-
{
85-
throw;
86-
}
87-
catch (Exception ex)
88-
{
89-
onLog($"[WARNING] Could not parse CUE file: {Path.GetFileName(cuePath)}. Error: {ex.Message}");
90-
91-
try
92-
{
93-
_ = App.SharedBugReportService?.SendBugReportAsync($"Error parsing CUE file: {Path.GetFileName(cuePath)}", ex);
94-
}
95-
catch
96-
{
97-
// Silently fail to avoid cascading errors
98-
}
99-
}
100-
101-
return referencedFiles;
22+
return ParseFileReferenceLinesAsync(cuePath, onLog, "CUE", token);
10223
}
10324

10425
/// <summary>
@@ -186,13 +107,19 @@ public static async Task<List<string>> GetReferencedFilesFromGdiAsync(string gdi
186107
/// <param name="onLog">Callback for logging messages.</param>
187108
/// <param name="token">Cancellation token to cancel the operation.</param>
188109
/// <returns>A list of file paths referenced by the TOC file.</returns>
189-
public static async Task<List<string>> GetReferencedFilesFromTocAsync(string tocPath, Action<string> onLog, CancellationToken token)
110+
public static Task<List<string>> GetReferencedFilesFromTocAsync(string tocPath, Action<string> onLog, CancellationToken token)
111+
{
112+
return ParseFileReferenceLinesAsync(tocPath, onLog, "TOC", token);
113+
}
114+
115+
private static async Task<List<string>> ParseFileReferenceLinesAsync(
116+
string filePath, Action<string> onLog, string fileType, CancellationToken token)
190117
{
191118
var referencedFiles = new List<string>();
192-
var tocDir = Path.GetDirectoryName(tocPath) ?? string.Empty;
119+
var directory = Path.GetDirectoryName(filePath) ?? string.Empty;
193120
try
194121
{
195-
var lines = await File.ReadAllLinesAsync(tocPath, token);
122+
var lines = await File.ReadAllLinesAsync(filePath, token);
196123
token.ThrowIfCancellationRequested();
197124
foreach (var line in lines)
198125
{
@@ -212,19 +139,16 @@ public static async Task<List<string>> GetReferencedFilesFromTocAsync(string toc
212139
}
213140
else
214141
{
215-
// Unquoted fallback: split with limit to preserve filename+spaces+type
216142
var parts = trimmedLine.Split(Separator, 2, StringSplitOptions.RemoveEmptyEntries);
217143
if (parts.Length < 2)
218144
{
219145
continue;
220146
}
221147

222-
// parts[1] is now "filename TYPE" — strip the trailing file type keyword
223148
var rest = parts[1].TrimEnd();
224149
var lastSpace = rest.LastIndexOf(' ');
225150
if (lastSpace > 0)
226151
{
227-
// Known TOC/CUE file type keywords that follow the filename
228152
var afterFilename = rest[(lastSpace + 1)..];
229153
if (afterFilename.Equals("BINARY", StringComparison.OrdinalIgnoreCase) ||
230154
afterFilename.Equals("WAVE", StringComparison.OrdinalIgnoreCase) ||
@@ -246,7 +170,7 @@ public static async Task<List<string>> GetReferencedFilesFromTocAsync(string toc
246170
}
247171
}
248172

249-
referencedFiles.Add(Path.Combine(tocDir, fileName));
173+
referencedFiles.Add(Path.Combine(directory, fileName));
250174
}
251175
}
252176
catch (OperationCanceledException)
@@ -255,11 +179,11 @@ public static async Task<List<string>> GetReferencedFilesFromTocAsync(string toc
255179
}
256180
catch (Exception ex)
257181
{
258-
onLog($"[WARNING] Could not parse TOC file: {Path.GetFileName(tocPath)}. Error: {ex.Message}");
182+
onLog($"[WARNING] Could not parse {fileType} file: {Path.GetFileName(filePath)}. Error: {ex.Message}");
259183

260184
try
261185
{
262-
_ = App.SharedBugReportService?.SendBugReportAsync($"Error parsing TOC file: {Path.GetFileName(tocPath)}", ex);
186+
_ = App.SharedBugReportService?.SendBugReportAsync($"Error parsing {fileType} file: {Path.GetFileName(filePath)}", ex);
263187
}
264188
catch
265189
{

CSharp_BatchConvertToCHD.sln.DotSettings.user

Lines changed: 0 additions & 3 deletions
This file was deleted.

0 commit comments

Comments
 (0)