|
|
Comments and Discussions
|
|
 |

|
This is awesome work, thank you!
Been looking for some time to get the zlib code persuaded to unzip to a _memory buffer_ instead of a file!
All my attempts resulted in some data, but arbitrarily put into location! (i. e. the 1767. byte was at location 258 etc., probably due to the original code only reading 8K chunks - contrib/miniunz.c, line 372)
OK, tested it:
UnzipToMemRaw did NOT work when compiled with MinGW/GCC. In the language of the Windows locale, it says "The specified module was not found".
It cannot be a missing DLL because I have it in both the UnzipToMemRaw/ directory and the root directory of the package.
[EDIT]
Found it out myself!
It's a bug in the code, which should be fixed.
The debug code was left in, and so is the directory! Smile
[unziptomemraw.c:49]
if ((unzipDll = (HMODULE)LoadLibrary(_T("../LiteUnzip/Debug/LiteUnzip.dll"))))
must be
if ((unzipDll = (HMODULE)LoadLibrary(_T("../LiteUnzip.dll"))))
and all of a sudden it works!
|
|
|
|

|
your zip project is much eary for user, but more bugs is posted on codeproject.
Thank you.
|
|
|
|

|
Hi,
Great job.... but I have one problem. I am using your \ZipFile example and when I zip files it I get Error Message: Aborted. The file iz zipped correctly though. What could be the problem???
Thanks,
DIno
|
|
|
|

|
I have some problem in using UnzipOpenBuffer()interface,my routine is as follows:
use ZipCreateBuffer() to create zipbuffer,
use ZipAddBufferA() to add string to zipbuffer through HZIP;
use ZipGetMemory() to get archived data memeory address (TZIP distination member)and data length;
all the above is ok;
But when i use the archived memory address got by ZipGetMemory()interface in UnzipOpenBuffer(), the retcode is 6,means corrupt data; I dont know why? Anyone has the same problem or anyone would help me?
retCode = ZipGetMemory(huz,(void **)&AfterCompressedBuffer,&AfterCompressed,(HANDLE *)&xp);
retCode = UnzipOpenBuffer(&hunzip,AfterCompressedBuffer,AfterCompressed,0);
|
|
|
|

|
1. the bug is belong in unzip.
2. the size of origin file must bigger than 16348.
3. unzip will lead failed!
4. line 3094 //tunzip->EntryReadVars.RemainingUncompressed -= uDoEncHead; ----> error
|
|
|
|

|
HOw are you jeff?
-천재원주-
|
|
|
|

|
I found a bug that causes a file to be unzipped minus the last n bytes, where n = the length of your password + 1. In my case, the file being unzipped was itself a zip file.
I commented out this line ( unzip.cpp, line 3517 ):
//pfile_in_zip_read_info->rest_read_uncompressed-=uDoEncHead;
and it now works properly.
|
|
|
|

|
It appears not to be the password length, but the length of the encryption header. By coincidence my password length was 11
|
|
|
|

|
Sorry, posted to wrong site - the bug is in the code this project was derived from.....
|
|
|
|

|
in liteunZip.c
struct ZIPENTRYINFO holds
unsigned long dosDate; // last mod file date in Dos fmt 4 bytes
Why only last modification date ?
Why not Last Access or creation time.
Is this reason why we do not get creation and last accesstime of unzipped file which is zipped with LiteZip.
Thanking in anticipation
sachin
|
|
|
|

|
Can the program preserve date timestamps when zip and unzip using LiteZip ..
e.g. if i used litezip and compress a file and use liteunzip to decompress will it preserve original creation, modification, access dates ?
thanks
sachin
|
|
|
|

|
Thank you for posting such a nice work. I want to use the function ZipAddDir() which has its header as given below:
//////////////////////////////////////////////////////
#define ZipAddDir ZipAddDirW
DWORD WINAPI ZipAddDirW(HZIP, const WCHAR *, DWORD);
I want to know about third argument which is offset value. I found that if I use offset value -1 then it is working properly. What is the correct value ?
Could you please explain? Also, any help to use Progress Bar during zipping ?
Thanking you in advance.
Regards,
Johnarg
Johnarg
|
|
|
|

