Skip to content

Commit d6ad016

Browse files
committed
Added ICabManager.MoveFileSet to the API.
1 parent aed5358 commit d6ad016

13 files changed

Lines changed: 217 additions & 14 deletions

File tree

CabinetManager/CabManager.cs

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ public int PackFileSet(IEnumerable<IFileToAddInCab> filesToPackIn) {
6060
var fileRelativePath = fileToAddInCab.RelativePathInCab.NormalizeRelativePath();
6161
cfCabinet.AddExternalFile(fileToAddInCab.SourcePath, fileRelativePath);
6262
nbFilesProcessed++;
63-
OnProgress?.Invoke(this, CabProgressionEventArgs.NewCompletedFile(cabGroupedFiles.Key, fileToAddInCab.RelativePathInCab));
63+
OnProgress?.Invoke(this, CabProgressionEventArgs.NewProcessedFile(cabGroupedFiles.Key, fileRelativePath));
6464
}
6565
cfCabinet.Save(_compressionType);
6666
} finally {
@@ -115,7 +115,7 @@ public int ExtractFileSet(IEnumerable<IFileInCabToExtract> filesToExtract) {
115115
var fileRelativePath = fileInCabToExtract.RelativePathInCab.NormalizeRelativePath();
116116
if (cfCabinet.ExtractToFile(fileRelativePath, fileInCabToExtract.ExtractionPath)) {
117117
nbFilesProcessed++;
118-
OnProgress?.Invoke(this, CabProgressionEventArgs.NewCompletedFile(cabGroupedFiles.Key, fileInCabToExtract.RelativePathInCab));
118+
OnProgress?.Invoke(this, CabProgressionEventArgs.NewProcessedFile(cabGroupedFiles.Key, fileRelativePath));
119119
}
120120
}
121121
} finally {
@@ -147,7 +147,7 @@ public int DeleteFileSet(IEnumerable<IFileInCabToDelete> filesToDeleteIn) {
147147
var fileRelativePath = fileToAddInCab.RelativePathInCab.NormalizeRelativePath();
148148
if (cfCabinet.DeleteFile(fileRelativePath)) {
149149
nbFilesProcessed++;
150-
OnProgress?.Invoke(this, CabProgressionEventArgs.NewCompletedFile(cabGroupedFiles.Key, fileToAddInCab.RelativePathInCab));
150+
OnProgress?.Invoke(this, CabProgressionEventArgs.NewProcessedFile(cabGroupedFiles.Key, fileRelativePath));
151151
}
152152
}
153153
cfCabinet.Save(_compressionType);
@@ -164,7 +164,40 @@ public int DeleteFileSet(IEnumerable<IFileInCabToDelete> filesToDeleteIn) {
164164
}
165165
return nbFilesProcessed;
166166
}
167-
167+
168+
/// <inheritdoc cref="ICabManager.MoveFileSet"/>
169+
public int MoveFileSet(IEnumerable<IFileInCabToMove> filesToMove) {
170+
int nbFilesProcessed = 0;
171+
foreach (var cabGroupedFiles in filesToMove.GroupBy(f => f.CabPath)) {
172+
if (!File.Exists(cabGroupedFiles.Key)) {
173+
continue;
174+
}
175+
try {
176+
using (var cfCabinet = new CfCabinet(cabGroupedFiles.Key, _cancelToken)) {
177+
cfCabinet.OnProgress += OnProgressionEvent;
178+
try {
179+
foreach (var fileToAddInCab in cabGroupedFiles) {
180+
var fileRelativePath = fileToAddInCab.RelativePathInCab.NormalizeRelativePath();
181+
if (cfCabinet.MoveFile(fileRelativePath, fileToAddInCab.NewRelativePathInCab.NormalizeRelativePath())) {
182+
nbFilesProcessed++;
183+
OnProgress?.Invoke(this, CabProgressionEventArgs.NewProcessedFile(cabGroupedFiles.Key, fileRelativePath));
184+
}
185+
}
186+
cfCabinet.Save(_compressionType);
187+
} finally {
188+
cfCabinet.OnProgress -= OnProgressionEvent;
189+
}
190+
}
191+
} catch (OperationCanceledException) {
192+
throw;
193+
} catch (Exception e) {
194+
throw new CabException($"Failed to move files from {cabGroupedFiles.Key}.", e);
195+
}
196+
OnProgress?.Invoke(this, CabProgressionEventArgs.NewCompletedCabinet(cabGroupedFiles.Key));
197+
}
198+
return nbFilesProcessed;
199+
}
200+
168201
/// <summary>
169202
/// Returns a string representation of a given cabinet file.
170203
/// </summary>

