Purebasics Integration ZIP Question (UncompressFile is -1)

Just starting out? Need help? Post your questions and find answers here.
Marty2PB
User
User
Posts: 47
Joined: Thu Mar 13, 2014 4:31 pm

Purebasics Integration ZIP Question (UncompressFile is -1)

Post by Marty2PB »

I just working on a Archiv Converter Source (conv. to 7z) and I have a severals zip files from djgpp Repository that can't unpack with Uncompressfile and integrated ZIP support :shock:

But no Errors with 7z tool.

Image

Files are here: https://mirrors.fe.up.pt/pub/djgpp/current/v2/

Code: Select all

UseZipPacker()

; Open the packed file
If OpenPack(0, "b:\testpack\frfaq21b.zip") 
	
	; List all the entries
	If ExaminePack(0)
		While NextPackEntry(0)
			Debug "Name: " + PackEntryName(0) + ", Size Uncompress: " + PackEntrySize(0, #PB_Packer_UncompressedSize) + " -:- Size compress: " + PackEntrySize(0, #PB_Packer_CompressedSize )
			szPackEntryname.s =  "B:\testpack\"+PackEntryName(0)
			
			ReplaceString( szPackEntryname, "/","\",#PB_String_InPlace)
			
;			If UncompressPackFile( 0, "B:\testpack\"+szPackEntryname) = -1 # FALSE

                        If UncompressPackFile( 0, szPackEntryname) = -1
				Debug "-1 : Cant DeCompress = " + szPackEntryname + #CRLF$
			EndIf	
		Wend
	EndIf
	
	ClosePack(0)
EndIf
Does this have anything to do with "Implode: v.xx", "Deflate"?

it is possible to check which zip version it is?

PS: B:\ is a small SDD Drive for Temps

greetings
Last edited by Marty2PB on Thu Feb 23, 2023 6:39 am, edited 1 time in total.
User avatar
yuki
Enthusiast
Enthusiast
Posts: 101
Joined: Sat Mar 31, 2018 9:09 pm

Re: Purebasics Integration ZIP Question (UncompressFile is -1)

Post by yuki »

Take care in the output filename argument you're using:

Code: Select all

			szPackEntryname.s =  "B:\testpack\"+PackEntryName(0)
			
			ReplaceString( szPackEntryname, "/","\",#PB_String_InPlace)
			If UncompressPackFile( 0, "B:\testpack\"+szPackEntryname) = -1
  1. szPackEntryname.s is initialised to "B:\testpack\"+PackEntryName(0), e.g. "B:\testpack\FRFAQ\LISEZMOI.FAQ"
  2. szPackEntryname.s has "/" replaced with "\" for Windows-path normalisation (unnecessary)
  3. you build an output path of "B:\testpack\"+szPackEntryname
  4. expanded, output path becomes: "B:\testpack\"+"B:\testpack\FRFAQ\LISEZMOI.FAQ"
  5. the resulting path is thus invalid (see two drive "B:\" prefixes): "B:\testpack\B:\testpack\FRFAQ\LISEZMOI.FAQ"
Marty2PB
User
User
Posts: 47
Joined: Thu Mar 13, 2014 4:31 pm

Re: Purebasics Integration ZIP Question (UncompressFile is -1)

Post by Marty2PB »

Yeah .. damned .. .... This was false in the Test. You right.

Code: Select all

If UncompressPackFile( 0, szPackEntryname) = -1
However it cant no uncompress. Other Zips worked fine but then exitsts Zips there cant uncompress. Can you Decompress the frfaq21b.zip with Purebasic. i use 5.73 LTS or PB 6.00 LTS?
User avatar
yuki
Enthusiast
Enthusiast
Posts: 101
Joined: Sat Mar 31, 2018 9:09 pm

Re: Purebasics Integration ZIP Question (UncompressFile is -1)

Post by yuki »

Hmm, I tested that archive with 6.01b4 and you're right: it doesn't seem to decompress properly.

This might warrant a bug report. I wonder if it's the implode method that PB's packer is struggling with, or another characteristic of this archive (it's from '96, quite early days of ZIP!).

I did make additional adjustments to your code, since there was another issue which will prevent unpacking even given valid archives. The output directory for UncompressPackFile(...) must always exist, otherwise it will fail to produce output.

For example, if decompressing a file to "B:/testpack/FRFAQ/LISEZMOI.FAQ", you have to ensure the folder "B:/testpack/FRFAQ/" exists first. You can feel free to use my EnsureDirectoryExistsDeep(...) for that purpose (or peek the forum for alternatives, though some others at least are known not to function with UNC paths).

Code: Select all

EnableExplicit

UseZipPacker()

; Output directory path where files should be unpacked to.
#OUT_DIRECTORY_PATH = "B:/testpack/"
; Archive which all files should be extracted from (to above output directory).
#IN_PACK_FILE_PATH = "B:/testpack/frfaq21b.zip"

;; Ensures that a directory matching the given path exists, creating it if necessary,
;; along with any parent directories.
;;
;; @param directoryPath Path of the directory to be created.
;;
;; @returns Returns #True if the desired directory already existed or was created without
;; issue. Otherwise returns #False.
Procedure.i EnsureDirectoryExistsDeep(directoryPath.s)
  ; Cached length of the input directory path.
  Protected directoryPathLength.i = Len(directoryPath)
  ; Current directory path constructed iteratively from amongst the given one, as the path
  ; tree is checked on the filesystem.
  Protected currentPath.s
  ; Current directory path segment being examined before appending to the total path.
  Protected currentPathSegment.s
  ; Index of the most recent delimiter character encountered.
  Protected currentSeparatorIndex.i
  ; Index of the prior delimiter character encountered, just before currentSeparatorIndex.
  Protected priorSeparatorIndex.i
  
  ; Normalise slashes to platform-respective form. This generally doesn't make a difference
  ; and Windows can usually handle both "/" and "\" just fine. It is, however, of critical
  ; importance when given UNC paths.
  CompilerIf #PB_Compiler_OS = #PB_OS_Windows
    Protected pathSeparator.s = "\"
    Protected charAtPos3.s = Mid(directoryPath, 3, 1)
    ; Handle UNC paths by skipping the first apparent slashes from normal directory-test logic.
    If directoryPathLength > 3 And Left(directoryPath, 2) = "\\" And charAtPos3 <> "\" And charAtPos3 <> "/"
      If charAtPos3 = "." Or charAtPos3 = "?" And Mid(directoryPath, 4, 1) = "\"
        currentPath = "\\" + charAtPos3 + "\"
        currentSeparatorIndex = 4
      Else
        currentPath = "\\"
        currentSeparatorIndex = 2
      EndIf
    EndIf
    directoryPath = ReplaceString(directoryPath, "/", "\")
  CompilerElse
    Protected pathSeparator.s = "/"
    directoryPath = ReplaceString(directoryPath, "\", "/")
  CompilerEndIf
  
  Repeat
    priorSeparatorIndex = currentSeparatorIndex
    currentSeparatorIndex = FindString(directoryPath, pathSeparator, priorSeparatorIndex + 1)
    
    If currentSeparatorIndex
      currentPathSegment = Mid(directoryPath, priorSeparatorIndex + 1, currentSeparatorIndex - priorSeparatorIndex)
    ElseIf priorSeparatorIndex < directoryPathLength
      currentPathSegment = Mid(directoryPath, priorSeparatorIndex + 1, directoryPathLength - priorSeparatorIndex) + pathSeparator
    Else
      currentPathSegment = ""
    EndIf
    
    If currentPathSegment And currentPathSegment <> pathSeparator
      currentPath + currentPathSegment
      ; If the current path doesn't already exist as a folder AND we've failed to create it, exit
      ; with fail state.
      If FileSize(currentPath) <> -2 And Not CreateDirectory(currentPath)
        ; Perform one last check just in case we've a networked path which fails the test
        ; using `FileSize()` but passes with `ExamineDirectory()`.
        ; This prevents issues given networked paths on Windows at least.
        Protected maybeDirectory.i = ExamineDirectory(#PB_Any, currentPath, "*.nil")
        If Not maybeDirectory
          ProcedureReturn #False
        Else
          FinishDirectory(maybeDirectory)
        EndIf
      EndIf
    EndIf
  Until Not currentSeparatorIndex
  
  ProcedureReturn #True
EndProcedure

; Begin main.
; ---------------------------------------------------------

Define targetPack.i = OpenPack(#PB_Any, #IN_PACK_FILE_PATH)
If Not targetPack
  DebuggerError("Failed to open desired pack file: " + #IN_PACK_FILE_PATH)
  End
EndIf

If Not ExaminePack(targetPack)
  DebuggerError("Failed to examine loaded pack file: " + #IN_PACK_FILE_PATH)
  Goto cleanup
EndIf

While NextPackEntry(targetPack)
  Define currentEntryName.s = PackEntryName(targetPack)
  Debug " - " + currentEntryName
  Debug "   + Original size:   " + PackEntrySize(targetPack, #PB_Packer_UncompressedSize)
  Debug "   + Compressed size: " + PackEntrySize(targetPack, #PB_Packer_CompressedSize)
  Debug ""
  
  ; Build the output path.
  Define currentEntryLocalPath.s = #OUT_DIRECTORY_PATH + currentEntryName
  
  ; Ensure the directory the file is being decompressed to exists beforehand.
  If Not EnsureDirectoryExistsDeep(GetPathPart(currentEntryLocalPath))
    DebuggerError("Failed to ensure local directory path for file: " + currentEntryLocalPath)
    Goto cleanup
  EndIf
  
  ; Finally, try and uncompress to the desired output path.
  If UncompressPackFile(targetPack, currentEntryLocalPath) = -1
    DebuggerError("Failed to extract pack file '" + currentEntryName + "' to local path: " + currentEntryLocalPath)
    Goto cleanup
  EndIf
Wend

cleanup:
ClosePack(targetPack)
User avatar
yuki
Enthusiast
Enthusiast
Posts: 101
Joined: Sat Mar 31, 2018 9:09 pm

Re: Purebasics Integration ZIP Question (UncompressFile is -1)

Post by yuki »

Just took a quick look through libzip which UseZipPacker() entails. It seems like they define PKWARE DCL imploding as well as ordinary implode here, though these aren't referenced elsewhere; and so it seems there doesn't exist decompression support for these methods.

Since it seems like this is by design of libzip, a bug report might not be appropriate (but instead a feature request). Imploding is very much a legacy method, so it might be a little hard to justify outside specialist cases (though completionism is always nice, realism bites).

It might be quite handy to have the available ZIP compression methods indicated in the PB docs.
Marty2PB
User
User
Posts: 47
Joined: Thu Mar 13, 2014 4:31 pm

Re: Purebasics Integration ZIP Question (UncompressFile is -1)

Post by Marty2PB »

Yes. That's a good find. Many thanks for your feedback.

Besides reporting this as a feature, is there any way to intercept this decompression method in PB?

It would be a good tip for the Purebasic doc to include the methods. Otherwise you spend hours why the "uncompressfile" command always brings -1.

What would be great, of course, to query the compression method/procedure for the current file.

The reason I use these files from the early days is because I compile the Doom port legacy with djgpp under Dosbox.



ImageOtherwise it works great. to compress everything (ZIP (also game archive PK3,Pk4,TSu etc... ), Rar, Amiga LZX etc... ) to 7z

greetings
User avatar
yuki
Enthusiast
Enthusiast
Posts: 101
Joined: Sat Mar 31, 2018 9:09 pm

Re: Purebasics Integration ZIP Question (UncompressFile is -1)

Post by yuki »

Marty2PB wrote: Thu Feb 23, 2023 10:47 am Besides reporting this as a feature, is there any way to intercept this decompression method in PB?
I don’t believe it’d be easy. You’d have to patch libzip and then either link it directly or figure out a way to patch the PB packer library based upon that.

One could always write a ZIP unpacker in PB with support for implode, or alternatively pull in other libraries which support it. 7z.dll might be the simplest while remaining free (though requiring attribution).
infratec
Always Here
Always Here
Posts: 7665
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: Purebasics Integration ZIP Question (UncompressFile is -1)

Post by infratec »

The old algorithms are now public domain.

Here are some links with explanations and also complete sourcecode (in C):

https://www.hanshq.net/zip2.html
https://github.com/jsummers/oldunzip
Post Reply