MicroPack.pbi - pack files and dirs, with filenames

Share your advanced PureBasic knowledge/code with the community.
Inf0Byt3
PureBasic Fanatic
PureBasic Fanatic
Posts: 2236
Joined: Fri Dec 09, 2005 12:15 pm
Location: Elbonia

MicroPack.pbi - pack files and dirs, with filenames

Post by Inf0Byt3 »

I needed this today for a project. Made in 30 mins (while smoking 2 cigs and drinking 1 coffee :lol: )

Code: Select all

;MicroPack.pbi
;(c) 2008 Trutia Alexandru
;PB4.20 B1
;www.bytessence.com
;
;Small include file for packing/depacking folders, recursive and with password
;The filenames are stored too, like in regular archives
;Very easy to extend
;License: Free for any use, credits appreciated but not necessary
;
;MP_PackFolder(Folder.s,Pack.s,Level) ;Pack a folder, level 0-9 (9 = best)
;MP_UnpackFolder(Pack.s,Folder.s) ;Unpack the files to a folder
;MP_GetPackFileCount(Pack.s) ;Count the files in a pack
;MP_SetPassword(Password.s) ;Set password for compression/decompression

;--------------------------------------------------

Global NewList FullPath.s()
Global NewList RelativePath.s()
Global MP_Internal_Pass.s