CabinetManager/ICabManager.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,20 @@ public interface ICabManager {
100100
/// <exception cref="OperationCanceledException"></exception>
101101
/// <returns>Total number of files actually deleted.</returns>
102102
int DeleteFileSet(IEnumerable<IFileInCabToDelete> filesToDelete);
103+
104+
/// <summary>
105+
/// <para>
106+
/// Moves the given files within cabinets.
107+
/// Requesting the movement from a non existing cabinet will not throw an exception.
108+
/// Requesting the movement a file that does not exist in the cabinet will not throw an exception.
109+
/// You can inspect which files are processed with the <see cref="OnProgress"/> event.
110+
/// </para>
111+
/// </summary>
112+
/// <param name="filesToMove"></param>
113+
/// <exception cref="CabException"></exception>
114+
/// <exception cref="OperationCanceledException"></exception>
115+
/// <returns>Total number of files actually deleted.</returns>
116+
int MoveFileSet(IEnumerable<IFileInCabToMove> filesToMove);
103117

104118
/// <summary>
105119
/// Returns a string representation of the <paramref name="cabPath"/>.

CabinetManager/IFileInCabToMove.cs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#region header
2+
// ========================================================================
3+
// Copyright (c) 2018 - Julien Caillon (julien.caillon@gmail.com)
4+
// This file (IFileArchivedToDelete.cs) is part of Oetools.Utilities.
5+
//
6+
// Oetools.Utilities is a free software: you can redistribute it and/or modify
7+
// it under the terms of the GNU General Public License as published by
8+
// the Free Software Foundation, either version 3 of the License, or
9+
// (at your option) any later version.
10+
//
11+
// Oetools.Utilities is distributed in the hope that it will be useful,
12+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
// GNU General Public License for more details.
15+
//
16+
// You should have received a copy of the GNU General Public License
17+
// along with Oetools.Utilities. If not, see <http://www.gnu.org/licenses/>.
18+
// ========================================================================
19+
#endregion
20+
21+
namespace CabinetManager {
22+
23+
/// <summary>
24+
/// Describes a file existing in a cabinet file that needs to be deleted in it.
25+
/// </summary>
26+
public interface IFileInCabToMove : IFileCabBase {
27+
28+
/// <summary>
29+
/// <para>
30+
/// The new relative path of the file within the cabinet file.
31+
/// This is the destination path for a file to move.
32+
/// This path is normalized to windows style path inside the cabinet (i.e. using \ instead of /).
33+
/// </para>
34+
/// </summary>
35+
string NewRelativePathInCab { get; }
36+
}
37+
}

CabinetManager/core/CfCabinet.cs

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -338,18 +338,48 @@ void Progress(CfSaveEventArgs args) {
338338
return true;
339339
}
340340

341+
/// <summary>
342+
/// Delete a file within this cabinet.
343+
/// </summary>
344+
/// <param name="relativePathInCab"></param>
345+
/// <returns></returns>
341346
public bool DeleteFile(string relativePathInCab) {
342347
if (!_dataHeadersRead) {
343348
ReadDataHeaders(_reader);
344349
}
345350

346351
int nbFileDeleted = 0;
347-
// remove existing files with the same name
352+
// Remove existing files with the same name (there could be many if the file is spread over several folders/cabinets).
348353
foreach (var folder in Folders) {
349354
nbFileDeleted += folder.Files.RemoveAll(f => f.RelativePathInCab.Equals(relativePathInCab, StringComparison.OrdinalIgnoreCase));
350355
}
351356
return nbFileDeleted > 0;
352357
}
358+
359+
/// <summary>
360+
/// Move (i.e. change the relative path) a file within this cabinet.
361+
/// </summary>
362+
/// <param name="relativePathInCab"></param>
363+
/// <param name="newRelativePathInCab"></param>
364+
/// <returns></returns>
365+
public bool MoveFile(string relativePathInCab, string newRelativePathInCab) {
366+
if (!_dataHeadersRead) {
367+
ReadDataHeaders(_reader);
368+
}
369+
370+
var fileToMove = Folders.SelectMany(folder => folder.Files).FirstOrDefault(file => file.RelativePathInCab.Equals(relativePathInCab, StringComparison.OrdinalIgnoreCase));
371+
if (fileToMove == null) {
372+
return false;
373+
}
374+
375+
if (!fileToMove.Parent.RenameFile(relativePathInCab, newRelativePathInCab)) {
376+
return false;
377+
}
378+
379+
fileToMove.RelativePathInCab = newRelativePathInCab;
380+
381+
return true;
382+
}
353383

354384
/// <summary>
355385
/// Save this instance of <see cref="CfCabinet"/> to <see cref="CabPath"/>.

CabinetManager/core/CfDataBlockReader.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,25 @@ public CfDataBlockReader(CfFolder folder) {
4848
}
4949
}
5050

