Open WGZero05 opened 2 years ago
do you want to alter file names in zipfiles or do you just want to "override" while extracting?
the first is doable with tools like zipnote
or zip_rename
but is not necessarily possible with normal libraries/tools without extracting and archiving again.
If filenames were the same length then you could simply "replace" the strings ("AAA.mp3" with "BBB.mp3") in the zip file .. but this is very hackish.
With "SetPathname()" you might be able to do that here (renaming while extracting). will try and report back.
Edit: so if you just want to do while "extracting":
While ra.ReadNextHeader(entry) = ARCHIVE_OK
Select entry.Pathname().Tolower()
case "files/old_name.bmx"
entry.SetPathname("files/new_name.bmx")
End Select
Is it possible to rename the files that are already inside of my zip file?
No. It doesn't work like that, I'm afraid. There is one flow for reading, and one flow for writing. It isn't designed for random access/updates of archive content.
I am already trying out to createWrong
OpenWrong OpenNew IterateOverWrong WriteNew(corrected)
CloseFiles
For now archive.mod/core.mod does not contain functionality to read creation/modification time of an entry (archive_entry_mtime
is not exposed).
Edit: same for filetype ... you can set it but not read it.
SuperStrict
Framework Archive.Zip
Import brl.standardio
'STEP 1: create "archive_rename_wrong.zip"
Local wa:TWriteArchive = New TWriteArchive
wa.SetFormat(EArchiveFormat.ZIP)
wa.Open("archive_rename_wrong.zip")
wa.AddEntry("archive_rename.bmx", "files/archive_rename_wrong_name.bmx")
wa.Close()
' file written now
'STEP 2: open it for reading
Local entry:TArchiveEntry = New TArchiveEntry
Local ra:TReadArchive = New TReadArchive
ra.SetFormat(EArchiveFormat.ZIP)
ra.Open("archive_rename_wrong.zip")
'STEP 3: create the new ("corrected") file
Local ca:TWriteArchive = New TWriteArchive
ca.SetFormat(EArchiveFormat.ZIP)
ca.Open("archive_rename_corrected.zip")
'STEP 4: read files from "wrong" archive - and save them in the "corrected"
' but with adjusted file names
While ra.ReadNextHeader(entry) = ARCHIVE_OK
Print "File : " + entry.Pathname()
Print "Size : " + entry.Size()
'correct names if needed
Select entry.Pathname().Tolower()
case "files/archive_rename_wrong_name.bmx"
entry.SetPathname("files/archive_rename.bmx")
End Select
'write into corrected archive
Local fTime:Long = 0 'entry.FTime())
Local fType:EArchiveFileType = EArchiveFileType.FILE 'entry.FType()
ca.AddEntry(ra.DataStream(), entry.Pathname(), entry.Size(), fTime, fType)
print " -> wrote file ~q" + entry.Pathname() + "~q into new archive"
Wend
'STEP 5: Close/free "wrong" file and also set "corrected" as done
ra.Free()
ca.Close()
print "done."
This file streams the "wrong" archive and corrects the name - and finally adds the extracted archive content into the new one. So it "recompresses" not just renames.
Afterwards you could remove the old archive and rename the new one. To manipulate the zip files without recompress you might use one of the tools above.
Another option also requires the help of @woollybah
you should be able to iterate over the entries in an archive .. and to set new names for them.
Once done, you should be able to write the new header into the file and done.
archive_entry_set_pathname
to set the name of the currently iterated entry
archive_write_header
to write the new information
hmm .... nah, seems it is not as easy to just manipulate the archive "header" (they only have entry-headers). So best thing is to use an approach like above (read file 1 + save file 2). Brucey might need to add FTime(), MTime() and FType() getters so you can recreate the entries accordingly
@GWRon That makes it more complicated but still thanks for the idea. I can wait for all the new features of this module. Still waiting for the Extractzipfile function, and more. I just wanna thank you so much Mr.WollyBah for this effort. I wanna learn more from him. God Bless you, Mr.Brucey. ππ»
Please provide a sample source file so we see what you are doing.
Also keep in mind that you can password secure the content...without password protecting the file list (you can look into zip files and list contained files...but extracting the files to see their content requires the password)
the issue is the aes256 ...
wa.SetFormatOption("encryption", "zipcrypt")
and it asks for a password
while this:
wa.SetFormatOption("encryption", "aes256") ' or zipcrypt,
print wa.ErrorString()
results in:
encryption not supported
C code looks like this:
} else if (strcmp(key, "encryption") == 0) {
if (val == NULL) {
zip->encryption_type = ENCRYPTION_NONE;
ret = ARCHIVE_OK;
} else if (val[0] == '1' || strcmp(val, "traditional") == 0
|| strcmp(val, "zipcrypt") == 0
|| strcmp(val, "ZipCrypt") == 0) {
if (is_traditional_pkware_encryption_supported()) {
zip->encryption_type = ENCRYPTION_TRADITIONAL;
ret = ARCHIVE_OK;
} else {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_MISC,
"encryption not supported");
}
} else if (strcmp(val, "aes128") == 0) {
if (is_winzip_aes_encryption_supported(
ENCRYPTION_WINZIP_AES128)) {
zip->encryption_type = ENCRYPTION_WINZIP_AES128;
ret = ARCHIVE_OK;
} else {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_MISC,
"encryption not supported");
}
} else if (strcmp(val, "aes256") == 0) {
if (is_winzip_aes_encryption_supported(
ENCRYPTION_WINZIP_AES256)) {
zip->encryption_type = ENCRYPTION_WINZIP_AES256;
ret = ARCHIVE_OK;
} else {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_MISC,
"encryption not supported");
So I made this here:
Local wa:TWriteArchive = New TWriteArchive
wa.SetFormat(EArchiveFormat.ZIP)
wa.SetFormatOption("encryption", "zipcrypt") ' or zipcrypt,
print wa.Errno() + ": " + wa.ErrorString()
wa.ClearError()
wa.SetFormatOption("encryption", "aes128") ' or zipcrypt,
print wa.Errno() + ": " + wa.ErrorString()
wa.ClearError()
wa.SetFormatOption("encryption", "aes256") ' or zipcrypt,
print wa.Errno() + ": " + wa.ErrorString()
wa.ClearError()
wa.SetPassphrase("abc123")
which on my LINUX computer outputs:
0:
-1: encryption not supported
-1: encryption not supported
Might be related to: https://github.com/libarchive/libarchive/issues/1607
entry.IsEncrypted() entry.IsMetadataEncrypted() entry.IsDataEncrypted()
for the archive itself: ra.HasEncryptedEntries()
Edit: Seems you cannot "open" before setting the passphrase ... so to identify if it needs a password you open it without password, then check HasEncryptedEntries() ... then close/free the archive again ... create it anew, set the password and open. Sounds rather...complicated.
Local ra:TReadArchive = New TReadArchive
ra.SetFormat(EArchiveFormat.ZIP)
ra.Open("data.zip")
if ra.HasEncryptedEntries()
ra.free()
print "has password protection ... asking for password"
'bla bla handling password request
'password = abc123
ra = new TReadArchive
ra.SetFormat(EArchiveFormat.ZIP)
ra.SetPassphrase("abc123")
ra.Open("data.zip")
endif
Think the corresponding functionality is not yet exposed directly... but I assume you set it via the format options:
wa.SetFormatOption("compression-level", "9")
https://www.mankier.com/3/archive_write_set_options#compression-level
if you would have tried it ... you would have recognized that it seems to work :)
archive size is bigger with "0" than with "9" ... so seems to do what it should
Regarding identifying zip files... the library offers: https://manpages.debian.org/testing/libarchive-dev/archive_read_add_passphrase.3.en.html
archive_read_add_passphrase() Register passphrases for reading an encryption archive. If passphrase is NULL or empty, this function will do nothing and ARCHIVE_FAILED will be returned. Otherwise, ARCHIVE_OK will be returned.
archive_read_set_passphrase_callback() Register a callback function that will be invoked to get a passphrase for decryption after trying all the passphrases registered by the archive_read_add_passphrase() function failed.
Dunno if one could add "empty" as password ... and in case it is failed, the callback would be executed ... the callback could ask for the password then.
The important thing to REMEMBER: "readArchive.SetPassphrase()" does not set a single password to use! ... it adds a password the archive tries out
ra.SetPassphrase("abc1231234546464656")
ra.SetPassphrase("abc123")
will add BOTH passwords -- and while the first fails the second succeeds. If it failed too, then above callback (if registered) would be called.
What about the Append? What if I'm going to open the zip file and add more files to the already existing zip file? How can I do add more files to my zip?
@Yushkun24 All I can do is to wait patiently for Mr.Brucey for the Doc examples and functions. So be patient and wait, buddy. :)
what is wrong with opening multiple issues ? what is wrong with pasting code here (in wrapped in 3 backticks ... ```code```) - better this than having people to write code from your snapshot
what about reading "line 10" and thinking about it ... zip zip rar zip zip ? :-)
Exactly... there is no .rar support in archive.mod yet
Hello Sir.Brucey. Can you please fix this wa.AddEntry("ν
μ€νΈ_λ°μ΄ν°.txt", "files/ν
μ€νΈ_λ°μ΄ν°.txt")
How could I extract a file when the entry.Pathname()
is empty? Wtf! π It is so strange how the mod can compress the name but it can't extract the name again. π
And also how could I get out or leave without terminating my code in Blitzmax when I'm using SetPassphraseCallback
? It keeps repeating again and again. π©
I now wanted to try out if you could "remove" the callback from the archive inside the callback (so it wont be called again) but ...
... simply running "example_03" does not ask me for a password :)
$ ./example_03
File : files/testdata.txt
Size : 67
String size : 67
First n chars : This is some data
File : files/ν
μ€νΈ_λ°μ΄ν°.txt
Size : 67
String size : 67
First n chars : This is some data
Needed to move encryption to "zip" not "aes" ...
I tried this here:
Function GetPass:String(archive:TReadArchive, data:Object)
Global IGotAskedTimes:Int
'remove this callback
If IGotAskedTimes = 2 Then archive.SetPassphraseCallback(Null, Null)
Local pass:String
If IGotAskedTimes = 0
pass = Input("Enter Password (abc123): ")
Else
pass = Input("Enter Password (abc123) attempt #" + (IGotAskedTimes + 1)+": ")
EndIf
IGotAskedTimes :+ 1
Return pass
End Function
but it seems it did not handle it as I wanted:
$ ./example_03
File : files/testdata.txt
Size : 67
Enter Password (abc123): hello
Enter Password (abc123) attempt #2: on
Enter Password (abc123) attempt #3: earth
Attempt to call uninitialized function pointer
Did not see a API function to remove that callback ... Also I do not see a way to abort the "open" action there. So Brucey might need to add a way to "null" the callback -- means you could set it inside your callback to "give up"
archive_read_add_passphrase.c:
int
archive_read_set_passphrase_callback(struct archive *_a, void *client_data,
archive_passphrase_callback *cb)
{
struct archive_read *a = (struct archive_read *)_a;
archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,
"archive_read_set_passphrase_callback");
a->passphrases.callback = cb;
a->passphrases.client_data = client_data;
return (ARCHIVE_OK);
}
....
/*
* Get a passphrase for decryption.
*/
const char *
__archive_read_next_passphrase(struct archive_read *a)
{
...
else if (a->passphrases.callback != NULL) {
/* Get a passphrase through a call-back function
* since we tried all passphrases out or we don't
* have it. */
I now wanted to try out if you could "remove" the callback from the archive inside the callback (so it wont be called again) but ...
... simply running "example_03" does not ask me for a password :)
$ ./example_03 File : files/testdata.txt Size : 67 String size : 67 First n chars : This is some data File : files/ν μ€νΈ_λ°μ΄ν°.txt Size : 67 String size : 67 First n chars : This is some data
Needed to move encryption to "zip" not "aes" ...
@GWRon How you did it? I still can't figure it out. I've been so stressed Haha.
?? as said ... I tried to remove the callback. Raised an issue for it (as you need - for now - to check a field <> Null inside the callback function)
While this removes the callback it then will continue processing (and is not able to iterate over the files because of the missing password). So it requires a way to "identify" if a password was required - and the right one was passed in.
@GWRon I did not use the Callback function and my zip is not encrypted either.
Can you show me how could you revealed the Korean words? files/ν
μ€νΈ_λ°μ΄ν°.txt
utf8 aware console ... dunno if maxide does it on windows.
I used Geany to edit the files and my simple compile-it-plugin to execute bmk with the appropriate commands.
If you "read" the filename it will be correct but once you write it to display it to you ... it might look "wrong". You could save the filename to a file (writestream("utf8::myfile.txt") and compare the content then.
Thank you for the update of RAR, Mr.WoollyBah. By the way... Why can't I create a rar file? It terminated my code without warning. What did I miss?
Rar support is read-only, I'm afraid, since that's what comes with the library we are using for all of this.
I assume rar write support is missing because of the licence for rar encoders/"archivers".
Simply use 7z...it is good enough as all purpose archiver
Sir.Brucey can you please help me how to get the string or the title of files from my zip file?
Some of my Korean mp3 songs from zip are not visible when I'm going to read the archive. The names are not visible. entry.pathname()
. Can you please fix this issue. Thank you. ππ»
And how could i know when the data inside zip is a file or folder? Is there any way how to get the filetype inside of zip? for example:
SuperStrict
Framework Archive.Zip
Import brl.standardio
Local wa:TWriteArchive = New TWriteArchive
wa.SetFormat(EArchiveFormat.ZIP)
wa.SetCompressionLevel(9)
wa.Open("data.zip")
wa.AddEntry("testdata.txt", "files/testdata.txt")
wa.AddEntry("ν
μ€νΈ_λ°μ΄ν°.txt", "files/ν
μ€νΈ_λ°μ΄ν°.txt")
wa.AddEntry("", "empty", 0, 0, EArchiveFileType.Dir)
wa.Close()
Local entry:TArchiveEntry = New TArchiveEntry
Local ra:TReadArchive = New TReadArchive
ra.SetFormat(EArchiveFormat.ZIP)
ra.Open("data.zip")
While ra.ReadNextHeader(entry) = ARCHIVE_OK
If Filetype (entry.Pathname())=1
print "This is a file: "+entry.Pathname() 'output: files/testdata.txt
else
print "Folder: "+entry.Pathname() 'output: empty
endif
Wend
ra.Free()
Can you give some filenames which do not work for you? Paste them as text here ..or better: write a .bmx sample file, zip it (manually ;-)) and attach it to your post here. That way we see the actual encoding you use ...and this might help brucey to replicate an issue (or to check if it must fail elsewhere)
SuperStrict
Framework Archive.Zip
Import brl.standardio
Local entry:TArchiveEntry = New TArchiveEntry
Local ra:TReadArchive = New TReadArchive
ra.SetFormat(EArchiveFormat.ZIP)
ra.Open("SampleMusic.zip")
While ra.ReadNextHeader(entry) = ARCHIVE_OK
print entry.Pathname()
Wend
ra.Free()
output:
./bmk makeapp -g x64 -t console -quick -r -x "/home/ronny/Arbeit/Projekte/Testcodes/archive_test/MyData/reader.bmx" (im Verzeichnis: /home/ronny/Arbeit/Tools/BlitzMaxNG/bin)
[ 88%] Processing:reader.bmx
[ 94%] Compiling:reader.bmx.console.release.linux.x64.c
[100%] Linking:reader
Executing:reader
( Code Geass ) ORANGE RANGE - Shiawase Neiro.mp3
04 Who Am I.mp3
05. WAITING FOR YOUR LOVE - STEVIE B.mp3
SHINee μ€μ΄λ_Sherlockβ’μ
λ‘ (Clue Note)_Music Video.mp3
and after adjusting 2 lines of code ("playMusic" is not defined in your app - commented it out)
maxgui adjustment:
Function CreateCanvas:TGadget( x,y,w,h,group:TGadget,style=0 )
Local t:TGadget=maxgui_driver.CreateGadget(GADGET_CANVAS,"",x,y,w,h,GetGroup(group),style)
t.AttachGraphics int(DefaultGraphicsFlags()) 'gfxFlags '<----------- default is long, attach wants int
Return t
End Function
@GWRon Well, this is my output. The Korean song was not added. Both in my Win7 and Win10. The result is still the same. The entry.Pathname()
is empty.
Can you please try my code on your Windows and not on Linux?
@woollybah Thank you Sir.Brucey for adding FileType()!. Can I use that method in all formats you created? Like Opening the .7z, .gz, etc.. ?
Can you try to append this: Len(entry.pathname()) Or use it instead of the path name when adding the gadgetitem?
If the len is 0..then indeed it had issues to read in the filename. If the len is a two digit number (am not using on my computer) then it just has an issue displaying/adding it to the gui.
You can also print when adding an entry... But always prepend something as "print" ignores empty lines (you do not get a simple new line).
Ok... who deleted my comment? I can't see my comment!
Can you see my comment with the photo? I can't see it!
I can see it..i even received it twice via notification mail.
The screenshot shows that it had indeed issues to decode the name correct... Now this will be something for Brucey to hopefully fiddle out.
It works on linux but seems not on (his) windows.
I can see it..i even received it twice via notification mail.
The screenshot shows that it had indeed issues to decode the name correct... Now this will be something for Brucey to hopefully fiddle out.
It works on linux but seems not on (his) windows.
I Hope Sir.brucey will fix this soon! ππ»
Hello Sir.Brucey. I'm still waiting you to show me how to add files to already existing archive. Please provide examples. π Thanks!
Think I have shown a way - and with the newly added method for archiveEntry objects it should be working.
There might be another approach but I am not sure if it works for all archive types - which might explain, why it is not existing as "convenient function":
Hello Sir.Brucey. Can you not use the 7-zip module? ( https://www.7-zip.org/ ) I found out that some paid softwares are using the module of 7-zip app bcoz the app is freeware. And they are also using all the commands from 7-zip Application. Can you not do cross the module of 7-zip with your archive.mod?
You can simply use TProcess to execute the 7z.exe with the params you need.
That shit idea is not what i want. What i want is how can I get all the names with Korean/Chinese language of the files from my zip file so that i could add them to AddGadgetItem (). Brucey Archive module is not satisfying and doesn't make me happy to use it anymore.
Is it possible to rename the files that are already inside of my zip file?
Example:
Local entry:TArchiveEntry = New TArchiveEntry
Local ra:TReadArchive = New TReadArchive ra.SetFormat(EArchiveFormat.ZIP) ra.SetPassphrase("abc123")
ra.Open("data.zip")
While ra.ReadNextHeader(entry) = ARCHIVE_OK
Wend
ra.Free()