#1 2010-07-11 18:33:55

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,654
Website

How to unzip or zip files content

First of all, all the zip compression is embedded in an unique Delphi unit, named SynZip.pas, which is meant to replace the default zlib unit of Delphi, and enhance it. It works from
Delphi 7 to Delphi 2010, from the same source code, which is released under a GPL/LGPL/MPL tri-license.

Do you want to compress some data in memory? Use CompressString() and UnCompressString() methods. Both work with RawByteString encoded data:

function test: boolean;
var  tmp: RawByteString;
begin
  tmp := 'some data';
  result := (UnCompressString(CompressString(tmp,False,comp))=tmp);
end;

Do you want to create a zip archive file? Use our TZipWrite class.

procedure TestCompression;
var FN: TFileName;
begin
  FN := ChangeFileExt(paramstr(0),'.zip');
  with TZipWrite.Create(FN) do
  try
    AddDeflated('one.exe',pointer(Data),length(Data));
    assert(Count=1);
    AddDeflated('ident.txt',M.Memory,M.Position);
    assert(Count=2);
  finally
    Free;
  end;
end;

Do you want to read a zip archive file? Use our TZipRead class.

procedure TestUnCompression;
var FN: TFileName;
i: integer;
begin
  FN := ChangeFileExt(paramstr(0),'.zip');
  with TZipRead.Create(FN) do
  try
    i := NameToIndex('ONE.exe');
    assert(i>=0);
    assert(UnZip(i)=Data);
    i := NameToIndex('ident.TXT');
    assert(i>=0);
    assert(Entry[i].info^.zcrc32=crc32(0,M.Memory,M.Position));
  finally
    Free;
  end;
  DeleteFile(FN);
end;

And if you want the file to be embedded to your executable, there is a dedicated Create constructor in the TZipRead just for handling that:
- create your exe file with a TZipRead instance created with it;
- append your zip content to your exe (by using TZipWrite or by using copy /b on command line);
- that's all!

Couldn't it be easier?

Code above was extracted and adapted from our SynSelfTests test unit.

The SynZip.pas unit itself can be downloaded from our Source Code repository, on with most of our projects.

Online

#2 2010-07-17 10:00:42

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,654
Website

Re: How to unzip or zip files content

Question: How to embeded images to EXE file?

We provided some free and open source classes to read a .zip archive bundled (or not) to an exe. You can therefore append any .zip archive to your exe, then extract any picture inside this .zip with one class.

Use the following method:

constructor TZipRead.Create(const aFileName: TFileName; ZipStartOffset, Size: cardinal);

and provide paramstr(0) - i.e. your exe - as aFileName and ZipStartOffset as a minimal original exe size: it will search for the beginning of the .zip file from this offset. Leave Size parameter as 0: it will get the size from the file size itself.

The same class can get any .zip archive embedded as a resource to your exe, if you prefer.

They are two ways of appending .zip content to an exe:

1. use copy /b original.exe+pictures.zip newembedded.exe
2. use the TZipWrite class provided, and its AddFromZip() method to create your exe from Delphi code: you can even compress and append your images on the fly, with no temporary pictures.zip file.

Online

#3 2010-07-20 07:11:32

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,654
Website

Re: How to unzip or zip files content

If you don't need fastest performance available, but very small code size or just prefer one pascal unit, we've release a self-contained 100% pure pascal source code for the same purpose: see our PasZip unit. It contains the same TZipRead and TZipWrite classes. I use this one to create embedded setup files, together with our LVCL units.

The PasZip unit can be accessible in our Source Code repository: login as anonymous, then select Files and get the PasZip unit.

This PasZip unit is expected to work with Delphi up to 2007 version. New Unicode versions (2009/2010) of Delphi are not supported directly: use our SynPas unit instead, of make the corrections.

Online

#4 2010-07-31 07:23:18

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,654
Website

Re: How to unzip or zip files content

I've used such a method, embedding all necessary files as a .zip archive inside the exe resources, then extracting on request.