|
Yes. ZipDir demo source code shows ZipAddDir should be used in this way:
result = strlen(&buffer[0]);
ZipAddDir(hz, &buffer[0], result + 1);
The offset can be used to control relative path in Zip file. Aobe code keep the original whole path.
|
|
|
|

|
I modded LiteZip.c/.h to support deletes and adds to an existing zipfile without having to decompress & recompress. If the author is interested, let me know.
modified on Saturday, June 7, 2008 5:19 PM
|
|
|
|

|
Hi,
I am interested in your changes. Can you please forward them to my email via fuqian@gmail.com? Thanks.
Best,
Fu Qian
|
|
|
|

|
When I try to add a file, using the example code:
ZipAddFile(hz, "simple.bmp");
I get a build error:
error C2660: 'ZipAddFileA' : function does not take 2 parameters
which is consistent with the declaration in LiteZip.h
DWORD WINAPI ZipCreateFileA(HZIP *, const char *, const char *);
Am I missing something obvious here?
Thanks to whoever can help..
|
|
|
|

|
when i add local compress(zip/rar) file into created zip file, no error occurred, but open this created zip file with WinRar, an error message displayed that created zip file is broken, why?? and i add other type file to this created zip file, open it with WinRar, no error. can not add compress file(zip/rar) into created zip file?
jacky_zz
2008-4-30
|
|
|
|

|
Litezip/Liteunzip is great packaging aroung JL. Gailly's original code (that widely available), especially fast/samll foorptint compared to other wrappers around.
However, I VERY STRONGLY SUSPECT a quite major difficulty, that is:
LiteZip compressing algorithm is hopelessly confused with files that are already in compressed (ie. PKZIP) format: whenever you request LiteZip to make an archive from a mix of "regular" and compressed (such as Windows .zip and/or Linux .gz files), the resulting archive cannot be retrieved by other unzipping programs: the zipped files contents seem to be compressed to ZERO size, with a zero CRC value); that' s, at least, what industry ZIP programs report (Winzip 9 ...).
I am afraid I don't have the time to go down tracing the code to see what' s going wrong, I might suggest that Litezip should discover that source file is already compressed (just by detecting the various "PKxx" record markers), copy file to output stream without any attempt to compress any further, while marking file's header as uncompressed, not deflated; does it make sense ?
Besides this, a very good piece of work.
Jean-Henri
|
|
|
|

|
I just figured out that the problem is because a bug inside the code.
The library will just "STORE" the already compressed file into the package. Inside the istore function, you need put "tzip->csize += cin;" inside the while loop too, which is only put outside the loop right now. That is why it always gets 0 size.
|
|
|
|

|
First of all, thanks for the excellent library.
Is there any way to avoid storing the path in the ZIP file? For ex, if the zip is "C:\Somewhere\Sample.zip" and I add two files to it, "C:\Another Place\First.doc" and "C:\One more place\Second.doc", the archive stores the paths within the zip archive. Is there a flag or setting to avoid that and not store a path, i.e., the un-zip (using say WinZip) will just unzip to selected folder. I know there is a flag within WinZip to ignore the file paths, but I wanted to know if it can be done while zipping.
|
|
|
|

|
Is it allowed to use your Code in a commercial application if yes how are the licensing details?
|
|
|
|

|
The licensing details are the same as the code it is based upon, zlib at http://www.gzip.org/zlib by Jean-Loup Gailly and Mark Adler.
|
|
|
|

|
Hi Jeff, Great article and equally great work. What I was trying to find out is how one could get the CRC values for the zip archive file and each file individually. I really actually only need the CRC of the archive file itself. It appears the code is in place but this information is not exposed or maybe I'm just missing it. We store the CRC value in a database along with the archive file itself so I'll need to get this value prior to incorporating you efforts into my small program. Thanks again Jeff or to whomever replies to this message. Craig
|
|
|
|

