PipiFax-ZIP-Include [all OS]

Hier könnt Ihr gute, von Euch geschriebene Codes posten. Sie müssen auf jeden Fall funktionieren und sollten möglichst effizient, elegant und beispielhaft oder einfach nur cool sein.
Benutzeravatar
HeX0R
Beiträge: 2959
Registriert: 10.09.2004 09:59
Computerausstattung: AMD Ryzen 7 5800X
96Gig Ram
NVIDIA GEFORCE RTX 3060TI/8Gig
Win10 64Bit
G19 Tastatur
2x 24" + 1x27" Monitore
Glorious O Wireless Maus
PB 3.x-PB 6.x
Oculus Quest 2
Kontaktdaten:

PipiFax-ZIP-Include [all OS]

Beitrag von HeX0R »

Ich brauche des öfteren eine einfache Art eine Datei in ein Zip-File zu komprimieren (z.B. für die Backupfunktion meines History Viewers).
Seit 20.06.2011 kann man auch zip-Dateien entpacken.

Es gibt viele Dinge wie pureZIP von gnozal oder die minizip von ts-soft,
aber ich wollte etwas, das auch bei allen OS funktioniert (und keine library ist).

Update (29.12.2012)
Dateinamen werden korrekt GEzippt (Danke an ts-soft)

Update (30.04.2012)
Dateinamen mit Umlauten werden korrekt entzippt.
(Da ist das zib-Format ein wenig altbacken, ich fürchte die Zip-Routine produziert beim zippen von Umlautdateinamen auch falsche Namen.
Muss ich mal bei Gelegenheit abändern)

Update (29.04.2012)
Zip-Dateien mit Extrafields werden nun auch unterstützt (Fehler von DROOPY gemeldet).

Neu (20.06.2011)
Entzippen-Funktion hinzugefügt.

Herausgekommen ist das hier:

Code: Alles auswählen

;/--------------
;| Pipifax Zip
;| Last modified: 29.12.2012
;|
;| Mini-Include to
;| create a zip file with just ONE file in it.
;| Extract zip files
;|
;| Should work with Win, Linux and MacOS
;|
;| (c)HeX0R 2012
;|
;/--------------

Structure z_stream
	*next_in;    /* next input byte */
	avail_in.l;  /* number of bytes available at next_in */
	total_in.l;  /* total nb of input bytes read so far */

	*next_out;   /* next output byte should be put there */
	avail_out.l; /* remaining free space at next_out */
	total_out.l; /* total nb of bytes output so far */

	*msg;        /* last error message, NULL if no error */
	*state;      /* not visible by applications */

	*zalloc;     /* used to allocate the internal state */
	*zfree;      /* used to free the internal state */
	*opaque;     /* private data object passed to zalloc and zfree */

	data_type.l; /* best guess about the data type: binary or text */
	adler.l;     /* adler32 value of the uncompressed data */
	reserved.l;  /* reserved for future use */
	CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
	Dummy.l
	CompilerEndIf
EndStructure