For example, we use HunSpell.dll external library to implement the spell checking of our SynProject open source tool.

Here is some extract from ProjectSpellCheck.pas:

constructor THunSpell.Create(DictionaryName: string='');
var Temp, HunSpell, Aff, Dic: TFileName;
    i: integer;
begin
  if DictionaryName='' then
    DictionaryName := 'en_US';
  Temp := GetSynopseCommonAppDataPath;
  HunSpell := Temp+'hunspell.dll';
  with TZipRead.Create(HInstance,'Zip','ZIP') do
  try
    Aff := DictionaryName+'.aff';
    if not FileExists(Temp+Aff) then
      StringToFile(Temp+Aff,UnZip(NameToIndex(Aff)));
    Dic := DictionaryName+'.dic';
    if not FileExists(Temp+Dic) then
      StringToFile(Temp+Dic,UnZip(NameToIndex(Dic)));
    if not FileExists(HunSpell) then
      StringToFile(HunSpell,UnZip(NameToIndex('hunspell.dll')));
  finally
    Free;
  end;
  fHunLib := SafeLoadLibrary(HunSpell);
  if fHunLib=0 then
    exit;
  if not LoadEntryPoints then begin
    FreeLibrary(fHunLib);
    fHunLib := 0;
    exit;
  end;
  fDictionaryName := DictionaryName;
  fHunHandle := Hunspell_create(pointer(Temp+Aff),pointer(Temp+Dic));
  if fHunHandle=nil then
    exit;
   (....)
end;

We extract both hunspell.dll and all dictionary files from an embedded .zip resource. It use our free SynZip unit.
See http://synopse.info/fossil/artifact/4ca … a7726e27f9

Here is the content of the ProjectRes.rc file used to create the resource:

Default TXT "Default.ini"
Zip ZIP "ProjectRes.zip"
wizard2 10 "wizard2.png"

All necessary files are stored in the ProjectRes.Zip archive, then extracted on the fly.

Online

#5 2011-05-17 15:31:44

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,654
Website

Re: How to unzip or zip files content

TZipRead and TZipWrite now handle Unicode file name inside zip (UTF-8 encoded).
Follows appendix D as specified by http://www.pkware.com/documents/casestudies/APPNOTE.TXT
Under Unicode Delphi (Delphi 2009/2010/XE), it will allow full Unicode encoding of file name inside the .zip.

It will also allow TZipWrite to append some content to an existing .zip file, with no copy on disk: it will be very fast e.g. for .log adding into a .zip archive.

For both units SynZip and SynZipFiles
See http://synopse.info/fossil/fdiff?v1=42b … 89b5a55f86
and http://synopse.info/fossil/fdiff?v1=48b … b22b2ca8c1

Online

#6 2012-01-17 09:48:46

proto
Member
From: Russia, Kostroma
Registered: 2011-09-12
Posts: 31

Re: How to unzip or zip files content

how can unzip password protected zip?

Offline

#7 2012-01-17 11:03:31

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,654
Website

Re: How to unzip or zip files content

proto wrote:

how can unzip password protected zip?

This feature is not implemented yet.
You can use your own encryption using the SynCrypto unit, if you wish, but it won't be the standard Zip encryption.
For standard Zip encryption (AES or RC4), you'll have to use another unit.

Online

#8 2012-06-14 06:11:49

PresleyDias
Member
Registered: 2012-06-14
Posts: 6

Re: How to unzip or zip files content

what is `data` in the following code?

procedure TestCompression;
var FN: TFileName;
begin
  FN := ChangeFileExt(paramstr(0),'.zip');
  with TZipWrite.Create(FN) do
  try
    AddDeflated('one.exe',pointer(Data),length(Data));  //here what is data?
    assert(Count=1);
    AddDeflated('ident.txt',M.Memory,M.Position);         //here what is M?
    assert(Count=2);
  finally
    Free;
  end;
end;


im trying this code for compressing a jpg file