|
Been looking for a mature and flexible compression solution. Standard C is the way to go to reduce bloat, increase flexibility, and ease porting code. While I have noticed readers commenting on specific bugs and issues, I think LiteZip is a candidate for further development.
However, I would prefer a static library, instead of a dynamic one, so that will be my primary focus delving into it...
Thank you for your efforts, they are much appreciated.
|
|
|
|

|
Hello,
thanks for this library.
I have a little problem when i unzip a file with liteunzip.
Some files (a lot) are not complete, some bytes are missing.
I tried to unzip the file with izarc and everything is ok.
So the archive file is correct and maybe there is a bug in the function.
Can you help me ?
Thanks very much.
Alexandre GAMBIER
here my code :
// Ouvre le fichier zip
if( UnzipOpenFile( &hZIP, szZIPFile, GLB_ZIPPASSWORD )!=ZR_OK )
return( FALSE );;
// Définit le répertoire de sortie
if( UnzipSetBaseDir( hZIP, szDstDir )!=ZR_OK )
{
UnzipClose( hZIP );
return( FALSE );
}
// Extrait tous les fichiers
memset( &tZipEntry, 0, sizeof( tZipEntry ) );
// Combien de fichier ?
tZipEntry.Index = -1;
if( UnzipGetItem( hZIP, &tZipEntry )!=ZR_OK )
{ UnzipClose( hZIP );
return( FALSE );;
}
dwEntryCount = tZipEntry.Index;
// Extrait les fichier un par un
wErr = FALSE;
for( tZipEntry.Index = 0; tZipEntry.IndexAdd( tZipEntry.Name );
}
}
// ferme le zip
UnzipClose( hZIP );
if( wErr!=FALSE ) return( FALSE );
return( TRUE );
|
|
|
|

