I need to unzip a file that I download from the internet, in C++. I've searched around for hours and I can't find anything.
For the moment I'm using libzip, and I can successfully read the file, I just have no idea on how to write it as files in a folder:
int unzipFile(std::string zipPath) {
//Open the ZIP archive
int err = 0;
zip* z = zip_open(zipPath.c_str(), 0, &err);
//Search for the file of given name
const char* name = "AvaloniaLauncher.exe";
struct zip_stat st;
zip_stat_init(&st);
zip_stat(z, name, 0, &st);
//Alloc memory for its uncompressed contents
char* contents = new char[st.size];
//Read the compressed file
zip_file* f = zip_fopen(z, name, 0);
zip_fread(f, contents, st.size);
zip_fclose(f);
//And close the archive
zip_close(z);
//Do something with the contents
printf(contents);
//delete allocated memory
delete[] contents;
return err;
}
I only found this snippet on a old thread from '12, so I would't wake that up again.
I now have the uncompressed contents of the file, but how would I go about on writing it?
Thanks.
Related
I'm using libZip in my project,
I success to create zip file output, but I'm having difficulty to set a password to a zip file.
I'm calling the zip_set_default_password fucntion and I'm getting the OK response, but when I'm trying to extract it didn't ask for a password.
Code sample:
int CompressWithPassword(const char * psFileContent, int iFileSize, const char * pcPassword)
{
zip_source *psZipSource = NULL;
zip_int64_t iIndex = 0;
int iError = EOK;
const char * pcZipOutputPath = "/home/user/Documents/myzip.zip";
// Open zip file.
m_psZip =
zip_open(pcZipOutputPath,
ZIP_CREATE /*Create the archive if it does not exist*/,
&iError);
// Zip opend ?
if(iError != ZIP_ER_OK)
{
Close();
return iError;
}
// Generate zip source content.
psZipSource =
zip_source_buffer(m_psZip,
psFileContent,
iFileSize,
0);
// Valid zip source ?
if(psZipSource == NULL)
{
Close();
iError = -1;
return iError;
}
iIndex =
zip_file_add(m_psZip,
pcZipOutputPath,
psZipSource, ZIP_FL_OVERWRITE);
if(iIndex < 0)
{
Close();
return iIndex;
}
// Create password
int iRetPassword =
zip_set_default_password(m_psZip, pcPassword);
// password set ?
if (iRetPassword == -1)
{
Close();
return iRetPassword;
}
// Close zip file.
Close();
return iError;
}
When I'm calling this function, I'm getting OK and the zip file is created, What I'm missing here?
LibZip version 1.1.3-1, OS: fedora 25
Thanks.
I saw that has a lot of people searching by this question, then i'll make an example of zip_file_set_encryption, the method basically ask for zip archive, file index,encryption method and the password:
int main(){
int errCode = 0;
zip *z = zip_open("package.zip",ZIP_CREATE,&errCode);
zip_source_t *source;
char buffer[] = "Hello world!";
source = zip_source_buffer(z,buffer,strlen(buffer),0);
zip_file_add(z,"example.txt",source,0);
/* Available encryption methods:
ZIP_EM_AES_128
ZIP_EM_AES_192
ZIP_EM_AES_256
*/
zip_file_set_encryption(z,/* Index of the file */ 0,/* Encryption method */ ZIP_EM_AES_256,/* Password to encrypt file */ "myPassword");
zip_close(z);
};
then when i use 7-zip to open the zip file created by my program:
7z e package.zip
It just prompt the password to me, if you type the correct then the files in your workspace will be filled with the content:
Enter password (will not be echoed):
with the libzip is possible set file password by name, but with a little process before:
int main(){
int errCode = 0;
zip *z = zip_open("package.zip",ZIP_CREATE,&errCode);
zip_source_t *source;
char buffer[] = "Hello world!";
source = zip_source_buffer(z,buffer,strlen(buffer),0);
zip_file_add(z,"example.txt",source,0);
source = zip_source_buffer(z,buffer,strlen(buffer),0);
zip_file_add(z,"example2.txt",source,0);
// Create struct of file stat
struct zip_stat st;
// Fill the struct with the file name that you want
zip_stat(z,"example2.txt",0,&st);
// Set the password to the file using index that had got by name
/* Available encryption methods:
ZIP_EM_AES_128
ZIP_EM_AES_192
ZIP_EM_AES_256
*/
zip_file_set_encryption(z,/* Index of file */ st.index, /* encryption method */ ZIP_EM_AES_256, /* password */"myPassword");
zip_close(z);
};
I'm creating an wrapper for libzip (not complete yet), an easy way to interact with zip files, the GitHub URL is there: https://github.com/Romulo-Moraes/zipCrafter
Caution, if you set an password to a file, you should set the same password for the whole zip file, cause it can generate an error when you try open with 7-zip, it will try open the first file with your password then will try the same password for the whole zip.
Some unzip program versions will skip your file that was set with password by libzip, i recommend 7-zip
As written in the Libzip Documentation here, 'zip_set_default_password' will "sets the default password used when accessing encrypted files", if you use 'zip_fopen' to open files. otherwise, if you have a different password for single files you can use 'zip_fopen_encrypted' to open them.
If you want to encrypt files you add to an archive you need to use 'zip_file_set_encryption' with (m_psZip, iIndex, method you choose, pcPassword).
I want to upload file using poco library.
Now I have the uploaded file in the istream variable but I don't know how I can save it to a file?
Here is my code where i can get the length of the file.
void handlePart(const MessageHeader &header, std::istream &stream) {
_type = header.get("Content-Type", "(unspecified)");
if (header.has("Content-Disposition")) {
std::string disp;
NameValueCollection params;
MessageHeader::splitParameters(header["Content-Disposition"], disp, params);
_name = params.get("name", "(unnamed)");
_fileName = params.get("filename", "(unnamed)");
}
CountingInputStream istr(stream);
NullOutputStream ostr;
StreamCopier::copyStream(istr, ostr);
_length = istr.chars();
}
Also now it's 1 file uploaded in the form if there be more than 1 file how it will be managed in istream?
Now there is 2 days I'm searching and testing different ways but I couldn't find any way, please help to resolve this problem.
Thank you in advanced.
Depend on #Abhinav question on this post:
We can write save code like this:
if (fileName.length() != 0){
std::ofstream fout( fileName, std::ios::binary);
fileList.push_back(fileName);
fout << stream.rdbuf() ;
fout.close();
}
But unfortunately it's working for one file if there is more than one this code can't catch correctly.
I would like to render files in node.js from C++ addon.
I want to apply some file processing and render the output to the browser via node.js
Here is my C++ Code
std::ifstream in(filename, std::ios::binary);
in.seekg (0, in.end);
int length = in.tellg();
in.seekg (0, in.beg);
char * buffer = new char [length];
in.read (buffer,length);
in.close();
return buffer;
Following is the V8 code to add bindings for node.js, here buffer is the output from the above c++ code.
Local<Function> cb = Local<Function>::Cast(args[1]);
const unsigned argc = 1;
Local<Value> argv[argc] = {Local<Value>::New(String::New(buffer))};
cb->Call(Context::GetCurrent()->Global(), argc, argv);
This code works well for normal text files. I'm getting problem when reading text files which are having unicode characters.
For eg,
Original text file
test start
Billél
last
When receiving in node, I will get
test start
Bill�l
last
Similarly when reading a jpg, png files the output file is different than the original file.
Please help.
I was having problems with this as well. I found an implementation in the V8 examples from Google. The example I found that properly handles UTF8 encoded files is found here:
https://code.google.com/p/v8/source/browse/trunk/samples/shell.cc#218
I adapted the source to this:
const char* ReadFile(const char* fileName, int* fileSize)
{
// reference to c-string version of file
char *fileBuffer = 0;
// attempt to open the file
FILE* fd = fopen(fileName, "rb");
// clear file size
*fileSize = 0;
// file was valid
if(fd != 0)
{
// get size of file
fseek(fd, 0, SEEK_END);
*fileSize = ftell(fd);
rewind(fd);
// allocate file buffer for file contents
fileBuffer = (char*)malloc(*fileSize + 1);
fileBuffer[*fileSize] = 0;
// copy file contents
for (int charCount = 0; charCount < *fileSize;)
{
int charRead = static_cast<int>(fread(&fileBuffer[charCount], 1, *fileSize - charCount, fd));
charCount += charRead;
}
// close the file
fclose(fd);
}
return fileBuffer;
}
Also, make sure when you create a V8 string that you create a String::Utf8Value.
String::Utf8Value v8Utf8String(...);
Then to use the String::Utf8Value as a char* use the following function:
https://code.google.com/p/v8/source/browse/trunk/samples/shell.cc#91
My function reads process list from /proc, then read process psinfo file into proper sturcture, as well as data about this file, and prints it.
The problem is, some of the data in those structures is wrong. As usual, the moment when program partially works, is the most confusing. It reads all data correct, except for PID (pr_pid), which is always 0, and UID of a file, which is also always 0. Why? Is it possible for data to load partially correctly? That shouldn't be possible.. 0 would be possible if we were talking about PPID, but solaris documentation clearly states pr_pid is the PID.
Links which I thought would have answers, but I couldn't find one:
http://docs.oracle.com/cd/E19963-01/html/821-1473/proc-4.html
http://linux.die.net/man/3/getpwnam
http://linux.die.net/man/2/stat
code:
void printProcessInformation(char pid[]){
//find full path name to your "stat" file
//DIR *dir;
//struct dirent *ent;
//Creating string with /proc/PID
char * s = malloc(snprintf(NULL, 0, "%s%s", "/proc/", pid) + 1);
sprintf(s, "%s%s", "/proc/", pid);
//Creating string with /proc/PID/psinfo (full path)
char * fullPath = malloc(snprintf(NULL, 0, "%s%s", s, "/psinfo") + 1);
sprintf(fullPath, "%s%s", s, "/psinfo");
free(s);
//printf("%s\n",fullPath);
//Reading data from file
FILE* file = fopen(fullPath, "r");
char* buffer;
buffer = (char*) malloc(sizeof(psinfo_t));
if(file == NULL)
{
perror("Error: Couldn't open file");
return;
}
fread((void *)buffer, sizeof(psinfo_t), 1, file);
psinfo_t* pData = (psinfo_t*) buffer;
free(buffer);
buffer = (char*) malloc(sizeof(stat));
stat(file,buffer);
struct stat* fileStat=(struct stat*) buffer;
printf("File owner id:%d\n",fileStat->st_uid);
free(buffer);
fclose(file);
struct passwd* pw=getpwuid(fileStat->st_uid);
//Loading data from structures
time_t sTime=pData->pr_start.tv_sec;
int pr_pid=pData->pr_pid;
char* fname=pData->pr_fname;
char* uid=pw->pw_name;
printf("%8s %5d %16s %.24s\n", uid, pr_pid, fname, ctime(&sTime));
}
Look at this:
psinfo_t* pData = (psinfo_t*) buffer;
free(buffer);
...
int pr_pid=pData->pr_pid;
You're setting pData to the contents of buffer in the first line and then freeing it. What pData points to is now lost to you, it may in fact be reused in the next malloc. When you try to use it in the last line above you're reading who knows what. You're freeing too agressively in this case. Don't free pData, (indirectly through buffer) until you're done using it.
Simply what it says on the tin
I'm loading a bitmap from a file using Bitmap::FromFile but afterwards I want to delete it from the disk.
The problem is, Bitmap::FromFile absolutely locks the file from any changes/deletion until the loaded image is unloaded
This is because I'm storing the bitmaps in a binary file, so I want to do it in this order:
1. extract the image from binary file
2. load the image
3. delete the file extracted in #1
(just some basic protection for my image resources, I just don't want them sitting in my program directory)
Bitmap::FromFile still locks the file from deletion even when cloning the loaded image from the file like in my attempt:
Bitmap* tempbmp = Bitmap::FromFile(fileanddir.c_str(),false);
Rect temprect( 0, 0, tempbmp->GetWidth(), tempbmp->GetHeight() );
// make the image to be used as a clone to the temporary
// bitmap to avoid file locking
image_to_be_used = tempbmp->Clone(temprect, PixelFormatDontCare);
// delete temporary loaded bitmap since it shouldn't be needed
delete tempbmp;
// delete the file itself, too bad the file is locked
int theresult = remove(tocharptr(fileanddir));
// returns -1, also: manually deleting at this point gives the error
// that the file is being used by another person/program
Any idea how I can load a bitmap or somehow copy it to memory so the file itself wouldn't be locked ?
(So i can delete it a moment after loading it)
You can do it this way
Gdiplus::Bitmap* LoadImageFromFileWithoutLocking(const WCHAR* fileName) {
using namespace Gdiplus;
Bitmap src( fileName );
if ( src.GetLastStatus() != Ok ) {
return 0;
}
Bitmap *dst = new Bitmap(src.GetWidth(), src.GetHeight(), PixelFormat32bppARGB);
BitmapData srcData;
BitmapData dstData;
Rect rc(0, 0, src.GetWidth(), src.GetHeight());
if (src.LockBits(& rc, ImageLockModeRead, PixelFormat32bppARGB, & srcData) == Ok)
{
if ( dst->LockBits(& rc, ImageLockModeWrite, PixelFormat32bppARGB, & dstData) == Ok ) {
uint8_t * srcBits = (uint8_t *) srcData.Scan0;
uint8_t * dstBits = (uint8_t *) dstData.Scan0;
unsigned int stride;
if (srcData.Stride > 0) {
stride = srcData.Stride;
} else {
stride = - srcData.Stride;
}
memcpy(dstBits, srcBits, src.GetHeight() * stride);
dst->UnlockBits(&dstData);
}
src.UnlockBits(&srcData);
}
return dst;
}
Take a look at Bitmap::FromStream. You should be able to use SHCreateStreamOnFileEx to open an IStream on the file. After loading your bitmap you can safely delete the stream and then the temporary file.
If the binary file is only compressed with a supported algorithm, then pass the corresponding flag to SHCreateStreamOnFileEx and have it read the archive, bypassing the extraction of the image into a temp file. Otherwise can implement the IStream interface to read the binary file and extract your image data directly.
if you interested in MFC-OLE sample:
CFile file;
CFileException fe;
CString strFileName = "C:\\yours.bmp";
if (!file.Open(strFileName, CFile::modeRead | CFile::shareDenyNone , &fe))
{
return;
}
COleStreamFile stream;
if(!stream.CreateMemoryStream(NULL))
{
return;
}
BYTE buf[1024];
int readed = 0;
do
{
readed = file.Read(buf,1024);
stream.Write(buf,readed);
}
while(readed > 0);
file.Close();
stream.SeekToBegin();
USES_CONVERSION;
m_pImage = new Gdiplus::Bitmap(stream.GetStream( ));