procedure TestCompression;
var FN: TFileName;
Data : string;
begin
  FN := ChangeFileExt(paramstr(0),'.zip');
  with TZipWrite.Create(FN) do
  try
    AddDeflated('C:\Documents and Settings\All Users\Documents\leakTracker\14_06_12 11_33_50 AM.jpg',pointer(Data),length(Data));
    assert(Count=1);
except
    on E : Exception do
      free ;
  end;
end;

it does not work, it shows the zip size a s 1 KB

can you tell me what is wrong?

Offline

#9 2012-06-14 13:23:54

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,654
Website

Re: How to unzip or zip files content

Both data and M are members of the test class.
They contain some data used to be compressed by the test routines.

Just click on variable with Ctrl on keyboard to navigate to the declaration of each variable.

So you are compressing the test data and name it as a .jpg file.

Online

#10 2012-06-15 05:00:14

PresleyDias
Member
Registered: 2012-06-14
Posts: 6

Re: How to unzip or zip files content

Ok, got it smile

i tried

procedure SynZipZipper(sZipFileName,sJpegFileName : string);
var
  Data     : string;
  sUmlDPath : string;
begin
 if FileExists(sZipFileName)  then DeleteFile(pchar(sZipFileName));
 with TZipWrite.Create(sZipFileName) do
  try
    AddDeflated(sJpegFileName);
    AddDeflated(FullUmldFilePath);  
  free;
except
    on E : Exception do
    begin
     free;
    end;
  end;

end;

Offline

#11 2012-09-25 12:44:03

Philip Bockaert
Member
Registered: 2012-09-25
Posts: 1

Re: How to unzip or zip files content

procedure synZipZipper(const aSourceFilename,aTargetFilename:string);
    begin if (fileExists(aTargetFilename)) then DeleteFile(aTargetFilename);
          with TZipWrite.Create(aTargetFilename) do
               try AddDeflated(aSourceFilename)
               finally free end
          end;

Offline

#12 2014-03-03 11:30:30

noobies
Member
Registered: 2011-09-13
Posts: 139

Re: How to unzip or zip files content

http://rouse.drkb.ru/components.php#fwzip
open source alternative with plenty of opportunities: large files, few need memory, password protect archive and unarchive, ppmd

Offline

#13 2014-03-03 17:23:47

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,654
Website

Re: How to unzip or zip files content

@phillip

This is indeed better with a try... finally Free end to protect your TZipWrite instance.
Like any other Delphi class, by the way. smile

As I wrote above - see http://synopse.info/forum/viewtopic.php?pid=163#p163

Online

#14 2014-08-04 18:11:42

HSposito
Member
Registered: 2014-08-04
Posts: 3

Re: How to unzip or zip files content

Hi!

I zipped a file in Java using a ZipOutputStream object and when I try to unzip it in Delphi using the TZipRead class I get the error: "Error -2 during zip/deflate process."

Any ideas on how to fix it?

Thanks a lot!

Offline

#15 2014-08-04 19:53:19

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,654
Website

Re: How to unzip or zip files content

Are you sure you are creating a valid .zip file, and not some raw "deflate" content?
Are you able to open the generated .zip file within the windows explorer (or Winzip/winrar tool)?

Online

#16 2014-08-04 20:18:27

HSposito
Member
Registered: 2014-08-04
Posts: 3

Re: How to unzip or zip files content

Thanks for your reply.

Yes, I can open the generated file within Windows Explorer and 7-Zip.

Offline

#17 2014-08-04 21:34:46

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,654
Website

Re: How to unzip or zip files content

What is the compression method used?

Online

#18 2014-08-04 22:48:31

HSposito
Member
Registered: 2014-08-04
Posts: 3

Re: How to unzip or zip files content

Deflate.

Offline

#19 2014-08-04 22:51:51

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,654
Website

Re: How to unzip or zip files content

Weird.

Can you send me some file?
Webcontact01 at synopse dot info

Online

