zlib minizip解压缩的可执行文件已损坏

时间:2018-07-02 19:02:33

标签: c++ zlib

我正在尝试使用miniunzip提取一些文件。它可以在Linux上运行。在Windows上,它不会引发任何错误,但是如果文件是可执行文件,则生成的二进制文件将不起作用。我得到一个消息窗口,其中包含有关与64位Windows不兼容的消息。如果我使用另一个实用程序(例如7-zip)来解压缩它,则一切正常,因此问题出在我的代码中。这是完成所有工作的类方法。

bool FileHandler::unzip( string inputFile, string outputDirectory )
{
    if (!fileExists(inputFile)) {
        this->errorMessage = "Can't find file at " + inputFile;
        return false;
    }
    unzFile zipFile = unzOpen(inputFile.c_str());
    if( zipFile == nullptr ){
        this->errorMessage = "FileHandler::unzip failed to open input file";
        return false;
    }
    vector<string> files;
    vector<string> folders;
    unz_global_info globalInfo;
    int err = unzGetGlobalInfo( zipFile, &globalInfo );
    if (unzGoToFirstFile(zipFile) != UNZ_OK) {
        this->errorMessage = "FileHandler::unzip failed calling unzGoToFirstFile";
        return false;
    }
    for ( unsigned long i=0; i < globalInfo.number_entry && err == UNZ_OK; i++ ){
        char filename[FILENAME_MAX];
        unz_file_info subFileInfo;
        err = unzGetCurrentFileInfo( zipFile, &subFileInfo, filename,
                                    sizeof(filename), NULL, 0, NULL, 0);
        if ( err == UNZ_OK )
        {
            char nLast = filename[subFileInfo.size_filename-1];
            if ( nLast =='/' || nLast == '\\' )
            {
                folders.push_back(filename);
            }
            else
            {
                files.push_back(filename);
            }

            err = unzGoToNextFile(zipFile);
        }
    }


    for ( string & folder : folders ){
        string strippedFolder = folder.substr(0, folder.length()-1);
        string dirPath = normalizePath(outputDirectory+"/"+strippedFolder);
        if( ! makeDirectory( dirPath ) ){
            this->errorMessage = "FileHandler::unzip Failed to create directory "+dirPath;
            return false;
        }
    }
    for ( auto it = files.begin(); it != files.end(); it++ ){
        if( zipFile == 0 ){
            this->errorMessage = "FileHandler::unzip invalid unzFile object at position 1";
            return false;
        }
        string filename = *it;

        //string filepath = outputDirectory + "/" + *it;
        string filepath = normalizePath( outputDirectory + "/" + *it );

        const char * cFile = filename.c_str();
        const char * cPath = filepath.c_str();
        int err = unzLocateFile( zipFile, cFile, 0 );
        if ( err != UNZ_OK ){
            this->errorMessage = "FileHandler::unzip error locating sub-file.";
            return false;
        }
        err = unzOpenCurrentFile( zipFile );
        if( err != UNZ_OK ){
            this->errorMessage = "FileHandler::unzip error opening current file";
            return false;
        }
        ofstream fileStream{ cPath };
        // Need an ostream object here.
        if( fileStream.fail() ){
            this->errorMessage = "FileHandler::unzip error opening file stream at "+string(cPath);
            return false;
        }
        unz_file_info curFileInfo;
        err = unzGetCurrentFileInfo( zipFile, &curFileInfo, 0, 0, 0, 0, 0, 0);
        if ( err != UNZ_OK )
        {
            this->errorMessage = "FileHandler::unzip failed to read size of file";
            return false;
        }
        unsigned int size = (unsigned int)curFileInfo.uncompressed_size;
        char * buf = new char[size];
        size = unzReadCurrentFile( zipFile, buf, size );
        if ( size < 0 ){
            this->errorMessage = "FileHandler::unzip unzReadCurrentFile returned an error. ";
            return false;
        }
        fileStream.write( buf, size );
        fileStream.flush();
        delete [] buf;

        fileStream.close();
#ifndef _WIN32
        vector<string> parts = splitString(filename, ".");
        if( parts.size() == 1 ){ // In linux, assume file without extension is executable
            mode_t old_mask = umask( 000 );
            chmod( cPath, S_IRWXU|S_IRWXG|S_IROTH|S_IXOTH );
            umask( old_mask );
        }
#endif
        unzCloseCurrentFile( zipFile );
    }
    unzClose(zipFile);
    return true;
}

1 个答案:

答案 0 :(得分:2)

std::ostream默认以文本模式打开文件,您需要改为使用二进制模式。

在Linux上,文本模式和二进制模式之间似乎没有任何区别。但是在Windows上,尝试将\n写入文本文件会产生\r\n,从而破坏您的数据。

您需要更改此行

ofstream fileStream{ cPath };

ofstream fileStream{ cPath, ostream::out | ostream::binary };