51+
/// <summary>
52+
/// To call when a file is renamed, so that we are sure to take the right data for the file.
53+
/// </summary>
54+
/// <param name="oldName"></param>
55+
/// <param name="newName"></param>
56+
/// <returns></returns>
57+
public bool RenameFile(string oldName, string newName) {
58+
if (_existingFileInfo.ContainsKey(oldName)) {
59+
if (_existingFileInfo.ContainsKey(newName)) {
60+
_existingFileInfo.Remove(newName);
61+
}
62+
_existingFileInfo.Add(newName, _existingFileInfo[oldName]);
63+
_existingFileInfo.Remove(oldName);
64+
return true;
65+
}
66+
67+
return false;
68+
}
69+
5170
/// <summary>
5271
/// Initialize this instance to read the file <paramref name="relativeFilePathInCab"/>.
5372
/// </summary>

CabinetManager/core/CfFolder.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,10 @@ public long FolderUncompressedSize {
132132

133133
private CfFolderTypeCompress _compressionType;
134134

135+
public bool RenameFile(string oldName, string newName) {
136+
return _blockReader.RenameFile(oldName, newName);
137+
}
138+
135139
/// <summary>
136140
/// Extract a file from the cabinet using data from <see cref="Data"/>.
137141
/// </summary>

CabinetManager/internal/CabProgressionEventArgs.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ internal class CabProgressionEventArgs : EventArgs, ICabProgressionEventArgs {
4444
/// </summary>
4545
public double PercentageDone { get; private set; }
4646

47-
internal static CabProgressionEventArgs NewCompletedFile(string cabPath, string relativePathInCab) {
47+
internal static CabProgressionEventArgs NewProcessedFile(string cabPath, string relativePathInCab) {
4848
return new CabProgressionEventArgs {
4949
CabPath = cabPath,
5050
EventType = CabEventType.FileProcessed,

CabinetManagerTest/Tests/ArchiveTest.cs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,39 @@ protected void DeleteFilesInArchive(ICabManager cabManager, List<FileInCab> list
119119
Assert.AreEqual(listFiles.Count, _nbFileFinished, "Problem in the progress event");
120120
Assert.AreEqual(listFiles.GroupBy(f => f.CabPath).Count(), _nbArchiveFinished, "Problem in the progress event, number of archives");
121121
}
122+
123+
protected void MoveInArchives(ICabManager cabManager, List<FileInCab> listFiles) {
124+
cabManager.OnProgress += ArchiverOnOnProgress;
125+
_nbFileFinished = 0;
126+
_nbArchiveFinished = 0;
127+
128+
// try to move a non existing file
129+
var modifiedList = listFiles.ToList();
130+
modifiedList.Add(new FileInCab {
131+
CabPath = listFiles.First().CabPath,
132+
ExtractionPath = listFiles.First().ExtractionPath,
133+
RelativePathInCab = "random.name"
134+
});
135+
modifiedList.ForEach(f => f.NewRelativePathInCab = $"{f.RelativePathInCab}_move");
136+
137+
Assert.AreEqual(modifiedList.Count - 1, cabManager.MoveFileSet(modifiedList));
138+
139+
cabManager.OnProgress -= ArchiverOnOnProgress;
140+
Assert.AreEqual(listFiles.Count, _nbFileFinished, "Problem in the progress event");
141+
Assert.AreEqual(listFiles.GroupBy(f => f.CabPath).Count(), _nbArchiveFinished, "Problem in the progress event, number of archives");
142+
143+
// move them back
144+
modifiedList.ForEach(f => {
145+
f.RelativePathInCab = f.NewRelativePathInCab;
146+
f.NewRelativePathInCab = f.NewRelativePathInCab.Substring(0, f.NewRelativePathInCab.Length - 5);
147+
});
148+
149+
Assert.AreEqual(modifiedList.Count - 1, cabManager.MoveFileSet(modifiedList));
150+
151+
modifiedList.ForEach(f => {
152+
f.RelativePathInCab = f.NewRelativePathInCab;
153+
});
154+
}
122155

123156
private void ArchiverOnOnProgress(object sender, ICabProgressionEventArgs e) {
124157
if (e.EventType == CabEventType.FileProcessed) {

CabinetManagerTest/Tests/CabTest.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ public void ClassicTest() {
5858
}
5959

6060
CreateArchive(archiver, listFiles);
61+
62+
MoveInArchives(archiver, listFiles);
6163

6264
// verify
6365
ListArchive(archiver, listFiles);

CabinetManagerTest/Tests/FileInCab.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,13 @@
2222
using CabinetManager;
2323

2424
namespace CabinetManagerTest.Tests {
25-
public class FileInCab : IFileInCabToDelete, IFileInCabToExtract, IFileToAddInCab {
25+
public class FileInCab : IFileInCabToDelete, IFileInCabToExtract, IFileToAddInCab, IFileInCabToMove {
2626
public string CabPath { get; set; }
2727
public string RelativePathInCab { get; set; }
2828
public ulong SizeInBytes { get; set; }
2929
public DateTime LastWriteTime { get; set; }
3030
public string ExtractionPath { get; set; }
3131
public string SourcePath { get; set; }
32+
public string NewRelativePathInCab { get; set; }
3233
}
3334
}

0 commit comments

Comments
 (0)