#20 2014-08-09 10:08:00

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,654
Website

Re: How to unzip or zip files content

The .zip file you sent to me is in an unsupported format.
The local fileInfo block has zcrc32=0 zzipSize=0 zfullZize=0.
This is clearly stated by the http://www.pkware.com/documents/casestudies/APPNOTE.TXT specifications as a possibility, if the bit 3 of the fileInfo "flags" is set.
A "data descriptor" block has to be recognized and read instead of the local fileInfo block.

We have therefore fixed UnZip() when crc and sizes are stored not within the file header but in this separate data descriptor block, after the compressed data.
It will either:
- Use the ending "central directory" information;
- Or search manually the "data descriptor" from the binary local data.
See http://synopse.info/fossil/info/324905c71ac

We have also added a new TZipRead.RetrieveFileInfo() method for this purpose.

Online

#21 2014-09-19 14:36:22

Himeko
Member
Registered: 2014-08-12
Posts: 21

Re: How to unzip or zip files content

Congrats, once again your code is the fastest of various I tried:

KAzip (very old component/library, had to update it for unicode/modern delphi)
Delphi's
Synopse

Both for listing and extracting your unit was the fastest after a series of benchmarks (listing the contents of 1000 zips, then extracting 1 a few times over).
Synopse was in both cases some ~10-20% faster than the other 2.

How do you extract a file btw? maybe my proc can be improved someway:

   ss: TZipRead;
   aa: RawByteString;

  ss := TZipRead.Create(zip);
  c := ss.NameToIndex(fil);
  SetLength(aa,ss.Entry[c].infoLocal.zfullSize);
  aa := ss.UnZip(c);
  With TFileStream.Create(s,fmCreate) do begin
    Write(aa[1],ss.Entry[c].infoLocal.zfullSize);
    Free;
  end;

Offline

#22 2014-09-19 15:20:19

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,654
Website

Re: How to unzip or zip files content

The following methods are able to unzip files directly into a destination folder:

    /// uncompress a file stored inside the .zip archive into a destination directory
    function UnZip(aIndex: integer; const DestDir: TFileName;
      DestDirIsFileName: boolean=false): boolean; overload;
    /// uncompress a file stored inside the .zip archive into a destination directory
    function UnZip(const aName, DestDir: TFileName;
      DestDirIsFileName: boolean=false): boolean; overload;
    /// uncompress all fields stored inside the .zip archive into the supplied
    // destination directory
    // - returns -1 on success, or the index in Entry[] of the failing file
    function UnZipAll(DestDir: TFileName): integer;

Ensure you retrieved the latest version from our source code repository.

Online

#23 2014-09-19 19:56:37

Himeko
Member
Registered: 2014-08-12
Posts: 21

Re: How to unzip or zip files content

That works great, didn't see the overloads somehow, thanks.

ps: does the board support watching threads? it would be nice to be able to receive email notifications of replies.

Offline

#24 2014-09-19 21:04:56

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,654
Website

Re: How to unzip or zip files content

Himeko wrote:

ps: does the board support watching threads? it would be nice to be able to receive email notifications of replies.

Not the current version, yet.
Sorry.

Online

#25 2014-09-19 23:24:48

Himeko
Member
Registered: 2014-08-12
Posts: 21

Re: How to unzip or zip files content

Maybe you could migrate the board to phpbb

https://github.com/fluxbb/converter

Offline

#26 2014-09-19 23:45:47

Himeko
Member
Registered: 2014-08-12
Posts: 21

Re: How to unzip or zip files content

Reporting a possible issue: I'm getting an exception "ZIP format." with a very specific zip file, after calling

TZipRead.Create(zip)

it triggers here in SynZip.pas

  for i := 0 to 127 do begin // resources size may be rounded up to alignment
    lhr := @BufZip[Size-sizeof(TLastHeader)];
    if lhr^.signature+1=(LASTHEADER_SIGNATURE+1) then
      break;
    dec(Size);
    if Size<=sizeof(lhr^) then
      break;
  end;
  if lhr^.signature+1<>(LASTHEADER_SIGNATURE+1) then begin
    UnMap;
    raise ESynZipException.Create('ZIP format');
  end;