|
bonjour Alexandre - Im a bit worried by your loop to 'Extract the files one by one' (// Extrait les fichier un par un) .. it doesnt seem to have displayed well here..
have you tried the code from unzipfile.c in the distribution verbatim ?
'G'
|
|
|
|

|
this code is working perfectly fine on windows but while working on sun4v it's having strange behaviour.I tried to debug the code but was unable to trace the correct problem .I think the problem is in getArchiveLong or reformat_long or reformat_short functions.
It would be great If someone can help me out.basically the stuucture of type CurrentEntryInfo is not getting filled properly.
|
|
|
|

|
YES! There is error in there reformat functions! I dont know what they do, but they clearly are wrong! Rewrite those two reformat functions and that unzip code will ROCK!
Reinis
|
|
|
|

|
Could it work under Vista?
|
|
|
|

|
It should, but I haven't personally tested it.
But note that the DLLs are compiled for a 32-bit, not 64-bit, version of Windows.
|
|
|
|

|
I have just got it going on my Vista Ultimate 64 bit computer. I use Borland C++ V5 and to get it to compile with Borland you need to convert the lib file with:
coff2omf -lib:st liteZip.lib liteZipNew.lib
to make it work.
Good stuff author - thanks.
|
|
|
|

|
Dear Gurus,
When I Zipped files with Password and then tried to Unzip the internal error (#define ZR_FLATE 0x05000000 // an internal error in the de/inflation code) raized. Could enyboday Help?
Thanks,
Vasil Mamikonyan
|
|
|
|

|
Hi to all,
I am using VC++ 2005 and trying to employ LiteUnzip a series of ZIPPED files but once I retrieve the file names within the ZIP I would like to decompress them using an alternate path, so I am trying to override ze.Name and give it a path which has been defined within a String.
Take a look at the code below to get an idea where I'm coming from:
private: void UnZIP(String^ file,String^ source, String^ target)
{
HUNZIP hz;
ZIPENTRY ze;
String^ inFile;
String^ outFile;
String^ fileName;
DWORD numitems;
inFile = source + file;
pin_ptr INFILE = PtrToStringChars(inFile);
UnzipOpenFile(&hz,INFILE,0);
ze.Index = (DWORD)-1;
UnzipGetItem(hz,&ze);
numitems = ze.Index;
for(ze.Index = 0;ze.Index < numitems + 1;ze.Index++)
{
UnzipGetItem(hz,&ze);
// Convert to a System::String
String^ systemstring = gcnew String(ze.Name);
fileName = Path::GetFileName(systemstring);
delete systemstring;
outFile = target + "\\" + fileName;
ze.Name = outFile; Need to find a way to convert a String to an acceptable type.
UnzipItemToFile(hz,ze.Name,&ze);
}
UnzipClose(hz);
}
Cheers
Fritzables.
|
|
|
|
|

|
Hi Jeff,
Thanks for making this available. I am guessing that the encryption method you've implemented is the ZIP 2.0 encryption, and not AES? Any tips on how to modify this to support AES?
Thanks,
Mark
http://www.beiley.com
|
|
|
|

|
I never bothered with the encryption stuff. Whatever was in the original sources is what I've kept in the DLL.
No idea how to support AES. Encryption isn't my area.
|
|
|
|

|
I've uploaded (to my own server) an updated codebase with bug fixes, and Linux support. After some of you give it more rigorous testing, and report back, then I'll update the article too.
Get the new code at:
http://home.roadrunner.com/~jgglatt/LiteZip.zip
I've added support to abort a zip. It is assumed that you'll launch a secondary thread to do the zipping. To abort from the UI thread, call:
ZipOptions(zipHandle, TZIP_OPTION_ABORT);
In this case, ZipAddFile/ZipAddBuffer/etc will return ZR_ABORT.
I decided not to bother adding any "progress callback". Since your zip thread loops around calls to ZipAddFile/ZipAddBuffer/etc (to add each file to the archive), your thread can update any progress display after each file is finished being zipped. I think that should be sufficient.
|
|
|
|

|
Hi Jeff,
LiteZip.def is missing export definitions for ZipAddDirA/W. This causes the ZipDir sample to crash, as it fails to get the function pointer in this call:
lpZipAddDir = (ZipAddDirPtr *)dlsym(zipDll, ZIPADDDIRNAME);
Thanks,
Mark
http://www.beiley.com
|
|
|
|

|
I must have forgot to add my updated DEF file to the zip archive. But otherwise, the compiled DLL I provided should have worked.
It's updated now.
|
|
|
|

|
ZipAddFile does not use local time for storing files in the zip archives. It looks like it using GMT which in our case causes all files to be 5 hours in the future. Is there anyway to use local server time instead? Thanks, Eugene.
|
|
|
|

|
I was under the impression that a ZIP file is supposed to use GMT because after all, there's no timezone information in the file.
Your unzip utility should be converting the GMT back to a local time.
|
|
|
|

|
Hi, I still think you need callbacks/abort hooks within ZipAddFile et al (and UnzipExtractFile etc.) - if the file is large (I'm adding files that are over a Gig in size), you'll get no progress update until the operation is finished, and no opportunity to abort the operation. If the user needs to exit the program/cancel the operation, you can't cleanly exit the secondary thread - you'll have to either wait or call TerminateThread.
|
|
|
|

|
1. Add callbacks for long-running operations - if you're zipping 2GB of files this can take a while. As it stands the library is useless for GUI/interactive applications without progress callbacks.
2. Add a way to cleanly abort a long-running operation. Related to (1) above.
|
|
|
|

|
For #1, if the zipping really takes that long, you should launch a separate thread to do the zipping. You really don't want the user interface thread to do the zipping.
For #2, I could add an API to set a "progress callback". I could also add a flag to the TZIP struct, which when set, will cause zipping to abort. And then I'll just add a thread safe function you can call to set that flag.
I'll look into that. I have to package all the bug fixes and updates. My latest code base also has Linux support (ie, you can compile a Linux LibUnzip.so and LibZip.so that are compatible with the Windows DLLs).
|
|
|
|

|
This happens, like the previous bug I reported, when you use ZipAddBuffer to add to a zip from a memory buffer, and STORE is used as the method.
The CRC is not calculated - so although the zip file appears to be created successfully, and can be opened, any attempt
to extract a file will fail with a CRC error.
In the istore function, a line to calculate the crc needs to be added:
static void istore(register TZIP *tzip)
{
register DWORD cin;
// If a memory buffer, we can write out those bytes all at once
if (tzip->flags & TZIP_SRCMEMORY)
{
// Original code was:
//
// writeDestination(tzip, tzip->destination, tzip->lenin);
//
// Which is incorrect; txip->destination is the file handle of the zip file we're writing to
writeDestination(tzip, tzip->source, tzip->lenin);
tzip->totalRead = tzip->csize = tzip->lenin;
// calculate CRC
tzip->crc = crc32(tzip->crc, tzip->source, tzip->totalRead);
}
// Otherwise, we read in the source in 16384 byte chunks, and write it out.
// Read upto the next 16384 bytes from the source. If no more, we're done
else while ((cin = readFromSource(tzip, tzip->buf, 16384)) && !tzip->lasterr)
{
// Write out those bytes
writeDestination(tzip, tzip->buf, cin);
// Increment total amount of bytes written (ie, the total size of the source)
tzip->csize += cin;
}
}
|
|
|
|

|
Yep. The CRC needs to be calculated. I think the most accurate bug fix (to LiteZip.c) should be as follows:
static void istore(register TZIP *tzip)
{
register DWORD cin;
if (tzip->flags & TZIP_SRCMEMORY)
{
cin = tzip->lenin;
writeDestination(tzip, tzip->source, cin);
tzip->totalRead += cin;
tzip->crc = crc32(tzip->crc, (UCH *)tzip->source, cin);
tzip->posin += cin;
}
else while ((cin = readFromSource(tzip, tzip->buf, 16384)) && !tzip->lasterr)
{
writeDestination(tzip, tzip->buf, cin);
}
tzip->csize += cin;
}
|
|
|
|

|
This protection fault is caused when using LiteUnzip to unzip a zip file created with LiteZip. This happens every 10-12 times and is hard to debug because running it from the debugger doesn't exhibit the issue. The exception is caused on either line 3332 or line 3339 of liteunzip.c, which looks like this:
lutime_t accessTime = ((extra[epos+0])<<0) | ((extra[epos+1])<<8) |((extra[epos+2])<<16) | ((extra[epos+3])<<24);
The failure happens because bits 1 or 2 of the flags field in the central copy of the extra header (EB_UT_FL_ATIME or EB_UT_FL_CTIME) are set, but the size of the extra header is too small (5 bytes instead of 13 bytes).
The exact bug appears here:
{
char xloc[EB_L_UT_SIZE];
zfi->extra = xloc;
zfi->ext = EB_L_UT_SIZE;
zfi->cextra = (unsigned char *)zfi + sizeof(TZIPFILEINFO);
zfi->cext = EB_C_UT_SIZE;
xloc[0] = 'U';
xloc[1] = 'T';
xloc[2] = EB_UT_LEN(3); xloc[3] = 0;
xloc[4] = EB_UT_FL_MTIME | EB_UT_FL_ATIME | EB_UT_FL_CTIME;
xloc[5] = (char)(times.mtime);
xloc[6] = (char)(times.mtime >> 8);
xloc[7] = (char)(times.mtime >> 16);
xloc[8] = (char)(times.mtime >> 24);
xloc[9] = (char)(times.atime);
xloc[10] = (char)(times.atime >> 8);
xloc[11] = (char)(times.atime >> 16);
xloc[12] = (char)(times.atime >> 24);
xloc[13] = (char)(times.ctime);
xloc[14] = (char)(times.ctime >> 8);
xloc[15] = (char)(times.ctime >> 16);
xloc[16] = (char)(times.ctime >> 24);
CopyMemory(zfi->cextra, zfi->extra, EB_C_UT_SIZE);
zfi->cextra[EB_LEN] = EB_UT_LEN(1); }
In these lines, the extra header created in the xloc array is copied to the central copy using EB_C_UT_SIZE (9 bytes). So far so good. And then the length of the extended header adjusted using EB_UT_LEN(1) (5 bytes, 9 - ext header size = 5). Again, so far so good. But look at xloc[4]. It still has all three flags set. This causes the follwoing code in liteunzip.c to fail because they read data beyond the last byte of the extra header:
if (flags & 1)
{
lutime_t modifyTime = ((extra[epos+0])<<0) | ((extra[epos+1])<<8) |((extra[epos+2])<<16) | ((extra[epos+3])<<24);
epos += 4;
timet2filetime(&ze->ModifyTime, modifyTime);
}
if (flags & 2)
{
lutime_t accessTime = ((extra[epos+0])<<0) | ((extra[epos+1])<<8) |((extra[epos+2])<<16) | ((extra[epos+3])<<24);
epos += 4;
timet2filetime(&ze->AccessTime, accessTime);
}
if (flags & 4)
{
lutime_t createTime = ((extra[epos+0])<<0) | ((extra[epos+1])<<8) |((extra[epos+2])<<16) | ((extra[epos+3])<<24);
epos += 4;
timet2filetime(&ze->CreateTime, createTime);
}
Notice that epos is incremented based on the flags, regardless of whether it has exceeded the size of the extra entry.
This could also be more robust to check. Simply add && epos < tunzip->CurrentEntryInfo.size_file_extra to each if the if (flags & xxx) lines above.
Then, in LiteZip, make the following change:
CopyMemory(zfi->cextra, zfi->extra, EB_C_UT_SIZE);
zfi->cextra[EB_LEN] = EB_UT_LEN(1);
zfi->cextra[EB_HEADSIZE] = EB_UT_FL_MTIME;
Tim Lewis
|
|
|
|

|
Yes, that could make it more fault tolerant.
|
|
|
|

|
In the istore function, tzip->totalRead needs to be set with the size of the memory buffer, otherwise
the stored file in the resulting zip file has a size of 0 bytes:
The corrected function (including the earlier bug I reported) is:
static void istore(register TZIP *tzip)
{
register DWORD cin;
// If a memory buffer, we can write out those bytes all at once
if (tzip->flags & TZIP_SRCMEMORY)
{
// Original code was:
//
// writeDestination(tzip, tzip->destination, tzip->lenin);
//
// Which is incorrect; txip->destination is the file handle of the zip file we're writing to
writeDestination(tzip, tzip->source, tzip->lenin);
tzip->totalRead = tzip->csize = tzip->lenin;
}
// Otherwise, we read in the source in 16384 byte chunks, and write it out.
// Read upto the next 16384 bytes from the source. If no more, we're done
else while ((cin = readFromSource(tzip, tzip->buf, 16384)) && !tzip->lasterr)
{
// Write out those bytes
writeDestination(tzip, tzip->buf, cin);
// Increment total amount of bytes written (ie, the total size of the source)
tzip->csize += cin;
}
}
|
|
|
|

|
Yep, that was a bug. It should be using tzip->source.
|
|
|
|
 |
|
|
General News Suggestion Question Bug Answer Joke Rant Admin
|
Easy to use, small-footprint DLLs to let your app create zip archives, and extract the contents of them. Useful for C, C++, VB, and other languages. Works for Win32 and Linux
| Type | Article |
| Licence | LGPL3 |
| First Posted | 9 Mar 2006 |
| Views | 205,313 |
| Downloads | 3,498 |
| Bookmarked | 141 times |
|
|