;All-OS compatible Import
;from jamirokwai [http://www.purebasic.fr/german/viewtopic.php?p=288981#p288981]
;{
CompilerSelect #PB_Compiler_OS
	CompilerCase #PB_OS_Windows
		ImportC "zlib.lib"
	CompilerCase #PB_OS_Linux
		ImportC #PB_Compiler_Home + "purelibraries/linux/libraries/zlib.a"
	CompilerCase #PB_OS_MacOS
		ImportC "/usr/lib/libz.dylib"     
	CompilerEndSelect
	compress2(*dest, *destLen, *source, sourceLen, level)
	uncompress(*a, *b, *c, d)
	inflateInit2_(*strm.z_stream, windowBits, *version, stream_size)
	inflate(*strm.z_stream, flush)
	inflateEnd(*strm.z_stream)
EndImport
;}

#Z_DEFAULT_COMPRESSION = -1
#Z_OK                  = 0
#Z_STREAM_END          = 1
#Z_FINISH              = 4

Structure _ZIP_Local_File_Header_
	signature.l ;0x04034b50
	VersionNeeded.w
	Generalflag.w
	Compressionmethod.w
	Last_modification.l
	CRC32.l
	Compressed_size.l
	Uncompressed_size.l
	Filename_length.w
	Extrafield_length.w
	*Filename
EndStructure

Structure _ZIP_Unicode_Path_Extra_Field_
	signature.w ;0x7075
	Size.w
	Version.b
	CRC32.l
	*FileName
EndStructure

Structure _ZIP_Data_Descriptor_
	signature.l ;0x08074b50
	CRC32.l
	Compressed_size.l
	Uncompressed_size.l
EndStructure

Structure _ZIP_Central_Directory_File_Header_
	signature.l ;0x02014b50
	madeby.w
	VersionNeeded.w
	Generalflag.w
	Compressionmethod.w
	Last_modification.l
	CRC32.l
	Compressed_size.l
	Uncompressed_size.l
	Filename_length.w
	Extrafield_length.w
	comment_length.w
	Disk_number_start.w
	Internal_file_attributes.w
	External_file_attributes.l
	offset_of_local_file_header.l
	*Filename
EndStructure

Structure _ZIP_End_of_central_directory_record_
	signature.l ;0x06054b50
	Number_of_this_disk.w
	Disk_Start.w
	Number_of_central_directory_records_on_disk.w
	Total_number_of_central_directory_records.w
	Size_of_central_directory.l
	Offset_of_start_of_central_directory.l
	filecomment_length.w
	*filecomment
EndStructure

Procedure UnixToMSDosDate(UnixDate)
	Protected Result, m
	
	m      = Year(UnixDate) - 1980
	Result | (m << 25)
	m      = Month(UnixDate)
	Result | (m << 21)
	m      = Day(UnixDate)
	Result | (m << 16)
	m      = Hour(UnixDate)
	Result | (m << 11)
	m      = Minute(UnixDate)
	Result | (m << 5)
	m      = Second(UnixDate) / 2
	Result | m
	
	ProcedureReturn Result
EndProcedure

Procedure MSDosDateToUnix(MSDos_Date)
	Protected Result, Y, M, D, H, Min, S
	
	Y      = 1980 + (MSDos_Date >> 25) & $7F
	M      = (MSDos_Date >> 21) & $0F
	D      = (MSDos_Date >> 16) & $1F
	H      = (MSDos_Date >> 11) & $1F
	Min    = (MSDos_Date >> 5) & $3F
	S      = (MSDos_Date & $1F) * 2
	Result = Date(Y, M, D, H, Min, S)
	
	ProcedureReturn Result
EndProcedure

Procedure CreateZipFile(FileToAdd.s, ZipFile.s)
	Protected i, j, k, l, Offset, Result, FID_Zip, FID_Orig, *B1, *B2
	Protected MSDos_Date
	Protected *ZLFH._ZIP_Local_File_Header_
	Protected *ZDD._ZIP_Data_Descriptor_ ;not used
	Protected *ZCDFH._ZIP_Central_Directory_File_Header_
	Protected *ZECDR._ZIP_End_of_central_directory_record_
	
	If FileSize(FileToAdd) > 0
		*ZLFH    = ?__ZIP_Local_File_Header_
		*ZDD     = ?__ZIP_Data_Descriptor_
		*ZCDFH   = ?__ZIP_Central_Directory_File_Header_
		*ZECDR   = ?__ZIP_End_of_central_directory_record_
		k        = CRC32FileFingerprint(FileToAdd)
		FID_Orig = ReadFile(#PB_Any, FileToAdd)
		If FID_Orig
			*B1 = AllocateMemory(Lof(FID_Orig))
			If *B1
				ReadData(FID_Orig, *B1, Lof(FID_Orig))
				i   = MemorySize(*B1)
				j   = i
				*B2 = AllocateMemory(i)
				If *B2
					If compress2(*B2, @i, *B1, j, #Z_DEFAULT_COMPRESSION) = #Z_OK
						FID_Zip = CreateFile(#PB_Any, ZipFile)
						If FID_Zip
							l                       = StringByteLength(GetFilePart(FileToAdd), #PB_UTF8)
							MSDos_Date              = UnixToMSDosDate(GetFileDate(FileToAdd, #PB_Date_Modified))
							*ZLFH\Last_modification = MSDos_Date
							*ZLFH\CRC32             = k
							*ZLFH\Compressed_size   = i - 6
							*ZLFH\Uncompressed_size = j
							*ZLFH\Filename_length   = l
							*ZLFH\Generalflag       = $800
							WriteData(FID_Zip, *ZLFH, OffsetOf(_ZIP_Local_File_Header_\Filename))
							WriteString(FID_Zip, GetFilePart(FileToAdd), #PB_UTF8)
							WriteData(FID_Zip, *B2 + 2, i - 6)

							Offset                          = Loc(FID_Zip)
							*ZCDFH\External_file_attributes = GetFileAttributes(FileToAdd)
							*ZCDFH\CRC32                    = k
							*ZCDFH\Compressed_size          = i - 6
							*ZCDFH\Uncompressed_size        = j
							*ZCDFH\Generalflag              = $800
							*ZCDFH\Filename_length          = l
							*ZCDFH\Last_modification        = MSDos_Date
							WriteData(FID_Zip, *ZCDFH, OffsetOf(_ZIP_Central_Directory_File_Header_\Filename))
							WriteString(FID_Zip, GetFilePart(FileToAdd), #PB_UTF8)
												
							*ZECDR\Size_of_central_directory            = OffsetOf(_ZIP_Central_Directory_File_Header_\Filename) + l
							*ZECDR\Offset_of_start_of_central_directory = Offset
							WriteData(FID_Zip, *ZECDR, OffsetOf(_ZIP_End_of_central_directory_record_\filecomment))
							CloseFile(FID_Zip)
							Result = #True
						EndIf
					EndIf
					FreeMemory(*B2)
				EndIf
				FreeMemory(*B1)
			EndIf
			CloseFile(FID_Orig)
		EndIf
	EndIf
	
	ProcedureReturn Result
EndProcedure

Procedure ExtractZipFile(ZipFile.s, DestinationFolder.s)
	Protected i, j, Result, R, FID_Zip, FID_Orig, *B1, *B2, *B3._ZIP_Unicode_Path_Extra_Field_
	Protected FileName.s, PathAdd.s, Version.s, FileCount, FilesOK, *FileNameBuffer
	Protected ZLFH._ZIP_Local_File_Header_
	Protected STREAM.z_stream
	
	If FileSize(ZipFile) > OffsetOf(_ZIP_Local_File_Header_\Filename) And FileSize(DestinationFolder) = -2
		FID_Zip = ReadFile(#PB_Any, ZipFile)
		If FID_Zip
			Repeat
				R = 0
				ReadData(FID_Zip, @ZLFH, OffsetOf(_ZIP_Local_File_Header_\Filename))
				If ZLFH\signature = $04034b50
					FileName        = ""
					*FileNameBuffer = AllocateMemory(ZLFH\Filename_length + 2)
					ReadData(FID_Zip, *FileNameBuffer, ZLFH\Filename_length)
					If ZLFH\Generalflag & $800
						FileName = PeekS(*FileNameBuffer, ZLFH\Filename_length, #PB_UTF8)
					Else
						FileName = PeekS(*FileNameBuffer, ZLFH\Filename_length, #PB_Ascii)
					EndIf
					FreeMemory(*FileNameBuffer)
					If ZLFH\Extrafield_length
						If *B3 = 0 Or MemorySize(*B3) < ZLFH\Extrafield_length
							*B3 = ReAllocateMemory(*B3, ZLFH\Extrafield_length)
						EndIf
						ReadData(FID_Zip, *B3, ZLFH\Extrafield_length)
						If *B3\signature = $7075
							;This filename is also in utf8 available
							FileName = PeekS(*B3 + OffsetOf(_ZIP_Unicode_Path_Extra_Field_\FileName), (*B3\Size & $FFFF) - 5, #PB_UTF8)
						EndIf
					EndIf
					Debug FileName
					PathAdd = ""
					For i = 1 To CountString(FileName, "/")
						PathAdd + StringField(FileName, i, "/") + "/"
						If FileSize(DestinationFolder + PathAdd) <> -2
							CreateDirectory(DestinationFolder + PathAdd)
						EndIf
					Next i
					If Right(FileName, 1) <> "/"
						FileCount + 1
						FID_Orig = CreateFile(#PB_Any, DestinationFolder + FileName)
						If FID_Orig
							If ZLFH\Uncompressed_size = 0
								R = #True
							ElseIf *B2 = 0 Or MemorySize(*B2) < ZLFH\Uncompressed_size
								*B2 = ReAllocateMemory(*B2, ZLFH\Uncompressed_size)
							EndIf
							If *B2
								If ZLFH\Uncompressed_size = ZLFH\Compressed_size
									;Not compressed!
									R = #True
									ReadData(FID_Zip, *B2, ZLFH\Uncompressed_size)
									WriteData(FID_Orig, *B2, ZLFH\Uncompressed_size)
								Else
									If *B1 = 0 Or MemorySize(*B1) < ZLFH\Compressed_size
										*B1 = ReAllocateMemory(*B1, ZLFH\Compressed_size)
									EndIf
									If *B1
										Version = "1.2.5"
										If inflateInit2_(@STREAM, -10, @Version, SizeOf(z_stream)) = #Z_OK
											STREAM\adler     = ZLFH\CRC32
											STREAM\next_in   = *B1
											STREAM\next_out  = *B2
											STREAM\avail_out = ZLFH\Uncompressed_size
											STREAM\avail_in  = ReadData(FID_Zip, *B1, ZLFH\Compressed_size)
											If inflate(@STREAM, #Z_FINISH) = #Z_STREAM_END
												If CRC32Fingerprint(*B2, ZLFH\UnCompressed_size) = ZLFH\CRC32 & $FFFFFFFF
													R = #True
													WriteData(FID_Orig, *B2, ZLFH\Uncompressed_size)
												EndIf
											EndIf
											inflateEnd(@STREAM)
										EndIf
									EndIf
								EndIf
							EndIf
							CloseFile(FID_Orig)
						EndIf
						If R
							SetFileDate(DestinationFolder + FileName, #PB_Date_Modified, MSDosDateToUnix(ZLFH\Last_modification))
							FilesOK + 1
						EndIf
					EndIf
				Else
					Break
				EndIf
			Until Eof(FID_Zip)
			CloseFile(FID_Zip)
		EndIf
	EndIf
	If *B1
		FreeMemory(*B1)
	EndIf
	If *B2
		FreeMemory(*B2)
	EndIf
	If *B3
		FreeMemory(*B3)
	EndIf
	
	If FileCount = FilesOK
		Result = #True
	EndIf
	ProcedureReturn Result
EndProcedure

DataSection
	__ZIP_Local_File_Header_:
	Data.l $04034b50
	Data.w $14, 0, 8
	Data.l 0, 0, 0, 0
	Data.w 0, 0
	__ZIP_Data_Descriptor_:
	Data.l $08074b50, 0, 0, 0
	__ZIP_Central_Directory_File_Header_:
	Data.l $02014b50
	Data.w $14, $14, 0, 8
	Data.l 0, 0, 0, 0
	Data.w 0, 0, 0, 0, 0
	Data.l 0, 0
	__ZIP_End_of_central_directory_record_:
	Data.l $06054b50
	Data.w 0, 0, 1, 1
	Data.l 0, 0
	Data.w 0
EndDataSection
Wer mehrere Dateien zippen möchte, oder gar ganze Verzeichnisse, darf das hier gerne mit dazubauen.

Gruß
Zuletzt geändert von HeX0R am 29.12.2012 01:12, insgesamt 10-mal geändert.
jamirokwai
Beiträge: 65
Registriert: 02.06.2008 16:10

Re: PipiFax-ZIP-Include [all OS]

Beitrag von jamirokwai »

Hi HeX0R,

funktioniert auf Mac OS X 10.6, wenn ich die Konstante #S_OK = 0 setze.
Was hat die denn sonst für einen Hintergrund bzw. Sinn?
Das erstellte Zip wird auch von Mac OS X wieder entpackt. Cool, danke!

Gruß
J.
Benutzeravatar
HeX0R
Beiträge: 2959
Registriert: 10.09.2004 09:59
Computerausstattung: AMD Ryzen 7 5800X
96Gig Ram
NVIDIA GEFORCE RTX 3060TI/8Gig
Win10 64Bit
G19 Tastatur
2x 24" + 1x27" Monitore
Glorious O Wireless Maus
PB 3.x-PB 6.x
Oculus Quest 2
Kontaktdaten:

Re: PipiFax-ZIP-Include [all OS]

Beitrag von HeX0R »

HaHaHa,

ja o.k. keine Ahnung, warum ich da eine WinAPI-Konstante genommen habe,
vermutlich fand ich = 0 irreführend.

Ich verbessere das da oben gleich mal.

Und vielen Dank für die Bestätigung, dass es unter MacOS funktioniert!
Benutzeravatar
rolaf
Beiträge: 3843
Registriert: 10.03.2005 14:01

Re: PipiFax-ZIP-Include [all OS]

Beitrag von rolaf »

Funktioniert prima bei mir. :allright:

Sowas würde ich mir auch für die umgekehrte Ausführung wünschen. Also nur simpel ein zipArchiv auspacken, nicht mehr.
:::: WIN 10 :: PB 5.73 :: (x64) ::::
Benutzeravatar
HeX0R
Beiträge: 2959
Registriert: 10.09.2004 09:59
Computerausstattung: AMD Ryzen 7 5800X
96Gig Ram
NVIDIA GEFORCE RTX 3060TI/8Gig
Win10 64Bit
G19 Tastatur
2x 24" + 1x27" Monitore
Glorious O Wireless Maus
PB 3.x-PB 6.x
Oculus Quest 2
Kontaktdaten:

Re: PipiFax-ZIP-Include [all OS]

Beitrag von HeX0R »

DrFalo hat geschrieben:Sowas würde ich mir auch für die umgekehrte Ausführung wünschen. Also nur simpel ein zipArchiv auspacken, nicht mehr.
Das Problem dabei ist, dass ich dann auch gezippte Verzeichnisse unterstützen müsste,
weil ich ja nicht weiss, mit welchem zip der User die Funktion füttert.

Also "Problem" bedeutet hier:
Ich habe davon momentan keinen Nutzen und daher auch keine große Lust mich damit zu beschäftigen.

Der Source ist ja da und wartet nur darauf erweitert zu werden.

Oder:
vielleicht brauche ich es ja doch mal, oder mir ist langweilig und ich beschäftige mich mal wieder mit dem zip-Format,
oder PB macht endlich wahr, was vor Jahren schon angedeutet wurde, oder mir wächst ein Furunkel am *, oder...
;)
Benutzeravatar
rolaf
Beiträge: 3843
Registriert: 10.03.2005 14:01

Re: PipiFax-ZIP-Include [all OS]

Beitrag von rolaf »

HeX0R hat geschrieben:Oder:
vielleicht brauche ich es ja doch mal, oder mir ist langweilig und ich beschäftige mich mal wieder mit dem zip-Format,
oder PB macht endlich wahr, was vor Jahren schon angedeutet wurde, oder mir wächst ein Furunkel am *, oder...
;)
War ja auch nur ein frommer Wunsch. Weihnachten ist ja noch nicht und mit Furunkel am Hintern programmiert es sich schlecht im Sitzen. :mrgreen: Ich würds ja machen aber schon dein Code oben sind böhmische Dörfer für mich. Da schmeiss ich mich eben weiter auf ne zip.dll, den Umgang damit bekommt mein Althirn noch gebacken. <)
:::: WIN 10 :: PB 5.73 :: (x64) ::::
Benutzeravatar
HeX0R
Beiträge: 2959
Registriert: 10.09.2004 09:59
Computerausstattung: AMD Ryzen 7 5800X
96Gig Ram
NVIDIA GEFORCE RTX 3060TI/8Gig
Win10 64Bit
G19 Tastatur
2x 24" + 1x27" Monitore
Glorious O Wireless Maus
PB 3.x-PB 6.x
Oculus Quest 2
Kontaktdaten:

Re: PipiFax-ZIP-Include [all OS]

Beitrag von HeX0R »

Entzippen beliebiger zips (ohne Passwortschutz!) sollte jetzt auch gehen.

Zu beachten wäre, dass alle Einzeldateien im Memory als ein Block entpackt werden.
Ich war zu faul das anders zu lösen, also keine zips benutzen in denen ein 3Gig-DVD-Image steckt ;)
Benutzeravatar
rolaf
Beiträge: 3843
Registriert: 10.03.2005 14:01

Re: PipiFax-ZIP-Include [all OS]

Beitrag von rolaf »

Hey interessant, Danke. :allright:
Wer eine einzippt will die meist auch wieder auszippen. :mrgreen:
Werd mich heute nachmittag mal mit beschäftigen.


Tante Edit (23.06.11):
War bissle faul die Tage, Rückmeldung folgt bis zum Wochenende wie ich doch hoffe. ;-)
Zuletzt geändert von rolaf am 23.06.2011 20:36, insgesamt 1-mal geändert.
:::: WIN 10 :: PB 5.73 :: (x64) ::::
Benutzeravatar
X0r
Beiträge: 2770
Registriert: 15.03.2007 21:47
Kontaktdaten:

Re: PipiFax-ZIP-Include [all OS]

Beitrag von X0r »

Zu beachten wäre, dass alle Einzeldateien im Memory als ein Block entpackt werden.
Das wollte ich auch schon anmerken. Mich würde aber darüber hinaus mal interessieren, wie groß man so einen Pack/Entpack-Puffer idealerweise wählt.
Benutzeravatar
HeX0R
Beiträge: 2959
Registriert: 10.09.2004 09:59
Computerausstattung: AMD Ryzen 7 5800X
96Gig Ram
NVIDIA GEFORCE RTX 3060TI/8Gig
Win10 64Bit
G19 Tastatur
2x 24" + 1x27" Monitore
Glorious O Wireless Maus
PB 3.x-PB 6.x
Oculus Quest 2
Kontaktdaten:

Re: PipiFax-ZIP-Include [all OS]

Beitrag von HeX0R »

Du meinst, wenn du es in Einzelstücken ver/entpackst?

Keine Ahnung, da müsste man evtl. eigene Performance-Tests machen.

Eine gezippte 250MB Datei wurde aber mit obigem Code problemlos entpackt.
Von daher genügt es mir im moment zumindest. ;)
Antworten