Let's think about it again...
The names first... I think the basic idea is correct. There is the name of the disk file which will be added to the zip - this is the DiskFileName. And there is the ArchiveFilename which is used inside the zip and requires forward slashes.
AddFileEntry has several overloads: two of them with an ArchiveFileName specified
procedure TZipFileEntry.SetArchiveFileName(const AValue: String);
begin
if FArchiveFileName=AValue then Exit;
// Zip standard: filenames inside the zip archive have / path separator
if DirectorySeparator='/' then
FArchiveFileName:=AValue
else
FArchiveFileName:=StringReplace(AValue, DirectorySeparator, '/', [rfReplaceAll]);
end;
Here, nothing is changed on Linux, but on Windows (DirectorySeparator <> '/') the backslashes are replaced by '/'.
The third overload has no ArchiveFileName as argument. It leaves the ArchiveFileName empty, but I think we should set the ArchiveFilename here equal to the DiskFileName since this will replace the backslashes on windows for the zip's internal name.
function TZipFileEntries.AddFileEntry(const ADiskFileName): TZipFileEntry;
begin
Result:=Add as TZipFileEntry;
Result.DiskFileName:=ADiskFileName;
Result.ArchiveFileName:=ADiskFileName; // ADDED. The setter SetArchiveFileName will replace '\' by '/' in Windows
end;
Let's look at the following line of my sample:
zip.Entries.AddFileEntry('subdir\a.txt', 'subdir\renamed_a.txt');
On Windows, the second parameter is changed to 'subdir/renamed_a.txt' which makes the zip valid. And the file itself is found for packing - fine.
On Linux, we have two problems: the first one is that the file itself is not found because of the backslash. And if we refrain from guessing what the user thinks we must keep it like that - or the user must code correctly with the correct path delimiter, i.e. the first parameter must be specified as 'subdir' + PathDelim + 'a.txt'. But this is no limitation of the zipper, this is general practice in file handling on Linux.
The other problem is the ArchiveFilename parameter, 'subdir\renamed_a.txt'. When the user knows and understands that this is the name of the file inside the zip he would specify it as 'subdir/renamed_a.txt' and everything would be fine. But he probably thinks that this is the name of the file after unzipping. Now we have the same problem as before, and the ArchiveFileName must be specified as a valid name of the file system: 'subdir' + PathDelim + 'renamed_a.txt' and let the setter of ArchiveFileName do the work to replace the PathDelim back to a forward slash.
This way the zip/unzip operation yields the desired results, on both Windows and Linux - I tested it.
To summarize we must
- fill the ArchiveFileName in the one-parameter overload of AddFileName to be equal to the DiskFileName, as shown above.
- assume that all names are to be understood as names of the filesystem, i.e. with the correct path delimiter. But this is rather self-evident.