Page 1 of 1

NextPackEntry() return value question

Posted: Fri Dec 09, 2022 2:22 pm
by Kukulkan
Hi. I face issues with Packer library and during some investigation I found some confusing behaviour.

The documentation for NextPackEntry() says:

Return value: Nonzero if the pack contain another entry, zero otherwise.

This also makes sense. This is how such works. So it returns 0 if no further entry exists.

But this code proofs that wrong:

Code: Select all

UseZipPacker()

infile.s = GetTemporaryDirectory()+"testfile.txt"
outfile.s = GetTemporaryDirectory()+"testfile.zip"

If OpenFile(0, infile.s)
  WriteStringN(0, "Some test content for ZIP archive test")
  CloseFile(0)
EndIf

; create a zip file
hZip = CreatePack(#PB_Any, outfile)
ret = AddPackFile(hZip, infile, GetFilePart(infile))
ClosePack(hZip)

; open the zip file
hZip = OpenPack(#PB_Any, outfile) 
If ExaminePack(hZip)
  Repeat 
    ret = NextPackEntry(hZip) ; DOCS: Returns nonzero if the pack contains another entry, zero otherwise. 
    Debug "Ret: " + str(ret) + " Name: " + PackEntryName(hZip) + ", Size: " + PackEntrySize(hZip)
  Until ret = 0
EndIf
ClosePack(hZip)

DeleteFile(infile.s)
DeleteFile(outfile.s)
Output:

Code: Select all

Ret: 1 Name: testfile.txt, Size: 40
Ret: 0 Name: , Size: 0
As you can see, NextPackEntry() returns 1 even if there is no further entry. Because of this, the second entry is output here.

I tested this on Windows 10 with PB 5.71, PB 5.73 and PB 6.00 beta6. All are affected the same way.

Is this really a bug or did I missunderstood something here?

Re: NextPackEntry() return value question

Posted: Fri Dec 09, 2022 2:33 pm
by jacdelad
I'm not good at explaining, but: your loop is doing exactly what it is meant to do.
NextPackEntry delivers <>0 if the next data for the next entry could be loaded. So it is 1 the first time it is called, because an entry was found. At the end of the loop the return value is still 1 -> goto start of loop. Catch next entry -> there is none, but the loop is still executed until it reaches its end.

The "right" way:

Code: Select all

UseZipPacker()

infile.s = GetTemporaryDirectory()+"testfile.txt"
outfile.s = GetTemporaryDirectory()+"testfile.zip"

If OpenFile(0, infile.s)
  WriteStringN(0, "Some test content for ZIP archive test")
  CloseFile(0)
EndIf

; create a zip file
hZip = CreatePack(#PB_Any, outfile)
RET = AddPackFile(hZip, infile, GetFilePart(infile))
ClosePack(hZip)

; open the zip file
hZip = OpenPack(#PB_Any, outfile) 
If ExaminePack(hZip)
  While NextPackEntry(hZip)
    Debug "Name: " + PackEntryName(hZip) + ", Size: " + PackEntrySize(hZip)
  Wend
EndIf
ClosePack(hZip)

DeleteFile(infile.s)
DeleteFile(outfile.s)
Also working, but in the way you wanted to build it (add an "If"):

Code: Select all

UseZipPacker()

infile.s = GetTemporaryDirectory()+"testfile.txt"
outfile.s = GetTemporaryDirectory()+"testfile.zip"

If OpenFile(0, infile.s)
  WriteStringN(0, "Some test content for ZIP archive test")
  CloseFile(0)
EndIf

; create a zip file
hZip = CreatePack(#PB_Any, outfile)
RET = AddPackFile(hZip, infile, GetFilePart(infile))
ClosePack(hZip)

; open the zip file
hZip = OpenPack(#PB_Any, outfile) 
If ExaminePack(hZip)
  Repeat 
    RET = NextPackEntry(hZip) ; DOCS: Returns nonzero if the pack contains another entry, zero otherwise. 
    If RET
      Debug "Ret: " + Str(RET) + " Name: " + PackEntryName(hZip) + ", Size: " + PackEntrySize(hZip)
    EndIf
  Until RET = 0
EndIf
ClosePack(hZip)

DeleteFile(infile.s)
DeleteFile(outfile.s)
It's the same way that ExamineDirectory and other Examine-commands work.

Re: NextPackEntry() return value question

Posted: Fri Dec 09, 2022 2:43 pm
by Kukulkan
Thanks, but you saying

NextPackEntry delivers <>0 if the next data for the next entry could be loaded.

But there is no next entry. Just this one (first).

And the docs are saying:

Nonzero if the pack contain another entry, zero otherwise.

I read it like "if there is 0, this is the last entry. Otherwise, there are others.". So the return value <> 0 indicates that there is another entry than the current one, which is simply wrong.

The thing is that I have such code:

Code: Select all

If ExaminePack(hZip)
  If NextPackEntry(hZip)
    Debug "Name: " + PackEntryName(hZip) + ", Size: " + PackEntrySize(hZip)
  EndIf
EndIf
This worked for many years now. But if the creator of the message was compiled with PB 5.73, it fails for these files as NextPackEntry() now returns 0 (like in the docs) and the first entry is not read. This is how I found that.

Re: NextPackEntry() return value question

Posted: Fri Dec 09, 2022 2:53 pm
by jacdelad
The first time, after the Repeat, the first entry is loaed by calling NextPackEntry. Now you can use PackEntryName, PackEntrySize etc. on it.
Then you reach the bottom of your Repeat-loop. RET is still 1, the loop is called once more.
The next time it's called, it delivers 0, because there are no more entries. PackEntryXXX delivers garbage, because no entry is loaded.
-> The loop is executed twice, but just one entry is in the zip. If you have a zip with 100 entries, the loop will be called 101 times. Etc.

The code above works, because NextPack Entry is called once, so the first item is loaded and can be processed.

The ANOTHER entry means another entry was loaded. Not that there are more to be loaded later.

Re: NextPackEntry() return value question

Posted: Fri Dec 09, 2022 3:05 pm
by Kukulkan
I understand what you say and I appreciate your answers and help. This is how it obviously works.

You say, a return value <> 0 means that a valid entry was selected (now available). And the reality seems to proof you.

But my point is, the docs saying something else...

Nonzero if the pack contain another entry, zero otherwise.

But there isn't another entry. Just the current one.

Re: NextPackEntry() return value question

Posted: Fri Dec 09, 2022 3:08 pm
by jacdelad
The "another entry" is becoming the current at the moment you call NextPackEntry. It's the same way NextElement works for linked lists.

Re: NextPackEntry() return value question

Posted: Fri Dec 09, 2022 4:42 pm
by mk-soft
;)

Code: Select all

While NextPackEntry(hZip)

Re: NextPackEntry() return value question

Posted: Fri Dec 09, 2022 4:46 pm
by Fred
May be the wording is not correct, but it works like all other NextXXX() commands, nonzero if there is something found, or zero if it's the end of the listing. If you have another sentence to explain it better, I will amend the doc.

Re: NextPackEntry() return value question

Posted: Fri Dec 09, 2022 5:05 pm
by Kukulkan
Hi Fred,

better to say

Returns <> 0 if there is a valid entry available. Returns 0 if you reached the end (do not call PackEntryName(), PackEntrySize(), PackEntryType() any more).

Re: NextPackEntry() return value question

Posted: Fri Dec 09, 2022 6:14 pm
by Little John
A short example code tells more than 1000 words. :D

Obviously, the key is here to use a proper While loop.