The file opens fine with winrar and 7zip, and if I make a new file with the contents (unpack and repack with winrar), it works fine as well with SynZip

Offline

#27 2014-09-20 07:17:12

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,654
Website

Re: How to unzip or zip files content

Try to increase 127.

.zip file seems to be truncated or invalid.

Online

#28 2014-09-20 13:56:02

Himeko
Member
Registered: 2014-08-12
Posts: 21

Re: How to unzip or zip files content

That works. In the case of 2 files I found with this issue, "i" was 1233 and 2714 after the loop (I set 65535 max)

Another issue with some other files:

"Zip error: ZIP format size=0"

In 2 cases I found (working fine with winrar etc), both zzipSize and zfullSize were 0

Offline

#29 2015-06-03 15:56:27

Eric
Member
Registered: 2012-11-26
Posts: 129
Website

Re: How to unzip or zip files content

TZipRead.UnZip is declared as returning a string, but it seems to be a relic of pre-Unicode Delphi, shouldn't it be a an AnsiString or a byte array? it's in PasZip, which apparently is a relic


In SynZip, TZipRead.Create raises an exception when a an entry has zero bytes, but a zero size file in a zip is valid.

Last edited by Eric (2015-06-04 11:13:14)

Offline

#30 2015-07-29 13:16:16

paolo.sciarrini
Member
Registered: 2015-07-29
Posts: 1

Re: How to unzip or zip files content

How can I store relative paths using TZipWrite? Thanks!

Last edited by paolo.sciarrini (2015-07-30 14:45:16)

Offline

#31 2016-07-12 06:21:53

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,654
Website

Re: How to unzip or zip files content

Just store the relative path within the file name.

Online

#32 2017-03-30 19:10:33

jurcuks
Member
Registered: 2017-03-30
Posts: 1

Re: How to unzip or zip files content

I use SynZip.pas on Lazarus. When I create zip archive with unicode filenames, it work fine, but when unzip, have error. After some changes in SynZip.pas I have support for unicode names in zip archive.
1) In uses add LazFileUtils
2) In constructor TZipRead.Create(const aFileName: TFileName; ZipStartOffset, Size: cardinal);
replace string

file_ := CreateFile(pointer(aFileName), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0);

with

file_ := CreateFileW(PWideChar(WideString(aFileName)), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0);

result

constructor TZipRead.Create(const aFileName: TFileName; ZipStartOffset, Size: cardinal);
begin
   file_ := CreateFileW(PWideChar(WideString(aFileName)), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0);
   Create(file_,ZipStartOffset, Size);
end;

3) In function EnsurePath(var Path: TFileName): boolean
replace strings

   if DirectoryExists(Path) then
...
   if CreateDirectory(pointer(path),nil) then

with

   if DirectoryExistsUTF8(Path) then
...
   if CreateDirectoryW(PWideChar(WideString(path)),nil) then

result

function EnsurePath(var Path: TFileName): boolean;
var Parent: TFileName;
begin
  result := false;
  if Path='' then exit;
  if Path[length(Path)]<>'\' then
    Path := Path+'\';
  if DirectoryExistsUTF8(Path) then
    result := true else begin
    Parent := ExtractFilePath(system.copy(Path,1,length(Path)-1));
    if (Parent<>'') and not DirectoryExists(Parent) then
      if not EnsurePath(Parent) then exit;
    if CreateDirectoryW(PWideChar(WideString(path)),nil) then
      result := true;
  end;
end;

After this changes I can unzip files with unicode filenames

Offline

#33 2021-07-05 10:52:18

mpv
Member
From: Ukraine
Registered: 2012-03-24
Posts: 1,571
Website

Re: How to unzip or zip files content