;Procedure MP_CRC32(fname.s)
; BufferSize = 1024000 ;1mb
; FileCRCH = ReadFile(#PB_Any,fname) 
; If IsFile(FileCRCH)
;  SizeToCheck = Lof(FileCRCH)
;  *mem = AllocateMemory(BufferSize)
;  If *mem 
;   While SizeToCheck
;    chunk = SizeToCheck
;    If chunk > BufferSize 
;     chunk = BufferSize 
;    EndIf 
;    ReadData(FileCRCH,*mem,chunk) 
;    crc = CRC32Fingerprint(*mem,chunk,crc) ; initially crc=0
;    SizeToCheck - chunk
;   Wend 
;   If *mem
;    FreeMemory(*mem)
;   EndIf
;   If IsFile(FileCRCH)
;    CloseFile(FileCRCH)
;   EndIf
;   ProcedureReturn crc
;  Else
;   ProcedureReturn -1
;  EndIf 
; Else
;  ProcedureReturn -2
; EndIf
;EndProcedure

Procedure MP_FileList(EntryPath.s,OldPath.s)
  If Right(EntryPath.s,1) <> "\"
   EntryPath + "\"
  EndIf
  UsedDirectory = ExamineDirectory(#PB_Any, EntryPath, "*.*")
  While NextDirectoryEntry(UsedDirectory)
    EntryType.l = DirectoryEntryType(UsedDirectory)
    EntryName.s = DirectoryEntryName(UsedDirectory)
    If EntryName = "." Or EntryName = ".."
     Continue
    EndIf
    If EntryType = #PB_DirectoryEntry_File
     FName.s = RemoveString(EntryPath + EntryName,OldPath)
     AddElement(FullPath())
     FullPath() = EntryPath + EntryName
     AddElement(RelativePath())
     RelativePath() = FName
    EndIf
    If EntryType = #PB_DirectoryEntry_Directory
     MP_FileList(EntryPath + EntryName,OldPath)
    EndIf
  Wend
  FinishDirectory(UsedDirectory)
  ProcedureReturn 1
EndProcedure

Procedure MP_RC4(Mem.l, memLen.l, Key.s)

 ;RC4Mem For PB by Pille, 15.07.2003
 ;Special Thanks to Rings
 ;Modded by Inf0Byte

 Dim S.w(255)
 Dim K.w(255)
  
 ;A little hack to strenghten it up a bit
 KeySha1.s = SHA1Fingerprint(@Key,Len(Key))
 For EnhanceKey = 1 To Len(Key)
  NewKey.s + Mid(Key,EnhanceKey,1) + KeySha1
 Next
 Key = NewKey

 For i = 0 To 255
  S(i) = i
 Next
 j = 1
 For i = 0 To 255
  If j > Len(key)
   j = 1
  EndIf
  K(i) = Asc(Mid(key, j, 1))
  j = j + 1
 Next i
 j = 0
 For i = 0 To 255
  j = (j + S(i) + K(i)) & 255
  temp = S(i)
  S(i) = S(j)
  S(j) = temp
 Next i
 i = 0
 j = 0
 For x = 0 To memLen-1
  i = (i + 1) & 255
  j = (j + S(i)) & 255
  temp = S(i)
  S(i) = S(j)
  S(j) = temp
  t = (S(i) + (S(j) & 255)) & 255
  Y = S(t)
  PokeB(Mem+x, PeekB(Mem+x)!Y)
 Next
 Key = ""
 
 ProcedureReturn Mem
 
EndProcedure

;--------------------------------------------------

Procedure MP_SetPassword(Password.s)

 MP_Internal_Pass.s = Password
 ProcedureReturn 1

EndProcedure

Procedure MP_PackFolder(Folder.s,Pack.s,Level)

 ClearList(FullPath())
 ClearList(RelativePath())

 If Right(folder.s,1) <> "\"
  Folder.s+"\"
 EndIf
 If MP_FileList(folder.s,folder.s) = 1
  ForEach RelativePath()
   FileTable.s + RelativePath() + #LF$
   Made + 1
  Next
  If CreatePack(pack.s)
   AddPackMemory(@FileTable,Len(Filetable),9)
   ForEach FullPath()
    If MP_Internal_Pass <> ""
     FLR = ReadFile(#PB_Any,FullPath())
     If IsFile(FLR)
      LenFile = Lof(FLR)
      *Temp = AllocateMemory(LenFile)
      ReadData(FLR,*Temp,LenFile)
      MP_RC4(*Temp,LenFile, MP_Internal_Pass)
      CloseFile(FLR)
     EndIf
     AddPackMemory(*Temp,LenFile,level)
     If *Temp
      FreeMemory(*Temp)
     EndIf
    Else
     AddPackFile(FullPath(),level)
    EndIf
   Next
   ClosePack()
   ProcedureReturn Made
  EndIf
 EndIf

 ProcedureReturn -1
 
EndProcedure

Procedure MP_UnpackFolder(Pack.s,Folder.s)

 ClearList(FullPath())
 ClearList(RelativePath())

 If Right(Folder.s,1) <> "\"
  Folder.s + "\"
 EndIf
 
 If FileSize(Folder) <> -2
  CreateDirectory(Folder)
 EndIf
 
 If OpenPack(Pack)
  *FileList = NextPackFile()
  Size = PackFileSize()
  If *FileList And Size
   DataString.s = PeekS(*FileList,Size)
   TotalFiles = CountString(DataString,#LF$)
   For SplitFiles = 1 To TotalFiles
    FName.s = StringField(DataString,SplitFiles,#LF$)
    AddElement(FullPath())
    FullPath() = Folder + FName
   Next
   ForEach FullPath()
    FolderName.s = GetPathPart(FullPath())
    If FileSize(FolderName) <> -2
     CreateDirectory(FolderName)
    EndIf
    *File = NextPackFile()
    Size = PackFileSize()
    FileOut = CreateFile(#PB_Any,FullPath())
    If IsFile(FileOut)
     If MP_Internal_Pass <> ""
      MP_RC4(*File,Size, MP_Internal_Pass)
     EndIf
     WriteData(FileOut,*File,Size)
     CloseFile(FileOut)
     Made + 1
    EndIf
   Next
  EndIf
  ClosePack()
 EndIf

 ProcedureReturn Made

EndProcedure

Procedure MP_GetPackFileCount(Pack.s)

 If OpenPack(Pack)
  *FileList = NextPackFile()
  Size = PackFileSize()
  If *FileList And Size
   DataString.s = PeekS(*FileList,Size)
   TotalFiles = CountString(DataString,#LF$)-1
  EndIf
  ClosePack()
 EndIf
 
 ProcedureReturn TotalFiles

EndProcedure

;--------------------------------------------------

;Example
;MP_SetPassword("TestPass")
MP_PackFolder("C:\Test\","C:\Test.pack",9) ;Pack all contents of "C:\MyFiles\"
;MP_SetPassword("TestPassa") ;1 letter changed and the files will be corrupted as the pass is different ;)
MP_UnpackFolder("C:\Test.pack","C:\Out\") ;And unpack the contents back to "C:\Out\" 
Enjoy!

[Edit]
Code updated to support password, but it kinda needs a crc32 check there. If I have some time i'll find a fix.
Last edited by Inf0Byt3 on Tue Jan 01, 2008 9:20 pm, edited 1 time in total.
None are more hopelessly enslaved than those who falsely believe they are free. (Goethe)
User avatar
Rook Zimbabwe
Addict
Addict
Posts: 4322
Joined: Tue Jan 02, 2007 8:16 pm
Location: Cypress TX
Contact:

Post by Rook Zimbabwe »

This is great! Now if only there was a password on the PAK process! Then it would be more than perfect... 8) 8) 8)
Binarily speaking... it takes 10 to Tango!!!

Image
http://www.bluemesapc.com/
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5494
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Post by Kwai chang caine »

Great code Inf0Byt3 8)

But be careful !!! The coffee and the cigaret smoking is bad for health :lol: :lol:

Thanks a lot
ImageThe happiness is a road...
Not a destination
User avatar
Rook Zimbabwe
Addict
Addict
Posts: 4322
Joined: Tue Jan 02, 2007 8:16 pm
Location: Cypress TX
Contact:

Post by Rook Zimbabwe »

Yes... drop me your address and I will send you some of my cigars!
Binarily speaking... it takes 10 to Tango!!!

Image
http://www.bluemesapc.com/
Inf0Byt3
PureBasic Fanatic
PureBasic Fanatic
Posts: 2236
Joined: Fri Dec 09, 2005 12:15 pm
Location: Elbonia

Post by Inf0Byt3 »

This is great! Now if only there was a password on the PAK process! Then it would be more than perfect... Cool Cool Cool
I'll see what i can do :D. It should not be <that> hard. I can make it use RC4 as it's the easyest and i'll also make some mods for buffered procedures, as if you compress a 2gb file now it will require 2gb of ram :lol: .

Catch ya in a few hours.

[Edit]
Sorry, slow typer here :).
About the cigs and stuff: Who gives a damn? I don't care, i'm set to die already. At least to die happy... Anyway, i'm 19 and i feel like 50 :shock: . Watch out, I may be in the news soon :lol: .

<the man who smoked more than he breathed>
None are more hopelessly enslaved than those who falsely believe they are free. (Goethe)
Inf0Byt3
PureBasic Fanatic
PureBasic Fanatic
Posts: 2236
Joined: Fri Dec 09, 2005 12:15 pm
Location: Elbonia

Post by Inf0Byt3 »

Back...

Well I tried to think of a solution to encrypt the files before compression but it ain't beautifull because when we use AddPackFile, the compression is "solid". PureBasic keeps track of the dictionary and the compression is very tight. In our case, the dictionary seems to be freed. This might be a bug in PB :/.

So when you want to encrypt the contents, it will affect the data inside and the packs will be bigger as the dictionary is forgotten between compression sessions.

Also, I don't recommend you to use it for files bigger than 10-20 mb, because it will hog the RAM.

The new code is in the first post :).

[Edit]

@Any expert, what's the difference between these 2 codes??

Code: Select all

     FLR = ReadFile(#PB_Any,FullPath())
     If IsFile(FLR)
      LenFile = Lof(FLR)
      *Temp = AllocateMemory(LenFile)
      ReadData(FLR,*Temp,LenFile)
      ;MP_RC4(*Temp,LenFile, MP_Internal_Pass)
      CloseFile(FLR)
     EndIf
     AddPackMemory(*Temp,LenFile,level)
     If *Temp
      FreeMemory(*Temp)
     EndIf

Code: Select all

   AddPackFile(FullPath(),level)
None are more hopelessly enslaved than those who falsely believe they are free. (Goethe)
User avatar
Rook Zimbabwe
Addict
Addict
Posts: 4322
Joined: Tue Jan 02, 2007 8:16 pm
Location: Cypress TX
Contact:

Post by Rook Zimbabwe »

Well...

The first code is 12 lines long and the second seems to be 1 line...

Last I checked... that is a diffrence of 11 lines. :D Glad I could help!

Seriously I hope this is easy to implement. Maybe just add a space at front or back of PAK for password and encrypt ONLY the password based on the password (Is that clear?)

I used to use PKPAK in Blitz to make my time limited software work or mnot work and handle registration.
Binarily speaking... it takes 10 to Tango!!!

Image
http://www.bluemesapc.com/
Inf0Byt3
PureBasic Fanatic
PureBasic Fanatic
Posts: 2236
Joined: Fri Dec 09, 2005 12:15 pm
Location: Elbonia

Post by Inf0Byt3 »

Seriously I hope this is easy to implement. Maybe just add a space at front or back of PAK for password and encrypt ONLY the password based on the password (Is that clear?)
Yup. Thought or that, to store the password's hash somewhere in the file, but that ain't secure, since anybody can make another program in pb and simply unpack the files. I could make something secure if there was lower level access to the buffers.

I'll come up with something.
None are more hopelessly enslaved than those who falsely believe they are free. (Goethe)
yrreti
Enthusiast
Enthusiast
Posts: 546
Joined: Tue Oct 31, 2006 4:34 am

Post by yrreti »

Inf0Byt3
I'm hanging on the line.

Code: Select all

 KeySha1.s = SHA1Fingerprint(@Key,Len(Key))
SHA1Fingerprint() is not a function, array, macro or linked list
Am I missing a library?
Thanks for your input.
Inf0Byt3
PureBasic Fanatic
PureBasic Fanatic
Posts: 2236
Joined: Fri Dec 09, 2005 12:15 pm
Location: Elbonia

Post by Inf0Byt3 »

Oh, just replace it with MD5Fingerprint(). SHA1 is available in the PB beta (v4.20).
None are more hopelessly enslaved than those who falsely believe they are free. (Goethe)
yrreti
Enthusiast
Enthusiast
Posts: 546
Joined: Tue Oct 31, 2006 4:34 am

Post by yrreti »

Thank you Inf0Byt3
It works fine now. :D
eJan
Enthusiast
Enthusiast
Posts: 366
Joined: Sun May 21, 2006 11:22 pm
Location: Sankt Veit am Flaum

Post by eJan »

Thanks Inf0Byt3!
I have tried with: 'C:\Program Files\Ace Utilities' - which contains 7 folders and 266 files, output have: 3 folders and 233 files.
PB 4.10.
Inf0Byt3
PureBasic Fanatic
PureBasic Fanatic
Posts: 2236
Joined: Fri Dec 09, 2005 12:15 pm
Location: Elbonia

Post by Inf0Byt3 »

Hmmm that's strange. It works here :/. 843 files and 12 folders, all out. But I think I know why. Notice that some files that are in use/hidden cannot be accessed and also, my code doesn't include empty folders and files. I'm sure that's why it failed to include all the stuff in the folder.

As I said it can be extended and improved, i just needed something quick.
None are more hopelessly enslaved than those who falsely believe they are free. (Goethe)
User avatar
Joakim Christiansen
Addict
Addict
Posts: 2452
Joined: Wed Dec 22, 2004 4:12 pm
Location: Norway
Contact:

Post by Joakim Christiansen »

Inf0Byt3 wrote:Anyway, I'm 19 and I feel like 50 :shock:
You and me both man! :wink:

Great code btw! :D
I like logic, hence I dislike humans but love computers.
Inf0Byt3
PureBasic Fanatic
PureBasic Fanatic
Posts: 2236
Joined: Fri Dec 09, 2005 12:15 pm
Location: Elbonia

Post by Inf0Byt3 »

You and me both man! Wink
Yup, there's something wrong. At least here, i expect to grow some wings, a few legs and a couple of fingers from the pollution.
Great code btw! Very Happy
Thank you!
None are more hopelessly enslaved than those who falsely believe they are free. (Goethe)
Post Reply