Hello qubodup,
qubodup {l Wrote}:Care to share how? (Just a link to the code file in the online-readable repo would be enough if available)
Of course, I'll try my best explaining it. (Here's the source:
Addons.cpp)
To make use of libarchive we need to include these two header files:
- {l Code}: {l Select All Code}
#include <archive.h>
#include <archive_entry.h>
Now the actual coding starts.
We create two archives, one for the file we want to extract and the for the destination we want to extract to.
Note that the name archive doesn't mean it is an archive, it can also be to disk.
- {l Code}: {l Select All Code}
archive *file;
archive *dest;
Since an archive can be multiple things we need to define them:
- {l Code}: {l Select All Code}
//This will be the archive we want to extract, so we make it a archive_[b]read[/b]_new();
file = archive_read_new();
//This will be the destination, so we make it a archive_[b]write_disk[/b]_new();
//If we leave out [b]_disk[/b] it will save write the files into another archive.
dest = archive_write_disk_new();
archive_write_disk_set_options(dest, ARCHIVE_EXTRACT_TIME);
archive_read_support_format_zip(file); //We configure which archive files are supported.
Now comes the actual reading.
ProcessFileName is a method in meandmyshadow which translates some strings like %DATA%/themes/... to ./themes/.
- {l Code}: {l Select All Code}
//Now read the archive.
if(archive_read_open_file(file, ProcessFileName(path).c_str(), 10240)) {
cerr<<"Error while reading archive "+path<<endl;
}
After opening the file we loop it's entries and write them to
dest.
First we try to read the
next header(files in the archive).
Then we check if there was an error or we reached the end of the file.
- {l Code}: {l Select All Code}
//Now write every entry to disk.
int status;
archive_entry *entry;
while(true) {
status=archive_read_next_header(file,&entry);
if(status==ARCHIVE_EOF){
break;
}
if(status!=ARCHIVE_OK){
cerr<<"Error while reading archive "+path<<endl;
}
That's the reading of the archive entries, now follows the writing.
First we override the pathname of the entry, this way we can write them to a file/location we want.
Again some checking if everything went ok.
- {l Code}: {l Select All Code}
archive_entry_set_pathname(entry,(ProcessFileName(destination) + archive_entry_pathname(entry)).c_str());
status=archive_write_header(dest,entry);
if(status!=ARCHIVE_OK){
cerr<<"Error while extracting archive "+path<<endl;
}else{
copyData(file, dest);
status=archive_write_finish_entry(dest);
if(status!=ARCHIVE_OK){
cerr<<"Error while extracting archive "+path<<endl;
}
}
}
And finally we close the archive:
- {l Code}: {l Select All Code}
archive_read_close(file);
archive_read_finish(file);
And here follows the copyData function.
There are only two lines of code that actually perform to coping:
archive_read_data_block(file, &buff, &size, &offset);archive_write_data_block(dest, buff, size, offset);- {l Code}: {l Select All Code}
void Addons::copyData(archive *file, archive *dest) {
int status;
const void *buff;
size_t size;
off_t offset;
while(true) {
status=archive_read_data_block(file, &buff, &size, &offset);
if(status==ARCHIVE_EOF){
return;
}
if(status!=ARCHIVE_OK){
cerr<<"Error while writing data to disk."<<endl;
return;
}
status=archive_write_data_block(dest, buff, size, offset);
if(status!=ARCHIVE_OK) {
cerr<<"Error while writing data to disk."<<endl;
return;
}
}
}
That's all that needs to be done!