I create a small fix for AddFromZip - current implementation of AddFromZip  produce invalid zip file in case source ZIP entry is STORED (not compressed) - see https://github.com/synopse/mORMot/pull/399
Not sure this is a best solution, but it works.

P.S. - in mORMot2 AddFromZip implementation is differs but seams has the same issue

Last edited by mpv (2021-07-05 10:54:31)

Offline

#34 2021-07-05 11:22:00

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,654
Website

Re: How to unzip or zip files content

Online

#35 2021-07-05 12:42:46

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,654
Website

Re: How to unzip or zip files content

https://github.com/synopse/mORMot/commi … 768be9b847 should fix it.

Your origin.zip file had a weird format with an "extralen" content.
How did you create it?

Online

#36 2021-07-05 13:39:26

mpv
Member
From: Ukraine
Registered: 2012-03-24
Posts: 1,571
Website

Re: How to unzip or zip files content

Thanks! After paths with

fhr.fileInfo.extraLen := 0; // source may have something here

all works.

My zip file is created using zip program from Ubuntu distribution

echo "Привет" > fileUtf8.txt && zip origin.zip fileUtf8.txt

Offline

#37 2021-07-05 13:53:32

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,654
Website

Re: How to unzip or zip files content

So Ubuntu "zip" add an "extralen" content to each zip entry.
My guess is that it had nothing to do with "stored" content.
This "extralen" content is likely to contain UNIX file properties.

It should now be handled in both mORMot 1 and mORMot 2.

Online

#38 2021-08-13 08:47:46

mpv
Member
From: Ukraine
Registered: 2012-03-24
Posts: 1,571
Website

Re: How to unzip or zip files content

Another small fix - https://github.com/synopse/mORMot/pull/401 for TZipWriteAbstract.AddFromZip - we must use an original file name instead of one, where we replace '/' -> '\' (see pull request description)

Last edited by mpv (2021-08-13 08:48:10)

Offline

#39 2021-09-21 02:22:13

swrdelphi
Member
Registered: 2021-09-21
Posts: 1

Re: How to unzip or zip files content

Thank you very much for all your hard work. I have two questions if you don't mind please.

1. Could you provide a code snippet on how to accomplish: use the TZipWrite class provided, and its AddFromZip() method to create your exe from Delphi code: you can even compress and append your images on the fly, with no temporary pictures.zip file. Just looking to append a zip file to an exe and extract it.

I don't quite understand it.

2. Any suggestions on how to implement a progressbar for zip extraction?

Thank you.

Offline

#40 2022-06-30 10:45:46

edwinsn
Member
Registered: 2010-07-02
Posts: 1,218

Re: How to unzip or zip files content

Does TZipWrite  support adding comments to the zip file?


Delphi XE4 Pro on Windows 7 64bit.
Lazarus trunk built with fpcupdelux on Windows with cross-compile for Linux 64bit.

Offline

#41 2022-06-30 16:54:36

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,654
Website

Re: How to unzip or zip files content

The comments are properly parsed by TZipRead but ignored and not handled by TZipWrite.

Online

#42 2022-07-01 02:40:23

edwinsn
Member
Registered: 2010-07-02
Posts: 1,218

Re: How to unzip or zip files content

Please also note that there are two types of comments:
- "zip file comment" and,
-  "comment of a file inside the zip file".


Delphi XE4 Pro on Windows 7 64bit.
Lazarus trunk built with fpcupdelux on Windows with cross-compile for Linux 64bit.

Offline

#43 2022-07-01 11:00:45

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,654
Website

Re: How to unzip or zip files content

Sadly, none is supported yet at writing (or extracting).
They are just ignored.

Online

#44 2022-07-01 11:06:39

edwinsn
Member
Registered: 2010-07-02
Posts: 1,218

Re: How to unzip or zip files content

no problem, just providing the info.


Delphi XE4 Pro on Windows 7 64bit.
Lazarus trunk built with fpcupdelux on Windows with cross-compile for Linux 64bit.

Offline

Board footer

Powered by FluxBB